Toyomasa Watarai
/
Mbed-example-WS-W27
Revision 0:119624335925, committed 2018-06-30
- Comitter:
- MACRUM
- Date:
- Sat Jun 30 01:40:30 2018 +0000
- Commit message:
- Initial commit
Changed in this revision
diff -r 000000000000 -r 119624335925 LM75B.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LM75B.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/chris/code/LM75B/#6a70c9303bbe
diff -r 000000000000 -r 119624335925 MMA7660.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MMA7660.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/Sissors/code/MMA7660/#36a163511e34
diff -r 000000000000 -r 119624335925 README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +# Mbed-example-WS-W27 +Mbed Cloud example program for workshop in W27 2018. + +## Prerequisites + +1. Replace mbed_cloud_dev_credentials.c +2. Modify Wi-Fi SSID and password in mbed_app.json + +## Build + +```$ mbed compile -t GCC_ARM -m K64F```
diff -r 000000000000 -r 119624335925 easy-connect.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/easy-connect/#5b52b5fa56c623d5853c5daf266b34986a0c20cc
diff -r 000000000000 -r 119624335925 easy-connect/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +5b52b5fa56c623d5853c5daf266b34986a0c20cc
diff -r 000000000000 -r 119624335925 easy-connect/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +aaf89690919fc378799e680119a58a222402799f
diff -r 000000000000 -r 119624335925 easy-connect/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/easy-connect/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 easy-connect/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 easy-connect/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 easy-connect/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 easy-connect/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 easy-connect/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 easy-connect/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 easy-connect/.git/index Binary file easy-connect/.git/index has changed
diff -r 000000000000 -r 119624335925 easy-connect/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores +atmel-rf-driver +esp8266-driver +mcr20a-rf-driver +stm-spirit1-rf-driver +wifi-ism43362 +wifi-x-nucleo-idw01m1 +wizfi310-driver +wnc14a2a-driver \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 aaf89690919fc378799e680119a58a222402799f www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322650 +0000 clone: from https://github.com/ARMmbed/easy-connect/ +aaf89690919fc378799e680119a58a222402799f 5b52b5fa56c623d5853c5daf266b34986a0c20cc www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322651 +0000 checkout: moving from master to 5b52b5fa56c623d5853c5daf266b34986a0c20cc
diff -r 000000000000 -r 119624335925 easy-connect/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 aaf89690919fc378799e680119a58a222402799f www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322650 +0000 clone: from https://github.com/ARMmbed/easy-connect/
diff -r 000000000000 -r 119624335925 easy-connect/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 aaf89690919fc378799e680119a58a222402799f www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322650 +0000 clone: from https://github.com/ARMmbed/easy-connect/
diff -r 000000000000 -r 119624335925 easy-connect/.git/objects/pack/pack-cf742d9e42d66228c1a91b7e60704bc9241175f6.idx Binary file easy-connect/.git/objects/pack/pack-cf742d9e42d66228c1a91b7e60704bc9241175f6.idx has changed
diff -r 000000000000 -r 119624335925 easy-connect/.git/objects/pack/pack-cf742d9e42d66228c1a91b7e60704bc9241175f6.pack Binary file easy-connect/.git/objects/pack/pack-cf742d9e42d66228c1a91b7e60704bc9241175f6.pack has changed
diff -r 000000000000 -r 119624335925 easy-connect/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,29 @@ +# pack-refs with: peeled +c5ce3e9a02c7a707a2ce4eca11a880ddae0824dd refs/remotes/origin/China_Unicom_Demo +c447f41a97f22fc58da960fd7f936d049058df9a refs/remotes/origin/README-issues +e790c499e9c60ad33b845094fc71fb61e90cc904 refs/remotes/origin/README-mbedignore +60f6100d519763c2087a399071ab91c7ac5f79a9 refs/remotes/origin/WISE1530 +8910b5106ba424d300afb357b0d42b547bf28d6c refs/remotes/origin/early_mac +0e924fc9504c5fc4425adf30f7ad85a9fe0bf4fd refs/remotes/origin/esp8266-latest +fcb6b507d0eb336c66342492611550dc43338ce8 refs/remotes/origin/gitign +8f0c5df3f39b20bc3d57f32b44087dabde1fa981 refs/remotes/origin/if_updates +aaf89690919fc378799e680119a58a222402799f refs/remotes/origin/master +e61ba698f31f71693451e91f68bb2035706695b7 refs/remotes/origin/mbedos5.3.4 +0c77697463c204aa53467a8b7c6286c31b973792 refs/remotes/origin/odin +bfed7888153a32712d1da875c09c3ab60ec3706c refs/remotes/origin/quectel_cellular +d3503403331d10000e1d061fe189c17f215d4e89 refs/remotes/origin/revert-mts +489b3343cb0d52d301752e085edb476efef38977 refs/remotes/origin/test-pin-mapping +2822a4f704b61664c38c119e4eea694b81ec91a6 refs/remotes/origin/ublox_cellular +cd93e9d4d03a39e15aa0a6418dacb28edf60820f refs/remotes/origin/wifi-ism +522e43fa1bba9483f12284e2e80882f526ec2830 refs/tags/v1.0.0 +06594ba91bc141f08fe4024d0e9471605827cbd0 refs/tags/v1.0.1 +836c2959c669164f1effb243128ff5a9479d5812 refs/tags/v1.0.2 +4e608305251d18851afc500dbbe704cca51db624 refs/tags/v1.0.3 +559d00bf1580a5dbc423c37a06a84602b6aae90d refs/tags/v1.1.0 +48d7e16f0e965766787b7383fbf0cd1d00b1efb5 refs/tags/v1.2.0 +ce7059cc482a383640afe306f96333de49008086 refs/tags/v1.2.10 +5b52b5fa56c623d5853c5daf266b34986a0c20cc refs/tags/v1.2.11 +6b2cce9f7cefd02e0503d6307ab5433b6197716d refs/tags/v1.2.2 +4aea66bdd42bad5a01b7c6afb195aaeead42f5ae refs/tags/v1.2.3 +7bc131ebae4a8bcfde095121e3f864407a158c82 refs/tags/v1.2.4 +21a78a40e94ba9298e05ce54738c6b42657ae010 refs/tags/v1.2.9
diff -r 000000000000 -r 119624335925 easy-connect/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +aaf89690919fc378799e680119a58a222402799f
diff -r 000000000000 -r 119624335925 easy-connect/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/.gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.gitignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,16 @@ +atmel-rf-driver/* +atmel-rf-driver +esp8266-driver/* +esp8266-driver +mcr20a-rf-driver/* +mcr20a-rf-driver +stm-spirit1-rf-driver +stm-spirit1-rf-driver/* +wifi-ism43362 +wifi-ism43362/* +wifi-x-nucleo-idw01m1 +wifi-x-nucleo-idw01m1/* +wizfi310-driver +wizfi310-driver/* +wnc14a2a-driver +wnc14a2a-driver/*
diff -r 000000000000 -r 119624335925 easy-connect/.msub --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/.msub Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +atmel-rf-driver = https://github.com/ARMmbed/atmel-rf-driver/#116:ca9782e68f5f47680b7ec82c3dcb60a98dd8e361 +esp8266-driver = https://github.com/ARMmbed/esp8266-driver/#44:5a0a2cba8c125d2b74e73e209342bd169ad11bbd +mcr20a-rf-driver = https://github.com/ARMmbed/mcr20a-rf-driver/#23:93661a696735279590378e6abef1d689799b713e +stm-spirit1-rf-driver = https://github.com/ARMmbed/stm-spirit1-rf-driver/#77:ce9e2f81f95f895652789eeb196443eff5ac6ed7 +wifi-ism43362 = https://github.com/ARMmbed/wifi-ism43362/#16:e847364be04499dc91d9e99f0df2ba6ecf95cd20 +wifi-x-nucleo-idw01m1 = https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/#86:376b457a84631f11178b895bee5c790ff6c3d768 +wizfi310-driver = https://github.com/ARMmbed/wizfi310-driver/#11:e0f7b9355e7e23daaa2d3f1d5c389c52528d6178 +wnc14a2a-driver = https://github.com/Avnet/wnc14a2a-driver/#18:90928b81747ef4b0fb4fdd94705142175e014b30
diff -r 000000000000 -r 119624335925 easy-connect/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,226 @@ +# Easy Connect - Easily add all supported connectivity methods to your mbed OS project + +You may want to give the users of your application the possibility to switch between connectivity methods. The `NetworkInterface` API makes this easy, but you still need a mechanism for the user to chooce the method, and perhaps throw in some `#define`'s. Easy Connect handles all of this for you. Just declare the desired connectivity method in your `mbed_app.json` file and call `easy_connect()` from your application. + +## Specifying the connectivity method + +Add the following to your `mbed_app.json` file: + +```json +{ + "config": { + "network-interface":{ + "help": "options are ETHERNET, WIFI_ESP8266, WIFI_IDW0XX1, WIFI_ODIN, WIFI_RTW, WIFI_WIZFI310, WIFI_ISM43362, MESH_LOWPAN_ND, MESH_THREAD, CELLULAR_ONBOARD", + "value": "ETHERNET" + } + }, + "target_overrides": { + "*": { + "target.features_add": ["NANOSTACK", "LOWPAN_ROUTER", "COMMON_PAL"], + "mbed-mesh-api.6lowpan-nd-channel-page": 0, + "mbed-mesh-api.6lowpan-nd-channel": 12 + } + } +} +``` + +### UBLOX ODIN/Ethernet + +#### Mbed OS 5.8 and older + +If you select `ETHERNET` with `UBLOX_ODIN_EVK_W2` you must add this to your `target-overrides` section in `mbed_app.json`: + +```json + "UBLOX_EVK_ODIN_W2": { + "target.device_has_remove": ["EMAC"] + } +``` + +#### Mbed OS 5.9 and newer + +With Mbed OS 5.9, the EMAC SW was refactored and a default network selector is used instead. You must add the following `target-overrides` section to `mbed_app.json`: + +```json + "UBLOX_EVK_ODIN_W2": { + "target.network-default-interface-type": "ETHERNET" + } +``` + +### Other WiFi stacks + +If you select `WIFI_ESP8266`, `WIFI_IDW0XX1`, `WIFI_ODIN` or `WIFI_RTW`, `WIFI_WIZFI310` you also need to add the WiFi SSID and password: + +```json + "config": { + "network-interface":{ + "help": "options are ETHERNET, WIFI_ESP8266, WIFI_IDW0XX1, WIFI_ODIN, WIFI_RTW, WIFI_WIZFI310, WIFI_ISM43362, MESH_LOWPAN_ND, MESH_THREAD, CELLULAR_ONBOARD", + "value": "WIFI_ESP8266" + }, + "wifi-ssid": { + "value": "\"SSID\"" + }, + "wifi-password": { + "value": "\"Password\"" + } + } +``` + +If you use `MESH_LOWPAN_ND` or `MESH_THREAD` you need to specify your radio module: + +```json + "config": { + "network-interface":{ + "help": "options are ETHERNET, WIFI_ESP8266, WIFI_IDW0XX1, WIFI_ODIN, WIFI_RTW, WIFI_WIZFI310, MESH_LOWPAN_ND, MESH_THREAD, CELLULAR_ONBOARD", + "value": "MESH_LOWPAN_ND" + }, + "mesh_radio_type": { + "help": "options are ATMEL, MCR20, SPIRIT1, EFR32", + "value": "ATMEL" + } + } +``` + +### CELLULAR_ONBOARD + +If you use [`CELLULAR_ONBOARD`](https://docs.mbed.com/docs/mbed-os-api-reference/en/latest/APIs/communication/cellular/) you must specify the following: + +```json + "target_overrides": { + "*": { + "ppp-cell-iface.apn-lookup": true + } + } +``` +...and you may also need to specify one or more of the following: + +```json + "config": { + "cellular-apn": { + "help": "Please provide the APN string for your SIM if it is not already included in APN_db.h.", + "value": "\"my_sims_apn\"" + }, + "cellular-username": { + "help": "May or may not be required for your APN, please consult your SIM provider.", + "value": "\"my_sim_apns_username\"" + }, + "cellular-password": { + "help": "May or may not be required for your APN, please consult your SIM provider.", + "value": "\"my_sim_apns_password\"" + }, + "cellular-sim-pin": { + "help": "Please provide the PIN for your SIM (as a four digit string) if your SIM is normally locked", + "value": "\"1234\"" + } + } +``` + +None of the optional settings need to be specified for the `UBLOX_C030_U201` cellular target, for which the APN settings are in `APN_db.h`. + +## Using Easy Connect from your application + +Easy Connect has just one function that returns either a `NetworkInterface`-pointer or `NULL`: + +```cpp +#include "easy-connect.h" + +int main(int, char**) { + NetworkInterface* network = easy_connect(true); /* has 1 argument, enable_logging (pass in true to log to serial port) */ + if (!network) { + printf("Connecting to the network failed... See serial output.\r\n"); + return 1; + } + + // Rest of your program +} +``` + +## Using Easy connect with WiFi + +The easy-connect `easy_connect()` is overloaded now for WiFi so that you can submit your WiFi SSID and password programmatically in you want +the user to be able to supply them via some means. + +```cpp +#include "easy-connect.h" + +int main(int, char**) { + char* wifi_SSID = "SSID"; + char* wifi_password = "password"; + + NetworkInterface* network = easy_connect(true, wifi_SSID, wifi_password); + if (!network) { + printf("Connecting to the network failed... See serial output.\r\n"); + return 1; + } + + // Rest of your program +} +``` + +## Overriding settings + +Easy-connect was changed recently with [PR #59](https://github.com/ARMmbed/easy-connect/pull/59) - where some of the defines expected via `mbed_app.json` were +moved to the [`mbed_lib.json`](https://github.com/ARMmbed/easy-connect/blob/master/mbed_lib.json). +This minimises the amount of lines needed (in typical cases) in the applications `mbed_app.json`. However, due to this the overrides +need to be done slightly differently, as you need to override the `easy-connect` defines. + +So, for example changing the ESP8266 TX/RX pins and enable debugs - you would now have modify as below. + +```json + "target_overrides": { + "*": { + "easy-connect.wifi-esp8266-tx": "A1", + "easy-connect.wifi-esp8266-rx": "A2", + "easy-connect.wifi-esp8266-debug: true + } + } +``` + + +## Configuration examples + +There are many things that you have to modify for all of the combinations. Examples for configurations are available for example in the [mbed-os-example-client](https://github.com/ARMmbed/mbed-os-example-client/tree/master/configs) repository. + +## Linking error with UBLOX_EVK_ODIN_W2 + +If you get a linking error such as below, you are compiling the `WIFI_ODIN` with the `EMAC override` section in `mbed_app.json`. Remove the `EMAC override` from your `mbed_app.json`. + +``` +Link: tls-client +./mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_UBLOX_EVK_ODIN_W2/sdk/TOOLCHAIN_GCC_ARM/libublox-odin-w2-driver.a(OdinWiFiInterface.o): In function `OdinWiFiInterface::handle_wlan_status_started(wlan_status_started_s*)': +OdinWiFiInterface.cpp:(.text._ZN17OdinWiFiInterface26handle_wlan_status_startedEP21wlan_status_started_s+0x46): undefined reference to `wifi_emac_get_interface()' +OdinWiFiInterface.cpp:(.text._ZN17OdinWiFiInterface26handle_wlan_status_startedEP21wlan_status_started_s+0x4c): undefined reference to `wifi_emac_init_mem()' +collect2: error: ld returned 1 exit status +[ERROR] ./mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_UBLOX_EVK_ODIN_W2/sdk/TOOLCHAIN_GCC_ARM/libublox-odin-w2-driver.a(OdinWiFiInterface.o): In function `OdinWiFiInterface::handle_wlan_status_started(wlan_status_started_s*)': +OdinWiFiInterface.cpp:(.text._ZN17OdinWiFiInterface26handle_wlan_status_startedEP21wlan_status_started_s+0x46): undefined reference to `wifi_emac_get_interface()' +OdinWiFiInterface.cpp:(.text._ZN17OdinWiFiInterface26handle_wlan_status_startedEP21wlan_status_started_s+0x4c): undefined reference to `wifi_emac_init_mem()' +collect2: error: ld returned 1 exit status + +[mbed] ERROR: "/usr/bin/python" returned error code 1. +``` + +## Network errors + +If Easy Connect cannot connect to the network, it returns a network error with an error code. To see what the error code means, see the [mbed OS Communication API](https://os.mbed.com/docs/latest/reference/network-socket.html). + +## CR/LF in serial output + +If you want to avoid using `\r\n` in your printouts and just use normal C style `\n` instead, please specify these to your `mbed_app.json`: + +```json + "target_overrides": { + "*": { + "platform.stdio-baud-rate": 115200, + "platform.stdio-convert-newlines": true + } + } +``` + +## For network stack developers + +Please try out the reliability of your networking stack using +[stress-test](https://github.com/ARMmbed/mbed-stress-test) to ensure +your stack is performing as expected. + +## Extra defines + +If you'd like to use Easy Connect with mbed Client then you're in luck. Easy Connect automatically defines the `MBED_SERVER_ADDRESS` macro depending on your connectivity method (either IPv4 or IPv6 address). Use this address to connect to the right instance of mbed Device Connector.
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/atmel-rf-driver/#ca9782e68f5f47680b7ec82c3dcb60a98dd8e361
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ca9782e68f5f47680b7ec82c3dcb60a98dd8e361
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +8cb119d4cca43238ee47e3e81078b3b5758870e8
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/atmel-rf-driver/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/index Binary file easy-connect/atmel-rf-driver/.git/index has changed
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 8cb119d4cca43238ee47e3e81078b3b5758870e8 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322697 +0000 clone: from https://github.com/ARMmbed/atmel-rf-driver/ +8cb119d4cca43238ee47e3e81078b3b5758870e8 ca9782e68f5f47680b7ec82c3dcb60a98dd8e361 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322698 +0000 checkout: moving from master to ca9782e68f5f47680b7ec82c3dcb60a98dd8e361
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 8cb119d4cca43238ee47e3e81078b3b5758870e8 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322697 +0000 clone: from https://github.com/ARMmbed/atmel-rf-driver/
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 8cb119d4cca43238ee47e3e81078b3b5758870e8 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322697 +0000 clone: from https://github.com/ARMmbed/atmel-rf-driver/
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/objects/pack/pack-22c1eb02287f0564e0edde981aecc37669c999bf.idx Binary file easy-connect/atmel-rf-driver/.git/objects/pack/pack-22c1eb02287f0564e0edde981aecc37669c999bf.idx has changed
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/objects/pack/pack-22c1eb02287f0564e0edde981aecc37669c999bf.pack Binary file easy-connect/atmel-rf-driver/.git/objects/pack/pack-22c1eb02287f0564e0edde981aecc37669c999bf.pack has changed
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,87 @@ +# pack-refs with: peeled +a2d72a667b7ed3ac4e70ae743fd3c02a6e02afda refs/remotes/origin/alpha2-release +d11d8a2564ef5f946c99f8003533caea13599d7b refs/remotes/origin/alpha3-release +6a5156bea2dc8981a7efd86bcdf341dc398307e3 refs/remotes/origin/dep_update +dc0c089e6782d66f3ef379736f3062afae708ef2 refs/remotes/origin/eui_chip_check +1bf67eedce0f85a16376876670d525144d887892 refs/remotes/origin/eui_mac_chip_check +1816200dbd1b336403525a9757a5d495cc7933e8 refs/remotes/origin/eventqueue +f29a7aaefdba350fee57572a7d56bba66a87464e refs/remotes/origin/fhss_dev +06296efdcc38e2719895af98e1f5ec911a1f00f8 refs/remotes/origin/mac_class_update +a41e721bbb81e4e15b812909cd36005a000b03f9 refs/remotes/origin/maint_merge +8cb119d4cca43238ee47e3e81078b3b5758870e8 refs/remotes/origin/master +b73c78b4f8ccbfa3295fd419173ce576ff9ddcf6 refs/remotes/origin/morpheus_dependency +248d04582db6ba2db423cf8eb4e3535d5ef4cb72 refs/remotes/origin/ns_minar_take2 +03f33d5a0fc026529fbf10943ba7a7de0fc64c62 refs/remotes/origin/perf_test +e89312f0278b8174e0159ec035cb49f639da6a45 refs/remotes/origin/pll_on_fail_fix +a36e17a728732268b404fc727940257830e208ac refs/remotes/origin/retries +a729202ba68a7537e4bdbea5f6d91d1522280ccd refs/remotes/origin/spi_timing_fix +a82eda14afc4bd57c0574d0d58443d4aa4dddf31 refs/remotes/origin/thread_start_cond +6666cb4f0f131803e315a5869be68dfbd911829b refs/remotes/origin/ublox_fixes +37e636728520d0d6d4e6caafff5e36962e5ceec0 refs/remotes/origin/update_mbed_dep +0f7255a79b69c09469f4b3377513a39a9e6b25f5 refs/remotes/origin/v1.0-maint +a7ff1a1ea2b3060139a345a09b72bdbf244cf4dc refs/remotes/origin/v2.1-maint +453e4e2324d1d634dad87b1e107a1bc762c8ff2f refs/tags/beta-release +a16a4ed6f6e8d5f2d009f25b6ab7c38affb5019c refs/tags/mbed-os-5.1.0-rc3 +a16a4ed6f6e8d5f2d009f25b6ab7c38affb5019c refs/tags/mbed-os-5.1.0-rc4 +a2d72a667b7ed3ac4e70ae743fd3c02a6e02afda refs/tags/mbedOS-alpha2 +4d2d328030c538a15cde01baa6c6e8f15ba7e0f4 refs/tags/mbedos-16.01-release +4d2d328030c538a15cde01baa6c6e8f15ba7e0f4 refs/tags/mbedos-16.03-release +4a7b2df89566412ab1f78c34acd66e114c210965 refs/tags/mbedos-2016q1-oob1 +4a7b2df89566412ab1f78c34acd66e114c210965 refs/tags/mbedos-2016q1-oob2 +4d2d328030c538a15cde01baa6c6e8f15ba7e0f4 refs/tags/mbedos-2016q1-oob3 +dcd91e50e2cef8a8944ec4acc30a9186fd250838 refs/tags/mbedos-release-15-11 +083d0d49ede86c2bf6417bf0a951ff37e497480c refs/tags/mbedos-techcon-oob2 +cf743c8ed7a61cd9217d010415b872629afa92ca refs/tags/v0.0.10 +d11d8a2564ef5f946c99f8003533caea13599d7b refs/tags/v0.0.11 +3b4d57bc558e26d357280c56908a2e0a211541dc refs/tags/v0.0.12 +7ee6cb249980d2b9f4e18744273ddd4da446e43b refs/tags/v0.0.13 +0ab8f39aebb09c3d57b1b612f562c5f2ea8e8217 refs/tags/v0.0.14 +^607843bac2c6677f69805fa45b169a9f4a89147c +5ddc1deddcabe511d9e92d82ba2943d4ab272901 refs/tags/v0.0.15 +^f2fa5831d8d80deaeff177fffb628c06f5e3f4ce +1b68214c528ef2fa41827292d0a8b919f530d4e6 refs/tags/v0.0.16 +^60256bb25d369570403ca27e752a6847b35b1424 +761c9ed3ee0e01563a1fa4783c03f3d4b40eb87b refs/tags/v0.0.18 +^f245f7ae3556436d017827d097904d85f8d7061c +83e3d05272235be8e2fbd671ecd0489f05974dd0 refs/tags/v0.0.19 +^7d53d340711421f2ceffa43bbc036530c1cab6d3 +4b57c221f603ec186f2939d25c17481954468ca4 refs/tags/v0.0.20 +^ec465a0701cf62542dea77b6a4933adcb3275028 +66cb6974dd688bb99be556ff87305a99cf6ff584 refs/tags/v0.0.21 +^453e4e2324d1d634dad87b1e107a1bc762c8ff2f +a8ed93388a3952da5c2a15d1bda443f092afb746 refs/tags/v0.0.22 +^a293db7a32e00d4e96e2c0af3692c047d2126037 +05edb4fd8c8503181aa07c2cad5ab262d748cb27 refs/tags/v0.0.23 +^d57710cdad5df1e55af0a1be179b98a6e59c4ebd +844097fe55cfcc3658bed3452469137badca2798 refs/tags/v0.0.24 +^6269d5ea5e313b33f011ece34318ecac79d6a626 +876b12b8b4f2bbe9399345259b68259d33d59909 refs/tags/v0.0.25 +^4614966ca81530bc1fb376062af078c120f24241 +1874e9cf58468a41e25450dcffeb0e0ca08d9ca6 refs/tags/v0.0.8 +cc0a6379a081f4fddc1dc98e96f1bc7c4573115c refs/tags/v0.0.9 +9b2561ff19aa36d2176cae99d05e883ddabcb70a refs/tags/v1.0.0 +^083d0d49ede86c2bf6417bf0a951ff37e497480c +303705bca8f05d221c1f2a44290d46147af52b6f refs/tags/v1.0.1 +^dcd91e50e2cef8a8944ec4acc30a9186fd250838 +755358c39f9484546ef1330932e63d430550c825 refs/tags/v1.0.2 +^efe496dcf42e2eed98f6d70c33f8d6bd7cfd430e +eeb91783261991c06f0541a547ccea44afea7370 refs/tags/v1.0.3 +^0f7255a79b69c09469f4b3377513a39a9e6b25f5 +b17a8d9177c6985379176ffa41cb836632644162 refs/tags/v2.0.0 +^a7a63cfea3492f9693f1904cda264b99037fe475 +8a6fb2273f4b1cbd9b6b6cb7d4aa58774f06a0be refs/tags/v2.0.1 +^232e2508475626865679b5b4e43e21f19e2d2b88 +91c188f0c616ce47b5d1d832bed97aeb5cc02384 refs/tags/v2.0.2 +^4a7b2df89566412ab1f78c34acd66e114c210965 +ca1cad744508e1abc981b4dbd359401385b4da75 refs/tags/v2.0.3 +^41441226a87109a7405e4c8ba048311484a4b1c4 +d382c3d7e1a3656176bbf1d05180928cded5217d refs/tags/v2.1.0 +^4d2d328030c538a15cde01baa6c6e8f15ba7e0f4 +17393a1acefd268c75c0376aaa24c3ae6617f2f3 refs/tags/v2.1.1 +^a7ff1a1ea2b3060139a345a09b72bdbf244cf4dc +c81741ac293409229df9c2343398016205797eae refs/tags/v3.0.0 +^50889f6c316d0b80520c781841f053b3a8aa8cd3 +b13508e3cd625d723a153d10626bdd3b342382f7 refs/tags/v3.0.1 +^3de9de8fa23b2a699cef382dd49e7f9a1dec6e5d +80b2af683c02ca10f40917dcf60dc0e5973504d8 refs/tags/v3.0.2 +^160ce634ac16723c18bb2be61f1ed21c776252c9
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +8cb119d4cca43238ee47e3e81078b3b5758870e8
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/.gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/.gitignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,6 @@ +*~ +*.swo +*.swp +build +yotta_modules +yotta_targets
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,7 @@ +# Example RF driver for Atmel 802.15.4 transceivers # + +Support for: + * AT86RF233 + * AT86RF212B + +This driver is used with 6LoWPAN stack. \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/apache-2.0.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NANOSTACK_RF_PHY_ATMEL_H_ +#define NANOSTACK_RF_PHY_ATMEL_H_ + +#include "at24mac.h" +#include "PinNames.h" + +#ifdef MBED_CONF_NANOSTACK_CONFIGURATION + +#include "NanostackRfPhy.h" + +// Arduino pin defaults for convenience +#if !defined(ATMEL_SPI_MOSI) +#define ATMEL_SPI_MOSI D11 +#endif +#if !defined(ATMEL_SPI_MISO) +#define ATMEL_SPI_MISO D12 +#endif +#if !defined(ATMEL_SPI_SCLK) +#define ATMEL_SPI_SCLK D13 +#endif +#if !defined(ATMEL_SPI_CS) +#define ATMEL_SPI_CS D10 +#endif +#if !defined(ATMEL_SPI_RST) +#define ATMEL_SPI_RST D5 +#endif +#if !defined(ATMEL_SPI_SLP) +#define ATMEL_SPI_SLP D7 +#endif +#if !defined(ATMEL_SPI_IRQ) +#define ATMEL_SPI_IRQ D9 +#endif +#if !defined(ATMEL_I2C_SDA) +#define ATMEL_I2C_SDA D14 +#endif +#if !defined(ATMEL_I2C_SCL) +#define ATMEL_I2C_SCL D15 +#endif + +class RFBits; + +class NanostackRfPhyAtmel : public NanostackRfPhy { +public: + NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq, + PinName i2c_sda, PinName i2c_scl); + virtual ~NanostackRfPhyAtmel(); + virtual int8_t rf_register(); + virtual void rf_unregister(); + virtual void get_mac_address(uint8_t *mac); + virtual void set_mac_address(uint8_t *mac); + +private: + AT24Mac _mac; + uint8_t _mac_addr[8]; + RFBits *_rf; + bool _mac_set; + + const PinName _spi_mosi; + const PinName _spi_miso; + const PinName _spi_sclk; + const PinName _spi_cs; + const PinName _spi_rst; + const PinName _spi_slp; + const PinName _spi_irq; +}; + +#endif /* MBED_CONF_NANOSTACK_CONFIGURATION */ +#endif /* NANOSTACK_RF_PHY_ATMEL_H_ */
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,30 @@ +{ + "name": "atmel-rf", + "config": { + "full-spi-speed": { + "help": "Maximum SPI clock speed (Hz), as long as sufficient inter-byte spacing", + "value": 7500000 + }, + "full-spi-speed-byte-spacing": { + "help": "Required byte spacing in nanoseconds if full SPI speed is in use", + "value": 250 + }, + "low-spi-speed": { + "help": "Maximum SPI clock speed (Hz) if no inter-byte spacing", + "value": 3750000 + }, + "use-spi-spacing-api": { + "help": "Use SPI spacing API proposed in https://github.com/ARMmbed/mbed-os/pull/5353 to ensure spacing between bytes - either run at full speed with spacing, or low with no spacing", + "value": false + }, + "assume-spaced-spi": { + "help": "If not using SPI spacing API, assume platform has widely-spaced bytes in bursts, so use full clock speed rather than low.", + "value": false + } + }, + "target_overrides": { + "STM": { + "assume-spaced-spi": true + } + } +}
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/module.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/module.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,17 @@ +{ + "name": "atmel-rf-driver", + "version": "3.0.2", + "description": "RF driver for Atmel AT86RF233", + "keywords": [ + "rf", + "driver" + ], + "author": "Seppo Takalo <seppo.takalo@arm.com>", + "license": "Apache-2.0", + "dependencies": { + "nanostack-libservice": "^3.0.0", + "sal-stack-nanostack": "^5.0.0", + "mbed-drivers": "^1.0.0" + }, + "targetDependencies": {} +}
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/source/AT86RFReg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/source/AT86RFReg.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AT86RFREG_H_ +#define AT86RFREG_H_ +#ifdef __cplusplus +extern "C" { +#endif + +/*AT86RF212 PHY Modes*/ +#define BPSK_20 0x00 +#define BPSK_40 0x04 +#define BPSK_40_ALT 0x14 +#define OQPSK_SIN_RC_100 0x08 +#define OQPSK_SIN_RC_200 0x09 +#define OQPSK_RC_100 0x18 +#define OQPSK_RC_200 0x19 +#define OQPSK_SIN_250 0x0c +#define OQPSK_SIN_500 0x0d +#define OQPSK_SIN_500_ALT 0x0f +#define OQPSK_RC_250 0x1c +#define OQPSK_RC_500 0x1d +#define OQPSK_RC_500_ALT 0x1f +#define OQPSK_SIN_RC_400_SCR_ON 0x2A +#define OQPSK_SIN_RC_400_SCR_OFF 0x0A +#define OQPSK_RC_400_SCR_ON 0x3A +#define OQPSK_RC_400_SCR_OFF 0x1A +#define OQPSK_SIN_1000_SCR_ON 0x2E +#define OQPSK_SIN_1000_SCR_OFF 0x0E +#define OQPSK_RC_1000_SCR_ON 0x3E +#define OQPSK_RC_1000_SCR_OFF 0x1E + +/*Supported transceivers*/ +#define PART_AT86RF231 0x03 +#define PART_AT86RF212 0x07 +#define PART_AT86RF233 0x0B +#define VERSION_AT86RF212 0x01 +#define VERSION_AT86RF212B 0x03 + +/*RF Configuration Registers*/ +#define TRX_STATUS 0x01 +#define TRX_STATE 0x02 +#define TRX_CTRL_0 0x03 +#define TRX_CTRL_1 0x04 +#define PHY_TX_PWR 0x05 +#define PHY_RSSI 0x06 +#define PHY_ED_LEVEL 0x07 +#define PHY_CC_CCA 0x08 +#define RX_CTRL 0x0A +#define SFD_VALUE 0x0B +#define TRX_CTRL_2 0x0C +#define ANT_DIV 0x0D +#define IRQ_MASK 0x0E +#define IRQ_STATUS 0x0F +#define VREG_CTRL 0x10 +#define BATMON 0x11 +#define XOSC_CTRL 0x12 +#define CC_CTRL_0 0x13 +#define CC_CTRL_1 0x14 +#define RX_SYN 0x15 +#define TRX_RPC 0x16 +#define RF_CTRL_0 0x16 +#define XAH_CTRL_1 0x17 +#define FTN_CTRL 0x18 +#define PLL_CF 0x1A +#define PLL_DCU 0x1B +#define PART_NUM 0x1C +#define VERSION_NUM 0x1D +#define MAN_ID_0 0x1E +#define MAN_ID_1 0x1F +#define SHORT_ADDR_0 0x20 +#define SHORT_ADDR_1 0x21 +#define PAN_ID_0 0x22 +#define PAN_ID_1 0x23 +#define IEEE_ADDR_0 0x24 +#define IEEE_ADDR_1 0x25 +#define IEEE_ADDR_2 0x26 +#define IEEE_ADDR_3 0x27 +#define IEEE_ADDR_4 0x28 +#define IEEE_ADDR_5 0x29 +#define IEEE_ADDR_6 0x2A +#define IEEE_ADDR_7 0x2B +#define XAH_CTRL_0 0x2C +#define CSMA_SEED_0 0x2D +#define CSMA_SEED_1 0x2E +#define CSMA_BE 0x2F + +/* CSMA_SEED_1*/ +#define AACK_FVN_MODE1 7 +#define AACK_FVN_MODE0 6 +#define AACK_SET_PD 5 +#define AACK_DIS_ACK 4 +#define AACK_I_AM_COORD 3 +#define CSMA_SEED_12 2 +#define CSMA_SEED_11 1 +#define CSMA_SEED_10 0 + +/*TRX_STATUS bits*/ +#define CCA_STATUS 0x40 +#define CCA_DONE 0x80 + +/*PHY_CC_CCA bits*/ +#define CCA_REQUEST 0x80 +#define CCA_MODE_3A 0x00 +#define CCA_MODE_1 0x20 +#define CCA_MODE_2 0x40 +#define CCA_MODE_3B 0x60 +#define CCA_MODE_MASK 0x60 +#define CCA_CHANNEL_MASK 0x1F + +/*IRQ_MASK bits*/ +#define RX_START 0x04 +#define TRX_END 0x08 +#define CCA_ED_DONE 0x10 +#define AMI 0x20 +#define TRX_UR 0x40 + +/*ANT_DIV bits*/ +#define ANT_DIV_EN 0x08 +#define ANT_EXT_SW_EN 0x04 +#define ANT_CTRL_DEFAULT 0x03 + +/*TRX_CTRL_1 bits*/ +#define PA_EXT_EN 0x80 +#define TX_AUTO_CRC_ON 0x20 +#define SPI_CMD_MODE_TRX_STATUS 0x04 +#define SPI_CMD_MODE_PHY_RSSI 0x08 +#define SPI_CMD_MODE_IRQ_STATUS 0x0C + +/*TRX_CTRL_2 bits*/ +#define RX_SAFE_MODE 0x80 + +/*FTN_CTRL bits*/ +#define FTN_START 0x80 + +/*PHY_RSSI bits*/ +#define CRC_VALID 0x80 + +/*RX_SYN bits*/ +#define RX_PDT_DIS 0x80 + +/*TRX_RPC bits */ +#define RX_RPC_CTRL 0xC0 +#define RX_RPC_EN 0x20 +#define PDT_RPC_EN 0x10 +#define PLL_RPC_EN 0x08 +#define XAH_TX_RPC_EN 0x04 +#define IPAN_RPC_EN 0x02 +#define TRX_RPC_RSVD_1 0x01 + +/*XAH_CTRL_1 bits*/ +#define AACK_PROM_MODE 0x02 + + +#ifdef __cplusplus +} +#endif + +#endif /* AT86RFREG_H_ */
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2455 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <string.h> + +#ifdef MBED_CONF_NANOSTACK_CONFIGURATION + +#include "platform/arm_hal_interrupt.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "ns_types.h" +#include "NanostackRfPhyAtmel.h" +#include "randLIB.h" +#include "AT86RFReg.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "mbed_trace.h" +#include "mbed_toolchain.h" + +#define TRACE_GROUP "AtRF" + +/*Worst case sensitivity*/ +#define RF_DEFAULT_SENSITIVITY -88 +/*Run calibration every 5 minutes*/ +#define RF_CALIBRATION_INTERVAL 6000000 +/*Wait ACK for 2.5ms*/ +#define RF_ACK_WAIT_DEFAULT_TIMEOUT 50 +/*Base CCA backoff (50us units) - substitutes for Inter-Frame Spacing*/ +#define RF_CCA_BASE_BACKOFF 13 /* 650us */ +/*CCA random backoff (50us units)*/ +#define RF_CCA_RANDOM_BACKOFF 51 /* 2550us */ + +#define RF_MTU 127 + +#define RF_PHY_MODE OQPSK_SIN_250 + +/*Radio RX and TX state definitions*/ +#define RFF_ON 0x01 +#define RFF_RX 0x02 +#define RFF_TX 0x04 +#define RFF_CCA 0x08 + +typedef enum +{ + RF_MODE_NORMAL = 0, + RF_MODE_SNIFFER = 1, + RF_MODE_ED = 2 +}rf_mode_t; + +/*Atmel RF Part Type*/ +typedef enum +{ + ATMEL_UNKNOW_DEV = 0, + ATMEL_AT86RF212, + ATMEL_AT86RF231, // No longer supported (doesn't give ED+status on frame read) + ATMEL_AT86RF233 +}rf_trx_part_e; + +/*Atmel RF states*/ +typedef enum +{ + NOP = 0x00, + BUSY_RX = 0x01, + BUSY_TX = 0x02, + RF_TX_START = 0x02, + FORCE_TRX_OFF = 0x03, + FORCE_PLL_ON = 0x04, + RX_ON = 0x06, + TRX_OFF = 0x08, + PLL_ON = 0x09, + BUSY_RX_AACK = 0x11, + SLEEP = 0x0F, + RX_AACK_ON = 0x16, + TX_ARET_ON = 0x19, + STATE_TRANSITION_IN_PROGRESS = 0x1F +}rf_trx_states_t; + +static const uint8_t *rf_tx_data; // Points to Nanostack's buffer +static uint8_t rf_tx_length; +/*ACK wait duration changes depending on data rate*/ +static uint16_t rf_ack_wait_duration = RF_ACK_WAIT_DEFAULT_TIMEOUT; + +static int8_t rf_sensitivity = RF_DEFAULT_SENSITIVITY; +static rf_mode_t rf_mode = RF_MODE_NORMAL; +static uint8_t radio_tx_power = 0x00; // Default to +4dBm +static uint8_t rf_phy_channel = 12; +static uint8_t rf_tuned = 1; +static uint8_t rf_use_antenna_diversity = 0; +static int16_t expected_ack_sequence = -1; +static uint8_t rf_rx_mode = 0; +static uint8_t rf_flags = 0; +static int8_t rf_radio_driver_id = -1; +static phy_device_driver_s device_driver; +static uint8_t mac_tx_handle = 0; +static uint8_t xah_ctrl_1; + +/* Channel configurations for 2.4 and sub-GHz */ +static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK}; +static const phy_rf_channel_configuration_s phy_subghz = {868300000U, 2000000U, 250000U, 11U, M_OQPSK}; + +static const phy_device_channel_page_s phy_channel_pages[] = { + { CHANNEL_PAGE_0, &phy_24ghz}, + { CHANNEL_PAGE_2, &phy_subghz}, + { CHANNEL_PAGE_0, NULL} +}; + +/** + * RF output power write + * + * \brief TX power has to be set before network start. + * + * \param power + * AT86RF233 + * 0 = 4 dBm + * 1 = 3.7 dBm + * 2 = 3.4 dBm + * 3 = 3 dBm + * 4 = 2.5 dBm + * 5 = 2 dBm + * 6 = 1 dBm + * 7 = 0 dBm + * 8 = -1 dBm + * 9 = -2 dBm + * 10 = -3 dBm + * 11 = -4 dBm + * 12 = -6 dBm + * 13 = -8 dBm + * 14 = -12 dBm + * 15 = -17 dBm + * + * AT86RF212B + * See datasheet for TX power settings + * + * \return 0, Supported Value + * \return -1, Not Supported Value + */ +static int8_t rf_tx_power_set(uint8_t power); +static rf_trx_part_e rf_radio_type_read(void); +static void rf_ack_wait_timer_start(uint16_t slots); +static void rf_ack_wait_timer_stop(void); +static void rf_handle_cca_ed_done(uint8_t full_trx_status); +static void rf_handle_tx_end(rf_trx_states_t trx_status); +static void rf_handle_rx_end(rf_trx_states_t trx_status); +static void rf_on(void); +static void rf_give_up_on_ack(void); +static void rf_receive(rf_trx_states_t trx_status = STATE_TRANSITION_IN_PROGRESS); +static rf_trx_states_t rf_poll_trx_state_change(rf_trx_states_t trx_state); +static void rf_init(void); +static int8_t rf_device_register(const uint8_t *mac_addr); +static void rf_device_unregister(void); +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ); +static void rf_cca_abort(void); +static void rf_calibration_cb(void); +static void rf_init_phy_mode(void); +static void rf_ack_wait_timer_interrupt(void); +static void rf_calibration_timer_interrupt(void); +static void rf_calibration_timer_start(uint32_t slots); +static void rf_cca_timer_interrupt(void); +static void rf_cca_timer_start(uint32_t slots); +static uint8_t rf_scale_lqi(int8_t rssi); + +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel); +static int8_t rf_extension(phy_extension_type_e extension_type,uint8_t *data_ptr); +static int8_t rf_address_write(phy_address_type_e address_type,uint8_t *address_ptr); + +static void rf_if_cca_timer_start(uint32_t slots); +static void rf_if_enable_promiscuous_mode(void); +static void rf_if_lock(void); +static void rf_if_unlock(void); +static uint8_t rf_if_read_rnd(void); +static void rf_if_calibration_timer_start(uint32_t slots); +static void rf_if_interrupt_handler(void); +static void rf_if_ack_wait_timer_start(uint16_t slots); +static void rf_if_ack_wait_timer_stop(void); +static void rf_if_ack_pending_ctrl(uint8_t state); +static void rf_if_calibration(void); +static uint8_t rf_if_read_register(uint8_t addr); +static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask); +static void rf_if_clear_bit(uint8_t addr, uint8_t bit); +static void rf_if_write_register(uint8_t addr, uint8_t data); +static void rf_if_reset_radio(void); +static void rf_if_enable_ant_div(void); +static void rf_if_disable_ant_div(void); +static void rf_if_enable_slptr(void); +static void rf_if_disable_slptr(void); +static void rf_if_write_antenna_diversity_settings(void); +static void rf_if_write_set_tx_power_register(uint8_t value); +static void rf_if_write_rf_settings(void); +static rf_trx_states_t rf_if_read_trx_state(void); +static uint16_t rf_if_read_packet(uint8_t data[RF_MTU], uint8_t *lqi_out, uint8_t *ed_out, bool *crc_good); +static void rf_if_write_short_addr_registers(uint8_t *short_address); +static uint8_t rf_if_last_acked_pending(void); +static void rf_if_write_pan_id_registers(uint8_t *pan_id); +static void rf_if_write_ieee_addr_registers(uint8_t *address); +static void rf_if_write_frame_buffer(const uint8_t *ptr, uint8_t length); +static rf_trx_states_t rf_if_change_trx_state(rf_trx_states_t trx_state); +static void rf_if_start_cca_process(void); +static int8_t rf_if_scale_rssi(uint8_t ed_level); +static void rf_if_set_channel_register(uint8_t channel); +static void rf_if_enable_promiscuous_mode(void); +static void rf_if_disable_promiscuous_mode(void); +static uint8_t rf_if_read_part_num(void); +static void rf_if_enable_irq(void); +static void rf_if_disable_irq(void); +static void rf_if_spi_exchange_n(const void *tx, size_t tx_len, void *rx, size_t rx_len); + +static inline rf_trx_states_t rf_if_trx_status_from_full(uint8_t full_trx_status) +{ + return (rf_trx_states_t) (full_trx_status & 0x1F); +} + +#ifdef MBED_CONF_RTOS_PRESENT +#include "mbed.h" +#include "rtos.h" + +static void rf_if_irq_task_process_irq(); + +#define SIG_RADIO 1 +#define SIG_TIMER_ACK 2 +#define SIG_TIMER_CAL 4 +#define SIG_TIMER_CCA 8 + +#define SIG_TIMERS (SIG_TIMER_ACK|SIG_TIMER_CAL|SIG_TIMER_CCA) +#define SIG_ALL (SIG_RADIO|SIG_TIMERS) +#endif + +// HW pins to RF chip + +class UnlockedSPI : public SPI { +public: + UnlockedSPI(PinName mosi, PinName miso, PinName sclk) : + SPI(mosi, miso, sclk) { } + virtual void lock() { } + virtual void unlock() { } +}; + +class RFBits { +public: + RFBits(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, + PinName spi_rst, PinName spi_slp, PinName spi_irq); + UnlockedSPI spi; + DigitalOut CS; + DigitalOut RST; + DigitalOut SLP_TR; + InterruptIn IRQ; + Timeout ack_timer; + Timeout cal_timer; + Timeout cca_timer; +#ifdef MBED_CONF_RTOS_PRESENT + Thread irq_thread; + Mutex mutex; + void rf_if_irq_task(); +#endif +}; + +RFBits::RFBits(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, + PinName spi_rst, PinName spi_slp, PinName spi_irq) + : spi(spi_mosi, spi_miso, spi_sclk), + CS(spi_cs), + RST(spi_rst), + SLP_TR(spi_slp), + IRQ(spi_irq) +#ifdef MBED_CONF_RTOS_PRESENT +,irq_thread(osPriorityRealtime, 1024) +#endif +{ +#ifdef MBED_CONF_RTOS_PRESENT + irq_thread.start(mbed::callback(this, &RFBits::rf_if_irq_task)); +#endif +} + +static RFBits *rf; +static uint8_t rf_part_num = 0; +/*TODO: RSSI Base value setting*/ +static int8_t rf_rssi_base_val = -91; + +static void rf_if_lock(void) +{ + platform_enter_critical(); +} + +static void rf_if_unlock(void) +{ + platform_exit_critical(); +} + +#ifdef MBED_CONF_RTOS_PRESENT +static void rf_if_cca_timer_signal(void) +{ + rf->irq_thread.signal_set(SIG_TIMER_CCA); +} + +static void rf_if_cal_timer_signal(void) +{ + rf->irq_thread.signal_set(SIG_TIMER_CAL); +} + +static void rf_if_ack_timer_signal(void) +{ + rf->irq_thread.signal_set(SIG_TIMER_ACK); +} +#endif + + +/* Delay functions for RF Chip SPI access */ +#ifdef __CC_ARM +__asm static void delay_loop(uint32_t count) +{ +1 + SUBS a1, a1, #1 + BCS %BT1 + BX lr +} +#elif defined (__ICCARM__) +static void delay_loop(uint32_t count) +{ + __asm volatile( + "loop: \n" + " SUBS %0, %0, #1 \n" + " BCS.n loop\n" + : "+r" (count) + : + : "cc" + ); +} +#else // GCC +static void delay_loop(uint32_t count) +{ + __asm__ volatile ( + "%=:\n\t" +#if defined(__thumb__) && !defined(__thumb2__) + "SUB %0, #1\n\t" +#else + "SUBS %0, %0, #1\n\t" +#endif + "BCS %=b\n\t" + : "+l" (count) + : + : "cc" + ); +} +#endif + +static void delay_ns(uint32_t ns) +{ + uint32_t cycles_per_us = SystemCoreClock / 1000000; + // Cortex-M0 takes 4 cycles per loop (SUB=1, BCS=3) + // Cortex-M3 and M4 takes 3 cycles per loop (SUB=1, BCS=2) + // Cortex-M7 - who knows? + // Cortex M3-M7 have "CYCCNT" - would be better than a software loop, but M0 doesn't + // Assume 3 cycles per loop for now - will be 33% slow on M0. No biggie, + // as original version of code was 300% slow on M4. + // [Note that this very calculation, plus call overhead, will take multiple + // cycles. Could well be 100ns on its own... So round down here, startup is + // worth at least one loop iteration.] + uint32_t count = (cycles_per_us * ns) / 3000; + + delay_loop(count); +} + +// t1 = 180ns, SEL falling edge to MISO active [SPI setup assumed slow enough to not need manual delay] +#define CS_SELECT() {rf->CS = 0; /* delay_ns(180); */} + // t9 = 250ns, last clock to SEL rising edge, t8 = 250ns, SPI idle time between consecutive access +#define CS_RELEASE() {delay_ns(250); rf->CS = 1; delay_ns(250);} + +/* + * \brief Function sets the TX power variable. + * + * \param power TX power setting + * + * \return 0 Success + * \return -1 Fail + */ +MBED_UNUSED static int8_t rf_tx_power_set(uint8_t power) +{ + int8_t ret_val = -1; + + radio_tx_power = power; + rf_if_lock(); + rf_if_write_set_tx_power_register(radio_tx_power); + rf_if_unlock(); + ret_val = 0; + + return ret_val; +} + +/* + * \brief Read connected radio part. + * + * This function only return valid information when rf_init() is called + * + * \return + */ +static rf_trx_part_e rf_radio_type_read(void) +{ + rf_trx_part_e ret_val = ATMEL_UNKNOW_DEV; + + switch (rf_part_num) + { + case PART_AT86RF212: + ret_val = ATMEL_AT86RF212; + break; + case PART_AT86RF233: + ret_val = ATMEL_AT86RF233; + break; + default: + break; + } + + return ret_val; +} + + +/* + * \brief Function starts the ACK wait timeout. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_if_ack_wait_timer_start(uint16_t slots) +{ +#ifdef MBED_CONF_RTOS_PRESENT + rf->ack_timer.attach_us(rf_if_ack_timer_signal, slots*50); +#else + rf->ack_timer.attach_us(rf_ack_wait_timer_interrupt, slots*50); +#endif +} + +/* + * \brief Function starts the calibration interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_if_calibration_timer_start(uint32_t slots) +{ +#ifdef MBED_CONF_RTOS_PRESENT + rf->cal_timer.attach_us(rf_if_cal_timer_signal, slots*50); +#else + rf->cal_timer.attach_us(rf_calibration_timer_interrupt, slots*50); +#endif +} + +/* + * \brief Function starts the CCA interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_if_cca_timer_start(uint32_t slots) +{ +#ifdef MBED_CONF_RTOS_PRESENT + rf->cca_timer.attach_us(rf_if_cca_timer_signal, slots*50); +#else + rf->cca_timer.attach_us(rf_cca_timer_interrupt, slots*50); +#endif +} + +/* + * \brief Function stops the CCA interval. + * + * \return none + */ +static void rf_if_cca_timer_stop(void) +{ + rf->cca_timer.detach(); +} + +/* + * \brief Function stops the ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_if_ack_wait_timer_stop(void) +{ + rf->ack_timer.detach(); +} + +/* + * \brief Function sets bit(s) in given RF register. + * + * \param addr Address of the register to set + * \param bit Bit(s) to set + * \param bit_mask Masks the field inside the register + * + * \return none + */ +static void rf_if_set_bit(uint8_t addr, uint8_t bit, uint8_t bit_mask) +{ + uint8_t reg = rf_if_read_register(addr); + reg &= ~bit_mask; + reg |= bit; + rf_if_write_register(addr, reg); +} + +/* + * \brief Function clears bit(s) in given RF register. + * + * \param addr Address of the register to clear + * \param bit Bit(s) to clear + * + * \return none + */ +static void rf_if_clear_bit(uint8_t addr, uint8_t bit) +{ + rf_if_set_bit(addr, 0, bit); +} + +/* + * \brief Function writes register in RF. + * + * \param addr Address on the RF + * \param data Written data + * + * \return none + */ +static void rf_if_write_register(uint8_t addr, uint8_t data) +{ + const uint8_t tx[2] = { static_cast<uint8_t>(0xC0 | addr), data }; + uint8_t rx[2]; + CS_SELECT(); + rf_if_spi_exchange_n(tx, 2, rx, 2); + CS_RELEASE(); +} + +/* + * \brief Function reads RF register, and also outputs PHY_STATUS + * + * \param addr Address on the RF + * \param[out] status_out Pointer to store PHY_STATUS + * + * \return Read register data + */ +static uint8_t rf_if_read_register_with_status(uint8_t addr, uint8_t *status_out) +{ + const uint8_t tx[1] = { static_cast<uint8_t>(0x80 | addr) }; + uint8_t rx[2]; + CS_SELECT(); + rf_if_spi_exchange_n(tx, 1, rx, 2); + CS_RELEASE(); + if (status_out) { + *status_out = rx[0]; + } + return rx[1]; +} + +/* + * \brief Function reads RF register. + * + * \param addr Address on the RF + * + * \return Read register data + */ +static uint8_t rf_if_read_register(uint8_t addr) +{ + return rf_if_read_register_with_status(addr, NULL); +} + +/* + * \brief Function resets the RF. + * + * \param none + * + * \return none + */ +static void rf_if_reset_radio(void) +{ +#if MBED_CONF_ATMEL_RF_USE_SPI_SPACING_API + rf->spi.frequency(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED); + int spacing = rf->spi.write_spacing(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED_BYTE_SPACING); + if (spacing < MBED_CONF_ATMEL_RF_FULL_SPI_SPEED_BYTE_SPACING) { + rf->spi.frequency(MBED_CONF_ATMEL_RF_LOW_SPI_SPEED); + rf->spi.write_spacing(0); + } +#elif MBED_CONF_ATMEL_RF_ASSUME_SPACED_SPI + rf->spi.frequency(MBED_CONF_ATMEL_RF_FULL_SPI_SPEED); +#else + rf->spi.frequency(MBED_CONF_ATMEL_RF_LOW_SPI_SPEED); +#endif + rf->IRQ.rise(0); + rf->RST = 1; + wait_ms(1); + rf->RST = 0; + wait_ms(10); + CS_RELEASE(); + rf->SLP_TR = 0; + wait_ms(10); + rf->RST = 1; + wait_ms(10); + + rf->IRQ.rise(&rf_if_interrupt_handler); +} + +/* + * \brief Function enables the promiscuous mode. + * + * \param none + * + * \return none + */ +static void rf_if_enable_promiscuous_mode(void) +{ + if (!(xah_ctrl_1 & AACK_PROM_MODE)) { + /*Set AACK_PROM_MODE to enable the promiscuous mode*/ + rf_if_write_register(XAH_CTRL_1, xah_ctrl_1 |= AACK_PROM_MODE); + } +} + +/* + * \brief Function disable the promiscuous mode. + * + * \param none + * + * \return none + */ +static void rf_if_disable_promiscuous_mode(void) +{ + if (xah_ctrl_1 & AACK_PROM_MODE) { + /*Clear AACK_PROM_MODE to disable the promiscuous mode*/ + rf_if_write_register(XAH_CTRL_1, xah_ctrl_1 &= ~AACK_PROM_MODE); + } +} + +/* + * \brief Function enables the Antenna diversity usage. + * + * \param none + * + * \return none + */ +static void rf_if_enable_ant_div(void) +{ + /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/ + rf_if_set_bit(ANT_DIV, ANT_EXT_SW_EN, ANT_EXT_SW_EN); +} + +/* + * \brief Function disables the Antenna diversity usage. + * + * \param none + * + * \return none + */ +static void rf_if_disable_ant_div(void) +{ + rf_if_clear_bit(ANT_DIV, ANT_EXT_SW_EN); +} + +/* + * \brief Function sets the SLP TR pin. + * + * \param none + * + * \return none + */ +static void rf_if_enable_slptr(void) +{ + rf->SLP_TR = 1; +} + +/* + * \brief Function clears the SLP TR pin. + * + * \param none + * + * \return none + */ +static void rf_if_disable_slptr(void) +{ + rf->SLP_TR = 0; +} + +/* + * \brief Function writes the antenna diversity settings. + * + * \param none + * + * \return none + */ +static void rf_if_write_antenna_diversity_settings(void) +{ + /*Recommended setting of PDT_THRES is 3 when antenna diversity is used*/ + rf_if_set_bit(RX_CTRL, 0x03, 0x0f); + rf_if_write_register(ANT_DIV, ANT_DIV_EN | ANT_EXT_SW_EN | ANT_CTRL_DEFAULT); +} + +/* + * \brief Function writes the TX output power register. + * + * \param value Given register value + * + * \return none + */ +static void rf_if_write_set_tx_power_register(uint8_t value) +{ + rf_if_write_register(PHY_TX_PWR, value); +} + +/* + * \brief Function returns the RF part number. + * + * \param none + * + * \return part number + */ +static uint8_t rf_if_read_part_num(void) +{ + return rf_if_read_register(PART_NUM); +} + +/* + * \brief Function writes the RF settings and initialises SPI interface. + * + * \param none + * + * \return none + */ +static void rf_if_write_rf_settings(void) +{ + /*Reset RF module*/ + rf_if_reset_radio(); + + rf_part_num = rf_if_read_part_num(); + + rf_if_write_register(XAH_CTRL_0,0); + + /* Auto CRC on, IRQ status shows unmasked only, TRX_STATUS output on all accesses */ + rf_if_write_register(TRX_CTRL_1, TX_AUTO_CRC_ON | SPI_CMD_MODE_TRX_STATUS); + + rf_if_write_register(IRQ_MASK, CCA_ED_DONE | TRX_END | TRX_UR); + + xah_ctrl_1 = rf_if_read_register(XAH_CTRL_1); + + /*Read transceiver PART_NUM*/ + rf_part_num = rf_if_read_register(PART_NUM); + + /*Sub-GHz RF settings*/ + if(rf_part_num == PART_AT86RF212) + { + /*GC_TX_OFFS mode-dependent setting - OQPSK*/ + rf_if_write_register(RF_CTRL_0, 0x32); + + if(rf_if_read_register(VERSION_NUM) == VERSION_AT86RF212B) + { + /*TX Output Power setting - 0 dBm North American Band*/ + rf_if_write_register(PHY_TX_PWR, 0x03); + } + else + { + /*TX Output Power setting - 0 dBm North American Band*/ + rf_if_write_register(PHY_TX_PWR, 0x24); + } + + /*PHY Mode: IEEE 802.15.4-2006/2011 - OQPSK-SIN-250*/ + rf_if_write_register(TRX_CTRL_2, RX_SAFE_MODE | RF_PHY_MODE); + /*Based on receiver Characteristics. See AT86RF212B Datasheet where RSSI BASE VALUE in range -97 - -100 dBm*/ + rf_rssi_base_val = -98; + } + /*2.4GHz RF settings*/ + else + { +#if 0 + /* Disable power saving functions for now - can only impact reliability, + * and don't have any users demanding it. */ + /*Set RPC register*/ + rf_if_write_register(TRX_RPC, RX_RPC_CTRL|RX_RPC_EN|PLL_RPC_EN|XAH_TX_RPC_EN|IPAN_RPC_EN|TRX_RPC_RSVD_1); +#endif + /*PHY Mode: IEEE 802.15.4 - Data Rate 250 kb/s*/ + rf_if_write_register(TRX_CTRL_2, RX_SAFE_MODE); + rf_rssi_base_val = -91; + } +} + +/* + * \brief Function returns the RF state + * + * \param none + * + * \return RF state + */ +static rf_trx_states_t rf_if_read_trx_state(void) +{ + return rf_if_trx_status_from_full(rf_if_read_register(TRX_STATUS)); +} + +/* + * \brief Function reads packet buffer. + * + * \param data_out Output buffer + * \param lqi_out LQI output + * \param ed_out ED output + * \param crc_good CRC good indication + * + * \return PSDU length [0..RF_MTU] + */ +static uint16_t rf_if_read_packet(uint8_t data_out[RF_MTU], uint8_t *lqi_out, uint8_t *ed_out, bool *crc_good) +{ + CS_SELECT(); + const uint8_t tx[1] = { 0x20 }; + uint8_t rx[3]; + rf_if_spi_exchange_n(tx, 1, rx, 2); + uint8_t len = rx[1] & 0x7F; + rf_if_spi_exchange_n(NULL, 0, data_out, len); + rf_if_spi_exchange_n(NULL, 0, rx, 3); + *lqi_out = rx[0]; + *ed_out = rx[1]; + *crc_good = rx[2] & 0x80; + CS_RELEASE(); + + return len; +} + +/* + * \brief Function writes RF short address registers + * + * \param short_address Given short address + * + * \return none + */ +static void rf_if_write_short_addr_registers(uint8_t *short_address) +{ + rf_if_write_register(SHORT_ADDR_1, *short_address++); + rf_if_write_register(SHORT_ADDR_0, *short_address); +} + +/* + * \brief Function sets the frame pending in ACK message + * + * \param state Given frame pending state + * + * \return none + */ +static void rf_if_ack_pending_ctrl(uint8_t state) +{ + rf_if_lock(); + if(state) + { + rf_if_set_bit(CSMA_SEED_1, (1 << AACK_SET_PD), (1 << AACK_SET_PD)); + } + else + { + rf_if_clear_bit(CSMA_SEED_1, (1 << AACK_SET_PD)); + } + rf_if_unlock(); +} + +/* + * \brief Function returns the state of frame pending control + * + * \param none + * + * \return Frame pending state + */ +static uint8_t rf_if_last_acked_pending(void) +{ + uint8_t last_acked_data_pending; + + rf_if_lock(); + if(rf_if_read_register(CSMA_SEED_1) & (1 << AACK_SET_PD)) + last_acked_data_pending = 1; + else + last_acked_data_pending = 0; + rf_if_unlock(); + + return last_acked_data_pending; +} + +/* + * \brief Function calibrates the RF part. + * + * \param none + * + * \return none + */ +static void rf_if_calibration(void) +{ + rf_if_set_bit(FTN_CTRL, FTN_START, FTN_START); + /*Wait while calibration is running*/ + while(rf_if_read_register(FTN_CTRL) & FTN_START); +} + +/* + * \brief Function writes RF PAN Id registers + * + * \param pan_id Given PAN Id + * + * \return none + */ +static void rf_if_write_pan_id_registers(uint8_t *pan_id) +{ + rf_if_write_register(PAN_ID_1, *pan_id++); + rf_if_write_register(PAN_ID_0, *pan_id); +} + +/* + * \brief Function writes RF IEEE Address registers + * + * \param address Given IEEE Address + * + * \return none + */ +static void rf_if_write_ieee_addr_registers(uint8_t *address) +{ + uint8_t i; + uint8_t temp = IEEE_ADDR_0; + + for(i=0; i<8; i++) + rf_if_write_register(temp++, address[7-i]); +} + +/* + * \brief Function writes data in RF frame buffer. + * + * \param ptr Pointer to data (PSDU, except FCS) + * \param length Pointer to length (PSDU length, minus 2 for FCS) + * + * \return none + */ +static void rf_if_write_frame_buffer(const uint8_t *ptr, uint8_t length) +{ + const uint8_t cmd[2] = { 0x60, static_cast<uint8_t>(length + 2) }; + + CS_SELECT(); + rf_if_spi_exchange_n(cmd, 2, NULL, 0); + rf_if_spi_exchange_n(ptr, length, NULL, 0); + CS_RELEASE(); +} + +/* + * \brief Function returns 8-bit random value. + * + * \param none + * + * \return random value + */ +static uint8_t rf_if_read_rnd(void) +{ + uint8_t temp; + uint8_t tmp_rpc_val = 0; + /*RPC must be disabled while reading the random number*/ + if(rf_part_num == PART_AT86RF233) + { + tmp_rpc_val = rf_if_read_register(TRX_RPC); + rf_if_write_register(TRX_RPC, RX_RPC_CTRL|TRX_RPC_RSVD_1); + } + + wait_ms(1); + temp = ((rf_if_read_register(PHY_RSSI)>>5) << 6); + wait_ms(1); + temp |= ((rf_if_read_register(PHY_RSSI)>>5) << 4); + wait_ms(1); + temp |= ((rf_if_read_register(PHY_RSSI)>>5) << 2); + wait_ms(1); + temp |= ((rf_if_read_register(PHY_RSSI)>>5)); + wait_ms(1); + if(rf_part_num == PART_AT86RF233) + rf_if_write_register(TRX_RPC, tmp_rpc_val); + return temp; +} + +/* + * \brief Function changes the state of the RF. + * + * \param trx_state Given RF state + * + * \return none + */ +static rf_trx_states_t rf_if_change_trx_state(rf_trx_states_t trx_state) +{ + rf_if_write_register(TRX_STATE, trx_state); + /*Wait while not in desired state*/ + return rf_poll_trx_state_change(trx_state); +} + +/* + * \brief Function starts the CCA process + * + * \param none + * + * \return none + */ +static void rf_if_start_cca_process(void) +{ + rf_if_write_register(PHY_CC_CCA, CCA_REQUEST | CCA_MODE_3A | rf_phy_channel); +} + +/* + * \brief Function scales RSSI + * + * \param ed_level ED level read from chip + * + * \return appropriately scaled RSSI dBm + */ +static int8_t rf_if_scale_rssi(uint8_t ed_level) +{ + if (rf_part_num == PART_AT86RF212) { + /* Data sheet says to multiply by 1.03 - this is 1.03125, rounding down */ + ed_level += ed_level >> 5; + } + return rf_rssi_base_val + ed_level; +} + +/* + * \brief Function sets the RF channel field + * + * \param Given channel + * + * \return none + */ +static void rf_if_set_channel_register(uint8_t channel) +{ + rf_if_set_bit(PHY_CC_CCA, channel, CCA_CHANNEL_MASK); +} + +/* + * \brief Function enables RF irq pin interrupts in RF interface. + * + * \param none + * + * \return none + */ +static void rf_if_enable_irq(void) +{ + rf->IRQ.enable_irq(); +} + +/* + * \brief Function disables RF irq pin interrupts in RF interface. + * + * \param none + * + * \return none + */ +static void rf_if_disable_irq(void) +{ + rf->IRQ.disable_irq(); +} + +#ifdef MBED_CONF_RTOS_PRESENT +static void rf_if_interrupt_handler(void) +{ + rf->irq_thread.signal_set(SIG_RADIO); +} + +// Started during construction of rf, so variable +// rf isn't set at the start. Uses 'this' instead. +void RFBits::rf_if_irq_task(void) +{ + for (;;) { + osEvent event = irq_thread.signal_wait(0); + if (event.status != osEventSignal) { + continue; + } + rf_if_lock(); + if (event.value.signals & SIG_RADIO) { + rf_if_irq_task_process_irq(); + } + if (event.value.signals & SIG_TIMER_ACK) { + rf_ack_wait_timer_interrupt(); + } + if (event.value.signals & SIG_TIMER_CCA) { + rf_cca_timer_interrupt(); + } + if (event.value.signals & SIG_TIMER_CAL) { + rf_calibration_timer_interrupt(); + } + rf_if_unlock(); + } +} + +static void rf_if_irq_task_process_irq(void) +#else +/* + * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt. + * + * \param none + * + * \return none + */ +static void rf_if_interrupt_handler(void) +#endif +{ + static uint8_t last_is, last_ts; + uint8_t irq_status, full_trx_status; + uint8_t orig_xah_ctrl_1 = xah_ctrl_1; + + /*Read and clear interrupt flag, and pick up trx_status*/ + irq_status = rf_if_read_register_with_status(IRQ_STATUS, &full_trx_status); + uint8_t orig_flags = rf_flags; + + /*Frame end interrupt (RX and TX)*/ + if(irq_status & TRX_END) + { + /*TX done interrupt*/ + rf_trx_states_t trx_status = rf_if_trx_status_from_full(full_trx_status); + if(trx_status == PLL_ON || trx_status == TX_ARET_ON) + { + rf_handle_tx_end(trx_status); + } + /*Frame received interrupt*/ + else + { + rf_handle_rx_end(trx_status); + } + } + if(irq_status & CCA_ED_DONE) + { + rf_handle_cca_ed_done(full_trx_status); + } + if (irq_status & TRX_UR) + { + tr_error("Radio underrun is %x->%x ts %x->%x fl %x->%x x1 %x", last_is, irq_status, last_ts, full_trx_status, orig_flags, rf_flags, orig_xah_ctrl_1); + } + last_is = irq_status; + last_ts = full_trx_status; +} + +/* + * \brief Function writes/read data in SPI interface + */ +static void rf_if_spi_exchange_n(const void *tx, size_t tx_len, void *rx, size_t rx_len) +{ +#if 1 + rf->spi.write(static_cast<const char *>(tx), tx_len, + static_cast<char *>(rx), rx_len); +#else + const uint8_t *txb = static_cast<const uint8_t *>(tx); + uint8_t *rxb = static_cast<uint8_t *>(rx); + while (tx_len > 0 || rx_len > 0) { + uint8_t b; + if (tx_len) { + tx_len--; + b = *txb++; + } else { + b = 0xFF; + } + b = rf->spi.write(b); + if (rx_len) { + rx_len--; + *rxb++ = b; + } + } +#endif +} + +/* + * \brief Function sets given RF flag on. + * + * \param x Given RF flag + * + * \return none + */ +static void rf_flags_set(uint8_t x) +{ + rf_flags |= x; +} + +/* + * \brief Function clears given RF flag on. + * + * \param x Given RF flag + * + * \return none + */ +static void rf_flags_clear(uint8_t x) +{ + rf_flags &= ~x; +} + +/* + * \brief Function checks if given RF flag is on. + * + * \param x Given RF flag + * + * \return states of the given flags + */ +static uint8_t rf_flags_check(uint8_t x) +{ + return (rf_flags & x); +} + +/* + * \brief Function clears all RF flags. + * + * \param none + * + * \return none + */ +static void rf_flags_reset(void) +{ + rf_flags = 0; +} + +/* + * \brief Function initialises and registers the RF driver. + * + * \param none + * + * \return rf_radio_driver_id Driver ID given by NET library + */ +static int8_t rf_device_register(const uint8_t *mac_addr) +{ + rf_trx_part_e radio_type; + + rf_init(); + + radio_type = rf_radio_type_read(); + if(radio_type != ATMEL_UNKNOW_DEV) + { + /*Set pointer to MAC address*/ + device_driver.PHY_MAC = (uint8_t *)mac_addr; + device_driver.driver_description = (char*)"ATMEL_MAC"; + //Create setup Used Radio chips + if(radio_type == ATMEL_AT86RF212) + { + device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE; + } + else + { + device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; + } + device_driver.phy_channel_pages = phy_channel_pages; + /*Maximum size of payload is 127*/ + device_driver.phy_MTU = 127; + /*No header in PHY*/ + device_driver.phy_header_length = 0; + /*No tail in PHY*/ + device_driver.phy_tail_length = 0; + /*Set address write function*/ + device_driver.address_write = &rf_address_write; + /*Set RF extension function*/ + device_driver.extension = &rf_extension; + /*Set RF state control function*/ + device_driver.state_control = &rf_interface_state_control; + /*Set transmit function*/ + device_driver.tx = &rf_start_cca; + /*NULLIFY rx and tx_done callbacks*/ + device_driver.phy_rx_cb = NULL; + device_driver.phy_tx_done_cb = NULL; + /*Register device driver*/ + rf_radio_driver_id = arm_net_phy_register(&device_driver); + } else { + rf_if_disable_irq(); + } + return rf_radio_driver_id; +} + +/* + * \brief Function unregisters the RF driver. + * + * \param none + * + * \return none + */ +static void rf_device_unregister() +{ + if (rf_radio_driver_id >= 0) { + arm_net_phy_unregister(rf_radio_driver_id); + rf_radio_driver_id = -1; + } +} + + +/* + * \brief Function is a call back for ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_ack_wait_timer_interrupt(void) +{ + rf_if_lock(); + rf_give_up_on_ack(); + rf_if_unlock(); +} + +/* + * \brief Function is a call back for calibration interval timer. + * + * \param none + * + * \return none + */ +static void rf_calibration_timer_interrupt(void) +{ + /*Calibrate RF*/ + rf_calibration_cb(); + /*Start new calibration timeout*/ + rf_calibration_timer_start(RF_CALIBRATION_INTERVAL); +} + +/* + * \brief Function is a call back for cca interval timer. + * + * \param none + * + * \return none + */ +static void rf_cca_timer_interrupt(void) +{ + rf_flags_set(RFF_CCA); + /*Start CCA process*/ + rf_if_start_cca_process(); +} + +/* + * \brief Function starts the ACK wait timeout. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_ack_wait_timer_start(uint16_t slots) +{ + rf_if_ack_wait_timer_start(slots); +} + +/* + * \brief Function starts the calibration interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_calibration_timer_start(uint32_t slots) +{ + rf_if_calibration_timer_start(slots); +} + +/* + * \brief Function starts the CCA backoff. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_cca_timer_start(uint32_t slots) +{ + rf_if_cca_timer_start(slots); +} + +/* + * \brief Function stops the CCA backoff. + * + * \return none + */ +static void rf_cca_timer_stop(void) +{ + rf_if_cca_timer_stop(); +} + +/* + * \brief Function stops the ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_ack_wait_timer_stop(void) +{ + rf_if_ack_wait_timer_stop(); +} + +/* + * \brief Function writes various RF settings in startup. + * + * \param none + * + * \return none + */ +static void rf_write_settings(void) +{ + rf_if_lock(); + rf_if_write_rf_settings(); + /*Set output power*/ + rf_if_write_set_tx_power_register(radio_tx_power); + /*Initialise Antenna Diversity*/ + if(rf_use_antenna_diversity) + rf_if_write_antenna_diversity_settings(); + rf_if_unlock(); +} + +/* + * \brief Function writes 16-bit address in RF address filter. + * + * \param short_address Given short address + * + * \return none + */ +static void rf_set_short_adr(uint8_t * short_address) +{ + rf_if_lock(); + /*Wake up RF if sleeping*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + } + /*Write address filter registers*/ + rf_if_write_short_addr_registers(short_address); + /*RF back to sleep*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_enable_slptr(); + } + rf_if_unlock(); +} + +/* + * \brief Function writes PAN Id in RF PAN Id filter. + * + * \param pan_id Given PAN Id + * + * \return none + */ +static void rf_set_pan_id(uint8_t *pan_id) +{ + rf_if_lock(); + /*Wake up RF if sleeping*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + } + /*Write address filter registers*/ + rf_if_write_pan_id_registers(pan_id); + /*RF back to sleep*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_enable_slptr(); + } + rf_if_unlock(); +} + +/* + * \brief Function writes 64-bit address in RF address filter. + * + * \param address Given 64-bit address + * + * \return none + */ +static void rf_set_address(uint8_t *address) +{ + rf_if_lock(); + /*Wake up RF if sleeping*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + } + /*Write address filter registers*/ + rf_if_write_ieee_addr_registers(address); + /*RF back to sleep*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_enable_slptr(); + } + rf_if_unlock(); +} + +/* + * \brief Function sets the RF channel. + * + * \param ch New channel + * + * \return none + */ +static void rf_channel_set(uint8_t ch) +{ + rf_if_lock(); + rf_phy_channel = ch; + if(ch < 0x1f) + rf_if_set_channel_register(ch); + rf_if_unlock(); +} + + +/* + * \brief Function initialises the radio driver and resets the radio. + * + * \param none + * + * \return none + */ +static void rf_init(void) +{ + rf_if_lock(); + + /*Write RF settings*/ + rf_write_settings(); + /*Initialise PHY mode*/ + rf_init_phy_mode(); + /*Clear RF flags*/ + rf_flags_reset(); + /*Set RF in TRX OFF state*/ + rf_if_change_trx_state(TRX_OFF); + /*Set RF in PLL_ON state*/ + rf_trx_states_t trx_status = rf_if_change_trx_state(PLL_ON); + /*Start receiver*/ + rf_receive(trx_status); + /*Read randomness, and add to seed*/ + randLIB_add_seed(rf_if_read_rnd()); + /*Start RF calibration timer*/ + rf_calibration_timer_start(RF_CALIBRATION_INTERVAL); + + rf_if_unlock(); +} + +/** + * \brief Function gets called when MAC is setting radio off. + * + * \param none + * + * \return none + */ +static void rf_off(void) +{ + if(rf_flags_check(RFF_ON)) + { + rf_if_lock(); + rf_cca_abort(); + uint16_t while_counter = 0; + /*Wait while receiving*/ + while(rf_if_read_trx_state() == BUSY_RX_AACK) + { + while_counter++; + if(while_counter == 0xffff) + break; + } + /*RF state change: RX_AACK_ON->PLL_ON->TRX_OFF->SLEEP*/ + if(rf_if_read_trx_state() == RX_AACK_ON) + { + rf_if_change_trx_state(PLL_ON); + } + rf_if_change_trx_state(TRX_OFF); + rf_if_enable_slptr(); + + /*Disable Antenna Diversity*/ + if(rf_use_antenna_diversity) + rf_if_disable_ant_div(); + rf_if_unlock(); + } + + /*Clears all flags*/ + rf_flags_reset(); +} + +/* + * \brief Function polls the RF state until it has changed to desired state. + * + * \param trx_state RF state + * + * \return none + */ +static rf_trx_states_t rf_poll_trx_state_change(rf_trx_states_t trx_state) +{ + uint16_t while_counter = 0; + + if(trx_state == FORCE_PLL_ON) + trx_state = PLL_ON; + else if(trx_state == FORCE_TRX_OFF) + trx_state = TRX_OFF; + + rf_trx_states_t state_out; + while((state_out = rf_if_read_trx_state()) != trx_state) + { + while_counter++; + if(while_counter == 0x1ff) + break; + } + + return state_out; +} + +/* + * \brief Function polls the RF state until it is no longer transitioning. + * + * \param trx_state RF state + * + * \return none + */ +static rf_trx_states_t rf_poll_for_state(void) +{ + rf_trx_states_t state_out; + while((state_out = rf_if_read_trx_state()) == STATE_TRANSITION_IN_PROGRESS) + { + } + + return state_out; +} + +/* + * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO. + * + * \param data_ptr Pointer to TX data (excluding FCS) + * \param data_length Length of the TX data (excluding FCS) + * \param tx_handle Handle to transmission + * \return 0 Success + * \return -1 Busy + */ +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ) +{ + (void)data_protocol; + rf_if_lock(); + /*Check if transmitter is busy*/ + rf_trx_states_t trx_state = rf_if_read_trx_state(); + if(trx_state == BUSY_RX || trx_state == BUSY_RX_AACK || data_length > RF_MTU - 2) + { + rf_if_unlock(); + /*Return busy*/ + return -1; + } + else + { + rf_give_up_on_ack(); + + /*Nanostack has a static TX buffer, which will remain valid until we*/ + /*generate a callback, so we just note the pointer for reading later.*/ + rf_tx_data = data_ptr; + rf_tx_length = data_length; + /*Start CCA timeout*/ + rf_cca_timer_start(RF_CCA_BASE_BACKOFF + randLIB_get_random_in_range(0, RF_CCA_RANDOM_BACKOFF)); + /*Store TX handle*/ + mac_tx_handle = tx_handle; + rf_if_unlock(); + } + + /*Return success*/ + return 0; +} + +/* + * \brief Function aborts CCA process. + * + * \param none + * + * \return none + */ +static void rf_cca_abort(void) +{ + rf_cca_timer_stop(); + rf_flags_clear(RFF_CCA); +} + +/* + * \brief Function starts the transmission of the frame. + * + * \param none + * + * \return none + */ +static bool rf_start_tx() +{ + /* Attempt change to PLL_ON */ + rf_if_write_register(TRX_STATE, PLL_ON); + + // It appears that if radio is busy, rather than ignoring the state change, + // the state change happens when it stops being busy - eg + // after address match fail or finishing reception. If this happens, we do + // not want to transmit - our channel clear check is stale (either someone is + // still transmitting, or it's a long time since we checked). So wait for the + // PLL_ON change and then go to receive mode without trying to transmit. + rf_trx_states_t state = rf_poll_for_state(); + int poll_count = 0; + while (state != PLL_ON) { + /* Change didn't work (yet) - must be busy - assume it will eventually change */ + state = rf_poll_for_state(); + poll_count++; + } + + rf_flags_clear(RFF_RX); + // Check whether we saw any delay in the PLL_ON transition. + if (poll_count > 0) { + tr_warning("PLL_ON delayed, retry count: %d", poll_count); + // let's get back to the receiving state. + rf_receive(state); + return false; + } + + rf_flags_set(RFF_TX); + /*RF state change: SLP_TR pulse triggers PLL_ON->BUSY_TX*/ + rf_if_enable_slptr(); + /*Chip permits us to write frame buffer while it is transmitting*/ + /*As long as first byte of data is in within 176us of TX start, we're good */ + rf_if_write_frame_buffer(rf_tx_data, rf_tx_length); + rf_if_disable_slptr(); + return true; +} + +/* + * \brief Function sets the RF in RX state. + * + * \param none + * + * \return none + */ +static void rf_receive(rf_trx_states_t trx_status) +{ + uint16_t while_counter = 0; + if(rf_flags_check(RFF_ON) == 0) + { + rf_on(); + rf_channel_set(rf_phy_channel); + trx_status = TRX_OFF; + } + /*If not yet in RX state set it*/ + if(rf_flags_check(RFF_RX) == 0) + { + /*Wait while receiving data. Just making sure, usually this shouldn't happen. */ + while(trx_status == BUSY_RX || trx_status == BUSY_RX_AACK || trx_status == STATE_TRANSITION_IN_PROGRESS) + { + while_counter++; + if(while_counter == 0xffff) + { + break; + } + trx_status = rf_if_read_trx_state(); + } + + if((rf_mode == RF_MODE_SNIFFER) || (rf_mode == RF_MODE_ED)) + { + if (trx_status != RX_ON) { + trx_status = rf_if_change_trx_state(RX_ON); + } + } + else + { + /*ACK is always received in promiscuous mode to bypass address filters*/ + if(rf_rx_mode) + { + rf_rx_mode = 0; + rf_if_enable_promiscuous_mode(); + } + else + { + rf_if_disable_promiscuous_mode(); + } + if (trx_status != RX_AACK_ON) { + trx_status = rf_if_change_trx_state(RX_AACK_ON); + } + } + /*If calibration timer was unable to calibrate the RF, run calibration now*/ + if(!rf_tuned) + { + /*Start calibration. This can be done in states TRX_OFF, PLL_ON or in any receive state*/ + rf_if_calibration(); + /*RF is tuned now*/ + rf_tuned = 1; + } + + rf_flags_set(RFF_RX); + } +} + +/* + * \brief Function calibrates the radio. + * + * \param none + * + * \return none + */ +static void rf_calibration_cb(void) +{ + /*clear tuned flag to start tuning in rf_receive*/ + rf_tuned = 0; + /*If RF is in default receive state, start calibration*/ + if(rf_if_read_trx_state() == RX_AACK_ON) + { + rf_if_lock(); + /*Set RF in PLL_ON state*/ + rf_if_change_trx_state(PLL_ON); + /*Set RF in TRX_OFF state to start PLL tuning*/ + rf_if_change_trx_state(TRX_OFF); + /*Set RF in RX_ON state to calibrate*/ + rf_trx_states_t trx_status = rf_if_change_trx_state(RX_ON); + /*Calibrate FTN*/ + rf_if_calibration(); + /*RF is tuned now*/ + rf_tuned = 1; + /*Back to default receive state*/ + rf_flags_clear(RFF_RX); + rf_receive(trx_status); + rf_if_unlock(); + } +} + +/* + * \brief Function sets RF_ON flag when radio is powered. + * + * \param none + * + * \return none + */ +static void rf_on(void) +{ + /*Set RFF_ON flag*/ + if(rf_flags_check(RFF_ON) == 0) + { + rf_if_lock(); + rf_flags_set(RFF_ON); + /*Enable Antenna diversity*/ + if(rf_use_antenna_diversity) + /*Set ANT_EXT_SW_EN to enable controlling of antenna diversity*/ + rf_if_enable_ant_div(); + + /*Wake up from sleep state*/ + rf_if_disable_slptr(); + rf_poll_trx_state_change(TRX_OFF); + rf_if_unlock(); + } +} + +/* + * \brief Abandon waiting for an ack frame + + * \return none + */ +static void rf_give_up_on_ack(void) +{ + if (expected_ack_sequence == -1) { + return; + } + + rf_if_disable_promiscuous_mode(); + rf_if_ack_wait_timer_stop(); + expected_ack_sequence = -1; + + if(device_driver.phy_tx_done_cb){ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_FAIL, 0, 0); + } +} + +/* + * \brief Function handles the received ACK frame. + * + * \param seq_number Sequence number of received ACK + * \param data_pending Pending bit state in received ACK + * + * \return none + */ +static void rf_handle_ack(uint8_t seq_number, uint8_t data_pending) +{ + phy_link_tx_status_e phy_status; + /*Received ACK sequence must be equal with transmitted packet sequence*/ + if(expected_ack_sequence == seq_number) + { + rf_if_disable_promiscuous_mode(); + rf_if_ack_wait_timer_stop(); + expected_ack_sequence = -1; + + /*When data pending bit in ACK frame is set, inform NET library*/ + if(data_pending) + phy_status = PHY_LINK_TX_DONE_PENDING; + else + phy_status = PHY_LINK_TX_DONE; + /*Call PHY TX Done API*/ + if(device_driver.phy_tx_done_cb){ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle,phy_status, 0, 0); + } + } else { + rf_give_up_on_ack(); + } +} + +/* + * \brief Function is a call back for RX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_rx_end(rf_trx_states_t trx_status) +{ + /*Frame received interrupt*/ + if(!rf_flags_check(RFF_RX)) { + return; + } + + static uint8_t rf_buffer[RF_MTU]; + uint8_t rf_lqi, rf_ed; + int8_t rf_rssi; + bool crc_good; + + /*Read received packet*/ + uint8_t len = rf_if_read_packet(rf_buffer, &rf_lqi, &rf_ed, &crc_good); + + if (len < 5 || !crc_good) { + rf_give_up_on_ack(); + return; + } + + /* Convert raw ED to dBm value (chip-dependent) */ + rf_rssi = rf_if_scale_rssi(rf_ed); + + /* Create a virtual LQI using received RSSI, forgetting actual HW LQI */ + /* (should be done through PHY_EXTENSION_CONVERT_SIGNAL_INFO) */ + rf_lqi = rf_scale_lqi(rf_rssi); + + /*Handle received ACK*/ + if((rf_buffer[0] & 0x07) == 0x02 && rf_mode != RF_MODE_SNIFFER) + { + /*Check if data is pending*/ + bool pending = (rf_buffer[0] & 0x10); + + /*Send sequence number in ACK handler*/ + rf_handle_ack(rf_buffer[2], pending); + } else { + rf_give_up_on_ack(); + if( device_driver.phy_rx_cb ){ + device_driver.phy_rx_cb(rf_buffer, len - 2, rf_lqi, rf_rssi, rf_radio_driver_id); + } + } +} + +/* + * \brief Function is called when MAC is shutting down the radio. + * + * \param none + * + * \return none + */ +static void rf_shutdown(void) +{ + /*Call RF OFF*/ + rf_off(); +} + +/* + * \brief Function is a call back for TX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_tx_end(rf_trx_states_t trx_status) +{ + rf_rx_mode = 0; + /*If ACK is needed for this transmission*/ + if((rf_tx_data[0] & 0x20) && rf_flags_check(RFF_TX)) + { + expected_ack_sequence = rf_tx_data[2]; + rf_ack_wait_timer_start(rf_ack_wait_duration); + rf_rx_mode = 1; + } + rf_flags_clear(RFF_TX); + /*Start receiver*/ + rf_receive(trx_status); + + /*Call PHY TX Done API*/ + if(device_driver.phy_tx_done_cb){ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 0, 0); + } +} + +/* + * \brief Function is a call back for CCA ED done interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_cca_ed_done(uint8_t full_trx_status) +{ + if (!rf_flags_check(RFF_CCA)) { + return; + } + rf_flags_clear(RFF_CCA); + + bool success = false; + + /*Check the result of CCA process*/ + if((full_trx_status & CCA_STATUS) && rf_if_trx_status_from_full(full_trx_status) == RX_AACK_ON) + { + success = rf_start_tx(); + } + + if (!success) + { + /*Send CCA fail notification*/ + if(device_driver.phy_tx_done_cb){ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); + } + } +} + +/* + * \brief Function returns the TX power variable. + * + * \param none + * + * \return radio_tx_power TX power variable + */ +MBED_UNUSED static uint8_t rf_tx_power_get(void) +{ + return radio_tx_power; +} + +/* + * \brief Function enables the usage of Antenna diversity. + * + * \param none + * + * \return 0 Success + */ +MBED_UNUSED static int8_t rf_enable_antenna_diversity(void) +{ + int8_t ret_val = 0; + rf_use_antenna_diversity = 1; + return ret_val; +} + +/* + * \brief Function gives the control of RF states to MAC. + * + * \param new_state RF state + * \param rf_channel RF channel + * + * \return 0 Success + */ +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel) +{ + int8_t ret_val = 0; + switch (new_state) + { + /*Reset PHY driver and set to idle*/ + case PHY_INTERFACE_RESET: + break; + /*Disable PHY Interface driver*/ + case PHY_INTERFACE_DOWN: + rf_shutdown(); + break; + /*Enable PHY Interface driver*/ + case PHY_INTERFACE_UP: + rf_if_lock(); + rf_mode = RF_MODE_NORMAL; + rf_channel_set(rf_channel); + rf_receive(); + rf_if_enable_irq(); + rf_if_unlock(); + break; + /*Enable wireless interface ED scan mode*/ + case PHY_INTERFACE_RX_ENERGY_STATE: + rf_mode = RF_MODE_ED; + rf_channel_set(rf_channel); + rf_receive(); + rf_if_disable_irq(); + // Read status to clear pending flags. + rf_if_read_register(IRQ_STATUS); + // ED can be initiated by writing arbitrary value to PHY_ED_LEVEL + rf_if_write_register(PHY_ED_LEVEL, 0xff); + break; + case PHY_INTERFACE_SNIFFER_STATE: /**< Enable Sniffer state */ + rf_mode = RF_MODE_SNIFFER; + rf_channel_set(rf_channel); + rf_flags_clear(RFF_RX); + rf_receive(); + rf_if_enable_irq(); + break; + } + return ret_val; +} + +/* + * \brief Function controls the ACK pending, channel setting and energy detection. + * + * \param extension_type Type of control + * \param data_ptr Data from NET library + * + * \return 0 Success + */ +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr) +{ + switch (extension_type) + { + /*Control MAC pending bit for Indirect data transmission*/ + case PHY_EXTENSION_CTRL_PENDING_BIT: + if(*data_ptr) + { + rf_if_ack_pending_ctrl(1); + } + else + { + rf_if_ack_pending_ctrl(0); + } + break; + /*Return frame pending status*/ + case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: + *data_ptr = rf_if_last_acked_pending(); + break; + /*Set channel*/ + case PHY_EXTENSION_SET_CHANNEL: + break; + /*Read energy on the channel*/ + case PHY_EXTENSION_READ_CHANNEL_ENERGY: + // End of the ED measurement is indicated by CCA_ED_DONE + while (!(rf_if_read_register(IRQ_STATUS) & CCA_ED_DONE)); + // RF input power: RSSI base level + 1[db] * PHY_ED_LEVEL + *data_ptr = rf_sensitivity + rf_if_read_register(PHY_ED_LEVEL); + // Read status to clear pending flags. + rf_if_read_register(IRQ_STATUS); + // Next ED measurement is started, next PHY_EXTENSION_READ_CHANNEL_ENERGY call will return the result. + rf_if_write_register(PHY_ED_LEVEL, 0xff); + break; + /*Read status of the link*/ + case PHY_EXTENSION_READ_LINK_STATUS: + break; + default: + break; + } + return 0; +} + +/* + * \brief Function sets the addresses to RF address filters. + * + * \param address_type Type of address + * \param address_ptr Pointer to given address + * + * \return 0 Success + */ +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr) +{ + int8_t ret_val = 0; + switch (address_type) + { + /*Set 48-bit address*/ + case PHY_MAC_48BIT: + break; + /*Set 64-bit address*/ + case PHY_MAC_64BIT: + rf_set_address(address_ptr); + break; + /*Set 16-bit address*/ + case PHY_MAC_16BIT: + rf_set_short_adr(address_ptr); + break; + /*Set PAN Id*/ + case PHY_MAC_PANID: + rf_set_pan_id(address_ptr); + break; + } + return ret_val; +} + +/* + * \brief Function initialises the ACK wait time and returns the used PHY mode. + * + * \param none + * + * \return tmp Used PHY mode + */ +static void rf_init_phy_mode(void) +{ + uint8_t tmp = 0; + uint8_t part = rf_if_read_part_num(); + /*Read used PHY Mode*/ + tmp = rf_if_read_register(TRX_CTRL_2); + /*Set ACK wait time for used data rate*/ + if(part == PART_AT86RF212) + { + if((tmp & 0x1f) == 0x00) + { + rf_sensitivity = -110; + rf_ack_wait_duration = 938; + tmp = BPSK_20; + } + else if((tmp & 0x1f) == 0x04) + { + rf_sensitivity = -108; + rf_ack_wait_duration = 469; + tmp = BPSK_40; + } + else if((tmp & 0x1f) == 0x14) + { + rf_sensitivity = -108; + rf_ack_wait_duration = 469; + tmp = BPSK_40_ALT; + } + else if((tmp & 0x1f) == 0x08) + { + rf_sensitivity = -101; + rf_ack_wait_duration = 50; + tmp = OQPSK_SIN_RC_100; + } + else if((tmp & 0x1f) == 0x09) + { + rf_sensitivity = -99; + rf_ack_wait_duration = 30; + tmp = OQPSK_SIN_RC_200; + } + else if((tmp & 0x1f) == 0x18) + { + rf_sensitivity = -102; + rf_ack_wait_duration = 50; + tmp = OQPSK_RC_100; + } + else if((tmp & 0x1f) == 0x19) + { + rf_sensitivity = -100; + rf_ack_wait_duration = 30; + tmp = OQPSK_RC_200; + } + else if((tmp & 0x1f) == 0x0c) + { + rf_sensitivity = -100; + rf_ack_wait_duration = 20; + tmp = OQPSK_SIN_250; + } + else if((tmp & 0x1f) == 0x0d) + { + rf_sensitivity = -98; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_500; + } + else if((tmp & 0x1f) == 0x0f) + { + rf_sensitivity = -98; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_500_ALT; + } + else if((tmp & 0x1f) == 0x1c) + { + rf_sensitivity = -101; + rf_ack_wait_duration = 20; + tmp = OQPSK_RC_250; + } + else if((tmp & 0x1f) == 0x1d) + { + rf_sensitivity = -99; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_500; + } + else if((tmp & 0x1f) == 0x1f) + { + rf_sensitivity = -99; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_500_ALT; + } + else if((tmp & 0x3f) == 0x2A) + { + rf_sensitivity = -91; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_RC_400_SCR_ON; + } + else if((tmp & 0x3f) == 0x0A) + { + rf_sensitivity = -91; + rf_ack_wait_duration = 25; + tmp = OQPSK_SIN_RC_400_SCR_OFF; + } + else if((tmp & 0x3f) == 0x3A) + { + rf_sensitivity = -97; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_400_SCR_ON; + } + else if((tmp & 0x3f) == 0x1A) + { + rf_sensitivity = -97; + rf_ack_wait_duration = 25; + tmp = OQPSK_RC_400_SCR_OFF; + } + else if((tmp & 0x3f) == 0x2E) + { + rf_sensitivity = -93; + rf_ack_wait_duration = 13; + tmp = OQPSK_SIN_1000_SCR_ON; + } + else if((tmp & 0x3f) == 0x0E) + { + rf_sensitivity = -93; + rf_ack_wait_duration = 13; + tmp = OQPSK_SIN_1000_SCR_OFF; + } + else if((tmp & 0x3f) == 0x3E) + { + rf_sensitivity = -95; + rf_ack_wait_duration = 13; + tmp = OQPSK_RC_1000_SCR_ON; + } + else if((tmp & 0x3f) == 0x1E) + { + rf_sensitivity = -95; + rf_ack_wait_duration = 13; + tmp = OQPSK_RC_1000_SCR_OFF; + } + } + else + { + rf_sensitivity = -101; + rf_ack_wait_duration = 20; + } + /*Board design might reduces the sensitivity*/ + //rf_sensitivity += RF_SENSITIVITY_CALIBRATION; +} + + +static uint8_t rf_scale_lqi(int8_t rssi) +{ + uint8_t scaled_lqi; + + /*rssi < RF sensitivity*/ + if(rssi < rf_sensitivity) + scaled_lqi=0; + /*-91 dBm < rssi < -81 dBm (AT86RF233 XPro)*/ + /*-90 dBm < rssi < -80 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 10)) + scaled_lqi=31; + /*-81 dBm < rssi < -71 dBm (AT86RF233 XPro)*/ + /*-80 dBm < rssi < -70 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 20)) + scaled_lqi=207; + /*-71 dBm < rssi < -61 dBm (AT86RF233 XPro)*/ + /*-70 dBm < rssi < -60 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 30)) + scaled_lqi=255; + /*-61 dBm < rssi < -51 dBm (AT86RF233 XPro)*/ + /*-60 dBm < rssi < -50 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 40)) + scaled_lqi=255; + /*-51 dBm < rssi < -41 dBm (AT86RF233 XPro)*/ + /*-50 dBm < rssi < -40 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 50)) + scaled_lqi=255; + /*-41 dBm < rssi < -31 dBm (AT86RF233 XPro)*/ + /*-40 dBm < rssi < -30 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 60)) + scaled_lqi=255; + /*-31 dBm < rssi < -21 dBm (AT86RF233 XPro)*/ + /*-30 dBm < rssi < -20 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 70)) + scaled_lqi=255; + /*rssi > RF saturation*/ + else if(rssi > (rf_sensitivity + 80)) + scaled_lqi=111; + /*-21 dBm < rssi < -11 dBm (AT86RF233 XPro)*/ + /*-20 dBm < rssi < -10 dBm (AT86RF212B XPro)*/ + else + scaled_lqi=255; + + return scaled_lqi; +} + +NanostackRfPhyAtmel::NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq, + PinName i2c_sda, PinName i2c_scl) + : _mac(i2c_sda, i2c_scl), _mac_addr(), _rf(NULL), _mac_set(false), + _spi_mosi(spi_mosi), _spi_miso(spi_miso), _spi_sclk(spi_sclk), + _spi_cs(spi_cs), _spi_rst(spi_rst), _spi_slp(spi_slp), _spi_irq(spi_irq) +{ + _rf = new RFBits(_spi_mosi, _spi_miso, _spi_sclk, _spi_cs, _spi_rst, _spi_slp, _spi_irq); +} + +NanostackRfPhyAtmel::~NanostackRfPhyAtmel() +{ + delete _rf; +} + +int8_t NanostackRfPhyAtmel::rf_register() +{ + if (NULL == _rf) { + return -1; + } + + rf_if_lock(); + + if (rf != NULL) { + rf_if_unlock(); + error("Multiple registrations of NanostackRfPhyAtmel not supported"); + return -1; + } + + // Read the mac address if it hasn't been set by a user + rf = _rf; + if (!_mac_set) { + int ret = _mac.read_eui64((void*)_mac_addr); + if (ret < 0) { + rf = NULL; + rf_if_unlock(); + return -1; + } + } + + int8_t radio_id = rf_device_register(_mac_addr); + if (radio_id < 0) { + rf = NULL; + } + + rf_if_unlock(); + return radio_id; +} + +void NanostackRfPhyAtmel::rf_unregister() +{ + rf_if_lock(); + + if (NULL == rf) { + rf_if_unlock(); + return; + } + + rf_device_unregister(); + rf = NULL; + + rf_if_unlock(); +} + +void NanostackRfPhyAtmel::get_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + if (NULL == rf) { + error("NanostackRfPhyAtmel Must be registered to read mac address"); + rf_if_unlock(); + return; + } + memcpy((void*)mac, (void*)_mac_addr, sizeof(_mac_addr)); + + rf_if_unlock(); +} + +void NanostackRfPhyAtmel::set_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + if (NULL != rf) { + error("NanostackRfPhyAtmel cannot change mac address when running"); + rf_if_unlock(); + return; + } + memcpy((void*)_mac_addr, (void*)mac, sizeof(_mac_addr)); + _mac_set = true; + + rf_if_unlock(); +} + +#endif // MBED_CONF_NANOSTACK_CONFIGURATION
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/source/at24mac.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/source/at24mac.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016-2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "at24mac.h" + +/* Device addressing */ +#define AT24MAC_EEPROM_ADDRESS (0x0A<<4) +#define AT24MAC_RW_PROTECT_ADDRESS (0x06<<4) +#define AT24MAC_SERIAL_ADDRESS (0x0B<<4) + +/* Known memory blocks */ +#define AT24MAC_SERIAL_OFFSET (0x80) +#define AT24MAC_EUI64_OFFSET (0x98) +#define AT24MAC_EUI48_OFFSET (0x9A) + +#define SERIAL_LEN 16 +#define EUI64_LEN 8 +#define EUI48_LEN 6 + +AT24Mac::I2CReset::I2CReset(PinName sda, PinName scl) +{ + mbed::DigitalInOut SDA(sda, PIN_OUTPUT, PullUp, 1); + mbed::DigitalInOut SCL(scl, PIN_OUTPUT, PullUp, 0); + //generate 9 clocks for worst-case scenario + for (int i = 0; i < 10; ++i) { + SCL = 1; + wait_us(5); + SCL = 0; + wait_us(5); + } + //generate a STOP condition + SDA = 0; + wait_us(5); + SCL = 1; + wait_us(5); + SDA = 1; + wait_us(5); +} + +/*I2C needs to be reset before constructing the I2C object (in case I2C is stuck) + because they use the same pins, therefore i2c_reset has to be before _i2c + in the initializer list*/ +AT24Mac::AT24Mac(PinName sda, PinName scl) : i2c_reset(sda, scl), _i2c(sda, scl) +{ + // Do nothing +} + +int AT24Mac::read_serial(void *buf) +{ + char offset = AT24MAC_SERIAL_OFFSET; + if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) + return -1; //No ACK + return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char*)buf, SERIAL_LEN); +} + +int AT24Mac::read_eui64(void *buf) +{ + char offset = AT24MAC_EUI64_OFFSET; + if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) + return -1; //No ACK + return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char*)buf, EUI64_LEN); +} + +int AT24Mac::read_eui48(void *buf) +{ + char offset = AT24MAC_EUI48_OFFSET; + if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) + return -1; //No ACK + return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char*)buf, EUI48_LEN); +}
diff -r 000000000000 -r 119624335925 easy-connect/atmel-rf-driver/source/at24mac.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/atmel-rf-driver/source/at24mac.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef AT24MAC_H +#define AT24MAC_H + +#include "PinNames.h" +#include "I2C.h" +#include "drivers/DigitalInOut.h" +#include "platform/mbed_wait_api.h" + +/* + * AT24MAC drivers. + * + * This is a EEPROM chip designed to contain factory programmed read-only EUI-64 or EUI-48, + * a 128bit serial number and some user programmable EEPROM. + * + * AT24MAC602 contains EUI-64, use read_eui64() + * AT24MAC402 contains EUI-64, use read_eui48() + * + * NOTE: You cannot use both EUI-64 and EUI-48. Chip contains only one of those. + */ + +class AT24Mac { +public: + AT24Mac(PinName sda, PinName scl); + + /** + * Read unique serial number from chip. + * \param buf pointer to write serial number to. Must have space for 16 bytes. + * \return zero on success, negative number on failure + */ + int read_serial(void *buf); + + /** + * Read EUI-64 from chip. + * \param buf pointer to write EUI-64 to. Must have space for 8 bytes. + * \return zero on success, negative number on failure + */ + int read_eui64(void *buf); + + /** + * Read EUI-48 from chip. + * \param buf pointer to write EUI-48 to. Must have space for 6 bytes. + * \return zero on success, negative number on failure + */ + int read_eui48(void *buf); + +private: + /* + * Dummy class to allow us to reset I2C before the I2C constructor is called in + * the initializer list of AT24Mac's constructor + */ + class I2CReset { + public: + I2CReset(PinName sda, PinName scl); + }; + I2CReset i2c_reset; + mbed::I2C _i2c; +}; + +#endif /* AT24MAC_H */
diff -r 000000000000 -r 119624335925 easy-connect/easy-connect.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/easy-connect.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,401 @@ +/* + * FILE: easy-connect.cpp + * + * Copyright (c) 2015 - 2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed.h" +#include "easy-connect.h" + +/* + * Instantiate the configured network interface + */ +#if MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ESP8266 +#include "ESP8266Interface.h" +#define EASY_CONNECT_WIFI_TYPE "ESP8266" + +#ifdef MBED_CONF_APP_ESP8266_DEBUG +ESP8266Interface wifi(MBED_CONF_EASY_CONNECT_WIFI_ESP8266_TX, MBED_CONF_EASY_CONNECT_WIFI_ESP8266_RX, MBED_CONF_EASY_CONNECT_WIFI_ESP8266_DEBUG); +#else +ESP8266Interface wifi(MBED_CONF_EASY_CONNECT_WIFI_ESP8266_TX, MBED_CONF_EASY_CONNECT_WIFI_ESP8266_RX); +#endif + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ODIN +#define EASY_CONNECT_WIFI_TYPE "Odin" +#include "OdinWiFiInterface.h" +OdinWiFiInterface wifi; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_RTW +#define EASY_CONNECT_WIFI_TYPE "RTW" +#include "RTWInterface.h" +RTWInterface wifi; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_IDW0XX1 +#include "SpwfSAInterface.h" + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW01M1 +#define EASY_CONNECT_WIFI_TYPE "IDW01M1" +SpwfSAInterface wifi(MBED_CONF_EASY_CONNECT_WIFI_IDW01M1_TX, MBED_CONF_EASY_CONNECT_WIFI_IDW01M1_RX); +#endif // MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW01M1 + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 +#define EASY_CONNECT_WIFI_TYPE "IDW04A1" +SpwfSAInterface wifi(MBED_CONF_EASY_CONNECT_WIFI_IDW04A1_TX, MBED_CONF_EASY_CONNECT_WIFI_IDW04A1_RX); +#endif // MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ISM43362 +#include "ISM43362Interface.h" +#define EASY_CONNECT_WIFI_TYPE "ISM43362" + +#ifdef MBED_CONF_APP_ISM43362_DEBUG +ISM43362Interface wifi(true); +#else +ISM43362Interface wifi; +#endif + +#elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET +#include "EthernetInterface.h" +EthernetInterface eth; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_LOWPAN_ND +#define EASY_CONNECT_MESH +#include "NanostackInterface.h" +LoWPANNDInterface mesh; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_THREAD +#define EASY_CONNECT_MESH +#include "NanostackInterface.h" +ThreadInterface mesh; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == CELLULAR_ONBOARD +#include "OnboardCellularInterface.h" +OnboardCellularInterface cellular; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == CELLULAR +#include "EasyCellularConnection.h" +EasyCellularConnection cellular; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_WIZFI310 +#include "WizFi310Interface.h" +#define EASY_CONNECT_WIFI_TYPE "WizFi310" + +#ifdef MBED_CONF_APP_WIZFI310_DEBUG + WizFi310Interface wifi(MBED_CONF_EASY_CONNECT_WIFI_WIZFI310_TX, MBED_CONF_EASY_CONNECT_WIFI_WIZFI310_RX, MBED_CONF_EASY_CONNECT_WIFI_WIZFI310_DEBUG); +#else + WizFi310Interface wifi(MBED_CONF_EASY_CONNECT_WIFI_WIZFI310_TX, MBED_CONF_EASY_CONNECT_WIFI_WIZFI310_RX); +#endif + +#elif MBED_CONF_APP_NETWORK_INTERFACE == CELLULAR_WNC14A2A +#include "WNC14A2AInterface.h" + +#if MBED_CONF_APP_WNC_DEBUG == true +#include "WNCDebug.h" +WNCDebug dbgout(stderr); +WNC14A2AInterface wnc(&dbgout); +#else +WNC14A2AInterface wnc; +#endif + + +#else +#error "No connectivity method chosen. Please add 'config.network-interfaces.value' to your mbed_app.json (see README.md for more information)." +#endif // MBED_CONF_APP_NETWORK_INTERFACE + +/* + * In case of Mesh, instantiate the configured RF PHY. + */ +#if defined (EASY_CONNECT_MESH) +#if MBED_CONF_APP_MESH_RADIO_TYPE == ATMEL +#include "NanostackRfPhyAtmel.h" +#define EASY_CONNECT_MESH_TYPE "Atmel" +NanostackRfPhyAtmel rf_phy(ATMEL_SPI_MOSI, ATMEL_SPI_MISO, ATMEL_SPI_SCLK, ATMEL_SPI_CS, + ATMEL_SPI_RST, ATMEL_SPI_SLP, ATMEL_SPI_IRQ, ATMEL_I2C_SDA, ATMEL_I2C_SCL); + +#elif MBED_CONF_APP_MESH_RADIO_TYPE == MCR20 +#include "NanostackRfPhyMcr20a.h" +#define EASY_CONNECT_MESH_TYPE "Mcr20A" +NanostackRfPhyMcr20a rf_phy(MCR20A_SPI_MOSI, MCR20A_SPI_MISO, MCR20A_SPI_SCLK, MCR20A_SPI_CS, MCR20A_SPI_RST, MCR20A_SPI_IRQ); + +#elif MBED_CONF_APP_MESH_RADIO_TYPE == SPIRIT1 +#include "NanostackRfPhySpirit1.h" +#define EASY_CONNECT_MESH_TYPE "Spirit1" +NanostackRfPhySpirit1 rf_phy(SPIRIT1_SPI_MOSI, SPIRIT1_SPI_MISO, SPIRIT1_SPI_SCLK, + SPIRIT1_DEV_IRQ, SPIRIT1_DEV_CS, SPIRIT1_DEV_SDN, SPIRIT1_BRD_LED); + +#elif MBED_CONF_APP_MESH_RADIO_TYPE == EFR32 +#include "NanostackRfPhyEfr32.h" +#define EASY_CONNECT_MESH_TYPE "EFR32" +NanostackRfPhyEfr32 rf_phy; + +#endif // MBED_CONF_APP_RADIO_TYPE +#endif // EASY_CONNECT_MESH + +#if defined (EASY_CONNECT_WIFI) +#define WIFI_SSID_MAX_LEN 32 // As per IEEE 802.11 chapter 7.3.2.1 (SSID element) +#define WIFI_PASSWORD_MAX_LEN 64 // + +char* _ssid = NULL; +char* _password = NULL; +#endif // EASY_CONNECT_WIFI + +/* \brief print_MAC - print_MAC - helper function to print out MAC address + * in: network_interface - pointer to network i/f + * bool log-messages print out logs or not + * MAC address is printed, if it can be acquired & log_messages is true. + * + */ +void print_MAC(NetworkInterface* network_interface, bool log_messages) { +#if MBED_CONF_APP_NETWORK_INTERFACE != CELLULAR_ONBOARD && MBED_CONF_APP_NETWORK_INTERFACE != CELLULAR + const char *mac_addr = network_interface->get_mac_address(); + if (mac_addr == NULL) { + if (log_messages) { + printf("[EasyConnect] ERROR - No MAC address\n"); + } + return; + } + if (log_messages) { + printf("[EasyConnect] MAC address %s\n", mac_addr); + } +#endif +} + + + +/* \brief easy_connect easy_connect() function to connect the pre-defined network bearer, + * config done via mbed_app.json (see README.md for details). + * + * IN: bool log_messages print out diagnostics or not. + */ +NetworkInterface* easy_connect(bool log_messages) { + NetworkInterface* network_interface = NULL; + int connect_success = -1; + +#if defined (EASY_CONNECT_WIFI) + // We check if the _ssid and _password have already been set (via the easy_connect() + // that takes thoses parameters or not. + // If they have not been set, use the ones we can gain from mbed_app.json. + if (_ssid == NULL) { + if(strlen(MBED_CONF_APP_WIFI_SSID) > WIFI_SSID_MAX_LEN) { + printf("ERROR - MBED_CONF_APP_WIFI_SSID is too long %d vs. %d\n", + strlen(MBED_CONF_APP_WIFI_SSID), + WIFI_SSID_MAX_LEN); + return NULL; + } + } + + if (_password == NULL) { + if(strlen(MBED_CONF_APP_WIFI_PASSWORD) > WIFI_PASSWORD_MAX_LEN) { + printf("ERROR - MBED_CONF_APP_WIFI_PASSWORD is too long %d vs. %d\n", + strlen(MBED_CONF_APP_WIFI_PASSWORD), + WIFI_PASSWORD_MAX_LEN); + return NULL; + } + } +#endif // EASY_CONNECT_WIFI + + /// This should be removed once mbedOS supports proper dual-stack + if (log_messages) { +#if defined (EASY_CONNECT_MESH) || (MBED_CONF_LWIP_IPV6_ENABLED==true) + printf("[EasyConnect] IPv6 mode\n"); +#else + printf("[EasyConnect] IPv4 mode\n"); +#endif + } + +#if defined (EASY_CONNECT_WIFI) + if (log_messages) { + printf("[EasyConnect] Using WiFi (%s) \n", EASY_CONNECT_WIFI_TYPE); + printf("[EasyConnect] Connecting to WiFi %s\n", + ((_ssid == NULL) ? MBED_CONF_APP_WIFI_SSID : _ssid) ); + } + network_interface = &wifi; + if (_ssid == NULL) { + connect_success = wifi.connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, + (strlen(MBED_CONF_APP_WIFI_PASSWORD) > 1) ? NSAPI_SECURITY_WPA_WPA2 : NSAPI_SECURITY_NONE); + } + else { + connect_success = wifi.connect(_ssid, _password, (strlen(_password) > 1) ? NSAPI_SECURITY_WPA_WPA2 : NSAPI_SECURITY_NONE); + } +#elif MBED_CONF_APP_NETWORK_INTERFACE == CELLULAR_ONBOARD || MBED_CONF_APP_NETWORK_INTERFACE == CELLULAR +# ifdef MBED_CONF_APP_CELLULAR_SIM_PIN + cellular.set_sim_pin(MBED_CONF_APP_CELLULAR_SIM_PIN); +# endif +# ifdef MBED_CONF_APP_CELLULAR_APN +# ifndef MBED_CONF_APP_CELLULAR_USERNAME +# define MBED_CONF_APP_CELLULAR_USERNAME 0 +# endif +# ifndef MBED_CONF_APP_CELLULAR_PASSWORD +# define MBED_CONF_APP_CELLULAR_PASSWORD 0 +# endif + cellular.set_credentials(MBED_CONF_APP_CELLULAR_APN, MBED_CONF_APP_CELLULAR_USERNAME, MBED_CONF_APP_CELLULAR_PASSWORD); + if (log_messages) { + printf("[EasyConnect] Connecting using Cellular interface and APN %s\n", MBED_CONF_APP_CELLULAR_APN); + } +# else + if (log_messages) { + printf("[EasyConnect] Connecting using Cellular interface and default APN\n"); + } +# endif + connect_success = cellular.connect(); + network_interface = &cellular; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == CELLULAR_WNC14A2A + if (log_messages) { + printf("[EasyConnect] Using WNC14A2A\n"); + } +# if MBED_CONF_APP_WNC_DEBUG == true + printf("[EasyConnect] With WNC14A2A debug output set to 0x%02X\n",MBED_CONF_APP_WNC_DEBUG_SETTING); + wnc.doDebug(MBED_CONF_APP_WNC_DEBUG_SETTING); +# endif + network_interface = &wnc; + connect_success = wnc.connect(); + +#elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET + if (log_messages) { + printf("[EasyConnect] Using Ethernet\n"); + } + network_interface = ð + connect_success = eth.connect(); +#endif + +#ifdef EASY_CONNECT_MESH + if (log_messages) { + printf("[EasyConnect] Using Mesh (%s)\n", EASY_CONNECT_MESH_TYPE); + printf("[EasyConnect] Connecting to Mesh...\n"); + } + network_interface = &mesh; + mesh.initialize(&rf_phy); + connect_success = mesh.connect(); +#endif + if(connect_success == 0) { + if (log_messages) { + printf("[EasyConnect] Connected to Network successfully\n"); + print_MAC(network_interface, log_messages); + } + } else { + if (log_messages) { + print_MAC(network_interface, log_messages); + printf("[EasyConnect] Connection to Network Failed %d!\n", connect_success); + } + return NULL; + } + const char *ip_addr = network_interface->get_ip_address(); + if (ip_addr == NULL) { + if (log_messages) { + printf("[EasyConnect] ERROR - No IP address\n"); + } + return NULL; + } + + if (log_messages) { + printf("[EasyConnect] IP address %s\n", ip_addr); + } + return network_interface; +} + +/* \brief easy_connect - easy_connect function to connect the pre-defined network bearer, + * config done via mbed_app.json (see README.md for details). + * This version is just a helper version and uses the easy_connect() with + * one parameters to do it's job. + * IN: bool log_messages print out diagnostics or not. + * char* WiFiSSID WiFi SSID - pointer to WiFi SSID, but if it is NULL + * then MBED_CONF_APP_WIFI_SSID will be used + * char* WiFiPassword WiFi Password - pointer to WiFI password, but if it's NULL + * then MBED_CONF_APP_WIFI_PASSWORD will be used + */ + +NetworkInterface* easy_connect(bool log_messages, + char* WiFiSSID, + char* WiFiPassword ) { + +// This functionality only makes sense when using WiFi +#if defined (EASY_CONNECT_WIFI) + // We essentially want to populate the _ssid and _password and then call easy_connect() again. + if (WiFiSSID != NULL) { + if(strlen(WiFiSSID) > WIFI_SSID_MAX_LEN) { + printf("ERROR - WiFi SSID is too long - %d vs %d.\n", strlen(WiFiSSID), WIFI_SSID_MAX_LEN); + return NULL; + } + _ssid = WiFiSSID; + } + + if (WiFiPassword != NULL) { + if(strlen(WiFiPassword) > WIFI_PASSWORD_MAX_LEN) { + printf("ERROR - WiFi Password is too long - %d vs %d\n", strlen(WiFiPassword), WIFI_PASSWORD_MAX_LEN); + return NULL; + } + _password = WiFiPassword; + } +#endif // EASY_CONNECT_WIFI + return easy_connect(log_messages); +} + +/* \brief easy_get_netif - easy_connect function to get pointer to network interface + * without connecting to it. + * + * IN: bool log_messages print out diagnostics or not. + */ +NetworkInterface* easy_get_netif(bool log_messages) { +#if defined (EASY_CONNECT_WIFI) + if (log_messages) { + printf("[EasyConnect] WiFi: %s\n", EASY_CONNECT_WIFI_TYPE); + } + return &wifi; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET + if (log_messages) { + printf("[EasyConnect] Ethernet\n"); + } + return ð + +#elif defined (EASY_CONNECT_MESH) + if (log_messages) { + printf("[EasyConnect] Mesh : %s\n", EASY_CONNECT_MESH_TYPE); + } + return &mesh; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == CELLULAR_ONBOARD || MBED_CONF_APP_NETWORK_INTERFACE == CELLULAR + if (log_messages) { + printf("[EasyConnect] Cellular\n"); + } + return &cellular; + +#elif MBED_CONF_APP_NETWORK_INTERFACE == CELLULAR_WNC14A2A + if (log_messages) { + printf("[EasyConnect] WNC14A2A\n"); + } + return &wnc; +#endif +} + +/* \brief easy_get_wifi - easy_connect function to get pointer to Wifi interface + * without connecting to it. You would want this 1st so that + * you can scan the APNs, choose the right one and then connect. + * + * IN: bool log_messages print out diagnostics or not. + */ +WiFiInterface* easy_get_wifi(bool log_messages) { +#if defined (EASY_CONNECT_WIFI) + if (log_messages) { + printf("[EasyConnect] WiFi: %s\n", EASY_CONNECT_WIFI_TYPE); + } + return &wifi; +#else + if (log_messages) { + printf("[EasyConnect] ERROR - Wifi not in use, can not return WifiInterface.\n"); + } + return NULL; +#endif +}
diff -r 000000000000 -r 119624335925 easy-connect/easy-connect.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/easy-connect.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,122 @@ +/* + * FILE: easy-connect.h + * + * Copyright (c) 2015 - 2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __EASY_CONNECT_H__ +#define __EASY_CONNECT_H__ + +#include "mbed.h" + +#define ETHERNET 1 +#define WIFI_ESP8266 11 +#define WIFI_ODIN 12 +#define WIFI_RTW 13 +#define WIFI_IDW0XX1 14 +#define WIFI_WIZFI310 15 +#define WIFI_ISM43362 16 +#define MESH_LOWPAN_ND 101 +#define MESH_THREAD 102 +#define CELLULAR_ONBOARD 201 +#define CELLULAR 202 +#define CELLULAR_WNC14A2A 203 + +/* Define supersets for WiFi and Mesh */ + +#if MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ESP8266 +#define EASY_CONNECT_WIFI + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ODIN +#define EASY_CONNECT_WIFI + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_RTW +#define EASY_CONNECT_WIFI + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_IDW0XX1 +#define EASY_CONNECT_WIFI + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_WIZFI310 +#define EASY_CONNECT_WIFI + +#elif MBED_CONF_APP_NETWORK_INTERFACE == WIFI_ISM43362 +#define EASY_CONNECT_WIFI + +#elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_LOWPAN_ND +#define EASY_CONNECT_MESH + +#elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_THREAD +#define EASY_CONNECT_MESH +#endif // MBED_CONF_APP_NETWORK_INTERFACE + +#if defined(EASY_CONNECT_MESH) + +// Define macros for radio type +#define ATMEL 1 +#define MCR20 2 +#define SPIRIT1 3 +#define EFR32 4 + +// This is address to mbed Device Connector (hard-coded IP due to DNS might not be there) +#define MBED_SERVER_ADDRESS "coaps://[2607:f0d0:2601:52::20]:5684" + +#else +// This is address to mbed Device Connector +#define MBED_SERVER_ADDRESS "coap://api.connector.mbed.com:5684" + +#endif // (EASY_CONNECT_MESH) + +/* \brief print_MAC - print_MAC - helper function to print out MAC address + * in: network_interface - pointer to network i/f + * bool log-messages print out logs or not + * MAC address is print, if it can be acquired & log_messages is true. + * + */ +void print_MAC(NetworkInterface* network_interface, bool log_messages); + + +/* \brief easy_connect - easy_connect function to connect the pre-defined network bearer, + * config done via mbed_app.json (see README.md for details). + * IN: bool log_messages print out diagnostics or not. + */ +NetworkInterface* easy_connect(bool log_messages = false); + +/* \brief easy_connect - easy_connect function to connect the pre-defined network bearer, + * config done via mbed_app.json (see README.md for details). + * IN: bool log_messages print out diagnostics or not. + * char* WiFiSSID WiFi SSID - by default NULL, but if it's NULL + * then MBED_CONF_APP_WIFI_SSID will be used + * char* WiFiPassword WiFi Password - by default NULL, but if it's NULL + * then MBED_CONF_APP_WIFI_PASSWORD will be used + */ +NetworkInterface* easy_connect(bool log_messages, + char* WiFiSSID, + char* WiFiPassword); + +/* \brief easy_get_netif - easy_connect function to get pointer to network interface w/o connect it. + You might need this for example getting the WiFi interface, then doing a scan + and then connecting to one of the SSIDs found with a password end user supplies. + * IN: bool log_messages print out diagnostics or not. + */ + +NetworkInterface* easy_get_netif(bool log_messages); +/* \brief easy_get_wifi - easy_connect function to get pointer to Wifi interface + * without connecting to it. You would want this 1st so that + * you can scan the APNs, choose the right one and then connect. + * + * IN: bool log_messages print out diagnostics or not. + */ +WiFiInterface* easy_get_wifi(bool log_messages); + +#endif // __EASY_CONNECT_H__
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/esp8266-driver/#5a0a2cba8c125d2b74e73e209342bd169ad11bbd
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +5a0a2cba8c125d2b74e73e209342bd169ad11bbd
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +5a88ff9c75e34d65e359d7f239bacc456824ed0e
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/esp8266-driver/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/index Binary file easy-connect/esp8266-driver/.git/index has changed
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 5a88ff9c75e34d65e359d7f239bacc456824ed0e www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322703 +0000 clone: from https://github.com/ARMmbed/esp8266-driver/ +5a88ff9c75e34d65e359d7f239bacc456824ed0e 5a0a2cba8c125d2b74e73e209342bd169ad11bbd www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322704 +0000 checkout: moving from master to 5a0a2cba8c125d2b74e73e209342bd169ad11bbd
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 5a88ff9c75e34d65e359d7f239bacc456824ed0e www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322703 +0000 clone: from https://github.com/ARMmbed/esp8266-driver/
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 5a88ff9c75e34d65e359d7f239bacc456824ed0e www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322703 +0000 clone: from https://github.com/ARMmbed/esp8266-driver/
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/objects/pack/pack-aa91c59f0e6c5523ec2a15631a90bc70278fcfbc.idx Binary file easy-connect/esp8266-driver/.git/objects/pack/pack-aa91c59f0e6c5523ec2a15631a90bc70278fcfbc.idx has changed
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/objects/pack/pack-aa91c59f0e6c5523ec2a15631a90bc70278fcfbc.pack Binary file easy-connect/esp8266-driver/.git/objects/pack/pack-aa91c59f0e6c5523ec2a15631a90bc70278fcfbc.pack has changed
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,23 @@ +# pack-refs with: peeled +13c6727bb9c0b3136c2c65cfe39da2afbb24ca93 refs/remotes/origin/OobChange +4ed87bf7fe37d5ba0de6c4e78868f604a82f8ecb refs/remotes/origin/firmware-0.2 +e47620ee6560c710adba1067e8e52937c4eacf3c refs/remotes/origin/firmware-2.0 +1ae21460e1c87bef97246f6221c104cf663c38d9 refs/remotes/origin/g-connect-retries +e69ab5198be50d2dd7b094119f5267afbbff57ba refs/remotes/origin/g-custom-baud-rate +af40fb408a9f6da7b25531ecb9c565ee36ac3b16 refs/remotes/origin/g-overflow-fix +2da720a291eb5b419fa2d569e8a5c056719dccdd refs/remotes/origin/g-remove-quotes +6081f72409ab93d670d9f7c30e1bdebb39ae8ef5 refs/remotes/origin/g-testing-cleanup +63cefc73abddc2637cafb0b5785bc2ef4b8ac280 refs/remotes/origin/imsherlock +3ad8b18ef9813e9b8ddefdbe751be6c975cc5885 refs/remotes/origin/janjongboom-patch-1 +5a88ff9c75e34d65e359d7f239bacc456824ed0e refs/remotes/origin/master +d48a1b10b59a136a78b10e8625f8b3cff82670c9 refs/remotes/origin/new_at +1cd02f142135b85a04de0006c89d37c0ec00253d refs/remotes/origin/socket_clear +a38dbbaf66265199af60050cabc6618c4b530edc refs/remotes/origin/testing +549e75ccdca290de43102679b44693dba344ba2e refs/remotes/origin/use-os-gethostbyname +450cc128865ffb90b5cbfe5af193621644024fa7 refs/tags/v1.0 +29d63ae2ee0a233e2fbd9577cdddc7661bb783d1 refs/tags/v1.1 +4ed87bf7fe37d5ba0de6c4e78868f604a82f8ecb refs/tags/v1.2 +cac4d0d8f97745fe9a613b705b406646aeacc3e2 refs/tags/v1.3 +44fb447c72a37fb397a413467e02208ffeddb88e refs/tags/v1.4 +59b5304361b43a8fcea7c9637f82e1321446c9d5 refs/tags/v1.5 +^5a88ff9c75e34d65e359d7f239bacc456824ed0e
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +5a88ff9c75e34d65e359d7f239bacc456824ed0e
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/ESP8266/ESP8266.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ESP8266.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,589 @@ +/* ESP8266 Example + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ESP8266.h" +#include "mbed_debug.h" +#include "nsapi_types.h" + +#include <cstring> + +#define ESP8266_DEFAULT_BAUD_RATE 115200 + +ESP8266::ESP8266(PinName tx, PinName rx, bool debug) + : _serial(tx, rx, ESP8266_DEFAULT_BAUD_RATE), + _parser(&_serial), + _packets(0), + _packets_end(&_packets), + _connect_error(0), + _fail(false), + _socket_open() +{ + _serial.set_baud( ESP8266_DEFAULT_BAUD_RATE ); + _parser.debug_on(debug); + _parser.set_delimiter("\r\n"); + _parser.oob("+IPD", callback(this, &ESP8266::_packet_handler)); + //Note: espressif at command document says that this should be +CWJAP_CUR:<error code> + //but seems that at least current version is not sending it + //https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf + //Also seems that ERROR is not sent, but FAIL instead + _parser.oob("+CWJAP:", callback(this, &ESP8266::_connect_error_handler)); + _parser.oob("0,CLOSED", callback(this, &ESP8266::_oob_socket0_closed_handler)); + _parser.oob("1,CLOSED", callback(this, &ESP8266::_oob_socket1_closed_handler)); + _parser.oob("2,CLOSED", callback(this, &ESP8266::_oob_socket2_closed_handler)); + _parser.oob("3,CLOSED", callback(this, &ESP8266::_oob_socket3_closed_handler)); + _parser.oob("4,CLOSED", callback(this, &ESP8266::_oob_socket4_closed_handler)); +} + +int ESP8266::get_firmware_version() +{ + int version; + + _smutex.lock(); + bool done = _parser.send("AT+GMR") + && _parser.recv("SDK version:%d", &version) + && _parser.recv("OK\n"); + _smutex.unlock(); + + if(done) { + return version; + } else { + // Older firmware versions do not prefix the version with "SDK version: " + return -1; + } +} + +bool ESP8266::startup(int mode) +{ + if (!(mode == WIFIMODE_STATION || mode == WIFIMODE_SOFTAP + || mode == WIFIMODE_STATION_SOFTAP)) { + return false; + } + + _smutex.lock(); + setTimeout(ESP8266_CONNECT_TIMEOUT); + bool done = _parser.send("AT+CWMODE_CUR=%d", mode) + && _parser.recv("OK\n") + &&_parser.send("AT+CIPMUX=1") + && _parser.recv("OK\n"); + setTimeout(); //Restore default + _smutex.unlock(); + + return done; +} + +bool ESP8266::reset(void) +{ + _smutex.lock(); + setTimeout(ESP8266_CONNECT_TIMEOUT); + + for (int i = 0; i < 2; i++) { + if (_parser.send("AT+RST") + && _parser.recv("OK\n") + && _parser.recv("ready")) { + _smutex.unlock(); + return true; + } + } + setTimeout(); + _smutex.unlock(); + + return false; +} + +bool ESP8266::dhcp(bool enabled, int mode) +{ + //only 3 valid modes + if (mode < 0 || mode > 2) { + return false; + } + + _smutex.lock(); + bool done = _parser.send("AT+CWDHCP_CUR=%d,%d", mode, enabled?1:0) + && _parser.recv("OK\n"); + _smutex.unlock(); + + return done; +} + +nsapi_error_t ESP8266::connect(const char *ap, const char *passPhrase) +{ + _smutex.lock(); + setTimeout(ESP8266_CONNECT_TIMEOUT); + + _parser.send("AT+CWJAP_CUR=\"%s\",\"%s\"", ap, passPhrase); + if (!_parser.recv("OK\n")) { + if (_fail) { + _smutex.unlock(); + nsapi_error_t ret; + if (_connect_error == 1) + ret = NSAPI_ERROR_CONNECTION_TIMEOUT; + else if (_connect_error == 2) + ret = NSAPI_ERROR_AUTH_FAILURE; + else if (_connect_error == 3) + ret = NSAPI_ERROR_NO_SSID; + else + ret = NSAPI_ERROR_NO_CONNECTION; + + _fail = false; + _connect_error = 0; + return ret; + } + } + setTimeout(); + _smutex.unlock(); + + return NSAPI_ERROR_OK; +} + +bool ESP8266::disconnect(void) +{ + _smutex.lock(); + bool done = _parser.send("AT+CWQAP") && _parser.recv("OK\n"); + _smutex.unlock(); + + return done; +} + +const char *ESP8266::getIPAddress(void) +{ + _smutex.lock(); + setTimeout(ESP8266_CONNECT_TIMEOUT); + if (!(_parser.send("AT+CIFSR") + && _parser.recv("+CIFSR:STAIP,\"%15[^\"]\"", _ip_buffer) + && _parser.recv("OK\n"))) { + _smutex.unlock(); + return 0; + } + setTimeout(); + _smutex.unlock(); + + return _ip_buffer; +} + +const char *ESP8266::getMACAddress(void) +{ + _smutex.lock(); + if (!(_parser.send("AT+CIFSR") + && _parser.recv("+CIFSR:STAMAC,\"%17[^\"]\"", _mac_buffer) + && _parser.recv("OK\n"))) { + _smutex.unlock(); + return 0; + } + _smutex.unlock(); + + return _mac_buffer; +} + +const char *ESP8266::getGateway() +{ + _smutex.lock(); + if (!(_parser.send("AT+CIPSTA_CUR?") + && _parser.recv("+CIPSTA_CUR:gateway:\"%15[^\"]\"", _gateway_buffer) + && _parser.recv("OK\n"))) { + _smutex.unlock(); + return 0; + } + _smutex.unlock(); + + return _gateway_buffer; +} + +const char *ESP8266::getNetmask() +{ + _smutex.lock(); + if (!(_parser.send("AT+CIPSTA_CUR?") + && _parser.recv("+CIPSTA_CUR:netmask:\"%15[^\"]\"", _netmask_buffer) + && _parser.recv("OK\n"))) { + _smutex.unlock(); + return 0; + } + _smutex.unlock(); + + return _netmask_buffer; +} + +int8_t ESP8266::getRSSI() +{ + int8_t rssi; + char bssid[18]; + + _smutex.lock(); + setTimeout(ESP8266_CONNECT_TIMEOUT); + if (!(_parser.send("AT+CWJAP_CUR?") + && _parser.recv("+CWJAP_CUR:\"%*[^\"]\",\"%17[^\"]\"", bssid) + && _parser.recv("OK\n"))) { + _smutex.unlock(); + return 0; + } + setTimeout(); + _smutex.unlock(); + + _smutex.lock(); + setTimeout(ESP8266_CONNECT_TIMEOUT); + if (!(_parser.send("AT+CWLAP=\"\",\"%s\",", bssid) + && _parser.recv("+CWLAP:(%*d,\"%*[^\"]\",%hhd,", &rssi) + && _parser.recv("OK\n"))) { + _smutex.unlock(); + return 0; + } + setTimeout(); + _smutex.unlock(); + + return rssi; +} + +int ESP8266::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned cnt = 0; + nsapi_wifi_ap_t ap; + + _smutex.lock(); + setTimeout(ESP8266_CONNECT_TIMEOUT); + + if (!_parser.send("AT+CWLAP")) { + _smutex.unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + + while (recv_ap(&ap)) { + if (cnt < limit) { + res[cnt] = WiFiAccessPoint(ap); + } + + cnt++; + if (limit != 0 && cnt >= limit) { + break; + } + } + setTimeout(); + _smutex.unlock(); + + return cnt; +} + +bool ESP8266::open_udp(int id, const char* addr, int port, int local_port) +{ + static const char *type = "UDP"; + bool done = false; + + if (id >= SOCKET_COUNT || _socket_open[id]) { + return false; + } + + _smutex.lock(); + if(local_port) { + done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, local_port) + && _parser.recv("OK\n"); + } else { + done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port) + && _parser.recv("OK\n"); + } + + if (done) { + _socket_open[id] = 1; + } + + _smutex.unlock(); + + return done; +} + +bool ESP8266::open_tcp(int id, const char* addr, int port, int keepalive) +{ + static const char *type = "TCP"; + bool done = false; + + if (id >= SOCKET_COUNT || _socket_open[id]) { + return false; + } + + _smutex.lock(); + if(keepalive) { + done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, keepalive) + && _parser.recv("OK\n"); + } else { + done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port) + && _parser.recv("OK\n"); + } + + if (done) { + _socket_open[id] = 1; + } + + _smutex.unlock(); + + return done; +} + +bool ESP8266::dns_lookup(const char* name, char* ip) +{ + _smutex.lock(); + bool done = _parser.send("AT+CIPDOMAIN=\"%s\"", name) && _parser.recv("+CIPDOMAIN:%s%*[\r]%*[\n]", ip); + _smutex.unlock(); + + return done; +} + +nsapi_error_t ESP8266::send(int id, const void *data, uint32_t amount) +{ + //May take a second try if device is busy + for (unsigned i = 0; i < 2; i++) { + _smutex.lock(); + setTimeout(ESP8266_SEND_TIMEOUT); + if (_parser.send("AT+CIPSEND=%d,%lu", id, amount) + && _parser.recv(">") + && _parser.write((char*)data, (int)amount) >= 0) { + while (_parser.process_oob()); // multiple sends in a row require this + _smutex.unlock(); + return NSAPI_ERROR_OK; + } + setTimeout(); + _smutex.unlock(); + } + + return NSAPI_ERROR_DEVICE_ERROR; +} + +void ESP8266::_packet_handler() +{ + int id; + int amount; + + // parse out the packet + if (!_parser.recv(",%d,%d:", &id, &amount)) { + return; + } + + struct packet *packet = (struct packet*)malloc( + sizeof(struct packet) + amount); + if (!packet) { + debug("Could not allocate memory for RX data\n"); + return; + } + + packet->id = id; + packet->len = amount; + packet->next = 0; + + if (_parser.read((char*)(packet + 1), amount) < amount) { + free(packet); + return; + } + + // append to packet list + *_packets_end = packet; + _packets_end = &packet->next; +} + +int32_t ESP8266::recv_tcp(int id, void *data, uint32_t amount) +{ + _smutex.lock(); + setTimeout(ESP8266_RECV_TIMEOUT); + + // Poll for inbound packets + while (_parser.process_oob()) { + } + + setTimeout(); + + // check if any packets are ready for us + for (struct packet **p = &_packets; *p; p = &(*p)->next) { + if ((*p)->id == id) { + struct packet *q = *p; + + if (q->len <= amount) { // Return and remove full packet + memcpy(data, q+1, q->len); + + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + _smutex.unlock(); + + uint32_t len = q->len; + free(q); + return len; + } else { // return only partial packet + memcpy(data, q+1, amount); + + q->len -= amount; + memmove(q+1, (uint8_t*)(q+1) + amount, q->len); + + _smutex.unlock(); + return amount; + } + } + } + if(!_socket_open[id]) { + _smutex.unlock(); + return 0; + } + _smutex.unlock(); + + return NSAPI_ERROR_WOULD_BLOCK; +} + +int32_t ESP8266::recv_udp(int id, void *data, uint32_t amount) +{ + _smutex.lock(); + setTimeout(ESP8266_RECV_TIMEOUT); + + // Poll for inbound packets + while (_parser.process_oob()) { + } + + setTimeout(); + + // check if any packets are ready for us + for (struct packet **p = &_packets; *p; p = &(*p)->next) { + if ((*p)->id == id) { + struct packet *q = *p; + + // Return and remove packet (truncated if necessary) + uint32_t len = q->len < amount ? q->len : amount; + memcpy(data, q+1, len); + + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + _smutex.unlock(); + + free(q); + return len; + } + } + _smutex.unlock(); + + return NSAPI_ERROR_WOULD_BLOCK; +} + +bool ESP8266::close(int id) +{ + //May take a second try if device is busy + for (unsigned i = 0; i < 2; i++) { + _smutex.lock(); + if (_parser.send("AT+CIPCLOSE=%d", id) && _parser.recv("OK\n")) { + if (!_socket_open[id]) { // recv(processing OOBs) needs to be done first + _smutex.unlock(); + return true; + } + } + _smutex.unlock(); + } + + return false; +} + +void ESP8266::setTimeout(uint32_t timeout_ms) +{ + _parser.set_timeout(timeout_ms); +} + +bool ESP8266::readable() +{ + return _serial.FileHandle::readable(); +} + +bool ESP8266::writeable() +{ + return _serial.FileHandle::writable(); +} + +void ESP8266::attach(Callback<void()> func) +{ + _serial.sigio(func); +} + +bool ESP8266::recv_ap(nsapi_wifi_ap_t *ap) +{ + int sec; + int dummy; + bool ret = _parser.recv("+CWLAP:(%d,\"%32[^\"]\",%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",%hhu,%d,%d)\n", + &sec, + ap->ssid, + &ap->rssi, + &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], &ap->bssid[5], + &ap->channel, + &dummy, + &dummy); + + ap->security = sec < 5 ? (nsapi_security_t)sec : NSAPI_SECURITY_UNKNOWN; + + return ret; +} + +void ESP8266::_connect_error_handler() +{ + _fail = false; + _connect_error = 0; + + if (_parser.recv("%d", &_connect_error) && _parser.recv("FAIL")) { + _fail = true; + _parser.abort(); + } +} + +void ESP8266::_oob_socket0_closed_handler() +{ + _socket_open[0] = 0; +} + +void ESP8266::_oob_socket1_closed_handler() +{ + _socket_open[1] = 0; +} + +void ESP8266::_oob_socket2_closed_handler() +{ + _socket_open[2] = 0; +} + +void ESP8266::_oob_socket3_closed_handler() +{ + _socket_open[3] = 0; +} + +void ESP8266::_oob_socket4_closed_handler() +{ + _socket_open[4] = 0; +} + +int8_t ESP8266::get_default_wifi_mode() +{ + int8_t mode; + + _smutex.lock(); + if (_parser.send("AT+CWMODE_DEF?") + && _parser.recv("+CWMODE_DEF:%hhd", &mode) + && _parser.recv("OK\n")) { + _smutex.unlock(); + return mode; + } + _smutex.unlock(); + + return 0; +} + +bool ESP8266::set_default_wifi_mode(const int8_t mode) +{ + _smutex.lock(); + bool done = _parser.send("AT+CWMODE_DEF=%hhd", mode) + && _parser.recv("OK\n"); + _smutex.unlock(); + + return done; +}
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/ESP8266/ESP8266.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266/ESP8266.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,291 @@ +/* ESP8266Interface Example + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ESP8266_H +#define ESP8266_H + +#include "ATCmdParser.h" +#include "nsapi_types.h" +#include "rtos.h" + +// Various timeouts for different ESP8266 operations +#ifndef ESP8266_CONNECT_TIMEOUT +#define ESP8266_CONNECT_TIMEOUT 15000 +#endif +#ifndef ESP8266_SEND_TIMEOUT +#define ESP8266_SEND_TIMEOUT 500 +#endif +#ifndef ESP8266_RECV_TIMEOUT +#define ESP8266_RECV_TIMEOUT 500 +#endif +#ifndef ESP8266_MISC_TIMEOUT +#define ESP8266_MISC_TIMEOUT 500 +#endif + +/** ESP8266Interface class. + This is an interface to a ESP8266 radio. + */ +class ESP8266 +{ +public: + ESP8266(PinName tx, PinName rx, bool debug=false); + + /** + * Check firmware version of ESP8266 + * + * @return integer firmware version or -1 if firmware query command gives outdated response + */ + int get_firmware_version(void); + + /** + * Startup the ESP8266 + * + * @param mode mode of WIFI 1-client, 2-host, 3-both + * @return true only if ESP8266 was setup correctly + */ + bool startup(int mode); + + /** + * Reset ESP8266 + * + * @return true only if ESP8266 resets successfully + */ + bool reset(void); + + /** + * Enable/Disable DHCP + * + * @param enabled DHCP enabled when true + * @param mode mode of DHCP 0-softAP, 1-station, 2-both + * @return true only if ESP8266 enables/disables DHCP successfully + */ + bool dhcp(bool enabled, int mode); + + /** + * Connect ESP8266 to AP + * + * @param ap the name of the AP + * @param passPhrase the password of AP + * @return NSAPI_ERROR_OK only if ESP8266 is connected successfully + */ + nsapi_error_t connect(const char *ap, const char *passPhrase); + + /** + * Disconnect ESP8266 from AP + * + * @return true only if ESP8266 is disconnected successfully + */ + bool disconnect(void); + + /** + * Get the IP address of ESP8266 + * + * @return null-teriminated IP address or null if no IP address is assigned + */ + const char *getIPAddress(void); + + /** + * Get the MAC address of ESP8266 + * + * @return null-terminated MAC address or null if no MAC address is assigned + */ + const char *getMACAddress(void); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been recieved + */ + const char *getGateway(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been recieved + */ + const char *getNetmask(); + + /* Return RSSI for active connection + * + * @return Measured RSSI + */ + int8_t getRSSI(); + + /** Scan for available networks + * + * @param ap Pointer to allocated array to store discovered AP + * @param limit Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + int scan(WiFiAccessPoint *res, unsigned limit); + + /**Perform a dns query + * + * @param name Hostname to resolve + * @param ip Buffer to store IP address + * @return 0 true on success, false on failure + */ + bool dns_lookup(const char *name, char *ip); + + /** + * Open a socketed connection + * + * @param type the type of socket to open "UDP" or "TCP" + * @param id id to give the new socket, valid 0-4 + * @param port port to open connection with + * @param addr the IP address of the destination + * @param port the port on the destination + * @param local_port UDP socket's local port, zero means any + * @return true only if socket opened successfully + */ + bool open_udp(int id, const char* addr, int port, int local_port = 0); + + /** + * Open a socketed connection + * + * @param type the type of socket to open "UDP" or "TCP" + * @param id id to give the new socket, valid 0-4 + * @param port port to open connection with + * @param addr the IP address of the destination + * @param port the port on the destination + * @param tcp_keepalive TCP connection's keep alive time, zero means disabled + * @return true only if socket opened successfully + */ + bool open_tcp(int id, const char* addr, int port, int keepalive = 0); + + /** + * Sends data to an open socket + * + * @param id id of socket to send to + * @param data data to be sent + * @param amount amount of data to be sent - max 1024 + * @return NSAPI_ERROR_OK in success, negative error code in failure + */ + nsapi_error_t send(int id, const void *data, uint32_t amount); + + /** + * Receives datagram from an open UDP socket + * + * @param id id to receive from + * @param data placeholder for returned information + * @param amount number of bytes to be received + * @return the number of bytes received + */ + int32_t recv_udp(int id, void *data, uint32_t amount); + + /** + * Receives stream data from an open TCP socket + * + * @param id id to receive from + * @param data placeholder for returned information + * @param amount number of bytes to be received + * @return the number of bytes received + */ + int32_t recv_tcp(int id, void *data, uint32_t amount); + + /** + * Closes a socket + * + * @param id id of socket to close, valid only 0-4 + * @return true only if socket is closed successfully + */ + bool close(int id); + + /** + * Allows timeout to be changed between commands + * + * @param timeout_ms timeout of the connection + */ + void setTimeout(uint32_t timeout_ms=ESP8266_MISC_TIMEOUT); + + /** + * Checks if data is available + */ + bool readable(); + + /** + * Checks if data can be written + */ + bool writeable(); + + /** + * Attach a function to call whenever network state has changed + * + * @param func A pointer to a void function, or 0 to set as none + */ + void attach(Callback<void()> func); + + /** + * Attach a function to call whenever network state has changed + * + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to call + */ + template <typename T, typename M> + void attach(T *obj, M method) { + attach(Callback<void()>(obj, method)); + } + + /** + * Read default Wifi mode from flash + * + * return Station, SoftAP or SoftAP+Station - 0 on failure + */ + int8_t get_default_wifi_mode(); + + /** + * Write default Wifi mode to flash + */ + bool set_default_wifi_mode(const int8_t mode); + + static const int8_t WIFIMODE_STATION = 1; + static const int8_t WIFIMODE_SOFTAP = 2; + static const int8_t WIFIMODE_STATION_SOFTAP = 3; + static const int8_t SOCKET_COUNT = 5; + +private: + UARTSerial _serial; + ATCmdParser _parser; + Mutex _smutex; // Protect serial port access + + struct packet { + struct packet *next; + int id; + uint32_t len; + // data follows + } *_packets, **_packets_end; + void _packet_handler(); + void _connect_error_handler(); + bool recv_ap(nsapi_wifi_ap_t *ap); + void _oob_socket0_closed_handler(); + void _oob_socket1_closed_handler(); + void _oob_socket2_closed_handler(); + void _oob_socket3_closed_handler(); + void _oob_socket4_closed_handler(); + + + char _ip_buffer[16]; + char _gateway_buffer[16]; + char _netmask_buffer[16]; + char _mac_buffer[18]; + + int _connect_error; + bool _fail; + int _socket_open[SOCKET_COUNT]; +}; + +#endif
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/ESP8266Interface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266Interface.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,499 @@ +/* ESP8266 implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cstring> +#include "ESP8266.h" +#include "ESP8266Interface.h" +#include "mbed_debug.h" +#include "nsapi_types.h" + + +// Firmware version +#define ESP8266_VERSION 2 + +// ESP8266Interface implementation +ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug) + : _esp(tx, rx, debug), + _initialized(false), + _started(false) +{ + memset(_ids, 0, sizeof(_ids)); + memset(_cbs, 0, sizeof(_cbs)); + memset(ap_ssid, 0, sizeof(ap_ssid)); + memset(ap_pass, 0, sizeof(ap_pass)); + memset(_local_ports, 0, sizeof(_local_ports)); + ap_sec = NSAPI_SECURITY_UNKNOWN; + + _esp.attach(this, &ESP8266Interface::event); + _esp.setTimeout(); +} + +int ESP8266Interface::connect(const char *ssid, const char *pass, nsapi_security_t security, + uint8_t channel) +{ + if (channel != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + + int err = set_credentials(ssid, pass, security); + if(err) { + return err; + } + + return connect(); +} + +int ESP8266Interface::connect() +{ + nsapi_error_t status; + + if (strlen(ap_ssid) == 0) { + return NSAPI_ERROR_NO_SSID; + } + + if (ap_sec != NSAPI_SECURITY_NONE) { + if (strlen(ap_pass) < ESP8266_PASSPHRASE_MIN_LENGTH) { + return NSAPI_ERROR_PARAMETER; + } + } + + status = _init(); + if(status != NSAPI_ERROR_OK) { + return status; + } + + if(get_ip_address()) { + return NSAPI_ERROR_IS_CONNECTED; + } + + status = _startup(ESP8266::WIFIMODE_STATION); + if(status != NSAPI_ERROR_OK) { + return status; + } + _started = true; + + if (!_esp.dhcp(true, 1)) { + return NSAPI_ERROR_DHCP_FAILURE; + } + + int connect_error = _esp.connect(ap_ssid, ap_pass); + if (connect_error) { + return connect_error; + } + + if (!get_ip_address()) { + return NSAPI_ERROR_DHCP_FAILURE; + } + + return NSAPI_ERROR_OK; +} + +int ESP8266Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + ap_sec = security; + + if (!ssid) { + return NSAPI_ERROR_PARAMETER; + } + + int ssid_length = strlen(ssid); + + if (ssid_length > 0 + && ssid_length <= ESP8266_SSID_MAX_LENGTH) { + memset(ap_ssid, 0, sizeof(ap_ssid)); + strncpy(ap_ssid, ssid, sizeof(ap_ssid)); + } else { + return NSAPI_ERROR_PARAMETER; + } + + if (ap_sec != NSAPI_SECURITY_NONE) { + + if (!pass) { + return NSAPI_ERROR_PARAMETER; + } + + int pass_length = strlen(pass); + if (pass_length >= ESP8266_PASSPHRASE_MIN_LENGTH + && pass_length <= ESP8266_PASSPHRASE_MAX_LENGTH ) { + memset(ap_pass, 0, sizeof(ap_pass)); + strncpy(ap_pass, pass, sizeof(ap_pass)); + } else { + return NSAPI_ERROR_PARAMETER; + } + } else { + memset(ap_pass, 0, sizeof(ap_pass)); + } + + return NSAPI_ERROR_OK; +} + +int ESP8266Interface::set_channel(uint8_t channel) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + + +int ESP8266Interface::disconnect() +{ + _started = false; + _initialized = false; + + return _esp.disconnect() ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR; +} + +const char *ESP8266Interface::get_ip_address() +{ + if(!_started) { + return NULL; + } + + const char *ip_buff = _esp.getIPAddress(); + if(!ip_buff || std::strcmp(ip_buff, "0.0.0.0") == 0) { + return NULL; + } + + return ip_buff; +} + +const char *ESP8266Interface::get_mac_address() +{ + return _esp.getMACAddress(); +} + +const char *ESP8266Interface::get_gateway() +{ + return _started ? _esp.getGateway() : NULL; +} + +const char *ESP8266Interface::get_netmask() +{ + return _started ? _esp.getNetmask() : NULL; +} + +int8_t ESP8266Interface::get_rssi() +{ + return _started ? _esp.getRSSI() : 0; +} + +int ESP8266Interface::scan(WiFiAccessPoint *res, unsigned count) +{ + nsapi_error_t status; + + status = _init(); + if(status != NSAPI_ERROR_OK) { + return status; + } + + status = _startup(ESP8266::WIFIMODE_STATION); + if(status != NSAPI_ERROR_OK) { + return status; + } + + return _esp.scan(res, count); +} + +bool ESP8266Interface::_get_firmware_ok() +{ + if (_esp.get_firmware_version() != ESP8266_VERSION) { + debug("ESP8266: ERROR: Firmware incompatible with this driver.\ + \r\nUpdate to v%d - https://developer.mbed.org/teams/ESP8266/wiki/Firmware-Update\r\n",ESP8266_VERSION); + return false; + } + + return true; +} + +bool ESP8266Interface::_disable_default_softap() +{ + static int disabled = false; + + if (disabled || _esp.get_default_wifi_mode() == ESP8266::WIFIMODE_STATION) { + disabled = true; + return true; + } + if (_esp.set_default_wifi_mode(ESP8266::WIFIMODE_STATION)) { + disabled = true; + return true; + } + + return false; +} + +nsapi_error_t ESP8266Interface::_init(void) +{ + if (!_initialized) { + if (!_esp.reset()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + if (!_get_firmware_ok()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + if (_disable_default_softap() == false) { + return NSAPI_ERROR_DEVICE_ERROR; + } + _initialized = true; + } + return NSAPI_ERROR_OK; +} + +nsapi_error_t ESP8266Interface::_startup(const int8_t wifi_mode) +{ + if (!_started) { + if (!_esp.startup(wifi_mode)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } + return NSAPI_ERROR_OK; +} + +struct esp8266_socket { + int id; + nsapi_protocol_t proto; + bool connected; + SocketAddress addr; + int keepalive; // TCP +}; + +int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto) +{ + // Look for an unused socket + int id = -1; + + for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) { + if (!_ids[i]) { + id = i; + _ids[i] = true; + break; + } + } + + if (id == -1) { + return NSAPI_ERROR_NO_SOCKET; + } + + struct esp8266_socket *socket = new struct esp8266_socket; + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + socket->id = id; + socket->proto = proto; + socket->connected = false; + socket->keepalive = 0; + *handle = socket; + return 0; +} + +int ESP8266Interface::socket_close(void *handle) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + int err = 0; + + if (socket->connected && !_esp.close(socket->id)) { + err = NSAPI_ERROR_DEVICE_ERROR; + } + + socket->connected = false; + _ids[socket->id] = false; + _local_ports[socket->id] = 0; + delete socket; + return err; +} + +int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + + if (socket->proto == NSAPI_UDP) { + if(address.get_addr().version != NSAPI_UNSPEC) { + return NSAPI_ERROR_UNSUPPORTED; + } + + for(int id = 0; id < ESP8266_SOCKET_COUNT; id++) { + if(_local_ports[id] == address.get_port() && id != socket->id) { // Port already reserved by another socket + return NSAPI_ERROR_PARAMETER; + } else if (id == socket->id && socket->connected) { + return NSAPI_ERROR_PARAMETER; + } + } + _local_ports[socket->id] = address.get_port(); + return 0; + } + + return NSAPI_ERROR_UNSUPPORTED; +} + +int ESP8266Interface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + + if (socket->proto == NSAPI_UDP) { + if (!_esp.open_udp(socket->id, addr.get_ip_address(), addr.get_port(), _local_ports[socket->id])) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } else { + if (!_esp.open_tcp(socket->id, addr.get_ip_address(), addr.get_port(), socket->keepalive)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } + + socket->connected = true; + return 0; +} + +int ESP8266Interface::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ESP8266Interface::socket_send(void *handle, const void *data, unsigned size) +{ + nsapi_error_t status; + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + + status = _esp.send(socket->id, data, size); + + return status != NSAPI_ERROR_OK ? status : size; +} + +int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + + int32_t recv; + if (socket->proto == NSAPI_TCP) { + recv = _esp.recv_tcp(socket->id, data, size); + if (recv <= 0 && recv != NSAPI_ERROR_WOULD_BLOCK) { + socket->connected = false; + } + } else { + recv = _esp.recv_udp(socket->id, data, size); + } + + return recv; +} + +int ESP8266Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + + if((strcmp(addr.get_ip_address(), "0.0.0.0") == 0) || !addr.get_port()) { + return NSAPI_ERROR_DNS_FAILURE; + } + + if (socket->connected && socket->addr != addr) { + if (!_esp.close(socket->id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + socket->connected = false; + } + + if (!socket->connected) { + int err = socket_connect(socket, addr); + if (err < 0) { + return err; + } + socket->addr = addr; + } + + return socket_send(socket, data, size); +} + +int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + int ret = socket_recv(socket, data, size); + if (ret >= 0 && addr) { + *addr = socket->addr; + } + + return ret; +} + +void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), void *data) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + _cbs[socket->id].callback = callback; + _cbs[socket->id].data = data; +} + +nsapi_error_t ESP8266Interface::setsockopt(nsapi_socket_t handle, int level, + int optname, const void *optval, unsigned optlen) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + + if (!optlen || !socket) { + return NSAPI_ERROR_PARAMETER; + } + + if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) { + switch (optname) { + case NSAPI_KEEPALIVE: { + if(socket->connected) {// ESP8266 limitation, keepalive needs to be given before connecting + return NSAPI_ERROR_UNSUPPORTED; + } + + if (optlen == sizeof(int)) { + int secs = *(int *)optval; + if (secs >= 0 && secs <= 7200) { + socket->keepalive = secs; + return NSAPI_ERROR_OK; + } + } + return NSAPI_ERROR_PARAMETER; + } + } + } + + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t ESP8266Interface::getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen) +{ + struct esp8266_socket *socket = (struct esp8266_socket *)handle; + + if (!optval || !optlen || !socket) { + return NSAPI_ERROR_PARAMETER; + } + + if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) { + switch (optname) { + case NSAPI_KEEPALIVE: { + if(*optlen > sizeof(int)) { + *optlen = sizeof(int); + } + memcpy(optval, &(socket->keepalive), *optlen); + return NSAPI_ERROR_OK; + } + } + } + + return NSAPI_ERROR_UNSUPPORTED; +} + + +void ESP8266Interface::event() { + for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) { + if (_cbs[i].callback) { + _cbs[i].callback(_cbs[i].data); + } + } +}
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/ESP8266Interface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/ESP8266Interface.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,320 @@ +/* ESP8266 implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ESP8266_INTERFACE_H +#define ESP8266_INTERFACE_H + +#include "mbed.h" +#include "ESP8266.h" + + +#define ESP8266_SOCKET_COUNT 5 + +/** ESP8266Interface class + * Implementation of the NetworkStack for the ESP8266 + */ +class ESP8266Interface : public NetworkStack, public WiFiInterface +{ +public: + /** ESP8266Interface lifetime + * @param tx TX pin + * @param rx RX pin + * @param debug Enable debugging + */ + ESP8266Interface(PinName tx, PinName rx, bool debug = false); + + /** Start the interface + * + * Attempts to connect to a WiFi network. Requires ssid and passphrase to be set. + * If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned. + * + * @return 0 on success, negative error code on failure + */ + virtual int connect(); + + /** Start the interface + * + * Attempts to connect to a WiFi network. + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE) + * @param channel This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED + * @return 0 on success, or error code on failure + */ + virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE, + uint8_t channel = 0); + + /** Set the WiFi network credentials + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection + * (defaults to NSAPI_SECURITY_NONE) + * @return 0 on success, or error code on failure + */ + virtual int set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE); + + /** Set the WiFi network channel - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0) + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual int set_channel(uint8_t channel); + + /** Stop the interface + * @return 0 on success, negative on failure + */ + virtual int disconnect(); + + /** Get the internally stored IP address + * @return IP address of the interface or null if not yet connected + */ + virtual const char *get_ip_address(); + + /** Get the internally stored MAC address + * @return MAC address of the interface + */ + virtual const char *get_mac_address(); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been recieved + */ + virtual const char *get_gateway(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been recieved + */ + virtual const char *get_netmask(); + + /** Gets the current radio signal strength for active connection + * + * @return Connection strength in dBm (negative value) + */ + virtual int8_t get_rssi(); + + /** Scan for available networks + * + * This function will block. + * + * @param ap Pointer to allocated array to store discovered AP + * @param count Size of allocated @a res array, or 0 to only count available AP + * @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0) + * @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + virtual int scan(WiFiAccessPoint *res, unsigned count); + + /** Translates a hostname to an IP address with specific version + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * + * @param address Destination for the host SocketAddress + * @param host Hostname to resolve + * @param version IP version of address to resolve, NSAPI_UNSPEC indicates + * version is chosen by the stack (defaults to NSAPI_UNSPEC) + * @return 0 on success, negative error code on failure + */ + using NetworkInterface::gethostbyname; + + /** Add a domain name server to list of servers to query + * + * @param addr Destination for the host address + * @return 0 on success, negative error code on failure + */ + using NetworkInterface::add_dns_server; + + /* Set socket options + * + * The setsockopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. + * + * @param handle Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level, + int optname, const void *optval, unsigned optlen); + + /* Get socket options + * + * getsockopt allows an application to retrieve stack-specific options + * from the underlying stack using stack-specific level and option names, + * or to request generic options using levels from nsapi_socket_level_t. + * + * For unsupported options, NSAPI_ERROR_UNSUPPORTED is returned + * and the socket is unmodified. + * + * @param level Stack-specific protocol level or nsapi_socket_level_t + * @param optname Level-specific option name + * @param optval Destination for option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level, int optname, + void *optval, unsigned *optlen); + +protected: + /** Open a socket + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure + */ + virtual int socket_open(void **handle, nsapi_protocol_t proto); + + /** Close the socket + * @param handle Socket handle + * @return 0 on success, negative on failure + * @note On failure, any memory associated with the socket must still + * be cleaned up + */ + virtual int socket_close(void *handle); + + /** Bind a server socket to a specific port + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + virtual int socket_bind(void *handle, const SocketAddress &address); + + /** Start listening for incoming connections + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return 0 on success, negative on failure + */ + virtual int socket_listen(void *handle, int backlog); + + /** Connects this TCP socket to the server + * @param handle Socket handle + * @param address SocketAddress to connect to + * @return 0 on success, negative on failure + */ + virtual int socket_connect(void *handle, const SocketAddress &address); + + /** Accept a new connection. + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return 0 on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_accept(void *handle, void **socket, SocketAddress *address); + + /** Send data to the remote host + * @param handle Socket handle + * @param data The buffer to send to the host + * @param size The length of the buffer to send + * @return Number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_send(void *handle, const void *data, unsigned size); + + /** Receive data from the remote host + * @param handle Socket handle + * @param data The buffer in which to store the data received from the host + * @param size The maximum length of the buffer + * @return Number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_recv(void *handle, void *data, unsigned size); + + /** Send a packet to a remote endpoint + * @param handle Socket handle + * @param address The remote SocketAddress + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return The number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size); + + /** Receive a packet from a remote endpoint + * @param handle Socket handle + * @param address Destination for the remote SocketAddress or null + * @param buffer The buffer for storing the incoming packet data + * If a packet is too long to fit in the supplied buffer, + * excess bytes are discarded + * @param size The length of the buffer + * @return The number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); + + /** Register a callback on state change of the socket + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + * @note Callback may be called in an interrupt context. + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); + + /** Provide access to the NetworkStack object + * + * @return The underlying NetworkStack object + */ + virtual NetworkStack *get_stack() + { + return this; + } + +private: + static const int ESP8266_SSID_MAX_LENGTH = 32; /* 32 is what 802.11 defines as longest possible name */ + static const int ESP8266_PASSPHRASE_MAX_LENGTH = 63; /* The longest allowed passphrase */ + static const int ESP8266_PASSPHRASE_MIN_LENGTH = 8; /* The shortest allowed passphrase */ + + ESP8266 _esp; + bool _ids[ESP8266_SOCKET_COUNT]; + int _initialized; + int _started; + + char ap_ssid[ESP8266_SSID_MAX_LENGTH + 1]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */ + nsapi_security_t ap_sec; + uint8_t ap_ch; + char ap_pass[ESP8266_PASSPHRASE_MAX_LENGTH + 1]; + uint16_t _local_ports[ESP8266_SOCKET_COUNT]; + + bool _disable_default_softap(); + void event(); + bool _get_firmware_ok(); + nsapi_error_t _init(void); + nsapi_error_t _startup(const int8_t wifi_mode); + + struct { + void (*callback)(void *); + void *data; + } _cbs[ESP8266_SOCKET_COUNT]; +}; + +#endif
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,10 @@ +# The ESP8266 WiFi driver for mbed-os +The mbed OS driver for the ESP8266 WiFi module + +## Firmware version +ESP8266 modules come in different shapes and forms, but most important difference is which firmware version it is programmed with. To make sure that your module has mbed-os compatible firmware follow update guide: https://developer.mbed.org/teams/ESP8266/wiki/Firmware-Update + +## Restrictions +- The ESP8266 WiFi module does not allow TCP client to bind on a specific port +- Setting up an UDP server is not possible +- Serial port does not have hardware flow control enabled. Also AT-command set does not have any way to limit download rate. Therefore downloading anything larger that serial port input buffer is unreliable. Application should be able to read fast enough to stay ahead of the network. This affects mostly the TCP protocol where data would be lost with no notification. On UDP this would lead to only packet losses which the higher layer protocol should recover from.
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +host_tests/* \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/connectivity/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/connectivity/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,76 @@ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" + +#include "ESP8266Interface.h" + +using namespace utest::v1; + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Bringing the network up and down +template <int COUNT> +void test_bring_up_down() { + ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); + net.set_credentials(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + + for (int i = 0; i < COUNT; i++) { + int err = net.connect(); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: IP Address %s\r\n", net.get_ip_address()); + printf("MBED: Netmask %s\r\n", net.get_netmask()); + printf("MBED: Gateway %s\r\n", net.get_gateway()); + TEST_ASSERT(net.get_ip_address()); + TEST_ASSERT(net.get_netmask()); + TEST_ASSERT(net.get_gateway()); + + UDPSocket udp; + err = udp.open(&net); + TEST_ASSERT_EQUAL(0, err); + err = udp.close(); + TEST_ASSERT_EQUAL(0, err); + + TCPSocket tcp; + err = tcp.open(&net); + TEST_ASSERT_EQUAL(0, err); + err = tcp.close(); + TEST_ASSERT_EQUAL(0, err); + + err = net.disconnect(); + TEST_ASSERT_EQUAL(0, err); + } +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Bringing the network up and down", test_bring_up_down<1>), + Case("Bringing the network up and down twice", test_bring_up_down<2>), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/gethostbyname/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/gethostbyname/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,118 @@ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include "ESP8266Interface.h" + +using namespace utest::v1; + +// Hostname for testing against +// Must have A and AAAA records +#ifndef MBED_DNS_TEST_HOST +#define MBED_DNS_TEST_HOST "connector.mbed.com" +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + +// Address info from stack +const char *ip_literal; +nsapi_version_t ip_pref; +const char *ip_pref_repr; + +// Network setup +ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); +void net_bringup() { + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + printf("MBED: Connected to network\n"); + printf("MBED: IP Address: %s\n", net.get_ip_address()); + + ip_literal = net.get_ip_address(); + ip_pref = SocketAddress(ip_literal).get_ip_version(); + ip_pref_repr = (ip_pref == NSAPI_IPv4) ? "ipv4" : + (ip_pref == NSAPI_IPv6) ? "ipv6" : "unspec"; +} + + +// DNS tests +void test_dns_query() { + SocketAddress addr; + int err = net.gethostbyname(MBED_DNS_TEST_HOST, &addr); + printf("DNS: query \"%s\" => \"%s\"\n", + MBED_DNS_TEST_HOST, addr.get_ip_address()); + + TEST_ASSERT_EQUAL(0, err); + TEST_ASSERT((bool)addr); + TEST_ASSERT(strlen(addr.get_ip_address()) > 1); +} + +void test_dns_query_pref() { + SocketAddress addr; + int err = net.gethostbyname(MBED_DNS_TEST_HOST, &addr, ip_pref); + printf("DNS: query %s \"%s\" => \"%s\"\n", + ip_pref_repr, MBED_DNS_TEST_HOST, addr.get_ip_address()); + + TEST_ASSERT_EQUAL(0, err); + TEST_ASSERT((bool)addr); + TEST_ASSERT(strlen(addr.get_ip_address()) > 1); + TEST_ASSERT_EQUAL(ip_pref, addr.get_ip_version()); +} + +void test_dns_literal() { + SocketAddress addr; + int err = net.gethostbyname(ip_literal, &addr); + printf("DNS: literal \"%s\" => \"%s\"\n", + ip_literal, addr.get_ip_address()); + + TEST_ASSERT_EQUAL(0, err); + TEST_ASSERT((bool)addr); + TEST_ASSERT(strlen(addr.get_ip_address()) > 1); + TEST_ASSERT(strcmp(ip_literal, addr.get_ip_address()) == 0); +} + +void test_dns_literal_pref() { + SocketAddress addr; + int err = net.gethostbyname(ip_literal, &addr, ip_pref); + printf("DNS: literal %s \"%s\" => \"%s\"\n", + ip_pref_repr, ip_literal, addr.get_ip_address()); + + TEST_ASSERT_EQUAL(0, err); + TEST_ASSERT((bool)addr); + TEST_ASSERT(strlen(addr.get_ip_address()) > 1); + TEST_ASSERT_EQUAL(ip_pref, addr.get_ip_version()); + TEST_ASSERT(strcmp(ip_literal, addr.get_ip_address()) == 0); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "default_auto"); + net_bringup(); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("DNS query", test_dns_query), + Case("DNS preference query", test_dns_query_pref), + Case("DNS literal", test_dns_literal), + Case("DNS preference literal", test_dns_literal_pref), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/host_tests/tcp_echo.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/host_tests/tcp_echo.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,195 @@ +# Copyright 2015 ARM Limited, All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import select +import socket +import logging +from threading import Thread +from sys import stdout +from SocketServer import BaseRequestHandler, TCPServer +from mbed_host_tests import BaseHostTest, event_callback + + +class TCPEchoClientHandler(BaseRequestHandler): + def handle(self): + """ + Handles a connection. Test starts by client(i.e. mbed) connecting to server. + This connection handler receives data and echoes back to the client util + {{end}} is received. Then it sits on recv() for client to terminate the + connection. + + Note: reason for not echoing data back after receiving {{end}} is that send + fails raising a SocketError as client closes connection. + """ + while self.server.isrunning(): + try: + data = self.recv() + if not data: break + except Exception as e: + break + + try: + # echo data back to the client + self.send(data) + except Exception as e: + break + + def recv(self): + """ + Try to receive until server is shutdown + """ + while self.server.isrunning(): + rl, wl, xl = select.select([self.request], [], [], 1) + if len(rl): + return self.request.recv(1024) + + def send(self, data): + """ + Try to send until server is shutdown + """ + while self.server.isrunning(): + rl, wl, xl = select.select([], [self.request], [], 1) + if len(wl): + self.request.sendall(data) + break + + +class TCPServerWrapper(TCPServer): + """ + Wrapper over TCP server to implement server initiated shutdown. + Adds a flag:= running that a request handler can check and come out of + recv loop when shutdown is called. + """ + + def __init__(self, addr, request_handler): + # hmm, TCPServer is not sub-classed from object! + if issubclass(TCPServer, object): + super(TCPServerWrapper, self).__init__(addr, request_handler) + else: + TCPServer.__init__(self, addr, request_handler) + self.running = False + + def serve_forever(self): + self.running = True + if issubclass(TCPServer, object): + super(TCPServerWrapper, self).serve_forever() + else: + TCPServer.serve_forever(self) + + def shutdown(self): + self.running = False + if issubclass(TCPServer, object): + super(TCPServerWrapper, self).shutdown() + else: + TCPServer.shutdown(self) + + def isrunning(self): + return self.running + + +class TCPEchoClientTest(BaseHostTest): + + def __init__(self): + """ + Initialise test parameters. + + :return: + """ + BaseHostTest.__init__(self) + self.SERVER_IP = None # Will be determined after knowing the target IP + self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port + self.server = None + self.server_thread = None + self.target_ip = None + + @staticmethod + def find_interface_to_target_addr(target_ip): + """ + Finds IP address of the interface through which it is connected to the target. + + :return: + """ + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect((target_ip, 0)) # Target IP, any port + except socket.error: + s.connect((target_ip, 8000)) # Target IP, 'random' port + ip = s.getsockname()[0] + s.close() + return ip + + def setup_tcp_server(self): + """ + sets up a TCP server for target to connect and send test data. + + :return: + """ + # !NOTE: There should mechanism to assert in the host test + if self.SERVER_IP is None: + self.log("setup_tcp_server() called before determining server IP!") + self.notify_complete(False) + + # Returning none will suppress host test from printing success code + self.server = TCPServerWrapper((self.SERVER_IP, self.SERVER_PORT), TCPEchoClientHandler) + ip, port = self.server.server_address + self.SERVER_PORT = port + self.server.allow_reuse_address = True + self.log("HOST: Listening for TCP connections: " + self.SERVER_IP + ":" + str(self.SERVER_PORT)) + self.server_thread = Thread(target=TCPEchoClientTest.server_thread_func, args=(self,)) + self.server_thread.start() + + @staticmethod + def server_thread_func(this): + """ + Thread function to run TCP server forever. + + :param this: + :return: + """ + this.server.serve_forever() + + @event_callback("target_ip") + def _callback_target_ip(self, key, value, timestamp): + """ + Callback to handle reception of target's IP address. + + :param key: + :param value: + :param timestamp: + :return: + """ + self.target_ip = value + self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip) + self.setup_tcp_server() + + @event_callback("host_ip") + def _callback_host_ip(self, key, value, timestamp): + """ + Callback for request for host IP Addr + + """ + self.send_kv("host_ip", self.SERVER_IP) + + @event_callback("host_port") + def _callback_host_port(self, key, value, timestamp): + """ + Callback for request for host port + """ + self.send_kv("host_port", self.SERVER_PORT) + + def teardown(self): + if self.server: + self.server.shutdown() + self.server_thread.join()
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/host_tests/udp_echo.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/host_tests/udp_echo.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,127 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import sys +import socket +from sys import stdout +from threading import Thread +from SocketServer import BaseRequestHandler, UDPServer +from mbed_host_tests import BaseHostTest, event_callback + + +class UDPEchoClientHandler(BaseRequestHandler): + def handle(self): + """ UDP packet handler. Echoes data back to sender's address. + """ + data, sock = self.request + sock.sendto(data, self.client_address) + + +class UDPEchoClientTest(BaseHostTest): + + def __init__(self): + """ + Initialise test parameters. + + :return: + """ + BaseHostTest.__init__(self) + self.SERVER_IP = None # Will be determined after knowing the target IP + self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port + self.server = None + self.server_thread = None + self.target_ip = None + + @staticmethod + def find_interface_to_target_addr(target_ip): + """ + Finds IP address of the interface through which it is connected to the target. + + :return: + """ + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect((target_ip, 0)) # Target IP, any port + except socket.error: + s.connect((target_ip, 8000)) # Target IP, 'random' port + ip = s.getsockname()[0] + s.close() + return ip + + def setup_udp_server(self): + """ + sets up a UDP server for target to connect and send test data. + + :return: + """ + # !NOTE: There should mechanism to assert in the host test + if self.SERVER_IP is None: + self.log("setup_udp_server() called before determining server IP!") + self.notify_complete(False) + + # Returning none will suppress host test from printing success code + self.server = UDPServer((self.SERVER_IP, self.SERVER_PORT), UDPEchoClientHandler) + ip, port = self.server.server_address + self.SERVER_PORT = port + self.server.allow_reuse_address = True + self.log("HOST: Listening for UDP packets: " + self.SERVER_IP + ":" + str(self.SERVER_PORT)) + self.server_thread = Thread(target=UDPEchoClientTest.server_thread_func, args=(self,)) + self.server_thread.start() + + @staticmethod + def server_thread_func(this): + """ + Thread function to run TCP server forever. + + :param this: + :return: + """ + this.server.serve_forever() + + @event_callback("target_ip") + def _callback_target_ip(self, key, value, timestamp): + """ + Callback to handle reception of target's IP address. + + :param key: + :param value: + :param timestamp: + :return: + """ + self.target_ip = value + self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip) + self.setup_udp_server() + + @event_callback("host_ip") + def _callback_host_ip(self, key, value, timestamp): + """ + Callback for request for host IP Addr + + """ + self.send_kv("host_ip", self.SERVER_IP) + + @event_callback("host_port") + def _callback_host_port(self, key, value, timestamp): + """ + Callback for request for host port + """ + self.send_kv("host_port", self.SERVER_PORT) + + def teardown(self): + if self.server: + self.server.shutdown() + self.server_thread.join()
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/host_tests/udp_shotgun.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/host_tests/udp_shotgun.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,142 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import sys +import socket +import json +import random +import itertools +import time +from sys import stdout +from threading import Thread +from SocketServer import BaseRequestHandler, UDPServer +from mbed_host_tests import BaseHostTest, event_callback + + +class UDPEchoClientHandler(BaseRequestHandler): + def handle(self): + """ UDP packet handler. Responds with multiple simultaneous packets + """ + data, sock = self.request + pattern = [ord(d) << 4 for d in data] + + # Each byte in request indicates size of packet to recieve + # Each packet size is shifted over by 4 to fit in a byte, which + # avoids any issues with endianess or decoding + for packet in pattern: + data = [random.randint(0, 255) for _ in range(packet-1)] + data.append(reduce(lambda a,b: a^b, data)) + data = ''.join(map(chr, data)) + sock.sendto(data, self.client_address) + + # Sleep a tiny bit to compensate for local network + time.sleep(0.01) + + +class UDPEchoClientTest(BaseHostTest): + def __init__(self): + """ + Initialise test parameters. + + :return: + """ + BaseHostTest.__init__(self) + self.SERVER_IP = None # Will be determined after knowing the target IP + self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port + self.server = None + self.server_thread = None + self.target_ip = None + + @staticmethod + def find_interface_to_target_addr(target_ip): + """ + Finds IP address of the interface through which it is connected to the target. + + :return: + """ + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect((target_ip, 0)) # Target IP, any port + except socket.error: + s.connect((target_ip, 8000)) # Target IP, 'random' port + ip = s.getsockname()[0] + s.close() + return ip + + def setup_udp_server(self): + """ + sets up a UDP server for target to connect and send test data. + + :return: + """ + # !NOTE: There should mechanism to assert in the host test + if self.SERVER_IP is None: + self.log("setup_udp_server() called before determining server IP!") + self.notify_complete(False) + + # Returning none will suppress host test from printing success code + self.server = UDPServer((self.SERVER_IP, self.SERVER_PORT), UDPEchoClientHandler) + ip, port = self.server.server_address + self.SERVER_PORT = port + self.server.allow_reuse_address = True + self.log("HOST: Listening for UDP packets: " + self.SERVER_IP + ":" + str(self.SERVER_PORT)) + self.server_thread = Thread(target=UDPEchoClientTest.server_thread_func, args=(self,)) + self.server_thread.start() + + @staticmethod + def server_thread_func(this): + """ + Thread function to run TCP server forever. + + :param this: + :return: + """ + this.server.serve_forever() + + @event_callback("target_ip") + def _callback_target_ip(self, key, value, timestamp): + """ + Callback to handle reception of target's IP address. + + :param key: + :param value: + :param timestamp: + :return: + """ + self.target_ip = value + self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip) + self.setup_udp_server() + + @event_callback("host_ip") + def _callback_host_ip(self, key, value, timestamp): + """ + Callback for request for host IP Addr + + """ + self.send_kv("host_ip", self.SERVER_IP) + + @event_callback("host_port") + def _callback_host_port(self, key, value, timestamp): + """ + Callback for request for host port + """ + self.send_kv("host_port", self.SERVER_PORT) + + def teardown(self): + if self.server: + self.server.shutdown() + self.server_thread.join()
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/tcp_echo/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/tcp_echo/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,112 @@ +#include "mbed.h" +#include "ESP8266Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE +#define MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE 256 +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + +namespace { + char tx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0}; + char rx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0}; + const char ASCII_MAX = '~' - ' '; +} + +void prep_buffer(char *tx_buffer, size_t tx_size) { + for (size_t i=0; i<tx_size; ++i) { + tx_buffer[i] = (rand() % 10) + '0'; + } +} + +void test_tcp_echo() { + ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + + if (err) { + printf("MBED: failed to connect with an error of %d\r\n", err); + TEST_ASSERT_EQUAL(0, err); + } + + printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: TCPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + bool result = false; + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + + TCPSocket sock(&net); + SocketAddress tcp_addr(ipbuf, port); + if (sock.connect(tcp_addr) == 0) { + printf("HTTP: Connected to %s:%d\r\n", ipbuf, port); + printf("tx_buffer buffer size: %u\r\n", sizeof(tx_buffer)); + printf("rx_buffer buffer size: %u\r\n", sizeof(rx_buffer)); + + prep_buffer(tx_buffer, sizeof(tx_buffer)); + sock.send(tx_buffer, sizeof(tx_buffer)); + printf("MBED: Finished sending\r\n"); + // Server will respond with HTTP GET's success code + const int ret = sock.recv(rx_buffer, sizeof(rx_buffer)); + printf("MBED: Finished receiving\r\n"); + + result = !memcmp(tx_buffer, rx_buffer, sizeof(tx_buffer)); + TEST_ASSERT_EQUAL(ret, sizeof(rx_buffer)); + TEST_ASSERT_EQUAL(true, result); + } + + sock.close(); + net.disconnect(); + TEST_ASSERT_EQUAL(true, result); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "tcp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP echo", test_tcp_echo), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/tcp_echo_parallel/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/tcp_echo_parallel/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,159 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Parallel tests are not supported by default +#endif + +#include "mbed.h" +#include "ESP8266Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE +#define MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE 64 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_ECHO_THREADS +#define MBED_CFG_TCP_CLIENT_ECHO_THREADS 3 +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); +SocketAddress tcp_addr; +Mutex iomutex; + +void prep_buffer(char *tx_buffer, size_t tx_size) { + for (size_t i=0; i<tx_size; ++i) { + tx_buffer[i] = (rand() % 10) + '0'; + } +} + + +// Each echo class is in charge of one parallel transaction +class Echo { +private: + char tx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE]; + char rx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE]; + + TCPSocket sock; + Thread thread; + +public: + // Limiting stack size to 1k + Echo(): thread(osPriorityNormal, 1024) { + } + + void start() { + osStatus status = thread.start(callback(this, &Echo::echo)); + TEST_ASSERT_EQUAL(osOK, status); + } + + void join() { + osStatus status = thread.join(); + TEST_ASSERT_EQUAL(osOK, status); + } + + void echo() { + int err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + + err = sock.connect(tcp_addr); + TEST_ASSERT_EQUAL(0, err); + + iomutex.lock(); + printf("HTTP: Connected to %s:%d\r\n", + tcp_addr.get_ip_address(), tcp_addr.get_port()); + printf("tx_buffer buffer size: %u\r\n", sizeof(tx_buffer)); + printf("rx_buffer buffer size: %u\r\n", sizeof(rx_buffer)); + iomutex.unlock(); + + prep_buffer(tx_buffer, sizeof(tx_buffer)); + sock.send(tx_buffer, sizeof(tx_buffer)); + + // Server will respond with HTTP GET's success code + const int ret = sock.recv(rx_buffer, sizeof(rx_buffer)); + bool result = !memcmp(tx_buffer, rx_buffer, sizeof(tx_buffer)); + TEST_ASSERT_EQUAL(ret, sizeof(rx_buffer)); + TEST_ASSERT_EQUAL(true, result); + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } +}; + +Echo *echoers[MBED_CFG_TCP_CLIENT_ECHO_THREADS]; + + +void test_tcp_echo_parallel() { + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: TCPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + tcp_addr.set_ip_address(ipbuf); + tcp_addr.set_port(port); + + // Startup echo threads in parallel + for (int i = 0; i < MBED_CFG_TCP_CLIENT_ECHO_THREADS; i++) { + echoers[i] = new Echo; + echoers[i]->start(); + } + + for (int i = 0; i < MBED_CFG_TCP_CLIENT_ECHO_THREADS; i++) { + echoers[i]->join(); + delete echoers[i]; + } + + net.disconnect(); +} + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "tcp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP echo parallel", test_tcp_echo_parallel), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/tcp_hello_world/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/tcp_hello_world/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,115 @@ +#include <algorithm> +#include "mbed.h" +#include "ESP8266Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +namespace { + // Test connection information + const char *HTTP_SERVER_NAME = "os.mbed.com"; + const char *HTTP_SERVER_FILE_PATH = "/media/uploads/mbed_official/hello.txt"; + const int HTTP_SERVER_PORT = 80; +#if defined(TARGET_VK_RZ_A1H) + const int RECV_BUFFER_SIZE = 300; +#else + const int RECV_BUFFER_SIZE = 512; +#endif + // Test related data + const char *HTTP_OK_STR = "200 OK"; + const char *HTTP_HELLO_STR = "Hello world!"; + + // Test buffers + char buffer[RECV_BUFFER_SIZE] = {0}; +} + +bool find_substring(const char *first, const char *last, const char *s_first, const char *s_last) { + const char *f = std::search(first, last, s_first, s_last); + return (f != last); +} + +void test_tcp_hello_world() { + bool result = false; + ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); + net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + printf("TCP client IP Address is %s\r\n", net.get_ip_address()); + + TCPSocket sock(&net); + printf("HTTP: Connection to %s:%d\r\n", HTTP_SERVER_NAME, HTTP_SERVER_PORT); + if (sock.connect(HTTP_SERVER_NAME, HTTP_SERVER_PORT) == 0) { + printf("HTTP: OK\r\n"); + + // We are constructing GET command like this: + // GET http://os.mbed.com/media/uploads/mbed_official/hello.txt HTTP/1.0\n\n + strcpy(buffer, "GET http://"); + strcat(buffer, HTTP_SERVER_NAME); + strcat(buffer, HTTP_SERVER_FILE_PATH); + strcat(buffer, " HTTP/1.0\n\n"); + // Send GET command + sock.send(buffer, strlen(buffer)); + + // Server will respond with HTTP GET's success code + const int ret = sock.recv(buffer, sizeof(buffer) - 1); + buffer[ret] = '\0'; + + // Find 200 OK HTTP status in reply + bool found_200_ok = find_substring(buffer, buffer + ret, HTTP_OK_STR, HTTP_OK_STR + strlen(HTTP_OK_STR)); + // Find "Hello World!" string in reply + bool found_hello = find_substring(buffer, buffer + ret, HTTP_HELLO_STR, HTTP_HELLO_STR + strlen(HTTP_HELLO_STR)); + + TEST_ASSERT_TRUE(found_200_ok); + TEST_ASSERT_TRUE(found_hello); + + if (found_200_ok && found_hello) result = true; + + printf("HTTP: Received %d chars from server\r\n", ret); + printf("HTTP: Received 200 OK status ... %s\r\n", found_200_ok ? "[OK]" : "[FAIL]"); + printf("HTTP: Received '%s' status ... %s\r\n", HTTP_HELLO_STR, found_hello ? "[OK]" : "[FAIL]"); + printf("HTTP: Received message:\r\n"); + printf("%s", buffer); + sock.close(); + } else { + printf("HTTP: ERROR\r\n"); + } + + net.disconnect(); + printf("Network disconnected\r\n"); + TEST_ASSERT_EQUAL(true, result); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP hello world", test_tcp_hello_world), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/tcp_packet_pressure/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/tcp_packet_pressure/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,253 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Pressure tests are not supported by default +#endif + +#include "mbed.h" +#include "ESP8266Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN 64 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX 0x80000 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG false +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Simple xorshift pseudorandom number generator +class RandSeq { +private: + uint32_t x; + uint32_t y; + static const int A = 15; + static const int B = 18; + static const int C = 11; + +public: + RandSeq(uint32_t seed=MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED) + : x(seed), y(seed) {} + + uint32_t next(void) { + x ^= x << A; + x ^= x >> B; + x ^= y ^ (y >> C); + return x + y; + } + + void skip(size_t size) { + for (size_t i = 0; i < size; i++) { + next(); + } + } + + void buffer(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + buffer[i] = lookahead.next() & 0xff; + } + } + + int cmp(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + int diff = buffer[i] - (lookahead.next() & 0xff); + if (diff != 0) { + return diff; + } + } + return 0; + } +}; + +// Shared buffer for network transactions +uint8_t *buffer; +size_t buffer_size; + +// Tries to get the biggest buffer possible on the device. Exponentially +// grows a buffer until heap runs out of space, and uses half to leave +// space for the rest of the program +void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) { + size_t i = min; + while (i < max) { + void *b = malloc(i); + if (!b) { + i /= 4; + if (i < min) { + i = min; + } + break; + } + free(b); + i *= 2; + } + + *buffer = (uint8_t *)malloc(i); + *size = i; + TEST_ASSERT(buffer); +} + + +void test_tcp_packet_pressure() { + generate_buffer(&buffer, &buffer_size, + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN, + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX); + printf("MBED: Generated buffer %d\r\n", buffer_size); + + ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: TCPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + + TCPSocket sock; + SocketAddress tcp_addr(ipbuf, port); + + Timer timer; + timer.start(); + + // Tests exponentially growing sequences + for (size_t size = MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN; + size < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX; + size *= 2) { + err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + err = sock.connect(tcp_addr); + TEST_ASSERT_EQUAL(0, err); + printf("TCP: %s:%d streaming %d bytes\r\n", ipbuf, port, size); + + sock.set_blocking(false); + + // Loop to send/recv all data + RandSeq tx_seq; + RandSeq rx_seq; + size_t rx_count = 0; + size_t tx_count = 0; + size_t window = buffer_size; + + while (tx_count < size || rx_count < size) { + // Send out data + if (tx_count < size) { + size_t chunk_size = size - tx_count; + if (chunk_size > window) { + chunk_size = window; + } + + tx_seq.buffer(buffer, chunk_size); + int td = sock.send(buffer, chunk_size); + + if (td > 0) { + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("TCP: tx -> %d\r\n", td); + } + tx_seq.skip(td); + tx_count += td; + } else if (td != NSAPI_ERROR_WOULD_BLOCK) { + // We may fail to send because of buffering issues, + // cut buffer in half + if (window > MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("TCP: Not sent (%d), window = %d\r\n", td, window); + } + } + } + + // Verify recieved data + while (rx_count < size) { + int rd = sock.recv(buffer, buffer_size); + TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK); + if (rd > 0) { + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("TCP: rx <- %d\r\n", rd); + } + int diff = rx_seq.cmp(buffer, rd); + TEST_ASSERT_EQUAL(0, diff); + rx_seq.skip(rd); + rx_count += rd; + } else if (rd == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } + + timer.stop(); + printf("MBED: Time taken: %fs\r\n", timer.read()); + printf("MBED: Speed: %.3fkb/s\r\n", + 8*(2*MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX - + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); + + net.disconnect(); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "tcp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP packet pressure", test_tcp_packet_pressure), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/tcp_packet_pressure_parallel/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/tcp_packet_pressure_parallel/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,315 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Parallel pressure tests are not supported by default +#endif + +#include "mbed.h" +#include "ESP8266Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN 64 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX 0x80000 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS 3 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG false +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Simple xorshift pseudorandom number generator +class RandSeq { +private: + uint32_t x; + uint32_t y; + static const int A = 15; + static const int B = 18; + static const int C = 11; + +public: + RandSeq(uint32_t seed=MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED) + : x(seed), y(seed) {} + + uint32_t next(void) { + x ^= x << A; + x ^= x >> B; + x ^= y ^ (y >> C); + return x + y; + } + + void skip(size_t size) { + for (size_t i = 0; i < size; i++) { + next(); + } + } + + void buffer(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + buffer[i] = lookahead.next() & 0xff; + } + } + + int cmp(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + int diff = buffer[i] - (lookahead.next() & 0xff); + if (diff != 0) { + return diff; + } + } + return 0; + } +}; + + +// Tries to get the biggest buffer possible on the device. Exponentially +// grows a buffer until heap runs out of space, and uses half to leave +// space for the rest of the program +void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) { + size_t i = min; + while (i < max) { + void *b = malloc(i); + if (!b) { + i /= 4; + if (i < min) { + i = min; + } + break; + } + free(b); + i *= 2; + } + + *buffer = (uint8_t *)malloc(i); + *size = i; + TEST_ASSERT(buffer); +} + + +// Global variables shared between pressure tests +ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); +SocketAddress tcp_addr; +Timer timer; +Mutex iomutex; + +// Single instance of a pressure test +class PressureTest { +private: + uint8_t *buffer; + size_t buffer_size; + + TCPSocket sock; + Thread thread; + +public: + PressureTest(uint8_t *buffer, size_t buffer_size) + : buffer(buffer), buffer_size(buffer_size) { + } + + void start() { + osStatus status = thread.start(callback(this, &PressureTest::run)); + TEST_ASSERT_EQUAL(osOK, status); + } + + void join() { + osStatus status = thread.join(); + TEST_ASSERT_EQUAL(osOK, status); + } + + void run() { + // Tests exponentially growing sequences + for (size_t size = MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN; + size < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX; + size *= 2) { + int err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + err = sock.connect(tcp_addr); + TEST_ASSERT_EQUAL(0, err); + iomutex.lock(); + printf("TCP: %s:%d streaming %d bytes\r\n", + tcp_addr.get_ip_address(), tcp_addr.get_port(), size); + iomutex.unlock(); + + sock.set_blocking(false); + + // Loop to send/recv all data + RandSeq tx_seq; + RandSeq rx_seq; + size_t rx_count = 0; + size_t tx_count = 0; + size_t window = buffer_size; + + while (tx_count < size || rx_count < size) { + // Send out data + if (tx_count < size) { + size_t chunk_size = size - tx_count; + if (chunk_size > window) { + chunk_size = window; + } + + tx_seq.buffer(buffer, chunk_size); + int td = sock.send(buffer, chunk_size); + + if (td > 0) { + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("TCP: tx -> %d\r\n", td); + iomutex.unlock(); + } + tx_seq.skip(td); + tx_count += td; + } else if (td != NSAPI_ERROR_WOULD_BLOCK) { + // We may fail to send because of buffering issues, + // cut buffer in half + if (window > MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("TCP: Not sent (%d), window = %d\r\n", td, window); + iomutex.unlock(); + } + } + } + + // Verify recieved data + while (rx_count < size) { + int rd = sock.recv(buffer, buffer_size); + TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK); + if (rd > 0) { + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("TCP: rx <- %d\r\n", rd); + iomutex.unlock(); + } + int diff = rx_seq.cmp(buffer, rd); + TEST_ASSERT_EQUAL(0, diff); + rx_seq.skip(rd); + rx_count += rd; + } else if (rd == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } + } +}; + +PressureTest *pressure_tests[MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS]; + + +void test_tcp_packet_pressure_parallel() { + uint8_t *buffer; + size_t buffer_size; + generate_buffer(&buffer, &buffer_size, + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN, + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX); + + size_t buffer_subsize = buffer_size / MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; + printf("MBED: Generated buffer %d\r\n", buffer_size); + printf("MBED: Split into %d buffers %d\r\n", + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS, + buffer_subsize); + + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: TCPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + tcp_addr.set_ip_address(ipbuf); + tcp_addr.set_port(port); + + timer.start(); + + // Startup pressure tests in parallel + for (int i = 0; i < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; i++) { + pressure_tests[i] = new PressureTest(&buffer[i*buffer_subsize], buffer_subsize); + pressure_tests[i]->start(); + } + + for (int i = 0; i < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; i++) { + pressure_tests[i]->join(); + delete pressure_tests[i]; + } + + timer.stop(); + printf("MBED: Time taken: %fs\r\n", timer.read()); + printf("MBED: Speed: %.3fkb/s\r\n", + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS* + 8*(2*MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX - + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); + + net.disconnect(); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "tcp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP packet pressure parallel", test_tcp_packet_pressure_parallel), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/udp_dtls_handshake/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/udp_dtls_handshake/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,159 @@ +#include "mbed.h" +#include "ESP8266Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_BUFFER_SIZE +#define MBED_CFG_UDP_DTLS_HANDSHAKE_BUFFER_SIZE 512 +#endif + +#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_RETRIES +#define MBED_CFG_UDP_DTLS_HANDSHAKE_RETRIES 16 +#endif + +#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_PATTERN +#define MBED_CFG_UDP_DTLS_HANDSHAKE_PATTERN 112, 384, 200, 219, 25 +#endif + +#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_TIMEOUT +#define MBED_CFG_UDP_DTLS_HANDSHAKE_TIMEOUT 1500 +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + +uint8_t buffer[MBED_CFG_UDP_DTLS_HANDSHAKE_BUFFER_SIZE] = {0}; +int udp_dtls_handshake_pattern[] = {MBED_CFG_UDP_DTLS_HANDSHAKE_PATTERN}; +const int udp_dtls_handshake_count = sizeof(udp_dtls_handshake_pattern) / sizeof(int); + +void test_udp_dtls_handshake() { + ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: UDPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: UDPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + bool result = false; + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: UDP Server IP address received: %s:%d \n", ipbuf, port); + + // align each size to 4-bits + for (int i = 0; i < udp_dtls_handshake_count; i++) { + udp_dtls_handshake_pattern[i] = (~0xf & udp_dtls_handshake_pattern[i]) + 0x10; + } + + printf("MBED: DTLS pattern ["); + for (int i = 0; i < udp_dtls_handshake_count; i++) { + printf("%d", udp_dtls_handshake_pattern[i]); + if (i != udp_dtls_handshake_count-1) { + printf(", "); + } + } + printf("]\r\n"); + + UDPSocket sock; + SocketAddress udp_addr(ipbuf, port); + sock.set_timeout(MBED_CFG_UDP_DTLS_HANDSHAKE_TIMEOUT); + + for (int attempt = 0; attempt < MBED_CFG_UDP_DTLS_HANDSHAKE_RETRIES; attempt++) { + err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + + for (int i = 0; i < udp_dtls_handshake_count; i++) { + buffer[i] = udp_dtls_handshake_pattern[i] >> 4; + } + + err = sock.sendto(udp_addr, buffer, udp_dtls_handshake_count); + printf("UDP: tx -> %d\r\n", err); + TEST_ASSERT_EQUAL(udp_dtls_handshake_count, err); + + int step = 0; + while (step < udp_dtls_handshake_count) { + err = sock.recvfrom(NULL, buffer, sizeof(buffer)); + printf("UDP: rx <- %d ", err); + + // check length + if (err != udp_dtls_handshake_pattern[step]) { + printf("x (expected %d)\r\n", udp_dtls_handshake_pattern[step]); + break; + } + + // check quick xor of packet + uint8_t check = 0; + for (int j = 0; j < udp_dtls_handshake_pattern[step]; j++) { + check ^= buffer[j]; + } + + if (check != 0) { + printf("x (checksum 0x%02x)\r\n", check); + break; + } + + // successfully got a packet + printf("\r\n"); + step += 1; + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + + // got through all steps, test passed + if (step == udp_dtls_handshake_count) { + result = true; + break; + } + } + + net.disconnect(); + TEST_ASSERT_EQUAL(true, result); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_shotgun"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP DTLS handshake", test_udp_dtls_handshake), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/udp_echo/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/udp_echo/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,151 @@ +#include "mbed.h" +#include "ESP8266Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE +#define MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE 64 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT +#define MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT 500 +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +namespace { + char tx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE] = {0}; + char rx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE] = {0}; + const char ASCII_MAX = '~' - ' '; + const int ECHO_LOOPS = 16; + char uuid[48] = {0}; +} + +void prep_buffer(char *uuid, char *tx_buffer, size_t tx_size) { + size_t i = 0; + + memcpy(tx_buffer, uuid, strlen(uuid)); + i += strlen(uuid); + + tx_buffer[i++] = ' '; + + for (; i<tx_size; ++i) { + tx_buffer[i] = (rand() % 10) + '0'; + } +} + +void test_udp_echo() { + ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); + + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + if (err) { + printf("MBED: failed to connect with an error of %d\r\n", err); + TEST_ASSERT_EQUAL(0, err); + } + + printf("UDP client IP Address is %s\n", net.get_ip_address()); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + UDPSocket sock; + sock.open(&net); + sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT); + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: UDP Server IP address received: %s:%d \n", ipbuf, port); + SocketAddress udp_addr(ipbuf, port); + + int success = 0; + for (int i = 0; success < ECHO_LOOPS; i++) { + prep_buffer(uuid, tx_buffer, sizeof(tx_buffer)); + const int ret = sock.sendto(udp_addr, tx_buffer, sizeof(tx_buffer)); + if (ret >= 0) { + printf("[%02d] sent %d bytes - %.*s \n", i, ret, ret, tx_buffer); + } else { + printf("[%02d] Network error %d\n", i, ret); + continue; + } + + SocketAddress temp_addr; + const int n = sock.recvfrom(&temp_addr, rx_buffer, sizeof(rx_buffer)); + if (n >= 0) { + printf("[%02d] recv %d bytes - %.*s \n", i, n, n, tx_buffer); + } else { + printf("[%02d] Network error %d\n", i, n); + continue; + } + + if ((temp_addr == udp_addr && + n == sizeof(tx_buffer) && + memcmp(rx_buffer, tx_buffer, sizeof(rx_buffer)) == 0)) { + success += 1; + + printf("[%02d] success #%d\n", i, success); + continue; + } + + // failed, clean out any remaining bad packets + sock.set_timeout(0); + while (true) { + err = sock.recvfrom(NULL, NULL, 0); + if (err == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT); + } + + sock.close(); + net.disconnect(); + TEST_ASSERT_EQUAL(ECHO_LOOPS, success); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP echo", test_udp_echo), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/udp_echo_parallel/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/udp_echo_parallel/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,231 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Parallel tests are not supported by default +#endif + +#include "mbed.h" +#include "ESP8266Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE +#define MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE 64 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT +#define MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT 500 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_THREADS +#define MBED_CFG_UDP_CLIENT_ECHO_THREADS 3 +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +const int ECHO_LOOPS = 16; +ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); +SocketAddress udp_addr; +Mutex iomutex; +char uuid[48] = {0}; + +// NOTE: assuming that "id" stays in the single digits +void prep_buffer(int id, char *uuid, char *tx_buffer, size_t tx_size) { + size_t i = 0; + + tx_buffer[i++] = '0' + id; + tx_buffer[i++] = ' '; + + memcpy(tx_buffer+i, uuid, strlen(uuid)); + i += strlen(uuid); + + tx_buffer[i++] = ' '; + + for (; i<tx_size; ++i) { + tx_buffer[i] = (rand() % 10) + '0'; + } +} + + +// Each echo class is in charge of one parallel transaction +class Echo { +private: + char tx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE]; + char rx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE]; + + UDPSocket sock; + Thread thread; + bool result; + int id; + char *uuid; + +public: + // Limiting stack size to 1k + Echo(): thread(osPriorityNormal, 1024), result(false) { + } + + void start(int id, char *uuid) { + this->id = id; + this->uuid = uuid; + osStatus status = thread.start(callback(this, &Echo::echo)); + } + + void join() { + osStatus status = thread.join(); + TEST_ASSERT_EQUAL(osOK, status); + } + + void echo() { + int success = 0; + + int err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + + sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT); + + for (int i = 0; success < ECHO_LOOPS; i++) { + prep_buffer(id, uuid, tx_buffer, sizeof(tx_buffer)); + const int ret = sock.sendto(udp_addr, tx_buffer, sizeof(tx_buffer)); + if (ret >= 0) { + iomutex.lock(); + printf("[ID:%01d][%02d] sent %d bytes - %.*s \n", id, i, ret, ret, tx_buffer); + iomutex.unlock(); + } else { + iomutex.lock(); + printf("[ID:%01d][%02d] Network error %d\n", id, i, ret); + iomutex.unlock(); + continue; + } + + SocketAddress temp_addr; + const int n = sock.recvfrom(&temp_addr, rx_buffer, sizeof(rx_buffer)); + if (n >= 0) { + iomutex.lock(); + printf("[ID:%01d][%02d] recv %d bytes - %.*s \n", id, i, n, n, tx_buffer); + iomutex.unlock(); + } else { + iomutex.lock(); + printf("[ID:%01d][%02d] Network error %d\n", id, i, n); + iomutex.unlock(); + continue; + } + + if ((temp_addr == udp_addr && + n == sizeof(tx_buffer) && + memcmp(rx_buffer, tx_buffer, sizeof(rx_buffer)) == 0)) { + success += 1; + iomutex.lock(); + printf("[ID:%01d][%02d] success #%d\n", id, i, success); + iomutex.unlock(); + continue; + } + + // failed, clean out any remaining bad packets + sock.set_timeout(0); + while (true) { + err = sock.recvfrom(NULL, NULL, 0); + if (err == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT); + } + + result = success == ECHO_LOOPS; + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + if (err) { + result = false; + } + } + + bool get_result() { + return result; + } +}; + +Echo *echoers[MBED_CFG_UDP_CLIENT_ECHO_THREADS]; + + +void test_udp_echo_parallel() { + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + if (err) { + printf("MBED: failed to connect with an error of %d\r\n", err); + GREENTEA_TESTSUITE_RESULT(false); + } else { + printf("UDP client IP Address is %s\n", net.get_ip_address()); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: UDP Server IP address received: %s:%d \n", ipbuf, port); + udp_addr.set_ip_address(ipbuf); + udp_addr.set_port(port); + + // Startup echo threads in parallel + for (int i = 0; i < MBED_CFG_UDP_CLIENT_ECHO_THREADS; i++) { + echoers[i] = new Echo; + echoers[i]->start(i, uuid); + } + + bool result = true; + + for (int i = 0; i < MBED_CFG_UDP_CLIENT_ECHO_THREADS; i++) { + echoers[i]->join(); + result = result && echoers[i]->get_result(); + delete echoers[i]; + } + + net.disconnect(); + TEST_ASSERT_EQUAL(true, result); + } +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP echo parallel", test_udp_echo_parallel), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/udp_packet_pressure/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/udp_packet_pressure/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,276 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Pressure tests are not supported by default +#endif + +#include "mbed.h" +#include "ESP8266Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN 64 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX 0x80000 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 100 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG false +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Simple xorshift pseudorandom number generator +class RandSeq { +private: + uint32_t x; + uint32_t y; + static const int A = 15; + static const int B = 18; + static const int C = 11; + +public: + RandSeq(uint32_t seed=MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED) + : x(seed), y(seed) {} + + uint32_t next(void) { + x ^= x << A; + x ^= x >> B; + x ^= y ^ (y >> C); + return x + y; + } + + void skip(size_t size) { + for (size_t i = 0; i < size; i++) { + next(); + } + } + + void buffer(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + buffer[i] = lookahead.next() & 0xff; + } + } + + int cmp(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + int diff = buffer[i] - (lookahead.next() & 0xff); + if (diff != 0) { + return diff; + } + } + return 0; + } +}; + +// Shared buffer for network transactions +uint8_t *buffer; +size_t buffer_size; + +// Tries to get the biggest buffer possible on the device. Exponentially +// grows a buffer until heap runs out of space, and uses half to leave +// space for the rest of the program +void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) { + size_t i = min; + while (i < max) { + void *b = malloc(i); + if (!b) { + i /= 4; + if (i < min) { + i = min; + } + break; + } + free(b); + i *= 2; + } + + *buffer = (uint8_t *)malloc(i); + *size = i; + TEST_ASSERT(buffer); +} + +void test_udp_packet_pressure() { + generate_buffer(&buffer, &buffer_size, + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN, + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX); + printf("MBED: Generated buffer %d\r\n", buffer_size); + + ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: UDPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: UDPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + + UDPSocket sock; + SocketAddress udp_addr(ipbuf, port); + + Timer timer; + timer.start(); + + // Tests exponentially growing sequences + for (size_t size = MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; + size < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX; + size *= 2) { + err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + printf("UDP: %s:%d streaming %d bytes\r\n", ipbuf, port, size); + + sock.set_blocking(false); + + // Loop to send/recv all data + RandSeq tx_seq; + RandSeq rx_seq; + size_t rx_count = 0; + size_t tx_count = 0; + int known_time = timer.read_ms(); + size_t window = buffer_size; + + while (tx_count < size || rx_count < size) { + // Send out packets + if (tx_count < size) { + size_t chunk_size = size - tx_count; + if (chunk_size > window) { + chunk_size = window; + } + + tx_seq.buffer(buffer, chunk_size); + int td = sock.sendto(udp_addr, buffer, chunk_size); + + if (td > 0) { + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("UDP: tx -> %d\r\n", td); + } + tx_seq.skip(td); + tx_count += td; + } else if (td != NSAPI_ERROR_WOULD_BLOCK) { + // We may fail to send because of buffering issues, revert to + // last good sequence and cut buffer in half + if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("UDP: Not sent (%d), window = %d\r\n", td, window); + } + } + } + + // Prioritize recieving over sending packets to avoid flooding + // the network while handling erronous packets + while (rx_count < size) { + int rd = sock.recvfrom(NULL, buffer, buffer_size); + TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK); + + if (rd > 0) { + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("UDP: rx <- %d\r\n", rd); + } + + if (rx_seq.cmp(buffer, rd) == 0) { + rx_seq.skip(rd); + rx_count += rd; + known_time = timer.read_ms(); + if (window < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX) { + window += MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; + } + } + } else if (timer.read_ms() - known_time > + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) { + // Dropped packet or out of order, revert to last good sequence + // and cut buffer in half + tx_seq = rx_seq; + tx_count = rx_count; + known_time = timer.read_ms(); + if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("UDP: Dropped, window = %d\r\n", window); + } + } else if (rd == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } + + timer.stop(); + printf("MBED: Time taken: %fs\r\n", timer.read()); + printf("MBED: Speed: %.3fkb/s\r\n", + 8*(2*MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX - + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); + + net.disconnect(); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP packet pressure", test_udp_packet_pressure), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/esp8266-driver/TESTS/net/udp_packet_pressure_parallel/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/esp8266-driver/TESTS/net/udp_packet_pressure_parallel/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,341 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Parallel pressure tests are not supported by default +#endif + +#include "mbed.h" +#include "ESP8266Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN 64 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX 0x80000 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 100 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS 3 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG false +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Simple xorshift pseudorandom number generator +class RandSeq { +private: + uint32_t x; + uint32_t y; + static const int A = 15; + static const int B = 18; + static const int C = 11; + +public: + RandSeq(uint32_t seed=MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED) + : x(seed), y(seed) {} + + uint32_t next(void) { + x ^= x << A; + x ^= x >> B; + x ^= y ^ (y >> C); + return x + y; + } + + void skip(size_t size) { + for (size_t i = 0; i < size; i++) { + next(); + } + } + + void buffer(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + buffer[i] = lookahead.next() & 0xff; + } + } + + int cmp(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + int diff = buffer[i] - (lookahead.next() & 0xff); + if (diff != 0) { + return diff; + } + } + return 0; + } +}; + +// Tries to get the biggest buffer possible on the device. Exponentially +// grows a buffer until heap runs out of space, and uses half to leave +// space for the rest of the program +void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) { + size_t i = min; + while (i < max) { + void *b = malloc(i); + if (!b) { + i /= 8; + if (i < min) { + i = min; + } + break; + } + free(b); + i *= 2; + } + + *buffer = (uint8_t *)malloc(i); + *size = i; + TEST_ASSERT(buffer); +} + + +// Global variables shared between pressure tests +ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); +SocketAddress udp_addr; +Timer timer; +Mutex iomutex; + +// Single instance of a pressure test +class PressureTest { +private: + uint8_t *buffer; + size_t buffer_size; + + UDPSocket sock; + Thread thread; + +public: + PressureTest(uint8_t *buffer, size_t buffer_size) + : buffer(buffer), buffer_size(buffer_size) { + } + + void start() { + osStatus status = thread.start(callback(this, &PressureTest::run)); + TEST_ASSERT_EQUAL(osOK, status); + } + + void join() { + osStatus status = thread.join(); + TEST_ASSERT_EQUAL(osOK, status); + } + + void run() { + // Tests exponentially growing sequences + for (size_t size = MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; + size < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX; + size *= 2) { + int err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + iomutex.lock(); + printf("UDP: %s:%d streaming %d bytes\r\n", + udp_addr.get_ip_address(), udp_addr.get_port(), size); + iomutex.unlock(); + + sock.set_blocking(false); + + // Loop to send/recv all data + RandSeq tx_seq; + RandSeq rx_seq; + size_t rx_count = 0; + size_t tx_count = 0; + int known_time = timer.read_ms(); + size_t window = buffer_size; + + while (tx_count < size || rx_count < size) { + // Send out packets + if (tx_count < size) { + size_t chunk_size = size - tx_count; + if (chunk_size > window) { + chunk_size = window; + } + + tx_seq.buffer(buffer, chunk_size); + int td = sock.sendto(udp_addr, buffer, chunk_size); + + if (td > 0) { + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("UDP: tx -> %d\r\n", td); + iomutex.unlock(); + } + tx_seq.skip(td); + tx_count += td; + } else if (td != NSAPI_ERROR_WOULD_BLOCK) { + // We may fail to send because of buffering issues, revert to + // last good sequence and cut buffer in half + if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("UDP: Not sent (%d), window = %d\r\n", td, window); + iomutex.unlock(); + } + } + } + + // Prioritize recieving over sending packets to avoid flooding + // the network while handling erronous packets + while (rx_count < size) { + int rd = sock.recvfrom(NULL, buffer, buffer_size); + TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK); + + if (rd > 0) { + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("UDP: rx <- %d\r\n", rd); + iomutex.unlock(); + } + + if (rx_seq.cmp(buffer, rd) == 0) { + rx_seq.skip(rd); + rx_count += rd; + known_time = timer.read_ms(); + if (window < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX) { + window += MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; + } + } + } else if (timer.read_ms() - known_time > + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) { + // Dropped packet or out of order, revert to last good sequence + // and cut buffer in half + tx_seq = rx_seq; + tx_count = rx_count; + known_time = timer.read_ms(); + if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("UDP: Dropped, window = %d\r\n", window); + iomutex.unlock(); + } + } else if (rd == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } + } +}; + +PressureTest *pressure_tests[MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS]; + + +void test_udp_packet_pressure_parallel() { + uint8_t *buffer; + size_t buffer_size; + generate_buffer(&buffer, &buffer_size, + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN, + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX); + + size_t buffer_subsize = buffer_size / MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; + printf("MBED: Generated buffer %d\r\n", buffer_size); + printf("MBED: Split into %d buffers %d\r\n", + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS, + buffer_subsize); + + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: UDPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: UDPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + udp_addr.set_ip_address(ipbuf); + udp_addr.set_port(port); + + timer.start(); + + // Startup pressure tests in parallel + for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) { + pressure_tests[i] = new PressureTest(&buffer[i*buffer_subsize], buffer_subsize); + pressure_tests[i]->start(); + } + + for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) { + pressure_tests[i]->join(); + delete pressure_tests[i]; + } + + timer.stop(); + printf("MBED: Time taken: %fs\r\n", timer.read()); + printf("MBED: Speed: %.3fkb/s\r\n", + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS* + 8*(2*MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX - + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); + + net.disconnect(); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP packet pressure parallel", test_udp_packet_pressure_parallel), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} + +
diff -r 000000000000 -r 119624335925 easy-connect/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,62 @@ +{ + "name": "easy-connect", + "config": { + "wifi-esp8266-tx": { + "help": "TX pin for serial connection to external device (ESP8266)", + "value": "D1" + }, + "wifi-esp8266-rx": { + "help": "RX pin for serial connection to external device (ESP8266)", + "value": "D0" + }, + "wifi-esp8266-debug": { + "help": "Enable debug logs for (ESP8266)", + "value": false + }, + "wifi-idw01m1-tx": { + "help": "TX pin for serial connection to external device (X-NUCLEO-IDW01M1)", + "value": "PA_9" + }, + "wifi-idw01m1-rx": { + "help": "RX pin for serial connection to external device (X-NUCLEO-IDW01M1)", + "value": "PA_10" + }, + "wifi-idw04a1-tx": { + "help": "TX pin for serial connection to external device (X-NUCLEO-IDW04A1)", + "value": "D8" + }, + "wifi-idw04a1-rx": { + "help": "RX pin for serial connection to external device (X-NUCLEO-IDW04A1)", + "value": "D2" + }, + "wifi-wizfi310-tx": { + "help": "TX pin for serial connection to external device (WizFi310)", + "value": "D1" + }, + "wifi-wizfi310-rx": { + "help": "RX pin for serial connection to external device (WizFi310)", + "value": "D0" + }, + "wifi-wizfi310-debug": { + "help": "Enable debug logs for (WizFi310)", + "value": false + } + }, + "target_overrides": { + "*": { + "target.features_add": ["COMMON_PAL"] + }, + "HEXIWEAR": { + "wifi-esp8266-tx": "PTD3", + "wifi-esp8266-rx": "PTD2" + }, + "NUCLEO_F401RE": { + "wifi-esp8266-tx": "D8", + "wifi-esp8266-rx": "D2" + }, + "NUCLEO_F411RE": { + "wifi-esp8266-tx": "D8", + "wifi-esp8266-rx": "D2" + } + } +}
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mcr20a-rf-driver/#93661a696735279590378e6abef1d689799b713e
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +93661a696735279590378e6abef1d689799b713e
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +17c467b64ab604887fc160cbe4118a51477e334b
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/mcr20a-rf-driver/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/index Binary file easy-connect/mcr20a-rf-driver/.git/index has changed
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 17c467b64ab604887fc160cbe4118a51477e334b www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322708 +0000 clone: from https://github.com/ARMmbed/mcr20a-rf-driver/ +17c467b64ab604887fc160cbe4118a51477e334b 93661a696735279590378e6abef1d689799b713e www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322709 +0000 checkout: moving from master to 93661a696735279590378e6abef1d689799b713e
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 17c467b64ab604887fc160cbe4118a51477e334b www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322708 +0000 clone: from https://github.com/ARMmbed/mcr20a-rf-driver/
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 17c467b64ab604887fc160cbe4118a51477e334b www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322708 +0000 clone: from https://github.com/ARMmbed/mcr20a-rf-driver/
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/objects/pack/pack-4fd1f9dc6d7f55ce0004c2ab82e8b967f7f3011b.idx Binary file easy-connect/mcr20a-rf-driver/.git/objects/pack/pack-4fd1f9dc6d7f55ce0004c2ab82e8b967f7f3011b.idx has changed
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/objects/pack/pack-4fd1f9dc6d7f55ce0004c2ab82e8b967f7f3011b.pack Binary file easy-connect/mcr20a-rf-driver/.git/objects/pack/pack-4fd1f9dc6d7f55ce0004c2ab82e8b967f7f3011b.pack has changed
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ +# pack-refs with: peeled +a28948345dfbd89719c60b765a9837ffbd434a2e refs/remotes/origin/fixing_mbed_path +17c467b64ab604887fc160cbe4118a51477e334b refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +17c467b64ab604887fc160cbe4118a51477e334b
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/.gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/.gitignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,6 @@ +*~ +*.swo +*.swp +build +yotta_modules +yotta_targets
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,6 @@ +# Example RF driver for Freescale 802.15.4 transceivers # + +Support for: + * MCR20A + +This driver is used with 6LoWPAN stack. \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/apache-2.0.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/mcr20a-rf-driver/NanostackRfPhyMcr20a.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/mcr20a-rf-driver/NanostackRfPhyMcr20a.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NANOSTACK_PHY_MCR20A_H_ +#define NANOSTACK_PHY_MCR20A_H_ + +#include "mbed.h" + +#ifdef MBED_CONF_NANOSTACK_CONFIGURATION + +#include "NanostackRfPhy.h" + +// Arduino pin defaults for convenience +#if !defined(MCR20A_SPI_MOSI) +#define MCR20A_SPI_MOSI D11 +#endif +#if !defined(MCR20A_SPI_MISO) +#define MCR20A_SPI_MISO D12 +#endif +#if !defined(MCR20A_SPI_SCLK) +#define MCR20A_SPI_SCLK D13 +#endif +#if !defined(MCR20A_SPI_CS) +#define MCR20A_SPI_CS D10 +#endif +#if !defined(MCR20A_SPI_RST) +#define MCR20A_SPI_RST D5 +#endif +#if !defined(MCR20A_SPI_IRQ) +#define MCR20A_SPI_IRQ D2 +#endif + +class NanostackRfPhyMcr20a : public NanostackRfPhy { +public: + NanostackRfPhyMcr20a(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, + PinName spi_irq); + virtual ~NanostackRfPhyMcr20a(); + virtual int8_t rf_register(); + virtual void rf_unregister(); + virtual void get_mac_address(uint8_t *mac); + virtual void set_mac_address(uint8_t *mac); + +private: + SPI _spi; + DigitalOut _rf_cs; + DigitalOut _rf_rst; + InterruptIn _rf_irq; + DigitalIn _rf_irq_pin; + + void _pins_set(); + void _pins_clear(); +}; + +#endif /* MBED_CONF_NANOSTACK_CONFIGURATION */ +#endif /* NANOSTACK_PHY_MCR20A_H_ */
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/module.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/module.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,18 @@ +{ + "name": "mcr20a-rf-driver", + "version": "0.0.1", + "description": "RF driver for Freescale MCR20A 2.4GHz 802.15.4 wireless transceiver", + "keywords": [ + "rf", + "driver", + "802.15.4" + ], + "author": "Andrei Kovacs <Andrei.Kovacs@freescale.com>", + "license": "BSD 3-clause", + "dependencies": { + "nanostack-libservice": "^3.0.0", + "sal-stack-nanostack": "^5.0.0", + "mbed-drivers": "^1.0.0" + }, + "targetDependencies": {} +}
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/source/MCR20Drv.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/MCR20Drv.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,683 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file MCR20Drv.c +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, 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. +*/ + + +/***************************************************************************** +* INCLUDED HEADERS * +*---------------------------------------------------------------------------* +* Add to this section all the headers that this module needs to include. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + +#include "MCR20Drv.h" +#include "MCR20Reg.h" +#include "XcvrSpi.h" + +#ifdef MBED_CONF_NANOSTACK_CONFIGURATION + +#include "platform/arm_hal_interrupt.h" + +/***************************************************************************** +* PRIVATE VARIABLES * +*---------------------------------------------------------------------------* +* Add to this section all the variables and constants that have local * +* (file) scope. * +* Each of this declarations shall be preceded by the 'static' keyword. * +* These variables / constants cannot be accessed outside this module. * +*---------------------------------------------------------------------------* +*****************************************************************************/ +uint32_t mPhyIrqDisableCnt = 1; + +/***************************************************************************** +* PUBLIC VARIABLES * +*---------------------------------------------------------------------------* +* Add to this section all the variables and constants that have global * +* (project) scope. * +* These variables / constants can be accessed outside this module. * +* These variables / constants shall be preceded by the 'extern' keyword in * +* the interface header. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + +/***************************************************************************** +* PRIVATE FUNCTIONS PROTOTYPES * +*---------------------------------------------------------------------------* +* Add to this section all the functions prototypes that have local (file) * +* scope. * +* These functions cannot be accessed outside this module. * +* These declarations shall be preceded by the 'static' keyword. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + +/***************************************************************************** +* PRIVATE FUNCTIONS * +*---------------------------------------------------------------------------* +* Add to this section all the functions that have local (file) scope. * +* These functions cannot be accessed outside this module. * +* These definitions shall be preceded by the 'static' keyword. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + + +/***************************************************************************** +* PUBLIC FUNCTIONS * +*---------------------------------------------------------------------------* +* Add to this section all the functions that have global (project) scope. * +* These functions can be accessed outside this module. * +* These functions shall have their declarations (prototypes) within the * +* interface header file and shall be preceded by the 'extern' keyword. * +*---------------------------------------------------------------------------* +*****************************************************************************/ + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_Init +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_Init +( +void +) +{ + xcvr_spi_init(gXcvrSpiInstance_c); + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrDeassertCS_d(); + #if !defined(TARGET_KW24D) + MCR20Drv_RST_B_Deassert(); + #endif + RF_IRQ_Init(); + RF_IRQ_Disable(); + mPhyIrqDisableCnt = 1; +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_DirectAccessSPIWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_DirectAccessSPIWrite +( +uint8_t address, +uint8_t value +) +{ + uint16_t txData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = (address & TransceiverSPI_DirectRegisterAddressMask); + txData |= value << 8; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t *)&txData, 0, sizeof(txData)); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_DirectAccessSPIMultiByteWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_DirectAccessSPIMultiByteWrite +( +uint8_t startAddress, +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint8_t txData; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = (startAddress & TransceiverSPI_DirectRegisterAddressMask); + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, byteArray, 0, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_PB_SPIByteWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_PB_SPIByteWrite +( +uint8_t address, +uint8_t value +) +{ + uint32_t txData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_WriteSelect | + TransceiverSPI_PacketBuffAccessSelect | + TransceiverSPI_PacketBuffByteModeSelect; + txData |= (address) << 8; + txData |= (value) << 16; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, 3); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_PB_SPIBurstWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_PB_SPIBurstWrite +( +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint8_t txData; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_WriteSelect | + TransceiverSPI_PacketBuffAccessSelect | + TransceiverSPI_PacketBuffBurstModeSelect; + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, 0, 1); + xcvr_spi_transfer(gXcvrSpiInstance_c, byteArray, 0, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_DirectAccessSPIRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ + +uint8_t MCR20Drv_DirectAccessSPIRead +( +uint8_t address +) +{ + uint8_t txData; + uint8_t rxData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = (address & TransceiverSPI_DirectRegisterAddressMask) | + TransceiverSPI_ReadSelect; + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, &rxData, sizeof(rxData)); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); + + return rxData; + +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_DirectAccessSPIMultyByteRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_DirectAccessSPIMultiByteRead +( +uint8_t startAddress, +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint8_t txData; + uint8_t phyIRQSTS1; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return 0; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = (startAddress & TransceiverSPI_DirectRegisterAddressMask) | + TransceiverSPI_ReadSelect; + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, &phyIRQSTS1, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, byteArray, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); + + return phyIRQSTS1; +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_PB_SPIBurstRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_PB_SPIBurstRead +( +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint8_t txData; + uint8_t phyIRQSTS1; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return 0; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_ReadSelect | + TransceiverSPI_PacketBuffAccessSelect | + TransceiverSPI_PacketBuffBurstModeSelect; + + xcvr_spi_transfer(gXcvrSpiInstance_c, &txData, &phyIRQSTS1, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, byteArray, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); + + return phyIRQSTS1; +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IndirectAccessSPIWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIWrite +( +uint8_t address, +uint8_t value +) +{ + uint32_t txData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_IARIndexReg; + txData |= (address) << 8; + txData |= (value) << 16; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, 3); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IndirectAccessSPIMultiByteWrite +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIMultiByteWrite +( +uint8_t startAddress, +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint16_t txData; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 16000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_IARIndexReg; + txData |= (startAddress) << 8; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)byteArray, 0, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IndirectAccessSPIRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_IndirectAccessSPIRead +( +uint8_t address +) +{ + uint16_t txData; + uint8_t rxData; + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = TransceiverSPI_IARIndexReg | TransceiverSPI_ReadSelect; + txData |= (address) << 8; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, &rxData, sizeof(rxData)); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); + + return rxData; +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IndirectAccessSPIMultiByteRead +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIMultiByteRead +( +uint8_t startAddress, +uint8_t * byteArray, +uint8_t numOfBytes +) +{ + uint16_t txData; + + if( (numOfBytes == 0) || (byteArray == 0) ) + { + return; + } + + ProtectFromMCR20Interrupt(); + + xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); + + gXcvrAssertCS_d(); + + txData = (TransceiverSPI_IARIndexReg | TransceiverSPI_ReadSelect); + txData |= (startAddress) << 8; + + xcvr_spi_transfer(gXcvrSpiInstance_c, (uint8_t*)&txData, 0, sizeof(txData)); + xcvr_spi_transfer(gXcvrSpiInstance_c, 0, byteArray, numOfBytes); + + gXcvrDeassertCS_d(); + UnprotectFromMCR20Interrupt(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IsIrqPending +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +uint32_t MCR20Drv_IsIrqPending +( +void +) +{ + return RF_isIRQ_Pending(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IRQ_Disable +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IRQ_Disable +( +void +) +{ + platform_enter_critical(); + + if( mPhyIrqDisableCnt == 0 ) + { + RF_IRQ_Disable(); + } + + mPhyIrqDisableCnt++; + + platform_exit_critical(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_IRQ_Enable +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_IRQ_Enable +( +void +) +{ + platform_enter_critical(); + + if( mPhyIrqDisableCnt ) + { + mPhyIrqDisableCnt--; + + if( mPhyIrqDisableCnt == 0 ) + { + RF_IRQ_Enable(); + } + } + + platform_exit_critical(); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_RST_Assert +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_Assert +( +void +) +{ + RF_RST_Set(0); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_RST_Deassert +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_Deassert +( +void +) +{ + RF_RST_Set(1); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_SoftRST_Assert +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_SoftRST_Assert +( +void +) +{ + MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x80)); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_SoftRST_Deassert +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_SoftRST_Deassert +( +void +) +{ + MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x00)); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_Soft_RESET +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_Soft_RESET +( +void +) +{ + //assert SOG_RST + MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x80)); + + //deassert SOG_RST + MCR20Drv_IndirectAccessSPIWrite(SOFT_RESET, (0x00)); +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_RESET +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_RESET +( +void +) +{ + #if !defined(TARGET_KW24D) + volatile uint32_t delay = 1000; + //assert RST_B + MCR20Drv_RST_B_Assert(); + + while(delay--); + + //deassert RST_B + MCR20Drv_RST_B_Deassert(); + #endif +} + +/*--------------------------------------------------------------------------- +* Name: MCR20Drv_Set_CLK_OUT_Freq +* Description: - +* Parameters: - +* Return: - +*---------------------------------------------------------------------------*/ +void MCR20Drv_Set_CLK_OUT_Freq +( +uint8_t freqDiv +) +{ + uint8_t clkOutCtrlReg = (freqDiv & cCLK_OUT_DIV_Mask) | cCLK_OUT_EN | cCLK_OUT_EXTEND; + + if(freqDiv == gCLK_OUT_FREQ_DISABLE) + { + clkOutCtrlReg = (cCLK_OUT_EXTEND | gCLK_OUT_FREQ_4_MHz); //reset value with clock out disabled + } + + MCR20Drv_DirectAccessSPIWrite((uint8_t) CLK_OUT_CTRL, clkOutCtrlReg); +} + +#endif /* MBED_CONF_NANOSTACK_CONFIGURATION */
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/source/MCR20Drv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/MCR20Drv.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,373 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file MCR20Drv.h +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, 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 __MCR20_DRV_H__ +#define __MCR20_DRV_H__ + +#include <stdint.h> + +/***************************************************************************** + * INCLUDED HEADERS * + *---------------------------------------------------------------------------* + * Add to this section all the headers that this module needs to include. * + * Note that it is not a good practice to include header files into header * + * files, so use this section only if there is no other better solution. * + *---------------------------------------------------------------------------* + *****************************************************************************/ + +/***************************************************************************** + * PRIVATE MACROS * + *---------------------------------------------------------------------------* + * Add to this section all the access macros, registers mappings, bit access * + * macros, masks, flags etc ... + *---------------------------------------------------------------------------* + *****************************************************************************/ + +/* Disable XCVR clock output by default, to reduce power consumption */ +#ifndef gMCR20_ClkOutFreq_d +#define gMCR20_ClkOutFreq_d gCLK_OUT_FREQ_DISABLE +#endif + +/***************************************************************************** + * PUBLIC FUNCTIONS * + *---------------------------------------------------------------------------* + * Add to this section all the global functions prototype preceded (as a * + * good practice) by the keyword 'extern' * + *---------------------------------------------------------------------------* + *****************************************************************************/ + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Init + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +extern void MCR20Drv_Init +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_SPI_DMA_Init + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_SPI_DMA_Init +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Start_PB_DMA_SPI_Write + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_Start_PB_DMA_SPI_Write +( + uint8_t * srcAddress, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Start_PB_DMA_SPI_Read + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_Start_PB_DMA_SPI_Read +( + uint8_t * dstAddress, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_DirectAccessSPIWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_DirectAccessSPIWrite +( + uint8_t address, + uint8_t value +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_DirectAccessSPIMultiByteWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_DirectAccessSPIMultiByteWrite +( + uint8_t startAddress, + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_PB_SPIBurstWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_PB_SPIBurstWrite +( + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_DirectAccessSPIRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_DirectAccessSPIRead +( + uint8_t address +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_DirectAccessSPIMultyByteRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ + +uint8_t MCR20Drv_DirectAccessSPIMultiByteRead +( + uint8_t startAddress, + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_PB_SPIByteWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_PB_SPIByteWrite +( + uint8_t address, + uint8_t value +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_PB_SPIBurstRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_PB_SPIBurstRead +( + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IndirectAccessSPIWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIWrite +( + uint8_t address, + uint8_t value +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IndirectAccessSPIMultiByteWrite + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIMultiByteWrite +( + uint8_t startAddress, + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IndirectAccessSPIRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +uint8_t MCR20Drv_IndirectAccessSPIRead +( + uint8_t address +); +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IndirectAccessSPIMultiByteRead + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IndirectAccessSPIMultiByteRead +( + uint8_t startAddress, + uint8_t * byteArray, + uint8_t numOfBytes +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IsIrqPending + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +uint32_t MCR20Drv_IsIrqPending +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IRQ_Disable + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IRQ_Disable +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_IRQ_Enable + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_IRQ_Enable +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_RST_PortConfig + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_PortConfig +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_RST_Assert + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_Assert +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_RST_Deassert + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_RST_B_Deassert +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_SoftRST_Assert + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_SoftRST_Assert +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_SoftRST_Deassert + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_SoftRST_Deassert +( + void +); + + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_RESET + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_RESET +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Soft_RESET + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_Soft_RESET +( + void +); + +/*--------------------------------------------------------------------------- + * Name: MCR20Drv_Set_CLK_OUT_Freq + * Description: - + * Parameters: - + * Return: - + *---------------------------------------------------------------------------*/ +void MCR20Drv_Set_CLK_OUT_Freq +( + uint8_t freqDiv +); + +#define ProtectFromMCR20Interrupt() MCR20Drv_IRQ_Disable() +#define UnprotectFromMCR20Interrupt() MCR20Drv_IRQ_Enable() + +#endif /* __MCR20_DRV_H__ */
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/source/MCR20Overwrites.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/MCR20Overwrites.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,309 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file MCR20Overwrites.h +* Description: Overwrites header file for MCR20 Register values +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, 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 OVERWRITES_H_ +#define OVERWRITES_H_ + +typedef struct overwrites_tag { + char address; + char data; +}overwrites_t; + + +/*****************************************************************************************************************/ +// This file is created exclusively for use with the transceiver 2.0 silicon +// and is provided for the world to use. It contains a list of all +// known overwrite values. Overwrite values are non-default register +// values that configure the transceiver device to a more optimally performing +// posture. It is expected that low level software (i.e. PHY) will +// consume this file as a #include, and transfer the contents to the +// the indicated addresses in the transceiver's memory space. This file has +// at least one required entry, that being its own version current version +// number, to be stored at transceiver's location 0x3B the +// OVERWRITES_VERSION_NUMBER register. The RAM register is provided in +// the transceiver address space to assist in future debug efforts. The +// analyst may read this location (once device has been booted with +// mysterious software) and have a good indication of what register +// overwrites were performed (with all versions of the overwrites.h file +// being archived forever at the Compass location shown above. +// +// The transceiver has an indirect register (IAR) space. Write access to this space +// requires 3 or more writes: +// 1st) the first write is an index value to the indirect (write Bit7=0, register access Bit 6=0) + 0x3E +// 2nd) IAR Register #0x00 - 0xFF. +// 3rd) The data to write +// nth) Burst mode additional data if required. +// +// Write access to direct space requires only a single address, data pair. + +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x0C}, //version 0C: new value for ACKDELAY targeting 198us (23 May, 2013, Larry Roshak) +{0x23, 0x17} //PA_PWR new default Power Step is "23" +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x55}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03}, //CHF_PMAGAIN +{0x22, 0x50}, //CCA1_THRESH +{0x4D, 0x13}, //CORR_NVAL moved from 0x14 to 0x13 for 0.5 dB improved Rx Sensitivity +{0x39, 0x3D} //ACKDELAY new value targeting a delay of 198us (23 May, 2013, Larry Roshak) +}; + + +/* begin of deprecated versions + +==VERSION 1== +(version 1 is empty) + +==VERSION 2== +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02} //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +}; + +==VERSION 3== +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +}; + +==VERSION 4== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x04} //version 04 is the current version: update PA_COILTUNING default +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71} //PA_TUNING: override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +}; + +==VERSION 5== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x05} //version 05: updates Channel Filter Register set (21 Dec 2012, on behalf of S. Soca) +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71} //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F} //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F} //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24} //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24} //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24} //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24} //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24} //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24} //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32} //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D} //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D} //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +}; + +==VERSION 6== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x06} //version 06: disable PA calibration +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07} //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71} //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F} //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F} //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24} //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24} //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24} //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24} //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24} //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24} //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32} //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D} //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D} //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28} //PA_CAL_DIS=1 Disabled PA calibration +}; + +==VERSION 7== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x07} //version 07: updated registers for ED/RSSI +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x73}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x60}, //RSSI_OFFSET +{0x69, 0x65} //RSSI_SLOPE +}; + + +==VERSION 8== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x08} //version 08: updated registers for ED/RSSI +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x73}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x69, 0x65} //RSSI_SLOPE +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03} //CHF_PMAGAIN +}; + + +==VERSION 9== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x09} //version 09: updated registers for ED/RSSI and PowerStep +{0x23, 0x17} //PA_PWR new default value +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x55}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03} //CHF_PMAGAIN +}; + +==VERSION A== +overwrites_t const overwrites_direct[] ={ +{0x3B, 0x0A} //version 0A: updated registers for CCA +{0x23, 0x17} //PA_PWR new default Power Step is "23" +}; + +overwrites_t const overwrites_indirect[] ={ +{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents) +{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3 +{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1 +{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid) +{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca) +{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca) +{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration +{0x52, 0x55}, //AGC_THR1 RSSI tune up +{0x53, 0x2D}, //AGC_THR2 RSSI tune up +{0x66, 0x5F}, //ATT_RSSI1 tune up +{0x67, 0x8F}, //ATT_RSSI2 tune up +{0x68, 0x61}, //RSSI_OFFSET +{0x78, 0x03} //CHF_PMAGAIN +{0x22, 0x50} //CCA1_THRESH +}; + +end of deprecated versions */ + + +#endif //OVERWRITES_H_ +
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/source/MCR20Reg.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/MCR20Reg.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,730 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file MCR20reg.h +* MCR20 Registers +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, 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 __MCR20_REG_H__ +#define __MCR20_REG_H__ +/***************************************************************************** + * INCLUDED HEADERS * + *---------------------------------------------------------------------------* + * Add to this section all the headers that this module needs to include. * + * Note that it is not a good practice to include header files into header * + * files, so use this section only if there is no other better solution. * + *---------------------------------------------------------------------------* + *****************************************************************************/ + +/****************************************************************************/ +/* Transceiver SPI Registers */ +/****************************************************************************/ + +#define TransceiverSPI_IARIndexReg (0x3E) + +#define TransceiverSPI_ReadSelect (1<<7) +#define TransceiverSPI_WriteSelect (0<<7) +#define TransceiverSPI_RegisterAccessSelect (0<<6) +#define TransceiverSPI_PacketBuffAccessSelect (1<<6) +#define TransceiverSPI_PacketBuffBurstModeSelect (0<<5) +#define TransceiverSPI_PacketBuffByteModeSelect (1<<5) + +#define TransceiverSPI_DirectRegisterAddressMask (0x3F) + +#define IRQSTS1 0x00 +#define IRQSTS2 0x01 +#define IRQSTS3 0x02 +#define PHY_CTRL1 0x03 +#define PHY_CTRL2 0x04 +#define PHY_CTRL3 0x05 +#define RX_FRM_LEN 0x06 +#define PHY_CTRL4 0x07 +#define SRC_CTRL 0x08 +#define SRC_ADDRS_SUM_LSB 0x09 +#define SRC_ADDRS_SUM_MSB 0x0A +#define CCA1_ED_FNL 0x0B +#define EVENT_TMR_LSB 0x0C +#define EVENT_TMR_MSB 0x0D +#define EVENT_TMR_USB 0x0E +#define TIMESTAMP_LSB 0x0F +#define TIMESTAMP_MSB 0x10 +#define TIMESTAMP_USB 0x11 +#define T3CMP_LSB 0x12 +#define T3CMP_MSB 0x13 +#define T3CMP_USB 0x14 +#define T2PRIMECMP_LSB 0x15 +#define T2PRIMECMP_MSB 0x16 +#define T1CMP_LSB 0x17 +#define T1CMP_MSB 0x18 +#define T1CMP_USB 0x19 +#define T2CMP_LSB 0x1A +#define T2CMP_MSB 0x1B +#define T2CMP_USB 0x1C +#define T4CMP_LSB 0x1D +#define T4CMP_MSB 0x1E +#define T4CMP_USB 0x1F +#define PLL_INT0 0x20 +#define PLL_FRAC0_LSB 0x21 +#define PLL_FRAC0_MSB 0x22 +#define PA_PWR 0x23 +#define SEQ_STATE 0x24 +#define LQI_VALUE 0x25 +#define RSSI_CCA_CONT 0x26 +//-------------- 0x27 +#define ASM_CTRL1 0x28 +#define ASM_CTRL2 0x29 +#define ASM_DATA_0 0x2A +#define ASM_DATA_1 0x2B +#define ASM_DATA_2 0x2C +#define ASM_DATA_3 0x2D +#define ASM_DATA_4 0x2E +#define ASM_DATA_5 0x2F +#define ASM_DATA_6 0x30 +#define ASM_DATA_7 0x31 +#define ASM_DATA_8 0x32 +#define ASM_DATA_9 0x33 +#define ASM_DATA_A 0x34 +#define ASM_DATA_B 0x35 +#define ASM_DATA_C 0x36 +#define ASM_DATA_D 0x37 +#define ASM_DATA_E 0x38 +#define ASM_DATA_F 0x39 +//------------------- 0x3A +#define OVERWRITE_VER 0x3B +#define CLK_OUT_CTRL 0x3C +#define PWR_MODES 0x3D +#define IAR_INDEX 0x3E +#define IAR_DATA 0x3F + + +#define PART_ID 0x00 +#define XTAL_TRIM 0x01 +#define PMC_LP_TRIM 0x02 +#define MACPANID0_LSB 0x03 +#define MACPANID0_MSB 0x04 +#define MACSHORTADDRS0_LSB 0x05 +#define MACSHORTADDRS0_MSB 0x06 +#define MACLONGADDRS0_0 0x07 +#define MACLONGADDRS0_8 0x08 +#define MACLONGADDRS0_16 0x09 +#define MACLONGADDRS0_24 0x0A +#define MACLONGADDRS0_32 0x0B +#define MACLONGADDRS0_40 0x0C +#define MACLONGADDRS0_48 0x0D +#define MACLONGADDRS0_56 0x0E +#define RX_FRAME_FILTER 0x0F +#define PLL_INT1 0x10 +#define PLL_FRAC1_LSB 0x11 +#define PLL_FRAC1_MSB 0x12 +#define MACPANID1_LSB 0x13 +#define MACPANID1_MSB 0x14 +#define MACSHORTADDRS1_LSB 0x15 +#define MACSHORTADDRS1_MSB 0x16 +#define MACLONGADDRS1_0 0x17 +#define MACLONGADDRS1_8 0x18 +#define MACLONGADDRS1_16 0x19 +#define MACLONGADDRS1_24 0x1A +#define MACLONGADDRS1_32 0x1B +#define MACLONGADDRS1_40 0x1C +#define MACLONGADDRS1_48 0x1D +#define MACLONGADDRS1_56 0x1E +#define DUAL_PAN_CTRL 0x1F +#define DUAL_PAN_DWELL 0x20 +#define DUAL_PAN_STS 0x21 +#define CCA1_THRESH 0x22 +#define CCA1_ED_OFFSET_COMP 0x23 +#define LQI_OFFSET_COMP 0x24 +#define CCA_CTRL 0x25 +#define CCA2_CORR_PEAKS 0x26 +#define CCA2_CORR_THRESH 0x27 +#define TMR_PRESCALE 0x28 +//---------------- 0x29 +#define GPIO_DATA 0x2A +#define GPIO_DIR 0x2B +#define GPIO_PUL_EN 0x2C +#define GPIO_PUL_SEL 0x2D +#define GPIO_DS 0x2E +//-------------- 0x2F +#define ANT_PAD_CTRL 0x30 +#define MISC_PAD_CTRL 0x31 +#define BSM_CTRL 0x32 +//--------------- 0x33 +#define _RNG 0x34 +#define RX_BYTE_COUNT 0x35 +#define RX_WTR_MARK 0x36 +#define SOFT_RESET 0x37 +#define TXDELAY 0x38 +#define ACKDELAY 0x39 +#define SEQ_MGR_CTRL 0x3A +#define SEQ_MGR_STS 0x3B +#define SEQ_T_STS 0x3C +#define ABORT_STS 0x3D +#define CCCA_BUSY_CNT 0x3E +#define SRC_ADDR_CHECKSUM1 0x3F +#define SRC_ADDR_CHECKSUM2 0x40 +#define SRC_TBL_VALID1 0x41 +#define SRC_TBL_VALID2 0x42 +#define FILTERFAIL_CODE1 0x43 +#define FILTERFAIL_CODE2 0x44 +#define SLOT_PRELOAD 0x45 +//---------------- 0x46 +#define CORR_VT 0x47 +#define SYNC_CTRL 0x48 +#define PN_LSB_0 0x49 +#define PN_LSB_1 0x4A +#define PN_MSB_0 0x4B +#define PN_MSB_1 0x4C +#define CORR_NVAL 0x4D +#define TX_MODE_CTRL 0x4E +#define SNF_THR 0x4F +#define FAD_THR 0x50 +#define ANT_AGC_CTRL 0x51 +#define AGC_THR1 0x52 +#define AGC_THR2 0x53 +#define AGC_HYS 0x54 +#define AFC 0x55 +//--------------- 0x56 +//--------------- 0x57 +#define PHY_STS 0x58 +#define RX_MAX_CORR 0x59 +#define RX_MAX_PREAMBLE 0x5A +#define RSSI 0x5B +//--------------- 0x5C +//--------------- 0x5D +#define PLL_DIG_CTRL 0x5E +#define VCO_CAL 0x5F +#define VCO_BEST_DIFF 0x60 +#define VCO_BIAS 0x61 +#define KMOD_CTRL 0x62 +#define KMOD_CAL 0x63 +#define PA_CAL 0x64 +#define PA_PWRCAL 0x65 +#define ATT_RSSI1 0x66 +#define ATT_RSSI2 0x67 +#define RSSI_OFFSET 0x68 +#define RSSI_SLOPE 0x69 +#define RSSI_CAL1 0x6A +#define RSSI_CAL2 0x6B +//--------------- 0x6C +//--------------- 0x6D +#define XTAL_CTRL 0x6E +#define XTAL_COMP_MIN 0x6F +#define XTAL_COMP_MAX 0x70 +#define XTAL_GM 0x71 +//--------------- 0x72 +//--------------- 0x73 +#define LNA_TUNE 0x74 +#define LNA_AGCGAIN 0x75 +//--------------- 0x76 +//--------------- 0x77 +#define CHF_PMA_GAIN 0x78 +#define CHF_IBUF 0x79 +#define CHF_QBUF 0x7A +#define CHF_IRIN 0x7B +#define CHF_QRIN 0x7C +#define CHF_IL 0x7D +#define CHF_QL 0x7E +#define CHF_CC1 0x7F +#define CHF_CCL 0x80 +#define CHF_CC2 0x81 +#define CHF_IROUT 0x82 +#define CHF_QROUT 0x83 +//--------------- 0x84 +//--------------- 0x85 +#define RSSI_CTRL 0x86 +//--------------- 0x87 +//--------------- 0x88 +#define PA_BIAS 0x89 +#define PA_TUNING 0x8A +//--------------- 0x8B +//--------------- 0x8C +#define PMC_HP_TRIM 0x8D +#define VREGA_TRIM 0x8E +//--------------- 0x8F +//--------------- 0x90 +#define VCO_CTRL1 0x91 +#define VCO_CTRL2 0x92 +//--------------- 0x93 +//--------------- 0x94 +#define ANA_SPARE_OUT1 0x95 +#define ANA_SPARE_OUT2 0x96 +#define ANA_SPARE_IN 0x97 +#define MISCELLANEOUS 0x98 +//--------------- 0x99 +#define SEQ_MGR_OVRD0 0x9A +#define SEQ_MGR_OVRD1 0x9B +#define SEQ_MGR_OVRD2 0x9C +#define SEQ_MGR_OVRD3 0x9D +#define SEQ_MGR_OVRD4 0x9E +#define SEQ_MGR_OVRD5 0x9F +#define SEQ_MGR_OVRD6 0xA0 +#define SEQ_MGR_OVRD7 0xA1 +//--------------- 0xA2 +#define TESTMODE_CTRL 0xA3 +#define DTM_CTRL1 0xA4 +#define DTM_CTRL2 0xA5 +#define ATM_CTRL1 0xA6 +#define ATM_CTRL2 0xA7 +#define ATM_CTRL3 0xA8 +//--------------- 0xA9 +#define LIM_FE_TEST_CTRL 0xAA +#define CHF_TEST_CTRL 0xAB +#define VCO_TEST_CTRL 0xAC +#define PLL_TEST_CTRL 0xAD +#define PA_TEST_CTRL 0xAE +#define PMC_TEST_CTRL 0xAF +#define SCAN_DTM_PROTECT_1 0xFE +#define SCAN_DTM_PROTECT_0 0xFF + +// IRQSTS1 bits +#define cIRQSTS1_RX_FRM_PEND (1<<7) +#define cIRQSTS1_PLL_UNLOCK_IRQ (1<<6) +#define cIRQSTS1_FILTERFAIL_IRQ (1<<5) +#define cIRQSTS1_RXWTRMRKIRQ (1<<4) +#define cIRQSTS1_CCAIRQ (1<<3) +#define cIRQSTS1_RXIRQ (1<<2) +#define cIRQSTS1_TXIRQ (1<<1) +#define cIRQSTS1_SEQIRQ (1<<0) + +typedef union regIRQSTS1_tag{ + uint8_t byte; + struct{ + uint8_t SEQIRQ:1; + uint8_t TXIRQ:1; + uint8_t RXIRQ:1; + uint8_t CCAIRQ:1; + uint8_t RXWTRMRKIRQ:1; + uint8_t FILTERFAIL_IRQ:1; + uint8_t PLL_UNLOCK_IRQ:1; + uint8_t RX_FRM_PEND:1; + }bit; +} regIRQSTS1_t; + +// IRQSTS2 bits +#define cIRQSTS2_CRCVALID (1<<7) +#define cIRQSTS2_CCA (1<<6) +#define cIRQSTS2_SRCADDR (1<<5) +#define cIRQSTS2_PI (1<<4) +#define cIRQSTS2_TMRSTATUS (1<<3) +#define cIRQSTS2_ASM_IRQ (1<<2) +#define cIRQSTS2_PB_ERR_IRQ (1<<1) +#define cIRQSTS2_WAKE_IRQ (1<<0) + +typedef union regIRQSTS2_tag{ + uint8_t byte; + struct{ + uint8_t WAKE_IRQ:1; + uint8_t PB_ERR_IRQ:1; + uint8_t ASM_IRQ:1; + uint8_t TMRSTATUS:1; + uint8_t PI_:1; + uint8_t SRCADDR:1; + uint8_t CCA:1; + uint8_t CRCVALID:1; + }bit; +} regIRQSTS2_t; + +// IRQSTS3 bits +#define cIRQSTS3_TMR4MSK (1<<7) +#define cIRQSTS3_TMR3MSK (1<<6) +#define cIRQSTS3_TMR2MSK (1<<5) +#define cIRQSTS3_TMR1MSK (1<<4) +#define cIRQSTS3_TMR4IRQ (1<<3) +#define cIRQSTS3_TMR3IRQ (1<<2) +#define cIRQSTS3_TMR2IRQ (1<<1) +#define cIRQSTS3_TMR1IRQ (1<<0) + +typedef union regIRQSTS3_tag{ + uint8_t byte; + struct{ + uint8_t TMR1IRQ:1; + uint8_t TMR2IRQ:1; + uint8_t TMR3IRQ:1; + uint8_t TMR4IRQ:1; + uint8_t TMR1MSK:1; + uint8_t TMR2MSK:1; + uint8_t TMR3MSK:1; + uint8_t TMR4MSK:1; + }bit; +} regIRQSTS3_t; + +// PHY_CTRL1 bits +#define cPHY_CTRL1_TMRTRIGEN (1<<7) +#define cPHY_CTRL1_SLOTTED (1<<6) +#define cPHY_CTRL1_CCABFRTX (1<<5) +#define cPHY_CTRL1_RXACKRQD (1<<4) +#define cPHY_CTRL1_AUTOACK (1<<3) +#define cPHY_CTRL1_XCVSEQ (7<<0) + +typedef union regPHY_CTRL1_tag{ + uint8_t byte; + struct{ + uint8_t XCVSEQ:3; + uint8_t AUTOACK:1; + uint8_t RXACKRQD:1; + uint8_t CCABFRTX:1; + uint8_t SLOTTED:1; + uint8_t TMRTRIGEN:1; + }bit; +} regPHY_CTRL1_t; + +// PHY_CTRL2 bits +#define cPHY_CTRL2_CRC_MSK (1<<7) +#define cPHY_CTRL2_PLL_UNLOCK_MSK (1<<6) +#define cPHY_CTRL2_FILTERFAIL_MSK (1<<5) +#define cPHY_CTRL2_RX_WMRK_MSK (1<<4) +#define cPHY_CTRL2_CCAMSK (1<<3) +#define cPHY_CTRL2_RXMSK (1<<2) +#define cPHY_CTRL2_TXMSK (1<<1) +#define cPHY_CTRL2_SEQMSK (1<<0) + +typedef union regPHY_CTRL2_tag{ + uint8_t byte; + struct{ + uint8_t SEQMSK:1; + uint8_t TXMSK:1; + uint8_t RXMSK:1; + uint8_t CCAMSK:1; + uint8_t RX_WMRK_MSK:1; + uint8_t FILTERFAIL_MSK:1; + uint8_t PLL_UNLOCK_MSK:1; + uint8_t CRC_MSK:1; + }bit; +} regPHY_CTRL2_t; + +// PHY_CTRL3 bits +#define cPHY_CTRL3_TMR4CMP_EN (1<<7) +#define cPHY_CTRL3_TMR3CMP_EN (1<<6) +#define cPHY_CTRL3_TMR2CMP_EN (1<<5) +#define cPHY_CTRL3_TMR1CMP_EN (1<<4) +#define cPHY_CTRL3_ASM_MSK (1<<2) +#define cPHY_CTRL3_PB_ERR_MSK (1<<1) +#define cPHY_CTRL3_WAKE_MSK (1<<0) + +typedef union regPHY_CTRL3_tag{ + uint8_t byte; + struct{ + uint8_t WAKE_MSK:1; + uint8_t PB_ERR_MSK:1; + uint8_t ASM_MSK:1; + uint8_t RESERVED:1; + uint8_t TMR1CMP_EN:1; + uint8_t TMR2CMP_EN:1; + uint8_t TMR3CMP_EN:1; + uint8_t TMR4CMP_EN:1; + }bit; +} regPHY_CTRL3_t; + +// RX_FRM_LEN bits +#define cRX_FRAME_LENGTH (0x7F) + +// PHY_CTRL4 bits +#define cPHY_CTRL4_TRCV_MSK (1<<7) +#define cPHY_CTRL4_TC3TMOUT (1<<6) +#define cPHY_CTRL4_PANCORDNTR0 (1<<5) +#define cPHY_CTRL4_CCATYPE (3<<0) +#define cPHY_CTRL4_CCATYPE_Shift_c (3) +#define cPHY_CTRL4_TMRLOAD (1<<2) +#define cPHY_CTRL4_PROMISCUOUS (1<<1) +#define cPHY_CTRL4_TC2PRIME_EN (1<<0) + +typedef union regPHY_CTRL4_tag{ + uint8_t byte; + struct{ + uint8_t TC2PRIME_EN:1; + uint8_t PROMISCUOUS:1; + uint8_t TMRLOAD:1; + uint8_t CCATYPE:2; + uint8_t PANCORDNTR0:1; + uint8_t TC3TMOUT:1; + uint8_t TRCV_MSK:1; + }bit; +} regPHY_CTRL4_t; + +// SRC_CTRL bits +#define cSRC_CTRL_INDEX (0x0F) +#define cSRC_CTRL_INDEX_Shift_c (4) +#define cSRC_CTRL_ACK_FRM_PND (1<<3) +#define cSRC_CTRL_SRCADDR_EN (1<<2) +#define cSRC_CTRL_INDEX_EN (1<<1) +#define cSRC_CTRL_INDEX_DISABLE (1<<0) + +typedef union regSRC_CTRL_tag{ + uint8_t byte; + struct{ + uint8_t INDEX_DISABLE:1; + uint8_t INDEX_EN:1; + uint8_t SRCADDR_EN:1; + uint8_t ACK_FRM_PND:1; + uint8_t INDEX:4; + }bit; +} regSRC_CTRL_t; + +// ASM_CTRL1 bits +#define cASM_CTRL1_CLEAR (1<<7) +#define cASM_CTRL1_START (1<<6) +#define cASM_CTRL1_SELFTST (1<<5) +#define cASM_CTRL1_CTR (1<<4) +#define cASM_CTRL1_CBC (1<<3) +#define cASM_CTRL1_AES (1<<2) +#define cASM_CTRL1_LOAD_MAC (1<<1) + +// ASM_CTRL2 bits +#define cASM_CTRL2_DATA_REG_TYPE_SEL (7) +#define cASM_CTRL2_DATA_REG_TYPE_SEL_Shift_c (5) +#define cASM_CTRL2_TSTPAS (1<<1) + +// CLK_OUT_CTRL bits +#define cCLK_OUT_CTRL_EXTEND (1<<7) +#define cCLK_OUT_CTRL_HIZ (1<<6) +#define cCLK_OUT_CTRL_SR (1<<5) +#define cCLK_OUT_CTRL_DS (1<<4) +#define cCLK_OUT_CTRL_EN (1<<3) +#define cCLK_OUT_CTRL_DIV (7) + +// PWR_MODES bits +#define cPWR_MODES_XTAL_READY (1<<5) +#define cPWR_MODES_XTALEN (1<<4) +#define cPWR_MODES_ASM_CLK_EN (1<<3) +#define cPWR_MODES_AUTODOZE (1<<1) +#define cPWR_MODES_PMC_MODE (1<<0) + +// RX_FRAME_FILTER bits +#define cRX_FRAME_FLT_FRM_VER (0xC0) +#define cRX_FRAME_FLT_FRM_VER_Shift_c (6) +#define cRX_FRAME_FLT_ACTIVE_PROMISCUOUS (1<<5) +#define cRX_FRAME_FLT_NS_FT (1<<4) +#define cRX_FRAME_FLT_CMD_FT (1<<3) +#define cRX_FRAME_FLT_ACK_FT (1<<2) +#define cRX_FRAME_FLT_DATA_FT (1<<1) +#define cRX_FRAME_FLT_BEACON_FT (1<<0) + +typedef union regRX_FRAME_FILTER_tag{ + uint8_t byte; + struct{ + uint8_t FRAME_FLT_BEACON_FT:1; + uint8_t FRAME_FLT_DATA_FT:1; + uint8_t FRAME_FLT_ACK_FT:1; + uint8_t FRAME_FLT_CMD_FT:1; + uint8_t FRAME_FLT_NS_FT:1; + uint8_t FRAME_FLT_ACTIVE_PROMISCUOUS:1; + uint8_t FRAME_FLT_FRM_VER:2; + }bit; +} regRX_FRAME_FILTER_t; + +// DUAL_PAN_CTRL bits +#define cDUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_MSK (0xF0) +#define cDUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_Shift_c (4) +#define cDUAL_PAN_CTRL_CURRENT_NETWORK (1<<3) +#define cDUAL_PAN_CTRL_PANCORDNTR1 (1<<2) +#define cDUAL_PAN_CTRL_DUAL_PAN_AUTO (1<<1) +#define cDUAL_PAN_CTRL_ACTIVE_NETWORK (1<<0) + +// DUAL_PAN_STS bits +#define cDUAL_PAN_STS_RECD_ON_PAN1 (1<<7) +#define cDUAL_PAN_STS_RECD_ON_PAN0 (1<<6) +#define cDUAL_PAN_STS_DUAL_PAN_REMAIN (0x3F) + +// CCA_CTRL bits +#define cCCA_CTRL_AGC_FRZ_EN (1<<6) +#define cCCA_CTRL_CONT_RSSI_EN (1<<5) +#define cCCA_CTRL_LQI_RSSI_NOT_CORR (1<<4) +#define cCCA_CTRL_CCA3_AND_NOT_OR (1<<3) +#define cCCA_CTRL_POWER_COMP_EN_LQI (1<<2) +#define cCCA_CTRL_POWER_COMP_EN_ED (1<<1) +#define cCCA_CTRL_POWER_COMP_EN_CCA1 (1<<0) + +// GPIO_DATA bits +#define cGPIO_DATA_7 (1<<7) +#define cGPIO_DATA_6 (1<<6) +#define cGPIO_DATA_5 (1<<5) +#define cGPIO_DATA_4 (1<<4) +#define cGPIO_DATA_3 (1<<3) +#define cGPIO_DATA_2 (1<<2) +#define cGPIO_DATA_1 (1<<1) +#define cGPIO_DATA_0 (1<<0) + +// GPIO_DIR bits +#define cGPIO_DIR_7 (1<<7) +#define cGPIO_DIR_6 (1<<6) +#define cGPIO_DIR_5 (1<<5) +#define cGPIO_DIR_4 (1<<4) +#define cGPIO_DIR_3 (1<<3) +#define cGPIO_DIR_2 (1<<2) +#define cGPIO_DIR_1 (1<<1) +#define cGPIO_DIR_0 (1<<0) + +// GPIO_PUL_EN bits +#define cGPIO_PUL_EN_7 (1<<7) +#define cGPIO_PUL_EN_6 (1<<6) +#define cGPIO_PUL_EN_5 (1<<5) +#define cGPIO_PUL_EN_4 (1<<4) +#define cGPIO_PUL_EN_3 (1<<3) +#define cGPIO_PUL_EN_2 (1<<2) +#define cGPIO_PUL_EN_1 (1<<1) +#define cGPIO_PUL_EN_0 (1<<0) + +// GPIO_PUL_SEL bits +#define cGPIO_PUL_SEL_7 (1<<7) +#define cGPIO_PUL_SEL_6 (1<<6) +#define cGPIO_PUL_SEL_5 (1<<5) +#define cGPIO_PUL_SEL_4 (1<<4) +#define cGPIO_PUL_SEL_3 (1<<3) +#define cGPIO_PUL_SEL_2 (1<<2) +#define cGPIO_PUL_SEL_1 (1<<1) +#define cGPIO_PUL_SEL_0 (1<<0) + +// GPIO_DS bits +#define cGPIO_DS_7 (1<<7) +#define cGPIO_DS_6 (1<<6) +#define cGPIO_DS_5 (1<<5) +#define cGPIO_DS_4 (1<<4) +#define cGPIO_DS_3 (1<<3) +#define cGPIO_DS_2 (1<<2) +#define cGPIO_DS_1 (1<<1) +#define cGPIO_DS_0 (1<<0) + +// SPI_CTRL bits +//#define cSPI_CTRL_MISO_HIZ_EN (1<<1) +//#define cSPI_CTRL_PB_PROTECT (1<<0) + +// ANT_PAD_CTRL bits +#define cANT_PAD_CTRL_ANTX_POL (0x0F) +#define cANT_PAD_CTRL_ANTX_POL_Shift_c (4) +#define cANT_PAD_CTRL_ANTX_CTRLMODE (1<<3) +#define cANT_PAD_CTRL_ANTX_HZ (1<<2) +#define cANT_PAD_CTRL_ANTX_EN (3) + +// MISC_PAD_CTRL bits +#define cMISC_PAD_CTRL_MISO_HIZ_EN (1<<3) +#define cMISC_PAD_CTRL_IRQ_B_OD (1<<2) +#define cMISC_PAD_CTRL_NON_GPIO_DS (1<<1) +#define cMISC_PAD_CTRL_ANTX_CURR (1<<0) + +// ANT_AGC_CTRL bits +#define cANT_AGC_CTRL_FAD_EN_Shift_c (0) +#define cANT_AGC_CTRL_FAD_EN_Mask_c (1<<cANT_AGC_CTRL_FAD_EN_Shift_c) +#define cANT_AGC_CTRL_ANTX_Shift_c (1) +#define cANT_AGC_CTRL_ANTX_Mask_c (1<<cANT_AGC_CTRL_ANTX_Shift_c) + +// BSM_CTRL bits +#define cBSM_CTRL_BSM_EN (1<<0) + +// SOFT_RESET bits +#define cSOFT_RESET_SOG_RST (1<<7) +#define cSOFT_RESET_REGS_RST (1<<4) +#define cSOFT_RESET_PLL_RST (1<<3) +#define cSOFT_RESET_TX_RST (1<<2) +#define cSOFT_RESET_RX_RST (1<<1) +#define cSOFT_RESET_SEQ_MGR_RST (1<<0) + +// SEQ_MGR_CTRL bits +#define cSEQ_MGR_CTRL_SEQ_STATE_CTRL (3) +#define cSEQ_MGR_CTRL_SEQ_STATE_CTRL_Shift_c (6) +#define cSEQ_MGR_CTRL_NO_RX_RECYCLE (1<<5) +#define cSEQ_MGR_CTRL_LATCH_PREAMBLE (1<<4) +#define cSEQ_MGR_CTRL_EVENT_TMR_DO_NOT_LATCH (1<<3) +#define cSEQ_MGR_CTRL_CLR_NEW_SEQ_INHIBIT (1<<2) +#define cSEQ_MGR_CTRL_PSM_LOCK_DIS (1<<1) +#define cSEQ_MGR_CTRL_PLL_ABORT_OVRD (1<<0) + +// SEQ_MGR_STS bits +#define cSEQ_MGR_STS_TMR2_SEQ_TRIG_ARMED (1<<7) +#define cSEQ_MGR_STS_RX_MODE (1<<6) +#define cSEQ_MGR_STS_RX_TIMEOUT_PENDING (1<<5) +#define cSEQ_MGR_STS_NEW_SEQ_INHIBIT (1<<4) +#define cSEQ_MGR_STS_SEQ_IDLE (1<<3) +#define cSEQ_MGR_STS_XCVSEQ_ACTUAL (7) + +// ABORT_STS bits +#define cABORT_STS_PLL_ABORTED (1<<2) +#define cABORT_STS_TC3_ABORTED (1<<1) +#define cABORT_STS_SW_ABORTED (1<<0) + +// FILTERFAIL_CODE2 bits +#define cFILTERFAIL_CODE2_PAN_SEL (1<<7) +#define cFILTERFAIL_CODE2_9_8 (3) + +// PHY_STS bits +#define cPHY_STS_PLL_UNLOCK (1<<7) +#define cPHY_STS_PLL_LOCK_ERR (1<<6) +#define cPHY_STS_PLL_LOCK (1<<5) +#define cPHY_STS_CRCVALID (1<<3) +#define cPHY_STS_FILTERFAIL_FLAG_SEL (1<<2) +#define cPHY_STS_SFD_DET (1<<1) +#define cPHY_STS_PREAMBLE_DET (1<<0) + +// TESTMODE_CTRL bits +#define cTEST_MODE_CTRL_HOT_ANT (1<<4) +#define cTEST_MODE_CTRL_IDEAL_RSSI_EN (1<<3) +#define cTEST_MODE_CTRL_IDEAL_PFC_EN (1<<2) +#define cTEST_MODE_CTRL_CONTINUOUS_EN (1<<1) +#define cTEST_MODE_CTRL_FPGA_EN (1<<0) + +// DTM_CTRL1 bits +#define cDTM_CTRL1_ATM_LOCKED (1<<7) +#define cDTM_CTRL1_DTM_EN (1<<6) +#define cDTM_CTRL1_PAGE5 (1<<5) +#define cDTM_CTRL1_PAGE4 (1<<4) +#define cDTM_CTRL1_PAGE3 (1<<3) +#define cDTM_CTRL1_PAGE2 (1<<2) +#define cDTM_CTRL1_PAGE1 (1<<1) +#define cDTM_CTRL1_PAGE0 (1<<0) + +// TX_MODE_CTRL +#define cTX_MODE_CTRL_TX_INV (1<<4) +#define cTX_MODE_CTRL_BT_EN (1<<3) +#define cTX_MODE_CTRL_DTS2 (1<<2) +#define cTX_MODE_CTRL_DTS1 (1<<1) +#define cTX_MODE_CTRL_DTS0 (1<<0) + +#define cTX_MODE_CTRL_DTS_MASK (7) + +// CLK_OUT_CTRL bits +#define cCLK_OUT_EXTEND (1<<7) +#define cCLK_OUT_HIZ (1<<6) +#define cCLK_OUT_SR (1<<5) +#define cCLK_OUT_DS (1<<4) +#define cCLK_OUT_EN (1<<3) +#define cCLK_OUT_DIV_Mask (7<<0) + +#define gCLK_OUT_FREQ_32_MHz (0) +#define gCLK_OUT_FREQ_16_MHz (1) +#define gCLK_OUT_FREQ_8_MHz (2) +#define gCLK_OUT_FREQ_4_MHz (3) +#define gCLK_OUT_FREQ_1_MHz (4) +#define gCLK_OUT_FREQ_250_KHz (5) +#define gCLK_OUT_FREQ_62_5_KHz (6) +#define gCLK_OUT_FREQ_32_78_KHz (7) +#define gCLK_OUT_FREQ_DISABLE (8) + + + + +#endif /* __MCR20_REG_H__ */
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1818 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "NanostackRfPhyMcr20a.h" + +#ifdef MBED_CONF_NANOSTACK_CONFIGURATION + +#include "ns_types.h" +#include "platform/arm_hal_interrupt.h" +#include "nanostack/platform/arm_hal_phy.h" +#include <string.h> +#include "rtos.h" + +/* Freescale headers which are for C files */ +extern "C" { +#include "MCR20Drv.h" +#include "MCR20Reg.h" +#include "MCR20Overwrites.h" +} + + +#define RF_BUFFER_SIZE 128 + +/*Radio RX and TX state definitions*/ +#define RFF_ON 0x01 +#define RFF_RX 0x02 +#define RFF_TX 0x04 +#define RFF_CCA 0x08 + +#define RF_MODE_NORMAL 0 +#define RF_MODE_SNIFFER 1 + +#define RF_CCA_THRESHOLD 75 /* -75 dBm */ + +#define RF_TX_POWER_MAX 0 + +/* PHY constants in symbols */ +#define gPhyWarmUpTime_c 9 +#define gPhySHRDuration_c 10 +#define gPhySymbolsPerOctet_c 2 +#define gPhyAckWaitDuration_c 54 + +#define gCcaED_c 0 +#define gCcaCCA_MODE1_c 1 + +#define gXcvrRunState_d gXcvrPwrAutodoze_c +#if !defined(TARGET_KW24D) + #define gXcvrLowPowerState_d gXcvrPwrHibernate_c +#else + #define gXcvrLowPowerState_d gXcvrPwrAutodoze_c +#endif + +/* MCR20A XCVR states */ +typedef enum xcvrState_tag{ + gIdle_c, + gRX_c, + gTX_c, + gCCA_c, + gTR_c, + gCCCA_c, +}xcvrState_t; + +/* MCR20A XCVR low power states */ +typedef enum xcvrPwrMode_tag{ + gXcvrPwrIdle_c, + gXcvrPwrAutodoze_c, + gXcvrPwrDoze_c, + gXcvrPwrHibernate_c +}xcvrPwrMode_t; + + +/*RF Part Type*/ +typedef enum +{ + FREESCALE_UNKNOW_DEV = 0, + FREESCALE_MCR20A +}rf_trx_part_e; + +/*Atmel RF states*/ +typedef enum +{ + NOP = 0x00, + BUSY_RX = 0x01, + RF_TX_START = 0x02, + FORCE_TRX_OFF = 0x03, + FORCE_PLL_ON = 0x04, + RX_ON = 0x06, + TRX_OFF = 0x08, + PLL_ON = 0x09, + BUSY_RX_AACK = 0x11, + SLEEP = 0x0F, + RX_AACK_ON = 0x16, + TX_ARET_ON = 0x19 +}rf_trx_states_t; + +/*RF receive buffer*/ +static uint8_t rf_buffer[RF_BUFFER_SIZE]; + +/* TX info */ +static uint8_t radio_tx_power = 0x17; /* 0 dBm */ +static uint8_t mac_tx_handle = 0; +static uint8_t need_ack = 0; +static uint16_t tx_len = 0; + +/* RF driver data */ +static xcvrState_t mPhySeqState; +static xcvrPwrMode_t mPwrState; +static phy_device_driver_s device_driver; +static uint8_t mStatusAndControlRegs[8]; +static uint8_t rf_rnd = 0; +static int8_t rf_radio_driver_id = -1; +static uint8_t MAC_address[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + +/* Driver instance handle and hardware */ +static NanostackRfPhyMcr20a *rf = NULL; +static SPI *spi = NULL; +static DigitalOut *cs = NULL; +static DigitalOut *rst = NULL; +static InterruptIn *irq = NULL; +static DigitalIn *irq_pin = NULL; +static Thread irq_thread(osPriorityRealtime, 1024); + +/* Channel info */ /* 2405 2410 2415 2420 2425 2430 2435 2440 2445 2450 2455 2460 2465 2470 2475 2480 */ +static const uint8_t pll_int[16] = {0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D}; +static const uint16_t pll_frac[16] = {0x2800, 0x5000, 0x7800, 0xA000, 0xC800, 0xF000, 0x1800, 0x4000, 0x6800, 0x9000, 0xB800, 0xE000, 0x0800, 0x3000, 0x5800, 0x8000}; + +/* Channel configurations for 2.4 */ +static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK}; + +static const phy_device_channel_page_s phy_channel_pages[] = { + { CHANNEL_PAGE_0, &phy_24ghz}, + { CHANNEL_PAGE_0, NULL} +}; + + +static rf_trx_part_e rf_radio_type_read(void); + +MBED_UNUSED static void rf_ack_wait_timer_start(uint16_t slots); +MBED_UNUSED static void rf_ack_wait_timer_stop(void); +MBED_UNUSED static void rf_handle_cca_ed_done(void); +MBED_UNUSED static void rf_handle_tx_end(void); +MBED_UNUSED static void rf_handle_rx_end(void); +MBED_UNUSED static void rf_on(void); +MBED_UNUSED static void rf_receive(void); +MBED_UNUSED static void rf_poll_trx_state_change(rf_trx_states_t trx_state); +MBED_UNUSED static void rf_init(void); +MBED_UNUSED static void rf_set_mac_address(const uint8_t *ptr); +MBED_UNUSED static int8_t rf_device_register(void); +MBED_UNUSED static void rf_device_unregister(void); +MBED_UNUSED static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ); +MBED_UNUSED static void rf_cca_abort(void); +MBED_UNUSED static void rf_read_mac_address(uint8_t *ptr); +MBED_UNUSED static int8_t rf_read_random(void); +MBED_UNUSED static void rf_calibration_cb(void); +MBED_UNUSED static void rf_init_phy_mode(void); +MBED_UNUSED static void rf_ack_wait_timer_interrupt(void); +MBED_UNUSED static void rf_calibration_timer_interrupt(void); +MBED_UNUSED static void rf_calibration_timer_start(uint32_t slots); +MBED_UNUSED static void rf_cca_timer_interrupt(void); +MBED_UNUSED static void rf_cca_timer_start(uint32_t slots); +MBED_UNUSED static uint16_t rf_get_phy_mtu_size(void); +MBED_UNUSED static uint8_t rf_scale_lqi(int8_t rssi); + +/** + * RF output power write + * + * \brief TX power has to be set before network start. + * + * \param power + * See datasheet for TX power settings + * + * \return 0, Supported Value + * \return -1, Not Supported Value + */ +MBED_UNUSED static int8_t rf_tx_power_set(uint8_t power); +MBED_UNUSED static uint8_t rf_tx_power_get(void); +MBED_UNUSED static int8_t rf_enable_antenna_diversity(void); + +/* Private functions */ +MBED_UNUSED static void rf_abort(void); +MBED_UNUSED static void rf_promiscuous(uint8_t mode); +MBED_UNUSED static void rf_get_timestamp(uint32_t *pRetClk); +MBED_UNUSED static void rf_set_timeout(uint32_t *pEndTime); +MBED_UNUSED static void rf_set_power_state(xcvrPwrMode_t newState); +MBED_UNUSED static uint8_t rf_if_read_rnd(void); +MBED_UNUSED static uint8_t rf_convert_LQI(uint8_t hwLqi); +MBED_UNUSED static uint8_t rf_get_channel_energy(void); +MBED_UNUSED static uint8_t rf_convert_energy_level(uint8_t energyLevel); +MBED_UNUSED static int8_t rf_convert_LQI_to_RSSI(uint8_t lqi); +MBED_UNUSED static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel); +MBED_UNUSED static int8_t rf_extension(phy_extension_type_e extension_type,uint8_t *data_ptr); +MBED_UNUSED static int8_t rf_address_write(phy_address_type_e address_type,uint8_t *address_ptr); +MBED_UNUSED static void rf_mac64_read(uint8_t *address); +static void PHY_InterruptThread(void); +static void handle_interrupt(void); + + +/* + * \brief Read connected radio part. + * + * This function only return valid information when rf_init() is called + * + * \return + */ +static rf_trx_part_e rf_radio_type_read(void) +{ + return FREESCALE_MCR20A; +} + +/* + * \brief Function initialises and registers the RF driver. + * + * \param none + * + * \return rf_radio_driver_id Driver ID given by NET library + */ +static int8_t rf_device_register(void) +{ + rf_trx_part_e radio_type; + + rf_init(); + + + + radio_type = rf_radio_type_read(); + if(radio_type == FREESCALE_MCR20A) + { + /*Set pointer to MAC address*/ + device_driver.PHY_MAC = MAC_address; + device_driver.driver_description = (char*)"FREESCALE_MAC"; + + //Create setup Used Radio chips + /*Type of RF PHY is SubGHz*/ + device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; + + device_driver.phy_channel_pages = phy_channel_pages; + /*Maximum size of payload is 127*/ + device_driver.phy_MTU = 127; + /*No header in PHY*/ + device_driver.phy_header_length = 0; + /*No tail in PHY*/ + device_driver.phy_tail_length = 0; + /*Set address write function*/ + device_driver.address_write = &rf_address_write; + /*Set RF extension function*/ + device_driver.extension = &rf_extension; + /*Set RF state control function*/ + device_driver.state_control = &rf_interface_state_control; + /*Set transmit function*/ + device_driver.tx = &rf_start_cca; + /*Upper layer callbacks init to NULL*/ + device_driver.phy_rx_cb = NULL; + device_driver.phy_tx_done_cb = NULL; + /*Virtual upper data callback init to NULL*/ + device_driver.arm_net_virtual_rx_cb = NULL; + device_driver.arm_net_virtual_tx_cb = NULL; + + /*Register device driver*/ + rf_radio_driver_id = arm_net_phy_register(&device_driver); + } + + return rf_radio_driver_id; +} + +/* + * \brief Function unregisters the RF driver. + * + * \param none + * + * \return none + */ +static void rf_device_unregister(void) +{ + arm_net_phy_unregister(rf_radio_driver_id); +} + +/* + * \brief Function returns the generated 8-bit random value for seeding Pseudo-random generator. + * + * \param none + * + * \return random value + */ +static int8_t rf_read_random(void) +{ + return rf_rnd; +} + +/* + * \brief Function is a call back for ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_ack_wait_timer_interrupt(void) +{ + /* The packet was transmitted successfully, but no ACK was received */ + if (device_driver.phy_tx_done_cb) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1); + } + rf_receive(); +} + +/* + * \brief Function is a call back for calibration interval timer. + * + * \param none + * + * \return none + */ +static void rf_calibration_timer_interrupt(void) +{ +} + +/* + * \brief Function is a call back for cca interval timer. + * + * \param none + * + * \return none + */ +static void rf_cca_timer_interrupt(void) +{ + /* CCA time-out handled by Hardware */ +} + + +/* + * \brief Function starts the ACK wait time-out. + * + * \param slots The ACK wait time-out in [symbols] + * + * \return none + */ +static void rf_ack_wait_timer_start(uint16_t time) +{ + uint32_t timeout; + + rf_get_timestamp(&timeout); + timeout += time; + rf_set_timeout(&timeout); +} + +/* + * \brief Function starts the calibration interval. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_calibration_timer_start(uint32_t slots) +{ + (void)slots; +} + +/* + * \brief Function starts the CCA timout. + * + * \param slots Given slots, resolution 50us + * + * \return none + */ +static void rf_cca_timer_start(uint32_t slots) +{ + (void)slots; +} + +/* + * \brief Function stops the ACK wait timeout. + * + * \param none + * + * \return none + */ +static void rf_ack_wait_timer_stop(void) +{ +} + +/* + * \brief Function reads the MAC address array. + * + * \param ptr Pointer to read array + * + * \return none + */ +static void rf_read_mac_address(uint8_t *ptr) +{ + memcpy(ptr, MAC_address, 8); +} + +/* + * \brief Function sets the MAC address array. + * + * \param ptr Pointer to given MAC address array + * + * \return none + */ +static void rf_set_mac_address(const uint8_t *ptr) +{ + memcpy(MAC_address, ptr, 8); +} + +static uint16_t rf_get_phy_mtu_size(void) +{ + return device_driver.phy_MTU; +} + +/* + * \brief Function writes 16-bit address in RF address filter. + * + * \param short_address Given short address + * + * \return none + */ +static void rf_set_short_adr(uint8_t * short_address) +{ + /* Write one register at a time to be accessible from hibernate mode */ + MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_MSB, short_address[0]); + MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_LSB, short_address[1]); +} + +/* + * \brief Function writes PAN Id in RF PAN Id filter. + * + * \param pan_id Given PAN Id + * + * \return none + */ +static void rf_set_pan_id(uint8_t *pan_id) +{ + /* Write one register at a time to be accessible from hibernate mode */ + MCR20Drv_IndirectAccessSPIWrite(MACPANID0_MSB, pan_id[0]); + MCR20Drv_IndirectAccessSPIWrite(MACPANID0_LSB, pan_id[1]); +} + +/* + * \brief Function writes 64-bit address in RF address filter. + * + * \param address Given 64-bit address + * + * \return none + */ +static void rf_set_address(uint8_t *address) +{ + /* Write one register at a time to be accessible from hibernate mode */ + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_0, address[7]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_8, address[6]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_16, address[5]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_24, address[4]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_32, address[3]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_40, address[2]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_48, address[1]); + MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_56, address[0]); +} + +/* + * \brief Function sets the RF channel. + * + * \param ch New channel + * + * \return none + */ +static void rf_channel_set(uint8_t channel) +{ + MCR20Drv_DirectAccessSPIWrite(PLL_INT0, pll_int[channel - 11]); + MCR20Drv_DirectAccessSPIMultiByteWrite(PLL_FRAC0_LSB, (uint8_t *) &pll_frac[channel - 11], 2); +} + + +/* + * \brief Function initialises the radio driver and resets the radio. + * + * \param none + * + * \return none + */ +static void rf_init(void) +{ + uint32_t index; + mPhySeqState = gIdle_c; + mPwrState = gXcvrPwrIdle_c; + /*Reset RF module*/ + MCR20Drv_RESET(); + /* Initialize the transceiver SPI driver */ + MCR20Drv_Init(); + /* Disable Tristate on MISO for SPI reads */ + MCR20Drv_IndirectAccessSPIWrite(MISC_PAD_CTRL, 0x02); + /* Set XCVR clock output settings */ + #if !defined(TARGET_KW24D) + MCR20Drv_Set_CLK_OUT_Freq(gMCR20_ClkOutFreq_d); + #endif + /* Set default XCVR power state */ + rf_set_power_state(gXcvrRunState_d); + + /* PHY_CTRL1 default HW settings + AUTOACK enabled */ + mStatusAndControlRegs[PHY_CTRL1] = cPHY_CTRL1_AUTOACK; + /* PHY_CTRL2 : mask all PP interrupts */ + mStatusAndControlRegs[PHY_CTRL2] = cPHY_CTRL2_CRC_MSK | \ + cPHY_CTRL2_PLL_UNLOCK_MSK | \ + /*cPHY_CTRL2_FILTERFAIL_MSK | */ \ + cPHY_CTRL2_RX_WMRK_MSK | \ + cPHY_CTRL2_CCAMSK | \ + cPHY_CTRL2_RXMSK | \ + cPHY_CTRL2_TXMSK | \ + cPHY_CTRL2_SEQMSK; + /* PHY_CTRL3 : enable timer 3 and disable remaining interrupts */ + mStatusAndControlRegs[PHY_CTRL3] = cPHY_CTRL3_ASM_MSK | \ + cPHY_CTRL3_PB_ERR_MSK | \ + cPHY_CTRL3_WAKE_MSK | \ + cPHY_CTRL3_TMR3CMP_EN; + /* PHY_CTRL4 unmask global TRX interrupts, enable 16 bit mode for TC2 - TC2 prime EN */ + mStatusAndControlRegs[PHY_CTRL4] = cPHY_CTRL4_TC2PRIME_EN | (gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c); + /* Clear all PP IRQ bits to avoid unexpected interrupts immediately after initialization */ + mStatusAndControlRegs[IRQSTS1] = cIRQSTS1_PLL_UNLOCK_IRQ | \ + cIRQSTS1_FILTERFAIL_IRQ | \ + cIRQSTS1_RXWTRMRKIRQ | \ + cIRQSTS1_CCAIRQ | \ + cIRQSTS1_RXIRQ | \ + cIRQSTS1_TXIRQ | \ + cIRQSTS1_SEQIRQ; + + mStatusAndControlRegs[IRQSTS2] = cIRQSTS2_ASM_IRQ | cIRQSTS2_PB_ERR_IRQ | cIRQSTS2_WAKE_IRQ; + /* Mask and clear all TMR IRQs */ + mStatusAndControlRegs[IRQSTS3] = cIRQSTS3_TMR4MSK | cIRQSTS3_TMR3MSK | cIRQSTS3_TMR2MSK | cIRQSTS3_TMR1MSK | \ + cIRQSTS3_TMR4IRQ | cIRQSTS3_TMR3IRQ | cIRQSTS3_TMR2IRQ | cIRQSTS3_TMR1IRQ; + /* Write settings to XCVR */ + MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 5); + /* Clear all interrupts */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, &mStatusAndControlRegs[IRQSTS1], 3); + + /* RX_FRAME_FILTER. Accept FrameVersion 0 and 1 packets, reject all others */ + MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, (cRX_FRAME_FLT_FRM_VER | \ + cRX_FRAME_FLT_BEACON_FT | \ + cRX_FRAME_FLT_DATA_FT | \ + cRX_FRAME_FLT_CMD_FT )); + /* Direct register overwrites */ + for (index = 0; index < sizeof(overwrites_direct)/sizeof(overwrites_t); index++) + MCR20Drv_DirectAccessSPIWrite(overwrites_direct[index].address, overwrites_direct[index].data); + /* Indirect register overwrites */ + for (index = 0; index < sizeof(overwrites_indirect)/sizeof(overwrites_t); index++) + MCR20Drv_IndirectAccessSPIWrite(overwrites_indirect[index].address, overwrites_indirect[index].data); + + /* Set the CCA energy threshold value */ + MCR20Drv_IndirectAccessSPIWrite(CCA1_THRESH, RF_CCA_THRESHOLD); + /* Set prescaller to obtain 1 symbol (16us) timebase */ + MCR20Drv_IndirectAccessSPIWrite(TMR_PRESCALE, 0x05); + + MCR20Drv_IRQ_Enable(); + + /*Read random variable. This will be used when seeding pseudo-random generator*/ + rf_rnd = rf_if_read_rnd(); + /*Read eui64*/ + rf_mac64_read(MAC_address); + /*set default channel to 11*/ + rf_channel_set(11); + /*Start receiver*/ + rf_receive(); +} + +/** + * \brief Function gets called when MAC is setting radio off. + * + * \param none + * + * \return none + */ +static void rf_off(void) +{ + /* Abort any ongoing sequences */ + rf_abort(); + /* Set XCVR in a low power state */ + rf_set_power_state(gXcvrLowPowerState_d); +} + +/* + * \brief Function polls the RF state until it has changed to desired state. + * + * \param trx_state RF state + * + * \return none + */ +static void rf_poll_trx_state_change(rf_trx_states_t trx_state) +{ + (void)trx_state; +} + +/* + * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO. + * + * \param data_ptr Pointer to TX data + * \param data_length Length of the TX data + * \param tx_handle Handle to transmission + * \return 0 Success + * \return -1 Busy + */ +static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol ) +{ + uint8_t ccaMode; + + /* Parameter validation */ + if( !data_ptr || (data_length > 125) || (PHY_LAYER_PAYLOAD != data_protocol) ) + { + return -1; + } + + if( mPhySeqState == gRX_c ) + { + uint8_t phyReg = MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F; + /* Check for an Rx in progress. */ + if((phyReg <= 0x06) || (phyReg == 0x15) || (phyReg == 0x16)) + { + if (device_driver.phy_tx_done_cb) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1); + } + return -1; + } + rf_abort(); + } + + /*Check if transmitter is busy*/ + if( mPhySeqState != gIdle_c ) + { + /*Return busy*/ + return -1; + } + + /*Store TX handle*/ + mac_tx_handle = tx_handle; + /*Check if transmitted data needs to be acked*/ + need_ack = (*data_ptr & 0x20) == 0x20; + + /* Set XCVR power state in run mode */ + rf_set_power_state(gXcvrRunState_d); + /* Load data into XCVR */ + tx_len = data_length + 2; + MCR20Drv_PB_SPIBurstWrite(data_ptr - 1, data_length + 1); + MCR20Drv_PB_SPIByteWrite(0,tx_len); + + /* Set CCA mode 1 */ + ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE; + if( ccaMode != gCcaCCA_MODE1_c ) + { + mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c); + mStatusAndControlRegs[PHY_CTRL4] |= gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c; + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]); + } + + /* Read XCVR registers */ + mStatusAndControlRegs[0] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[1], 4); + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c; + mPhySeqState = gCCA_c; + + /* Ensure that no spurious interrupts are raised */ + mStatusAndControlRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */ + mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ); + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3); + + /* Write XCVR settings */ + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + + /* Unmask SEQ interrupt */ + mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]); + + /*Return success*/ + return 0; +} + +/* + * \brief Function aborts CCA process. + * + * \param none + * + * \return none + */ +static void rf_cca_abort(void) +{ + rf_abort(); +} + +/* + * \brief Function starts the transmission of the frame. Called from ISR context! + * + * \param none + * + * \return none + */ +static void rf_start_tx(void) +{ + /* Perform TxRxAck sequence if required by phyTxMode */ + if( need_ack ) + { + mStatusAndControlRegs[PHY_CTRL1] |= cPHY_CTRL1_RXACKRQD; + mPhySeqState = gTR_c; + } + else + { + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_RXACKRQD); + mPhySeqState = gTX_c; + } + + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + mStatusAndControlRegs[PHY_CTRL1] |= mPhySeqState; + + /* Unmask SEQ interrupt */ + mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK); + + /* Start the sequence immediately */ + MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 2); + + if( need_ack ) + { + rf_ack_wait_timer_start(gPhyWarmUpTime_c + gPhySHRDuration_c + tx_len * gPhySymbolsPerOctet_c + gPhyAckWaitDuration_c); + } +} + +/* + * \brief Function sets the RF in RX state. Called from ISR context! + * + * \param none + * + * \return none + */ +static void rf_receive(void) +{ + uint8_t phyRegs[5]; + + /* RX can start only from Idle state */ + if( mPhySeqState != gIdle_c ) + { + return; + } + + /* Set XCVR power state in run mode */ + rf_set_power_state(gXcvrRunState_d); + /* read XVCR settings */ + phyRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &phyRegs[IRQSTS2], 4); + /* unmask SEQ interrupt */ + phyRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK); + /* set XcvrSeq to RX */ + phyRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + phyRegs[PHY_CTRL1] |= gRX_c; + mPhySeqState = gRX_c; + /* Ensure that no spurious interrupts are raised */ + phyRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */ + phyRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ; + /* sync settings with XCVR */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, phyRegs, 5); +} + +/* + * \brief Function calibrates the radio. + * + * \param none + * + * \return none + */ +static void rf_calibration_cb(void) +{ +} + +/* + * \brief Function sets RF_ON flag when radio is powered. + * + * \param none + * + * \return none + */ +static void rf_on(void) +{ +} + +/* + * \brief Function is a call back for RX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_rx_end(void) +{ + uint8_t rf_lqi = MCR20Drv_DirectAccessSPIRead(LQI_VALUE); + int8_t rf_rssi = 0; + uint8_t len = mStatusAndControlRegs[RX_FRM_LEN] - 2; + + + /*Start receiver*/ + rf_receive(); + + /*Check the length is valid*/ + if(len > 1 && len < RF_BUFFER_SIZE) + { + rf_lqi = rf_convert_LQI(rf_lqi); + rf_rssi = rf_convert_LQI_to_RSSI(rf_lqi); + /*gcararu: Scale LQI using received RSSI, to match the LQI reported by the ATMEL radio */ + rf_lqi = rf_scale_lqi(rf_rssi); + + /*Read received packet*/ + MCR20Drv_PB_SPIBurstRead(rf_buffer, len); + if (device_driver.phy_rx_cb) { + device_driver.phy_rx_cb(rf_buffer, len, rf_lqi, rf_rssi, rf_radio_driver_id); + } + } +} + +/* + * \brief Function is called when MAC is shutting down the radio. + * + * \param none + * + * \return none + */ +static void rf_shutdown(void) +{ + /*Call RF OFF*/ + rf_off(); +} + +/* + * \brief Function is a call back for TX end interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_tx_end(void) +{ + uint8_t rx_frame_pending = mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_RX_FRM_PEND; + + /*Start receiver*/ + rf_receive(); + + if (!device_driver.phy_tx_done_cb) { + return; + } + + /*Call PHY TX Done API*/ + if( need_ack ) + { + if( rx_frame_pending ) + { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE_PENDING, 1, 1); + } + else + { + // arm_net_phy_tx_done(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1); + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE, 1, 1); + } + } + else + { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1); + } +} + +/* + * \brief Function is a call back for CCA ED done interrupt. + * + * \param none + * + * \return none + */ +static void rf_handle_cca_ed_done(void) +{ + /*Check the result of CCA process*/ + if( !(mStatusAndControlRegs[IRQSTS2] & cIRQSTS2_CCA) ) + { + rf_start_tx(); + } + else if (device_driver.phy_tx_done_cb) + { + /*Send CCA fail notification*/ + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1); + } +} + +/* + * \brief Function sets the TX power variable. + * + * \param power TX power setting + * + * \return 0 Success + * \return -1 Fail + */ +static int8_t rf_tx_power_set(uint8_t power) +{ + /* gcapraru: Map MCR20A Tx power levels over ATMEL values */ + static uint8_t pwrLevelMapping[16] = {25,25,25,24,24,24,23,23,22,22,21,20,19,18,17,14}; + + if( power > 15 ) + { + return -1; + } + + radio_tx_power = power; + MCR20Drv_DirectAccessSPIWrite(PA_PWR, pwrLevelMapping[power]); + return 0; +} + +/* + * \brief Function returns the TX power variable. + * + * \param none + * + * \return radio_tx_power TX power variable + */ +static uint8_t rf_tx_power_get(void) +{ + return radio_tx_power; +} + +/* + * \brief Function enables the usage of Antenna diversity. + * + * \param none + * + * \return 0 Success + */ +static int8_t rf_enable_antenna_diversity(void) +{ + uint8_t phyReg; + + phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_AGC_CTRL); + phyReg |= cANT_AGC_CTRL_FAD_EN_Mask_c; + MCR20Drv_IndirectAccessSPIWrite(ANT_AGC_CTRL, phyReg); + + phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_PAD_CTRL); + phyReg |= 0x02; + MCR20Drv_IndirectAccessSPIWrite(ANT_PAD_CTRL, phyReg); + + return 0; +} + +/* + * \brief Function gives the control of RF states to MAC. + * + * \param new_state RF state + * \param rf_channel RF channel + * + * \return 0 Success + */ +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel) +{ + int8_t ret_val = 0; + switch (new_state) + { + /*Reset PHY driver and set to idle*/ + case PHY_INTERFACE_RESET: + break; + /*Disable PHY Interface driver*/ + case PHY_INTERFACE_DOWN: + rf_shutdown(); + break; + /*Enable PHY Interface driver*/ + case PHY_INTERFACE_UP: + rf_channel_set(rf_channel); + rf_receive(); + break; + /*Enable wireless interface ED scan mode*/ + case PHY_INTERFACE_RX_ENERGY_STATE: + rf_abort(); + rf_channel_set(rf_channel); + break; + case PHY_INTERFACE_SNIFFER_STATE: /**< Enable Sniffer state */ + rf_promiscuous(1); + rf_channel_set(rf_channel); + rf_receive(); + break; + } + return ret_val; +} + +/* + * \brief Function controls the ACK pending, channel setting and energy detection. + * + * \param extension_type Type of control + * \param data_ptr Data from NET library + * + * \return 0 Success + */ +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr) +{ + switch (extension_type) + { + /*Control MAC pending bit for Indirect data transmission*/ + case PHY_EXTENSION_CTRL_PENDING_BIT: + { + uint8_t reg = MCR20Drv_DirectAccessSPIRead(SRC_CTRL); + + if(*data_ptr) + { + reg |= cSRC_CTRL_ACK_FRM_PND; + } + else + { + reg &= ~cSRC_CTRL_ACK_FRM_PND; + } + + MCR20Drv_DirectAccessSPIWrite(SRC_CTRL, reg); + break; + + } + /*Return frame Auto Ack frame pending status*/ + case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: { + uint8_t reg = MCR20Drv_DirectAccessSPIRead(SRC_CTRL); + if (reg & cSRC_CTRL_ACK_FRM_PND) { + *data_ptr = 1; + } else { + *data_ptr = 0; + } + break; + } + /*Set channel*/ + case PHY_EXTENSION_SET_CHANNEL: + break; + /*Read energy on the channel*/ + case PHY_EXTENSION_READ_CHANNEL_ENERGY: + *data_ptr = rf_get_channel_energy(); + break; + /*Read status of the link*/ + case PHY_EXTENSION_READ_LINK_STATUS: + break; + case PHY_EXTENSION_CONVERT_SIGNAL_INFO: + break; + case PHY_EXTENSION_ACCEPT_ANY_BEACON: + break; + } + return 0; +} + +/* + * \brief Function sets the addresses to RF address filters. + * + * \param address_type Type of address + * \param address_ptr Pointer to given address + * + * \return 0 Success + */ +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr) +{ + int8_t ret_val = 0; + switch (address_type) + { + /*Set 48-bit address*/ + case PHY_MAC_48BIT: + break; + /*Set 64-bit address*/ + case PHY_MAC_64BIT: + rf_set_address(address_ptr); + break; + /*Set 16-bit address*/ + case PHY_MAC_16BIT: + rf_set_short_adr(address_ptr); + break; + /*Set PAN Id*/ + case PHY_MAC_PANID: + rf_set_pan_id(address_ptr); + break; + } + return ret_val; +} + +static void rf_mac64_read(uint8_t *address) +{ + /* Write one register at a time to be accessible from hibernate mode */ + address[7] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_0); + address[6] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_8); + address[5] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_16); + address[4] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_24); + address[3] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_32); + address[2] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_40); + address[1] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_48); + address[0] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_56); + +} + +/* + * \brief Function initialises the ACK wait time and returns the used PHY mode. + * + * \param none + * + * \return tmp Used PHY mode + */ +static void rf_init_phy_mode(void) +{ +} + +/* + * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt. + * + * \param none + * + * \return none + */ +static void PHY_InterruptHandler(void) +{ + /* Disable and clear transceiver(IRQ_B) interrupt */ + MCR20Drv_IRQ_Disable(); + irq_thread.signal_set(1); +} + +static void PHY_InterruptThread(void) +{ + for (;;) { + osEvent event = irq_thread.signal_wait(0); + if (event.status != osEventSignal) { + continue; + } + handle_interrupt(); + } +} + +static void handle_interrupt(void) +{ + uint8_t xcvseqCopy; + + //MCR20Drv_IRQ_Clear(); + + /* Read transceiver interrupt status and control registers */ + mStatusAndControlRegs[IRQSTS1] = + MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 7); + + xcvseqCopy = mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ; + + /* Flter Fail IRQ */ + if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_FILTERFAIL_IRQ) && + !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_FILTERFAIL_MSK) ) + { + if( xcvseqCopy == gRX_c ) + { + /* Abort current SEQ */ + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + /* Wait for Sequence Idle */ + while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0); + /* Clear IRQ flags: */ + MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ); + /* Restart Rx asap */ + mStatusAndControlRegs[PHY_CTRL1] |= gRX_c; + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + } + } + + /* TMR3 IRQ: ACK wait time-out */ + if( (mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3IRQ) && + !(mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3MSK) ) + { + /* Disable TMR3 IRQ */ + mStatusAndControlRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK; + + if( xcvseqCopy == gTR_c ) + { + /* Set XCVR to Idle */ + mPhySeqState = gIdle_c; + mStatusAndControlRegs[PHY_CTRL1] &= ~( cPHY_CTRL1_XCVSEQ ); + /* Mask interrupts */ + mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK; + /* Sync settings with XCVR */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5); + + rf_ack_wait_timer_interrupt(); + MCR20Drv_IRQ_Enable(); + return; + } + } + + /* Sequencer interrupt, the autosequence has completed */ + if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_SEQIRQ) && + !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_SEQMSK) ) + { + /* Set XCVR to Idle */ + mPhySeqState = gIdle_c; + mStatusAndControlRegs[PHY_CTRL1] &= ~( cPHY_CTRL1_XCVSEQ ); + /* Mask interrupts */ + mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK; + /* Sync settings with XCVR */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5); + + /* PLL unlock, the autosequence has been aborted due to PLL unlock */ + if( mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_PLL_UNLOCK_IRQ ) + { + if(xcvseqCopy == gRX_c) + { + rf_receive(); + } + MCR20Drv_IRQ_Enable(); + return; + } + + switch(xcvseqCopy) + { + case gTX_c: + case gTR_c: + rf_handle_tx_end(); + break; + + case gRX_c: + rf_handle_rx_end(); + break; + + case gCCA_c: + rf_handle_cca_ed_done(); + break; + + default: + break; + } + + MCR20Drv_IRQ_Enable(); + return; + } + /* Other IRQ. Clear XCVR interrupt flags */ + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3); + MCR20Drv_IRQ_Enable(); +} + +/* + * \brief Function forces the XCVR to Idle state. + * + * \param none + * + * \return none + */ +static void rf_abort(void) +{ + /* Mask XCVR irq */ + MCR20Drv_IRQ_Disable(); + + mPhySeqState = gIdle_c; + + mStatusAndControlRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 5); + + /* Mask SEQ interrupt */ + mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_SEQMSK; + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]); + + if( (mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ) != gIdle_c ) + { + /* Abort current SEQ */ + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + + /* Wait for Sequence Idle (if not already) */ + while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0); + //while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ)); + mStatusAndControlRegs[IRQSTS1] |= cIRQSTS1_SEQIRQ; + } + + /* Clear all PP IRQ bits to avoid unexpected interrupts and mask TMR3 interrupt. + Do not change TMR IRQ status. */ + mStatusAndControlRegs[IRQSTS3] &= 0xF0; + mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ); + MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3); + + /* Unmask XCVR irq */ + MCR20Drv_IRQ_Enable(); +} + +/* + * \brief Function reads a time-stamp value from XCVR [symbols] + * + * \param pEndTime pointer to location where time-stamp will be stored + * + * \return none + */ +static void rf_get_timestamp(uint32_t *pRetClk) +{ + if(NULL == pRetClk) + { + return; + } + + platform_enter_critical(); + + *pRetClk = 0; + MCR20Drv_DirectAccessSPIMultiByteRead(EVENT_TMR_LSB, (uint8_t *) pRetClk, 3); + + platform_exit_critical(); +} + +/* + * \brief Function set a time-out to an XCVR sequence. + * + * \param pEndTime pointer to the sequence time-out value [symbols] + * + * \return none + */ +static void rf_set_timeout(uint32_t *pEndTime) +{ + uint8_t phyReg; + + if(NULL == pEndTime) + { + return; + } + + platform_enter_critical(); + + phyReg = MCR20Drv_DirectAccessSPIRead(IRQSTS3); + phyReg &= 0xF0; /* do not change IRQ status */ + phyReg |= (cIRQSTS3_TMR3MSK); /* mask TMR3 interrupt */ + MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg); + + MCR20Drv_DirectAccessSPIMultiByteWrite(T3CMP_LSB, (uint8_t *) pEndTime, 3); + + phyReg &= ~(cIRQSTS3_TMR3MSK); /* unmask TMR3 interrupt */ + phyReg |= (cIRQSTS3_TMR3IRQ); /* aknowledge TMR3 IRQ */ + MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg); + + platform_exit_critical(); +} + +/* + * \brief Function reads a random number from RF. + * + * \param none + * + * \return 8-bit random number + */ +static uint8_t rf_if_read_rnd(void) +{ + uint8_t phyReg; + + MCR20Drv_IRQ_Disable(); + /* Check if XCVR is idle */ + phyReg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL1); + + if( (phyReg & cPHY_CTRL1_XCVSEQ) == gIdle_c ) + { + /* Program a new sequence */ + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, phyReg | gCCA_c); + /* Wait for sequence to finish */ + while( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ) ); + /* Clear interrupt flag */ + MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ); + } + + MCR20Drv_IRQ_Enable(); + + return MCR20Drv_IndirectAccessSPIRead(_RNG); +} + +/* + * \brief Function converts LQI into RSSI. + * + * \param LQI + * + * \return RSSI + */ +static int8_t rf_convert_LQI_to_RSSI(uint8_t lqi) +{ + int32_t rssi = (50*lqi - 16820) / 163; + return (int8_t)rssi; +} + +/* + * \brief Function scale the LQI value reported by RF into a 0-255 value. + * + * \param hwLqi - the LQI value reported by RF + * + * \return scaled LQI + */ +static uint8_t rf_convert_LQI(uint8_t hwLqi) +{ + uint32_t tmpLQI; + + /* LQI Saturation Level */ + if (hwLqi >= 230) + { + return 0xFF; + } + else if (hwLqi <= 9) + { + return 0; + } + else + { + /* Rescale the LQI values from min to saturation to the 0x00 - 0xFF range */ + /* The LQI value mst be multiplied by ~1.1087 */ + /* tmpLQI = hwLqi * 7123 ~= hwLqi * 65536 * 0.1087 = hwLqi * 2^16 * 0.1087*/ + tmpLQI = ((uint32_t)hwLqi * (uint32_t)7123 ); + /* tmpLQI = (tmpLQI / 2^16) + hwLqi */ + tmpLQI = (uint32_t)(tmpLQI >> 16) + (uint32_t)hwLqi; + + return (uint8_t)tmpLQI; + } +} + +/* + * \brief Function enables/disables Rx promiscuous mode. + * + * \param state of XCVR promiscuous mode + * + * \return none + */ +static void rf_promiscuous(uint8_t state) +{ + uint8_t rxFrameFltReg, phyCtrl4Reg; + + rxFrameFltReg = MCR20Drv_IndirectAccessSPIRead(RX_FRAME_FILTER); + phyCtrl4Reg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL4); + + if( state ) + { + /* FRM_VER[1:0] = b00. 00: Any FrameVersion accepted (0,1,2 & 3) */ + /* All frame types accepted*/ + phyCtrl4Reg |= cPHY_CTRL4_PROMISCUOUS; + rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER); + rxFrameFltReg |= (cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT); + } + else + { + phyCtrl4Reg &= ~cPHY_CTRL4_PROMISCUOUS; + /* FRM_VER[1:0] = b11. Accept FrameVersion 0 and 1 packets, reject all others */ + /* Beacon, Data and MAC command frame types accepted */ + rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER); + rxFrameFltReg |= (0x03 << cRX_FRAME_FLT_FRM_VER_Shift_c); + rxFrameFltReg &= ~(cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT); + } + + MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, rxFrameFltReg); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, phyCtrl4Reg); +} + +/* + * \brief Function used to switch XCVR power state. + * + * \param state The XCVR power mode + * + * \return none + */ +static void rf_set_power_state(xcvrPwrMode_t newState) +{ + uint8_t pwrMode; + uint8_t xtalState; + + if( mPwrState == newState ) + { + return; + } + + /* Read power settings from RF */ + pwrMode = MCR20Drv_DirectAccessSPIRead(PWR_MODES); + xtalState = pwrMode & cPWR_MODES_XTALEN; + + switch( newState ) + { + case gXcvrPwrIdle_c: + pwrMode &= ~(cPWR_MODES_AUTODOZE); + pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_PMC_MODE); + break; + case gXcvrPwrAutodoze_c: + pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE); + break; + case gXcvrPwrDoze_c: + pwrMode &= ~(cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE); + pwrMode |= cPWR_MODES_XTALEN; + break; + case gXcvrPwrHibernate_c: + pwrMode &= ~(cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE); + break; + default: + return; + } + + mPwrState = newState; + MCR20Drv_DirectAccessSPIWrite(PWR_MODES, pwrMode); + + if( !xtalState && (pwrMode & cPWR_MODES_XTALEN)) + { + /* wait for crystal oscillator to complet its warmup */ + while( ( MCR20Drv_DirectAccessSPIRead(PWR_MODES) & cPWR_MODES_XTAL_READY ) != cPWR_MODES_XTAL_READY); + /* wait for radio wakeup from hibernate interrupt */ + while( ( MCR20Drv_DirectAccessSPIRead(IRQSTS2) & (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) ) != (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) ); + + MCR20Drv_DirectAccessSPIWrite(IRQSTS2, cIRQSTS2_WAKE_IRQ); + } +} + +/* + * \brief Function reads the energy level on the preselected channel. + * + * \return energy level + */ +static uint8_t rf_get_channel_energy(void) +{ + uint8_t ccaMode; + + MCR20Drv_IRQ_Disable(); + /* RX can start only from Idle state */ + if( mPhySeqState != gIdle_c ) + { + MCR20Drv_IRQ_Enable(); + return 0; + } + + /* Set XCVR power state in run mode */ + rf_set_power_state(gXcvrRunState_d); + + /* Switch to ED mode */ + ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE; + if( ccaMode != gCcaED_c ) + { + mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c); + mStatusAndControlRegs[PHY_CTRL4] |= gCcaED_c << cPHY_CTRL4_CCATYPE_Shift_c; + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]); + } + + /* Start ED sequence */ + mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c; + MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + /* Wait for sequence to finish */ + while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ)); + /* Set XCVR to Idle */ + mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ); + MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]); + MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ); + + MCR20Drv_IRQ_Enable(); + + return rf_convert_energy_level(MCR20Drv_DirectAccessSPIRead(CCA1_ED_FNL)); +} + +/* + * \brief Function converts the energy level from dBm to a 0-255 value. + * + * \param energyLevel in dBm + * + * \return energy level (0-255) + */ +static uint8_t rf_convert_energy_level(uint8_t energyLevel) +{ + if(energyLevel >= 90) + { + /* ED value is below minimum. Return 0x00. */ + energyLevel = 0x00; + } + else if(energyLevel <= 26) + { + /* ED value is above maximum. Return 0xFF. */ + energyLevel = 0xFF; + } + else + { + /* Energy level (-90 dBm to -26 dBm ) --> varies form 0 to 64 */ + energyLevel = (90 - energyLevel); + /* Rescale the energy level values to the 0x00-0xff range (0 to 64 translates in 0 to 255) */ + /* energyLevel * 3.9844 ~= 4 */ + /* Multiply with 4=2^2 by shifting left. + The multiplication will not overflow beacause energyLevel has values between 0 and 63 */ + energyLevel <<= 2; + } + + return energyLevel; +} + +static uint8_t rf_scale_lqi(int8_t rssi) +{ + uint8_t scaled_lqi; + /*Worst case sensitivity*/ + const int8_t rf_sensitivity = -98; + + /*rssi < RF sensitivity*/ + if(rssi < rf_sensitivity) + scaled_lqi=0; + /*-91 dBm < rssi < -81 dBm (AT86RF233 XPro)*/ + /*-90 dBm < rssi < -80 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 10)) + scaled_lqi=31; + /*-81 dBm < rssi < -71 dBm (AT86RF233 XPro)*/ + /*-80 dBm < rssi < -70 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 20)) + scaled_lqi=207; + /*-71 dBm < rssi < -61 dBm (AT86RF233 XPro)*/ + /*-70 dBm < rssi < -60 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 30)) + scaled_lqi=255; + /*-61 dBm < rssi < -51 dBm (AT86RF233 XPro)*/ + /*-60 dBm < rssi < -50 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 40)) + scaled_lqi=255; + /*-51 dBm < rssi < -41 dBm (AT86RF233 XPro)*/ + /*-50 dBm < rssi < -40 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 50)) + scaled_lqi=255; + /*-41 dBm < rssi < -31 dBm (AT86RF233 XPro)*/ + /*-40 dBm < rssi < -30 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 60)) + scaled_lqi=255; + /*-31 dBm < rssi < -21 dBm (AT86RF233 XPro)*/ + /*-30 dBm < rssi < -20 dBm (AT86RF212B XPro)*/ + else if(rssi < (rf_sensitivity + 70)) + scaled_lqi=255; + /*rssi > RF saturation*/ + else if(rssi > (rf_sensitivity + 80)) + scaled_lqi=111; + /*-21 dBm < rssi < -11 dBm (AT86RF233 XPro)*/ + /*-20 dBm < rssi < -10 dBm (AT86RF212B XPro)*/ + else + scaled_lqi=255; + + return scaled_lqi; +} + + +/*****************************************************************************/ +/* Layer porting to the Freescale driver */ +/*****************************************************************************/ +extern "C" void xcvr_spi_init(uint32_t instance) +{ + (void)instance; +} + +extern "C" void RF_IRQ_Init(void) { + MBED_ASSERT(irq != NULL); + irq->mode(PullUp); + irq->fall(&PHY_InterruptHandler); +} + +extern "C" void RF_IRQ_Enable(void) { + MBED_ASSERT(irq != NULL); + irq->enable_irq(); +} + +extern "C" void RF_IRQ_Disable(void) { + MBED_ASSERT(irq != NULL); + irq->disable_irq(); +} + +extern "C" uint8_t RF_isIRQ_Pending(void) { + MBED_ASSERT(rf != NULL); + return !irq_pin->read(); +} + +extern "C" void RF_RST_Set(int state) { + MBED_ASSERT(rst != NULL); + *rst = state; +} + +extern "C" void gXcvrAssertCS_d(void) +{ + MBED_ASSERT(cs != NULL); + *cs = 0; +} + +extern "C" void gXcvrDeassertCS_d(void) +{ + MBED_ASSERT(cs != NULL); + *cs = 1; +} + +extern "C" void xcvr_spi_configure_speed(uint32_t instance, uint32_t freq) +{ + MBED_ASSERT(spi != NULL); + (void)instance; + spi->frequency(freq); +} + +extern "C" void xcvr_spi_transfer(uint32_t instance, + uint8_t * sendBuffer, + uint8_t * receiveBuffer, + size_t transferByteCount) +{ + MBED_ASSERT(spi != NULL); + (void)instance; + volatile uint8_t dummy; + + if( !transferByteCount ) + return; + + if( !sendBuffer && !receiveBuffer ) + return; + + while( transferByteCount-- ) + { + if( sendBuffer ) + { + dummy = *sendBuffer; + sendBuffer++; + } + else + { + dummy = 0xFF; + } + + dummy = spi->write(dummy); + + if( receiveBuffer ) + { + *receiveBuffer = dummy; + receiveBuffer++; + } + } +} + +/*****************************************************************************/ +/*****************************************************************************/ + +static void rf_if_lock(void) +{ + platform_enter_critical(); +} + +static void rf_if_unlock(void) +{ + platform_exit_critical(); +} + +NanostackRfPhyMcr20a::NanostackRfPhyMcr20a(PinName spi_mosi, PinName spi_miso, + PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_irq) + : _spi(spi_mosi, spi_miso, spi_sclk), _rf_cs(spi_cs), _rf_rst(spi_rst, 1), + _rf_irq(spi_irq), _rf_irq_pin(spi_irq) +{ + // Do nothing +} + +NanostackRfPhyMcr20a::~NanostackRfPhyMcr20a() +{ + // Do nothing +} + +int8_t NanostackRfPhyMcr20a::rf_register() +{ + + rf_if_lock(); + + if (rf != NULL) { + rf_if_unlock(); + error("Multiple registrations of NanostackRfPhyMcr20a not supported"); + return -1; + } + + irq_thread.start(mbed::callback(PHY_InterruptThread)); + + _pins_set(); + int8_t radio_id = rf_device_register(); + if (radio_id < 0) { + _pins_clear(); + rf = NULL; + } + + rf_if_unlock(); + return radio_id; +} + +void NanostackRfPhyMcr20a::rf_unregister() +{ + rf_if_lock(); + + if (rf != this) { + rf_if_unlock(); + return; + } + + rf_device_unregister(); + rf = NULL; + _pins_clear(); + + rf_if_unlock(); +} + +void NanostackRfPhyMcr20a::get_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + memcpy((void*)mac, (void*)MAC_address, sizeof(MAC_address)); + + rf_if_unlock(); +} + +void NanostackRfPhyMcr20a::set_mac_address(uint8_t *mac) +{ + rf_if_lock(); + + if (NULL != rf) { + error("NanostackRfPhyAtmel cannot change mac address when running"); + rf_if_unlock(); + return; + } + memcpy((void*)MAC_address, (void*)mac, sizeof(MAC_address)); + + rf_if_unlock(); +} + +void NanostackRfPhyMcr20a::_pins_set() +{ + spi = &_spi; + cs = &_rf_cs; + rst = &_rf_rst; + irq = &_rf_irq; + irq_pin = &_rf_irq_pin; +} + +void NanostackRfPhyMcr20a::_pins_clear() +{ + spi = NULL; + cs = NULL; + rst = NULL; + irq = NULL; + irq_pin = NULL; +} + +#endif // MBED_CONF_NANOSTACK_CONFIGURATION
diff -r 000000000000 -r 119624335925 easy-connect/mcr20a-rf-driver/source/XcvrSpi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/mcr20a-rf-driver/source/XcvrSpi.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,89 @@ +/*! +* Copyright (c) 2015, Freescale Semiconductor, Inc. +* All rights reserved. +* +* \file XcvrSpi.h +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* +* o Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer. +* +* o Redistributions in binary form must reproduce the above copyright notice, this +* list of conditions and the following disclaimer in the documentation and/or +* other materials provided with the distribution. +* +* o Neither the name of Freescale Semiconductor, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, 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 __XCVR_SPI_H__ +#define __XCVR_SPI_H__ + + +/***************************************************************************** + * INCLUDED HEADERS * + *---------------------------------------------------------------------------* + * Add to this section all the headers that this module needs to include. * + * Note that it is not a good practice to include header files into header * + * files, so use this section only if there is no other better solution. * + *---------------------------------------------------------------------------* + *****************************************************************************/ + + +/***************************************************************************** + * PUBLIC MACROS * + *---------------------------------------------------------------------------* + * Add to this section all the access macros, registers mappings, bit access * + * macros, masks, flags etc ... + *---------------------------------------------------------------------------* + *****************************************************************************/ +#define gXcvrSpiInstance_c 0 + +/***************************************************************************** + * PUBLIC FUNCTIONS * + *---------------------------------------------------------------------------* + * Add to this section all the global functions prototype preceded (as a * + * good practice) by the keyword 'extern' * + *---------------------------------------------------------------------------* + *****************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +void RF_RST_Set(int state); +void RF_CS_Set(int state); +void RF_IRQ_Init(void); +void RF_IRQ_Disable(void); +void RF_IRQ_Enable(void); +uint8_t RF_isIRQ_Pending(void); + +void gXcvrAssertCS_d(void); +void gXcvrDeassertCS_d(void); + +void xcvr_spi_init(uint32_t instance); +void xcvr_spi_configure_speed(uint32_t instance, uint32_t freq); +void xcvr_spi_transfer(uint32_t instance, + uint8_t * sendBuffer, + uint8_t * receiveBuffer, + uint32_t transferByteCount); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* __XCVR_SPI_H__ */
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/stm-spirit1-rf-driver/#ce9e2f81f95f895652789eeb196443eff5ac6ed7
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ce9e2f81f95f895652789eeb196443eff5ac6ed7
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +b8e3da9b2999d1aec1e500d0acf6e725060d3515
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/stm-spirit1-rf-driver/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/index Binary file easy-connect/stm-spirit1-rf-driver/.git/index has changed
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 b8e3da9b2999d1aec1e500d0acf6e725060d3515 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322713 +0000 clone: from https://github.com/ARMmbed/stm-spirit1-rf-driver/ +b8e3da9b2999d1aec1e500d0acf6e725060d3515 ce9e2f81f95f895652789eeb196443eff5ac6ed7 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322715 +0000 checkout: moving from master to ce9e2f81f95f895652789eeb196443eff5ac6ed7
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 b8e3da9b2999d1aec1e500d0acf6e725060d3515 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322713 +0000 clone: from https://github.com/ARMmbed/stm-spirit1-rf-driver/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 b8e3da9b2999d1aec1e500d0acf6e725060d3515 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322713 +0000 clone: from https://github.com/ARMmbed/stm-spirit1-rf-driver/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/objects/pack/pack-0689660497529bb7343db960a700c59133742283.idx Binary file easy-connect/stm-spirit1-rf-driver/.git/objects/pack/pack-0689660497529bb7343db960a700c59133742283.idx has changed
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/objects/pack/pack-0689660497529bb7343db960a700c59133742283.pack Binary file easy-connect/stm-spirit1-rf-driver/.git/objects/pack/pack-0689660497529bb7343db960a700c59133742283.pack has changed
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,4 @@ +# pack-refs with: peeled +b8e3da9b2999d1aec1e500d0acf6e725060d3515 refs/remotes/origin/master +0ff4ca7537f0f2e9137c61ac21251ac06ca42bc3 refs/tags/v1.0.0 +ce9e2f81f95f895652789eeb196443eff5ac6ed7 refs/tags/v1.0.1
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +b8e3da9b2999d1aec1e500d0acf6e725060d3515
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/.gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/.gitignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,6 @@ +BUILD +.mbed +projectfiles +*.py* +RCS +atmel-rf-driver
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,12 @@ +# Prototype RF Driver for STM Sub-1 GHz RF Expansion Boards based on the SPSGRF-868 Module for STM32 Nucleo # + +Currently supported boards: + * [X-NUCLEO-IDS01A4](http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-connect-hw/x-nucleo-ids01a4.html) + +**Note**, in order to use expansion board `X-NUCLEO-IDS01A4` in mbed you need to perform the following HW modifications on the board: + * **Un**mount resistor `R4` + * **Mount** resistor `R7` + +Furthermore, on some Nucleo development boards (e.g. the [NUCLEO_F429ZI](https://developer.mbed.org/platforms/ST-Nucleo-F429ZI/)), in order to be able to use Ethernet together with these Sub-1 GHz RF expansion boards, you need to compile this driver with macro `SPIRIT1_SPI_MOSI=PB_5` defined, while the development board typically requires some HW modification as e.g. described [here](https://github.com/ARMmbed/sal-nanostack-driver-stm32-eth)! + +This driver can be used together with the 6LoWPAN stack (*a.k.a.* Nanostack).
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,7 @@ +{ + "name": "spirit1", + "config": { + "mac-address": "{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}" + }, + "macros": ["USE_STM32F4XX_NUCLEO", "X_NUCLEO_IDS01A4", "SPIRIT_USE_FULL_ASSERT"] +}
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/NanostackRfPhySpirit1.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/NanostackRfPhySpirit1.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,832 @@ +#include "NanostackRfPhySpirit1.h" + +#ifdef MBED_CONF_NANOSTACK_CONFIGURATION +#if MBED_CONF_RTOS_PRESENT + +#include "SimpleSpirit1.h" +#include "nanostack/platform/arm_hal_phy.h" +#include "platform/arm_hal_interrupt.h" + +#include "mbed_trace.h" +#define TRACE_GROUP "SPIRIT" + +/* Define beyond macro if you want to perform heavy debug tracing (includes tracing in IRQ context) */ +// #define HEAVY_TRACING + +static phy_device_driver_s device_driver; +static int8_t rf_radio_driver_id = -1; + +const phy_rf_channel_configuration_s phy_subghz = {868000000, 1000000, 250000, 11, M_GFSK}; + +static phy_device_channel_page_s phy_channel_pages[] = { + {CHANNEL_PAGE_2, &phy_subghz}, + {CHANNEL_PAGE_0, NULL} +}; + +static uint8_t tx_sequence = 0xff; +static uint8_t mac_tx_handle = 0; + +static SimpleSpirit1 *rf_device = NULL; +static uint8_t rf_rx_buf[MAX_PACKET_LEN]; + +static uint16_t stored_short_adr; +static uint16_t stored_pan_id; +static uint8_t stored_mac_address[8] = MBED_CONF_SPIRIT1_MAC_ADDRESS; + +#define RF_SIG_ACK_NEEDED (1<<0) +#define RF_SIG_CB_TX_DONE (1<<1) +#define RF_SIG_CB_RX_RCVD (1<<2) +static Thread rf_ack_sender(osPriorityRealtime); +static volatile uint8_t rf_rx_sequence; +static volatile bool rf_ack_sent = false; +static volatile bool expecting_ack = false; +static volatile bool need_ack = false; + +/* MAC frame helper macros */ +#define MAC_FCF_FRAME_TYPE_MASK 0x0007 +#define MAC_FCF_FRAME_TYPE_SHIFT 0 +#define MAC_FCF_SECURITY_BIT_MASK 0x0008 +#define MAC_FCF_SECURITY_BIT_SHIFT 3 +#define MAC_FCF_PENDING_BIT_MASK 0x0010 +#define MAC_FCF_PENDING_BIT_SHIFT 4 +#define MAC_FCF_ACK_REQ_BIT_MASK 0x0020 +#define MAC_FCF_ACK_REQ_BIT_SHIFT 5 +#define MAC_FCF_INTRA_PANID_MASK 0x0040 +#define MAC_FCF_INTRA_PANID_SHIFT 6 +#define MAC_FCF_DST_ADDR_MASK 0x0c00 +#define MAC_FCF_DST_ADDR_SHIFT 10 +#define MAC_FCF_VERSION_MASK 0x3000 +#define MAC_FCF_VERSION_SHIFT 12 +#define MAC_FCF_SRC_ADDR_MASK 0xc000 +#define MAC_FCF_SRC_ADDR_SHIFT 14 + +/* MAC supported frame types */ +#define FC_BEACON_FRAME 0x00 +#define FC_DATA_FRAME 0x01 +#define FC_ACK_FRAME 0x02 +#define FC_CMD_FRAME 0x03 + +static inline void rf_if_lock(void) +{ + platform_enter_critical(); +} + +static inline void rf_if_unlock(void) +{ + platform_exit_critical(); +} + +static inline uint16_t rf_read_16_bit(uint8_t *data_ptr) { // little-endian + uint16_t ret; + + ret = ((uint16_t)data_ptr[0]) + (((uint16_t)data_ptr[1]) << 8); + return ret; +} + +/* Note: we are in IRQ context */ +static inline void rf_send_signal(int32_t signal) { +#ifdef HEAVY_TRACING + tr_info("%s (%d): %d", __func__, __LINE__, signal); +#endif + rf_ack_sender.signal_set(signal); +} + +static volatile phy_link_tx_status_e phy_status; +/* Note: we are in IRQ context */ +static void rf_handle_ack(uint8_t seq_number) +{ + /*Received ACK sequence must be equal with transmitted packet sequence*/ + if(tx_sequence == seq_number) + { +#ifdef HEAVY_TRACING + tr_info("%s (%d)", __func__, __LINE__); +#endif + + /*Call PHY TX Done API*/ + if(device_driver.phy_tx_done_cb){ + phy_status = PHY_LINK_TX_DONE; + rf_send_signal(RF_SIG_CB_TX_DONE); + } + } else { +#ifdef HEAVY_TRACING + tr_info("%s (%d)", __func__, __LINE__); +#endif + + /*Call PHY TX Done API*/ + if(device_driver.phy_tx_done_cb){ + phy_status = PHY_LINK_TX_FAIL; + rf_send_signal(RF_SIG_CB_TX_DONE); + } + } +} + +/* Note: we are in IRQ context */ +static inline bool rf_check_mac_address(uint8_t *dest) { + for(int i = 0; i < 8; i++) { + if(dest[i] != stored_mac_address[7-i]) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d): i=%d, dest=%x, stored=%x", + __func__, __LINE__, + i, dest[i], stored_mac_address[7-i]); +#endif + return false; + } + } + return true; +} + +/* Note: we are in IRQ context */ +/* Returns true if packet should be accepted */ +static bool rf_check_destination(int len, uint8_t *ack_requested) { + uint8_t frame_type; + uint16_t dst_pan_id; + uint16_t dst_short_adr; + uint8_t dst_addr_mode = 0x0; /*0x00 = no address 0x01 = reserved 0x02 = 16-bit short address 0x03 = 64-bit extended address */ + uint8_t src_addr_mode = 0x0; /*0x00 = no address 0x01 = reserved 0x02 = 16-bit short address 0x03 = 64-bit extended address */ + uint8_t min_size = 3; // FCF & SeqNr + bool ret = false; +#if defined(HEAVY_TRACING) + bool panid_compr = false; +#endif + + if(len < 3) { + tr_debug("%s (%d)", __func__, __LINE__); + return false; + } + + uint16_t fcf = rf_read_16_bit(rf_rx_buf); + frame_type = ((fcf & MAC_FCF_FRAME_TYPE_MASK) >> MAC_FCF_FRAME_TYPE_SHIFT); + (*ack_requested) = ((fcf & MAC_FCF_ACK_REQ_BIT_MASK) >> MAC_FCF_ACK_REQ_BIT_SHIFT); + dst_addr_mode = ((fcf & MAC_FCF_DST_ADDR_MASK) >> MAC_FCF_DST_ADDR_SHIFT); + src_addr_mode = ((fcf & MAC_FCF_SRC_ADDR_MASK) >> MAC_FCF_SRC_ADDR_SHIFT); +#if defined(HEAVY_TRACING) + panid_compr = ((fcf & MAC_FCF_INTRA_PANID_MASK) >> MAC_FCF_INTRA_PANID_SHIFT); +#endif + +#ifdef HEAVY_TRACING + tr_info("%s (%d): len=%d, ftype=%x, snr=%x, ack=%d, dst=%x, src=%x, intra=%d", __func__, __LINE__, len, frame_type, + rf_rx_buf[2], (*ack_requested), dst_addr_mode, src_addr_mode, panid_compr); +#endif + + if(frame_type == FC_ACK_FRAME) { // betzw: we support up to two different forms of ACK frames! + if((len == 3) && (dst_addr_mode == 0x0) && (src_addr_mode == 0x0)) { + ret = true; + } + +#ifdef HEAVY_TRACING + tr_info("%s (%d): ret=%d", __func__, __LINE__, ret); +#endif + (*ack_requested) = 0; // Never acknowledge ACK frames + return ret; + } + + switch(dst_addr_mode) { + case 0x00: + ret = true; // no check possible; + break; + + case 0x02: + min_size += 4; // pan id + short dest adr + + if(len < 5) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return false; + } + + dst_pan_id = rf_read_16_bit(&rf_rx_buf[3]); + if((dst_pan_id != stored_pan_id) && (dst_pan_id != 0xFFFF)) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return false; + } + + if(len < 7) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return false; + } + + dst_short_adr = rf_read_16_bit(&rf_rx_buf[5]); + if((dst_short_adr != stored_short_adr) && (dst_short_adr != 0xFFFF)) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d): %d!=%d", __func__, __LINE__, dst_short_adr, stored_short_adr); +#endif + return false; + } + + ret = true; + break; + + case 0x03: + min_size += 10; // pan id + dest mac addr + + if(len < 5) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return false; + } + + dst_pan_id = rf_read_16_bit(&rf_rx_buf[3]); + if((dst_pan_id != stored_pan_id) && (dst_pan_id != 0xFFFF)) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return false; + } + + if(len < 13) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return false; + } + + ret = rf_check_mac_address(&rf_rx_buf[5]); + + if(!ret) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return false; + } + + break; + + default: + /* not supported */ +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return false; + } + + if(ret && (*ack_requested)) { + rf_rx_sequence = rf_rx_buf[2]; + } + +#ifdef HEAVY_TRACING + tr_info("%s (%d), ret=%d, ack=%d", __func__, __LINE__, ret, (*ack_requested)); +#endif + return ret; +} + +static uint16_t rf_buffer_len = 0; +static uint8_t rf_sqi; +static int8_t rf_rssi; +/* Note: we are in IRQ context */ +static inline void rf_handle_rx_end(void) +{ + uint8_t ack_requested = 0; + + /* Get received data */ + rf_buffer_len = rf_device->read(rf_rx_buf, MAX_PACKET_LEN); + if(!rf_buffer_len) + return; + +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + + /* Check if packet should be accepted */ + if(!rf_check_destination(rf_buffer_len, &ack_requested)) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return; + } + + /* If waiting for ACK, check here if the packet is an ACK to a message previously sent */ + if(expecting_ack) { + uint16_t fcf = rf_read_16_bit(rf_rx_buf); + expecting_ack = false; + + if(((fcf & MAC_FCF_FRAME_TYPE_MASK) >> MAC_FCF_FRAME_TYPE_SHIFT) == FC_ACK_FRAME) { + /*Send sequence number in ACK handler*/ +#ifdef HEAVY_TRACING + tr_debug("%s (%d), len=%u", __func__, __LINE__, (unsigned int)rf_buffer_len); +#endif + rf_handle_ack(rf_rx_buf[2]); + return; + } else { + /*Call PHY TX Done API*/ + if(device_driver.phy_tx_done_cb){ + phy_status = PHY_LINK_TX_FAIL; + rf_send_signal(RF_SIG_CB_TX_DONE); + } + } + } + + /* Kick off ACK sending */ + if(ack_requested) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d), len=%u", __func__, __LINE__, (unsigned int)rf_buffer_len); +#endif + rf_send_signal(RF_SIG_ACK_NEEDED); + } + + /* Get link information */ + rf_rssi = (int8_t)rf_device->get_last_rssi_dbm(); + rf_sqi = (uint8_t)rf_device->get_last_sqi(); // use SQI as link quality + + /* Note: Checksum of the packet must be checked and removed before entering here */ + /* TODO - betzw: what to do? */ + +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + + /* Send received data and link information to the network stack */ + if( device_driver.phy_rx_cb ){ + rf_send_signal(RF_SIG_CB_RX_RCVD); + } +} + +/* Note: we are in IRQ context */ +static inline void rf_handle_tx_end(void) +{ + /* Check if this is an ACK sending which is still pending */ + if(rf_ack_sent) { + rf_ack_sent = false; +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + return; // no need to inform stack + } + + /* Transform `need_ack` in `expecting_ack` */ + if(need_ack) { + need_ack = false; + expecting_ack = true; + } + + /*Call PHY TX Done API*/ + if(device_driver.phy_tx_done_cb){ + phy_status = PHY_LINK_TX_SUCCESS; + rf_send_signal(RF_SIG_CB_TX_DONE); + } +} + +/* Note: we might be in IRQ context */ +static inline void rf_handle_tx_err(phy_link_tx_status_e phy_val = PHY_LINK_TX_FAIL) { + /*Call PHY TX Done API*/ + if(device_driver.phy_tx_done_cb){ + need_ack = false; + phy_status = phy_val; + rf_send_signal(RF_SIG_CB_TX_DONE); + } +} + +/* Note: we are in IRQ context */ +static void rf_callback_func(int event) { + switch(event) { + case SimpleSpirit1::RX_DONE: + rf_handle_rx_end(); + break; + case SimpleSpirit1::TX_DONE: + rf_handle_tx_end(); + break; + case SimpleSpirit1::TX_ERR: +#ifdef HEAVY_TRACING + tr_debug("%s (%d): TX_ERR!!!", __func__, __LINE__); +#endif + rf_handle_tx_err(); + break; + } +} + +static int8_t rf_trigger_send(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol) +{ +#ifndef NDEBUG + debug_if(!(data_length >= 3), "\r\nassert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + + /* Give 'rf_ack_sender' a better chance to run */ + Thread::yield(); + + /* Get Lock */ + rf_if_lock(); + + /*Check if transmitter is busy*/ + if(rf_device->is_receiving()) { /* betzw - WAS: (rf_device->channel_clear() != 0)), do NOT use this but rather study and enable automatic CCA */ +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + + /* Release Lock */ + rf_if_unlock(); + + /*Return busy*/ + return -1; + } else { + uint16_t fcf = rf_read_16_bit(data_ptr); + + /*Check if transmitted data needs to be acked*/ + if((fcf & MAC_FCF_ACK_REQ_BIT_MASK) >> MAC_FCF_ACK_REQ_BIT_SHIFT) + need_ack = true; + else + need_ack = false; + + /*Store the sequence number for ACK handling*/ + tx_sequence = *(data_ptr + 2); + + /*Store TX handle*/ + mac_tx_handle = tx_handle; + +#ifdef HEAVY_TRACING + tr_info("%s (%d), len=%d, tx_handle=%x, tx_seq=%x, need_ack=%d (%x:%x, %x:%x, %x:%x, %x:%x)", __func__, __LINE__, + data_length, tx_handle, tx_sequence, need_ack, + data_ptr[3], data_ptr[4], data_ptr[5], data_ptr[6], + data_ptr[7], data_ptr[8], data_ptr[9], data_ptr[10]); +#endif + + /*Send the packet*/ + int ret = rf_device->send(data_ptr, data_length); + if(ret != RADIO_TX_OK) { + rf_handle_tx_err(PHY_LINK_CCA_FAIL); + } + + /* Release Lock */ + rf_if_unlock(); + } + + /*Return success*/ + return 0; +} + +static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel) +{ + int8_t ret_val = 0; + switch (new_state) + { + /*Reset PHY driver and set to idle*/ + case PHY_INTERFACE_RESET: + tr_debug("%s (%d)", __func__, __LINE__); + rf_device->reset_board(); + break; + /*Disable PHY Interface driver*/ + case PHY_INTERFACE_DOWN: + tr_debug("%s (%d)", __func__, __LINE__); + ret_val = rf_device->off(); + if(ret_val != 0) ret_val = -1; + break; + /*Enable PHY Interface driver*/ + case PHY_INTERFACE_UP: + ret_val = rf_device->on(); + if(ret_val != 0) { + tr_debug("%s (%d)", __func__, __LINE__); + ret_val = -1; + break; + } + tr_debug("%s (%d) - channel: %d", __func__, __LINE__, (int)rf_channel); + rf_device->set_channel(rf_channel); + break; + /*Enable wireless interface ED scan mode*/ + case PHY_INTERFACE_RX_ENERGY_STATE: + tr_debug("%s (%d)", __func__, __LINE__); + break; + /*Enable Sniffer state*/ + case PHY_INTERFACE_SNIFFER_STATE: + // TODO - if we really need this - WAS: rf_setup_sniffer(rf_channel); + tr_debug("%s (%d)", __func__, __LINE__); + ret_val = -1; + break; + default: + tr_debug("%s (%d)", __func__, __LINE__); + break; + } + return ret_val; +} + +static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr) +{ + switch (extension_type) + { + /*Control MAC pending bit for Indirect data transmission*/ + case PHY_EXTENSION_CTRL_PENDING_BIT: + tr_debug("%s (%d)", __func__, __LINE__); + break; + + /*Return frame pending status*/ + case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS: + tr_debug("%s (%d)", __func__, __LINE__); + *data_ptr = 0; + break; + + /*Set channel, used for setting channel for energy scan*/ + case PHY_EXTENSION_SET_CHANNEL: + tr_debug("%s (%d)", __func__, __LINE__); + break; + + /*Read energy on the channel*/ + case PHY_EXTENSION_READ_CHANNEL_ENERGY: + // TODO: *data_ptr = rf_get_channel_energy(); + tr_debug("%s (%d)", __func__, __LINE__); + *data_ptr = (int8_t)rf_device->get_last_rssi_dbm(); + break; + + /*Read status of the link*/ + case PHY_EXTENSION_READ_LINK_STATUS: + // TODO: *data_ptr = rf_get_link_status(); + tr_debug("%s (%d)", __func__, __LINE__); + *data_ptr = rf_device->get_last_sqi(); // use SQI as link quality + break; + + default: + tr_debug("%s (%d)", __func__, __LINE__); + break; + } + return 0; +} + +static inline void rf_set_mac_address(uint8_t *ptr) { + tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x, adr6=%x, adr7=%x", + __func__, __LINE__, + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]); + for(int i = 0; i < 8; i++) { + stored_mac_address[i] = ptr[i]; + } +} + +static inline void rf_get_mac_address(uint8_t *ptr) { + for(int i = 0; i < 8; i++) { + ptr[i] = stored_mac_address[i]; + } + tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x, adr6=%x, adr7=%x", + __func__, __LINE__, + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]); +} + +static inline void rf_set_short_adr(uint8_t *ptr) { + stored_short_adr = (ptr[0] << 8) + ptr[1]; // big-endian + tr_debug("%s (%d), adr0=%x, adr1=%x, val=%d", + __func__, __LINE__, + ptr[0], ptr[1], stored_short_adr); +} + +static inline void rf_set_pan_id(uint8_t *ptr) { + stored_pan_id = (ptr[0] << 8) + ptr[1]; // big-endian + tr_debug("%s (%d), adr0=%x, adr1=%x, val=%d", + __func__, __LINE__, + ptr[0], ptr[1], stored_pan_id); +} + +static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr) +{ + switch (address_type) + { + /*Set 48-bit address*/ + case PHY_MAC_48BIT: + /* Not used in this example */ + // betzw - WAS: rf_set_mac_48bit(address_ptr); + break; + /*Set 64-bit address*/ + case PHY_MAC_64BIT: + rf_set_mac_address(address_ptr); + break; + /*Set 16-bit address*/ + case PHY_MAC_16BIT: + rf_set_short_adr(address_ptr); + break; + /*Set PAN Id*/ + case PHY_MAC_PANID: + rf_set_pan_id(address_ptr); + break; + } + + return 0; +} + +static void rf_ack_loop(void) { + static uint16_t buffer[2] = { + (FC_ACK_FRAME << MAC_FCF_FRAME_TYPE_SHIFT), + 0x0 + }; + + tr_debug("%s (%d)", __func__, __LINE__); + + do { + /* Wait for signal */ + osEvent event = rf_ack_sender.signal_wait(0); + + if(event.status != osEventSignal) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + continue; + } + + int32_t signals = event.value.signals; + +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + + /* Get Lock */ + rf_if_lock(); + + if(signals & RF_SIG_ACK_NEEDED) { +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + + /* Prepare payload */ + uint8_t *ptr = (uint8_t*)&buffer[1]; + ptr[0] = rf_rx_sequence; // Sequence number + + /* Wait for device not receiving */ + while(rf_device->is_receiving()) { +#ifdef HEAVY_TRACING + tr_info("%s (%d)", __func__, __LINE__); +#endif + wait_us(10); + } + +#ifdef HEAVY_TRACING + tr_debug("%s (%d), hdr=%x, nr=%x", __func__, __LINE__, buffer[0], ptr[0]); +#endif + + /* Set information that we have sent an ACK */ + rf_ack_sent = true; + + /*Send the packet*/ + rf_device->send((uint8_t*)buffer, 3, false); + +#ifdef HEAVY_TRACING + tr_debug("%s (%d), hdr=%x, nr=%x", __func__, __LINE__, buffer[0], ptr[0]); +#endif + } + + if(signals & RF_SIG_CB_TX_DONE) { + device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status, + (phy_status == PHY_LINK_CCA_FAIL) ? 0xFF : 0, 0); +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + } + + if(signals & RF_SIG_CB_RX_RCVD) { + device_driver.phy_rx_cb(rf_rx_buf, rf_buffer_len, rf_sqi, rf_rssi, rf_radio_driver_id); +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + } + + /* Release Lock */ + rf_if_unlock(); + +#ifdef HEAVY_TRACING + tr_debug("%s (%d)", __func__, __LINE__); +#endif + } while(true); +} + +void NanostackRfPhySpirit1::rf_init(void) { +#ifndef NDEBUG + osStatus ret; +#endif + + if(rf_device == NULL) { + rf_device = &SimpleSpirit1::CreateInstance(_spi_mosi, _spi_miso, _spi_sclk, _dev_irq, _dev_cs, _dev_sdn, _brd_led); + rf_device->attach_irq_callback(rf_callback_func); + +#ifndef NDEBUG + ret = +#endif + rf_ack_sender.start(rf_ack_loop); + +#ifndef NDEBUG + debug_if(!(ret == osOK), "\r\nassert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + } +} + +NanostackRfPhySpirit1::NanostackRfPhySpirit1(PinName spi_mosi, PinName spi_miso, PinName spi_sclk, + PinName dev_irq, PinName dev_cs, PinName dev_sdn, PinName brd_led) : + _spi_mosi(spi_mosi), + _spi_miso(spi_miso), + _spi_sclk(spi_sclk), + _dev_irq(dev_irq), + _dev_cs(dev_cs), + _dev_sdn(dev_sdn), + _brd_led(brd_led) +{ + /* Nothing to do */ + tr_debug("%s (%d)", __func__, __LINE__); +} + +NanostackRfPhySpirit1::~NanostackRfPhySpirit1() +{ + /* Nothing to do */ + tr_debug("%s (%d)", __func__, __LINE__); +} + +int8_t NanostackRfPhySpirit1::rf_register() +{ + tr_debug("%s (%d)", __func__, __LINE__); + + /* Get Lock */ + rf_if_lock(); + + /* Do some initialization */ + rf_init(); + + /* Set pointer to MAC address */ + device_driver.PHY_MAC = stored_mac_address; + + /* Set driver Name */ + device_driver.driver_description = (char*)"Spirit1 Sub-GHz RF"; + + /*Type of RF PHY is SubGHz*/ + device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE; + + /*Maximum size of payload*/ + device_driver.phy_MTU = MAX_PACKET_LEN; + + /*No header in PHY*/ + device_driver.phy_header_length = 0; + + /*No tail in PHY*/ + device_driver.phy_tail_length = 0; + + /*Set up driver functions*/ + device_driver.address_write = &rf_address_write; + device_driver.extension = &rf_extension; + device_driver.state_control = &rf_interface_state_control; + device_driver.tx = &rf_trigger_send; + + /*Set supported channel pages*/ + device_driver.phy_channel_pages = phy_channel_pages; + + //Nullify rx/tx callbacks + device_driver.phy_rx_cb = NULL; + device_driver.phy_tx_done_cb = NULL; + device_driver.arm_net_virtual_rx_cb = NULL; + device_driver.arm_net_virtual_tx_cb = NULL; + + /*Register device driver*/ + rf_radio_driver_id = arm_net_phy_register(&device_driver); + + /* Release Lock */ + rf_if_unlock(); + + tr_debug("%s (%d)", __func__, __LINE__); + return rf_radio_driver_id; +} + +void NanostackRfPhySpirit1::rf_unregister() +{ + tr_debug("%s (%d)", __func__, __LINE__); + + /* Get Lock */ + rf_if_lock(); + + if (rf_radio_driver_id >= 0) { + arm_net_phy_unregister(rf_radio_driver_id); + rf_radio_driver_id = -1; + } + + /* Release Lock */ + rf_if_unlock(); +} + +void NanostackRfPhySpirit1::get_mac_address(uint8_t *mac) +{ + tr_debug("%s (%d)", __func__, __LINE__); + + /* Get Lock */ + rf_if_lock(); + + if(rf_radio_driver_id >= 0) { + rf_get_mac_address(mac); + } else { + error("NanostackRfPhySpirit1 must be registered to read mac address"); + } + + /* Release Lock */ + rf_if_unlock(); +} + +void NanostackRfPhySpirit1::set_mac_address(uint8_t *mac) +{ + tr_debug("%s (%d)", __func__, __LINE__); + + /* Get Lock */ + rf_if_lock(); + + if(rf_radio_driver_id < 0) { + rf_set_mac_address(mac); + } else { + error("NanostackRfPhySpirit1 cannot change mac address when running"); + } + + /* Release Lock */ + rf_if_unlock(); +} + +#endif /* MBED_CONF_RTOS_PRESENT */ +#endif /* MBED_CONF_NANOSTACK_CONFIGURATION */ \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/SimpleSpirit1.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/SimpleSpirit1.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,634 @@ +/*** Mbed Includes ***/ +#include "SimpleSpirit1.h" +#include "radio_spi.h" + +#define SPIRIT_GPIO_IRQ (SPIRIT_GPIO_3) + +static uint16_t last_state; +#define SPIRIT1_STATUS() ((last_state = (uint16_t)refresh_state()) & SPIRIT1_STATE_STATEBITS) + +#define XO_ON (0x1) + +#define BUSYWAIT_UNTIL(cond, millisecs) \ + do { \ + uint32_t start = us_ticker_read(); \ + uint32_t limit = (uint32_t)millisecs*1000U; \ + while (!(cond)) { \ + uint32_t now = us_ticker_read(); \ + if((now - start) > limit) break; \ + } \ + } while(0) + +#define st_lib_spirit_irqs SpiritIrqs + +#define STATE_TIMEOUT (100) + +// betzw: switching force & back from standby is on some devices quite unstable +#define USE_STANDBY_STATE + +/*** Class Implementation ***/ +/** Static Class Variables **/ +SimpleSpirit1 *SimpleSpirit1::_singleton = NULL; + +/** Constructor **/ +SimpleSpirit1::SimpleSpirit1(PinName mosi, PinName miso, PinName sclk, + PinName irq, PinName cs, PinName sdn, + PinName led) : + _spi(mosi, miso, sclk), + _irq(irq), + _chip_select(cs), + _shut_down(sdn), + _led(led), + _current_irq_callback(), + _rx_receiving_timeout() +{ +} + +/** Init Function **/ +void SimpleSpirit1::init() { + /* reset irq disable counter and irq callback & disable irq */ + _nr_of_irq_disables = 0; + disable_spirit_irq(); + + /* unselect chip */ + chip_unselect(); + + /* configure spi */ + _spi.format(8, 0); /* 8-bit, mode = 0, [order = SPI_MSB] only available in mbed3 */ + _spi.frequency(10000000); // 10MHz (i.e. max speed allowed for Spirit1) + + /* install irq handler */ + _irq.mode(PullUp); + _irq.fall(Callback<void()>(this, &SimpleSpirit1::IrqHandler)); + + /* init cube vars */ + spirit_on = OFF; + last_rssi = 0 ; //MGR + last_sqi = 0 ; //MGR + + /* set frequencies */ + radio_set_xtal_freq(XTAL_FREQUENCY); + mgmt_set_freq_base((uint32_t)BASE_FREQUENCY); + + /* restart board */ + enter_shutdown(); + exit_shutdown(); + + /* soft core reset */ + cmd_strobe(SPIRIT1_STROBE_SRES); + + /* Configures the SPIRIT1 radio part */ + SRadioInit x_radio_init = { + XTAL_OFFSET_PPM, + (uint32_t)BASE_FREQUENCY, + (uint32_t)CHANNEL_SPACE, + CHANNEL_NUMBER, + MODULATION_SELECT, + DATARATE, + (uint32_t)FREQ_DEVIATION, + (uint32_t)BANDWIDTH + }; + radio_init(&x_radio_init); + radio_set_pa_level_dbm(0,POWER_DBM); + radio_set_pa_level_max_index(0); + + /* Configures the SPIRIT1 packet handler part*/ + PktBasicInit x_basic_init = { + PREAMBLE_LENGTH, + SYNC_LENGTH, + SYNC_WORD, + LENGTH_TYPE, + LENGTH_WIDTH, + CRC_MODE, + CONTROL_LENGTH, + EN_ADDRESS, + EN_FEC, + EN_WHITENING + }; + pkt_basic_init(&x_basic_init); + + /* Enable the following interrupt sources, routed to GPIO */ + irq_de_init(NULL); + irq_clear_status(); + irq_set_status(TX_DATA_SENT, S_ENABLE); + irq_set_status(RX_DATA_READY,S_ENABLE); + irq_set_status(RX_DATA_DISC, S_ENABLE); + irq_set_status(VALID_SYNC, S_ENABLE); + irq_set_status(TX_FIFO_ERROR, S_ENABLE); + irq_set_status(RX_FIFO_ERROR, S_ENABLE); +#ifndef RX_FIFO_THR_WA + irq_set_status(TX_FIFO_ALMOST_EMPTY, S_ENABLE); + irq_set_status(RX_FIFO_ALMOST_FULL, S_ENABLE); +#endif // !RX_FIFO_THR_WA + + /* Configure Spirit1 */ + radio_persistent_rx(S_ENABLE); + qi_set_sqi_threshold(SQI_TH_0); + qi_sqi_check(S_ENABLE); + qi_set_rssi_threshold_dbm(CCA_THRESHOLD); + timer_set_rx_timeout_stop_condition(SQI_ABOVE_THRESHOLD); + timer_set_infinite_rx_timeout(); + radio_afc_freeze_on_sync(S_ENABLE); + calibration_rco(S_ENABLE); + + spirit_on = OFF; + CLEAR_TXBUF(); + CLEAR_RXBUF(); + _spirit_tx_started = false; + _is_receiving = false; + + /* Configure the radio to route the IRQ signal to its GPIO 3 */ + SGpioInit x_gpio_init = { + SPIRIT_GPIO_IRQ, + SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_LP, + SPIRIT_GPIO_DIG_OUT_IRQ + }; + spirit_gpio_init(&x_gpio_init); + + /* Setup CSMA/CA */ + CsmaInit x_csma_init = { + S_ENABLE, // enable persistent mode + TBIT_TIME_64, // Tcca time + TCCA_TIME_3, // Lcca length + 5, // max nr of backoffs (<8) + 1, // BU counter seed + 8 // BU prescaler + }; + csma_ca_init(&x_csma_init); + +#ifdef USE_STANDBY_STATE + /* Puts the SPIRIT1 in STANDBY mode (125us -> rx/tx) */ + cmd_strobe(SPIRIT1_STROBE_STANDBY); +#endif // USE_STANDBY_STATE +} + +static volatile int tx_fifo_remaining = 0; // to be used in irq handler +static volatile int tx_buffer_pos = 0; // to be used in irq handler +static const volatile uint8_t *tx_fifo_buffer = NULL; // to be used in irq handler +int SimpleSpirit1::send(const void *payload, unsigned int payload_len, bool use_csma_ca) { + /* Checks if the payload length is supported */ + if(payload_len > MAX_PACKET_LEN) { + return RADIO_TX_ERR; + } + + disable_spirit_irq(); + + BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT); +#ifndef NDEBUG + if((last_state & SPIRIT1_STATE_STATEBITS) != SPIRIT1_STATE_RX) { + debug("\r\nAssert failed in: %s (%d): state=%x\r\n", __func__, __LINE__, last_state>>1); + } +#endif + + /* Reset State to Ready */ + set_ready_state(); + + cmd_strobe(SPIRIT1_STROBE_FTX); // flush TX FIFO buffer + +#ifndef NDEBUG + debug_if(!(linear_fifo_read_num_elements_tx_fifo() == 0), "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + + pkt_basic_set_payload_length(payload_len); // set desired payload len + + if(use_csma_ca) { + csma_ca_state(S_ENABLE); // enable CSMA/CA + } + + /* Init buffer & number of bytes to be send */ + tx_fifo_remaining = payload_len; + tx_fifo_buffer = (const uint8_t*)payload; + + int8_t fifo_available = SPIRIT_MAX_FIFO_LEN; // fill-up whole fifo + int8_t to_send = (tx_fifo_remaining > fifo_available) ? fifo_available : tx_fifo_remaining; + + tx_fifo_remaining -= to_send; + + /* Fill FIFO Buffer */ + if(to_send > 0) { + spi_write_linear_fifo(to_send, (uint8_t*)&tx_fifo_buffer[0]); + } + + tx_buffer_pos = to_send; + _spirit_tx_started = true; + + enable_spirit_irq(); + + /* Start transmitting */ + cmd_strobe(SPIRIT1_STROBE_TX); + + while(tx_fifo_remaining != 0); // wait until not everything is yet send (evtl. by irq handler) + + BUSYWAIT_UNTIL(!_spirit_tx_started, STATE_TIMEOUT); +#ifdef HEAVY_DEBUG + debug("\r\n%s (%d): state=%x, _spirit_tx_started=%d\r\n", __func__, __LINE__, SPIRIT1_STATUS()>>1, _spirit_tx_started); +#endif + + if(use_csma_ca) { + csma_ca_state(S_DISABLE); // disable CSMA/CA + } + + cmd_strobe(SPIRIT1_STROBE_RX); // Return to RX state + + disable_spirit_irq(); + if(_spirit_tx_started) { // in case of state timeout + _spirit_tx_started = false; + enable_spirit_irq(); + return RADIO_TX_ERR; + } else { + enable_spirit_irq(); + return RADIO_TX_OK; + } +} + +/** Set Ready State **/ +void SimpleSpirit1::set_ready_state(void) { + uint16_t state; + + disable_spirit_irq(); + + _spirit_tx_started = false; + _is_receiving = false; + stop_rx_timeout(); + + cmd_strobe(SPIRIT1_STROBE_FRX); + CLEAR_RXBUF(); + CLEAR_TXBUF(); + + state = SPIRIT1_STATUS(); + if(state == SPIRIT1_STATE_STANDBY) { + cmd_strobe(SPIRIT1_STROBE_READY); + } else if(state == SPIRIT1_STATE_RX) { + cmd_strobe(SPIRIT1_STROBE_SABORT); + } else if(state != SPIRIT1_STATE_READY) { +#ifndef NDEBUG + debug("\r\nAssert failed in: %s (%d): state=%x\r\n", __func__, __LINE__, state>>1); +#endif + } + + BUSYWAIT_UNTIL((SPIRIT1_STATUS() == SPIRIT1_STATE_READY) && ((last_state & XO_ON) == XO_ON), STATE_TIMEOUT); + if(last_state != (SPIRIT1_STATE_READY | XO_ON)) { + error("\r\nSpirit1: failed to become ready (%x) => pls. reset!\r\n", last_state); + enable_spirit_irq(); + return; + } + + irq_clear_status(); + + enable_spirit_irq(); +} + +int SimpleSpirit1::off(void) { + if(spirit_on == ON) { + /* Disables the mcu to get IRQ from the SPIRIT1 */ + disable_spirit_irq(); + + /* first stop rx/tx */ + set_ready_state(); + +#ifdef USE_STANDBY_STATE + /* Puts the SPIRIT1 in STANDBY */ + cmd_strobe(SPIRIT1_STROBE_STANDBY); + BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY, STATE_TIMEOUT); + if((last_state & SPIRIT1_STATE_STATEBITS) != SPIRIT1_STATE_STANDBY) { + error("\r\nSpirit1: failed to enter standby (%x)\r\n", last_state>>1); + return 1; + } +#endif // USE_STANDBY_STATE + + spirit_on = OFF; + _nr_of_irq_disables = 1; + } + return 0; +} + +int SimpleSpirit1::on(void) { + if(spirit_on == OFF) { + set_ready_state(); + + /* now we go to Rx */ + cmd_strobe(SPIRIT1_STROBE_RX); + + BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT); + if((last_state & SPIRIT1_STATE_STATEBITS) != SPIRIT1_STATE_RX) { + error("\r\nSpirit1: failed to enter rx (%x) => retry\r\n", last_state>>1); + } + + /* Enables the mcu to get IRQ from the SPIRIT1 */ + spirit_on = ON; +#ifndef NDEBUG + debug_if(!(_nr_of_irq_disables == 1), "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + enable_spirit_irq(); + } + +#ifndef NDEBUG + if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) { + debug("\r\nAssert failed in: %s (%d): state=%x\r\n", __func__, __LINE__, last_state>>1); + } +#endif + + return 0; +} + +uint8_t SimpleSpirit1::refresh_state(void) { + uint8_t mcstate; + + SpiritSpiReadRegisters(MC_STATE0_BASE, 1, &mcstate); + + return mcstate; +} + +int SimpleSpirit1::read(void *buf, unsigned int bufsize) +{ + disable_spirit_irq(); + + /* Checks if the RX buffer is empty */ + if(IS_RXBUF_EMPTY()) { +#ifndef NDEBUG + debug("\r\nBuffer is empty\r\n"); +#endif + set_ready_state(); + + cmd_strobe(SPIRIT1_STROBE_RX); + BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT); + enable_spirit_irq(); + return 0; + } + + if(bufsize < spirit_rx_len) { + enable_spirit_irq(); + + /* If buf has the correct size */ +#ifndef NDEBUG + debug("\r\nTOO SMALL BUF\r\n"); +#endif + return 0; + } else { + /* Copies the packet received */ + memcpy(buf, spirit_rx_buf, spirit_rx_len); + + bufsize = spirit_rx_len; + CLEAR_RXBUF(); + + enable_spirit_irq(); + + return bufsize; + } + +} + +int SimpleSpirit1::channel_clear(void) +{ + float rssi_value; + /* Local variable used to memorize the SPIRIT1 state */ + uint8_t spirit_state = ON; + + if(spirit_on == OFF) { + /* Wakes up the SPIRIT1 */ + on(); + spirit_state = OFF; + } + +#ifndef NDEBUG + if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) { + debug("\r\nAssert failed in: %s (%d): state=%x\r\n", __func__, __LINE__, last_state>>1); + } +#endif + + disable_spirit_irq(); + + /* Reset State to Ready */ + set_ready_state(); + + /* Stores the RSSI value */ + rssi_value = qi_get_rssi_dbm(); + + enable_spirit_irq(); + + /* Puts the SPIRIT1 in its previous state */ + if(spirit_state==OFF) { + off(); +#ifndef NDEBUG +#ifdef USE_STANDBY_STATE + if(SPIRIT1_STATUS() != SPIRIT1_STATE_STANDBY) { +#else + if(SPIRIT1_STATUS() != SPIRIT1_STATE_READY) { +#endif + debug("\r\nAssert failed in: %s (%d): state=%x\r\n", __func__, __LINE__, last_state>>1); + } +#endif + } else { + disable_spirit_irq(); + + set_ready_state(); + + cmd_strobe(SPIRIT1_STROBE_RX); + BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT); + if((last_state & SPIRIT1_STATE_STATEBITS) != SPIRIT1_STATE_RX) { + error("\r\nSpirit1: (#2) failed to enter rx (%x) => retry\r\n", last_state>>1); + } + + enable_spirit_irq(); + +#ifndef NDEBUG + if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) { + debug("\r\nAssert failed in: %s (%d): state=%x\r\n", __func__, __LINE__, last_state>>1); + } +#endif + } + + /* Checks the RSSI value with the threshold */ + if(rssi_value<CCA_THRESHOLD) { + return 0; + } else { + return 1; + } + } + + int SimpleSpirit1::get_pending_packet(void) + { + return !IS_RXBUF_EMPTY(); + } + + /** Spirit Irq Callback **/ + /* betzw - TODO: use threaded interrupt handling when `MBED_CONF_RTOS_PRESENT` is defined (see `atmel-rf-driver`) */ + void SimpleSpirit1::IrqHandler() { + st_lib_spirit_irqs x_irq_status; + + /* get interrupt source from radio */ + irq_get_status(&x_irq_status); + + /* The IRQ_TX_DATA_SENT notifies the packet has been sent. Puts the SPIRIT1 in RX */ + if(x_irq_status.IRQ_TX_DATA_SENT) { /* betzw - NOTE: MUST be handled before `IRQ_RX_DATA_READY` for Nanostack integration! + Logically, Nanostack only expects the "DONE" after "SUCCESS" (if it gets + DONE before SUCCESS, it assumes you're not going to bother to send SUCCESS). + */ +#ifdef DEBUG_IRQ + uint32_t *tmp = (uint32_t*)&x_irq_status; + debug_if(!((*tmp) & IRQ_TX_DATA_SENT_MASK), "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); + debug_if(tx_fifo_remaining != 0, "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + + if(_spirit_tx_started) { + _spirit_tx_started = false; + + /* call user callback */ + if(_current_irq_callback) { + _current_irq_callback(TX_DONE); + } + } + + /* Disable handling of other TX flags */ + x_irq_status.IRQ_TX_FIFO_ALMOST_EMPTY = S_RESET; + tx_fifo_buffer = NULL; + } + +#ifndef RX_FIFO_THR_WA + /* The IRQ_TX_FIFO_ALMOST_EMPTY notifies an nearly empty TX fifo */ + if(x_irq_status.IRQ_TX_FIFO_ALMOST_EMPTY) { +#ifdef DEBUG_IRQ + uint32_t *tmp = (uint32_t*)&x_irq_status; + debug_if(!((*tmp) & IRQ_TX_FIFO_ALMOST_EMPTY_MASK), "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); + debug_if(!_spirit_tx_started, "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); + debug_if(tx_fifo_buffer == NULL, "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + + int8_t fifo_available = SPIRIT_MAX_FIFO_LEN/2; // fill-up half fifo + int8_t to_send = (tx_fifo_remaining > fifo_available) ? fifo_available : tx_fifo_remaining; + + tx_fifo_remaining -= to_send; + + /* Fill FIFO Buffer */ + if(to_send > 0) { + spi_write_linear_fifo(to_send, (uint8_t*)&tx_fifo_buffer[tx_buffer_pos]); + } + tx_buffer_pos += to_send; + } +#endif // !RX_FIFO_THR_WA + + /* TX FIFO underflow/overflow error */ + if(x_irq_status.IRQ_TX_FIFO_ERROR) { +#ifdef DEBUG_IRQ + uint32_t *tmp = (uint32_t*)&x_irq_status; + debug("\r\n%s (%d): irq=%x\r\n", __func__, __LINE__, *tmp); + debug_if(!((*tmp) & IRQ_TX_FIFO_ERROR_MASK), "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + if(_spirit_tx_started) { + _spirit_tx_started = false; + /* call user callback */ + if(_current_irq_callback) { + _current_irq_callback(TX_ERR); + } + } + + /* reset data still to be sent */ + tx_fifo_remaining = 0; + } + + /* The IRQ_RX_DATA_READY notifies a new packet arrived */ + if(x_irq_status.IRQ_RX_DATA_READY) { +#ifdef DEBUG_IRQ + uint32_t *tmp = (uint32_t*)&x_irq_status; + debug_if(!((*tmp) & IRQ_RX_DATA_READY_MASK), "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + + if(!_is_receiving) { // spurious irq?!? (betzw: see comments on macro 'RX_FIFO_THR_WA'!) +#ifdef HEAVY_DEBUG + debug("\r\n%s (%d): irq=%x\r\n", __func__, __LINE__, *tmp); +#endif + } else { + _is_receiving = false; // Finished receiving + stop_rx_timeout(); + + spirit_rx_len = pkt_basic_get_received_pkt_length(); + +#ifdef DEBUG_IRQ + debug_if(!(spirit_rx_len <= MAX_PACKET_LEN), "\r\n%s (%d): irq=%x\r\n", __func__, __LINE__, *tmp); +#endif + + if(spirit_rx_len <= MAX_PACKET_LEN) { + uint8_t to_receive = spirit_rx_len - _spirit_rx_pos; + if(to_receive > 0) { + spi_read_linear_fifo(to_receive, &spirit_rx_buf[_spirit_rx_pos]); + _spirit_rx_pos += to_receive; + } + } + + cmd_strobe(SPIRIT1_STROBE_FRX); + + last_rssi = qi_get_rssi(); //MGR + last_sqi = qi_get_sqi(); //MGR + + /* call user callback */ + if((_spirit_rx_pos == spirit_rx_len) && _current_irq_callback) { + _current_irq_callback(RX_DONE); + } + + /* Disable handling of other RX flags */ + x_irq_status.IRQ_RX_FIFO_ALMOST_FULL = S_RESET; + } + } + +#ifndef RX_FIFO_THR_WA + /* RX FIFO almost full */ + if(x_irq_status.IRQ_RX_FIFO_ALMOST_FULL) { +#ifdef DEBUG_IRQ + uint32_t *tmp = (uint32_t*)&x_irq_status; + debug_if(!((*tmp) & IRQ_RX_FIFO_ALMOST_FULL_MASK), "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + if(!_is_receiving) { // spurious irq?!? +#ifdef DEBUG_IRQ + debug("\r\n%s (%d): irq=%x\r\n", __func__, __LINE__, *tmp); +#endif + } else { + uint8_t fifo_available = linear_fifo_read_num_elements_rx_fifo(); + if((fifo_available + _spirit_rx_pos) <= MAX_PACKET_LEN) { + spi_read_linear_fifo(fifo_available, &spirit_rx_buf[_spirit_rx_pos]); + _spirit_rx_pos += fifo_available; + } else { +#ifdef DEBUG_IRQ + debug("\r\n%s (%d): irq=%x\r\n", __func__, __LINE__, *tmp); +#endif + } + } + } +#endif // !RX_FIFO_THR_WA + + /* Reception errors */ + if((x_irq_status.IRQ_RX_FIFO_ERROR) || (x_irq_status.IRQ_RX_DATA_DISC)) { +#ifdef DEBUG_IRQ + uint32_t *tmp = (uint32_t*)&x_irq_status; + debug("\r\n%s (%d): irq=%x\r\n", __func__, __LINE__, *tmp); + debug_if(!((*tmp) & (IRQ_RX_FIFO_ERROR_MASK | IRQ_RX_DATA_DISC_MASK)), "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + rx_timeout_handler(); + if(_spirit_tx_started) { + _spirit_tx_started = false; + /* call user callback */ + if(_current_irq_callback) { + _current_irq_callback(TX_ERR); + } + } + } + + /* The IRQ_VALID_SYNC is used to notify a new packet is coming */ + if(x_irq_status.IRQ_VALID_SYNC) { +#ifdef DEBUG_IRQ + uint32_t *tmp = (uint32_t*)&x_irq_status; + debug_if(!((*tmp) & IRQ_VALID_SYNC_MASK), "\r\nAssert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + /* betzw - NOTE: there is a race condition between Spirit1 receiving packets and + * the MCU trying to send a packet, which gets resolved in favor of + * sending. + */ + if(_spirit_tx_started) { +#ifdef DEBUG_IRQ + debug("\r\n%s (%d): irq=%x\r\n", __func__, __LINE__, *tmp); +#endif + } else { + _is_receiving = true; + start_rx_timeout(); + } + } + }
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,155 @@ +Getting Started with Contiki for STM32 Nucleo equipped with sub-1GHz SPIRIT1 expansion boards +============================================================================================= + +This guide explains how to get started with the STM32 Nucleo and expansion boards port to Contiki. + +Port Feature +============ + +The port supports the following boards from ST: +- NUCLEO-L152RE board, based on the STM32L152RET6 ultra-low power microcontroller +- X-NUCLEO-IDS01A4 based on sub-1GHz SPSGRF-868 SPIRIT1 module (operating at 868 MHz) +- X-NUCLEO-IDS01A5 based on sub-1GHz SPSGRF-915 SPIRIT1 module (operating at 915 MHz) +- X-NUCLEO-IKS01A1 featuring motion MEMS and environmental sensors (optional) + +The following drivers are included: +- LEDs and buttons (user, reset) +- USB +- SPIRIT1 sub-1GHz transceiver +- HTS221, LIS3MDL, LPS25HB, LSM6DS0 sensors + + +Hardware Requirements +===================== + +* NUCLEO-L152RE development board + + >The NUCLEO-L152RE board belongs to the STM32 Nucleo family. +It features an STM32L152RET6 ultra-low power microcontroller based on ARM Cortex M3 MCU. +Detailed information on the NUCLEO-L152RE development board can be found at: +http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260002 + + +* X-NUCLEO-IDS01Ax sub-1GHz expansion board + + >The X-NUCLEO-IDS01A4 and X-NUCLEO-IDS01A5 are STM32 Nucleo expansion boards that use +the module SPSGRF-868 or SPSGRF-915 based on SPIRIT1 low data rate, low power sub-1 GHz transceiver. + + >The user can select the X-NUCLEO-IDS01A4 board to operate the SPIRIT1 transceiver at 868MHz or the X-NUCLEO-IDS01A5 board to operate the SPIRIT1 transceiver at 915MHz. + + >Detailed information on the X-NUCLEO-IDS01A4 expansion board can be found at: +http://www.st.com/web/catalog/tools/FM146/CL2167/SC2006/PF261982 + + >Detailed information on the X-NUCLEO-IDS01A5 expansion board can be found at: +http://www.st.com/web/catalog/tools/FM146/CL2167/SC2006/PF261983 + + >Detailed information on the SPIRIT1 sub-1GHz transceiver can be found at: +http://www.st.com/web/catalog/sense_power/FM2185/SC1845/PF253167 + +* X-NUCLEO-IKS01A1, motion MEMS and environmental sensors expansion board (OPTIONAL) + + >The X-NUCLEO-IKS01A1 is a motion MEMS and environmental sensor evaluation board. +The use of this board is optional in the stm32nucleo-spirit1 Contiki platform. + + >Detailed information on the X-NUCLEO-IKS01A1 expansion board can be found at: +http://www.st.com/web/catalog/tools/FM146/CL2167/SC2006/PF261191 + + +* USB type A to Mini-B USB cable, to connect the STM32 Nucleo board to the PC + +Software Requirements +===================== + +The following software are needed: + +* ST port of Contiki for STM32 Nucleo and expansion boards. + + >The port is automatically installed when both the Contiki and the submodule repository are cloned: the former hosts the Contiki distribution and the ST platform interface, the latter hosts the actual library. The following commands are needed to download the full porting: + + git clone https://github.com/STclab/contiki.git + cd contiki/ + git checkout stm32nucleo-spirit1 + git submodule init + git submodule update + + +Note: the first and third steps are required only if using the STclab GitHub repository, they won't be needed any more once the Pull Request is accepted. + +The platform name is: stm32nucleo-spirit1 + +* A toolchain to build the firmware: The port has been developed and tested with GNU Tools +for ARM Embedded Processors. + >The toolchain can be found at: https://launchpad.net/gcc-arm-embedded +The port was developed and tested using this version: gcc-arm-none-eabi v4.8.3 + + +Examples +======== + +The following examples have been successfully tested: + +* examples/stm32nucleo-spirit1/sensor-demo +* examples/ipv6/simple-udp-rpl (multicast, rpl-border-router, simple-udp-rpl) + + +Build an example +================ +In order to build an example go to the selected example directory (see a list of tested +examples in the previous section). + +For example, go to examples/ipv6/simple-udp-rpl directory. + + +If the X-NUCLEO-IDS01A4 sub-1GHz RF expansion board is used, the following must be run: + + make TARGET=stm32nucleo-spirit1 USE_SUBGHZ_BOARD=IDS01A4 clean + make TARGET=stm32nucleo-spirit1 USE_SUBGHZ_BOARD=IDS01A4 + +If the X-NUCLEO-IDS01A5 sub-1GHz RF expansion board is used, the following must be run: + + make TARGET=stm32nucleo-spirit1 USE_SUBGHZ_BOARD=IDS01A5 clean + make TARGET=stm32nucleo-spirit1 USE_SUBGHZ_BOARD=IDS01A5 + + +This will create executables for UDP sender and receiver nodes. + +In order to generate binary files that can be flashed on the STM32 Nucleo the following command must be run: + + arm-none-eabi-objcopy -O binary unicast-sender.stm32nucleo-spirit1 unicast-sender.bin + arm-none-eabi-objcopy -O binary unicast-receiver.stm32nucleo-spirit1 unicast-receiver.bin + +These executables can be programmed on the nodes using the procedure described hereafter. + + +In case you need to build an example that uses the additional sensors expansion board +(for example, considering a system made of NUCLEO-L152RE, X-NUCLEO-IDS01A4 and X-NUCLEO-IKS01A1) +then the command to be run would be: + + make TARGET=stm32nucleo-spirit1 USE_SUBGHZ_BOARD=IDS01A4 USE_SENSOR_BOARD=1 + +System setup +============ + +1. Check that the jumper on the J1 connector on the X-NUCLEO-IDS01Ax expansion board is connected. +This jumper provides the required voltage to the devices on the board. + +2. Connect the X-NUCLEO-IDS01Ax board to the STM32 Nucleo board (NUCLEO-L152RE) from the top. + +3. If the optional X-NUCLEO-IKS01A1 board is used, connect it on top of the X-NUCLEO-IDS01Ax board. + +4. Power the STM32 Nucleo board using the Mini-B USB cable connected to the PC. + +5. Program the firmware on the STM32 Nucleo board. +This can be done by copying the binary file on the USB mass storage that is +automatically created when plugging the STM32 Nucleo board to the PC. + +6. Reset the MCU by using the reset button on the STM32 Nucleo board + + + + + + + + +
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/contiki-conf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/contiki-conf.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,155 @@ +/** +****************************************************************************** +* @file platform/stm32nucleo-spirit1/contiki-conf.h +* @author System LAB +* @version V1.0.0 +* @date 17-May-2015 +* @brief Contiki configuration parameters +****************************************************************************** +* @attention +* +* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, 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 __CONTIKI_CONF_H__ +#define __CONTIKI_CONF_H__ +/*---------------------------------------------------------------------------*/ +#include "platform-conf.h" +//#include "project-conf.h" +/*---------------------------------------------------------------------------*/ +#define SLIP_BRIDGE_CONF_NO_PUTCHAR 1 + +#define NETSTACK_CONF_RDC_CHANNEL_CHECK_RATE 8 +#define NULLRDC_CONF_802154_AUTOACK 0 +#define NETSTACK_CONF_FRAMER framer_802154 +#define NETSTACK_CONF_NETWORK sicslowpan_driver + +#undef NETSTACK_CONF_RDC +#define NETSTACK_CONF_RDC nullrdc_driver +#define NETSTACK_RDC_HEADER_LEN 0 + +#undef NETSTACK_CONF_MAC +#define NETSTACK_CONF_MAC csma_driver +#define NETSTACK_MAC_HEADER_LEN 0 + +#define SICSLOWPAN_CONF_MAC_MAX_PAYLOAD \ + (NETSTACK_RADIO_MAX_PAYLOAD_LEN - NETSTACK_MAC_HEADER_LEN - \ + NETSTACK_RDC_HEADER_LEN ) + +#define RIMESTATS_CONF_ENABLED 0 +#define RIMESTATS_CONF_ON 0 + + +/* Network setup for IPv6 */ + +#define CXMAC_CONF_ANNOUNCEMENTS 0 + + +/* A trick to resolve a compilation error with IAR. */ +#ifdef __ICCARM__ +#define UIP_CONF_DS6_AADDR_NBU 1 +#endif + +/* radio driver blocks until ACK is received */ +#define NULLRDC_CONF_ACK_WAIT_TIME (0) +#define CONTIKIMAC_CONF_BROADCAST_RATE_LIMIT 0 +#define IEEE802154_CONF_PANID 0xABCD + +#define AODV_COMPLIANCE + +#define WITH_ASCII 1 + +#define PROCESS_CONF_NUMEVENTS 8 +#define PROCESS_CONF_STATS 1 +/*#define PROCESS_CONF_FASTPOLL 4*/ + + +#define LINKADDR_CONF_SIZE 8 + +#define UIP_CONF_LL_802154 1 +#define UIP_CONF_LLH_LEN 0 + +#define UIP_CONF_ROUTER 1 + +/* configure number of neighbors and routes */ +#ifndef UIP_CONF_DS6_ROUTE_NBU +#define UIP_CONF_DS6_ROUTE_NBU 30 +#endif /* UIP_CONF_DS6_ROUTE_NBU */ + +#ifndef UIP_CONF_ND6_SEND_RA +#define UIP_CONF_ND6_SEND_RA 0 +#endif +#define UIP_CONF_ND6_REACHABLE_TIME 600000 //90000// 600000 +#define UIP_CONF_ND6_RETRANS_TIMER 10000 + + +#define UIP_CONF_IPV6 1 +#ifndef UIP_CONF_IPV6_QUEUE_PKT +#define UIP_CONF_IPV6_QUEUE_PKT 0 +#endif /* UIP_CONF_IPV6_QUEUE_PKT */ +#define UIP_CONF_IP_FORWARD 0 +#ifndef UIP_CONF_BUFFER_SIZE +//#define UIP_CONF_BUFFER_SIZE 280 +#define UIP_CONF_BUFFER_SIZE 600 +#endif + +#define SICSLOWPAN_CONF_MAXAGE 4 +#define SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS 2 + + +#ifndef SICSLOWPAN_CONF_MAX_MAC_TRANSMISSIONS +#define SICSLOWPAN_CONF_MAX_MAC_TRANSMISSIONS 5 +#endif /* SICSLOWPAN_CONF_MAX_MAC_TRANSMISSIONS */ + +#define UIP_CONF_ICMP_DEST_UNREACH 1 + +#define UIP_CONF_DHCP_LIGHT +#define UIP_CONF_LLH_LEN 0 +#ifndef UIP_CONF_RECEIVE_WINDOW +#define UIP_CONF_RECEIVE_WINDOW 150 +#endif +#ifndef UIP_CONF_TCP_MSS +#define UIP_CONF_TCP_MSS UIP_CONF_RECEIVE_WINDOW +#endif +#define UIP_CONF_MAX_CONNECTIONS 4 +#define UIP_CONF_MAX_LISTENPORTS 8 +#define UIP_CONF_UDP_CONNS 12 +#define UIP_CONF_FWCACHE_SIZE 30 +#define UIP_CONF_BROADCAST 1 +#define UIP_ARCH_IPCHKSUM 0 +#define UIP_CONF_UDP 1 +#define UIP_CONF_UDP_CHECKSUMS 1 +#define UIP_CONF_TCP 1 +/*---------------------------------------------------------------------------*/ +/* include the project config */ +/* PROJECT_CONF_H might be defined in the project Makefile */ +#ifdef PROJECT_CONF_H +#include "project-conf.h" +#endif /* PROJECT_CONF_H */ +/*---------------------------------------------------------------------------*/ +#endif /* CONTIKI_CONF_H */ +/*---------------------------------------------------------------------------*/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/hw-config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/hw-config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,125 @@ + /** + ****************************************************************************** + * @file hw-config.h + * @author System LAB + * @version V1.0.0 + * @date 17-May-2015 + * @brief Header file for Hardware Configuration & Setup + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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 __HW_CONFIG_H +#define __HW_CONFIG_H +/*---------------------------------------------------------------------------*/ +#include "stm32l-spirit1-config.h" +/*---------------------------------------------------------------------------*/ +#define UART_RxBufferSize 512 +/*---------------------------------------------------------------------------*/ +#define I2Cx I2C1 +#define I2Cx_CLK_ENABLE() __I2C1_CLK_ENABLE() +#define I2Cx_SDA_GPIO_CLK_ENABLE() __GPIOB_CLK_ENABLE() +#define I2Cx_SCL_GPIO_CLK_ENABLE() __GPIOB_CLK_ENABLE() +/*---------------------------------------------------------------------------*/ +#define I2Cx_FORCE_RESET() __I2C1_FORCE_RESET() +#define I2Cx_RELEASE_RESET() __I2C1_RELEASE_RESET() +/*---------------------------------------------------------------------------*/ +/* Definition for I2Cx Pins */ +#define I2Cx_SCL_PIN GPIO_PIN_8 +#define I2Cx_SCL_GPIO_PORT GPIOB +#define I2Cx_SDA_PIN GPIO_PIN_9 +#define I2Cx_SDA_GPIO_PORT GPIOB +#define I2Cx_SCL_SDA_AF GPIO_AF4_I2C1 + +/* Definition for I2Cx's NVIC */ +#define I2Cx_EV_IRQn I2C1_EV_IRQn +#define I2Cx_ER_IRQn I2C1_ER_IRQn +#define I2Cx_EV_IRQHandler I2C1_EV_IRQHandler +#define I2Cx_ER_IRQHandler I2C1_ER_IRQHandler + + +#define I2Cx I2C1 +#define I2Cx_CLK_ENABLE() __I2C1_CLK_ENABLE() +#define I2Cx_SDA_GPIO_CLK_ENABLE() __GPIOB_CLK_ENABLE() +#define I2Cx_SCL_GPIO_CLK_ENABLE() __GPIOB_CLK_ENABLE() + +#define I2Cx_FORCE_RESET() __I2C1_FORCE_RESET() +#define I2Cx_RELEASE_RESET() __I2C1_RELEASE_RESET() + +/* Definition for I2Cx Pins */ +#define I2Cx_SCL_PIN GPIO_PIN_8 +#define I2Cx_SCL_GPIO_PORT GPIOB +#define I2Cx_SDA_PIN GPIO_PIN_9 +#define I2Cx_SDA_GPIO_PORT GPIOB +#define I2Cx_SCL_SDA_AF GPIO_AF4_I2C1 + +/* Definition for I2Cx's NVIC */ +#define I2Cx_EV_IRQn I2C1_EV_IRQn +#define I2Cx_ER_IRQn I2C1_ER_IRQn +#define I2Cx_EV_IRQHandler I2C1_EV_IRQHandler +#define I2Cx_ER_IRQHandler I2C1_ER_IRQHandler + +/* User can use this section to tailor USARTx/UARTx instance used and associated + resources */ +/* Definition for USARTx clock resources */ +#define USARTx USART2 +#define USARTx_CLK_ENABLE() __USART2_CLK_ENABLE(); +#define DMAx_CLK_ENABLE() __DMA1_CLK_ENABLE() +#define USARTx_RX_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE() +#define USARTx_TX_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE() + +#define USARTx_FORCE_RESET() __USART2_FORCE_RESET() +#define USARTx_RELEASE_RESET() __USART2_RELEASE_RESET() + +/* Definition for USARTx Pins */ +#define USARTx_TX_PIN GPIO_PIN_2 +#define USARTx_TX_GPIO_PORT GPIOA + +#define USARTx_RX_PIN GPIO_PIN_3 +#define USARTx_RX_GPIO_PORT GPIOA + + /* Definition for USARTx's NVIC */ +#define USARTx_IRQn USART2_IRQn +#define USARTx_IRQHandler USART2_IRQHandler + +#define USARTx_TX_AF GPIO_AF7_USART2 +#define USARTx_RX_AF GPIO_AF7_USART2 + + + /* Enable sensor mask */ +#define PRESSURE_SENSOR 0x00000001 +#define TEMPERATURE_SENSOR 0x00000002 +#define HUMIDITY_SENSOR 0x00000004 +#define UV_SENSOR 0x00000008 +#define ACCELEROMETER_SENSOR 0x00000010 +#define GYROSCOPE_SENSOR 0x00000020 +#define MAGNETIC_SENSOR 0x00000040 +/*---------------------------------------------------------------------------*/ +#endif /*__HW_CONFIG_H*/ +/*---------------------------------------------------------------------------*/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/ip64-conf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/ip64-conf.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,97 @@ +/* + * 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 IP64_CONF_H +#define IP64_CONF_H + +/* +#include "ip64-tap-driver.h" +#include "ip64-eth-interface.h" + +#define IP64_CONF_UIP_FALLBACK_INTERFACE ip64_eth_interface +#define IP64_CONF_INPUT ip64_eth_interface_input + +#define IP64_CONF_ETH_DRIVER ip64_tap_driver + + +#undef UIP_FALLBACK_INTERFACE +#define UIP_FALLBACK_INTERFACE ip64_uip_fallback_interface +*/ +#ifdef MY_DRIVERS +#include <my_wifi_interface.h> +#include <my_wifi_driver.h> + +#define IP64_CONF_UIP_FALLBACK_INTERFACE_SLIP 0 +#define IP64_CONF_UIP_FALLBACK_INTERFACE my_wifi_interface +#define IP64_CONF_INPUT my_wifi_interface_input +#define IP64_CONF_ETH_DRIVER my_wifi_driver + +#undef UIP_CONF_ND6_RA_RDNSS +#define UIP_CONF_ND6_RA_RDNSS 1 + +#undef UIP_CONF_ND6_SEND_RA +#define UIP_CONF_ND6_SEND_RA 1 + +#undef UIP_CONF_ROUTER +#define UIP_CONF_ROUTER 1 + +#ifndef QUEUEBUF_CONF_NUM +#define QUEUEBUF_CONF_NUM 16 +#endif + + +#else + + +#include "net/ip64/ip64-slip-interface.h" +#include "net/ip64/ip64-null-driver.h" + +#define IP64_CONF_UIP_FALLBACK_INTERFACE_SLIP 1 +#define IP64_CONF_UIP_FALLBACK_INTERFACE ip64_slip_interface +#define IP64_CONF_INPUT ip64_slip_interface_input +#define IP64_CONF_ETH_DRIVER ip64_null_driver + +#undef UIP_CONF_ND6_RA_RDNSS +#define UIP_CONF_ND6_RA_RDNSS 1 + +#undef UIP_CONF_ND6_SEND_RA +#define UIP_CONF_ND6_SEND_RA 1 + +#undef UIP_CONF_ROUTER +#define UIP_CONF_ROUTER 1 + +#ifndef QUEUEBUF_CONF_NUM +#define QUEUEBUF_CONF_NUM 16 +#endif + +#endif//MY_DRIVERS + +#endif /* IP64_CONF_H */
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/platform-conf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/platform-conf.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,197 @@ +/** +****************************************************************************** +* @file platform/stm32nucleo-spirit1/platform-conf.h +* @author System LAB +* @version V1.0.0 +* @date 17-May-2015 +* @brief Configuration parameters +****************************************************************************** +* @attention +* +* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. +* +****************************************************************************** +*/ +/*---------------------------------------------------------------------------*/ +/** + * \addtogroup stm32nucleo-spirit1 + * @{ + * + * \defgroup stm32nucleo-spirit1-peripherals User Button on STM32 Nucleo + * + * Defines some of the platforms capabilities + * @{ + * + * \file + * Header file for the stm32nucleo-spirit1 platform configuration + */ +/*---------------------------------------------------------------------------*/ +#ifndef __PLATFORM_CONF_H__ +#define __PLATFORM_CONF_H__ +/*---------------------------------------------------------------------------*/ +#ifdef USE_STM32L1XX_NUCLEO +#include <inttypes.h> +#include <string.h> +/*---------------------------------------------------------------------------*/ +#define PLATFORM_HAS_LEDS 1 +#define PLATFORM_HAS_BUTTON 1 +#define PLATFORM_HAS_RADIO 1 + +#define LEDS_GREEN 1 /*Nucleo LED*/ +#define LEDS_RED 2 /*SPIRIT1 LED*/ + +#ifdef COMPILE_SENSORS +#define LEDS_CONF_ALL 1 /*Can't use SPIRIT1 LED in this case*/ +#else +#define LEDS_CONF_ALL 3 /*No sensors -> we can use SPIRIT1 LED in this case*/ +#endif /*COMPILE_SENSORS*/ +/*---------------------------------------------------------------------------*/ +#define F_CPU 32000000ul +#define RTIMER_ARCH_SECOND 32768 +#define PRESCALER ((F_CPU / (RTIMER_ARCH_SECOND*2))) + +#define UART1_CONF_TX_WITH_INTERRUPT 0 +#define WITH_SERIAL_LINE_INPUT 1 +#define TELNETD_CONF_NUMLINES 6 +#define NETSTACK_CONF_RADIO spirit_radio_driver +#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 96 /* spirit1-config.h */ + +#if WITH_IP64 +#include "ip64-conf.h" +#define WITH_SLIP 1 +#ifndef UIP_FALLBACK_INTERFACE +#define UIP_FALLBACK_INTERFACE ip64_uip_fallback_interface +#endif +#endif /* WITH_IP64 */ + +/*---------------------------------------------------------------------------*/ +/* define ticks/second for slow and fast clocks. Notice that these should be a + power of two, eg 64,128,256,512 etc, for efficiency as POT's can be optimized + well. */ +#define CLOCK_CONF_SECOND 128 +#define RELOAD_VALUE ((F_CPU/CLOCK_CONF_SECOND) - 1) +/* One tick: 62.5 ms */ + +#define RTIMER_CLOCK_LT(a,b) ((signed short)((a)-(b)) < 0) +/*---------------------------------------------------------------------------*/ +typedef unsigned long clock_time_t; +typedef unsigned long long rtimer_clock_t; +/*---------------------------------------------------------------------------*/ +#define CC_CONF_REGISTER_ARGS 0 +#define CC_CONF_FUNCTION_POINTER_ARGS 1 +#define CC_CONF_FASTCALL +#define CC_CONF_VA_ARGS 1 +#define CC_CONF_INLINE inline + +#define CCIF +#define CLIF +/*---------------------------------------------------------------------------*/ +typedef uint8_t u8_t; +typedef uint16_t u16_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; +typedef unsigned short uip_stats_t; +/*---------------------------------------------------------------------------*/ +#define MULTICHAN_CONF_SET_CHANNEL(x) +#define MULTICHAN_CONF_READ_RSSI(x) 0 +/*---------------------------------------------------------------------------*/ +#endif//USE_STM32L1XX_NUCLEO + +#ifdef USE_STM32F4XX_NUCLEO +#include <inttypes.h> +#include <string.h> +#include "main.h" +/*---------------------------------------------------------------------------*/ +#define PLATFORM_HAS_LEDS 1 +#define PLATFORM_HAS_BUTTON 1 +#define PLATFORM_HAS_RADIO 1 + +#define LEDS_GREEN 1 /*Nucleo LED*/ +#define LEDS_RED 2 /*SPIRIT1 LED*/ + +#ifdef COMPILE_SENSORS +#define LEDS_CONF_ALL 1 /*Can't use SPIRIT1 LED in this case*/ +#else +#define LEDS_CONF_ALL 3 /*No sensors -> we can use SPIRIT1 LED in this case*/ +#endif /*COMPILE_SENSORS*/ +/*---------------------------------------------------------------------------*/ +#define F_CPU 84000000ul +#define RTIMER_ARCH_SECOND 96000//32678 +//#define PRESCALER uwPrescalerValue + +#define UART1_CONF_TX_WITH_INTERRUPT 0 +#define WITH_SERIAL_LINE_INPUT 1 +#define TELNETD_CONF_NUMLINES 6 +#define NETSTACK_CONF_RADIO spirit_radio_driver +#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 96 /* spirit1-config.h */ + +#if WITH_IP64 +#include "ip64-conf.h" +#define WITH_SLIP 1 +#ifndef UIP_FALLBACK_INTERFACE +#define UIP_FALLBACK_INTERFACE ip64_uip_fallback_interface +#endif +#endif /* WITH_IP64 */ + +/*---------------------------------------------------------------------------*/ +/* define ticks/second for slow and fast clocks. Notice that these should be a + power of two, eg 64,128,256,512 etc, for efficiency as POT's can be optimized + well. */ +#define CLOCK_CONF_SECOND 512 +#define RELOAD_VALUE ((F_CPU/CLOCK_CONF_SECOND) - 1) + +/* One tick: 62.5 ms */ + +#define RTIMER_CLOCK_LT(a,b) ((signed short)((a)-(b)) < 0) +/*---------------------------------------------------------------------------*/ +typedef unsigned long clock_time_t; +typedef unsigned long long rtimer_clock_t; +/*---------------------------------------------------------------------------*/ +#define CC_CONF_REGISTER_ARGS 0 +#define CC_CONF_FUNCTION_POINTER_ARGS 1 +#define CC_CONF_FASTCALL +#define CC_CONF_VA_ARGS 1 +#define CC_CONF_INLINE inline + +#define CCIF +#define CLIF +/*---------------------------------------------------------------------------*/ +typedef uint8_t u8_t; +typedef uint16_t u16_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; +typedef unsigned short uip_stats_t; +/*---------------------------------------------------------------------------*/ +#define MULTICHAN_CONF_SET_CHANNEL(x) +#define MULTICHAN_CONF_READ_RSSI(x) 0 +/*---------------------------------------------------------------------------*/ +#endif//USE_STM32F4XX_NUCLEO + +#endif /* __PLATFORM_CONF_H__ */ +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + */
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/radio.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/radio.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * Header file for the radio API + * \author + * Adam Dunkels <adam@sics.se> + * Joakim Eriksson <joakime@sics.se> + * Niclas Finne <nfi@sics.se> + * Nicolas Tsiftes <nvt@sics.se> + */ + +/** + * \addtogroup dev + * @{ + */ + +/** + * \defgroup radio Radio API + * + * The radio API module defines a set of functions that a radio device + * driver must implement. + * + * @{ + */ + +#ifndef RADIO_H_ +#define RADIO_H_ + +#include <stddef.h> + +/** + * Each radio has a set of parameters that designate the current + * configuration and state of the radio. Parameters can either have + * values of type radio_value_t, or, when this type is insufficient, a + * generic object that is specified by a memory pointer and the size + * of the object. + * + * The radio_value_t type is set to an integer type that can hold most + * values used to configure the radio, and is therefore the most + * common type used for a parameter. Certain parameters require + * objects of a considerably larger size than radio_value_t, however, + * and in these cases the documentation below for the parameter will + * indicate this. + * + * All radio parameters that can vary during runtime are prefixed by + * "RADIO_PARAM", whereas those "parameters" that are guaranteed to + * remain immutable are prefixed by "RADIO_CONST". Each mutable + * parameter has a set of valid parameter values. When attempting to + * set a parameter to an invalid value, the radio will return + * RADIO_RESULT_INVALID_VALUE. + * + * Some radios support only a subset of the defined radio parameters. + * When trying to set or get such an unsupported parameter, the radio + * will return RADIO_RESULT_NOT_SUPPORTED. + */ + +typedef int radio_value_t; +typedef unsigned radio_param_t; + +enum { + + /* Radio power mode determines if the radio is on + (RADIO_POWER_MODE_ON) or off (RADIO_POWER_MODE_OFF). */ + RADIO_PARAM_POWER_MODE, + + /* + * Channel used for radio communication. The channel depends on the + * communication standard used by the radio. The values can range + * from RADIO_CONST_CHANNEL_MIN to RADIO_CONST_CHANNEL_MAX. + */ + RADIO_PARAM_CHANNEL, + + /* Personal area network identifier, which is used by the address filter. */ + RADIO_PARAM_PAN_ID, + + /* Short address (16 bits) for the radio, which is used by the address + filter. */ + RADIO_PARAM_16BIT_ADDR, + + /* + * Radio receiver mode determines if the radio has address filter + * (RADIO_RX_MODE_ADDRESS_FILTER) and auto-ACK (RADIO_RX_MODE_AUTOACK) + * enabled. This parameter is set as a bit mask. + */ + RADIO_PARAM_RX_MODE, + + /* + * Radio transmission mode determines if the radio has send on CCA + * (RADIO_TX_MODE_SEND_ON_CCA) enabled or not. This parameter is set + * as a bit mask. + */ + RADIO_PARAM_TX_MODE, + + /* + * Transmission power in dBm. The values can range from + * RADIO_CONST_TXPOWER_MIN to RADIO_CONST_TXPOWER_MAX. + * + * Some radios restrict the available values to a subset of this + * range. If an unavailable TXPOWER value is requested to be set, + * the radio may select another TXPOWER close to the requested + * one. When getting the value of this parameter, the actual value + * used by the radio will be returned. + */ + RADIO_PARAM_TXPOWER, + + /* + * Clear channel assessment threshold in dBm. This threshold + * determines the minimum RSSI level at which the radio will assume + * that there is a packet in the air. + * + * The CCA threshold must be set to a level above the noise floor of + * the deployment. Otherwise mechanisms such as send-on-CCA and + * low-power-listening duty cycling protocols may not work + * correctly. Hence, the default value of the system may not be + * optimal for any given deployment. + */ + RADIO_PARAM_CCA_THRESHOLD, + + /* Received signal strength indicator in dBm. */ + RADIO_PARAM_RSSI, + + /* + * Long (64 bits) address for the radio, which is used by the address filter. + * The address is specified in network byte order. + * + * Because this parameter value is larger than what fits in radio_value_t, + * it needs to be used with radio.get_object()/set_object(). + */ + RADIO_PARAM_64BIT_ADDR, + + /* Constants (read only) */ + + /* The lowest radio channel. */ + RADIO_CONST_CHANNEL_MIN, + /* The highest radio channel. */ + RADIO_CONST_CHANNEL_MAX, + + /* The minimum transmission power in dBm. */ + RADIO_CONST_TXPOWER_MIN, + /* The maximum transmission power in dBm. */ + RADIO_CONST_TXPOWER_MAX +}; + +/* Radio power modes */ +enum { + RADIO_POWER_MODE_OFF, + RADIO_POWER_MODE_ON +}; + +/** + * The radio reception mode controls address filtering and automatic + * transmission of acknowledgements in the radio (if such operations + * are supported by the radio). A single parameter is used to allow + * setting these features simultaneously as an atomic operation. + * + * To enable both address filter and transmissions of automatic + * acknowledgments: + * + * NETSTACK_RADIO.set_value(RADIO_PARAM_RX_MODE, + * RADIO_RX_MODE_ADDRESS_FILTER | RADIO_RX_MODE_AUTOACK); + */ +#define RADIO_RX_MODE_ADDRESS_FILTER (1 << 0) +#define RADIO_RX_MODE_AUTOACK (1 << 1) + +/** + * The radio transmission mode controls whether transmissions should + * be done using clear channel assessment (if supported by the + * radio). If send-on-CCA is enabled, the radio's send function will + * wait for a radio-specific time window for the channel to become + * clear. If this does not happen, the send function will return + * RADIO_TX_COLLISION. + */ +#define RADIO_TX_MODE_SEND_ON_CCA (1 << 0) + +/* Radio return values when setting or getting radio parameters. */ +typedef enum { + RADIO_RESULT_OK, + RADIO_RESULT_NOT_SUPPORTED, + RADIO_RESULT_INVALID_VALUE, + RADIO_RESULT_ERROR +} radio_result_t; + +/* Radio return values for transmissions. */ +enum { + RADIO_TX_OK, + RADIO_TX_ERR, + RADIO_TX_COLLISION, + RADIO_TX_NOACK, +}; + +/** + * The structure of a device driver for a radio in Contiki. + */ +struct radio_driver { + + int (* init)(void); + + /** Prepare the radio with a packet to be sent. */ + int (* prepare)(const void *payload, unsigned short payload_len); + + /** Send the packet that has previously been prepared. */ + int (* transmit)(unsigned short transmit_len); + + /** Prepare & transmit a packet. */ + int (* send)(const void *payload, unsigned short payload_len); + + /** Read a received packet into a buffer. */ + int (* read)(void *buf, unsigned short buf_len); + + /** Perform a Clear-Channel Assessment (CCA) to find out if there is + a packet in the air or not. */ + int (* channel_clear)(void); + + /** Check if the radio driver is currently receiving a packet */ + int (* receiving_packet)(void); + + /** Check if the radio driver has just received a packet */ + int (* pending_packet)(void); + + /** Turn the radio on. */ + int (* on)(void); + + /** Turn the radio off. */ + int (* off)(void); + + /** Get a radio parameter value. */ + radio_result_t (* get_value)(radio_param_t param, radio_value_t *value); + + /** Set a radio parameter value. */ + radio_result_t (* set_value)(radio_param_t param, radio_value_t value); + + /** + * Get a radio parameter object. The argument 'dest' must point to a + * memory area of at least 'size' bytes, and this memory area will + * contain the parameter object if the function succeeds. + */ + radio_result_t (* get_object)(radio_param_t param, void *dest, size_t size); + + /** + * Set a radio parameter object. The memory area referred to by the + * argument 'src' will not be accessed after the function returns. + */ + radio_result_t (* set_object)(radio_param_t param, const void *src, + size_t size); + +}; + +#endif /* RADIO_H_ */ + +/** @} */ +/** @} */
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/spirit1-config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/spirit1-config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012, STMicroelectronics. + * 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. + * + */ +/*---------------------------------------------------------------------------*/ +#ifndef __SPIRIT1_CONFIG_H__ +#define __SPIRIT1_CONFIG_H__ +/*---------------------------------------------------------------------------*/ +#include "radio.h" +#include "SPIRIT_Config.h" +#include "spirit1-const.h" +/*---------------------------------------------------------------------------*/ +#define CCA_THRESHOLD -98.0 /* dBm */ +#define XTAL_FREQUENCY 50000000 /* Hz */ +#define SPIRIT_MAX_FIFO_LEN (96) // betzw - WAS: 600 +/*---------------------------------------------------------------------------*/ + +/* Sometimes Spirit1 seems to NOT deliver (correctly) the 'IRQ_RX_DATA_READY' + * event for packets which have a length which is close to a multiple of + * RX FIFO size. Furthermore, in these cases also the content delivery seems + * to be compromised as well as the generation of RX/TX FIFO errors. + * This can be avoided by reducing the maximum packet length to a value which + * is lower than the RX FIFO size. + * + * Enable beyond macro if you want to use the version of the driver which avoids + * FIFO overflows by reducing packet length. + * + * NOTE: the non delivery of event 'IRQ_RX_DATA_READY' MUST still be + * investigated further deeply (both on HW & SW level)! + */ +#define RX_FIFO_THR_WA + +/** + * The MAX_PACKET_LEN is an arbitrary value used to define the two array + * spirit_txbuf and spirit_rxbuf. + * The SPIRIT1 supports with its packet handler a length of 65,535 bytes, + * and in direct mode (without packet handler) there is no limit of data. + */ +#ifdef RX_FIFO_THR_WA +#define MAX_PACKET_LEN (SPIRIT_MAX_FIFO_LEN-1) +#else +#define MAX_PACKET_LEN (255) // betzw - WAS: SPIRIT_MAX_FIFO_LEN, but LEN_WIDTH is set to 7 so the variable payload length is theoretically from 0 to 255 bytes +#endif + +/*---------------------------------------------------------------------------*/ +/** + * Spirit1 IC version + */ +#define SPIRIT1_VERSION SPIRIT_VERSION_3_0 +/*---------------------------------------------------------------------------*/ +#endif /* __SPIRIT1_CONFIG_H__ */ +/*---------------------------------------------------------------------------*/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/spirit1-const.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/spirit1-const.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012, STMicroelectronics. + * 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 __SPIRIT1_CONST_H__ +#define __SPIRIT1_CONST_H__ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ + +/* The state bitfield and values for different states, as read from MC_STATE[1:0] registers, +which are returned on any SPI read or write operation. */ +#define SPIRIT1_STATE_STATEBITS (0x00FE) +/*---------------------------------------------------------------------------*/ + +#define SPIRIT1_STATE_STANDBY ((0x0040)<<1) +#define SPIRIT1_STATE_SLEEP ((0x0036)<<1) +#define SPIRIT1_STATE_READY ((0x0003)<<1) +#define SPIRIT1_STATE_LOCK ((0x000F)<<1) +#define SPIRIT1_STATE_RX ((0x0033)<<1) +#define SPIRIT1_STATE_TX ((0x005F)<<1) +/* NB the below states were extracted from ST drivers, but are not specified in the datasheet */ +#define SPIRIT1_STATE_PM_SETUP ((0x003D)<<1) +#define SPIRIT1_STATE_XO_SETTLING ((0x0023)<<1) +#define SPIRIT1_STATE_SYNTH_SETUP ((0x0053)<<1) +#define SPIRIT1_STATE_PROTOCOL ((0x001F)<<1) +#define SPIRIT1_STATE_SYNTH_CALIBRATION ((0x004F)<<1) +/*---------------------------------------------------------------------------*/ +/* strobe commands */ +#define SPIRIT1_STROBE_TX 0x60 +#define SPIRIT1_STROBE_RX 0x61 +#define SPIRIT1_STROBE_READY 0x62 +#define SPIRIT1_STROBE_STANDBY 0x63 +#define SPIRIT1_STROBE_SLEEP 0x64 +#define SPIRIT1_STROBE_SABORT 0x67 +#define SPIRIT1_STROBE_SRES 0x70 +#define SPIRIT1_STROBE_FRX 0x71 +#define SPIRIT1_STROBE_FTX 0x72 +/*---------------------------------------------------------------------------*/ + + + +/* Exported types ------------------------------------------------------------*/ +/*------------------------------------------------------------------*/ + + +#endif /* __SPIRIT1_CONST_H__ */ +/*---------------------------------------------------------------------------*/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/spirit1.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/spirit1.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2012, STMicroelectronics. + * 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. + * + */ +/*---------------------------------------------------------------------------*/ +#ifndef __SPIRIT_H__ +#define __SPIRIT_H__ +/*---------------------------------------------------------------------------*/ +#include "radio.h" +#include "SPIRIT_Config.h" +#include "spirit1-config.h" +//#include "spirit1_appli.h" +#include "spirit1-const.h" +/*---------------------------------------------------------------------------*/ +extern const struct radio_driver spirit_radio_driver; +void spirit1_interrupt_callback(void); + +/* exported from spirit1appli.h */ + +#include "radio_shield_config.h" +#include "MCU_Interface.h" +#include "SPIRIT_Config.h" +// betzw - WAS: #include "SPIRIT1_Util.h" + + +#if defined(X_NUCLEO_IDS01A3) + #define USE_SPIRIT1_433MHz +#elif defined(X_NUCLEO_IDS01A4) + #define USE_SPIRIT1_868MHz +#elif defined(X_NUCLEO_IDS01A5) + #define USE_SPIRIT1_915MHz +#else +#error SPIRIT1 Nucleo Shield undefined or unsupported +#endif + +/* Uncomment the Link Layer features to be used */ +// #define USE_AUTO_ACK +// #define USE_AUTO_ACK_PIGGYBACKING +// #define USE_AUTO_RETRANSMISSION + +#if defined(USE_AUTO_ACK)&& defined(USE_AUTO_ACK_PIGGYBACKING)&& defined(USE_AUTO_RETRANSMISSION) +#define USE_STack_PROTOCOL + +/* LLP configuration parameters */ +#define EN_AUTOACK S_ENABLE +#define EN_PIGGYBACKING S_ENABLE +#define MAX_RETRANSMISSIONS PKT_N_RETX_2 + +#else +#define USE_BASIC_PROTOCOL + +#endif + +/* Uncomment the system Operating mode */ +//#define USE_LOW_POWER_MODE + +#if defined (USE_LOW_POWER_MODE) +#define LPM_ENABLE +#define MCU_STOP_MODE +//#define MCU_SLEEP_MODE +//#define RF_STANDBY +#endif + + +/* Exported constants --------------------------------------------------------*/ + +/* Radio configuration parameters */ +/* General Remarks: + * Two SPSGRF modules will only communicate when both are having same frequency , same channel number, + * same modulation scheme, same data rate, etc. + * For example, the SPSGRF-915 module supports frequencies 902 to 928 MHz. User can select any frequency + * between this band. + */ +#define XTAL_OFFSET_PPM 0 +#define INFINITE_TIMEOUT 0.0 + +#ifdef USE_SPIRIT1_433MHz +#define BASE_FREQUENCY 433.0e6 +#endif + +#ifdef USE_SPIRIT1_868MHz +#define BASE_FREQUENCY 868.0e6 +#endif + +#ifdef USE_SPIRIT1_915MHz +#define BASE_FREQUENCY 915.0e6 +#endif + + +/* Addresses configuration parameters */ +#define EN_FILT_MY_ADDRESS S_DISABLE +#define MY_ADDRESS 0x24 +#define EN_FILT_MULTICAST_ADDRESS S_DISABLE +#define MULTICAST_ADDRESS 0xEE +#define EN_FILT_BROADCAST_ADDRESS S_DISABLE +#define BROADCAST_ADDRESS 0xFF +#define DESTINATION_ADDRESS 0x44 +#define EN_FILT_SOURCE_ADDRESS S_DISABLE +#define SOURCE_ADDR_MASK 0xf0 +#define SOURCE_ADDR_REF 0x37 + +#define APPLI_CMD 0x11 +#define NWK_CMD 0x22 +#define LED_TOGGLE 0xff +#define ACK_OK 0x01 +#define MAX_BUFFER_LEN 96 +#define TIME_TO_EXIT_RX 3000 +#define DELAY_RX_LED_TOGGLE 200 +#define DELAY_TX_LED_GLOW 1000 +#define LPM_WAKEUP_TIME 100 +#define DATA_SEND_TIME 30 + +#define PREAMBLE_LENGTH PKT_PREAMBLE_LENGTH_04BYTES +#define SYNC_LENGTH PKT_SYNC_LENGTH_4BYTES +#define CONTROL_LENGTH PKT_CONTROL_LENGTH_0BYTES +#define EN_ADDRESS S_DISABLE +#define EN_FEC S_DISABLE +#define CHANNEL_NUMBER 1 // betzw - WAS: 0 +#define LENGTH_TYPE PKT_LENGTH_VAR +#define POWER_INDEX 7 +#define RECEIVE_TIMEOUT 2000.0 /*change the value for required timeout period*/ +#define RSSI_THRESHOLD -120 + + + +#define POWER_DBM 11.6 +#define CHANNEL_SPACE 100e3 +#define FREQ_DEVIATION 127e3 +#define BANDWIDTH 540.0e3 +#define MODULATION_SELECT GFSK_BT1 +#define DATARATE 250000 +#define XTAL_OFFSET_PPM 0 +#define SYNC_WORD 0x88888888 +#define LENGTH_WIDTH 8 // betzw - NOTE: only 255 bytes for payload!!! +#define CRC_MODE PKT_CRC_MODE_16BITS_2 +#define EN_WHITENING S_DISABLE +#define INFINITE_TIMEOUT 0.0 + +// extern volatile FlagStatus xRxDoneFlag, xTxDoneFlag; +// extern volatile FlagStatus PushButtonStatusWakeup; +extern uint16_t wakeupCounter; +extern uint16_t dataSendCounter ; +// extern volatile FlagStatus PushButtonStatusData, datasendFlag; + +typedef struct +{ + uint8_t Cmdtag; + uint8_t CmdType; + uint8_t CmdLen; + uint8_t Cmd; + uint8_t DataLen; + uint8_t* DataBuff; +}AppliFrame_t; + +/*---------------------------------------------------------------------------*/ +#endif /* __SPIRIT_H__ */ +/*---------------------------------------------------------------------------*/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/stm32l-spirit1-config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/Contiki_STM32_Library/stm32l-spirit1-config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,98 @@ +/** + ****************************************************************************** + * @file stm32l-spirit1-config.h + * @author MCD Application Team + * @version V3.4.0 + * @date 29-June-2012 + * @brief Evaluation board specific configuration file. + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT 2012 STMicroelectronics</center></h2> + * + * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.st.com/software_license_agreement_liberty_v2 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L_SPIRIT1_CONFIG_H +#define __STM32L_SPIRIT1_CONFIG_H + +/* Includes ------------------------------------------------------------------*/ + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* Define the STM32F10x hardware depending on the used evaluation board */ +#ifdef USE_STM3210B_EVAL + #define USB_DISCONNECT GPIOD + #define USB_DISCONNECT_PIN GPIO_PIN_9 + #define RCC_APB2Periph_GPIO_DISCONNECT RCC_APB2Periph_GPIOD + #define EVAL_COM1_IRQHandler USART1_IRQHandler + +#elif defined (USE_STM3210E_EVAL) + #define USB_DISCONNECT GPIOB + #define USB_DISCONNECT_PIN GPIO_PIN_14 + #define RCC_APB2Periph_GPIO_DISCONNECT RCC_APB2Periph_GPIOB + #define EVAL_COM1_IRQHandler USART1_IRQHandler + +#elif defined (USE_STM3210C_EVAL) + #define USB_DISCONNECT 0 + #define USB_DISCONNECT_PIN 0 + #define RCC_APB2Periph_GPIO_DISCONNECT 0 + #define EVAL_COM1_IRQHandler USART2_IRQHandler + +#elif defined (USE_STM32L152_EVAL) || defined (USE_STM32L152D_EVAL) + /* + For STM32L15xx devices it is possible to use the internal USB pullup + controlled by register SYSCFG_PMC (refer to RM0038 reference manual for + more details). + It is also possible to use external pullup (and disable the internal pullup) + by setting the define USB_USE_EXTERNAL_PULLUP in file platform_config.h + and configuring the right pin to be used for the external pull up configuration. + To have more details on how to use an external pull up, please refer to + STM3210E-EVAL evaluation board manuals. + */ + /* Uncomment the following define to use an external pull up instead of the + integrated STM32L15xx internal pull up. In this case make sure to set up + correctly the external required hardware and the GPIO defines below.*/ +/* #define USB_USE_EXTERNAL_PULLUP */ + + #if !defined(USB_USE_EXTERNAL_PULLUP) + #define STM32L15_USB_CONNECT SYSCFG_USBPuCmd(ENABLE) + #define STM32L15_USB_DISCONNECT SYSCFG_USBPuCmd(DISABLE) + + #elif defined(USB_USE_EXTERNAL_PULLUP) + /* PA0 is chosen just as illustrating example, you should modify the defines + below according to your hardware configuration. */ + #define USB_DISCONNECT GPIOA + #define USB_DISCONNECT_PIN GPIO_PIN_0 + #define RCC_AHBPeriph_GPIO_DISCONNECT RCC_AHBPeriph_GPIOA + #define STM32L15_USB_CONNECT GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN) + #define STM32L15_USB_DISCONNECT GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN) + #endif /* USB_USE_EXTERNAL_PULLUP */ + +#ifdef USE_STM32L152_EVAL + #define EVAL_COM1_IRQHandler USART2_IRQHandler +#elif defined (USE_STM32L152D_EVAL) + #define EVAL_COM1_IRQHandler USART1_IRQHandler +#endif /*USE_STM32L152_EVAL*/ + +#endif /* USE_STM3210B_EVAL */ + +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +#endif /* __STM32L_SPIRIT1_CONFIG_H */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/Release_Notes.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/Release_Notes.html Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,154 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-html40"><head> + +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> +<link rel="File-List" href="Library_files/filelist.xml"> +<link rel="Edit-Time-Data" href="Library_files/editdata.mso"><!--[if !mso]> <style> v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} </style> <![endif]--><title>Release Notes for SPIRIT1 Driver</title><!--[if gte mso 9]><xml> <o:DocumentProperties> <o:Author>STMicroelectronics</o:Author> <o:LastAuthor>STMicroelectronics</o:LastAuthor> <o:Revision>37</o:Revision> <o:TotalTime>136</o:TotalTime> <o:Created>2009-02-27T19:26:00Z</o:Created> <o:LastSaved>2009-03-01T17:56:00Z</o:LastSaved> <o:Pages>1</o:Pages> <o:Words>522</o:Words> <o:Characters>2977</o:Characters> <o:Company>STMicroelectronics</o:Company> <o:Lines>24</o:Lines> <o:Paragraphs>6</o:Paragraphs> <o:CharactersWithSpaces>3493</o:CharactersWithSpaces> <o:Version>11.6568</o:Version> </o:DocumentProperties> </xml><![endif]--><!--[if gte mso 9]><xml> <w:WordDocument> <w:Zoom>110</w:Zoom> <w:ValidateAgainstSchemas/> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" LatentStyleCount="156"> </w:LatentStyles> </xml><![endif]--> + + + +<style> +<!-- +/* Style Definitions */ +p.MsoNormal, li.MsoNormal, div.MsoNormal +{mso-style-parent:""; +margin:0in; +margin-bottom:.0001pt; +mso-pagination:widow-orphan; +font-size:12.0pt; +font-family:"Times New Roman"; +mso-fareast-font-family:"Times New Roman";} +h2 +{mso-style-next:Normal; +margin-top:12.0pt; +margin-right:0in; +margin-bottom:3.0pt; +margin-left:0in; +mso-pagination:widow-orphan; +page-break-after:avoid; +mso-outline-level:2; +font-size:14.0pt; +font-family:Arial; +font-weight:bold; +font-style:italic;} +a:link, span.MsoHyperlink +{color:blue; +text-decoration:underline; +text-underline:single;} +a:visited, span.MsoHyperlinkFollowed +{color:blue; +text-decoration:underline; +text-underline:single;} +p +{mso-margin-top-alt:auto; +margin-right:0in; +mso-margin-bottom-alt:auto; +margin-left:0in; +mso-pagination:widow-orphan; +font-size:12.0pt; +font-family:"Times New Roman"; +mso-fareast-font-family:"Times New Roman";} +@page Section1 +{size:8.5in 11.0in; +margin:1.0in 1.25in 1.0in 1.25in; +mso-header-margin:.5in; +mso-footer-margin:.5in; +mso-paper-source:0;} +div.Section1 +{page:Section1;} +--> +</style><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]--><!--[if gte mso 9]><xml> <o:shapedefaults v:ext="edit" spidmax="5122"/> </xml><![endif]--><!--[if gte mso 9]><xml> <o:shapelayout v:ext="edit"> <o:idmap v:ext="edit" data="1"/> </o:shapelayout></xml><![endif]--> +<meta content="MCD Application Team" name="author"></head><body link="blue" vlink="blue"> +<div class="Section1"> +<p class="MsoNormal"><span style="font-family: Arial;"><o:p><br> +</o:p></span></p> +<div align="center"> +<table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" cellspacing="0" width="900"> +<tbody> +<tr> +<td style="padding: 0cm;" valign="top"> +<table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" cellspacing="0" width="900"> +<tbody> +<tr> +<td style="vertical-align: top;"> +<p class="MsoNormal"><span style="font-size: 8pt; font-family: Arial; color: blue;"><a href="../../../../Release_Notes.html">Back to Release page</a><o:p></o:p></span></p> +</td> +</tr> +<tr style=""> +<td style="padding: 1.5pt;"> +<h1 style="margin-bottom: 18pt; text-align: center;" align="center"><span style="font-size: 20pt; font-family: Verdana; color: rgb(51, 102, 255);">Release +Notes for SPIRIT1 Driver</span><span style="font-size: 20pt; font-family: Verdana;"><o:p></o:p></span></h1> +<p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: Arial; color: black;">Copyright +2014 STMicroelectronics</span><span style="color: black;"><u1:p></u1:p><o:p></o:p></span></p> +<p class="MsoNormal" style="text-align: center;" align="center"><span style="font-size: 10pt; font-family: Arial; color: black;"><img alt="" id="_x0000_i1025" src="../../../../_htmresc/st_logo.png" style="border: 0px solid ; width: 86px; height: 65px;"></span><span style="font-size: 10pt;"><o:p></o:p></span></p> +</td> +</tr> +</tbody> +</table> +<p class="MsoNormal"><span style="font-family: Arial; display: none;"><o:p> </o:p></span></p> +<table class="MsoNormalTable" style="width: 675pt;" border="0" cellpadding="0" width="900"> +<tbody> +<tr style=""> +<td style="padding: 0cm;" valign="top"> +<span style="font-family: "Times New Roman";"> +</span> +<h2 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><a name="History"></a><span style="font-size: 12pt; color: white;">Update History</span></h2> +<span style="font-size: 10pt; font-family: Verdana;"></span> +<h3 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-right: 500pt; width: 200px;"><span style="font-size: 10pt; font-family: Arial; color: white;">V3.0.1 +/ 10-Oct-2014</span></h3> +<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt;"><b style=""><u><span style="font-size: 10pt; font-family: Verdana; color: black;">Main +Changes<o:p></o:p></span></u></b></p> +<span style="font-size: 10pt; font-family: Verdana;"></span> +<span style="font-size: 10pt; font-family: Verdana;"></span> +<span style="font-size: 10pt; font-family: Verdana;"></span><span style="font-size: 10pt; font-family: Verdana;"></span> +<span style="font-size: 10pt; font-family: Verdana;"></span> +<span style="font-size: 10pt; font-family: Verdana;"></span> +<span style="font-size: 10pt; font-family: Verdana;"></span> +<span style="font-size: 10pt; font-family: Verdana;"></span> +<span style="font-size: 10pt; font-family: Verdana;"></span> +<span style="font-size: 10pt; font-family: Verdana;"></span> +<ul style="list-style-type: square;"> +<li><span style="font-size: 10pt; font-family: Verdana;">First +official release.</span><span style="color: rgb(0, 0, 0); font-family: Verdana; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; display: inline ! important; float: none;"></span><span style="font-size: 10pt; font-family: Verdana;"></span><span style="font-size: 10pt; font-family: Verdana;"></span></li> +</ul> +<span style="font-size: 10pt; font-family: Verdana;"><span style="font-style: italic; font-weight: bold;"></span></span><span style="font-size: 10pt; font-family: Verdana;"><span style="font-style: italic; font-weight: bold;"></span></span><span style="font-size: 10pt; font-family: Verdana;"><span style="font-style: italic; font-weight: bold;"></span></span><span style="font-size: 10pt; font-family: Verdana;"><span style="font-style: italic; font-weight: bold;"></span></span><span style="font-size: 10pt; font-family: Verdana;"><span style="font-style: italic; font-weight: bold;"></span></span><span style="font-size: 10pt; font-family: Verdana;"></span> +<h2 style="background: rgb(51, 102, 255) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><a name="License"></a><span style="font-size: 12pt; color: white;">License<o:p></o:p></span><br> +</h2> + + +<font size="-1"><span style="font-family: "Verdana","sans-serif";">Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"). You may not use this file except in compliance with the License. You may obtain a copy of the License at:</span><br><br> + + +<font size="-1"><span style="font-family: "Verdana","sans-serif";"><center> +<a href=http://www.st.com/software_license_agreement_liberty_v2> http://www.st.com/software_license_agreement_liberty_v2</a></center></span><br><br> + +<font size="-1"><span style="font-family: "Verdana","sans-serif";">Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +</a></span> + +</font> + + +<p class="MsoNormal"><span style="font-size: 10pt; font-family: "Verdana","sans-serif"; color: black;"><o:p></o:p></span></p> +<b><span style="font-size: 10pt; font-family: Verdana; color: black;"></span></b> +<div class="MsoNormal" style="text-align: center;" align="center"><span style="color: black;"> +<hr align="center" size="2" width="100%"></span></div> +<p class="MsoNormal" style="margin: 4.5pt 0cm 4.5pt 18pt; text-align: center;" align="center"><span style="font-size: 10pt; font-family: Verdana; color: black;">For +complete documentation on</span><span style="font-size: 10pt; font-family: Verdana;"><span style="color: black;"> SPIRIT1 Driver +visit </span><u><span style="color: blue;"><a href="http://www.st.com/web/catalog/sense_power/FM1968/CL1976/SC1845/PF253167" target="_blank">www.st.com/SPIRIT1</a></span></u></span><span style="font-size: 10pt; font-family: Verdana;"><a target="_blank" href="http://www.st.com/web/catalog/sense_power/FM1968/CL1976/SC1898/PF258646"><u><span style="color: blue;"></span></u></a></span><span style="font-size: 10pt; font-family: Verdana;"><u><span style="color: blue;"></span></u></span><span style="color: black;"><o:p></o:p></span></p> +</td> +</tr> +</tbody> +</table> +<p class="MsoNormal"><span style="font-size: 10pt;"><o:p></o:p></span></p> +</td> +</tr> +</tbody> +</table> +</div> +<p class="MsoNormal"><o:p> </o:p></p> +</div> +</body></html> \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/MCU_Interface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/MCU_Interface.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,152 @@ +/** + * @file MCU_Interface.h + * @author VMA division - AMS + * @version V2.0.2 + * @date Febrary 7, 2015 + * @brief Header file for low level SPIRIT SPI driver. + * @details + * + * This header file constitutes an interface to the SPI driver used to + * communicate with Spirit. + * It exports some function prototypes to write/read registers and FIFOs + * and to send command strobes. + * Since the Spirit libraries are totally platform independent, the implementation + * of these functions are not provided here. The user have to implement these functions + * taking care to keep the exported prototypes. + * + * These functions are: + * + * <ul> + * <li>SpiritSpiInit</i> + * <li>SpiritSpiWriteRegisters</i> + * <li>SpiritSpiReadRegisters</i> + * <li>SpiritSpiCommandStrobes</i> + * <li>SpiritSpiWriteLinearFifo</i> + * <li>SpiritSpiReadLinearFifo</i> + * </ul> + * + * @note An example of SPI driver implementation is available in the <i>Sdk_Eval</i> library. + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * THIS SOURCE CODE IS PROTECTED BY A LICENSE. + * FOR MORE INFORMATION PLEASE CAREFULLY READ THE LICENSE AGREEMENT FILE LOCATED + * IN THE ROOT DIRECTORY OF THIS FIRMWARE PACKAGE. + * + * <h2><center>© COPYRIGHT 2015 STMicroelectronics</center></h2> + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MCU_INTERFACE_H +#define __MCU_INTERFACE_H + + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** @defgroup SPIRIT_SPI_Driver SPI Driver + * @brief Header file for low level SPIRIT SPI driver. + * @details See the file <i>@ref MCU_Interface.h</i> for more details. + * @{ + */ + + + +/** @defgroup SPI_Exported_Types SPI Exported Types + * @{ + */ + +/** + * @} + */ + + + +/** @defgroup SPI_Exported_Constants SPI Exported Constants + * @{ + */ + +/** + * @} + */ + + + +/** @defgroup SPI_Exported_Macros SPI Exported Macros + * @{ + */ + +/** + * @} + */ + + + +/** @defgroup SPI_Exported_Functions SPI Exported Functions + * @{ + */ + +typedef SpiritStatus StatusBytes; + +void SdkEvalSpiInit(void); +StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); +StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); +StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode); +StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer); +StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer); + +void SdkEvalEnterShutdown(void); +void SdkEvalExitShutdown(void); +SpiritFlagStatus SdkEvalCheckShutdown(void); + +#define SpiritEnterShutdown SdkEvalEnterShutdown +#define SpiritExitShutdown SdkEvalExitShutdown +#define SpiritCheckShutdown (SpiritFlagStatus)SdkEvalCheckShutdown + + +#define SpiritSpiInit SdkEvalSpiInit +#define SpiritSpiWriteRegisters(cRegAddress, cNbBytes, pcBuffer) SdkEvalSpiWriteRegisters(cRegAddress, cNbBytes, pcBuffer) +#define SpiritSpiReadRegisters(cRegAddress, cNbBytes, pcBuffer) SdkEvalSpiReadRegisters(cRegAddress, cNbBytes, pcBuffer) +#define SpiritSpiCommandStrobes(cCommandCode) SdkEvalSpiCommandStrobes(cCommandCode) +#define SpiritSpiWriteLinearFifo(cNbBytes, pcBuffer) SdkEvalSpiWriteFifo(cNbBytes, pcBuffer) +#define SpiritSpiReadLinearFifo(cNbBytes, pcBuffer) SdkEvalSpiReadFifo(cNbBytes, pcBuffer) + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Aes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Aes.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,205 @@ +/** + ****************************************************************************** + * @file SPIRIT_Aes.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT AES Engine. + * + * @details + * + * In order to encrypt data, the user must manage the AES_END IRQ. + * The data have to be splitted in blocks of 16 bytes and written + * into the <i>AES DATA IN registers</i>. Then, after the key is written + * into the <i>AES KEY registers</i>, a command of <i>Execute encryption</i> + * has to be sent. + * + * <b>Example:</b> + * @code + * + * SpiritAesWriteDataIn(data_buff , N_BYTES); + * SpiritAesExecuteEncryption(); + * + * while(!aes_end_flag); // the flag is set by the ISR routine which manages the AES_END irq + * aes_end_flag=RESET; + * + * SpiritAesReadDataOut(enc_data_buff , N_BYTES); + * + * @endcode + * + * In order to decrypt data, the user must manage the AES_END IRQ and have a decryption key. + * There are two operative modes to make the data decryption: + * <ul> + * <li> Derive the decryption key from the encryption key and decrypt data directly + * using the <i>SpiritAesDeriveDecKeyExecuteDec()</i> function + * + * <b>Example:</b> + * @code + * + * SpiritAesWriteDataIn(enc_data_buff , N_BYTES); + * SpiritAesDeriveDecKeyExecuteDec(); + * + * while(!aes_end_flag); // the flag is set by the ISR routine which manages the AES_END irq + * aes_end_flag=RESET; + * + * SpiritAesReadDataOut(data_buff , N_BYTES); + * + * @endcode + * </li> + * + * <li> Derive the decryption key from the encryption key using the <i>SpiritAesDeriveDecKeyFromEnc()</i> + * function, store it into the <i>AES KEY registers</i> and then decrypt data using the + * <i>SpiritAesExecuteDecryption()</i> function + * + * <b>Example:</b> + * @code + * + * SpiritAesWriteDataIn(key_enc , 16); + * SpiritAesDeriveDecKeyFromEnc(); + * + * while(!aes_end_flag); // the flag is set by the ISR routine which manages the AES_END irq + * aes_end_flag=RESET; + * + * SpiritAesReadDataOut(key_dec , 16); + * + * SpiritAesWriteKey(key_dec); + * SpiritAesWriteDataIn(enc_data_buff , 16); + * SpiritAesExecuteDecryption(); + * + * while(!aes_end_flag); // the flag is set by the ISR routine which manages the AES_END irq + * aes_end_flag=RESET; + * + * SpiritAesReadDataOut(data_buff , N_BYTES); + * + * @endcode + * </li> + * </ul> + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_AES_H +#define __SPIRIT_AES_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_Aes AES + * @brief Configuration and management of SPIRIT AES Engine. + * @details See the file <i>@ref SPIRIT_Aes.h</i> for more details. + * @{ + */ + +/** + * @defgroup Aes_Exported_Types AES Exported Types + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup Aes_Exported_Constants AES Exported Constants + * @{ + */ + + +/** + * @} + */ + + +/** + * @defgroup Aes_Exported_Macros AES Exported Macros + * @{ + */ + + +/** + * @} + */ + + +/** + * @defgroup Aes_Exported_Functions AES Exported Functions + * @{ + */ + +void SpiritAesMode(SpiritFunctionalState xNewState); +void SpiritAesWriteDataIn(uint8_t* pcBufferDataIn, uint8_t cDataLength); +void SpiritAesReadDataOut(uint8_t* pcBufferDataOut, uint8_t cDataLength); +void SpiritAesWriteKey(uint8_t* pcKey); +void SpiritAesReadKey(uint8_t* pcKey); +void SpiritAesDeriveDecKeyFromEnc(void); +void SpiritAesExecuteEncryption(void); +void SpiritAesExecuteDecryption(void); +void SpiritAesDeriveDecKeyExecuteDec(void); + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + + + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Calibration.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Calibration.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,226 @@ +/** + ****************************************************************************** + * @file SPIRIT_Calibration.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT VCO-RCO calibration. + * + * @details + * + * This module allows the user to set some parameters which deal + * with the oscillators calibration. + * The state machine of Spirit contemplates some optional calibrating operations + * in the transition between the READY and the LOCK state. + * The user is allowed to enable or disable the automatic RCO/VCO calibration + * by calling the functions <i>@ref SpiritCalibrationVco()</i> and <i>@ref SpiritCalibrationRco()</i>. + * The following example shows how to do an initial calibration of VCO. + * + * <b>Example:</b> + * @code + * uint8_t calData; + * + * SpiritCalibrationVco(S_ENABLE); + * SpiritCmdStrobeLockTx(); + * + * while(g_xStatus.MC_STATE != MC_STATE_LOCK){ + * SpiritRefreshStatus(); + * } + * + * calData = SpiritCalibrationGetVcoCalDataTx(); + * SpiritCalibrationSetVcoCalDataTx(calData); + * + * SpiritCmdStrobeReady(); + * SpiritCalibrationVco(S_DISABLE); + * + * @endcode + * + * Similar operations can be done for the RCO calibrator. + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_CALIBRATION_H +#define __SPIRIT_CALIBRATION_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_Calibration Calibration + * @brief Configuration and management of SPIRIT VCO-RCO calibration. + * @details See the file <i>@ref SPIRIT_Calibration.h</i> for more details. + * @{ + */ + +/** + * @defgroup Calibration_Exported_Types Calibration Exported Types + * @{ + */ + + +/** + * @brief VCO / RCO calibration window. + */ +typedef enum +{ + + CALIB_TIME_7_33_US_24MHZ = 0x00, /*!< calibration window of 7.33 us with XTAL=24MHz */ + CALIB_TIME_14_67_US_24MHZ, /*!< calibration window of 14.67 us with XTAL=24MHz */ + CALIB_TIME_29_33_US_24MHZ, /*!< calibration window of 29.33 us with XTAL=24MHz */ + CALIB_TIME_58_67_US_24MHZ, /*!< calibration window of 58.67 us with XTAL=24MHz */ + + CALIB_TIME_6_77_US_26MHZ = 0x00, /*!< calibration window of 6.77 us with XTAL=26MHz */ + CALIB_TIME_13_54_US_26MHZ, /*!< calibration window of 13.54 us with XTAL=26MHz */ + CALIB_TIME_27_08_US_26MHZ, /*!< calibration window of 27.08 us with XTAL=26MHz */ + CALIB_TIME_54_15_US_26MHZ /*!< calibration window of 54.15 us with XTAL=26MHz */ + +} VcoWin; + + +#define IS_VCO_WIN(REF) (REF == CALIB_TIME_7_33_US_24MHZ ||\ + REF == CALIB_TIME_14_67_US_24MHZ ||\ + REF == CALIB_TIME_29_33_US_24MHZ ||\ + REF == CALIB_TIME_58_67_US_24MHZ ||\ + REF == CALIB_TIME_6_77_US_26MHZ ||\ + REF == CALIB_TIME_13_54_US_26MHZ ||\ + REF == CALIB_TIME_27_08_US_26MHZ ||\ + REF == CALIB_TIME_54_15_US_26MHZ \ + ) + +/** + * @brief VCO_H / VCO_L selection. + */ +typedef enum +{ + + VCO_L = 0x00, /*!< VCO lower */ + VCO_H, /*!< VCO higher */ +} VcoSel; + + +#define IS_VCO_SEL(REF) (REF == VCO_L ||\ + REF == VCO_H \ + ) + + +/** + * @} + */ + + +/** + * @defgroup Calibration_Exported_Constants Calibration Exported Constants + * @{ + */ + +/** + * @} + */ + + + +/** @defgroup VCO_Calibration VCO Calibration + * @{ + */ + +/** + * @} + */ + + + + +/** + * @defgroup Calibration_Exported_Macros Calibration Exported Macros + * @{ + */ + + +/** + * @} + */ + + +/** + * @defgroup Calibration_Exported_Functions Calibration Exported Functions + * @{ + */ + +void SpiritCalibrationRco(SpiritFunctionalState xNewState); +void SpiritCalibrationVco(SpiritFunctionalState xNewState); +void SpiritCalibrationSetRcoCalWords(uint8_t cRwt, uint8_t cRfb); +void SpiritCalibrationGetRcoCalWords(uint8_t* pcRwt, uint8_t* pcRfb); +uint8_t SpiritCalibrationGetVcoCalData(void); +void SpiritCalibrationSetVcoCalDataTx(uint8_t cVcoCalData); +uint8_t SpiritCalibrationGetVcoCalDataTx(void); +void SpiritCalibrationSetVcoCalDataRx(uint8_t cVcoCalData); +uint8_t SpiritCalibrationGetVcoCalDataRx(void); +void SpiritCalibrationSetVcoWindow(VcoWin xRefWord); +VcoWin SpiritCalibrationGetVcoWindow(void); +VcoSel SpiritCalibrationGetVcoSelecttion(void); +void SpiritCalibrationSelectVco(VcoSel xVco); + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Commands.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Commands.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,336 @@ +/** + ****************************************************************************** + * @file SPIRIT_Commands.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Management of SPIRIT Commands. + * + * @details + * + * In this module can be found all the API used to strobe commands to + * Spirit. + * Every command strobe is an SPI transaction with a specific command code. + * + * <b>Example:</b> + * @code + * ... + * + * SpiritCmdStrobeRx(); + * + * ... + * @endcode + * + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_COMMANDS_H +#define __SPIRIT_COMMANDS_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_Commands Commands + * @brief Management of SPIRIT Commands. + * @details See the file <i>@ref SPIRIT_Commands.h</i> for more details. + * @{ + */ + +/** + * @defgroup Commands_Exported_Types Commands Exported Types + * @{ + */ + +/** + * @brief SPIRIT Commands codes enumeration + */ +typedef enum +{ + CMD_TX = COMMAND_TX, /*!< Start to transmit; valid only from READY */ + CMD_RX = COMMAND_RX, /*!< Start to receive; valid only from READY */ + CMD_READY = COMMAND_READY, /*!< Go to READY; valid only from STANDBY or SLEEP or LOCK */ + CMD_STANDBY = COMMAND_STANDBY, /*!< Go to STANDBY; valid only from READY */ + CMD_SLEEP = COMMAND_SLEEP, /*!< Go to SLEEP; valid only from READY */ + CMD_LOCKRX = COMMAND_LOCKRX, /*!< Go to LOCK state by using the RX configuration of the synth; valid only from READY */ + CMD_LOCKTX = COMMAND_LOCKTX, /*!< Go to LOCK state by using the TX configuration of the synth; valid only from READY */ + CMD_SABORT = COMMAND_SABORT, /*!< Force exit form TX or RX states and go to READY state; valid only from TX or RX */ + CMD_LDC_RELOAD = COMMAND_LDC_RELOAD, /*!< LDC Mode: Reload the LDC timer with the value stored in the LDC_PRESCALER / COUNTER registers; valid from all states */ + CMD_SEQUENCE_UPDATE = COMMAND_SEQUENCE_UPDATE, /*!< Autoretransmission: Reload the Packet sequence counter with the value stored in the PROTOCOL[2] register valid from all states */ + CMD_AES_ENC = COMMAND_AES_ENC, /*!< Commands: Start the encryption routine; valid from all states; valid from all states */ + CMD_AES_KEY = COMMAND_AES_KEY, /*!< Commands: Start the procedure to compute the key for the decryption; valid from all states */ + CMD_AES_DEC = COMMAND_AES_DEC, /*!< Commands: Start the decryption routine using the current key; valid from all states */ + CMD_AES_KEY_DEC = COMMAND_AES_KEY_DEC, /*!< Commands: Compute the key and start the decryption; valid from all states */ + CMD_SRES = COMMAND_SRES, /*!< Reset of all digital part, except SPI registers */ + CMD_FLUSHRXFIFO = COMMAND_FLUSHRXFIFO, /*!< Clean the RX FIFO; valid from all states */ + CMD_FLUSHTXFIFO = COMMAND_FLUSHTXFIFO, /*!< Clean the TX FIFO; valid from all states */ +} SpiritCmd; + +#define IS_SPIRIT_CMD(CMD) (CMD == CMD_TX || \ + CMD == CMD_RX || \ + CMD == CMD_READY || \ + CMD == CMD_STANDBY || \ + CMD == CMD_SLEEP || \ + CMD == CMD_LOCKRX || \ + CMD == CMD_LOCKTX || \ + CMD == CMD_SABORT || \ + CMD == CMD_LDC_RELOAD || \ + CMD == CMD_SEQUENCE_UPDATE || \ + CMD == CMD_AES_ENC || \ + CMD == CMD_AES_KEY || \ + CMD == CMD_AES_DEC || \ + CMD == CMD_AES_KEY_DEC || \ + CMD == CMD_SRES || \ + CMD == CMD_FLUSHRXFIFO || \ + CMD == CMD_FLUSHTXFIFO \ + ) + +/** + * @} + */ + + +/** + * @defgroup Commands_Exported_Constants Commands Exported Constants + * @{ + */ + + +/** + * @} + */ + + +/** + * @defgroup Commands_Exported_Macros Commands Exported Macros + * @{ + */ + +/** + * @brief Sends the TX command to SPIRIT. Start to transmit. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeTx() {SpiritManagementWaCmdStrobeTx(); \ + SpiritCmdStrobeCommand(CMD_TX);} + + +/** + * @brief Sends the RX command to SPIRIT. Start to receive. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeRx() {SpiritManagementWaCmdStrobeRx(); \ + SpiritCmdStrobeCommand(CMD_RX); \ + } + + +/** + * @brief Sends the Ready state command to SPIRIT. Go to READY. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeReady() SpiritCmdStrobeCommand(CMD_READY) + + + +/** + * @brief Sends the Standby command to SPIRIT. Go to STANDBY. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeStandby() SpiritCmdStrobeCommand(CMD_STANDBY) + + + +/** + * @brief Sends the Sleep command to SPIRIT. Go to SLEEP. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeSleep() SpiritCmdStrobeCommand(CMD_SLEEP) + + + +/** + * @brief Sends the LOCK_RX command to SPIRIT. Go to the LOCK state by using the RX configuration of the synthesizer. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeLockRx() SpiritCmdStrobeCommand(CMD_LOCKRX) + + + +/** + * @brief Sends the LOCK_TX command to SPIRIT. Go to the LOCK state by using the TX configuration of the synthesizer. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeLockTx() SpiritCmdStrobeCommand(CMD_LOCKTX) + + + +/** + * @brief Sends the SABORT command to SPIRIT. Exit from TX or RX states and go to READY state. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeSabort() SpiritCmdStrobeCommand(CMD_SABORT) + + +/** + * @brief Sends the LDC_RELOAD command to SPIRIT. Reload the LDC timer with the value stored in the LDC_PRESCALER / COUNTER registers. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeLdcReload() SpiritCmdStrobeCommand(CMD_LDC_RELOAD) + + + +/** + * @brief Sends the SEQUENCE_UPDATE command to SPIRIT. Reload the Packet sequence counter with the value stored in the PROTOCOL[2] register. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeSequenceUpdate() SpiritCmdStrobeCommand(CMD_SEQUENCE_UPDATE) + + + +/** + * @brief Sends the AES_ENC command to SPIRIT. Starts the encryption routine. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeAesEnc() SpiritCmdStrobeCommand(CMD_AES_ENC) + + + +/** + * @brief Sends the AES_KEY command to SPIRIT. Starts the procedure to compute the key for the decryption. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeAesKey() SpiritCmdStrobeCommand(CMD_AES_KEY) + + + +/** + * @brief Sends the AES_DEC command to SPIRIT. Starts the decryption using the current key. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeAesDec() SpiritCmdStrobeCommand(CMD_AES_DEC) + + + +/** + * @brief Sends the KEY_DEC command to SPIRIT. Computes the key derivation and start the decryption. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeAesKeyDec() SpiritCmdStrobeCommand(CMD_AES_KEY_DEC) + +/** + * @brief Sends the SRES command to SPIRIT. Partial reset: all digital circuit will be reset (exception for SPI only). + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeSres() SpiritCmdStrobeCommand(CMD_SRES) + + +/** + * @brief Sends the FLUSHRXFIFO command to SPIRIT. Clean the RX FIFO. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeFlushRxFifo() SpiritCmdStrobeCommand(CMD_FLUSHRXFIFO) + + + +/** + * @brief Sends the FLUSHTXFIFO command to SPIRIT. Clean the TX FIFO. + * @param None. + * @retval None. + */ +#define SpiritCmdStrobeFlushTxFifo() SpiritCmdStrobeCommand(CMD_FLUSHTXFIFO) + + + +/** + * @} + */ + + +/** + * @defgroup Commands_Exported_Functions Commands Exported Functions + * @{ + */ +void SpiritCmdStrobeCommand(SpiritCmd xCommandCode); + + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + + + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,147 @@ +/** + ****************************************************************************** + * @file SPIRIT_Config.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Spirit Configuration and useful defines + * + * @details + * + * This file is used to include all or a part of the Spirit + * libraries into the application program which will be used. + * Moreover some important parameters are defined here and the + * user is allowed to edit them. + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_CONFIG_H +#define __SPIRIT_CONFIG_H + + + /* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Regs.h" +#include "SPIRIT_Aes.h" +#include "SPIRIT_Calibration.h" +#include "SPIRIT_Commands.h" +#include "SPIRIT_Csma.h" +#include "SPIRIT_DirectRF.h" +#include "SPIRIT_General.h" +#include "SPIRIT_Gpio.h" +#include "SPIRIT_Irq.h" +#include "SPIRIT_Timer.h" +#include "SPIRIT_LinearFifo.h" +#include "SPIRIT_PktBasic.h" +#include "SPIRIT_PktMbus.h" +#include "SPIRIT_PktStack.h" + +#include "SPIRIT_Qi.h" +#include "SPIRIT_Radio.h" +#include "MCU_Interface.h" +#include "SPIRIT_Types.h" +#include "SPIRIT_Management.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** @addtogroup SPIRIT_Libraries SPIRIT Libraries + * @brief This firmware implements libraries which allow the user + * to manage the features of Spirit without knowing the hardware details. + * @details The <i>SPIRIT_Libraries</i> modules are totally platform independent. The library provides one + * module for each device feature. Each module refers to some functions whose prototypes are located in the + * header file <i>@ref MCU_Interface.h</i>. The user who want to use these libraries on a particular + * platform has to implement these functions respecting them signatures. + * @{ + */ + +/** @defgroup SPIRIT_Configuration Configuration + * @brief Spirit Configuration and useful defines. + * @details See the file <i>@ref SPIRIT_Config.h</i> for more details. + * @{ + */ + + +/** @defgroup Configuration_Exported_Types Configuration Exported Types + * @{ + */ + +/** + * @} + */ + + +/** @defgroup Configuration_Exported_Constants Configuration Exported Constants + * @{ + */ +#define DOUBLE_XTAL_THR 30000000 + +/** + * @} + */ + + +/** @defgroup Configuration_Exported_Macros Configuration Exported Macros + * @{ + */ + +/** + * @} + */ + + +/** @defgroup Configuration_Exported_Functions Configuration Exported Functions + * @{ + */ + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Csma.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Csma.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,263 @@ +/** + ****************************************************************************** + * @file SPIRIT_Csma.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT CSMA. + * @details + * + * The Spirit CSMA feature, when configured and enabled, is transparent + * for the user. It means the user has only to call the <i>@ref SpiritCsmaInit()</i> + * function on a filled structure and then enable the CSMA policy using the <i>@ref SpiritCsma()</i> + * function. + * + * <b>Example:</b> + * @code + * + * CsmaInit csmaInit={ + * S_DISABLE, // persistent mode + * TBIT_TIME_64, // Tbit time + * TCCA_TIME_3, // Tcca time + * 5, // max number of backoffs + * 0xFA21, // BU counter seed + * 32 // CU prescaler + * }; + * + * ... + * + * SpiritCsmaInit(&csmaInit); + * SpiritCsma(S_ENABLE); + * + * + * @endcode + * + * @note The CS status depends of the RSSI threshold set. Please see the Spirit_Qi + * module for details. + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_CSMA_H +#define __SPIRIT_CSMA_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Types.h" +#include "SPIRIT_Regs.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_Csma CSMA + * @brief Configuration and management of SPIRIT CSMA. + * @details See the file <i>@ref SPIRIT_Csma.h</i> for more details. + * @{ + */ + +/** + * @defgroup Csma_Exported_Types CSMA Exported Types + * @{ + */ + + +/** + * @brief Multiplier for Tcca time enumeration (Tcca = Multiplier*Tbit). + */ +typedef enum +{ + TBIT_TIME_64 = CSMA_CCA_PERIOD_64TBIT, /*!< CSMA/CA: Sets CCA period to 64*TBIT */ + TBIT_TIME_128 = CSMA_CCA_PERIOD_128TBIT, /*!< CSMA/CA: Sets CCA period to 128*TBIT */ + TBIT_TIME_256 = CSMA_CCA_PERIOD_256TBIT, /*!< CSMA/CA: Sets CCA period to 256*TBIT */ + TBIT_TIME_512 = CSMA_CCA_PERIOD_512TBIT, /*!< CSMA/CA: Sets CCA period to 512*TBIT */ +}CcaPeriod; + +#define IS_CCA_PERIOD(PERIOD) (PERIOD == TBIT_TIME_64 || \ + PERIOD == TBIT_TIME_128 || \ + PERIOD == TBIT_TIME_256 || \ + PERIOD == TBIT_TIME_512) + + +/** + * @brief Multiplier of Tcca time enumeration to obtain Tlisten (Tlisten = [1...15]*Tcca). + */ +typedef enum +{ + TCCA_TIME_0 = 0x00, /*!< CSMA/CA: Sets CCA length to 0 */ + TCCA_TIME_1 = 0x10, /*!< CSMA/CA: Sets CCA length to 1*TLISTEN */ + TCCA_TIME_2 = 0x20, /*!< CSMA/CA: Sets CCA length to 2*TLISTEN */ + TCCA_TIME_3 = 0x30, /*!< CSMA/CA: Sets CCA length to 3*TLISTEN */ + TCCA_TIME_4 = 0x40, /*!< CSMA/CA: Sets CCA length to 4*TLISTEN */ + TCCA_TIME_5 = 0x50, /*!< CSMA/CA: Sets CCA length to 5*TLISTEN */ + TCCA_TIME_6 = 0x60, /*!< CSMA/CA: Sets CCA length to 6*TLISTEN */ + TCCA_TIME_7 = 0x70, /*!< CSMA/CA: Sets CCA length to 7*TLISTEN */ + TCCA_TIME_8 = 0x80, /*!< CSMA/CA: Sets CCA length to 8*TLISTEN */ + TCCA_TIME_9 = 0x90, /*!< CSMA/CA: Sets CCA length to 9*TLISTEN */ + TCCA_TIME_10 = 0xA0, /*!< CSMA/CA: Sets CCA length to 10*TLISTEN */ + TCCA_TIME_11 = 0xB0, /*!< CSMA/CA: Sets CCA length to 11*TLISTEN */ + TCCA_TIME_12 = 0xC0, /*!< CSMA/CA: Sets CCA length to 12*TLISTEN */ + TCCA_TIME_13 = 0xD0, /*!< CSMA/CA: Sets CCA length to 13*TLISTEN */ + TCCA_TIME_14 = 0xE0, /*!< CSMA/CA: Sets CCA length to 14*TLISTEN */ + TCCA_TIME_15 = 0xF0, /*!< CSMA/CA: Sets CCA length to 15*TLISTEN */ +}CsmaLength; + +#define IS_CSMA_LENGTH(LENGTH) (LENGTH == TCCA_TIME_0 || \ + LENGTH == TCCA_TIME_1 || \ + LENGTH == TCCA_TIME_2 || \ + LENGTH == TCCA_TIME_3 || \ + LENGTH == TCCA_TIME_4 || \ + LENGTH == TCCA_TIME_5 || \ + LENGTH == TCCA_TIME_6 || \ + LENGTH == TCCA_TIME_7 || \ + LENGTH == TCCA_TIME_8 || \ + LENGTH == TCCA_TIME_9 || \ + LENGTH == TCCA_TIME_10 || \ + LENGTH == TCCA_TIME_11 || \ + LENGTH == TCCA_TIME_12 || \ + LENGTH == TCCA_TIME_13 || \ + LENGTH == TCCA_TIME_14 || \ + LENGTH == TCCA_TIME_15) + + +/** + * @brief SPIRIT CSMA Init structure definition + */ +typedef struct +{ + SpiritFunctionalState xCsmaPersistentMode; /*!< Specifies if the CSMA persistent mode has to be on or off. + This parameter can be S_ENABLE or S_DISABLE */ + CcaPeriod xMultiplierTbit; /*!< Specifies the Tbit multiplier to obtain the Tcca. + This parameter can be a value of @ref CcaPeriod */ + CsmaLength xCcaLength; /*!< Specifies the Tcca multiplier to determinate the Tlisten. + This parameter can be a value of @ref CsmaLength. */ + uint8_t cMaxNb; /*!< Specifies the max number of backoff cycles. Not used in persistent mode. + This parameter is an uint8_t. */ + uint16_t nBuCounterSeed; /*!< Specifies the BU counter seed. Not used in persistent mode. + This parameter can be a value of 16 bits. */ + uint8_t cBuPrescaler; /*!< Specifies the BU prescaler. Not used in persistent mode. + This parameter can be a value of 6 bits. */ +}CsmaInit; + + +/** + *@} + */ + + +/** + * @defgroup Csma_Exported_Constants CSMA Exported Constants + * @{ + */ + +/** + * @defgroup Csma_Parameters CSMA Parameters + * @{ + */ + +#define IS_BU_COUNTER_SEED(SEED) (SEED!=0) +#define IS_BU_PRESCALER(PRESCALER) (PRESCALER<64) +#define IS_CMAX_NB(NB) (NB<8) + +/** + *@} + */ + +/** + *@} + */ + + +/** + * @defgroup Csma_Exported_Macros CSMA Exported Macros + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup Csma_Exported_Functions CSMA Exported Functions + * @{ + */ + +void SpiritCsmaInit(CsmaInit* pxCsmaInit); +void SpiritCsmaGetInfo(CsmaInit* pxCsmaInit); +void SpiritCsma(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritCsmaGetCsma(void); +void SpiritCsmaPersistentMode(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritCsmaGetPersistentMode(void); +void SpiritCsmaSeedReloadMode(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritCsmaGetSeedReloadMode(void); +void SpiritCsmaSetBuCounterSeed(uint16_t nBuCounterSeed); +uint16_t SpiritCsmaGetBuCounterSeed(void); +void SpiritCsmaSetBuPrescaler(uint8_t cBuPrescaler); +uint8_t SpiritCsmaGetBuPrescaler(void); +void SpiritCsmaSetCcaPeriod(CcaPeriod xMultiplierTbit); +CcaPeriod SpiritCsmaGetCcaPeriod(void); +void SpiritCsmaSetCcaLength(CsmaLength xCcaLength); +uint8_t SpiritCsmaGetCcaLength(void); +void SpiritCsmaSetMaxNumberBackoff(uint8_t cMaxNb); +uint8_t SpiritCsmaGetMaxNumberBackoff(void); + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_DirectRF.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_DirectRF.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +/** + ****************************************************************************** + * @file SPIRIT_DirectRF.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT direct transmission / receive modes. + * @details + * + * This module contains functions to manage the direct Tx/Rx mode. + * The user can choose the way to send data to Spirit through the + * enumerative types <i>@ref DirectTx</i>/<i>@ref DirectRx</i>. + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT1_DIRECT_RF_H +#define __SPIRIT1_DIRECT_RF_H + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_DirectRf Direct RF + * @brief Configuration and management of SPIRIT direct transmission / receive modes. + * @details See the file <i>@ref SPIRIT_DirectRF.h</i> for more details. + * @{ + */ + +/** + * @defgroup DirectRf_Exported_Types Direct RF Exported Types + * @{ + */ + +/** + * @brief Direct transmission mode enumeration for SPIRIT. + */ +typedef enum +{ + NORMAL_TX_MODE = 0x00, /*!< Normal mode, no direct transmission is used */ + DIRECT_TX_FIFO_MODE = 0x04, /*!< Source is FIFO: payload bits are continuously read from the TX FIFO */ + DIRECT_TX_GPIO_MODE = 0x08, /*!< Source is GPIO: payload bits are continuously read from one of the GPIO ports and transmitted without any processing */ + PN9_TX_MODE = 0x0C /*!< A pseudorandom binary sequence is generated internally */ +}DirectTx; + +#define IS_DIRECT_TX(MODE) (((MODE) == NORMAL_TX_MODE) || \ + ((MODE) == DIRECT_TX_FIFO_MODE) || \ + ((MODE) == DIRECT_TX_GPIO_MODE) || \ + ((MODE) == PN9_TX_MODE)) + +/** + * @brief Direct receive mode enumeration for SPIRIT. + */ +typedef enum +{ + NORMAL_RX_MODE = 0x00, /*!< Normal mode, no direct reception is used */ + DIRECT_RX_FIFO_MODE = 0x10, /*!< Destination is FIFO: payload bits are continuously written to the RX FIFO and not subjected to any processing*/ + DIRECT_RX_GPIO_MODE = 0x20 /*!< Destination is GPIO: payload bits are continuously written to one of the GPIO ports and not subjected to any processing*/ +}DirectRx; + +#define IS_DIRECT_RX(MODE) (((MODE) == NORMAL_RX_MODE) || \ + ((MODE) == DIRECT_RX_FIFO_MODE) || \ + ((MODE) == DIRECT_RX_GPIO_MODE)) + + +/** + *@} + */ + + +/** + * @defgroup DirectRf_Exported_Constants Direct RF Exported Constants + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup DirectRf_Exported_Macros Direct RF Exported Macros + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup DirectRf_Exported_Functions Direct RF Exported Functions + * @{ + */ + +void SpiritDirectRfSetRxMode(DirectRx xDirectRx); +DirectRx SpiritDirectRfGetRxMode(void); +void SpiritDirectRfSetTxMode(DirectTx xDirectTx); +DirectTx SpiritDirectRfGetTxMode(void); + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_General.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_General.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,227 @@ +/** + ****************************************************************************** + * @file SPIRIT_General.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT General functionalities. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_GENERAL_H +#define __SPIRIT_GENERAL_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_General General + * @brief Configuration and management of SPIRIT General functionalities. + * @details See the file <i>@ref SPIRIT_General.h</i> for more details. + * @{ + */ + +/** + * @defgroup General_Exported_Types General Exported Types + * @{ + */ + + +/** + * @brief SPIRIT ModeExtRef enumeration + */ + +typedef enum +{ + MODE_EXT_XO = 0, + MODE_EXT_XIN = !MODE_EXT_XO +} ModeExtRef; + +#define IS_MODE_EXT(MODE) (MODE == MODE_EXT_XO || \ + MODE == MODE_EXT_XIN) + + +/** + * @brief SPIRIT BatteryLevel enumeration + */ + +typedef enum +{ + BLD_LVL_2_7_V = 0, + BLD_LVL_2_5_V = 1, + BLD_LVL_2_3_V = 2, + BLD_LVL_2_1_V = 3 +} BatteryLevel; + +#define IS_BLD_LVL(MODE) (MODE == BLD_LVL_2_7_V || \ + MODE == BLD_LVL_2_5_V || \ + MODE == BLD_LVL_2_3_V || \ + MODE == BLD_LVL_2_1_V) + + +/** + * @brief SPIRIT GmConf enumeration + */ + +typedef enum +{ + GM_SU_13_2 = 0, + GM_SU_18_2, + GM_SU_21_5, + GM_SU_25_6, + GM_SU_28_8, + GM_SU_33_9, + GM_SU_38_5, + GM_SU_43_0 +} GmConf; + +#define IS_GM_CONF(MODE) (MODE == GM_SU_13_2 || \ + MODE == GM_SU_18_2 || \ + MODE == GM_SU_21_5 || \ + MODE == GM_SU_25_6 || \ + MODE == GM_SU_28_8 || \ + MODE == GM_SU_33_9 || \ + MODE == GM_SU_38_5 || \ + MODE == GM_SU_43_0) + + +/** + * @brief SPIRIT packet type enumeration + */ + +typedef enum +{ + PKT_BASIC = 0x00, + PKT_MBUS = 0x02, + PKT_STACK + +} PacketType; + +#define IS_PKT_TYPE(TYPE) (TYPE == PKT_BASIC || \ + TYPE == PKT_MBUS || \ + TYPE == PKT_STACK || \ + ) + + +/** + * @brief SPIRIT version type enumeration + */ + +typedef enum +{ + SPIRIT_VERSION_2_1 = 0x01, /* Deprecated */ + SPIRIT_VERSION_3_0, /* The only version of SPIRIT1 */ +} SpiritVersion; + + +/** + * @} + */ + + +/** + * @defgroup General_Exported_Constants General Exported Constants + * @{ + */ + + +/** + * @} + */ + + +/** + * @defgroup General_Exported_Macros General Exported Macros + * @{ + */ +#define SpiritGeneralLibraryVersion() "Spirit1_Libraries_v.3.2.0" + + +/** + * @} + */ + + +/** + * @defgroup General_Exported_Functions General Exported Functions + * @{ + */ + + +void SpiritGeneralBatteryLevel(SpiritFunctionalState xNewState); +void SpiritGeneralSetBatteryLevel(BatteryLevel xBatteryLevel); +BatteryLevel SpiritGeneralGetBatteryLevel(void); +void SpiritGeneralBrownOut(SpiritFunctionalState xNewState); +void SpiritGeneralHighPwr(SpiritFunctionalState xNewState); +void SpiritGeneralSetExtRef(ModeExtRef xExtMode); +ModeExtRef SpiritGeneralGetExtRef(void); +void SpiritGeneralSetXoGm(GmConf xGm); +GmConf SpiritGeneralGetXoGm(void); +PacketType SpiritGeneralGetPktType(void); +uint16_t SpiritGeneralGetDevicePartNumber(void); +uint8_t SpiritGeneralGetSpiritVersion(void); + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Gpio.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Gpio.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,405 @@ +/** + ****************************************************************************** + * @file SPIRIT_Gpio.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief This file provides all the low level API to manage SPIRIT GPIO. + * + * @details + * + * This module can be used to configure the Spirit GPIO pins to perform + * specific functions. + * The structure <i>@ref gpioIRQ</i> can be used to specify these features for + * one of the four Spirit Gpio pin. + * The following example shows how to configure a pin (GPIO 3) to be used as an IRQ source + * for a microcontroller using the <i>@ref SpiritGpioInit()</i> function. + * + * <b>Example:</b> + * @code + * + * SGpioInit gpioIRQ={ + * SPIRIT_GPIO_3, + * SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_LP, + * SPIRIT_GPIO_DIG_OUT_IRQ + * }; + * + * ... + * + * SpiritGpioInit(&gpioIRQ); + * + * @endcode + * + * @note Please read the functions documentation for the other GPIO features. + * + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_GPIO_H +#define __SPIRIT_GPIO_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** @defgroup SPIRIT_Gpio GPIO + * @brief Configuration and management of SPIRIT GPIO. + * @details See the file <i>@ref SPIRIT_Gpio.h</i> for more details. + * @{ + */ + + + +/** @defgroup Gpio_Exported_Types GPIO Exported Types + * @{ + */ + +/** + * @brief SPIRIT GPIO pin enumeration. + */ +typedef enum +{ + SPIRIT_GPIO_0 = GPIO0_CONF_BASE, /*!< GPIO_0 selected */ + SPIRIT_GPIO_1 = GPIO1_CONF_BASE, /*!< GPIO_1 selected */ + SPIRIT_GPIO_2 = GPIO2_CONF_BASE, /*!< GPIO_2 selected */ + SPIRIT_GPIO_3 = GPIO3_CONF_BASE /*!< GPIO_3 selected */ +}SpiritGpioPin; + + +#define IS_SPIRIT_GPIO(PIN) ((PIN == SPIRIT_GPIO_0) || \ + (PIN == SPIRIT_GPIO_1) || \ + (PIN == SPIRIT_GPIO_2) || \ + (PIN == SPIRIT_GPIO_3)) + + +/** + * @brief SPIRIT GPIO mode enumeration. + */ +typedef enum +{ + SPIRIT_GPIO_MODE_DIGITAL_INPUT = 0x01, /*!< Digital Input on GPIO */ + SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_LP = 0x02, /*!< Digital Output on GPIO (low current) */ + SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_HP = 0x03 /*!< Digital Output on GPIO (high current) */ +}SpiritGpioMode; + +#define IS_SPIRIT_GPIO_MODE(MODE) ((MODE == SPIRIT_GPIO_MODE_DIGITAL_INPUT) || \ + (MODE == SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_LP) || \ + (MODE == SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_HP)) + + + +/** + * @brief SPIRIT I/O selection enumeration. + */ +typedef enum +{ + SPIRIT_GPIO_DIG_OUT_IRQ = 0x00, /*!< nIRQ (Interrupt Request, active low) , default configuration after POR */ + SPIRIT_GPIO_DIG_OUT_POR_INV = 0x08, /*!< POR inverted (active low) */ + SPIRIT_GPIO_DIG_OUT_WUT_EXP = 0x10, /*!< Wake-Up Timer expiration: "1" when WUT has expired */ + SPIRIT_GPIO_DIG_OUT_LBD = 0x18, /*!< Low battery detection: "1" when battery is below threshold setting */ + SPIRIT_GPIO_DIG_OUT_TX_DATA = 0x20, /*!< TX data internal clock output (TX data are sampled on the rising edge of it) */ + SPIRIT_GPIO_DIG_OUT_TX_STATE = 0x28, /*!< TX state indication: "1" when Spirit1 is passing in the TX state */ + SPIRIT_GPIO_DIG_OUT_TX_FIFO_ALMOST_EMPTY = 0x30, /*!< TX FIFO Almost Empty Flag */ + SPIRIT_GPIO_DIG_OUT_TX_FIFO_ALMOST_FULL = 0x38, /*!< TX FIFO Almost Full Flag */ + SPIRIT_GPIO_DIG_OUT_RX_DATA = 0x40, /*!< RX data output */ + SPIRIT_GPIO_DIG_OUT_RX_CLOCK = 0x48, /*!< RX clock output (recovered from received data) */ + SPIRIT_GPIO_DIG_OUT_RX_STATE = 0x50, /*!< RX state indication: "1" when Spirit1 is passing in the RX state */ + SPIRIT_GPIO_DIG_OUT_RX_FIFO_ALMOST_FULL = 0x58, /*!< RX FIFO Almost Full Flag */ + SPIRIT_GPIO_DIG_OUT_RX_FIFO_ALMOST_EMPTY = 0x60, /*!< RX FIFO Almost Empty Flag */ + SPIRIT_GPIO_DIG_OUT_ANTENNA_SWITCH = 0x68, /*!< Antenna switch used for antenna diversity */ + SPIRIT_GPIO_DIG_OUT_VALID_PREAMBLE = 0x70, /*!< Valid Preamble Detected Flag */ + SPIRIT_GPIO_DIG_OUT_SYNC_DETECTED = 0x78, /*!< Sync WordSync Word Detected Flag */ + SPIRIT_GPIO_DIG_OUT_RSSI_THRESHOLD = 0x80, /*!< RSSI above threshold */ + SPIRIT_GPIO_DIG_OUT_MCU_CLOCK = 0x88, /*!< MCU Clock */ + SPIRIT_GPIO_DIG_OUT_TX_RX_MODE = 0x90, /*!< TX or RX mode indicator (to enable an external range extender) */ + SPIRIT_GPIO_DIG_OUT_VDD = 0x98, /*!< VDD (to emulate an additional GPIO of the MCU, programmable by SPI) */ + SPIRIT_GPIO_DIG_OUT_GND = 0xA0, /*!< GND (to emulate an additional GPIO of the MCU, programmable by SPI) */ + SPIRIT_GPIO_DIG_OUT_SMPS_EXT = 0xA8, /*!< External SMPS enable signal (active high) */ + SPIRIT_GPIO_DIG_OUT_SLEEP_OR_STANDBY = 0xB0, + SPIRIT_GPIO_DIG_OUT_READY = 0xB8, + SPIRIT_GPIO_DIG_OUT_LOCK = 0xC0, + SPIRIT_GPIO_DIG_OUT_WAIT_FOR_LOCK_SIG = 0xC8, + SPIRIT_GPIO_DIG_OUT_WAIT_FOR_TIMER_FOR_LOCK = 0xD0, + SPIRIT_GPIO_DIG_OUT_WAIT_FOR_READY2_SIG = 0xD8, + SPIRIT_GPIO_DIG_OUT_WAIT_FOR_TIMER_FOR_PM_SET = 0xE0, + SPIRIT_GPIO_DIG_OUT_WAIT_VCO_CALIBRATION = 0xE8, + SPIRIT_GPIO_DIG_OUT_ENABLE_SYNTH_FULL_CIRCUIT = 0xF0, + SPIRIT_GPIO_DIG_OUT_WAIT_FOR_RCCAL_OK_SIG = 0xFF, + + SPIRIT_GPIO_DIG_IN_TX_COMMAND = 0x00, + SPIRIT_GPIO_DIG_IN_RX_COMMAND = 0x08, + SPIRIT_GPIO_DIG_IN_TX_DATA_INPUT_FOR_DIRECTRF = 0x10, + SPIRIT_GPIO_DIG_IN_DATA_WAKEUP = 0x18, + SPIRIT_GPIO_DIG_IN_EXT_CLOCK_AT_34_7KHZ = 0x20 + +}SpiritGpioIO; + +#define IS_SPIRIT_GPIO_IO(IO_SEL) ((IO_SEL == SPIRIT_GPIO_DIG_OUT_IRQ) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_POR_INV) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_WUT_EXP) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_LBD) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_TX_DATA) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_TX_STATE) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_TX_FIFO_ALMOST_EMPTY) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_TX_FIFO_ALMOST_FULL) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_RX_DATA) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_RX_CLOCK) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_RX_STATE) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_RX_FIFO_ALMOST_FULL) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_RX_FIFO_ALMOST_EMPTY) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_ANTENNA_SWITCH) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_VALID_PREAMBLE) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_SYNC_DETECTED) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_RSSI_THRESHOLD) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_MCU_CLOCK) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_TX_RX_MODE) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_VDD) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_GND) || \ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_SMPS_EXT) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_SLEEP_OR_STANDBY) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_READY) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_LOCK) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_WAIT_FOR_LOCK_SIG) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_WAIT_FOR_TIMER_FOR_LOCK) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_WAIT_FOR_READY2_SIG) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_WAIT_FOR_TIMER_FOR_PM_SET) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_WAIT_VCO_CALIBRATION) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_ENABLE_SYNTH_FULL_CIRCUIT) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_OUT_WAIT_FOR_RCCAL_OK_SIG) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_IN_TX_COMMAND) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_IN_RX_COMMAND) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_IN_TX_DATA_INPUT_FOR_DIRECTRF) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_IN_DATA_WAKEUP) ||\ + (IO_SEL == SPIRIT_GPIO_DIG_IN_EXT_CLOCK_AT_34_7KHZ)) + +/** + * @brief SPIRIT OutputLevel enumeration. + */ + +typedef enum +{ + LOW = 0, + HIGH = !LOW +}OutputLevel; + +#define IS_SPIRIT_GPIO_LEVEL(LEVEL) ((LEVEL == LOW) || \ + (LEVEL == HIGH)) + + +/** + * @brief SPIRIT GPIO Init structure definition. + */ +typedef struct +{ + SpiritGpioPin xSpiritGpioPin; /*!< Specifies the GPIO pins to be configured. + This parameter can be any value of @ref SpiritGpioPin */ + + SpiritGpioMode xSpiritGpioMode; /*!< Specifies the operating mode for the selected pins. + This parameter can be a value of @ref SpiritGpioMode */ + + SpiritGpioIO xSpiritGpioIO; /*!< Specifies the I/O selection for the selected pins. + This parameter can be a value of @ref SpiritGpioIO */ + +}SGpioInit; + + + +/** + * @brief SPIRIT clock output XO prescaler enumeration. + */ + +typedef enum +{ + XO_RATIO_1 = 0x00, /*!< XO Clock signal available on the GPIO divided by 1 */ + XO_RATIO_2_3 = 0x02, /*!< XO Clock signal available on the GPIO divided by 2/3 */ + XO_RATIO_1_2 = 0x04, /*!< XO Clock signal available on the GPIO divided by 1/2 */ + XO_RATIO_1_3 = 0x06, /*!< XO Clock signal available on the GPIO divided by 1/3 */ + XO_RATIO_1_4 = 0x08, /*!< XO Clock signal available on the GPIO divided by 1/4 */ + XO_RATIO_1_6 = 0x0A, /*!< XO Clock signal available on the GPIO divided by 1/6 */ + XO_RATIO_1_8 = 0x0C, /*!< XO Clock signal available on the GPIO divided by 1/8 */ + XO_RATIO_1_12 = 0x0E, /*!< XO Clock signal available on the GPIO divided by 1/12 */ + XO_RATIO_1_16 = 0x10, /*!< XO Clock signal available on the GPIO divided by 1/16 */ + XO_RATIO_1_24 = 0x12, /*!< XO Clock signal available on the GPIO divided by 1/24 */ + XO_RATIO_1_36 = 0x14, /*!< XO Clock signal available on the GPIO divided by 1/36 */ + XO_RATIO_1_48 = 0x16, /*!< XO Clock signal available on the GPIO divided by 1/48 */ + XO_RATIO_1_64 = 0x18, /*!< XO Clock signal available on the GPIO divided by 1/64 */ + XO_RATIO_1_96 = 0x1A, /*!< XO Clock signal available on the GPIO divided by 1/96 */ + XO_RATIO_1_128 = 0x1C, /*!< XO Clock signal available on the GPIO divided by 1/128 */ + XO_RATIO_1_192 = 0x1E /*!< XO Clock signal available on the GPIO divided by 1/196 */ +}ClockOutputXOPrescaler; + +#define IS_SPIRIT_CLOCK_OUTPUT_XO(RATIO) ((RATIO == XO_RATIO_1) || \ + (RATIO == XO_RATIO_2_3) || \ + (RATIO == XO_RATIO_1_2) || \ + (RATIO == XO_RATIO_1_3) || \ + (RATIO == XO_RATIO_1_4) || \ + (RATIO == XO_RATIO_1_6) || \ + (RATIO == XO_RATIO_1_8) || \ + (RATIO == XO_RATIO_1_12) || \ + (RATIO == XO_RATIO_1_16) || \ + (RATIO == XO_RATIO_1_24) || \ + (RATIO == XO_RATIO_1_36) || \ + (RATIO == XO_RATIO_1_48) || \ + (RATIO == XO_RATIO_1_64) || \ + (RATIO == XO_RATIO_1_96) || \ + (RATIO == XO_RATIO_1_128) || \ + (RATIO == XO_RATIO_1_192)) + +/** + * @brief SPIRIT Clock Output RCO prescaler enumeration. + */ + +typedef enum +{ + RCO_RATIO_1 = 0x00, /*!< RCO Clock signal available on the GPIO divided by 1 */ + RCO_RATIO_1_128 = 0x01 /*!< RCO Clock signal available on the GPIO divided by 1/128 */ +}ClockOutputRCOPrescaler; + +#define IS_SPIRIT_CLOCK_OUTPUT_RCO(RATIO) ((RATIO == RCO_RATIO_1) || \ + (RATIO == RCO_RATIO_1_128)) + +/** + * @brief SPIRIT ExtraClockCycles enumeration. + */ + +typedef enum +{ +EXTRA_CLOCK_CYCLES_0 = 0x00, /*!< 0 extra clock cycles provided to the MCU before switching to STANDBY state */ +EXTRA_CLOCK_CYCLES_64 = 0x20, /*!< 64 extra clock cycles provided to the MCU before switching to STANDBY state */ +EXTRA_CLOCK_CYCLES_256 = 0x40, /*!< 256 extra clock cycles provided to the MCU before switching to STANDBY state */ +EXTRA_CLOCK_CYCLES_512 = 0x60 /*!< 512 extra clock cycles provided to the MCU before switching to STANDBY state */ +}ExtraClockCycles; + +#define IS_SPIRIT_CLOCK_OUTPUT_EXTRA_CYCLES(CYCLES) ((CYCLES == EXTRA_CLOCK_CYCLES_0) || \ + (CYCLES == EXTRA_CLOCK_CYCLES_64) || \ + (CYCLES == EXTRA_CLOCK_CYCLES_256) || \ + (CYCLES == EXTRA_CLOCK_CYCLES_512)) + + +/** + * @brief SPIRIT Clock Output initialization structure definition. + */ +typedef struct +{ + ClockOutputXOPrescaler xClockOutputXOPrescaler; /*!< Specifies the XO Ratio as clock output. + This parameter can be any value of @ref ClockOutputXOPrescaler */ + + ClockOutputRCOPrescaler xClockOutputRCOPrescaler; /*!< Specifies the RCO Ratio as clock output. + This parameter can be a value of @ref ClockOutputRCOPrescaler */ + + ExtraClockCycles xExtraClockCycles; /*!< Specifies the Extra Clock Cycles provided before entering in Standby State. + This parameter can be a value of @ref ExtraClockCycles */ + +}ClockOutputInit; + + + +/** + * @} + */ + + + +/** @defgroup Gpio_Exported_Constants GPIO Exported Constants + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup Gpio_Exported_Macros GPIO Exported Macros + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup Gpio_Exported_Functions GPIO Exported Functions + * @{ + */ + +void SpiritGpioInit(SGpioInit* pxGpioInitStruct); +void SpiritGpioTemperatureSensor(SpiritFunctionalState xNewState); +void SpiritGpioSetLevel(SpiritGpioPin xGpioX, OutputLevel xLevel); +OutputLevel SpiritGpioGetLevel(SpiritGpioPin xGpioX); +void SpiritGpioClockOutput(SpiritFunctionalState xNewState); +void SpiritGpioClockOutputInit(ClockOutputInit* pxClockOutputInitStruct); +void SpiritGpioSetXOPrescaler(ClockOutputXOPrescaler xXOPrescaler); +ClockOutputXOPrescaler SpiritGpioGetXOPrescaler(void); +void SpiritGpioSetRCOPrescaler(ClockOutputRCOPrescaler xRCOPrescaler); +ClockOutputRCOPrescaler SpiritGpioGetRCOPrescaler(void); +void SpiritGpioSetExtraClockCycles(ExtraClockCycles xExtraCycles); +ExtraClockCycles SpiritGpioGetExtraClockCycles(void); + + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Irq.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Irq.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,357 @@ +/** + ****************************************************************************** + * @file SPIRIT_Irq.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT IRQs. + * + * @details + * + * On the Spirit side specific IRQs can be enabled by setting a specific bitmask. + * The Spirit libraries allow the user to do this in two different ways: + * <ul> + * + * <li>The first enables the IRQs one by one, i.e. using an SPI transaction for each + * IRQ to enable. + * + * <b>Example:</b> + * @code + * + * SpiritIrqDeInit(NULL); // this call is used to reset the IRQ mask registers + * SpiritIrq(RX_DATA_READY , S_ENABLE); + * SpiritIrq(VALID_SYNC , S_ENABLE); + * SpiritIrq(RX_TIMEOUT , S_ENABLE); + * + * @endcode + * + * </li> + * + * <li>The second strategy is to set the IRQ bitfields structure. So, during the initialization the user + * has to fill the @ref SpiritIrqs structure setting to one the single field related to the IRQ he + * wants to enable, and to zero the single field related to all the IRQs he wants to disable. + * + * <b>Example:</b> + * @code + * + * SpiritIrqs irqMask; + * + * ... + * + * SpiritIrqDeInit(&irqMask); // this call is used to reset the IRQ mask registers + * // and to set to 0x00000000 the irq mask in order to disable + * // all IRQs (disabled by default on startup) + * irqMask.IRQ_RX_DATA_READY = 1; + * irqMask.IRQ_VALID_SYNC = 1; + * irqMask.IRQ_RX_TIMEOUT = 1; + * + * ... + * @endcode + * </li> + * </ul> + * + * The most applications will require a Spirit IRQ notification on an microcontroller EXTI line. + * Then, the user can check which IRQ has been raised using two different ways. + * + * On the ISR of the EXTI line phisically linked to the Spirit pin configured for IRQ: + * + * <ul> + * <li> Check <b>only one</b> Spirit IRQ (because the Spirit IRQ status register automatically blanks itself + * after an SPI reading) into the ISR. + * + * <b>Example:</b> + * @code + * + * if(SpiritIrqCheckFlag(RX_DATA_READY)) + * { + * // do something... + * } + * + * @endcode + * </li> + * + * <li> Check more than one Spirit IRQ status by storing the entire IRQ status registers into a bitfields <i>@ref SpiritIrqs</i> structure + * and then check the interested bits. + * + * <b>Example:</b> + * @code + * + * SpiritIrqGetStatus(&irqStatus); + * + * if(irqStatus.IRQ_RX_DATA_READY) + * { + * // do something... + * } + * if(irqStatus.IRQ_VALID_SYNC) + * { + * // do something... + * } + * if(irqStatus.RX_TIMEOUT) + * { + * // do something... + * } + * + * @endcode + * </li> + * </ul> + * + + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT1_IRQ_H +#define __SPIRIT1_IRQ_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_Irq IRQ + * @brief Configuration and management of SPIRIT IRQs. + * @details See the file <i>@ref SPIRIT_Irq.h</i> for more details. + * @{ + */ + +/** + * @defgroup Irq_Exported_Types IRQ Exported Types + * @{ + */ + + +/** + * @brief IRQ bitfield structure for SPIRIT. This structure is used to read or write the single IRQ bit. + * During the initialization the user has to fill this structure setting to one the single field related + * to the IRQ he wants to enable, and to zero the single field related to all the IRQs he wants to disable. + * The same structure can be used to retrieve all the IRQ events from the IRQ registers IRQ_STATUS[3:0], + * and read if one or more specific IRQ raised. + * @note The fields order in the structure depends on used endianness (little or big + * endian). The actual definition is valid ONLY for LITTLE ENDIAN mode. Be sure to + * change opportunely the fields order when use a different endianness. + */ +typedef struct +{ + SpiritFlagStatus IRQ_SYNTH_LOCK_TIMEOUT:1; /*!< IRQ: only for debug; LOCK state timeout */ + SpiritFlagStatus IRQ_SYNTH_LOCK_STARTUP:1; /*!< IRQ: only for debug; see CALIBR_START_COUNTER */ + SpiritFlagStatus IRQ_SYNTH_CAL_TIMEOUT:1; /*!< IRQ: only for debug; SYNTH calibration timeout */ + SpiritFlagStatus IRQ_TX_START_TIME:1; /*!< IRQ: only for debug; TX circuitry startup time; see TX_START_COUNTER */ + SpiritFlagStatus IRQ_RX_START_TIME:1; /*!< IRQ: only for debug; RX circuitry startup time; see TX_START_COUNTER */ + SpiritFlagStatus IRQ_RX_TIMEOUT:1; /*!< IRQ: RX operation timeout */ + SpiritFlagStatus IRQ_AES_END:1; /*!< IRQ: AES End of operation */ + SpiritFlagStatus reserved:1; /*!< Reserved bit */ + + SpiritFlagStatus IRQ_READY:1; /*!< IRQ: READY state */ + SpiritFlagStatus IRQ_STANDBY_DELAYED:1; /*!< IRQ: STANDBY state after MCU_CK_CONF_CLOCK_TAIL_X clock cycles */ + SpiritFlagStatus IRQ_LOW_BATT_LVL:1; /*!< IRQ: Battery level below threshold*/ + SpiritFlagStatus IRQ_POR:1; /*!< IRQ: Power On Reset */ + SpiritFlagStatus IRQ_BOR:1; /*!< IRQ: Brown out event (both accurate and inaccurate)*/ + SpiritFlagStatus IRQ_LOCK:1; /*!< IRQ: LOCK state */ + SpiritFlagStatus IRQ_PM_COUNT_EXPIRED:1; /*!< IRQ: only for debug; Power Management startup timer expiration (see reg PM_START_COUNTER, 0xB5) */ + SpiritFlagStatus IRQ_XO_COUNT_EXPIRED:1; /*!< IRQ: only for debug; Crystal oscillator settling time counter expired */ + + SpiritFlagStatus IRQ_TX_FIFO_ALMOST_EMPTY:1; /*!< IRQ: TX FIFO almost empty */ + SpiritFlagStatus IRQ_RX_FIFO_ALMOST_FULL:1; /*!< IRQ: RX FIFO almost full */ + SpiritFlagStatus IRQ_RX_FIFO_ALMOST_EMPTY:1; /*!< IRQ: RX FIFO almost empty */ + SpiritFlagStatus IRQ_MAX_BO_CCA_REACH:1; /*!< IRQ: Max number of back-off during CCA */ + SpiritFlagStatus IRQ_VALID_PREAMBLE:1; /*!< IRQ: Valid preamble detected */ + SpiritFlagStatus IRQ_VALID_SYNC:1; /*!< IRQ: Sync word detected */ + SpiritFlagStatus IRQ_RSSI_ABOVE_TH:1; /*!< IRQ: RSSI above threshold */ + SpiritFlagStatus IRQ_WKUP_TOUT_LDC:1; /*!< IRQ: Wake-up timeout in LDC mode */ + + SpiritFlagStatus IRQ_RX_DATA_READY:1; /*!< IRQ: RX data ready */ + SpiritFlagStatus IRQ_RX_DATA_DISC:1; /*!< IRQ: RX data discarded (upon filtering) */ + SpiritFlagStatus IRQ_TX_DATA_SENT:1; /*!< IRQ: TX data sent */ + SpiritFlagStatus IRQ_MAX_RE_TX_REACH:1; /*!< IRQ: Max re-TX reached */ + SpiritFlagStatus IRQ_CRC_ERROR:1; /*!< IRQ: CRC error */ + SpiritFlagStatus IRQ_TX_FIFO_ERROR:1; /*!< IRQ: TX FIFO underflow/overflow error */ + SpiritFlagStatus IRQ_RX_FIFO_ERROR:1; /*!< IRQ: RX FIFO underflow/overflow error */ + SpiritFlagStatus IRQ_TX_FIFO_ALMOST_FULL:1; /*!< IRQ: TX FIFO almost full */ +} SpiritIrqs; + +// betzw: uint32_t masks +#define IRQ_TX_FIFO_ALMOST_EMPTY_MASK (0x00010000) /* (1<<16) */ +#define IRQ_RX_FIFO_ALMOST_FULL_MASK (0x00020000) /* (1<<17) */ +#define IRQ_VALID_SYNC_MASK (0x00200000) /* (1<<21) */ +#define IRQ_RX_DATA_READY_MASK (0x01000000) /* (1<<24) */ +#define IRQ_RX_DATA_DISC_MASK (0x02000000) /* (1<<25) */ +#define IRQ_TX_DATA_SENT_MASK (0x04000000) /* (1<<26) */ +#define IRQ_TX_FIFO_ERROR_MASK (0x20000000) /* (1<<29) */ +#define IRQ_RX_FIFO_ERROR_MASK (0x40000000) /* (1<<30) */ + +/** + * @brief IRQ list enumeration for SPIRIT. This enumeration type can be used to address a + * specific IRQ. + */ +typedef enum +{ + RX_DATA_READY = 0x00000001, /*!< IRQ: RX data ready */ + RX_DATA_DISC = 0x00000002, /*!< IRQ: RX data discarded (upon filtering) */ + TX_DATA_SENT = 0x00000004, /*!< IRQ: TX data sent */ + MAX_RE_TX_REACH = 0x00000008, /*!< IRQ: Max re-TX reached */ + CRC_ERROR = 0x00000010, /*!< IRQ: CRC error */ + TX_FIFO_ERROR = 0x00000020, /*!< IRQ: TX FIFO underflow/overflow error */ + RX_FIFO_ERROR = 0x00000040, /*!< IRQ: RX FIFO underflow/overflow error */ + TX_FIFO_ALMOST_FULL = 0x00000080, /*!< IRQ: TX FIFO almost full */ + TX_FIFO_ALMOST_EMPTY = 0x00000100, /*!< IRQ: TX FIFO almost empty */ + RX_FIFO_ALMOST_FULL = 0x00000200, /*!< IRQ: RX FIFO almost full */ + RX_FIFO_ALMOST_EMPTY = 0x00000400, /*!< IRQ: RX FIFO almost empty */ + MAX_BO_CCA_REACH = 0x00000800, /*!< IRQ: Max number of back-off during CCA */ + VALID_PREAMBLE = 0x00001000, /*!< IRQ: Valid preamble detected */ + VALID_SYNC = 0x00002000, /*!< IRQ: Sync word detected */ + RSSI_ABOVE_TH = 0x00004000, /*!< IRQ: RSSI above threshold */ + WKUP_TOUT_LDC = 0x00008000, /*!< IRQ: Wake-up timeout in LDC mode */ + READY = 0x00010000, /*!< IRQ: READY state */ + STANDBY_DELAYED = 0x00020000, /*!< IRQ: STANDBY state after MCU_CK_CONF_CLOCK_TAIL_X clock cycles */ + LOW_BATT_LVL = 0x00040000, /*!< IRQ: Battery level below threshold*/ + POR = 0x00080000, /*!< IRQ: Power On Reset */ + BOR = 0x00100000, /*!< IRQ: Brown out event (both accurate and inaccurate)*/ + LOCK = 0x00200000, /*!< IRQ: LOCK state */ + PM_COUNT_EXPIRED = 0x00400000, /*!< IRQ: only for debug; Power Management startup timer expiration (see reg PM_START_COUNTER, 0xB5) */ + XO_COUNT_EXPIRED = 0x00800000, /*!< IRQ: only for debug; Crystal oscillator settling time counter expired */ + SYNTH_LOCK_TIMEOUT = 0x01000000, /*!< IRQ: only for debug; LOCK state timeout */ + SYNTH_LOCK_STARTUP = 0x02000000, /*!< IRQ: only for debug; see CALIBR_START_COUNTER */ + SYNTH_CAL_TIMEOUT = 0x04000000, /*!< IRQ: only for debug; SYNTH calibration timeout */ + TX_START_TIME = 0x08000000, /*!< IRQ: only for debug; TX circuitry startup time; see TX_START_COUNTER */ + RX_START_TIME = 0x10000000, /*!< IRQ: only for debug; RX circuitry startup time; see TX_START_COUNTER */ + RX_TIMEOUT = 0x20000000, /*!< IRQ: RX operation timeout */ + AES_END = 0x40000000, /*!< IRQ: AES End of operation */ + ALL_IRQ = 0x7FFFFFFF /*!< All the above mentioned IRQs */ + +} IrqList; + +#define IS_SPIRIT_IRQ_LIST(VALUE) ((VALUE == RX_DATA_READY) || \ + (VALUE == RX_DATA_DISC) || \ + (VALUE == TX_DATA_SENT) || \ + (VALUE == MAX_RE_TX_REACH) || \ + (VALUE == CRC_ERROR) || \ + (VALUE == TX_FIFO_ERROR) || \ + (VALUE == RX_FIFO_ERROR) || \ + (VALUE == TX_FIFO_ALMOST_FULL) || \ + (VALUE == TX_FIFO_ALMOST_EMPTY) || \ + (VALUE == RX_FIFO_ALMOST_FULL) || \ + (VALUE == RX_FIFO_ALMOST_EMPTY) || \ + (VALUE == MAX_BO_CCA_REACH) || \ + (VALUE == VALID_PREAMBLE) || \ + (VALUE == VALID_SYNC) || \ + (VALUE == RSSI_ABOVE_TH) || \ + (VALUE == WKUP_TOUT_LDC) || \ + (VALUE == READY) || \ + (VALUE == STANDBY_DELAYED) || \ + (VALUE == LOW_BATT_LVL) || \ + (VALUE == POR) || \ + (VALUE == BOR) || \ + (VALUE == LOCK) || \ + (VALUE == PM_COUNT_EXPIRED) || \ + (VALUE == XO_COUNT_EXPIRED) || \ + (VALUE == SYNTH_LOCK_TIMEOUT) || \ + (VALUE == SYNTH_LOCK_STARTUP) || \ + (VALUE == SYNTH_CAL_TIMEOUT) || \ + (VALUE == TX_START_TIME) || \ + (VALUE == RX_START_TIME) || \ + (VALUE == RX_TIMEOUT) || \ + (VALUE == AES_END) || \ + (VALUE == ALL_IRQ )) + + +/** + * @} + */ + + +/** + * @defgroup Irq_Exported_Constants IRQ Exported Constants + * @{ + */ + + +/** + * @} + */ + + +/** + * @defgroup Irq_Exported_Macros IRQ Exported Macros + * @{ + */ + + +/** + * @} + */ + + +/** + * @defgroup Irq_Exported_Functions IRQ Exported Functions + * @{ + */ + +void SpiritIrqDeInit(SpiritIrqs* pxIrqInit); +void SpiritIrqInit(SpiritIrqs* pxIrqInit); +void SpiritIrq(IrqList xIrq, SpiritFunctionalState xNewState); +void SpiritIrqGetMask(SpiritIrqs* pxIrqMask); +void SpiritIrqGetStatus(SpiritIrqs* pxIrqStatus); +void SpiritIrqClearStatus(void); +SpiritBool SpiritIrqCheckFlag(IrqList xFlag); + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_LinearFifo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_LinearFifo.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,136 @@ +/** + ****************************************************************************** + * @file SPIRIT_LinearFifo.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT Fifo. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_LINEAR_FIFO_H +#define __SPIRIT_LINEAR_FIFO_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_LinearFifo Linear FIFO + * @brief Configuration and management of SPIRIT FIFO. + * @details See the file <i>@ref SPIRIT_LinearFifo.h</i> for more details. + * @{ + */ + +/** + * @defgroup LinearFifo_Exported_Types Linear FIFO Exported Types + * @{ + */ + + +/** + * @} + */ + + +/** + * @defgroup LinearFifo_Exported_Constants Linear FIFO Exported Constants + * @{ + */ +#define IS_FIFO_THR(VAL) (VAL<=96) + +/** + * @} + */ + + +/** + * @defgroup LinearFifo_Exported_Macros Linear FIFO Exported Macros + * @{ + */ + + +/** + * @} + */ + + +/** + * @defgroup LinearFifo_Exported_Functions Linear FIFO Exported Functions + * @{ + */ + +uint8_t SpiritLinearFifoReadNumElementsRxFifo(void); +uint8_t SpiritLinearFifoReadNumElementsTxFifo(void); +void SpiritLinearFifoSetAlmostFullThresholdRx(uint8_t cThrRxFifo); +uint8_t SpiritLinearFifoGetAlmostFullThresholdRx(void); +void SpiritLinearFifoSetAlmostEmptyThresholdRx(uint8_t cThrRxFifo); +uint8_t SpiritLinearFifoGetAlmostEmptyThresholdRx(void); +void SpiritLinearFifoSetAlmostFullThresholdTx(uint8_t cThrTxFifo); +uint8_t SpiritLinearFifoGetAlmostFullThresholdTx(void); +void SpiritLinearFifoSetAlmostEmptyThresholdTx(uint8_t cThrTxFifo); +uint8_t SpiritLinearFifoGetAlmostEmptyThresholdTx(void); + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Management.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Management.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,100 @@ +/** + ****************************************************************************** + * @file SPIRIT_Management.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief The management layer for SPIRIT1 library. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef SPIRIT_MANAGEMENT_H_ +#define SPIRIT_MANAGEMENT_H_ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Config.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_MANAGEMENT Management + * @brief Workarounds for Spirit1. + * @details See the file <i>@ref SPIRIT_Management.h</i> for more details. + * @{ + */ + + +/** + * @addgroup SPIRIT_MANAGEMENT_FUNCTIONS + * @{ + */ + + + + +uint8_t SpiritManagementWaVcoCalibration(void); +void SpiritManagementWaCmdStrobeTx(void); +void SpiritManagementWaCmdStrobeRx(void); +void SpiritManagementWaTRxFcMem(uint32_t nDesiredFreq); +void SpiritManagementWaExtraCurrent(void); + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +#ifdef __cplusplus +} +#endif + + +#endif + + + /******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ +
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_PktBasic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_PktBasic.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,696 @@ +/** + ****************************************************************************** + * @file SPIRIT_PktBasic.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT Basic packets. + * + * @details + * + * This module can be used to manage the configuration of Spirit Basic + * packets. + * The user can obtain a packet configuration filling the structure + * <i>@ref PktBasicInit</i>, defining in it some general parameters + * for the Spirit Basic packet format. + * Another structure the user can fill is <i>@ref PktBasicAddressesInit</i> + * to define the addresses which will be used during the communication. + * Moreover, functions to set the payload length and the destination address + * are provided. + * + * <b>Example:</b> + * @code + * + * PktBasicInit basicInit={ + * PKT_PREAMBLE_LENGTH_08BYTES, // preamble length in bytes + * PKT_SYNC_LENGTH_4BYTES, // sync word length in bytes + * 0x1A2635A8, // sync word + * PKT_LENGTH_VAR, // variable or fixed payload length + * 7, // length field width in bits (used only for variable length) + * PKT_NO_CRC, // CRC mode + * PKT_CONTROL_LENGTH_0BYTES, // control field length + * S_ENABLE, // address field + * S_DISABLE, // FEC + * S_ENABLE // whitening + * }; + * + * PktBasicAddressesInit addressInit={ + * S_ENABLE, // enable/disable filtering on my address + * 0x34, // my address (address of the current node) + * S_DISABLE, // enable/disable filtering on multicast address + * 0xEE, // multicast address + * S_DISABLE, // enable/disable filtering on broadcast address + * 0xFF // broadcast address + * }; + * + * ... + * + * SpiritPktBasicInit(&basicInit); + * SpiritPktBasicAddressesInit(&addressInit); + * + * ... + * + * SpiritPktBasicSetPayloadLength(20); + * SpiritPktBasicSetDestinationAddress(0x44); + * + * ... + * + * @endcode + * + * The module provides some other functions that can be used to modify + * or read only some configuration parameters. + * + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_PKT_BASIC_H +#define __SPIRIT_PKT_BASIC_H + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" +#include "SPIRIT_PktCommon.h" + +#ifdef __cplusplus + extern "C" { +#endif + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_PktBasic Pkt Basic + * @brief Configuration and management of SPIRIT Basic packets. + * @details See the file <i>@ref SPIRIT_PktBasic.h</i> for more details. + * @{ + */ + +/** + * @defgroup PktBasic_Exported_Types Pkt Basic Exported Types + * @{ + */ + + +/** + * @brief Preamble length in bytes enumeration. + */ +typedef PktPreambleLength BasicPreambleLength; + +#define IS_BASIC_PREAMBLE_LENGTH IS_PKT_PREAMBLE_LENGTH + +/** + * @brief Sync length in bytes enumeration. + */ +typedef PktSyncLength BasicSyncLength; + +#define IS_BASIC_SYNC_LENGTH IS_PKT_SYNC_LENGTH + + + +/** + * @brief CRC length in bytes enumeration. + */ +typedef PktCrcMode BasicCrcMode; + +#define IS_BASIC_CRC_MODE IS_PKT_CRC_MODE + + +/** + * @brief Fixed or variable payload length enumeration. + */ +typedef PktFixVarLength BasicFixVarLength; + +#define IS_BASIC_FIX_VAR_LENGTH IS_PKT_FIX_VAR_LENGTH + +/** + * @brief Control length in bytes enumeration. + */ +typedef PktControlLength BasicControlLength; + +#define IS_BASIC_CONTROL_LENGTH IS_PKT_CONTROL_LENGTH + +/** + * @brief Sync words enumeration. + */ +typedef PktSyncX BasicSyncX; + +#define IS_BASIC_SYNCx IS_PKT_SYNCx + + +/** + * @brief SPIRIT Basic Packet Init structure definition. This structure allows users to set the main options + * for the Basic packet. + */ +typedef struct +{ + + BasicPreambleLength xPreambleLength; /*!< Specifies the preamble length. + This parameter can be any value of @ref BasicPreambleLength */ + BasicSyncLength xSyncLength; /*!< Specifies the sync word length. The 32bit word passed (lSyncWords) will be stored in the SYNCx registers from the MSb + until the number of bytes in xSyncLength has been stored. + This parameter can be any value of @ref BasicSyncLength */ + uint32_t lSyncWords; /*!< Specifies the sync words. + This parameter is a uint32_t word with format: 0x|SYNC1|SYNC2|SYNC3|SYNC4| */ + BasicFixVarLength xFixVarLength; /*!< Specifies if a fixed length of packet has to be used. + This parameter can be any value of @ref BasicFixVarLength */ + uint8_t cPktLengthWidth; /*!< Specifies the size of the length of packet in bits. This field is useful only if + the field xFixVarLength is set to BASIC_LENGTH_VAR. For Basic packets the length width + is log2( max payload length + control length (0 to 4) + address length (0 or 1)). + This parameter is an uint8_t */ + BasicCrcMode xCrcMode; /*!< Specifies the CRC word length of packet. + This parameter can be any value of @ref BasicCrcMode */ + BasicControlLength xControlLength; /*!< Specifies the length of a control field to be sent. + This parameter can be any value of @ref BasicControlLength */ + SpiritFunctionalState xAddressField; /*!< Specifies if the destination address has to be sent. + This parameter can be S_ENABLE or S_DISABLE */ + SpiritFunctionalState xFec; /*!< Specifies if FEC has to be enabled. + This parameter can be S_ENABLE or S_DISABLE */ + SpiritFunctionalState xDataWhitening; /*!< Specifies if data whitening has to be enabled. + This parameter can be S_ENABLE or S_DISABLE */ +}PktBasicInit; + + +/** + * @brief SPIRIT Basic Packet address structure definition. This structure allows users to specify + * the node/multicast/broadcast addresses and the correspondent filtering options. + */ +typedef struct +{ + + SpiritFunctionalState xFilterOnMyAddress; /*!< If set RX packet is accepted if its destination address matches with cMyAddress. + This parameter can be S_ENABLE or S_DISABLE */ + uint8_t cMyAddress; /*!< Specifies the TX packet source address (address of this node). + This parameter is an uint8_t */ + SpiritFunctionalState xFilterOnMulticastAddress; /*!< If set RX packet is accepted if its destination address matches with cMulticastAddress. + This parameter can be S_ENABLE or S_DISABLE */ + uint8_t cMulticastAddress; /*!< Specifies the Multicast group address for this node. + This parameter is an uint8_t */ + SpiritFunctionalState xFilterOnBroadcastAddress; /*!< If set RX packet is accepted if its destination address matches with cBroadcastAddress. + This parameter can be S_ENABLE or S_DISABLE */ + uint8_t cBroadcastAddress; /*!< Specifies the Broadcast address for this node. + This parameter is an uint8_t */ +}PktBasicAddressesInit; + +/** + *@} + */ + + +/** + * @defgroup PktBasic_Exported_Constants Pkt Basic Exported Constants + * @{ + */ + +#define IS_BASIC_LENGTH_WIDTH_BITS IS_PKT_LENGTH_WIDTH_BITS + + +/** + *@} + */ + + +/** + * @defgroup PktBasic_Exported_Macros Pkt Basic Exported Macros + * @{ + */ + +/** + * @brief Macro used to compute per lower part of the packet length + * for Spirit Basic packets, to write in the PCKTLEN0 register. + * @param nLength Length of the packet payload. + * This parameter is an uint16_t. + * @retval None. + */ +#define BASIC_BUILD_PCKTLEN0(nLength) BUILD_PCKTLEN0(nLength) + + +/** + * @brief Macro used to compute per upper part of the packet length + * for Spirit Basic packets, to write the PCKTLEN1 register. + * @param nLengthLength of the packet payload. + * This parameter is an uint16_t. + * @retval None. + */ +#define BASIC_BUILD_PCKTLEN1(nLength) BUILD_PCKTLEN1(nLength) + +/** + * @brief Sets the CONTROL field length for SPIRIT Basic packets. + * @param xControlLength length of CONTROL field in bytes. + * This parameter can be any value of @ref PktControlLength. + * @retval None. + */ +#define SpiritPktBasicSetControlLength(xControlLength) SpiritPktCommonSetControlLength(xControlLength) + + +/** + * @brief Returns the CONTROL field length for SPIRIT Basic packets. + * @param None. + * @retval uint8_t Control field length. + */ +#define SpiritPktBasicGetControlLength() SpiritPktCommonGetControlLength() + + +/** + * @brief Sets the PREAMBLE field length for SPIRIT Basic packets. + * @param xPreambleLength length of PREAMBLE field in bytes. + * This parameter can be any value of @ref BasicPreambleLength. + * @retval None. + */ +#define SpiritPktBasicSetPreambleLength(xPreambleLength) SpiritPktCommonSetPreambleLength((PktPreambleLength)xPreambleLength) + + +/** + * @brief Returns the PREAMBLE field length mode for SPIRIT Basic packets. + * @param None. + * @retval uint8_t Preamble field length in bytes. + */ +#define SpiritPktBasicGetPreambleLength() SpiritPktCommonGetPreambleLength() + + +/** + * @brief Sets the SYNC field length for SPIRIT Basic packets. + * @param xSyncLength length of SYNC field in bytes. + * This parameter can be any value of @ref BasicSyncLength. + * @retval None. + */ +#define SpiritPktBasicSetSyncLength(xSyncLength) SpiritPktCommonSetSyncLength((PktSyncLength)xSyncLength) + + +/** + * @brief Returns the SYNC field length for SPIRIT Basic packets. + * @param None. + * @retval uint8_t SYNC field length in bytes. + */ +#define SpiritPktBasicGetSyncLength() SpiritPktCommonGetSyncLength() + + +/** + * @brief Sets fixed or variable payload length mode for SPIRIT packets. + * @param xFixVarLength variable or fixed length. + * BASIC_FIXED_LENGTH_VAR -> variable (the length is extracted from the received packet). + * BASIC_FIXED_LENGTH_FIX -> fix (the length is set by PCKTLEN0 and PCKTLEN1). + * @retval None. + */ +#define SpiritPktBasicSetFixVarLength(xFixVarLength) SpiritPktCommonSetFixVarLength((PktFixVarLength)xFixVarLength) + + +/** + * @brief Enables or Disables the CRC filtering. + * @param xNewState new state for CRC_CHECK. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktBasicFilterOnCrc(xNewState) SpiritPktCommonFilterOnCrc(xNewState) + + +/** + * @brief Returns the CRC filtering bit. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktBasicGetFilterOnCrc() SpiritPktCommonGetFilterOnCrc() + + +/** + * @brief Sets the CRC mode for SPIRIT Basic packets. + * @param xCrcMode CRC mode. + * This parameter can be any value of @ref BasicCrcMode. + * @retval None. + */ +#define SpiritPktBasicSetCrcMode(xCrcMode) SpiritPktCommonSetCrcMode((PktCrcMode)xCrcMode) + + +/** + * @brief Returns the CRC mode for SPIRIT Basic packets. + * @param None. + * @retval BasicCrcMode Crc mode. + */ +#define SpiritPktBasicGetCrcMode() (BasicCrcMode)SpiritPktCommonGetCrcMode() + + +/** + * @brief Enables or Disables WHITENING for SPIRIT packets. + * @param xNewState new state for WHITENING mode. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktBasicWhitening(xNewState) SpiritPktCommonWhitening(xNewState) + + +/** + * @brief Enables or Disables FEC for SPIRIT Basic packets. + * @param xNewState new state for FEC mode. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktBasicFec(xNewState) SpiritPktCommonFec(xNewState) + + +/** + * @brief Sets a specific SYNC word for SPIRIT Basic packets. + * @param xSyncX SYNC word number to be set. + * This parameter can be any value of @ref BasicSyncX. + * @param cSyncWord SYNC word. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktBasicSetSyncxWord(xSyncX, cSyncWord) SpiritPktCommonSetSyncxWord((PktSyncX)xSyncX, cSyncWord) + + +/** + * @brief Returns a specific SYNC words for SPIRIT Basic packets. + * @param xSyncX SYNC word number to be get. + * This parameter can be any value of @ref BasicSyncX. + * @retval uint8_t Sync word x. + */ +#define SpiritPktBasicGetSyncxWord(xSyncX) SpiritPktCommonGetSyncxWord(xSyncX) + + +/** + * @brief Sets multiple SYNC words for SPIRIT Basic packets. + * @param lSyncWords SYNC words to be set with format: 0x|SYNC1|SYNC2|SYNC3|SYNC4|. + * This parameter is a uint32_t. + * @param xSyncLength SYNC length in bytes. The 32bit word passed will be stored in the SYNCx registers from the MSb + * until the number of bytes in xSyncLength has been stored. + * This parameter is a @ref BasicSyncLength. + * @retval None. + */ +#define SpiritPktBasicSetSyncWords(lSyncWords, xSyncLength) SpiritPktCommonSetSyncWords(lSyncWords, (PktSyncLength)xSyncLength) + + +/** + * @brief Returns multiple SYNC words for SPIRIT Basic packets. + * @param xSyncLength SYNC length in bytes. The 32bit word passed will be stored in the SYNCx registers from the MSb + * until the number of bytes in xSyncLength has been stored. + * This parameter is a pointer to @ref BasicSyncLength. + * @retval uint32_t Sync words. The format of the read 32 bit word is 0x|SYNC1|SYNC2|SYNC3|SYNC4|. + */ +#define SpiritPktBasicGetSyncWords(xSyncLength) SpiritPktCommonGetSyncWords((PktSyncLength)xSyncLength) + + +/** + * @brief Returns the SPIRIT variable length width (in number of bits). + * @param None. + * @retval Variable length width in bits. + */ +#define SpiritPktBasicGetVarLengthWidth() SpiritPktCommonGetVarLengthWidth() + + +/** + * @brief Sets the destination address for the Tx packet. + * @param cAddress destination address. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktBasicSetDestinationAddress(cAddress) SpiritPktCommonSetDestinationAddress(cAddress) + + +/** + * @brief Returns the settled destination address. + * @param None. + * @retval uint8_t Transmitted destination address. + */ +#define SpiritPktBasicGetTransmittedDestAddress() SpiritPktCommonGetTransmittedDestAddress() + + +/** + * @brief Sets the node address. When the filtering on my address is on, if the destination address extracted from the received packet is equal to the content of the + * my address, then the packet is accepted (this is the address of the node). + * @param cAddress Address of the present node. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktBasicSetMyAddress(cAddress) SpiritPktCommonSetMyAddress(cAddress) + + +/** + * @brief Returns the address of the present node. + * @param None. + * @retval uint8_t My address (address of this node). + */ +#define SpiritPktBasicGetMyAddress() SpiritPktCommonGetMyAddress() + + +/** + * @brief Sets the broadcast address. When the broadcast filtering is on, if the destination address extracted from the received packet is equal to the content of the + * BROADCAST_ADDR register, then the packet is accepted. + * @param cAddress Broadcast address. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktBasicSetBroadcastAddress(cAddress) SpiritPktCommonSetBroadcastAddress(cAddress) + + +/** + * @brief Returns the broadcast address. + * @param None. + * @retval uint8_t Broadcast address. + */ +#define SpiritPktBasicGetBroadcastAddress() SpiritPktCommonGetBroadcastAddress() + + +/** + * @brief Sets the multicast address. When the multicast filtering is on, if the destination address extracted from the received packet is equal to the content of the + * MULTICAST_ADDR register, then the packet is accepted. + * @param cAddress Multicast address. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktBasicSetMulticastAddress(cAddress) SpiritPktCommonSetMulticastAddress(cAddress) + + +/** + * @brief Returns the multicast address. + * @param None. + * @retval uint8_t Multicast address. + */ +#define SpiritPktBasicGetMulticastAddress() SpiritPktCommonGetMulticastAddress() + + +/** + * @brief Sets the control mask. The 1 bits of the CONTROL_MASK indicate the + * bits to be used in filtering. (All 0s no filtering) + * @param lMask Control mask. + * This parameter is an uint32_t. + * @retval None. + */ +#define SpiritPktBasicSetCtrlMask(lMask) SpiritPktCommonSetCtrlMask(lMask) + + +/** + * @brief Returns the control mask. The 1 bits of the CONTROL_MASK indicate the + * bits to be used in filtering. (All 0s no filtering) + * @param None. + * @retval uint32_t Control mask. + */ +#define SpiritPktBasicGetCtrlMask() SpiritPktCommonGetCtrlMask() + + +/** + * @brief Sets the control field reference. If the bits enabled by the + * CONTROL_MASK match the ones of the control fields extracted from the received packet + * then the packet is accepted. + * @param lReference Control reference. + * This parameter is an uint32_t. + * @retval None. + */ +#define SpiritPktBasicSetCtrlReference(lReference) SpiritPktCommonSetCtrlReference(lReference) + + +/** + * @brief Returns the control field reference. + * @param None. + * @retval uint32_t Control reference. + */ +#define SpiritPktBasicGetCtrlReference() SpiritPktCommonGetCtrlReference() + + +/** + * @brief Sets the TX control field. + * @param lField Tx control field. + * This parameter is an uint32_t. + * @retval None. + */ +#define SpiritPktBasicSetTransmittedCtrlField(lField) SpiritPktCommonSetTransmittedCtrlField(lField) + + +/** + * @brief Returns the TX control field. + * @param None. + * @retval uint32_t Control field of the transmitted packet. + */ +#define SpiritPktBasicGetTransmittedCtrlField() SpiritPktCommonGetTransmittedCtrlField() + + +/** + * @brief If enabled RX packet is accepted if its destination address matches with My address. + * @param xNewState new state for DEST_VS_SOURCE_ADDRESS. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktBasicFilterOnMyAddress(xNewState) SpiritPktCommonFilterOnMyAddress(xNewState) + + +/** + * @brief If enabled RX packet is accepted if its destination address matches with multicast address. + * @param xNewState new state for DEST_VS_MULTICAST_ADDRESS. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktBasicFilterOnMulticastAddress(xNewState) SpiritPktCommonFilterOnMulticastAddress(xNewState) + + +/** + * @brief If enabled RX packet is accepted if its destination address matches with broadcast address. + * @param xNewState new state for DEST_VS_BROADCAST_ADDRESS. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktBasicFilterOnBroadcastAddress(xNewState) SpiritPktCommonFilterOnBroadcastAddress(xNewState) + + +/** + * @brief Returns the enable bit of the my address filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktBasicGetFilterOnMyAddress() SpiritPktCommonGetFilterOnMyAddress(); + + +/** + * @brief Returns the enable bit of the multicast address filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktBasicGetFilterOnMulticastAddress() SpiritPktCommonGetFilterOnMulticastAddress(); + + +/** + * @brief Returns the enable bit of the broadcast address filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktBasicGetFilterOnBroadcastAddress() SpiritPktCommonGetFilterOnBroadcastAddress(); + + +/** + * @brief Returns the destination address of the received packet. + * @param None. + * @retval uint8_t Destination address of the received packet. + */ +#define SpiritPktBasicGetReceivedDestAddress() SpiritPktCommonGetReceivedDestAddress() + + +/** + * @brief Returns the control field of the received packet. + * @param None. + * @retval uint32_t Received control field. + */ +#define SpiritPktBasicGetReceivedCtrlField() SpiritPktCommonGetReceivedCtrlField() + + +/** + * @brief Returns the CRC field of the received packet. + * @param cCrcFieldVect array in which the CRC field has to be stored. + * This parameter is an uint8_t array of 3 elements. + * @retval None. + */ +#define SpiritPktBasicGetReceivedCrcField(cCrcFieldVect) SpiritPktCommonGetReceivedCrcField(cCrcFieldVect) + + +/** + * @brief If enabled RX packet is accepted only if the masked control field matches the + * masked control field reference (CONTROL_MASK & CONTROL_FIELD_REF == CONTROL_MASK & RX_CONTROL_FIELD). + * @param xNewState new state for Control filtering enable bit. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + * @note This filtering control is enabled by default but the control mask is by default set to 0. + * As a matter of fact the user has to enable the control filtering bit after the packet initialization + * because the PktInit routine disables it. + */ +#define SpiritPktBasicFilterOnControlField(xNewState) SpiritPktCommonFilterOnControlField(xNewState) + + +/** + * @brief Returns the enable bit of the control field filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktBasicGetFilterOnControlField() SpiritPktCommonGetFilterOnControlField(); + +/** + *@} + */ + + +/** + * @defgroup PktBasic_Exported_Functions Pkt Basic Exported Functions + * @{ + */ + +void SpiritPktBasicInit(PktBasicInit* pxPktBasicInit); +void SpiritPktBasicGetInfo(PktBasicInit* pxPktBasicInit); +void SpiritPktBasicAddressesInit(PktBasicAddressesInit* pxPktBasicAddresses); +void SpiritPktBasicGetAddressesInfo(PktBasicAddressesInit* pxPktBasicAddresses); +void SpiritPktBasicSetFormat(void); +void SpiritPktBasicAddressField(SpiritFunctionalState xAddressField); +SpiritFunctionalState SpiritPktBasicGetAddressField(void); +void SpiritPktBasicSetPayloadLength(uint16_t nPayloadLength); +uint16_t SpiritPktBasicGetPayloadLength(void); +uint16_t SpiritPktBasicGetReceivedPktLength(void); +void SpiritPktBasicSetVarLengthWidth(uint16_t nMaxPayloadLength,SpiritFunctionalState xAddressField, BasicControlLength xControlLength); + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_PktCommon.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_PktCommon.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,432 @@ +/** + ****************************************************************************** + * @file SPIRIT_PktCommon.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of the common features of SPIRIT packets. + * + * @details + * + * This module provides all the common functions and definitions used by the + * packets modules. + * Here are also defined all the generic enumeration types that are redefined + * in the specific packets modules, but every enumeration value is referred + * to this module. So the user who wants to configure the preamble of a Basic, + * or a STack packet has to use the enumeration values defined here. + * + * <b>Example:</b> + * @code + * + * ... + * + * SpiritPktBasicSetPreambleLength(PKT_PREAMBLE_LENGTH_18BYTES); + * + * ... + * + * @endcode + * + * @note Is recommended for the user to not use these API directly + * importing this module in his application. + * + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_PKT_COMMON_H +#define __SPIRIT_PKT_COMMON_H + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_PktCommon Pkt Common + * @brief Configuration and management of the common features of SPIRIT packets. + * @details See the file <i>@ref SPIRIT_PktCommon.h</i> for more details. + * @{ + */ + +/** + * @defgroup PktCommon_Exported_Types Pkt Common Exported Types + * @{ + */ + + +/** + * @brief Preamble length in bytes enumeration. + */ +typedef enum +{ + PKT_PREAMBLE_LENGTH_01BYTE = 0x00, /*!< Preamble length 1 byte*/ + PKT_PREAMBLE_LENGTH_02BYTES = 0x08, /*!< Preamble length 2 bytes */ + PKT_PREAMBLE_LENGTH_03BYTES = 0x10, /*!< Preamble length 3 bytes */ + PKT_PREAMBLE_LENGTH_04BYTES = 0x18, /*!< Preamble length 4 bytes */ + PKT_PREAMBLE_LENGTH_05BYTES = 0x20, /*!< Preamble length 5 bytes */ + PKT_PREAMBLE_LENGTH_06BYTES = 0x28, /*!< Preamble length 6 bytes */ + PKT_PREAMBLE_LENGTH_07BYTES = 0x30, /*!< Preamble length 7 bytes */ + PKT_PREAMBLE_LENGTH_08BYTES = 0x38, /*!< Preamble length 8 bytes */ + PKT_PREAMBLE_LENGTH_09BYTES = 0x40, /*!< Preamble length 9 bytes */ + PKT_PREAMBLE_LENGTH_10BYTES = 0x48, /*!< Preamble length 10 bytes */ + PKT_PREAMBLE_LENGTH_11BYTES = 0x50, /*!< Preamble length 11 bytes */ + PKT_PREAMBLE_LENGTH_12BYTES = 0x58, /*!< Preamble length 12 bytes */ + PKT_PREAMBLE_LENGTH_13BYTES = 0x60, /*!< Preamble length 13 bytes */ + PKT_PREAMBLE_LENGTH_14BYTES = 0x68, /*!< Preamble length 14 bytes */ + PKT_PREAMBLE_LENGTH_15BYTES = 0x70, /*!< Preamble length 15 bytes */ + PKT_PREAMBLE_LENGTH_16BYTES = 0x78, /*!< Preamble length 16 bytes */ + PKT_PREAMBLE_LENGTH_17BYTES = 0x80, /*!< Preamble length 17 bytes */ + PKT_PREAMBLE_LENGTH_18BYTES = 0x88, /*!< Preamble length 18 bytes */ + PKT_PREAMBLE_LENGTH_19BYTES = 0x90, /*!< Preamble length 19 bytes */ + PKT_PREAMBLE_LENGTH_20BYTES = 0x98, /*!< Preamble length 20 bytes */ + PKT_PREAMBLE_LENGTH_21BYTES = 0xA0, /*!< Preamble length 21 bytes */ + PKT_PREAMBLE_LENGTH_22BYTES = 0xA8, /*!< Preamble length 22 bytes */ + PKT_PREAMBLE_LENGTH_23BYTES = 0xB0, /*!< Preamble length 23 bytes */ + PKT_PREAMBLE_LENGTH_24BYTES = 0xB8, /*!< Preamble length 24 bytes */ + PKT_PREAMBLE_LENGTH_25BYTES = 0xC0, /*!< Preamble length 25 bytes */ + PKT_PREAMBLE_LENGTH_26BYTES = 0xC8, /*!< Preamble length 26 bytes */ + PKT_PREAMBLE_LENGTH_27BYTES = 0xD0, /*!< Preamble length 27 bytes */ + PKT_PREAMBLE_LENGTH_28BYTES = 0xD8, /*!< Preamble length 28 bytes */ + PKT_PREAMBLE_LENGTH_29BYTES = 0xE0, /*!< Preamble length 29 bytes */ + PKT_PREAMBLE_LENGTH_30BYTES = 0xE8, /*!< Preamble length 30 bytes */ + PKT_PREAMBLE_LENGTH_31BYTES = 0xF0, /*!< Preamble length 31 bytes */ + PKT_PREAMBLE_LENGTH_32BYTES = 0xF8 /*!< Preamble length 32 bytes */ + +}PktPreambleLength; + +#define IS_PKT_PREAMBLE_LENGTH(LENGTH) ((LENGTH == PKT_PREAMBLE_LENGTH_01BYTE) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_02BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_03BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_04BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_05BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_06BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_07BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_08BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_09BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_10BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_11BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_12BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_13BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_14BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_15BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_16BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_17BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_18BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_19BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_20BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_21BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_22BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_23BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_24BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_25BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_26BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_27BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_28BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_29BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_30BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_31BYTES) || \ + (LENGTH == PKT_PREAMBLE_LENGTH_32BYTES)) + + + +/** + * @brief Sync length in bytes enumeration. + */ +typedef enum +{ + PKT_SYNC_LENGTH_1BYTE = 0x00, /*!< Sync length 1 byte*/ + PKT_SYNC_LENGTH_2BYTES = 0x02, /*!< Sync length 2 bytes*/ + PKT_SYNC_LENGTH_3BYTES = 0x04, /*!< Sync length 3 bytes */ + PKT_SYNC_LENGTH_4BYTES = 0x06 , /*!< Sync length 4 bytes */ + +}PktSyncLength; + +#define IS_PKT_SYNC_LENGTH(LENGTH) ((LENGTH == PKT_SYNC_LENGTH_1BYTE) || \ + (LENGTH == PKT_SYNC_LENGTH_2BYTES)|| \ + (LENGTH == PKT_SYNC_LENGTH_3BYTES)|| \ + (LENGTH == PKT_SYNC_LENGTH_4BYTES)) + + + +/** + * @brief CRC length in bytes enumeration. + */ +typedef enum +{ + PKT_NO_CRC = 0x00, /*!< No CRC */ + PKT_CRC_MODE_8BITS = 0x20, /*!< CRC length 8 bits - poly: 0x07 */ + PKT_CRC_MODE_16BITS_1 = 0x40, /*!< CRC length 16 bits - poly: 0x8005 */ + PKT_CRC_MODE_16BITS_2 = 0x60, /*!< CRC length 16 bits - poly: 0x1021 */ + PKT_CRC_MODE_24BITS = 0x80, /*!< CRC length 24 bits - poly: 0x864CFB */ + +}PktCrcMode; + +#define IS_PKT_CRC_MODE(MODE) ((MODE == PKT_NO_CRC) || \ + (MODE == PKT_CRC_MODE_8BITS) || \ + (MODE == PKT_CRC_MODE_16BITS_1) || \ + (MODE == PKT_CRC_MODE_16BITS_2) || \ + (MODE == PKT_CRC_MODE_24BITS)) + + + +/** + * @brief Fixed or variable payload length enumeration. + */ +typedef enum +{ + PKT_LENGTH_FIX = 0x00, /*!< Fixed payload length */ + PKT_LENGTH_VAR = 0x01 /*!< Variable payload length */ + +}PktFixVarLength; + +#define IS_PKT_FIX_VAR_LENGTH(LENGTH) ((LENGTH == PKT_LENGTH_FIX) || \ + (LENGTH == PKT_LENGTH_VAR)) + + +/** + * @brief Control length in bytes enumeration for SPIRIT packets. + */ +typedef enum +{ + PKT_CONTROL_LENGTH_0BYTES = 0x00, /*!< Control length 0 byte*/ + PKT_CONTROL_LENGTH_1BYTE, /*!< Control length 1 byte*/ + PKT_CONTROL_LENGTH_2BYTES, /*!< Control length 2 bytes*/ + PKT_CONTROL_LENGTH_3BYTES, /*!< Control length 3 bytes*/ + PKT_CONTROL_LENGTH_4BYTES /*!< Control length 4 bytes*/ + +}PktControlLength; + +#define IS_PKT_CONTROL_LENGTH(LENGTH) ((LENGTH == PKT_CONTROL_LENGTH_0BYTES) || \ + (LENGTH == PKT_CONTROL_LENGTH_1BYTE) || \ + (LENGTH == PKT_CONTROL_LENGTH_2BYTES) || \ + (LENGTH == PKT_CONTROL_LENGTH_3BYTES) || \ + (LENGTH == PKT_CONTROL_LENGTH_4BYTES)) + +/** + * @brief Sync words enumeration for SPIRIT packets. + */ +typedef enum +{ + PKT_SYNC_WORD_1=0x01, /*!< Index of the 1st sync word*/ + PKT_SYNC_WORD_2, /*!< Index of the 2nd sync word*/ + PKT_SYNC_WORD_3, /*!< Index of the 3rd sync word*/ + PKT_SYNC_WORD_4 /*!< Index of the 4th sync word*/ + +}PktSyncX; + +#define IS_PKT_SYNCx(WORD) ((WORD == PKT_SYNC_WORD_1) || \ + (WORD == PKT_SYNC_WORD_2) || \ + (WORD == PKT_SYNC_WORD_3) || \ + (WORD == PKT_SYNC_WORD_4)) + + + +/** + * @brief Max retransmissions number enumeration for SPIRIT packets. + */ +typedef enum +{ + PKT_DISABLE_RETX = 0x00, /*!< No retrasmissions*/ + PKT_N_RETX_1 = 0x10, /*!< Max retrasmissions 1*/ + PKT_N_RETX_2 = 0x20, /*!< Max retrasmissions 2*/ + PKT_N_RETX_3 = 0x30, /*!< Max retrasmissions 3*/ + PKT_N_RETX_4 = 0x40, /*!< Max retrasmissions 4*/ + PKT_N_RETX_5 = 0x50, /*!< Max retrasmissions 5*/ + PKT_N_RETX_6 = 0x60, /*!< Max retrasmissions 6*/ + PKT_N_RETX_7 = 0x70, /*!< Max retrasmissions 7*/ + PKT_N_RETX_8 = 0x80, /*!< Max retrasmissions 8*/ + PKT_N_RETX_9 = 0x90, /*!< Max retrasmissions 9*/ + PKT_N_RETX_10 = 0xA0, /*!< Max retrasmissions 10*/ + PKT_N_RETX_11 = 0xB0, /*!< Max retrasmissions 11*/ + PKT_N_RETX_12 = 0xC0, /*!< Max retrasmissions 12*/ + PKT_N_RETX_13 = 0xD0, /*!< Max retrasmissions 13*/ + PKT_N_RETX_14 = 0xE0, /*!< Max retrasmissions 14*/ + PKT_N_RETX_15 = 0xF0 /*!< Max retrasmissions 15*/ + +}PktNMaxReTx; + +#define IS_PKT_NMAX_RETX(N_RETX) ((N_RETX == PKT_DISABLE_RETX) || \ + (N_RETX == PKT_N_RETX_1) || \ + (N_RETX == PKT_N_RETX_2) || \ + (N_RETX == PKT_N_RETX_3) || \ + (N_RETX == PKT_N_RETX_4) || \ + (N_RETX == PKT_N_RETX_5) || \ + (N_RETX == PKT_N_RETX_6) || \ + (N_RETX == PKT_N_RETX_7) || \ + (N_RETX == PKT_N_RETX_8) || \ + (N_RETX == PKT_N_RETX_9) || \ + (N_RETX == PKT_N_RETX_10) || \ + (N_RETX == PKT_N_RETX_11) || \ + (N_RETX == PKT_N_RETX_12) || \ + (N_RETX == PKT_N_RETX_13) || \ + (N_RETX == PKT_N_RETX_14) || \ + (N_RETX == PKT_N_RETX_15)) + + +/** + *@} + */ + + +/** + * @defgroup PktCommon_Exported_Constants Pkt Common Exported Constants + * @{ + */ + +#define IS_PKT_LENGTH_WIDTH_BITS(BITS) (BITS<=16) +#define IS_PKT_SEQ_NUMBER_RELOAD(SEQN) (SEQN<=3) + +/** + *@} + */ + + +/** + * @defgroup PktCommon_Exported_Macros Pkt Common Exported Macros + * @{ + */ + + +/** + * @brief Macro used to compute the lower part of the packet length, to write in the PCKTLEN0 register + * @param nLength Length of the packet payload. + * This parameter is an uint16_t. + * @retval None. + */ +#define BUILD_PCKTLEN0(nLength) ((nLength) & 0xFF) + + +/** + * @brief Macro used to compute the upper part of the packet length, to write the PCKTLEN1 register + * @param nLength Length of the packet payload. + * This parameter is an uint16_t. + * @retval None. + */ +#define BUILD_PCKTLEN1(nLength) ((nLength) >> 8) + +/** + *@} + */ + + +/** + * @defgroup PktCommon_Exported_Functions Pkt Common Exported Functions + * @{ + */ + +void SpiritPktCommonSetControlLength(PktControlLength xControlLength); +uint8_t SpiritPktCommonGetControlLength(void); +void SpiritPktCommonSetPreambleLength(PktPreambleLength xPreambleLength); +uint8_t SpiritPktCommonGetPreambleLength(void); +void SpiritPktCommonSetSyncLength(PktSyncLength xSyncLength); +uint8_t SpiritPktCommonGetSyncLength(void); +void SpiritPktCommonSetFixVarLength(PktFixVarLength xFixVarLength); +void SpiritPktCommonFilterOnCrc(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritPktCommonGetFilterOnCrc(void); +void SpiritPktCommonSetCrcMode(PktCrcMode xCrcLength); +PktCrcMode SpiritPktCommonGetCrcMode(void); +void SpiritPktCommonWhitening(SpiritFunctionalState xNewState); +void SpiritPktCommonFec(SpiritFunctionalState xNewState); +void SpiritPktCommonSetSyncxWord(PktSyncX xSyncX, uint8_t cSyncWord); +uint8_t SpiritPktCommonGetSyncxWord(PktSyncX xSyncX); +void SpiritPktCommonSetSyncWords(uint32_t lSyncWords, PktSyncLength xSyncLength); +uint32_t SpiritPktCommonGetSyncWords(PktSyncLength xSyncLength); +uint8_t SpiritPktCommonGetVarLengthWidth(void); +void SpiritPktCommonSetDestinationAddress(uint8_t cAddress); +uint8_t SpiritPktCommonGetTransmittedDestAddress(void); +void SpiritPktCommonSetMyAddress(uint8_t cAddress); +uint8_t SpiritPktCommonGetMyAddress(void); +void SpiritPktCommonSetBroadcastAddress(uint8_t cAddress); +uint8_t SpiritPktCommonGetBroadcastAddress(void); +SpiritFunctionalState SpiritPktCommonGetTxAckRequest(void); +void SpiritPktCommonSetMulticastAddress(uint8_t cAddress); +uint8_t SpiritPktCommonGetMulticastAddress(void); +void SpiritPktCommonSetCtrlMask(uint32_t lMask); +uint32_t SpiritPktCommonGetCtrlMask(void); +void SpiritPktCommonSetCtrlReference(uint32_t lReference); +uint32_t SpiritPktCommonGetCtrlReference(void); +void SpiritPktCommonSetTransmittedCtrlField(uint32_t lField); +uint32_t SpiritPktCommonGetTransmittedCtrlField(void); +void SpiritPktCommonFilterOnMyAddress(SpiritFunctionalState xNewState); +void SpiritPktCommonFilterOnMulticastAddress(SpiritFunctionalState xNewState); +void SpiritPktCommonFilterOnBroadcastAddress(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritPktCommonGetFilterOnMyAddress(void); +SpiritFunctionalState SpiritPktCommonGetFilterOnMulticastAddress(void); +SpiritFunctionalState SpiritPktCommonGetFilterOnBroadcastAddress(void); +uint8_t SpiritPktCommonGetReceivedDestAddress(void); +uint32_t SpiritPktCommonGetReceivedCtrlField(void); +void SpiritPktCommonGetReceivedCrcField(uint8_t* cCrcFieldVect); +void SpiritPktCommonAutoAck(SpiritFunctionalState xAutoAck,SpiritFunctionalState xPiggybacking); +void SpiritPktCommonRequireAck(SpiritFunctionalState xRequireAck); +void SpiritPktCommonSetTransmittedSeqNumberReload(uint8_t cSeqNumberReload); +void SpiritPktCommonSetNMaxReTx(PktNMaxReTx xNMaxReTx); +uint8_t SpiritPktCommonGetNMaxReTx(void); +uint8_t SpiritPktCommonGetReceivedDestAddress(void); +uint8_t SpiritPktCommonGetReceivedSourceAddress(void); +uint8_t SpiritPktCommonGetReceivedSeqNumber(void); +uint8_t SpiritPktCommonGetReceivedNackRx(void); +uint8_t SpiritPktCommonGetTransmittedSeqNumber(void); +uint8_t SpiritPktCommonGetNReTx(void); +void SpiritPktCommonFilterOnControlField(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritPktCommonGetFilterOnControlField(void); + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_PktMbus.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_PktMbus.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,206 @@ +/** + ****************************************************************************** + * @file SPIRIT_PktMbus.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT MBUS packets. + * + * @details + * + * This module can be used to manage the configuration of Spirit MBUS + * packets. + * The user can obtain a packet configuration filling the structure + * <i>@ref PktMbusInit</i>, defining in it some general parameters + * for the Spirit MBUS packet format. + * Since the MBUS protocol is a standard, the configuration of a MBUS + * packet is very simple to do. + * + * <b>Example:</b> + * @code + * + * PktMbusInit mbusInit={ + * MBUS_SUBMODE_S1_S2_LONG_HEADER, // MBUS submode selection + * 36, // added "01" chips on preamble + * 16 // postamble length in "01" chips + * }; + * + * ... + * + * SpiritPktMbusInit(&mbusInit); + * + * ... + * + * @endcode + * + * The module provides some other functions that can be used to modify + * or read only some configuration parameters. + * + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_PACKET_MBUS_H +#define __SPIRIT_PACKET_MBUS_H + + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" +#include "SPIRIT_PktCommon.h" + +#ifdef __cplusplus + extern "C" { +#endif + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_PktMbus Pkt MBUS + * @brief Configuration and management of SPIRIT MBUS packets. + * @details See the file <i>@ref SPIRIT_PktMbus.h</i> for more details. + * @{ + */ + +/** + * @defgroup PktMbus_Exported_Types Pkt MBUS Exported Types + * @{ + */ + + + +/** + * @brief MBUS submode enumeration. + */ + +typedef enum +{ + MBUS_SUBMODE_S1_S2_LONG_HEADER = MBUS_CTRL_MBUS_SUBMODE_S1_S2L, /*!< MBUS submode S1, S2 (long header) - Header length = mbus_prmbl_ctrl + 279 (in "01" bit pairs) , Sync word = 0x7696 (length 18 bits) */ + MBUS_SUBMODE_S1_M_S2_T2_OTHER_TO_METER = MBUS_CTRL_MBUS_SUBMODE_S2_S1M_T2_OTHER, /*!< MBUS submode S1-m, S2, T2 (other to meter) - Header length = mbus_prmbl_ctrl + 15 (in "01" bit pairs) , Sync word = 0x7696 (length 18 bits)*/ + MBUS_SUBMODE_T1_T2_METER_TO_OTHER = MBUS_CTRL_MBUS_SUBMODE_T1_T2_METER, /*!< MBUS submode T1, T2 (meter to other) - Header length = mbus_prmbl_ctrl + 19 (in "01" bit pairs) , Sync word = 0x3D (length 10 bits)*/ + MBUS_SUBMODE_R2_SHORT_HEADER = MBUS_CTRL_MBUS_SUBMODE_R2, /*!< MBUS submode R2, short header - Header length = mbus_prmbl_ctrl + 39 (in "01" bit pairs) , Sync word = 0x7696 (length 18 bits)*/ + +}MbusSubmode; + +#define IS_MBUS_SUBMODE(MODE) (((MODE) == MBUS_SUBMODE_S1_S2_LONG_HEADER) || \ + ((MODE) == MBUS_SUBMODE_S1_M_S2_T2_OTHER_TO_METER) || \ + ((MODE) == MBUS_SUBMODE_T1_T2_METER_TO_OTHER) || \ + ((MODE) == MBUS_SUBMODE_R2_SHORT_HEADER)) + + +/** + * @brief SPIRIT MBUS Packet Init structure definition + */ +typedef struct +{ + MbusSubmode xMbusSubmode; /*!< Specifies the SUBMODE to be configured. + This parameter can be a value of @ref MbusSubmode */ + + uint8_t cPreambleLength; /*!< Specifies the PREAMBLE length. + This parameter can be any value between 0 and 255 chip sequence '01' */ + + uint8_t cPostambleLength; /*!< Specifies the POSTAMBLE length. + This parameter can be any value between 0 and 255 chip sequence '01' */ + +}PktMbusInit; + +/** + *@} + */ + + +/** + * @defgroup PktMbus_Exported_Constants Pkt MBUS Exported Constants + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup PktMbus_Exported_Macros Pkt MBUS Exported Macros + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup PktMbus_Exported_Functions Pkt MBUS Exported Functions + * @{ + */ +void SpiritPktMbusInit(PktMbusInit* pxPktMbusInit); +void SpiritPktMbusGetInfo(PktMbusInit* pxPktMbusInit); +void SpiritPktMbusSetFormat(void); +void SpiritPktMbusSetPreamble(uint8_t cPreamble); +uint8_t SpiritPktMbusGetPreamble(void); +void SpiritPktMbusSetPostamble(uint8_t cPostamble); +uint8_t SpiritPktMbusGetPostamble(void); +void SpiritPktMbusSetSubmode(MbusSubmode xMbusSubmode); +MbusSubmode SpiritPktMbusGetSubmode(void); +void SpiritPktMbusSetPayloadLength(uint16_t nPayloadLength); +uint16_t SpiritPktMbusGetPayloadLength(void); + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_PktStack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_PktStack.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,849 @@ +/** + ****************************************************************************** + * @file SPIRIT_PktStack.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT STack packets. + * + * @details + * + * This module can be used to manage the configuration of Spirit STack + * packets, and it is quite similar to the Basic packets one since the + * STack packets can be considered an extension of Basic. + * The user can obtain a packet configuration filling the structure + * <i>@ref PktStackInit</i>, defining in it some general parameters + * for the Spirit STack packet format. + * Another structure the user can fill is <i>@ref PktStackAddressesInit</i> + * to define the addresses which will be used during the communication. + * The structure <i>@ref PktStackLlpInit</i> is provided in order to configure + * the link layer protocol features like autoack, autoretransmission + * or piggybacking. + * Moreover, functions to set the payload length and the destination address + * are provided. + * + * <b>Example:</b> + * @code + * + * PktStackInit stackInit={ + * PKT_PREAMBLE_LENGTH_08BYTES, // preamble length in bytes + * PKT_SYNC_LENGTH_4BYTES, // sync word length in bytes + * 0x1A2635A8, // sync word + * PKT_LENGTH_VAR, // variable or fixed payload length + * 7, // length field width in bits (used only for variable length) + * PKT_NO_CRC, // CRC mode + * PKT_CONTROL_LENGTH_0BYTES, // control field length + * S_DISABLE, // FEC + * S_ENABLE // whitening + * }; + * + * PktStackAddressesInit addressInit={ + * S_ENABLE, // enable/disable filtering on my address + * 0x34, // my address (address of the current node) + * S_DISABLE, // enable/disable filtering on multicast address + * 0xEE, // multicast address + * S_DISABLE, // enable/disable filtering on broadcast address + * 0xFF // broadcast address + * }; + * + * PktStackLlpInit stackLLPInit ={ + * S_DISABLE, // enable/disable the autoack feature + * S_DISABLE, // enable/disable the piggybacking feature + * PKT_DISABLE_RETX // set the max number of retransmissions or disable them + * }; + * ... + * + * SpiritPktStackInit(&stackInit); + * SpiritPktStackAddressesInit(&addressInit); + * SpiritPktStackLlpInit(&stackLLPInit); + * + * ... + * + * SpiritPktStackSetPayloadLength(20); + * SpiritPktStackSetDestinationAddress(0x44); + * + * ... + * + * @endcode + * + * The module provides some other functions that can be used to modify + * or read only some configuration parameters. + * + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_PKT_STACK_H +#define __SPIRIT_PKT_STACK_H + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" +#include "SPIRIT_PktCommon.h" + +#ifdef __cplusplus + extern "C" { +#endif + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_PktStack Pkt STack + * @brief Configuration and management of SPIRIT STack packets. + * @details See the file <i>@ref SPIRIT_PktStack.h</i> for more details. + * @{ + */ + +/** + * @defgroup PktStack_Exported_Types Pkt STack Exported Types + * @{ + */ + +/** + * @brief Preamble length in bytes enumeration. + */ +typedef PktPreambleLength StackPreambleLength; + +#define IS_STACK_PREAMBLE_LENGTH IS_PKT_PREAMBLE_LENGTH + +/** + * @brief Sync length in bytes enumeration. + */ +typedef PktSyncLength StackSyncLength; + +#define IS_STACK_SYNC_LENGTH IS_PKT_SYNC_LENGTH + + + +/** + * @brief CRC length in bytes enumeration. + */ +typedef PktCrcMode StackCrcMode; + +#define IS_STACK_CRC_MODE IS_PKT_CRC_MODE + + +/** + * @brief Fixed or variable payload length enumeration. + */ +typedef PktFixVarLength StackFixVarLength; + +#define IS_STACK_FIX_VAR_LENGTH IS_PKT_FIX_VAR_LENGTH + +/** + * @brief Control length in bytes enumeration for SPIRIT. + */ +typedef PktControlLength StackControlLength; + +#define IS_STACK_CONTROL_LENGTH IS_PKT_CONTROL_LENGTH + +/** + * @brief Sync words enumeration for SPIRIT. + */ +typedef PktSyncX StackSyncX; + +#define IS_STACK_SYNCx IS_PKT_SYNCx + +/** + * @brief Max retransmission number enumeration for SPIRIT. + */ +typedef PktNMaxReTx StackNMaxReTx; + +#define IS_STACK_NMAX_RETX IS_PKT_NMAX_RETX + + +/** + * @brief SPIRIT STack Packet Init structure definition. This structure allows users to set the main options + * for the STack packet. + */ +typedef struct +{ + + StackPreambleLength xPreambleLength; /*!< Specifies the preamble length of packet. + This parameter can be any value of @ref StackPreambleLength */ + StackSyncLength xSyncLength; /*!< Specifies the sync word length of packet. + This parameter can be any value of @ref StackSyncLength */ + uint32_t lSyncWords; /*!< Specifies the sync words. + This parameter is a uint32_t word with format: 0x|SYNC1|SYNC2|SYNC3|SYNC4| */ + StackFixVarLength xFixVarLength; /*!< Specifies if a fixed length of packet has to be used. + This parameter can be any value of @ref StackFixVarLength */ + uint8_t cPktLengthWidth; /*!< Specifies the size of the length of packet in bits. This field is useful only if + the field xFixVarLength is set to STACK_LENGTH_VAR. For STack packets the length width + is log2( max payload length + control length (0 to 4) + address length (always 2)). + This parameter is an uint8_t */ + StackCrcMode xCrcMode; /*!< Specifies the CRC word length of packet. + This parameter can be any value of @ref StackCrcMode */ + StackControlLength xControlLength; /*!< Specifies the length of a control field to be sent. + This parameter can be any value of @ref StackControlLength */ + SpiritFunctionalState xFec; /*!< Specifies if FEC has to be enabled. + This parameter can be any value of @ref SpiritFunctionalState */ + SpiritFunctionalState xDataWhitening; /*!< Specifies if data whitening has to be enabled. + This parameter can be any value of @ref SpiritFunctionalState */ + +}PktStackInit; + + +/** + * @brief SPIRIT STack packet address structure definition. This structure allows users to specify + * the node/multicast/broadcast addresses and the correspondent filtering options. + */ +typedef struct +{ + + SpiritFunctionalState xFilterOnMyAddress; /*!< If set RX packet is accepted if its destination address matches with cMyAddress. + This parameter can be S_ENABLE or S_DISABLE */ + uint8_t cMyAddress; /*!< Specifies the TX packet source address (address of this node). + This parameter is an uint8_t */ + SpiritFunctionalState xFilterOnMulticastAddress; /*!< If set RX packet is accepted if its destination address matches with cMulticastAddress. + This parameter can be S_ENABLE or S_DISABLE */ + uint8_t cMulticastAddress; /*!< Specifies the Multicast group address for this node. + This parameter is an uint8_t */ + SpiritFunctionalState xFilterOnBroadcastAddress; /*!< If set RX packet is accepted if its destination address matches with cBroadcastAddress. + This parameter can be S_ENABLE or S_DISABLE */ + uint8_t cBroadcastAddress; /*!< Specifies the Broadcast address for this node. + This parameter is an uint8_t */ +}PktStackAddressesInit; + + +/** + * @brief SPIRIT STack packet LLP structure definition. This structure allows users to configure + * all the LLP options for STack packets. + */ +typedef struct +{ + + SpiritFunctionalState xAutoAck; /*!< Specifies if the auto ACK feature is used or not. + This parameter can be a value of @ref SpiritFunctionalState */ + SpiritFunctionalState xPiggybacking; /*!< Specifies if the piggybacking feature is used or not. + This parameter can be a value of @ref SpiritFunctionalState */ + StackNMaxReTx xNMaxRetx; /*!< Specifies the number of MAX-Retransmissions. + This parameter can be a value of @ref StackNMaxReTx */ +}PktStackLlpInit; + + + +/** + *@} + */ + + +/** + * @defgroup PktStack_Exported_Constants Pkt STack Exported Constants + * @{ + */ + +#define IS_STACK_LENGTH_WIDTH_BITS IS_PKT_LENGTH_WIDTH_BITS + +/** + *@} + */ + + +/** + * @defgroup PktStack_Exported_Macros Pkt STack Exported Macros + * @{ + */ + +/** + * @brief Macro used to compute the lower part of the packet length + * for Spirit STack packets, to write in the PCKTLEN0 register. + * @param nLength length of the packet payload. + * This parameter is an uint16_t. + * @retval None. + */ +#define STACK_BUILD_PCKTLEN0(nLength) BUILD_PCKTLEN0(nLength) + + +/** + * @brief Macro used to compute the upper part of the packet length + * for Spirit STack packets, to write the PCKTLEN1 register. + * @param nLength length of the packet payload. + * This parameter is an uint16_t. + * @retval None. + */ +#define STACK_BUILD_PCKTLEN1(nLength) BUILD_PCKTLEN1(nLength) + + +/** + * @brief Sets the CONTROL length for SPIRIT STack packets. + * @param xControlLength length of CONTROL field in bytes. + * This parameter can be any value of @ref StackControlLength. + * @retval None. + */ +#define SpiritPktStackSetControlLength(xControlLength) SpiritPktCommonSetControlLength(xControlLength) + + +/** + * @brief Returns the CONTROL length for SPIRIT STack packets. + * @param None. + * @retval Control length. + */ +#define SpiritPktStackGetControlLength() SpiritPktCommonGetControlLength() + + +/** + * @brief Sets the PREAMBLE Length mode for SPIRIT STack packets. + * @param xPreambleLength length of PREAMBLE field in bytes. + * This parameter can be any value of @ref StackPreambleLength. + * @retval None. + */ +#define SpiritPktStackSetPreambleLength(xPreambleLength) SpiritPktCommonSetPreambleLength((PktPreambleLength)xPreambleLength) + + +/** + * @brief Returns the PREAMBLE Length mode for SPIRIT STack packets. + * @param None. + * @retval uint8_t Preamble length in bytes. + */ +#define SpiritPktStackGetPreambleLength() SpiritPktCommonGetPreambleLength() + + +/** + * @brief Sets the SYNC Length for SPIRIT STack packets. + * @param xSyncLength length of SYNC field in bytes. + * This parameter can be any value of @ref StackSyncLength. + * @retval None. + */ +#define SpiritPktStackSetSyncLength(xSyncLength) SpiritPktCommonSetSyncLength((PktSyncLength)xSyncLength) + + +/** + * @brief Returns the SYNC Length for SPIRIT STack packets. + * @param None. + * @retval uint8_t Sync length in bytes. + */ +#define SpiritPktStackGetSyncLength() SpiritPktCommonGetSyncLength() + + +/** + * @brief Sets fixed or variable payload length mode for SPIRIT STack packets. + * @param xFixVarLength variable or fixed length. + * PKT_FIXED_LENGTH_VAR -> variable (the length is extracted from the received packet). + * PKT_FIXED_LENGTH_FIX -> fix (the length is set by PCKTLEN0 and PCKTLEN1). + * @retval None. + */ +#define SpiritPktStackSetFixVarLength(xFixVarLength) SpiritPktCommonSetFixVarLength((PktFixVarLength)xFixVarLength) + + +/** + * @brief Enables or Disables the CRC filtering. + * @param xNewState new state for CRC_CHECK. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktStackFilterOnCrc(xNewState) SpiritPktCommonFilterOnCrc(xNewState) + + +/** + * @brief Returns the CRC filtering bit. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktStackGetFilterOnCrc() SpiritPktCommonGetFilterOnCrc() + + +/** + * @brief Sets the CRC mode for SPIRIT STack packets. + * @param xCrcMode CRC mode. + * This parameter can be any value of @ref StackCrcMode. + * @retval None. + */ +#define SpiritPktStackSetCrcMode(xCrcMode) SpiritPktCommonSetCrcMode((PktCrcMode)xCrcMode) + + +/** + * @brief Returns the CRC mode for SPIRIT packets. + * @param None. + * @retval StackCrcMode Crc mode. + */ +#define SpiritPktStackGetCrcMode() (StackCrcMode)SpiritPktCommonGetCrcMode() + + +/** + * @brief Enables or Disables WHITENING for SPIRIT STack packets. + * @param xNewState new state for WHITENING mode. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktStackWhitening(xNewState) SpiritPktCommonWhitening(xNewState) + + +/** + * @brief Enables or Disables FEC for SPIRIT STack packets. + * @param xNewState new state for FEC mode. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktStackFec(xNewState) SpiritPktCommonFec(xNewState) + + +/** + * @brief Sets a specific SYNC word for SPIRIT STack packets. + * @param xSyncX SYNC word number to be set. + * This parameter can be any value of @ref StackSyncX. + * @param cSyncWord SYNC word. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktStackSetSyncxWord(xSyncX, cSyncWord) SpiritPktCommonSetSyncxWord((PktSyncX)xSyncX,cSyncWord) + + +/** + * @brief Returns a specific SYNC word for SPIRIT STack packets. + * @param xSyncX SYNC word number to be get. + * This parameter can be any value of @ref StackSyncX. + * @retval uint8_t Sync word x. + */ +#define SpiritPktStackGetSyncxWord(xSyncX) SpiritPktCommonGetSyncxWord(xSyncX) + + +/** + * @brief Sets multiple SYNC words for SPIRIT STack packets. + * @param lSyncWords SYNC words to be set with format: 0x|SYNC1|SYNC2|SYNC3|SYNC4|. + * This parameter is a uint32_t. + * @param xSyncLength SYNC length in bytes. The 32bit word passed will be stored in the SYNCx registers from the MSb + * until the number of bytes in xSyncLength has been stored. + * This parameter is a @ref StackSyncLength. + * @retval None. + */ +#define SpiritPktStackSetSyncWords(lSyncWords, xSyncLength) SpiritPktCommonSetSyncWords(lSyncWords,(PktSyncLength)xSyncLength) + + +/** + * @brief Returns multiple SYNC words for SPIRIT packets. + * @param xSyncLength SYNC length in bytes. The 32bit word passed will be stored in the SYNCx registers from the MSb + * until the number of bytes in xSyncLength has been stored. + * This parameter is a pointer to @ref StackSyncLength. + * @retval uint32_t Sync words. The format of the read 32 bit word is 0x|SYNC1|SYNC2|SYNC3|SYNC4|. + */ +#define SpiritPktStackGetSyncWords(xSyncLength) SpiritPktCommonGetSyncWords((PktSyncLength)xSyncLength) + + +/** + * @brief Returns the SPIRIT variable length width (in number of bits). + * @param None. + * @retval uint8_t Variable length width in bits. + */ +#define SpiritPktStackGetVarLengthWidth() SpiritPktCommonGetVarLengthWidth() + + +/** + * @brief Sets the destination address for the Tx packet. + * @param cAddress destination address. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktStackSetDestinationAddress(cAddress) SpiritPktCommonSetDestinationAddress(cAddress) + + +/** + * @brief Sets the Rx packet reference source address. The source address extracted from the received packet is masked + * with the source reference mask and then compared to the masked reference value. + * @param cAddress Reference source address. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktStackSetSourceReferenceAddress(cAddress) SpiritPktCommonSetDestinationAddress(cAddress) + + +/** + * @brief Returns the Rx packet reference source address. The source address extracted from the received packet is masked + * with the source reference mask and then compared to the masked reference value. + * @param cAddress Reference source address. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktStackGetSourceReferenceAddress() SpiritPktCommonGetTransmittedDestAddress() + + +/** + * @brief Returns the settled destination address. + * @param None. + * @retval uint8_t Transmitted destination address. + */ +#define SpiritPktStackGetTransmittedDestAddress() SpiritPktCommonGetTransmittedDestAddress() + + +/** + * @brief Sets the node address. When the filtering on my address is on, if the destination address extracted from the received packet is equal to the content of the + * my address, then the packet is accepted (this is the address of the node). + * @param cAddress Address of the present node. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktStackSetMyAddress(cAddress) SpiritPktCommonSetMyAddress(cAddress) + + +/** + * @brief Returns the address of the present node. + * @param None. + * @retval uint8_t My address (address of this node). + */ +#define SpiritPktStackGetMyAddress() SpiritPktCommonGetMyAddress() + + +/** + * @brief Sets the broadcast address. When the broadcast filtering is on, if the destination address extracted from the received packet is equal to the content of the + * BROADCAST_ADDR register, then the packet is accepted. + * @param cAddress Broadcast address. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktStackSetBroadcastAddress(cAddress) SpiritPktCommonSetBroadcastAddress(cAddress) + + +/** + * @brief Returns the broadcast address. + * @param None. + * @retval uint8_t Broadcast address. + */ +#define SpiritPktStackGetBroadcastAddress() SpiritPktCommonGetBroadcastAddress() + + +/** + * @brief Sets the multicast address. When the multicast filtering is on, if the destination address extracted from the received packet is equal to the content of the + * MULTICAST_ADDR register, then the packet is accepted. + * @param cAddress Multicast address. + * This parameter is an uint8_t. + * @retval None. + */ +#define SpiritPktStackSetMulticastAddress(cAddress) SpiritPktCommonSetMulticastAddress(cAddress) + + +/** + * @brief Returns the multicast address. + * @param None. + * @retval uint8_t Multicast address. + */ +#define SpiritPktStackGetMulticastAddress() SpiritPktCommonGetMulticastAddress() + + +/** + * @brief Sets the control mask. The 1 bits of the CONTROL_MASK indicate the + * bits to be used in filtering. (All 0s no filtering) + * @param lMask Control mask. + * This parameter is an uint32_t. + * @retval None. + */ +#define SpiritPktStackSetCtrlMask(lMask) SpiritPktCommonSetCtrlMask(lMask) + + +/** + * @brief Returns the control mask. The 1 bits of the CONTROL_MASK indicate the + * bits to be used in filtering. (All 0s no filtering) + * @param None. + * @retval uint32_t Control mask. + */ +#define SpiritPktStackGetCtrlMask() SpiritPktCommonGetCtrlMask() + + +/** + * @brief Sets the control field reference. If the bits enabled by the + * CONTROL_MASK match the ones of the control fields extracted from the received packet + * then the packet is accepted. + * @param lReference Control reference. + * This parameter is an uint32_t. + * @retval None. + */ +#define SpiritPktStackSetCtrlReference(lReference) SpiritPktCommonSetCtrlReference(lReference) + + +/** + * @brief Returns the control field reference. + * @param None. + * @retval uint32_t Control reference. + */ +#define SpiritPktStackGetCtrlReference() SpiritPktCommonGetCtrlReference() + + +/** + * @brief Sets the TX control field. + * @param lField TX CONTROL FIELD. + * This parameter is an uint32_t. + * @retval None. + */ +#define SpiritPktStackSetTransmittedCtrlField(lField) SpiritPktCommonSetTransmittedCtrlField(lField) + + +/** + * @brief Returns the TX control field. + * @param None. + * @retval uint32_t Control field of the transmitted packet. + */ +#define SpiritPktStackGetTransmittedCtrlField() SpiritPktCommonGetTransmittedCtrlField() + + +/** + * @brief If enabled RX packet is accepted if its destination address matches with TX_SOURCE_ADDRESS. + * @param xNewState new state for DEST_VS_SOURCE_ADDRESS. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktStackFilterOnMyAddress(xNewState) SpiritPktCommonFilterOnMyAddress(xNewState) + + +/** + * @brief If enabled RX packet is accepted if its destination address matches with MULTICAST_ADDRESS. + * @param xNewState new state for DEST_VS_MULTICAST_ADDRESS. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktStackFilterOnMulticastAddress(xNewState) SpiritPktCommonFilterOnMulticastAddress(xNewState) + + +/** + * @brief If enabled RX packet is accepted if its destination address matches with BROADCAST_ADDRESS. + * @param xNewState new state for DEST_VS_BROADCAST_ADDRESS. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktStackFilterOnBroadcastAddress(xNewState) SpiritPktCommonFilterOnBroadcastAddress(xNewState) + + +/** + * @brief Returns the enable bit of the my address filtering. + * @param None. + * @retval SpiritFunctionalStateThis parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktStackGetFilterOnMyAddress() SpiritPktCommonGetFilterOnMyAddress(); + + +/** + * @brief Returns the enable bit of the multicast address filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktStackGetFilterOnMulticastAddress() SpiritPktCommonGetFilterOnMulticastAddress(); + + +/** + * @brief Returns the enable bit of the broadcast address filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktStackGetFilterOnBroadcastAddress() SpiritPktCommonGetFilterOnBroadcastAddress(); + + +/** + * @brief Returns the control field of the received packet. + * @param None. + * @retval uint32_t Received control field. + */ +#define SpiritPktStackGetReceivedCtrlField() SpiritPktCommonGetReceivedCtrlField() + + +/** + * @brief Returns the CRC field of the received packet. + * @param cCrcFieldVect array in which the CRC field has to be stored. + * This parameter is an uint8_t array of 3 elements. + * @retval None. + */ +#define SpiritPktStackGetReceivedCrcField(cCrcFieldVect) SpiritPktCommonGetReceivedCrcField(cCrcFieldVect) + +/** + * @brief Sets the AUTO ACKNOLEDGEMENT mechanism on the receiver. When the feature is enabled and + * a data packet has been correctly received, then an acknowledgement packet is sent back to the originator of the received + * packet. If the PIGGYBACKING bit is also set, payload data will be read from the FIFO; otherwise an empty packet is sent + * only containing the source and destination addresses and the sequence number of the packet being acknowledged. + * @param xAutoAck new state for autoack. + * This parameter can be: S_ENABLE or S_DISABLE. + * @param xPiggybacking new state for autoack. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktStackAutoAck(xAutoAck, xPiggybacking) SpiritPktCommonAutoAck(xAutoAck, xPiggybacking) + + +/** + * @brief Sets the AUTO ACKNOLEDGEMENT mechanism on the transmitter. On the transmitter side, the NACK_TX field can be used to require or not an acknowledgment for each individual packet: if + * NACK_TX is set to "1" then acknowledgment will not be required; if NACK_TX is set to "0" then acknowledgment will be + * required. + * @param xNewState new state for TX_AUTOACK. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktStackRequireAck(xNewState) SpiritPktCommonRequireAck(xNewState) + + +/** + * @brief Sets the TX sequence number to be used to start counting. + * @param cSeqNumberReload new value for Tx seq number reload. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +#define SpiritPktStackSetTransmittedSeqNumberReload(cSeqNumberReload) SpiritPktCommonSetTransmittedSeqNumberReload(cSeqNumberReload) + + +/** + * @brief Sets the max number of automatic retransmission. + * @param xNMaxReTx max number of retransmission. + * This parameter can be any value of @ref PktNMaxReTx. + * @retval None. + */ +#define SpiritPktStackSetNMaxReTx(xNMaxReTx) SpiritPktCommonSetNMaxReTx((PktNMaxReTx)xNMaxReTx) + + +/** + * @brief Returns the max number of automatic retransmission. + * @param None. + * @retval uint8_t Max number of retransmissions. + */ +#define SpiritPktStackGetNMaxReTx() SpiritPktCommonGetNMaxReTx() + + +/** + * @brief Returns the TX ACK request. + * @param None. + * @retval SpiritFunctionalState. + */ +#define SpiritPktStackGetGetTxAckRequest() SpiritPktCommonGetTxAckRequest() + +/** + * @brief Returns the destination address of the received packet. + * @param None. + * @retval uint8_t Destination address of the received packet. + */ +#define SpiritPktStackGetReceivedDestAddress() SpiritPktCommonGetReceivedDestAddress() + + +/** + * @brief Returns the source address of the received packet. + * @param None. + * @retval uint8_t Source address of the received packet. + */ +#define SpiritPktStackGetReceivedSourceAddress() SpiritPktCommonGetReceivedSourceAddress() + + +/** + * @brief Returns the sequence number of the received packet. + * @param None. + * @retval uint8_t Received Sequence number. + */ +#define SpiritPktStackGetReceivedSeqNumber() SpiritPktCommonGetReceivedSeqNumber() + + +/** + * @brief Returns the Nack bit of the received packet + * @param None. + * @retval uint8_t Value of the NAck bit. + */ +#define SpiritPktStackGetReceivedNackRx() SpiritPktCommonGetReceivedNackRx() + + +/** + * @brief Returns the sequence number of the transmitted packet. + * @param None. + * @retval uint8_t Sequence number of the transmitted packet. + */ +#define SpiritPktStackGetTransmittedSeqNumber() SpiritPktCommonGetTransmittedSeqNumber() + + +/** + * @brief Returns the number of retransmission done on the transmitted packet. + * @param None. + * @retval uint8_t Number of retransmissions done until now. + */ +#define SpiritPktStackGetNReTx() SpiritPktCommonGetNReTx() + + +/** + * @brief If enabled RX packet is accepted only if the masked control field matches the + * masked control field reference (CONTROL_MASK & CONTROL_FIELD_REF == CONTROL_MASK & RX_CONTROL_FIELD). + * @param xNewState new state for Control filtering enable bit. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + * @note This filtering control is enabled by default but the control mask is by default set to 0. + * As a matter of fact the user has to enable the control filtering bit after the packet initialization + * because the PktInit routine disables it. + */ +#define SpiritPktStackFilterOnControlField(xNewState) SpiritPktCommonFilterOnControlField(xNewState) + + +/** + * @brief Returns the enable bit of the control field filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +#define SpiritPktStackGetFilterOnControlField() SpiritPktCommonGetFilterOnControlField(); + + +/** + *@} + */ + + +/** + * @defgroup PktStack_Exported_Functions Pkt STack Exported Functions + * @{ + */ + +void SpiritPktStackInit(PktStackInit* pxPktStackInit); +void SpiritPktStackGetInfo(PktStackInit* pxPktStackInit); +void SpiritPktStackAddressesInit(PktStackAddressesInit* pxPktStackAddresses); +void SpiritPktStackGetAddressesInfo(PktStackAddressesInit* pxPktStackAddresses); +void SpiritPktStackLlpInit(PktStackLlpInit* pxPktStackLlpInit); +void SpiritPktStackLlpGetInfo(PktStackLlpInit* pxPktStackLlpInit); +void SpiritPktStackSetFormat(void); +void SpiritPktStackSetPayloadLength(uint16_t nPayloadLength); +uint16_t SpiritPktStackGetPayloadLength(void); +void SpiritPktStackSetVarLengthWidth(uint16_t nMaxPayloadLength, StackControlLength xControlLength); +void SpiritPktStackSetRxSourceMask(uint8_t cMask); +uint8_t SpiritPktStackGetRxSourceMask(void); +uint16_t SpiritPktStackGetReceivedPktLength(void); +void SpiritPktStackFilterOnSourceAddress(SpiritFunctionalState xNewState); +void SpiritPktStackSetAddressLength(void); + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Qi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Qi.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,300 @@ +/** + ****************************************************************************** + * @file SPIRIT_Qi.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT QI. + * @details + * + * This module can be used to configure and read some quality indicators + * used by Spirit. + * API to set thresholds and to read values in raw mode or in dBm are + * provided. + * + * <b>Example:</b> + * @code + * + * float rssiValuedBm; + * uint8_t pqiValue, sqiValue; + * + * SpiritQiPqiCheck(S_ENABLE); + * SpiritQiSqiCheck(S_ENABLE); + * + * ... + * + * rssiValueDbm = SpiritQiGetRssidBm(); + * pqiValue = SpiritQiGetPqi(); + * sqiValue = SpiritQiGetSqi(); + * + * ... + * + * @endcode + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_QI_H +#define __SPIRIT_QI_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_Qi QI + * @brief Configuration and management of SPIRIT QI. + * @details See the file <i>@ref SPIRIT_Qi.h</i> for more details. + * @{ + */ + +/** + * @defgroup Qi_Exported_Types QI Exported Types + * @{ + */ + + +/** + * @brief PQI threshold value enumeration. + */ +typedef enum +{ + PQI_TH_0=0x00, + PQI_TH_1=0x04, + PQI_TH_2=0x08, + PQI_TH_3=0x0C, + PQI_TH_4=0x10, + PQI_TH_5=0x14, + PQI_TH_6=0x18, + PQI_TH_7=0x1C, + PQI_TH_8=0x20, + PQI_TH_9=0x24, + PQI_TH_10=0x28, + PQI_TH_11=0x2C, + PQI_TH_12=0x30, + PQI_TH_13=0x34, + PQI_TH_14=0x38, + PQI_TH_15=0x3C + +} PqiThreshold; + +#define IS_PQI_THR(VALUE) (VALUE==PQI_TH_0 ||\ + VALUE==PQI_TH_1 ||\ + VALUE==PQI_TH_2 ||\ + VALUE==PQI_TH_3 ||\ + VALUE==PQI_TH_4 ||\ + VALUE==PQI_TH_5 ||\ + VALUE==PQI_TH_6 ||\ + VALUE==PQI_TH_7 ||\ + VALUE==PQI_TH_8 ||\ + VALUE==PQI_TH_9 ||\ + VALUE==PQI_TH_10 ||\ + VALUE==PQI_TH_11 ||\ + VALUE==PQI_TH_12 ||\ + VALUE==PQI_TH_13 ||\ + VALUE==PQI_TH_14 ||\ + VALUE==PQI_TH_15) + +/** + * @brief SQI threshold value enumeration. + */ +typedef enum +{ + SQI_TH_0=0x00, + SQI_TH_1=0x40, + SQI_TH_2=0x80, + SQI_TH_3=0xC0 + +} SqiThreshold; + +#define IS_SQI_THR(VALUE) (VALUE==SQI_TH_0 ||\ + VALUE==SQI_TH_1 ||\ + VALUE==SQI_TH_2 ||\ + VALUE==SQI_TH_3) + + +/** + * @brief RSSI filter gain value enumeration. + */ +typedef enum +{ + RSSI_FG_0=0x00, + RSSI_FG_1=0x10, + RSSI_FG_2=0x20, + RSSI_FG_3=0x30, + RSSI_FG_4=0x40, + RSSI_FG_5=0x50, + RSSI_FG_6=0x60, + RSSI_FG_7=0x70, + RSSI_FG_8=0x80, + RSSI_FG_9=0x90, + RSSI_FG_10=0xA0, + RSSI_FG_11=0xB0, + RSSI_FG_12=0xC0, + RSSI_FG_13=0xD0, + RSSI_FG_14=0xE0, /*<! recommended value */ + RSSI_FG_15=0xF0 + +} RssiFilterGain; + +#define IS_RSSI_FILTER_GAIN(VALUE) (VALUE==RSSI_FG_0 ||\ + VALUE==RSSI_FG_1 ||\ + VALUE==RSSI_FG_2 ||\ + VALUE==RSSI_FG_3 ||\ + VALUE==RSSI_FG_4 ||\ + VALUE==RSSI_FG_5 ||\ + VALUE==RSSI_FG_6 ||\ + VALUE==RSSI_FG_7 ||\ + VALUE==RSSI_FG_8 ||\ + VALUE==RSSI_FG_9 ||\ + VALUE==RSSI_FG_10 ||\ + VALUE==RSSI_FG_11 ||\ + VALUE==RSSI_FG_12 ||\ + VALUE==RSSI_FG_13 ||\ + VALUE==RSSI_FG_14 ||\ + VALUE==RSSI_FG_15) + +/** + * @brief CS mode enumeration. + */ +typedef enum +{ + CS_MODE_STATIC_3DB=0x00, + CS_MODE_DYNAMIC_6DB=0x04, + CS_MODE_DYNAMIC_12DB=0x08, + CS_MODE_DYNAMIC_18DB=0x0C + +} CSMode; + +#define IS_CS_MODE(MODE) (MODE==CS_MODE_STATIC_3DB ||\ + MODE==CS_MODE_DYNAMIC_6DB ||\ + MODE==CS_MODE_DYNAMIC_12DB ||\ + MODE==CS_MODE_DYNAMIC_18DB) + +/** + *@} + */ + + +/** + * @defgroup Qi_Exported_Constants QI Exported Constants + * @{ + */ + +/* range for the RSSI Threshold in dBm */ +#define IS_RSSI_THR_DBM(VALUE) (VALUE>=-130 && VALUE<=-2) + +/** + *@} + */ + + +/** + * @defgroup Qi_Exported_Macros QI Exported Macros + * @{ + */ + +/** + * @brief Macro to obtain the RSSI value in dBm + * @param None. + * @retval RSSI in dBm. + * This parameter is a float. + */ +#define SpiritQiGetRssidBm() (-120.0+((float)(SpiritQiGetRssi()-20))/2) + +/** + *@} + */ + + +/** + * @defgroup Qi_Exported_Functions QI Exported Functions + * @{ + */ + +void SpiritQiPqiCheck(SpiritFunctionalState xNewState); +void SpiritQiSqiCheck(SpiritFunctionalState xNewState); +void SpiritQiSetPqiThreshold(PqiThreshold xPqiThr); +PqiThreshold SpiritQiGetPqiThreshold(void); +void SpiritQiSetSqiThreshold(SqiThreshold xSqiThr); +SqiThreshold SpiritQiGetSqiThreshold(void); +void SpiritQiSetRssiThreshold(uint8_t cRssiThr); +uint8_t SpiritQiGetRssiThreshold(void); +uint8_t SpiritQiComputeRssiThreshold(int cDbmValue); +void SpiritQiSetRssiThresholddBm(int nDbmValue); +uint8_t SpiritQiGetPqi(void); +uint8_t SpiritQiGetSqi(void); +uint8_t SpiritQiGetLqi(void); +SpiritFlagStatus SpiritQiGetCs(void); +uint8_t SpiritQiGetRssi(void); +void SpiritQiSetRssiFilterGain(RssiFilterGain xRssiFg); +RssiFilterGain SpiritQiGetRssiFilterGain(void); +void SpiritQiSetCsMode(CSMode xCsMode); +CSMode SpiritQiGetCsMode(void); +void SpiritQiCsTimeoutMask(SpiritFunctionalState xNewState); +void SpiritQiPqiTimeoutMask(SpiritFunctionalState xNewState); +void SpiritQiSqiTimeoutMask(SpiritFunctionalState xNewState); + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Radio.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Radio.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,636 @@ +/** + ****************************************************************************** + * @file SPIRIT_Radio.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief This file provides all the low level API to manage Analog and Digital + * radio part of SPIRIT. + * @details + * + * In order to configure the Radio main parameters, the user can + * fit <i>SRadioInit</i> structure the and call the <i>SpiritRadioInit()</i> + * function passing its pointer as an argument. + * + * <b>Example:</b> + * @code + * + * SRadioInit radioInit = { + * 0, // Xtal offset in ppm + * 433.4e6, // base frequency + * 20e3, // channel space + * 0, // channel number + * FSK, // modulation select + * 38400, // datarate + * 20e3, // frequency deviation + * 100.5e3 // channel filter bandwidth + * }; + * + * ... + * + * SpiritRadioInit(&radioInit); + * @endcode + * + * Another important parameter for the radio configuration is the + * transmission power. + * The user is allowed to configure it using the function <i>SpiritRadioSetPALeveldBm()</i> + * which sets the PA LEVEL specified by the first argument to the + * power expressed in dBm by the second parameter. + * + * <b>Example:</b> + * @code + * + * SpiritRadioSetPALeveldBm(0 , 10.0); + * + * @endcode + * + * + * @note The effective power that is set can be a little different from the + * passed argument in dBm because the function performs an approximation. + * + + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_RADIO_H +#define __SPIRIT_RADIO_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" +#include "SPIRIT_Config.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** @defgroup SPIRIT_Radio Radio + * @brief Configuration and management of SPIRIT RF Analog and Digital part. + * @details See the file <i>@ref SPIRIT_Radio.h</i> for more details. + * @{ + */ + + + +/** @defgroup Radio_Exported_Types Radio Exported Types + * @{ + */ + + +/** + * @brief SPIRIT XTAL frequency enumeration + */ +typedef enum +{ + XTAL_FLAG_24_MHz = 0x00, /*!< 24 MHz Xtal selected */ + XTAL_FLAG_26_MHz = 0x01 /*!< 26 MHz Xtal selected */ + +}XtalFlag; + + +#define IS_XTAL_FLAG(FLAG) (((FLAG) == XTAL_FLAG_24_MHz) || \ + ((FLAG) == XTAL_FLAG_26_MHz)) + +/** + * @brief SPIRIT Band enumeration + */ +typedef enum +{ + HIGH_BAND = 0x00, /*!< High_Band selected: from 779 MHz to 915 MHz */ + MIDDLE_BAND = 0x01, /*!< Middle Band selected: from 387 MHz to 470 MHz */ + LOW_BAND = 0x02, /*!< Low Band selected: from 300 MHz to 348 MHz */ + VERY_LOW_BAND = 0x03 /*!< Vary low Band selected: from 150 MHz to 174 MHz */ +}BandSelect; + + +#define IS_BAND_SELECTED(BAND) ((BAND == HIGH_BAND) || \ + (BAND == MIDDLE_BAND) || \ + (BAND == LOW_BAND) || \ + (BAND == VERY_LOW_BAND)) + +/** + * @brief SPIRIT Modulation enumeration + */ +typedef enum +{ + FSK = 0x00, /*!< 2-FSK modulation selected */ + GFSK_BT05 = 0x50, /*!< GFSK modulation selected with BT=0.5 */ + GFSK_BT1 = 0x10, /*!< GFSK modulation selected with BT=1 */ + ASK_OOK = 0x20, /*!< ASK or OOK modulation selected. ASK will use power ramping */ + MSK = 0x30 /*!< MSK modulation selected */ + +}ModulationSelect; + + +#define IS_MODULATION_SELECTED(MOD) (((MOD) == FSK) || \ + ((MOD) == GFSK_BT05) || \ + ((MOD) == GFSK_BT1) || \ + ((MOD) == ASK_OOK) || \ + ((MOD) == MSK)) + + +/** + * @brief SPIRIT PA additional load capacitors bank enumeration + */ +typedef enum +{ + LOAD_0_PF = PA_POWER0_CWC_0, /*!< No additional PA load capacitor */ + LOAD_1_2_PF = PA_POWER0_CWC_1_2P, /*!< 1.2pF additional PA load capacitor */ + LOAD_2_4_PF = PA_POWER0_CWC_2_4P, /*!< 2.4pF additional PA load capacitor */ + LOAD_3_6_PF = PA_POWER0_CWC_3_6P /*!< 3.6pF additional PA load capacitor */ + +}PALoadCapacitor; + +#define IS_PA_LOAD_CAP(CWC) (((CWC) == LOAD_0_PF) || \ + ((CWC) == LOAD_1_2_PF) || \ + ((CWC) == LOAD_2_4_PF) || \ + ((CWC) == LOAD_3_6_PF)) + + +/** + * @brief SPIRIT AFC Mode selection + */ +typedef enum +{ + AFC_SLICER_CORRECTION = AFC2_AFC_MODE_SLICER, /*!< AFC loop closed on slicer */ + AFC_2ND_IF_CORRECTION = AFC2_AFC_MODE_MIXER /*!< AFC loop closed on 2nd conversion stage */ + +}AFCMode; + +#define IS_AFC_MODE(MODE) ((MODE) == AFC_SLICER_CORRECTION || (MODE) == AFC_2ND_IF_CORRECTION) + + +/** + * @brief SPIRIT AGC Mode selection + */ +typedef enum +{ + AGC_LINEAR_MODE = AGCCTRL0_AGC_MODE_LINEAR, /*!< AGC works in linear mode */ + AGC_BINARY_MODE = AGCCTRL0_AGC_MODE_BINARY /*!< AGC works in binary mode */ + +}AGCMode; + +#define IS_AGC_MODE(MODE) ((MODE) == AGC_LINEAR_MODE || (MODE) == AGC_BINARY_MODE) + + +/** + * @brief SPIRIT Clock Recovery Mode selection + */ +typedef enum +{ + CLK_REC_PLL = FDEV0_CLOCK_REG_ALGO_SEL_PLL, /*!< PLL alogrithm for clock recovery */ + CLK_REC_DLL = FDEV0_CLOCK_REG_ALGO_SEL_DLL /*!< DLL alogrithm for clock recovery */ + +}ClkRecMode; + +#define IS_CLK_REC_MODE(MODE) ((MODE) == CLK_REC_PLL || (MODE) == CLK_REC_DLL) + + +/** + * @brief SPIRIT Postfilter length + */ +typedef enum +{ + PSTFLT_LENGTH_8 = 0x00, /*!< Postfilter length is 8 symbols */ + PSTFLT_LENGTH_16 = 0x10 /*!< Postfilter length is 16 symbols */ + +}PstFltLength; + +#define IS_PST_FLT_LENGTH(LENGTH) ((LENGTH) == PSTFLT_LENGTH_8 || (LENGTH) == PSTFLT_LENGTH_16) + + +/** + * @brief SPIRIT OOK Peak Decay + */ +typedef enum +{ + FAST_DECAY = 0x00, /*!< Peak decay control for OOK: fast decay */ + MEDIUM_FAST_DECAY = 0x01, /*!< Peak decay control for OOK: medium_fast decay */ + MEDIUM_SLOW_DECAY = 0x02, /*!< Peak decay control for OOK: medium_fast decay */ + SLOW_DECAY = 0x03 /*!< Peak decay control for OOK: slow decay */ + +}OokPeakDecay; + +#define IS_OOK_PEAK_DECAY(DECAY) (((DECAY) == FAST_DECAY) ||\ + ((DECAY) == MEDIUM_FAST_DECAY) ||\ + ((DECAY) == MEDIUM_SLOW_DECAY) ||\ + ((DECAY) == SLOW_DECAY)) + + +/** + * @brief SPIRIT Radio Init structure definition + */ +typedef struct +{ + int16_t nXtalOffsetPpm; /*!< Specifies the offset frequency (in ppm) + to compensate crystal inaccuracy expressed + as signed value.*/ + + uint32_t lFrequencyBase; /*!< Specifies the base carrier frequency (in Hz), + i.e. the carrier frequency of channel #0. + This parameter can be in one of the following ranges: + High_Band: from 779 MHz to 915 MHz + Middle Band: from 387 MHz to 470 MHz + Low Band: from 300 MHz to 348 MHz */ + uint32_t nChannelSpace; /*!< Specifies the channel spacing expressed in Hz. + The channel spacing is expressed as: + NxFREQUENCY_STEPS, where FREQUENCY STEPS + is F_Xo/2^15. + This parameter can be in the range: [0, F_Xo/2^15*255] Hz */ + uint8_t cChannelNumber; /*!< Specifies the channel number. This value + is multiplied by the channel spacing and + added to synthesizer base frequency to + generate the actual RF carrier frequency */ + ModulationSelect xModulationSelect; /*!< Specifies the modulation. This + parameter can be any value of + @ref ModulationSelect */ + uint32_t lDatarate; /*!< Specifies the datarate expressed in bps. + This parameter can be in the range between + 100 bps and 500 kbps */ + uint32_t lFreqDev; /*!< Specifies the frequency deviation expressed in Hz. + This parameter can be in the range: [F_Xo*8/2^18, F_Xo*7680/2^18] Hz */ + uint32_t lBandwidth; /*!< Specifies the channel filter bandwidth + expressed in Hz. This parameter can be + in the range between 1100 and 800100 Hz */ + +}SRadioInit; + +/** + * @} + */ + + + +/** @defgroup Radio_Exported_Constants Radio Exported Constants + * @{ + */ + +/** @defgroup Radio_Band + * @{ + */ + +#define FBASE_DIVIDER 262144 /*!< 2^18 factor dividing fxo in fbase formula */ + +#define HIGH_BAND_FACTOR 6 /*!< Band select factor for high band. Factor B in the equation 2 */ +#define MIDDLE_BAND_FACTOR 12 /*!< Band select factor for middle band. Factor B in the equation 2 */ +#define LOW_BAND_FACTOR 16 /*!< Band select factor for low band. Factor B in the equation 2 */ +#define VERY_LOW_BAND_FACTOR 32 /*!< Band select factor for very low band. Factor B in the equation 2 */ + +#define HIGH_BAND_LOWER_LIMIT 778000000 /*!< Lower limit of the high band: 779 MHz */ +#define HIGH_BAND_UPPER_LIMIT 957100000 /*!< Upper limit of the high band: 956 MHz */ +#define MIDDLE_BAND_LOWER_LIMIT 386000000 /*!< Lower limit of the middle band: 387 MHz */ +#define MIDDLE_BAND_UPPER_LIMIT 471100000 /*!< Upper limit of the middle band: 470 MHz */ +#define LOW_BAND_LOWER_LIMIT 299000000 /*!< Lower limit of the low band: 300 MHz */ +#define LOW_BAND_UPPER_LIMIT 349100000 /*!< Upper limit of the low band: 348 MHz */ +#define VERY_LOW_BAND_LOWER_LIMIT 149000000 /*!< Lower limit of the very low band: 150 MHz */ +#define VERY_LOW_BAND_UPPER_LIMIT 175100000 /*!< Upper limit of the very low band: 174 MHz */ + +#define IS_FREQUENCY_BAND_HIGH(FREQUENCY) ((FREQUENCY)>=HIGH_BAND_LOWER_LIMIT && \ + (FREQUENCY)<=HIGH_BAND_UPPER_LIMIT) + +#define IS_FREQUENCY_BAND_MIDDLE(FREQUENCY) ((FREQUENCY)>=MIDDLE_BAND_LOWER_LIMIT && \ + (FREQUENCY)<=MIDDLE_BAND_UPPER_LIMIT) + +#define IS_FREQUENCY_BAND_LOW(FREQUENCY) ((FREQUENCY)>=LOW_BAND_LOWER_LIMIT && \ + (FREQUENCY)<=LOW_BAND_UPPER_LIMIT) + +#define IS_FREQUENCY_BAND_VERY_LOW(FREQUENCY) ((FREQUENCY)>=VERY_LOW_BAND_LOWER_LIMIT && \ + (FREQUENCY)<=VERY_LOW_BAND_UPPER_LIMIT) + +#define IS_FREQUENCY_BAND(FREQUENCY) (IS_FREQUENCY_BAND_HIGH(FREQUENCY)|| \ + IS_FREQUENCY_BAND_MIDDLE(FREQUENCY)|| \ + IS_FREQUENCY_BAND_LOW(FREQUENCY)|| \ + IS_FREQUENCY_BAND_VERY_LOW(FREQUENCY)) + +/** + * @} + */ + + +/** @defgroup Radio_IF_Offset Radio IF Offset + * @{ + */ +#define IF_OFFSET_ANA(F_Xo) (lroundf(480140.0/(F_Xo)*12288-64.0)) /*!< It represents the IF_OFFSET_ANA in order + to have an intermediate frequency of 480 kHz */ +/** + * @} + */ + + +/** @defgroup Radio_FC_Offset Radio FC Offset + * @{ + */ +#define F_OFFSET_DIVIDER 262144 /*!< 2^18 factor dividing fxo in foffset formula */ +#define PPM_FACTOR 1000000 /*!< 10^6 factor to use with Xtal_offset_ppm */ + + +#define F_OFFSET_LOWER_LIMIT(F_Xo) ((-(int32_t)F_Xo)/F_OFFSET_DIVIDER*2048) +#define F_OFFSET_UPPER_LIMIT(F_Xo) ((int32_t)(F_Xo/F_OFFSET_DIVIDER*2047)) + +#define IS_FREQUENCY_OFFSET(OFFSET, F_Xo) (OFFSET>=F_OFFSET_LOWER_LIMIT(F_Xo) && OFFSET<=F_OFFSET_UPPER_LIMIT(F_Xo)) + + +/** + * @} + */ + + +/** @defgroup Radio_Channel_Space Radio Channel Space + * @{ + */ + + +#define CHSPACE_DIVIDER 32768 /*!< 2^15 factor dividing fxo in channel space formula */ + +#define IS_CHANNEL_SPACE(CHANNELSPACE, F_Xo) (CHANNELSPACE<=(F_Xo/32768*255)) + + + + + +/** + * @} + */ + + +/** @defgroup Radio_Datarate Radio Datarate + * @{ + */ +#define MINIMUM_DATARATE 100 /*!< Minimum datarate supported by SPIRIT1 100 bps */ +#define MAXIMUM_DATARATE 510000 /*!< Maximum datarate supported by SPIRIT1 500 kbps */ + +#define IS_DATARATE(DATARATE) (DATARATE>=MINIMUM_DATARATE && DATARATE<=MAXIMUM_DATARATE) + +/** + * @} + */ + + +/** @defgroup Radio_Frequency_Deviation Radio Frequency Deviation + * @{ + */ +#define F_DEV_MANTISSA_UPPER_LIMIT 7 /*!< Maximum value for the mantissa in frequency deviation formula */ +#define F_DEV_EXPONENT_UPPER_LIMIT 9 /*!< Maximum value for the exponent in frequency deviation formula */ + +#define F_DEV_LOWER_LIMIT(F_Xo) (F_Xo>>16) +#define F_DEV_UPPER_LIMIT(F_Xo) ((F_Xo*15)>>10) + +#define IS_F_DEV(FDEV,F_Xo) (FDEV>=F_DEV_LOWER_LIMIT(F_Xo) && FDEV<=F_DEV_UPPER_LIMIT(F_Xo)) + + +/** + * @} + */ + + +/** @defgroup Radio_Channel_Bandwidth Radio Channel Bandwidth + * @{ + */ +#define CH_BW_LOWER_LIMIT(F_Xo) 1100*(F_Xo/1000000)/26 /*!< Minimum value of the channel filter bandwidth */ +#define CH_BW_UPPER_LIMIT(F_Xo) 800100*(F_Xo/1000000)/26 /*!< Maximum value of the channel filter bandwidth */ + +#define IS_CH_BW(BW,F_Xo) ((BW)>=CH_BW_LOWER_LIMIT(F_Xo) && (BW)<=CH_BW_UPPER_LIMIT(F_Xo)) + +/** + * @} + */ + + +/** @defgroup Radio_Power_Amplifier Radio Power Amplifier + * @{ + */ + +#define IS_PA_MAX_INDEX(INDEX) ((INDEX)<=7) +#define IS_PAPOWER_DBM(PATABLE) ((PATABLE)>= (-31) && (PATABLE)<=(12)) +#define IS_PAPOWER(PATABLE) ((PATABLE)<=90) +#define IS_PA_STEP_WIDTH(WIDTH) ((WIDTH)>=1 && (WIDTH)<=4) + +/** + * @} + */ + + +/** @defgroup Radio_Automatic_Frequency_Correction Radio Automatic Frequency Correction + * @{ + */ + +#define IS_AFC_FAST_GAIN(GAIN) ((GAIN)<=15) +#define IS_AFC_SLOW_GAIN(GAIN) ((GAIN)<=15) +#define IS_AFC_PD_LEAKAGE(LEAKAGE) ((LEAKAGE)<=31) + +/** + * @} + */ + +/** @defgroup Radio_Automatic_Gain_Control Radio Automatic Gain Control + * @{ + */ + +#define AGC_MEASURE_TIME_UPPER_LIMIT_US(F_Xo) (393216.0/F_Xo) + +#define IS_AGC_MEASURE_TIME_US(TIME, F_Xo) (TIME<=AGC_MEASURE_TIME_UPPER_LIMIT_US(F_Xo)) + +#define IS_AGC_MEASURE_TIME(TIME) (TIME<=15) + +#define AGC_HOLD_TIME_UPPER_LIMIT_US(F_Xo) (756.0/F_Xo) + +#define IS_AGC_HOLD_TIME_US(TIME,F_Xo) (TIME<=AGC_HOLD_TIME_UPPER_LIMIT_US(F_Xo)) + + +#define IS_AGC_HOLD_TIME(TIME) (TIME<=63) + +#define IS_AGC_THRESHOLD(THRESHOLD) (THRESHOLD<=15) + +/** + * @} + */ + + +/** @defgroup Radio_Clock_Recovery Radio Clock Recovery + * @{ + */ + +#define IS_CLK_REC_P_GAIN(GAIN) ((GAIN)<=7) +#define IS_CLK_REC_I_GAIN(GAIN) ((GAIN)<=15) + +/** + * @} + */ + +/** + * @} + */ + + + +/** @defgroup Radio_Exported_Macros Radio Exported Macros + * @{ + */ + + +/** + * @} + */ + +/** @defgroup Radio_Exported_Functions Radio Exported Functions + * @{ + */ + +uint8_t SpiritRadioInit(SRadioInit* pxSRadioInitStruct); +void SpiritRadioGetInfo(SRadioInit* pxSRadioInitStruct); +void SpiritRadioSetXtalFlag(XtalFlag xXtal); +XtalFlag SpiritRadioGetXtalFlag(void); +uint8_t SpiritRadioSearchWCP(uint32_t lFc); +void SpiritRadioSetSynthWord(uint32_t lSynthWord); +uint32_t SpiritRadioGetSynthWord(void); +void SpiritRadioSetBand(BandSelect xBand); +BandSelect SpiritRadioGetBand(void); +void SpiritRadioSetChannel(uint8_t cChannel); +uint8_t SpiritRadioGetChannel(void); +void SpiritRadioSetChannelSpace(uint32_t lChannelSpace); +uint32_t SpiritRadioGetChannelSpace(void); +void SpiritRadioSetFrequencyOffsetPpm(int16_t nXtalPpm); +void SpiritRadioSetFrequencyOffset(int32_t lFOffset); +int32_t SpiritRadioGetFrequencyOffset(void); +void SpiritRadioVcoCalibrationWAFB(SpiritFunctionalState xNewstate); +uint8_t SpiritRadioSetFrequencyBase(uint32_t lFBase); +uint32_t SpiritRadioGetFrequencyBase(void); +uint32_t SpiritRadioGetCenterFrequency(void); +void SpiritRadioSearchDatarateME(uint32_t lDatarate, uint8_t* pcM, uint8_t* pcE); +void SpiritRadioSearchFreqDevME(uint32_t lFDev, uint8_t* pcM, uint8_t* pcE); +void SpiritRadioSearchChannelBwME(uint32_t lBandwidth, uint8_t* pcM, uint8_t* pcE); +void SpiritRadioSetDatarate(uint32_t lDatarate); +uint32_t SpiritRadioGetDatarate(void); +void SpiritRadioSetFrequencyDev(uint32_t lFDev); +uint32_t SpiritRadioGetFrequencyDev(void); +void SpiritRadioSetChannelBW(uint32_t lBandwidth); +uint32_t SpiritRadioGetChannelBW(void); +void SpiritRadioSetModulation(ModulationSelect xModulation); +ModulationSelect SpiritRadioGetModulation(void); +void SpiritRadioCWTransmitMode(SpiritFunctionalState xNewState); +void SpiritRadioSetOokPeakDecay(OokPeakDecay xOokDecay); +OokPeakDecay SpiritRadioGetOokPeakDecay(void); +uint8_t SpiritRadioGetdBm2Reg(uint32_t lFBase, float fPowerdBm); +float SpiritRadioGetReg2dBm(uint32_t lFBase, uint8_t cPowerReg); +void SpiritRadioSetPATabledBm(uint8_t cPALevelMaxIndex, uint8_t cWidth, PALoadCapacitor xCLoad, float* pfPAtabledBm); +void SpiritRadioGetPATabledBm(uint8_t* pcPALevelMaxIndex, float* pfPAtabledBm); +void SpiritRadioSetPATable(uint8_t cPALevelMaxIndex, uint8_t cWidth, PALoadCapacitor xCLoad, uint8_t* pcPAtable); +void SpiritRadioGetPATable(uint8_t* pcPALevelMaxIndex, uint8_t* pcPAtable); +void SpiritRadioSetPALeveldBm(uint8_t cIndex, float fPowerdBm); +float SpiritRadioGetPALeveldBm(uint8_t cIndex); +void SpiritRadioSetPALevel(uint8_t cIndex, uint8_t cPower); +uint8_t SpiritRadioGetPALevel(uint8_t cIndex); +void SpiritRadioSetPACwc(PALoadCapacitor xCLoad); +PALoadCapacitor SpiritRadioGetPACwc(void); +void SpiritRadioSetPALevelMaxIndex(uint8_t cIndex); +uint8_t SpiritRadioGetPALevelMaxIndex(void); +void SpiritRadioSetPAStepWidth(uint8_t cWidth); +uint8_t SpiritRadioGetPAStepWidth(void); +void SpiritRadioPARamping(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritRadioGetPARamping(void); +void SpiritRadioAFC(SpiritFunctionalState xNewState); +void SpiritRadioAFCFreezeOnSync(SpiritFunctionalState xNewState); +void SpiritRadioSetAFCMode(AFCMode xMode); +AFCMode SpiritRadioGetAFCMode(void); +void SpiritRadioSetAFCPDLeakage(uint8_t cLeakage); +uint8_t SpiritRadioGetAFCPDLeakage(void); +void SpiritRadioSetAFCFastPeriod(uint8_t cLength); +uint8_t SpiritRadioGetAFCFastPeriod(void); +void SpiritRadioSetAFCFastGain(uint8_t cGain); +uint8_t SpiritRadioGetAFCFastGain(void); +void SpiritRadioSetAFCSlowGain(uint8_t cGain); +uint8_t SpiritRadioGetAFCSlowGain(void); +int8_t SpiritRadioGetAFCCorrectionReg(void); +int32_t SpiritRadioGetAFCCorrectionHz(void); +void SpiritRadioAGC(SpiritFunctionalState xNewState); +void SpiritRadioSetAGCMode(AGCMode xMode); +AGCMode SpiritRadioGetAGCMode(void); +void SpiritRadioAGCFreezeOnSteady(SpiritFunctionalState xNewState); +void SpiritRadioAGCFreezeOnSync(SpiritFunctionalState xNewState); +void SpiritRadioAGCStartMaxAttenuation(SpiritFunctionalState xNewState); +void SpiritRadioSetAGCMeasureTimeUs(uint16_t nTime); +uint16_t SpiritRadioGetAGCMeasureTimeUs(void); +void SpiritRadioSetAGCMeasureTime(uint8_t cTime); +uint8_t SpiritRadioGetAGCMeasureTime(void); +void SpiritRadioSetAGCHoldTimeUs(uint8_t cTime); +uint8_t SpiritRadioGetAGCHoldTimeUs(void); +void SpiritRadioSetAGCHoldTime(uint8_t cTime); +uint8_t SpiritRadioGetAGCHoldTime(void); +void SpiritRadioSetAGCHighThreshold(uint8_t cHighThreshold); +uint8_t SpiritRadioGetAGCHighThreshold(void); +void SpiritRadioSetAGCLowThreshold(uint8_t cLowThreshold); +uint8_t SpiritRadioGetAGCLowThreshold(void); +void SpiritRadioSetClkRecMode(ClkRecMode xMode); +ClkRecMode SpiritRadioGetClkRecMode(void); +void SpiritRadioSetClkRecPGain(uint8_t cPGain); +uint8_t SpiritRadioGetClkRecPGain(void); +void SpiritRadioSetClkRecIGain(uint8_t cIGain); +uint8_t SpiritRadioGetClkRecIGain(void); +void SpiritRadioSetClkRecPstFltLength(PstFltLength xLength); +PstFltLength SpiritRadioGetClkRecPstFltLength(void); +void SpiritRadioCsBlanking(SpiritFunctionalState xNewState); +void SpiritRadioPersistenRx(SpiritFunctionalState xNewState); +uint32_t SpiritRadioGetXtalFrequency(void); +void SpiritRadioSetXtalFrequency(uint32_t lXtalFrequency); +void SpiritRadioSetRefDiv(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritRadioGetRefDiv(void); +void SpiritRadioSetDigDiv(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritRadioGetDigDiv(void); +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Regs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Regs.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3244 @@ +/** + ****************************************************************************** + * @file SPIRIT_Regs.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief This file contains all the SPIRIT registers address and masks. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT1_REGS_H +#define __SPIRIT1_REGS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * @addtogroup SPIRIT_Registers SPIRIT Registers + * @brief Header file containing all the SPIRIT registers address and masks. + * @details See the file <i>@ref SPIRIT_Regs.h</i> for more details. + * @{ + */ + +/** @defgroup General_Configuration_Registers + * @{ + */ + +/** @defgroup ANA_FUNC_CONF_1_Register + * @{ + */ + +/** + * \brief ANA_FUNC_CONF register 1 + * \code + * Read Write + * Default value: 0x0C + * 7:5 NUM_EN_PIPES: Number of enabled pipes (starting from Data Pipe 0). + * 4:2 GM_CONF[2:0]: Sets the driver gm of the XO at start-up: + * GM_CONF2 | GM_CONF1 | GM_CONF0 | GM [mS] + * ------------------------------------------ + * 0 | 0 | 0 | 13.2 + * 0 | 0 | 1 | 18.2 + * 0 | 1 | 0 | 21.5 + * 0 | 1 | 1 | 25.6 + * 1 | 0 | 0 | 28.8 + * 1 | 0 | 1 | 33.9 + * 1 | 1 | 0 | 38.5 + * 1 | 1 | 1 | 43.0 + * 1:0 SET_BLD_LVL[1:0]: Sets the Battery Level Detector threshold: + * SET_BLD_LVL1 | SET_BLD_LVL0 | Threshold [V] + * ------------------------------------------ + * 0 | 0 | 2.7 + * 0 | 1 | 2.5 + * 1 | 0 | 2.3 + * 1 | 1 | 2.1 + * \endcode + */ + +#define ANA_FUNC_CONF1_BASE ((uint8_t)0x00) /*!< ANA_FUNC_CONF1 Address (R/W) */ + +#define ANA_FUNC_CONF1_NUM_PIPES_MASK ((uint8_t)0xE0) /*!< Mask for number of enabled pipes*/ + +#define ANA_FUNC_CONF1_GMCONF_MASK ((uint8_t)0x1C) /*!< Mask of the GmConf field of ANA_FUNC_CONF1 register (R/W) */ + +#define GM_13_2 ((uint8_t)0x00) /*!< Transconducatance Gm at start-up 13.2 mS */ +#define GM_18_2 ((uint8_t)0x04) /*!< Transconducatance Gm at start-up 18.2 mS */ +#define GM_21_5 ((uint8_t)0x08) /*!< Transconducatance Gm at start-up 21.5 mS */ +#define GM_25_6 ((uint8_t)0x0C) /*!< Transconducatance Gm at start-up 25.6 mS */ +#define GM_28_8 ((uint8_t)0x10) /*!< Transconducatance Gm at start-up 28.8 mS */ +#define GM_33_9 ((uint8_t)0x14) /*!< Transconducatance Gm at start-up 33.9 mS */ +#define GM_38_5 ((uint8_t)0x18) /*!< Transconducatance Gm at start-up 38.5 mS */ +#define GM_43_0 ((uint8_t)0x1C) /*!< Transconducatance Gm at start-up 43.0 mS */ + +#define ANA_FUNC_CONF1_SET_BLD_LVL_MASK ((uint8_t)0x03) /*!< Mask of the SET_BLD_LV field of ANA_FUNC_CONF1 register (R/W) */ + +#define BLD_LVL_2_7 ((uint8_t)0x00) /*!< Sets the Battery Level Detector threshold to 2.7V */ +#define BLD_LVL_2_5 ((uint8_t)0x01) /*!< Sets the Battery Level Detector threshold to 2.5V */ +#define BLD_LVL_2_3 ((uint8_t)0x02) /*!< Sets the Battery Level Detector threshold to 2.3V */ +#define BLD_LVL_2_1 ((uint8_t)0x03) /*!< Sets the Battery Level Detector threshold to 2.1V */ + +/** + * @} + */ + + +/** @defgroup ANA_FUNC_CONF_0_Register + * @{ + */ + +/** + * \brief ANA_FUNC_CONF register 0 + * \code + * Read Write + * Default value: 0xC0 + * 7 Reserved. + * 6 24_26_MHz_SELECT: 1 - 26 MHz configuration + * 0 - 24 MHz configuration + * 5 AES_ON: 1 - AES engine enabled + * 0 - AES engine disabled + * 4 EXT_REF: 1 - Reference signal from XIN pin + * 0 - Reference signal from XO circuit + * 3 HIGH_POWER_MODE: 1 - SET_SMPS_LEVEL word will be set to the value to + * PM_TEST register in RX state, while in TX state it + * will be fixed to 111 (which programs the SMPS output + * at max value 1.8V) + * 0 - SET_SMPS_LEVEL word will hold the value written in the + * PM_TEST register both in RX and TX state + * 2 BROWN_OUT: 1 - Brown_Out Detection enabled + * 0 - Brown_Out Detection disabled + * 1 BATTERY_LEVEL: 1 - Battery level detector enabled + * 0 - Battery level detector disabled + * 0 TS: 1 - Enable the "Temperature Sensor" function + * 0 - Disable the "Temperature Sensor" function + * \endcode + */ + + +#define ANA_FUNC_CONF0_BASE ((uint8_t)0x01) /*!< ANA_FUNC_CONF0 Address (R/W) */ + +#define SELECT_24_26_MHZ_MASK ((uint8_t)0x40) /*!< Configure the RCO if using 26 MHz or 24 MHz master clock/reference signal */ +#define AES_MASK ((uint8_t)0x20) /*!< AES engine on/off */ +#define EXT_REF_MASK ((uint8_t)0x10) /*!< Reference signal from XIN pin (oscillator external) or from XO circuit (oscillator internal)*/ +#define HIGH_POWER_MODE_MASK ((uint8_t)0x08) /*!< SET_SMPS_LEVEL word will be set to the value to PM_TEST register + in RX state, while in TX state it will be fixed to 111 + (which programs the SMPS output at max value, 1.8V) */ +#define BROWN_OUT_MASK ((uint8_t)0x04) /*!< Accurate Brown-Out detection on/off */ +#define BATTERY_LEVEL_MASK ((uint8_t)0x02) /*!< Battery level detector circuit on/off */ +#define TEMPERATURE_SENSOR_MASK ((uint8_t)0x01) /*!< The Temperature Sensor (available on GPIO0) on/off */ + +/** + * @} + */ + +/** @defgroup ANT_SELECT_CONF_Register + * @{ + */ + +/** + * \brief ANT_SELECT_CONF register + * \code + * Read Write + * Default value: 0x05 + * + * 7:5 Reserved. + * + * 4 CS_BLANKING: Blank received data if signal is below the CS threshold + * + * 3 AS_ENABLE: Enable antenna switching + * 1 - Enable + * 0 - Disable + * + * 2:0 AS_MEAS_TIME[2:0]: Measurement time according to the formula Tmeas = 24*2^(EchFlt)*2^AS_MEAS_TIME/fxo + * \endcode + */ +#define ANT_SELECT_CONF_BASE ((uint8_t)0x27) /*!< Antenna diversity (works only in static carrier sense mode) */ +#define ANT_SELECT_CS_BLANKING_MASK ((uint8_t)0x10) /*!< CS data blanking on/off */ +#define ANT_SELECT_CONF_AS_MASK ((uint8_t)0x08) /*!< Antenna diversity on/off */ + +/** + * @} + */ + +/** @defgroup DEVICE_INFO1_Register + * @{ + */ + +/** + * \brief DEVICE_INFO1[7:0] registers + * \code + * Default value: 0x01 + * Read + * + * 7:0 PARTNUM[7:0]: Device part number + * \endcode + */ +#define DEVICE_INFO1_PARTNUM ((uint8_t)(0xF0)) /*!< Device part number [7:0] */ + +/** + * @} + */ + +/** @defgroup DEVICE_INFO0_Register + * @{ + */ + +/** + * \brief DEVICE_INFO0[7:0] registers + * \code + * Read + * + * 7:0 VERSION[7:0]: Device version number + * \endcode + */ +#define DEVICE_INFO0_VERSION ((uint8_t)(0xF1)) /*!< Device version [7:0]; (0x55 in CUT1.0) */ + +/** + * @} + */ + + +/** + * @} + */ + + +/** @defgroup GPIO_Registers + * @{ + */ + +/** @defgroup GPIOx_CONF_Registers + * @{ + */ + +/** + * \brief GPIOx registers + * \code + * Read Write + * Default value: 0x03 + * 7:3 GPIO_SELECT[4:0]: Specify the I/O signal. + * GPIO_SELECT[4:0] | I/O | Signal + * ------------------------------------------------ + * 0 | Output | nIRQ + * 0 | Input | TX command + * 1 | Output | POR inverted + * 1 | Input | RX command + * 2 | Output | Wake-Up timer expiration + * 2 | Input | TX data for direct modulation + * 3 | Output | Low Battery Detection + * 3 | Input | Wake-up from external input + * 4 | Output | TX clock output + * 5 | Output | TX state + * 6 | Output | TX FIFO Almost Empty Flag + * 7 | Output | TX FIFO ALmost Full Flag + * 8 | Output | RX data output + * 9 | Output | RX clock output + * 10 | Output | RX state + * 11 | Output | RX FIFO Almost Full Flag + * 12 | Output | RX FIFO Almost Empty Flag + * 13 | Output | Antenna switch + * 14 | Output | Valid preamble detected + * 15 | Output | Sync word detected + * 16 | Output | RSSI above threshold + * 17 | Output | MCU clock + * 18 | Output | TX or RX mode indicator + * 19 | Output | VDD + * 20 | Output | GND + * 21 | Output | External SMPS enable signal + * 22-31 | Not Used | Not Used + * 2 Reserved + * 1:0 GpioMode[1:0]: Specify the mode: + * GPIO_MODE1 | GPIO_MODE0 | MODE + * ------------------------------------------------------------ + * 0 | 0 | Analog (valid only for GPIO_0) + * 0 | 1 | Digital Input + * 1 | 0 | Digital Output Low Power + * 1 | 1 | Digital Output High Power + * + * Note: The Analog mode is used only for temperature sensor indication. This is available only + * on GPIO_0 by setting the TS bit in the ANA_FUNC_CONF_0_Register. + * \endcode + */ + + +#define GPIO3_CONF_BASE ((uint8_t)0x02) /*!< GPIO_3 register address */ +#define GPIO2_CONF_BASE ((uint8_t)0x03) /*!< GPIO_3 register address */ +#define GPIO1_CONF_BASE ((uint8_t)0x04) /*!< GPIO_3 register address */ +#define GPIO0_CONF_BASE ((uint8_t)0x05) /*!< GPIO_3 register address */ + +#define CONF_GPIO_IN_TX_Command ((uint8_t)0x00) /*!< TX command direct from PIN (rising edge, width min=50ns) */ +#define CONF_GPIO_IN_RX_Command ((uint8_t)0x08) /*!< RX command direct from PIN (rising edge, width min=50ns)*/ +#define CONF_GPIO_IN_TX_Data ((uint8_t)0x10) /*!< TX data input for direct modulation */ +#define CONF_GPIO_IN_WKUP_Ext ((uint8_t)0x18) /*!< Wake up from external input */ + +#define CONF_GPIO_OUT_nIRQ ((uint8_t)0x00) /*!< nIRQ (Interrupt Request, active low) , default configuration after POR */ +#define CONF_GPIO_OUT_POR_Inv ((uint8_t)0x08) /*!< POR inverted (active low) */ +#define CONF_GPIO_OUT_WUT_Exp ((uint8_t)0x10) /*!< Wake-Up Timer expiration: 1 when WUT has expired */ +#define CONF_GPIO_OUT_LBD ((uint8_t)0x18) /*!< Low battery detection: 1 when battery is below threshold setting */ +#define CONF_GPIO_OUT_TX_Data ((uint8_t)0x20) /*!< TX data internal clock output (TX data are sampled on the rising edge of it) */ +#define CONF_GPIO_OUT_TX_State ((uint8_t)0x28) /*!< TX state indication: 1 when Spirit1 is transiting in the TX state */ +#define CONF_GPIO_OUT_TX_FIFO_Almost_Empty ((uint8_t)0x30) /*!< TX FIFO Almost Empty Flag */ +#define CONF_GPIO_OUT_TX_FIFO_Amost_Full ((uint8_t)0x38) /*!< TX FIFO Almost Full Flag */ +#define CONF_GPIO_OUT_RX_Data ((uint8_t)0x40) /*!< RX data output */ +#define CONF_GPIO_OUT_RX_Clock ((uint8_t)0x48) /*!< RX clock output (recovered from received data) */ +#define CONF_GPIO_OUT_RX_State ((uint8_t)0x50) /*!< RX state indication: 1 when Spirit1 is transiting in the RX state */ +#define CONF_GPIO_OUT_RX_FIFO_Almost_Full ((uint8_t)0x58) /*!< RX FIFO Almost Full Flag */ +#define CONF_GPIO_OUT_RX_FIFO_Almost_Empty ((uint8_t)0x60) /*!< RX FIFO Almost Empty Flag */ +#define CONF_GPIO_OUT_Antenna_Switch ((uint8_t)0x68) /*!< Antenna switch used for antenna diversity */ +#define CONF_GPIO_OUT_Valid_Preamble ((uint8_t)0x70) /*!< Valid Preamble Detected Flag */ +#define CONF_GPIO_OUT_Sync_Detected ((uint8_t)0x78) /*!< Sync WordSync Word Detected Flag */ +#define CONF_GPIO_OUT_RSSI_Threshold ((uint8_t)0x80) /*!< CCA Assessment Flag */ +#define CONF_GPIO_OUT_MCU_Clock ((uint8_t)0x88) /*!< MCU Clock */ +#define CONF_GPIO_OUT_TX_RX_Mode ((uint8_t)0x90) /*!< TX or RX mode indicator (to enable an external range extender) */ +#define CONF_GPIO_OUT_VDD ((uint8_t)0x98) /*!< VDD (to emulate an additional GPIO of the MCU, programmable by SPI) */ +#define CONF_GPIO_OUT_GND ((uint8_t)0xA0) /*!< GND (to emulate an additional GPIO of the MCU, programmable by SPI) */ +#define CONF_GPIO_OUT_SMPS_Ext ((uint8_t)0xA8) /*!< External SMPS enable signal (active high) */ + +#define CONF_GPIO_MODE_ANALOG ((uint8_t)0x00) /*!< Analog test BUS on GPIO; used only in test mode (except for temperature sensor) */ +#define CONF_GPIO_MODE_DIG_IN ((uint8_t)0x01) /*!< Digital Input on GPIO */ +#define CONF_GPIO_MODE_DIG_OUTL ((uint8_t)0x02) /*!< Digital Output on GPIO (low current) */ +#define CONF_GPIO_MODE_DIG_OUTH ((uint8_t)0x03) /*!< Digital Output on GPIO (high current) */ + +/** + * @} + */ + + +/** @defgroup MCU_CK_CONF_Register + * @{ + */ + +/** + * \brief MCU_CK_CONF register + * \code + * Read Write + * Default value: 0x00 + * 7 Reserved. + * 6:5 CLOCK_TAIL[1:0]: Specifies the number of extra cylces provided before entering in STANDBY state. + * CLOCK_TAIL1 | CLOCK_TAIL0 | Number of Extra Cycles + * ------------------------------------------------------------ + * 0 | 0 | 0 + * 0 | 1 | 64 + * 1 | 0 | 256 + * 1 | 1 | 512 + * 4:1 XO_RATIO[3:0]: Specifies the division ratio when XO oscillator is the clock source + * XO_RATIO[3:0] | Division Ratio + * ----------------------------------- + * 0 | 1 + * 1 | 2/3 + * 2 | 1/2 + * 3 | 1/3 + * 4 | 1/4 + * 5 | 1/6 + * 6 | 1/8 + * 7 | 1/12 + * 8 | 1/16 + * 9 | 1/24 + * 10 | 1/36 + * 11 | 1/48 + * 12 | 1/64 + * 13 | 1/96 + * 14 | 1/128 + * 15 | 1/256 + * 0 RCO_RATIO: Specifies the divsion ratio when RC oscillator is the clock source + * 0 - Division Ratio equal to 0 + * 1 - Division Ratio equal to 1/128 + * \endcode + */ + + +#define MCU_CK_CONF_BASE ((uint8_t)0x06) /*!< MCU Clock Config register address */ + +#define MCU_CK_ENABLE ((uint8_t)0x80) /*!< MCU clock enable bit */ + +#define MCU_CK_CONF_CLOCK_TAIL_0 ((uint8_t)0x00) /*!< 0 extra clock cycles provided to the MCU before switching to STANDBY state */ +#define MCU_CK_CONF_CLOCK_TAIL_64 ((uint8_t)0x20) /*!< 64 extra clock cycles provided to the MCU before switching to STANDBY state */ +#define MCU_CK_CONF_CLOCK_TAIL_256 ((uint8_t)0x40) /*!< 256 extra clock cycles provided to the MCU before switching to STANDBY state */ +#define MCU_CK_CONF_CLOCK_TAIL_512 ((uint8_t)0x60) /*!< 512 extra clock cycles provided to the MCU before switching to STANDBY state */ +#define MCU_CK_CONF_XO_RATIO_1 ((uint8_t)0x00) /*!< XO Clock signal available on the GPIO divided by 1 */ +#define MCU_CK_CONF_XO_RATIO_2_3 ((uint8_t)0x02) /*!< XO Clock signal available on the GPIO divided by 2/3 */ +#define MCU_CK_CONF_XO_RATIO_1_2 ((uint8_t)0x04) /*!< XO Clock signal available on the GPIO divided by 1/2 */ +#define MCU_CK_CONF_XO_RATIO_1_3 ((uint8_t)0x06) /*!< XO Clock signal available on the GPIO divided by 1/3 */ +#define MCU_CK_CONF_XO_RATIO_1_4 ((uint8_t)0x08) /*!< XO Clock signal available on the GPIO divided by 1/4 */ +#define MCU_CK_CONF_XO_RATIO_1_6 ((uint8_t)0x0A) /*!< XO Clock signal available on the GPIO divided by 1/6 */ +#define MCU_CK_CONF_XO_RATIO_1_8 ((uint8_t)0x0C) /*!< XO Clock signal available on the GPIO divided by 1/8 */ +#define MCU_CK_CONF_XO_RATIO_1_12 ((uint8_t)0x0E) /*!< XO Clock signal available on the GPIO divided by 1/12 */ +#define MCU_CK_CONF_XO_RATIO_1_16 ((uint8_t)0x10) /*!< XO Clock signal available on the GPIO divided by 1/16 */ +#define MCU_CK_CONF_XO_RATIO_1_24 ((uint8_t)0x12) /*!< XO Clock signal available on the GPIO divided by 1/24 */ +#define MCU_CK_CONF_XO_RATIO_1_36 ((uint8_t)0x14) /*!< XO Clock signal available on the GPIO divided by 1/36 */ +#define MCU_CK_CONF_XO_RATIO_1_48 ((uint8_t)0x16) /*!< XO Clock signal available on the GPIO divided by 1/48 */ +#define MCU_CK_CONF_XO_RATIO_1_64 ((uint8_t)0x18) /*!< XO Clock signal available on the GPIO divided by 1/64 */ +#define MCU_CK_CONF_XO_RATIO_1_96 ((uint8_t)0x1A) /*!< XO Clock signal available on the GPIO divided by 1/96 */ +#define MCU_CK_CONF_XO_RATIO_1_128 ((uint8_t)0x1C) /*!< XO Clock signal available on the GPIO divided by 1/128 */ +#define MCU_CK_CONF_XO_RATIO_1_192 ((uint8_t)0x1E) /*!< XO Clock signal available on the GPIO divided by 1/196 */ +#define MCU_CK_CONF_RCO_RATIO_1 ((uint8_t)0x00) /*!< RCO Clock signal available on the GPIO divided by 1 */ +#define MCU_CK_CONF_RCO_RATIO_1_128 ((uint8_t)0x01) /*!< RCO Clock signal available on the GPIO divided by 1/128*/ + +/** + * @} + */ + +/** + * @} + */ + + +/** @defgroup Radio_Configuration_Registers + * @{ + */ + + + +/** @defgroup SYNT3_Register + * @{ + */ + +/** + * \brief SYNT3 register + * \code + * Read Write + * Default value: 0x0C + * + * 7:5 WCP[2:0]: Set the charge pump current according to the VCO frequency in RX mode. + * + * VCO Frequency | WCP2 | WCP1 | WCP0 | Charge Pump Current (uA) + * ------------------------------------------------------------------------------------------------------------ + * 4644-4678 | 0 | 0 | 0 | 378.4 + * 4708-4772 | 0 | 0 | 1 | 368.9 + * 4772-4836 | 0 | 1 | 0 | 359.5 + * 4836-4902 | 0 | 1 | 1 | 350 + * 4902-4966 | 1 | 0 | 0 | 340.5 + * 4966-5030 | 1 | 0 | 1 | 331.1 + * 5030-5095 | 1 | 1 | 0 | 321.6 + * 5095-5161 | 1 | 1 | 1 | 312.2 + * 5161-5232 | 0 | 0 | 0 | 378.4 + * 5232-5303 | 0 | 0 | 1 | 368.9 + * 5303-5375 | 0 | 1 | 0 | 359.5 + * 5375-5448 | 0 | 1 | 1 | 350 + * 5448-5519 | 1 | 0 | 0 | 340.5 + * 5519-5592 | 1 | 0 | 1 | 331.1 + * 5592-5663 | 1 | 1 | 0 | 321.6 + * 5663-5736 | 1 | 1 | 1 | 312.2 + * + * + * 4:0 SYNT[25:21]: highest 5 bits of the PLL programmable divider + * The valid range depends on fXO and REFDIV settings; for + * fXO=26MHz + * REFDIV = 0 - SYNT[25:21] = 11...13 + * REFDIV = 1 - SYNT[25:21] = 22 27 + * + * + * \endcode + */ +#define SYNT3_BASE ((uint8_t)0x08) /*!< [4:0] -> SYNT[25:21], highest 5 bits of the PLL programmable divider */ + +#define WCP_CONF_WCP_378UA ((uint8_t)0x00) /*!< Charge pump current nominal value = 378uA [VCO 4644-4708]&[VCO 5161-5232] */ +#define WCP_CONF_WCP_369UA ((uint8_t)0x01) /*!< Charge pump current nominal value = 369uA [VCO 4708-4772]&[VCO 5232-5303] */ +#define WCP_CONF_WCP_359UA ((uint8_t)0x02) /*!< Charge pump current nominal value = 359uA [VCO 4772-4836]&[VCO 5303-5375] */ +#define WCP_CONF_WCP_350UA ((uint8_t)0x03) /*!< Charge pump current nominal value = 350uA [VCO 4836-4902]&[VCO 5375-5448] */ +#define WCP_CONF_WCP_340UA ((uint8_t)0x04) /*!< Charge pump current nominal value = 340uA [VCO 4902-4966]&[VCO 5448-5519] */ +#define WCP_CONF_WCP_331UA ((uint8_t)0x05) /*!< Charge pump current nominal value = 331uA [VCO 4966-5030]&[VCO 5519-5592] */ +#define WCP_CONF_WCP_321UA ((uint8_t)0x06) /*!< Charge pump current nominal value = 321uA [VCO 5030-5095]&[VCO 5592-5563] */ +#define WCP_CONF_WCP_312UA ((uint8_t)0x07) /*!< Charge pump current nominal value = 312uA [VCO 5095-5160]&[VCO 5563-5736] */ + + +/** + * @} + */ + + +/** @defgroup SYNT2_Register + * @{ + */ + +/** + * \brief SYNT2 register + * \code + * Read Write + * Default value: 0x84 + * 7:0 SYNT[20:13]: intermediate bits of the PLL programmable divider. + * + * \endcode + */ + +#define SYNT2_BASE ((uint8_t)0x09) /*!< SYNT[20:13], intermediate bits of the PLL programmable divider */ + +/** + * @} + */ + +/** @defgroup SYNT1_Register + * @{ + */ + +/** + * \brief SYNT1 register + * \code + * Read Write + * Default value: 0xEC + * 7:0 SYNT[12:5]: intermediate bits of the PLL programmable divider. + * + * \endcode + */ + +#define SYNT1_BASE ((uint8_t)0x0A) /*!< SYNT[12:5], intermediate bits of the PLL programmable divider */ + +/** + * @} + */ + +/** @defgroup SYNT0_Register + * @{ + */ + +/** + * \brief SYNT0 register + * \code + * Read Write + * Default value: 0x51 + * 7:3 SYNT[4:0]: lowest bits of the PLL programmable divider. + * 2:0 BS[2:0]: Synthesizer band select. This parameter selects the out-of-loop divide factor of the synthesizer + * according to the formula fxo/(B/2)/D*SYNT/2^18 + * + * BS2 | BS1 | BS0 | value of B + * --------------------------------------------------------------------------- + * 0 | 0 | 1 | 6 + * 0 | 1 | 0 | 8 + * 0 | 1 | 1 | 12 + * 1 | 0 | 0 | 16 + * 1 | 0 | 1 | 32 + * + * \endcode + */ +#define SYNT0_BASE ((uint8_t)0x0B) /*!< [7:3] -> SYNT[4:0], lowest bits of the PLL programmable divider */ + +#define SYNT0_BS_6 ((uint8_t)0x01) /*!< Synthesizer band select (out-of-loop divide factor of the synthesizer)=6 (779-956MHz) */ +#define SYNT0_BS_8 ((uint8_t)0x02) /*!< Synthesizer band select (out-of-loop divide factor of the synthesizer)=8 (387-470MHz)*/ +#define SYNT0_BS_12 ((uint8_t)0x03) /*!< Synthesizer band select (out-of-loop divide factor of the synthesizer)=12 (387-470MHz)*/ +#define SYNT0_BS_16 ((uint8_t)0x04) /*!< Synthesizer band select (out-of-loop divide factor of the synthesizer)=16 (300-348MHz)*/ +#define SYNT0_BS_32 ((uint8_t)0x05) /*!< Synthesizer band select (out-of-loop divide factor of the synthesizer)=32 (150-174MHz)*/ + +/** + * @} + */ + +/** @defgroup CHSPACE_Register + * @{ + */ + +/** + * \brief CHSPACE register + * \code + * Read Write + * Default value: 0xFC + * 7:0 CH_SPACING[7:0]: Channel spacing. From ~793Hz to ~200KHz in 793Hz steps + * (in general, frequency step is fXO/215=26MHz/215~793Hz). + * + * \endcode + */ + +#define CHSPACE_BASE ((uint8_t)0x0C) /*!< Channel spacing. From ~0.8KHz to ~200KHz in (fXO/2^15)Hz (793Hz for 26MHz XO) steps */ + +/** + * @} + */ + + + +/** @defgroup IF_OFFSET_DIG_Register + * @{ + */ + +/** + * \brief IF_OFFSET_DIG register + * \code + * Read Write + * Default value: 0xA3 + * 7:0 IF_OFFSET_DIG[7:0]: Intermediate frequency setting for the digital shift-to-baseband circuits. According to the formula: fIF=fXO*(IF_OFFSET_ANA+64)/(12*2^10)=fCLK*(IF_OFFSET_DIG+64)/(12*2^10) Hz. + * + * \endcode + */ +#define IF_OFFSET_DIG_BASE ((uint8_t)0x0D) /*!< Intermediate frequency fIF=fXO*(IF_OFFSET_ANA+64)/(12*2^10)=fCLK*(IF_OFFSET_DIG+64)/(12*2^10) Hz */ + +/** + * @} + */ + +/** @defgroup IF_OFFSET_ANA_Register + * @{ + */ + +/** + * \brief IF_OFFSET_ANA register + * \code + * Read Write + * Default value: 0xA3 + * 7:0 IF_OFFSET_ANA[7:0]: Intermediate frequency setting for the digital shift-to-baseband circuits. According to the formula: fIF=fXO*(IF_OFFSET_ANA+64)/(12*2^10)=fCLK*(IF_OFFSET_DIG+64)/(12*2^10) Hz. + * + * \endcode + */ +#define IF_OFFSET_ANA_BASE ((uint8_t)0x07) /*!< Intermediate frequency fIF=fXO*(IF_OFFSET_ANA+64)/(12*2^10)=fCLK*(IF_OFFSET_DIG+64)/(12*2^10) Hz */ + + +/** + * @} + */ + +/** @defgroup FC_OFFSET1_Register + * @{ + */ + +/** + * \brief FC_OFFSET1 registers + * \code + * Read Write + * Default value: 0xA3 + * 7:4 Reserved. + * 3:0 FC_OFFSET[11:8]: Carrier offset. This value is the higher part of a 12-bit 2s complement integer + * representing an offset in 99Hz(2) units added/subtracted to the + * carrier frequency set by registers SYNT3 SYNT0. + * This register can be used to set a fixed correction value + * obtained e.g. from crystal measurements. + * + * \endcode + */ +#define FC_OFFSET1_BASE ((uint8_t)0x0E) /*!< [3:0] -> [11:8] Carrier offset (upper part) */ + +/** + * @} + */ + + +/** @defgroup FC_OFFSET0_Register + * @{ + */ + +/** + * \brief FC_OFFSET0 registers + * \code + * Default value: 0x00 + * Read Write + * 7:0 FC_OFFSET[7:0]: Carrier offset. This value is the lower part of a 12-bit 2s complement integer + * representing an offset in 99Hz(2) units added/subtracted to the + * carrier frequency set by registers SYNT3 SYNT0. + * This register can be used to set a fixed correction value + * obtained e.g. from crystal measurements. + * + * \endcode + */ +#define FC_OFFSET0_BASE ((uint8_t)0x0F) /*!< [7:0] -> [7:0] Carrier offset (lower part). This value is a 12-bit 2s complement integer + representing an offset in fXO/2^18 (99Hz for 26 MHz XO) units added/subtracted to the carrier frequency + set by registers SYNT3 SYNT0. Range is +/-200kHz with 26 MHz XO */ +/** + * @} + */ + + +/** @defgroup PA_LEVEL_x_Registers + * @{ + */ + +/** + * \brief PA_POWER_x[8:1] registers + * \code + * Default values from 8 to 1: [0x03, 0x0E, 0x1A, 0x25, 0x35, 0x40, 0x4E, 0x00] + * Read Write + * + * 7 Reserved. + * 6:0 PA_LEVEL_(x-1)[6:0]: Output power level for x-th slot. + * \endcode + */ + +#define PA_POWER8_BASE ((uint8_t)0x10) /*!< PA Power level for 8th slot of PA ramping or ASK modulation */ +#define PA_POWER7_BASE ((uint8_t)0x11) /*!< PA Power level for 7th slot of PA ramping or ASK modulation */ +#define PA_POWER6_BASE ((uint8_t)0x12) /*!< PA Power level for 6th slot of PA ramping or ASK modulation */ +#define PA_POWER5_BASE ((uint8_t)0x13) /*!< PA Power level for 5th slot of PA ramping or ASK modulation */ +#define PA_POWER4_BASE ((uint8_t)0x14) /*!< PA Power level for 4th slot of PA ramping or ASK modulation */ +#define PA_POWER3_BASE ((uint8_t)0x15) /*!< PA Power level for 3rd slot of PA ramping or ASK modulation */ +#define PA_POWER2_BASE ((uint8_t)0x16) /*!< PA Power level for 2nd slot of PA ramping or ASK modulation */ +#define PA_POWER1_BASE ((uint8_t)0x17) /*!< PA Power level for 1st slot of PA ramping or ASK modulation */ + +/** + * @} + */ + +/** @defgroup PA_POWER_CONF_Registers + * @{ + */ + +/** + * \brief PA_POWER_CONF_Registers + * \code + * Default value:0x07 + * Read Write + * + * 7:6 CWC[1:0]: Output stage additional load capacitors bank (to be used to + * optimize the PA for different sub-bands). + * + * CWC1 | CWC0 | Total capacity in pF + * --------------------------------------------------------- + * 0 | 0 | 0 + * 0 | 1 | 1.2 + * 1 | 0 | 2.4 + * 1 | 1 | 3.6 + * + * 5 PA_RAMP_ENABLE: + * 1 - Enable the power ramping + * 0 - Disable the power ramping + * 4:3 PA_RAMP_STEP_WIDTH[1:0]: Step width in bit period + * + * PA_RAMP_STEP_WIDTH1 | PA_RAMP_STEP_WIDTH0 | PA ramping time step + * ------------------------------------------------------------------------------------------- + * 0 | 0 | 1/8 Bit period + * 0 | 1 | 2/8 Bit period + * 1 | 0 | 3/8 Bit period + * 1 | 1 | 4/8 Bit period + * + * 2:0 PA_LEVEL_MAX_INDEX[2:0]: Fixes the MAX PA LEVEL in PA ramping or ASK modulation + * + * \endcode + */ +#define PA_POWER0_BASE ((uint8_t)0x18) /*!< PA ramping settings and additional load capacitor banks used + for PA optimization in different sub bands*/ +#define PA_POWER0_CWC_MASK ((uint8_t)0x20) /*!< Output stage additional load capacitors bank */ +#define PA_POWER0_CWC_0 ((uint8_t)0x00) /*!< No additional PA load capacitor */ +#define PA_POWER0_CWC_1_2P ((uint8_t)0x40) /*!< 1.2pF additional PA load capacitor */ +#define PA_POWER0_CWC_2_4P ((uint8_t)0x80) /*!< 2.4pF additional PA load capacitor */ +#define PA_POWER0_CWC_3_6P ((uint8_t)0xC0) /*!< 3.6pF additional PA load capacitor */ +#define PA_POWER0_PA_RAMP_MASK ((uint8_t)0x20) /*!< The PA power ramping */ +#define PA_POWER0_PA_RAMP_STEP_WIDTH_MASK ((uint8_t)0x20) /*!< The step width */ +#define PA_POWER0_PA_RAMP_STEP_WIDTH_TB_8 ((uint8_t)0x00) /*!< PA ramping time step = 1/8 Bit period*/ +#define PA_POWER0_PA_RAMP_STEP_WIDTH_TB_4 ((uint8_t)0x08) /*!< PA ramping time step = 2/8 Bit period*/ +#define PA_POWER0_PA_RAMP_STEP_WIDTH_3TB_8 ((uint8_t)0x10) /*!< PA ramping time step = 3/8 Bit period*/ +#define PA_POWER0_PA_RAMP_STEP_WIDTH_TB_2 ((uint8_t)0x18) /*!< PA ramping time step = 4/8 Bit period*/ +#define PA_POWER0_PA_LEVEL_MAX_INDEX ((uint8_t)0x20) /*!< Final level for power ramping */ +#define PA_POWER0_PA_LEVEL_MAX_INDEX_0 ((uint8_t)0x00) /*!< */ +#define PA_POWER0_PA_LEVEL_MAX_INDEX_1 ((uint8_t)0x01) /*!< Fixes the MAX PA LEVEL in PA ramping or ASK modulation */ +#define PA_POWER0_PA_LEVEL_MAX_INDEX_2 ((uint8_t)0x02) /*!< */ +#define PA_POWER0_PA_LEVEL_MAX_INDEX_3 ((uint8_t)0x03) /*!< _________ */ +#define PA_POWER0_PA_LEVEL_MAX_INDEX_4 ((uint8_t)0x04) /*!< PA_LVL2 _| <--| */ +#define PA_POWER0_PA_LEVEL_MAX_INDEX_5 ((uint8_t)0x05) /*!< _| | */ +#define PA_POWER0_PA_LEVEL_MAX_INDEX_6 ((uint8_t)0x06) /*!< PA_LVL1 _| | */ +#define PA_POWER0_PA_LEVEL_MAX_INDEX_7 ((uint8_t)0x07) /*!< PA_LVL0 _| MAX_INDEX- */ + + + +/** + * @} + */ + + +/** @defgroup MOD1_Register + * @{ + */ + +/** + * \brief MOD1 register + * \code + * Read Write + * Default value: 0x83 + * 7:0 DATARATE_M[7:0]: The Mantissa of the specified data rate + * + * \endcode + */ +#define MOD1_BASE ((uint8_t)0x1A) /*!< The Mantissa of the specified data rate */ + +/** + * @} + */ + +/** @defgroup MOD0_Register + * @{ + */ + +/** + * \brief MOD0 register + * \code + * Read Write + * Default value: 0x1A + * 7 CW: 1 - CW Mode enabled - enables the generation of a continous wave carrier without any modulation + * 0 - CW Mode disabled + * + * 6 BT_SEL: Select BT value for GFSK + * 1 - BT=0.5 + * 0 - BT=1 + * + * 5:4 MOD_TYPE[1:0]: Modulation type + * + * + * MOD_TYPE1 | MOD_TYPE0 | Modulation + * --------------------------------------------------------- + * 0 | 0 | 2-FSK,MSK + * 0 | 1 | GFSK,GMSK + * 1 | 0 | ASK/OOK + * + * 3:0 DATARATE_E[3:0]: The Exponent of the specified data rate + * + * \endcode + */ +#define MOD0_BASE ((uint8_t)0x1B) /*!< Modulation Settings, Exponent of the specified data rate, CW mode*/ + +#define MOD0_MOD_TYPE_2_FSK ((uint8_t)0x00) /*!< Modulation type 2-FSK (MSK if the frequency deviation is identical to a quarter of the data rate) */ +#define MOD0_MOD_TYPE_GFSK ((uint8_t)0x10) /*!< Modulation type GFSK (GMSK if the frequency deviation is identical to a quarter of the data rate) */ +#define MOD0_MOD_TYPE_ASK ((uint8_t)0x20) /*!< Modulation type ASK (OOK the PA is switched off for symbol "0") */ +#define MOD0_MOD_TYPE_MSK ((uint8_t)0x00) /*!< Modulation type MSK (the frequency deviation must be identical to a quarter of the data rate) */ +#define MOD0_MOD_TYPE_GMSK ((uint8_t)0x10) /*!< Modulation type GMSK (the frequency deviation must be identical to a quarter of the data rate) */ +#define MOD0_BT_SEL_BT_MASK ((uint8_t)0x00) /*!< Select the BT = 1 or BT = 0.5 valid only for GFSK or GMSK modulation*/ +#define MOD0_CW ((uint8_t)0x80) /*!< Set the Continous Wave (no modulation) transmit mode */ + +/** + * @} + */ + + +/** @defgroup FDEV0_Register + * @{ + */ + +/** + * \brief FDEV0 register + * \code + * Read Write + * Default value: 0x45 + * 7:4 FDEV_E[3:0]: Exponent of the frequency deviation (allowed values from 0 to 9) + * + * 3 CLOCK_REC_ALGO_SEL: Select PLL or DLL mode for clock recovery + * 1 - DLL mode + * 0 - PLL mode + * + * 2:0 FDEV_M[1:0]: Mantissa of the frequency deviation (allowed values from 0 to 7) + * + * + * \endcode + */ +#define FDEV0_BASE ((uint8_t)0x1C) /*!< Sets the Mantissa and exponent of frequency deviation (frequency separation/2) + and PLL or DLL alogrithm from clock recovery in RX digital demod*/ +#define FDEV0_CLOCK_REG_ALGO_SEL_MASK ((uint8_t)0x08) /*!< Can be DLL or PLL algorithm for clock recovery in RX digital demod (see CLOCKREC reg) */ +#define FDEV0_CLOCK_REG_ALGO_SEL_PLL ((uint8_t)0x00) /*!< Sets PLL alogrithm for clock recovery in RX digital demod (see CLOCKREC reg) */ +#define FDEV0_CLOCK_REG_ALGO_SEL_DLL ((uint8_t)0x08) /*!< Sets DLL alogrithm for clock recovery in RX digital demod (see CLOCKREC reg) */ + +/** + * @} + */ + +/** @defgroup CHFLT_Register + * @{ + */ + +/** + * \brief CHFLT register + * \code + * Read Write + * Default value: 0x23 + * 7:4 CHFLT_M[3:0]: Mantissa of the channel filter BW (allowed values from 0 to 8) + * + * 3:0 CHFLT_E[3:0]: Exponent of the channel filter BW (allowed values from 0 to 9) + * + * M\E | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | + * -----+-------+-------+-------+-------+------+------+------+-----+-----+-----+ + * 0 | 800.1 | 450.9 | 224.7 | 112.3 | 56.1 | 28.0 | 14.0 | 7.0 | 3.5 | 1.8 | + * 1 | 795.1 | 425.9 | 212.4 | 106.2 | 53.0 | 26.5 | 13.3 | 6.6 | 3.3 | 1.7 | + * 2 | 768.4 | 403.2 | 201.1 | 100.5 | 50.2 | 25.1 | 12.6 | 6.3 | 3.1 | 1.6 | + * 3 | 736.8 | 380.8 | 190.0 | 95.0 | 47.4 | 23.7 | 11.9 | 5.9 | 3.0 | 1.5 | + * 4 | 705.1 | 362.1 | 180.7 | 90.3 | 45.1 | 22.6 | 11.3 | 5.6 | 2.8 | 1.4 | + * 5 | 670.9 | 341.7 | 170.6 | 85.3 | 42.6 | 21.3 | 10.6 | 5.3 | 2.7 | 1.3 | + * 6 | 642.3 | 325.4 | 162.4 | 81.2 | 40.6 | 20.3 | 10.1 | 5.1 | 2.5 | 1.3 | + * 7 | 586.7 | 294.5 | 147.1 | 73.5 | 36.7 | 18.4 | 9.2 | 4.6 | 2.3 | 1.2 | + * 8 | 541.4 | 270.3 | 135.0 | 67.5 | 33.7 | 16.9 | 8.4 | 4.2 | 2.1 | 1.1 | + * + * \endcode + */ +#define CHFLT_BASE ((uint8_t)0x1D) /*!< RX Channel Filter Bandwidth */ + +#define CHFLT_800_1 ((uint8_t)0x00) /*!< RX Channel Filter Bandwidth = 800.1 kHz */ +#define CHFLT_795_1 ((uint8_t)0x10) /*!< RX Channel Filter Bandwidth = 795.1 kHz */ +#define CHFLT_768_4 ((uint8_t)0x20) /*!< RX Channel Filter Bandwidth = 768.4 kHz */ +#define CHFLT_736_8 ((uint8_t)0x30) /*!< RX Channel Filter Bandwidth = 736.8 kHz */ +#define CHFLT_705_1 ((uint8_t)0x40) /*!< RX Channel Filter Bandwidth = 705.1 kHz */ +#define CHFLT_670_9 ((uint8_t)0x50) /*!< RX Channel Filter Bandwidth = 670.9 kHz */ +#define CHFLT_642_3 ((uint8_t)0x60) /*!< RX Channel Filter Bandwidth = 642.3 kHz */ +#define CHFLT_586_7 ((uint8_t)0x70) /*!< RX Channel Filter Bandwidth = 586.7 kHz */ +#define CHFLT_541_4 ((uint8_t)0x80) /*!< RX Channel Filter Bandwidth = 541.4 kHz */ +#define CHFLT_450_9 ((uint8_t)0x01) /*!< RX Channel Filter Bandwidth = 450.9 kHz */ +#define CHFLT_425_9 ((uint8_t)0x11) /*!< RX Channel Filter Bandwidth = 425.9 kHz */ +#define CHFLT_403_2 ((uint8_t)0x21) /*!< RX Channel Filter Bandwidth = 403.2 kHz */ +#define CHFLT_380_8 ((uint8_t)0x31) /*!< RX Channel Filter Bandwidth = 380.8 kHz */ +#define CHFLT_362_1 ((uint8_t)0x41) /*!< RX Channel Filter Bandwidth = 362.1 kHz */ +#define CHFLT_341_7 ((uint8_t)0x51) /*!< RX Channel Filter Bandwidth = 341.7 kHz */ +#define CHFLT_325_4 ((uint8_t)0x61) /*!< RX Channel Filter Bandwidth = 325.4 kHz */ +#define CHFLT_294_5 ((uint8_t)0x71) /*!< RX Channel Filter Bandwidth = 294.5 kHz */ +#define CHFLT_270_3 ((uint8_t)0x81) /*!< RX Channel Filter Bandwidth = 270.3 kHz */ +#define CHFLT_224_7 ((uint8_t)0x02) /*!< RX Channel Filter Bandwidth = 224.7 kHz */ +#define CHFLT_212_4 ((uint8_t)0x12) /*!< RX Channel Filter Bandwidth = 212.4 kHz */ +#define CHFLT_201_1 ((uint8_t)0x22) /*!< RX Channel Filter Bandwidth = 201.1 kHz */ +#define CHFLT_190 ((uint8_t)0x32) /*!< RX Channel Filter Bandwidth = 190.0 kHz */ +#define CHFLT_180_7 ((uint8_t)0x42) /*!< RX Channel Filter Bandwidth = 180.7 kHz */ +#define CHFLT_170_6 ((uint8_t)0x52) /*!< RX Channel Filter Bandwidth = 170.6 kHz */ +#define CHFLT_162_4 ((uint8_t)0x62) /*!< RX Channel Filter Bandwidth = 162.4 kHz */ +#define CHFLT_147_1 ((uint8_t)0x72) /*!< RX Channel Filter Bandwidth = 147.1 kHz */ +#define CHFLT_135 ((uint8_t)0x82) /*!< RX Channel Filter Bandwidth = 135.0 kHz */ +#define CHFLT_112_3 ((uint8_t)0x03) /*!< RX Channel Filter Bandwidth = 112.3 kHz */ +#define CHFLT_106_2 ((uint8_t)0x13) /*!< RX Channel Filter Bandwidth = 106.2 kHz */ +#define CHFLT_100_5 ((uint8_t)0x23) /*!< RX Channel Filter Bandwidth = 100.5 kHz */ +#define CHFLT_95 ((uint8_t)0x33) /*!< RX Channel Filter Bandwidth = 95.0 kHz */ +#define CHFLT_90_3 ((uint8_t)0x43) /*!< RX Channel Filter Bandwidth = 90.3 kHz */ +#define CHFLT_85_3 ((uint8_t)0x53) /*!< RX Channel Filter Bandwidth = 85.3 kHz */ +#define CHFLT_81_2 ((uint8_t)0x63) /*!< RX Channel Filter Bandwidth = 81.2 kHz */ +#define CHFLT_73_5 ((uint8_t)0x73) /*!< RX Channel Filter Bandwidth = 73.5 kHz */ +#define CHFLT_67_5 ((uint8_t)0x83) /*!< RX Channel Filter Bandwidth = 67.5 kHz */ +#define CHFLT_56_1 ((uint8_t)0x04) /*!< RX Channel Filter Bandwidth = 56.1 kHz */ +#define CHFLT_53 ((uint8_t)0x14) /*!< RX Channel Filter Bandwidth = 53.0 kHz */ +#define CHFLT_50_2 ((uint8_t)0x24) /*!< RX Channel Filter Bandwidth = 50.2 kHz */ +#define CHFLT_47_4 ((uint8_t)0x34) /*!< RX Channel Filter Bandwidth = 47.4 kHz */ +#define CHFLT_45_1 ((uint8_t)0x44) /*!< RX Channel Filter Bandwidth = 45.1 kHz */ +#define CHFLT_42_6 ((uint8_t)0x54) /*!< RX Channel Filter Bandwidth = 42.6 kHz */ +#define CHFLT_40_6 ((uint8_t)0x64) /*!< RX Channel Filter Bandwidth = 40.6 kHz */ +#define CHFLT_36_7 ((uint8_t)0x74) /*!< RX Channel Filter Bandwidth = 36.7 kHz */ +#define CHFLT_33_7 ((uint8_t)0x84) /*!< RX Channel Filter Bandwidth = 33.7 kHz */ +#define CHFLT_28 ((uint8_t)0x05) /*!< RX Channel Filter Bandwidth = 28.0 kHz */ +#define CHFLT_26_5 ((uint8_t)0x15) /*!< RX Channel Filter Bandwidth = 26.5 kHz */ +#define CHFLT_25_1 ((uint8_t)0x25) /*!< RX Channel Filter Bandwidth = 25.1 kHz */ +#define CHFLT_23_7 ((uint8_t)0x35) /*!< RX Channel Filter Bandwidth = 23.7 kHz */ +#define CHFLT_22_6 ((uint8_t)0x45) /*!< RX Channel Filter Bandwidth = 22.6 kHz */ +#define CHFLT_21_3 ((uint8_t)0x55) /*!< RX Channel Filter Bandwidth = 21.3 kHz */ +#define CHFLT_20_3 ((uint8_t)0x65) /*!< RX Channel Filter Bandwidth = 20.3 kHz */ +#define CHFLT_18_4 ((uint8_t)0x75) /*!< RX Channel Filter Bandwidth = 18.4 kHz */ +#define CHFLT_16_9 ((uint8_t)0x85) /*!< RX Channel Filter Bandwidth = 16.9 kHz */ +#define CHFLT_14 ((uint8_t)0x06) /*!< RX Channel Filter Bandwidth = 14.0 kHz */ +#define CHFLT_13_3 ((uint8_t)0x16) /*!< RX Channel Filter Bandwidth = 13.3 kHz */ +#define CHFLT_12_6 ((uint8_t)0x26) /*!< RX Channel Filter Bandwidth = 12.6 kHz */ +#define CHFLT_11_9 ((uint8_t)0x36) /*!< RX Channel Filter Bandwidth = 11.9 kHz */ +#define CHFLT_11_3 ((uint8_t)0x46) /*!< RX Channel Filter Bandwidth = 11.3 kHz */ +#define CHFLT_10_6 ((uint8_t)0x56) /*!< RX Channel Filter Bandwidth = 10.6 kHz */ +#define CHFLT_10_1 ((uint8_t)0x66) /*!< RX Channel Filter Bandwidth = 10.1 kHz */ +#define CHFLT_9_2 ((uint8_t)0x76) /*!< RX Channel Filter Bandwidth = 9.2 kHz */ +#define CHFLT_8_4 ((uint8_t)0x86) /*!< RX Channel Filter Bandwidth = 8.4 kHz */ +#define CHFLT_7 ((uint8_t)0x07) /*!< RX Channel Filter Bandwidth = 7.0 kHz */ +#define CHFLT_6_6 ((uint8_t)0x17) /*!< RX Channel Filter Bandwidth = 6.6 kHz */ +#define CHFLT_6_3 ((uint8_t)0x27) /*!< RX Channel Filter Bandwidth = 6.3 kHz */ +#define CHFLT_5_9 ((uint8_t)0x37) /*!< RX Channel Filter Bandwidth = 5.9 kHz */ +#define CHFLT_5_6 ((uint8_t)0x47) /*!< RX Channel Filter Bandwidth = 5.6 kHz */ +#define CHFLT_5_3 ((uint8_t)0x57) /*!< RX Channel Filter Bandwidth = 5.3 kHz */ +#define CHFLT_5_1 ((uint8_t)0x67) /*!< RX Channel Filter Bandwidth = 5.1 kHz */ +#define CHFLT_4_6 ((uint8_t)0x77) /*!< RX Channel Filter Bandwidth = 4.6 kHz */ +#define CHFLT_4_2 ((uint8_t)0x87) /*!< RX Channel Filter Bandwidth = 4.2 kHz */ +#define CHFLT_3_5 ((uint8_t)0x08) /*!< RX Channel Filter Bandwidth = 3.5 kHz */ +#define CHFLT_3_3 ((uint8_t)0x18) /*!< RX Channel Filter Bandwidth = 3.3 kHz */ +#define CHFLT_3_1 ((uint8_t)0x28) /*!< RX Channel Filter Bandwidth = 3.1 kHz */ +#define CHFLT_3 ((uint8_t)0x38) /*!< RX Channel Filter Bandwidth = 3.0 kHz */ +#define CHFLT_2_8 ((uint8_t)0x48) /*!< RX Channel Filter Bandwidth = 2.8 kHz */ +#define CHFLT_2_7 ((uint8_t)0x58) /*!< RX Channel Filter Bandwidth = 2.7 kHz */ +#define CHFLT_2_5 ((uint8_t)0x68) /*!< RX Channel Filter Bandwidth = 2.5 kHz */ +#define CHFLT_2_3 ((uint8_t)0x78) /*!< RX Channel Filter Bandwidth = 2.3 kHz */ +#define CHFLT_2_1 ((uint8_t)0x88) /*!< RX Channel Filter Bandwidth = 2.1 kHz */ +#define CHFLT_1_8 ((uint8_t)0x09) /*!< RX Channel Filter Bandwidth = 1.8 kHz */ +#define CHFLT_1_7 ((uint8_t)0x19) /*!< RX Channel Filter Bandwidth = 1.7 kHz */ +#define CHFLT_1_6 ((uint8_t)0x29) /*!< RX Channel Filter Bandwidth = 1.6 kHz */ +#define CHFLT_1_5 ((uint8_t)0x39) /*!< RX Channel Filter Bandwidth = 1.5 kHz */ +#define CHFLT_1_4 ((uint8_t)0x49) /*!< RX Channel Filter Bandwidth = 1.4 kHz */ +#define CHFLT_1_3a ((uint8_t)0x59) /*!< RX Channel Filter Bandwidth = 1.3 kHz */ +#define CHFLT_1_3 ((uint8_t)0x69) /*!< RX Channel Filter Bandwidth = 1.3 kHz */ +#define CHFLT_1_2 ((uint8_t)0x79) /*!< RX Channel Filter Bandwidth = 1.2 kHz */ +#define CHFLT_1_1 ((uint8_t)0x89) /*!< RX Channel Filter Bandwidth = 1.1 kHz */ + +/** + * @} + */ + +/** @defgroup AFC2_Register + * @{ + */ + +/** + * \brief AFC2 register + * \code + * Read Write + * Default value: 0x48 + * 7 AFC Freeze on Sync: Freeze AFC correction upon sync word detection. + * 1 - AFC Freeze enabled + * 0 - AFC Freeze disabled + * + * 6 AFC Enabled: Enable AFC + * 1 - AFC enabled + * 0 - AFC disabled + * + * 5 AFC Mode: Select AFC mode + * 1 - AFC Loop closed on 2nd conversion stage. + * 0 - AFC Loop closed on slicer + * + * 4:0 AFC PD leakage[4:0]: Peak detector leakage. This parameter sets the decay speed of the min/max frequency peak detector (AFC2 register), + * the range allowed is 0..31 (0 - no leakage, 31 - high leakage). The recommended value for this parameter is 4. + * + * \endcode + */ +#define AFC2_BASE ((uint8_t)0x1E) /*!< Automatic frequency compensation algorithm parameters (FSK/GFSK/MSK)*/ + +#define AFC2_AFC_FREEZE_ON_SYNC_MASK ((uint8_t)0x80) /*!< The frequency correction value is frozen when SYNC word is detected */ +#define AFC2_AFC_MASK ((uint8_t)0x40) /*!< Mask of Automatic Frequency Correction */ +#define AFC2_AFC_MODE_MASK ((uint8_t)0x20) /*!< Automatic Frequency Correction can be in Main MODE or Auxiliary MODE*/ +#define AFC2_AFC_MODE_SLICER ((uint8_t)0x00) /*!< Automatic Frequency Correction Main MODE */ +#define AFC2_AFC_MODE_MIXER ((uint8_t)0x20) /*!< Automatic Frequency Correction Auxiliary MODE */ + +/** + * @} + */ + +/** @defgroup AFC1_Register + * @{ + */ + +/** + * \brief AFC1 register + * \code + * Read Write + * Default value: 0x18 + * 7:0 AFC_FAST_PERIOD: Length of the AFC fast period. this parameter sets the length of the fast period in number of samples (AFC1 register), the range allowed + * is 0..255. The recommended setting for this parameter is such that the fast period equals the preamble length. Since the + * algorithm operates typically on 2 samples per symbol, the programmed value should be twice the number of preamble + * symbols. + * + * \endcode + */ +#define AFC1_BASE ((uint8_t)0x1F) /*!< Length of the AFC fast period */ + +/** + * @} + */ + +/** @defgroup AFC0_Register + * @{ + */ + +/** + * \brief AFC0 register + * \code + * Read Write + * Default value: 0x25 + * 7:4 AFC_FAST_GAIN_LOG2[3:0]: AFC loop gain in fast mode (2's log) + * + * 3:0 AFC_SLOW_GAIN_LOG2[3:0]: AFC loop gain in slow mode (2's log) + * + * \endcode + */ +#define AFC0_BASE ((uint8_t)0x20) /*!< AFC loop gain in fast and slow modes (2's log) */ + +/** + * @} + */ + +/** @defgroup CLOCKREC_Register + * @{ + */ + +/** + * \brief CLOCKREC register + * \code + * Read Write + * Default value: 0x58 + * + * 7:5 CLK_REC_P_GAIN [2:0]: Clock recovery loop gain (log2) + * + * 4 PSTFLT_LEN: Set Postfilter length + * 1 - 16 symbols + * 0 - 8 symbols + * + * 3:0 CLK_REC_I_GAIN[3:0]: Integral gain for the clock recovery loop + * \endcode + */ + +#define CLOCKREC_BASE ((uint8_t)0x23) /*!< Gain of clock recovery loop - Postfilter length 0-8 symbols, 1-16 symbols */ + +/** + * @} + */ + +/** @defgroup AGCCTRL2_Register + * @{ + */ + +/** + * \brief AGCCTRL2 register + * \code + * Read Write + * Default value: 0x22 + * + * 7 Reserved + * + * 6 FREEZE_ON_STEADY: Enable freezing on steady state + * 1 - Enable + * 0 - Disable + * + * 5 FREEZE_ON_SYNC: Enable freezing on sync detection + * 1 - Enable + * 0 - Disable + * + * 4 START_MAX_ATTENUATION: Start with max attenuation + * 1 - Enable + * 0 - Disable + * + * 3:0 MEAS_TIME[3:0]: Measure time during which the signal peak is detected (according to the formula 12/fxo*2^MEAS_TIME) + * \endcode + */ +#define AGCCTRL2_BASE ((uint8_t)0x24) /*!< AGC freeze strategy, AGC attenuation strategy, AGC measure time */ + +#define AGCCTRL2_FREEZE_ON_STEADY_MASK ((uint8_t)0x40) /*!< The attenuation settings will be frozen as soon as signal level + is betweeen min and max treshold (see AGCCTRL1) */ +#define AGCCTRL2_FREEZE_ON_SYNC_MASK ((uint8_t)0x20) /*!< The attenuation settings will be frozen as soon sync word is detected */ +#define AGCCTRL2_START_MAX_ATTENUATION_MASK ((uint8_t)0x10) /*!< The AGC algorithm can start with MAX attenuation or MIN attenuation */ + +/** + * @} + */ + +/** @defgroup AGCCTRL1_Register + * @{ + */ + +/** + * \brief AGCCTRL1 register + * \code + * Read Write + * Default value: 0x65 + * + * 7:4 THRESHOLD_HIGH[3:0]: High threshold for the AGC + * + * 3:0 THRESHOLD_LOW[3:0]: Low threshold for the AGC + * \endcode + */ +#define AGCCTRL1_BASE ((uint8_t)0x25) /*!< Sets low and high threshold for AGC */ + +/** + * @} + */ + +/** @defgroup AGCCTRL0_Register + * @{ + */ + +/** + * \brief AGCCTRL0 register + * \code + * Read Write + * Default value: 0x8A + * + * 7 AGC S_ENABLE: Enable AGC + * 1 - Enable + * 0 - Disable + * + * 6 AGC_MODE: Set linear-Binary AGC mode + * 1 - Enable + * 0 - Disable + * + * 5:0 HOLD_TIME[5:0]: Hold time after gain adjustment according to formula 12/fxo*HOLD_TIME + * \endcode + */ +#define AGCCTRL0_BASE ((uint8_t)0x26) /*!< Enables AGC, set AGC algo between linear/binary mode, set hold time + to account signal propagation through RX chain */ +#define AGCCTRL0_AGC_MASK ((uint8_t)0x80) /*!< AGC on/off */ +#define AGCCTRL0_AGC_MODE_MASK ((uint8_t)0x40) /*!< AGC search correct attenuation in binary mode or sequential mode */ +#define AGCCTRL0_AGC_MODE_LINEAR ((uint8_t)0x00) /*!< AGC search correct attenuation in sequential mode (recommended) */ +#define AGCCTRL0_AGC_MODE_BINARY ((uint8_t)0x40) /*!< AGC search correct attenuation in binary mode */ + +/** + * @} + */ + +/** @defgroup CHNUM_Register + * @{ + */ + +/** + * \brief CHNUM registers + * \code + * Default value: 0x00 + * Read Write + * 7:0 CH_NUM[7:0]: Channel number. This value is multiplied by the channel spacing and added to the + * synthesizer base frequency to generate the actual RF carrier frequency. + * \endcode + */ +#define CHNUM_BASE ((uint8_t)0x6C) /*!< Channel number. This value is multiplied by the channel + spacing and added to the synthesizer base frequency to generate the actual RF carrier frequency */ +/** + * @} + */ + +/** @defgroup AFC_CORR_Register + * @{ + */ + +/** + * \brief AFC_CORR registers + * \code + * Default value: 0x00 + * Read + * + * 7:0 AFC_CORR[7:0]: AFC word of the received packet + * \endcode + */ +#define AFC_CORR_BASE ((uint8_t)(0xC4)) /*!< AFC word of the received packet */ + +/** + * @} + */ + +/** + * @} + */ + + +/** @defgroup Packet_Configuration_Registers + * @{ + */ + +/** @defgroup PCKTCTRL4_Register + * @{ + */ + +/** + * \brief PCKTCTRL4 register + * \code + * Read Write + * Default value: 0x00 + * + * 7:5 NOT_USED. + * + * 4:3 ADDRESS_LEN[1:0]: length of address field in bytes + * + * 2:0 control_len[2:0]: length of control field in bytes + * \endcode + */ +#define PCKTCTRL4_BASE ((uint8_t)0x30) /*!< lenghts of address and control field */ + +#define PCKTCTRL4_ADDRESS_LEN_MASK ((uint8_t)0x18) +#define PCKTCTRL4_CONTROL_LEN_MASK ((uint8_t)0x07) + +/** + * @} + */ + +/** @defgroup PCKTCTRL3_Register + * @{ + */ + +/** + * \brief PCKTCTRL3 register + * \code + * Read Write + * Default value: 0x07 + * + * 7:6 PCKT_FRMT[1:0]: format of packet + * + * PCKT_FRMT1 | PCKT_FRMT0 | Format + * ---------------------------------------------------------------------- + * 0 | 0 | BASIC + * 1 | 0 | MBUS + * 1 | 1 | STACK + * + * 5:4 RX_MODE[1:0]: length of address 0x30 field in bytes + * + * RX_MODE1 | RX_MODE0 | Rx Mode + * -------------------------------------------------------------------- + * 0 | 0 | normal + * 0 | 1 | direct through FIFO + * 1 | 0 | direct through GPIO + * + * 3:0 LEN_WID[3:0]: length of length field in bits + * \endcode + */ +#define PCKTCTRL3_BASE ((uint8_t)0x31) /*!< packet format, RX mode, lenght of length field */ + +#define PCKTCTRL3_PCKT_FRMT_BASIC ((uint8_t)0x00) /*!< Basic Packet Format */ +#define PCKTCTRL3_PCKT_FRMT_MBUS ((uint8_t)0x80) /*!< Wireless M-BUS Packet Format */ +#define PCKTCTRL3_PCKT_FRMT_STACK ((uint8_t)0xC0) /*!< STack Packet Format */ + +#define PCKTCTRL3_RX_MODE_NORMAL ((uint8_t)0x00) /*!< Normal RX Mode */ +#define PCKTCTRL3_RX_MODE_DIRECT_FIFO ((uint8_t)0x10) /*!< RX Direct Mode; data available through FIFO */ +#define PCKTCTRL3_RX_MODE_DIRECT_GPIO ((uint8_t)0x20) /*!< RX Direct Mode; data available through selected GPIO */ + +#define PCKTCTRL3_PKT_FRMT_MASK ((uint8_t)0xC0) +#define PCKTCTRL3_RX_MODE_MASK ((uint8_t)0x30) +#define PCKTCTRL3_LEN_WID_MASK ((uint8_t)0x0F) + +/** + * @} + */ + +/** @defgroup PCKTCTRL2_Register + * @{ + */ + +/** + * \brief PCKTCTRL2 register + * \code + * Read Write + * Default value: 0x1E + * + * 7:3 PREAMBLE_LENGTH[4:0]: length of preamble field in bytes (0..31) + * + * + * 2:1 SYNC_LENGTH[1:0]: length of sync field in bytes + * + * + * 0 FIX_VAR_LEN: fixed/variable packet length + * 1 - Variable + * 0 - Fixed + * \endcode + */ +#define PCKTCTRL2_BASE ((uint8_t)0x32) /*!< length of preamble and sync fields (in bytes), fix or variable packet length */ + +#define PCKTCTRL2_FIX_VAR_LEN_MASK ((uint8_t)0x01) /*!< Enable/disable the length mode */ +#define PCKTCTRL2_PREAMBLE_LENGTH_MASK ((uint8_t)0xF8) +#define PCKTCTRL2_SYNC_LENGTH_MASK ((uint8_t)0x06) + +/** + * @} + */ + +/** @defgroup PCKTCTRL1_Register + * @{ + */ + +/** + * \brief PCKTCTRL1 register + * \code + * Read Write + * Default value: 0x20 + * + * 7:5 CRC_MODE[2:0]: CRC type (0, 8, 16, 24 bits) + * + * CRC_MODE2 | CRC_MODE1 | CRC_MODE0 | CRC Mode (n. bits - poly) + * ------------------------------------------------------------------------------------------------- + * 0 | 0 | 1 | 8 - 0x07 + * 0 | 1 | 0 | 16 - 0x8005 + * 0 | 1 | 1 | 16 - 0x1021 + * 1 | 0 | 0 | 24 - 0x864CBF + * + * 4 WHIT_EN[0]: Enable Whitening + * 1 - Enable + * 0 - Disable + * + * 3:2 TX_SOURCE[1:0]: length of sync field in bytes + * + * TX_SOURCE1 | TX_SOURCE0 | Tx Mode + * -------------------------------------------------------------------- + * 0 | 0 | normal + * 0 | 1 | direct through FIFO + * 1 | 0 | direct through GPIO + * 1 | 1 | pn9 + * + * 1 NOT_USED + * + * 0 FEC_EN: enable FEC + * 1 - FEC in TX , Viterbi decoding in RX + * 0 - Disabled + * \endcode + */ +#define PCKTCTRL1_BASE ((uint8_t)0x33) /*!< CRC type, whitening enable, TX mode */ + +#define PCKTCTRL1_FEC_MASK ((uint8_t)0x01) /*!< Enable/disable the Forward Error Correction */ +#define PCKTCTRL1_TX_SOURCE_MASK ((uint8_t)0x0C) /*!< TX source mode */ +#define PCKTCTRL1_CRC_MODE_MASK ((uint8_t)0xE0) /*!< CRC type */ +#define PCKTCTRL1_WHIT_MASK ((uint8_t)0x10) /*!< Enable/disable the Whitening */ + +/** + * @} + */ + + + +/** @defgroup PCKTLEN1_Register + * @{ + */ + +/** + * \brief PCKTLEN1 register + * \code + * Read Write + * Default value: 0x00 + * + * 7:0 pktlen1[7:0]: lenght of packet in bytes (upper field) LENGHT/256 + * \endcode + */ +#define PCKTLEN1_BASE ((uint8_t)0x34) /*!< lenght of packet in bytes (upper field) */ + +/** + * @} + */ + +/** @defgroup PCKTLEN0_Register + * @{ + */ + +/** + * \brief PCKTLEN0 register + * \code + * Read Write + * Default value: 0x14 + * + * 7:0 pktlen0[7:0]: lenght of packet in bytes (lower field) LENGHT%256 + * \endcode + */ +#define PCKTLEN0_BASE ((uint8_t)0x35) /*!< lenght of packet in bytes (lower field) [PCKTLEN=PCKTLEN1x256+PCKTLEN0]*/ + +/** + * @} + */ + +/** @defgroup SYNCx_Registers + * @{ + */ +/** + * \brief SYNCx[4:1] Registers + * \code + * Read Write + * Default value: 0x88 + * + * 7:0 SYNCx[7:0]: xth sync word + * \endcode + */ +#define SYNC4_BASE ((uint8_t)0x36) /*!< Sync word 4 */ +#define SYNC3_BASE ((uint8_t)0x37) /*!< Sync word 3 */ +#define SYNC2_BASE ((uint8_t)0x38) /*!< Sync word 2 */ +#define SYNC1_BASE ((uint8_t)0x39) /*!< Sync word 1 */ + +/** + * @} + */ + + +/** @defgroup MBUS_PRMBL_Register + * @{ + */ + +/** + * \brief MBUS_PRMBL register + * \code + * Read Write + * Default value: 0x20 + * + * 7:0 MBUS_PRMBL[7:0]: MBUS preamble control + * \endcode + */ +#define MBUS_PRMBL_BASE ((uint8_t)0x3B) /*!< MBUS preamble lenght (in 01 bit pairs) */ + +/** + * @} + */ + + +/** @defgroup MBUS_PSTMBL_Register + * @{ + */ + +/** + * \brief MBUS_PSTMBL register + * \code + * Read Write + * Default value: 0x20 + * + * 7:0 MBUS_PSTMBL[7:0]: MBUS postamble control + * \endcode + */ +#define MBUS_PSTMBL_BASE ((uint8_t)0x3C) /*!< MBUS postamble length (in 01 bit pairs) */ + +/** + * @} + */ + +/** @defgroup MBUS_CTRL_Register + * @{ + */ + +/** + * \brief MBUS_CTRL register + * \code + * Read Write + * Default value: 0x00 + * + * 7:4 NOT_USED + * + * 3:1 MBUS_SUBMODE[2:0]: MBUS submode (allowed values are 0,1,3,5) + * + * 0 NOT_USED + * \endcode + */ +#define MBUS_CTRL_BASE ((uint8_t)0x3D) /*!< MBUS sub-modes (S1, S2 short/long header, T1, T2, R2) */ + +#define MBUS_CTRL_MBUS_SUBMODE_S1_S2L ((uint8_t)0x00) /*!< MBUS sub-modes S1 & S2L, header lenght min 279, sync 0x7696, Manchester */ +#define MBUS_CTRL_MBUS_SUBMODE_S2_S1M_T2_OTHER ((uint8_t)0x02) /*!< MBUS sub-modes S2, S1-m, T2 (only other to meter) short header, header lenght min 15, sync 0x7696, Manchester */ +#define MBUS_CTRL_MBUS_SUBMODE_T1_T2_METER ((uint8_t)0x06) /*!< MBUS sub-modes T1, T2 (only meter to other), header lenght min 19, sync 0x3D, 3 out of 6 */ +#define MBUS_CTRL_MBUS_SUBMODE_R2 ((uint8_t)0x0A) /*!< MBUS sub-mode R2, header lenght min 39, sync 0x7696, Manchester */ + +/** + * @} + */ + + + +/** @defgroup PCKT_FLT_GOALS_CONTROLx_MASK_Registers + * @{ + */ + +/** + * \brief PCKT_FLT_GOALS_CONTROLx_MASK registers + * \code + * Default value: 0x00 + * Read Write + * 7:0 CONTROLx_MASK[7:0]: All 0s - no filtering + * + * \endcode + */ +#define PCKT_FLT_GOALS_CONTROL0_MASK_BASE ((uint8_t)0x42) /*!< Packet control field #3 mask, all 0s -> no filtering */ + +#define PCKT_FLT_GOALS_CONTROL1_MASK_BASE ((uint8_t)0x43) /*!< Packet control field #2 mask, all 0s -> no filtering */ + +#define PCKT_FLT_GOALS_CONTROL2_MASK_BASE ((uint8_t)0x44) /*!< Packet control field #1 mask, all 0s -> no filtering */ + +#define PCKT_FLT_GOALS_CONTROL3_MASK_BASE ((uint8_t)0x45) /*!< Packet control field #0 mask, all 0s -> no filtering */ + +/** + * @} + */ + +/** @defgroup PCKT_FLT_GOALS_CONTROLx_FIELD_Registers + * @{ + */ + +/** + * \brief PCKT_FLT_GOALS_CONTROLx_FIELD registers + * \code + * Default value: 0x00 + * Read Write + * 7:0 CONTROLx_FIELD[7:0]: Control field (byte x) to be used as reference + * + * \endcode + */ +#define PCKT_FLT_GOALS_CONTROL0_FIELD_BASE ((uint8_t)0x46) /*!< Control field (byte #3) */ + +#define PCKT_FLT_GOALS_CONTROL1_FIELD_BASE ((uint8_t)0x47) /*!< Control field (byte #2) */ + +#define PCKT_FLT_GOALS_CONTROL2_FIELD_BASE ((uint8_t)0x48) /*!< Control field (byte #1) */ + +#define PCKT_FLT_GOALS_CONTROL3_FIELD_BASE ((uint8_t)0x49) /*!< Control field (byte #0) */ + +/** + * @} + */ + +/** @defgroup PCKT_FLT_GOALS_SOURCE_MASK_Register + * @{ + */ + +/** + * \brief PCKT_FLT_GOALS_SOURCE_MASK register + * \code + * Default value: 0x00 + * Read Write + * 7:0 RX_SOURCE_MASK[7:0]: For received packet only: all 0s - no filtering + * + * \endcode + */ +#define PCKT_FLT_GOALS_SOURCE_MASK_BASE ((uint8_t)0x4A) /*!< Source address mask, valid in RX mode */ + +/** + * @} + */ + +/** @defgroup PCKT_FLT_GOALS_SOURCE_ADDR_Register + * @{ + */ +/** + * \brief PCKT_FLT_GOALS_SOURCE_ADDR register + * \code + * Default value: 0x00 + * Read Write + * 7:0 RX_SOURCE_ADDR[7:0]: RX packet source / TX packet destination fields + * + * \endcode + */ +#define PCKT_FLT_GOALS_SOURCE_ADDR_BASE ((uint8_t)0x4B) /*!< Source address */ + +/** + * @} + */ + +/** @defgroup PCKT_FLT_GOALS_BROADCAST_Register + * @{ + */ + +/** + * \brief PCKT_FLT_GOALS_BROADCAST register + * \code + * Default value: 0x00 + * Read Write + * 7:0 BROADCAST[7:0]: Address shared for broadcast communication link + * + * \endcode + */ +#define PCKT_FLT_GOALS_BROADCAST_BASE ((uint8_t)0x4C) /*!< Address shared for broadcast communication links */ + +/** + * @} + */ + +/** @defgroup PCKT_FLT_GOALS_MULTICAST_Register + * @{ + */ + +/** + * \brief PCKT_FLT_GOALS_MULTICAST register + * \code + * Default value: 0x00 + * Read Write + * 7:0 MULTICAST[7:0]: Address shared for multicast communication links + * + * \endcode + */ +#define PCKT_FLT_GOALS_MULTICAST_BASE ((uint8_t)0x4D) /*!< Address shared for multicast communication links */ + +/** + * @} + */ + +/** @defgroup PCKT_FLT_GOALS_TX_SOURCE_ADDR_Register + * @{ + */ + +/** + * \brief PCKT_FLT_GOALS_TX_SOURCE_ADDR register + * \code + * Default value: 0x00 + * Read Write + * 7:0 TX_SOURCE_ADDR[7:0]: TX packet source / RX packet destination fields + * + * \endcode + */ +#define PCKT_FLT_GOALS_TX_ADDR_BASE ((uint8_t)0x4E) /*!< Address of the destination (also device own address) */ + +/** + * @} + */ + +/** @defgroup PCKT_FLT_OPTIONS_Register + * @{ + */ + +/** + * \brief PCKT_FLT_OPTIONS register + * \code + * Default value: 0x70 + * Read Write + * 7 Reserved. + * + * 6 RX_TIMEOUT_AND_OR_SELECT[0]: 1 - OR logical function applied to CS/SQI/PQI + * values (masked by 7:5 bits in PROTOCOL register) + * 5 CONTROL_FILTERING[0]: 1 - RX packet accepted if its control fields matches + * with masked CONTROLx_FIELD registers. + * 4 SOURCE_FILTERING[0]: 1 - RX packet accepted if its source field + * matches w/ masked RX_SOURCE_ADDR register. + * 3 DEST_VS_ SOURCE _ADDR[0]: 1 - RX packet accepted if its destination + * address matches with TX_SOURCE_ADDR reg. + * 2 DEST_VS_MULTICAST_ADDR[0]: 1 - RX packet accepted if its destination + * address matches with MULTICAST register + * 1 DEST_VS_BROADCAST_ADDR[0]: 1 - RX packet accepted if its destination + * address matches with BROADCAST register. + * 0 CRC_CHECK[0]: 1 - packet discarded if CRC not valid. + * + * \endcode + */ +#define PCKT_FLT_OPTIONS_BASE ((uint8_t)0x4F) /*!< Options relative to packet filtering */ + +#define PCKT_FLT_OPTIONS_CRC_CHECK_MASK ((uint8_t)0x01) /*!< Enable/disable of CRC check: packet is discarded if CRC is not valid [RX] */ +#define PCKT_FLT_OPTIONS_DEST_VS_BROADCAST_ADDR_MASK ((uint8_t)0x02) /*!< Packet discarded if destination address differs from BROADCAST register [RX] */ +#define PCKT_FLT_OPTIONS_DEST_VS_MULTICAST_ADDR_MASK ((uint8_t)0x04) /*!< Packet discarded if destination address differs from MULTICAST register [RX] */ +#define PCKT_FLT_OPTIONS_DEST_VS_TX_ADDR_MASK ((uint8_t)0x08) /*!< Packet discarded if destination address differs from TX_ADDR register [RX] */ +#define PCKT_FLT_OPTIONS_SOURCE_FILTERING_MASK ((uint8_t)0x10) /*!< Packet discarded if source address (masked by the SOURCE_MASK register) + differs from SOURCE_ADDR register [RX] */ +#define PCKT_FLT_OPTIONS_CONTROL_FILTERING_MASK ((uint8_t)0x20) /*!< Packet discarded if the x-byte (x=1¸4) control field (masked by the CONTROLx_MASK register) + differs from CONTROLx_FIELD register [RX] */ +#define PCKT_FLT_OPTIONS_RX_TIMEOUT_AND_OR_SELECT ((uint8_t)0x40) /*!< Logical function applied to CS/SQI/PQI values (masked by [7:5] bits in PROTOCOL[2] + register) */ + +/** + * @} + */ + +/** @defgroup TX_CTRL_FIELD_Registers + * @{ + */ + +/** + * \brief TX_CTRL_FIELDx registers + * \code + * Default value: 0x00 + * Read Write + * 7:0 TX_CTRLx[7:0]: Control field value to be used in TX packet as byte n.x + * \endcode + */ +#define TX_CTRL_FIELD3_BASE ((uint8_t)0x68) /*!< Control field value to be used in TX packet as byte n.3 */ + +#define TX_CTRL_FIELD2_BASE ((uint8_t)0x69) /*!< Control field value to be used in TX packet as byte n.2 */ + +#define TX_CTRL_FIELD1_BASE ((uint8_t)0x6A) /*!< Control field value to be used in TX packet as byte n.1 */ + +#define TX_CTRL_FIELD0_BASE ((uint8_t)0x6B) /*!< Control field value to be used in TX packet as byte n.0 */ + +/** + * @} + */ + + +/** @defgroup TX_PCKT_INFO_Register + * @{ + */ + +/** + * \brief TX_PCKT_INFO registers + * \code + * Default value: 0x00 + * Read + * + * 7:6 Not used. + * + * 5:4 TX_SEQ_NUM: Current TX packet sequence number + * + * 0 N_RETX[3:0]: Number of retransmissions done on the + * last TX packet + * \endcode + */ +#define TX_PCKT_INFO_BASE ((uint8_t)(0xC2)) /*!< Current TX packet sequence number [5:4]; + Number of retransmissions done on the last TX packet [3:0]*/ +/** + * @} + */ + +/** @defgroup RX_PCKT_INFO_Register + * @{ + */ + +/** + * \brief RX_PCKT_INFO registers + * \code + * Default value: 0x00 + * Read + * + * 7:3 Not used. + * + * 2 NACK_RX: NACK field of the received packet + * + * 1:0 RX_SEQ_NUM[1:0]: Sequence number of the received packet + * \endcode + */ +#define RX_PCKT_INFO_BASE ((uint8_t)(0xC3)) /*!< NO_ACK field of the received packet [2]; + sequence number of the received packet [1:0]*/ + +#define TX_PCKT_INFO_NACK_RX ((uint8_t)(0x04)) /*!< NACK field of the received packet */ + +/** + * @} + */ + +/** @defgroup RX_PCKT_LEN1 + * @{ + */ + +/** + * \brief RX_PCKT_LEN1 registers + * \code + * Default value: 0x00 + * Read + * + * 7:0 RX_PCKT_LEN1[7:0]: Length (number of bytes) of the received packet: RX_PCKT_LEN=RX_PCKT_LEN1 × 256 + RX_PCKT_LEN0 + * This value is packet_length/256 + * \endcode + */ +#define RX_PCKT_LEN1_BASE ((uint8_t)(0xC9)) /*!< Length (number of bytes) of the received packet: */ + +/** + * @} + */ + +/** @defgroup RX_PCKT_LEN0 + * @{ + */ + +/** + * \brief RX_PCKT_LEN0 registers + * \code + * Default value: 0x00 + * Read + * + * 7:0 RX_PCKT_LEN0[7:0]: Length (number of bytes) of the received packet: RX_PCKT_LEN=RX_PCKT_LEN1 × 256 + RX_PCKT_LEN0 + * This value is packet_length%256 + * \endcode + */ +#define RX_PCKT_LEN0_BASE ((uint8_t)(0xCA)) /*!< RX_PCKT_LEN=RX_PCKT_LEN1 × 256 + RX_PCKT_LEN0 */ + +/** + * @} + */ + + +/** @defgroup CRC_FIELD_Register + * @{ + */ + +/** + * \brief CRC_FIELD[2:0] registers + * \code + * Default value: 0x00 + * Read + * + * 7:0 CRC_FIELDx[7:0]: upper(x=2), middle(x=1) and lower(x=0) part of the crc field of the received packet + * \endcode + */ +#define CRC_FIELD2_BASE ((uint8_t)(0xCB)) /*!< CRC2 field of the received packet */ + +#define CRC_FIELD1_BASE ((uint8_t)(0xCC)) /*!< CRC1 field of the received packet */ + +#define CRC_FIELD0_BASE ((uint8_t)(0xCD)) /*!< CRC0 field of the received packet */ + +/** + * @} + */ + +/** @defgroup RX_CTRL_FIELD_Register + * @{ + */ + +/** + * \brief RX_CTRL_FIELD[3:0] registers + * \code + * Default value: 0x00 + * Read + * + * 7:0 RX_CTRL_FIELDx[7:0]: upper(x=3), middle(x=2), middle(x=1) and lower(x=0) part of the control field of the received packet + * \endcode + */ +#define RX_CTRL_FIELD0_BASE ((uint8_t)(0xCE)) /*!< CRTL3 Control field of the received packet */ + +#define RX_CTRL_FIELD1_BASE ((uint8_t)(0xCF)) /*!< CRTL2 Control field of the received packet */ + +#define RX_CTRL_FIELD2_BASE ((uint8_t)(0xD0)) /*!< CRTL1 Control field of the received packet */ + +#define RX_CTRL_FIELD3_BASE ((uint8_t)(0xD1)) /*!< CRTL0 Control field of the received packet */ + +/** + * @} + */ + +/** @defgroup RX_ADDR_FIELD_Register + * @{ + */ + +/** + * \brief RX_ADDR_FIELD[1:0] registers + * \code + * Default value: 0x00 + * Read + * + * 7:0 RX_ADDR_FIELDx[7:0]: source(x=1) and destination(x=0) address field of the received packet + * \endcode + */ +#define RX_ADDR_FIELD1_BASE ((uint8_t)(0xD2)) /*!< ADDR1 Address field of the received packet */ + +#define RX_ADDR_FIELD0_BASE ((uint8_t)(0xD3)) /*!< ADDR0 Address field of the received packet */ + +/** + * @} + */ + +/** + * @} + */ + + +/** @defgroup Protocol_Registers + * @{ + */ + +/** @defgroup PROTOCOL2_Register + * @{ + */ + +/** + * \brief PROTOCOL2 register + * \code + * Default value: 0x06 + * Read Write + * 7 CS_TIMEOUT_MASK: 1 - CS value contributes to timeout disabling + * + * 6 SQI_TIMEOUT_MASK: 1 - SQI value contributes to timeout disabling + * + * 5 PQI_TIMEOUT_MASK: 1 - PQI value contributes to timeout disabling + * + * 4:3 TX_SEQ_NUM_RELOAD[1:0]: TX sequence number to be used when counting reset is required using the related command. + * + * 2 RCO_CALIBRATION[0]: 1 - Enables the automatic RCO calibration + * + * 1 VCO_CALIBRATION[0]: 1 - Enables the automatic VCO calibration + * + * 0 LDCR_MODE[0]: 1 - LDCR mode enabled + * + * \endcode + */ +#define PROTOCOL2_BASE ((uint8_t)0x50) /*!< Protocol2 regisetr address */ + +#define PROTOCOL2_LDC_MODE_MASK ((uint8_t)0x01) /*!< Enable/disable Low duty Cycle mode */ +#define PROTOCOL2_VCO_CALIBRATION_MASK ((uint8_t)0x02) /*!< Enable/disable VCO automatic calibration */ +#define PROTOCOL2_RCO_CALIBRATION_MASK ((uint8_t)0x04) /*!< Enable/disable RCO automatic calibration */ +#define PROTOCOL2_PQI_TIMEOUT_MASK ((uint8_t)0x20) /*!< PQI value contributes to timeout disabling */ +#define PROTOCOL2_SQI_TIMEOUT_MASK ((uint8_t)0x40) /*!< SQI value contributes to timeout disabling */ +#define PROTOCOL2_CS_TIMEOUT_MASK ((uint8_t)0x80) /*!< CS value contributes to timeout disabling */ + +/** + * @} + */ + +/** @defgroup PROTOCOL1_Register + * @{ + */ + +/** + * \brief PROTOCOL1 register + * \code + * Default value: 0x00 + * Read Write + * 7 LDCR_RELOAD_ON_SYNC: 1 - LDCR timer will be reloaded with the value stored in the LDCR_RELOAD registers + * + * 6 PIGGYBACKING: 1 - PIGGYBACKING enabled + * + * 5:4 Reserved. + * + * 3 SEED_RELOAD[0]: 1 - Reload the back-off random generator + * seed using the value written in the + * BU_COUNTER_SEED_MSByte / LSByte registers + * + * 2 CSMA_ON [0]: 1 - CSMA channel access mode enabled + * + * 1 CSMA_PERS_ON[0]: 1 - CSMA persistent (no back-off) enabled + * + * 0 AUTO_PCKT_FLT[0]: 1 - automatic packet filtering mode enabled + * + * \endcode + */ +#define PROTOCOL1_BASE ((uint8_t)0x51) /*!< Protocol1 regisetr address */ + +#define PROTOCOL1_AUTO_PCKT_FLT_MASK ((uint8_t)0x01) /*!< Enable/disable automatic packet filtering mode */ +#define PROTOCOL1_CSMA_PERS_ON_MASK ((uint8_t)0x02) /*!< Enable/disable CSMA persistent (no back-off) */ +#define PROTOCOL1_CSMA_ON_MASK ((uint8_t)0x04) /*!< Enable/disable CSMA channel access mode */ +#define PROTOCOL1_SEED_RELOAD_MASK ((uint8_t)0x08) /*!< Reloads the seed of the PN generator for CSMA procedure */ +#define PROTOCOL1_PIGGYBACKING_MASK ((uint8_t)0x40) /*!< Enable/disable Piggybacking */ +#define PROTOCOL1_LDC_RELOAD_ON_SYNC_MASK ((uint8_t)0x80) /*!< LDC timer will be reloaded with the value stored in the LDC_RELOAD registers */ + +/** + * @} + */ + +/** @defgroup PROTOCOL0_Register + * @{ + */ + +/** + * \brief PROTOCOL0 register + * \code + * Default value: 0x08 + * Read Write + * 7:4 NMAX_RETX[3:0]: Max number of re-TX. 0 - re-transmission is not performed + * + * 3 NACK_TX[0]: 1 - field NO_ACK=1 on transmitted packet + * + * 2 AUTO_ACK[0]: 1 - automatic ack after RX + * + * 1 PERS_RX[0]: 1 - persistent reception enabled + * + * 0 PERS_TX[0]: 1 - persistent transmission enabled + * + * \endcode + */ +#define PROTOCOL0_BASE ((uint8_t)0x52) /*!< Persistent RX/TX, autoack, Max number of retransmissions */ + +#define PROTOCOL0_PERS_TX_MASK ((uint8_t)0x01) /*!< Enables persistent transmission */ +#define PROTOCOL0_PERS_RX_MASK ((uint8_t)0x02) /*!< Enables persistent reception */ +#define PROTOCOL0_AUTO_ACK_MASK ((uint8_t)0x04) /*!< Enables auto acknowlegment */ +#define PROTOCOL0_NACK_TX_MASK ((uint8_t)0x08) /*!< Writes field NO_ACK=1 on transmitted packet */ +#define PROTOCOL0_NMAX_RETX_MASK ((uint8_t)0xF0) /*!< Retransmission mask */ + +/** + * @} + */ + +/** @defgroup TIMERS5_Register + * @{ + */ + +/** + * \brief TIMERS5 register + * \code + * Default value: 0x00 + * Read Write + * 7:0 RX_TIMEOUT_PRESCALER[7:0] : RX operation timeout: prescaler value + * \endcode + */ +#define TIMERS5_RX_TIMEOUT_PRESCALER_BASE ((uint8_t)0x53) /*!< RX operation timeout: prescaler value */ + +/** + * @} + */ + +/** @defgroup TIMERS4_Register + * @{ + */ + +/** + * \brief TIMERS4 register + * \code + * Default value: 0x00 + * Read Write + * 7:0 RX_TIMEOUT_COUNTER[7:0] : RX operation timeout: counter value + * \endcode + */ +#define TIMERS4_RX_TIMEOUT_COUNTER_BASE ((uint8_t)0x54) /*!< RX operation timeout: counter value */ + +/** + * @} + */ + +/** @defgroup TIMERS3_Register + * @{ + */ + +/** + * \brief TIMERS3 register + * \code + * Default value: 0x00 + * Read Write + * 7:0 LDCR_PRESCALER[7:0] : LDC Mode: Prescaler part of the wake-up value + * \endcode + */ +#define TIMERS3_LDC_PRESCALER_BASE ((uint8_t)0x55) /*!< LDC Mode: Prescaler of the wake-up timer */ + +/** + * @} + */ + +/** @defgroup TIMERS2_Register + * @{ + */ + +/** + * \brief TIMERS2 register + * \code + * Default value: 0x00 + * Read Write + * 7:0 LDCR_COUNTER[7:0] : LDC Mode: counter part of the wake-up value + * \endcode + */ +#define TIMERS2_LDC_COUNTER_BASE ((uint8_t)0x56) /*!< LDC Mode: counter of the wake-up timer */ + +/** + * @} + */ + +/** @defgroup TIMERS1_Register + * @{ + */ + +/** + * \brief TIMERS1 register + * \code + * Default value: 0x00 + * Read Write + * 7:0 LDCR_RELOAD_PRESCALER[7:0] : LDC Mode: Prescaler part of the reload value + * \endcode + */ +#define TIMERS1_LDC_RELOAD_PRESCALER_BASE ((uint8_t)0x57) /*!< LDC Mode: Prescaler part of the reload value */ + +/** + * @} + */ + +/** @defgroup TIMERS0_Register + * @{ + */ + +/** + * \brief TIMERS0 register + * \code + * Default value: 0x00 + * Read Write + * 7:0 LDCR_RELOAD_COUNTER[7:0] : LDC Mode: Counter part of the reload value + * \endcode + */ +#define TIMERS0_LDC_RELOAD_COUNTER_BASE ((uint8_t)0x58) /*!< LDC Mode: Counter part of the reload value */ + +/** + * @} + */ + + +/** @defgroup CSMA_CONFIG3_Register + * @{ + */ + +/** + * \brief CSMA_CONFIG3 registers + * \code + * Default value: 0xFF + * Read Write + * 7:0 BU_COUNTER_SEED_MSByte: Seed of the random number generator used to apply the BEB (Binary Exponential Backoff) algorithm (MSB) + * \endcode + */ +#define CSMA_CONFIG3_BASE ((uint8_t)0x64) /*!< CSMA/CA: Seed of the random number generator used to apply the BEB (Binary Exponential Backoff) algorithm (MSB) */ + +/** + * @} + */ + +/** @defgroup CSMA_CONFIG2_Register + * @{ + */ + +/** + * \brief CSMA_CONFIG2 registers + * \code + * Default value: 0x00 + * Read Write + * 7:0 BU_COUNTER_SEED_LSByte: Seed of the random number generator used to apply the BEB (Binary Exponential Backoff) algorithm (LSB) + * \endcode + */ +#define CSMA_CONFIG2_BASE ((uint8_t)0x65) /*!< CSMA/CA: Seed of the random number generator used to apply the BEB (Binary Exponential Backoff) algorithm (LSB) */ + +/** + * @} + */ + +/** @defgroup CSMA_CONFIG1_Register + * @{ + */ + +/** + * \brief CSMA_CONFIG1 registers + * \code + * Default value: 0x04 + * Read Write + * 7:2 BU_PRESCALER[5:0]: Used to program the back-off unit BU + * + * 1:0 CCA_PERIOD[1:0]: Used to program the Tcca time (64 / 128 /256 / 512 × Tbit. + * \endcode + */ +#define CSMA_CONFIG1_BASE ((uint8_t)0x66) /*!< CSMA/CA: Prescaler of the back-off time unit (BU); CCA period */ + +#define CSMA_CCA_PERIOD_64TBIT ((uint8_t)0x00) /*!< CSMA/CA: Sets CCA period to 64*TBIT */ +#define CSMA_CCA_PERIOD_128TBIT ((uint8_t)0x01) /*!< CSMA/CA: Sets CCA period to 128*TBIT */ +#define CSMA_CCA_PERIOD_256TBIT ((uint8_t)0x02) /*!< CSMA/CA: Sets CCA period to 256*TBIT */ +#define CSMA_CCA_PERIOD_512TBIT ((uint8_t)0x03) /*!< CSMA/CA: Sets CCA period to 512*TBIT */ + +/** + * @} + */ + +/** @defgroup CSMA_CONFIG0_Register + * @{ + */ + +/** + * \brief CSMA_CONFIG0 registers + * \code + * Default value: 0x00 + * Read Write + * 7:4 CCA_LENGTH[3:0]: Used to program the Tlisten time + * + * 3 Reserved. + * + * 2:0 NBACKOFF_MAX[2:0]: Max number of back-off cycles. + * \endcode + */ +#define CSMA_CONFIG0_BASE ((uint8_t)0x67) /*!< CSMA/CA: CCA lenght; Max number of backoff cycles */ + +/** + * @} + */ + +/** + * @} + */ + + +/** @defgroup Link_Quality_Registers + * @{ + */ + +/** @defgroup QI_Register + * @{ + */ + +/** + * \brief QI register + * \code + * Read Write + * Default value: 0x02 + * + * 7:6 SQI_TH[1:0]: SQI threshold according to the formula: 8*SYNC_LEN - 2*SQI_TH + * + * 5:2 PQI_TH[3:0]: PQI threshold according to the formula: 4*PQI_THR + * + * + * 1 SQI_EN[0]: SQI enable + * 1 - Enable + * 0 - Disable + * + * 0 PQI_EN[0]: PQI enable + * 1 - Enable + * 0 - Disable + * \endcode + */ +#define QI_BASE ((uint8_t)0x3A) /*!< QI register */ + +#define QI_PQI_MASK ((uint8_t)0x01) /*!< PQI enable/disable */ +#define QI_SQI_MASK ((uint8_t)0x02) /*!< SQI enable/disable */ + +/** + * @} + */ + +/** @defgroup LINK_QUALIF2 + * @{ + */ + +/** + * \brief LINK_QUALIF2 registers + * \code + * Default value: 0x00 + * Read + * + * 7:0 PQI[7:0]: PQI value of the received packet + * \endcode + */ +#define LINK_QUALIF2_BASE ((uint8_t)(0xC5)) /*!< PQI value of the received packet */ + +/** + * @} + */ + +/** @defgroup LINK_QUALIF1 + * @{ + */ + +/** + * \brief LINK_QUALIF1 registers + * \code + * Default value: 0x00 + * Read + * + * 7 CS: Carrier Sense indication + * + * 6:0 SQI[6:0]: SQI value of the received packet + * \endcode + */ +#define LINK_QUALIF1_BASE ((uint8_t)(0xC6)) /*!< Carrier sense indication [7]; SQI value of the received packet */ + +#define LINK_QUALIF1_CS ((uint8_t)(0x80)) /*!< Carrier sense indication [7] */ + +/** + * @} + */ + +/** @defgroup LINK_QUALIF0 + * @{ + */ + +/** + * \brief LINK_QUALIF0 registers + * \code + * Default value: 0x00 + * Read + * + * 7:4 LQI [3:0]: LQI value of the received packet + * + * 3:0 AGC_WORD[3:0]: AGC word of the received packet + * \endcode + */ +#define LINK_QUALIF0_BASE ((uint8_t)(0xC7)) /*!< LQI value of the received packet [7:4]; AGC word of the received packet [3:0] */ + +/** + * @} + */ + +/** @defgroup RSSI_LEVEL + * @{ + */ + +/** + * \brief RSSI_LEVEL registers + * \code + * Default value: 0x00 + * Read + * + * 7:0 RSSI_LEVEL[7:0]: RSSI level of the received packet + * \endcode + */ +#define RSSI_LEVEL_BASE ((uint8_t)(0xC8)) /*!< RSSI level of the received packet */ + +/** + * @} + */ + +/** @defgroup RSSI_FLT_Register + * @{ + */ + +/** + * \brief RSSI register + * \code + * Read Write + * Default value: 0xF3 + * 7:4 RSSI_FLT[3:0]: Gain of the RSSI filter + * + * 3:2 CS_MODE[1:0]: AFC loop gain in slow mode (2's log) + * + * CS_MODE1 | CS_MODE0 | CS Mode + * ----------------------------------------------------------------------------------------- + * 0 | 0 | Static CS + * 0 | 1 | Dynamic CS with 6dB dynamic threshold + * 1 | 0 | Dynamic CS with 12dB dynamic threshold + * 1 | 1 | Dynamic CS with 18dB dynamic threshold + * + * 1:0 OOK_PEAK_DECAY[1:0]: Peak decay control for OOK: 3 slow decay; 0 fast decay + * + * \endcode + */ +#define RSSI_FLT_BASE ((uint8_t)0x21) /*!< Gain of the RSSI filter; lower value is fast but inaccurate, + higher value is slow and more accurate */ +#define RSSI_FLT_CS_MODE_MASK ((uint8_t)0x0C) /*!< Carrier sense mode mask */ +#define RSSI_FLT_CS_MODE_STATIC ((uint8_t)0x00) /*!< Carrier sense mode; static carrier sensing */ +#define RSSI_FLT_CS_MODE_DYNAMIC_6 ((uint8_t)0x04) /*!< Carrier sense mode; dynamic carrier sensing with 6dB threshold */ +#define RSSI_FLT_CS_MODE_DYNAMIC_12 ((uint8_t)0x08) /*!< Carrier sense mode; dynamic carrier sensing with 12dB threshold */ +#define RSSI_FLT_CS_MODE_DYNAMIC_18 ((uint8_t)0x0C) /*!< Carrier sense mode; dynamic carrier sensing with 18dB threshold */ +#define RSSI_FLT_OOK_PEAK_DECAY_MASK ((uint8_t)0x03) /*!< Peak decay control for OOK mask */ +#define RSSI_FLT_OOK_PEAK_DECAY_FAST ((uint8_t)0x00) /*!< Peak decay control for OOK: fast decay */ +#define RSSI_FLT_OOK_PEAK_DECAY_MEDIUM_FAST ((uint8_t)0x01) /*!< Peak decay control for OOK: medium_fast decay */ +#define RSSI_FLT_OOK_PEAK_DECAY_MEDIUM_SLOW ((uint8_t)0x02) /*!< Peak decay control for OOK: medium_fast decay */ +#define RSSI_FLT_OOK_PEAK_DECAY_SLOW ((uint8_t)0x03) /*!< Peak decay control for OOK: slow decay */ + +/** + * @} + */ + +/** @defgroup RSSI_TH_Register + * @{ + */ + +/** + * \brief RSSI_TH register + * \code + * Read Write + * Default value: 0x24 + * + * 7:0 RSSI_THRESHOLD [7:0]: Signal detect threshold in 0.5dB. -120dBm corresponds to 20 + * \endcode + */ +#define RSSI_TH_BASE ((uint8_t)0x22) /*!< Signal detect threshold in 0.5dB stp. 20 correspond to -120 dBm */ + +/** + * @} + */ + +/** + * @} + */ + + +/** @defgroup FIFO_Registers + * @{ + */ + +/** @defgroup FIFO_CONFIG3_Register + * @{ + */ + +/** + * \brief FIFO_CONFIG3 registers + * \code + * Default value: 0x30 + * Read Write + * 7 Reserved. + * + * 6:0 rxafthr [6:0]: FIFO Almost Full threshold for rx fifo. + * + * \endcode + */ +#define FIFO_CONFIG3_RXAFTHR_BASE ((uint8_t)0x3E) /*!< FIFO Almost Full threshold for rx fifo [6:0] */ + +/** + * @} + */ + +/** @defgroup FIFO_CONFIG2_Register + * @{ + */ + +/** + * \brief FIFO_CONFIG2 registers + * \code + * Default value: 0x30 + * Read Write + * 7 Reserved. + * + * 6:0 rxaethr [6:0]: FIFO Almost Empty threshold for rx fifo. + * + * \endcode + */ +#define FIFO_CONFIG2_RXAETHR_BASE ((uint8_t)0x3F) /*!< FIFO Almost Empty threshold for rx fifo [6:0] */ + +/** + * @} + */ + +/** @defgroup FIFO_CONFIG1_Register + * @{ + */ + +/** + * \brief FIFO_CONFIG1 registers + * \code + * Default value: 0x30 + * Read Write + * 7 Reserved. + * + * 6:0 txafthr [6:0]: FIFO Almost Full threshold for tx fifo. + * + * \endcode + */ +#define FIFO_CONFIG1_TXAFTHR_BASE ((uint8_t)0x40) /*!< FIFO Almost Full threshold for tx fifo [6:0] */ + +/** + * @} + */ + +/** @defgroup FIFO_CONFIG0_Register + * @{ + */ + +/** + * \brief FIFO_CONFIG0 registers + * \code + * Default value: 0x30 + * Read Write + * 7 Reserved. + * + * 6:0 txaethr [6:0]: FIFO Almost Empty threshold for tx fifo. + * + * \endcode + */ +#define FIFO_CONFIG0_TXAETHR_BASE ((uint8_t)0x41) /*!< FIFO Almost Empty threshold for tx fifo [6:0] */ + +/** + * @} + */ + +/** @defgroup LINEAR_FIFO_STATUS1_Register + * @{ + */ + +/** + * \brief LINEAR_FIFO_STATUS1 registers + * \code + * Default value: 0x00 + * Read + * + * 7 Reserved. + * + * 6:0 elem_txfifo[6:0]: Number of elements in the linear TXFIFO (<=96) + * \endcode + */ +#define LINEAR_FIFO_STATUS1_BASE ((uint8_t)(0xE6)) /*!< Number of elements in the linear TX FIFO [6:0] (<=96) */ + +/** + * @} + */ + +/** @defgroup LINEAR_FIFO_STATUS0_Register + * @{ + */ + +/** + * \brief LINEAR_FIFO_STATUS0 registers + * \code + * Default value: 0x00 + * Read + * + * 7 Reserved. + * + * 6:0 elem_rxfifo[6:0]: Number of elements in the linear RXFIFO (<=96) + * \endcode + */ +#define LINEAR_FIFO_STATUS0_BASE ((uint8_t)(0xE7)) /*!< Number of elements in the linear RX FIFO [6:0] (<=96) */ + +/** + * @} + */ + + +/** + * @} + */ + + +/** @defgroup Calibration_Registers + * @{ + */ + +/** @defgroup RCO_VCO_CALIBR_IN2_Register + * @{ + */ + +/** + * \brief RCO_VCO_CALIBR_IN2 registers + * \code + * Default value: 0x70 + * Read Write + * 7:4 RWT_IN[3:0]: RaWThermometric word value for the RCO [7:4] + * + * 3:0 RFB_IN[4:1]: ResistorFineBit word value for the RCO (first 4 bits) + * \endcode + */ +#define RCO_VCO_CALIBR_IN2_BASE ((uint8_t)0x6D) /*!< RaWThermometric word value for the RCO [7:4]; ResistorFineBit word value for the RCO [3:0] */ + +/** + * @} + */ + +/** @defgroup RCO_VCO_CALIBR_IN1_Register + * @{ + */ + +/** + * \brief RCO_VCO_CALIBR_IN1 registers + * \code + * Default value: 0x48 + * Read Write + * + * 7 RFB_IN[0]: ResistorFineBit word value for the RCO (LSb) + * + * 6:0 VCO_CALIBR_TX[6:0]: Word value for the VCO to be used in TX mode + * \endcode + */ +#define RCO_VCO_CALIBR_IN1_BASE ((uint8_t)0x6E) /*!< ResistorFineBit word value for the RCO [7]; Word value for the VCO to be used in TX mode [6:0]*/ + +/** + * @} + */ + +/** @defgroup RCO_VCO_CALIBR_IN0_Register + * @{ + */ + +/** + * \brief RCO_VCO_CALIBR_IN0 registers + * \code + * Default value: 0x48 + * Read Write + * + * 7 Reserved. + * + * 6:0 VCO_CALIBR_RX[6:0]: Word value for the VCO to be used in RX mode + * \endcode + */ +#define RCO_VCO_CALIBR_IN0_BASE ((uint8_t)0x6F) /*!< Word value for the VCO to be used in RX mode [6:0] */ + +/** + * @} + */ + +/** @defgroup RCO_VCO_CALIBR_OUT1_Register + * @{ + */ + +/** + * \brief RCO_VCO_CALIBR_OUT1 registers + * \code + * Default value: 0x00 + * Read + * + * 7:4 RWT_OUT[3:0]: RWT word from internal RCO calibrator + * + * 3:0 RFB_OUT[4:1]: RFB word from internal RCO calibrator (upper part) + * \endcode + */ +#define RCO_VCO_CALIBR_OUT1_BASE ((uint8_t)(0xE4)) /*!< RaWThermometric RWT word from internal RCO calibrator [7]; + ResistorFineBit RFB word from internal RCO oscillator [6:0] */ +/** + * @} + */ + +/** @defgroup RCO_VCO_CALIBR_OUT0_Register + * @{ + */ + +/** + * \brief RCO_VCO_CALIBR_OUT0 registers + * \code + * Default value: 0x00 + * Read + * + * 7 RFB_OUT[0]: RFB word from internal RCO calibrator (last bit LSB) + * + * 6:0 VCO_CALIBR_DATA[6:0]: Output word from internal VCO calibrator + * \endcode + */ +#define RCO_VCO_CALIBR_OUT0_BASE ((uint8_t)(0xE5)) /*!< ResistorFineBit RFB word from internal RCO oscillator [0]; + Output word from internal calibrator [6:0]; */ +/** + * @} + */ + +/** + * @} + */ + + +/** @defgroup AES_Registers + * @{ + */ + +/** @defgroup AES_KEY_IN_Register + * @{ + */ + +/** + * \brief AES_KEY_INx registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 AES_KEY_INx[7:0]: AES engine key input (total - 128 bits) + * \endcode + */ +#define AES_KEY_IN_15_BASE ((uint8_t)0x70) /*!< AES engine key input 15 */ + +#define AES_KEY_IN_14_BASE ((uint8_t)0x71) /*!< AES engine key input 14 */ + +#define AES_KEY_IN_13_BASE ((uint8_t)0x72) /*!< AES engine key input 13 */ + +#define AES_KEY_IN_12_BASE ((uint8_t)0x73) /*!< AES engine key input 12 */ + +#define AES_KEY_IN_11_BASE ((uint8_t)0x74) /*!< AES engine key input 11 */ + +#define AES_KEY_IN_10_BASE ((uint8_t)0x75) /*!< AES engine key input 10 */ + +#define AES_KEY_IN_9_BASE ((uint8_t)0x76) /*!< AES engine key input 9 */ + +#define AES_KEY_IN_8_BASE ((uint8_t)0x77) /*!< AES engine key input 8 */ + +#define AES_KEY_IN_7_BASE ((uint8_t)0x78) /*!< AES engine key input 7 */ + +#define AES_KEY_IN_6_BASE ((uint8_t)0x79) /*!< AES engine key input 6 */ + +#define AES_KEY_IN_5_BASE ((uint8_t)0x7A) /*!< AES engine key input 5 */ + +#define AES_KEY_IN_4_BASE ((uint8_t)0x7B) /*!< AES engine key input 4 */ + +#define AES_KEY_IN_3_BASE ((uint8_t)0x7C) /*!< AES engine key input 3 */ + +#define AES_KEY_IN_2_BASE ((uint8_t)0x7D) /*!< AES engine key input 2 */ + +#define AES_KEY_IN_1_BASE ((uint8_t)0x7E) /*!< AES engine key input 1 */ + +#define AES_KEY_IN_0_BASE ((uint8_t)0x7F) /*!< AES engine key input 0 */ + +/** + * @} + */ + +/** @defgroup AES_DATA_IN_Register + * @{ + */ + +/** + * \brief AES_DATA_INx registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 AES_DATA_INx[7:0]: AES engine data input (total - 128 bits) + * \endcode + */ +#define AES_DATA_IN_15_BASE ((uint8_t)0x80) /*!< AES engine data input 15 + Take care: Address is in reverse order respect data numbering; eg.: 0x81 -> AES_data14[7:0] */ +#define AES_DATA_IN_14_BASE ((uint8_t)0x81) /*!< AES engine data input 14 */ + +#define AES_DATA_IN_13_BASE ((uint8_t)0x82) /*!< AES engine data input 13 */ + +#define AES_DATA_IN_12_BASE ((uint8_t)0x83) /*!< AES engine data input 12 */ + +#define AES_DATA_IN_11_BASE ((uint8_t)0x84) /*!< AES engine data input 11 */ + +#define AES_DATA_IN_10_BASE ((uint8_t)0x85) /*!< AES engine data input 10 */ + +#define AES_DATA_IN_9_BASE ((uint8_t)0x86) /*!< AES engine data input 9 */ + +#define AES_DATA_IN_8_BASE ((uint8_t)0x87) /*!< AES engine data input 8 */ + +#define AES_DATA_IN_7_BASE ((uint8_t)0x88) /*!< AES engine data input 7 */ + +#define AES_DATA_IN_6_BASE ((uint8_t)0x89) /*!< AES engine data input 6 */ + +#define AES_DATA_IN_5_BASE ((uint8_t)0x8A) /*!< AES engine data input 5 */ + +#define AES_DATA_IN_4_BASE ((uint8_t)0x8B) /*!< AES engine data input 4 */ + +#define AES_DATA_IN_3_BASE ((uint8_t)0x8C) /*!< AES engine data input 3 */ + +#define AES_DATA_IN_2_BASE ((uint8_t)0x8D) /*!< AES engine data input 2 */ + +#define AES_DATA_IN_1_BASE ((uint8_t)0x8E) /*!< AES engine data input 1 */ + +#define AES_DATA_IN_0_BASE ((uint8_t)0x8F) /*!< AES engine data input 0 */ + +/** + * @} + */ + +/** @defgroup AES_DATA_OUT_Register + * @{ + */ + +/** + * \brief AES_DATA_OUT[15:0] registers + * \code + * Default value: 0x00 + * Read + * + * 7:0 AES_DATA_OUTx[7:0]: AES engine data output (128 bits) + * \endcode + */ +#define AES_DATA_OUT_15_BASE ((uint8_t)(0xD4)) /*!< AES engine data output 15 */ + +#define AES_DATA_OUT_14_BASE ((uint8_t)(0xD5)) /*!< AES engine data output 14 */ + +#define AES_DATA_OUT_13_BASE ((uint8_t)(0xD6)) /*!< AES engine data output 13 */ + +#define AES_DATA_OUT_12_BASE ((uint8_t)(0xD7)) /*!< AES engine data output 12 */ + +#define AES_DATA_OUT_11_BASE ((uint8_t)(0xD8)) /*!< AES engine data output 11 */ + +#define AES_DATA_OUT_10_BASE ((uint8_t)(0xD9)) /*!< AES engine data output 10 */ + +#define AES_DATA_OUT_9_BASE ((uint8_t)(0xDA)) /*!< AES engine data output 9 */ + +#define AES_DATA_OUT_8_BASE ((uint8_t)(0xDB)) /*!< AES engine data output 8 */ + +#define AES_DATA_OUT_7_BASE ((uint8_t)(0xDC)) /*!< AES engine data output 7 */ + +#define AES_DATA_OUT_6_BASE ((uint8_t)(0xDD)) /*!< AES engine data output 6 */ + +#define AES_DATA_OUT_5_BASE ((uint8_t)(0xDE)) /*!< AES engine data output 5 */ + +#define AES_DATA_OUT_4_BASE ((uint8_t)(0xDF)) /*!< AES engine data output 4 */ + +#define AES_DATA_OUT_3_BASE ((uint8_t)(0xE0)) /*!< AES engine data output 3 */ + +#define AES_DATA_OUT_2_BASE ((uint8_t)(0xE1)) /*!< AES engine data output 2 */ + +#define AES_DATA_OUT_1_BASE ((uint8_t)(0xE2)) /*!< AES engine data output 1 */ + +#define AES_DATA_OUT_0_BASE ((uint8_t)(0xE3)) /*!< AES engine data output 0 */ + +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup IRQ_Registers + * @{ + */ + +/** @defgroup IRQ_MASK0_Register + * @{ + */ + +/** + * \brief IRQ_MASK0 registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 INT_MASK0: IRQ mask, if the correspondent bit is set and IRQ can be generated (according to the next table) + * + * Bit | Events Group Interrupt Event + * ------------------------------------------------------- + * 0 | RX data ready + * 1 | RX data discarded (upon filtering) + * 2 | TX data sent + * 3 | Max re-TX reached + * 4 | CRC error + * 5 | TX FIFO underflow/overflow error + * 6 | RX FIFO underflow/overflow error + * 7 | TX FIFO almost full + * \endcode + */ + + +#define IRQ_MASK0_BASE ((uint8_t)0x93) /*!< IRQ_MASK is split into 4 registers*/ + +#define IRQ_MASK0_RX_DATA_READY ((uint8_t)0x01) /*!< IRQ: RX data ready */ +#define IRQ_MASK0_RX_DATA_DISC ((uint8_t)0x02) /*!< IRQ: RX data discarded (upon filtering) */ +#define IRQ_MASK0_TX_DATA_SENT ((uint8_t)0x04) /*!< IRQ: TX data sent */ +#define IRQ_MASK0_MAX_RE_TX_REACH ((uint8_t)0x08) /*!< IRQ: Max re-TX reached */ +#define IRQ_MASK0_CRC_ERROR ((uint8_t)0x10) /*!< IRQ: CRC error */ +#define IRQ_MASK0_TX_FIFO_ERROR ((uint8_t)0x20) /*!< IRQ: TX FIFO underflow/overflow error */ +#define IRQ_MASK0_RX_FIFO_ERROR ((uint8_t)0x40) /*!< IRQ: RX FIFO underflow/overflow error */ +#define IRQ_MASK0_TX_FIFO_ALMOST_FULL ((uint8_t)0x80) /*!< IRQ: TX FIFO almost full */ + +/** + * @} + */ + +/** @defgroup IRQ_MASK1_Register + * @{ + */ + +/** + * \brief IRQ_MASK1 registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 INT_MASK1: IRQ mask, if the correspondent bit is set and IRQ can be generated (according to the next table) + * + * Bit | Events Group Interrupt Event + * ------------------------------------------------------- + * 8 | TX FIFO almost empty + * 9 | RX FIFO almost full + * 10 | RX FIFO almost empty + * 11 | Max number of back-off during CCA + * 12 | Valid preamble detected + * 13 | Sync word detected + * 14 | RSSI above threshold (Carrier Sense) + * 15 | Wake-up timeout in LDCR mode13 + * \endcode + */ + +#define IRQ_MASK1_BASE ((uint8_t)0x92) /*!< IRQ_MASK is split into 4 registers*/ + +#define IRQ_MASK1_TX_FIFO_ALMOST_EMPTY ((uint8_t)0x01) /*!< IRQ: TX FIFO almost empty */ +#define IRQ_MASK1_RX_FIFO_ALMOST_FULL ((uint8_t)0x02) /*!< IRQ: RX FIFO almost full */ +#define IRQ_MASK1_RX_FIFO_ALMOST_EMPTY ((uint8_t)0x04) /*!< IRQ: RX FIFO almost empty */ +#define IRQ_MASK1_MAX_BO_CCA_REACH ((uint8_t)0x08) /*!< IRQ: Max number of back-off during CCA */ +#define IRQ_MASK1_VALID_PREAMBLE ((uint8_t)0x10) /*!< IRQ: Valid preamble detected */ +#define IRQ_MASK1_VALID_SYNC ((uint8_t)0x20) /*!< IRQ: Sync word detected */ +#define IRQ_MASK1_RSSI_ABOVE_TH ((uint8_t)0x40) /*!< IRQ: RSSI above threshold */ +#define IRQ_MASK1_WKUP_TOUT_LDC ((uint8_t)0x80) /*!< IRQ: Wake-up timeout in LDC mode */ + +/** + * @} + */ + +/** @defgroup IRQ_MASK2_Register + * @{ + */ + +/** + * \brief IRQ_MASK2 registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 INT_MASK2: IRQ mask, if the correspondent bit is set and IRQ can be generated (according to the next table) + * + * Bit | Events Group Interrupt Event + * ------------------------------------------------------- + * 16 | READY state in steady condition14 + * 17 | STANDBY state switching in progress + * 18 | Low battery level + * 19 | Power-On reset + * 20 | Brown-Out event + * 21 | LOCK state in steady condition + * 22 | PM start-up timer expiration + * 23 | XO settling timeout + * \endcode + */ +#define IRQ_MASK2_BASE ((uint8_t)0x91) /*!< IRQ_MASK is split into 4 registers*/ + +#define IRQ_MASK2_READY ((uint8_t)0x01) /*!< IRQ: READY state */ +#define IRQ_MASK2_STANDBY_DELAYED ((uint8_t)0x02) /*!< IRQ: STANDBY state after MCU_CK_CONF_CLOCK_TAIL_X clock cycles */ +#define IRQ_MASK2_LOW_BATT_LVL ((uint8_t)0x04) /*!< IRQ: Battery level below threshold*/ +#define IRQ_MASK2_POR ((uint8_t)0x08) /*!< IRQ: Power On Reset */ +#define IRQ_MASK2_BOR ((uint8_t)0x10) /*!< IRQ: Brown out event (both accurate and inaccurate)*/ +#define IRQ_MASK2_LOCK ((uint8_t)0x20) /*!< IRQ: LOCK state */ +#define IRQ_MASK2_PM_COUNT_EXPIRED ((uint8_t)0x40) /*!< IRQ: only for debug; Power Management startup timer expiration (see reg PM_START_COUNTER, 0xB5) */ +#define IRQ_MASK2_XO_COUNT_EXPIRED ((uint8_t)0x80) /*!< IRQ: only for debug; Crystal oscillator settling time counter expired */ + +/** + * @} + */ + +/** @defgroup IRQ_MASK3_Register + * @{ + */ + +/** + * \brief IRQ_MASK3 registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 INT_MASK3: IRQ mask, if the correspondent bit is set and IRQ can be generated (according to the next table) + * + * Bit | Events Group Interrupt Event + * ------------------------------------------------------- + * 24 | SYNTH locking timeout + * 25 | SYNTH calibration start-up time + * 26 | SYNTH calibration timeout + * 27 | TX circuitry start-up time + * 28 | RX circuitry start-up time + * 29 | RX operation timeout + * 30 | Others AES Endof Operation + * 31 | Reserved + * \endcode + */ +#define IRQ_MASK3_BASE ((uint8_t)0x90) /*!< IRQ_MASK is split into 4 registers*/ + +#define IRQ_MASK3_SYNTH_LOCK_TIMEOUT ((uint8_t)0x01) /*!< IRQ: only for debug; LOCK state timeout */ +#define IRQ_MASK3_SYNTH_LOCK_STARTUP ((uint8_t)0x02) /*!< IRQ: only for debug; see CALIBR_START_COUNTER */ +#define IRQ_MASK3_SYNTH_CAL_TIMEOUT ((uint8_t)0x04) /*!< IRQ: only for debug; SYNTH calibration timeout */ +#define IRQ_MASK3_TX_START_TIME ((uint8_t)0x08) /*!< IRQ: only for debug; TX circuitry startup time; see TX_START_COUNTER */ +#define IRQ_MASK3_RX_START_TIME ((uint8_t)0x10) /*!< IRQ: only for debug; RX circuitry startup time; see TX_START_COUNTER */ +#define IRQ_MASK3_RX_TIMEOUT ((uint8_t)0x20) /*!< IRQ: RX operation timeout */ +#define IRQ_MASK3_AES_END ((uint8_t)0x40) /*!< IRQ: AES End of operation */ + +/** + * @} + */ + + +/** @defgroup IRQ_STATUS0_Register + * @{ + */ + +/** + * \brief IRQ_STATUS0 registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 INT_STATUS0: IRQ status, if the correspondent bit is set and IRQ has been generated (according to the next table) + * + * Bit | Events Group Interrupt Event + * ------------------------------------------------------- + * 0 | RX data ready + * 1 | RX data discarded (upon filtering) + * 2 | TX data sent + * 3 | Max re-TX reached + * 4 | CRC error + * 5 | TX FIFO underflow/overflow error + * 6 | RX FIFO underflow/overflow error + * 7 | TX FIFO almost full + * \endcode + */ + +#define IRQ_STATUS0_BASE ((uint8_t)(0xFD)) /*!< IRQ Events(RR, split into 4 registers) */ + +#define IRQ_STATUS0_SYNTH_LOCK_TIMEOUT ((uint8_t)(0x01)) /*!< IRQ: LOCK state timeout */ +#define IRQ_STATUS0_SYNTH_LOCK_STARTUP ((uint8_t)(0x02)) /*!< IRQ: only for debug; see CALIBR_START_COUNTER */ +#define IRQ_STATUS0_SYNTH_CAL_TIMEOUT ((uint8_t)(0x04)) /*!< IRQ: SYNTH locking timeout */ +#define IRQ_STATUS0_TX_START_TIME ((uint8_t)(0x08)) /*!< IRQ: only for debug; TX circuitry startup time; see TX_START_COUNTER */ +#define IRQ_STATUS0_RX_START_TIME ((uint8_t)(0x10)) /*!< IRQ: only for debug; RX circuitry startup time; see TX_START_COUNTER */ +#define IRQ_STATUS0_RX_TIMEOUT ((uint8_t)(0x20)) /*!< IRQ: RX operation timeout expiration */ +#define IRQ_STATUS0_AES_END ((uint8_t)(0x40)) /*!< IRQ: AES End of operation */ + +/** + * @} + */ + +/** @defgroup IRQ_STATUS1_Register + * @{ + */ + +/** + * \brief IRQ_STATUS1 registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 INT_STATUS1: IRQ status, if the correspondent bit is set and IRQ has been generated (according to the next table) + * + * Bit | Events Group Interrupt Event + * ------------------------------------------------------- + * 8 | TX FIFO almost empty + * 9 | RX FIFO almost full + * 10 | RX FIFO almost empty + * 11 | Max number of back-off during CCA + * 12 | Valid preamble detected + * 13 | Sync word detected + * 14 | RSSI above threshold (Carrier Sense) + * 15 | Wake-up timeout in LDCR mode13 + * \endcode + */ + +#define IRQ_STATUS1_BASE ((uint8_t)(0xFC)) /*!< IRQ Events(RR, split into 4 registers) */ + +#define IRQ_STATUS1_READY ((uint8_t)(0x01)) /*!< IRQ: READY state in steady condition*/ +#define IRQ_STATUS1_STANDBY_DELAYED ((uint8_t)(0x02)) /*!< IRQ: STANDBY state after MCU_CK_CONF_CLOCK_TAIL_X clock cycles */ +#define IRQ_STATUS1_LOW_BATT_LVL ((uint8_t)(0x04)) /*!< IRQ: Battery level below threshold*/ +#define IRQ_STATUS1_POR ((uint8_t)(0x08)) /*!< IRQ: Power On Reset */ +#define IRQ_STATUS1_BOR ((uint8_t)(0x10)) /*!< IRQ: Brown out event (both accurate and inaccurate)*/ +#define IRQ_STATUS1_LOCK ((uint8_t)(0x20)) /*!< IRQ: LOCK state in steady condition */ +#define IRQ_STATUS1_PM_COUNT_EXPIRED ((uint8_t)(0x40)) /*!< IRQ: Power Management startup timer expiration (see reg PM_START_COUNTER, 0xB5) */ +#define IRQ_STATUS1_XO_COUNT_EXPIRED ((uint8_t)(0x80)) /*!< IRQ: Crystal oscillator settling time counter expired */ + +/** + * @} + */ + +/** @defgroup IRQ_STATUS2_Register + * @{ + */ + +/** + * \brief IRQ_STATUS2 registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 INT_STATUS2: IRQ status, if the correspondent bit is set and IRQ has been generated (according to the next table) + * + * Bit | Events Group Interrupt Event + * ------------------------------------------------------- + * 16 | READY state in steady condition14 + * 17 | STANDBY state switching in progress + * 18 | Low battery level + * 19 | Power-On reset + * 20 | Brown-Out event + * 21 | LOCK state in steady condition + * 22 | PM start-up timer expiration + * 23 | XO settling timeout + * \endcode + */ + +#define IRQ_STATUS2_BASE ((uint8_t)0xFB) /*!< IRQ Events(RR, split into 4 registers) */ + +#define IRQ_STATUS2_TX_FIFO_ALMOST_EMPTY ((uint8_t)0x01) /*!< IRQ: TX FIFO almost empty */ +#define IRQ_STATUS2_RX_FIFO_ALMOST_FULL ((uint8_t)0x02) /*!< IRQ: RX FIFO almost full */ +#define IRQ_STATUS2_RX_FIFO_ALMOST_EMPTY ((uint8_t)0x04) /*!< IRQ: RX FIFO almost empty */ +#define IRQ_STATUS2_MAX_BO_CCA_REACH ((uint8_t)0x08) /*!< IRQ: Max number of back-off during CCA */ +#define IRQ_STATUS2_VALID_PREAMBLE ((uint8_t)0x10) /*!< IRQ: Valid preamble detected */ +#define IRQ_STATUS2_VALID_SYNC ((uint8_t)0x20) /*!< IRQ: Sync word detected */ +#define IRQ_STATUS2_RSSI_ABOVE_TH ((uint8_t)(0x40)) /*!< IRQ: RSSI above threshold */ +#define IRQ_STATUS2_WKUP_TOUT_LDC ((uint8_t)(0x80)) /*!< IRQ: Wake-up timeout in LDC mode */ + +/** + * @} + */ + +/** @defgroup IRQ_STATUS3_Register + * @{ + */ + +/** + * \brief IRQ_STATUS3 registers + * \code + * Default value: 0x00 + * Read Write + * + * 7:0 INT_STATUS3: IRQ status, if the correspondent bit is set and IRQ has been generated (according to the next table) + * + * Bit | Events Group Interrupt Event + * ------------------------------------------------------- + * 24 | SYNTH locking timeout + * 25 | SYNTH calibration start-up time + * 26 | SYNTH calibration timeout + * 27 | TX circuitry start-up time + * 28 | RX circuitry start-up time + * 29 | RX operation timeout + * 30 | Others AES Endof Operation + * 31 | Reserved + * \endcode + */ +#define IRQ_STATUS3_BASE ((uint8_t)0xFA) /*!< IRQ Events(RR, split into 4 registers) */ + +#define IRQ_STATUS3_RX_DATA_READY ((uint8_t)0x01) /*!< IRQ: RX data ready */ +#define IRQ_STATUS3_RX_DATA_DISC ((uint8_t)0x02) /*!< IRQ: RX data discarded (upon filtering) */ +#define IRQ_STATUS3_TX_DATA_SENT ((uint8_t)0x04) /*!< IRQ: TX data sent */ +#define IRQ_STATUS3_MAX_RE_TX_REACH ((uint8_t)0x08) /*!< IRQ: Max re-TX reached */ +#define IRQ_STATUS3_CRC_ERROR ((uint8_t)0x10) /*!< IRQ: CRC error */ +#define IRQ_STATUS3_TX_FIFO_ERROR ((uint8_t)0x20) /*!< IRQ: TX FIFO underflow/overflow error */ +#define IRQ_STATUS3_RX_FIFO_ERROR ((uint8_t)0x40) /*!< IRQ: RX FIFO underflow/overflow error */ +#define IRQ_STATUS3_TX_FIFO_ALMOST_FULL ((uint8_t)0x80) /*!< IRQ: TX FIFO almost full */ + +/** + * @} + */ + +/** + * @} + */ + + +/** @defgroup MC_STATE_Registers + * @{ + */ + +/** @defgroup MC_STATE1_Register + * @{ + */ + +/** + * \brief MC_STATE1 registers + * \code + * Default value: 0x50 + * Read + * + * 7:4 Reserved. + * + * 3 ANT_SELECT: Currently selected antenna + * + * 2 TX_FIFO_Full: 1 - TX FIFO is full + * + * 1 RX_FIFO_Empty: 1 - RX FIFO is empty + * + * 0 ERROR_LOCK: 1 - RCO calibrator error + * \endcode + */ +#define MC_STATE1_BASE ((uint8_t)(0xC0)) /*!< MC_STATE1 register address (see the SpiritStatus struct */ + + +/** + * @} + */ + + +/** @defgroup MC_STATE0_Register + * @{ + */ + +/** + * \brief MC_STATE0 registers + * \code + * Default value: 0x00 + * Read + * + * 7:1 STATE[6:0]: Current MC state. + * + * REGISTER VALUE | STATE + * -------------------------------------------- + * 0x40 | STANDBY + * 0x36 | SLEEP + * 0x03 | READY + * 0x3B | PM setup + * 0x23 | XO settling + * 0x53 | SYNTH setup + * 0x1F | PROTOCOL + * 0x4F | SYNTH calibration + * 0x0F | LOCK + * 0x33 | RX + * 0x5F | TX + * + * 0 XO_ON: 1 - XO is operating + * \endcode + */ +#define MC_STATE0_BASE ((uint8_t)(0xC1)) /*!< MC_STATE0 register address. In this version ALL existing states have been inserted + and are still to be verified */ +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup Engineering-Test_Registers + * @{ + */ + +#define SYNTH_CONFIG1_BASE ((uint8_t)(0x9E)) /*!< Synthesizier registers: M, A, K data sync on positive/negative clock edges [4], + Enable Linearization of the charge pump [3], split time 1.75/3.45ns [2], VCO calibration window 16,32,64,128 clock cycles [1:0]*/ +#define SYNTH_CONFIG0_BASE ((uint8_t)(0x9F)) /*!< Enable DSM randomizer [7], Window width 1.2-7.5ns (Down-up) of lock detector*/ +#define VCOTH_BASE ((uint8_t)(0xA0)) /*!< Controls the threshold frequency between VCO low and VCO high [7:0] + VCOth frequency=2*fXO*(96+VCO_TH/16), fmin=4992 MHz, fmax=5820 MHz*/ +#define PM_CONFIG2_BASE ((uint8_t)(0xA4)) /*!< Enables high current buffer on Temperature sensor, sets SMPS options */ +#define PM_CONFIG1_BASE ((uint8_t)(0xA5)) /*!< Set SMPS options */ +#define PM_CONFIG0_BASE ((uint8_t)(0xA6)) /*!< Set SMPS options */ +#define VCO_CONFIG_BASE ((uint8_t)(0xA1)) /*!< Set VCO current [5:2]part and [1:0] part */ +#define XO_CONFIG_BASE ((uint8_t)(0xA7)) /*!< Clock management options from XO to digital part */ + +#define XO_RCO_TEST_BASE ((uint8_t)(0xB4)) /*!< Test of XO and RCO */ + +/** + * @} + */ + + +/** @addtogroup Commands + * @{ + */ + +#define COMMAND_TX ((uint8_t)(0x60)) /*!< Start to transmit; valid only from READY */ +#define COMMAND_RX ((uint8_t)(0x61)) /*!< Start to receive; valid only from READY */ +#define COMMAND_READY ((uint8_t)(0x62)) /*!< Go to READY; valid only from STANDBY or SLEEP or LOCK */ +#define COMMAND_STANDBY ((uint8_t)(0x63)) /*!< Go to STANDBY; valid only from READY */ +#define COMMAND_SLEEP ((uint8_t)(0x64)) /*!< Go to SLEEP; valid only from READY */ +#define COMMAND_LOCKRX ((uint8_t)(0x65)) /*!< Go to LOCK state by using the RX configuration of the synth; valid only from READY */ +#define COMMAND_LOCKTX ((uint8_t)(0x66)) /*!< Go to LOCK state by using the TX configuration of the synth; valid only from READY */ +#define COMMAND_SABORT ((uint8_t)(0x67)) /*!< Force exit form TX or RX states and go to READY state; valid only from TX or RX */ +#define COMMAND_LDC_RELOAD ((uint8_t)(0x68)) /*!< LDC Mode: Reload the LDC timer with the value stored in the LDC_PRESCALER / COUNTER + registers; valid from all states */ +#define COMMAND_SEQUENCE_UPDATE ((uint8_t)(0x69)) /*!< Autoretransmission: Reload the Packet sequence counter with the value stored in the PROTOCOL[2] register + valid from all states */ +#define COMMAND_AES_ENC ((uint8_t)(0x6A)) /*!< AES: Start the encryption routine; valid from all states; valid from all states */ +#define COMMAND_AES_KEY ((uint8_t)(0x6B)) /*!< AES: Start the procedure to compute the key for the decryption; valid from all states */ +#define COMMAND_AES_DEC ((uint8_t)(0x6C)) /*!< AES: Start the decryption routine using the current key; valid from all states */ +#define COMMAND_AES_KEY_DEC ((uint8_t)(0x6D)) /*!< AES: Compute the key and start the decryption; valid from all states */ +#define COMMAND_SRES ((uint8_t)(0x70)) /*!< Reset of all digital part, except SPI registers */ +#define COMMAND_FLUSHRXFIFO ((uint8_t)(0x71)) /*!< Clean the RX FIFO; valid from all states */ +#define COMMAND_FLUSHTXFIFO ((uint8_t)(0x72)) /*!< Clean the TX FIFO; valid from all states */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Timer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Timer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,239 @@ +/** + ****************************************************************************** + * @file SPIRIT_Timer.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT timers. + * @details + * + * This module provides API to configure the Spirit timing mechanisms. + * They allow the user to set the timer registers using raw values or + * compute them since the desired timer value is expressed in ms. + * Moreover the management of the Spirit LDCR mode can be done using + * these API. + * + * <b>Example:</b> + * @code + * ... + * + * SpiritTimerSetRxTimeoutMs(50.0); + * SpiritTimerSetWakeUpTimerMs(150.0); + * + * // IRQ configuration for RX_TIMEOUT and WAKEUP_TIMEOUT + * ... + * + * SpiritTimerLdcrMode(S_ENABLE); + * + * ... + * + * @endcode + * + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT1_TIMER_H +#define __SPIRIT1_TIMER_H + + +/* Includes ------------------------------------------------------------------*/ + +#include "SPIRIT_Regs.h" +#include "SPIRIT_Types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_Timer Timer + * @brief Configuration and management of SPIRIT Timers. + * @details See the file <i>@ref SPIRIT_Timer.h</i> for more details. + * @{ + */ + + +/** + * @defgroup Timer_Exported_Types Timer Exported Types + * @{ + */ + +/** + * @brief All the possible RX timeout stop conditions enumeration. + */ +typedef enum{ + + NO_TIMEOUT_STOP = 0x00, /*!< Timeout never stopped */ + TIMEOUT_ALWAYS_STOPPED = 0x08, /*!< Timeout always stopped (default) */ + RSSI_ABOVE_THRESHOLD = 0x04, /*!< Timeout stopped on RSSI above threshold */ + SQI_ABOVE_THRESHOLD = 0x02, /*!< Timeout stopped on SQI above threshold */ + PQI_ABOVE_THRESHOLD = 0x01, /*!< Timeout stopped on PQI above threshold */ + RSSI_AND_SQI_ABOVE_THRESHOLD = 0x06, /*!< Timeout stopped on both RSSI and SQI above threshold */ + RSSI_AND_PQI_ABOVE_THRESHOLD = 0x05, /*!< Timeout stopped on both RSSI and PQI above threshold */ + SQI_AND_PQI_ABOVE_THRESHOLD = 0x03, /*!< Timeout stopped on both SQI and PQI above threshold */ + ALL_ABOVE_THRESHOLD = 0x07, /*!< Timeout stopped only if RSSI, SQI and PQI are above threshold */ + RSSI_OR_SQI_ABOVE_THRESHOLD = 0x0E, /*!< Timeout stopped if one between RSSI or SQI are above threshold */ + RSSI_OR_PQI_ABOVE_THRESHOLD = 0x0D, /*!< Timeout stopped if one between RSSI or PQI are above threshold */ + SQI_OR_PQI_ABOVE_THRESHOLD = 0x0B, /*!< Timeout stopped if one between SQI or PQI are above threshold */ + ANY_ABOVE_THRESHOLD = 0x0F /*!< Timeout stopped if one among RSSI, SQI or SQI are above threshold */ + +} RxTimeoutStopCondition; + + +#define IS_RX_TIMEOUT_STOP_CONDITION(COND) ( COND == NO_TIMEOUT_STOP || \ + COND == TIMEOUT_ALWAYS_STOPPED || \ + COND == RSSI_ABOVE_THRESHOLD || \ + COND == SQI_ABOVE_THRESHOLD || \ + COND == PQI_ABOVE_THRESHOLD || \ + COND == RSSI_AND_SQI_ABOVE_THRESHOLD || \ + COND == RSSI_AND_PQI_ABOVE_THRESHOLD || \ + COND == SQI_AND_PQI_ABOVE_THRESHOLD || \ + COND == ALL_ABOVE_THRESHOLD || \ + COND == RSSI_OR_SQI_ABOVE_THRESHOLD || \ + COND == RSSI_OR_PQI_ABOVE_THRESHOLD || \ + COND == SQI_OR_PQI_ABOVE_THRESHOLD || \ + COND == ANY_ABOVE_THRESHOLD ) + + + +/** + * @} + */ + + +/** + * @defgroup Timer_Exported_Constants Timer Exported Constants + * @{ + */ + +/** + * @brief It represents the Time Step for RX_Timeout timer in case of 24 MHz Crystal, expressed in us. + * It is equal to 1210/(24*10^6). With this time step it is possible to fix the RX_Timeout to + * a minimum value of 50.417us to a maximum value of about 3.278 s. + * Remember that it is possible to have infinite RX_Timeout writing 0 in the RX_Timeout_Counter and/or RX_Timeout_Prescaler registers. + */ +#define RX_TCLK_24MHz 50.417f +#define IS_RX_TIMEOUT_24MHz(TIMEOUT) (TIMEOUT*1000)>=RX_TCLK_24MHz + +/** + * @brief It represents the Time Step for RX_Timeout timer in case of 26 MHz Crystal, expressed in us. + * It is equal to 1210/(26*10^6). With this time step it is possible to fix the RX_Timeout to + * a minimum value of 46.538us to a maximum value of about 3.026 s. + * Remember that it is possible to have infinite RX_Timeout writing 0 in the RX_Timeout_Counter register. + */ +#define RX_TCLK_26MHz 46.538f +#define IS_RX_TIMEOUT_26MHz(TIMEOUT) (TIMEOUT*1000)>=RX_TCLK_26MHz + +/** + * @brief It represents the Time Step for RX_Wakeup timer expressed in us. This timer is based on RCO (about 34.7 kHZ). + * With this time step it is possible to fix the Wakeup_Timeout to a minimum value of 28.818us to a maximum + * value of about 1.888 s. + */ +#define WAKEUP_TCLK 28.818f +#define IS_WKUP_TIMEOUT(TIMEOUT) (TIMEOUT*1000)>=WAKEUP_TCLK + + + +/** + * @} + */ + + +/** + * @defgroup Timer_Exported_Macros Timer Exported Macros + * @{ + */ + +#define SET_INFINITE_RX_TIMEOUT() SpiritTimerSetRxTimeoutCounter(0) + +/** + * @} + */ + + +/** + * @defgroup Timer_Exported_Functions Timer Exported Functions + * @{ + */ + +void SpiritTimerLdcrMode(SpiritFunctionalState xNewState); +void SpiritTimerLdcrAutoReload(SpiritFunctionalState xNewState); +SpiritFunctionalState SpiritTimerLdcrGetAutoReload(void); +void SpiritTimerSetRxTimeout(uint8_t cCounter , uint8_t cPrescaler); +void SpiritTimerSetRxTimeoutMs(float fDesiredMsec); +void SpiritTimerSetRxTimeoutCounter(uint8_t cCounter); +void SpiritTimerSetRxTimeoutPrescaler(uint8_t cPrescaler); +void SpiritTimerGetRxTimeout(float* pfTimeoutMsec, uint8_t* pcCounter , uint8_t* pcPrescaler); +void SpiritTimerSetWakeUpTimer(uint8_t cCounter , uint8_t cPrescaler); +void SpiritTimerSetWakeUpTimerMs(float fDesiredMsec); +void SpiritTimerSetWakeUpTimerCounter(uint8_t cCounter); +void SpiritTimerSetWakeUpTimerPrescaler(uint8_t cPrescaler); +void SpiritTimerSetWakeUpTimerReloadMs(float fDesiredMsec); +void SpiritTimerGetWakeUpTimer(float* pfWakeUpMsec, uint8_t* pcCounter , uint8_t* pcPrescaler); +void SpiritTimerSetWakeUpTimerReload(uint8_t cCounter , uint8_t cPrescaler); +void SpiritTimerSetWakeUpTimerReloadCounter(uint8_t cCounter); +void SpiritTimerSetWakeUpTimerReloadPrescaler(uint8_t cPrescaler); +void SpiritTimerGetWakeUpTimerReload(float* pfWakeUpReloadMsec, uint8_t* pcCounter , uint8_t* pcPrescaler); +void SpiritTimerComputeWakeUpValues(float fDesiredMsec , uint8_t* pcCounter , uint8_t* pcPrescaler); +void SpiritTimerComputeRxTimeoutValues(float fDesiredMsec , uint8_t* pcCounter , uint8_t* pcPrescaler); +void SpiritTimerSetRxTimeoutStopCondition(RxTimeoutStopCondition xStopCondition); +void SpiritTimerReloadStrobe(void); +uint16_t SpiritTimerGetRcoFrequency(void); + +/** + * @} + */ + +/** + * @} + */ + + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ +
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Types.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,276 @@ +/** + ****************************************************************************** + * @file SPIRIT_Types.h + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Header file for SPIRIT types. + * @details + * + * This module provide some types definitions which will be used in + * all the modules of this library. Here is defined also the global + * variable @ref g_xStatus which contains the status of Spirit and + * is updated every time an SPI transaction occurs. + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SPIRIT_GENERICTYPES_H +#define __SPIRIT_GENERICTYPES_H + + +/* Includes ------------------------------------------------------------------*/ + +/* Include all integer types definitions */ +#include <stdint.h> +#include <stdio.h> +#include "SPIRIT_Regs.h" + + + +#ifdef __cplusplus + extern "C" { +#endif + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @defgroup SPIRIT_Types Types + * @brief Module for SPIRIT types definition. + * * @details See the file <i>@ref SPIRIT_Types.h</i> for more details. + * @{ + */ + +/** + * @defgroup Types_Exported_Types Types Exported Types + * @{ + */ + +/** + * @brief Spirit Functional state. Used to enable or disable a specific option. + */ +typedef enum +{ + S_DISABLE = 0, + S_ENABLE = !S_DISABLE + +} SpiritFunctionalState; + +#define IS_SPIRIT_FUNCTIONAL_STATE(STATE) (STATE == S_DISABLE || STATE == S_ENABLE) + +/** + * @brief Spirit Flag status. Used to control the state of a flag. + */ +typedef enum +{ + S_RESET = 0, + S_SET = !S_RESET + +} SpiritFlagStatus; + +#define IS_SPIRIT_FLAG_STATUS(STATUS) (STATUS == S_RESET || STATUS == S_SET) + + +/** + * @brief boolean type enumeration. + */ +typedef enum +{ + S_FALSE = 0, + S_TRUE = !S_FALSE + +} SpiritBool; + + +/** + * @brief SPIRIT States enumeration. + */ +typedef enum +{ + MC_STATE_STANDBY =0x40, /*!< STANDBY */ + MC_STATE_SLEEP =0x36, /*!< SLEEP */ + MC_STATE_READY =0x03, /*!< READY */ + MC_STATE_PM_SETUP =0x3D, /*!< PM_SETUP */ + MC_STATE_XO_SETTLING =0x23, /*!< XO_SETTLING */ + MC_STATE_SYNTH_SETUP =0x53, /*!< SYNT_SETUP */ + MC_STATE_PROTOCOL =0x1F, /*!< PROTOCOL */ + MC_STATE_SYNTH_CALIBRATION =0x4F, /*!< SYNTH */ + MC_STATE_LOCK =0x0F, /*!< LOCK */ + MC_STATE_RX =0x33, /*!< RX */ + MC_STATE_TX =0x5F /*!< TX */ + +} SpiritState; + + + +/** + * @brief SPIRIT Status. This definition represents the single field of the SPIRIT + * status returned on each SPI transaction, equal also to the MC_STATE registers. + * This field-oriented structure allows user to address in simple way the single + * field of the SPIRIT status. + * The user shall define a variable of SpiritStatus type to access on SPIRIT status fields. + * @note The fields order in the structure depends on used endianness (little or big + * endian). The actual definition is valid ONLY for LITTLE ENDIAN mode. Be sure to + * change opportunely the fields order when use a different endianness. + */ + +typedef struct +{ + uint8_t XO_ON:1; /*!< This one bit field notifies if XO is operating + (XO_ON is 1) or not (XO_On is 0) */ + SpiritState MC_STATE: 7; /*!< This 7 bits field indicates the state of the + Main Controller of SPIRIT. The possible states + and their corresponding values are defined in + @ref SpiritState */ + uint8_t ERROR_LOCK: 1; /*!< This one bit field notifies if there is an + error on RCO calibration (ERROR_LOCK is 1) or + not (ERROR_LOCK is 0) */ + uint8_t RX_FIFO_EMPTY: 1; /*!< This one bit field notifies if RX FIFO is empty + (RX_FIFO_EMPTY is 1) or not (RX_FIFO_EMPTY is 0) */ + uint8_t TX_FIFO_FULL: 1; /*!< This one bit field notifies if TX FIFO is full + (TX_FIFO_FULL is 1) or not (TX_FIFO_FULL is 0) */ + uint8_t ANT_SELECT: 1; /*!< This one bit field notifies the currently selected + antenna */ + uint8_t : 4; /*!< This 4 bits field are reserved and equal to 5 */ + +}SpiritStatus; + + + +/** + * @} + */ + + +/** + * @defgroup Types_Exported_Constants Types Exported Constants + * @{ + */ + + +/** + * @} + */ + +/** + * @defgroup Types_Exported_Variables Types Exported Variables + * @{ + */ + +extern volatile SpiritStatus g_xStatus; + +/** + * @} + */ + +/** + * @defgroup Types_Exported_Macros Types Exported Macros + * @{ + */ + +#ifdef SPIRIT_USE_FULL_ASSERT + /** + * @brief The s_assert_param macro is used for function's parameters check. + * @param expr If expr is false, it calls assert_failed function which reports + * the name of the source file and the source line number of the call + * that failed. If expr is true, it returns no value. + * @retval None + */ + #define s_assert_param(expr) ((expr) ? (void)0 : s_assert_failed((uint8_t *)__FILE__, __LINE__)) + void s_assert_failed(uint8_t* file, uint32_t line); +#elif SPIRIT_USE_VCOM_ASSERT + /** + * @brief The s_assert_param macro is used for function's parameters check. + * @param expr If expr is false, it calls assert_failed function which reports + * the name of the source file and the source line number of the call + * that failed. If expr is true, it returns no value. + * @retval None + */ + #define s_assert_param(expr) ((expr) ? (void)0 : s_assert_failed((uint8_t *)__FILE__, __LINE__,#expr)) + void s_assert_failed(uint8_t* file, uint32_t line, char* expression); + +#elif SPIRIT_USE_FRAME_ASSERT + /** + * @brief The s_assert_param macro is used for function's parameters check. + * @param expr If expr is false, it calls assert_failed function which reports + * the name of the source file and the source line number of the call + * that failed. If expr is true, it returns no value. + * @retval None + */ +#define s_assert_param(expr) ((expr) ? (void)0 : s_assert_failed(#expr)) + void s_assert_failed(char* expression); +#else +#define s_assert_param(expr) {} +#endif + +/** + * @brief Returns the absolute value. + */ +#define S_ABS(a) ((a)>0?(a):-(a)) + + +/** + * @} + */ + + +/** + * @defgroup Types_Exported_Functions Types Exported Functions + * @{ + */ + +void SpiritRefreshStatus(void); + +/** + *@} + */ + +/** + * @} + */ + + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Aes.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Aes.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,319 @@ +/** + ****************************************************************************** + * @file SPIRIT_Aes.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT AES Engine. + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Aes.h" +#include "MCU_Interface.h" + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_Aes + * @{ + */ + + +/** + * @defgroup Aes_Private_TypesDefinitions AES Private Types Definitions + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup Aes_Private_Defines AES Private Defines + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup Aes_Private_Macros AES Private Macros + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup Aes_Private_Variables AES Private Variables + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup Aes_Private_FunctionPrototypes AES Private Function Prototypes + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup Aes_Private_Functions AES Private Functions + * @{ + */ + + +/** + * @brief Enables or Disables the AES engine. + * @param xNewState new state for AES engine. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None + */ +void SpiritAesMode(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Modifies the register value */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |= AES_MASK; + } + else + { + tempRegValue &= ~AES_MASK; + } + + /* Writes the ANA_FUNC_CONF0 register to enable or disable the AES engine */ + g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Writes the data to encrypt or decrypt, or the encryption key for the + * derive decryption key operation into the AES_DATA_IN registers. + * @param pcBufferDataIn pointer to the user data buffer. The first byte of the array + * shall be the MSB byte and it will be put in the AES_DATA_IN[0] register, while + * the last one shall be the LSB and it will be put in the AES_DATA_IN[cDataLength-1] + * register. If data to write are less than 16 bytes the remaining AES_DATA_IN registers + * will be filled with bytes equal to 0. This parameter is an uint8_t*. + * @param cDataLength length of data in bytes. + * This parameter is an uint8_t. + * @retval None + */ +void SpiritAesWriteDataIn(uint8_t* pcBufferDataIn, uint8_t cDataLength) +{ + uint8_t i, dataInArray[16]; + + /* Verifies that there are no more than 16 bytes */ + (cDataLength>16) ? (cDataLength=16) : cDataLength; + + /* Fill the dataInArray with the data buffer, using padding */ + for(i=0;i<16;i++) + { + (i<(16 - cDataLength)) ? (dataInArray[i]=0):(dataInArray[i]=pcBufferDataIn[15-i]); + + } + + /* Writes the AES_DATA_IN registers */ + g_xStatus = SpiritSpiWriteRegisters(AES_DATA_IN_15_BASE, 16, dataInArray); + +} + + +/** + * @brief Returns the encrypted or decrypted data or the decription key from the AES_DATA_OUT register. + * @param pcBufferDataOut pointer to the user data buffer. The AES_DATA_OUT[0] + * register value will be put as first element of the buffer (MSB), while the + * AES_DAT_OUT[cDataLength-1] register value will be put as last element of the buffer (LSB). + * This parameter is a uint8_t*. + * @param cDataLength length of data to read in bytes. + * This parameter is a uint8_t. + * @retval None + */ +void SpiritAesReadDataOut(uint8_t* pcBufferDataOut, uint8_t cDataLength) +{ + uint8_t address, dataOutArray[16]; + + /* Verifies that there are no more than 16 bytes */ + (cDataLength>16) ? (cDataLength=16) : cDataLength; + + /* Evaluates the address of AES_DATA_OUT from which start to read */ + address = AES_DATA_OUT_15_BASE+16-cDataLength; + + /* Reads the exact number of AES_DATA_OUT registers */ + g_xStatus = (SpiritSpiReadRegisters(address, cDataLength, dataOutArray)); + + /* Copy in the user buffer the read values changing the order */ + for(int i = (cDataLength-1); i>=0; i--) + { + *pcBufferDataOut = dataOutArray[i]; + pcBufferDataOut++; + } + +} + + +/** + * @brief Writes the encryption key into the AES_KEY_IN register. + * @param pcKey pointer to the buffer of 4 words containing the AES key. + * The first byte of the buffer shall be the most significant byte AES_KEY_0 of the AES key. + * The last byte of the buffer shall be the less significant byte AES_KEY_15 of the AES key. + * This parameter is an uint8_t*. + * @retval None + */ +void SpiritAesWriteKey(uint8_t* pcKey) +{ + uint8_t pcTempKey[16]; + for (uint8_t i = 0; i < 16; i++) + { + pcTempKey[15-i] = pcKey[i]; + } + + /* Writes the AES_DATA_IN registers */ + g_xStatus = SpiritSpiWriteRegisters(AES_KEY_IN_15_BASE, 16, pcTempKey); + +} + +/** + * @brief Returns the encryption/decryption key from the AES_KEY_IN register. + * @param pcKey pointer to the buffer of 4 words (16 bytes) containing the AES key. + * The first byte of the buffer shall be the most significant byte AES_KEY_0 of the AES key. + * The last byte of the buffer shall be the less significant byte AES_KEY_15 of the AES key. + * This parameter is an uint8_t*. + * @retval None + */ +void SpiritAesReadKey(uint8_t* pcKey) +{ + uint8_t pcTempKey[16]; + + /* Reads the AES_DATA_IN registers */ + g_xStatus = SpiritSpiReadRegisters(AES_KEY_IN_15_BASE, 16, pcTempKey); + + + for (uint8_t i = 0; i < 16; i++) + pcKey[i] = pcTempKey[15-i]; + +} + + + +/** + * @brief Derives the decryption key from a given encryption key. + * @param None. + * @retval None. + */ +void SpiritAesDeriveDecKeyFromEnc(void) +{ + /* Sends the COMMAND_AES_KEY command */ + g_xStatus = SpiritSpiCommandStrobes(COMMAND_AES_KEY); + +} + + +/** + * @brief Executes the encryption operation. + * @param None. + * @retval None. + */ +void SpiritAesExecuteEncryption(void) +{ + /* Sends the COMMAND_AES_ENC command */ + g_xStatus = SpiritSpiCommandStrobes(COMMAND_AES_ENC); + +} + + +/** + * @brief Executes the decryption operation. + * @param None. + * @retval None. + */ +void SpiritAesExecuteDecryption(void) +{ + /* Sends the COMMAND_AES_DEC command */ + g_xStatus = SpiritSpiCommandStrobes(COMMAND_AES_DEC); + +} + + +/** + * @brief Executes the key derivation and the decryption operation. + * @param None. + * @retval None. + */ +void SpiritAesDeriveDecKeyExecuteDec(void) +{ + /* Sends the COMMAND_AES_KEY_DEC command */ + g_xStatus = SpiritSpiCommandStrobes(COMMAND_AES_KEY_DEC); + +} + + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Calibration.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Calibration.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,491 @@ +/** + ****************************************************************************** + * @file SPIRIT_Calibration.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT VCO-RCO calibration. + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Calibration.h" +#include "MCU_Interface.h" + + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_Calibration + * @{ + */ + + +/** + * @defgroup Calibration_Private_TypesDefinitions Calibration Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Calibration_Private_Defines Calibration Private Defines + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup Calibration_Private_Macros Calibration Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Calibration_Private_Variables Calibration Private Variables + * @{ + */ + +/** + *@} + */ + + + +/** + * @defgroup Calibration_Private_FunctionPrototypes Calibration Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Calibration_Private_Functions Calibration Private Functions + * @{ + */ + +/** + * @brief Enables or Disables the RCO calibration. + * @param xNewState new state for RCO calibration. + This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritCalibrationRco(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + + /* Build new value for the register */ + if(xNewState==S_ENABLE) + { + tempRegValue |= PROTOCOL2_RCO_CALIBRATION_MASK; + } + else + { + tempRegValue &= ~PROTOCOL2_RCO_CALIBRATION_MASK; + } + + /* Writes register to enable or disable the RCO calibration */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Enables or Disables the VCO calibration. + * @param xNewState new state for VCO calibration. + This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritCalibrationVco(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + + /* Build new value for the register */ + if(xNewState==S_ENABLE) + tempRegValue |= PROTOCOL2_VCO_CALIBRATION_MASK; + else + tempRegValue &= ~PROTOCOL2_VCO_CALIBRATION_MASK; + + /* Writes register to enable or disable the VCO calibration */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets the RCO calibration words. + * @param cRwt RWT word for RCO calibration. + * This parameter can be a value of uint8_t. + * @param cRfb RFB word for RCO calibration. + * This parameter can be a value of uint8_t. + * @retval None. + */ +void SpiritCalibrationSetRcoCalWords(uint8_t cRwt, uint8_t cRfb) +{ + uint8_t tempRegValue[2]; + + /* Build the value of RWT and the MSbits of the RFB word */ + tempRegValue[0] = (cRwt << 4) | (cRfb >> 1); + + /* Reads the register value to update the LSbit of RFB */ + g_xStatus = SpiritSpiReadRegisters(RCO_VCO_CALIBR_IN1_BASE, 1, &tempRegValue[1]); + + /* Build new value for the register */ + tempRegValue[1] = (tempRegValue[1] & 0x7F) | (cRfb<<7); + + /* Writes the new value for RCO calibration words */ + g_xStatus = SpiritSpiWriteRegisters(RCO_VCO_CALIBR_IN2_BASE, 2, tempRegValue); + +} + + +/** + * @brief Returns the RCO calibration words. + * @param pcRwt pointer to the variable in which the RWT word has to be stored. + * This parameter is a variable of uint8_t*. + * @param pcRfb pointer to the variable in which the RFB word has to be stored. + * This parameter is a variable of uint8_t*. + * @retval None. + */ +void SpiritCalibrationGetRcoCalWords(uint8_t* pcRwt, uint8_t* pcRfb) +{ + uint8_t tempRegValue[2]; + + /* Reads the registers values */ + g_xStatus = SpiritSpiReadRegisters(RCO_VCO_CALIBR_OUT1_BASE, 2, tempRegValue); + + /* Build the RWT value */ + (*pcRwt) = tempRegValue[0] >> 4; + /* Build the RFB value */ + (*pcRfb) = (tempRegValue[0] & 0x0F)<<1 | (tempRegValue[1]>>7); + +} + + +/** + * @brief Returns the VCO calibration data from internal VCO calibrator. + * @param None. + * @retval uint8_t VCO calibration data word. + */ +uint8_t SpiritCalibrationGetVcoCalData(void) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(RCO_VCO_CALIBR_OUT0_BASE, 1, &tempRegValue); + + /* Build and returns the VCO calibration data value */ + return (tempRegValue & 0x7F); + +} + + +/** + * @brief Sets the VCO calibration data to be used in TX mode. + * @param cVcoCalData calibration data word to be set. + * This parameter is a variable of uint8_t. + * @retval None. + */ +void SpiritCalibrationSetVcoCalDataTx(uint8_t cVcoCalData) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(RCO_VCO_CALIBR_IN1_BASE, 1, &tempRegValue); + + /* Build the value to be written */ + tempRegValue &= 0x80; + tempRegValue |= cVcoCalData; + + /* Writes the new value of calibration data in TX */ + g_xStatus = SpiritSpiWriteRegisters(RCO_VCO_CALIBR_IN1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the actual VCO calibration data used in TX mode. + * @param None. + * @retval uint8_t Calibration data word used in TX mode. + */ +uint8_t SpiritCalibrationGetVcoCalDataTx(void) +{ + uint8_t tempRegValue; + + /* Reads the register containing the calibration data word used in TX mode */ + g_xStatus = SpiritSpiReadRegisters(RCO_VCO_CALIBR_IN1_BASE, 1, &tempRegValue); + + /* Mask the VCO_CALIBR_TX field and returns the value */ + return (tempRegValue & 0x7F); + +} + + +/** + * @brief Sets the VCO calibration data to be used in RX mode. + * @param cVcoCalData calibration data word to be set. + * This parameter is a variable of uint8_t. + * @retval None. + */ +void SpiritCalibrationSetVcoCalDataRx(uint8_t cVcoCalData) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(RCO_VCO_CALIBR_IN0_BASE, 1, &tempRegValue); + + /* Build the value to be written */ + tempRegValue &= 0x80; + tempRegValue |= cVcoCalData; + + /* Writes the new value of calibration data in RX */ + g_xStatus = SpiritSpiWriteRegisters(RCO_VCO_CALIBR_IN0_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the actual VCO calibration data used in RX mode. + * @param None. + * @retval uint8_t Calibration data word used in RX mode. + */ +uint8_t SpiritCalibrationGetVcoCalDataRx(void) +{ + uint8_t tempRegValue; + + /* Reads the register containing the calibration data word used in TX mode */ + g_xStatus = SpiritSpiReadRegisters(RCO_VCO_CALIBR_IN0_BASE, 1, &tempRegValue); + + /* Mask the VCO_CALIBR_RX field and returns the value */ + return (tempRegValue & 0x7F); + +} + + +/** + * @brief Sets the VCO calibration window. + * @param xRefWord value of REFWORD corresponding to the Ref_period according to the formula: CALIBRATION_WIN = 11*Ref_period/fxo. + This parameter can be a value of @ref VcoWin. + * @retval None. + */ +void SpiritCalibrationSetVcoWindow(VcoWin xRefWord) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_VCO_WIN(xRefWord)); + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue); + + /* Build the values to be written */ + tempRegValue &= 0xFC; + tempRegValue |= xRefWord; + + /* Writes the new value of VCO calibration window */ + g_xStatus = SpiritSpiWriteRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the VCO calibration window. + * @param None. + * @retval VcoWin Value of REFWORD corresponding to the Ref_period according to the formula: CALIBRATION_WIN = 11*Ref_period/fxo. + * This parameter can be a value of @ref VcoWin. + */ +VcoWin SpiritCalibrationGetVcoWindow(void) +{ + uint8_t tempRegValue1, tempRegValue2; + VcoWin refWord; + + /* Reads the register containing the REFWORD value */ + g_xStatus = SpiritSpiReadRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue1); + + /* Reads the Xtal configuration */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue2); + + /* Mask the REFWORD field */ + tempRegValue1 &= 0x03; + + /* Mask the 24_26_MHz_SELECT field */ + tempRegValue2 = ((tempRegValue2 & 0x40)>>6); + + /* In case of 26 MHz crystal */ + if(tempRegValue2) + { + switch(tempRegValue1) + { + case 0: + refWord = CALIB_TIME_6_77_US_26MHZ; + break; + case 1: + refWord = CALIB_TIME_13_54_US_26MHZ; + break; + case 2: + refWord = CALIB_TIME_27_08_US_26MHZ; + break; + case 3: + refWord = CALIB_TIME_54_15_US_26MHZ; + break; + } + } + + /* In case of 24 MHz crystal */ + else + { + switch(tempRegValue1) + { + case 0: + refWord = CALIB_TIME_7_33_US_24MHZ; + break; + case 1: + refWord = CALIB_TIME_14_67_US_24MHZ; + break; + case 2: + refWord = CALIB_TIME_29_33_US_24MHZ; + break; + case 3: + refWord = CALIB_TIME_58_67_US_24MHZ; + break; + } + } + + return refWord; + +} + +/** + * @brief Selects a VCO. + * @param xVco can be VCO_H or VCO_L according to which VCO select. + * This parameter can be a value of @ref VcoSel. + * @retval None. + */ +void SpiritCalibrationSelectVco(VcoSel xVco) +{ + uint8_t tempRegValue; + + /* Check the parameter */ + s_assert_param(IS_VCO_SEL(xVco)); + + SpiritSpiReadRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue); + + tempRegValue &= 0xF9; + + if(xVco == VCO_H) + { + tempRegValue |= 0x02; + + } + else + { + tempRegValue |= 0x04; + } + SpiritSpiWriteRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue); + +} + + + +/** + * @brief Returns the VCO selected. + * @param void. + * @retval VCO_H or VCO_L according to which VCO selected. + * This parameter can be a value of @ref VcoSel. + */ +VcoSel SpiritCalibrationGetVcoSelecttion(void) +{ + uint8_t tempRegValue; + + SpiritSpiReadRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue); + + tempRegValue = (tempRegValue>>1)&0x3; + + if(tempRegValue == 0x01) + { + return VCO_H; + + } + else + { + return VCO_L; + } + +} + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Commands.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Commands.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,144 @@ +/** + ****************************************************************************** + * @file SPIRIT_Commands.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Management of SPIRIT Commands. + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Commands.h" +#include "MCU_Interface.h" + + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_Commands + * @{ + */ + + +/** + * @defgroup Commands_Private_TypesDefinitions Commands Private TypesDefinitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Commands_Private_Defines Commands Private Defines + * @{ + */ + +/** + *@} + */ + +/** + * @defgroup Commands_Private_Macros Commands Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Commands_Private_Variables Commands Private Variables + * @{ + */ + +/** + *@} + */ + + + +/** + * @defgroup Commands_Private_FunctionPrototypes Commands Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Commands_Private_Functions Commands Private Functions + * @{ + */ + +/** + * @brief Sends a specific command to SPIRIT. + * @param xCommandCode code of the command to send. + This parameter can be any value of @ref SpiritCmd. + * @retval None. + */ +void SpiritCmdStrobeCommand(SpiritCmd xCommandCode) +{ + /* Check the parameters */ + s_assert_param(IS_SPIRIT_CMD(xCommandCode)); + + g_xStatus = SpiritSpiCommandStrobes((uint8_t) xCommandCode); +} + + +/** + *@} + */ + + +/** + *@} + */ + + +/** + *@} + */ + + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Csma.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Csma.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,600 @@ +/** + ****************************************************************************** + * @file SPIRIT_Csma.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT CSMA. + * @details + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Csma.h" +#include "MCU_Interface.h" + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_Csma + * @{ + */ + + +/** + * @defgroup Csma_Private_TypesDefinitions CSMA Private TypesDefinitions + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup Csma_Private_Defines CSMA Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Csma_Private_Macros CSMA Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Csma_Private_Variables CSMA Private Variables + * @{ + */ + +/** + *@} + */ + + + +/** + * @defgroup Csma_Private_FunctionPrototypes CSMA Private FunctionPrototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Csma_Private_Functions CSMA Private Functions + * @{ + */ + + +/** + * @brief Initializes the SPIRIT CSMA according to the specified parameters in the CsmaInit. + * @param pxCsmaInit Csma init structure. + * This parameter is a pointer to @ref CsmaInit. + * @retval None. + */ +void SpiritCsmaInit(CsmaInit* pxCsmaInit) +{ + uint8_t tempRegValue[5]; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxCsmaInit->xCsmaPersistentMode)); + s_assert_param(IS_CCA_PERIOD(pxCsmaInit->xMultiplierTbit)); + s_assert_param(IS_CSMA_LENGTH(pxCsmaInit->xCcaLength)); + s_assert_param(IS_BU_COUNTER_SEED(pxCsmaInit->nBuCounterSeed)); + s_assert_param(IS_BU_PRESCALER(pxCsmaInit->cBuPrescaler)); + s_assert_param(IS_CMAX_NB(pxCsmaInit->cMaxNb)); + + /* CSMA BU counter seed (MSB) config */ + tempRegValue[0] = (uint8_t)(pxCsmaInit->nBuCounterSeed >> 8); + + /* CSMA BU counter seed (LSB) config */ + tempRegValue[1] = (uint8_t) pxCsmaInit->nBuCounterSeed; + + /* CSMA BU prescaler config and CCA period config */ + tempRegValue[2] = (pxCsmaInit->cBuPrescaler << 2) | pxCsmaInit->xMultiplierTbit; + + /* CSMA CCA length config and max number of back-off */ + tempRegValue[3] = (pxCsmaInit->xCcaLength | pxCsmaInit->cMaxNb); + + /* Reads the PROTOCOL1_BASE register value, to write the SEED_RELOAD and CSMA_PERS_ON fields */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue[4]); + + /* Writes the new value for persistent mode */ + if(pxCsmaInit->xCsmaPersistentMode==S_ENABLE) + { + tempRegValue[4] |= PROTOCOL1_CSMA_PERS_ON_MASK; + } + else + { + tempRegValue[4] &= ~PROTOCOL1_CSMA_PERS_ON_MASK; + } + + /* Writes PROTOCOL1_BASE register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue[4]); + + /* Writes CSMA_CONFIGx_BASE registers */ + g_xStatus = SpiritSpiWriteRegisters(CSMA_CONFIG3_BASE, 4, tempRegValue); + +} + + + /** + * @brief Returns the fitted structure CsmaInit starting from the registers values. + * @param pxCsmaInit Csma structure to be fitted. + * This parameter is a pointer to @ref CsmaInit. + * @retval None. + */ +void SpiritCsmaGetInfo(CsmaInit* pxCsmaInit) +{ + uint8_t tempRegValue[5]; + + /* Reads PROTOCOL1_BASE register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue[4]); + + /* Reads CSMA_CONFIGx_BASE registers */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG3_BASE, 4, tempRegValue); + + /* Reads the bu counter seed */ + pxCsmaInit->nBuCounterSeed = (uint16_t)tempRegValue[1] | ((uint16_t)(tempRegValue[0] << 8)); + + /* Reads the bu prescaler */ + pxCsmaInit->cBuPrescaler = tempRegValue[2]>>2; + + /* Reads the Cca period */ + pxCsmaInit->xMultiplierTbit = (CcaPeriod)(tempRegValue[2] & 0x03); + + /* Reads the Cca length */ + pxCsmaInit->xCcaLength = (CsmaLength)(tempRegValue[3]&0xF0); + + /* Reads the max number of back off */ + pxCsmaInit->cMaxNb = tempRegValue[3] & 0x07; + + /* Reads the persistent mode enable bit */ + pxCsmaInit->xCsmaPersistentMode = (SpiritFunctionalState)((tempRegValue[4]>>1) & 0x01); + +} + + +/** + * @brief Enables or Disables the CSMA. + * @param xNewState the state of the CSMA mode. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritCsma(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PROTOCOL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Sets or resets the CSMA enable bit */ + if(xNewState==S_ENABLE) + { + tempRegValue |= PROTOCOL1_CSMA_ON_MASK; + } + else + { + tempRegValue &= ~PROTOCOL1_CSMA_ON_MASK; + } + + /* Writes the new value on the PROTOCOL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + +} + +/** + * @brief Gets the CSMA mode. Says if it is enabled or disabled. + * @param None. + * @retval SpiritFunctionalState: CSMA mode. + */ +SpiritFunctionalState SpiritCsmaGetCsma(void) +{ + uint8_t tempRegValue; + + /* Reads the PROTOCOL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Return if set or reset */ + if(tempRegValue & PROTOCOL1_CSMA_ON_MASK) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } + +} + +/** + * @brief Enables or Disables the persistent CSMA mode. + * @param xNewState the state of the persistent CSMA mode. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritCsmaPersistentMode(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PROTOCOL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Enables/disables the CSMA persistent mode */ + if(xNewState==S_ENABLE) + { + tempRegValue |= PROTOCOL1_CSMA_PERS_ON_MASK; + } + else + { + tempRegValue &= ~PROTOCOL1_CSMA_PERS_ON_MASK; + } + + /* Writes the new vaue on the PROTOCOL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Gets the persistent CSMA mode. + * @param None. + * @retval SpiritFunctionalState: CSMA persistent mode. + */ +SpiritFunctionalState SpiritCsmaGetPersistentMode(void) +{ + uint8_t tempRegValue; + + /* Reads the PROTOCOL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Return if set or reset */ + if(tempRegValue & PROTOCOL1_CSMA_PERS_ON_MASK) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } + +} + + +/** + * @brief Enables or Disables the seed reload mode (if enabled it reloads the back-off generator seed using the value written in the BU_COUNTER_SEED register). + * @param xNewState the state of the seed reload mode. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritCsmaSeedReloadMode(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PROTOCOL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Enables/disables the seed reload mode */ + if(xNewState==S_ENABLE) + { + tempRegValue |= PROTOCOL1_SEED_RELOAD_MASK; + } + else + { + tempRegValue &= ~PROTOCOL1_SEED_RELOAD_MASK; + } + + /* Writes the new value on the PROTOCOL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Gets the seed reload mode. + * @param None. + * @retval SpiritFunctionalState: CSMA seed reload mode. + */ +SpiritFunctionalState SpiritCsmaGetSeedReloadMode(void) +{ + uint8_t tempRegValue; + + /* Reads the PROTOCOL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Return if set or reset */ + if(tempRegValue & PROTOCOL1_SEED_RELOAD_MASK) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } +} + + +/** + * @brief Sets the BU counter seed (BU_COUNTER_SEED register). The CSMA back off time is given by the formula: BO = rand(2^NB)*BU. + * @param nBuCounterSeed seed of the random number generator used to apply the BBE algorithm. + * This parameter is an uint16_t. + * @retval None. + */ +void SpiritCsmaSetBuCounterSeed(uint16_t nBuCounterSeed) +{ + uint8_t tempRegValue[2]; + + /* Check parameters */ + s_assert_param(IS_BU_COUNTER_SEED(nBuCounterSeed)); + + /* Build value (MSB)*/ + tempRegValue[0]=(uint8_t)(nBuCounterSeed>>8); + /* Build value (LSB) */ + tempRegValue[1]=(uint8_t)nBuCounterSeed; + + /* Writes the CSMA_CONFIG3 registers */ + g_xStatus = SpiritSpiWriteRegisters(CSMA_CONFIG3_BASE, 2, tempRegValue); + +} + +/** + * @brief Returns the BU counter seed (BU_COUNTER_SEED register). + * @param None. + * @retval uint16_t Seed of the random number generator used to apply the BBE algorithm. + */ +uint16_t SpiritCsmaGetBuCounterSeed(void) +{ + uint8_t tempRegValue[2]; + + /* Reads the CSMA_CONFIGx registers value */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG3_BASE, 2, tempRegValue); + + /* Build the counter seed and return it */ + return ((uint16_t)tempRegValue[1] + (((uint16_t)tempRegValue[0])<<8)); + +} + + +/** + * @brief Sets the BU prescaler. The CSMA back off time is given by the formula: BO = rand(2^NB)*BU. + * @param cBuPrescaler used to program the back-off unit BU. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritCsmaSetBuPrescaler(uint8_t cBuPrescaler) +{ + uint8_t tempRegValue; + + /* Check parameters */ + s_assert_param(IS_BU_PRESCALER(cBuPrescaler)); + + /* Reads the CSMA_CONFIG1 register value */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG1_BASE, 1, &tempRegValue); + + /* Build the new value for the BU prescaler */ + tempRegValue &= 0x03; + tempRegValue |= (cBuPrescaler<<2); + + /* Writes the new value on the CSMA_CONFIG1_BASE register */ + g_xStatus = SpiritSpiWriteRegisters(CSMA_CONFIG1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the BU prescaler. + * @param None. + * @retval uint8_t Value back-off unit (BU). + */ +uint8_t SpiritCsmaGetBuPrescaler(void) +{ + uint8_t tempRegValue; + + /* Reads the CSMA_CONFIG1 register value */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG1_BASE, 1, &tempRegValue); + + /* Build and return the BU prescaler value */ + return (tempRegValue >> 2); + +} + + +/** + * @brief Sets the CCA period. + * @param xMultiplierTbit value of CCA period to store. + * This parameter can be a value of @ref CcaPeriod. + * @retval None. + */ +void SpiritCsmaSetCcaPeriod(CcaPeriod xMultiplierTbit) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_CCA_PERIOD(xMultiplierTbit)); + + /* Reads the CSMA_CONFIG1 register value */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG1_BASE, 1, &tempRegValue); + + /* Build the new value setting the the CCA period */ + tempRegValue &= 0xFC; + tempRegValue |= xMultiplierTbit; + + /* Writes the new value on the CSMA_CONFIG1 register */ + g_xStatus = SpiritSpiWriteRegisters(CSMA_CONFIG1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the CCA period. + * @param None. + * @retval CcaPeriod CCA period. + */ +CcaPeriod SpiritCsmaGetCcaPeriod(void) +{ + uint8_t tempRegValue; + + /* Reads the CSMA_CONFIG1 register value */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG1_BASE, 1, &tempRegValue); + + /* Build and return the CCA period value */ + return (CcaPeriod)(tempRegValue & 0x03); + +} + + +/** + * @brief Sets the CCA length. + * @param xCcaLength the CCA length (a value between 1 and 15 that multiplies the CCA period). + * This parameter can be any value of @ref CsmaLength. + * @retval None. + */ +void SpiritCsmaSetCcaLength(CsmaLength xCcaLength) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_CSMA_LENGTH(xCcaLength)); + + /* Reads the CSMA_CONFIG0 register value */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG0_BASE, 1, &tempRegValue); + + /* Build the value of CCA length to be set */ + tempRegValue &= 0x0F; + tempRegValue |= xCcaLength; + + /* Writes the new value on the CSMA_CONFIG0 register */ + g_xStatus = SpiritSpiWriteRegisters(CSMA_CONFIG0_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the CCA length. + * @param None. + * @retval uint8_t CCA length. + */ +uint8_t SpiritCsmaGetCcaLength(void) +{ + uint8_t tempRegValue; + + /* Reads the CSMA_CONFIG0 register value */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG0_BASE, 1, &tempRegValue); + + /* Build and return the CCA length */ + return tempRegValue >> 4; + +} + + +/** + * @brief Sets the max number of back-off. If reached Spirit stops the transmission. + * @param cMaxNb the max number of back-off. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritCsmaSetMaxNumberBackoff(uint8_t cMaxNb) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_CMAX_NB(cMaxNb)); + + /* Reads the CSMA_CONFIG0 register value */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG0_BASE, 1, &tempRegValue); + + /* Build the value of max back off to be set */ + tempRegValue &= 0xF8; + tempRegValue |= cMaxNb; + + /* Writes the new value on the CSMA_CONFIG0 register */ + g_xStatus = SpiritSpiWriteRegisters(CSMA_CONFIG0_BASE, 1, &tempRegValue); +} + +/** + * @brief Returns the max number of back-off. + * @param None. + * @retval uint8_t Max number of back-off. + */ +uint8_t SpiritCsmaGetMaxNumberBackoff(void) +{ + uint8_t tempRegValue; + + /* Reads the CSMA_CONFIG0 register value */ + g_xStatus = SpiritSpiReadRegisters(CSMA_CONFIG0_BASE, 1, &tempRegValue); + + /* Build and return the max number of back-off */ + return (tempRegValue & 0x07); + +} + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_DirectRF.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_DirectRF.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,215 @@ +/** + ****************************************************************************** + * @file SPIRIT_DirectRF.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT direct transmission / receive modes. + * @details + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_DirectRF.h" +#include "MCU_Interface.h" + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_DirectRf + * @{ + */ + + +/** + * @defgroup DirectRf_Private_TypesDefinitions Direct RF Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup DirectRf_Private_Defines Direct RF Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup DirectRf_Private_Macros Direct RF Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup DirectRf_Private_Variables Direct RF Private Variables + * @{ + */ + +/** + *@} + */ + + + +/** + * @defgroup DirectRf_Private_FunctionPrototypes Direct RF Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup DirectRf_Private_Functions Direct RF Private Functions + * @{ + */ + +/** + * @brief Sets the DirectRF RX mode of SPIRIT. + * @param xDirectRx code of the desired mode. + * This parameter can be any value of @ref DirectRx. + * @retval None. + */ +void SpiritDirectRfSetRxMode(DirectRx xDirectRx) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_DIRECT_RX(xDirectRx)); + + /* Reads the register value */ + SpiritSpiReadRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Build the value to be stored */ + tempRegValue &= ~PCKTCTRL3_RX_MODE_MASK; + tempRegValue |= (uint8_t)xDirectRx; + + /* Writes value on register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the DirectRF RX mode of SPIRIT. + * @param None. + * @retval DirectRx Direct Rx mode. + */ +DirectRx SpiritDirectRfGetRxMode(void) +{ + uint8_t tempRegValue; + + /* Reads the register value and mask the RX_Mode field */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Rebuild and return value */ + return (DirectRx)(tempRegValue & 0x30); + +} + + +/** + * @brief Sets the TX mode of SPIRIT. + * @param xDirectTx code of the desired source. + * This parameter can be any value of @ref DirectTx. + * @retval None. + */ +void SpiritDirectRfSetTxMode(DirectTx xDirectTx) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_DIRECT_TX(xDirectTx)); + + /* Reads the register value */ + SpiritSpiReadRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Build the value to be stored */ + tempRegValue &= ~PCKTCTRL1_TX_SOURCE_MASK; + tempRegValue |= (uint8_t)xDirectTx; + + /* Writes value on register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the DirectRF TX mode of SPIRIT. + * @param None. + * @retval DirectTx Direct Tx mode. + */ +DirectTx SpiritDirectRfGetTxMode(void) +{ + uint8_t tempRegValue; + + /* Reads the register value and mask the RX_Mode field */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Returns value */ + return (DirectTx)(tempRegValue & 0x0C); + +} + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_General.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_General.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,449 @@ +/** + ****************************************************************************** + * @file SPIRIT_General.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT General functionalities. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_General.h" +#include "MCU_Interface.h" + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_General + * @{ + */ + + +/** + * @defgroup General_Private_TypesDefinitions General Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup General_Private_Defines General Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup General_Private_Macros General Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup General_Private_Variables General Private Variables + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup General_Private_FunctionPrototypes General Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup General_Private_Functions General Private Functions + * @{ + */ + +/** + * @brief Enables or Disables the output of battery level detector. + * @param xNewState new state for battery level detector. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None + */ +void SpiritGeneralBatteryLevel(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the ANA_FUNC_CONF0_BASE register value */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + + /* Build the value to be stored */ + if(xNewState == S_ENABLE) + { + tempRegValue |= BATTERY_LEVEL_MASK; + } + else + { + tempRegValue &= ~BATTERY_LEVEL_MASK; + } + + /* Writes the new value */ + g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets the battery level. + * @param xBatteryLevel new state for battery level. + * This parameter can be a value of @ref BatteryLevel. + * @retval None. + */ +void SpiritGeneralSetBatteryLevel(BatteryLevel xBatteryLevel) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_BLD_LVL(xBatteryLevel)); + + /* Reads the ANA_FUNC_CONF1_BASE register value */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF1_BASE, 1, &tempRegValue); + + /* Build the value to be stored */ + tempRegValue &= ~ANA_FUNC_CONF1_SET_BLD_LVL_MASK; + switch(xBatteryLevel) + { + case BLD_LVL_2_7_V: + tempRegValue |= BLD_LVL_2_7; + break; + case BLD_LVL_2_5_V: + tempRegValue |= BLD_LVL_2_5; + break; + case BLD_LVL_2_3_V: + tempRegValue |= BLD_LVL_2_3; + break; + case BLD_LVL_2_1_V: + tempRegValue |= BLD_LVL_2_1; + break; + } + + /* Writes the new value */ + g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the settled battery level. + * @param None. + * @retval BatteryLevel Settled battery level. This parameter can be a value of @ref BatteryLevel. + */ +BatteryLevel SpiritGeneralGetBatteryLevel(void) +{ + uint8_t tempRegValue; + + /* Reads the ANA_FUNC_CONF1_BASE register value */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF1_BASE, 1, &tempRegValue); + + /* Mask the battery level field and returns the settled battery level */ + return ((BatteryLevel)(tempRegValue & ANA_FUNC_CONF1_SET_BLD_LVL_MASK)); + +} + + +/** + * @brief Enables or Disables the output of brown out detector. + * @param xNewState new state for brown out detector. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritGeneralBrownOut(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the ANA_FUNC_CONF0_BASE register value */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + + /* Build the value to be stored */ + if(xNewState == S_ENABLE) + { + tempRegValue |= BROWN_OUT_MASK; + } + else + { + tempRegValue &= ~BROWN_OUT_MASK; + } + + /* Writes value on register */ + g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets High Power Mode. + * @param xNewState new state for High Power Mode. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritGeneralHighPwr(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the ANA_FUNC_CONF0_BASE register value */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + + /* Build the value to write */ + if(xNewState == S_ENABLE) + { + tempRegValue |= HIGH_POWER_MODE_MASK; + } + else + { + tempRegValue &= ~HIGH_POWER_MODE_MASK; + } + + /* Writes the new value on register */ + g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets External Reference. + * @param xExtMode new state for the external reference. + * This parameter can be: MODE_EXT_XO or MODE_EXT_XIN. + * @retval None. + */ +void SpiritGeneralSetExtRef(ModeExtRef xExtMode) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_MODE_EXT(xExtMode)); + + /* Reads the ANA_FUNC_CONF0_BASE register value */ + SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + + /* Build the value to write */ + if(xExtMode == MODE_EXT_XO) + { + tempRegValue &= ~EXT_REF_MASK; + } + else + { + tempRegValue |= EXT_REF_MASK; + } + + /* Writes value on register */ + g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns External Reference. + * @param None. + * @retval ModeExtRef Settled external reference. + * This parameter can be: MODE_EXT_XO or MODE_EXT_XIN. + */ +ModeExtRef SpiritGeneralGetExtRef(void) +{ + uint8_t tempRegValue; + + /* Reads the ANA_FUNC_CONF0_BASE register value and return the result */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + + /* Mask the EXT_REF field field and returns the settled reference signal */ + return ((ModeExtRef)((tempRegValue & 0x10)>>4)); + +} + + +/** + * @brief Sets XO gm at startup. + * @param xGm transconductance value of XO at startup. + * This parameter can be a value of @ref GmConf. + * @retval None. + */ +void SpiritGeneralSetXoGm(GmConf xGm) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_GM_CONF(xGm)); + + /* Reads the ANA_FUNC_CONF1_BASE register value */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF1_BASE, 1, &tempRegValue); + + /* Build the value to write */ + tempRegValue &= ~ANA_FUNC_CONF1_GMCONF_MASK; + switch(xGm) + { + case GM_SU_13_2: + tempRegValue |= GM_13_2; + break; + case GM_SU_18_2: + tempRegValue |= GM_18_2; + break; + case GM_SU_21_5: + tempRegValue |= GM_21_5; + break; + case GM_SU_25_6: + tempRegValue |= GM_25_6; + break; + case GM_SU_28_8: + tempRegValue |= GM_28_8; + break; + case GM_SU_33_9: + tempRegValue |= GM_33_9; + break; + case GM_SU_38_5: + tempRegValue |= GM_38_5; + break; + case GM_SU_43_0: + tempRegValue |= GM_43_0; + break; + } + + /* Writes new value on register */ + g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the configured XO gm at startup. + * @param None. + * @retval GmConf Settled XO gm. This parameter can be a value of @ref GmConf. + */ +GmConf SpiritGeneralGetXoGm(void) +{ + uint8_t tempRegValue; + + /* Reads the ANA_FUNC_CONF1_BASE register value */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF1_BASE, 1, &tempRegValue); + + /* Mask the GM_CONF field field and returns the settled transconductance of the XO at startup */ + return ((GmConf)((tempRegValue & 0x1C)>>2)); + +} + + +/** + * @brief Returns the settled packet format. + * @param None. + * @retval PacketType Settled packet type. This parameter can be a value of @ref PacketType. + */ +PacketType SpiritGeneralGetPktType(void) +{ + uint8_t tempRegValue; + + /* Reads the PROTOCOL1 register */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* cast and return value */ + return (PacketType)(tempRegValue>>6); + +} + + + +/** + * @brief Returns device part number. + * @param None. + * @retval uint16_t Device part number. + */ +uint16_t SpiritGeneralGetDevicePartNumber(void) +{ + uint8_t tempRegValue[2]; + + /* Reads the register value containing the device part number */ + g_xStatus = SpiritSpiReadRegisters(DEVICE_INFO1_PARTNUM, 2, tempRegValue); + + return ((((uint16_t)tempRegValue[0])<<8) | ((uint16_t)tempRegValue[1])); + +} + +/** + * @brief Returns SPIRIT RF board version. + * @param None. + * @retval SPIRIT RF board version: 0x30 is the only admitted value + */ +uint8_t SpiritGeneralGetSpiritVersion(void) +{ + uint8_t ver; + SpiritSpiReadRegisters(DEVICE_INFO0_VERSION, 1, &ver); + return ver; +} + +/** + *@} + */ + + +/** + *@} + */ + + +/** + *@} + */ + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Gpio.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Gpio.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,458 @@ +/** + ****************************************************************************** + * @file SPIRIT_Gpio.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief This file provides all the low level API to manage SPIRIT GPIO. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Gpio.h" +#include "MCU_Interface.h" + + +/** @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** @addtogroup SPIRIT_Gpio + * @{ + */ + + +/** @defgroup Gpio_Private_TypesDefinitions GPIO Private Types Definitions + * @{ + */ + + +/** + * @} + */ + + +/** @defgroup Gpio_Private_Defines GPIO Private Defines + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup Gpio_Private_Macros GPIO Private Macros + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup Gpio_Private_Variables GPIO Private Variables + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup Gpio_Private_FunctionPrototypes GPIO Private Function Prototypes + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup Gpio_Private_Functions GPIO Private Functions + * @{ + */ + +/** + * @brief Initializes the SPIRIT GPIOx according to the specified + * parameters in the pxGpioInitStruct. + * @param pxGpioInitStruct pointer to a SGpioInit structure that + * contains the configuration information for the specified SPIRIT GPIO. + * @retval None. + */ +void SpiritGpioInit(SGpioInit* pxGpioInitStruct) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_GPIO(pxGpioInitStruct->xSpiritGpioPin)); + s_assert_param(IS_SPIRIT_GPIO_MODE(pxGpioInitStruct->xSpiritGpioMode)); + s_assert_param(IS_SPIRIT_GPIO_IO(pxGpioInitStruct->xSpiritGpioIO)); + + tempRegValue = ((uint8_t)(pxGpioInitStruct->xSpiritGpioMode) | (uint8_t)(pxGpioInitStruct->xSpiritGpioIO)); + + g_xStatus = SpiritSpiWriteRegisters(pxGpioInitStruct->xSpiritGpioPin, 1, &tempRegValue); + +} + + +/** + * @brief Enables or Disables the output of temperature sensor on SPIRIT GPIO_0. + * @param xNewState new state for temperature sensor. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritGpioTemperatureSensor(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue = 0x00; + uint8_t gpio0tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the ANA_FUNC_CONF0 register and mask the result to enable or disable the + temperature sensor */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |= TEMPERATURE_SENSOR_MASK; + } + else + { + tempRegValue &= (~TEMPERATURE_SENSOR_MASK); + gpio0tempRegValue = 0x0A; /* Default value */ + } + g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + + /* Sets the SPIRIT GPIO_0 according to input request */ + g_xStatus = SpiritSpiWriteRegisters(GPIO0_CONF_BASE, 1, &gpio0tempRegValue); + +} + + +/** + * @brief Forces SPIRIT GPIO_x configured as digital output, to VDD or GND. + * @param xGpioX Specifies the GPIO to be configured. + * This parameter can be one of following parameters: + * @arg SPIRIT_GPIO_0: SPIRIT GPIO_0 + * @arg SPIRIT_GPIO_1: SPIRIT GPIO_1 + * @arg SPIRIT_GPIO_2: SPIRIT GPIO_2 + * @arg SPIRIT_GPIO_3: SPIRIT GPIO_3 + * @param xLevel Specifies the level. + * This parameter can be: HIGH or LOW. + * @retval None. + */ +void SpiritGpioSetLevel(SpiritGpioPin xGpioX, OutputLevel xLevel) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_GPIO(xGpioX)); + s_assert_param(IS_SPIRIT_GPIO_LEVEL(xLevel)); + + /* Reads the SPIRIT_GPIOx register and mask the GPIO_SELECT field */ + g_xStatus = SpiritSpiReadRegisters(xGpioX, 1, &tempRegValue); + tempRegValue &= 0x04; + + /* Sets the value of the SPIRIT GPIO register according to the specified level */ + if(xLevel == HIGH) + { + tempRegValue |= (uint8_t)SPIRIT_GPIO_DIG_OUT_VDD | (uint8_t)SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_HP; + } + else + { + tempRegValue |= (uint8_t)SPIRIT_GPIO_DIG_OUT_GND | (uint8_t)SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_HP; + } + + /* Writes the SPIRIT GPIO register */ + g_xStatus = SpiritSpiWriteRegisters(xGpioX, 1, &tempRegValue); + +} + + +/** + * @brief Returns output value (VDD or GND) of SPIRIT GPIO_x, when it is configured as digital output. + * @param xGpioX Specifies the GPIO to be read. + * This parameter can be one of following parameters: + * @arg SPIRIT_GPIO_0: SPIRIT GPIO_0 + * @arg SPIRIT_GPIO_1: SPIRIT GPIO_1 + * @arg SPIRIT_GPIO_2: SPIRIT GPIO_2 + * @arg SPIRIT_GPIO_3: SPIRIT GPIO_3 + * @retval OutputLevel Logical level of selected GPIO configured as digital output. + * This parameter can be: HIGH or LOW. + */ +OutputLevel SpiritGpioGetLevel(SpiritGpioPin xGpioX) +{ + uint8_t tempRegValue = 0x00; + OutputLevel level; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_GPIO(xGpioX)); + + /* Reads the SPIRIT_GPIOx register */ + g_xStatus = SpiritSpiReadRegisters(xGpioX, 1, &tempRegValue); + + /* Mask the GPIO_SELECT field and returns the value according */ + tempRegValue &= 0xF8; + if(tempRegValue == SPIRIT_GPIO_DIG_OUT_VDD) + { + level = HIGH; + } + else + { + level = LOW; + } + + return level; + +} + + +/** + * @brief Enables or Disables the MCU clock output. + * @param xNewState new state for the MCU clock output. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritGpioClockOutput(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the MCU_CK_CONF register and mask the result to enable or disable the clock output */ + g_xStatus = SpiritSpiReadRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + + if(xNewState) + { + tempRegValue |= MCU_CK_ENABLE; + } + else + { + tempRegValue &= (~MCU_CK_ENABLE); + } + + /* Writes the MCU_CK_CONF register */ + g_xStatus = SpiritSpiWriteRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Initializes the SPIRIT Clock Output according to the specified + * parameters in the xClockOutputInitStruct. + * @param pxClockOutputInitStruct pointer to a ClockOutputInit structure that + * contains the configuration information for the SPIRIT Clock Output. + * @retval None. + * @note The function SpiritGpioClockOutput() must be called in order to enable + * or disable the MCU clock dividers. + */ +void SpiritGpioClockOutputInit(ClockOutputInit* pxClockOutputInitStruct) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_CLOCK_OUTPUT_XO(pxClockOutputInitStruct->xClockOutputXOPrescaler)); + s_assert_param(IS_SPIRIT_CLOCK_OUTPUT_RCO(pxClockOutputInitStruct->xClockOutputRCOPrescaler)); + s_assert_param(IS_SPIRIT_CLOCK_OUTPUT_EXTRA_CYCLES(pxClockOutputInitStruct->xExtraClockCycles)); + + /* Calculates the register value to write according to the specified configuration */ + tempRegValue = ((uint8_t)(pxClockOutputInitStruct->xClockOutputXOPrescaler) | (uint8_t)(pxClockOutputInitStruct->xClockOutputRCOPrescaler) | \ + (uint8_t)(pxClockOutputInitStruct->xExtraClockCycles)); + + /* Writes the MCU_CLOCK register */ + g_xStatus = SpiritSpiWriteRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets the XO ratio as clock output. + * @param xXOPrescaler the XO prescaler to be used as clock output. + * This parameter can be any value of @ref ClockOutputXOPrescaler . + * @retval None + */ +void SpiritGpioSetXOPrescaler(ClockOutputXOPrescaler xXOPrescaler) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_CLOCK_OUTPUT_XO(xXOPrescaler)); + + /* Reads the MCU_CLK_CONFIG register */ + g_xStatus = SpiritSpiReadRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + + /* Mask the XO_RATIO field and writes the new value */ + tempRegValue &= 0x61; + tempRegValue |= ((uint8_t)xXOPrescaler); + + /* Writes the new XO prescaler in the MCU_CLOCK register */ + g_xStatus = SpiritSpiWriteRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the settled XO prescaler as clock output. + * @param None. + * @retval ClockOutputXOPrescaler Settled XO prescaler used for clock + * output. This parameter can be a value of @ref ClockOutputXOPrescaler . + */ +ClockOutputXOPrescaler SpiritGpioGetXOPrescaler(void) +{ + uint8_t tempRegValue = 0x00; + + /* Reads the MCU_CLK_CONFIG register */ + g_xStatus = SpiritSpiReadRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + + /* Mask the XO_RATIO field and return the value */ + return ((ClockOutputXOPrescaler)(tempRegValue & 0x1E)); + +} + + +/** + * @brief Sets the RCO ratio as clock output + * @param xRCOPrescaler the RCO prescaler to be used as clock output. + * This parameter can be any value of @ref ClockOutputRCOPrescaler . + * @retval None. + */ +void SpiritGpioSetRCOPrescaler(ClockOutputRCOPrescaler xRCOPrescaler) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_CLOCK_OUTPUT_RCO(xRCOPrescaler)); + + /* Reads the MCU_CLK_CONFIG register */ + g_xStatus = SpiritSpiReadRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + + /* Mask the RCO_RATIO field and writes the new value */ + tempRegValue &= 0xFE; + tempRegValue |= ((uint8_t)xRCOPrescaler); + + /* Writes the new RCO prescaler in the MCU_CLOCK register */ + g_xStatus = SpiritSpiWriteRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the settled RCO prescaler as clock output. + * @param None. + * @retval ClockOutputRCOPrescaler Settled RCO prescaler used for clock + * output. This parameter can be a value of @ref ClockOutputRCOPrescaler. + */ +ClockOutputRCOPrescaler SpiritGpioGetRCOPrescaler(void) +{ + uint8_t tempRegValue = 0x00; + + /* Reads the MCU_CLK_CONFIG register */ + g_xStatus = SpiritSpiReadRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + + /* Mask the RCO_RATIO field and returns the value */ + return ((ClockOutputRCOPrescaler)(tempRegValue & 0x01)); + +} + + +/** + * @brief Sets the RCO ratio as clock output. + * @param xExtraCycles the number of extra clock cycles provided before switching + * to STANDBY state. This parameter can be any value of @ref ExtraClockCycles . + * @retval None. + */ +void SpiritGpioSetExtraClockCycles(ExtraClockCycles xExtraCycles) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_CLOCK_OUTPUT_EXTRA_CYCLES(xExtraCycles)); + + /* Reads the MCU_CLK_CONFIG register */ + g_xStatus = SpiritSpiReadRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + + /* Mask the CLOCK_TAIL field and writes the new value */ + tempRegValue &= 0x9F; + tempRegValue |= ((uint8_t)xExtraCycles); + + /* Writes the new number of extra clock cycles in the MCU_CLOCK register */ + g_xStatus = SpiritSpiWriteRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the settled RCO prescaler as clock output. + * @param None. + * @retval ExtraClockCycles Settled number of extra clock cycles + * provided before switching to STANDBY state. This parameter can be + * any value of @ref ExtraClockCycles . + */ +ExtraClockCycles SpiritGpioGetExtraClockCycles(void) +{ + uint8_t tempRegValue = 0x00; + + /* Reads the MCU_CLK_CONFIG register */ + g_xStatus = SpiritSpiReadRegisters(MCU_CK_CONF_BASE, 1, &tempRegValue); + + /* Mask the CLOCK_TAIL field and returns the value */ + return ((ExtraClockCycles)(tempRegValue & 0x60)); + +} + + +/** + * @} + */ + + +/** + * @} + */ + + +/** + * @} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Irq.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Irq.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,320 @@ +/** + ****************************************************************************** + * @file SPIRIT_Irq.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT IRQs. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Irq.h" +#include "MCU_Interface.h" + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_Irq + * @{ + */ + + +/** + * @defgroup Irq_Private_TypesDefinitions IRQ Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Irq_Private_Defines IRQ Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Irq_Private_Macros IRQ Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Irq_Private_Variables IRQ Private Variables + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup Irq_Private_FunctionPrototypes IRQ Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Irq_Private_Functions IRQ Private Functions + * @{ + */ + + +/** + * @brief De initializate the SpiritIrqs structure setting all the bitfield to 0. + * Moreover, it sets the IRQ mask registers to 0x00000000, disabling all IRQs. + * @param pxIrqInit pointer to a variable of type @ref SpiritIrqs, in which all the + * bitfields will be settled to zero. + * @retval None. + */ +void SpiritIrqDeInit(SpiritIrqs* pxIrqInit) +{ + uint8_t tempRegValue[4]={0x00,0x00,0x00,0x00}; + + if(pxIrqInit!=NULL) + { + /* Sets the bitfields of passed structure to one */ + *(uint32_t*)pxIrqInit = 0x0; + } + + /* Writes the IRQ_MASK registers */ + g_xStatus = SpiritSpiWriteRegisters(IRQ_MASK3_BASE, 4, tempRegValue); +} + + +/** + * @brief Enables all the IRQs according to the user defined pxIrqInit structure. + * @param pxIrqInit pointer to a variable of type @ref SpiritIrqs, through which the + * user enable specific IRQs. This parameter is a pointer to a SpiritIrqs. + * For example suppose to enable only the two IRQ Low Battery Level and Tx Data Sent: + * @code + * SpiritIrqs myIrqInit = {0}; + * myIrqInit.IRQ_LOW_BATT_LVL = 1; + * myIrqInit.IRQ_TX_DATA_SENT = 1; + * SpiritIrqInit(&myIrqInit); + * @endcode + * @retval None. + */ +void SpiritIrqInit(SpiritIrqs* pxIrqInit) +{ + /* Writes the IRQ_MASK registers */ + g_xStatus = SpiritSpiWriteRegisters(IRQ_MASK3_BASE, 4, (uint8_t*)pxIrqInit); + +} + + +/** + * @brief Enables or disables a specific IRQ. + * @param xIrq IRQ to enable or disable. + * This parameter can be any value of @ref IrqList. + * @param xNewState new state for the IRQ. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritIrq(IrqList xIrq, SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue[4]; + uint32_t tempValue = 0; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_IRQ_LIST(xIrq)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the IRQ_MASK registers */ + g_xStatus = SpiritSpiReadRegisters(IRQ_MASK3_BASE, 4, tempRegValue); + + /* Build the IRQ mask word */ + for(uint8_t i=0; i<4; i++) + { + tempValue += ((uint32_t)tempRegValue[i])<<(8*(3-i)); + } + + /* Rebuild the new mask according to user request */ + if(xNewState == S_DISABLE) + { + tempValue &= (~xIrq); + } + else + { + tempValue |= (xIrq); + } + + /* Build the array of bytes to write in the IRQ_MASK registers */ + for(uint8_t j=0; j<4; j++) + { + tempRegValue[j] = (uint8_t)(tempValue>>(8*(3-j))); + } + + /* Writes the new IRQ mask in the corresponding registers */ + g_xStatus = SpiritSpiWriteRegisters(IRQ_MASK3_BASE, 4, tempRegValue); + +} + + +/** + * @brief Fills a pointer to a structure of SpiritIrqs type reading the IRQ_MASK registers. + * @param pxIrqMask pointer to a variable of type @ref SpiritIrqs, through which the + * user can read which IRQs are enabled. All the bitfields equals to zero correspond + * to enabled IRQs, while all the bitfields equals to one correspond to disabled IRQs. + * This parameter is a pointer to a SpiritIrqs. + * For example suppose that the Power On Reset and RX Data ready are the only enabled IRQs. + * @code + * SpiritIrqs myIrqMask; + * SpiritIrqGetStatus(&myIrqMask); + * @endcode + * Then + * myIrqMask.IRQ_POR and myIrqMask.IRQ_RX_DATA_READY are equal to 0 + * while all the other bitfields are equal to one. + * @retval None. + */ +void SpiritIrqGetMask(SpiritIrqs* pxIrqMask) +{ + /* Reads IRQ_MASK registers */ + g_xStatus = SpiritSpiReadRegisters(IRQ_MASK3_BASE, 4, (uint8_t*)pxIrqMask); +} + + +/** + * @brief Filla a pointer to a structure of SpiritIrqs type reading the IRQ_STATUS registers. + * @param pxIrqStatus pointer to a variable of type @ref SpiritIrqs, through which the + * user can read the status of all the IRQs. All the bitfields equals to one correspond + * to the raised interrupts. This parameter is a pointer to a SpiritIrqs. + * For example suppose that the XO settling timeout is raised as well as the Sync word + * detection. + * @code + * SpiritIrqs myIrqStatus; + * SpiritIrqGetStatus(&myIrqStatus); + * @endcode + * Then + * myIrqStatus.IRQ_XO_COUNT_EXPIRED and myIrqStatus.IRQ_VALID_SYNC are equals to 1 + * while all the other bitfields are equals to zero. + * @retval None. + */ +void SpiritIrqGetStatus(SpiritIrqs* pxIrqStatus) +{ + /* Reads IRQ_STATUS registers */ + g_xStatus = SpiritSpiReadRegisters(IRQ_STATUS3_BASE, 4, (uint8_t*)pxIrqStatus); +} + + +/** + * @brief Clear the IRQ status registers. + * @param None. + * @retval None. + */ +void SpiritIrqClearStatus(void) +{ + uint8_t tempRegValue[4]; + + /* Reads the IRQ_STATUS registers clearing all the flags */ + g_xStatus = SpiritSpiReadRegisters(IRQ_STATUS3_BASE, 4, tempRegValue); + +} + + +/** + * @brief Verifies if a specific IRQ has been generated. + * The call resets all the IRQ status, so it can't be used in case of multiple raising interrupts. + * @param xFlag IRQ flag to be checked. + * This parameter can be any value of @ref IrqList. + * @retval SpiritBool S_TRUE or S_FALSE. + */ +SpiritBool SpiritIrqCheckFlag(IrqList xFlag) +{ + uint8_t tempRegValue[4]; + uint32_t tempValue = 0; + SpiritBool flag; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_IRQ_LIST(xFlag)); + + /* Reads registers and build the status word */ + g_xStatus = SpiritSpiReadRegisters(IRQ_STATUS3_BASE, 4, tempRegValue); + for(uint8_t i=0; i<4; i++) + { + tempValue += ((uint32_t)tempRegValue[i])<<(8*(3-i)); + } + + if(tempValue & xFlag) + { + flag = S_TRUE; + } + else + { + flag = S_FALSE; + } + + return flag; + +} + + +/** + *@} + */ + + +/** + *@} + */ + + +/** + *@} + */ + + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_LinearFifo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_LinearFifo.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,337 @@ +/** + ****************************************************************************** + * @file SPIRIT_LinearFifo.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT Fifo. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_LinearFifo.h" +#include "MCU_Interface.h" + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_LinearFifo + * @{ + */ + + +/** + * @defgroup LinearFifo_Private_TypesDefinitions Linear FIFO Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup LinearFifo_Private_Defines Linear FIFO Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup LinearFifo_Private_Macros Linear FIFO Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup LinearFifo_Private_Variables Linear FIFO Private Variables + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup LinearFifo_Private_FunctionPrototypes Linear FIFO Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup LinearFifo_Private_Functions Linear FIFO Private Functions + * @{ + */ + +/** + * @brief Returns the number of elements in the Rx FIFO. + * @param None. + * @retval uint8_t Number of elements in the Rx FIFO. + */ +uint8_t SpiritLinearFifoReadNumElementsRxFifo(void) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(LINEAR_FIFO_STATUS0_BASE, 1, &tempRegValue); + + /* Build and return value */ + return (tempRegValue & 0x7F); + +} + + +/** + * @brief Returns the number of elements in the Tx FIFO. + * @param None. + * @retval uint8_t Number of elements in the Tx FIFO. + */ +uint8_t SpiritLinearFifoReadNumElementsTxFifo(void) +{ + uint8_t tempRegValue; + + /* Reads the number of elements in TX FIFO and return the value */ + g_xStatus = SpiritSpiReadRegisters(LINEAR_FIFO_STATUS1_BASE, 1, &tempRegValue); + + /* Build and return value */ + return (tempRegValue & 0x7F); +} + + +/** + * @brief Sets the almost full threshold for the Rx FIFO. When the number of elements in RX FIFO reaches this value an interrupt can be generated to the MCU. + * @note The almost full threshold is encountered from the top of the FIFO. For example, if it is set to 7 the almost + * full FIFO irq will be raised when the number of elements is equals to 96-7 = 89. + * @param cThrRxFifo almost full threshold. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritLinearFifoSetAlmostFullThresholdRx(uint8_t cThrRxFifo) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_FIFO_THR(cThrRxFifo)); + + /* Build the register value */ + tempRegValue = cThrRxFifo & 0x7F; + + /* Writes the Almost Full threshold for RX in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(FIFO_CONFIG3_RXAFTHR_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the almost full threshold for RX FIFO. + * @note The almost full threshold is encountered from the top of the FIFO. For example, if it is 7 the almost + * full FIFO irq will be raised when the number of elements is equals to 96-7 = 89. + * @param None. + * @retval uint8_t Almost full threshold for Rx FIFO. + */ +uint8_t SpiritLinearFifoGetAlmostFullThresholdRx(void) +{ + uint8_t tempRegValue; + + /* Reads the almost full threshold for RX FIFO and return the value */ + g_xStatus = SpiritSpiReadRegisters(FIFO_CONFIG3_RXAFTHR_BASE, 1, &tempRegValue); + + /* Build and return value */ + return (tempRegValue & 0x7F); + +} + + +/** + * @brief Sets the almost empty threshold for the Rx FIFO. When the number of elements in RX FIFO reaches this value an interrupt can be generated to the MCU. + * @param cThrRxFifo almost empty threshold. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritLinearFifoSetAlmostEmptyThresholdRx(uint8_t cThrRxFifo) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_FIFO_THR(cThrRxFifo)); + + /* Build the register value */ + tempRegValue = cThrRxFifo & 0x7F; + + /* Writes the Almost Empty threshold for RX in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(FIFO_CONFIG2_RXAETHR_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the almost empty threshold for Rx FIFO. + * @param None. + * @retval uint8_t Almost empty threshold for Rx FIFO. + */ +uint8_t SpiritLinearFifoGetAlmostEmptyThresholdRx(void) +{ + uint8_t tempRegValue; + + /* Reads the almost empty threshold for RX FIFO and returns the value */ + g_xStatus = SpiritSpiReadRegisters(FIFO_CONFIG2_RXAETHR_BASE, 1, &tempRegValue); + + /* Build and return value */ + return (tempRegValue & 0x7F); + +} + + +/** + * @brief Sets the almost full threshold for the Tx FIFO. When the number of elements in TX FIFO reaches this value an interrupt can be generated to the MCU. + * @note The almost full threshold is encountered from the top of the FIFO. For example, if it is set to 7 the almost + * full FIFO irq will be raised when the number of elements is equals to 96-7 = 89. + * @param cThrTxFifo almost full threshold. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritLinearFifoSetAlmostFullThresholdTx(uint8_t cThrTxFifo) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_FIFO_THR(cThrTxFifo)); + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(FIFO_CONFIG1_TXAFTHR_BASE, 1, &tempRegValue); + + /* Build the register value */ + tempRegValue &= 0x80; + tempRegValue |= cThrTxFifo; + + /* Writes the Almost Full threshold for Tx in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(FIFO_CONFIG1_TXAFTHR_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the almost full threshold for Tx FIFO. + * @note The almost full threshold is encountered from the top of the FIFO. For example, if it is set to 7 the almost + * full FIFO irq will be raised when the number of elements is equals to 96-7 = 89. + * @param None. + * @retval uint8_t Almost full threshold for Tx FIFO. + */ +uint8_t SpiritLinearFifoGetAlmostFullThresholdTx(void) +{ + uint8_t tempRegValue; + + /* Reads the almost full threshold for Tx FIFO and returns the value */ + g_xStatus = SpiritSpiReadRegisters(FIFO_CONFIG1_TXAFTHR_BASE, 1, &tempRegValue); + + /* Build and returns value */ + return (tempRegValue & 0x7F); + +} + + +/** + * @brief Sets the almost empty threshold for the Tx FIFO. When the number of elements in Tx FIFO reaches this value an interrupt can can be generated to the MCU. + * @param cThrTxFifo: almost empty threshold. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritLinearFifoSetAlmostEmptyThresholdTx(uint8_t cThrTxFifo) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_FIFO_THR(cThrTxFifo)); + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(FIFO_CONFIG0_TXAETHR_BASE, 1, &tempRegValue); + + /* Build the register value */ + tempRegValue &= 0x80; + tempRegValue |= cThrTxFifo; + + /* Writes the Almost Empty threshold for Tx in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(FIFO_CONFIG0_TXAETHR_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the almost empty threshold for Tx FIFO. + * @param None. + * @retval uint8_t Almost empty threshold for Tx FIFO. + */ +uint8_t SpiritLinearFifoGetAlmostEmptyThresholdTx(void) +{ + uint8_t tempRegValue; + + /* Reads the almost empty threshold for TX FIFO and returns the value */ + g_xStatus = SpiritSpiReadRegisters(FIFO_CONFIG0_TXAETHR_BASE, 1, &tempRegValue); + + /* Build and return value */ + return (tempRegValue & 0x7F); + +} + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Management.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Management.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,364 @@ +/** + ****************************************************************************** + * @file SPIRIT_Management.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief The management layer for SPIRIT1 library. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Management.h" + +/** +* @addtogroup SPIRIT_Libraries +* @{ +*/ + + +/** +* @defgroup SPIRIT_MANAGEMENT SPIRIT Management +* @{ +*/ + +/** +* @brief BS value to write in the SYNT0 register according to the selected band +*/ +static const uint8_t s_vectcBandRegValue[4]={SYNT0_BS_6, SYNT0_BS_12, SYNT0_BS_16, SYNT0_BS_32}; + +#define COMMUNICATION_STATE_TX 0 +#define COMMUNICATION_STATE_RX 1 +#define COMMUNICATION_STATE_NONE 2 + +static uint32_t s_nDesiredFrequency; + +static volatile uint8_t s_cCommunicationState = COMMUNICATION_STATE_NONE; + + +/** +* @brief Factor is: B/2 used in the formula for SYNTH word calculation +*/ +static const uint8_t s_vectcBHalfFactor[4]={(HIGH_BAND_FACTOR/2), (MIDDLE_BAND_FACTOR/2), (LOW_BAND_FACTOR/2), (VERY_LOW_BAND_FACTOR/2)}; + + +/** +* @defgroup SPIRIT_MANAGEMENT_FUNCTIONS SPIRIT Management Functions +* @{ +*/ + + +/** +* @defgroup WORKAROUND_FUNCTIONS SPIRIT Management Workaround Functions +* @{ +*/ + +/** +* @brief Private SpiritRadioSetFrequencyBase function only used in SpiritManagementWaVcoCalibration. +* @param lFBase the base carrier frequency expressed in Hz as unsigned word. +* @retval None. +*/ +void SpiritManagementSetFrequencyBase(uint32_t lFBase) +{ + uint32_t synthWord, Fc; + uint8_t band = 0, anaRadioRegArray[4], wcp; + + /* Check the parameter */ + s_assert_param(IS_FREQUENCY_BAND(lFBase)); + + /* Search the operating band */ + if(IS_FREQUENCY_BAND_HIGH(lFBase)) + { + band = HIGH_BAND; + } + else if(IS_FREQUENCY_BAND_MIDDLE(lFBase)) + { + band = MIDDLE_BAND; + } + else if(IS_FREQUENCY_BAND_LOW(lFBase)) + { + band = LOW_BAND; + } + else if(IS_FREQUENCY_BAND_VERY_LOW(lFBase)) + { + band = VERY_LOW_BAND; + } + + int32_t FOffset = SpiritRadioGetFrequencyOffset(); + uint32_t lChannelSpace = SpiritRadioGetChannelSpace(); + uint8_t cChannelNum = SpiritRadioGetChannel(); + + /* Calculates the channel center frequency */ + Fc = lFBase + FOffset + lChannelSpace*cChannelNum; + + /* Reads the reference divider */ + uint8_t cRefDiv = (uint8_t)SpiritRadioGetRefDiv()+1; + + switch(band) + { + case VERY_LOW_BAND: + if(Fc<161281250) + { + SpiritCalibrationSelectVco(VCO_L); + } + else + { + SpiritCalibrationSelectVco(VCO_H); + } + break; + + case LOW_BAND: + if(Fc<322562500) + { + SpiritCalibrationSelectVco(VCO_L); + } + else + { + SpiritCalibrationSelectVco(VCO_H); + } + break; + + case MIDDLE_BAND: + if(Fc<430083334) + { + SpiritCalibrationSelectVco(VCO_L); + } + else + { + SpiritCalibrationSelectVco(VCO_H); + } + break; + + case HIGH_BAND: + if(Fc<860166667) + { + SpiritCalibrationSelectVco(VCO_L); + } + else + { + SpiritCalibrationSelectVco(VCO_H); + } + } + + /* Search the VCO charge pump word and set the corresponding register */ + wcp = SpiritRadioSearchWCP(Fc); + + synthWord = (uint32_t)(lFBase*(((double)(FBASE_DIVIDER*cRefDiv*s_vectcBHalfFactor[band]))/SpiritRadioGetXtalFrequency())); + + /* Build the array of registers values for the analog part */ + anaRadioRegArray[0] = (uint8_t)(((synthWord>>21)&(0x0000001F))|(wcp<<5)); + anaRadioRegArray[1] = (uint8_t)((synthWord>>13)&(0x000000FF)); + anaRadioRegArray[2] = (uint8_t)((synthWord>>5)&(0x000000FF)); + anaRadioRegArray[3] = (uint8_t)(((synthWord&0x0000001F)<<3)| s_vectcBandRegValue[band]); + + /* Configures the needed Analog Radio registers */ + g_xStatus = SpiritSpiWriteRegisters(SYNT3_BASE, 4, anaRadioRegArray); +} + +uint8_t SpiritManagementWaVcoCalibration(void) +{ + uint8_t s_cVcoWordRx; + uint8_t s_cVcoWordTx; + uint32_t nFreq; + uint8_t cRestore = 0; + uint8_t cStandby = 0; + uint32_t xtal_frequency = SpiritRadioGetXtalFrequency(); + + /* Enable the reference divider if the XTAL is between 48 and 52 MHz */ + if(xtal_frequency>DOUBLE_XTAL_THR) + { + if(!SpiritRadioGetRefDiv()) + { + cRestore = 1; + nFreq = SpiritRadioGetFrequencyBase(); + SpiritRadioSetRefDiv(S_ENABLE); + SpiritManagementSetFrequencyBase(nFreq); + } + } + nFreq = SpiritRadioGetFrequencyBase(); + + /* Increase the VCO current */ + uint8_t tmp = 0x19; SpiritSpiWriteRegisters(0xA1,1,&tmp); + + SpiritCalibrationVco(S_ENABLE); + + SpiritRefreshStatus(); + if(g_xStatus.MC_STATE == MC_STATE_STANDBY) + { + cStandby = 1; + SpiritCmdStrobeReady(); + do{ + SpiritRefreshStatus(); + if(g_xStatus.MC_STATE == 0x13) + { + return 1; + } + }while(g_xStatus.MC_STATE != MC_STATE_READY); + } + + SpiritCmdStrobeLockTx(); + + do{ + SpiritRefreshStatus(); + if(g_xStatus.MC_STATE == 0x13) + { + return 1; + } + }while(g_xStatus.MC_STATE != MC_STATE_LOCK); + + s_cVcoWordTx = SpiritCalibrationGetVcoCalData(); + + SpiritCmdStrobeReady(); + + do{ + SpiritRefreshStatus(); + }while(g_xStatus.MC_STATE != MC_STATE_READY); + + + SpiritCmdStrobeLockRx(); + + do{ + SpiritRefreshStatus(); + if(g_xStatus.MC_STATE == 0x13) + { + return 1; + } + }while(g_xStatus.MC_STATE != MC_STATE_LOCK); + + s_cVcoWordRx = SpiritCalibrationGetVcoCalData(); + + SpiritCmdStrobeReady(); + + do{ + SpiritRefreshStatus(); + if(g_xStatus.MC_STATE == 0x13) + { + return 1; + } + }while(g_xStatus.MC_STATE != MC_STATE_READY); + + if(cStandby == 1) + { + SpiritCmdStrobeStandby(); + } + SpiritCalibrationVco(S_DISABLE); + + /* Disable the reference divider if the XTAL is between 48 and 52 MHz */ + if(cRestore) + { + SpiritRadioSetRefDiv(S_DISABLE); + SpiritManagementSetFrequencyBase(nFreq); + } + + /* Restore the VCO current */ + tmp = 0x11; SpiritSpiWriteRegisters(0xA1,1,&tmp); + + SpiritCalibrationSetVcoCalDataTx(s_cVcoWordTx); + SpiritCalibrationSetVcoCalDataRx(s_cVcoWordRx); + + return 0; +} + + +void SpiritManagementWaCmdStrobeTx(void) +{ + if(s_cCommunicationState != COMMUNICATION_STATE_TX) + { + //uint32_t xtal_frequency = SpiritRadioGetXtalFrequency(); + + /* To achive the max output power */ + if(s_nDesiredFrequency>=150000000 && s_nDesiredFrequency<=470000000) + { + /* Optimal setting for Tx mode only */ + SpiritRadioSetPACwc(LOAD_3_6_PF); + } + else + { + /* Optimal setting for Tx mode only */ + SpiritRadioSetPACwc(LOAD_0_PF); + } + + uint8_t tmp = 0x11; SpiritSpiWriteRegisters(0xa9, 1, &tmp); /* Enable VCO_L buffer */ + tmp = 0x20; SpiritSpiWriteRegisters(PM_CONFIG1_BASE, 1, &tmp); /* Set SMPS switching frequency */ + + s_cCommunicationState = COMMUNICATION_STATE_TX; + } +} + + +void SpiritManagementWaCmdStrobeRx(void) +{ + if(s_cCommunicationState != COMMUNICATION_STATE_RX) + { + uint8_t tmp = 0x98; SpiritSpiWriteRegisters(PM_CONFIG1_BASE, 1, &tmp); /* Set SMPS switching frequency */ + SpiritRadioSetPACwc(LOAD_0_PF); /* Set the correct CWC parameter */ + + s_cCommunicationState = COMMUNICATION_STATE_RX; + } +} + +void SpiritManagementWaTRxFcMem(uint32_t nDesiredFreq) +{ + s_cCommunicationState = COMMUNICATION_STATE_NONE; + s_nDesiredFrequency = nDesiredFreq; +} + + +void SpiritManagementWaExtraCurrent(void) +{ + uint8_t tmp= 0xCA;SpiritSpiWriteRegisters(0xB2, 1, &tmp); + tmp= 0x04;SpiritSpiWriteRegisters(0xA8, 1, &tmp); + /* just a read to loose some microsecs more */ + SpiritSpiReadRegisters(0xA8, 1, &tmp); + tmp= 0x00;SpiritSpiWriteRegisters(0xA8, 1, &tmp); +} + +/** +* @} +*/ + + + +/** +* @} +*/ + + +/** +* @} +*/ + +/** +* @} +*/ + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_PktBasic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_PktBasic.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,615 @@ +/** + ****************************************************************************** + * @file SPIRIT_PktBasic.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT Basic packets. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_PktBasic.h" +#include "MCU_Interface.h" + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_PktBasic + * @{ + */ + + +/** + * @defgroup PktBasic_Private_TypesDefinitions Pkt Basic Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktBasic_Private_Defines Pkt Basic Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktBasic_Private_Macros Pkt Basic Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktBasic_Private_Variables Pkt Basic Private Variables + * @{ + */ + +/** + *@} + */ + + + +/** + * @defgroup PktBasic_Private_FunctionPrototypes Pkt Basic Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktBasic_Private_Functions Pkt Basic Private Functions + * @{ + */ + +/** + * @brief Initializes the SPIRIT Basic packet according to the specified parameters in the PktBasicInit struct. + * Notice that this function sets the autofiltering option on CRC if it is set to any value different from BASIC_NO_CRC. + * @param pxPktBasicInit Basic packet init structure. + * This parameter is a pointer to @ref PktBasicInit. + * @retval None. + */ +void SpiritPktBasicInit(PktBasicInit* pxPktBasicInit) +{ + uint8_t tempRegValue[4], i; + + /* Check the parameters */ + s_assert_param(IS_BASIC_PREAMBLE_LENGTH(pxPktBasicInit->xPreambleLength)); + s_assert_param(IS_BASIC_SYNC_LENGTH(pxPktBasicInit->xSyncLength)); + s_assert_param(IS_BASIC_CRC_MODE(pxPktBasicInit->xCrcMode)); + s_assert_param(IS_BASIC_LENGTH_WIDTH_BITS(pxPktBasicInit->cPktLengthWidth)); + s_assert_param(IS_BASIC_FIX_VAR_LENGTH(pxPktBasicInit->xFixVarLength)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktBasicInit->xAddressField)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktBasicInit->xFec)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktBasicInit->xDataWhitening)); + s_assert_param(IS_BASIC_CONTROL_LENGTH(pxPktBasicInit->xControlLength)); + + /* Reads the PROTOCOL1 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue[0]); + + /* Mask a reserved bit */ + tempRegValue[0] &= ~0x20; + + /* Always set the automatic packet filtering */ + tempRegValue[0] |= PROTOCOL1_AUTO_PCKT_FLT_MASK; + + /* Writes the value on register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue[0]); + + /* Reads the PCKT_FLT_OPTIONS register */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + /* Always reset the control and source filtering (also if it is not present in basic) */ + tempRegValue[0] &= ~(PCKT_FLT_OPTIONS_SOURCE_FILTERING_MASK | PCKT_FLT_OPTIONS_CONTROL_FILTERING_MASK); + + /* Writes the value on register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + if(pxPktBasicInit->xAddressField == S_ENABLE) + { + tempRegValue[0]=0x08; + } + else + { + tempRegValue[0]=0x00; + } + /* Address and control length setting */ + tempRegValue[0] |= ((uint8_t) pxPktBasicInit->xControlLength); + + /* Packet format and width length setting */ + pxPktBasicInit->cPktLengthWidth == 0 ? pxPktBasicInit->cPktLengthWidth=1 : pxPktBasicInit->cPktLengthWidth; + tempRegValue[1] = ((uint8_t) PCKTCTRL3_PCKT_FRMT_BASIC) | ((uint8_t)(pxPktBasicInit->cPktLengthWidth-1)); + + /* Preamble, sync and fixed or variable length setting */ + tempRegValue[2] = ((uint8_t) pxPktBasicInit->xPreambleLength) | ((uint8_t) pxPktBasicInit->xSyncLength) | + ((uint8_t) pxPktBasicInit->xFixVarLength); + + /* CRC length, whitening and FEC setting */ + tempRegValue[3] = (uint8_t) pxPktBasicInit->xCrcMode; + + if(pxPktBasicInit->xDataWhitening == S_ENABLE) + { + tempRegValue[3] |= PCKTCTRL1_WHIT_MASK; + } + + if(pxPktBasicInit->xFec == S_ENABLE) + { + tempRegValue[3] |= PCKTCTRL1_FEC_MASK; + } + + /* Writes registers */ + SpiritSpiWriteRegisters(PCKTCTRL4_BASE, 4, tempRegValue); + + /* Sync words setting */ + for(i=0;i<4;i++) + { + if(i<3-(pxPktBasicInit->xSyncLength >>1)) + { + tempRegValue[i]=0; + } + else + { + tempRegValue[i] = (uint8_t)(pxPktBasicInit->lSyncWords>>(8*i)); + } + } + + /* Sets CRC check bit */ + if(pxPktBasicInit->xCrcMode == PKT_NO_CRC) + { + SpiritPktBasicFilterOnCrc(S_DISABLE); + } + else + { + SpiritPktBasicFilterOnCrc(S_ENABLE); + } + + + g_xStatus = SpiritSpiWriteRegisters(SYNC4_BASE, 4, tempRegValue); + +} + + +/** + * @brief Returns the SPIRIT Basic packet structure according to the specified parameters in the registers. + * @param pxPktBasicInit Basic packet init structure. + * This parameter is a pointer to @ref PktBasicInit. + * @retval None. + */ +void SpiritPktBasicGetInfo(PktBasicInit* pxPktBasicInit) +{ + uint8_t tempRegValue[10]; + + /* Reads registers */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL4_BASE, 10, tempRegValue); + + /* Length width */ + pxPktBasicInit->cPktLengthWidth=(tempRegValue[1] & 0x0F)+1; + + /* Address field */ + pxPktBasicInit->xAddressField=(SpiritFunctionalState)((tempRegValue[0]>>3) & 0x01); + + /* Control length */ + pxPktBasicInit->xControlLength=(BasicControlLength)(tempRegValue[0] & 0x07); + + /* CRC mode */ + pxPktBasicInit->xCrcMode=(BasicCrcMode)(tempRegValue[3] & 0xE0); + + /* Whitening */ + pxPktBasicInit->xDataWhitening=(SpiritFunctionalState)((tempRegValue[3] >> 4) & 0x01); + + /* FEC */ + pxPktBasicInit->xFec=(SpiritFunctionalState)(tempRegValue[3] & 0x01); + + /* FIX or VAR bit */ + pxPktBasicInit->xFixVarLength=(BasicFixVarLength)(tempRegValue[2] & 0x01); + + /* Preamble length */ + pxPktBasicInit->xPreambleLength=(BasicPreambleLength)(tempRegValue[2] & 0xF8); + + /* Sync length */ + pxPktBasicInit->xSyncLength=(BasicSyncLength)(tempRegValue[2] & 0x06); + + /* sync Words */ + pxPktBasicInit->lSyncWords=0; + for(uint8_t i=0 ; i<4 ; i++) + { + if(i>2-(((uint8_t)pxPktBasicInit->xSyncLength) >>1)) + { + pxPktBasicInit->lSyncWords |= (uint32_t)(tempRegValue[i+6])<<(8*i); + } + } + +} + + +/** + * @brief Initializes the SPIRIT Basic packet addresses according to the specified + * parameters in the PktBasicAddressesInit struct. + * @param pxPktBasicAddresses Basic packet addresses init structure. + * This parameter is a pointer to @ref PktBasicAddresses. + * @retval None. + */ +void SpiritPktBasicAddressesInit(PktBasicAddressesInit* pxPktBasicAddresses) +{ + uint8_t tempRegValue[3]; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktBasicAddresses->xFilterOnMyAddress)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktBasicAddresses->xFilterOnMulticastAddress)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktBasicAddresses->xFilterOnBroadcastAddress)); + + + /* Reads the PCKT_FLT_OPTIONS ragister */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + /* Enables or disables filtering on my address */ + if(pxPktBasicAddresses->xFilterOnMyAddress == S_ENABLE) + { + tempRegValue[0] |= PCKT_FLT_OPTIONS_DEST_VS_TX_ADDR_MASK; + } + else + { + tempRegValue[0] &= ~PCKT_FLT_OPTIONS_DEST_VS_TX_ADDR_MASK; + } + + /* Enables or disables filtering on multicast address */ + if(pxPktBasicAddresses->xFilterOnMulticastAddress == S_ENABLE) + { + tempRegValue[0] |= PCKT_FLT_OPTIONS_DEST_VS_MULTICAST_ADDR_MASK; + } + else + { + tempRegValue[0] &= ~PCKT_FLT_OPTIONS_DEST_VS_MULTICAST_ADDR_MASK; + } + + /* Enables or disables filtering on broadcast address */ + if(pxPktBasicAddresses->xFilterOnBroadcastAddress == S_ENABLE) + { + tempRegValue[0] |= PCKT_FLT_OPTIONS_DEST_VS_BROADCAST_ADDR_MASK; + } + else + { + tempRegValue[0] &= ~PCKT_FLT_OPTIONS_DEST_VS_BROADCAST_ADDR_MASK; + } + + /* Writes the new value on the PCKT_FLT_OPTIONS register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + /* Fills the array with the addresses passed in the structure */ + tempRegValue[0] = pxPktBasicAddresses->cBroadcastAddress; + tempRegValue[1] = pxPktBasicAddresses->cMulticastAddress; + tempRegValue[2] = pxPktBasicAddresses->cMyAddress; + + /* Writes values on the PCKT_FLT_GOALS registers */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_GOALS_BROADCAST_BASE, 3, tempRegValue); + + +} + + +/** + * @brief Returns the SPIRIT Basic packet addresses structure according to the specified + * parameters in the registers. + * @param pxPktBasicAddresses Basic packet addresses init structure. + * This parameter is a pointer to @ref PktBasicAddresses. + * @retval None. + */ +void SpiritPktBasicGetAddressesInfo(PktBasicAddressesInit* pxPktBasicAddresses) +{ + uint8_t tempRegValue[3]; + + /* Reads values on the PCKT_FLT_GOALS registers */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_GOALS_BROADCAST_BASE, 3, tempRegValue); + + /* Fit the structure with the read addresses */ + pxPktBasicAddresses->cBroadcastAddress = tempRegValue[0]; + pxPktBasicAddresses->cMulticastAddress = tempRegValue[1]; + pxPktBasicAddresses->cMyAddress = tempRegValue[2]; + + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + /* Fit the structure with the read filtering bits */ + pxPktBasicAddresses->xFilterOnBroadcastAddress = (SpiritFunctionalState)((tempRegValue[0] >> 1) & 0x01); + pxPktBasicAddresses->xFilterOnMulticastAddress = (SpiritFunctionalState)((tempRegValue[0] >> 2) & 0x01); + pxPktBasicAddresses->xFilterOnMyAddress = (SpiritFunctionalState)((tempRegValue[0] >> 3) & 0x01); + +} + + +/** + * @brief Configures the Basic packet format as packet used by SPIRIT. + * @param None. + * @retval None. + */ +void SpiritPktBasicSetFormat(void) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Build the new value. Also set to 0 the direct RX mode bits */ + tempRegValue &= 0x0F; + tempRegValue |= (uint8_t)PCKTCTRL3_PCKT_FRMT_BASIC; + + /* Writes the value on the PCKTCTRL3 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Reads the PCKTCTRL1_BASE register */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Build the new value. Set to 0 the direct TX mode bits */ + tempRegValue &= 0xF3; + + /* Writes the value on the PCKTCTRL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Reads the PROTOCOL1 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Mask a reserved bit */ + tempRegValue &= ~0x20; + + /* Writes the value on register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue); +} + + +/** + * @brief Sets the address length for SPIRIT Basic packets. + * @param xAddressField length of ADDRESS in bytes. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktBasicAddressField(SpiritFunctionalState xAddressField) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xAddressField)); + + /* Reads the PCKTCTRL4 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL4_BASE, 1, &tempRegValue); + + /* Build the address length for the register */ + if(xAddressField==S_ENABLE) + { + tempRegValue |= 0x08; + } + else + { + tempRegValue &= 0x07; + } + + /* Writes the new value on the PCKTCTRL4 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL4_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Specifies if the Address field for SPIRIT Basic packets is enabled or disabled. + * @param None. + * @retval SpiritFunctionalState Notifies if the address field is enabled or disabled. + */ +SpiritFunctionalState SpiritPktBasicGetAddressField(void) +{ + uint8_t tempRegValue; + + /* Reads the PCKTCTRL4 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL4_BASE, 1, &tempRegValue); + + /* Returns the address field value */ + if(tempRegValue & PCKTCTRL4_ADDRESS_LEN_MASK) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } + +} + + +/** + * @brief Sets the payload length for SPIRIT Basic packets. Since the packet length + * depends from the address and the control field size, this + * function reads the correspondent registers in order to determine + * the correct packet length to be written. + * @param nPayloadLength payload length in bytes. + * This parameter is an uint16_t. + * @retval None. + */ +void SpiritPktBasicSetPayloadLength(uint16_t nPayloadLength) +{ + uint8_t tempRegValue[2]; + uint16_t overSize=0; + + /* Computes the oversize (address + control) size */ + if(SpiritPktBasicGetAddressField()) + { + overSize=1; + } + overSize += (uint16_t) SpiritPktBasicGetControlLength(); + + /* Computes PCKTLEN0 value from nPayloadLength */ + tempRegValue[1]=BASIC_BUILD_PCKTLEN0(nPayloadLength+overSize); + /* Computes PCKTLEN1 value from nPayloadLength */ + tempRegValue[0]=BASIC_BUILD_PCKTLEN1(nPayloadLength+overSize); + + /* Writes data on the PCKTLEN1/0 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTLEN1_BASE, 2, tempRegValue); + +} + + +/** + * @brief Returns the payload length for SPIRIT Basic packets. Since the + * packet length depends from the address and the control + * field size, this function reads the correspondent + * registers in order to determine the correct payload length + * to be returned. + * @param None. + * @retval uint16_t Payload length in bytes. + */ +uint16_t SpiritPktBasicGetPayloadLength(void) +{ + uint8_t tempRegValue[2]; + uint16_t overSize=0; + + /* Computes the oversize (address + control) size */ + if(SpiritPktBasicGetAddressField()) + { + overSize=1; + } + overSize += (uint16_t) SpiritPktBasicGetControlLength(); + + /* Reads the packet length registers */ + g_xStatus = SpiritSpiReadRegisters(PCKTLEN1_BASE, 2, tempRegValue); + + /* Returns the packet length */ + return ((((uint16_t)tempRegValue[0])<<8) + (uint16_t) tempRegValue[1]) - overSize; +} + +/** + * @brief Returns the packet length field of the received packet. + * @param None. + * @retval uint16_t Packet length. + */ +uint16_t SpiritPktBasicGetReceivedPktLength(void) +{ + uint8_t tempRegValue[2]; + uint16_t overSize=0; + + /* Computes the oversize (address + control) size */ + if(SpiritPktBasicGetAddressField()) + { + overSize=1; + } + overSize += (uint16_t) SpiritPktBasicGetControlLength(); + + /* Reads the RX_PCKT_LENx registers value */ + g_xStatus = SpiritSpiReadRegisters(RX_PCKT_LEN1_BASE, 2, tempRegValue); + + /* Rebuild and return the length field */ + return (((((uint16_t) tempRegValue[0]) << 8) + (uint16_t) tempRegValue[1]) - overSize); +} + +/** + * @brief Computes and sets the variable payload length for SPIRIT Basic packets. + * @param nMaxPayloadLength payload length in bytes. + * This parameter is an uint16_t. + * @param xAddressField Enable or Disable Address Field. + * This parameter can be S_ENABLE or S_DISABLE. + * @param xControlLength Control length in bytes. + * This parameter can be any value of @ref BasicControlLength. + * @retval None. + */ +void SpiritPktBasicSetVarLengthWidth(uint16_t nMaxPayloadLength, SpiritFunctionalState xAddressField, BasicControlLength xControlLength) +{ + uint8_t tempRegValue, + addressLength, + i; + uint32_t packetLength; + + /* Sets the address length according to xAddressField */ + if(xAddressField == S_ENABLE) + { + addressLength=1; + } + else + { + addressLength=0; + } + + /* packet length = payload length + address length + control length */ + packetLength=nMaxPayloadLength+addressLength+xControlLength; + + /* Computes the number of bits */ + for(i=0;i<16;i++) + { + if(packetLength == 0) break; + { + packetLength >>= 1; + } + } + i==0 ? i=1 : i; + + /* Reads the PCKTCTRL3 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Build value for the length width */ + tempRegValue &= ~PCKTCTRL3_LEN_WID_MASK; + tempRegValue |= (uint8_t)(i-1); + + /* Writes the PCKTCTRL3 register value */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + +} + + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_PktCommon.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_PktCommon.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1453 @@ +/** + ****************************************************************************** + * @file SPIRIT_PktCommon.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of the common features of SPIRIT packets. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_PktCommon.h" +#include "MCU_Interface.h" + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_PktCommon + * @{ + */ + + +/** + * @defgroup PktCommon_Private_TypesDefinitions Pkt Common Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktCommon_Private_Defines Pkt Common Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktCommon_Private_Macros Pkt Common Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktCommon_Private_Variables Pkt Common Private Variables + * @{ + */ + +/** + *@} + */ + + + +/** + * @defgroup PktCommon_Private_FunctionPrototypes Pkt Common Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktCommon_Private_Functions Pkt Common Private Functions + * @{ + */ + +/** + * @brief Sets the CONTROL field length for SPIRIT packets. + * @param xControlLength length of CONTROL field in bytes. + * This parameter can be any value of @ref PktControlLength. + * @retval None. + */ +void SpiritPktCommonSetControlLength(PktControlLength xControlLength) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PKT_CONTROL_LENGTH(xControlLength)); + + /* Reads the PCKTCTRL4 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL4_BASE, 1, &tempRegValue); + + /* Set the control length */ + tempRegValue &= ~PCKTCTRL4_CONTROL_LEN_MASK; + tempRegValue |= (uint8_t)xControlLength; + + /* Writes the new value on the PCKTCTRL4 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL4_BASE, 1, &tempRegValue); +} + + +/** + * @brief Returns the CONTROL field length for SPIRIT packets. + * @param None. + * @retval uint8_t Control field length. + */ +uint8_t SpiritPktCommonGetControlLength(void) +{ + uint8_t tempRegValue; + + /* Reads the PCKTCTRL4 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL4_BASE, 1, &tempRegValue); + + /* Rebuild and return value */ + return (tempRegValue & PCKTCTRL4_CONTROL_LEN_MASK); +} + + +/** + * @brief Sets the PREAMBLE field Length mode for SPIRIT packets. + * @param xPreambleLength length of PREAMBLE field in bytes. + * This parameter can be any value of @ref PktPreambleLength. + * @retval None. + */ +void SpiritPktCommonSetPreambleLength(PktPreambleLength xPreambleLength) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PKT_PREAMBLE_LENGTH(xPreambleLength)); + + /* Reads the PCKTCTRL2 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL2_BASE, 1, &tempRegValue); + + /* Set the preamble length */ + tempRegValue &= ~PCKTCTRL2_PREAMBLE_LENGTH_MASK; + tempRegValue |= (uint8_t)xPreambleLength; + + /* Writes the new value on the PCKTCTRL2 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL2_BASE, 1, &tempRegValue); +} + + +/** + * @brief Returns the PREAMBLE field Length mode for SPIRIT packets. + * @param None. + * @retval uint8_t Preamble field length in bytes. + */ +uint8_t SpiritPktCommonGetPreambleLength(void) +{ + uint8_t tempRegValue; + + /* Reads the PCKTCTRL2 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL2_BASE, 1, &tempRegValue); + + /* Rebuild and return value */ + return ((tempRegValue & PCKTCTRL2_PREAMBLE_LENGTH_MASK)>>3) + 1; + +} + + +/** + * @brief Sets the SYNC field Length for SPIRIT packets. + * @param xSyncLength length of SYNC field in bytes. + * This parameter can be any value of @ref PktSyncLength. + * @retval None. + */ +void SpiritPktCommonSetSyncLength(PktSyncLength xSyncLength) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PKT_SYNC_LENGTH(xSyncLength)); + + /* Reads the PCKTCTRL2 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL2_BASE, 1, &tempRegValue); + + /* Set the sync length */ + tempRegValue &= ~PCKTCTRL2_SYNC_LENGTH_MASK; + tempRegValue |= (uint8_t)xSyncLength; + + /* Writes the new value on the PCKTCTRL2 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL2_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the SYNC field Length for SPIRIT packets. + * @param None. + * @retval uint8_t Sync field length in bytes. + */ +uint8_t SpiritPktCommonGetSyncLength(void) +{ + uint8_t tempRetValue; + + /* Reads the PCKTCTRL2 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL2_BASE, 1, &tempRetValue); + + /* Rebuild and return value */ + return ((tempRetValue & PCKTCTRL2_SYNC_LENGTH_MASK)>>1) + 1; + +} + + +/** + * @brief Sets fixed or variable payload length mode for SPIRIT packets. + * @param xFixVarLength variable or fixed length. + * PKT_FIXED_LENGTH_VAR -> variable (the length is extracted from the received packet). + * PKT_FIXED_LENGTH_FIX -> fix (the length is set by PCKTLEN0 and PCKTLEN1). + * @retval None. + */ +void SpiritPktCommonSetFixVarLength(PktFixVarLength xFixVarLength) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PKT_FIX_VAR_LENGTH(xFixVarLength)); + + /* Reads the PCKTCTRL2 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL2_BASE, 1, &tempRegValue); + + /* Set fixed or variable address mode */ + tempRegValue &= ~PCKTCTRL2_FIX_VAR_LEN_MASK; + tempRegValue |= (uint8_t)xFixVarLength; + + /* Writes the new value on the PCKTCTRL2 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL2_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Enables or Disables the filtering on CRC. + * @param xNewState new state for CRC_CHECK. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktCommonFilterOnCrc(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PCKT_FLT_OPTIONS register value */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Modify the register value: enable or disable the CRC filtering */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PCKT_FLT_OPTIONS_CRC_CHECK_MASK; + } + else + { + tempRegValue &= ~PCKT_FLT_OPTIONS_CRC_CHECK_MASK; + } + + /* Writes the PCKT_FLT_OPTIONS register value */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the CRC filtering enable bit. + * @param None. + * @retval SpiritFunctionalState CRC filtering. + */ +SpiritFunctionalState SpiritPktCommonGetFilterOnCrc(void) +{ + uint8_t tempRegValue; + + + /* Reads the PCKT_FLT_OPTIONS register value */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Check the CRC filtering bit */ + if(tempRegValue & PCKT_FLT_OPTIONS_CRC_CHECK_MASK) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } + +} + + +/** + * @brief Sets the CRC mode for SPIRIT packets. + * @param xCrcMode length of CRC field in bytes. + * This parameter can be any value of @ref PktCrcMode. + * @retval None. + */ +void SpiritPktCommonSetCrcMode(PktCrcMode xCrcMode) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PKT_CRC_MODE(xCrcMode)); + + /* Reads the PCKTCTRL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Build data to write setting the CRC mode */ + tempRegValue &= ~PCKTCTRL1_CRC_MODE_MASK; + tempRegValue |= (uint8_t)xCrcMode; + + /* Writes the new value on the PCKTCTRL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the CRC mode for SPIRIT packets. + * @param None. + * @retval PktCrcMode Crc mode. + */ +PktCrcMode SpiritPktCommonGetCrcMode(void) +{ + uint8_t tempRegValue; + + /* Reads the PCKTCTRL1 register */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Rebuild and return value */ + return (PktCrcMode)(tempRegValue & 0xE0); + +} + + +/** + * @brief Enables or Disables WHITENING for SPIRIT packets. + * @param xNewState new state for WHITENING mode. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktCommonWhitening(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PCKTCTRL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Build data to write: set or reset the whitening enable bit */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PCKTCTRL1_WHIT_MASK; + } + else + { + tempRegValue &= ~PCKTCTRL1_WHIT_MASK; + } + + /* Writes the new value on the PCKTCTRL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Enables or Disables FEC for SPIRIT packets. + * @param xNewState new state for FEC mode. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktCommonFec(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PCKTCTRL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Build data to write: set or reset the FEC enable bit */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PCKTCTRL1_FEC_MASK; + } + else + { + tempRegValue &= ~PCKTCTRL1_FEC_MASK; + } + + /* Writes data on the PCKTCTRL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets a specific SYNC word for SPIRIT packets. + * @param xSyncX SYNC word number to be set. + * This parameter can be any value of @ref PktSyncX. + * @param cSyncWord SYNC word. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritPktCommonSetSyncxWord(PktSyncX xSyncX , uint8_t cSyncWord) +{ + uint8_t tempRegAddress; + + /* Check the parameters */ + s_assert_param(IS_PKT_SYNCx(xSyncX)); + + /* Set the specified address */ + switch(xSyncX) + { + case PKT_SYNC_WORD_1: + tempRegAddress=SYNC1_BASE; + break; + case PKT_SYNC_WORD_2: + tempRegAddress=SYNC2_BASE; + break; + case PKT_SYNC_WORD_3: + tempRegAddress=SYNC3_BASE; + break; + default: + tempRegAddress=SYNC4_BASE; + break; + } + + /* Writes value on the selected register */ + g_xStatus = SpiritSpiWriteRegisters(tempRegAddress, 1, &cSyncWord); + +} + + +/** + * @brief Returns a specific SYNC word for SPIRIT packets. + * @param xSyncX SYNC word number to be get. + * This parameter can be any value of @ref PktSyncX. + * @retval uint8_t Sync word x. + */ +uint8_t SpiritPktCommonGetSyncxWord(PktSyncX xSyncX) +{ + uint8_t tempRegAddress, tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PKT_SYNCx(xSyncX)); + + /* Set the specified address */ + switch(xSyncX) + { + case PKT_SYNC_WORD_1: + tempRegAddress=SYNC1_BASE; + break; + case PKT_SYNC_WORD_2: + tempRegAddress=SYNC2_BASE; + break; + case PKT_SYNC_WORD_3: + tempRegAddress=SYNC3_BASE; + break; + default: + tempRegAddress=SYNC4_BASE; + break; + } + + /* Reads the selected register value */ + g_xStatus = SpiritSpiReadRegisters(tempRegAddress, 1, &tempRegValue); + + /* Returns the read value */ + return tempRegValue; + +} + + +/** + * @brief Sets multiple SYNC words for SPIRIT packets. + * @param lSyncWords SYNC words to be set with format: 0x|SYNC1|SYNC2|SYNC3|SYNC4|. + * This parameter is a uint32_t. + * @param xSyncLength SYNC length in bytes. The 32bit word passed will be stored in the SYNCx registers from the MSb + * until the number of bytes in xSyncLength has been stored. + * This parameter is a @ref PktSyncLength. + * @retval None. + */ +void SpiritPktCommonSetSyncWords(uint32_t lSyncWords, PktSyncLength xSyncLength) +{ + uint8_t tempRegValue[4]; + + /* Split the 32-bit value in 4 8-bit values */ + for(uint8_t i=0 ; i<4 ; i++) + { + if(i< ((3-xSyncLength) >>1) ) + { + tempRegValue[i]=0; + } + else + { + tempRegValue[i]=(uint8_t)(lSyncWords>>(8*i)); + } + } + + /* Writes SYNC value on the SYNCx registers */ + g_xStatus = SpiritSpiWriteRegisters(SYNC4_BASE, 4, tempRegValue); + +} + + +/** + * @brief Returns multiple SYNC words for SPIRIT packets. + * @param xSyncLength SYNC length in bytes. The 32bit word passed will be stored in the SYNCx registers from the MSb + * until the number of bytes in xSyncLength has been stored. + * This parameter is a pointer to @ref PktSyncLength. + * @retval uint32_t Sync words. The format of the read 32 bit word is 0x|SYNC1|SYNC2|SYNC3|SYNC4|. + */ +uint32_t SpiritPktCommonGetSyncWords(PktSyncLength xSyncLength) +{ + uint8_t tempRegValue[4]; + uint32_t tempRetValue=0; + + /* Reads the SYNCx registers value */ + g_xStatus = SpiritSpiReadRegisters(SYNC4_BASE, 4, tempRegValue); + + /* Rebuild the SYNC words */ + for(uint8_t i=0 ; i<4 ; i++) + { + if(i>2-(xSyncLength >>1)) + { + tempRetValue |= tempRegValue[i]<<(8*i); + } + } + + /* Return SYNC words */ + return tempRetValue; + +} + + +/** + * @brief Returns the variable length width (in number of bits). + * @param None. + * @retval uint8_t Variable length width in bits. + */ +uint8_t SpiritPktCommonGetVarLengthWidth(void) +{ + uint8_t tempRegValue; + + /* Reads the PCKTCTRL3 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Rebuild and return value */ + return (tempRegValue & PCKTCTRL3_LEN_WID_MASK)+1; + +} + + +/** + * @brief Sets the destination address for the Tx packet. + * @param cAddress Destination address. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritPktCommonSetDestinationAddress(uint8_t cAddress) +{ + /* Writes value on PCKT_FLT_GOALS_SOURCE_ADDR register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_GOALS_SOURCE_ADDR_BASE, 1, &cAddress); + +} + + +/** + * @brief Returns the settled destination address. + * @param None. + * @retval uint8_t Transmitted destination address. + */ +uint8_t SpiritPktCommonGetTransmittedDestAddress(void) +{ + uint8_t tempRegValue; + + /* Reads value on the PCKT_FLT_GOALS_SOURCE_ADDR register */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_GOALS_SOURCE_ADDR_BASE, 1, &tempRegValue); + + /* Return value */ + return tempRegValue; + +} + + +/** + * @brief Sets the node my address. When the filtering on my address is on, if the destination address extracted from the received packet is equal to the content of the + * my address, then the packet is accepted (this is the address of the node). + * @param cAddress Address of the present node. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritPktCommonSetMyAddress(uint8_t cAddress) +{ + /* Writes value on the PCKT_FLT_GOALS_TX_ADDR register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_GOALS_TX_ADDR_BASE, 1, &cAddress); + +} + + +/** + * @brief Returns the address of the present node. + * @param None. + * @retval uint8_t My address (address of this node). + */ +uint8_t SpiritPktCommonGetMyAddress(void) +{ + uint8_t tempRegValue; + + /* Reads value on the PCKT_FLT_GOALS_TX_ADDR register */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_GOALS_TX_ADDR_BASE, 1, &tempRegValue); + + /* Return value */ + return tempRegValue; + +} + + +/** + * @brief Sets the broadcast address. If the destination address extracted from the received packet is equal to the content of the + * BROADCAST_ADDR register, then the packet is accepted. + * @param cAddress Broadcast address. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritPktCommonSetBroadcastAddress(uint8_t cAddress) +{ + /* Writes value on the PCKT_FLT_GOALS_BROADCAST register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_GOALS_BROADCAST_BASE, 1, &cAddress); + +} + + +/** + * @brief Returns the broadcast address. + * @param None. + * @retval uint8_t Broadcast address. + */ +uint8_t SpiritPktCommonGetBroadcastAddress(void) +{ + uint8_t tempRegValue; + + /* Reads value on the PCKT_FLT_GOALS_BROADCAST register */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_GOALS_BROADCAST_BASE, 1, &tempRegValue); + + /* Return value */ + return tempRegValue; + +} + + +/** + * @brief Sets the multicast address. When the multicast filtering is on, if the destination address extracted from the received packet is equal to the content of the + * MULTICAST_ADDR register, then the packet is accepted. + * @param cAddress Multicast address. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritPktCommonSetMulticastAddress(uint8_t cAddress) +{ + /* Writes value on the PCKT_FLT_GOALS_MULTICAST register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_GOALS_MULTICAST_BASE, 1, &cAddress); + +} + + +/** + * @brief Returns the multicast address. + * @param None. + * @retval uint8_t Multicast address. + */ +uint8_t SpiritPktCommonGetMulticastAddress(void) +{ + uint8_t tempRegValue; + + /* Reads value on the PCKT_FLT_GOALS_MULTICAST register */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_GOALS_MULTICAST_BASE, 1, &tempRegValue); + + /* Return value */ + return tempRegValue; + +} + + +/** + * @brief Sets the control mask. The 1 bits of the CONTROL_MASK indicate the + * bits to be used in filtering. (All 0s no filtering) + * @param lMask Control mask. + * This parameter is an uint32_t. + * @retval None. + */ +void SpiritPktCommonSetCtrlMask(uint32_t lMask) +{ + uint8_t tempRegValue[4]; + + /* Split the 32-bit value in 4 8-bit values */ + tempRegValue[0] = (uint8_t) lMask; + tempRegValue[1] = (uint8_t)(lMask >> 8); + tempRegValue[2] = (uint8_t)(lMask >> 16); + tempRegValue[3] = (uint8_t)(lMask >> 24); + + /* Writes values on the CKT_FLT_GOALS_CONTROLx_MASK registers */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_GOALS_CONTROL0_MASK_BASE, 4, tempRegValue); + +} + + +/** + * @brief Returns the control mask. The 1 bits of the CONTROL_MASK indicate the + * bits to be used in filtering. (All 0s no filtering) + * @param None. + * @retval uint32_t Control mask. + */ +uint32_t SpiritPktCommonGetCtrlMask(void) +{ + uint8_t tempRegValue[4]; + uint32_t tempRetValue=0; + + /* Reads the PCKT_FLT_GOALS_CONTROLx_MASK registers */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_GOALS_CONTROL0_MASK_BASE, 4, tempRegValue); + + /* Rebuild the control mask value on a 32-bit integer variable */ + for(uint8_t i=0 ; i<4 ; i++) + { + tempRetValue |= ((uint32_t)tempRegValue[i])<<(8*i); + } + + /* Return value */ + return tempRetValue; +} + +/** + * @brief Sets the control field reference. If the bits enabled by the CONTROL_MASK + * match the ones of the control fields extracted from the received packet + * then the packet is accepted. + * @param lReference Control reference. + * This parameter is an uint32_t. + * @retval None. + */ +void SpiritPktCommonSetCtrlReference(uint32_t lReference) +{ + uint8_t tempRegValue[4]; + + /* Split the 32-bit value in 4 8-bit values */ + tempRegValue[0] = (uint8_t) lReference; + tempRegValue[1] = (uint8_t)(lReference >> 8); + tempRegValue[2] = (uint8_t)(lReference >> 16); + tempRegValue[3] = (uint8_t)(lReference >> 24); + + /* Writes values on the CKT_FLT_GOALS_CONTROLx_FIELD registers */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_GOALS_CONTROL0_FIELD_BASE, 4, tempRegValue); + +} + + +/** + * @brief Returns the control field reference. + * @param None. + * @retval uint32_t Control reference. + */ +uint32_t SpiritPktCommonGetCtrlReference(void) +{ + uint8_t tempRegValue[4]; + uint32_t tempRetValue=0; + + /* Reads the PCKT_FLT_GOALS_CONTROLx_FIELD registers */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_GOALS_CONTROL0_FIELD_BASE, 4, tempRegValue); + + /* Rebuild the control mask value on a 32-bit integer variable */ + for(uint8_t i=0 ; i<4 ; i++) + { + tempRetValue |= ((uint32_t)tempRegValue[i])<<(8*i); + } + + /* Return value */ + return tempRetValue; +} + + +/** + * @brief Sets the TX control field. + * @param lField Tx contro field. + * This parameter is an uint32_t. + * @retval None. + */ +void SpiritPktCommonSetTransmittedCtrlField(uint32_t lField) +{ + uint8_t tempRegValue[4]; + + /* Split the 32-bit value in 4 8-bit values */ + tempRegValue[3] = (uint8_t) lField; + tempRegValue[2] = (uint8_t)(lField >> 8); + tempRegValue[1] = (uint8_t)(lField >> 16); + tempRegValue[0] = (uint8_t)(lField >> 24); + + /* Writes value on the TX_CTRL_FIELDx register */ + g_xStatus = SpiritSpiWriteRegisters(TX_CTRL_FIELD3_BASE, 4, tempRegValue); + +} + + +/** + * @brief Returns the Tx control field. + * @param None. + * @retval uint32_t Control field of the transmitted packet. + */ +uint32_t SpiritPktCommonGetTransmittedCtrlField(void) +{ + uint8_t tempRegValue[4]; + uint32_t tempRetValue=0; + + /* Reads the TX_CTRL_FIELDx registers */ + g_xStatus = SpiritSpiReadRegisters(TX_CTRL_FIELD3_BASE, 4, tempRegValue); + + /* Rebuild value: build a 32-bit value from the read bytes */ + for(uint8_t i=0 ; i<4 ; i++) + { + tempRetValue |= ((uint32_t)tempRegValue[i])<<(8*(3-i)); + } + + /* Return value */ + return tempRetValue; + +} + + +/** + * @brief If enabled RX packet is accepted if its destination address matches with My address. + * @param xNewState new state for DEST_VS_SOURCE_ADDRESS. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktCommonFilterOnMyAddress(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + + /* Modify the register value: set or reset the TX source address control */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Set or reset the DESTINATION vs TX enabling bit */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PCKT_FLT_OPTIONS_DEST_VS_TX_ADDR_MASK; + } + else + { + tempRegValue &= ~PCKT_FLT_OPTIONS_DEST_VS_TX_ADDR_MASK; + } + + /* Writes the new value on the PCKT_FLT_OPTIONS register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + +} + + +/** + * @brief If enabled RX packet is accepted if its destination address matches with multicast address. + * @param xNewState new state for DEST_VS_MULTICAST_ADDRESS. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktCommonFilterOnMulticastAddress(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PCKT_FLT_OPTIONS register value */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Enable or disable the filtering option */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PCKT_FLT_OPTIONS_DEST_VS_MULTICAST_ADDR_MASK; + } + else + { + tempRegValue &= ~PCKT_FLT_OPTIONS_DEST_VS_MULTICAST_ADDR_MASK; + } + + /* Writes the new value on the PCKT_FLT_OPTIONS register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + +} + + +/** + * @brief If enabled RX packet is accepted if its destination address matches with broadcast address. + * @param xNewState new state for DEST_VS_BROADCAST_ADDRESS. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktCommonFilterOnBroadcastAddress(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Enable or disable the filtering option */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PCKT_FLT_OPTIONS_DEST_VS_BROADCAST_ADDR_MASK; + } + else + { + tempRegValue &= ~PCKT_FLT_OPTIONS_DEST_VS_BROADCAST_ADDR_MASK; + } + + /* Writes the new value on the PCKT_FLT_OPTIONS register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the enable bit of the my address filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +SpiritFunctionalState SpiritPktCommonGetFilterOnMyAddress(void) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Gets the enable/disable bit in form of SpiritFunctionalState type */ + if(tempRegValue & 0x08) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } + +} + +/** + * @brief Returns the enable bit of the multicast address filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +SpiritFunctionalState SpiritPktCommonGetFilterOnMulticastAddress(void) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Get the enable/disable bit in form of SpiritFunctionalState type */ + if(tempRegValue & 0x04) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } + +} + +/** + * @brief Returns the enable bit of the broadcast address filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +SpiritFunctionalState SpiritPktCommonGetFilterOnBroadcastAddress(void) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Get the enable/disable bit in form of SpiritFunctionalState type */ + if(tempRegValue & 0x02) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } + +} + + +/** + * @brief Returns the destination address of the received packet. + * @param None. + * @retval uint8_t Destination address of the received address. + */ +uint8_t SpiritPktCommonGetReceivedDestAddress(void) +{ + uint8_t tempRegValue; + + /* Reads the RX_ADDR_FIELD0 register value */ + g_xStatus = SpiritSpiReadRegisters(RX_ADDR_FIELD0_BASE, 1, &tempRegValue); + + /* Return value */ + return tempRegValue; + +} + + +/** + * @brief Returns the control field of the received packet. + * @param None. + * @retval uint32_t Received control field. + */ +uint32_t SpiritPktCommonGetReceivedCtrlField(void) +{ + uint8_t tempRegValue[4]; + uint32_t tempRetValue=0; + + /* Reads the PCKT_FLT_GOALS_CONTROLx_MASK registers */ + g_xStatus = SpiritSpiReadRegisters(RX_CTRL_FIELD0_BASE, 4, tempRegValue); + + /* Rebuild the control mask value on a 32-bit integer variable */ + for(uint8_t i=0 ; i<4 ; i++) + { + tempRetValue |= ((uint32_t)tempRegValue[i])<<(8*i); + } + + /* Returns value */ + return tempRetValue; +} + + +/** + * @brief Returns the CRC field of the received packet. + * @param cCrcFieldVect array in which the CRC field has to be stored. + * This parameter is an uint8_t array of 3 elements. + * @retval None. + */ +void SpiritPktCommonGetReceivedCrcField(uint8_t* cCrcFieldVect) +{ + uint8_t tempRegValue[3],crcLength; + PktCrcMode crcMode; + + /* Gets the CRC mode in PktCrcMode enum */ + crcMode=SpiritPktCommonGetCrcMode(); + + /* Cast to uint8_t */ + crcLength = (uint8_t)crcMode; + + /* Obtains the real length: see the @ref PktCrcMode enumeration */ + crcLength >>= 5; + if(crcLength>=3) crcLength--; + + /* Reads the CRC_FIELDx registers value */ + g_xStatus = SpiritSpiReadRegisters(CRC_FIELD2_BASE, 3,tempRegValue); + + /* Sets the array to be returned */ + for(uint8_t i=0 ; i<3 ; i++) + { + if(i<crcLength) + { + cCrcFieldVect[i]=tempRegValue[2-i]; + } + else + { + cCrcFieldVect[i]=0; + } + } + +} + + +/** + * @brief Sets the AUTO ACKNOLEDGEMENT mechanism on the receiver. When the feature is enabled and + * a data packet has been correctly received, then an acknowledgement packet is sent back to the originator of the received + * packet. If the PIGGYBACKING bit is also set, payload data will be read from the FIFO; otherwise an empty packet is sent + * only containing the source and destination addresses and the sequence number of the packet being acknowledged. + * @param xAutoAck new state for autoack. + * This parameter can be: S_ENABLE or S_DISABLE. + * @param xPiggybacking new state for autoack. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktCommonAutoAck(SpiritFunctionalState xAutoAck , SpiritFunctionalState xPiggybacking) +{ + uint8_t tempRegValue[2]; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xAutoAck)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xPiggybacking)); + /* Check if piggybacking is enabled and autoack is disabled */ + s_assert_param(!(xPiggybacking==S_ENABLE && xAutoAck==S_DISABLE)); + + /* Reads the PROTOCOL[1:0] registers value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 2, tempRegValue); + + /* Sets the specified LLP option */ + /* Autoack setting */ + if(xAutoAck == S_ENABLE) + { + tempRegValue[1] |= PROTOCOL0_AUTO_ACK_MASK; + } + else + { + tempRegValue[1] &= (~PROTOCOL0_AUTO_ACK_MASK); + } + + /* Piggybacking setting */ + if(xPiggybacking == S_ENABLE) + { + tempRegValue[0] |= PROTOCOL1_PIGGYBACKING_MASK; + } + else + { + tempRegValue[0] &= (~PROTOCOL1_PIGGYBACKING_MASK); + } + + /* Writes data on the PROTOCOL[1:0] registers */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 2, tempRegValue); + +} + + +/** + * @brief Sets the AUTO ACKNOLEDGEMENT mechanism on the transmitter. On the transmitter side, the NACK_TX field can be used to require or not an acknowledgment for each individual packet: if + * NACK_TX is set to "1" then acknowledgment will not be required; if NACK_TX is set to "0" then acknowledgment will be + * required. + * @param xNewState new state for TX_AUTOACK. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktCommonRequireAck(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads value on the PROTOCOL0 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL0_BASE, 1, &tempRegValue); + + /* Enables or disables the ack requirement option */ + if(xNewState == S_DISABLE) + { + tempRegValue |= PROTOCOL0_NACK_TX_MASK; + } + else + { + tempRegValue &= ~PROTOCOL0_NACK_TX_MASK; + } + + /* Writes value on the PROTOCOL0 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL0_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets the TX sequence number to be used to start counting. + * @param cSeqNumberReload new value for Tx seq number reload. + * @retval None. + */ +void SpiritPktCommonSetTransmittedSeqNumberReload(uint8_t cSeqNumberReload){ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PKT_SEQ_NUMBER_RELOAD(cSeqNumberReload)); + + /* Reads value on the PROTOCOL2 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + + tempRegValue &= 0xE7; + tempRegValue |= (cSeqNumberReload << 3); + + /* Writes value on the PROTOCOL2 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets the TX sequence number to be used to start counting. + * @param cSeqNumberReload new value for Tx seq number reload. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritPktCommonSetNMaxReTx(PktNMaxReTx xNMaxReTx) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PKT_NMAX_RETX(xNMaxReTx)); + + /* Reads the PROTOCOL0 register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL0_BASE, 1, &tempRegValue); + + /* Build the value to be written */ + tempRegValue &= ~PROTOCOL0_NMAX_RETX_MASK; + tempRegValue |= xNMaxReTx; + + /* Writes value on the PROTOCOL0 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL0_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the max number of automatic retransmission. + * @param None. + * @retval uint8_t Max number of retransmissions. + * This parameter is an uint8_t. + */ +uint8_t SpiritPktCommonGetNMaxReTx(void) +{ + uint8_t tempRegValue; + + /* Reads the PROTOCOL0 register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL0_BASE, 1, &tempRegValue); + + /* Build the value to be written */ + return ((tempRegValue & PROTOCOL0_NMAX_RETX_MASK)>>4); + +} + +/** + * @brief Returns the TX ACK request + * @param None. + * @retval uint8_t Max number of retransmissions. + * This parameter is an uint8_t. + */ +SpiritFunctionalState SpiritPktCommonGetTxAckRequest(void) +{ + uint8_t tempRegValue; + + /* Reads the PROTOCOL0 register value */ + g_xStatus = SpiritSpiReadRegisters(RX_PCKT_INFO_BASE, 1, &tempRegValue); + + /* Build the value to be written */ + return (SpiritFunctionalState)((tempRegValue & TX_PCKT_INFO_NACK_RX)>>2); + +} + + +/** + * @brief Returns the source address of the received packet. + * @param None. + * @retval uint8_t Source address of the received packet. + */ +uint8_t SpiritPktCommonGetReceivedSourceAddress(void) +{ + uint8_t tempRegValue; + + /* Reads the RX_ADDR_FIELD1 register value */ + g_xStatus = SpiritSpiReadRegisters(RX_ADDR_FIELD1_BASE, 1, &tempRegValue); + + /* Returns value */ + return tempRegValue; + +} + + +/** + * @brief Returns the sequence number of the received packet. + * @param None. + * @retval uint8_t Received Sequence number. + */ +uint8_t SpiritPktCommonGetReceivedSeqNumber(void) +{ + uint8_t tempRegValue; + + /* Reads the RX_PCKT_INFO register value */ + g_xStatus = SpiritSpiReadRegisters(RX_PCKT_INFO_BASE, 1, &tempRegValue); + + /* Obtains and returns the sequence number */ + return tempRegValue & 0x03; + +} + + +/** + * @brief Returns the Nack bit of the received packet + * @param None. + * @retval uint8_t Value of the Nack bit. + */ +uint8_t SpiritPktCommonGetReceivedNackRx(void) +{ + uint8_t tempRegValue; + + /* Reads the RX_PCKT_INFO register value */ + g_xStatus = SpiritSpiReadRegisters(RX_PCKT_INFO_BASE, 1, &tempRegValue); + + /* Obtains and returns the RX nack bit */ + return (tempRegValue >> 2) & 0x01; + +} + + +/** + * @brief Returns the sequence number of the transmitted packet. + * @param None. + * @retval uint8_t Sequence number of the transmitted packet. + */ +uint8_t SpiritPktCommonGetTransmittedSeqNumber(void) +{ + uint8_t tempRegValue; + + /* Reads the TX_PCKT_INFO register value */ + g_xStatus = SpiritSpiReadRegisters(TX_PCKT_INFO_BASE, 1, &tempRegValue); + + /* Obtains and returns the TX sequence number */ + return (tempRegValue >> 4) & 0x07; + +} + + +/** + * @brief Returns the number of retransmission done on the transmitted packet. + * @param None. + * @retval uint8_t Number of retransmissions done until now. + */ +uint8_t SpiritPktCommonGetNReTx(void) +{ + uint8_t tempRetValue; + + /* Reads the TX_PCKT_INFO register value */ + g_xStatus = SpiritSpiReadRegisters(TX_PCKT_INFO_BASE, 1, &tempRetValue); + + /* Obtains and returns the number of retransmission done */ + return (tempRetValue & 0x0F); + +} + + +/** + * @brief If enabled RX packet is accepted only if the masked control field matches the + * masked control field reference (CONTROL_MASK & CONTROL_FIELD_REF == CONTROL_MASK & RX_CONTROL_FIELD). + * @param xNewState new state for Control filtering enable bit. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + * @note This filtering control is enabled by default but the control mask is by default set to 0. + * As a matter of fact the user has to enable the control filtering bit after the packet initialization + * because the PktInit routine disables it. + */ +void SpiritPktCommonFilterOnControlField(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + + /* Modify the register value: set or reset the control bit filtering */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Set or reset the CONTROL filtering enabling bit */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PCKT_FLT_OPTIONS_CONTROL_FILTERING_MASK; + } + else + { + tempRegValue &= ~PCKT_FLT_OPTIONS_CONTROL_FILTERING_MASK; + } + + /* Writes the new value on the PCKT_FLT_OPTIONS register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the enable bit of the control field filtering. + * @param None. + * @retval SpiritFunctionalState This parameter can be S_ENABLE or S_DISABLE. + */ +SpiritFunctionalState SpiritPktCommonGetFilterOnControlField(void) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Gets the enable/disable bit in form of SpiritFunctionalState type */ + if(tempRegValue & PCKT_FLT_OPTIONS_CONTROL_FILTERING_MASK) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } + +} + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_PktMbus.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_PktMbus.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,354 @@ +/** + ****************************************************************************** + * @file SPIRIT_PktMbus.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT MBUS packets. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_PktMbus.h" +#include "SPIRIT_Radio.h" +#include "MCU_Interface.h" + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_PktMbus + * @{ + */ + + +/** + * @defgroup PktMbus_Private_TypesDefinitions Pkt MBUS Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktMbus_Private_Defines Pkt MBUS Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktMbus_Private_Macros Pkt MBUS Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktMbus_Private_Variables Pkt MBUS Private Variables + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktMbus_Private_FunctionPrototypes Pkt MBUS Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktMbus_Private_Functions Pkt MBUS Private Functions + * @{ + */ + + +/** + * @brief Initializes the SPIRIT MBUS packet according to the specified parameters in the PktMbusInit struct. + * @param pxPktMbusInit pointer to a PktMbusInit structure that contains the configuration information for the specified SPIRIT MBUS PACKET FORMAT. + * This parameter is a pointer to @ref PktMbusInit. + * @retval None. + */ +void SpiritPktMbusInit(PktMbusInit* pxPktMbusInit) +{ + uint8_t tempRegValue[3]; + + /* Check the parameters */ + s_assert_param(IS_MBUS_SUBMODE(pxPktMbusInit->xMbusSubmode)); + + /* Packet format config */ + SpiritPktMbusSetFormat(); + SpiritPktCommonFilterOnCrc(S_DISABLE); + SpiritRadioCsBlanking(S_ENABLE); + + /* Preamble, postamble and submode config */ + tempRegValue[0] = pxPktMbusInit->cPreambleLength; + tempRegValue[1] = pxPktMbusInit->cPostambleLength; + tempRegValue[2] = (uint8_t) pxPktMbusInit->xMbusSubmode; + + /* Writes the new values on the MBUS_PRMBL registers */ + g_xStatus = SpiritSpiWriteRegisters(MBUS_PRMBL_BASE, 3, tempRegValue); + +} + +/** + * @brief Returns the SPIRIT MBUS packet structure according to the specified parameters in the registers. + * @param pxPktMbusInit MBUS packet init structure. + * This parameter is a pointer to @ref PktMbusInit. + * @retval None. + */ +void SpiritPktMbusGetInfo(PktMbusInit* pxPktMbusInit) +{ + uint8_t tempRegValue[3]; + + /* Reads the MBUS regs value */ + g_xStatus = SpiritSpiReadRegisters(MBUS_PRMBL_BASE, 3, tempRegValue); + + /* Fit the structure */ + pxPktMbusInit->cPreambleLength = tempRegValue[0]; + pxPktMbusInit->cPostambleLength = tempRegValue[1]; + pxPktMbusInit->xMbusSubmode = (MbusSubmode) (tempRegValue[2]&0x0E); + +} + + +/** + * @brief Configures the MBUS packet format as the one used by SPIRIT. + * @param None. + * @retval None. + */ +void SpiritPktMbusSetFormat(void) +{ + uint8_t tempRegValue; + + /* Reads the PCKTCTRL3 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Sets format bits. Also set to 0 the direct RX mode bits */ + tempRegValue &= 0x0F; + tempRegValue |= ((uint8_t)PCKTCTRL3_PCKT_FRMT_MBUS); + + /* Writes value on the PCKTCTRL3 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Reads the PCKTCTRL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Build the new value. Set to 0 the direct TX mode bits */ + tempRegValue &= 0xF3; + + /* Writes the value on the PCKTCTRL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Reads the PROTOCOL1 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Mask a reserved bit */ + tempRegValue &= ~0x20; + + /* Writes the value on the PROTOCOL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets how many chip sequence 01 shall be added in the preamble + * respect to the minimum value as defined according to the specified sub-mode. + * @param cPreamble the number of chip sequence. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritPktMbusSetPreamble(uint8_t cPreamble) +{ + /* Modifies the MBUS_PRMBL register value */ + g_xStatus = SpiritSpiWriteRegisters(MBUS_PRMBL_BASE, 1, &cPreamble); + +} + + +/** + * @brief Returns how many chip sequence "01" are added in the preamble + * respect to the minimum value as defined according to the specified sub-mode. + * @param None. + * @retval uint8_t Preable in number of "01" chip sequences. + */ +uint8_t SpiritPktMbusGetPreamble(void) +{ + uint8_t tempRegValue; + + /* Modifies the MBUS_PRMBL register value */ + g_xStatus = SpiritSpiReadRegisters(MBUS_PRMBL_BASE, 1, &tempRegValue); + + /* Return value */ + return tempRegValue; + +} + + +/** + * @brief Sets how many chip sequence 01 will be used in postamble + * @param cPostamble the number of chip sequence. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritPktMbusSetPostamble(uint8_t cPostamble) +{ + /* Modifies the MBUS_PSTMBL register value */ + g_xStatus = SpiritSpiWriteRegisters(MBUS_PSTMBL_BASE, 1, &cPostamble); + +} + + +/** + * @brief Returns how many chip sequence "01" are used in the postamble + * @param None. + * @retval uint8_t Postamble in number of "01" chip sequences. + */ +uint8_t SpiritPktMbusGetPostamble(void) +{ + uint8_t tempRegValue; + + /* Reads the MBUS_PSTMBL register */ + g_xStatus = SpiritSpiReadRegisters(MBUS_PSTMBL_BASE, 1, &tempRegValue); + + /* Returns value */ + return tempRegValue; + +} + + +/** + * @brief Sets the MBUS submode used. + * @param xMbusSubmode the submode used. + * This parameter can be any value of @ref MbusSubmode. + * @retval None. + */ +void SpiritPktMbusSetSubmode(MbusSubmode xMbusSubmode) +{ + /* Modifies the MBUS_CTRL register value */ + g_xStatus = SpiritSpiWriteRegisters(MBUS_CTRL_BASE, 1, (uint8_t*)xMbusSubmode); + +} + + +/** + * @brief Returns the MBUS submode used. + * @param None. + * @retval MbusSubmode MBUS submode. + */ +MbusSubmode SpiritPktMbusGetSubmode(void) +{ + uint8_t tempRegValue; + + /* Reads the MBUS_CTRL register value */ + g_xStatus = SpiritSpiReadRegisters(MBUS_CTRL_BASE, 1, &tempRegValue); + + /* Returns value */ + return (MbusSubmode) tempRegValue; + +} + + +/** + * @brief Sets the payload length for SPIRIT MBUS packets. + * @param nPayloadLength payload length in bytes. + * This parameter is an uint16_t. + * @retval None. + */ +void SpiritPktMbusSetPayloadLength(uint16_t nPayloadLength) +{ + uint8_t tempRegValue[2]; + + /* Computes PCKTLEN0 value from nPayloadLength */ + tempRegValue[1]=BUILD_PCKTLEN0(nPayloadLength);//(uint8_t)nPayloadLength; + /* Computes PCKTLEN1 value from nPayloadLength */ + tempRegValue[0]=BUILD_PCKTLEN1(nPayloadLength);//(uint8_t)(nPayloadLength>>8); + + /* Writes data on the PCKTLEN1/0 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTLEN1_BASE, 2, tempRegValue); + +} + + +/** + * @brief Returns the payload length for SPIRIT MBUS packets. + * @param None. + * @retval uint16_t Payload length in bytes. + */ +uint16_t SpiritPktMbusGetPayloadLength(void) +{ + uint8_t tempRegValue[2]; + + /* Reads the packet length registers */ + g_xStatus = SpiritSpiReadRegisters(PCKTLEN1_BASE, 2, tempRegValue); + + /* Returns the packet length */ + return ((((uint16_t)tempRegValue[0])<<8) + (uint16_t) tempRegValue[1]); + +} + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_PktStack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_PktStack.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,687 @@ +/** + ****************************************************************************** + * @file SPIRIT_PktStack.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT STack packets. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_PktStack.h" +#include "MCU_Interface.h" + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_PktStack + * @{ + */ + + +/** + * @defgroup PktStack_Private_TypesDefinitions Pkt STack Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktStack_Private_Defines Pkt STack Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktStack_Private_Macros Pkt STack Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktStack_Private_Variables Pkt STack Private Variables + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktStack_Private_FunctionPrototypes Pkt STack Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup PktStack_Private_Functions Pkt STack Private Functions + * @{ + */ + + +/** + * @brief Initializes the SPIRIT STack packet according to the specified + * parameters in the PktStackInit. + * @param pxPktStackInit STack packet init structure. + * This parameter is a pointer to @ref PktStackInit. + * @retval None. + */ +void SpiritPktStackInit(PktStackInit* pxPktStackInit) +{ + uint8_t tempRegValue[4], i; + + /* Check the parameters */ + s_assert_param(IS_STACK_PREAMBLE_LENGTH(pxPktStackInit->xPreambleLength)); + s_assert_param(IS_STACK_SYNC_LENGTH(pxPktStackInit->xSyncLength)); + s_assert_param(IS_STACK_CRC_MODE(pxPktStackInit->xCrcMode)); + s_assert_param(IS_STACK_LENGTH_WIDTH_BITS(pxPktStackInit->cPktLengthWidth)); + s_assert_param(IS_STACK_FIX_VAR_LENGTH(pxPktStackInit->xFixVarLength)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktStackInit->xFec)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktStackInit->xDataWhitening)); + s_assert_param(IS_STACK_CONTROL_LENGTH(pxPktStackInit->xControlLength)); + + + /* Reads the PROTOCOL1 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue[0]); + + /* Mask a reserved bit */ + tempRegValue[0] &= ~0x20; + + /* Always (!) set the automatic packet filtering */ + tempRegValue[0] |= PROTOCOL1_AUTO_PCKT_FLT_MASK; + + /* Writes the value on register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue[0]); + + /* Reads the PCKT_FLT_OPTIONS register */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + /* Always reset the control and source filtering */ + tempRegValue[0] &= ~(PCKT_FLT_OPTIONS_SOURCE_FILTERING_MASK | PCKT_FLT_OPTIONS_CONTROL_FILTERING_MASK); + + /* Writes the value on register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + + /* Address and control length setting: source and destination address are always present so ADDRESS_LENGTH=2 */ + tempRegValue[0] = 0x10 | ((uint8_t) pxPktStackInit->xControlLength); + + + /* Packet format and width length setting */ + pxPktStackInit->cPktLengthWidth == 0 ? pxPktStackInit->cPktLengthWidth=1 : pxPktStackInit->cPktLengthWidth; + tempRegValue[1] = ((uint8_t) PCKTCTRL3_PCKT_FRMT_STACK) | ((uint8_t)(pxPktStackInit->cPktLengthWidth-1)); + + /* Preamble, sync and fixed or variable length setting */ + tempRegValue[2] = ((uint8_t) pxPktStackInit->xPreambleLength) | ((uint8_t) pxPktStackInit->xSyncLength) | + ((uint8_t) pxPktStackInit->xFixVarLength); + + /* CRC length, whitening and FEC setting */ + tempRegValue[3] = (uint8_t) pxPktStackInit->xCrcMode; + + if(pxPktStackInit->xDataWhitening == S_ENABLE) + { + tempRegValue[3] |= PCKTCTRL1_WHIT_MASK; + } + + if(pxPktStackInit->xFec == S_ENABLE) + { + tempRegValue[3] |= PCKTCTRL1_FEC_MASK; + } + + /* Writes registers */ + SpiritSpiWriteRegisters(PCKTCTRL4_BASE, 4, tempRegValue); + + /* Sync words setting */ + for(i=0;i<4;i++) + { + if(i<3-(pxPktStackInit->xSyncLength >>1)) + { + tempRegValue[i]=0; + } + else + { + tempRegValue[i] = (uint8_t)(pxPktStackInit->lSyncWords>>(8*i)); + } + } + + /* Enables or disables the CRC check */ + if(pxPktStackInit->xCrcMode == PKT_NO_CRC) + { + SpiritPktStackFilterOnCrc(S_DISABLE); + } + else + { + SpiritPktStackFilterOnCrc(S_ENABLE); + } + + /* Writes registers */ + g_xStatus = SpiritSpiWriteRegisters(SYNC4_BASE, 4, tempRegValue); + +} + + +/** + * @brief Returns the SPIRIT STack packet structure according to the specified parameters in the registers. + * @param pxPktStackInit STack packet init structure. + * This parameter is a pointer to @ref PktStackInit. + * @retval None. + */ +void SpiritPktStackGetInfo(PktStackInit* pxPktStackInit) +{ + uint8_t tempRegValue[10]; + + /* Reads registers */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL4_BASE, 10, tempRegValue); + + /* Length width */ + pxPktStackInit->cPktLengthWidth=(tempRegValue[1] & 0x0F)+1; + + /* Control length */ + pxPktStackInit->xControlLength=(StackControlLength)(tempRegValue[0] & 0x07); + + /* CRC mode */ + pxPktStackInit->xCrcMode=(StackCrcMode)(tempRegValue[3] & 0xE0); + + /* Whitening */ + pxPktStackInit->xDataWhitening=(SpiritFunctionalState)((tempRegValue[3] >> 4) & 0x01); + + /* FEC */ + pxPktStackInit->xFec=(SpiritFunctionalState)(tempRegValue[3] & 0x01); + + /* FIX or VAR bit */ + pxPktStackInit->xFixVarLength=(StackFixVarLength)(tempRegValue[2] & 0x01); + + /* Preamble length */ + pxPktStackInit->xPreambleLength=(StackPreambleLength)(tempRegValue[2] & 0xF8); + + /* Sync length */ + pxPktStackInit->xSyncLength=(StackSyncLength)(tempRegValue[2] & 0x06); + + /* sync Words */ + pxPktStackInit->lSyncWords=0; + for(uint8_t i=0 ; i<4 ; i++) + { + if(i>2-(pxPktStackInit->xSyncLength >>1)) + { + pxPktStackInit->lSyncWords |= tempRegValue[i+6]<<(8*i); + } + } + +} + + +/** + * @brief Initializes the SPIRIT STack packet addresses according to the specified + * parameters in the PktStackAddresses struct. + * @param pxPktStackAddresses STack packet addresses init structure. + * This parameter is a pointer to @ref PktStackAddressesInit . + * @retval None. + */ +void SpiritPktStackAddressesInit(PktStackAddressesInit* pxPktStackAddresses) +{ + uint8_t tempRegValue[3]; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktStackAddresses->xFilterOnMyAddress)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktStackAddresses->xFilterOnMulticastAddress)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktStackAddresses->xFilterOnBroadcastAddress)); + + /* Reads the filtering options ragister */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + /* Enables or disables filtering on my address */ + if(pxPktStackAddresses->xFilterOnMyAddress == S_ENABLE) + { + tempRegValue[0] |= PCKT_FLT_OPTIONS_DEST_VS_TX_ADDR_MASK; + } + else + { + tempRegValue[0] &= ~PCKT_FLT_OPTIONS_DEST_VS_TX_ADDR_MASK; + } + + /* Enables or disables filtering on multicast address */ + if(pxPktStackAddresses->xFilterOnMulticastAddress == S_ENABLE) + { + tempRegValue[0] |= PCKT_FLT_OPTIONS_DEST_VS_MULTICAST_ADDR_MASK; + } + else + { + tempRegValue[0] &= ~PCKT_FLT_OPTIONS_DEST_VS_MULTICAST_ADDR_MASK; + } + + /* Enables or disables filtering on broadcast address */ + if(pxPktStackAddresses->xFilterOnBroadcastAddress == S_ENABLE) + { + tempRegValue[0] |= PCKT_FLT_OPTIONS_DEST_VS_BROADCAST_ADDR_MASK; + } + else + { + tempRegValue[0] &= ~PCKT_FLT_OPTIONS_DEST_VS_BROADCAST_ADDR_MASK; + } + + /* Writes value on the register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + /* Fills array with the addresses passed in the structure */ + tempRegValue[0] = pxPktStackAddresses->cBroadcastAddress; + tempRegValue[1] = pxPktStackAddresses->cMulticastAddress; + tempRegValue[2] = pxPktStackAddresses->cMyAddress; + + /* Writes them on the addresses registers */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_GOALS_BROADCAST_BASE, 3, tempRegValue); + +} + + +/** +* @brief Returns the SPIRIT STack packet addresses structure according to the specified +* parameters in the registers. +* @param pxPktStackAddresses STack packet addresses init structure. +* This parameter is a pointer to @ref PktStackAddresses. +* @retval None. +*/ +void SpiritPktStackGetAddressesInfo(PktStackAddressesInit* pxPktStackAddresses) +{ + uint8_t tempRegValue[3]; + + /* Reads values on the PCKT_FLT_GOALS registers */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_GOALS_BROADCAST_BASE, 3, tempRegValue); + + /* Fit the structure with the read addresses */ + pxPktStackAddresses->cBroadcastAddress = tempRegValue[0]; + pxPktStackAddresses->cMulticastAddress = tempRegValue[1]; + pxPktStackAddresses->cMyAddress = tempRegValue[2]; + + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue[0]); + + /* Fit the structure with the read filtering bits */ + pxPktStackAddresses->xFilterOnBroadcastAddress = (SpiritFunctionalState)((tempRegValue[0] >> 1) & 0x01); + pxPktStackAddresses->xFilterOnMulticastAddress = (SpiritFunctionalState)((tempRegValue[0] >> 2) & 0x01); + pxPktStackAddresses->xFilterOnMyAddress = (SpiritFunctionalState)((tempRegValue[0] >> 3) & 0x01); + +} + + +/** +* @brief Initializes the SPIRIT STack packet LLP options according to the specified +* parameters in the PktStackLlpInit struct. +* @param pxPktStackLlpInit STack packet LLP init structure. +* This parameter is a pointer to @ref PktStackLlpInit. +* @retval None. +*/ +void SpiritPktStackLlpInit(PktStackLlpInit* pxPktStackLlpInit) +{ + uint8_t tempRegValue[2]; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktStackLlpInit->xPiggybacking)); + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(pxPktStackLlpInit->xAutoAck)); + s_assert_param(IS_STACK_NMAX_RETX(pxPktStackLlpInit->xNMaxRetx)); + /* check if piggybacking is enabled and autoack is disabled */ + s_assert_param(!(pxPktStackLlpInit->xPiggybacking==S_ENABLE && pxPktStackLlpInit->xAutoAck==S_DISABLE)); + + /* Piggybacking mechanism setting on the PROTOCOL1 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 2, tempRegValue); + if(pxPktStackLlpInit->xPiggybacking == S_ENABLE) + { + tempRegValue[0] |= PROTOCOL1_PIGGYBACKING_MASK; + } + else + { + tempRegValue[0] &= ~PROTOCOL1_PIGGYBACKING_MASK; + } + + /* RX and TX autoack mechanisms setting on the PROTOCOL0 register */ + if(pxPktStackLlpInit->xAutoAck == S_ENABLE) + { + tempRegValue[1] |= PROTOCOL0_AUTO_ACK_MASK; + } + else + { + tempRegValue[1] &= ~PROTOCOL0_AUTO_ACK_MASK; + } + + /* Max number of retransmission setting */ + tempRegValue[1] &= ~PROTOCOL0_NMAX_RETX_MASK; + tempRegValue[1] |= pxPktStackLlpInit->xNMaxRetx; + + /* Writes registers */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 2, tempRegValue); + +} + + +/** + * @brief Returns the SPIRIT STack packet LLP options according to the specified + * values in the registers. + * @param pxPktStackLlpInit STack packet LLP structure. + * This parameter is a pointer to @ref PktStackLlpInit. + * @retval None. + */ +void SpiritPktStackLlpGetInfo(PktStackLlpInit* pxPktStackLlpInit) +{ + uint8_t tempRegValue[2]; + + /* Piggybacking mechanism setting on the PROTOCOL1 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 2, tempRegValue); + + /* Fit the structure with the read values */ + pxPktStackLlpInit->xPiggybacking = (SpiritFunctionalState)((tempRegValue[0] >> 6) & 0x01); + pxPktStackLlpInit->xAutoAck = (SpiritFunctionalState)((tempRegValue[1] >> 2) & 0x01); + pxPktStackLlpInit->xNMaxRetx = (StackNMaxReTx)(tempRegValue[1] & PROTOCOL0_NMAX_RETX_MASK); + +} + + +/** + * @brief Configures the STack packet format for SPIRIT. + * @param None. + * @retval None. + */ +void SpiritPktStackSetFormat(void) +{ + uint8_t tempRegValue; + + /* Reads the PCKTCTRL3 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Build value to be written. Also set to 0 the direct RX mode bits */ + tempRegValue &= 0x0F; + tempRegValue |= ((uint8_t)PCKTCTRL3_PCKT_FRMT_STACK); + + /* Writes the value on the PCKTCTRL3 register. */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Reads the PCKTCTRL1 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Build the new value. Set to 0 the direct TX mode bits */ + tempRegValue &= 0xF3; + + /* Writes the PCKTCTRL1 value on register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL1_BASE, 1, &tempRegValue); + + /* Reads the PROTOCOL1 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Mask a reserved bit */ + tempRegValue &= ~0x20; + + /* Writes the value on the PROTOCOL1 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets the address length for SPIRIT STack packets (always 2). + * @param None. + * @retval None. + */ +void SpiritPktStackSetAddressLength(void) +{ + uint8_t tempRegValue; + + /* Reads the PCKTCTRL4 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL4_BASE, 1, &tempRegValue); + + /* Build the new value */ + tempRegValue &= ~PCKTCTRL4_ADDRESS_LEN_MASK; + tempRegValue |= ((uint8_t)0x10); + + /* Writes the value on the PCKTCTRL4 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL4_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets the payload length for SPIRIT STack packets. Since the packet length + * depends from the address (always 2 for this packet format) + * and the control field size, this function reads the control length register + * content in order to determine the correct packet length to be written. + * @param nPayloadLength payload length in bytes. + * This parameter can be any value of uint16_t. + * @retval None. + */ +void SpiritPktStackSetPayloadLength(uint16_t nPayloadLength) +{ + uint8_t tempRegValue[2]; + + /* Computes the oversize (address + control) size */ + uint16_t overSize = 2 + (uint16_t) SpiritPktStackGetControlLength(); + + /* Computes PCKTLEN0 value from lPayloadLength */ + tempRegValue[1]=STACK_BUILD_PCKTLEN0(nPayloadLength+overSize); + /* Computes PCKTLEN1 value from lPayloadLength */ + tempRegValue[0]=STACK_BUILD_PCKTLEN1(nPayloadLength+overSize); + + /* Writes the value on the PCKTLENx registers */ + g_xStatus = SpiritSpiWriteRegisters(PCKTLEN1_BASE, 2, tempRegValue); + +} + + +/** + * @brief Returns the payload length for SPIRIT STack packets. Since the + * packet length depends from the address and the control + * field size, this function reads the correspondent + * registers in order to determine the correct payload length + * to be returned. + * @param None. + * @retval uint16_t Payload length. + */ +uint16_t SpiritPktStackGetPayloadLength(void) +{ + uint8_t tempRegValue[2]; + /* Computes the oversize (address + control) size */ + uint16_t overSize = 2 + (uint16_t) SpiritPktStackGetControlLength(); + + /* Reads the PCKTLEN1 registers value */ + g_xStatus = SpiritSpiReadRegisters(PCKTLEN1_BASE, 2, tempRegValue); + + /* Rebuild and return the payload length value */ + return ((((uint16_t) tempRegValue[1])<<8) + (uint16_t) tempRegValue[0] - overSize); + +} + + +/** + * @brief Computes and sets the variable payload length for SPIRIT STack packets. + * @param nMaxPayloadLength payload length in bytes. + * This parameter is an uint16_t. + * @param xControlLength control length in bytes. + * This parameter can be any value of @ref StackControlLength. + * @retval None. + */ +void SpiritPktStackSetVarLengthWidth(uint16_t nMaxPayloadLength, StackControlLength xControlLength) +{ + uint8_t tempRegValue, + i; + uint32_t packetLength; + + + /* packet length = payload length + address length (2) + control length */ + packetLength=nMaxPayloadLength+2+xControlLength; + + /* Computes the number of bits */ + for(i=0;i<16;i++) + { + if(packetLength == 0) + { + break; + } + packetLength >>= 1; + } + i==0 ? i=1 : i; + + /* Reads the PCKTCTRL3 register value */ + g_xStatus = SpiritSpiReadRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + + /* Build the register value */ + tempRegValue &= ~PCKTCTRL3_LEN_WID_MASK; + tempRegValue |= ((uint8_t)(i-1)); + + /* Writes the PCKTCTRL3 register value */ + g_xStatus = SpiritSpiWriteRegisters(PCKTCTRL3_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Rx packet source mask. Used to mask the address of the accepted packets. If 0 -> no filtering. + * @param cMask Rx source mask. + * This parameter is an uint8_t. + * @retval None. + */ +void SpiritPktStackSetRxSourceMask(uint8_t cMask) +{ + /* Writes value on the register PCKT_FLT_GOALS_SOURCE_MASK */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_GOALS_SOURCE_MASK_BASE, 1, &cMask); + +} + + +/** + * @brief Returns the Rx packet source mask. Used to mask the address of the accepted packets. If 0 -> no filtering. + * @param None. + * @retval uint8_t Rx source mask. + */ +uint8_t SpiritPktStackGetRxSourceMask(void) +{ + uint8_t tempRegValue; + + /* Writes value on the PCKT_FLT_GOALS_SOURCE_MASK register */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_GOALS_SOURCE_MASK_BASE, 1, &tempRegValue); + + /* Return the read value */ + return tempRegValue; + +} + +/** + * @brief Returns the packet length field of the received packet. + * @param None. + * @retval uint16_t Packet length. + */ +uint16_t SpiritPktStackGetReceivedPktLength(void) +{ + uint8_t tempRegValue[2]; + uint16_t tempLength; + + /* Reads the RX_PCKT_LENx registers value */ + g_xStatus = SpiritSpiReadRegisters(RX_PCKT_LEN1_BASE, 2, tempRegValue); + + /* Rebuild and return the the length field */ + tempLength = ((((uint16_t) tempRegValue[0]) << 8) + (uint16_t) tempRegValue[1]); + + /* Computes the oversize (address + control) size */ + tempLength -= 2 + (uint16_t) SpiritPktStackGetControlLength(); + + return tempLength; + +} + + +/** + * @brief If enabled RX packet is accepted only if the masked source address field matches the + * masked source address field reference (SOURCE_MASK & SOURCE_FIELD_REF == SOURCE_MASK & RX_SOURCE_FIELD). + * @param xNewState new state for Source address filtering enable bit. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + * @note This filtering control is enabled by default but the source address mask is by default set to 0. + * As a matter of fact the user has to enable the source filtering bit after the packet initialization + * because the PktInit routine disables it. + */ +void SpiritPktStackFilterOnSourceAddress(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + + /* Modify the register value: set or reset the source bit filtering */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + + /* Set or reset the SOURCE ADDRESS filtering enabling bit */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PCKT_FLT_OPTIONS_SOURCE_FILTERING_MASK; + } + else + { + tempRegValue &= ~PCKT_FLT_OPTIONS_SOURCE_FILTERING_MASK; + } + + /* Writes the new value on the PCKT_FLT_OPTIONS register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 1, &tempRegValue); + +} + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Qi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Qi.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,636 @@ +/** + ****************************************************************************** + * @file SPIRIT_Qi.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT QI. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Qi.h" +#include "MCU_Interface.h" + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_Qi + * @{ + */ + + +/** + * @defgroup Qi_Private_TypesDefinitions QI Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Qi_Private_Defines QI Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Qi_Private_Macros QI Private Macros + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Qi_Private_Variables QI Private Variables + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Qi_Private_FunctionPrototypes QI Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Qi_Private_Functions QI Private Functions + * @{ + */ + +/** + * @brief Enables/Disables the PQI Preamble Quality Indicator check. The running peak PQI is + * compared to a threshold value and the preamble valid IRQ is asserted as soon as the threshold is passed. + * @param xNewState new state for PQI check. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritQiPqiCheck(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the QI register value */ + g_xStatus = SpiritSpiReadRegisters(QI_BASE, 1, &tempRegValue); + + /* Enables or disables the PQI Check bit on the QI_BASE register */ + if(xNewState == S_ENABLE) + { + tempRegValue |= QI_PQI_MASK; + } + else + { + tempRegValue &= ~QI_PQI_MASK; + } + + /* Writes value on the QI register */ + g_xStatus = SpiritSpiWriteRegisters(QI_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Enables/Disables the Synchronization Quality Indicator check. The running peak SQI is + * compared to a threshold value and the sync valid IRQ is asserted as soon as the threshold is passed. + * @param xNewState new state for SQI check. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritQiSqiCheck(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the QI register value */ + g_xStatus = SpiritSpiReadRegisters(QI_BASE, 1, &tempRegValue); + + /* Enables or disables the SQI Check bit on the QI_BASE register */ + if(xNewState == S_ENABLE) + { + tempRegValue |= QI_SQI_MASK; + } + else + { + tempRegValue &= ~QI_SQI_MASK; + } + + /* Writes value on the QI register */ + g_xStatus = SpiritSpiWriteRegisters(QI_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Sets the PQI threshold. The preamble quality threshold is 4*PQI_TH (PQI_TH = 0..15). + * @param xPqiThr parameter of the formula above. + * This variable is a @ref PqiThreshold. + * @retval None. + */ +void SpiritQiSetPqiThreshold(PqiThreshold xPqiThr) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PQI_THR(xPqiThr)); + + /* Reads the QI register value */ + g_xStatus = SpiritSpiReadRegisters(QI_BASE, 1, &tempRegValue); + + /* Build the PQI threshold value to be written */ + tempRegValue &= 0xC3; + tempRegValue |= ((uint8_t)xPqiThr); + + /* Writes value on the QI register */ + g_xStatus = SpiritSpiWriteRegisters(QI_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the PQI threshold. The preamble quality threshold is 4*PQI_TH (PQI_TH = 0..15). + * @param None. + * @retval PqiThreshold PQI threshold (PQI_TH of the formula above). + */ +PqiThreshold SpiritQiGetPqiThreshold(void) +{ + uint8_t tempRegValue; + + /* Reads the QI register value */ + g_xStatus = SpiritSpiReadRegisters(QI_BASE, 1, &tempRegValue); + + /* Rebuild and return the PQI threshold value */ + return (PqiThreshold)(tempRegValue & 0x3C); + +} + + +/** + * @brief Sets the SQI threshold. The synchronization quality + * threshold is equal to 8 * SYNC_LEN - 2 * SQI_TH with SQI_TH = 0..3. When SQI_TH is 0 perfect match is required; when + * SQI_TH = 1, 2, 3 then 1, 2, or 3 bit errors are respectively accepted. It is recommended that the SQI check is always + * enabled. + * @param xSqiThr parameter of the formula above. + * This parameter is a @ref SqiThreshold. + * @retval None. + */ +void SpiritQiSetSqiThreshold(SqiThreshold xSqiThr) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SQI_THR(xSqiThr)); + + /* Reads the QI register value */ + g_xStatus = SpiritSpiReadRegisters(QI_BASE, 1, &tempRegValue); + + /* Build the SQI threshold value to be written */ + tempRegValue &= 0x3F; + tempRegValue |= ((uint8_t)xSqiThr); + + /* Writes the new value on the QI register */ + g_xStatus = SpiritSpiWriteRegisters(QI_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the SQI threshold. The synchronization quality threshold is equal to 8 * SYNC_LEN - 2 * SQI_TH with SQI_TH = 0..3. + * @param None. + * @retval SqiThreshold SQI threshold (SQI_TH of the formula above). + */ +SqiThreshold SpiritQiGetSqiThreshold(void) +{ + uint8_t tempRegValue; + + /* Reads the QI register value */ + g_xStatus = SpiritSpiReadRegisters(QI_BASE, 1, &tempRegValue); + + /* Rebuild and return the SQI threshold value */ + return (SqiThreshold)(tempRegValue & 0xC0); + +} + + +/** + * @brief Returns the PQI value. + * @param None. + * @retval uint8_t PQI value. + */ +uint8_t SpiritQiGetPqi(void) +{ + uint8_t tempRegValue; + + /* Reads the LINK_QUALIF2 register value */ + g_xStatus = SpiritSpiReadRegisters(LINK_QUALIF2_BASE, 1, &tempRegValue); + + /* Returns the PQI value */ + return tempRegValue; + +} + + +/** + * @brief Returns the SQI value. + * @param None. + * @retval uint8_t SQI value. + */ +uint8_t SpiritQiGetSqi(void) +{ + uint8_t tempRegValue; + + /* Reads the register LINK_QUALIF1 value */ + g_xStatus = SpiritSpiReadRegisters(LINK_QUALIF1_BASE, 1, &tempRegValue); + + /* Rebuild and return the SQI value */ + return (tempRegValue & 0x7F); + +} + + +/** + * @brief Returns the LQI value. + * @param None. + * @retval uint8_t LQI value. + */ +uint8_t SpiritQiGetLqi(void) +{ + uint8_t tempRegValue; + + /* Reads the LINK_QUALIF0 register value */ + g_xStatus = SpiritSpiReadRegisters(LINK_QUALIF0_BASE, 1, &tempRegValue); + + /* Rebuild and return the LQI value */ + return ((tempRegValue & 0xF0)>> 4); + +} + + +/** + * @brief Returns the CS status. + * @param None. + * @retval SpiritFlagStatus CS value (S_SET or S_RESET). + */ +SpiritFlagStatus SpiritQiGetCs(void) +{ + uint8_t tempRegValue; + + /* Reads the LINK_QUALIF1 register value */ + g_xStatus = SpiritSpiReadRegisters(LINK_QUALIF1_BASE, 1, &tempRegValue); + + /* Rebuild and returns the CS status value */ + if((tempRegValue & 0x80) == 0) + { + return S_RESET; + } + else + { + return S_SET; + } + +} + + +/** + * @brief Returns the RSSI value. The measured power is reported in steps of half a dB from 0 to 255 and is offset in such a way that -120 dBm corresponds + * to 20. + * @param None. + * @retval uint8_t RSSI value. + */ +uint8_t SpiritQiGetRssi(void) +{ + uint8_t tempRegValue; + + /* Reads the RSSI_LEVEL register value */ + g_xStatus = SpiritSpiReadRegisters(RSSI_LEVEL_BASE, 1, &tempRegValue); + + /* Returns the RSSI value */ + return tempRegValue; + +} + + +/** + * @brief Sets the RSSI threshold. + * @param cRssiThr RSSI threshold reported in steps of half a dBm with a -130 dBm offset. + * This parameter must be a uint8_t. + * @retval None. + */ +void SpiritQiSetRssiThreshold(uint8_t cRssiThr) +{ + /* Writes the new value on the RSSI_TH register */ + g_xStatus = SpiritSpiWriteRegisters(RSSI_TH_BASE, 1, &cRssiThr); + +} + + +/** + * @brief Returns the RSSI threshold. + * @param None. + * @retval uint8_t RSSI threshold. + */ +uint8_t SpiritQiGetRssiThreshold(void) +{ + uint8_t tempRegValue; + + /* Reads the RSSI_TH register value */ + g_xStatus = SpiritSpiReadRegisters(RSSI_TH_BASE, 1, &tempRegValue); + + /* Returns RSSI threshold */ + return tempRegValue; + +} + + +/** + * @brief Computes the RSSI threshold from its dBm value according to the formula: (RSSI[Dbm] + 130)/0.5 + * @param nDbmValue RSSI threshold reported in dBm. + * This parameter must be a sint16_t. + * @retval uint8_t RSSI threshold corresponding to dBm value. + */ +uint8_t SpiritQiComputeRssiThreshold(int nDbmValue) +{ + /* Check the parameters */ + s_assert_param(IS_RSSI_THR_DBM(nDbmValue)); + + /* Computes the RSSI threshold for register */ + return 2*(nDbmValue+130); + +} + +/** + * @brief Sets the RSSI threshold from its dBm value according to the formula: (RSSI[Dbm] + 130)/0.5. + * @param nDbmValue RSSI threshold reported in dBm. + * This parameter must be a sint16_t. + * @retval None. + */ +void SpiritQiSetRssiThresholddBm(int nDbmValue) +{ + uint8_t tempRegValue=2*(nDbmValue+130); + + /* Check the parameters */ + s_assert_param(IS_RSSI_THR_DBM(nDbmValue)); + + /* Writes the new value on the RSSI_TH register */ + g_xStatus = SpiritSpiWriteRegisters(RSSI_TH_BASE, 1, &tempRegValue); + +} + +/** + * @brief Sets the RSSI filter gain. This parameter sets the bandwidth of a low pass IIR filter (RSSI_FLT register, allowed values 0..15), a + * lower values gives a faster settling of the measurements but lower precision. The recommended value for such parameter is 14. + * @param xRssiFg RSSI filter gain value. + * This parameter can be any value of @ref RssiFilterGain. + * @retval None. + */ +void SpiritQiSetRssiFilterGain(RssiFilterGain xRssiFg) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_RSSI_FILTER_GAIN(xRssiFg)); + + /* Reads the RSSI_FLT register */ + g_xStatus = SpiritSpiReadRegisters(RSSI_FLT_BASE, 1, &tempRegValue); + + /* Sets the specified filter gain */ + tempRegValue &= 0x0F; + tempRegValue |= ((uint8_t)xRssiFg); + + /* Writes the new value on the RSSI_FLT register */ + g_xStatus = SpiritSpiWriteRegisters(RSSI_FLT_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the RSSI filter gain. + * @param None. + * @retval RssiFilterGain RSSI filter gain. + */ +RssiFilterGain SpiritQiGetRssiFilterGain(void) +{ + uint8_t tempRegValue; + + /* Reads the RSSI_FLT register */ + g_xStatus = SpiritSpiReadRegisters(RSSI_FLT_BASE, 1, &tempRegValue); + + /* Rebuild and returns the filter gain value */ + return (RssiFilterGain)(tempRegValue & 0xF0); + +} + + +/** + * @brief Sets the CS Mode. When static carrier sensing is used (cs_mode = 0), the carrier sense signal is asserted when the measured RSSI is above the + * value specified in the RSSI_TH register and is deasserted when the RSSI falls 3 dB below the same threshold. + * When dynamic carrier sense is used (cs_mode = 1, 2, 3), the carrier sense signal is asserted if the signal is above the + * threshold and a fast power increase of 6, 12 or 18 dB is detected; it is deasserted if a power fall of the same amplitude is + * detected. + * @param xCsMode CS mode selector. + * This parameter can be any value of @ref CSMode. + * @retval None. + */ +void SpiritQiSetCsMode(CSMode xCsMode) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_CS_MODE(xCsMode)); + + /* Reads the RSSI_FLT register */ + g_xStatus = SpiritSpiReadRegisters(RSSI_FLT_BASE, 1, &tempRegValue); + + /* Sets bit to select the CS mode */ + tempRegValue &= ~0x0C; + tempRegValue |= ((uint8_t)xCsMode); + + /* Writes the new value on the RSSI_FLT register */ + g_xStatus = SpiritSpiWriteRegisters(RSSI_FLT_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the CS Mode. + * @param None. + * @retval CSMode CS mode. + */ +CSMode SpiritQiGetCsMode(void) +{ + uint8_t tempRegValue; + + /* Reads the RSSI_FLT register */ + g_xStatus = SpiritSpiReadRegisters(RSSI_FLT_BASE, 1, &tempRegValue); + + /* Rebuild and returns the CS mode value */ + return (CSMode)(tempRegValue & 0x0C); + +} + +/** + * @brief Enables/Disables the CS Timeout Mask. If enabled CS value contributes to timeout disabling. + * @param xNewState new state for CS Timeout Mask. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritQiCsTimeoutMask(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PROTOCOL2 register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + + /* Enables or disables the CS timeout mask */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PROTOCOL2_CS_TIMEOUT_MASK; + } + else + { + tempRegValue &= ~PROTOCOL2_CS_TIMEOUT_MASK; + } + + /* Writes the new value on the PROTOCOL2 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Enables/Disables the PQI Timeout Mask. If enabled PQI value contributes to timeout disabling. + * @param xNewState new state for PQI Timeout Mask. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritQiPqiTimeoutMask(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PROTOCOL2 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + + /* Enables or disables the PQI timeout mask */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PROTOCOL2_PQI_TIMEOUT_MASK; + } + else + { + tempRegValue &= ~PROTOCOL2_PQI_TIMEOUT_MASK; + } + + /* Writes the new value on the PROTOCOL2 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Enables/Disables the SQI Timeout Mask. If enabled SQI value contributes to timeout disabling. + * @param xNewState new state for SQI Timeout Mask. + * This parameter can be S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritQiSqiTimeoutMask(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PROTOCOL2 register */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + + /* Enables or disables the SQI timeout mask */ + if(xNewState == S_ENABLE) + { + tempRegValue |= PROTOCOL2_SQI_TIMEOUT_MASK; + } + else + { + tempRegValue &= ~PROTOCOL2_SQI_TIMEOUT_MASK; + } + + /* Writes the new value on the PROTOCOL2 register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + +} + + +/** + *@} + */ + +/** + *@} + */ + + +/** + *@} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Radio.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Radio.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3144 @@ +/** + ****************************************************************************** + * @file SPIRIT_Radio.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief This file provides all the low level API to manage Analog and Digital + * radio part of SPIRIT. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Radio.h" +#include "MCU_Interface.h" +#include <math.h> + +/** @addtogroup SPIRIT_Libraries +* @{ +*/ + + +/** @addtogroup SPIRIT_Radio +* @{ +*/ + + +/** @defgroup Radio_Private_TypesDefinitions Radio Private Types Definitions +* @{ +*/ + + +/** +* @} +*/ + + +/** @defgroup Radio_Private_Defines Radio Private Defines +* @{ +*/ + + + + +/** +* @} +*/ + + +/** @defgroup Radio_Private_Macros Radio Private Macros +* @{ +*/ +#define XTAL_FLAG(xtalFrequency) (xtalFrequency>=25e6) ? XTAL_FLAG_26_MHz:XTAL_FLAG_24_MHz + +#define ROUND(A) (((A-(uint32_t)A)> 0.5)? (uint32_t)A+1:(uint32_t)A) +/** +* @} +*/ + + +/** @defgroup Radio_Private_Variables Radio Private Variables +* @{ +*/ +/** +* @brief The Xtal frequency. To be set by the user (see SetXtalFreq() function) +*/ +static uint32_t s_lXtalFrequency; + +/** +* @brief Factor is: B/2 used in the formula for SYNTH word calculation +*/ +static const uint8_t s_vectcBHalfFactor[4]={(HIGH_BAND_FACTOR/2), (MIDDLE_BAND_FACTOR/2), (LOW_BAND_FACTOR/2), (VERY_LOW_BAND_FACTOR/2)}; + +/** +* @brief BS value to write in the SYNT0 register according to the selected band +*/ +static const uint8_t s_vectcBandRegValue[4]={SYNT0_BS_6, SYNT0_BS_12, SYNT0_BS_16, SYNT0_BS_32}; + + +/** +* @brief It represents the available channel bandwidth times 10 for 26 Mhz xtal. +* @note The channel bandwidth for others xtal frequencies can be computed since this table +* multiplying the current table by a factor xtal_frequency/26e6. +*/ +static const uint16_t s_vectnBandwidth26M[90]= +{ + 8001, 7951, 7684, 7368, 7051, 6709, 6423, 5867, 5414, \ + 4509, 4259, 4032, 3808, 3621, 3417, 3254, 2945, 2703, \ + 2247, 2124, 2015, 1900, 1807, 1706, 1624, 1471, 1350, \ + 1123, 1062, 1005, 950, 903, 853, 812, 735, 675, \ + 561, 530, 502, 474, 451, 426, 406, 367, 337, \ + 280, 265, 251, 237, 226, 213, 203, 184, 169, \ + 140, 133, 126, 119, 113, 106, 101, 92, 84, \ + 70, 66, 63, 59, 56, 53, 51, 46, 42, \ + 35, 33, 31, 30, 28, 27, 25, 23, 21, \ + 18, 17, 16, 15, 14, 13, 13, 12, 11 +}; + +/** +* @brief It represents the available VCO frequencies +*/ +static const uint16_t s_vectnVCOFreq[16]= +{ + 4644, 4708, 4772, 4836, 4902, 4966, 5030, 5095, \ + 5161, 5232, 5303, 5375, 5448, 5519, 5592, 5663 +}; + +/** +* @brief This variable is used to enable or disable +* the VCO calibration WA called at the end of the SpiritRadioSetFrequencyBase fcn. +* Default is enabled. +*/ +static SpiritFunctionalState xDoVcoCalibrationWA=S_ENABLE; + + +/** +* @brief These values are used to interpolate the power curves. +* Interpolation curves are linear in the following 3 regions: +* - reg value: 1 to 13 (up region) +* - reg value: 13 to 40 (mid region) +* - reg value: 41 to 90 (low region) +* power_reg = m*power_dBm + q +* For each band the order is: {m-up, q-up, m-mid, q-mid, m-low, q-low}. +* @note The power interpolation curves have been extracted +* by measurements done on the divisional evaluation boards. +*/ +static const float fPowerFactors[5][6]={ + {-2.11,25.66,-2.11,25.66,-2.00,31.28}, /* 915 */ + {-2.04,23.45,-2.04,23.45,-1.95,27.66}, /* 868 */ + {-3.48,38.45,-1.89,27.66,-1.92,30.23}, /* 433 */ + {-3.27,35.43,-1.80,26.31,-1.89,29.61}, /* 315 */ + {-4.18,50.66,-1.80,30.04,-1.86,32.22}, /* 169 */ +}; + +/** +* @} +*/ + + +/** @defgroup Radio_Private_FunctionPrototypes Radio Private Function Prototypes +* @{ +*/ + + +/** +* @} +*/ + + +/** @defgroup Radio_Private_Functions Radio Private Functions +* @{ +*/ + +/** +* @brief Initializes the SPIRIT analog and digital radio part according to the specified +* parameters in the pxSRadioInitStruct. +* @param pxSRadioInitStruct pointer to a SRadioInit structure that +* contains the configuration information for the analog radio part of SPIRIT. +* @retval Error code: 0=no error, 1=error during calibration of VCO. +*/ +uint8_t SpiritRadioInit(SRadioInit* pxSRadioInitStruct) +{ + int32_t FOffsetTmp; + uint8_t anaRadioRegArray[8], digRadioRegArray[4]; + int16_t xtalOffsetFactor; + uint8_t drM, drE, FdevM, FdevE, bwM, bwE; + + /* Workaround for Vtune */ + uint8_t value = 0xA0; SpiritSpiWriteRegisters(0x9F, 1, &value); + + /* Calculates the offset respect to RF frequency and according to xtal_ppm parameter: (xtal_ppm*FBase)/10^6 */ + FOffsetTmp = (int32_t)(((float)pxSRadioInitStruct->nXtalOffsetPpm*pxSRadioInitStruct->lFrequencyBase)/PPM_FACTOR); + + /* Check the parameters */ + s_assert_param(IS_FREQUENCY_BAND(pxSRadioInitStruct->lFrequencyBase)); + s_assert_param(IS_MODULATION_SELECTED(pxSRadioInitStruct->xModulationSelect)); + s_assert_param(IS_DATARATE(pxSRadioInitStruct->lDatarate)); + s_assert_param(IS_FREQUENCY_OFFSET(FOffsetTmp,s_lXtalFrequency)); + s_assert_param(IS_CHANNEL_SPACE(pxSRadioInitStruct->nChannelSpace,s_lXtalFrequency)); + s_assert_param(IS_F_DEV(pxSRadioInitStruct->lFreqDev,s_lXtalFrequency)); + + /* Disable the digital, ADC, SMPS reference clock divider if fXO>24MHz or fXO<26MHz */ + SpiritSpiCommandStrobes(COMMAND_STANDBY); + do{ + /* Delay for state transition */ + for(volatile uint8_t i=0; i!=0xFF; i++); + + /* Reads the MC_STATUS register */ + SpiritRefreshStatus(); + }while(g_xStatus.MC_STATE!=MC_STATE_STANDBY); + + if(s_lXtalFrequency<DOUBLE_XTAL_THR) + { + SpiritRadioSetDigDiv(S_DISABLE); + s_assert_param(IS_CH_BW(pxSRadioInitStruct->lBandwidth,s_lXtalFrequency)); + } + else + { + SpiritRadioSetDigDiv(S_ENABLE); + s_assert_param(IS_CH_BW(pxSRadioInitStruct->lBandwidth,(s_lXtalFrequency>>1))); + } + + /* Goes in READY state */ + SpiritSpiCommandStrobes(COMMAND_READY); + do{ + /* Delay for state transition */ + for(volatile uint8_t i=0; i!=0xFF; i++); + + /* Reads the MC_STATUS register */ + SpiritRefreshStatus(); + }while(g_xStatus.MC_STATE!=MC_STATE_READY); + + /* Calculates the FC_OFFSET parameter and cast as signed int: FOffsetTmp = (Fxtal/2^18)*FC_OFFSET */ + xtalOffsetFactor = (int16_t)(((float)FOffsetTmp*FBASE_DIVIDER)/s_lXtalFrequency); + anaRadioRegArray[2] = (uint8_t)((((uint16_t)xtalOffsetFactor)>>8)&0x0F); + anaRadioRegArray[3] = (uint8_t)(xtalOffsetFactor); + + /* Calculates the channel space factor */ + anaRadioRegArray[0] =((uint32_t)pxSRadioInitStruct->nChannelSpace<<9)/(s_lXtalFrequency>>6)+1; + + SpiritManagementWaTRxFcMem(pxSRadioInitStruct->lFrequencyBase); + + /* 2nd order DEM algorithm enabling */ + uint8_t tmpreg; SpiritSpiReadRegisters(0xA3, 1, &tmpreg); + tmpreg &= ~0x02; SpiritSpiWriteRegisters(0xA3, 1, &tmpreg); + + /* Check the channel center frequency is in one of the possible range */ + s_assert_param(IS_FREQUENCY_BAND((pxSRadioInitStruct->lFrequencyBase + ((xtalOffsetFactor*s_lXtalFrequency)/FBASE_DIVIDER) + pxSRadioInitStruct->nChannelSpace * pxSRadioInitStruct->cChannelNumber))); + + /* Calculates the datarate mantissa and exponent */ + SpiritRadioSearchDatarateME(pxSRadioInitStruct->lDatarate, &drM, &drE); + digRadioRegArray[0] = (uint8_t)(drM); + digRadioRegArray[1] = (uint8_t)(0x00 | pxSRadioInitStruct->xModulationSelect |drE); + + /* Read the fdev register to preserve the clock recovery algo bit */ + SpiritSpiReadRegisters(0x1C, 1, &tmpreg); + + /* Calculates the frequency deviation mantissa and exponent */ + SpiritRadioSearchFreqDevME(pxSRadioInitStruct->lFreqDev, &FdevM, &FdevE); + digRadioRegArray[2] = (uint8_t)((FdevE<<4) | (tmpreg&0x08) | FdevM); + + /* Calculates the channel filter mantissa and exponent */ + SpiritRadioSearchChannelBwME(pxSRadioInitStruct->lBandwidth, &bwM, &bwE); + + digRadioRegArray[3] = (uint8_t)((bwM<<4) | bwE); + + float if_off=(3.0*480140)/(s_lXtalFrequency>>12)-64; + + uint8_t ifOffsetAna = ROUND(if_off); + + if(s_lXtalFrequency<DOUBLE_XTAL_THR) + { + /* if offset digital is the same in case of single xtal */ + anaRadioRegArray[1] = ifOffsetAna; + } + else + { + if_off=(3.0*480140)/(s_lXtalFrequency>>13)-64; + + /* ... otherwise recompute it */ + anaRadioRegArray[1] = ROUND(if_off); + } +// if(s_lXtalFrequency==24000000) { +// ifOffsetAna = 0xB6; +// anaRadioRegArray[1] = 0xB6; +// } +// if(s_lXtalFrequency==25000000) { +// ifOffsetAna = 0xAC; +// anaRadioRegArray[1] = 0xAC; +// } +// if(s_lXtalFrequency==26000000) { +// ifOffsetAna = 0xA3; +// anaRadioRegArray[1] = 0xA3; +// } +// if(s_lXtalFrequency==48000000) { +// ifOffsetAna = 0x3B; +// anaRadioRegArray[1] = 0xB6; +// } +// if(s_lXtalFrequency==50000000) { +// ifOffsetAna = 0x36; +// anaRadioRegArray[1] = 0xAC; +// } +// if(s_lXtalFrequency==52000000) { +// ifOffsetAna = 0x31; +// anaRadioRegArray[1] = 0xA3; +// } + + g_xStatus = SpiritSpiWriteRegisters(IF_OFFSET_ANA_BASE, 1, &ifOffsetAna); + + + /* Sets Xtal configuration */ + if(s_lXtalFrequency>DOUBLE_XTAL_THR) + { + SpiritRadioSetXtalFlag(XTAL_FLAG((s_lXtalFrequency/2))); + } + else + { + SpiritRadioSetXtalFlag(XTAL_FLAG(s_lXtalFrequency)); + } + + /* Sets the channel number in the corresponding register */ + SpiritSpiWriteRegisters(CHNUM_BASE, 1, &pxSRadioInitStruct->cChannelNumber); + + /* Configures the Analog Radio registers */ + SpiritSpiWriteRegisters(CHSPACE_BASE, 4, anaRadioRegArray); + + /* Configures the Digital Radio registers */ + g_xStatus = SpiritSpiWriteRegisters(MOD1_BASE, 4, digRadioRegArray); + + /* Enable the freeze option of the AFC on the SYNC word */ + SpiritRadioAFCFreezeOnSync(S_ENABLE); + + /* Set the IQC correction optimal value */ + anaRadioRegArray[0]=0x80; + anaRadioRegArray[1]=0xE3; + g_xStatus = SpiritSpiWriteRegisters(0x99, 2, anaRadioRegArray); + + return SpiritRadioSetFrequencyBase(pxSRadioInitStruct->lFrequencyBase); + +} + + +/** +* @brief Returns the SPIRIT analog and digital radio structure according to the registers value. +* @param pxSRadioInitStruct pointer to a SRadioInit structure that +* contains the configuration information for the analog radio part of SPIRIT. +* @retval None. +*/ +void SpiritRadioGetInfo(SRadioInit* pxSRadioInitStruct) +{ + uint8_t anaRadioRegArray[8], digRadioRegArray[4]; + BandSelect band; + int16_t xtalOffsetFactor; + + /* Get the RF board version */ + //SpiritVersion xSpiritVersion = SpiritGeneralGetSpiritVersion(); + + /* Reads the Analog Radio registers */ + SpiritSpiReadRegisters(SYNT3_BASE, 8, anaRadioRegArray); + + /* Reads the Digital Radio registers */ + g_xStatus = SpiritSpiReadRegisters(MOD1_BASE, 4, digRadioRegArray); + + /* Reads the operating band masking the Band selected field */ + if((anaRadioRegArray[3] & 0x07) == SYNT0_BS_6) + { + band = HIGH_BAND; + } + else if ((anaRadioRegArray[3] & 0x07) == SYNT0_BS_12) + { + band = MIDDLE_BAND; + } + else if ((anaRadioRegArray[3] & 0x07) == SYNT0_BS_16) + { + band = LOW_BAND; + } + else if ((anaRadioRegArray[3] & 0x07) == SYNT0_BS_32) + { + band = VERY_LOW_BAND; + } + else + { + /* if it is another value, set it to a valid one in order to avoid access violation */ + uint8_t tmp=(anaRadioRegArray[3]&0xF8)|SYNT0_BS_6; + SpiritSpiWriteRegisters(SYNT0_BASE,1,&tmp); + band = HIGH_BAND; + } + + /* Computes the synth word */ + uint32_t synthWord = (uint32_t)((((uint32_t)(anaRadioRegArray[0]&0x1F))<<21)+(((uint32_t)(anaRadioRegArray[1]))<<13)+\ + (((uint32_t)(anaRadioRegArray[2]))<<5)+(((uint32_t)(anaRadioRegArray[3]))>>3)); + + /* Calculates the frequency base */ + uint8_t cRefDiv = (uint8_t)SpiritRadioGetRefDiv()+1; + pxSRadioInitStruct->lFrequencyBase = (uint32_t)round(synthWord*(((double)s_lXtalFrequency)/(FBASE_DIVIDER*cRefDiv*s_vectcBHalfFactor[band]))); + + /* Calculates the Offset Factor */ + uint16_t xtalOffTemp = ((((uint16_t)anaRadioRegArray[6])<<8)+((uint16_t)anaRadioRegArray[7])); + + /* If a negative number then convert the 12 bit 2-complement in a 16 bit number */ + if(xtalOffTemp & 0x0800) + { + xtalOffTemp = xtalOffTemp | 0xF000; + } + else + { + xtalOffTemp = xtalOffTemp & 0x0FFF; + } + + xtalOffsetFactor = *((int16_t*)(&xtalOffTemp)); + + /* Calculates the frequency offset in ppm */ + pxSRadioInitStruct->nXtalOffsetPpm =(int16_t)((uint32_t)xtalOffsetFactor*s_lXtalFrequency*PPM_FACTOR)/((uint32_t)FBASE_DIVIDER*pxSRadioInitStruct->lFrequencyBase); + + /* Channel space */ + pxSRadioInitStruct->nChannelSpace = anaRadioRegArray[4]*(s_lXtalFrequency>>15); + + /* Channel number */ + pxSRadioInitStruct->cChannelNumber = SpiritRadioGetChannel(); + + /* Modulation select */ + pxSRadioInitStruct->xModulationSelect = (ModulationSelect)(digRadioRegArray[1] & 0x70); + + /* Reads the frequency deviation for mantissa and exponent */ + uint8_t FDevM = digRadioRegArray[2]&0x07; + uint8_t FDevE = (digRadioRegArray[2]&0xF0)>>4; + + /* Reads the channel filter register for mantissa and exponent */ + uint8_t bwM = (digRadioRegArray[3]&0xF0)>>4; + uint8_t bwE = digRadioRegArray[3]&0x0F; + + uint8_t cDivider = 0; + cDivider = SpiritRadioGetDigDiv(); + + /* Calculates the datarate */ + pxSRadioInitStruct->lDatarate = ((s_lXtalFrequency>>(5+cDivider))*(256+digRadioRegArray[0]))>>(23-(digRadioRegArray[1]&0x0F)); + + /* Calculates the frequency deviation */ + // (((s_lXtalFrequency>>6)*(8+FDevM))>>(12-FDevE+cCorrection)); + pxSRadioInitStruct->lFreqDev =(uint32_t)((float)s_lXtalFrequency/(((uint32_t)1)<<18)*(uint32_t)((8.0+FDevM)/2*(1<<FDevE))); + + /* Reads the channel filter bandwidth from the look-up table and return it */ + pxSRadioInitStruct->lBandwidth = (uint32_t)(100.0*s_vectnBandwidth26M[bwM+(bwE*9)]*((s_lXtalFrequency>>cDivider)/26e6)); + +} + + +/** +* @brief Sets the Xtal configuration in the ANA_FUNC_CONF0 register. +* @param xXtal one of the possible value of the enum type XtalFrequency. +* @arg XTAL_FLAG_24_MHz: in case of 24 MHz crystal +* @arg XTAL_FLAG_26_MHz: in case of 26 MHz crystal +* @retval None. +*/ +void SpiritRadioSetXtalFlag(XtalFlag xXtal) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_XTAL_FLAG(xXtal)); + + /* Reads the ANA_FUNC_CONF_0 register */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + if(xXtal == XTAL_FLAG_26_MHz) + { + tempRegValue|=SELECT_24_26_MHZ_MASK; + } + else + { + tempRegValue &= (~SELECT_24_26_MHZ_MASK); + } + + /* Sets the 24_26MHz_SELECT field in the ANA_FUNC_CONF_0 register */ + g_xStatus = SpiritSpiWriteRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the Xtal configuration in the ANA_FUNC_CONF0 register. +* @param None. +* @retval XtalFrequency Settled Xtal configuration. +*/ +XtalFlag SpiritRadioGetXtalFlag(void) +{ + uint8_t tempRegValue; + + /* Reads the Xtal configuration in the ANA_FUNC_CONF_0 register and return the value */ + g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &tempRegValue); + + return (XtalFlag)((tempRegValue & 0x40)>>6); + +} + + +/** +* @brief Returns the charge pump word for a given VCO frequency. +* @param lFc channel center frequency expressed in Hz. +* This parameter can be a value in one of the following ranges:<ul> +* <li> High_Band: from 779 MHz to 915 MHz </li> +* <li> Middle Band: from 387 MHz to 470 MHz </li> +* <li> Low Band: from 300 MHz to 348 MHz </li> +* <li> Very low Band: from 150 MHz to 174 MHz </li> </ul> +* @retval uint8_t Charge pump word. +*/ +uint8_t SpiritRadioSearchWCP(uint32_t lFc) +{ + int8_t i; + uint32_t vcofreq; + uint8_t BFactor; + + /* Check the channel center frequency is in one of the possible range */ + s_assert_param(IS_FREQUENCY_BAND(lFc)); + + /* Search the operating band */ + if(IS_FREQUENCY_BAND_HIGH(lFc)) + { + BFactor = HIGH_BAND_FACTOR; + } + else if(IS_FREQUENCY_BAND_MIDDLE(lFc)) + { + BFactor = MIDDLE_BAND_FACTOR; + } + else if(IS_FREQUENCY_BAND_LOW(lFc)) + { + BFactor = LOW_BAND_FACTOR; + } + else + { + BFactor = VERY_LOW_BAND_FACTOR; + } + + /* Calculates the VCO frequency VCOFreq = lFc*B */ + vcofreq = (lFc/1000000)*BFactor; + + /* Search in the vco frequency array the charge pump word */ + if(vcofreq>=s_vectnVCOFreq[15]) + { + i=15; + } + else + { + /* Search the value */ + for(i=0 ; i<15 && vcofreq>s_vectnVCOFreq[i] ; i++); + + /* Be sure that it is the best approssimation */ + if (i!=0 && s_vectnVCOFreq[i]-vcofreq>vcofreq-s_vectnVCOFreq[i-1]) + i--; + } + + /* Return index */ + return (i%8); + +} + +/** +* @brief Returns the synth word. +* @param None. +* @retval uint32_t Synth word. +*/ +uint32_t SpiritRadioGetSynthWord(void) +{ + uint8_t regArray[4]; + + /* Reads the SYNTH registers, build the synth word and return it */ + g_xStatus = SpiritSpiReadRegisters(SYNT3_BASE, 4, regArray); + return ((((uint32_t)(regArray[0]&0x1F))<<21)+(((uint32_t)(regArray[1]))<<13)+\ + (((uint32_t)(regArray[2]))<<5)+(((uint32_t)(regArray[3]))>>3)); + +} + + +/** +* @brief Sets the SYNTH registers. +* @param lSynthWord the synth word to write in the SYNTH[3:0] registers. +* @retval None. +*/ +void SpiritRadioSetSynthWord(uint32_t lSynthWord) +{ + uint8_t tempArray[4]; + uint8_t tempRegValue; + + /* Reads the SYNT0 register */ + g_xStatus = SpiritSpiReadRegisters(SYNT0_BASE, 1, &tempRegValue); + + /* Mask the Band selected field */ + tempRegValue &= 0x07; + + /* Build the array for SYNTH registers */ + tempArray[0] = (uint8_t)((lSynthWord>>21)&(0x0000001F)); + tempArray[1] = (uint8_t)((lSynthWord>>13)&(0x000000FF)); + tempArray[2] = (uint8_t)((lSynthWord>>5)&(0x000000FF)); + tempArray[3] = (uint8_t)(((lSynthWord&0x0000001F)<<3)| tempRegValue); + + /* Writes the synth word in the SYNTH registers */ + g_xStatus = SpiritSpiWriteRegisters(SYNT3_BASE, 4, tempArray); + +} + + +/** +* @brief Sets the operating band. +* @param xBand the band to set. +* This parameter can be one of following parameters: +* @arg HIGH_BAND High_Band selected: from 779 MHz to 915 MHz +* @arg MIDDLE_BAND: Middle Band selected: from 387 MHz to 470 MHz +* @arg LOW_BAND: Low Band selected: from 300 MHz to 348 MHz +* @arg VERY_LOW_BAND: Very low Band selected: from 150 MHz to 174 MHz +* @retval None. +*/ +void SpiritRadioSetBand(BandSelect xBand) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_BAND_SELECTED(xBand)); + + /* Reads the SYNT0 register*/ + g_xStatus = SpiritSpiReadRegisters(SYNT0_BASE, 1, &tempRegValue); + + /* Mask the SYNTH[4;0] field and write the BS value */ + tempRegValue &= 0xF8; + tempRegValue |= s_vectcBandRegValue[xBand]; + + /* Configures the SYNT0 register setting the operating band */ + g_xStatus = SpiritSpiWriteRegisters(SYNT0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the operating band. +* @param None. +* @retval BandSelect Settled band. +* This returned value can be one of the following parameters: +* @arg HIGH_BAND High_Band selected: from 779 MHz to 915 MHz +* @arg MIDDLE_BAND: Middle Band selected: from 387 MHz to 470 MHz +* @arg LOW_BAND: Low Band selected: from 300 MHz to 348 MHz +* @arg VERY_LOW_BAND: Very low Band selected: from 150 MHz to 174 MHz +*/ +BandSelect SpiritRadioGetBand(void) +{ + uint8_t tempRegValue; + + /* Reads the SYNT0 register */ + g_xStatus = SpiritSpiReadRegisters(SYNT0_BASE, 1, &tempRegValue); + + /* Mask the Band selected field */ + if((tempRegValue & 0x07) == SYNT0_BS_6) + { + return HIGH_BAND; + } + else if ((tempRegValue & 0x07) == SYNT0_BS_12) + { + return MIDDLE_BAND; + } + else if ((tempRegValue & 0x07) == SYNT0_BS_16) + { + return LOW_BAND; + } + else + { + return VERY_LOW_BAND; + } + +} + + +/** +* @brief Sets the channel number. +* @param cChannel the channel number. +* @retval None. +*/ +void SpiritRadioSetChannel(uint8_t cChannel) +{ + /* Writes the CHNUM register */ + g_xStatus = SpiritSpiWriteRegisters(CHNUM_BASE, 1, &cChannel); + +} + + +/** +* @brief Returns the actual channel number. +* @param None. +* @retval uint8_t Actual channel number. +*/ +uint8_t SpiritRadioGetChannel(void) +{ + uint8_t tempRegValue; + + /* Reads the CHNUM register and return the value */ + g_xStatus = SpiritSpiReadRegisters(CHNUM_BASE, 1, &tempRegValue); + + return tempRegValue; + +} + + +/** +* @brief Sets the channel space factor in channel space register. +* The channel spacing step is computed as F_Xo/32768. +* @param fChannelSpace the channel space expressed in Hz. +* @retval None. +*/ +void SpiritRadioSetChannelSpace(uint32_t fChannelSpace) +{ + uint8_t cChannelSpaceFactor; + + /* Round to the nearest integer */ + cChannelSpaceFactor = ((uint32_t)fChannelSpace*CHSPACE_DIVIDER)/s_lXtalFrequency; + + /* Write value into the register */ + g_xStatus = SpiritSpiWriteRegisters(CHSPACE_BASE, 1, &cChannelSpaceFactor); + +} + + +/** +* @brief Returns the channel space register. +* @param None. +* @retval uint32_t Channel space. The channel space is: CS = channel_space_factor x XtalFrequency/2^15 +* where channel_space_factor is the CHSPACE register value. +*/ +uint32_t SpiritRadioGetChannelSpace(void) +{ + uint8_t channelSpaceFactor; + + /* Reads the CHSPACE register, calculate the channel space and return it */ + g_xStatus = SpiritSpiReadRegisters(CHSPACE_BASE, 1, &channelSpaceFactor); + + /* Compute the Hertz value and return it */ + return ((channelSpaceFactor*s_lXtalFrequency)/CHSPACE_DIVIDER); + +} + + +/** +* @brief Sets the FC OFFSET register starting from xtal ppm value. +* @param nXtalPpm the xtal offset expressed in ppm. +* @retval None. +*/ +void SpiritRadioSetFrequencyOffsetPpm(int16_t nXtalPpm) +{ + uint8_t tempArray[2]; + int16_t xtalOffsetFactor; + uint32_t synthWord, fBase; + int32_t FOffsetTmp; + BandSelect band; + + /* Reads the synth word */ + synthWord = SpiritRadioGetSynthWord(); + + /* Reads the operating band */ + band = SpiritRadioGetBand(); + + /* Calculates the frequency base */ + uint8_t cRefDiv = (uint8_t)SpiritRadioGetRefDiv()+1; + fBase = synthWord*(s_lXtalFrequency/(s_vectcBHalfFactor[band]*cRefDiv)/FBASE_DIVIDER); + + /* Calculates the offset respect to RF frequency and according to xtal_ppm parameter */ + FOffsetTmp = (int32_t)(((float)nXtalPpm*fBase)/PPM_FACTOR); + + /* Check the Offset is in the correct range */ + s_assert_param(IS_FREQUENCY_OFFSET(FOffsetTmp,s_lXtalFrequency)); + + /* Calculates the FC_OFFSET value to write in the corresponding register */ + xtalOffsetFactor = (int16_t)(((float)FOffsetTmp*FBASE_DIVIDER)/s_lXtalFrequency); + + /* Build the array related to the FC_OFFSET_1 and FC_OFFSET_0 register */ + tempArray[0]=(uint8_t)((((uint16_t)xtalOffsetFactor)>>8)&0x0F); + tempArray[1]=(uint8_t)(xtalOffsetFactor); + + /* Writes the FC_OFFSET registers */ + g_xStatus = SpiritSpiWriteRegisters(FC_OFFSET1_BASE, 2, tempArray); + +} + + +/** +* @brief Sets the FC OFFSET register starting from frequency offset expressed in Hz. +* @param lFOffset frequency offset expressed in Hz as signed word. +* @retval None. +*/ +void SpiritRadioSetFrequencyOffset(int32_t lFOffset) +{ + uint8_t tempArray[2]; + int16_t offset; + + /* Check that the Offset is in the correct range */ + s_assert_param(IS_FREQUENCY_OFFSET(lFOffset,s_lXtalFrequency)); + + /* Calculates the offset value to write in the FC_OFFSET register */ + offset = (int16_t)(((float)lFOffset*FBASE_DIVIDER)/s_lXtalFrequency); + + /* Build the array related to the FC_OFFSET_1 and FC_OFFSET_0 register */ + tempArray[0]=(uint8_t)((((uint16_t)offset)>>8)&0x0F); + tempArray[1]=(uint8_t)(offset); + + /* Writes the FC_OFFSET registers */ + g_xStatus = SpiritSpiWriteRegisters(FC_OFFSET1_BASE, 2, tempArray); + +} + + +/** +* @brief Returns the actual frequency offset. +* @param None. +* @retval int32_t Frequency offset expressed in Hz as signed word. +*/ +int32_t SpiritRadioGetFrequencyOffset(void) +{ + uint8_t tempArray[2]; + int16_t xtalOffsetFactor; + + /* Reads the FC_OFFSET registers */ + g_xStatus = SpiritSpiReadRegisters(FC_OFFSET1_BASE, 2, tempArray); + + /* Calculates the Offset Factor */ + uint16_t xtalOffTemp = ((((uint16_t)tempArray[0])<<8)+((uint16_t)tempArray[1])); + + if(xtalOffTemp & 0x0800) + { + xtalOffTemp = xtalOffTemp | 0xF000; + } + else + { + xtalOffTemp = xtalOffTemp & 0x0FFF; + } + + xtalOffsetFactor = *((int16_t*)(&xtalOffTemp)); + + /* Calculates the frequency offset and return it */ + return ((int32_t)(xtalOffsetFactor*s_lXtalFrequency)/FBASE_DIVIDER); + +} + + + +/** +* @brief Sets the Synth word and the Band Select register according to desired base carrier frequency. +* In this API the Xtal configuration is read out from +* the corresponding register. The user shall fix it before call this API. +* @param lFBase the base carrier frequency expressed in Hz as unsigned word. +* @retval Error code: 0=no error, 1=error during calibration of VCO. +*/ +uint8_t SpiritRadioSetFrequencyBase(uint32_t lFBase) +{ + uint32_t synthWord, Fc; + uint8_t band, anaRadioRegArray[4], wcp; + + /* Check the parameter */ + s_assert_param(IS_FREQUENCY_BAND(lFBase)); + + /* Search the operating band */ + if(IS_FREQUENCY_BAND_HIGH(lFBase)) + { + band = HIGH_BAND; + } + else if(IS_FREQUENCY_BAND_MIDDLE(lFBase)) + { + band = MIDDLE_BAND; + } + else if(IS_FREQUENCY_BAND_LOW(lFBase)) + { + band = LOW_BAND; + } + else + { + band = VERY_LOW_BAND; + } + + int32_t FOffset = SpiritRadioGetFrequencyOffset(); + uint32_t lChannelSpace = SpiritRadioGetChannelSpace(); + uint8_t cChannelNum = SpiritRadioGetChannel(); + + /* Calculates the channel center frequency */ + Fc = lFBase + FOffset + lChannelSpace*cChannelNum; + + /* Reads the reference divider */ + uint8_t cRefDiv = (uint8_t)SpiritRadioGetRefDiv()+1; + + /* Selects the VCO */ + switch(band) + { + case VERY_LOW_BAND: + if(Fc<161281250) + { + SpiritCalibrationSelectVco(VCO_L); + } + else + { + SpiritCalibrationSelectVco(VCO_H); + } + break; + + case LOW_BAND: + if(Fc<322562500) + { + SpiritCalibrationSelectVco(VCO_L); + } + else + { + SpiritCalibrationSelectVco(VCO_H); + } + break; + + case MIDDLE_BAND: + if(Fc<430083334) + { + SpiritCalibrationSelectVco(VCO_L); + } + else + { + SpiritCalibrationSelectVco(VCO_H); + } + break; + + case HIGH_BAND: + if(Fc<860166667) + { + SpiritCalibrationSelectVco(VCO_L); + } + else + { + SpiritCalibrationSelectVco(VCO_H); + } + } + + /* Search the VCO charge pump word and set the corresponding register */ + wcp = SpiritRadioSearchWCP(Fc); + + synthWord = (uint32_t)(lFBase*s_vectcBHalfFactor[band]*(((double)(FBASE_DIVIDER*cRefDiv))/s_lXtalFrequency)); + + /* Build the array of registers values for the analog part */ + anaRadioRegArray[0] = (uint8_t)(((synthWord>>21)&(0x0000001F))|(wcp<<5)); + anaRadioRegArray[1] = (uint8_t)((synthWord>>13)&(0x000000FF)); + anaRadioRegArray[2] = (uint8_t)((synthWord>>5)&(0x000000FF)); + anaRadioRegArray[3] = (uint8_t)(((synthWord&0x0000001F)<<3)| s_vectcBandRegValue[band]); + + /* Configures the needed Analog Radio registers */ + g_xStatus = SpiritSpiWriteRegisters(SYNT3_BASE, 4, anaRadioRegArray); + + if(xDoVcoCalibrationWA==S_ENABLE) + return SpiritManagementWaVcoCalibration(); + + return 0; +} + +/** +* @brief To say to the set frequency base if do or not the VCO calibration WA. +* @param S_ENABLE or S_DISABLE the WA procedure. +* @retval None. +*/ +void SpiritRadioVcoCalibrationWAFB(SpiritFunctionalState xNewstate) +{ + xDoVcoCalibrationWA=xNewstate; +} + +/** +* @brief Returns the base carrier frequency. +* @param None. +* @retval uint32_t Base carrier frequency expressed in Hz as unsigned word. +*/ +uint32_t SpiritRadioGetFrequencyBase(void) +{ + uint32_t synthWord; + BandSelect band; + + /* Reads the synth word */ + synthWord = SpiritRadioGetSynthWord(); + + /* Reads the operating band */ + band = SpiritRadioGetBand(); + + uint8_t cRefDiv = (uint8_t)SpiritRadioGetRefDiv() + 1; + + /* Calculates the frequency base and return it */ + return (uint32_t)round(synthWord*(((double)s_lXtalFrequency)/(FBASE_DIVIDER*cRefDiv*s_vectcBHalfFactor[band]))); +} + + +/** +* @brief Returns the actual channel center frequency. +* @param None. +* @retval uint32_t Actual channel center frequency expressed in Hz. +*/ +uint32_t SpiritRadioGetCenterFrequency(void) +{ + int32_t offset; + uint8_t channel; + uint32_t fBase; + uint32_t channelSpace; + + /* Reads the frequency base */ + fBase = SpiritRadioGetFrequencyBase(); + + /* Reads the frequency offset */ + offset = SpiritRadioGetFrequencyOffset(); + + /* Reads the channel space */ + channelSpace = SpiritRadioGetChannelSpace(); + + /* Reads the channel number */ + channel = SpiritRadioGetChannel(); + + /* Calculates the channel center frequency and return it */ + return (uint32_t)(fBase + offset + (uint32_t)(channelSpace*channel)); + +} + + +/** +* @brief Returns the mantissa and exponent, whose value used in the datarate formula +* will give the datarate value closer to the given datarate. +* @param fDatarate datarate expressed in bps. This parameter ranging between 100 and 500000. +* @param pcM pointer to the returned mantissa value. +* @param pcE pointer to the returned exponent value. +* @retval None. +*/ +void SpiritRadioSearchDatarateME(uint32_t lDatarate, uint8_t* pcM, uint8_t* pcE) +{ + volatile SpiritBool find = S_FALSE; + int8_t i=15; + uint8_t cMantissaTmp; + uint8_t cDivider = 0; + + /* Check the parameters */ + s_assert_param(IS_DATARATE(lDatarate)); + + cDivider = (uint8_t)SpiritRadioGetDigDiv(); + + /* Search in the datarate array the exponent value */ + while(!find && i>=0) + { + if(lDatarate>=(s_lXtalFrequency>>(20-i+cDivider))) + { + find = S_TRUE; + } + else + { + i--; + } + } + i<0 ? i=0 : i; + *pcE = i; + + /* Calculates the mantissa value according to the datarate formula */ + cMantissaTmp = (lDatarate*((uint32_t)1<<(23-i)))/(s_lXtalFrequency>>(5+cDivider))-256; + + /* Finds the mantissa value with less approximation */ + int16_t mantissaCalculation[3]; + for(uint8_t j=0;j<3;j++) + { + if((cMantissaTmp+j-1)) + { + mantissaCalculation[j]=lDatarate-(((256+cMantissaTmp+j-1)*(s_lXtalFrequency>>(5+cDivider)))>>(23-i)); + } + else + { + mantissaCalculation[j]=0x7FFF; + } + } + uint16_t mantissaCalculationDelta = 0xFFFF; + for(uint8_t j=0;j<3;j++) + { + if(S_ABS(mantissaCalculation[j])<mantissaCalculationDelta) + { + mantissaCalculationDelta = S_ABS(mantissaCalculation[j]); + *pcM = cMantissaTmp+j-1; + } + } + +} + + +/** +* @brief Returns the mantissa and exponent for a given bandwidth. +* Even if it is possible to pass as parameter any value in the below mentioned range, +* the API will search the closer value according to a fixed table of channel +* bandwidth values (@ref s_vectnBandwidth), as defined in the datasheet, returning the corresponding mantissa +* and exponent value. +* @param lBandwidth bandwidth expressed in Hz. This parameter ranging between 1100 and 800100. +* @param pcM pointer to the returned mantissa value. +* @param pcE pointer to the returned exponent value. +* @retval None. +*/ +void SpiritRadioSearchChannelBwME(uint32_t lBandwidth, uint8_t* pcM, uint8_t* pcE) +{ + int8_t i, i_tmp; + uint8_t cDivider = 1; + + /* Search in the channel filter bandwidth table the exponent value */ + if(SpiritRadioGetDigDiv()) + { + cDivider = 2; + } + else + { + cDivider = 1; + } + + s_assert_param(IS_CH_BW(lBandwidth,s_lXtalFrequency/cDivider)); + + uint32_t lChfltFactor = (s_lXtalFrequency/cDivider)/100; + + for(i=0;i<90 && (lBandwidth<(uint32_t)((s_vectnBandwidth26M[i]*lChfltFactor)/2600));i++); + + if(i!=0) + { + /* Finds the mantissa value with less approximation */ + i_tmp=i; + int16_t chfltCalculation[3]; + for(uint8_t j=0;j<3;j++) + { + if(((i_tmp+j-1)>=0) || ((i_tmp+j-1)<=89)) + { + chfltCalculation[j] = lBandwidth - (uint32_t)((s_vectnBandwidth26M[i_tmp+j-1]*lChfltFactor)/2600); + } + else + { + chfltCalculation[j] = 0x7FFF; + } + } + uint16_t chfltDelta = 0xFFFF; + + for(uint8_t j=0;j<3;j++) + { + if(S_ABS(chfltCalculation[j])<chfltDelta) + { + chfltDelta = S_ABS(chfltCalculation[j]); + i=i_tmp+j-1; + } + } + } + (*pcE) = (uint8_t)(i/9); + (*pcM) = (uint8_t)(i%9); + +} + +/** +* @brief Returns the mantissa and exponent, whose value used in the frequency deviation formula +* will give a frequency deviation value most closer to the given frequency deviation. +* @param fFDev frequency deviation expressed in Hz. This parameter can be a value in the range [F_Xo*8/2^18, F_Xo*7680/2^18]. +* @param pcM pointer to the returned mantissa value. +* @param pcE pointer to the returned exponent value. +* @retval None. +*/ +void SpiritRadioSearchFreqDevME(uint32_t lFDev, uint8_t* pcM, uint8_t* pcE) +{ + uint8_t i; + uint32_t a,bp,b=0; + float xtalDivtmp=(float)s_lXtalFrequency/(((uint32_t)1)<<18); + + /* Check the parameters */ + s_assert_param(IS_F_DEV(lFDev,s_lXtalFrequency)); + + for(i=0;i<10;i++) + { + a=(uint32_t)(xtalDivtmp*(uint32_t)(7.5*(1<<i))); + if(lFDev<a) + break; + } + (*pcE) = i; + + for(i=0;i<8;i++) + { + bp=b; + b=(uint32_t)(xtalDivtmp*(uint32_t)((8.0+i)/2*(1<<(*pcE)))); + if(lFDev<b) + break; + } + + (*pcM)=i; + if((lFDev-bp)<(b-lFDev)) + (*pcM)--; + +} + + +/** +* @brief Sets the datarate. +* @param fDatarate datarate expressed in bps. This value shall be in the range +* [100 500000]. +* @retval None. +*/ +void SpiritRadioSetDatarate(uint32_t lDatarate) +{ + uint8_t drE, tempRegValue[2]; + + /* Check the parameters */ + s_assert_param(IS_DATARATE(lDatarate)); + + /* Calculates the datarate mantissa and exponent */ + SpiritRadioSearchDatarateME(lDatarate, &tempRegValue[0], &drE); + + /* Reads the MOD_O register*/ + SpiritSpiReadRegisters(MOD0_BASE, 1, &tempRegValue[1]); + + /* Mask the other fields and set the datarate exponent */ + tempRegValue[1] &= 0xF0; + tempRegValue[1] |= drE; + + /* Writes the Datarate registers */ + g_xStatus = SpiritSpiWriteRegisters(MOD1_BASE, 2, tempRegValue); + +} + + +/** +* @brief Returns the datarate. +* @param None. +* @retval uint32_t Settled datarate expressed in bps. +*/ +uint32_t SpiritRadioGetDatarate(void) +{ + uint8_t tempRegValue[2]; + uint8_t cDivider=0; + + /* Reads the datarate registers for mantissa and exponent */ + g_xStatus = SpiritSpiReadRegisters(MOD1_BASE, 2, tempRegValue); + + /* Calculates the datarate */ + cDivider = (uint8_t)SpiritRadioGetDigDiv(); + + return (((s_lXtalFrequency>>(5+cDivider))*(256+tempRegValue[0]))>>(23-(tempRegValue[1]&0x0F))); +} + + +/** +* @brief Sets the frequency deviation. +* @param fFDev frequency deviation expressed in Hz. Be sure that this value +* is in the correct range [F_Xo*8/2^18, F_Xo*7680/2^18] Hz. +* @retval None. +*/ +void SpiritRadioSetFrequencyDev(uint32_t lFDev) +{ + uint8_t FDevM, FDevE, tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_F_DEV(lFDev, s_lXtalFrequency)); + + /* Calculates the frequency deviation mantissa and exponent */ + SpiritRadioSearchFreqDevME(lFDev, &FDevM, &FDevE); + + /* Reads the FDEV0 register */ + SpiritSpiReadRegisters(FDEV0_BASE, 1, &tempRegValue); + + /* Mask the other fields and set the frequency deviation mantissa and exponent */ + tempRegValue &= 0x08; + tempRegValue |= ((FDevE<<4)|(FDevM)); + + /* Writes the Frequency deviation register */ + g_xStatus = SpiritSpiWriteRegisters(FDEV0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the frequency deviation. +* @param None. +* @retval uint32_t Frequency deviation value expressed in Hz. +* This value will be in the range [F_Xo*8/2^18, F_Xo*7680/2^18] Hz. +*/ +uint32_t SpiritRadioGetFrequencyDev(void) +{ + uint8_t tempRegValue, FDevM, FDevE; + + + /* Reads the frequency deviation register for mantissa and exponent */ + g_xStatus = SpiritSpiReadRegisters(FDEV0_BASE, 1, &tempRegValue); + FDevM = tempRegValue&0x07; + FDevE = (tempRegValue&0xF0)>>4; + + /* Calculates the frequency deviation and return it */ + //return (((s_lXtalFrequency>>6)*(8+FDevM))>>(13-FDevE)); + + return (uint32_t)((float)s_lXtalFrequency/(((uint32_t)1)<<18)*(uint32_t)((8.0+FDevM)/2*(1<<FDevE))); + +} + + +/** +* @brief Sets the channel filter bandwidth. +* @param lBandwidth channel filter bandwidth expressed in Hz. This parameter shall be in the range [1100 800100] +* Even if it is possible to pass as parameter any value in the above mentioned range, +* the API will search the most closer value according to a fixed table of channel +* bandwidth values (@ref s_vectnBandwidth), as defined in the datasheet. To verify the settled channel bandwidth +* it is possible to use the SpiritRadioGetChannelBW() API. +* @retval None. +*/ +void SpiritRadioSetChannelBW(uint32_t lBandwidth) +{ + uint8_t bwM, bwE, tempRegValue; + + /* Search in the channel filter bandwidth table the exponent value */ + if(SpiritRadioGetDigDiv()) + { + s_assert_param(IS_CH_BW(lBandwidth,(s_lXtalFrequency/2))); + } + else + { + s_assert_param(IS_CH_BW(lBandwidth,(s_lXtalFrequency))); + } + + /* Calculates the channel bandwidth mantissa and exponent */ + SpiritRadioSearchChannelBwME(lBandwidth, &bwM, &bwE); + tempRegValue = (bwM<<4)|(bwE); + + /* Writes the Channel filter register */ + g_xStatus = SpiritSpiWriteRegisters(CHFLT_BASE, 1, &tempRegValue); + +} + +/** +* @brief Returns the channel filter bandwidth. +* @param None. +* @retval uint32_t Channel filter bandwidth expressed in Hz. +*/ +uint32_t SpiritRadioGetChannelBW(void) +{ + uint8_t tempRegValue, bwM, bwE; + + /* Reads the channel filter register for mantissa and exponent */ + g_xStatus = SpiritSpiReadRegisters(CHFLT_BASE, 1, &tempRegValue); + bwM = (tempRegValue&0xF0)>>4; + bwE = tempRegValue&0x0F; + + /* Reads the channel filter bandwidth from the look-up table and return it */ + return (uint32_t)(100.0*s_vectnBandwidth26M[bwM+(bwE*9)]*s_lXtalFrequency/26e6); + +} + + +/** +* @brief Sets the modulation type. +* @param xModulation modulation to set. +* This parameter shall be of type @ref ModulationSelect . +* @retval None. +*/ +void SpiritRadioSetModulation(ModulationSelect xModulation) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_MODULATION_SELECTED(xModulation)); + + /* Reads the modulation register */ + SpiritSpiReadRegisters(MOD0_BASE, 1, &tempRegValue); + + /* Mask the other fields and set the modulation type */ + tempRegValue &=0x8F; + tempRegValue |= xModulation; + + /* Writes the modulation register */ + g_xStatus = SpiritSpiWriteRegisters(MOD0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the modulation type used. +* @param None. +* @retval ModulationSelect Settled modulation type. +*/ +ModulationSelect SpiritRadioGetModulation(void) +{ + uint8_t tempRegValue; + + /* Reads the modulation register MOD0*/ + g_xStatus = SpiritSpiReadRegisters(MOD0_BASE, 1, &tempRegValue); + + /* Return the modulation type */ + return (ModulationSelect)(tempRegValue&0x70); + +} + + +/** +* @brief Enables or Disables the Continuous Wave transmit mode. +* @param xNewState new state for power ramping. +* This parameter can be: S_ENABLE or S_DISABLE . +* @retval None. +*/ +void SpiritRadioCWTransmitMode(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the modulation register MOD0 and mask the CW field */ + SpiritSpiReadRegisters(MOD0_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |=MOD0_CW; + } + else + { + tempRegValue &= (~MOD0_CW); + } + + /* Writes the new value in the MOD0 register */ + g_xStatus = SpiritSpiWriteRegisters(MOD0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Sets the OOK Peak Decay. +* @param xOokDecay Peak decay control for OOK. +* This parameter shall be of type @ref OokPeakDecay . +* @retval None. +*/ +void SpiritRadioSetOokPeakDecay(OokPeakDecay xOokDecay) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_OOK_PEAK_DECAY(xOokDecay)); + + /* Reads the RSSI_FLT register */ + SpiritSpiReadRegisters(RSSI_FLT_BASE, 1, &tempRegValue); + + /* Mask the other fields and set OOK Peak Decay */ + tempRegValue &= 0xFC; + tempRegValue |= xOokDecay; + + /* Writes the RSSI_FLT register to set the new OOK peak dacay value */ + g_xStatus = SpiritSpiWriteRegisters(RSSI_FLT_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the OOK Peak Decay. +* @param None +* @retval OokPeakDecay Ook peak decay value. +*/ +OokPeakDecay SpiritRadioGetOokPeakDecay(void) +{ + uint8_t tempRegValue; + + /* Reads the OOK peak decay register RSSI_FLT_BASE*/ + g_xStatus = SpiritSpiReadRegisters(RSSI_FLT_BASE, 1, &tempRegValue); + + /* Returns the OOK peak decay */ + return (OokPeakDecay) (tempRegValue & 0x03); + +} + +/** +* @brief Returns the PA register value that corresponds to the passed dBm power. +* @param lFbase Frequency base expressed in Hz. +* @param fPowerdBm Desired power in dBm. +* @retval Register value as byte. +* @note The power interpolation curves used by this function have been extracted +* by measurements done on the divisional evaluation boards. +*/ +uint8_t SpiritRadioGetdBm2Reg(uint32_t lFBase, float fPowerdBm) +{ + uint8_t i=0; + uint8_t j=0; + float fReg; + + if(IS_FREQUENCY_BAND_HIGH(lFBase)) + { + i=0; + if(lFBase<900000000) i=1;// 868 + } + else if(IS_FREQUENCY_BAND_MIDDLE(lFBase)) + { + i=2; + } + else if(IS_FREQUENCY_BAND_LOW(lFBase)) + { + i=3; + } + else if(IS_FREQUENCY_BAND_VERY_LOW(lFBase)) + { + i=4; + } + + j=1; + if(fPowerdBm>0 && 13.0/fPowerFactors[i][2]-fPowerFactors[i][3]/fPowerFactors[i][2]<fPowerdBm) + j=0; + else if(fPowerdBm<=0 && 40.0/fPowerFactors[i][2]-fPowerFactors[i][3]/fPowerFactors[i][2]>fPowerdBm) + j=2; + + fReg=fPowerFactors[i][2*j]*fPowerdBm+fPowerFactors[i][2*j+1]; + + if(fReg<1) + fReg=1; + else if(fReg>90) + fReg=90; + + return ((uint8_t)fReg); +} + + +/** +* @brief Returns the dBm power that corresponds to the value of PA register. +* @param lFbase Frequency base expressed in Hz. +* @param cPowerReg Register value of the PA. +* @retval Power in dBm as float. +* @note The power interpolation curves used by this function have been extracted +* by measurements done on the divisional evaluation boards. +*/ +float SpiritRadioGetReg2dBm(uint32_t lFBase, uint8_t cPowerReg) +{ + uint8_t i=0; + uint8_t j=0; + float fPower; + + if(cPowerReg==0 || cPowerReg>90) + return (-130.0); + + if(IS_FREQUENCY_BAND_HIGH(lFBase)) + { + i=0; + if(lFBase<900000000) i=1;// 868 + } + else if(IS_FREQUENCY_BAND_MIDDLE(lFBase)) + { + i=2; + } + else if(IS_FREQUENCY_BAND_LOW(lFBase)) + { + i=3; + } + else if(IS_FREQUENCY_BAND_VERY_LOW(lFBase)) + { + i=4; + } + + j=1; + if(cPowerReg<13) j=0; + else if(cPowerReg>40) j=2; + + fPower=(((float)cPowerReg)/fPowerFactors[i][2*j]-fPowerFactors[i][2*j+1]/fPowerFactors[i][2*j]); + + return fPower; +} + +/** +* @brief Configures the Power Amplifier Table and registers with value expressed in dBm. +* @param cPALevelMaxIndex number of levels to set. This parameter shall be in the range [0:7]. +* @param cWidth step width expressed in terms of bit period units Tb/8. +* This parameter shall be in the range [1:4]. +* @param xCLoad one of the possible value of the enum type PALoadCapacitor. +* @arg LOAD_0_PF No additional PA load capacitor +* @arg LOAD_1_2_PF 1.2pF additional PA load capacitor +* @arg LOAD_2_4_PF 2.4pF additional PA load capacitor +* @arg LOAD_3_6_PF 3.6pF additional PA load capacitor +* @param pfPAtabledBm pointer to an array of PA values in dbm between [-PA_LOWER_LIMIT: PA_UPPER_LIMIT] dbm. +* The first element shall be the lower level (PA_LEVEL[0]) value and the last element +* the higher level one (PA_LEVEL[paLevelMaxIndex]). +* @retval None. +*/ +void SpiritRadioSetPATabledBm(uint8_t cPALevelMaxIndex, uint8_t cWidth, PALoadCapacitor xCLoad, float* pfPAtabledBm) +{ + uint8_t palevel[9], address, paLevelValue; + uint32_t lFBase=SpiritRadioGetFrequencyBase(); + + /* Check the parameters */ + s_assert_param(IS_PA_MAX_INDEX(cPALevelMaxIndex)); + s_assert_param(IS_PA_STEP_WIDTH(cWidth)); + s_assert_param(IS_PA_LOAD_CAP(xCLoad)); + + /* Check the PA level in dBm is in the range and calculate the PA_LEVEL value + to write in the corresponding register using the linearization formula */ + for(int i=0; i<=cPALevelMaxIndex; i++) + { + s_assert_param(IS_PAPOWER_DBM(*pfPAtabledBm)); + paLevelValue=SpiritRadioGetdBm2Reg(lFBase,(*pfPAtabledBm)); + palevel[cPALevelMaxIndex-i]=paLevelValue; + pfPAtabledBm++; + } + + /* Sets the PA_POWER[0] register */ + palevel[cPALevelMaxIndex+1]=xCLoad|(cWidth-1)<<3|cPALevelMaxIndex; + + /* Sets the base address */ + address=PA_POWER8_BASE+7-cPALevelMaxIndex; + + /* Configures the PA_POWER registers */ + g_xStatus = SpiritSpiWriteRegisters(address, cPALevelMaxIndex+2, palevel); + +} + + +/** +* @brief Returns the Power Amplifier Table and registers, returning values in dBm. +* @param pcPALevelMaxIndex pointer to the number of levels settled. +* This parameter will be in the range [0:7]. +* @param pfPAtabledBm pointer to an array of 8 elements containing the PA value in dbm. +* The first element will be the PA_LEVEL_0 and the last element +* will be PA_LEVEL_7. Any value higher than PA_UPPER_LIMIT implies no output +* power (output stage is in high impedance). +* @retval None. +*/ +void SpiritRadioGetPATabledBm(uint8_t* pcPALevelMaxIndex, float* pfPAtabledBm) +{ + uint8_t palevelvect[9]; + uint32_t lFBase=SpiritRadioGetFrequencyBase(); + + /* Reads the PA_LEVEL_x registers and the PA_POWER_0 register */ + g_xStatus = SpiritSpiReadRegisters(PA_POWER8_BASE, 9, palevelvect); + + /* Fill the PAtable */ + for(int i=7; i>=0; i--) + { + (*pfPAtabledBm)=SpiritRadioGetReg2dBm(lFBase,palevelvect[i]); + pfPAtabledBm++; + } + + /* Return the settled index */ + *pcPALevelMaxIndex = palevelvect[8]&0x07; + +} + + + + + + +/** +* @brief Sets a specific PA_LEVEL register, with a value given in dBm. +* @param cIndex PA_LEVEL to set. This parameter shall be in the range [0:7]. +* @param fPowerdBm PA value to write expressed in dBm . Be sure that this values is in the +* correct range [-PA_LOWER_LIMIT: PA_UPPER_LIMIT] dBm. +* @retval None. +* @note This function makes use of the @ref SpiritRadioGetdBm2Reg fcn to interpolate the +* power value. +*/ +void SpiritRadioSetPALeveldBm(uint8_t cIndex, float fPowerdBm) +{ + uint8_t address, paLevelValue; + + /* Check the parameters */ + s_assert_param(IS_PA_MAX_INDEX(cIndex)); + s_assert_param(IS_PAPOWER_DBM(fPowerdBm)); + + /* interpolate the power level */ + paLevelValue=SpiritRadioGetdBm2Reg(SpiritRadioGetFrequencyBase(),fPowerdBm); + + /* Sets the base address */ + address=PA_POWER8_BASE+7-cIndex; + + /* Configures the PA_LEVEL register */ + g_xStatus = SpiritSpiWriteRegisters(address, 1, &paLevelValue); + +} + + +/** +* @brief Returns a specific PA_LEVEL register, returning a value in dBm. +* @param cIndex PA_LEVEL to read. This parameter shall be in the range [0:7] +* @retval float Settled power level expressed in dBm. A value +* higher than PA_UPPER_LIMIT dBm implies no output power +* (output stage is in high impedance). +* @note This function makes use of the @ref SpiritRadioGetReg2dBm fcn to interpolate the +* power value. +*/ +float SpiritRadioGetPALeveldBm(uint8_t cIndex) +{ + uint8_t address, paLevelValue; + + /* Check the parameters */ + s_assert_param(IS_PA_MAX_INDEX(cIndex)); + + /* Sets the base address */ + address=PA_POWER8_BASE+7-cIndex; + + /* Reads the PA_LEVEL[cIndex] register */ + g_xStatus = SpiritSpiReadRegisters(address, 1, &paLevelValue); + + return SpiritRadioGetReg2dBm(SpiritRadioGetFrequencyBase(),paLevelValue); +} + + +/** +* @brief Configures the Power Amplifier Table and registers. +* @param cPALevelMaxIndex number of levels to set. This parameter shall be in the range [0:7]. +* @param cWidth step width expressed in terms of bit period units Tb/8. +* This parameter shall be in the range [1:4]. +* @param xCLoad one of the possible value of the enum type PALoadCapacitor. +* @arg LOAD_0_PF No additional PA load capacitor +* @arg LOAD_1_2_PF 1.2pF additional PA load capacitor +* @arg LOAD_2_4_PF 2.4pF additional PA load capacitor +* @arg LOAD_3_6_PF 3.6pF additional PA load capacitor +* @param pcPAtable pointer to an array of PA values in the range [0: 90], where 0 implies no +* output power, 1 will be the maximum level and 90 the minimum one +* The first element shall be the lower level (PA_LEVEL[0]) value and the last element +* the higher level one (PA_LEVEL[paLevelMaxIndex]). +* @retval None. +*/ +void SpiritRadioSetPATable(uint8_t cPALevelMaxIndex, uint8_t cWidth, PALoadCapacitor xCLoad, uint8_t* pcPAtable) +{ + uint8_t palevel[9], address; + + /* Check the parameters */ + s_assert_param(IS_PA_MAX_INDEX(cPALevelMaxIndex)); + s_assert_param(IS_PA_STEP_WIDTH(cWidth)); + s_assert_param(IS_PA_LOAD_CAP(xCLoad)); + + /* Check the PA levels are in the range */ + for(int i=0; i<=cPALevelMaxIndex; i++) + { + s_assert_param(IS_PAPOWER(*pcPAtable)); + palevel[cPALevelMaxIndex-i]=*pcPAtable; + pcPAtable++; + } + + /* Sets the PA_POWER[0] register */ + palevel[cPALevelMaxIndex+1]=xCLoad|((cWidth-1)<<3)|cPALevelMaxIndex; + + /* Sets the base address */ + address=PA_POWER8_BASE+7-cPALevelMaxIndex; + + /* Configures the PA_POWER registers */ + g_xStatus = SpiritSpiWriteRegisters(address, cPALevelMaxIndex+2, palevel); + +} + + +/** +* @brief Returns the Power Amplifier Table and registers. +* @param pcPALevelMaxIndex pointer to the number of levels settled. +* This parameter shall be in the range [0:7]. +* @param pcPAtable pointer to an array of 8 elements containing the PA value. +* The first element will be the PA_LEVEL_0 and the last element +* will be PA_LEVEL_7. Any value equals to 0 implies that level has +* no output power (output stage is in high impedance). +* @retval None +*/ +void SpiritRadioGetPATable(uint8_t* pcPALevelMaxIndex, uint8_t* pcPAtable) +{ + uint8_t palevelvect[9]; + + /* Reads the PA_LEVEL_x registers and the PA_POWER_0 register */ + g_xStatus = SpiritSpiReadRegisters(PA_POWER8_BASE, 9, palevelvect); + + /* Fill the PAtable */ + for(int i=7; i>=0; i--) + { + *pcPAtable = palevelvect[i]; + pcPAtable++; + } + + /* Return the settled index */ + *pcPALevelMaxIndex = palevelvect[8]&0x07; + +} + + +/** +* @brief Sets a specific PA_LEVEL register. +* @param cIndex PA_LEVEL to set. This parameter shall be in the range [0:7]. +* @param cPower PA value to write in the register. Be sure that this values is in the +* correct range [0 : 90]. +* @retval None. +*/ +void SpiritRadioSetPALevel(uint8_t cIndex, uint8_t cPower) +{ + uint8_t address; + + /* Check the parameters */ + s_assert_param(IS_PA_MAX_INDEX(cIndex)); + s_assert_param(IS_PAPOWER(cPower)); + + /* Sets the base address */ + address=PA_POWER8_BASE+7-cIndex; + + /* Configures the PA_LEVEL register */ + g_xStatus = SpiritSpiWriteRegisters(address, 1, &cPower); + +} + + +/** +* @brief Returns a specific PA_LEVEL register. +* @param cIndex PA_LEVEL to read. This parameter shall be in the range [0:7]. +* @retval uint8_t PA_LEVEL value. A value equal to zero +* implies no output power (output stage is in high impedance). +*/ +uint8_t SpiritRadioGetPALevel(uint8_t cIndex) +{ + uint8_t address, tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PA_MAX_INDEX(cIndex)); + + /* Sets the base address */ + address=PA_POWER8_BASE+7-cIndex; + + /* Reads the PA_LEVEL[cIndex] register and return the value */ + g_xStatus = SpiritSpiReadRegisters(address, 1, &tempRegValue); + return tempRegValue; + +} + + +/** +* @brief Sets the output stage additional load capacitor bank. +* @param xCLoad one of the possible value of the enum type PALoadCapacitor. +* @arg LOAD_0_PF No additional PA load capacitor +* @arg LOAD_1_2_PF 1.2pF additional PA load capacitor +* @arg LOAD_2_4_PF 2.4pF additional PA load capacitor +* @arg LOAD_3_6_PF 3.6pF additional PA load capacitor +* @retval None. +*/ +void SpiritRadioSetPACwc(PALoadCapacitor xCLoad) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PA_LOAD_CAP(xCLoad)); + + /* Reads the PA_POWER_0 register */ + SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue); + + /* Mask the CWC[1:0] field and write the new value */ + tempRegValue &= 0x3F; + tempRegValue |= xCLoad; + + /* Configures the PA_POWER_0 register */ + g_xStatus = SpiritSpiWriteRegisters(PA_POWER0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the output stage additional load capacitor bank. +* @param None. +* @retval PALoadCapacitor Output stage additional load capacitor bank. +* This parameter can be: +* @arg LOAD_0_PF No additional PA load capacitor +* @arg LOAD_1_2_PF 1.2pF additional PA load capacitor +* @arg LOAD_2_4_PF 2.4pF additional PA load capacitor +* @arg LOAD_3_6_PF 3.6pF additional PA load capacitor +*/ +PALoadCapacitor SpiritRadioGetPACwc(void) +{ + uint8_t tempRegValue; + + /* Reads the PA_POWER_0 register */ + g_xStatus = SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue); + + /* Mask the CWC[1:0] field and return the value*/ + return (PALoadCapacitor)(tempRegValue & 0xC0); + +} + + +/** +* @brief Sets a specific PA_LEVEL_MAX_INDEX. +* @param cIndex PA_LEVEL_MAX_INDEX to set. This parameter shall be in the range [0:7]. +* @retval None +*/ +void SpiritRadioSetPALevelMaxIndex(uint8_t cIndex) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PA_MAX_INDEX(cIndex)); + + /* Reads the PA_POWER_0 register */ + SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue); + + /* Mask the PA_LEVEL_MAX_INDEX[1:0] field and write the new value */ + tempRegValue &= 0xF8; + tempRegValue |= cIndex; + + /* Configures the PA_POWER_0 register */ + g_xStatus = SpiritSpiWriteRegisters(PA_POWER0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the actual PA_LEVEL_MAX_INDEX. +* @param None. +* @retval uint8_t Actual PA_LEVEL_MAX_INDEX. This parameter will be in the range [0:7]. +*/ +uint8_t SpiritRadioGetPALevelMaxIndex(void) +{ + uint8_t tempRegValue; + + /* Reads the PA_POWER_0 register */ + g_xStatus = SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue); + + /* Mask the PA_LEVEL_MAX_INDEX[1:0] field and return the value */ + return (tempRegValue & 0x07); + +} + + +/** +* @brief Sets a specific PA_RAMP_STEP_WIDTH. +* @param cWidth step width expressed in terms of bit period units Tb/8. +* This parameter shall be in the range [1:4]. +* @retval None. +*/ +void SpiritRadioSetPAStepWidth(uint8_t cWidth) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_PA_STEP_WIDTH(cWidth)); + + /* Reads the PA_POWER_0 register */ + SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue); + + /* Mask the PA_RAMP_STEP_WIDTH[1:0] field and write the new value */ + tempRegValue &= 0xE7; + tempRegValue |= (cWidth-1)<<3; + + /* Configures the PA_POWER_0 register */ + g_xStatus = SpiritSpiWriteRegisters(PA_POWER0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the actual PA_RAMP_STEP_WIDTH. +* @param None. +* @retval uint8_t Step width value expressed in terms of bit period units Tb/8. +* This parameter will be in the range [1:4]. +*/ +uint8_t SpiritRadioGetPAStepWidth(void) +{ + uint8_t tempRegValue; + + /* Reads the PA_POWER_0 register */ + g_xStatus = SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue); + + /* Mask the PA_RAMP_STEP_WIDTH[1:0] field and return the value */ + tempRegValue &= 0x18; + return ((tempRegValue>>3)+1); + +} + + +/** +* @brief Enables or Disables the Power Ramping. +* @param xNewState new state for power ramping. +* This parameter can be: S_ENABLE or S_DISABLE. +* @retval None. +*/ +void SpiritRadioPARamping(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PA_POWER_0 register and configure the PA_RAMP_ENABLE field */ + SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |= PA_POWER0_PA_RAMP_MASK; + } + else + { + tempRegValue &= (~PA_POWER0_PA_RAMP_MASK); + } + + /* Sets the PA_POWER_0 register */ + g_xStatus = SpiritSpiWriteRegisters(PA_POWER0_BASE, 1, &tempRegValue); + +} + +/** +* @brief Returns the Power Ramping enable bit. +* @param xNewState new state for power ramping. +* This parameter can be: S_ENABLE or S_DISABLE. +* @retval None. +*/ +SpiritFunctionalState SpiritRadioGetPARamping(void) +{ + uint8_t tempRegValue; + + /* Reads the PA_POWER_0 register and configure the PA_RAMP_ENABLE field */ + g_xStatus = SpiritSpiReadRegisters(PA_POWER0_BASE, 1, &tempRegValue); + + /* Mask and return data */ + return (SpiritFunctionalState)((tempRegValue>>5) & 0x01); + +} + + +/** +* @brief Enables or Disables the AFC. +* @param xNewState new state for AFC. +* This parameter can be: S_ENABLE or S_DISABLE. +* @retval None. +*/ +void SpiritRadioAFC(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the AFC_2 register and configure the AFC Enabled field */ + SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |= AFC2_AFC_MASK; + } + else + { + tempRegValue &= (~AFC2_AFC_MASK); + } + + /* Sets the AFC_2 register */ + g_xStatus = SpiritSpiWriteRegisters(AFC2_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Enables or Disables the AFC freeze on sync word detection. +* @param xNewState new state for AFC freeze on sync word detection. +* This parameter can be: S_ENABLE or S_DISABLE. +* @retval None. +*/ +void SpiritRadioAFCFreezeOnSync(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the AFC_2 register and configure the AFC Freeze on Sync field */ + SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |= AFC2_AFC_FREEZE_ON_SYNC_MASK; + } + else + { + tempRegValue &= (~AFC2_AFC_FREEZE_ON_SYNC_MASK); + } + + /* Sets the AFC_2 register */ + g_xStatus = SpiritSpiWriteRegisters(AFC2_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Sets the AFC working mode. +* @param xMode the AFC mode. This parameter can be one of the values defined in @ref AFCMode : +* @arg AFC_SLICER_CORRECTION AFC loop closed on slicer +* @arg AFC_2ND_IF_CORRECTION AFC loop closed on 2nd conversion stage +* @retval None. +*/ +void SpiritRadioSetAFCMode(AFCMode xMode) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_AFC_MODE(xMode)); + + /* Reads the AFC_2 register and configure the AFC Mode field */ + SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue); + if(xMode == AFC_2ND_IF_CORRECTION) + { + tempRegValue |= AFC_2ND_IF_CORRECTION; + } + else + { + tempRegValue &= (~AFC_2ND_IF_CORRECTION); + } + + /* Sets the AFC_2 register */ + g_xStatus = SpiritSpiWriteRegisters(AFC2_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AFC working mode. +* @param None. +* @retval AFCMode Settled AFC mode. This parameter will be one of the values defined in @ref AFCMode : +* @arg AFC_SLICER_CORRECTION AFC loop closed on slicer +* @arg AFC_2ND_IF_CORRECTION AFC loop closed on 2nd conversion stage +*/ +AFCMode SpiritRadioGetAFCMode(void) +{ + uint8_t tempRegValue; + + /* Reads the AFC_2 register */ + g_xStatus = SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue); + + /* Mask the AFC Mode field and returns the value */ + return (AFCMode)(tempRegValue & 0x20); + +} + + +/** +* @brief Sets the AFC peak detector leakage. +* @param cLeakage the peak detector leakage. This parameter shall be in the range: +* [0:31]. +* @retval None. +*/ +void SpiritRadioSetAFCPDLeakage(uint8_t cLeakage) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_AFC_PD_LEAKAGE(cLeakage)); + + /* Reads the AFC_2 register and configure the AFC PD leakage field */ + SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue); + tempRegValue &= 0xE0; + tempRegValue |= cLeakage; + + /* Sets the AFC_2 register */ + g_xStatus = SpiritSpiWriteRegisters(AFC2_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AFC peak detector leakage. +* @param None. +* @retval uint8_t Peak detector leakage value. This parameter will be in the range: +* [0:31]. +*/ +uint8_t SpiritRadioGetAFCPDLeakage(void) +{ + uint8_t tempRegValue; + + /* Reads the AFC_2 register */ + g_xStatus = SpiritSpiReadRegisters(AFC2_BASE, 1, &tempRegValue); + + /* Mask the AFC PD leakage field and return the value */ + return (tempRegValue & 0x1F); + +} + + +/** +* @brief Sets the length of the AFC fast period expressed as number of samples. +* @param cLength length of the fast period in number of samples. +* @retval None. +*/ +void SpiritRadioSetAFCFastPeriod(uint8_t cLength) +{ + /* Sets the AFC_1 register */ + g_xStatus = SpiritSpiWriteRegisters(AFC1_BASE, 1, &cLength); + +} + + +/** +* @brief Returns the AFC fast period expressed as number of samples. +* @param None. +* @retval uint8_t Length of the fast period in number of samples. +*/ +uint8_t SpiritRadioGetAFCFastPeriod(void) +{ + uint8_t tempRegValue; + + /* Reads the AFC 1 register and return the value */ + g_xStatus = SpiritSpiReadRegisters(AFC1_BASE, 1, &tempRegValue); + + return tempRegValue; + +} + + +/** +* @brief Sets the AFC loop gain in fast mode. +* @param cGain AFC loop gain in fast mode. This parameter shall be in the range: +* [0:15]. +* @retval None. +*/ +void SpiritRadioSetAFCFastGain(uint8_t cGain) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_AFC_FAST_GAIN(cGain)); + + /* Reads the AFC_0 register and configure the AFC Fast Gain field */ + SpiritSpiReadRegisters(AFC0_BASE, 1, &tempRegValue); + tempRegValue &= 0x0F; + tempRegValue |= cGain<<4; + + /* Sets the AFC_0 register */ + g_xStatus = SpiritSpiWriteRegisters(AFC0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AFC loop gain in fast mode. +* @param None. +* @retval uint8_t AFC loop gain in fast mode. This parameter will be in the range: +* [0:15]. +*/ +uint8_t SpiritRadioGetAFCFastGain(void) +{ + uint8_t tempRegValue; + + /* Reads the AFC_0 register, mask the AFC Fast Gain field and return the value */ + g_xStatus = SpiritSpiReadRegisters(AFC0_BASE, 1, &tempRegValue); + + return ((tempRegValue & 0xF0)>>4); + +} + + +/** +* @brief Sets the AFC loop gain in slow mode. +* @param cGain AFC loop gain in slow mode. This parameter shall be in the range: +* [0:15]. +* @retval None. +*/ +void SpiritRadioSetAFCSlowGain(uint8_t cGain) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_AFC_SLOW_GAIN(cGain)); + + /* Reads the AFC_0 register and configure the AFC Slow Gain field */ + SpiritSpiReadRegisters(AFC0_BASE, 1, &tempRegValue); + tempRegValue &= 0xF0; + tempRegValue |= cGain; + + /* Sets the AFC_0 register */ + g_xStatus = SpiritSpiWriteRegisters(AFC0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AFC loop gain in slow mode. +* @param None. +* @retval uint8_t AFC loop gain in slow mode. This parameter will be in the range: +* [0:15]. +*/ +uint8_t SpiritRadioGetAFCSlowGain(void) +{ + uint8_t tempRegValue; + + /* Reads the AFC_0 register, mask the AFC Slow Gain field and return the value */ + g_xStatus = SpiritSpiReadRegisters(AFC0_BASE, 1, &tempRegValue); + + return (tempRegValue & 0x0F); + +} + + +/** +* @brief Returns the AFC correction from the corresponding register. +* @param None. +* @retval int8_t AFC correction, read from the corresponding register. +* This parameter will be in the range [-128:127]. +*/ +int8_t SpiritRadioGetAFCCorrectionReg(void) +{ + uint8_t tempRegValue; + + /* Reads the AFC_CORR register, cast the read value as signed char and return it */ + g_xStatus = SpiritSpiReadRegisters(AFC_CORR_BASE, 1, &tempRegValue); + + return (int8_t)tempRegValue; + +} + + +/** +* @brief Returns the AFC correction expressed in Hz. +* @param None. +* @retval int32_t AFC correction expressed in Hz +* according to the following formula:<ul> +* <li> Fafc[Hz]= (Fdig/(12*2^10))*AFC_CORR where </li> +* <li> AFC_CORR is the value read in the AFC_CORR register </li> </ul> +*/ +int32_t SpiritRadioGetAFCCorrectionHz(void) +{ + int8_t correction; + uint32_t xtal = s_lXtalFrequency; + + /* Reads the AFC correction register */ + correction = SpiritRadioGetAFCCorrectionReg(); + + if(xtal>DOUBLE_XTAL_THR) + { + xtal /= 2; + } + + /* Calculates and return the Frequency Correction */ + return (int32_t)(xtal/(12*pow(2,10))*correction); + +} + + +/** +* @brief Enables or Disables the AGC. +* @param xNewState new state for AGC. +* This parameter can be: S_ENABLE or S_DISABLE +* @retval None. +*/ +void SpiritRadioAGC(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the AGCCTRL_0 register and configure the AGC Enabled field */ + SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |= AGCCTRL0_AGC_MASK; + } + else + { + tempRegValue &= (~AGCCTRL0_AGC_MASK); + } + + /* Sets the AGCCTRL_0 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Sets the AGC working mode. +* @param xMode the AGC mode. This parameter can be one of the values defined in @ref AGCMode : +* @arg AGC_LINEAR_MODE AGC works in linear mode +* @arg AGC_BINARY_MODE AGC works in binary mode +* @retval None. +*/ +void SpiritRadioSetAGCMode(AGCMode xMode) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_AGC_MODE(xMode)); + + /* Reads the AGCCTRL_0 register and configure the AGC Mode field */ + SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + if(xMode == AGC_BINARY_MODE) + { + tempRegValue |= AGC_BINARY_MODE; + } + else + { + tempRegValue &= (~AGC_BINARY_MODE); + } + + /* Sets the AGCCTRL_0 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AGC working mode. +* @param None. +* @retval AGCMode Settled AGC mode. This parameter can be one of the values defined in @ref AGCMode : +* @arg AGC_LINEAR_MODE AGC works in linear mode +* @arg AGC_BINARY_MODE AGC works in binary mode +*/ +AGCMode SpiritRadioGetAGCMode(void) +{ + uint8_t tempRegValue; + + /* Reads the AGCCTRL_0 register, mask the AGC Mode field and return the value */ + g_xStatus = SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + + return (AGCMode)(tempRegValue & 0x40); + +} + + +/** +* @brief Enables or Disables the AGC freeze on steady state. +* @param xNewState new state for AGC freeze on steady state. +* This parameter can be: S_ENABLE or S_DISABLE. +* @retval None. +*/ +void SpiritRadioAGCFreezeOnSteady(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the AGCCTRL_2 register and configure the AGC Freeze On Steady field */ + SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |= AGCCTRL2_FREEZE_ON_STEADY_MASK; + } + else + { + tempRegValue &= (~AGCCTRL2_FREEZE_ON_STEADY_MASK); + } + + /* Sets the AGCCTRL_2 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Enable or Disable the AGC freeze on sync detection. +* @param xNewState new state for AGC freeze on sync detection. +* This parameter can be: S_ENABLE or S_DISABLE. +* @retval None. +*/ +void SpiritRadioAGCFreezeOnSync(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the AGCCTRL_2 register and configure the AGC Freeze On Sync field */ + SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |= AGCCTRL2_FREEZE_ON_SYNC_MASK; + } + else + { + tempRegValue &= (~AGCCTRL2_FREEZE_ON_SYNC_MASK); + } + + /* Sets the AGCCTRL_2 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Enable or Disable the AGC to start with max attenuation. +* @param xNewState new state for AGC start with max attenuation mode. +* This parameter can be: S_ENABLE or S_DISABLE. +* @retval None. +*/ +void SpiritRadioAGCStartMaxAttenuation(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue = 0x00; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the AGCCTRL_2 register and configure the AGC Start Max Attenuation field */ + SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + if(xNewState == S_ENABLE) + { + tempRegValue |= AGCCTRL2_START_MAX_ATTENUATION_MASK; + } + else + { + tempRegValue &= (~AGCCTRL2_START_MAX_ATTENUATION_MASK); + } + + /* Sets the AGCCTRL_2 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Sets the AGC measure time. +* @param nTime AGC measure time expressed in us. This parameter shall be in the range [0, 393216/F_Xo]. +* @retval None. +*/ +void SpiritRadioSetAGCMeasureTimeUs(uint16_t nTime) +{ + uint8_t tempRegValue, measure; + + /* Check the parameter */ + s_assert_param(IS_AGC_MEASURE_TIME_US(nTime,s_lXtalFrequency)); + + /* Reads the AGCCTRL_2 register */ + SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + + /* Calculates the measure time value to write in the register */ + measure = (uint8_t)lroundf(log2((float)nTime/1e6 * s_lXtalFrequency/12)); + (measure>15) ? (measure=15):(measure); + + /* Mask the MEAS_TIME field and write the new value */ + tempRegValue &= 0xF0; + tempRegValue |= measure; + + /* Sets the AGCCTRL_2 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AGC measure time. +* @param None. +* @retval uint16_t AGC measure time expressed in us. This parameter will be in the range [0, 393216/F_Xo]. +*/ +uint16_t SpiritRadioGetAGCMeasureTimeUs(void) +{ + uint8_t measure; + + /* Reads the AGCCTRL_2 register */ + g_xStatus = SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &measure); + + /* Mask the MEAS_TIME field */ + measure &= 0x0F; + + /* Calculates the measure time value to write in the register */ + return (uint16_t)((12.0/s_lXtalFrequency)*(float)pow(2,measure)*1e6); + +} + + +/** +* @brief Sets the AGC measure time. +* @param cTime AGC measure time to write in the MEAS_TIME field of AGCCTRL_2 register. +* This parameter shall be in the range [0:15]. +* @retval None. +*/ +void SpiritRadioSetAGCMeasureTime(uint8_t cTime) +{ + uint8_t tempRegValue; + + /* Check the parameter */ + s_assert_param(IS_AGC_MEASURE_TIME(cTime)); + + /* Reads the AGCCTRL_2 register */ + SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + + /* Mask the MEAS_TIME field and write the new value */ + tempRegValue &= 0xF0; + tempRegValue |= cTime; + + /* Sets the AGCCTRL_2 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AGC measure time. +* @param None. +* @retval uint8_t AGC measure time read from the MEAS_TIME field of AGCCTRL_2 register. +* This parameter will be in the range [0:15]. +*/ +uint8_t SpiritRadioGetAGCMeasureTime(void) +{ + uint8_t tempRegValue; + + /* Reads the AGCCTRL_2 register, mask the MEAS_TIME field and return the value */ + g_xStatus = SpiritSpiReadRegisters(AGCCTRL2_BASE, 1, &tempRegValue); + + return (tempRegValue & 0x0F); + +} + + +/** +* @brief Sets the AGC hold time. +* @param cTime AGC hold time expressed in us. This parameter shall be in the range[0, 756/F_Xo]. +* @retval None. +*/ +void SpiritRadioSetAGCHoldTimeUs(uint8_t cTime) +{ + uint8_t tempRegValue, hold; + + /* Check the parameter */ + s_assert_param(IS_AGC_HOLD_TIME_US(cTime,s_lXtalFrequency)); + + /* Reads the AGCCTRL_0 register */ + SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + + /* Calculates the hold time value to write in the register */ + hold = (uint8_t)lroundf(((float)cTime/1e6 * s_lXtalFrequency)/12); + (hold>63) ? (hold=63):(hold); + + /* Mask the HOLD_TIME field and write the new value */ + tempRegValue &= 0xC0; + tempRegValue |= hold; + + /* Sets the AGCCTRL_0 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AGC hold time. +* @param None. +* @retval uint8_t AGC hold time expressed in us. This parameter will be in the range: +* [0, 756/F_Xo]. +*/ +uint8_t SpiritRadioGetAGCHoldTimeUs(void) +{ + uint8_t tempRegValue; + + /* Reads the AGCCTRL_0 register */ + g_xStatus = SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + + /* Mask the HOLD_TIME field */ + tempRegValue &= 0x3F; + + /* Calculates the hold time value and return it */ + return (uint8_t)lroundf ((12.0/s_lXtalFrequency)*(tempRegValue*1e6)); + +} + + +/** +* @brief Sets the AGC hold time. +* @param cTime AGC hold time to write in the HOLD_TIME field of AGCCTRL_0 register. +* This parameter shall be in the range [0:63]. +* @retval None. +*/ +void SpiritRadioSetAGCHoldTime(uint8_t cTime) +{ + uint8_t tempRegValue; + + /* Check the parameter */ + s_assert_param(IS_AGC_HOLD_TIME(cTime)); + + /* Reads the AGCCTRL_0 register */ + SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + + /* Mask the HOLD_TIME field and write the new value */ + tempRegValue &= 0xC0; + tempRegValue |= cTime; + + /* Sets the AGCCTRL_0 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AGC hold time. +* @param None. +* @retval uint8_t AGC hold time read from the HOLD_TIME field of AGCCTRL_0 register. +* This parameter will be in the range [0:63]. +*/ +uint8_t SpiritRadioGetAGCHoldTime(void) +{ + uint8_t tempRegValue; + + /* Reads the AGCCTRL_0 register, mask the MEAS_TIME field and return the value */ + g_xStatus = SpiritSpiReadRegisters(AGCCTRL0_BASE, 1, &tempRegValue); + + return (tempRegValue & 0x3F); + +} + + +/** +* @brief Sets the AGC high threshold. +* @param cHighThreshold AGC high threshold to write in the THRESHOLD_HIGH field of AGCCTRL_1 register. +* This parameter shall be in the range [0:15]. +* @retval None. +*/ +void SpiritRadioSetAGCHighThreshold(uint8_t cHighThreshold) +{ + uint8_t tempRegValue; + + /* Check the parameter */ + s_assert_param(IS_AGC_THRESHOLD(cHighThreshold)); + + /* Reads the AGCCTRL_1 register */ + SpiritSpiReadRegisters(AGCCTRL1_BASE, 1, &tempRegValue); + + /* Mask the THRESHOLD_HIGH field and write the new value */ + tempRegValue &= 0x0F; + tempRegValue |= cHighThreshold<<4; + + /* Sets the AGCCTRL_1 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL1_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AGC high threshold. +* @param None. +* @retval uint8_t AGC high threshold read from the THRESHOLD_HIGH field of AGCCTRL_1 register. +* This parameter will be in the range [0:15]. +*/ +uint8_t SpiritRadioGetAGCHighThreshold(void) +{ + uint8_t tempRegValue; + + /* Reads the AGCCTRL_1 register, mask the THRESHOLD_HIGH field and return the value */ + g_xStatus = SpiritSpiReadRegisters(AGCCTRL1_BASE, 1, &tempRegValue); + + return ((tempRegValue & 0xF0)>>4); + +} + + +/** +* @brief Sets the AGC low threshold. +* @param cLowThreshold AGC low threshold to write in the THRESHOLD_LOW field of AGCCTRL_1 register. +* This parameter shall be in the range [0:15]. +* @retval None. +*/ +void SpiritRadioSetAGCLowThreshold(uint8_t cLowThreshold) +{ + uint8_t tempRegValue; + + /* Check the parameter */ + s_assert_param(IS_AGC_THRESHOLD(cLowThreshold)); + + /* Reads the AGCCTRL_1 register */ + SpiritSpiReadRegisters(AGCCTRL1_BASE, 1, &tempRegValue); + + /* Mask the THRESHOLD_LOW field and write the new value */ + tempRegValue &= 0xF0; + tempRegValue |= cLowThreshold; + + /* Sets the AGCCTRL_1 register */ + g_xStatus = SpiritSpiWriteRegisters(AGCCTRL1_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the AGC low threshold. +* @param None. +* @retval uint8_t AGC low threshold read from the THRESHOLD_LOW field of AGCCTRL_1 register. +* This parameter will be in the range [0:15]. +*/ +uint8_t SpiritRadioGetAGCLowThreshold(void) +{ + uint8_t tempRegValue; + + /* Reads the AGCCTRL_1 register, mask the THRESHOLD_LOW field and return the value */ + g_xStatus = SpiritSpiReadRegisters(AGCCTRL1_BASE, 1, &tempRegValue); + + return (tempRegValue & 0x0F); + +} + + +/** +* @brief Sets the clock recovery algorithm. +* @param xMode the Clock Recovery mode. This parameter can be one of the values defined in @ref ClkRecMode : +* @arg CLK_REC_PLL PLL alogrithm for clock recovery +* @arg CLK_REC_DLL DLL alogrithm for clock recovery +* @retval None. +*/ +void SpiritRadioSetClkRecMode(ClkRecMode xMode) +{ + uint8_t tempRegValue; + + /* Check the parameter */ + s_assert_param(IS_CLK_REC_MODE(xMode)); + + /* Reads the FDEV_0 register */ + SpiritSpiReadRegisters(FDEV0_BASE, 1, &tempRegValue); + + /* Mask the CLOCK_REC_ALGO_SEL field and write the new value */ + tempRegValue &= 0xF7; + tempRegValue |= (uint8_t)xMode; + + /* Sets the FDEV_0 register */ + g_xStatus = SpiritSpiWriteRegisters(FDEV0_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the Clock Recovery working mode. +* @param None. +* @retval ClkRecMode Clock Recovery mode. This parameter can be one of the values defined in @ref ClkRecMode : +* @arg CLK_REC_PLL PLL alogrithm for clock recovery +* @arg CLK_REC_DLL DLL alogrithm for clock recovery +*/ +ClkRecMode SpiritRadioGetClkRecMode(void) +{ + uint8_t tempRegValue; + + /* Reads the FDEV_0 register, mask the CLOCK_REC_ALGO_SEL field and return the value */ + g_xStatus = SpiritSpiReadRegisters(FDEV0_BASE, 1, &tempRegValue); + + return (ClkRecMode)(tempRegValue & 0x08); + +} + + +/** +* @brief Sets the clock recovery proportional gain. +* @param cPGain the Clock Recovery proportional gain to write in the CLK_REC_P_GAIN field of CLOCKREC register. +* It represents is log2 value of the clock recovery proportional gain. +* This parameter shall be in the range [0:7]. +* @retval None. +*/ +void SpiritRadioSetClkRecPGain(uint8_t cPGain) +{ + uint8_t tempRegValue; + + /* Check the parameter */ + s_assert_param(IS_CLK_REC_P_GAIN(cPGain)); + + /* Reads the CLOCKREC register */ + SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue); + + /* Mask the CLK_REC_P_GAIN field and write the new value */ + tempRegValue &= 0x1F; + tempRegValue |= (cPGain<<5); + + /* Sets the CLOCKREC register */ + g_xStatus = SpiritSpiWriteRegisters(CLOCKREC_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the log2 of the clock recovery proportional gain. +* @param None. +* @retval uint8_t Clock Recovery proportional gain read from the CLK_REC_P_GAIN field of CLOCKREC register. +* This parameter will be in the range [0:7]. +*/ +uint8_t SpiritRadioGetClkRecPGain(void) +{ + uint8_t tempRegValue; + + /* Reads the CLOCKREC register, mask the CLK_REC_P_GAIN field and return the value */ + g_xStatus = SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue); + + return ((tempRegValue & 0xEF)>>5); + +} + + +/** +* @brief Sets the clock recovery integral gain. +* @param cIGain the Clock Recovery integral gain to write in the CLK_REC_I_GAIN field of CLOCKREC register. +* This parameter shall be in the range [0:15]. +* @retval None. +*/ +void SpiritRadioSetClkRecIGain(uint8_t cIGain) +{ + uint8_t tempRegValue; + + /* Check the parameter */ + s_assert_param(IS_CLK_REC_I_GAIN(cIGain)); + + /* Reads the CLOCKREC register */ + SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue); + + /* Mask the CLK_REC_P_GAIN field and write the new value */ + tempRegValue &= 0xF0; + tempRegValue |= cIGain; + + /* Sets the CLOCKREC register */ + g_xStatus = SpiritSpiWriteRegisters(CLOCKREC_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the clock recovery integral gain. +* @param None. +* @retval uint8_t Clock Recovery integral gain read from the +* CLK_REC_I_GAIN field of CLOCKREC register. +* This parameter will be in the range [0:15]. +*/ +uint8_t SpiritRadioGetClkRecIGain(void) +{ + uint8_t tempRegValue; + + /* Reads the CLOCKREC register, mask the CLK_REC_I_GAIN field and return the value */ + g_xStatus = SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue); + + return (tempRegValue & 0x0F); + +} + + +/** +* @brief Sets the postfilter length for clock recovery algorithm. +* @param xLength the postfilter length in symbols. This parameter can be one of the values defined in @ref PstFltLength : +* @arg PSTFLT_LENGTH_8 Postfilter length is 8 symbols +* @arg PSTFLT_LENGTH_16 Postfilter length is 16 symbols +* @retval None. +*/ +void SpiritRadioSetClkRecPstFltLength(PstFltLength xLength) +{ + uint8_t tempRegValue; + + /* Check the parameter */ + s_assert_param(IS_PST_FLT_LENGTH(xLength)); + + /* Reads the CLOCKREC register */ + SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue); + + /* Mask the PSTFLT_LEN field and write the new value */ + tempRegValue &= 0xEF; + tempRegValue |= (uint8_t)xLength; + + /* Sets the CLOCKREC register */ + g_xStatus = SpiritSpiWriteRegisters(CLOCKREC_BASE, 1, &tempRegValue); + +} + + +/** +* @brief Returns the postfilter length for clock recovery algorithm. +* @param None. +* @retval PstFltLength Postfilter length in symbols. This parameter can be one of the values defined in @ref PstFltLength : +* @arg PSTFLT_LENGTH_8 Postfilter length is 8 symbols +* @arg PSTFLT_LENGTH_16 Postfilter length is 16 symbols +*/ +PstFltLength SpiritRadioGetClkRecPstFltLength(void) +{ + uint8_t tempRegValue; + + /* Reads the CLOCKREC register, mask the PSTFLT_LEN field and return the value */ + g_xStatus = SpiritSpiReadRegisters(CLOCKREC_BASE, 1, &tempRegValue); + + return (PstFltLength)(tempRegValue & 0x10); + +} + + +/** +* @brief Enables or Disables the received data blanking when the CS is under the threshold. +* @param xNewState new state of this mode. +* This parameter can be: S_ENABLE or S_DISABLE . +* @retval None. +*/ +void SpiritRadioCsBlanking(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the ANT_SELECT_CONF_BASE and mask the CS_BLANKING BIT field */ + SpiritSpiReadRegisters(ANT_SELECT_CONF_BASE, 1, &tempRegValue); + + if(xNewState == S_ENABLE) + { + tempRegValue |= ANT_SELECT_CS_BLANKING_MASK; + } + else + { + tempRegValue &= (~ANT_SELECT_CS_BLANKING_MASK); + } + + /* Writes the new value in the ANT_SELECT_CONF register */ + g_xStatus = SpiritSpiWriteRegisters(ANT_SELECT_CONF_BASE, 1, &tempRegValue); + + +} + +/** +* @brief Enables or Disables the persistent RX mode. +* @param xNewState new state of this mode. +* This parameter can be: S_ENABLE or S_DISABLE . +* @retval None. +*/ +void SpiritRadioPersistenRx(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the PROTOCOL0_BASE and mask the PROTOCOL0_PERS_RX_MASK bitfield */ + SpiritSpiReadRegisters(PROTOCOL0_BASE, 1, &tempRegValue); + + if(xNewState == S_ENABLE) + { + tempRegValue |= PROTOCOL0_PERS_RX_MASK; + } + else + { + tempRegValue &= (~PROTOCOL0_PERS_RX_MASK); + } + + /* Writes the new value in the PROTOCOL0_BASE register */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL0_BASE, 1, &tempRegValue); + +} + +/** +* @brief Enables or Disables the synthesizer reference divider. +* @param xNewState new state for synthesizer reference divider. +* This parameter can be: S_ENABLE or S_DISABLE . +* @retval None. +*/ +void SpiritRadioSetRefDiv(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the SYNTH_CONFIG1_BASE and mask the REFDIV bit field */ + SpiritSpiReadRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue); + + if(xNewState == S_ENABLE) + { + tempRegValue |= 0x80; + } + else + { + tempRegValue &= 0x7F; + } + + /* Writes the new value in the SYNTH_CONFIG1_BASE register */ + g_xStatus = SpiritSpiWriteRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue); + +} + +/** +* @brief Get the the synthesizer reference divider state. +* @param void. +* @retval None. +*/ +SpiritFunctionalState SpiritRadioGetRefDiv(void) +{ + uint8_t tempRegValue; + + g_xStatus = SpiritSpiReadRegisters(SYNTH_CONFIG1_BASE, 1, &tempRegValue); + + if(((tempRegValue>>7)&0x1)) + { + return S_ENABLE; + } + else + { + return S_DISABLE; + } + +} + +/** +* @brief Enables or Disables the synthesizer reference divider. +* @param xNewState new state for synthesizer reference divider. +* This parameter can be: S_ENABLE or S_DISABLE . +* @retval None. +*/ +void SpiritRadioSetDigDiv(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Check the parameters */ + s_assert_param(IS_SPIRIT_FUNCTIONAL_STATE(xNewState)); + + /* Reads the XO_RCO_TEST_BASE and mask the PD_CLKDIV bit field */ + SpiritSpiReadRegisters(XO_RCO_TEST_BASE, 1, &tempRegValue); + + if(xNewState == S_ENABLE) + { + tempRegValue &= 0xf7; + } + else + { + + tempRegValue |= 0x08; + } + + /* Writes the new value in the XO_RCO_TEST_BASE register */ + g_xStatus = SpiritSpiWriteRegisters(XO_RCO_TEST_BASE, 1, &tempRegValue); + +} + +/** +* @brief Get the the synthesizer reference divider state. +* @param void. +* @retval None. +*/ +SpiritFunctionalState SpiritRadioGetDigDiv(void) +{ + uint8_t tempRegValue; + + g_xStatus = SpiritSpiReadRegisters(XO_RCO_TEST_BASE, 1, &tempRegValue); + + if(((tempRegValue>>3)&0x1)) + { + return S_DISABLE; + } + else + { + return S_ENABLE; + } + +} + +/** +* @brief Returns the XTAL frequency. +* @param void. +* @retval uint32_t XTAL frequency. +*/ +uint32_t SpiritRadioGetXtalFrequency(void) +{ + return s_lXtalFrequency; +} + +/** +* @brief Sets the XTAL frequency. +* @param uint32_t XTAL frequency. +* @retval void. +*/ +void SpiritRadioSetXtalFrequency(uint32_t lXtalFrequency) +{ + s_lXtalFrequency = lXtalFrequency; +} + +/** +* @} +*/ + + +/** +* @} +*/ + + +/** +* @} +*/ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/ +
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Timer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Timer.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,700 @@ +/** + ****************************************************************************** + * @file SPIRIT_Timer.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief Configuration and management of SPIRIT timers. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Timer.h" +#include "SPIRIT_Radio.h" +#include "MCU_Interface.h" + + + + +/** + * @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** + * @addtogroup SPIRIT_Timer + * @{ + */ + + +/** + * @defgroup Timer_Private_TypesDefinitions Timer Private Types Definitions + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Timer_Private_Defines Timer Private Defines + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Timer_Private_Macros Timer Private Macros + * @{ + */ + + +/** + *@} + */ + + +/** + * @defgroup Timer_Private_Variables Timer Private Variables + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Timer_Private_FunctionPrototypes Timer Private Function Prototypes + * @{ + */ + +/** + *@} + */ + + +/** + * @defgroup Timer_Private_Functions Timer Private Functions + * @{ + */ + +/** + * @brief Enables or Disables the LDCR mode. + * @param xNewState new state for LDCR mode. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritTimerLdcrMode(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + + /* Mask the read value to enable or disable the LDC mode */ + if(xNewState==S_ENABLE) + { + tempRegValue |= PROTOCOL2_LDC_MODE_MASK; + } + else + { + tempRegValue &= ~PROTOCOL2_LDC_MODE_MASK; + } + + /* Writes the register to Enable or Disable the LDCR mode */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL2_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Enables or Disables the LDCR timer reloading with the value stored in the LDCR_RELOAD registers. + * @param xNewState new state for LDCR reloading. + * This parameter can be: S_ENABLE or S_DISABLE. + * @retval None. + */ +void SpiritTimerLdcrAutoReload(SpiritFunctionalState xNewState) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + /* Mask te read value to enable or disable the reload on sync mode */ + if(xNewState==S_ENABLE) + { + tempRegValue |= PROTOCOL1_LDC_RELOAD_ON_SYNC_MASK; + } + else + { + tempRegValue &= ~PROTOCOL1_LDC_RELOAD_ON_SYNC_MASK; + } + + /* Writes the register to Enable or Disable the Auto Reload */ + g_xStatus = SpiritSpiWriteRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + +} + + +/** + * @brief Returns the LDCR timer reload bit. + * @param None. + * @retval SpiritFunctionalState: value of the reload bit. + */ +SpiritFunctionalState SpiritTimerLdcrGetAutoReload(void) +{ + uint8_t tempRegValue; + + /* Reads the register value */ + g_xStatus = SpiritSpiReadRegisters(PROTOCOL1_BASE, 1, &tempRegValue); + + return (SpiritFunctionalState)(tempRegValue & 0x80); + +} + +/** + * @brief Sets the RX timeout timer initialization registers with the values of COUNTER and PRESCALER according to the formula: Trx=PRESCALER*COUNTER*Tck. + * Remember that it is possible to have infinite RX_Timeout writing 0 in the RX_Timeout_Counter and/or RX_Timeout_Prescaler registers. + * @param cCounter value for the timer counter. + * This parameter must be an uint8_t. + * @param cPrescaler value for the timer prescaler. + * This parameter must be an uint8_t. + * @retval None. + */ +void SpiritTimerSetRxTimeout(uint8_t cCounter , uint8_t cPrescaler) +{ + uint8_t tempRegValue[2]={cPrescaler,cCounter}; + + /* Writes the prescaler and counter value for RX timeout in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS5_RX_TIMEOUT_PRESCALER_BASE, 2, tempRegValue); + +} + + +/** + * @brief Sets the RX timeout timer counter and prescaler from the desired value in ms. it is possible to fix the RX_Timeout to + * a minimum value of 50.417us to a maximum value of about 3.28 s. + * @param fDesiredMsec desired timer value. + * This parameter must be a float. + * @retval None + */ + +void SpiritTimerSetRxTimeoutMs(float fDesiredMsec) +{ + uint8_t tempRegValue[2]; + + /* Computes the counter and prescaler value */ + SpiritTimerComputeRxTimeoutValues(fDesiredMsec , &tempRegValue[1] , &tempRegValue[0]); + + /* Writes the prescaler and counter value for RX timeout in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS5_RX_TIMEOUT_PRESCALER_BASE, 2, tempRegValue); + +} + + +/** + * @brief Sets the RX timeout timer counter. If it is equal to 0 the timeout is infinite. + * @param cCounter value for the timer counter. + * This parameter must be an uint8_t. + * @retval None. + */ +void SpiritTimerSetRxTimeoutCounter(uint8_t cCounter) +{ + /* Writes the counter value for RX timeout in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS4_RX_TIMEOUT_COUNTER_BASE, 1, &cCounter); + +} + + +/** + * @brief Sets the RX timeout timer prescaler. If it is equal to 0 the timeout is infinite. + * @param cPrescaler value for the timer prescaler. + * This parameter must be an uint8_t. + * @retval None + */ +void SpiritTimerSetRxTimeoutPrescaler(uint8_t cPrescaler) +{ + /* Writes the prescaler value for RX timeout in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS5_RX_TIMEOUT_PRESCALER_BASE, 1, &cPrescaler); + +} + + +/** + * @brief Returns the RX timeout timer. + * @param pfTimeoutMsec pointer to the variable in which the timeout expressed in milliseconds has to be stored. + * If the returned value is 0, it means that the RX_Timeout is infinite. + * This parameter must be a float*. + * @param pcCounter pointer to the variable in which the timer counter has to be stored. + * This parameter must be an uint8_t*. + * @param pcPrescaler pointer to the variable in which the timer prescaler has to be stored. + * This parameter must be an uint8_t*. + * @retval None. + */ +void SpiritTimerGetRxTimeout(float* pfTimeoutMsec, uint8_t* pcCounter , uint8_t* pcPrescaler) +{ + uint8_t tempRegValue[2]; + + /* Reads the RX timeout registers value */ + g_xStatus = SpiritSpiReadRegisters(TIMERS5_RX_TIMEOUT_PRESCALER_BASE, 2, tempRegValue); + + /* Returns values */ + (*pcPrescaler) = tempRegValue[0]; + (*pcCounter) = tempRegValue[1]; + + float nXtalFrequency = (float)SpiritRadioGetXtalFrequency(); + if(nXtalFrequency>DOUBLE_XTAL_THR) { + nXtalFrequency /= 2.0; + } + nXtalFrequency /= 1000.0; + *pfTimeoutMsec = (float)((tempRegValue[0]+1)*tempRegValue[1]*(1210.0/nXtalFrequency)); + + +} + + +/** + * @brief Sets the LDCR wake up timer initialization registers with the values of + * COUNTER and PRESCALER according to the formula: Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where + * Tck = 28.818 us. The minimum vale of the wakeup timeout is 28.818us (PRESCALER and + * COUNTER equals to 0) and the maximum value is about 1.89 s (PRESCALER anc COUNTER equals + * to 255). + * @param cCounter value for the timer counter. + * This parameter must be an uint8_t. + * @param cPrescaler value for the timer prescaler. + * This parameter must be an uint8_t. + * @retval None. + */ +void SpiritTimerSetWakeUpTimer(uint8_t cCounter , uint8_t cPrescaler) +{ + uint8_t tempRegValue[2]={cPrescaler,cCounter}; + + /* Writes the counter and prescaler value of wake-up timer in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS3_LDC_PRESCALER_BASE, 2, tempRegValue); + +} + + +/** + * @brief Sets the LDCR wake up timer counter and prescaler from the desired value in ms, + * according to the formula: Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where Tck = 28.818 us. + * The minimum vale of the wakeup timeout is 28.818us (PRESCALER and COUNTER equals to 0) + * and the maximum value is about 1.89 s (PRESCALER anc COUNTER equals to 255). + * @param fDesiredMsec desired timer value. + * This parameter must be a float. + * @retval None. + */ +void SpiritTimerSetWakeUpTimerMs(float fDesiredMsec) +{ + uint8_t tempRegValue[2]; + + /* Computes counter and prescaler */ + SpiritTimerComputeWakeUpValues(fDesiredMsec , &tempRegValue[1] , &tempRegValue[0]); + + /* Writes the counter and prescaler value of wake-up timer in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS3_LDC_PRESCALER_BASE, 2, tempRegValue); + +} + + +/** + * @brief Sets the LDCR wake up timer counter. Remember that this value is incresead by one in the Twu calculation. + * Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where Tck = 28.818 us + * @param cCounter value for the timer counter. + * This parameter must be an uint8_t. + * @retval None. + */ +void SpiritTimerSetWakeUpTimerCounter(uint8_t cCounter) +{ + /* Writes the counter value for Wake_Up timer in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS2_LDC_COUNTER_BASE, 1, &cCounter); + +} + + +/** + * @brief Sets the LDCR wake up timer prescaler. Remember that this value is incresead by one in the Twu calculation. + * Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where Tck = 28.818 us + * @param cPrescaler value for the timer prescaler. + * This parameter must be an uint8_t. + * @retval None. + */ +void SpiritTimerSetWakeUpTimerPrescaler(uint8_t cPrescaler) +{ + /* Writes the prescaler value for Wake_Up timer in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS3_LDC_PRESCALER_BASE, 1, &cPrescaler); + +} + + +/** + * @brief Returns the LDCR wake up timer, according to the formula: Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where Tck = 28.818 us. + * @param pfWakeUpMsec pointer to the variable in which the wake-up time expressed in milliseconds has to be stored. + * This parameter must be a float*. + * @param pcCounter pointer to the variable in which the timer counter has to be stored. + * This parameter must be an uint8_t*. + * @param pcPrescaler pointer to the variable in which the timer prescaler has to be stored. + * This parameter must be an uint8_t*. + * @retval None. + */ +void SpiritTimerGetWakeUpTimer(float* pfWakeUpMsec, uint8_t* pcCounter , uint8_t* pcPrescaler) +{ + uint8_t tempRegValue[2]; + //uint32_t xtal=SpiritRadioGetXtalFrequency(); + float rco_freq; + + rco_freq=(float)SpiritTimerGetRcoFrequency(); + + /* Reads the Wake_Up timer registers value */ + g_xStatus = SpiritSpiReadRegisters(TIMERS3_LDC_PRESCALER_BASE, 2, tempRegValue); + + /* Returns values */ + (*pcPrescaler)=tempRegValue[0]; + (*pcCounter)=tempRegValue[1]; + *pfWakeUpMsec = (float)((((*pcPrescaler)+1)*((*pcCounter)+1)*(1000.0/rco_freq))); + +} + + +/** + * @brief Sets the LDCR wake up timer reloading registers with the values of + * COUNTER and PRESCALER according to the formula: Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where + * Tck = 28.818 us. The minimum vale of the wakeup timeout is 28.818us (PRESCALER and + * COUNTER equals to 0) and the maximum value is about 1.89 s (PRESCALER anc COUNTER equals + * to 255). + * @param cCounter reload value for the timer counter. + * This parameter must be an uint8_t. + * @param cPrescaler reload value for the timer prescaler. + * This parameter must be an uint8_t. + * @retval None. + */ +void SpiritTimerSetWakeUpTimerReload(uint8_t cCounter , uint8_t cPrescaler) +{ + uint8_t tempRegValue[2]={cPrescaler,cCounter}; + + /* Writes the counter and prescaler value of reload wake-up timer in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS1_LDC_RELOAD_PRESCALER_BASE, 2, tempRegValue); + +} + + +/** + * @brief Sets the LDCR wake up reload timer counter and prescaler from the desired value in ms, + * according to the formula: Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where Tck = 28.818 us. + * The minimum vale of the wakeup timeout is 28.818us (PRESCALER and COUNTER equals to 0) + * and the maximum value is about 1.89 s (PRESCALER anc COUNTER equals to 255). + * @param fDesiredMsec desired timer value. + * This parameter must be a float. + * @retval None. + */ +void SpiritTimerSetWakeUpTimerReloadMs(float fDesiredMsec) +{ + uint8_t tempRegValue[2]; + + /* Computes counter and prescaler */ + SpiritTimerComputeWakeUpValues(fDesiredMsec , &tempRegValue[1] , &tempRegValue[0]); + + /* Writes the counter and prescaler value of reload wake-up timer in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS1_LDC_RELOAD_PRESCALER_BASE, 2, tempRegValue); + +} + + +/** + * @brief Sets the LDCR wake up timer reload counter. Remember that this value is incresead by one in the Twu calculation. + * Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where Tck = 28.818 us + * @param cCounter value for the timer counter. + * This parameter must be an uint8_t. + * @retval None + */ +void SpiritTimerSetWakeUpTimerReloadCounter(uint8_t cCounter) +{ + /* Writes the counter value for reload Wake_Up timer in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS0_LDC_RELOAD_COUNTER_BASE, 1, &cCounter); + +} + + +/** + * @brief Sets the LDCR wake up timer reload prescaler. Remember that this value is incresead by one in the Twu calculation. + * Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where Tck = 28.818 us + * @param cPrescaler value for the timer prescaler. + * This parameter must be an uint8_t. + * @retval None + */ +void SpiritTimerSetWakeUpTimerReloadPrescaler(uint8_t cPrescaler) +{ + /* Writes the prescaler value for reload Wake_Up timer in the corresponding register */ + g_xStatus = SpiritSpiWriteRegisters(TIMERS1_LDC_RELOAD_PRESCALER_BASE, 1, &cPrescaler); + +} + + +/** + * @brief Returns the LDCR wake up reload timer, according to the formula: Twu=(PRESCALER +1)*(COUNTER+1)*Tck, where Tck = 28.818 us. + * @param pfWakeUpReloadMsec pointer to the variable in which the wake-up reload time expressed in milliseconds has to be stored. + * This parameter must be a float*. + * @param pcCounter pointer to the variable in which the timer counter has to be stored. + * This parameter must be an uint8_t*. + * @param pcPrescaler pointer to the variable in which the timer prescaler has to be stored. + * This parameter must be an uint8_t*. + * @retval None. + */ +void SpiritTimerGetWakeUpTimerReload(float* pfWakeUpReloadMsec, uint8_t* pcCounter , uint8_t* pcPrescaler) +{ + uint8_t tempRegValue[2]; + //uint32_t xtal=SpiritRadioGetXtalFrequency(); + float rco_freq; + + rco_freq=(float)SpiritTimerGetRcoFrequency(); + + /* Reads the reload Wake_Up timer registers value */ + g_xStatus = SpiritSpiReadRegisters(TIMERS1_LDC_RELOAD_PRESCALER_BASE, 2, tempRegValue); + + /* Returns values */ + (*pcPrescaler)=tempRegValue[0]; + (*pcCounter)=tempRegValue[1]; + *pfWakeUpReloadMsec = (float)((((*pcPrescaler)+1)*((*pcCounter)+1)*(1000.0/rco_freq))); + +} + +/** + * @brief Computes and returns the RCO frequency. + * This frequency depends on the xtal frequency and the XTAL bit in register 0x01. + * @retval RCO frequency in Hz as an uint16_t. + */ +uint16_t SpiritTimerGetRcoFrequency(void) +{ + uint16_t rco_freq=34700; + uint32_t xtal=SpiritRadioGetXtalFrequency(); + + if(xtal>30000000) xtal/=2; + + if(xtal==25000000) + { + uint8_t xtal_flag; + SpiritSpiReadRegisters(0x01, 1, &xtal_flag); + xtal_flag=(xtal_flag&0x40); + + if(xtal_flag==0) + { + rco_freq=36100; + } + else + { + rco_freq=33300; + } + } + + return rco_freq; +} + +/** + * @brief Computes the values of the wakeup timer counter and prescaler from the user time expressed in millisecond. + * The prescaler and the counter values are computed maintaining the prescaler value as + * small as possible in order to obtain the best resolution, and in the meantime minimizing the error. + * @param fDesiredMsec desired wakeup timeout in millisecs. + * This parameter must be a float. Since the counter and prescaler are 8 bit registers the maximum + * reachable value is maxTime = fTclk x 256 x 256. + * @param pcCounter pointer to the variable in which the value for the wakeup timer counter has to be stored. + * This parameter must be a uint8_t*. + * @param pcPrescaler pointer to the variable in which the value for the wakeup timer prescaler has to be stored. + * This parameter must be an uint8_t*. + * @retval None + */ +void SpiritTimerComputeWakeUpValues(float fDesiredMsec , uint8_t* pcCounter , uint8_t* pcPrescaler) +{ + float rco_freq,err; + uint32_t n; + + rco_freq=((float)SpiritTimerGetRcoFrequency())/1000; + + /* N cycles in the time base of the timer: + - clock of the timer is RCO frequency + - divide times 1000 more because we have an input in ms (variable rco_freq is already this frequency divided by 1000) + */ + n=(uint32_t)(fDesiredMsec*rco_freq); + + /* check if it is possible to reach that target with prescaler and counter of spirit1 */ + if(n/0xFF>0xFD) + { + /* if not return the maximum possible value */ + (*pcCounter) = 0xFF; + (*pcPrescaler) = 0xFF; + return; + } + + /* prescaler is really 2 as min value */ + (*pcPrescaler)=(n/0xFF)+2; + (*pcCounter) = n / (*pcPrescaler); + + /* check if the error is minimum */ + err=S_ABS((float)(*pcCounter)*(*pcPrescaler)/rco_freq-fDesiredMsec); + + if((*pcCounter)<=254) + { + if(S_ABS((float)((*pcCounter)+1)*(*pcPrescaler)/rco_freq-fDesiredMsec)<err) + (*pcCounter)=(*pcCounter)+1; + } + + /* decrement prescaler and counter according to the logic of this timer in spirit1 */ + (*pcPrescaler)--; + if((*pcCounter)>1) + (*pcCounter)--; + else + (*pcCounter)=1; +} + + +/** + * @brief Computes the values of the rx_timeout timer counter and prescaler from the user time expressed in millisecond. + * The prescaler and the counter values are computed maintaining the prescaler value as + * small as possible in order to obtain the best resolution, and in the meantime minimizing the error. + * @param fDesiredMsec desired rx_timeout in millisecs. + * This parameter must be a float. Since the counter and prescaler are 8 bit registers the maximum + * reachable value is maxTime = fTclk x 255 x 255. + * @param pcCounter pointer to the variable in which the value for the rx_timeout counter has to be stored. + * This parameter must be a uint8_t*. + * @param pcPrescaler pointer to the variable in which the value for the rx_timeout prescaler has to be stored. + * This parameter must be an uint8_t*. + * @retval None + */ +void SpiritTimerComputeRxTimeoutValues(float fDesiredMsec , uint8_t* pcCounter , uint8_t* pcPrescaler) +{ + uint32_t nXtalFrequency = SpiritRadioGetXtalFrequency(); + uint32_t n; + float err; + + /* if xtal is doubled divide it by 2 */ + if(nXtalFrequency>DOUBLE_XTAL_THR) { + nXtalFrequency >>= 1; + } + + /* N cycles in the time base of the timer: + - clock of the timer is xtal/1210 + - divide times 1000 more because we have an input in ms + */ + n=(uint32_t)(fDesiredMsec*nXtalFrequency/1210000); + + /* check if it is possible to reach that target with prescaler and counter of spirit1 */ + if(n/0xFF>0xFD) + { + /* if not return the maximum possible value */ + (*pcCounter) = 0xFF; + (*pcPrescaler) = 0xFF; + return; + } + + /* prescaler is really 2 as min value */ + (*pcPrescaler)=(n/0xFF)+2; + (*pcCounter) = n / (*pcPrescaler); + + /* check if the error is minimum */ + err=S_ABS((float)(*pcCounter)*(*pcPrescaler)*1210000/nXtalFrequency-fDesiredMsec); + + if((*pcCounter)<=254) + { + if(S_ABS((float)((*pcCounter)+1)*(*pcPrescaler)*1210000/nXtalFrequency-fDesiredMsec)<err) + (*pcCounter)=(*pcCounter)+1; + } + + /* decrement prescaler and counter according to the logic of this timer in spirit1 */ + (*pcPrescaler)--; + if((*pcCounter)>1) + (*pcCounter)--; + else + (*pcCounter)=1; +} + + +/** + * @brief Sets the RX timeout stop conditions. + * @param xStopCondition new stop condition. + * This parameter can be any value of @ref RxTimeoutStopCondition. + * @retval None + */ +void SpiritTimerSetRxTimeoutStopCondition(RxTimeoutStopCondition xStopCondition) +{ + uint8_t tempRegValue[2]; + + /* Check the parameters */ + s_assert_param(IS_RX_TIMEOUT_STOP_CONDITION(xStopCondition)); + + /* Reads value on the PKT_FLT_OPTIONS and PROTOCOL2 register */ + g_xStatus = SpiritSpiReadRegisters(PCKT_FLT_OPTIONS_BASE, 2, tempRegValue); + + tempRegValue[0] &= 0xBF; + tempRegValue[0] |= ((xStopCondition & 0x08) << 3); + + tempRegValue[1] &= 0x1F; + tempRegValue[1] |= (xStopCondition << 5); + + /* Writes value on the PKT_FLT_OPTIONS and PROTOCOL2 register */ + g_xStatus = SpiritSpiWriteRegisters(PCKT_FLT_OPTIONS_BASE, 2, tempRegValue); + +} + +/** + * @brief Sends the LDC_RELOAD command to SPIRIT. Reload the LDC timer with the value stored in the LDC_PRESCALER / COUNTER registers. + * @param None. + * @retval None + */ +void SpiritTimerReloadStrobe(void) +{ + /* Sends the CMD_LDC_RELOAD command */ + g_xStatus = SpiritSpiCommandStrobes(COMMAND_LDC_RELOAD); + +} + + +/** + *@} + */ + + +/** + *@} + */ + + +/** + *@} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Types.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/SPIRIT1_Library/Src/SPIRIT_Types.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,225 @@ +/** + ****************************************************************************** + * @file SPIRIT_Types.c + * @author VMA division - AMS + * @version 3.2.2 + * @date 08-July-2015 + * @brief File for SPIRIT types. + * @details + * + * @attention + * + * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "SPIRIT_Types.h" +#include "MCU_Interface.h" + + +/** @addtogroup SPIRIT_Libraries + * @{ + */ + + +/** @addtogroup SPIRIT_Types + * @{ + */ + + +/** @defgroup Types_Private_TypesDefinitions Types Private Types Definitions + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup Types_Private_Defines Types Private Defines + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup Types_Private_Macros Types Private Macros + * @{ + */ + + +/** + * @} + */ + + + +/** @defgroup Types_Private_Variables Types Private Variables + * @{ + */ + +/** + * @brief Spirit Status global variable. + * This global variable of @ref SpiritStatus type is updated on every SPI transaction + * to maintain memory of Spirit Status. + */ + +volatile SpiritStatus g_xStatus; + +/** + * @} + */ + + + +/** @defgroup Types_Private_FunctionPrototypes Types Private FunctionPrototypes + * @{ + */ + + + +/** + * @} + */ + + + +/** @defgroup Types_Private_Functions Types Private Functions + * @{ + */ + +#ifdef SPIRIT_USE_FULL_ASSERT +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file pointer to the source file name + * @param line assert_param error line source number + * @retval : None + */ +void s_assert_failed(uint8_t* file, uint32_t line) +{ + /* User can add his own implementation to report the file name and line number */ + printf("Wrong parameters value: file %s on line %d\r\n", file, (int)line); + + /* Infinite loop */ + while (1) + { + } +} +#elif SPIRIT_USE_VCOM_ASSERT + +#include "SDK_EVAL_VC_General.h" + +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file pointer to the source file name + * @param line assert_param error line source number + * @param expression: string representing the assert failed expression + * @retval : None + */ +void s_assert_failed(uint8_t* file, uint32_t line, char* expression) +{ + + printf("\n\rVCOM DEBUG: Incorrect parameter. Please reboot.\n\r"); + printf("%s:%d \n\r",file,line); + printf("The expression %s returned FALSE.\n\r", expression); + + /* Infinite loop */ + while (1) + { + } +} + +#elif SPIRIT_USE_FRAME_ASSERT + +#include "SdkUsbProtocol.h" + +/** + * @brief Sends a notify frame with a payload indicating the name + * of the assert failed. + * @param expression: string representing the assert failed expression + * @retval : None + */ +void s_assert_failed(char* expression) +{ + char pcPayload[100]; + uint16_t i; + + for(i = 0 ; expression[i]!='(' ; i++); + expression[i]='\0'; + + strcpy(pcPayload, &expression[3]); + + //sprintf(pcPayload, "The expression %s returned FALSE.\n\r", expression); + SpiritNotifyAssertFailed(pcPayload); + +} + +#endif + + +/** + * @brief Updates the gState (the global variable used to maintain memory of Spirit Status) + * reading the MC_STATE register of SPIRIT. + * @param None + * @retval None + */ +void SpiritRefreshStatus(void) +{ + uint8_t tempRegValue; + + /* Reads the MC_STATUS register to update the g_xStatus */ + g_xStatus = SpiritSpiReadRegisters(MC_STATE1_BASE, 1, &tempRegValue); +} + + +/** + * @} + */ + + + +/** + * @} + */ + + + +/** + * @} + */ + + + +/******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/X-NUCLEO-IDS01Ax/radio_gpio.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/X-NUCLEO-IDS01Ax/radio_gpio.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,224 @@ +/** +****************************************************************************** +* @file radio_gpio.h +* @author System Lab - NOIDA +* @version V1.0.0 +* @date 15-May-2014 +* @brief This file contains all the functions prototypes for the gpio +****************************************************************************** +* @attention +* +* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. +* +****************************************************************************** +*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported Variables ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RADIO_GPIO_H +#define __RADIO_GPIO_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#ifdef USE_STM32L1XX_NUCLEO +#include "stm32l1xx_hal.h" +#endif + +#ifdef USE_STM32F4XX_NUCLEO +#include "stm32f4xx_hal.h" +#endif +#include "SPIRIT_Types.h" + +/** + * @addtogroup BSP + * @{ + */ + + +/* Exported types ------------------------------------------------------------*/ + /* MCU GPIO pin working mode for GPIO */ +typedef enum +{ + RADIO_MODE_GPIO_IN = 0x00, /*!< Work as GPIO input */ + RADIO_MODE_EXTI_IN, /*!< Work as EXTI */ + RADIO_MODE_GPIO_OUT, /*!< Work as GPIO output */ +}RadioGpioMode; + + /* MCU GPIO pin enumeration for GPIO */ +typedef enum +{ + RADIO_GPIO_0 = 0x00, /*!< GPIO_0 selected */ + RADIO_GPIO_1 = 0x01, /*!< GPIO_1 selected */ + RADIO_GPIO_2 = 0x02, /*!< GPIO_2 selected */ + RADIO_GPIO_3 = 0x03, /*!< GPIO_3 selected */ + RADIO_GPIO_SDN = 0x04, /*!< GPIO_SDN selected */ +} +RadioGpioPin; + + +/* Exported constants --------------------------------------------------------*/ + + +/* Exported macro ------------------------------------------------------------*/ + /* MCU GPIO pin working mode for GPIO */ +#define IS_RADIO_GPIO_MODE(MODE) (((MODE) == RADIO_MODE_GPIO_IN) || \ + ((MODE) == RADIO_MODE_EXTI_IN) || \ + ((MODE) == RADIO_MODE_GPIO_OUT)) + +/* Number of Arduino pins used for RADIO GPIO interface */ +#define RADIO_GPIO_NUMBER ((uint8_t)5) + +/* MCU GPIO pin enumeration for GPIO */ +#define IS_RADIO_GPIO_PIN(PIN) (((PIN) == RADIO_GPIO_0) || \ + ((PIN) == RADIO_GPIO_1) || \ + ((PIN) == RADIO_GPIO_2) || \ + ((PIN) == RADIO_GPIO_3) || \ + ((PIN) == RADIO_GPIO_SDN)) + +/* Define for RADIO board */ +#if !defined (USE_SPIRIT1_DEFAULT) + #define USE_SPIRIT1_DEFAULT +#endif + +/* @defgroup Radio_Gpio_config_Define */ +/*NOTE: GPIO0, GPIO1, GPIO2 of SPIRIT1 is not used in the shield*/ + +#define RADIO_GPIO_0_PORT GPIOC +#define RADIO_GPIO_0_PIN GPIO_PIN_1 +#define RADIO_GPIO_0_CLOCK_ENABLE() __GPIOC_CLK_ENABLE() +#define RADIO_GPIO_0_CLOCK_DISABLE() __GPIOC_CLK_ENABLE() +#define RADIO_GPIO_0_SPEED GPIO_SPEED_HIGH +#define RADIO_GPIO_0_PUPD GPIO_NOPULL +#define RADIO_GPIO_0_EXTI_LINE GPIO_PIN_1 +#define RADIO_GPIO_0_EXTI_MODE GPIO_MODE_IT_FALLING +#define RADIO_GPIO_0_EXTI_IRQN EXTI1_IRQn +#define RADIO_GPIO_0_EXTI_PREEMPTION_PRIORITY 2 +#define RADIO_GPIO_0_EXTI_SUB_PRIORITY 2 +#define RADIO_GPIO_0_EXTI_IRQ_HANDLER EXTI1_IRQHandler + +#define RADIO_GPIO_1_PORT GPIOB +#define RADIO_GPIO_1_PIN GPIO_PIN_0 +#define RADIO_GPIO_1_CLOCK_ENABLE() __GPIOB_CLK_ENABLE() +#define RADIO_GPIO_1_CLOCK_DISABLE() __GPIOB_CLK_ENABLE() +#define RADIO_GPIO_1_SPEED GPIO_SPEED_HIGH +#define RADIO_GPIO_1_PUPD GPIO_NOPULL +#define RADIO_GPIO_1_EXTI_LINE GPIO_PIN_0 +#define RADIO_GPIO_1_EXTI_MODE GPIO_MODE_IT_FALLING +#define RADIO_GPIO_1_EXTI_IRQN EXTI0_IRQn +#define RADIO_GPIO_1_EXTI_PREEMPTION_PRIORITY 2 +#define RADIO_GPIO_1_EXTI_SUB_PRIORITY 2 +#define RADIO_GPIO_1_EXTI_IRQ_HANDLER EXTI0_IRQHandler + +#define RADIO_GPIO_2_PORT GPIOA +#define RADIO_GPIO_2_PIN GPIO_PIN_4 +#define RADIO_GPIO_2_CLOCK_ENABLE() __GPIOA_CLK_ENABLE() +#define RADIO_GPIO_2_CLOCK_DISABLE() __GPIOA_CLK_ENABLE() +#define RADIO_GPIO_2_SPEED GPIO_SPEED_HIGH +#define RADIO_GPIO_2_PUPD GPIO_NOPULL +#define RADIO_GPIO_2_EXTI_LINE GPIO_PIN_4 +#define RADIO_GPIO_2_EXTI_MODE GPIO_MODE_IT_FALLING +#define RADIO_GPIO_2_EXTI_IRQN EXTI4_IRQn +#define RADIO_GPIO_2_EXTI_PREEMPTION_PRIORITY 2 +#define RADIO_GPIO_2_EXTI_SUB_PRIORITY 2 +#define RADIO_GPIO_2_EXTI_IRQ_HANDLER EXTI4_IRQHandler + + +#if defined (USE_SPIRIT1_DEFAULT) + + +#define RADIO_GPIO_3_PORT GPIOC +#define RADIO_GPIO_3_PIN GPIO_PIN_7 +#define RADIO_GPIO_3_CLOCK_ENABLE() __GPIOC_CLK_ENABLE() +#define RADIO_GPIO_3_CLOCK_DISABLE() __GPIOC_CLK_DISABLE() +#define RADIO_GPIO_3_SPEED GPIO_SPEED_HIGH +#define RADIO_GPIO_3_PUPD GPIO_NOPULL +#define RADIO_GPIO_3_EXTI_LINE GPIO_PIN_7 +#define RADIO_GPIO_3_EXTI_MODE GPIO_MODE_IT_FALLING +#define RADIO_GPIO_3_EXTI_IRQN EXTI9_5_IRQn +#define RADIO_GPIO_3_EXTI_PREEMPTION_PRIORITY 2 +#define RADIO_GPIO_3_EXTI_SUB_PRIORITY 2 +#define RADIO_GPIO_3_EXTI_IRQ_HANDLER EXTI9_5_IRQHandler + +#else + +#define RADIO_GPIO_3_PORT GPIOA +#define RADIO_GPIO_3_PIN GPIO_PIN_0 +#define RADIO_GPIO_3_CLOCK_ENABLE() __GPIOA_CLK_ENABLE() +#define RADIO_GPIO_3_CLOCK_DISABLE() __GPIOA_CLK_DISABLE() +#define RADIO_GPIO_3_SPEED GPIO_SPEED_HIGH +#define RADIO_GPIO_3_PUPD GPIO_NOPULL +#define RADIO_GPIO_3_EXTI_LINE GPIO_PIN_0 +#define RADIO_GPIO_3_EXTI_MODE GPIO_MODE_IT_FALLING +#define RADIO_GPIO_3_EXTI_IRQN EXTI0_IRQn +#define RADIO_GPIO_3_EXTI_PREEMPTION_PRIORITY 2 +#define RADIO_GPIO_3_EXTI_SUB_PRIORITY 2 +#define RADIO_GPIO_3_EXTI_IRQ_HANDLER EXTI0_IRQHandler + +#endif + +#define RADIO_GPIO_SDN_PORT GPIOA +#define RADIO_GPIO_SDN_PIN GPIO_PIN_10 +#define RADIO_GPIO_SDN_CLOCK_ENABLE() __GPIOA_CLK_ENABLE() +#define RADIO_GPIO_SDN_CLOCK_DISABLE() __GPIOA_CLK_DISABLE() +#define RADIO_GPIO_SDN_SPEED GPIO_SPEED_HIGH +#define RADIO_GPIO_SDN_PUPD GPIO_PULLUP + + +#define RADIO_GPIO_IRQ RADIO_GPIO_3 +#define SPIRIT_GPIO_IRQ SPIRIT_GPIO_3 + +/* Exported Variables ------------------------------------------------------------*/ + + +/* Exported functions ------------------------------------------------------- */ +FlagStatus RadioGpioGetLevel(RadioGpioPin xGpio); +void RadioGpioSetLevel(RadioGpioPin xGpio, GPIO_PinState xState); +void SdkEvalEnterShutdown(void); +void SdkEvalExitShutdown(void); +SpiritFlagStatus SdkEvalCheckShutdown(void); +void RadioGpioInit(RadioGpioPin xGpio, RadioGpioMode xGpioMode); +void RadioGpioInterruptCmd(RadioGpioPin xGpio, uint8_t nPreemption, uint8_t nSubpriority, FunctionalState xNewState); + + +#ifdef __cplusplus +} +#endif +#endif /*__RADIO_GPIO_H */ + +/** +* @} +*/ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/X-NUCLEO-IDS01Ax/radio_shield_config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/libs/spirit1/X-NUCLEO-IDS01Ax/radio_shield_config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,120 @@ +/** +****************************************************************************** +* @file radio_shield_config.h +* @author System Lab - NOIDA +* @version V1.0.0 +* @date 15-May-2014 +* @brief This file contains definitions for: +* - LEDs and push-button available on RF shields +****************************************************************************** +* @attention +* +* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. +* +****************************************************************************** +*/ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RADIO_SHIELD_CONFIG_H +#define __RADIO_SHIELD_CONFIG_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#ifdef USE_STM32L1XX_NUCLEO +// #include "stm32l1xx_hal.h" +#endif + +#ifdef USE_STM32F4XX_NUCLEO +// #include "stm32f4xx_hal.h" +#endif + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup X-NUCLEO-IDS02Ax + * @{ + */ + +/** @addtogroup RADIO_SHILED_LOW_LEVEL + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +typedef enum +{ + RADIO_SHIELD_LED = 0 +} Led_t; + + + +/* Exported constants --------------------------------------------------------*/ + + +/* Exported macro ------------------------------------------------------------*/ + /** @addtogroup RF_SHIELD_CONFIG_LOW_LEVEL_LED + * @{ + */ +#define RADIO_SHIELD_LEDn ((uint8_t)1) + +#define RADIO_SHIELD_LED_GPIO_PIN GPIO_PIN_4 /*Rx Indicator LED*/ +#define RADIO_SHIELD_LED_GPIO_PORT GPIOB +#define RADIO_SHIELD_LED_GPIO_CLK_ENABLE() __GPIOB_CLK_ENABLE() +#define RADIO_SHIELD_LED_GPIO_CLK_DISABLE() __GPIOB_CLK_DISABLE() + + +/* Exported Variables ------------------------------------------------------------*/ + + +/* Exported functions ------------------------------------------------------- */ +void RadioShieldLedInit(Led_t Led); +void RadioShieldLedOn(Led_t Led); +void RadioShieldLedOff(Led_t Led); +void RadioShieldLedToggle(Led_t Led); + + + +#ifdef __cplusplus +} +#endif + +#endif /* __RADIO_SHIELD_CONFIG_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/source/radio_spi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/source/radio_spi.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,335 @@ +/** +****************************************************************************** +* @file radio_spi.c +* @author System Lab - NOIDA +* @version V1.0.0 +* @date 15-May-2014 +* @brief This file provides code for the configuration of the SPI instances. +****************************************************************************** +* @attention +* +* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. +* +****************************************************************************** +*/ + + +/* Includes ------------------------------------------------------------------*/ +#include "radio_spi.h" + +#include "SimpleSpirit1.h" + + +/** + * @addtogroup BSP + * @{ + */ + + +/** + * @addtogroup X-NUCLEO-IDS02Ax + * @{ + */ + + +/** + * @defgroup RADIO_SPI_Private_TypesDefinitions RADIO_SPI Private Types Definitions + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup RADIO_SPI_Private_Defines RADIO_SPI Private Defines + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup RADIO_SPI_Private_Macros RADIO_SPI Private Macros + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup RADIO_SPI_Private_Variables RADIO_SPI Private Variables + * @{ + */ + +/** + * @} + */ + + +/** + * @defgroup RADIO_SPI_Private_FunctionPrototypes RADIO_SPI Private Function Prototypes + * @{ + */ + +/** + * @} + */ + +/** + * @defgroup RADIO_SPI_Private_Functions RADIO_SPI Private Functions + * @{ + */ + +/** +* @} +*/ + +/** +* @brief Write single or multiple RF Transceivers register +* @param cRegAddress: base register's address to be write +* @param cNbBytes: number of registers and bytes to be write +* @param pcBuffer: pointer to the buffer of values have to be written into registers +* @retval StatusBytes +*/ +StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer) +{ + return SimpleSpirit1::Instance().SdkEvalSpiWriteRegisters(cRegAddress, cNbBytes, pcBuffer); +} + +StatusBytes SimpleSpirit1::SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer) +{ + uint8_t aHeader[2] = {0}; + uint16_t tmpstatus = 0x0000; + StatusBytes *pStatus=(StatusBytes *)&tmpstatus; + + /* Built the aHeader bytes */ + aHeader[0] = WRITE_HEADER; + aHeader[1] = cRegAddress; + + /* Puts the SPI chip select low to start the transaction */ + chip_sync_select(); + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus = _spi.write(aHeader[0]); + tmpstatus = tmpstatus << 8; + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus |= _spi.write(aHeader[1]); + + /* Writes the registers according to the number of bytes */ + for (int index = 0; index < cNbBytes; index++) + { + _spi.write(pcBuffer[index]); + } + + /* Puts the SPI chip select high to end the transaction */ + chip_sync_unselect(); + + return *pStatus; +} + + +/** +* @brief Read single or multiple SPIRIT1 register +* @param cRegAddress: base register's address to be read +* @param cNbBytes: number of registers and bytes to be read +* @param pcBuffer: pointer to the buffer of registers' values read +* @retval StatusBytes +*/ +StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer) +{ + return SimpleSpirit1::Instance().SdkEvalSpiReadRegisters(cRegAddress, cNbBytes, pcBuffer); +} + +StatusBytes SimpleSpirit1::SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer) +{ + uint16_t tmpstatus = 0x00; + StatusBytes *pStatus = (StatusBytes *)&tmpstatus; + + uint8_t aHeader[2] = {0}; + + /* Built the aHeader bytes */ + aHeader[0] = READ_HEADER; + aHeader[1] = cRegAddress; + + /* Put the SPI chip select low to start the transaction */ + chip_sync_select(); + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus = _spi.write(aHeader[0]); + tmpstatus = tmpstatus << 8; + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus |= _spi.write(aHeader[1]); + + for (int index = 0; index < cNbBytes; index++) + { + pcBuffer[index] = _spi.write(0xFF); + } + + /* Put the SPI chip select high to end the transaction */ + chip_sync_unselect(); + + return *pStatus; +} + + +/** +* @brief Send a command +* @param cCommandCode: command code to be sent +* @retval StatusBytes +*/ +StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode) +{ + return SimpleSpirit1::Instance().SdkEvalSpiCommandStrobes(cCommandCode); +} + +StatusBytes SimpleSpirit1::SdkEvalSpiCommandStrobes(uint8_t cCommandCode) +{ + uint8_t aHeader[2] = {0}; + uint16_t tmpstatus = 0x0000; + + StatusBytes *pStatus = (StatusBytes *)&tmpstatus; + + /* Built the aHeader bytes */ + aHeader[0] = COMMAND_HEADER; + aHeader[1] = cCommandCode; + + /* Puts the SPI chip select low to start the transaction */ + chip_sync_select(); + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus = _spi.write(aHeader[0]); + tmpstatus = tmpstatus<<8; + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus |= _spi.write(aHeader[1]); + + /* Puts the SPI chip select high to end the transaction */ + chip_sync_unselect(); + + return *pStatus; +} + + +/** +* @brief Write data into TX FIFO +* @param cNbBytes: number of bytes to be written into TX FIFO +* @param pcBuffer: pointer to data to write +* @retval StatusBytes +*/ +StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer) +{ + return SimpleSpirit1::Instance().SdkEvalSpiWriteFifo(cNbBytes, pcBuffer); +} + +StatusBytes SimpleSpirit1::SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer) +{ + uint16_t tmpstatus = 0x0000; + StatusBytes *pStatus = (StatusBytes *)&tmpstatus; + + uint8_t aHeader[2] = {0}; + + /* Built the aHeader bytes */ + aHeader[0] = WRITE_HEADER; + aHeader[1] = LINEAR_FIFO_ADDRESS; + + /* Put the SPI chip select low to start the transaction */ + chip_sync_select(); + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus = _spi.write(aHeader[0]); + tmpstatus = tmpstatus<<8; + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus |= _spi.write(aHeader[1]); + + /* Writes the registers according to the number of bytes */ + for (int index = 0; index < cNbBytes; index++) + { + _spi.write(pcBuffer[index]); + } + + /* Put the SPI chip select high to end the transaction */ + chip_sync_unselect(); + + return *pStatus; +} + +/** +* @brief Read data from RX FIFO +* @param cNbBytes: number of bytes to read from RX FIFO +* @param pcBuffer: pointer to data read from RX FIFO +* @retval StatusBytes +*/ +StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer) +{ + return SimpleSpirit1::Instance().SdkEvalSpiReadFifo(cNbBytes, pcBuffer); +} + +StatusBytes SimpleSpirit1::SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer) +{ + uint16_t tmpstatus = 0x0000; + StatusBytes *pStatus = (StatusBytes *)&tmpstatus; + + uint8_t aHeader[2]; + + /* Built the aHeader bytes */ + aHeader[0]=READ_HEADER; + aHeader[1]=LINEAR_FIFO_ADDRESS; + + /* Put the SPI chip select low to start the transaction */ + chip_sync_select(); + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus = _spi.write(aHeader[0]); + tmpstatus = tmpstatus<<8; + + /* Write the aHeader bytes and read the SPIRIT1 status bytes */ + tmpstatus |= _spi.write(aHeader[1]); + + for (int index = 0; index < cNbBytes; index++) + { + pcBuffer[index] = _spi.write(0xFF); + } + + /* Put the SPI chip select high to end the transaction */ + chip_sync_unselect(); + + return *pStatus; +} + + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/stm-spirit1-rf-driver/NanostackRfPhySpirit1.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/stm-spirit1-rf-driver/NanostackRfPhySpirit1.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +#ifndef NANOSTACK_RF_PHY_SPIRIT1_H_ +#define NANOSTACK_RF_PHY_SPIRIT1_H_ + +#include <stdint.h> + +#ifdef MBED_CONF_NANOSTACK_CONFIGURATION + +#include "NanostackRfPhy.h" +#include "PinNames.h" + +// Arduino pin defaults for convenience +#if !defined(SPIRIT1_SPI_MOSI) +#define SPIRIT1_SPI_MOSI D11 +#endif +#if !defined(SPIRIT1_SPI_MISO) +#define SPIRIT1_SPI_MISO D12 +#endif +#if !defined(SPIRIT1_SPI_SCLK) +#define SPIRIT1_SPI_SCLK D13 +#endif +#if !defined(SPIRIT1_DEV_IRQ) +#define SPIRIT1_DEV_IRQ D9 +#endif +#if !defined(SPIRIT1_DEV_CS) +#define SPIRIT1_DEV_CS D10 +#endif +#if !defined(SPIRIT1_DEV_SDN) +#define SPIRIT1_DEV_SDN D2 +#endif +#if !defined(SPIRIT1_BRD_LED) +#define SPIRIT1_BRD_LED NC +#endif + +class NanostackRfPhySpirit1 : public NanostackRfPhy { +public: + NanostackRfPhySpirit1(PinName spi_mosi, PinName spi_miso, PinName spi_sclk, + PinName dev_irq, PinName dev_cs, PinName dev_sdn, PinName brd_led); + ~NanostackRfPhySpirit1(); + int8_t rf_register(); + void rf_unregister(); + void get_mac_address(uint8_t *mac); + void set_mac_address(uint8_t *mac); + +private: + void rf_init(void); + + const PinName _spi_mosi; + const PinName _spi_miso; + const PinName _spi_sclk; + const PinName _dev_irq; + const PinName _dev_cs; + const PinName _dev_sdn; + const PinName _brd_led; +}; + +#endif /* MBED_CONF_NANOSTACK_CONFIGURATION */ +#endif /* NANOSTACK_RF_PHY_SPIRIT1_H_ */
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/stm-spirit1-rf-driver/SimpleSpirit1.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/stm-spirit1-rf-driver/SimpleSpirit1.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,561 @@ +/*** Mbed Includes ***/ +#include "mbed.h" +#include "mbed_debug.h" + + +/*** Cube Includes ***/ +#include "SPIRIT_Radio.h" +#include "SPIRIT_Management.h" +#include "SPIRIT_Commands.h" +#include "MCU_Interface.h" + + +/*** Contiki Lib Includes ***/ +#include "spirit1.h" +#include "spirit1-config.h" +#include "spirit1-const.h" + + +// betzw: enable beyond macro if you want debug messages also from IRQ handler +// #define DEBUG_IRQ + + +/*** Macros from Cube Implementation ***/ +#define CLEAR_TXBUF() (spirit_tx_len = 0) +#define IS_RXBUF_EMPTY() (spirit_rx_len == 0) +#define CLEAR_RXBUF() do { \ + spirit_rx_len = 0; \ + _spirit_rx_pos = 0; \ + } while(0) + + +/*** Macros from Cube Implementation ***/ +/* transceiver state. */ +#define ON 0 +#define OFF 1 + + +/*** Macros for Spirit1 API ***/ +/* max payload */ +#define SPIRIT1_MAX_PAYLOAD (MAX_PACKET_LEN) + + +/*** Missing Cube External Declarations ***/ +extern "C" void SpiritManagementSetFrequencyBase(uint32_t); + + +/*** UnlockedSPI for Usage in IRQ context ***/ +class UnlockedSPI : public SPI { +public: + UnlockedSPI(PinName mosi, PinName miso, PinName sclk) : + SPI(mosi, miso, sclk) { } + virtual ~UnlockedSPI() {} + virtual void lock() { } + virtual void unlock() { } +}; + + +/*** A Simple Spirit1 Class ***/ +// NOTE: must be a singleton (due to mix of MBED/CUBE code)!!! +// NOTE: implementation is IRQ-save but (intentionally) NOT thread-safe!!! +/** Simple Spirit1 Class + * + * @Note Synchronization level: implementation is IRQ-save but (intentionally) NOT thread-safe!!! + * + * Example: + * @code + * #include "mbed.h" + * #include "SimpleSpirit1.h" + * + * static char send_buf[] = "Hello World!"; + * + * static SimpleSpirit1 &myspirit = SimpleSpirit1::CreateInstance(D11, D12, D3, D9, D10, D2); + * + * static volatile bool tx_done_flag = false; + * + * static void callback_func(int event) + * { + * if (event == SimpleSpirit1::TX_DONE) { + * tx_done_flag = true; + * } + * } + * + * int main() + * { + * myspirit.attach_irq_callback(callback_func); + * myspirit.on(); + * + * while(1) + * { + * size_t curr_len = strlen((const char*)send_buf); + * myspirit.send(send_buf, curr_len); + * + * while(!tx_done_flag); + * tx_done_flag = false; + * } + * } + * @endcode + */ +class SimpleSpirit1 { + protected: + static SimpleSpirit1 *_singleton; + + /** Communication Interface Instance Variables **/ + UnlockedSPI _spi; // betzw - NOTE: Morpho/Zio pins are valid only for NUCLEO-F401RE + // mosi: PA_7 (D11) + // miso: PA_6 (D12) + // sclk: PB_3 (D3) or + // PA_5 (D13) (only in case you unmount R4 & mount R7, + // (note: in this case you may not use LED1 on some platforms) + // bits: 8-bit + // mode: 0 + // ordr: MSB + // freq: max 10MHz + InterruptIn _irq; // PC_7 (D9) (falling) + DigitalOut _chip_select; // PB_6 (D10) ('1' == chip unselected) + DigitalOut _shut_down; // PA_10 (D2) ('1' == shut_down) + DigitalOut _led; // PB_4 (D5) (optional) + + Callback<void(int)> _current_irq_callback; + Timeout _rx_receiving_timeout; + + void rx_timeout_handler(void) { + set_ready_state(); + cmd_strobe(SPIRIT1_STROBE_RX); +#ifdef DEBUG_IRQ + debug("\r\n%s (%d)\r\n", __func__, __LINE__); +#endif + } + + void start_rx_timeout(void) { + _rx_receiving_timeout.attach_us(Callback<void()>(this, &SimpleSpirit1::rx_timeout_handler), 100 * 1000); // 100ms + } + + void stop_rx_timeout(void) { + _rx_receiving_timeout.detach(); + } + + /** Static Variables from Cube Implementation **/ + /* + * The buffers which hold incoming data. + * The +1 because of the first byte, + * which will contain the length of the packet. + */ + volatile uint16_t spirit_tx_len; + volatile bool _spirit_tx_started; + volatile uint16_t spirit_rx_len; + volatile uint16_t _spirit_rx_pos; + volatile bool _spirit_rx_err; + uint8_t spirit_rx_buf[MAX_PACKET_LEN]; + volatile bool _is_receiving; + + /** Status Variables from Cube Implementation **/ + unsigned int spirit_on; + uint8_t last_rssi; //MGR + uint8_t last_sqi; //MGR + + /** Low Level Instance Variables **/ + unsigned int _nr_of_irq_disables; + + /** Low Level Instance Methods **/ + void disable_spirit_irq(void) { + _irq.disable_irq(); + _nr_of_irq_disables++; +#ifndef NDEBUG + debug_if(_nr_of_irq_disables == 0, "\r\nassert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + } + + void enable_spirit_irq(void) { +#ifndef NDEBUG + debug_if(_nr_of_irq_disables == 0, "\r\nassert failed in: %s (%d)\r\n", __func__, __LINE__); +#endif + if(--_nr_of_irq_disables == 0) + _irq.enable_irq(); + } + + void chip_select() { _chip_select = 0; } + void chip_unselect() { _chip_select = 1; } + + void enter_shutdown() { + _shut_down = 1; + wait_ms(5); // wait 5 milliseconds (to allow Spirit1 to shut down) + } + + void exit_shutdown() { + _shut_down = 0; + wait_ms(10); // wait 10 milliseconds (to allow Spirit1 a proper boot-up sequence) + } + + void cs_to_sclk_delay(void) { + wait_us(1); // heuristic value + } + + /** + * @brief Write and read a buffer to/from the SPI peripheral device at the same time + * in 8-bit data mode using synchronous SPI communication. + * @param[in] pBufferToWrite pointer to the buffer of data to send. + * @param[out] pBufferToRead pointer to the buffer to read data into. + * @param[in] NumBytes number of bytes to read and write. + * @retval 0 if ok. + * @retval -1 if data format error. + * @note When using the SPI in Interrupt-mode, remember to disable interrupts + * before calling this function and to enable them again after. + */ + void spi_write_read(uint8_t* pBufferToWrite, uint8_t* pBufferToRead, uint16_t NumBytes) + { + /* Read and write data at the same time. */ + for (int i = 0; i < NumBytes; i++) { + pBufferToRead[i] = _spi.write(pBufferToWrite[i]); + } + } + + /** Radio Instance Methods **/ + void radio_set_xtal_freq(uint32_t freq) { + SpiritRadioSetXtalFrequency(freq); + } + + void radio_set_pa_level_dbm(uint8_t cIndex, float fPowerdBm) { + SpiritRadioSetPALeveldBm(cIndex, fPowerdBm); + } + + void radio_set_pa_level_max_index(uint8_t cIndex) { + SpiritRadioSetPALevelMaxIndex(cIndex); + } + + uint8_t radio_init(SRadioInit *init_struct) { + return SpiritRadioInit(init_struct); + } + + void radio_persistent_rx(SpiritFunctionalState xNewState) { + SpiritRadioPersistenRx(xNewState); + } + + void radio_afc_freeze_on_sync(SpiritFunctionalState xNewState) { + SpiritRadioAFCFreezeOnSync(xNewState); + } + + /** Packet System Instance Methods **/ + void pkt_basic_init(PktBasicInit* pxPktBasicInit) { + SpiritPktBasicInit(pxPktBasicInit); + } + + void pkt_basic_set_payload_length(uint16_t nPayloadLength) { + SpiritPktBasicSetPayloadLength(nPayloadLength); + } + + uint16_t pkt_basic_get_received_pkt_length(void) { + return SpiritPktBasicGetReceivedPktLength(); + } + + /** IRQ Instance Methods **/ + void irq_de_init(SpiritIrqs* pxIrqInit) { + SpiritIrqDeInit(pxIrqInit); + } + + void irq_clear_status(void) { + SpiritIrqClearStatus(); + } + + void irq_set_status(IrqList xIrq, SpiritFunctionalState xNewState) { + SpiritIrq(xIrq, xNewState); + } + + void irq_get_status(SpiritIrqs* pxIrqStatus) { + SpiritIrqGetStatus(pxIrqStatus); + } + + /** Management Instance Methods **/ + void mgmt_set_freq_base(uint32_t freq) { + SpiritManagementSetFrequencyBase(freq); + } + + void mgmt_refresh_status(void) { + SpiritRefreshStatus(); + } + + /** Spirit GPIO Instance Methods **/ + void spirit_gpio_init(SGpioInit* pxGpioInitStruct) { + SpiritGpioInit(pxGpioInitStruct); + } + + /** Qi Instance Methods **/ + void qi_set_sqi_threshold(SqiThreshold xSqiThr) { + SpiritQiSetSqiThreshold(xSqiThr); + } + + void qi_sqi_check(SpiritFunctionalState xNewState) { + SpiritQiSqiCheck(xNewState); + } + + void qi_set_rssi_threshold_dbm(int nDbmValue) { + SpiritQiSetRssiThresholddBm(nDbmValue); + } + + float qi_get_rssi_dbm() { + last_rssi = qi_get_rssi(); + return get_last_rssi_dbm(); + } + + uint8_t qi_get_rssi() { + return SpiritQiGetRssi(); + } + + uint8_t qi_get_sqi() { + return SpiritQiGetSqi(); + } + + /** Timer Instance Methods **/ + void timer_set_rx_timeout_stop_condition(RxTimeoutStopCondition xStopCondition) { + SpiritTimerSetRxTimeoutStopCondition(xStopCondition); + } + + void timer_set_rx_timeout_counter(uint8_t cCounter) { + SpiritTimerSetRxTimeoutCounter(cCounter); + } + + void timer_set_infinite_rx_timeout(void) { + timer_set_rx_timeout_counter(0); + } + + /** CSMA/CA Instance Methods **/ + void csma_ca_state(SpiritFunctionalState xNewState) { + SpiritCsma(xNewState); + } + + void csma_ca_init(CsmaInit* pxCsmaInit) { + csma_ca_state(S_DISABLE); // Disabled at init + SpiritCsmaInit(pxCsmaInit); + SpiritCsmaSeedReloadMode(S_DISABLE); // always disable seed reload + } + + /** Command Instance Methods**/ + void cmd_strobe(uint8_t cmd) { + SpiritCmdStrobeCommand((SpiritCmd)cmd); + } + + void cmd_strobe_flush_rx_fifo() { + SpiritCmdStrobeCommand(CMD_FLUSHRXFIFO); + } + + /** SPI Instance Methods **/ + StatusBytes spi_write_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) { + return SdkEvalSpiWriteFifo(cNbBytes, pcBuffer); + } + + StatusBytes spi_read_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) { + return SdkEvalSpiReadFifo(cNbBytes, pcBuffer); + } + + /** Linear FIFO Instance Methods **/ + uint8_t linear_fifo_read_num_elements_rx_fifo(void) { + return SpiritLinearFifoReadNumElementsRxFifo(); + } + + uint8_t linear_fifo_read_num_elements_tx_fifo(void) { + return SpiritLinearFifoReadNumElementsTxFifo(); + } + + void linear_fifo_set_almost_full_thr_rx(uint8_t cThrRxFifo) { + SpiritLinearFifoSetAlmostFullThresholdRx(cThrRxFifo); + } + + /** Calibration Instance Methods **/ + void calibration_rco(SpiritFunctionalState xNewState) { + SpiritCalibrationRco(xNewState); + } + + /** Internal Spirit Methods */ + void set_ready_state(void); + uint8_t refresh_state(void); + + /** Friend Functions **/ + friend StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); + friend StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); + friend StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode); + friend StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer); + friend StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer); + + /** Sdk Instance Methods **/ + StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); + StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); + StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode); + StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer); + StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer); + + /** Helper Instance Methods **/ + void chip_sync_select() { + disable_spirit_irq(); + chip_select(); + cs_to_sclk_delay(); + } + + void chip_sync_unselect() { + chip_unselect(); + enable_spirit_irq(); + } + + /** Init Instance Method **/ + void init(); + + /** Spirit Irq Callback */ + void IrqHandler(); + + /** Constructor **/ + SimpleSpirit1(PinName mosi, PinName miso, PinName sclk, + PinName irq, PinName cs, PinName sdn, + PinName led); + + /** Destructor **/ + ~SimpleSpirit1(void); // should never be called! + +public: + enum { + RX_DONE, + TX_DONE, + TX_ERR + }; + + /** Create singleton instance of 'SimpleSpirit1' + * + * @param mosi 'PinName' of mosi pin to use + * @param miso 'PinName' of miso pin to use + * @param sclk 'PinName' of clock pin to use + * @param irq 'PinName' of interrupt pin to use + * @param cs 'PinName' of chip-select pin pin to use + * @param sdn 'PinName' of pin to use for device shutdown + * + * @returns reference to singleton instance + */ + static SimpleSpirit1& CreateInstance(PinName mosi, PinName miso, PinName sclk, + PinName irq, PinName cs, PinName sdn, + PinName led = NC) { + + if(_singleton == NULL) { + _singleton = new SimpleSpirit1(mosi, miso, sclk, + irq, cs, sdn, led); + _singleton->init(); + } else { + error("SimpleSpirit1 singleton already created!\n"); + } + + return *_singleton; + } + + /** Create singleton instance of 'SimpleSpirit1' + * + * @param mosi 'PinName' of mosi pin to use + * @param miso 'PinName' of miso pin to use + * @param sclk 'PinName' of clock pin to use + * @param irq 'PinName' of interrupt pin to use + * @param cs 'PinName' of chip-select pin pin to use + * @param sdn 'PinName' of pin to use for device shutdown + * + * @returns reference to singleton instance + */ + static SimpleSpirit1& Instance() { + if(_singleton == NULL) { + error("SimpleSpirit1 must be created before used!\n"); + } + + return *_singleton; + } + + /** Attach a function to be called by the Spirit Irq handler when an event has occurred + * + * @param func A void(int) callback, or 0 to set as none + * + * @note Function 'func' will be executed in interrupt context! + * @note Function 'func' will be call with either 'RX_DONE', 'TX_DONE', or 'TX_ERR' as parameter + * to indicate which event has occurred. + */ + void attach_irq_callback(Callback<void(int)> func) { + _current_irq_callback = func; + } + + /** Switch Radio On + */ + int on(void); + /** Switch Radio Off + */ + int off(void); + + /** Set Channel + */ + void set_channel(uint8_t channel) { + SpiritRadioSetChannel(channel); + } + + /** Send a Buffer + * + * @param payload pointer to buffer to be send + * @param payload_len length of payload buffer in bytes + * @param use_csma_ca should CSMA/CA be enabled for transmission + * + * @returns zero in case of success, non-zero error code otherwise + * + * @note the maximum payload size in bytes allowed is defined by macro 'SPIRIT1_MAX_PAYLOAD' + */ + int send(const void *payload, unsigned int payload_len, bool use_csma_ca = true); + + /** Copy received data into buffer + * + * @param buf pointer to buffer to be filled + * @param bufsize size of buffer + * + * @returns number of bytes copied into the buffer + * + * @note the buffer should be (at least) of size 'SPIRIT1_MAX_PAYLOAD' (in bytes). + */ + int read(void *buf, unsigned int bufsize); + + /** Perform a Clear-Channel Assessment (CCA) to find out if there is a packet in the air or not. + * + * @returns 1 if packet has been seen. + */ + int channel_clear(void); + + /** Check if the radio driver has just received a packet + */ + int get_pending_packet(void); + + /** Is radio currently receiving + */ + bool is_receiving(void) { + return _is_receiving; + } + + /** Get latest value of RSSI (in dBm) + */ + float get_last_rssi_dbm(void) { + get_last_rssi_raw(); + return (-120.0+((float)(last_rssi-20))/2); + } + + /** Get latest value of RSSI (as Spirit1 raw value) + */ + uint8_t get_last_rssi_raw(void) { + if(last_rssi == 0) { + last_rssi = qi_get_rssi(); + } + return last_rssi; + } + + /** Get latest value of LQI (scaled to 8-bit) + */ + uint8_t get_last_sqi(void) { + const uint8_t max_sqi = 8 * ((SYNC_LENGTH>>1)+1); + if(last_sqi == 0) { + last_sqi = qi_get_sqi(); + } + if(last_sqi > max_sqi) last_sqi = max_sqi; + + return (last_sqi * 255 / max_sqi); + } + + /** Reset Board + */ + void reset_board() { + init(); + } +};
diff -r 000000000000 -r 119624335925 easy-connect/stm-spirit1-rf-driver/stm-spirit1-rf-driver/radio_spi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/stm-spirit1-rf-driver/stm-spirit1-rf-driver/radio_spi.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,185 @@ +/** +****************************************************************************** +* @file radio_spi.h +* @author System Lab - NOIDA +* @version V1.0.0 +* @date 15-May-2014 +* @brief This file contains all the functions prototypes for SPI . +****************************************************************************** +* @attention +* +* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> +* +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright 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 STMicroelectronics nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, 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. +* +****************************************************************************** +*/ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RADIO_SPI_H +#define __RADIO_SPI_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#ifdef USE_STM32L1XX_NUCLEO +// #include "stm32l1xx_hal.h" +#endif + +#ifdef USE_STM32F4XX_NUCLEO +// #include "stm32f4xx_hal.h" +#endif +#include "SPIRIT_Config.h" +#include "radio_spi.h" +// #include "spirit1-arch.h" + +/** + * @addtogroup BSP + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + + +/* Exported constants --------------------------------------------------------*/ + + +/* Exported macro ------------------------------------------------------------*/ + /* Define for SPIRIT1 board */ + #if !defined (USE_SPIRIT1_DEFAULT) + #define USE_SPIRIT1_DEFAULT +#endif + +/* SPIRIT1_Spi_config */ +/* SPI1 */ +#define RADIO_SPI SPI1 +#define RADIO_SPI_CLK_ENABLE() __SPI1_CLK_ENABLE() +#define RADIO_SPI_CLK_DISABLE() __SPI1_CLK_DISABLE() + +#define RADIO_SPI_MISO_PORT GPIOA +#define RADIO_SPI_MISO_PIN GPIO_PIN_6 +#define RADIO_SPI_MISO_CLOCK_ENABLE() __GPIOA_CLK_ENABLE() +#define RADIO_SPI_MISO_CLOCK_DISABLE() __GPIOA_CLK_DISABLE() + +#define RADIO_SPI_MOSI_PORT GPIOA +#define RADIO_SPI_MOSI_PIN GPIO_PIN_7 +#define RADIO_SPI_MOSI_CLOCK_ENABLE() __GPIOA_CLK_ENABLE() +#define RADIO_SPI_MOSI_CLOCK_DISABLE() __GPIOA_CLK_DISABLE() + + + +#ifdef USE_SPIRIT1_DEFAULT + +#define RADIO_SPI_SCK_PORT GPIOB +#define RADIO_SPI_SCK_PIN GPIO_PIN_3 +#define RADIO_SPI_SCK_CLOCK_ENABLE() __GPIOB_CLK_ENABLE() +#define RADIO_SPI_SCK_CLOCK_DISABLE() __GPIOB_CLK_DISABLE() + + +#define RADIO_SPI_CS_PORT GPIOB +#define RADIO_SPI_CS_PIN GPIO_PIN_6 +#define RADIO_SPI_CS_CLOCK_ENABLE() __GPIOB_CLK_ENABLE() +#define RADIO_SPI_CS_CLOCK_DISABLE() __GPIOB_CLK_DISABLE() + +#else + +#define RADIO_SPI_SCK_PORT GPIOB +#define RADIO_SPI_SCK_PIN GPIO_PIN_3 +#define RADIO_SPI_SCK_CLOCK_ENABLE() __GPIOB_CLK_ENABLE() +#define RADIO_SPI_SCK_CLOCK_DISABLE() __GPIOB_CLK_DISABLE() + + +#define RADIO_SPI_CS_PORT GPIOB +#define RADIO_SPI_CS_PIN GPIO_PIN_6 +#define RADIO_SPI_CS_CLOCK_ENABLE() __GPIOB_CLK_ENABLE() +#define RADIO_SPI_CS_CLOCK_DISABLE() __GPIOB_CLK_DISABLE() + +#endif + +/* Maximum Timeout values for flags waiting loops. These timeouts are not based + on accurate values, they just guarantee that the application will not remain + stuck if the SPI communication is corrupted. + You may modify these timeout values depending on CPU frequency and application + conditions (interrupts routines ...) */ +#define RADIO_SPI_TIMEOUT_MAX ((uint32_t)1000) + +/* SPIRIT1_Spi_config_Private_Defines */ +#define CS_TO_SCLK_DELAY 0x0200//FIXME what is this doing? +#define CLK_TO_CS_DELAY 0x0001 + +/* SPIRIT1_Spi_config_Headers */ +#define HEADER_WRITE_MASK 0x00 /*!< Write mask for header byte*/ +#define HEADER_READ_MASK 0x01 /*!< Read mask for header byte*/ +#define HEADER_ADDRESS_MASK 0x00 /*!< Address mask for header byte*/ +#define HEADER_COMMAND_MASK 0x80 /*!< Command mask for header byte*/ + +#define LINEAR_FIFO_ADDRESS 0xFF /*!< Linear FIFO address*/ + +/* SPIRIT1_Spi_config_Private_FunctionPrototypes */ +#define SPI_ENTER_CRITICAL() IRQ_DISABLE() +#define SPI_EXIT_CRITICAL() IRQ_ENABLE() + +/* SPIRIT1_Spi_config_Private_Functions */ +#define RadioSpiCSLow() HAL_GPIO_WritePin(RADIO_SPI_CS_PORT, RADIO_SPI_CS_PIN, GPIO_PIN_RESET) +#define RadioSpiCSHigh() HAL_GPIO_WritePin(RADIO_SPI_CS_PORT, RADIO_SPI_CS_PIN, GPIO_PIN_SET) + +/* SPIRIT1_Spi_config_Private_Macros */ +#define BUILT_HEADER(add_comm, w_r) (add_comm | w_r) /*!< macro to build the header byte*/ +#define WRITE_HEADER BUILT_HEADER(HEADER_ADDRESS_MASK, HEADER_WRITE_MASK) /*!< macro to build the write + header byte*/ +#define READ_HEADER BUILT_HEADER(HEADER_ADDRESS_MASK, HEADER_READ_MASK) /*!< macro to build the read + header byte*/ +#define COMMAND_HEADER BUILT_HEADER(HEADER_COMMAND_MASK, HEADER_WRITE_MASK) /*!< macro to build the command + header byte*/ + + + +/* Exported Variables --------------------------------------------------------*/ + + +/* Exported functions ------------------------------------------------------- */ +void SdkEvalSpiInit(void); +// void SpiCSGpioSetLevel(GPIO_PinState xState); +StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); +StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer); +StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode); +StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer); +StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer); + + +#ifdef __cplusplus +} +#endif +#endif /*__RADIO_SPI_H */ + +/** +* @} +*/ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/wifi-ism43362/#e847364be04499dc91d9e99f0df2ba6ecf95cd20
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +e847364be04499dc91d9e99f0df2ba6ecf95cd20
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +117eb2dbd1d863f3f856c002db4ffac5032efab2
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/wifi-ism43362/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/index Binary file easy-connect/wifi-ism43362/.git/index has changed
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 117eb2dbd1d863f3f856c002db4ffac5032efab2 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322720 +0000 clone: from https://github.com/ARMmbed/wifi-ism43362/ +117eb2dbd1d863f3f856c002db4ffac5032efab2 e847364be04499dc91d9e99f0df2ba6ecf95cd20 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322720 +0000 checkout: moving from master to e847364be04499dc91d9e99f0df2ba6ecf95cd20
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 117eb2dbd1d863f3f856c002db4ffac5032efab2 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322720 +0000 clone: from https://github.com/ARMmbed/wifi-ism43362/
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 117eb2dbd1d863f3f856c002db4ffac5032efab2 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322720 +0000 clone: from https://github.com/ARMmbed/wifi-ism43362/
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/objects/pack/pack-8558fca7b3b9b24b90a817af8b435460cb2c589e.idx Binary file easy-connect/wifi-ism43362/.git/objects/pack/pack-8558fca7b3b9b24b90a817af8b435460cb2c589e.idx has changed
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/objects/pack/pack-8558fca7b3b9b24b90a817af8b435460cb2c589e.pack Binary file easy-connect/wifi-ism43362/.git/objects/pack/pack-8558fca7b3b9b24b90a817af8b435460cb2c589e.pack has changed
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ +# pack-refs with: peeled +117eb2dbd1d863f3f856c002db4ffac5032efab2 refs/remotes/origin/master +43817d8fe90469c57d5b21f7a8a1acb66d890392 refs/tags/v1.0
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +117eb2dbd1d863f3f856c002db4ffac5032efab2
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362/ATParser/ATParser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ATParser/ATParser.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,427 @@ +/* Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @section DESCRIPTION + * + * Parser for the AT command syntax + * + */ + +#include "ATParser.h" +#include "mbed_debug.h" + +#ifdef LF +#undef LF +#define LF 10 +#else +#define LF 10 +#endif + +#ifdef CR +#undef CR +#define CR 13 +#else +#define CR 13 +#endif +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#define dbg_on 0 +//#define TRACE_AT_DATA 1 + +// getc/putc handling with timeouts +int ATParser::putc(char c) +{ + return _serial_spi->putc(c); +} + +int ATParser::getc() +{ + return _serial_spi->getc(); +} + +void ATParser::flush() +{ + _bufferMutex.lock(); + while (_serial_spi->readable()) { + _serial_spi->getc(); + } + _bufferMutex.unlock(); +} + +// read/write handling with timeouts +int ATParser::write(const char *data, int size_of_data, int size_in_buff) +{ + int i = 0; + _bufferMutex.lock(); + for ( ; i < size_of_data; i++) { + if (putc(data[i]) < 0) { + _bufferMutex.unlock(); + return -1; + } + } + + _serial_spi->buffsend(size_of_data + size_in_buff); + _bufferMutex.unlock(); + return (size_of_data + size_in_buff); +} + +int ATParser::read(char *data) +{ + int readsize; + int i = 0; + + _bufferMutex.lock(); + + //this->flush(); + if(!_serial_spi->readable()) { + readsize = _serial_spi->read(); + } else { + error("Pending data when reading from WIFI\r\n"); + return -1; + } + + debug_if(dbg_on, "Avail in SPI %d\r\n", readsize); + + if ( readsize < 0) { + _bufferMutex.unlock(); + return -1; + } + + for (i = 0 ; i < readsize; i++) { + int c = getc(); + if (c < 0) { + _bufferMutex.unlock(); + return -1; + } + data[i] = c; + } + +#if TRACE_AT_DATA + debug_if(dbg_on, "AT<< %d BYTES\r\n", readsize); + for (i = 0; i < readsize; i++) { + debug_if(dbg_on, "%2X ", data[i]); + } + debug_if(dbg_on, "\r\n"); +#endif + + _bufferMutex.unlock(); + + return (readsize); +} + +// printf/scanf handling +int ATParser::vprintf(const char *format, va_list args) +{ + _bufferMutex.lock(); + if (vsprintf(_buffer, format, args) < 0) { + _bufferMutex.unlock(); + return false; + } + + int i = 0; + for ( ; _buffer[i]; i++) { + if (putc(_buffer[i]) < 0) { + _bufferMutex.unlock(); + return -1; + } + } + _bufferMutex.unlock(); + + return i; +} + +int ATParser::vscanf(const char *format, va_list args) +{ + // Since format is const, we need to copy it into our buffer to + // add the line's null terminator and clobber value-matches with asterisks. + // + // We just use the beginning of the buffer to avoid unnecessary allocations. + int i = 0; + int offset = 0; + + _bufferMutex.lock(); + + while (format[i]) { + if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') { + _buffer[offset++] = '%'; + _buffer[offset++] = '*'; + i++; + } else { + _buffer[offset++] = format[i++]; + } + } + + // Scanf has very poor support for catching errors + // fortunately, we can abuse the %n specifier to determine + // if the entire string was matched. + _buffer[offset++] = '%'; + _buffer[offset++] = 'n'; + _buffer[offset++] = 0; + + // To workaround scanf's lack of error reporting, we actually + // make two passes. One checks the validity with the modified + // format string that only stores the matched characters (%n). + // The other reads in the actual matched values. + // + // We keep trying the match until we succeed or some other error + // derails us. + int j = 0; + + while (true) { + // Ran out of space + if (j+1 >= _buffer_size - offset) { + _bufferMutex.unlock(); + return false; + } + // Recieve next character + int c = getc(); + if (c < 0) { + _bufferMutex.unlock(); + return -1; + } + _buffer[offset + j++] = c; + _buffer[offset + j] = 0; + + // Check for match + int count = -1; + sscanf(_buffer+offset, _buffer, &count); + + // We only succeed if all characters in the response are matched + if (count == j) { + // Store the found results + vsscanf(_buffer+offset, format, args); + _bufferMutex.unlock(); + return j; + } + } +} + + +// Command parsing with line handling +bool ATParser::vsend(const char *command, va_list args) +{ + int i=0, j=0; + _bufferMutex.lock(); + // Create and send command + if (vsprintf(_buffer, command, args) < 0) { + _bufferMutex.unlock(); + return false; + } + /* get buffer length */ + for (i = 0; _buffer[i]; i++) { + } + + for (j=0; _delimiter[j]; j++) { + _buffer[i+j] = _delimiter[j]; + } + _buffer[i+j]=0; // only to get a clean debug log + + bool ret = !(_serial_spi->buffwrite(_buffer, i+j) < 0); + + debug_if(dbg_on, "AT> %s\n", _buffer); + _bufferMutex.unlock(); + return ret; +} + +bool ATParser::vrecv(const char *response, va_list args) +{ + _bufferMutex.lock(); + /* Read from the wifi module, fill _rxbuffer */ + //this->flush(); + if(!_serial_spi->readable()) { + debug_if(dbg_on, "NO DATA, read again\r\n"); + if (_serial_spi->read() < 0) { + return false; + } + } else { + debug_if(dbg_on, "Pending data\r\n"); + } +restart: + _aborted = false; + // Iterate through each line in the expected response + while (response[0]) { + // Since response is const, we need to copy it into our buffer to + // add the line's null terminator and clobber value-matches with asterisks. + // + // We just use the beginning of the buffer to avoid unnecessary allocations. + int i = 0; + int offset = 0; + bool whole_line_wanted = false; + + while (response[i]) { + if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') { + _buffer[offset++] = '%'; + _buffer[offset++] = '*'; + i++; + } else { + _buffer[offset++] = response[i++]; + // Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification + if (response[i - 1] == '\n' && !(i >= 3 && response[i-3] == '[' && response[i-2] == '^')) { + whole_line_wanted = true; + break; + } + } + } + + // Scanf has very poor support for catching errors + // fortunately, we can abuse the %n specifier to determine + // if the entire string was matched. + _buffer[offset++] = '%'; + _buffer[offset++] = 'n'; + _buffer[offset++] = 0; + + debug_if(dbg_on, "AT? ====%s====\n", _buffer); + // To workaround scanf's lack of error reporting, we actually + // make two passes. One checks the validity with the modified + // format string that only stores the matched characters (%n). + // The other reads in the actual matched values. + // + // We keep trying the match until we succeed or some other error + // derails us. + int j = 0; + + while (true) { + // Recieve next character + int c = getc(); + if (c < 0) { + debug_if(dbg_on, "AT(Timeout)\n"); + _bufferMutex.unlock(); + return false; + } + +#if TRACE_AT_DATA + debug_if(dbg_on, "%2X ", c); +#endif + _buffer[offset + j++] = c; + _buffer[offset + j] = 0; + + // Check for oob data + for (struct oob *oob = _oobs; oob; oob = oob->next) { + if ((unsigned)j == oob->len && memcmp( + oob->prefix, _buffer+offset, oob->len) == 0) { + debug_if(dbg_on, "AT! %s\n", oob->prefix); + oob->cb(); + + if (_aborted) { + debug_if(dbg_on, "AT(Aborted)\n"); + _bufferMutex.unlock(); + return false; + } + // oob may have corrupted non-reentrant buffer, + // so we need to set it up again + goto restart; + } + } + + // Check for match + int count = -1; + if (whole_line_wanted && c != '\n') { + // Don't attempt scanning until we get delimiter if they included it in format + // This allows recv("Foo: %s\n") to work, and not match with just the first character of a string + // (scanf does not itself match whitespace in its format string, so \n is not significant to it) + } else { + sscanf(_buffer+offset, _buffer, &count); + } + + // We only succeed if all characters in the response are matched + if (count == j) { + debug_if(dbg_on, "AT= ====%s====\n", _buffer + offset); + // Reuse the front end of the buffer + memcpy(_buffer, response, i); + _buffer[i] = 0; + + // Store the found results + vsscanf(_buffer+offset, _buffer, args); + + // Jump to next line and continue parsing + response += i; + break; + } + + // Clear the buffer when we hit a newline or ran out of space + // running out of space usually means we ran into binary data + if ((c == '\n') ) { + debug_if(dbg_on, "New line AT<<< %s", _buffer+offset); + j = 0; + } + if ((j + 1 >= (_buffer_size - offset))) { + + debug_if(dbg_on, "Out of space AT<<< %s, j=%d", _buffer+offset, j); + j = 0; + } + } + } + + _bufferMutex.unlock(); + + return true; +} + + +// Mapping to vararg functions +int ATParser::printf(const char *format, ...) +{ + va_list args; + va_start(args, format); + int res = vprintf(format, args); + va_end(args); + return res; +} + +int ATParser::scanf(const char *format, ...) +{ + va_list args; + va_start(args, format); + int res = vscanf(format, args); + va_end(args); + return res; +} + +bool ATParser::send(const char *command, ...) +{ + va_list args; + va_start(args, command); + bool res = vsend(command, args); + va_end(args); + return res; +} + +bool ATParser::recv(const char *response, ...) +{ + va_list args; + va_start(args, response); + bool res = vrecv(response, args); + va_end(args); + return res; +} + + +// oob registration +void ATParser::oob(const char *prefix, Callback<void()> cb) +{ + struct oob *oob = new struct oob; + oob->len = strlen(prefix); + oob->prefix = prefix; + oob->cb = cb; + oob->next = _oobs; + _oobs = oob; +} + +void ATParser::abort() +{ + _aborted = true; +} + + +
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362/ATParser/ATParser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ATParser/ATParser.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,264 @@ +/* Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @section DESCRIPTION + * + * Parser for the AT command syntax + * + */ +#ifndef AT_PARSER_H +#define AT_PARSER_H + +#include "mbed.h" +#include <cstdarg> +#include <vector> +#include "BufferedSpi.h" +#include "Callback.h" + + +/** +* Parser class for parsing AT commands +* +* Here are some examples: +* @code +* ATParser at = ATParser(serial, "\r\n"); +* int value; +* char buffer[100]; +* +* at.send("AT") && at.recv("OK"); +* at.send("AT+CWMODE=%d", 3) && at.recv("OK"); +* at.send("AT+CWMODE?") && at.recv("+CWMODE:%d\r\nOK", &value); +* at.recv("+IPD,%d:", &value); +* at.read(buffer, value); +* at.recv("OK"); +* @endcode +*/ +class ATParser +{ +private: + // Serial information + BufferedSpi *_serial_spi; + int _buffer_size; + char *_buffer; + Mutex _bufferMutex; + volatile int _timeout; + + // Parsing information + const char *_delimiter; + int _delim_size; + char _in_prev; + bool dbg_on; + volatile bool _aborted; + + struct oob { + unsigned len; + const char *prefix; + mbed::Callback<void()> cb; + oob *next; + }; + oob *_oobs; + +public: + /** + * Constructor + * + * @param serial spi interface to use for AT commands + * @param buffer_size size of internal buffer for transaction + * @param timeout timeout of the connection + * @param delimiter string of characters to use as line delimiters + */ + ATParser(BufferedSpi &serial_spi, const char *delimiter = "\r\n", int buffer_size = 1440, int timeout = 8000, bool debug = false) : + _serial_spi(&serial_spi), + _buffer_size(buffer_size), _in_prev(0), _oobs(NULL) + { + _buffer = new char[buffer_size]; + setTimeout(timeout); + setDelimiter(delimiter); + debugOn(debug); + } + + /** + * Destructor + */ + ~ATParser() + { + while (_oobs) { + struct oob *oob = _oobs; + _oobs = oob->next; + delete oob; + } + delete[] _buffer; + } + + /** + * Allows timeout to be changed between commands + * + * @param timeout timeout of the connection + */ + void setTimeout(int timeout) + { + _timeout = timeout; + _serial_spi->setTimeout(timeout); + } + + /** + * Sets string of characters to use as line delimiters + * + * @param delimiter string of characters to use as line delimiters + */ + void setDelimiter(const char *delimiter) { + _delimiter = delimiter; + _delim_size = strlen(delimiter); + } + + /** + * Allows echo to be on or off + * + * @param echo 1 for echo and 0 turns it off + */ + void debugOn(uint8_t on) { + dbg_on = (on) ? 1 : 0; + } + + /** + * Sends an AT command + * + * Sends a formatted command using printf style formatting + * @see printf + * + * @param command printf-like format string of command to send which + * is appended with a newline + * @param ... all printf-like arguments to insert into command + * @return true only if command is successfully sent + */ + bool send(const char *command, ...); + + bool vsend(const char *command, va_list args); + + /** + * Receive an AT response + * + * Receives a formatted response using scanf style formatting + * @see scanf + * + * Responses are parsed line at a time. + * Any received data that does not match the response is ignored until + * a timeout occurs. + * + * @param response scanf-like format string of response to expect + * @param ... all scanf-like arguments to extract from response + * @return true only if response is successfully matched + */ + bool recv(const char *response, ...); + bool vrecv(const char *response, va_list args); + + + /** + * Write a single byte to the underlying stream + * + * @param c The byte to write + * @return The byte that was written or -1 during a timeout + */ + int putc(char c); + + /** + * Get a single byte from the underlying stream + * + * @return The byte that was read or -1 during a timeout + */ + int getc(); + + /** + * Write an array of bytes to the underlying stream + * assuming the header of the command is already in _txbuffer + * + * @param data the array of bytes to write + * @param size_of_data number of bytes in data array + * @param size_in_buff number of bytes already in the internal buff + * @return number of bytes written or -1 on failure + */ + int write(const char *data, int size_of_data, int size_in_buff); + + /** + * Read an array of bytes from the underlying stream + * + * @param data the destination for the read bytes + * @param size number of bytes to read + * @return number of bytes read or -1 on failure + */ + int read(char *data); + + /** + * Direct printf to underlying stream + * @see printf + * + * @param format format string to pass to printf + * @param ... arguments to printf + * @return number of bytes written or -1 on failure + */ + int printf(const char *format, ...); + int vprintf(const char *format, va_list args); + + /** + * Direct scanf on underlying stream + * @see ::scanf + * + * @param format format string to pass to scanf + * @param ... arguments to scanf + * @return number of bytes read or -1 on failure + */ + int scanf(const char *format, ...); + + int vscanf(const char *format, va_list args); + + /** + * Attach a callback for out-of-band data + * + * @param prefix string on when to initiate callback + * @param func callback to call when string is read + * @note out-of-band data is only processed during a scanf call + */ + void oob(const char *prefix, mbed::Callback<void()> func); + + /** + * Flushes the underlying stream + */ + void flush(); + + /** + * Abort current recv + * + * Can be called from oob handler to interrupt the current + * recv operation. + */ + void abort(); + + /** + * Process out-of-band data + * + * Process out-of-band data in the receive buffer. This function + * returns immediately if there is no data to process. + * + * @return true if oob data processed, false otherwise + */ + bool process_oob(void); + /** + * Get buffer_size + */ + int get_size(void) { + return _buffer_size; + } + +}; +#endif
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,83 @@ + +/** + * @file Buffer.cpp + * @brief Software Buffer - Templated Ring Buffer for most data types + * @author sam grove + * @version 1.0 + * @see + * + * Copyright (c) 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MyBuffer.h" + +template <class T> +MyBuffer<T>::MyBuffer(uint32_t size) +{ + _buf = new T [size]; + _size = size; + clear(); + + return; +} + +template <class T> +MyBuffer<T>::~MyBuffer() +{ + delete [] _buf; + + return; +} + +template <class T> +uint32_t MyBuffer<T>::getSize() +{ + return this->_size; +} + +template <class T> + uint32_t MyBuffer<T>::getNbAvailable() +{ + if ( _wloc >= _rloc) return (_wloc - _rloc); + else return (_size - _rloc + _wloc); +} + +template <class T> +void MyBuffer<T>::clear(void) +{ + _wloc = 0; + _rloc = 0; + memset(_buf, 0, _size); + + return; +} + +template <class T> +uint32_t MyBuffer<T>::peek(char c) +{ + return 1; +} + +// make the linker aware of some possible types +template class MyBuffer<uint8_t>; +template class MyBuffer<int8_t>; +template class MyBuffer<uint16_t>; +template class MyBuffer<int16_t>; +template class MyBuffer<uint32_t>; +template class MyBuffer<int32_t>; +template class MyBuffer<uint64_t>; +template class MyBuffer<int64_t>; +template class MyBuffer<char>; +template class MyBuffer<wchar_t>;
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ + +/** + * @file Buffer.h + * @brief Software Buffer - Templated Ring Buffer for most data types + * @author sam grove + * @version 1.0 + * @see + * + * Copyright (c) 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MYBUFFER_H +#define MYBUFFER_H + +#include <stdint.h> +#include <string.h> + +/** A templated software ring buffer + * + * Example: + * @code + * #include "mbed.h" + * #include "MyBuffer.h" + * + * MyBuffer <char> buf; + * + * int main() + * { + * buf = 'a'; + * buf.put('b'); + * char *head = buf.head(); + * puts(head); + * + * char whats_in_there[2] = {0}; + * int pos = 0; + * + * while(buf.available()) + * { + * whats_in_there[pos++] = buf; + * } + * printf("%c %c\n", whats_in_there[0], whats_in_there[1]); + * buf.clear(); + * error("done\n\n\n"); + * } + * @endcode + */ + +template <typename T> +class MyBuffer +{ +private: + T *_buf; + volatile uint32_t _wloc; + volatile uint32_t _rloc; + uint32_t _size; + +public: + /** Create a Buffer and allocate memory for it + * @param size The size of the buffer + */ + MyBuffer(uint32_t size = 0x100); + + /** Get the size of the ring buffer + * @return the size of the ring buffer + */ + uint32_t getSize(); + uint32_t getNbAvailable(); + + /** Destry a Buffer and release it's allocated memory + */ + ~MyBuffer(); + + /** Add a data element into the buffer + * @param data Something to add to the buffer + */ + void put(T data); + + /** Remove a data element from the buffer + * @return Pull the oldest element from the buffer + */ + T get(void); + + /** Get the address to the head of the buffer + * @return The address of element 0 in the buffer + */ + T *head(void); + + /** Reset the buffer to 0. Useful if using head() to parse packeted data + */ + void clear(void); + + /** Determine if anything is readable in the buffer + * @return 1 if something can be read, 0 otherwise + */ + uint32_t available(void); + + /** Overloaded operator for writing to the buffer + * @param data Something to put in the buffer + * @return + */ + MyBuffer &operator= (T data) + { + put(data); + return *this; + } + + /** Overloaded operator for reading from the buffer + * @return Pull the oldest element from the buffer + */ + operator int(void) + { + return get(); + } + + uint32_t peek(char c); + +}; + +template <class T> +inline void MyBuffer<T>::put(T data) +{ + _buf[_wloc++] = data; + _wloc %= (_size-1); + + return; +} + +template <class T> +inline T MyBuffer<T>::get(void) +{ + T data_pos = _buf[_rloc++]; + _rloc %= (_size-1); + + return data_pos; +} + +template <class T> +inline T *MyBuffer<T>::head(void) +{ + T *data_pos = &_buf[0]; + + return data_pos; +} + +template <class T> +inline uint32_t MyBuffer<T>::available(void) +{ + return (_wloc == _rloc) ? 0 : 1; + //return 1; +} + +#endif +
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/BufferedPrint.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/BufferedPrint.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "mbed_error.h" + +size_t BufferedSpiThunk(void *buf_serial, const void *s, size_t length); + +int BufferedPrintfC(void *stream, int size, const char* format, va_list arg) +{ + int r; + char buffer[512]; + if (size >= 512) { + return -1; + } + memset(buffer, 0, size); + r = vsprintf(buffer, format, arg); + // this may not hit the heap but should alert the user anyways + if(r > (int32_t) size) { + error("%s %d buffer overwrite (max_buf_size: %d exceeded: %d)!\r\n", __FILE__, __LINE__, size, r); + return 0; + } + if ( r > 0 ) { + BufferedSpiThunk(stream, buffer, r); + } + return r; +}
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,326 @@ +/** + * @file BufferedSpi.cpp + * @brief Software Buffer - Extends mbed SPI functionallity + * @author Armelle Duboc + * @version 1.0 + * @see + * + * Copyright (c) STMicroelectronics 2017 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BufferedSpi.h" +#include <stdarg.h> +#include "mbed_debug.h" +#include "mbed_error.h" + +// change to true to add few SPI debug lines +#define local_debug false + +extern "C" int BufferedPrintfC(void *stream, int size, const char* format, va_list arg); + +void BufferedSpi::DatareadyRising(void) +{ + if (_cmddata_rdy_rising_event == 1) { + _cmddata_rdy_rising_event=0; + } +} + +int BufferedSpi::wait_cmddata_rdy_high(void) +{ + Timer timer; + timer.start(); + + /* wait for dataready = 1 */ + while(dataready.read() == 0) { + if (timer.read_ms() > _timeout) { + debug_if(local_debug,"ERROR: SPI write timeout\r\n"); + return -1; + } + } + + _cmddata_rdy_rising_event = 1; + + return 0; +} + +int BufferedSpi::wait_cmddata_rdy_rising_event(void) +{ + Timer timer; + timer.start(); + + while (_cmddata_rdy_rising_event == 1) { + if (timer.read_ms() > _timeout) { + _cmddata_rdy_rising_event = 0; + if (dataready.read() == 1) { + debug_if(local_debug,"ERROR: We missed rising event !! (timemout=%d)\r\n", _timeout); + } + debug_if(local_debug,"ERROR: SPI read timeout\r\n"); + return -1; + } + } + + return 0; +} + +BufferedSpi::BufferedSpi(PinName mosi, PinName miso, PinName sclk, PinName _nss, PinName _datareadypin, + uint32_t buf_size, uint32_t tx_multiple, const char* name) + : SPI(mosi, miso, sclk, NC), nss(_nss), _txbuf((uint32_t)(tx_multiple*buf_size)), _rxbuf(buf_size), dataready(_datareadypin) +{ + this->_buf_size = buf_size; + this->_tx_multiple = tx_multiple; + this->_sigio_event = 0; + + _datareadyInt = new InterruptIn(_datareadypin); + _datareadyInt->rise(callback(this, &BufferedSpi::DatareadyRising)); + + _cmddata_rdy_rising_event = 1; + + return; +} + +BufferedSpi::~BufferedSpi(void) +{ + + return; +} + +void BufferedSpi::frequency(int hz) +{ + SPI::frequency(hz); +} + +void BufferedSpi::format(int bits, int mode) +{ + SPI::format(bits, mode); +} + +void BufferedSpi::disable_nss() +{ + nss = 1; + wait_us(15); +} + +void BufferedSpi::enable_nss() +{ + nss = 0; + wait_us(15); +} + +int BufferedSpi::readable(void) +{ + return _rxbuf.available(); // note: look if things are in the buffer +} + +int BufferedSpi::writeable(void) +{ + return 1; // buffer allows overwriting by design, always true +} + +int BufferedSpi::getc(void) +{ + if (_rxbuf.available()) + return _rxbuf; + else return -1; +} + +int BufferedSpi::putc(int c) +{ + _txbuf = (char)c; + + return c; +} + +void BufferedSpi::flush_txbuf(void) +{ + _txbuf.clear(); +} + +int BufferedSpi::puts(const char *s) +{ + if (s != NULL) { + const char* ptr = s; + + while(*(ptr) != 0) { + _txbuf = *(ptr++); + } + _txbuf = '\n'; // done per puts definition + BufferedSpi::txIrq(); // only write to hardware in one place + return (ptr - s) + 1; + } + return 0; +} + +extern "C" size_t BufferedSpiThunk(void *buf_spi, const void *s, size_t length) +{ + BufferedSpi *buffered_spi = (BufferedSpi *)buf_spi; + return buffered_spi->buffwrite(s, length); +} + +int BufferedSpi::printf(const char* format, ...) +{ + va_list arg; + va_start(arg, format); + int r = BufferedPrintfC((void*)this, this->_buf_size, format, arg); + va_end(arg); + return r; +} + +ssize_t BufferedSpi::buffwrite(const void *s, size_t length) +{ + /* flush buffer from previous message */ + this->flush_txbuf(); + + if (wait_cmddata_rdy_high() < 0) { + debug_if(local_debug, "BufferedSpi::buffwrite timeout (%d)\r\n", _timeout); + return -1; + } + + this->enable_nss(); + + if (s != NULL && length > 0) { + /* 1st fill _txbuf */ + const char* ptr = (const char*)s; + const char* end = ptr + length; + + while (ptr != end) { + _txbuf = *(ptr++); + } + if (length&1) { /* padding to send the last char */ + _txbuf = '\n'; + length++; + } + + /* 2nd write in SPI */ + BufferedSpi::txIrq(); // only write to hardware in one place + + this->disable_nss(); + return ptr - (const char*)s; + } + this->disable_nss(); + + return 0; +} + +ssize_t BufferedSpi::buffsend(size_t length) +{ + /* wait for dataready = 1 */ + if (wait_cmddata_rdy_high() < 0) { + debug_if(local_debug, "BufferedSpi::buffsend timeout (%d)\r\n", _timeout); + return -1; + } + + this->enable_nss(); + + /* _txbuffer is already filled with data to send */ + /* check if _txbuffer needs padding to send the last char */ + if (length & 1) { + _txbuf = '\n'; + length++; + } + BufferedSpi::txIrq(); // only write to hardware in one place + + this->disable_nss(); + + return length; +} + +ssize_t BufferedSpi::read() +{ + return this->read(0); +} + +ssize_t BufferedSpi::read(uint32_t max) +{ + uint32_t len = 0; + int tmp; + + disable_nss(); + + /* wait for data ready is up */ + if(wait_cmddata_rdy_rising_event() != 0) { + debug_if(local_debug, "BufferedSpi::read timeout (%d)\r\n", _timeout); + return -1; + } + + enable_nss(); + while (dataready.read() == 1 && (len < (_buf_size - 1))) { + tmp = SPI::write(0xAA); // dummy write to receive 2 bytes + + if (!((len == 0) && (tmp == 0x0A0D))) { + /* do not take into account the 2 firts \r \n char in the buffer */ + if ((max == 0) || (len < max)) { + _rxbuf = (char)(tmp & 0x00FF); + _rxbuf = (char)((tmp >>8)& 0xFF); + len += 2; + } + } + } + disable_nss(); + + if (len >= _buf_size) { + debug_if(local_debug, "firmware ERROR ES_WIFI_ERROR_STUFFING_FOREVER\r\n"); + return -1; + } + + debug_if(local_debug, "SPI READ %d BYTES\r\n", len); + + return len; +} + +void BufferedSpi::txIrq(void) +{ /* write everything available in the _txbuffer */ + int value = 0; + int dbg_cnt = 0; + while (_txbuf.available() && (_txbuf.getNbAvailable()>0)) { + value = _txbuf.get(); + if (_txbuf.available() && ((_txbuf.getNbAvailable()%2)!=0)) { + value |= ((_txbuf.get()<<8)&0XFF00); + SPI::write(value); + dbg_cnt++; + } + } + debug_if(local_debug, "SPI Sent %d BYTES\r\n", 2*dbg_cnt); + // disable the TX interrupt when there is nothing left to send + BufferedSpi::attach(NULL, BufferedSpi::TxIrq); + // trigger callback if necessary + if (_cbs[TxIrq]) { + _cbs[TxIrq](); + } + return; +} + +void BufferedSpi::prime(void) +{ + BufferedSpi::txIrq(); // only write to hardware in one place + return; +} + +void BufferedSpi::attach(Callback<void()> func, IrqType type) +{ + _cbs[type] = func; +} + +void BufferedSpi::sigio(Callback<void()> func) { + core_util_critical_section_enter(); + _sigio_cb = func; + if (_sigio_cb) { + if (_sigio_event == 1) { + _sigio_cb(); + _sigio_event = 0; + } + } + core_util_critical_section_exit(); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,235 @@ + +/** + * @file BufferedSpi.h + * @brief Software Buffer - Extends mbed SPI functionallity + * @author Armelle Duboc + * @version 1.0 + * @see + * + * Copyright (c) STMicroelectronics 2017 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BUFFEREDSPI_H +#define BUFFEREDSPI_H + +#include "mbed.h" +#include "MyBuffer.h" + +/** A spi port (SPI) for communication with wifi device + * + * Can be used for Full Duplex communication, or Simplex by specifying + * one pin as NC (Not Connected) + * + * Example: + * @code + * #include "mbed.h" + * #include "BufferedSerial.h" + * + * BufferedSerial pc(USBTX, USBRX); + * + * int main() + * { + * while(1) + * { + * Timer s; + * + * s.start(); + * pc.printf("Hello World - buffered\n"); + * int buffered_time = s.read_us(); + * wait(0.1f); // give time for the buffer to empty + * + * s.reset(); + * printf("Hello World - blocking\n"); + * int polled_time = s.read_us(); + * s.stop(); + * wait(0.1f); // give time for the buffer to empty + * + * pc.printf("printf buffered took %d us\n", buffered_time); + * pc.printf("printf blocking took %d us\n", polled_time); + * wait(0.5f); + * } + * } + * @endcode + */ + +/** + * @class BufferedSpi + * @brief Software buffers and interrupt driven tx and rx for Serial + */ +class BufferedSpi : public SPI +{ +private: + DigitalOut nss; + MyBuffer <char> _txbuf; + uint32_t _buf_size; + uint32_t _tx_multiple; + volatile int _timeout; + void txIrq(void); + void prime(void); + + InterruptIn* _datareadyInt; + volatile int _cmddata_rdy_rising_event; + void DatareadyRising(void); + int wait_cmddata_rdy_rising_event(void); + int wait_cmddata_rdy_high(void); + + + Callback<void()> _cbs[2]; + + Callback<void()> _sigio_cb; + uint8_t _sigio_event; + +public: + MyBuffer <char> _rxbuf; + DigitalIn dataready; + enum IrqType { + RxIrq = 0, + TxIrq, + + IrqCnt + }; + + /** Create a BufferedSpi Port, connected to the specified transmit and receive pins + * @param SPI mosi pin + * @param SPI miso pin + * @param SPI sclk pin + * @param SPI nss pin + * @param Dataready pin + * @param buf_size printf() buffer size + * @param tx_multiple amount of max printf() present in the internal ring buffer at one time + * @param name optional name + */ + BufferedSpi(PinName mosi, PinName miso, PinName sclk, PinName nss, PinName datareadypin, uint32_t buf_size = 1480, uint32_t tx_multiple = 4,const char* name=NULL); + + /** Destroy a BufferedSpi Port + */ + virtual ~BufferedSpi(void); + + /** call to SPI frequency Function + */ + virtual void frequency(int hz); + + /** clear the transmit buffer + */ + virtual void flush_txbuf(void); + + /** call to SPI format function + */ + virtual void format(int bits, int mode); + + virtual void enable_nss(void); + + virtual void disable_nss(void); + + /** Check on how many bytes are in the rx buffer + * @return 1 if something exists, 0 otherwise + */ + virtual int readable(void); + + /** Check to see if the tx buffer has room + * @return 1 always has room and can overwrite previous content if too small / slow + */ + virtual int writeable(void); + + /** Get a single byte from the BufferedSpi Port. + * Should check readable() before calling this. + * @return A byte that came in on the SPI Port + */ + virtual int getc(void); + + /** Write a single byte to the BufferedSpi Port. + * @param c The byte to write to the SPI Port + * @return The byte that was written to the SPI Port Buffer + */ + virtual int putc(int c); + + /** Write a string to the BufferedSpi Port. Must be NULL terminated + * @param s The string to write to the Spi Port + * @return The number of bytes written to the Spi Port Buffer + */ + virtual int puts(const char *s); + + /** Write a formatted string to the BufferedSpi Port. + * @param format The string + format specifiers to write to the Spi Port + * @return The number of bytes written to the Spi Port Buffer + */ + virtual int printf(const char* format, ...); + + /** Write data to the Buffered Spi Port + * @param s A pointer to data to send + * @param length The amount of data being pointed to + * @return The number of bytes written to the Spi Port Buffer + */ + virtual ssize_t buffwrite(const void *s, std::size_t length); + + /** Send datas to the Spi port that are already present + * in the internal _txbuffer + * @param length + * @return the number of bytes written on the SPI port + */ + virtual ssize_t buffsend(size_t length); + + /** Read data from the Spi Port to the _rxbuf + * @param max: optional. = max sieze of the input read + * @return The number of bytes read from the SPI port and written to the _rxbuf + */ + virtual ssize_t read(); + virtual ssize_t read(uint32_t max); + + /** + * Allows timeout to be changed between commands + * + * @param timeout timeout of the connection + */ + void setTimeout(int timeout) + { + /* this is a safe guard timeout in case module is stuck + * so take 5 sec margin compared to module timeout, to + * really only detect case where module is stuck */ + _timeout = timeout + 5000; + } + + /** Register a callback once any data is ready for sockets + * @param func Function to call on state change + */ + virtual void sigio(Callback<void()> func); + + /** Attach a function to call whenever a serial interrupt is generated + * @param func A pointer to a void function, or 0 to set as none + * @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty) + */ + virtual void attach(Callback<void()> func, IrqType type=RxIrq); + + /** Attach a member function to call whenever a serial interrupt is generated + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to call + * @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty) + */ + template <typename T> + void attach(T *obj, void (T::*method)(), IrqType type=RxIrq) { + attach(Callback<void()>(obj, method), type); + } + + /** Attach a member function to call whenever a serial interrupt is generated + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to call + * @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty) + */ + template <typename T> + void attach(T *obj, void (*method)(T*), IrqType type=RxIrq) { + attach(Callback<void()>(obj, method), type); + } +}; +#endif
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362/ISM43362.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ISM43362.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,677 @@ +/* ISM43362 Example +* +* Copyright (c) STMicroelectronics 2018 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <string.h> +#include "ISM43362.h" +#include "mbed_debug.h" + +// activate / de-activate debug +#define ism_debug false + +ISM43362::ISM43362(PinName mosi, PinName miso, PinName sclk, PinName nss, PinName resetpin, PinName datareadypin, PinName wakeup, bool debug) + : _bufferspi(mosi, miso, sclk, nss, datareadypin), _parser(_bufferspi), _resetpin(resetpin), + _packets(0), _packets_end(&_packets) +{ + DigitalOut wakeup_pin(wakeup); + ISM43362::setTimeout((uint32_t)5000); + _bufferspi.format(16, 0); /* 16bits, ploarity low, phase 1Edge, master mode */ + _bufferspi.frequency(20000000); /* up to 20 MHz */ + _active_id = 0xFF; + + reset(); + + _ism_debug = debug || ism_debug; + _parser.debugOn(debug); +} + +/** + * @brief Parses and returns number from string. + * @param ptr: pointer to string + * @param cnt: pointer to the number of parsed digit + * @retval integer value. + */ +#define CHARISHEXNUM(x) (((x) >= '0' && (x) <= '9') || \ + ((x) >= 'a' && (x) <= 'f') || \ + ((x) >= 'A' && (x) <= 'F')) +#define CHARISNUM(x) ((x) >= '0' && (x) <= '9') +#define CHAR2NUM(x) ((x) - '0') + + +extern "C" int32_t ParseNumber(char* ptr, uint8_t* cnt) +{ + uint8_t minus = 0, i = 0; + int32_t sum = 0; + + if (*ptr == '-') { /* Check for minus character */ + minus = 1; + ptr++; + i++; + } + while (CHARISNUM(*ptr) || (*ptr=='.')) { /* Parse number */ + if (*ptr == '.') { + ptr++; // next char + } else { + sum = 10 * sum + CHAR2NUM(*ptr); + ptr++; + i++; + } + } + + if (cnt != NULL) { /* Save number of characters used for number */ + *cnt = i; + } + if (minus) { /* Minus detected */ + return 0 - sum; + } + return sum; /* Return number */ +} + +const char *ISM43362::get_firmware_version(void) +{ + char tmp_buffer[250]; + char *ptr, *ptr2; + + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if(!(_parser.send("I?") && _parser.recv("%[^\n^\r]\r\n", tmp_buffer) && check_response())) { + debug_if(_ism_debug, "ISM43362: get_firmware_version is FAIL\r\n"); + return 0; + } + + // Get the first version in the string + ptr = strtok((char *)tmp_buffer, ","); + ptr = strtok(NULL, ","); + ptr2 = strtok(NULL, ","); + if (ptr == NULL) { + debug_if(_ism_debug, "ISM43362: get_firmware_version decoding is FAIL\r\n"); + return 0; + } + strncpy(_fw_version, ptr , ptr2-ptr); + + debug_if(_ism_debug, "ISM43362: get_firmware_version = [%s]\r\n", _fw_version); + + return _fw_version; +} + +bool ISM43362::reset(void) +{ + char tmp_buffer[100]; + debug_if(_ism_debug,"ISM43362: Reset Module\r\n"); + _resetpin = 0; + wait_ms(10); + _resetpin = 1; + wait_ms(500); + + /* Wait for prompt line : the string is "> ". */ + /* As the space char is not detected by sscanf function in parser.recv, */ + /* we need to use %[\n] */ + if (!_parser.recv(">%[^\n]", tmp_buffer)) { + debug_if(_ism_debug,"ISM43362: Reset Module failed\r\n"); + return false; + } + return true; +} + +void ISM43362::print_rx_buff(void) { + char tmp[150] = {0}; + uint16_t i = 0; + debug_if(_ism_debug,"ISM43362: "); + while(i < 150) { + int c = _parser.getc(); + if (c < 0) + break; + tmp[i] = c; + debug_if(_ism_debug,"0x%2X ",c); + i++; + } + debug_if(_ism_debug,"\n"); + debug_if(_ism_debug,"ISM43362: Buffer content =====%s=====\r\n",tmp); +} + +/* checks the standard OK response of the WIFI module, shouldbe: + * \r\nDATA\r\nOK\r\n>sp + * or + * \r\nERROR\r\nUSAGE\r\n>sp + * function returns true if OK, false otherwise. In case of error, + * print error content then flush buffer */ +bool ISM43362::check_response(void) +{ + char tmp_buffer[100]; + if(!_parser.recv("OK\r\n")) { + print_rx_buff(); + _parser.flush(); + return false; + } + + /* Then we should get the prompt: "> " */ + /* As the space char is not detected by sscanf function in parser.recv, */ + /* we need to use %[\n] */ + if (!_parser.recv(">%[^\n]", tmp_buffer)) { + debug_if(_ism_debug, "ISM43362: Missing prompt in WIFI resp\r\n"); + print_rx_buff(); + _parser.flush(); + return false; + } + + /* Inventek module do stuffing / padding of data with 0x15, + * in case buffer contains such */ + while(1) { + int c = _parser.getc(); + if ( c == 0x15) { + debug_if(_ism_debug, "ISM43362: Flush char 0x%x\n", c); + continue; + } else { + /* How to put it back if needed ? */ + break; + } + } + return true; +} + +bool ISM43362::dhcp(bool enabled) +{ + return (_parser.send("C4=%d", enabled ? 1:0) && check_response()); +} + +int ISM43362::connect(const char *ap, const char *passPhrase, ism_security_t ap_sec) +{ + char tmp[256]; + + if (!(_parser.send("C1=%s", ap) && check_response())) { + return NSAPI_ERROR_PARAMETER; + } + + if (!(_parser.send("C2=%s", passPhrase) && check_response())) { + return NSAPI_ERROR_PARAMETER; + } + + /* Check security level is acceptable */ + if (ap_sec > ISM_SECURITY_WPA_WPA2 ) { + debug_if(_ism_debug, "ISM43362: Unsupported security level %d\n", ap_sec); + return NSAPI_ERROR_UNSUPPORTED; + } + + if (!(_parser.send("C3=%d", ap_sec) && check_response())) { + return NSAPI_ERROR_PARAMETER; + } + + if(_parser.send("C0")) { + while (_parser.recv("%[^\n]\n", tmp)) { + if(strstr(tmp, "OK")) { + _parser.flush(); + return NSAPI_ERROR_OK; + } + if(strstr(tmp, "JOIN")) { + if(strstr(tmp, "Failed")) { + _parser.flush(); + return NSAPI_ERROR_AUTH_FAILURE; + } + } + } + } + + return NSAPI_ERROR_NO_CONNECTION; +} + +bool ISM43362::disconnect(void) +{ + return (_parser.send("CD") && check_response()); +} + +const char *ISM43362::getIPAddress(void) +{ + char tmp_ip_buffer[250]; + char *ptr, *ptr2; + + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if(!(_parser.send("C?") + && _parser.recv("%[^\n^\r]\r\n", tmp_ip_buffer) + && check_response())) { + debug_if(_ism_debug,"ISM43362: getIPAddress LINE KO: %s\n", tmp_ip_buffer); + return 0; + } + + /* Get the IP address in the result */ + /* TODO : check if the begining of the string is always = "eS-WiFi_AP_C47F51011231," */ + ptr = strtok((char *)tmp_ip_buffer, ","); + ptr = strtok(NULL, ","); + ptr = strtok(NULL, ","); + ptr = strtok(NULL, ","); + ptr = strtok(NULL, ","); + ptr = strtok(NULL, ","); + ptr2 = strtok(NULL, ","); + if (ptr == NULL) return 0; + strncpy(_ip_buffer, ptr , ptr2-ptr); + + tmp_ip_buffer[59] = 0; + debug_if(_ism_debug,"ISM43362: receivedIPAddress: %s\n", _ip_buffer); + + return _ip_buffer; +} + +const char *ISM43362::getMACAddress(void) +{ + if(!(_parser.send("Z5") && _parser.recv("%s\r\n", _mac_buffer) && check_response())) { + debug_if(_ism_debug,"ISM43362: receivedMacAddress LINE KO: %s\n", _mac_buffer); + return 0; + } + + debug_if(_ism_debug,"ISM43362: receivedMacAddress:%s, size=%d\r\n", _mac_buffer, sizeof(_mac_buffer)); + + return _mac_buffer; +} + +const char *ISM43362::getGateway() +{ + char tmp[250]; + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if(!(_parser.send("C?") && _parser.recv("%[^\n^\r]\r\n", tmp) && check_response())) { + debug_if(_ism_debug,"ISM43362: getGateway LINE KO: %s\r\n", tmp); + return 0; + } + + /* Extract the Gateway in the received buffer */ + char *ptr; + ptr = strtok(tmp,","); + for (int i = 0; i< 7;i++) { + if (ptr == NULL) break; + ptr = strtok(NULL,","); + } + + strncpy(_gateway_buffer, ptr, sizeof(_gateway_buffer)); + + debug_if(_ism_debug,"ISM43362: getGateway: %s\r\n", _gateway_buffer); + + return _gateway_buffer; +} + +const char *ISM43362::getNetmask() +{ + char tmp[250]; + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if(!(_parser.send("C?") && _parser.recv("%[^\n^\r]\r\n", tmp) && check_response())) { + debug_if(_ism_debug,"ISM43362: getNetmask LINE KO: %s\n", tmp); + return 0; + } + + /* Extract Netmask in the received buffer */ + char *ptr; + ptr = strtok(tmp,","); + for (int i = 0; i< 6;i++) { + if (ptr == NULL) break; + ptr = strtok(NULL,","); + } + + strncpy(_netmask_buffer, ptr, sizeof(_netmask_buffer)); + + debug_if(_ism_debug,"ISM43362: getNetmask: %s\r\n", _netmask_buffer); + + return _netmask_buffer; +} + +int8_t ISM43362::getRSSI() +{ + int8_t rssi; + char tmp[25]; + + if(!(_parser.send("CR") && _parser.recv("%s\r\n", tmp) && check_response())) { + debug_if(_ism_debug,"ISM43362: getRSSI LINE KO: %s\r\n", tmp); + return 0; + } + + rssi = ParseNumber(tmp, NULL); + + debug_if(_ism_debug,"ISM43362: getRSSI: %d\r\n", rssi); + + return rssi; +} +/** + * @brief Parses Security type. + * @param ptr: pointer to string + * @retval Encryption type. + */ +extern "C" nsapi_security_t ParseSecurity(char* ptr) +{ + if(strstr(ptr,"Open")) return NSAPI_SECURITY_NONE; + else if(strstr(ptr,"WEP")) return NSAPI_SECURITY_WEP; + else if(strstr(ptr,"WPA2 AES")) return NSAPI_SECURITY_WPA2; + else if(strstr(ptr,"WPA WPA2")) return NSAPI_SECURITY_WPA_WPA2; + else if(strstr(ptr,"WPA2 TKIP")) return NSAPI_SECURITY_UNKNOWN; // no match in mbed + else if(strstr(ptr,"WPA2")) return NSAPI_SECURITY_WPA2; // catch any other WPA2 formula + else if(strstr(ptr,"WPA")) return NSAPI_SECURITY_WPA; + else return NSAPI_SECURITY_UNKNOWN; +} + +/** + * @brief Convert char in Hex format to integer. + * @param a: character to convert + * @retval integer value. + */ +extern "C" uint8_t Hex2Num(char a) +{ + if (a >= '0' && a <= '9') { /* Char is num */ + return a - '0'; + } else if (a >= 'a' && a <= 'f') { /* Char is lowercase character A - Z (hex) */ + return (a - 'a') + 10; + } else if (a >= 'A' && a <= 'F') { /* Char is uppercase character A - Z (hex) */ + return (a - 'A') + 10; + } + + return 0; +} + +/** + * @brief Extract a hex number from a string. + * @param ptr: pointer to string + * @param cnt: pointer to the number of parsed digit + * @retval Hex value. + */ +extern "C" uint32_t ParseHexNumber(char* ptr, uint8_t* cnt) +{ + uint32_t sum = 0; + uint8_t i = 0; + + while (CHARISHEXNUM(*ptr)) { /* Parse number */ + sum <<= 4; + sum += Hex2Num(*ptr); + ptr++; + i++; + } + + if (cnt != NULL) { /* Save number of characters used for number */ + *cnt = i; + } + return sum; /* Return number */ +} + +bool ISM43362::isConnected(void) +{ + return getIPAddress() != 0; +} + +int ISM43362::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned cnt = 0, num=0; + char *ptr; + char tmp[256]; + + if(!(_parser.send("F0"))) { + debug_if(_ism_debug,"ISM43362: scan error\r\n"); + return 0; + } + + /* Parse the received buffer and fill AP buffer */ + /* Use %[^\n] instead of %s to allow having spaces in the string */ + while (_parser.recv("#%[^\n]\n", tmp)) { + if (limit != 0 && cnt >= limit) { + /* reached end */ + break; + } + nsapi_wifi_ap_t ap = {0}; + debug_if(_ism_debug,"ISM43362: received:%s\n", tmp); + ptr = strtok(tmp, ","); + num = 0; + while (ptr != NULL) { + switch (num++) { + case 0: /* Ignore index */ + case 4: /* Ignore Max Rate */ + case 5: /* Ignore Network Type */ + case 7: /* Ignore Radio Band */ + break; + case 1: + ptr[strlen(ptr) - 1] = 0; + strncpy((char *)ap.ssid, ptr+ 1, 32); + break; + case 2: + for (int i=0; i<6; i++) { + ap.bssid[i] = ParseHexNumber(ptr + (i*3), NULL); + } + break; + case 3: + ap.rssi = ParseNumber(ptr, NULL); + break; + case 6: + ap.security = ParseSecurity(ptr); + break; + case 8: + ap.channel = ParseNumber(ptr, NULL); + num = 1; + break; + default: + break; + } + ptr = strtok(NULL, ","); + } + res[cnt] = WiFiAccessPoint(ap); + cnt++; + } + + /* We may stop before having read all the APs list, so flush the rest of + * it as well as OK commands */ + _parser.flush(); + + debug_if(_ism_debug, "ISM43362: End of Scan: cnt=%d\n", cnt); + + return cnt; + +} + +bool ISM43362::open(const char *type, int id, const char* addr, int port) +{ /* TODO : This is the implementation for the client socket, need to check if need to create openserver too */ + //IDs only 0-3 + if((id < 0) ||(id > 3)) { + debug_if(_ism_debug, "ISM43362: open: wrong id\n"); + return false; + } + /* Set communication socket */ + debug_if(_ism_debug, "ISM43362: OPEN socket\n"); + _active_id = id; + if (!(_parser.send("P0=%d", id) && check_response())) { + return false; + } + /* Set protocol */ + if (!(_parser.send("P1=%s", type) && check_response())) { + return false; + } + /* Set address */ + if (!(_parser.send("P3=%s", addr) && check_response())) { + return false; + } + if (!(_parser.send("P4=%d", port) && check_response())) { + return false; + } + /* Start client */ + if (!(_parser.send("P6=1") && check_response())) { + return false; + } + + /* request as much data as possible - i.e. module max size */ + if (!(_parser.send("R1=%d", ES_WIFI_MAX_RX_PACKET_SIZE)&& check_response())) { + return -1; + } + + return true; +} + +bool ISM43362::dns_lookup(const char* name, char* ip) +{ + char tmp[30]; + + if (!(_parser.send("D0=%s", name) && _parser.recv("%s\r\n", tmp) + && check_response())) { + debug_if(_ism_debug,"ISM43362: dns_lookup LINE KO: %s\n", tmp); + return 0; + } + + strncpy(ip, tmp, sizeof(tmp)); + + debug_if(_ism_debug, "ISM43362: ip of DNSlookup: %s\n", ip); + return 1; +} + +bool ISM43362::send(int id, const void *data, uint32_t amount) +{ + // The Size limit has to be checked on caller side. + if (amount > ES_WIFI_MAX_RX_PACKET_SIZE) { + return false; + } + + /* Activate the socket id in the wifi module */ + if ((id < 0) ||(id > 3)) { + return false; + } + debug_if(_ism_debug, "ISM43362: SEND socket amount %d\n", amount); + if (_active_id != id) { + _active_id = id; + if (!(_parser.send("P0=%d",id) && check_response())) { + return false; + } + } + + /* Change the write timeout */ + if (!(_parser.send("S2=%d", _timeout) && check_response())) { + return false; + } + /* set Write Transport Packet Size */ + int i = _parser.printf("S3=%d\r", (int)amount); + if (i < 0) { + return false; + } + i = _parser.write((const char *)data, amount, i); + if (i < 0) { + return false; + } + + if (!check_response()) { + return false; + } + + return true; +} + +int ISM43362::check_recv_status(int id, void *data) +{ + int read_amount; + static int keep_to = 0; + + debug_if(_ism_debug, "ISM43362: ISM43362 req check_recv_status\r\n"); + /* Activate the socket id in the wifi module */ + if ((id < 0) ||(id > 3)) { + return -1; + } + + if (_active_id != id) { + _active_id = id; + if (!(_parser.send("P0=%d",id) && check_response())) { + return -1; + } + } + + + /* MBED wifi driver is meant to be non-blocking, but we need anyway to + * wait for some data on the RECV side to avoid overflow on TX side, the + * tiemout is defined in higher layer */ + if (keep_to != _timeout) { + if (!(_parser.send("R2=%d", _timeout) && check_response())) { + return -1; + } + keep_to = _timeout; + } + + if (!_parser.send("R0")) { + return -1; + } + read_amount = _parser.read((char *)data); + + if(read_amount < 0) { + debug_if(_ism_debug, "ISM43362: ERROR in data RECV, timeout?\r\n"); + return -1; /* nothing to read */ + } + + /* If there are spurious 0x15 at the end of the data, this is an error + * we hall can get rid off of them :-( + * This should not happen, but let's try to clean-up anyway + */ + char *cleanup = (char *) data; + while ((read_amount > 0) && (cleanup[read_amount-1] == 0x15)) { + debug_if(_ism_debug, "ISM43362: spurious 0X15 trashed\r\n"); + /* Remove the trailling char then search again */ + read_amount--; + } + + if ((read_amount >= 6) && (strncmp("OK\r\n> ", (char *)data, 6) == 0)) { + debug_if(_ism_debug, "ISM43362: recv 2 nothing to read=%d\r\n", read_amount); + return 0; /* nothing to read */ + } else if ((read_amount >= 8) && (strncmp((char *)((uint32_t) data + read_amount - 8), "\r\nOK\r\n> ", 8)) == 0) { + /* bypass ""\r\nOK\r\n> " if present at the end of the chain */ + read_amount -= 8; + } else { + debug_if(_ism_debug, "ISM43362: ERROR in data RECV?, flushing %d bytes\r\n", read_amount); + int i = 0; + debug_if(_ism_debug, "ISM43362: "); + for (i = 0; i < read_amount; i++) { + debug_if(_ism_debug, "%2X ", cleanup[i]); + } + cleanup[i] = 0; + debug_if(_ism_debug, "\r\n%s\r\n", cleanup); + return -1; /* nothing to read */ + } + + debug_if(_ism_debug, "ISM43362: read_amount=%d\r\n", read_amount); + return read_amount; +} + +bool ISM43362::close(int id) +{ + if ((id <0) || (id > 3)) { + debug_if(_ism_debug,"ISM43362: Wrong socket number\n"); + return false; + } + /* Set connection on this socket */ + debug_if(_ism_debug,"ISM43362: CLOSE socket id=%d\n", id); + _active_id = id; + if (!(_parser.send("P0=%d", id) && check_response())) { + return false; + } + /* close this socket */ + if (!(_parser.send("P6=0") && check_response())) { + return false; + } + return true; +} + +void ISM43362::setTimeout(uint32_t timeout_ms) +{ + _timeout = timeout_ms; + _parser.setTimeout(timeout_ms); +} + +bool ISM43362::readable() +{ + /* not applicable with SPI api */ + return true; +} + +bool ISM43362::writeable() +{ + /* not applicable with SPI api */ + return true; +} + +void ISM43362::attach(Callback<void()> func) +{ + /* not applicable with SPI api */ +} +
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362/ISM43362.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ISM43362.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,256 @@ +/* ISM43362Interface Example + * Copyright (c) STMicroelectronics 2017 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ISM43362_H +#define ISM43362_H +#include "ATParser.h" + +#define ES_WIFI_MAX_SSID_NAME_SIZE 32 +#define ES_WIFI_MAX_PSWD_NAME_SIZE 32 +#define ES_WIFI_PRODUCT_ID_SIZE 32 +#define ES_WIFI_PRODUCT_NAME_SIZE 32 +#define ES_WIFI_FW_REV_SIZE 16 +#define ES_WIFI_API_REV_SIZE 16 +#define ES_WIFI_STACK_REV_SIZE 16 +#define ES_WIFI_RTOS_REV_SIZE 16 + +// The input range for AT Command 'R1' is 0 to 1200 bytes +// 'R1' Set Read Transport Packet Size (bytes) +#define ES_WIFI_MAX_RX_PACKET_SIZE 1200 +// Module maxume DATA payload for Tx packet is 1460 +#define ES_WIFI_MAX_TX_PACKET_SIZE 1460 +typedef enum ism_security { + ISM_SECURITY_NONE = 0x0, /*!< open access point */ + ISM_SECURITY_WEP = 0x1, /*!< phrase conforms to WEP */ + ISM_SECURITY_WPA = 0x2, /*!< phrase conforms to WPA */ + ISM_SECURITY_WPA2 = 0x3, /*!< phrase conforms to WPA2 */ + ISM_SECURITY_WPA_WPA2 = 0x4, /*!< phrase conforms to WPA/WPA2 */ + ISM_SECURITY_UNKNOWN = 0xFF, /*!< unknown/unsupported security in scan results */ +} ism_security_t; + +/** ISM43362Interface class. + This is an interface to a ISM43362 radio. + */ +class ISM43362 +{ +public: + ISM43362(PinName mosi, PinName miso, PinName clk, PinName nss, PinName resetpin, PinName datareadypin, PinName wakeup, bool debug=false); + + /** + * Check firmware version of ISM43362 + * + * @return null-terminated fw version or null if no version is read + */ + const char *get_firmware_version(void); + + /** + * Reset ISM43362 + * + * @return true only if ISM43362 resets successfully + */ + bool reset(void); + + /** + * Enable/Disable DHCP + * + * @param enabled DHCP enabled when true + * @return true only if ISM43362 enables/disables DHCP successfully + */ + bool dhcp(bool enabled); + + /** + * Connect ISM43362 to AP + * + * @param ap the name of the AP + * @param passPhrase the password of AP + * @param ap_sec the security level of network AP + * @return nsapi_error enum + */ + int connect(const char *ap, const char *passPhrase, ism_security_t ap_sec); + + /** + * Disconnect ISM43362 from AP + * + * @return true only if ISM43362 is disconnected successfully + */ + bool disconnect(void); + + /** + * Get the IP address of ISM43362 + * + * @return null-teriminated IP address or null if no IP address is assigned + */ + const char *getIPAddress(void); + + /** + * Get the MAC address of ISM43362 + * + * @return null-terminated MAC address or null if no MAC address is assigned + */ + const char *getMACAddress(void); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been recieved + */ + const char *getGateway(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been recieved + */ + const char *getNetmask(); + + /* Return RSSI for active connection + * + * @return Measured RSSI + */ + int8_t getRSSI(); + + /** + * Check if ISM43362 is conenected + * + * @return true only if the chip has an IP address + */ + bool isConnected(void); + + /** Scan for available networks + * + * @param ap Pointer to allocated array to store discovered AP + * @param limit Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + int scan(WiFiAccessPoint *res, unsigned limit); + + /**Perform a dns query + * + * @param name Hostname to resolve + * @param ip Buffer to store IP address + * @return 0 true on success, false on failure + */ + bool dns_lookup(const char *name, char *ip); + + /** + * Open a socketed connection + * + * @param type the type of socket to open "UDP" or "TCP" + * @param id id to give the new socket, valid 0-4 + * @param port port to open connection with + * @param addr the IP address of the destination + * @return true only if socket opened successfully + */ + bool open(const char *type, int id, const char* addr, int port); + + /** + * Sends data to an open socket + * + * @param id id of socket to send to + * @param data data to be sent + * @param amount amount of data to be sent - max 1024 + * @return true only if data sent successfully + */ + bool send(int id, const void *data, uint32_t amount); + + /** + * Receives data from an open socket + * + * @param id id to receive from + * @param data placeholder for returned information + * @param amount number of bytes to be received + * @return the number of bytes received + */ + int32_t recv(int id, void *data, uint32_t amount); + + /** + * Closes a socket + * + * @param id id of socket to close, valid only 0-4 + * @return true only if socket is closed successfully + */ + bool close(int id); + + /** + * Allows timeout to be changed between commands + * + * @param timeout_ms timeout of the connection + */ + void setTimeout(uint32_t timeout_ms); + + /** + * Checks if data is available + */ + bool readable(); + + /** + * Checks if data can be written + */ + bool writeable(); + + /** + * Attach a function to call whenever network state has changed + * + * @param func A pointer to a void function, or 0 to set as none + */ + void attach(Callback<void()> func); + + /** + * Check is datas are available to read for a socket + * @param id socket id + * @param data placeholder for returned information + * @param amount size to read for the check + * @return amount of read value, or -1 for errors + */ + int check_recv_status(int id, void *data); + + /** + * Attach a function to call whenever network state has changed + * + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to call + */ + template <typename T, typename M> + void attach(T *obj, M method) { + attach(Callback<void()>(obj, method)); + } + +private: + BufferedSpi _bufferspi; + ATParser _parser; + DigitalOut _resetpin; + volatile int _timeout; + volatile int _active_id; + void print_rx_buff(void); + bool check_response(void); + struct packet { + struct packet *next; + int id; + uint32_t len; + // data follows + } *_packets, **_packets_end; + void _packet_handler(); + bool _ism_debug; + + char _ip_buffer[16]; + char _gateway_buffer[16]; + char _netmask_buffer[16]; + char _mac_buffer[18]; + char _fw_version[16]; +}; + +#endif
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362Interface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362Interface.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,557 @@ +/* ISM43362 implementation of NetworkInterfaceAPI + * Copyright (c) STMicroelectronics 2018 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> +#include "ISM43362Interface.h" +#include "mbed_debug.h" + +// activate / de-activate debug +#define ism_debug false + +// Various timeouts for different ISM43362 operations +#define ISM43362_CONNECT_TIMEOUT 50000 /* milliseconds */ +#define ISM43362_SEND_TIMEOUT 1000 /* milliseconds */ +#define ISM43362_RECV_TIMEOUT 100 /* milliseconds */ +#define ISM43362_MISC_TIMEOUT 100 /* milliseconds */ + +// Tested firmware versions +// Example of versions string returned by the module: +// "ISM43362-M3G-L44-SPI,C3.5.2.3.BETA9,v3.5.2,v1.4.0.rc1,v8.2.1,120000000,Inventek eS-WiFi" +// "ISM43362-M3G-L44-SPI,C3.5.2.2,v3.5.2,v1.4.0.rc1,v8.2.1,120000000,Inventek eS-WiFi" +// Only the first version is checked ! +const char supported_fw_versions[2][15] = {"C3.5.2.3.BETA9", "C3.5.2.2"}; + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +// ISM43362Interface implementation +ISM43362Interface::ISM43362Interface(bool debug) + : _ism(MBED_CONF_ISM43362_WIFI_MOSI, MBED_CONF_ISM43362_WIFI_MISO, MBED_CONF_ISM43362_WIFI_SCLK, MBED_CONF_ISM43362_WIFI_NSS, MBED_CONF_ISM43362_WIFI_RESET, MBED_CONF_ISM43362_WIFI_DATAREADY, MBED_CONF_ISM43362_WIFI_WAKEUP, debug) +{ + _ism_debug = ism_debug || debug; + memset(_ids, 0, sizeof(_ids)); + memset(_socket_obj, 0, sizeof(_socket_obj)); + memset(_cbs, 0, sizeof(_cbs)); + memset(ap_ssid, 0, sizeof(ap_ssid)); + memset(ap_pass, 0, sizeof(ap_pass)); + ap_sec = ISM_SECURITY_UNKNOWN; + + thread_read_socket.start(callback(this, &ISM43362Interface::socket_check_read)); +} + +int ISM43362Interface::connect(const char *ssid, const char *pass, nsapi_security_t security, + uint8_t channel) +{ + if (channel != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + + nsapi_error_t credentials_status = set_credentials(ssid, pass, security); + if (credentials_status) { + return credentials_status; + } + + return connect(); +} + +int ISM43362Interface::connect() +{ + if (strlen(ap_ssid) == 0) { + return NSAPI_ERROR_NO_SSID; + } + + _mutex.lock(); + const char* read_version; + + _ism.setTimeout(ISM43362_MISC_TIMEOUT); + + // Check all supported firmware versions + read_version = _ism.get_firmware_version(); + + if (!read_version) { + debug_if(_ism_debug, "ISM43362Interface: ERROR cannot read firmware version\r\n"); + _mutex.unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + debug_if(_ism_debug, "ISM43362Interface: read_version = [%s]\r\n", read_version); + + if ((strcmp(read_version, supported_fw_versions[0]) == 0) || (strcmp(read_version, supported_fw_versions[1]) == 0)) { + debug_if(_ism_debug, "ISM43362Interface: firmware version is OK\r\n"); + } else { + debug_if(_ism_debug, "ISM43362Interface: WARNING this firmware version has not been tested !\r\n"); + } + + if (!_ism.dhcp(true)) { + _mutex.unlock(); + return NSAPI_ERROR_DHCP_FAILURE; + } + + _ism.setTimeout(ISM43362_CONNECT_TIMEOUT); + int connect_status = _ism.connect(ap_ssid, ap_pass, ap_sec); + debug_if(_ism_debug, "ISM43362Interface: connect_status %d\n", connect_status); + + if (connect_status != NSAPI_ERROR_OK) { + _mutex.unlock(); + return connect_status; + } + + _ism.setTimeout(ISM43362_MISC_TIMEOUT); + if (!_ism.getIPAddress()) { + _mutex.unlock(); + return NSAPI_ERROR_DHCP_FAILURE; + } + + _mutex.unlock(); + + return NSAPI_ERROR_OK; +} + +nsapi_error_t ISM43362Interface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version) +{ + _mutex.lock(); + if (address->set_ip_address(name)) { + if (version != NSAPI_UNSPEC && address->get_ip_version() != version) { + _mutex.unlock(); + return NSAPI_ERROR_DNS_FAILURE; + } + + _mutex.unlock(); + return NSAPI_ERROR_OK; + } + + char *ipbuff = new char[NSAPI_IP_SIZE]; + int ret = 0; + _ism.setTimeout(ISM43362_CONNECT_TIMEOUT); + if(!_ism.dns_lookup(name, ipbuff)) { + ret = NSAPI_ERROR_DEVICE_ERROR; + } else { + address->set_ip_address(ipbuff); + } + _mutex.unlock(); + + delete[] ipbuff; + + return ret; +} + +int ISM43362Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + if ( (strlen(ssid) == 0) || (strlen(ssid) > 32) ) { + return NSAPI_ERROR_PARAMETER; + } + + if ( (security != NSAPI_SECURITY_NONE) && (strcmp(pass, "") == 0)) { + return NSAPI_ERROR_PARAMETER; + } + + if (strlen(pass) > 63) { + return NSAPI_ERROR_PARAMETER; + } + + _mutex.lock(); + memset(ap_ssid, 0, sizeof(ap_ssid)); + strncpy(ap_ssid, ssid, sizeof(ap_ssid)); + + memset(ap_pass, 0, sizeof(ap_pass)); + strncpy(ap_pass, pass, sizeof(ap_pass)); + + switch(security) { + case NSAPI_SECURITY_NONE: + ap_sec = ISM_SECURITY_NONE; + break; + case NSAPI_SECURITY_WEP: + ap_sec = ISM_SECURITY_WEP; + break; + case NSAPI_SECURITY_WPA: + ap_sec = ISM_SECURITY_WPA; + break; + case NSAPI_SECURITY_WPA2: + ap_sec = ISM_SECURITY_WPA2; + break; + case NSAPI_SECURITY_WPA_WPA2: + ap_sec = ISM_SECURITY_WPA_WPA2; + break; + default: + ap_sec = ISM_SECURITY_UNKNOWN; + break; + } + _mutex.unlock(); + + return NSAPI_ERROR_OK; +} + +int ISM43362Interface::set_channel(uint8_t channel) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ISM43362Interface::disconnect() +{ + _mutex.lock(); + + _ism.setTimeout(ISM43362_MISC_TIMEOUT); + + if (!_ism.disconnect()) { + _mutex.unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + + _mutex.unlock(); + + return NSAPI_ERROR_OK; +} + +const char *ISM43362Interface::get_ip_address() +{ + _mutex.lock(); + const char *ret = _ism.getIPAddress(); + _mutex.unlock(); + return ret; +} + +const char *ISM43362Interface::get_mac_address() +{ + _mutex.lock(); + const char *ret = _ism.getMACAddress(); + _mutex.unlock(); + return ret; +} + +const char *ISM43362Interface::get_gateway() +{ + _mutex.lock(); + const char *ret = _ism.getGateway(); + _mutex.unlock(); + return ret; +} + +const char *ISM43362Interface::get_netmask() +{ + _mutex.lock(); + const char *ret = _ism.getNetmask(); + _mutex.unlock(); + return ret; +} + +int8_t ISM43362Interface::get_rssi() +{ + _mutex.lock(); + int8_t ret = _ism.getRSSI(); + _mutex.unlock(); + return ret; +} + +int ISM43362Interface::scan(WiFiAccessPoint *res, unsigned count) +{ + _mutex.lock(); + _ism.setTimeout(ISM43362_CONNECT_TIMEOUT); + int ret = _ism.scan(res, count); + _mutex.unlock(); + return ret; +} + +struct ISM43362_socket { + int id; + nsapi_protocol_t proto; + volatile bool connected; + SocketAddress addr; + char read_data[1400]; + volatile uint32_t read_data_size; +}; + +int ISM43362Interface::socket_open(void **handle, nsapi_protocol_t proto) +{ + // Look for an unused socket + int id = -1; + for (int i = 0; i < ISM43362_SOCKET_COUNT; i++) { + if (!_ids[i]) { + id = i; + _ids[i] = true; + break; + } + } + + if (id == -1) { + return NSAPI_ERROR_NO_SOCKET; + } + _mutex.lock(); + struct ISM43362_socket *socket = new struct ISM43362_socket; + if (!socket) { + _mutex.unlock(); + return NSAPI_ERROR_NO_SOCKET; + } + socket->id = id; + debug_if(_ism_debug, "ISM43362Interface: socket_open, id=%d\n", socket->id); + memset(socket->read_data, 0, sizeof(socket->read_data)); + socket->addr = 0; + socket->read_data_size = 0; + socket->proto = proto; + socket->connected = false; + *handle = socket; + _mutex.unlock(); + + return 0; +} + +int ISM43362Interface::socket_close(void *handle) +{ + _mutex.lock(); + struct ISM43362_socket *socket = (struct ISM43362_socket *)handle; + debug_if(_ism_debug, "ISM43362Interface: socket_close, id=%d\n", socket->id); + int err = 0; + _ism.setTimeout(ISM43362_MISC_TIMEOUT); + + if (!_ism.close(socket->id)) { + err = NSAPI_ERROR_DEVICE_ERROR; + } + + socket->connected = false; + _ids[socket->id] = false; + _socket_obj[socket->id] = 0; + _mutex.unlock(); + delete socket; + return err; +} + +int ISM43362Interface::socket_bind(void *handle, const SocketAddress &address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ISM43362Interface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ISM43362Interface::socket_connect(void *handle, const SocketAddress &addr) +{ + _mutex.lock(); + int ret = socket_connect_nolock(handle, addr); + _mutex.unlock(); + return ret; +} + +int ISM43362Interface::socket_connect_nolock(void *handle, const SocketAddress &addr) +{ + struct ISM43362_socket *socket = (struct ISM43362_socket *)handle; + _ism.setTimeout(ISM43362_CONNECT_TIMEOUT); + const char *proto = (socket->proto == NSAPI_UDP) ? "1" : "0"; + if (!_ism.open(proto, socket->id, addr.get_ip_address(), addr.get_port())) { + return NSAPI_ERROR_DEVICE_ERROR; + } + _ids[socket->id] = true; + _socket_obj[socket->id] = (uint32_t)socket; + socket->connected = true; + return 0; + +} + + + +void ISM43362Interface::socket_check_read() +{ + while (1) { + for (int i = 0; i < ISM43362_SOCKET_COUNT; i++) { + _mutex.lock(); + if (_socket_obj[i] != 0) { + struct ISM43362_socket *socket = (struct ISM43362_socket *)_socket_obj[i]; + /* Check if there is something to read for this socket. But if it */ + /* has already been read : don't read again */ + if ((socket->connected) && (socket->read_data_size == 0) && _cbs[socket->id].callback) { + _ism.setTimeout(1); + /* if no callback is set, no need to read ?*/ + int read_amount = _ism.check_recv_status(socket->id, socket->read_data); + if (read_amount > 0) { + socket->read_data_size = read_amount; + } else if (read_amount < 0) { + /* Mark donw connection has been lost or closed */ + socket->connected = false; + } + if (read_amount != 0) { + /* There is something to read in this socket*/ + if (_cbs[socket->id].callback) { + _cbs[socket->id].callback(_cbs[socket->id].data); + } + } + } + } + _mutex.unlock(); + } + wait_ms(50); + } +} + +int ISM43362Interface::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ISM43362Interface::socket_send(void *handle, const void *data, unsigned size) +{ + _mutex.lock(); + int ret = socket_send_nolock(handle, data, size); + _mutex.unlock(); + return ret; +} + +/* CAREFULL LOCK must be taken before callling this function */ +int ISM43362Interface::socket_send_nolock(void *handle, const void *data, unsigned size) +{ + struct ISM43362_socket *socket = (struct ISM43362_socket *)handle; + _ism.setTimeout(ISM43362_SEND_TIMEOUT); + + if (size > ES_WIFI_MAX_TX_PACKET_SIZE) { + size = ES_WIFI_MAX_TX_PACKET_SIZE; + } + + if (!_ism.send(socket->id, data, size)) { + debug_if(_ism_debug, "ISM43362Interface: socket_send ERROR\r\n"); + return NSAPI_ERROR_DEVICE_ERROR; // or WOULD_BLOCK ? + } + + return size; +} + +int ISM43362Interface::socket_recv(void *handle, void *data, unsigned size) +{ + _mutex.lock(); + unsigned recv = 0; + struct ISM43362_socket *socket = (struct ISM43362_socket *)handle; + char *ptr = (char *)data; + + debug_if(_ism_debug, "ISM43362Interface: [socket_recv] req=%d\r\n", size); + + if (!socket->connected) { + _mutex.unlock(); + return NSAPI_ERROR_CONNECTION_LOST; + } + + _ism.setTimeout(ISM43362_RECV_TIMEOUT); + + if (socket->read_data_size == 0) { + /* if no callback is set, no need to read ?*/ + int read_amount = _ism.check_recv_status(socket->id, socket->read_data); + if (read_amount > 0) { + socket->read_data_size = read_amount; + } else if (read_amount < 0) { + socket->connected = false; + _mutex.unlock(); + return NSAPI_ERROR_CONNECTION_LOST; + } + } + + if (socket->read_data_size != 0) { + debug_if(_ism_debug, "ISM43362Interface: read_data_size=%d\r\n", socket->read_data_size); + uint32_t i=0; + while ((i < socket->read_data_size) && (i < size)) { + *ptr++ = socket->read_data[i]; + i++; + } + + debug_if(_ism_debug, "ISM43362Interface: Copied i bytes=%d, vs %d requestd\r\n", i, size); + recv += i; + + if (i >= socket->read_data_size) { + /* All the storeed data has been read, reset buffer */ + memset(socket->read_data, 0, sizeof(socket->read_data)); + socket->read_data_size = 0; + debug_if(_ism_debug, "ISM43362Interface: Socket_recv buffer reset\r\n"); + } else { + /* In case there is remaining data in buffer, update socket content + * For now by shift copy of all data (not very efficient to be + * revised */ + while (i < socket->read_data_size) { + socket->read_data[i - size] = socket->read_data[i]; + i++; + } + + socket->read_data_size -= size; + } + } else { + debug_if(_ism_debug, "ISM43362Interface: Nothing in buffer\r\n"); + } + + debug_if(_ism_debug, "ISM43362Interface: [socket_recv]read_datasize=%d, recv=%d\r\n", socket->read_data_size, recv); + _mutex.unlock(); + + if (recv > 0) { + return recv; + } else { + debug_if(_ism_debug, "ISM43362Interface: sock_recv returns WOULD BLOCK\r\n"); + return NSAPI_ERROR_WOULD_BLOCK; + } +} + +int ISM43362Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) +{ + _mutex.lock(); + struct ISM43362_socket *socket = (struct ISM43362_socket *)handle; + + if (socket->connected && socket->addr != addr) { + _ism.setTimeout(ISM43362_MISC_TIMEOUT); + if (!_ism.close(socket->id)) { + debug_if(_ism_debug, "ISM43362Interface: socket_send ERROR\r\n"); + _mutex.unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + socket->connected = false; + _ids[socket->id] = false; + _socket_obj[socket->id] = 0; + } + + if (!socket->connected) { + int err = socket_connect_nolock(socket, addr); + if (err < 0) { + _mutex.unlock(); + return err; + } + socket->addr = addr; + } + + int ret = socket_send_nolock(socket, data, size); + + _mutex.unlock(); + + return ret; +} + +int ISM43362Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + int ret = socket_recv(handle, data, size); + _mutex.lock(); + if ((ret >= 0) && addr) { + struct ISM43362_socket *socket = (struct ISM43362_socket *)handle; + *addr = socket->addr; + } + _mutex.unlock(); + return ret; +} + +void ISM43362Interface::socket_attach(void *handle, void (*cb)(void *), void *data) +{ + _mutex.lock(); + struct ISM43362_socket *socket = (struct ISM43362_socket *)handle; + _cbs[socket->id].callback = cb; + _cbs[socket->id].data = data; + _mutex.unlock(); +} + +void ISM43362Interface::event() { + for (int i = 0; i < ISM43362_SOCKET_COUNT; i++) { + if (_cbs[i].callback) { + _cbs[i].callback(_cbs[i].data); + } + } +}
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/ISM43362Interface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362Interface.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,297 @@ +/* ISM43362 implementation of NetworkInterfaceAPI + * Copyright (c) STMicroelectronics 2017 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ISM43362_INTERFACE_H +#define ISM43362_INTERFACE_H + +#include "mbed.h" +#include "ISM43362.h" + + +#define ISM43362_SOCKET_COUNT 4 + +/** ISM43362Interface class + * Implementation of the NetworkStack for the ISM43362 + */ +class ISM43362Interface : public NetworkStack, public WiFiInterface +{ +public: + /** ISM43362Interface lifetime + * @param debug Enable debugging + */ + ISM43362Interface(bool debug = false); + + /** Start the interface + * + * Attempts to connect to a WiFi network. Requires ssid and passphrase to be set. + * If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned. + * + * @return 0 on success, negative error code on failure + */ + virtual int connect(); + + /** Start the interface + * + * Attempts to connect to a WiFi network. + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE) + * @param channel This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED + * @return 0 on success, or error code on failure + */ + virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE, + uint8_t channel = 0); + + /** Translates a hostname to an IP address with specific version + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * + * @param host Hostname to resolve + * @param address Destination for the host SocketAddress + * @param version IP version of address to resolve, NSAPI_UNSPEC indicates + * version is chosen by the stack (defaults to NSAPI_UNSPEC) + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC); + + /** Set the WiFi network credentials + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection + * (defaults to NSAPI_SECURITY_NONE) + * @return 0 on success, or error code on failure + */ + virtual int set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE); + + /** Set the WiFi network channel - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0) + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual int set_channel(uint8_t channel); + + /** Stop the interface + * @return 0 on success, negative on failure + */ + virtual int disconnect(); + + /** Get the internally stored IP address + * @return IP address of the interface or null if not yet connected + */ + virtual const char *get_ip_address(); + + /** Get the internally stored MAC address + * @return MAC address of the interface + */ + virtual const char *get_mac_address(); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been recieved + */ + virtual const char *get_gateway(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been recieved + */ + virtual const char *get_netmask(); + + /** Gets the current radio signal strength for active connection + * + * @return Connection strength in dBm (negative value) + */ + virtual int8_t get_rssi(); + + /** Scan for available networks + * + * This function will block. + * + * @param ap Pointer to allocated array to store discovered AP + * @param count Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + virtual int scan(WiFiAccessPoint *res, unsigned count); + + /** Translates a hostname to an IP address with specific version + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * + * @param address Destination for the host SocketAddress + * @param host Hostname to resolve + * @param version IP version of address to resolve, NSAPI_UNSPEC indicates + * version is chosen by the stack (defaults to NSAPI_UNSPEC) + * @return 0 on success, negative error code on failure + */ + using NetworkInterface::gethostbyname; + + /** Add a domain name server to list of servers to query + * + * @param addr Destination for the host address + * @return 0 on success, negative error code on failure + */ + using NetworkInterface::add_dns_server; + +protected: + /** Open a socket + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure + */ + virtual int socket_open(void **handle, nsapi_protocol_t proto); + + /** Close the socket + * @param handle Socket handle + * @return 0 on success, negative on failure + * @note On failure, any memory associated with the socket must still + * be cleaned up + */ + virtual int socket_close(void *handle); + + /** Bind a server socket to a specific port + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + virtual int socket_bind(void *handle, const SocketAddress &address); + + /** Start listening for incoming connections + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return 0 on success, negative on failure + */ + virtual int socket_listen(void *handle, int backlog); + + /** Connects this TCP socket to the server + * @param handle Socket handle + * @param address SocketAddress to connect to + * @return 0 on success, negative on failure + */ + virtual int socket_connect(void *handle, const SocketAddress &address); + + /** Accept a new connection. + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return 0 on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_accept(void *handle, void **socket, SocketAddress *address); + + /** Send data to the remote host + * @param handle Socket handle + * @param data The buffer to send to the host + * @param size The length of the buffer to send + * @return Number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_send(void *handle, const void *data, unsigned size); + + /** Receive data from the remote host + * @param handle Socket handle + * @param data The buffer in which to store the data received from the host + * @param size The maximum length of the buffer + * @return Number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_recv(void *handle, void *data, unsigned size); + + /** Send a packet to a remote endpoint + * @param handle Socket handle + * @param address The remote SocketAddress + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return The number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size); + + /** Receive a packet from a remote endpoint + * @param handle Socket handle + * @param address Destination for the remote SocketAddress or null + * @param buffer The buffer for storing the incoming packet data + * If a packet is too long to fit in the supplied buffer, + * excess bytes are discarded + * @param size The length of the buffer + * @return The number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); + + /** Register a callback on state change of the socket + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + * @note Callback may be called in an interrupt context. + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); + + /** Provide access to the NetworkStack object + * + * @return The underlying NetworkStack object + */ + virtual NetworkStack *get_stack() + { + return this; + } + +private: + ISM43362 _ism; + bool _ids[ISM43362_SOCKET_COUNT]; + uint32_t _socket_obj[ISM43362_SOCKET_COUNT]; // store addresses of socket handles + Mutex _mutex; + Thread thread_read_socket; + char ap_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */ + ism_security_t ap_sec; + uint8_t ap_ch; + char ap_pass[64]; /* The longest allowed passphrase */ + + bool _ism_debug; + + void event(); + struct { + void (*callback)(void *); + void *data; + } _cbs[ISM43362_SOCKET_COUNT]; + + /** Function called by the socket read thread to check if data is available on the wifi module + * + */ + virtual void socket_check_read(); + int socket_send_nolock(void *handle, const void *data, unsigned size); + int socket_connect_nolock(void *handle, const SocketAddress &addr); + +}; + +#endif
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,29 @@ +# ISM43362 WiFi driver for mbed-os +The mbed OS driver for the ISM43362 WiFi module + +## Currently supported platforms +ISM43362 module is soldered on the following platforms from STMicroelectronics +* DISCO_L475VG_IOT01A +* DISCO_F413ZH + +## Configuration + +Correct pins have already been configured for both supported platforms. + +Here is configured pins: + +- MBED_CONF_ISM43362_WIFI_MISO : spi-miso pin for the ism43362 connection +- MBED_CONF_ISM43362_WIFI__MOSI : spi-mosi pin for the ism43362 connection +- MBED_CONF_ISM43362_WIFI_SPI_SCLK : spi-clock pin for the ism43362 connection +- MBED_CONF_ISM43362_WIFI_SPI_NSS : spi-nss pin for the ism43362 connection +- MBED_CONF_ISM43362_WIFI_RESET : Reset pin for the ism43362 wifi module +- MBED_CONF_ISM43362_WIFI_DATAREADY : Data Ready pin for the ism43362 wifi module +- MBED_CONF_ISM43362_WIFI_WAKEUP : Wakeup pin for the ism43362 wifi module + + +## Firmware version +This driver supports ISM43362-M3G-L44-SPI,C3.5.2.3.BETA9 and C3.5.2.2 firmware version + +## wifi module FW update +For more information about the wifi FW version, refer to the detailed procedure in +http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-embedded-software-expansion/x-cube-azure.html
diff -r 000000000000 -r 119624335925 easy-connect/wifi-ism43362/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,53 @@ +{ + "name": "ism43362", + "config": { + "wifi-miso": { + "help": "SPI-MISO connection to external device", + "value": "NC" + }, + "wifi-mosi": { + "help": "SPI-MOSI connection to external device", + "value": "NC" + }, + "wifi-sclk": { + "help": "SPI-CLOCK connection to external device", + "value": "NC" + }, + "wifi-nss": { + "help": "SPI chip select of external device", + "value": "NC" + }, + "wifi-reset": { + "help": "ISM43362 reset", + "value": "NC" + }, + "wifi-dataready": { + "help": "ISM43362 dataready", + "value": "NC" + }, + "wifi-wakeup": { + "help": "ISM43362 wakeup", + "value": "NC" + } + }, + "target_overrides": { + "DISCO_F413ZH": { + "ism43362.wifi-miso": "PB_4", + "ism43362.wifi-mosi": "PB_5", + "ism43362.wifi-sclk": "PB_12", + "ism43362.wifi-nss": "PG_11", + "ism43362.wifi-reset": "PH_1", + "ism43362.wifi-dataready": "PG_12", + "ism43362.wifi-wakeup": "PB_15" + }, + "DISCO_L475VG_IOT01A": { + "ism43362.wifi-miso": "PC_11", + "ism43362.wifi-mosi": "PC_12", + "ism43362.wifi-sclk": "PC_10", + "ism43362.wifi-nss": "PE_0", + "ism43362.wifi-reset": "PE_8", + "ism43362.wifi-dataready": "PE_1", + "ism43362.wifi-wakeup": "PB_13" + } + } +}
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/#376b457a84631f11178b895bee5c790ff6c3d768
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +376b457a84631f11178b895bee5c790ff6c3d768
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +b28712c890b73be18884cd323aa884310cf85e3b
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/index Binary file easy-connect/wifi-x-nucleo-idw01m1/.git/index has changed
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 b28712c890b73be18884cd323aa884310cf85e3b www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322724 +0000 clone: from https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/ +b28712c890b73be18884cd323aa884310cf85e3b 376b457a84631f11178b895bee5c790ff6c3d768 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322725 +0000 checkout: moving from master to 376b457a84631f11178b895bee5c790ff6c3d768
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 b28712c890b73be18884cd323aa884310cf85e3b www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322724 +0000 clone: from https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 b28712c890b73be18884cd323aa884310cf85e3b www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322724 +0000 clone: from https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/objects/pack/pack-4ea3e0be59e8a7dee78f0864181543eafe0344c7.idx Binary file easy-connect/wifi-x-nucleo-idw01m1/.git/objects/pack/pack-4ea3e0be59e8a7dee78f0864181543eafe0344c7.idx has changed
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/objects/pack/pack-4ea3e0be59e8a7dee78f0864181543eafe0344c7.pack Binary file easy-connect/wifi-x-nucleo-idw01m1/.git/objects/pack/pack-4ea3e0be59e8a7dee78f0864181543eafe0344c7.pack has changed
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,40 @@ +# pack-refs with: peeled +b28712c890b73be18884cd323aa884310cf85e3b refs/remotes/origin/master +f7c2b16169949700bb3a506600203c7ea7b19483 refs/tags/release_v0.0.0 +ee306fa5f5edeceae145e6ea05b00d62c72712da refs/tags/release_v0.1.0 +d88bd648020b8cfbfed69d848380105540af0ab6 refs/tags/release_v0.1.1 +a9bc601856a3c5fc43e553907ba5355e03ec0a44 refs/tags/release_v0.1.2 +e31ca1f09ba24461d343d6233ebb4df3701aa974 refs/tags/release_v0.1.3 +ce9afc1b796f64be94a8c51919259a8531f2c388 refs/tags/release_v0.2.0 +7d74d5822be0e48d704f94b61db01095acef5276 refs/tags/release_v0.2.1 +6ce14f1f186e844e452a090fc93f2955ffa30ced refs/tags/release_v0.3.0 +5831f72291b7bb5b9789dd0bf623069df86819ab refs/tags/release_v0.3.1 +f28c51f3e8e44211674a7d5c7409fa08b62e956a refs/tags/release_v0.3.2 +82ed479b9a5650b5bcb354aab34bc510741d3a76 refs/tags/release_v1.0.0-rc1 +cefb1b79ad088442c523a72385ab9c179e30848e refs/tags/release_v1.0.0-rc2 +0d182c111485d34d53ad4580e289d8bc44d6d454 refs/tags/release_v1.0.0-rc3 +5dd2b7d994c8461f550e85a40106151498fb6006 refs/tags/release_v1.0.0-rc4 +f7c2b16169949700bb3a506600203c7ea7b19483 refs/tags/v0.0.0 +ee306fa5f5edeceae145e6ea05b00d62c72712da refs/tags/v0.1.0 +d88bd648020b8cfbfed69d848380105540af0ab6 refs/tags/v0.1.1 +a9bc601856a3c5fc43e553907ba5355e03ec0a44 refs/tags/v0.1.2 +e31ca1f09ba24461d343d6233ebb4df3701aa974 refs/tags/v0.1.3 +ce9afc1b796f64be94a8c51919259a8531f2c388 refs/tags/v0.2.0 +7d74d5822be0e48d704f94b61db01095acef5276 refs/tags/v0.2.1 +6ce14f1f186e844e452a090fc93f2955ffa30ced refs/tags/v0.3.0 +5831f72291b7bb5b9789dd0bf623069df86819ab refs/tags/v0.3.1 +f28c51f3e8e44211674a7d5c7409fa08b62e956a refs/tags/v0.3.2 +82ed479b9a5650b5bcb354aab34bc510741d3a76 refs/tags/v0.4.0 +cefb1b79ad088442c523a72385ab9c179e30848e refs/tags/v0.4.1 +0d182c111485d34d53ad4580e289d8bc44d6d454 refs/tags/v0.4.2 +5dd2b7d994c8461f550e85a40106151498fb6006 refs/tags/v0.4.3 +8c3a3fbbdc3d8e604127f6d06645d93f691a592a refs/tags/v1.0.0 +974ecf7ac236db300e30981f2e00b802007795b7 refs/tags/v1.1.0 +d24c1a0d24fb9c640ffd80a82c5a132adb28a277 refs/tags/v1.1.1 +e567dffd5831f7635465b8022105995296f78ef2 refs/tags/v1.1.2 +8877938af9c1b01ea777e42a5b74f75eef26f362 refs/tags/v1.1.3 +b1c6d9284db969b3c140affba2afb991d754e5e0 refs/tags/v1.1.4 +15026eca242707d8c1f65da4d9b1b1d4fa4c7161 refs/tags/v1.1.5 +35fc005f6fc60dedff4728e77d5a697408689aeb refs/tags/v1.1.6 +8482339d91b028dfa048528dc3c50bb7b0789968 refs/tags/v1.1.7 +b8348c58a9e6f80263f43219c56f90b81d8717cc refs/tags/v1.1.8
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +b28712c890b73be18884cd323aa884310cf85e3b
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/.gitignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/.gitignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ +BUILD +TESTS +.mbed
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/BlockExecuter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/BlockExecuter.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,22 @@ +#ifndef BLOCK_EXEC_H +#define BLOCK_EXEC_H + +#include "mbed.h" + +/* Helper class to execute something whenever entering/leaving a basic block */ +class BlockExecuter { +public: + BlockExecuter(Callback<void()> exit_cb, Callback<void()> enter_cb = Callback<void()>()) : + _exit_cb(exit_cb) { + if((bool)enter_cb) enter_cb(); + } + + ~BlockExecuter(void) { + _exit_cb(); + } + +private: + Callback<void()> _exit_cb; +}; + +#endif //BLOCK_EXEC_H
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,68 @@ +# Prototype Driver for STM Wi-Fi Expansion Boards based on the SPWFxx Module for STM32 Nucleo # + +## Currently supported expansion boards + * [X-NUCLEO-IDW01M1](http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-connect-hw/x-nucleo-idw01m1.html), by setting `mbed` configuration variable `idw0xx1.expansion-board` to value `IDW01M1` + * [X-NUCLEO-IDW04A1](http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-connect-hw/x-nucleo-idw04a1.html), by setting `mbed` configuration variable `idw0xx1.expansion-board` to value `IDW04A1`. You might also need to define macro `IDW04A1_WIFI_HW_BUG_WA` _(see beyond)_. + +## Configuration examples + +### Generic concepts + +For the ones, which might be less familiar with the **"The mbed configuration system"** in general, here is a [link](https://docs.mbed.com/docs/mbed-os-handbook/en/latest/advanced/config_system/) which points to the latest version of the respective _mbed OS 5 handbook tutorial_. + +Furthermore, with respect to this driver, pls. refer to files [`mbed_app_idw01m1.json`](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/blob/master/mbed_app_idw01m1.json) and [`mbed_app_idw04a1.json`](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/blob/master/mbed_app_idw04a1.json) regarding additional reference for what is explained beyond. + +### IDW01M1 + +Add the following lines to the `target_overrides`-section of your `mbed_app.json` file. + +``` json + "idw0xx1.expansion-board": "IDW01M1", + "drivers.uart-serial-txbuf-size": 512, + "drivers.uart-serial-rxbuf-size": 512 +``` + +`IDW01M1` is the default value in the [`mbed_lib.json`](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/blob/master/mbed_lib.json) file, so setting the expansion board is not mandatory for `IDW01M1`, while setting the TX & RX buffer sizes is highly recommended. + +### IDW04A1 + +Add the following lines to the `target_overrides`-section of your `mbed_app.json` file. + +``` json + "idw0xx1.expansion-board": "IDW04A1", + "drivers.uart-serial-txbuf-size": 512, + "drivers.uart-serial-rxbuf-size": 512 +``` + +### Further configuration macros + +All configuration options mentioned in this section are optional and when required have to be added to the `macros`-section of your `mbed_app.json` file, e.g.: + +``` json + "macros": [..., "IDW04A1_WIFI_HW_BUG_WA", "SPWFSAXX_RESET_PIN=D7"] +``` + +Beyond you can find the list of available configuration macros each with a short explanation: + * `IDW04A1_WIFI_HW_BUG_WA`: activates the HW bug workaround for `IDW04A1` + * `SPWFSAXX_WAKEUP_PIN`: defines module wakeup pin _(requires value)_ + * `SPWFSAXX_RESET_PIN`: defines module reset pin _(requires value)_ + * `SPWFSAXX_RTS_PIN`: defines RTS pin of the UART device used _(requires value)_ + * `SPWFSAXX_CTS_PIN`: defines CTS pin of the UART device used _(requires value)_ + +**Note**: if the values of both `SPWFSAXX_RTS_PIN` and `SPWFSAXX_CTS_PIN` are different from `NC`, hardware flow control - if available on your development board - will be enabled on the used UART device (provided you are using `mbed-os` version greater than or equal to `v5.7.0`). + + +## Firmware upgrade + +Please make sure that you are using the latest firmware available for the expansion boards. For information on how to perform a FW upgrade you may refer to [X-CUBE-WIFI1](http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-embedded-software-expansion/x-cube-wifi1.html), especially to document **"X-NUCLEO-IDW0xx1- FW upgrading over UART_v1.2.pdf"** which is contained within folder **"Documentation"** of the X-CUBE-WIFI1 software archive you need to download. + +The actual firmware `.bin` or `.hex` files can be found under +- [STSW-WIFI001](http://www.st.com/content/st_com/en/products/embedded-software/wireless-connectivity-software/stsw-wifi001.html) _for what concerns expansion board_ X-NUCLEO-IDW01M1 _and under_ +- [STSW-WIFI004](http://www.st.com/content/st_com/en/products/embedded-software/wireless-connectivity-software/stsw-wifi004.html) _when considering_ X-NUCLEO-IDW04A1. + + +## Known limitations + + * Like explained in issue [#11](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/issues/11), sockets might fail to close in case they are connected to a streaming server (e.g. a [RFC 864](https://tools.ietf.org/html/rfc864) test server). + * As highlighted by issue [#13](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/issues/13), the module FW limits the maximum segment size for TCP to 730 bytes, while the maximum UDP datagram length might even be further limited (but usually is also equal to 730 bytes). + \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SPWFSA01/SPWFSA01.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SPWFSA01/SPWFSA01.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,284 @@ +/* SPWFSA01 Device + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SPWFSA01.h" +#include "SpwfSAInterface.h" +#include "mbed_debug.h" + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW01M1 + +SPWFSA01::SPWFSA01(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset) +: SPWFSAxx(tx, rx, rts, cts, ifce, debug, wakeup, reset) { +} + +bool SPWFSA01::open(const char *type, int* spwf_id, const char* addr, int port) +{ + int socket_id; + int value; + int trials; + + if(!_parser.send("AT+S.SOCKON=%s,%d,%s,ind", addr, port, type)) + { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA01::open`: error opening socket (%d)\r\n", __LINE__); + return false; + } + + /* handle both response possibilities here before returning + * otherwise module seems to remain in inconsistent state. + */ + + /* wait for first character */ + trials = 0; + while((value = _parser.getc()) < 0) { + if(trials++ > SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + } + + if(value != _cr_) { // Note: this is different to what the spec exactly says + debug_if(_dbg_on, "\r\nSPWF> error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + + if(!_recv_delim_lf()) { // Note: this is different to what the spec exactly says + debug_if(_dbg_on, "\r\nSPWF> error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + + value = _parser.getc(); + switch(value) { + case ' ': + if(_parser.recv("ID: %d\n", &socket_id) + && _recv_ok()) { + debug_if(_dbg_on, "AT^ ID: %d\r\n", socket_id); + + *spwf_id = socket_id; + return true; + } else { + empty_rx_buffer(); + } + break; + case 'E': + if(_parser.recv("RROR: %255[^\n]\n", _msg_buffer) && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ ERROR: %s (%d)\r\n", _msg_buffer, __LINE__); + } else { + debug_if(_dbg_on, "\r\nSPWF> error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + } + break; + default: + debug_if(_dbg_on, "\r\nSPWF> error opening socket (value=%d, %d)\r\n", value, __LINE__); + break; + } + + return false; +} + +int SPWFSA01::_read_in(char* buffer, int spwf_id, uint32_t amount) { + int ret = -1; + + MBED_ASSERT(buffer != NULL); + + /* block asynchronous indications */ + if(!_winds_off()) { + return -1; + } + + /* read in data */ + if(_parser.send("AT+S.SOCKR=%d,%u", spwf_id, (unsigned int)amount)) { + /* set high timeout */ + _parser.set_timeout(SPWF_READ_BIN_TIMEOUT); + /* read in binary data */ + int read = _parser.read(buffer, amount); + /* reset timeout value */ + _parser.set_timeout(_timeout); + if(read > 0) { + if(_recv_ok()) { + ret = amount; + + /* remove from pending sizes + * (MUST be done before next async indications handling (e.g. `_winds_on()`)) */ + _remove_pending_pkt_size(spwf_id, amount); + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to receive OK (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to read binary data (%u:%d), (%s, %d)\r\n", amount, read, __func__, __LINE__); + empty_rx_buffer(); + } + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to send SOCKR (%s, %d)\r\n", __func__, __LINE__); + } + + debug_if(_dbg_on, "\r\nSPWF> %s():\t%d:%d\r\n", __func__, spwf_id, amount); + + /* unblock asynchronous indications */ + _winds_on(); + + return ret; +} + +/* betzw - TODO: improve performance! */ +bool SPWFSA01::_recv_ap(nsapi_wifi_ap_t *ap) +{ + bool ret; + unsigned int channel; + int trials; + + ap->security = NSAPI_SECURITY_UNKNOWN; + + /* check for end of list */ + if(_recv_delim_cr_lf()) { + return false; + } + + /* run to 'horizontal tab' */ + trials = 0; + while(_parser.getc() != '\x09') { + if(trials++ > SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + } + + /* read in next line */ + ret = _parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf(); + + /* parse line - first phase */ + if(ret) { + int val = sscanf(_msg_buffer, + " %*s %hhx:%hhx:%hhx:%hhx:%hhx:%hhx CHAN: %u RSSI: %hhd SSID: \'%*255[^\']\'", + &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], &ap->bssid[5], + &channel, &ap->rssi); + if(val < 8) { + ret = false; + } + } + + /* parse line - second phase */ + if(ret) { // ret == true + char value; + char *rest, *first, *last; + + /* decide about position of `CAPS:` */ + first = strchr(_msg_buffer, '\''); + if(first == NULL) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + last = strrchr(_msg_buffer, '\''); + if((last == NULL) || (last < (first+1))) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + rest = strstr(last, "CAPS:"); + if(rest == NULL) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + + /* substitute '\'' with '\0' */ + *last = '\0'; + + /* copy values */ + memcpy(&ap->ssid, first+1, sizeof(ap->ssid)-1); + ap->ssid[sizeof(ap->ssid)-1] = '\0'; + ap->channel = channel; + + /* skip `CAPS: 0421 ` */ + if(strlen(rest) < 11) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + rest += 11; + + /* get next character */ + value = *rest++; + if(value != 'W') { // no security + ap->security = NSAPI_SECURITY_NONE; + return true; + } + + /* determine security */ + { + char buffer[10]; + + if(!(sscanf(rest, "%s%*[\x20]", (char*)&buffer) > 0)) { // '\0x20' == <space> + return true; + } else if(strncmp("EP", buffer, 10) == 0) { + ap->security = NSAPI_SECURITY_WEP; + return true; + } else if(strncmp("PA2", buffer, 10) == 0) { + ap->security = NSAPI_SECURITY_WPA2; + return true; + } else if(strncmp("PA", buffer, 10) != 0) { + return true; + } + + /* got a "WPA", check for "WPA2" */ + rest += strlen(buffer); + value = *rest++; + if(value == '\0') { // no further protocol + ap->security = NSAPI_SECURITY_WPA; + return true; + } else { // assume "WPA2" + ap->security = NSAPI_SECURITY_WPA_WPA2; + return true; + } + } + } else { // ret == false + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + } + + return ret; +} + +int SPWFSA01::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned cnt = 0; + nsapi_wifi_ap_t ap; + + if (!_parser.send("AT+S.SCAN=a,s")) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + while (_recv_ap(&ap)) { + if (cnt < limit) { + res[cnt] = WiFiAccessPoint(ap); + } + + cnt++; + if (limit != 0 && cnt >= limit) { + break; + } + } + + if(!_recv_ok()) { + empty_rx_buffer(); + } + + return cnt; +} + +#endif // MBED_CONF_IDW0XX1_EXPANSION_BOARD
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SPWFSA01/SPWFSA01.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SPWFSA01/SPWFSA01.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,66 @@ +/* SPWFSA01 Device + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SPWFSA01_H +#define SPWFSA01_H + +#include "mbed.h" +#include "ATCmdParser.h" +#include "BlockExecuter.h" + +#include "./spwfsa01_at_strings.h" +#include "../SPWFSAxx.h" + +class SpwfSAInterface; + +/** SPWFSA01 Interface class. + This is an interface to a SPWFSA01 module. + */ +class SPWFSA01 : public SPWFSAxx +{ +public: + SPWFSA01(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset); + + /** + * Open a socketed connection + * + * @param type the type of socket to open "u" (UDP) or "t" (TCP) + * @param id id to get the new socket number, valid 0-7 + * @param port port to open connection with + * @param addr the IP address of the destination + * @return true only if socket opened successfully + */ + bool open(const char *type, int* id, const char* addr, int port); + + /** Scan for available networks + * + * @param ap Pointer to allocated array to store discovered AP + * @param limit Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + nsapi_size_or_error_t scan(WiFiAccessPoint *res, unsigned limit); + +private: + bool _recv_ap(nsapi_wifi_ap_t *ap); + + virtual int _read_in(char*, int, uint32_t); +}; + +#endif // SPWFSA01_H
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SPWFSA01/spwfsa01_at_strings.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SPWFSA01/spwfsa01_at_strings.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,58 @@ +#ifndef SPWFSAXX_AT_STRINGS_H +#define SPWFSAXX_AT_STRINGS_H + +#if defined(TARGET_FF_MORPHO) + +#if !defined(SPWFSAXX_WAKEUP_PIN) +#define SPWFSAXX_WAKEUP_PIN PC_8 // A3 +#endif // !defined(SPWFSAXX_WAKEUP_PIN) +#if !defined(SPWFSAXX_RESET_PIN) +#define SPWFSAXX_RESET_PIN PC_12 // D7 / NC +#endif // !defined(SPWFSAXX_RESET_PIN) + +#else // !defined(TARGET_FF_MORPHO) + +#if !defined(SPWFSAXX_WAKEUP_PIN) +#define SPWFSAXX_WAKEUP_PIN NC // A3 +#endif // !defined(SPWFSAXX_WAKEUP_PIN) +#if !defined(SPWFSAXX_RESET_PIN) +#define SPWFSAXX_RESET_PIN NC // D7 / NC +#endif // !defined(SPWFSAXX_RESET_PIN) + +#endif // !defined(TARGET_FF_MORPHO) + +#define SPWFXX_SEND_RECV_PKTSIZE (730) + +#define SPWFXX_OOB_ERROR "ERROR:" // "AT-S.ERROR:" + +#define SPWFXX_RECV_OK "OK\n" // "AT-S.OK\n" +#define SPWFXX_RECV_WIFI_UP "+WIND:24:WiFi Up:%u.%u.%u.%u\n" // "+WIND:24:WiFi Up:%*u:%u.%u.%u.%u\n" +#define SPWFXX_RECV_IP_ADDR "# ip_ipaddr = %u.%u.%u.%u\n" // "AT-S.Var:ip_ipaddr=%u.%u.%u.%u\n" +#define SPWFXX_RECV_GATEWAY "# ip_gw = %u.%u.%u.%u\n" // "AT-S.Var:ip_gw=%u.%u.%u.%u\n" +#define SPWFXX_RECV_NETMASK "# ip_netmask = %u.%u.%u.%u\n" // "AT-S.Var:ip_netmask=%u.%u.%u.%u\n" +#define SPWFXX_RECV_RX_RSSI "# 0.rx_rssi = %d\n" // "AT-S.Var:0.rx_rssi=%d\n" +#define SPWFXX_RECV_MAC_ADDR "# nv_wifi_macaddr = %x:%x:%x:%x:%x:%x\n" // "AT-S.Var:nv_wifi_macaddr=%x:%x:%x:%x:%x:%x\n" +#define SPWFXX_RECV_DATALEN " DATALEN: %u\n" // "AT-S.Query:%u\n" +#define SPWFXX_RECV_PENDING_DATA ":%d:%d\n" // "::%u:%*u:%u\n" +#define SPWFXX_RECV_SOCKET_CLOSED ":%d\n" // ":%u:%*u\n" + +#define SPWFXX_SEND_FWCFG "AT&F" // "AT+S.FCFG" +#define SPWFXX_SEND_DISABLE_LE "AT+S.SCFG=localecho1,0" // "AT+S.SCFG=console_echo,0" +#define SPWFXX_SEND_DSPLY_CFGV "AT&V" // "AT+S.GCFG" +#define SPWFXX_SEND_GET_CONS_STATE "AT+S.GCFG=console1_enabled" // "AT+S.GCFG=console_enabled" +#define SPWFXX_SEND_GET_CONS_SPEED "AT+S.GCFG=console1_speed" // "AT+S.GCFG=console_speed" +#define SPWFXX_SEND_GET_HWFC_STATE "AT+S.GCFG=console1_hwfc" // "AT+S.GCFG=console_hwfc" +#define SPWFXX_SEND_GET_CONS_DELIM "AT+S.GCFG=console1_delimiter" // "AT+S.GCFG=console_delimiter" +#define SPWFXX_SEND_GET_CONS_ERRS "AT+S.GCFG=console1_errs" // "AT+S.GCFG=console_errs" +#define SPWFXX_SEND_DISABLE_FC "AT+S.SCFG=console1_hwfc,0" // "AT+S.SCFG=console_hwfc,0" +#define SPWFXX_SEND_ENABLE_FC "AT+S.SCFG=console1_hwfc,1" // "AT+S.SCFG=console_hwfc,1" +#define SPWFXX_SEND_SW_RESET "AT+CFUN=1" // "AT+S.RESET" +#define SPWFXX_SEND_SAVE_SETTINGS "AT&W" // "AT+S.WCFG" +#define SPWFXX_SEND_WIND_OFF_HIGH "AT+S.SCFG=wind_off_high," // "AT+S.SCFG=console_wind_off_high," +#define SPWFXX_SEND_WIND_OFF_MEDIUM "AT+S.SCFG=wind_off_medium," // "AT+S.SCFG=console_wind_off_medium," +#define SPWFXX_SEND_WIND_OFF_LOW "AT+S.SCFG=wind_off_low," // "AT+S.SCFG=console_wind_off_low," + +#define SPWFXX_WINDS_HIGH_ON "0x00000000" // "0x00100000" +#define SPWFXX_WINDS_MEDIUM_ON "0x00000000" // "0x80000000" + +#endif // SPWFSAXX_AT_STRINGS_H
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SPWFSA04/SPWFSA04.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SPWFSA04/SPWFSA04.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,318 @@ +/* SPWFSA04 Device + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SPWFSA04.h" +#include "SpwfSAInterface.h" +#include "mbed_debug.h" + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + +SPWFSA04::SPWFSA04(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset) +: SPWFSAxx(tx, rx, rts, cts, ifce, debug, wakeup, reset) { +} + +bool SPWFSA04::open(const char *type, int* spwf_id, const char* addr, int port) +{ + int socket_id; + int value; + int trials; + + if(!_parser.send("AT+S.SOCKON=%s,%d,NULL,%s", addr, port, type)) + { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + return false; + } + + /* handle both response possibilities here before returning + * otherwise module seems to remain in inconsistent state. + */ + + if(!_parser.recv("AT-S.")) { // get prefix + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + + /* wait for next character */ + trials = 0; + while((value = _parser.getc()) < 0) { + if(++trials >= SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + } + + switch(value) { + case 'O': + /* get next character */ + value = _parser.getc(); + if(value != 'n') { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d) (%d, \'%c\')\r\n", + __LINE__, value, value); + empty_rx_buffer(); + return false; + } + + /* get socket id */ + if(!(_parser.recv(":%*u.%*u.%*u.%*u:%d\n", &socket_id) + && _recv_delim_lf() + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + debug_if(_dbg_on, "AT^ AT-S.On:%s:%d\r\n", addr, socket_id); + + *spwf_id = socket_id; + return true; + case 'E': + int err_nr; + if(_parser.recv("RROR:%d:%255[^\n]\n", &err_nr, _msg_buffer) && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ AT-S.ERROR:%d:%s (%d)\r\n", err_nr, _msg_buffer, __LINE__); + } else { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + } + break; + default: + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d) (%d, \'%c\')\r\n", + __LINE__, value, value); + empty_rx_buffer(); + break; + } + + return false; +} + +int SPWFSA04::_read_in(char* buffer, int spwf_id, uint32_t amount) { + int ret = -1; + int received, cumulative; + + MBED_ASSERT(buffer != NULL); + + /* block asynchronous indications */ + if(!_winds_off()) { + return -1; + } + + /* read in data */ + if(_parser.send("AT+S.SOCKR=%d,%d", spwf_id, (unsigned int)amount)) { + if(!(_parser.recv("AT-S.Reading:%d:%d\n", &received, &cumulative) && + _recv_delim_lf())) { + debug_if(_dbg_on, "\r\nSPWF> failed to receive AT-S.Reading (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } else { + /* set high timeout */ + _parser.set_timeout(SPWF_READ_BIN_TIMEOUT); + /* read in binary data */ + int read = _parser.read(buffer, amount); + /* reset timeout value */ + _parser.set_timeout(_timeout); + if(read > 0) { + if(_recv_ok()) { + ret = amount; + + /* remove from pending sizes + * (MUST be done before next async indications handling (e.g. `_winds_on()`)) */ + _remove_pending_pkt_size(spwf_id, amount); + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to receive OK (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to read binary data (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } + } + } else { + debug_if(_dbg_on, "%s(%d): failed to send SOCKR\r\n", __func__, __LINE__); + } + + debug_if(_dbg_on, "\r\nSPWF> %s():\t%d:%d\r\n", __func__, spwf_id, amount); + + /* unblock asynchronous indications */ + _winds_on(); + + return ret; +} + +/* betzw - TODO: improve performance! */ +bool SPWFSA04::_recv_ap(nsapi_wifi_ap_t *ap) +{ + bool ret; + int curr; + unsigned int channel; + int trials; + + ap->security = NSAPI_SECURITY_UNKNOWN; + + /* determine list end */ + curr = _parser.getc(); + if(curr == 'A') { // assume end of list ("AT-S.OK") + if(!(_parser.recv("T-S.OK\n") && _recv_delim_lf())) { + empty_rx_buffer(); + } + return false; + } + + /* run to 'horizontal tab' */ + trials = 0; + while(_parser.getc() != '\x09') { + if(trials++ > SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + } + + /* read in next line */ + ret = _parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf(); + + /* parse line - first phase */ + if(ret) { + int val = sscanf(_msg_buffer, + " %*s %hhx:%hhx:%hhx:%hhx:%hhx:%hhx CHAN: %u RSSI: %hhd SSID: \'%*255[^\']\'", + &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], &ap->bssid[5], + &channel, &ap->rssi); + if(val < 8) { + ret = false; + } + } + + /* parse line - second phase */ + if(ret) { // ret == true + char value; + char *rest, *first, *last; + + /* decide about position of `CAPS:` */ + first = strchr(_msg_buffer, '\''); + if(first == NULL) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + last = strrchr(_msg_buffer, '\''); + if((last == NULL) || (last < (first+1))) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + rest = strstr(last, "CAPS:"); + if(rest == NULL) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + + /* substitute '\'' with '\0' */ + *last = '\0'; + + /* copy values */ + memcpy(&ap->ssid, first+1, sizeof(ap->ssid)-1); + ap->ssid[sizeof(ap->ssid)-1] = '\0'; + ap->channel = channel; + + /* skip `CAPS: 0421 ` */ + if(strlen(rest) < 11) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + rest += 11; + + /* get next character */ + value = *rest++; + if(value != 'W') { // no security + ap->security = NSAPI_SECURITY_NONE; + return true; + } + + /* determine security */ + { + char buffer[10]; + + if(!(sscanf(rest, "%s%*[\x20]", (char*)&buffer) > 0)) { // '\0x20' == <space> + return true; + } else if(strncmp("EP", buffer, 10) == 0) { + ap->security = NSAPI_SECURITY_WEP; + return true; + } else if(strncmp("PA2", buffer, 10) == 0) { + ap->security = NSAPI_SECURITY_WPA2; + return true; + } else if(strncmp("PA", buffer, 10) != 0) { + return true; + } + + /* got a "WPA", check for "WPA2" */ + rest += strlen(buffer); + value = *rest++; + if(value == '\0') { // no further protocol + ap->security = NSAPI_SECURITY_WPA; + return true; + } else { // assume "WPA2" + ap->security = NSAPI_SECURITY_WPA_WPA2; + return true; + } + } + } else { // ret == false + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } + + return ret; +} + +nsapi_size_or_error_t SPWFSA04::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned int cnt = 0, found; + nsapi_wifi_ap_t ap; + + if (!_parser.send("AT+S.SCAN=s,")) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + if(!(_parser.recv("AT-S.Parsing Networks:%u\n", &found) && _recv_delim_lf())) { + debug_if(_dbg_on, "SPWF> error start network scanning\r\n"); + empty_rx_buffer(); + return NSAPI_ERROR_DEVICE_ERROR; + } + + debug_if(_dbg_on, "AT^ AT-S.Parsing Networks:%u\r\n", found); + + if(found > 0) { + while (_recv_ap(&ap)) { + if (cnt < limit) { + res[cnt] = WiFiAccessPoint(ap); + } + + if (!((limit != 0) && ((cnt + 1) > limit))) { + cnt++; + } + } + } else { + if(!_recv_ok()) { + empty_rx_buffer(); + } + } + + return cnt; +} + +#endif // MBED_CONF_IDW0XX1_EXPANSION_BOARD
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SPWFSA04/SPWFSA04.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SPWFSA04/SPWFSA04.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,66 @@ +/* SPWFSA04 Device + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SPWFSA04_H +#define SPWFSA04_H + +#include "mbed.h" +#include "ATCmdParser.h" +#include "BlockExecuter.h" + +#include "./spwfsa04_at_strings.h" +#include "../SPWFSAxx.h" + +class SpwfSAInterface; + +/** SPWFSA04 Interface class. + This is an interface to a SPWFSA04 module. + */ +class SPWFSA04 : public SPWFSAxx +{ +public: + SPWFSA04(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset); + + /** + * Open a socketed connection + * + * @param type the type of socket to open "u" (UDP) or "t" (TCP) + * @param id id to get the new socket number, valid 0-7 + * @param port port to open connection with + * @param addr the IP address of the destination + * @return true only if socket opened successfully + */ + bool open(const char *type, int* id, const char* addr, int port); + + /** Scan for available networks + * + * @param ap Pointer to allocated array to store discovered AP + * @param limit Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + nsapi_size_or_error_t scan(WiFiAccessPoint *res, unsigned limit); + +private: + bool _recv_ap(nsapi_wifi_ap_t *ap); + + virtual int _read_in(char*, int, uint32_t); +}; + +#endif // SPWFSA04_H
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SPWFSA04/spwfsa04_at_strings.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SPWFSA04/spwfsa04_at_strings.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,65 @@ +#ifndef SPWFSAXX_AT_STRINGS_H +#define SPWFSAXX_AT_STRINGS_H + +/* Define beyond macro if your X-NUCLEO-IDW04A1 expansion board has NOT the `WIFI_RST` HW patch applied on it */ +// #define IDW04A1_WIFI_HW_BUG_WA // delegated to mbed config system + +#if defined(TARGET_FF_ARDUINO) + +#if !defined(SPWFSAXX_WAKEUP_PIN) +#define SPWFSAXX_WAKEUP_PIN A3 +#endif +#if !defined(SPWFSAXX_RESET_PIN) +#ifndef IDW04A1_WIFI_HW_BUG_WA +#define SPWFSAXX_RESET_PIN D7 +#else // IDW04A1_WIFI_HW_PATCH +#define SPWFSAXX_RESET_PIN NC +#endif // !IDW04A1_WIFI_HW_PATCH +#endif + +#else // !defined(TARGET_FF_ARDUINO) + +#if !defined(SPWFSAXX_WAKEUP_PIN) +#define SPWFSAXX_WAKEUP_PIN NC +#endif +#if !defined(SPWFSAXX_RESET_PIN) +#define SPWFSAXX_RESET_PIN NC +#endif + +#endif // !defined(TARGET_FF_ARDUINO) + +#define SPWFXX_SEND_RECV_PKTSIZE (730) + +#define SPWFXX_OOB_ERROR "AT-S.ERROR:" // "ERROR:" + +#define SPWFXX_RECV_OK "AT-S.OK\n" // "OK\n" +#define SPWFXX_RECV_WIFI_UP "+WIND:24:WiFi Up:%*u:%u.%u.%u.%u\n" // "+WIND:24:WiFi Up:%u.%u.%u.%u\n" +#define SPWFXX_RECV_IP_ADDR "AT-S.Var:ip_ipaddr=%u.%u.%u.%u\n" // "# ip_ipaddr = %u.%u.%u.%u\n" +#define SPWFXX_RECV_GATEWAY "AT-S.Var:ip_gw=%u.%u.%u.%u\n" // "# ip_gw = %u.%u.%u.%u\n" +#define SPWFXX_RECV_NETMASK "AT-S.Var:ip_netmask=%u.%u.%u.%u\n" // "# ip_netmask = %u.%u.%u.%u\n" +#define SPWFXX_RECV_RX_RSSI "AT-S.Var:0.rx_rssi=%d\n" // "# 0.rx_rssi = %d\n" +#define SPWFXX_RECV_MAC_ADDR "AT-S.Var:nv_wifi_macaddr=%x:%x:%x:%x:%x:%x\n" // "# nv_wifi_macaddr = %x:%x:%x:%x:%x:%x\n" +#define SPWFXX_RECV_DATALEN "AT-S.Query:%u\n" // " DATALEN: %u\n" +#define SPWFXX_RECV_PENDING_DATA "::%u:%*u:%u\n" // ":%d:%d\n" +#define SPWFXX_RECV_SOCKET_CLOSED ":%u:%*u\n" // ":%d\n" + +#define SPWFXX_SEND_FWCFG "AT+S.FCFG" // "AT&F" +#define SPWFXX_SEND_DISABLE_LE "AT+S.SCFG=console_echo,0" // "AT+S.SCFG=localecho1,0" +#define SPWFXX_SEND_DSPLY_CFGV "AT+S.GCFG" // "AT&V" +#define SPWFXX_SEND_GET_CONS_STATE "AT+S.GCFG=console_enabled" // "AT+S.GCFG=console1_enabled" +#define SPWFXX_SEND_GET_CONS_SPEED "AT+S.GCFG=console_speed" // "AT+S.GCFG=console1_speed" +#define SPWFXX_SEND_GET_HWFC_STATE "AT+S.GCFG=console_hwfc" // "AT+S.GCFG=console1_hwfc" +#define SPWFXX_SEND_GET_CONS_DELIM "AT+S.GCFG=console_delimiter" // "AT+S.GCFG=console1_delimiter" +#define SPWFXX_SEND_GET_CONS_ERRS "AT+S.GCFG=console_errs" // "AT+S.GCFG=console1_errs" +#define SPWFXX_SEND_DISABLE_FC "AT+S.SCFG=console_hwfc,0" // "AT+S.SCFG=console1_hwfc,0" +#define SPWFXX_SEND_ENABLE_FC "AT+S.SCFG=console_hwfc,1" // "AT+S.SCFG=console1_hwfc,1" +#define SPWFXX_SEND_SW_RESET "AT+S.RESET" // "AT+CFUN=1" +#define SPWFXX_SEND_SAVE_SETTINGS "AT+S.WCFG" // "AT&W" +#define SPWFXX_SEND_WIND_OFF_HIGH "AT+S.SCFG=console_wind_off_high," // "AT+S.SCFG=wind_off_high," +#define SPWFXX_SEND_WIND_OFF_MEDIUM "AT+S.SCFG=console_wind_off_medium," // "AT+S.SCFG=wind_off_medium," +#define SPWFXX_SEND_WIND_OFF_LOW "AT+S.SCFG=console_wind_off_low," // "AT+S.SCFG=wind_off_low," + +#define SPWFXX_WINDS_HIGH_ON "0x00100000" // "0x00000000" +#define SPWFXX_WINDS_MEDIUM_ON "0x80000000" // "0x00000000" + +#endif // SPWFSAXX_AT_STRINGS_H
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SPWFSAxx.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SPWFSAxx.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1287 @@ +/* SPWFSAxx Devices + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed_debug.h" + +#include "SpwfSAInterface.h" /* must be included first */ +#include "SPWFSAxx.h" + +static const char out_delim[] = {SPWFSAxx::_cr_, '\0'}; + +SPWFSAxx::SPWFSAxx(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset) +: _serial(tx, rx, SPWFXX_DEFAULT_BAUD_RATE), _parser(&_serial, out_delim), + _wakeup(wakeup, 1), _reset(reset, 1), + _rts(rts), _cts(cts), + _timeout(SPWF_INIT_TIMEOUT), _dbg_on(debug), + _pending_sockets_bitmap(0), + _network_lost_flag(false), + _associated_interface(ifce), + _call_event_callback_blocked(0), + _callback_func(), + _packets(0), _packets_end(&_packets) +{ + memset(_pending_pkt_sizes, 0, sizeof(_pending_pkt_sizes)); + + _serial.sigio(Callback<void()>(this, &SPWFSAxx::_event_handler)); + _parser.debug_on(debug); + _parser.set_timeout(_timeout); + + /* unlikely OOBs */ + _parser.oob("+WIND:5:WiFi Hardware Failure", callback(this, &SPWFSAxx::_wifi_hwfault_handler)); + _parser.oob("+WIND:33:WiFi Network Lost", callback(this, &SPWFSAxx::_network_lost_handler_th)); +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + _parser.oob("+WIND:24:WiFi Up::", callback(this, &SPWFSAxx::_skip_oob)); +#endif + _parser.oob("+WIND:8:Hard Fault", callback(this, &SPWFSAxx::_hard_fault_handler)); + + /* most likely OOBs */ + _parser.oob(SPWFXX_OOB_ERROR, callback(this, &SPWFSAxx::_error_handler)); + _parser.oob("+WIND:58:Socket Closed", callback(this, &SPWFSAxx::_server_gone_handler)); + _parser.oob("+WIND:55:Pending Data", callback(this, &SPWFSAxx::_packet_handler_th)); +} + +bool SPWFSAxx::startup(int mode) +{ + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + /*Reset module*/ + if(!hw_reset()) { + debug_if(_dbg_on, "\r\nSPWF> HW reset failed\r\n"); + return false; + } + + /* factory reset */ + if(!(_parser.send(SPWFXX_SEND_FWCFG) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error restore factory default settings\r\n"); + return false; + } + + /*switch off led*/ + if(!(_parser.send("AT+S.SCFG=blink_led,0") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error stop blinking led (%d)\r\n", __LINE__); + return false; + } + + /*set local echo to 0*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_LE) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error local echo set\r\n"); + return false; + } + + /*set the operational rates*/ + if(!(_parser.send("AT+S.SCFG=wifi_opr_rate_mask,0x003FFFCF") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error setting ht_mode\r\n"); + return false; + } + + /*enable the 802.11n mode*/ + if(!(_parser.send("AT+S.SCFG=wifi_ht_mode,1") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error setting operational rates\r\n"); + return false; + } + + /*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/ + if(!(_parser.send("AT+S.SCFG=wifi_mode,%d", mode) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error WiFi mode set idle (%d)\r\n", __LINE__); + return false; + } + +#if defined(MBED_MAJOR_VERSION) +#if !DEVICE_SERIAL_FC || (MBED_VERSION < MBED_ENCODE_VERSION(5, 7, 0)) + /*disable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n"); + return false; + } +#else // DEVICE_SERIAL_FC && (MBED_VERSION >= MBED_ENCODE_VERSION(5, 7, 0)) + if((_rts != NC) && (_cts != NC)) { + /*enable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_ENABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error enabling HW flow control\r\n"); + return false; + } + + /*configure pins for HW flow control*/ + _serial.set_flow_control(SerialBase::RTSCTS, _rts, _cts); + } else { + /*disable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n"); + return false; + } + } +#endif // DEVICE_SERIAL_FC && (MBED_VERSION >= MBED_ENCODE_VERSION(5, 7, 0)) +#else // !defined(MBED_MAJOR_VERSION) - Assuming `master` branch +#if !DEVICE_SERIAL_FC + /*disable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n"); + return false; + } +#else // DEVICE_SERIAL_FC + if((_rts != NC) && (_cts != NC)) { + /*enable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_ENABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error enabling HW flow control\r\n"); + return false; + } + + /*configure pins for HW flow control*/ + _serial.set_flow_control(SerialBase::RTSCTS, _rts, _cts); + } else { + /*disable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n"); + return false; + } + } +#endif // DEVICE_SERIAL_FC +#endif // !defined(MBED_MAJOR_VERSION) + + /* Disable selected WINDs */ + _winds_on(); + + /* sw reset */ + if(!reset()) { + debug_if(_dbg_on, "\r\nSPWF> SW reset failed (%s, %d)\r\n", __func__, __LINE__); + return false; + } + +#ifndef NDEBUG + if (!(_parser.send(SPWFXX_SEND_GET_CONS_STATE) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting console state\r\n"); + return false; + } + + if (!(_parser.send(SPWFXX_SEND_GET_CONS_SPEED) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting console speed\r\n"); + return false; + } + + if (!(_parser.send(SPWFXX_SEND_GET_HWFC_STATE) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting hwfc state\r\n"); + return false; + } + +#if (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) || defined(IDW01M1_FW_REL_35X) + /* betzw: IDW01M1 FW versions <3.5 seem to have problems with the following two commands. + * For the sake of simplicity, just excluding them for IDW01M1 in general. + */ + if (!(_parser.send(SPWFXX_SEND_GET_CONS_DELIM) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting console delimiter\r\n"); + return false; + } + + if (!(_parser.send(SPWFXX_SEND_GET_CONS_ERRS) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting console error setting\r\n"); + return false; + } +#endif // (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) || defined(IDW01M1_FW_REL_35X) + + if (!(_parser.send("AT+S.GCFG=sleep_enabled") + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting sleep state enabled\r\n"); + return false; + } + + if (!(_parser.send("AT+S.GCFG=wifi_powersave") + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting powersave mode\r\n"); + return false; + } + + if (!(_parser.send("AT+S.GCFG=standby_enabled") + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting standby state enabled\r\n"); + return false; + } +#endif + + return true; +} + +bool SPWFSAxx::_wait_console_active(void) { + int trials = 0; + + while(true) { + if (_parser.recv("+WIND:0:Console active\n") && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ +WIND:0:Console active\r\n"); + return true; + } + if(++trials >= SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> ERROR: Should never happen! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + } +} + +bool SPWFSAxx::_wait_wifi_hw_started(void) { + int trials = 0; + + while(true) { + if (_parser.recv("+WIND:32:WiFi Hardware Started\n") && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ +WIND:32:WiFi Hardware Started\r\n"); + return true; + } + if(++trials >= SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> ERROR: Should never happen! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + } +} + +bool SPWFSAxx::hw_reset(void) +{ +#if (MBED_CONF_IDW0XX1_EXPANSION_BOARD != IDW04A1) || !defined(IDW04A1_WIFI_HW_BUG_WA) // betzw: HW reset doesn't work as expected on unmodified X_NUCLEO_IDW04A1 expansion boards + _reset.write(0); + wait_ms(200); + _reset.write(1); +#else // (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) && defined(IDW04A1_WIFI_HW_BUG_WA): substitute with SW reset + _parser.send(SPWFXX_SEND_SW_RESET); +#endif // (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) && defined(IDW04A1_WIFI_HW_BUG_WA) + return _wait_console_active(); +} + +bool SPWFSAxx::reset(void) +{ + bool ret; + + /* save current setting in flash */ + if(!(_parser.send(SPWFXX_SEND_SAVE_SETTINGS) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error saving configuration to flash (%s, %d)\r\n", __func__, __LINE__); + return false; + } + + if(!_parser.send(SPWFXX_SEND_SW_RESET)) return false; /* betzw - NOTE: "keep the current state and reset the device". + We assume that the module informs us about the + eventual closing of sockets via "WIND" asynchronous + indications! So everything regarding the clean-up + of these situations is handled there. */ + + /* waiting for HW to start */ + ret = _wait_wifi_hw_started(); + + return ret; +} + +/* Security Mode + None = 0, + WEP = 1, + WPA_Personal = 2, + */ +bool SPWFSAxx::connect(const char *ap, const char *passPhrase, int securityMode) +{ + int trials; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + //AT+S.SCFG=wifi_wpa_psk_text,%s + if(!(_parser.send("AT+S.SCFG=wifi_wpa_psk_text,%s", passPhrase) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error pass set\r\n"); + return false; + } + + //AT+S.SSIDTXT=%s + if(!(_parser.send("AT+S.SSIDTXT=%s", ap) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error ssid set\r\n"); + return false; + } + + //AT+S.SCFG=wifi_priv_mode,%d + if(!(_parser.send("AT+S.SCFG=wifi_priv_mode,%d", securityMode) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error security mode set\r\n"); + return false; + } + + /*set STA mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/ + if(!(_parser.send("AT+S.SCFG=wifi_mode,1") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error WiFi mode set 1 (STA)\r\n"); + return false; + } + + /* sw reset */ + if(!reset()) { + debug_if(_dbg_on, "\r\nSPWF> SW reset failed (%s, %d)\r\n", __func__, __LINE__); + return false; + } + + trials = 0; + while(true) { + if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) + { + if(strstr(_msg_buffer, ":24:") != NULL) { // WiFi Up + debug_if(_dbg_on, "AT^ %s\n", _msg_buffer); + if(strchr(_msg_buffer, '.') != NULL) { // IPv4 address + break; + } else { + continue; + } + } + if(strstr(_msg_buffer, ":40:") != NULL) { // Deauthentication + debug_if(_dbg_on, "AT~ %s\n", _msg_buffer); + if(++trials < SPWFXX_MAX_TRIALS) { // give it three trials + continue; + } + disconnect(); + empty_rx_buffer(); + return false; + } else { + debug_if(_dbg_on, "AT] %s\n", _msg_buffer); + } + continue; + } + if(++trials >= SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> ERROR: Should never happen! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + } + + return true; +} + +bool SPWFSAxx::disconnect(void) +{ + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + /*disable Wi-Fi device*/ + if(!(_parser.send("AT+S.WIFI=0") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling WiFi\r\n"); + return false; + } +#endif // IDW04A1 + + /*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/ + if(!(_parser.send("AT+S.SCFG=wifi_mode,0") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error WiFi mode set idle (%d)\r\n", __LINE__); + return false; + } + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + /*enable Wi-Fi device*/ + if(!(_parser.send("AT+S.WIFI=1") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error enabling WiFi\r\n"); + return false; + } +#endif // IDW04A1 + + // reset module + if(!reset()) { + debug_if(_dbg_on, "\r\nSPWF> SW reset failed (%s, %d)\r\n", __func__, __LINE__); + return false; + } + + /* clean up state */ + _associated_interface.inner_constructor(); + _free_all_packets(); + + return true; +} + +const char *SPWFSAxx::getIPAddress(void) +{ + unsigned int n1, n2, n3, n4; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.STS=ip_ipaddr") + && _parser.recv(SPWFXX_RECV_IP_ADDR, &n1, &n2, &n3, &n4) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get IP address error\r\n"); + return NULL; + } + + debug_if(_dbg_on, "AT^ ip_ipaddr = %u.%u.%u.%u\r\n", n1, n2, n3, n4); + + sprintf((char*)_ip_buffer,"%u.%u.%u.%u", n1, n2, n3, n4); + return _ip_buffer; +} + +const char *SPWFSAxx::getGateway(void) +{ + unsigned int n1, n2, n3, n4; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.STS=ip_gw") + && _parser.recv(SPWFXX_RECV_GATEWAY, &n1, &n2, &n3, &n4) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get gateway error\r\n"); + return NULL; + } + + debug_if(_dbg_on, "AT^ ip_gw = %u.%u.%u.%u\r\n", n1, n2, n3, n4); + + sprintf((char*)_gateway_buffer,"%u.%u.%u.%u", n1, n2, n3, n4); + return _gateway_buffer; +} + +const char *SPWFSAxx::getNetmask(void) +{ + unsigned int n1, n2, n3, n4; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.STS=ip_netmask") + && _parser.recv(SPWFXX_RECV_NETMASK, &n1, &n2, &n3, &n4) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get netmask error\r\n"); + return NULL; + } + + debug_if(_dbg_on, "AT^ ip_netmask = %u.%u.%u.%u\r\n", n1, n2, n3, n4); + + sprintf((char*)_netmask_buffer,"%u.%u.%u.%u", n1, n2, n3, n4); + return _netmask_buffer; +} + +int8_t SPWFSAxx::getRssi(void) +{ + int ret; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.PEERS=0,rx_rssi") + && _parser.recv(SPWFXX_RECV_RX_RSSI, &ret) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get RX rssi error\r\n"); + return 0; + } + + return (int8_t)ret; +} + +const char *SPWFSAxx::getMACAddress(void) +{ + unsigned int n1, n2, n3, n4, n5, n6; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.GCFG=nv_wifi_macaddr") + && _parser.recv(SPWFXX_RECV_MAC_ADDR, &n1, &n2, &n3, &n4, &n5, &n6) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get MAC address error\r\n"); + return 0; + } + + debug_if(_dbg_on, "AT^ nv_wifi_macaddr = %x:%x:%x:%x:%x:%x\r\n", n1, n2, n3, n4, n5, n6); + + sprintf((char*)_mac_buffer,"%02X:%02X:%02X:%02X:%02X:%02X", n1, n2, n3, n4, n5, n6); + return _mac_buffer; +} + +bool SPWFSAxx::isConnected(void) +{ + return _associated_interface._connected_to_network; +} + +nsapi_size_or_error_t SPWFSAxx::send(int spwf_id, const void *data, uint32_t amount, int internal_id) +{ + uint32_t sent = 0U, to_send; + nsapi_size_or_error_t ret; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + _process_winds(); // perform async indication handling (to early detect eventually closed sockets) + + /* betzw - WORK AROUND module FW issues: split up big packages in smaller ones */ + for(to_send = (amount > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : amount; + sent < amount; + to_send = ((amount - sent) > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : (amount - sent)) { + { + BlockExecuter bh_handler(Callback<void()>(this, &SPWFSAxx::_execute_bottom_halves)); + + // betzw - TODO: handle different errors more accurately! + if (!_associated_interface._socket_is_still_connected(internal_id)) { + debug_if(_dbg_on, "\r\nSPWF> Socket not connected anymore: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__); + break; + } else if(!_parser.send("AT+S.SOCKW=%d,%d", spwf_id, (unsigned int)to_send)) { + debug_if(_dbg_on, "\r\nSPWF> Sending command failed: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__); + break; + } else if(_parser.write(((char*)data)+sent, (int)to_send) != (int)to_send) { + debug_if(_dbg_on, "\r\nSPWF> Sending data failed: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__); + break; + } else if(!_recv_ok()) { + debug_if(_dbg_on, "\r\nSPWF> Sending did not receive OK: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__); + break; + } + } + + sent += to_send; + } + + if(sent > 0) { // `sent == 0` indicates a potential error + ret = sent; + } else if(amount == 0) { + ret = NSAPI_ERROR_OK; + } else if(_associated_interface._socket_is_still_connected(internal_id)) { + ret = NSAPI_ERROR_DEVICE_ERROR; + } else { + ret = NSAPI_ERROR_CONNECTION_LOST; + } + + return ret; +} + +int SPWFSAxx::_read_len(int spwf_id) { + unsigned int amount; + + if (!(_parser.send("AT+S.SOCKQ=%d", spwf_id) + && _parser.recv(SPWFXX_RECV_DATALEN, &amount) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed\r\n", __func__); + return SPWFXX_ERR_LEN; + } + + if(amount > 0) { + debug_if(_dbg_on, "\r\nSPWF> %s():\t\t%d:%d\r\n", __func__, spwf_id, amount); + } + + MBED_ASSERT(((int)amount) >= 0); + + return (int)amount; +} + +#define SPWFXX_WINDS_OFF "0xFFFFFFFF" + +void SPWFSAxx::_winds_on(void) { + MBED_ASSERT(_is_event_callback_blocked()); + + if(!(_parser.send(SPWFXX_SEND_WIND_OFF_HIGH SPWFXX_WINDS_HIGH_ON) && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); + } + if(!(_parser.send(SPWFXX_SEND_WIND_OFF_MEDIUM SPWFXX_WINDS_MEDIUM_ON) && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); + } + if(!(_parser.send(SPWFXX_SEND_WIND_OFF_LOW SPWFXX_WINDS_LOW_ON) && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); + } +} + +/* Define beyond macro in case you want to report back failures in switching off WINDs to the caller */ +// #define SPWFXX_SOWF +/* Note: in case of error blocking has been (tried to be) lifted */ +bool SPWFSAxx::_winds_off(void) { + MBED_ASSERT(_is_event_callback_blocked()); + + if (!(_parser.send(SPWFXX_SEND_WIND_OFF_LOW SPWFXX_WINDS_OFF) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); +#ifdef SPWFXX_SOWF // betzw: try to continue + _winds_on(); + return false; +#endif + } + + if (!(_parser.send(SPWFXX_SEND_WIND_OFF_MEDIUM SPWFXX_WINDS_OFF) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); +#ifdef SPWFXX_SOWF // betzw: try to continue + _winds_on(); + return false; +#endif + } + + if (!(_parser.send(SPWFXX_SEND_WIND_OFF_HIGH SPWFXX_WINDS_OFF) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); +#ifdef SPWFXX_SOWF // betzw: try to continue + _winds_on(); + return false; +#endif + } + + return true; +} + +void SPWFSAxx::_execute_bottom_halves(void) { + _network_lost_handler_bh(); + _packet_handler_bh(); +} + +void SPWFSAxx::_read_in_pending(void) { + static int internal_id_cnt = 0; + + while(_is_data_pending()) { + if(_associated_interface._socket_has_connected(internal_id_cnt)) { + int spwf_id = _associated_interface._ids[internal_id_cnt].spwf_id; + + if(_is_data_pending(spwf_id)) { + int amount; + + amount = _read_in_pkt(spwf_id, false); + if(amount == SPWFXX_ERR_OOM) { /* consider only 'SPWFXX_ERR_OOM' as non recoverable */ + return; + } + } + + if(!_is_data_pending(spwf_id)) { + internal_id_cnt++; + internal_id_cnt %= SPWFSA_SOCKET_COUNT; + } + } else { + internal_id_cnt++; + internal_id_cnt %= SPWFSA_SOCKET_COUNT; + } + } +} + +/* Note: returns + * 'SPWFXX_ERR_OK' in case of success + * 'SPWFXX_ERR_OOM' in case of "out of memory" + * 'SPWFXX_ERR_READ' in case of `_read_in()` error + */ +int SPWFSAxx::_read_in_packet(int spwf_id, uint32_t amount) { + struct packet *packet = (struct packet*)malloc(sizeof(struct packet) + amount); + if (!packet) { +#ifndef NDEBUG + error("\r\nSPWF> %s(%d): Out of memory!\r\n", __func__, __LINE__); +#else // NDEBUG + debug("\r\nSPWF> %s(%d): Out of memory!\r\n", __func__, __LINE__); +#endif + debug_if(_dbg_on, "\r\nSPWF> %s failed (%d)\r\n", __func__, __LINE__); + return SPWFXX_ERR_OOM; /* out of memory: give up here! */ + } + + /* init packet */ + packet->id = spwf_id; + packet->len = amount; + packet->next = 0; + + /* read data in */ + if(!(_read_in((char*)(packet + 1), spwf_id, amount) > 0)) { + free(packet); + debug_if(_dbg_on, "\r\nSPWF> %s failed (%d)\r\n", __func__, __LINE__); + return SPWFXX_ERR_READ; + } else { + debug_if(_dbg_on, "\r\nSPWF> %s():\t%d:%d\r\n", __func__, spwf_id, amount); + + /* append to packet list */ + *_packets_end = packet; + _packets_end = &packet->next; + + /* force call of (external) callback */ + _call_callback(); + } + + return SPWFXX_ERR_OK; +} + +void SPWFSAxx::_free_packets(int spwf_id) { + // check if any packets are ready for `spwf_id` + for(struct packet **p = &_packets; *p;) { + if ((*p)->id == spwf_id) { + struct packet *q = *p; + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + free(q); + } else { + p = &(*p)->next; + } + } +} + +void SPWFSAxx::_free_all_packets() { + for (int spwf_id = 0; spwf_id < SPWFSA_SOCKET_COUNT; spwf_id++) { + _free_packets(spwf_id); + } +} + +bool SPWFSAxx::close(int spwf_id) +{ + bool ret = false; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + MBED_ASSERT(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); // `spwf_id` is valid + + for(int retry_cnt = 0; retry_cnt < SPWFXX_MAX_TRIALS; retry_cnt++) { + Timer timer; + timer.start(); + + // Flush out pending data + while(true) { + int amount = _read_in_pkt(spwf_id, true); + if(amount < 0) { // SPWFXX error + /* empty RX buffer & try to close */ + empty_rx_buffer(); + break; + } + if(amount == 0) break; // no more data to be read + + /* Try to work around module API bug: + * break out & try to close after 20 seconds + */ + if(timer.read() > 20) { + break; + } + + /* immediately free packet(s) (to avoid "out of memory") */ + _free_packets(spwf_id); + + /* interleave bottom halves */ + _execute_bottom_halves(); + } + + // Close socket + if (_parser.send("AT+S.SOCKC=%d", spwf_id) + && _recv_ok()) { + ret = true; + break; // finish closing + } else { // close failed + debug_if(_dbg_on, "\r\nSPWF> %s failed (%d)\r\n", __func__, __LINE__); + /* interleave bottom halves */ + _execute_bottom_halves(); + + /* free packets */ + _free_packets(spwf_id); + } + } + + /* anticipate bottom halves */ + _execute_bottom_halves(); + + if(ret) { + /* clear pending data flag (should be redundant) */ + _clear_pending_data(spwf_id); + + /* free packets for this socket */ + _free_packets(spwf_id); + + /* reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + } else { + debug_if(_dbg_on, "\r\nSPWF> SPWFSAxx::close failed (%d)\r\n", __LINE__); + + int internal_id = _associated_interface.get_internal_id(spwf_id); + if(!_associated_interface._socket_is_still_connected(internal_id)) { + /* clear pending data flag (should be redundant) */ + _clear_pending_data(spwf_id); + + /* free packets for this socket */ + _free_packets(spwf_id); + + /* reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + + ret = true; + } + } + + return ret; +} + +/* + * Buffered serial event handler + * + * Note: executed in IRQ context! + * Note: do not call (external) callback in IRQ context while performing critical module operations + */ +void SPWFSAxx::_event_handler(void) +{ + if(!_is_event_callback_blocked()) { + _call_callback(); + } +} + +/* + * Common error handler + */ +void SPWFSAxx::_error_handler(void) +{ + if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ ERROR:%s (%d)\r\n", _msg_buffer, __LINE__); + } else { + debug_if(_dbg_on, "\r\nSPWF> Unknown ERROR string in SPWFSAxx::_error_handler (%d)\r\n", __LINE__); + } + + /* force call of (external) callback */ + _call_callback(); +} + +/* + * Handling oob ("+WIND:33:WiFi Network Lost") + */ +void SPWFSAxx::_network_lost_handler_th(void) +{ +#ifndef NDEBUG + static unsigned int net_loss_cnt = 0; + net_loss_cnt++; +#endif + + _recv_delim_cr_lf(); + + debug_if(_dbg_on, "AT^ +WIND:33:WiFi Network Lost\r\n"); + +#ifndef NDEBUG + debug_if(_dbg_on, "\r\nSPWF> Getting out of SPWFSAxx::_network_lost_handler_th: %d\r\n", net_loss_cnt); +#else // NDEBUG + debug_if(_dbg_on, "\r\nSPWF> Getting out of SPWFSAxx::_network_lost_handler_th: %d\r\n", __LINE__); +#endif // NDEBUG + + /* set flag to signal network loss */ + _network_lost_flag = true; + + /* force call of (external) callback */ + _call_callback(); + + return; +} + +/* betzw - WORK AROUND module FW issues: split up big packages in smaller ones */ +void SPWFSAxx::_add_pending_packet_sz(int spwf_id, uint32_t size) { + uint32_t to_add; + uint32_t added = _get_cumulative_size(spwf_id); + + if(size <= added) { // might happen due to delayed WIND delivery + debug_if(_dbg_on, "\r\nSPWF> WARNING: %s failed at line #%d\r\n", __func__, __LINE__); + return; + } + + for(to_add = ((size - added) > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : (size - added); + added < size; + to_add = ((size - added) > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : (size - added)) { + _add_pending_pkt_size(spwf_id, added + to_add); + added += to_add; + } + + /* force call of (external) callback */ + _call_callback(); + + /* set that data is pending */ + _set_pending_data(spwf_id); +} + +/* + * Handling oob ("+WIND:55:Pending Data") + */ +void SPWFSAxx::_packet_handler_th(void) +{ + int internal_id, spwf_id; + int amount; + + /* parse out the socket id & amount */ + if (!(_parser.recv(SPWFXX_RECV_PENDING_DATA, &spwf_id, &amount) && _recv_delim_lf())) { +#ifndef NDEBUG + error("\r\nSPWF> SPWFSAxx::%s failed!\r\n", __func__); +#endif + return; + } + + debug_if(_dbg_on, "AT^ +WIND:55:Pending Data:%d:%d\r\n", spwf_id, amount); + + /* check for the module to report a valid id */ + MBED_ASSERT(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + /* set that there is pending data for socket */ + /* NOTE: it seems as if asynchronous indications might report not up-to-date data length values + * therefore we just record the socket id without considering the `amount` of data reported! + */ + internal_id = _associated_interface.get_internal_id(spwf_id); + if(internal_id != SPWFSA_SOCKET_COUNT) { + debug_if(_dbg_on, "AT^ +WIND:55:Pending Data:%d:%d - #2\r\n", spwf_id, amount); + _add_pending_packet_sz(spwf_id, amount); + + MBED_ASSERT(_get_pending_pkt_size(spwf_id) != 0); + } else { + debug_if(_dbg_on, "\r\nSPWFSAxx::%s got invalid id %d\r\n", __func__, spwf_id); + } +} + +void SPWFSAxx::_network_lost_handler_bh(void) +{ + if(!_network_lost_flag) return; + _network_lost_flag = false; + + { + bool were_connected; + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* do not call (external) callback in IRQ context as long as network is lost */ + Timer timer; + timer.start(); + + _parser.set_timeout(SPWF_NETLOST_TIMEOUT); + + were_connected = isConnected(); + _associated_interface._connected_to_network = false; + + if(were_connected) { + unsigned int n1, n2, n3, n4; + + while(true) { + if (timer.read_ms() > SPWF_CONNECT_TIMEOUT) { + debug_if(_dbg_on, "\r\nSPWF> SPWFSAxx::_network_lost_handler_bh() #%d\r\n", __LINE__); + disconnect(); + empty_rx_buffer(); + goto nlh_get_out; + } + + if((_parser.recv(SPWFXX_RECV_WIFI_UP, &n1, &n2, &n3, &n4)) && _recv_delim_lf()) { + debug_if(_dbg_on, "\r\nSPWF> Re-connected (%u.%u.%u.%u)!\r\n", n1, n2, n3, n4); + + _associated_interface._connected_to_network = true; + goto nlh_get_out; + } + } + } else { + debug_if(_dbg_on, "\r\nSPWF> Leaving SPWFSAxx::_network_lost_handler_bh\r\n"); + goto nlh_get_out; + } + + nlh_get_out: + debug_if(_dbg_on, "\r\nSPWF> Getting out of SPWFSAxx::_network_lost_handler_bh\r\n"); + _parser.set_timeout(_timeout); + + /* force call of (external) callback */ + _call_callback(); + + return; + } +} + +void SPWFSAxx::_recover_from_hard_faults(void) { + disconnect(); + empty_rx_buffer(); + + /* force call of (external) callback */ + _call_callback(); +} + +/* + * Handling oob ("+WIND:8:Hard Fault") + */ +void SPWFSAxx::_hard_fault_handler(void) +{ + _parser.set_timeout(SPWF_RECV_TIMEOUT); + if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) { +#ifndef NDEBUG + error("\r\nSPWF> hard fault error:\r\n%s\r\n", _msg_buffer); +#else // NDEBUG + debug("\r\nSPWF> hard fault error:\r\n%s\r\n", _msg_buffer); +#endif // NDEBUG + } else { +#ifndef NDEBUG + error("\r\nSPWF> unknown hard fault error\r\n"); +#else // NDEBUG + debug("\r\nSPWF> unknown hard fault error\r\n"); +#endif // NDEBUG + } + + // This is most likely the best we can do to recover from this module hard fault + _parser.set_timeout(SPWF_HF_TIMEOUT); + _recover_from_hard_faults(); + _parser.set_timeout(_timeout); + + /* force call of (external) callback */ + _call_callback(); +} + +/* + * Handling oob ("+WIND:5:WiFi Hardware Failure") + */ +void SPWFSAxx::_wifi_hwfault_handler(void) +{ + unsigned int failure_nr; + + /* parse out the socket id & amount */ + _parser.recv(":%u\n", &failure_nr); + _recv_delim_lf(); + +#ifndef NDEBUG + error("\r\nSPWF> WiFi HW fault error: %u\r\n", failure_nr); +#else // NDEBUG + debug("\r\nSPWF> WiFi HW fault error: %u\r\n", failure_nr); + + // This is most likely the best we can do to recover from this module hard fault + _parser.set_timeout(SPWF_HF_TIMEOUT); + _recover_from_hard_faults(); + _parser.set_timeout(_timeout); +#endif // NDEBUG + + /* force call of (external) callback */ + _call_callback(); +} + +/* + * Handling oob ("+WIND:58:Socket Closed") + * when server closes a client connection + * + * NOTE: When a socket client receives an indication about socket server gone (only for TCP sockets, WIND:58), + * the socket connection is NOT automatically closed! + */ +void SPWFSAxx::_server_gone_handler(void) +{ + int spwf_id, internal_id; + + if(!(_parser.recv(SPWFXX_RECV_SOCKET_CLOSED, &spwf_id) && _recv_delim_lf())) { +#ifndef NDEBUG + error("\r\nSPWF> SPWFSAxx::%s failed!\r\n", __func__); +#endif + goto _get_out; + } + + debug_if(_dbg_on, "AT^ +WIND:58:Socket Closed:%d\r\n", spwf_id); + + /* check for the module to report a valid id */ + MBED_ASSERT(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + /* only set `server_gone` + * user still can receive data & must still explicitly close the socket + */ + internal_id = _associated_interface.get_internal_id(spwf_id); + if(internal_id != SPWFSA_SOCKET_COUNT) { + _associated_interface._ids[internal_id].server_gone = true; + } + +_get_out: + /* force call of (external) callback */ + _call_callback(); +} + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 +/* + * Handling oob (currently only for "+WIND:24:WiFi Up::") + */ +void SPWFSAxx::_skip_oob(void) +{ + if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ +WIND:24:WiFi Up::%s\r\n", _msg_buffer); + } else { + debug_if(_dbg_on, "\r\nSPWF> Invalid string in SPWFSAxx::_skip_oob (%d)\r\n", __LINE__); + } +} +#endif + +void SPWFSAxx::setTimeout(uint32_t timeout_ms) +{ + _timeout = timeout_ms; + _parser.set_timeout(timeout_ms); +} + +void SPWFSAxx::attach(Callback<void()> func) +{ + _callback_func = func; /* do not call (external) callback in IRQ context during critical module operations */ +} + +/** + * Recv Function + */ +int32_t SPWFSAxx::recv(int spwf_id, void *data, uint32_t amount, bool datagram) +{ + BlockExecuter bh_handler(Callback<void()>(this, &SPWFSAxx::_execute_bottom_halves)); + + while (true) { + /* check if any packets are ready for us */ + for (struct packet **p = &_packets; *p; p = &(*p)->next) { + if ((*p)->id == spwf_id) { + debug_if(_dbg_on, "\r\nSPWF> Read done on ID %d and length of packet is %d\r\n",spwf_id,(*p)->len); + struct packet *q = *p; + + MBED_ASSERT(q->len > 0); + + if(datagram) { // UDP => always remove pkt size + // will always consume a whole pending size + uint32_t ret; + + debug_if(_dbg_on, "\r\nSPWF> %s():\t\t\t%d:%d (datagram)\r\n", __func__, spwf_id, q->len); + + ret = (amount < q->len) ? amount : q->len; + memcpy(data, q+1, ret); + + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + free(q); + + return ret; + } else { // TCP + if (q->len <= amount) { // return and remove full packet + memcpy(data, q+1, q->len); + + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + uint32_t len = q->len; + free(q); + + return len; + } else { // `q->len > amount`, return only partial packet + if(amount > 0) { + memcpy(data, q+1, amount); + q->len -= amount; + memmove(q+1, (uint8_t*)(q+1) + amount, q->len); + } + + return amount; + } + } + } + } + + /* check for pending data on module */ + { + int len; + + len = _read_in_pkt(spwf_id, false); + if(len <= 0) { /* SPWFXX error or no more data to be read */ + return -1; + } + } + } +} + +void SPWFSAxx::_process_winds(void) { + do { + if(_parser.process_oob()) { + /* nothing else to do! */; + } else { + debug_if(_dbg_on, "%s():\t\tNo (more) oob's found!\r\n", __func__); + return; // no (more) oob's found + } + } while(true); +} + +/* Note: returns + * '>=0' in case of success, amount of read in data (in bytes) + * 'SPWFXX_ERR_OOM' in case of "out of memory" + * 'SPWFXX_ERR_READ' in case of other `_read_in_packet()` error + * 'SPWFXX_ERR_LEN' in case of `_read_len()` error + */ +int SPWFSAxx::_read_in_pkt(int spwf_id, bool close) { + int pending; + uint32_t wind_pending; + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* do not call (external) callback in IRQ context while receiving */ + + _process_winds(); // perform async indication handling + + if(close) { // read in all data + wind_pending = pending = _read_len(spwf_id); // triggers also async indication handling! + + if(pending > 0) { + /* reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + /* create new entry for pending size */ + _add_pending_pkt_size(spwf_id, (uint32_t)pending); +#ifndef NDEBUG + wind_pending = _get_pending_pkt_size(spwf_id); + MBED_ASSERT(pending == (int)wind_pending); +#endif + } else if(pending < 0) { + debug_if(_dbg_on, "\r\nSPWF> %s(), #%d:`_read_len()` failed (%d)!\r\n", __func__, __LINE__, pending); + } + } else { // only read in already notified data + pending = wind_pending = _get_pending_pkt_size(spwf_id); + if(pending == 0) { // special handling for no packets pending (to WORK AROUND missing WINDs)! + pending = _read_len(spwf_id); // triggers also async indication handling! + + if(pending > 0) { + _process_winds(); // perform async indication handling (again) + wind_pending = _get_pending_pkt_size(spwf_id); + + if(wind_pending == 0) { + /* betzw - WORK AROUND module FW issues: create new entry for pending size */ + debug_if(_dbg_on, "%s():\t\tAdd packet w/o WIND (%d)!\r\n", __func__, pending); + _add_pending_packet_sz(spwf_id, (uint32_t)pending); + + pending = wind_pending = _get_pending_pkt_size(spwf_id); + MBED_ASSERT(wind_pending > 0); + } + } else if(pending < 0) { + debug_if(_dbg_on, "\r\nSPWF> %s(), #%d:`_read_len()` failed (%d)!\r\n", __func__, __LINE__, pending); + } + } + } + + if((pending > 0) && (wind_pending > 0)) { + int ret = _read_in_packet(spwf_id, wind_pending); + if(ret < 0) { /* "out of memory" or `_read_in_packet()` error */ + /* we do not know if data is still pending at this point + but leaving the pending data bit set might lead to an endless loop */ + _clear_pending_data(spwf_id); + /* also reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + + return ret; + } + + if((_get_cumulative_size(spwf_id) == 0) && (pending <= (int)wind_pending)) { + _clear_pending_data(spwf_id); + } + } else if(pending < 0) { /* 'SPWFXX_ERR_LEN' error */ + MBED_ASSERT(pending == SPWFXX_ERR_LEN); + /* we do not know if data is still pending at this point + but leaving the pending data bit set might lead to an endless loop */ + _clear_pending_data(spwf_id); + /* also reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + + return pending; + } else if(pending == 0) { + MBED_ASSERT(wind_pending == 0); + _clear_pending_data(spwf_id); + } else if(wind_pending == 0) { // `pending > 0` + /* betzw: should never happen! */ + MBED_ASSERT(false); + } + + return (int)wind_pending; +}
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SPWFSAxx.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SPWFSAxx.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,446 @@ +/* SPWFSAxx Devices + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SPWFSAXX_H +#define SPWFSAXX_H + +#include "mbed.h" +#include "ATCmdParser.h" +#include "BlockExecuter.h" + +/* Common SPWFSAxx macros */ +#define SPWFXX_WINDS_LOW_ON "0x00000000" +#define SPWFXX_DEFAULT_BAUD_RATE 115200 +#define SPWFXX_MAX_TRIALS 3 + +#if !defined(SPWFSAXX_RTS_PIN) +#define SPWFSAXX_RTS_PIN NC +#endif // !defined(SPWFSAXX_RTS_PIN) +#if !defined(SPWFSAXX_CTS_PIN) +#define SPWFSAXX_CTS_PIN NC +#endif // !defined(SPWFSAXX_CTS_PIN) + +#define SPWFXX_ERR_OK (+1) +#define SPWFXX_ERR_OOM (-1) +#define SPWFXX_ERR_READ (-2) +#define SPWFXX_ERR_LEN (-3) + + +/* Max number of sockets & packets */ +#define SPWFSA_SOCKET_COUNT (8) +#define SPWFSA_MAX_PACKETS (4) + +#define PENDING_DATA_SLOTS (13) + +/* Pending data packets size buffer */ +class SpwfRealPendingPackets { +public: + SpwfRealPendingPackets() { + reset(); + } + + void add(uint32_t new_cum_size) { + MBED_ASSERT(new_cum_size >= cumulative_size); + + if(new_cum_size == cumulative_size) { + /* nothing to do */ + return; + } + + /* => `new_cum_size > cumulative_size` */ + real_pkt_sizes[last_pkt_ptr] = (uint16_t)(new_cum_size - cumulative_size); + cumulative_size = new_cum_size; + + last_pkt_ptr = (last_pkt_ptr + 1) % PENDING_DATA_SLOTS; + + MBED_ASSERT(first_pkt_ptr != last_pkt_ptr); + } + + uint32_t get(void) { + if(empty()) return 0; + + return real_pkt_sizes[first_pkt_ptr]; + } + + uint32_t cumulative(void) { + return cumulative_size; + } + + uint32_t remove(uint32_t size) { + MBED_ASSERT(!empty()); + + uint32_t ret = real_pkt_sizes[first_pkt_ptr]; + first_pkt_ptr = (first_pkt_ptr + 1) % PENDING_DATA_SLOTS; + + MBED_ASSERT(ret == size); + MBED_ASSERT(ret <= cumulative_size); + cumulative_size -= ret; + + return ret; + } + + void reset(void) { + memset(this, 0, sizeof(*this)); + } + +private: + bool empty(void) { + if(first_pkt_ptr == last_pkt_ptr) { + MBED_ASSERT(cumulative_size == 0); + return true; + } + return false; + } + + uint16_t real_pkt_sizes[PENDING_DATA_SLOTS]; + uint8_t first_pkt_ptr; + uint8_t last_pkt_ptr; + uint32_t cumulative_size; +}; + +class SpwfSAInterface; + +/** SPWFSAxx Interface class. + This is an interface to a SPWFSAxx module. + */ +class SPWFSAxx +{ +private: + /* abstract class*/ + SPWFSAxx(PinName tx, PinName rx, PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset); + +public: + /** + * Init the SPWFSAxx + * + * @param mode mode in which to startup + * @return true only if SPWFSAxx has started up correctly + */ + bool startup(int mode); + + /** + * Connect SPWFSAxx to AP + * + * @param ap the name of the AP + * @param passPhrase the password of AP + * @param securityMode the security mode of AP (WPA/WPA2, WEP, Open) + * @return true only if SPWFSAxx is connected successfully + */ + bool connect(const char *ap, const char *passPhrase, int securityMode); + + /** + * Disconnect SPWFSAxx from AP + * + * @return true only if SPWFSAxx is disconnected successfully + */ + bool disconnect(void); + + /** + * Get the IP address of SPWFSAxx + * + * @return null-terminated IP address or null if no IP address is assigned + */ + const char *getIPAddress(void); + + /** + * Get the MAC address of SPWFSAxx + * + * @return null-terminated MAC address or null if no MAC address is assigned + */ + const char *getMACAddress(void); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been received + */ + const char *getGateway(void); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been received + */ + const char *getNetmask(void); + + /** Gets the current radio signal strength for active connection + * + * @return Connection strength in dBm (negative value) + */ + int8_t getRssi(); + + /** + * Sends data to an open socket + * + * @param spwf_id module id of socket to send to + * @param data data to be sent + * @param amount amount of data to be sent - max 1024 + * @param internal_id driver id of socket to send to + * @return number of written bytes on success, negative on failure + */ + nsapi_size_or_error_t send(int spwf_id, const void *data, uint32_t amount, int internal_id); + + /** + * Receives data from an open socket + * + * @param id id to receive from + * @param data placeholder for returned information + * @param amount number of bytes to be received + * @param datagram receive a datagram packet + * @return the number of bytes received + */ + int32_t recv(int id, void *data, uint32_t amount, bool datagram); + + /** + * Closes a socket + * + * @param id id of socket to close, valid only 0-4 + * @return true only if socket is closed successfully + */ + bool close(int id); + + /** + * Allows timeout to be changed between commands + * + * @param timeout_ms timeout of the connection + */ + void setTimeout(uint32_t timeout_ms); + + /** + * Attach a function to call whenever network state has changed + * + * @param func A pointer to a void function, or 0 to set as none + */ + void attach(Callback<void()> func); + + /** + * Attach a function to call whenever network state has changed + * + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to call + */ + template <typename T, typename M> + void attach(T *obj, M method) { + attach(Callback<void()>(obj, method)); + } + + static const char _cr_ = '\x0d'; // '\r' carriage return + static const char _lf_ = '\x0a'; // '\n' line feed + +private: + UARTSerial _serial; + ATCmdParser _parser; + + DigitalOut _wakeup; + DigitalOut _reset; + PinName _rts; + PinName _cts; + + int _timeout; + bool _dbg_on; + + int _pending_sockets_bitmap; + SpwfRealPendingPackets _pending_pkt_sizes[SPWFSA_SOCKET_COUNT]; + + bool _network_lost_flag; + SpwfSAInterface &_associated_interface; + + /** + * Reset SPWFSAxx + * + * @return true only if SPWFSAxx resets successfully + */ + bool hw_reset(void); + bool reset(void); + + /** + * Check if SPWFSAxx is connected + * + * @return true only if the chip has an IP address + */ + bool isConnected(void); + + /** + * Checks if data is available + */ + bool readable(void) { + return _serial.FileHandle::readable(); + } + + /** + * Checks if data can be written + */ + bool writeable(void) { + return _serial.FileHandle::writable(); + } + + /** + * Try to empty RX buffer + * Can be used when commands fail receiving expected response to try to recover situation + * @note Gives no guarantee that situation improves + */ + void empty_rx_buffer(void) { + while(readable()) _parser.getc(); + } + + /* block calling (external) callback */ + volatile unsigned int _call_event_callback_blocked; + Callback<void()> _callback_func; + + struct packet { + struct packet *next; + int id; + uint32_t len; + // data follows + } *_packets, **_packets_end; + + void _packet_handler_th(void); + void _execute_bottom_halves(void); + void _network_lost_handler_th(void); + void _network_lost_handler_bh(void); + void _hard_fault_handler(void); + void _wifi_hwfault_handler(void); + void _server_gone_handler(void); +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + void _skip_oob(void); +#endif + bool _wait_wifi_hw_started(void); + bool _wait_console_active(void); + int _read_len(int); + int _flush_in(char*, int); + bool _winds_off(void); + void _winds_on(void); + void _read_in_pending(void); + int _read_in_pkt(int spwf_id, bool close); + int _read_in_packet(int spwf_id, uint32_t amount); + void _recover_from_hard_faults(void); + void _free_packets(int spwf_id); + void _free_all_packets(void); + void _process_winds(); + + virtual int _read_in(char*, int, uint32_t) = 0; + + bool _recv_delim_lf(void) { + return (_parser.getc() == _lf_); + } + + bool _recv_delim_cr(void) { + return (_parser.getc() == _cr_); + } + + bool _recv_delim_cr_lf(void) { + return _recv_delim_cr() && _recv_delim_lf(); + } + + bool _recv_ok(void) { + return _parser.recv(SPWFXX_RECV_OK) && _recv_delim_lf(); + } + + void _add_pending_packet_sz(int spwf_id, uint32_t size); + void _add_pending_pkt_size(int spwf_id, uint32_t size) { + _pending_pkt_sizes[spwf_id].add(size); + } + + uint32_t _get_cumulative_size(int spwf_id) { + return _pending_pkt_sizes[spwf_id].cumulative(); + } + + uint32_t _remove_pending_pkt_size(int spwf_id, uint32_t size) { + return _pending_pkt_sizes[spwf_id].remove(size); + } + + uint32_t _get_pending_pkt_size(int spwf_id) { + return _pending_pkt_sizes[spwf_id].get(); + } + + void _reset_pending_pkt_sizes(int spwf_id) { + _pending_pkt_sizes[spwf_id].reset(); + } + + void _set_pending_data(int spwf_id) { + _pending_sockets_bitmap |= (1 << spwf_id); + } + + void _clear_pending_data(int spwf_id) { + _pending_sockets_bitmap &= ~(1 << spwf_id); + } + + bool _is_data_pending(int spwf_id) { + return (_pending_sockets_bitmap & (1 << spwf_id)) ? true : false; + } + + bool _is_data_pending(void) { + if(_pending_sockets_bitmap != 0) return true; + else return false; + } + + void _packet_handler_bh(void) { + /* read in other eventually pending packages */ + _read_in_pending(); + } + + /* Do not call the (external) callback in IRQ context while performing critical module operations */ + void _event_handler(void); + + void _error_handler(void); + + void _call_callback(void) { + if((bool)_callback_func) { + _callback_func(); + } + } + + bool _is_event_callback_blocked(void) { + return (_call_event_callback_blocked != 0); + } + + void _block_event_callback(void) { + _call_event_callback_blocked++; + } + + void _unblock_event_callback(void) { + MBED_ASSERT(_call_event_callback_blocked > 0); + _call_event_callback_blocked--; + if(_call_event_callback_blocked == 0) { + _trigger_event_callback(); + } + } + + /* trigger call of (external) callback in case there is still data */ + void _trigger_event_callback(void) { + MBED_ASSERT(_call_event_callback_blocked == 0); + /* if still data available */ + if(readable()) { + _call_callback(); + } + } + + char _ip_buffer[16]; + char _gateway_buffer[16]; + char _netmask_buffer[16]; + char _mac_buffer[18]; + + char _msg_buffer[256]; + +private: + friend class SPWFSA01; + friend class SPWFSA04; + friend class SpwfSAInterface; +}; + +#endif // SPWFSAXX_H
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SpwfSAInterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SpwfSAInterface.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,512 @@ +/* mbed Microcontroller Library + * Copyright (c) 20015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + ****************************************************************************** + * @file SpwfSAInterface.cpp + * @author STMicroelectronics + * @brief Implementation of the NetworkStack for the SPWF Device + ****************************************************************************** + * @copy + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +#include "SpwfSAInterface.h" +#include "mbed_debug.h" +#include "BlockExecuter.h" + +#if MBED_CONF_RTOS_PRESENT +static Mutex _spwf_mutex; // assuming a recursive mutex +static void _spwf_lock() { + (void)(_spwf_mutex.lock()); +} +static Callback<void()> _callback_spwf_lock(&_spwf_lock); + +static void _spwf_unlock() { + (void)(_spwf_mutex.unlock()); +} +static Callback<void()> _callback_spwf_unlock(&_spwf_unlock); + +#define SYNC_HANDLER \ + BlockExecuter sync_handler(_callback_spwf_unlock, _callback_spwf_lock) +#else +#define SYNC_HANDLER +#endif + + +SpwfSAInterface::SpwfSAInterface(PinName tx, PinName rx, + PinName rts, PinName cts, bool debug, + PinName wakeup, PinName reset) +: _spwf(tx, rx, rts, cts, *this, debug, wakeup, reset), + _dbg_on(debug) +{ + inner_constructor(); + reset_credentials(); +} + +nsapi_error_t SpwfSAInterface::init(void) +{ + _spwf.setTimeout(SPWF_INIT_TIMEOUT); + + if(_spwf.startup(0)) { + return NSAPI_ERROR_OK; + } + else return NSAPI_ERROR_DEVICE_ERROR; +} + +nsapi_error_t SpwfSAInterface::connect(void) +{ + int mode; + char *pass_phrase = ap_pass; + SYNC_HANDLER; + + // check for valid SSID + if(ap_ssid[0] == '\0') { + return NSAPI_ERROR_PARAMETER; + } + + switch(ap_sec) + { + case NSAPI_SECURITY_NONE: + mode = 0; + pass_phrase = NULL; + break; + case NSAPI_SECURITY_WEP: + mode = 1; + break; + case NSAPI_SECURITY_WPA: + case NSAPI_SECURITY_WPA2: + mode = 2; + break; + default: + mode = 2; + break; + } + + // First: disconnect + if(_connected_to_network) { + if(!disconnect()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } + + //initialize the device before connecting + if(!_isInitialized) + { + if(init() != NSAPI_ERROR_OK) return NSAPI_ERROR_DEVICE_ERROR; + _isInitialized=true; + } + + // Then: (re-)connect + _spwf.setTimeout(SPWF_CONNECT_TIMEOUT); + + if (!_spwf.connect(ap_ssid, pass_phrase, mode)) { + return NSAPI_ERROR_AUTH_FAILURE; + } + + if (!_spwf.getIPAddress()) { + return NSAPI_ERROR_DHCP_FAILURE; + } + + _connected_to_network = true; + return NSAPI_ERROR_OK; +} + +nsapi_error_t SpwfSAInterface::connect(const char *ssid, const char *pass, nsapi_security_t security, + uint8_t channel) +{ + nsapi_error_t ret; + SYNC_HANDLER; + + if (channel != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + + ret = set_credentials(ssid, pass, security); + if(ret != NSAPI_ERROR_OK) return ret; + + return connect(); +} + +nsapi_error_t SpwfSAInterface::disconnect(void) +{ + SYNC_HANDLER; + + _spwf.setTimeout(SPWF_DISCONNECT_TIMEOUT); + + if (!_spwf.disconnect()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + return NSAPI_ERROR_OK; +} + +const char *SpwfSAInterface::get_ip_address(void) +{ + SYNC_HANDLER; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getIPAddress(); +} + +const char *SpwfSAInterface::get_mac_address(void) +{ + SYNC_HANDLER; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getMACAddress(); +} + +const char *SpwfSAInterface::get_gateway(void) +{ + SYNC_HANDLER; + + if(!_connected_to_network) return NULL; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getGateway(); +} + +const char *SpwfSAInterface::get_netmask(void) +{ + SYNC_HANDLER; + + if(!_connected_to_network) return NULL; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getNetmask(); +} + +nsapi_error_t SpwfSAInterface::socket_open(void **handle, nsapi_protocol_t proto) +{ + int internal_id; + SYNC_HANDLER; + + for (internal_id = 0; internal_id < SPWFSA_SOCKET_COUNT; internal_id++) { + if(_ids[internal_id].internal_id == SPWFSA_SOCKET_COUNT) break; + } + + if(internal_id == SPWFSA_SOCKET_COUNT) { + debug_if(_dbg_on, "NO Socket ID Error\r\n"); + return NSAPI_ERROR_NO_SOCKET; + } + + spwf_socket_t *socket = &_ids[internal_id]; + socket->internal_id = internal_id; + socket->spwf_id = SPWFSA_SOCKET_COUNT; + socket->server_gone = false; + socket->no_more_data = false; + socket->proto = proto; + socket->addr = SocketAddress(); + + *handle = socket; + return NSAPI_ERROR_OK; +} + +nsapi_error_t SpwfSAInterface::socket_connect(void *handle, const SocketAddress &addr) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + MBED_ASSERT(((unsigned int)socket->internal_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + if(_socket_has_connected(socket->internal_id)) { + return NSAPI_ERROR_IS_CONNECTED; + } + + _spwf.setTimeout(SPWF_OPEN_TIMEOUT); + + const char *proto = (socket->proto == NSAPI_UDP) ? "u" : "t"; //"s" for secure socket? + + if(addr.get_ip_version() != NSAPI_IPv4) { // IPv6 not supported (yet) + return NSAPI_ERROR_UNSUPPORTED; + } + + { + BlockExecuter netsock_wa_obj(Callback<void()>(&_spwf, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(&_spwf, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + /* block asynchronous indications */ + if(!_spwf._winds_off()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + { + BlockExecuter bh_handler(Callback<void()>(&_spwf, &SPWFSAxx::_execute_bottom_halves)); + { + BlockExecuter winds_enabler(Callback<void()>(&_spwf, &SPWFSAxx::_winds_on)); + + if(!_spwf.open(proto, &socket->spwf_id, addr.get_ip_address(), addr.get_port())) { + MBED_ASSERT(_spwf._call_event_callback_blocked == 1); + + return NSAPI_ERROR_DEVICE_ERROR; + } + + /* check for the module to report a valid id */ + MBED_ASSERT(((unsigned int)socket->spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + _internal_ids[socket->spwf_id] = socket->internal_id; + socket->addr = addr; + + MBED_ASSERT(_spwf._call_event_callback_blocked == 1); + + return NSAPI_ERROR_OK; + } + } + } +} + +nsapi_error_t SpwfSAInterface::socket_bind(void *handle, const SocketAddress &address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t SpwfSAInterface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t SpwfSAInterface::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t SpwfSAInterface::socket_close(void *handle) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + int internal_id = socket->internal_id; + SYNC_HANDLER; + + if(!_socket_is_open(internal_id)) return NSAPI_ERROR_NO_SOCKET; + + if(_socket_has_connected(socket)) { + _spwf.setTimeout(SPWF_CLOSE_TIMEOUT); + if (!_spwf.close(socket->spwf_id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + _internal_ids[socket->spwf_id] = SPWFSA_SOCKET_COUNT; + } + + _ids[internal_id].internal_id = SPWFSA_SOCKET_COUNT; + _ids[internal_id].spwf_id = SPWFSA_SOCKET_COUNT; + + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t SpwfSAInterface::socket_send(void *handle, const void *data, unsigned size) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + CHECK_NOT_CONNECTED_ERR(); + + _spwf.setTimeout(SPWF_SEND_TIMEOUT); + return _spwf.send(socket->spwf_id, data, size, socket->internal_id); +} + +nsapi_size_or_error_t SpwfSAInterface::socket_recv(void *handle, void *data, unsigned size) +{ + SYNC_HANDLER; + + return _socket_recv(handle, data, size, false); +} + +nsapi_size_or_error_t SpwfSAInterface::_socket_recv(void *handle, void *data, unsigned size, bool datagram) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + + CHECK_NOT_CONNECTED_ERR(); + + if(!_socket_has_connected(socket)) { + return NSAPI_ERROR_WOULD_BLOCK; + } else if(socket->no_more_data) { + return 0; + } + + _spwf.setTimeout(SPWF_RECV_TIMEOUT); + + int32_t recv = _spwf.recv(socket->spwf_id, (char*)data, (uint32_t)size, datagram); + + MBED_ASSERT(!_spwf._is_event_callback_blocked()); + MBED_ASSERT((recv != 0) || (size == 0)); + + if (recv < 0) { + if(!_socket_is_still_connected(socket)) { + socket->no_more_data = true; + return 0; + } + + return NSAPI_ERROR_WOULD_BLOCK; + } + + return recv; +} + +nsapi_size_or_error_t SpwfSAInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + CHECK_NOT_CONNECTED_ERR(); + + if ((_socket_has_connected(socket)) && (socket->addr != addr)) { + _spwf.setTimeout(SPWF_CLOSE_TIMEOUT); + if (!_spwf.close(socket->spwf_id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + _internal_ids[socket->spwf_id] = SPWFSA_SOCKET_COUNT; + socket->spwf_id = SPWFSA_SOCKET_COUNT; + } + + _spwf.setTimeout(SPWF_CONN_SND_TIMEOUT); + if (!_socket_has_connected(socket)) { + nsapi_error_t err = socket_connect(socket, addr); + if (err < 0) { + return err; + } + } + + return socket_send(socket, data, size); +} + +nsapi_size_or_error_t SpwfSAInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + nsapi_error_t ret; + SYNC_HANDLER; + + ret = _socket_recv(socket, data, size, true); + if (ret >= 0 && addr) { + *addr = socket->addr; + } + + return ret; +} + +void SpwfSAInterface::socket_attach(void *handle, void (*callback)(void *), void *data) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + if(!_socket_is_open(socket)) return; // might happen e.g. after module hard fault or voluntary disconnection + + _cbs[socket->internal_id].callback = callback; + _cbs[socket->internal_id].data = data; +} + +void SpwfSAInterface::event(void) { + for (int internal_id = 0; internal_id < SPWFSA_SOCKET_COUNT; internal_id++) { + if (_cbs[internal_id].callback && (_ids[internal_id].internal_id != SPWFSA_SOCKET_COUNT)) { + _cbs[internal_id].callback(_cbs[internal_id].data); + } + } +} + +nsapi_error_t SpwfSAInterface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + SYNC_HANDLER; + + if((ssid == NULL) || (strlen(ssid) == 0)) { + return NSAPI_ERROR_PARAMETER; + } + + if((pass != NULL) && (strlen(pass) > 0)) { + if(strlen(pass) < sizeof(ap_pass)) { + if(security == NSAPI_SECURITY_NONE) { + return NSAPI_ERROR_PARAMETER; + } + } else { + return NSAPI_ERROR_PARAMETER; + } + } else if(security != NSAPI_SECURITY_NONE) { + return NSAPI_ERROR_PARAMETER; + } + + reset_credentials(); + + ap_sec = security; + strncpy(ap_ssid, ssid, sizeof(ap_ssid) - 1); + strncpy(ap_pass, pass, sizeof(ap_pass) - 1); + + return NSAPI_ERROR_OK; +} + +nsapi_error_t SpwfSAInterface::set_channel(uint8_t channel) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int8_t SpwfSAInterface::get_rssi(void) +{ + SYNC_HANDLER; + + if(!_connected_to_network) return 0; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getRssi(); +} + +nsapi_size_or_error_t SpwfSAInterface::scan(WiFiAccessPoint *res, unsigned count) +{ + SYNC_HANDLER; + + nsapi_size_or_error_t ret; + + //initialize the device before scanning + if(!_isInitialized) + { + if(init() != NSAPI_ERROR_OK) return NSAPI_ERROR_DEVICE_ERROR; + } + + _spwf.setTimeout(SPWF_SCAN_TIMEOUT); + + { + BlockExecuter netsock_wa_obj(Callback<void()>(&_spwf, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(&_spwf, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + /* block asynchronous indications */ + if(!_spwf._winds_off()) { + MBED_ASSERT(_spwf._call_event_callback_blocked == 1); + + return NSAPI_ERROR_DEVICE_ERROR; + } + + ret = _spwf.scan(res, count); + + /* unblock asynchronous indications */ + _spwf._winds_on(); + } + + MBED_ASSERT(!_spwf._is_event_callback_blocked()); + + //de-initialize the device after scanning + if(!_isInitialized) + { + nsapi_error_t err = disconnect(); + if(err != NSAPI_ERROR_OK) return err; + } + + return ret; +}
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/SpwfSAInterface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/SpwfSAInterface.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,439 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + ****************************************************************************** + * @file SpwfSAInterface.h + * @author STMicroelectronics + * @brief Header file of the NetworkStack for the SPWF Device + ****************************************************************************** + * @copy + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +#ifndef SPWFSA_INTERFACE_H +#define SPWFSA_INTERFACE_H + +#include <limits.h> + +#include "mbed.h" + +#define IDW01M1 1 +#define IDW04A1 2 + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW01M1 +#include "SPWFSA01/SPWFSA01.h" +#elif MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 +#include "SPWFSA04/SPWFSA04.h" +#else +#error No (valid) Wi-Fi exapnsion board defined (MBED_CONF_IDW0XX1_EXPANSION_BOARD: options are IDW01M1 and IDW04A1) +#endif + +// Various timeouts for different SPWF operations +#define SPWF_CONNECT_TIMEOUT 60000 +#define SPWF_DISCONNECT_TIMEOUT 30002 +#define SPWF_HF_TIMEOUT 30001 +#define SPWF_NETLOST_TIMEOUT 30000 +#define SPWF_READ_BIN_TIMEOUT 13000 +#define SPWF_CLOSE_TIMEOUT 10001 +#define SPWF_SEND_TIMEOUT 10000 +#define SPWF_INIT_TIMEOUT 8000 +#define SPWF_OPEN_TIMEOUT 5002 +#define SPWF_CONN_SND_TIMEOUT 5001 +#define SPWF_SCAN_TIMEOUT 5000 +#define SPWF_MISC_TIMEOUT 301 +#define SPWF_RECV_TIMEOUT 300 + +/** SpwfSAInterface class + * Implementation of the NetworkStack for the SPWF Device + */ +// NOTE - betzw - TODO: MUST become singleton! +class SpwfSAInterface : public NetworkStack, public WiFiInterface +{ +public: + /** SpwfSAInterface constructor + * @param tx TX pin + * @param rx RX pin + * @param rts RTS pin + * @param cts CTS pin + * @param debug Enable debugging + * @param wakeup Wakeup pin + * @param reset Reset pin + */ + SpwfSAInterface(PinName tx, PinName rx, + PinName rts = SPWFSAXX_RTS_PIN, PinName cts = SPWFSAXX_CTS_PIN, bool debug = false, + PinName wakeup = SPWFSAXX_WAKEUP_PIN, PinName reset = SPWFSAXX_RESET_PIN); + + /** Start the interface + * + * Attempts to connect to a WiFi network. Requires ssid and passphrase to be set. + * If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned. + * + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t connect(); + + /** Start the interface + * + * Attempts to connect to a WiFi network. + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE) + * @param channel This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED + * @return 0 on success, or error code on failure + */ + virtual nsapi_error_t connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE, + uint8_t channel = 0); + + /** Set the WiFi network credentials + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection + * (defaults to NSAPI_SECURITY_NONE) + * @return 0 on success, or error code on failure + */ + virtual nsapi_error_t set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE); + + /** Set the WiFi network channel - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0) + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_error_t set_channel(uint8_t channel); + + /** Stop the interface + * @return `NSAPI_ERROR_OK` on success, negative on failure + */ + virtual nsapi_error_t disconnect(); + + /** Get the internally stored IP address + * @return IP address of the interface or null if not yet connected + */ + virtual const char *get_ip_address(); + + /** Get the internally stored MAC address + * @return MAC address of the interface + */ + virtual const char *get_mac_address(); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been received + */ + virtual const char *get_gateway(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been received + */ + virtual const char *get_netmask(); + + /** Gets the current radio signal strength for active connection + * + * @return Connection strength in dBm (negative value) + */ + virtual int8_t get_rssi(); + + /** Scan for available networks + * + * This function will block. If the @a count is 0, function will only return count of available networks, so that + * user can allocated necessary memory. If the @count is grater than 0 and the @a ap is not NULL it'll be populated + * with discovered networks up to value of @a count. + * + * @param res Pointer to allocated array to store discovered AP + * @param count Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a, or if @a count was 0 number of available networks, + * negative on error see @a nsapi_error + */ + virtual nsapi_size_or_error_t scan(WiFiAccessPoint *res, unsigned count); + + /** Translates a hostname to an IP address with specific version + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * + * @param address Destination for the host SocketAddress + * @param host Hostname to resolve + * @param version IP version of address to resolve, NSAPI_UNSPEC indicates + * version is chosen by the stack (defaults to NSAPI_UNSPEC) + * @return 0 on success, negative error code on failure + */ + using NetworkInterface::gethostbyname; + + /** Add a domain name server to list of servers to query + * + * @param addr Destination for the host address + * @return 0 on success, negative error code on failure + */ + using NetworkInterface::add_dns_server; + +private: + /** Open a socket + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return `NSAPI_ERROR_OK` on success, negative on failure + */ + virtual nsapi_error_t socket_open(void **handle, nsapi_protocol_t proto); + + /** Close the socket + * @param handle Socket handle + * @return `NSAPI_ERROR_OK` on success, negative on failure + * @note On failure, any memory associated with the socket must still + * be cleaned up + */ + virtual nsapi_error_t socket_close(void *handle); + + /** Bind a server socket to a specific port - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_error_t socket_bind(void *handle, const SocketAddress &address); + + /** Start listening for incoming connections - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_error_t socket_listen(void *handle, int backlog); + + /** Connects this TCP socket to the server + * @param handle Socket handle + * @param address SocketAddress to connect to + * @return `NSAPI_ERROR_OK` on success, negative on failure + */ + virtual nsapi_error_t socket_connect(void *handle, const SocketAddress &address); + + /** Accept a new connection - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_error_t socket_accept(void *handle, void **socket, SocketAddress *address); + + /** Send data to the remote host + * @param handle Socket handle + * @param data The buffer to send to the host + * @param size The length of the buffer to send + * @return Number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_BLOCK + */ + virtual nsapi_size_or_error_t socket_send(void *handle, const void *data, unsigned size); + + /** Receive data from the remote host + * @param handle Socket handle + * @param data The buffer in which to store the data received from the host + * @param size The maximum length of the buffer + * @return Number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_BLOCK + */ + virtual nsapi_size_or_error_t socket_recv(void *handle, void *data, unsigned size); + + /** Send a packet to a remote endpoint + * @param handle Socket handle + * @param address The remote SocketAddress + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return The number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_BLOCK + */ + virtual nsapi_size_or_error_t socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size); + + /** Receive a packet from a remote endpoint + * @param handle Socket handle + * @param address Destination for the remote SocketAddress or null + * @param buffer The buffer for storing the incoming packet data + * If a packet is too long to fit in the supplied buffer, + * excess bytes are discarded + * @param size The length of the buffer + * @return The number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_BLOCK + */ + virtual nsapi_size_or_error_t socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); + + /** Register a callback on state change of the socket + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + * @note Callback may be called in an interrupt context. + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); + + /** Provide access to the NetworkStack object + * + * @return The underlying NetworkStack object + */ + virtual NetworkStack *get_stack() + { + return this; + } + +private: + /** spwf_socket class + * Implementation of SPWF socket structure + */ + typedef struct spwf_socket { + int8_t internal_id; + int spwf_id; + bool server_gone; + bool no_more_data; + nsapi_protocol_t proto; + SocketAddress addr; + } spwf_socket_t; + + bool _socket_is_open(spwf_socket_t *sock) { + if(((unsigned int)sock->internal_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)) { + return (_ids[sock->internal_id].internal_id == sock->internal_id); + } + return false; + } + + bool _socket_has_connected(spwf_socket_t *sock) { + return (_socket_is_open(sock) && (((unsigned int)sock->spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT))); + } + + bool _socket_is_still_connected(spwf_socket_t *sock) { + return (_socket_has_connected(sock) && !sock->server_gone); + } + + bool _socket_is_open(int internal_id) { + if(((unsigned int)internal_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)) { + return (_ids[internal_id].internal_id == internal_id); + } + return false; + } + + bool _socket_has_connected(int internal_id) { + if(!_socket_is_open(internal_id)) return false; + + spwf_socket_t &sock = _ids[internal_id]; + return (sock.spwf_id != SPWFSA_SOCKET_COUNT); + } + + bool _socket_is_still_connected(int internal_id) { + if(!_socket_has_connected(internal_id)) return false; + + spwf_socket_t &sock = _ids[internal_id]; + return (!sock.server_gone); + } + + void reset_credentials() { + memset(ap_ssid, 0, sizeof(ap_ssid)); + memset(ap_pass, 0, sizeof(ap_pass)); + ap_sec = NSAPI_SECURITY_NONE; + } + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW01M1 + SPWFSA01 _spwf; +#elif MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + SPWFSA04 _spwf; +#endif + + bool _isInitialized; + bool _dbg_on; + bool _connected_to_network; + + spwf_socket_t _ids[SPWFSA_SOCKET_COUNT]; + struct { + void (*callback)(void *); + void *data; + } _cbs[SPWFSA_SOCKET_COUNT]; + int _internal_ids[SPWFSA_SOCKET_COUNT]; + + char ap_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */ + nsapi_security_t ap_sec; + char ap_pass[64]; /* The longest allowed passphrase */ + +private: + void event(void); + nsapi_error_t init(void); + nsapi_size_or_error_t _socket_recv(void *handle, void *data, unsigned size, bool datagram); + + + int get_internal_id(int spwf_id) { // checks also if `spwf_id` is (still) "valid" + if(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)) { // valid `spwf_id` + int internal_id = _internal_ids[spwf_id]; + if((_socket_is_open(internal_id)) && (_ids[internal_id].spwf_id == spwf_id)) { + return internal_id; + } else { + return SPWFSA_SOCKET_COUNT; + } + } else { // invalid `spwf_id` + return SPWFSA_SOCKET_COUNT; + } + } + + /* Called at initialization or after module hard fault */ + void inner_constructor() { + memset(_ids, 0, sizeof(_ids)); + memset(_cbs, 0, sizeof(_cbs)); + + for (int sock_cnt = 0; sock_cnt < SPWFSA_SOCKET_COUNT; sock_cnt++) { + _ids[sock_cnt].internal_id = SPWFSA_SOCKET_COUNT; + _ids[sock_cnt].spwf_id = SPWFSA_SOCKET_COUNT; + _internal_ids[sock_cnt] = SPWFSA_SOCKET_COUNT; + } + + _spwf.attach(this, &SpwfSAInterface::event); + + _connected_to_network = false; + _isInitialized = false; + } + +private: + friend class SPWFSAxx; + friend class SPWFSA01; + friend class SPWFSA04; +}; + +#define CHECK_NOT_CONNECTED_ERR() { \ + if(!_connected_to_network) return NSAPI_ERROR_NO_CONNECTION; \ +} \ + + +#endif
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/mbed_app_idw01m1.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/mbed_app_idw01m1.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,9 @@ +{ + "target_overrides": { + "*": { + "idw0xx1.expansion-board": "IDW01M1", + "drivers.uart-serial-txbuf-size": 512, + "drivers.uart-serial-rxbuf-size": 512 + } + } +}
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/mbed_app_idw04a1.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/mbed_app_idw04a1.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,10 @@ +{ + "target_overrides": { + "*": { + "idw0xx1.expansion-board": "IDW04A1", + "drivers.uart-serial-txbuf-size": 512, + "drivers.uart-serial-rxbuf-size": 512 + } + }, + "macros": ["IDW04A1_WIFI_HW_BUG_WA"] +}
diff -r 000000000000 -r 119624335925 easy-connect/wifi-x-nucleo-idw01m1/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-x-nucleo-idw01m1/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,9 @@ +{ + "name": "idw0xx1", + "config": { + "expansion-board":{ + "help": "Options are IDW01M1 and IDW04A1", + "value": "IDW01M1" + } + } +}
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/wizfi310-driver/#e0f7b9355e7e23daaa2d3f1d5c389c52528d6178
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +e0f7b9355e7e23daaa2d3f1d5c389c52528d6178
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +5dfda1506e54116d52517776b3d4bc375b0e47dd
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/wizfi310-driver/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/index Binary file easy-connect/wizfi310-driver/.git/index has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 5dfda1506e54116d52517776b3d4bc375b0e47dd www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322734 +0000 clone: from https://github.com/ARMmbed/wizfi310-driver/ +5dfda1506e54116d52517776b3d4bc375b0e47dd e0f7b9355e7e23daaa2d3f1d5c389c52528d6178 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322735 +0000 checkout: moving from master to e0f7b9355e7e23daaa2d3f1d5c389c52528d6178
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 5dfda1506e54116d52517776b3d4bc375b0e47dd www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322734 +0000 clone: from https://github.com/ARMmbed/wizfi310-driver/
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 5dfda1506e54116d52517776b3d4bc375b0e47dd www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322734 +0000 clone: from https://github.com/ARMmbed/wizfi310-driver/
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/00/401ab45c3204984253869f7d916d6633fe06b2 Binary file easy-connect/wizfi310-driver/.git/objects/00/401ab45c3204984253869f7d916d6633fe06b2 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/00/a2b4aff477485342f02f56fabde59a34531295 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/00/a2b4aff477485342f02f56fabde59a34531295 Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +xÁJÅ0E]÷+f/>f¦m@ÄðÓdúlÒLç×ÛâÞݹçrá<ÏIÁZ÷ ðà:$® ½¦i£Cã¢q}P¸®VÞdQ0c+Q¼3Ôû°mGìm77l¸wMÛV¼ë7xçô%Kçàù_o3§éòüäÈvD<<¢G¬{\Tù׸zË1 I"¼oA ä( V.t<XBÙÊ¥§£_ >ÞÏ|ãwÑþ¾ð,§Ð°^%ùG¦|ýÌÛOµÇú»èj \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/07/2d57faf64c5b01a28db0e3f81cd20eee004fbb Binary file easy-connect/wizfi310-driver/.git/objects/07/2d57faf64c5b01a28db0e3f81cd20eee004fbb has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/09/85d774f0fd529622c2f3ff07769049863d2eb5 Binary file easy-connect/wizfi310-driver/.git/objects/09/85d774f0fd529622c2f3ff07769049863d2eb5 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/0e/85b05165bd11fd946fcb629473f6e2a988ac7f Binary file easy-connect/wizfi310-driver/.git/objects/0e/85b05165bd11fd946fcb629473f6e2a988ac7f has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/0e/9caf92e9fb35c6653fe74e4deabafd079648c8 Binary file easy-connect/wizfi310-driver/.git/objects/0e/9caf92e9fb35c6653fe74e4deabafd079648c8 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/0e/d429d556c14aef2d71cf301c37f1c0d94dc207 Binary file easy-connect/wizfi310-driver/.git/objects/0e/d429d556c14aef2d71cf301c37f1c0d94dc207 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/0e/ff312656892788ff4dd8b888c926aa33813a31 Binary file easy-connect/wizfi310-driver/.git/objects/0e/ff312656892788ff4dd8b888c926aa33813a31 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/12/6c376c9cc004b868e1af16362558f93d51ae62 Binary file easy-connect/wizfi310-driver/.git/objects/12/6c376c9cc004b868e1af16362558f93d51ae62 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/14/ff426bf1f717816ec28d90bab8f6b61b53e931 Binary file easy-connect/wizfi310-driver/.git/objects/14/ff426bf1f717816ec28d90bab8f6b61b53e931 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/15/d4bdd9cd7cd7ed1ee549b89c4a7e99d6658a57 Binary file easy-connect/wizfi310-driver/.git/objects/15/d4bdd9cd7cd7ed1ee549b89c4a7e99d6658a57 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/1e/8270897c70aeef78b6402c1e423b1878b65a39 Binary file easy-connect/wizfi310-driver/.git/objects/1e/8270897c70aeef78b6402c1e423b1878b65a39 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/1f/a99f1f76a6b6a943c487c70e6cad65883dfa9f Binary file easy-connect/wizfi310-driver/.git/objects/1f/a99f1f76a6b6a943c487c70e6cad65883dfa9f has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/20/71f70c4fdc7fdd823f7283fb2613bb955cbb8f Binary file easy-connect/wizfi310-driver/.git/objects/20/71f70c4fdc7fdd823f7283fb2613bb955cbb8f has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/27/a9430a6da43ae3019d404c6e335081aeeebb92 Binary file easy-connect/wizfi310-driver/.git/objects/27/a9430a6da43ae3019d404c6e335081aeeebb92 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/2b/491ac196620ca5c95279b1f2ecf5397babbe12 Binary file easy-connect/wizfi310-driver/.git/objects/2b/491ac196620ca5c95279b1f2ecf5397babbe12 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/2c/0d7ede9521b96108c7ce51a938f1a6a2ab5677 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/2c/0d7ede9521b96108c7ce51a938f1a6a2ab5677 Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +x; +ADçÒósºAÄÈ+ϧW]WÆÑÀÓ»``nVTñ§q¬ÞD qÐÆXÃÅ"Sq,ÁÙ$rÌZ4GêÜ:&²%Å8EÜ̳ø7V,_ÄX2'ý<5¸ÄúyÔ°ýåýiõºÎÓ¸íµ Æ;M°DFTs;+vùVÚ¾0ÌÇú>T«qUZ}ISÅ^Ká \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/2e/7409ca382245f646f6a83f1b167b9f61f8320f Binary file easy-connect/wizfi310-driver/.git/objects/2e/7409ca382245f646f6a83f1b167b9f61f8320f has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/2f/30f60a983da5934aabceadca987814772d91e0 Binary file easy-connect/wizfi310-driver/.git/objects/2f/30f60a983da5934aabceadca987814772d91e0 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/33/820d24ad52508b208afebf766de2a415bda6ec Binary file easy-connect/wizfi310-driver/.git/objects/33/820d24ad52508b208afebf766de2a415bda6ec has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/34/2e1218b8fc8d1b72065788c2667f6a18f33f53 Binary file easy-connect/wizfi310-driver/.git/objects/34/2e1218b8fc8d1b72065788c2667f6a18f33f53 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/35/410c56543df31a4c25f615e19770e994d3670d Binary file easy-connect/wizfi310-driver/.git/objects/35/410c56543df31a4c25f615e19770e994d3670d has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/37/55a1fc09ed014efc2e923a9e194fafebe1f7be Binary file easy-connect/wizfi310-driver/.git/objects/37/55a1fc09ed014efc2e923a9e194fafebe1f7be has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/38/bd26afb7323675521e531790be86c42e41ecab Binary file easy-connect/wizfi310-driver/.git/objects/38/bd26afb7323675521e531790be86c42e41ecab has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/3d/cf4a1948e2c23029e524deb169a22b8e338461 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/3d/cf4a1948e2c23029e524deb169a22b8e338461 Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +xKj!D3vwþ QÛO!äCÖ®z%&mÛØõÇÀÛ@UEN¨¥är³O½Ê%¡Ð{#ÐEÂâ$1u3ìÄFÇ<zåá< NKë¼HBÒ«³~¢HH£Ö÷£÷o8Î3ïÏøïG~ÅVPË-WÆh 7¾rÎf;E;ýax Ø{9eêqõ6BF½Â¸§ø±g¿|]õ4H ÇÞá÷Aûë"_p \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/3e/449bc9238964c7ab9b8144ec1b8d64f3ca0cb3 Binary file easy-connect/wizfi310-driver/.git/objects/3e/449bc9238964c7ab9b8144ec1b8d64f3ca0cb3 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/3e/55a70b5c26517e2eb76ec236f2d760951f5809 Binary file easy-connect/wizfi310-driver/.git/objects/3e/55a70b5c26517e2eb76ec236f2d760951f5809 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/44/3b26c8fbd375fee896203b09947fd55a10feca Binary file easy-connect/wizfi310-driver/.git/objects/44/3b26c8fbd375fee896203b09947fd55a10feca has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/44/da28b3939492182c12d5617a4da95ac9a2e693 Binary file easy-connect/wizfi310-driver/.git/objects/44/da28b3939492182c12d5617a4da95ac9a2e693 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/46/e27ea53f589f93c6f6881b6cd68025ae1367f8 Binary file easy-connect/wizfi310-driver/.git/objects/46/e27ea53f589f93c6f6881b6cd68025ae1367f8 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/48/3e0b9c0330ae3a53fe79e3aa1bafa6ee765616 Binary file easy-connect/wizfi310-driver/.git/objects/48/3e0b9c0330ae3a53fe79e3aa1bafa6ee765616 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/49/41c44aa94f5d7508a6f797a172c77c18d5d5c2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/49/41c44aa94f5d7508a6f797a172c77c18d5d5c2 Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +x»j1ESë+¦7Ñk%A©Ò¥N=F¶weä1Æþúl>ݹ.2Öµ%¼Èdçl6K-W|ci1h3¦äB«ÞÆÆ Ô &o)p4½ñ5:jV£uÆUÏ5G²To!eE79 ?Ô¼EÞþøã¸R?¿±¾öÚ&4h8`BT»Ý ÿuV_£öÖ¹Hà»??û ý +W÷9¶ã>Êmvy<.¬~°rSÎ \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/4e/b6236c8af779825bc7839803f2ac399b181dfc Binary file easy-connect/wizfi310-driver/.git/objects/4e/b6236c8af779825bc7839803f2ac399b181dfc has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/51/f93f992e7582e579999c6fedea9b70a0b9ad98 Binary file easy-connect/wizfi310-driver/.git/objects/51/f93f992e7582e579999c6fedea9b70a0b9ad98 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/54/f0857b2addfac6ed2ec1d32ef75410569f7aa6 Binary file easy-connect/wizfi310-driver/.git/objects/54/f0857b2addfac6ed2ec1d32ef75410569f7aa6 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/59/de1c488e73b30b8af04e7682e55c0023dffb1c Binary file easy-connect/wizfi310-driver/.git/objects/59/de1c488e73b30b8af04e7682e55c0023dffb1c has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/5d/6e1992a0d858f4e3aeffc980cc7d8e6e84b8a1 Binary file easy-connect/wizfi310-driver/.git/objects/5d/6e1992a0d858f4e3aeffc980cc7d8e6e84b8a1 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/5d/fda1506e54116d52517776b3d4bc375b0e47dd Binary file easy-connect/wizfi310-driver/.git/objects/5d/fda1506e54116d52517776b3d4bc375b0e47dd has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/5f/119106e9e80ce289a4a8e753686f1c3713b6a2 Binary file easy-connect/wizfi310-driver/.git/objects/5f/119106e9e80ce289a4a8e753686f1c3713b6a2 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/75/4b51dc057d8aae08085051911d1e70351b387e Binary file easy-connect/wizfi310-driver/.git/objects/75/4b51dc057d8aae08085051911d1e70351b387e has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/7a/26c47b7a7bc9148293461b7dcd774d71bb300e Binary file easy-connect/wizfi310-driver/.git/objects/7a/26c47b7a7bc9148293461b7dcd774d71bb300e has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/7d/49f14abb61a9d7a4ec8a001e1840e2adc386aa Binary file easy-connect/wizfi310-driver/.git/objects/7d/49f14abb61a9d7a4ec8a001e1840e2adc386aa has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/7e/442de6ee3c1f594f0b516f0a4305786b24e0e4 Binary file easy-connect/wizfi310-driver/.git/objects/7e/442de6ee3c1f594f0b516f0a4305786b24e0e4 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/80/b83dbacb9ba0691ee5cc63e388875de2f0dc9b Binary file easy-connect/wizfi310-driver/.git/objects/80/b83dbacb9ba0691ee5cc63e388875de2f0dc9b has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/82/abc831be67639211674f0b2f300bef5762dff2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/82/abc831be67639211674f0b2f300bef5762dff2 Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +x½P1Â0dÎ+¬L 1ÊÄ`d@H°&BR¥i©Zõï$)-lx²Î§»óIe$ldÖ1ðõx ßRS²^ñå§FçtóE ]°Ãï¨ p¾BArc¡DKBÐ:2lZíákJæjÁqñ¶k¡ªé¸ãw?ä +$n¿Ä8ý/F²£Çtc!{-¤Bÿ®g2·2vóûí\¨?Çg={rnr \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/8a/528dbee9038ed90855836556014e9389539f41 Binary file easy-connect/wizfi310-driver/.git/objects/8a/528dbee9038ed90855836556014e9389539f41 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/91/6170f3c0bc5a1a15e2a6ee0340515f29fdc883 Binary file easy-connect/wizfi310-driver/.git/objects/91/6170f3c0bc5a1a15e2a6ee0340515f29fdc883 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/96/21f62afe178351ff2ed654b870615f7a48c47f Binary file easy-connect/wizfi310-driver/.git/objects/96/21f62afe178351ff2ed654b870615f7a48c47f has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/97/dbe5ef12656b8f8ab04be92095afd769915fc9 Binary file easy-connect/wizfi310-driver/.git/objects/97/dbe5ef12656b8f8ab04be92095afd769915fc9 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/97/e82be525d84af3103424d5e4e1e8a3ad35f79b --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/97/e82be525d84af3103424d5e4e1e8a3ad35f79b Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +x½jÄ0Së)¶ZýYR]XI«³H,ßyú4éÓÍ|ÃSÖeéf²O²3ºÖ ¹ap¸XÎc9`öEµÑÎC p¡Xt®%cõNû:·S*9hªN£2¯;|Pÿæ½FxùËo· ú祬Ë+ GÑháY'ÕIÏÂÿÕµ?¸Ì$p~l\äìïW¨$ýë!Û!ð5ó;ÚÇíw»¨DUÇ \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/98/c1fdf41760af2e67ade48bc754106da6d67135 Binary file easy-connect/wizfi310-driver/.git/objects/98/c1fdf41760af2e67ade48bc754106da6d67135 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/9b/d4203e9b6ae90071c913337f9ce43039b5d381 Binary file easy-connect/wizfi310-driver/.git/objects/9b/d4203e9b6ae90071c913337f9ce43039b5d381 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/9c/1d51bf6e8d5e2a0ab9cee5636d489f2d2cbb11 Binary file easy-connect/wizfi310-driver/.git/objects/9c/1d51bf6e8d5e2a0ab9cee5636d489f2d2cbb11 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/9c/825b35d795d0944c2c01928b183dd8a5649656 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/9c/825b35d795d0944c2c01928b183dd8a5649656 Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,5 @@ +xK +1]çÙC:¿N@Ä«ô$=4Ñ §wvî]<( + +^jµ!µ1»ÑeRÙ .1û 22d¼M{ö50hMâA×!m´¬%vq +äH:!&Ùe´ ׸¶.oT>¼§@|¾T*÷)µzàÀãSr¯¢Rb³ÛÅÁÅ¢smouæ|hÏé^fñ"ÃGa \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/9d/2cf66e0fbc14b020e91d035b89a2055ddaa879 Binary file easy-connect/wizfi310-driver/.git/objects/9d/2cf66e0fbc14b020e91d035b89a2055ddaa879 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/a7/42404bad762433025e4fc2bde434909b15beb0 Binary file easy-connect/wizfi310-driver/.git/objects/a7/42404bad762433025e4fc2bde434909b15beb0 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/a9/518f3fc76aecd91dfc153afdd0f88ee7e3fa5a Binary file easy-connect/wizfi310-driver/.git/objects/a9/518f3fc76aecd91dfc153afdd0f88ee7e3fa5a has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/aa/69a975673ab0313d93975f911910dd1e140745 Binary file easy-connect/wizfi310-driver/.git/objects/aa/69a975673ab0313d93975f911910dd1e140745 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/af/5801a4eaa092d267d340035025d25bdeb10ea4 Binary file easy-connect/wizfi310-driver/.git/objects/af/5801a4eaa092d267d340035025d25bdeb10ea4 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/b4/60979bfb17363ba28ec2a0f0a3bbae07d04657 Binary file easy-connect/wizfi310-driver/.git/objects/b4/60979bfb17363ba28ec2a0f0a3bbae07d04657 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/b4/e3469322445a5a724ceec5b3d7cd3a4138f29e --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/b4/e3469322445a5a724ceec5b3d7cd3a4138f29e Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +xµ±0ûN8@prVÀèÚÂUÔ»ÛÁÅèäMÿ.ÿÿÝqe8l²lÑðE5»#Ý}ÈNÈ,MèzÔs£ ¼úIO¢] ÐOEo¨Ê`pº@)5c¡B+o¡1wÒhp°uhµld°<ËîW¯ÈÙ±aªL»ÎÙÃȨýqüFò£@^Ð#Ýô½f\¡?×o2×*þæ÷Ù© +ßwÇn yñµn9 \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/b7/6c36970375f3160aafc7656f13461f8abaef50 Binary file easy-connect/wizfi310-driver/.git/objects/b7/6c36970375f3160aafc7656f13461f8abaef50 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/b9/7122329d3098d49730df275c92b84991e19748 Binary file easy-connect/wizfi310-driver/.git/objects/b9/7122329d3098d49730df275c92b84991e19748 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/be/65fd9b32f49571fb3b51b693f85ff39daf0e2e Binary file easy-connect/wizfi310-driver/.git/objects/be/65fd9b32f49571fb3b51b693f85ff39daf0e2e has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/be/ed53fc1c95d1dfe669293d5f810b3433fecbd8 Binary file easy-connect/wizfi310-driver/.git/objects/be/ed53fc1c95d1dfe669293d5f810b3433fecbd8 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/c0/d63215cee680d7e1da9eda926e63e21e122a77 Binary file easy-connect/wizfi310-driver/.git/objects/c0/d63215cee680d7e1da9eda926e63e21e122a77 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/c5/355f3cf28190b268b60c074a9d87a39c004459 Binary file easy-connect/wizfi310-driver/.git/objects/c5/355f3cf28190b268b60c074a9d87a39c004459 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/c9/cf86315b34821d034dcbdf0a4fdfc287951a61 Binary file easy-connect/wizfi310-driver/.git/objects/c9/cf86315b34821d034dcbdf0a4fdfc287951a61 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/cc/40b4406711db805de7a3a5a3b276de09d040e0 Binary file easy-connect/wizfi310-driver/.git/objects/cc/40b4406711db805de7a3a5a3b276de09d040e0 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/cd/f18f963bf7b878b9801d5f590f99222ecaeb5d Binary file easy-connect/wizfi310-driver/.git/objects/cd/f18f963bf7b878b9801d5f590f99222ecaeb5d has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/ce/2d6f94acbcedc5a808c8b4382b5d1280feded4 Binary file easy-connect/wizfi310-driver/.git/objects/ce/2d6f94acbcedc5a808c8b4382b5d1280feded4 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/ce/f66c3144f95b8d5405810bff899cb60ad40127 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/ce/f66c3144f95b8d5405810bff899cb60ad40127 Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +xÎA +Â0 a×9ÅìL2m"zI2Ñ¢±RÓ§·;÷î?<øòÜÚÔ\ÜõE²RjôSÖYwK«-Þ¼dÑgD¡ä¥V?>°óT*URQâ<;K¬ý6/pé£ÏÀháøÛçkéqÈs;eëµn$ØcD4[Ý]ÿ:KÙ¸ÐõÝßëÔêhIù¥hJ \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/d8/55f95f69f75e67e1026d062834fcf510756e36 Binary file easy-connect/wizfi310-driver/.git/objects/d8/55f95f69f75e67e1026d062834fcf510756e36 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/d8/be40eae25fe17ea60c6de31f529f7ef421b59f Binary file easy-connect/wizfi310-driver/.git/objects/d8/be40eae25fe17ea60c6de31f529f7ef421b59f has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/dc/036e7f55cc86358b1da0e8c7f744e3a403a68c Binary file easy-connect/wizfi310-driver/.git/objects/dc/036e7f55cc86358b1da0e8c7f744e3a403a68c has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/df/9cbdfd31fba2901a96eb682922fff3d935c6d3 Binary file easy-connect/wizfi310-driver/.git/objects/df/9cbdfd31fba2901a96eb682922fff3d935c6d3 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/e0/c44112e8a36753ca7add1d975882ca0d0209cc Binary file easy-connect/wizfi310-driver/.git/objects/e0/c44112e8a36753ca7add1d975882ca0d0209cc has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/e0/f7b9355e7e23daaa2d3f1d5c389c52528d6178 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/e0/f7b9355e7e23daaa2d3f1d5c389c52528d6178 Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +x»j1E]ë+¦7=V3`ãÚMþ`$lá}µ@¾>Û¥Ow9p7/ÓÔ:Xo}:$Ǭ|~`E"MÌ ,ÁèÕW;És"ç²å*X¢w #W\FN·þXVxrû9xmàãoï·ñé7:#8ꨵÚé~±Ë¿du[J«M +ìWÒvḭ̈½._·ëÕ/ÙFMç \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/e2/a0b9ed1e5fd94f6e164a6e2416ddcfadce289a --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/e2/a0b9ed1e5fd94f6e164a6e2416ddcfadce289a Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +xuË +@F[÷ÿhCÔfê2à%f´ÄÍOê@7r|ÿ¤Mv¶çðñÕÝXu鮯MÖÌ (ÐS Ò"E±s¢ª2|Æ¥Ð4iÆ~zvO|Á1#¼É*ÔuPkÉ¿OòâiÍwe³ÈKÆÏFæ°i¸ðÙ×ò}¥!r%¯Bi,<£Jz1ªÒ/BÔ²ìè~×þåùOÞìßW\ú \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/e3/ff13799017881625c8df6503d6f3e121516bf6 Binary file easy-connect/wizfi310-driver/.git/objects/e3/ff13799017881625c8df6503d6f3e121516bf6 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/e5/b5886878a8dd2cb06d1740acda01293f760df9 Binary file easy-connect/wizfi310-driver/.git/objects/e5/b5886878a8dd2cb06d1740acda01293f760df9 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/e6/3195ae4ab54a1510b868b8cd368909f18010b3 Binary file easy-connect/wizfi310-driver/.git/objects/e6/3195ae4ab54a1510b868b8cd368909f18010b3 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/e7/8ec79cf496133c2afe4196d953b69af5b3c6ab --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/e7/8ec79cf496133c2afe4196d953b69af5b3c6ab Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +xA +Â0E]ç³dâ4I"'¤¶hÆ Þºrïîñy^È)MÔîj¦%Aß$BbCQ\·kϳÆj«.2WðβCr&¶ÈÃW«cË%Tü¬c.pçé-skPÃéÇ!ñô8Î 6HÆQ{ìÕ¶nUþ:«kßK·¼¼Ê4¬+¢>À¹I¯ \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/e8/2268b5ebb1aa4aec1e2b3525d0b5640d82fcc7 Binary file easy-connect/wizfi310-driver/.git/objects/e8/2268b5ebb1aa4aec1e2b3525d0b5640d82fcc7 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/ea/0cea6d8c45d6e899fe656c13e05cd578d46fb6 Binary file easy-connect/wizfi310-driver/.git/objects/ea/0cea6d8c45d6e899fe656c13e05cd578d46fb6 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/ea/c6ce00407e87029d520e5cb3fa445f5fbd2670 Binary file easy-connect/wizfi310-driver/.git/objects/ea/c6ce00407e87029d520e5cb3fa445f5fbd2670 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/f0/5e9ec62379951ad4ad42bb3fdd5fdce9df373c Binary file easy-connect/wizfi310-driver/.git/objects/f0/5e9ec62379951ad4ad42bb3fdd5fdce9df373c has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/f1/fd445acfd0a79dcc6af6b5e55aa47150e73d89 Binary file easy-connect/wizfi310-driver/.git/objects/f1/fd445acfd0a79dcc6af6b5e55aa47150e73d89 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/f3/ccff32c1709f1a597d93faf374d9c529b75251 Binary file easy-connect/wizfi310-driver/.git/objects/f3/ccff32c1709f1a597d93faf374d9c529b75251 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/f4/b3a1720efb5c954a1882677ee07aad726de695 Binary file easy-connect/wizfi310-driver/.git/objects/f4/b3a1720efb5c954a1882677ee07aad726de695 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/f8/630fc0e322c960c8bd3fe8a1283ddf7369d4ae Binary file easy-connect/wizfi310-driver/.git/objects/f8/630fc0e322c960c8bd3fe8a1283ddf7369d4ae has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/f8/b0d6b9cae85fedee1afbf5dc96e9761d51004e Binary file easy-connect/wizfi310-driver/.git/objects/f8/b0d6b9cae85fedee1afbf5dc96e9761d51004e has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/f9/0c70dd59bebba7854b632e80348cf31f8fc0bb Binary file easy-connect/wizfi310-driver/.git/objects/f9/0c70dd59bebba7854b632e80348cf31f8fc0bb has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/fb/2afde9cba8b0b8d24553673e6c2fcaee969a5b Binary file easy-connect/wizfi310-driver/.git/objects/fb/2afde9cba8b0b8d24553673e6c2fcaee969a5b has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/fc/d6a31d15893cac88aefd2c36189c8b1915437b Binary file easy-connect/wizfi310-driver/.git/objects/fc/d6a31d15893cac88aefd2c36189c8b1915437b has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/fe/571f99ec0414a974082283951cd71329db85f1 Binary file easy-connect/wizfi310-driver/.git/objects/fe/571f99ec0414a974082283951cd71329db85f1 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/fe/e3eaea4fe3859351cc2605c0ff2d1484ad7217 Binary file easy-connect/wizfi310-driver/.git/objects/fe/e3eaea4fe3859351cc2605c0ff2d1484ad7217 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/ff/182764540d789a7f5ff6ae17fd7745349b5886 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/objects/ff/182764540d789a7f5ff6ae17fd7745349b5886 Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ +x¥Kj1½Ö)z0R·$K`BÜ¡GjÙçǸ'ç÷rìªjñxeÇ^C8è*> +µrËTb)¹.ÅÀâ(Z2¯2)P-ͳË> $Yú*»$DÉGgxÓǼÂeRíáÆÛ²ôÃýøüó/^ÇcÇOp3Yë3ÁÝÁìu?ªò s}ðt +Uo¼@gø¾7¤{Q` \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/objects/ff/18371b9ca9218388c1c3b8ed203f47e9d31c77 Binary file easy-connect/wizfi310-driver/.git/objects/ff/18371b9ca9218388c1c3b8ed203f47e9d31c77 has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ +# pack-refs with: peeled +5dfda1506e54116d52517776b3d4bc375b0e47dd refs/remotes/origin/master +e78ec79cf496133c2afe4196d953b69af5b3c6ab refs/tags/V1.0
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +5dfda1506e54116d52517776b3d4bc375b0e47dd
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,34 @@ +# The WizFi310 WiFi driver for mbed-os +The mbed OS driver for the WizFi310 Wi-Fi module + +## Testing +The WizFi310 library contains the core network tests taken from mbed OS. To run the tests you will need mbed CLI and mbed OS. + +First, setup the the WizFi310-driver and mbed-os repositories for testing: +``` bash +# Sets up the WizFi310 for testing +mbed import wizfi310-driver +cd wizfi310-driver +mbed add mbed-os +``` + +Now you should be able to run the network tests with `mbed test`: +``` bash +# Runs the WizFi310 network tests, requires a wifi access point +mbed test -t <COMPILER HERE> -m <BOARD HERE> -n tests-net* --compile -DMBED_CFG_WIZFI310_SSID=<SSID HERE> -DMBED_CFG_WIZFI310_PASS=<PASS HERE> +mbed test -t <COMPILER HERE> -m <BOARD HERE> -n tests-net* --run --verbose +``` + +There are a couple other options that can be used during testing: +- MBED_CFG_WIZFI310_SSID - SSID of the wifi access point to connect to +- MBED_CFG_WIZFI310_PASS - Passphrase of the wifi access point to connect to +- MBED_CFG_WIZFI310_TX - TX pin for the WizFi310 serial connection (defaults to D1) +- MBED_CFG_WIZFI310_RX - TX pin for the WizFi310 serial connection (defaults to D0) +- MBED_CFG_WIZFI310_DEBUG - Enabled debug output from the WizFi310 + +For example, here is how to enabled the debug output from the WizFi310: +``` bash +# Run the WizFi310 network tests with debug output, requires a wifi access point +mbed test -t <COMPILER HERE> -m <BOARD HERE> -n tests-net* --compile -DMBED_CFG_WIZFI310_SSID=<SSID HERE> -DMBED_CFG_WIZFI310_PASS=<PASS HERE> -MBED_CFG_WIZFI310_DEBUG=true +mbed test -t <COMPILER HERE> -m <BOARD HERE> -n tests-net* --run --verbose +```
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/connectivity/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/connectivity/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,76 @@ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" + +#include "WizFi310Interface.h" + +using namespace utest::v1; + +#ifndef MBED_CFG_WIZFI310_TX +#define MBED_CFG_WIZFI310_TX D1 +#endif + +#ifndef MBED_CFG_WIZFI310_RX +#define MBED_CFG_WIZFI310_RX D0 +#endif + +#ifndef MBED_CFG_WIZFI310_DEBUG +#define MBED_CFG_WIZFI310_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Bringing the network up and down +template <int COUNT> +void test_bring_up_down() { + WizFi310Interface net(MBED_CFG_WIZFI310_TX, MBED_CFG_WIZFI310_RX, MBED_CFG_WIZFI310_DEBUG); + net.set_credentials(STRINGIZEWIZFI310_SSID), STRINGIZE(MBED_CFG_WIZFI310_PASS)); + + for (int i = 0; i < COUNT; i++) { + int err = net.connect(); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: IP Address %s\r\n", net.get_ip_address()); + printf("MBED: Netmask %s\r\n", net.get_netmask()); + printf("MBED: Gateway %s\r\n", net.get_gateway()); + TEST_ASSERT(net.get_ip_address()); + TEST_ASSERT(net.get_netmask()); + TEST_ASSERT(net.get_gateway()); + + UDPSocket udp; + err = udp.open(&net); + TEST_ASSERT_EQUAL(0, err); + err = udp.close(); + TEST_ASSERT_EQUAL(0, err); + + TCPSocket tcp; + err = tcp.open(&net); + TEST_ASSERT_EQUAL(0, err); + err = tcp.close(); + TEST_ASSERT_EQUAL(0, err); + + err = net.disconnect(); + TEST_ASSERT_EQUAL(0, err); + } +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Bringing the network up and down", test_bring_up_down<1>), + Case("Bringing the network up and down twice", test_bring_up_down<2>), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/gethostbyname/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/gethostbyname/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,118 @@ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include "WizFi310Interface.h" + +using namespace utest::v1; + +// Hostname for testing against +// Must have A and AAAA records +#ifndef MBED_DNS_TEST_HOST +#define MBED_DNS_TEST_HOST "connector.mbed.com" +#endif + +#ifndef MBED_CFG_WIZFI310_TX +#define MBED_CFG_WIZFI310_TX D1 +#endif + +#ifndef MBED_CFG_WIZFI310_RX +#define MBED_CFG_WIZFI310_RX D0 +#endif + +#ifndef MBED_CFG_WIZFI310_DEBUG +#define MBED_CFG_WIZFI310_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + +// Address info from stack +const char *ip_literal; +nsapi_version_t ip_pref; +const char *ip_pref_repr; + +// Network setup +WizFi310Interface net(MBED_CFG_WIZFI310_TX, MBED_CFG_WIZFI310_RX, MBED_CFG_WIZFI310_DEBUG); +void net_bringup() { + int err = net.connect(STRINGIZE(MBED_CFG_WIZFI310_SSID), STRINGIZE(MBED_CFG_WIZFI310_PASS)); + TEST_ASSERT_EQUAL(0, err); + printf("MBED: Connected to network\n"); + printf("MBED: IP Address: %s\n", net.get_ip_address()); + + ip_literal = net.get_ip_address(); + ip_pref = SocketAddress(ip_literal).get_ip_version(); + ip_pref_repr = (ip_pref == NSAPI_IPv4) ? "ipv4" : + (ip_pref == NSAPI_IPv6) ? "ipv6" : "unspec"; +} + + +// DNS tests +void test_dns_query() { + SocketAddress addr; + int err = net.gethostbyname(MBED_DNS_TEST_HOST, &addr); + printf("DNS: query \"%s\" => \"%s\"\n", + MBED_DNS_TEST_HOST, addr.get_ip_address()); + + TEST_ASSERT_EQUAL(0, err); + TEST_ASSERT((bool)addr); + TEST_ASSERT(strlen(addr.get_ip_address()) > 1); +} + +void test_dns_query_pref() { + SocketAddress addr; + int err = net.gethostbyname(MBED_DNS_TEST_HOST, &addr, ip_pref); + printf("DNS: query %s \"%s\" => \"%s\"\n", + ip_pref_repr, MBED_DNS_TEST_HOST, addr.get_ip_address()); + + TEST_ASSERT_EQUAL(0, err); + TEST_ASSERT((bool)addr); + TEST_ASSERT(strlen(addr.get_ip_address()) > 1); + TEST_ASSERT_EQUAL(ip_pref, addr.get_ip_version()); +} + +void test_dns_literal() { + SocketAddress addr; + int err = net.gethostbyname(ip_literal, &addr); + printf("DNS: literal \"%s\" => \"%s\"\n", + ip_literal, addr.get_ip_address()); + + TEST_ASSERT_EQUAL(0, err); + TEST_ASSERT((bool)addr); + TEST_ASSERT(strlen(addr.get_ip_address()) > 1); + TEST_ASSERT(strcmp(ip_literal, addr.get_ip_address()) == 0); +} + +void test_dns_literal_pref() { + SocketAddress addr; + int err = net.gethostbyname(ip_literal, &addr, ip_pref); + printf("DNS: literal %s \"%s\" => \"%s\"\n", + ip_pref_repr, ip_literal, addr.get_ip_address()); + + TEST_ASSERT_EQUAL(0, err); + TEST_ASSERT((bool)addr); + TEST_ASSERT(strlen(addr.get_ip_address()) > 1); + TEST_ASSERT_EQUAL(ip_pref, addr.get_ip_version()); + TEST_ASSERT(strcmp(ip_literal, addr.get_ip_address()) == 0); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "default_auto"); + net_bringup(); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("DNS query", test_dns_query), + Case("DNS preference query", test_dns_query_pref), + Case("DNS literal", test_dns_literal), + Case("DNS preference literal", test_dns_literal_pref), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/host_tests/tcp_echo.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/host_tests/tcp_echo.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,195 @@ +# Copyright 2015 ARM Limited, All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import select +import socket +import logging +from threading import Thread +from sys import stdout +from SocketServer import BaseRequestHandler, TCPServer +from mbed_host_tests import BaseHostTest, event_callback + + +class TCPEchoClientHandler(BaseRequestHandler): + def handle(self): + """ + Handles a connection. Test starts by client(i.e. mbed) connecting to server. + This connection handler receives data and echoes back to the client util + {{end}} is received. Then it sits on recv() for client to terminate the + connection. + + Note: reason for not echoing data back after receiving {{end}} is that send + fails raising a SocketError as client closes connection. + """ + while self.server.isrunning(): + try: + data = self.recv() + if not data: break + except Exception as e: + break + + try: + # echo data back to the client + self.send(data) + except Exception as e: + break + + def recv(self): + """ + Try to receive until server is shutdown + """ + while self.server.isrunning(): + rl, wl, xl = select.select([self.request], [], [], 1) + if len(rl): + return self.request.recv(1024) + + def send(self, data): + """ + Try to send until server is shutdown + """ + while self.server.isrunning(): + rl, wl, xl = select.select([], [self.request], [], 1) + if len(wl): + self.request.sendall(data) + break + + +class TCPServerWrapper(TCPServer): + """ + Wrapper over TCP server to implement server initiated shutdown. + Adds a flag:= running that a request handler can check and come out of + recv loop when shutdown is called. + """ + + def __init__(self, addr, request_handler): + # hmm, TCPServer is not sub-classed from object! + if issubclass(TCPServer, object): + super(TCPServerWrapper, self).__init__(addr, request_handler) + else: + TCPServer.__init__(self, addr, request_handler) + self.running = False + + def serve_forever(self): + self.running = True + if issubclass(TCPServer, object): + super(TCPServerWrapper, self).serve_forever() + else: + TCPServer.serve_forever(self) + + def shutdown(self): + self.running = False + if issubclass(TCPServer, object): + super(TCPServerWrapper, self).shutdown() + else: + TCPServer.shutdown(self) + + def isrunning(self): + return self.running + + +class TCPEchoClientTest(BaseHostTest): + + def __init__(self): + """ + Initialise test parameters. + + :return: + """ + BaseHostTest.__init__(self) + self.SERVER_IP = None # Will be determined after knowing the target IP + self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port + self.server = None + self.server_thread = None + self.target_ip = None + + @staticmethod + def find_interface_to_target_addr(target_ip): + """ + Finds IP address of the interface through which it is connected to the target. + + :return: + """ + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect((target_ip, 0)) # Target IP, any port + except socket.error: + s.connect((target_ip, 8000)) # Target IP, 'random' port + ip = s.getsockname()[0] + s.close() + return ip + + def setup_tcp_server(self): + """ + sets up a TCP server for target to connect and send test data. + + :return: + """ + # !NOTE: There should mechanism to assert in the host test + if self.SERVER_IP is None: + self.log("setup_tcp_server() called before determining server IP!") + self.notify_complete(False) + + # Returning none will suppress host test from printing success code + self.server = TCPServerWrapper((self.SERVER_IP, self.SERVER_PORT), TCPEchoClientHandler) + ip, port = self.server.server_address + self.SERVER_PORT = port + self.server.allow_reuse_address = True + self.log("HOST: Listening for TCP connections: " + self.SERVER_IP + ":" + str(self.SERVER_PORT)) + self.server_thread = Thread(target=TCPEchoClientTest.server_thread_func, args=(self,)) + self.server_thread.start() + + @staticmethod + def server_thread_func(this): + """ + Thread function to run TCP server forever. + + :param this: + :return: + """ + this.server.serve_forever() + + @event_callback("target_ip") + def _callback_target_ip(self, key, value, timestamp): + """ + Callback to handle reception of target's IP address. + + :param key: + :param value: + :param timestamp: + :return: + """ + self.target_ip = value + self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip) + self.setup_tcp_server() + + @event_callback("host_ip") + def _callback_host_ip(self, key, value, timestamp): + """ + Callback for request for host IP Addr + + """ + self.send_kv("host_ip", self.SERVER_IP) + + @event_callback("host_port") + def _callback_host_port(self, key, value, timestamp): + """ + Callback for request for host port + """ + self.send_kv("host_port", self.SERVER_PORT) + + def teardown(self): + if self.server: + self.server.shutdown() + self.server_thread.join()
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/host_tests/tcp_echo.pyc Binary file easy-connect/wizfi310-driver/TESTS/net/host_tests/tcp_echo.pyc has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/host_tests/udp_echo.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/host_tests/udp_echo.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,127 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import sys +import socket +from sys import stdout +from threading import Thread +from SocketServer import BaseRequestHandler, UDPServer +from mbed_host_tests import BaseHostTest, event_callback + + +class UDPEchoClientHandler(BaseRequestHandler): + def handle(self): + """ UDP packet handler. Echoes data back to sender's address. + """ + data, sock = self.request + sock.sendto(data, self.client_address) + + +class UDPEchoClientTest(BaseHostTest): + + def __init__(self): + """ + Initialise test parameters. + + :return: + """ + BaseHostTest.__init__(self) + self.SERVER_IP = None # Will be determined after knowing the target IP + self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port + self.server = None + self.server_thread = None + self.target_ip = None + + @staticmethod + def find_interface_to_target_addr(target_ip): + """ + Finds IP address of the interface through which it is connected to the target. + + :return: + """ + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect((target_ip, 0)) # Target IP, any port + except socket.error: + s.connect((target_ip, 8000)) # Target IP, 'random' port + ip = s.getsockname()[0] + s.close() + return ip + + def setup_udp_server(self): + """ + sets up a UDP server for target to connect and send test data. + + :return: + """ + # !NOTE: There should mechanism to assert in the host test + if self.SERVER_IP is None: + self.log("setup_udp_server() called before determining server IP!") + self.notify_complete(False) + + # Returning none will suppress host test from printing success code + self.server = UDPServer((self.SERVER_IP, self.SERVER_PORT), UDPEchoClientHandler) + ip, port = self.server.server_address + self.SERVER_PORT = port + self.server.allow_reuse_address = True + self.log("HOST: Listening for UDP packets: " + self.SERVER_IP + ":" + str(self.SERVER_PORT)) + self.server_thread = Thread(target=UDPEchoClientTest.server_thread_func, args=(self,)) + self.server_thread.start() + + @staticmethod + def server_thread_func(this): + """ + Thread function to run TCP server forever. + + :param this: + :return: + """ + this.server.serve_forever() + + @event_callback("target_ip") + def _callback_target_ip(self, key, value, timestamp): + """ + Callback to handle reception of target's IP address. + + :param key: + :param value: + :param timestamp: + :return: + """ + self.target_ip = value + self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip) + self.setup_udp_server() + + @event_callback("host_ip") + def _callback_host_ip(self, key, value, timestamp): + """ + Callback for request for host IP Addr + + """ + self.send_kv("host_ip", self.SERVER_IP) + + @event_callback("host_port") + def _callback_host_port(self, key, value, timestamp): + """ + Callback for request for host port + """ + self.send_kv("host_port", self.SERVER_PORT) + + def teardown(self): + if self.server: + self.server.shutdown() + self.server_thread.join()
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/host_tests/udp_echo.pyc Binary file easy-connect/wizfi310-driver/TESTS/net/host_tests/udp_echo.pyc has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/host_tests/udp_shotgun.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/host_tests/udp_shotgun.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,142 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import sys +import socket +import json +import random +import itertools +import time +from sys import stdout +from threading import Thread +from SocketServer import BaseRequestHandler, UDPServer +from mbed_host_tests import BaseHostTest, event_callback + + +class UDPEchoClientHandler(BaseRequestHandler): + def handle(self): + """ UDP packet handler. Responds with multiple simultaneous packets + """ + data, sock = self.request + pattern = [ord(d) << 4 for d in data] + + # Each byte in request indicates size of packet to recieve + # Each packet size is shifted over by 4 to fit in a byte, which + # avoids any issues with endianess or decoding + for packet in pattern: + data = [random.randint(0, 255) for _ in range(packet-1)] + data.append(reduce(lambda a,b: a^b, data)) + data = ''.join(map(chr, data)) + sock.sendto(data, self.client_address) + + # Sleep a tiny bit to compensate for local network + time.sleep(0.01) + + +class UDPEchoClientTest(BaseHostTest): + def __init__(self): + """ + Initialise test parameters. + + :return: + """ + BaseHostTest.__init__(self) + self.SERVER_IP = None # Will be determined after knowing the target IP + self.SERVER_PORT = 0 # Let TCPServer choose an arbitrary port + self.server = None + self.server_thread = None + self.target_ip = None + + @staticmethod + def find_interface_to_target_addr(target_ip): + """ + Finds IP address of the interface through which it is connected to the target. + + :return: + """ + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + s.connect((target_ip, 0)) # Target IP, any port + except socket.error: + s.connect((target_ip, 8000)) # Target IP, 'random' port + ip = s.getsockname()[0] + s.close() + return ip + + def setup_udp_server(self): + """ + sets up a UDP server for target to connect and send test data. + + :return: + """ + # !NOTE: There should mechanism to assert in the host test + if self.SERVER_IP is None: + self.log("setup_udp_server() called before determining server IP!") + self.notify_complete(False) + + # Returning none will suppress host test from printing success code + self.server = UDPServer((self.SERVER_IP, self.SERVER_PORT), UDPEchoClientHandler) + ip, port = self.server.server_address + self.SERVER_PORT = port + self.server.allow_reuse_address = True + self.log("HOST: Listening for UDP packets: " + self.SERVER_IP + ":" + str(self.SERVER_PORT)) + self.server_thread = Thread(target=UDPEchoClientTest.server_thread_func, args=(self,)) + self.server_thread.start() + + @staticmethod + def server_thread_func(this): + """ + Thread function to run TCP server forever. + + :param this: + :return: + """ + this.server.serve_forever() + + @event_callback("target_ip") + def _callback_target_ip(self, key, value, timestamp): + """ + Callback to handle reception of target's IP address. + + :param key: + :param value: + :param timestamp: + :return: + """ + self.target_ip = value + self.SERVER_IP = self.find_interface_to_target_addr(self.target_ip) + self.setup_udp_server() + + @event_callback("host_ip") + def _callback_host_ip(self, key, value, timestamp): + """ + Callback for request for host IP Addr + + """ + self.send_kv("host_ip", self.SERVER_IP) + + @event_callback("host_port") + def _callback_host_port(self, key, value, timestamp): + """ + Callback for request for host port + """ + self.send_kv("host_port", self.SERVER_PORT) + + def teardown(self): + if self.server: + self.server.shutdown() + self.server_thread.join()
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/host_tests/udp_shotgun.pyc Binary file easy-connect/wizfi310-driver/TESTS/net/host_tests/udp_shotgun.pyc has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/tcp_echo/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/tcp_echo/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,112 @@ +#include "mbed.h" +#include "WizFi310Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE +#define MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE 256 +#endif + +#ifndef MBED_CFG_WIZFI310_TX +#define MBED_CFG_WIZFI310_TX D1 +#endif + +#ifndef MBED_CFG_WIZFI310_RX +#define MBED_CFG_WIZFI310_RX D0 +#endif + +#ifndef MBED_CFG_WIZFI310_DEBUG +#define MBED_CFG_WIZFI310_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + +namespace { + char tx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0}; + char rx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0}; + const char ASCII_MAX = '~' - ' '; +} + +void prep_buffer(char *tx_buffer, size_t tx_size) { + for (size_t i=0; i<tx_size; ++i) { + tx_buffer[i] = (rand() % 10) + '0'; + } +} + +void test_tcp_echo() { + WizFi310Interface net(MBED_CFG_WIZFI310_TX, MBED_CFG_WIZFI310_RX, MBED_CFG_WIZFI310_DEBUG); + int err = net.connect(STRINGIZE(MBED_CFG_WIZFI310_SSID), STRINGIZE(MBED_CFG_WIZFI310_PASS)); + + if (err) { + printf("MBED: failed to connect with an error of %d\r\n", err); + TEST_ASSERT_EQUAL(0, err); + } + + printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: TCPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + bool result = false; + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + + TCPSocket sock(&net); + SocketAddress tcp_addr(ipbuf, port); + if (sock.connect(tcp_addr) == 0) { + printf("HTTP: Connected to %s:%d\r\n", ipbuf, port); + printf("tx_buffer buffer size: %u\r\n", sizeof(tx_buffer)); + printf("rx_buffer buffer size: %u\r\n", sizeof(rx_buffer)); + + prep_buffer(tx_buffer, sizeof(tx_buffer)); + sock.send(tx_buffer, sizeof(tx_buffer)); + printf("MBED: Finished sending\r\n"); + // Server will respond with HTTP GET's success code + const int ret = sock.recv(rx_buffer, sizeof(rx_buffer)); + printf("MBED: Finished receiving\r\n"); + + result = !memcmp(tx_buffer, rx_buffer, sizeof(tx_buffer)); + TEST_ASSERT_EQUAL(ret, sizeof(rx_buffer)); + TEST_ASSERT_EQUAL(true, result); + } + + sock.close(); + net.disconnect(); + TEST_ASSERT_EQUAL(true, result); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "tcp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP echo", test_tcp_echo), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/tcp_echo_parallel/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/tcp_echo_parallel/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,159 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Parallel tests are not supported by default +#endif + +#include "mbed.h" +#include "WizFi310Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE +#define MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE 64 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_ECHO_THREADS +#define MBED_CFG_TCP_CLIENT_ECHO_THREADS 3 +#endif + +#ifndef MBED_CFG_WIZFI310_TX +#define MBED_CFG_WIZFI310_TX D1 +#endif + +#ifndef MBED_CFG_WIZFI310_RX +#define MBED_CFG_WIZFI310_RX D0 +#endif + +#ifndef MBED_CFG_WIZFI310_DEBUG +#define MBED_CFG_WIZFI310_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +WizFi310Interface net(MBED_CFG_WIZFI310_TX, MBED_CFG_WIZFI310_RX, MBED_CFG_WIZFI310_DEBUG); +SocketAddress tcp_addr; +Mutex iomutex; + +void prep_buffer(char *tx_buffer, size_t tx_size) { + for (size_t i=0; i<tx_size; ++i) { + tx_buffer[i] = (rand() % 10) + '0'; + } +} + + +// Each echo class is in charge of one parallel transaction +class Echo { +private: + char tx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE]; + char rx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE]; + + TCPSocket sock; + Thread thread; + +public: + // Limiting stack size to 1k + Echo(): thread(osPriorityNormal, 1024) { + } + + void start() { + osStatus status = thread.start(callback(this, &Echo::echo)); + TEST_ASSERT_EQUAL(osOK, status); + } + + void join() { + osStatus status = thread.join(); + TEST_ASSERT_EQUAL(osOK, status); + } + + void echo() { + int err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + + err = sock.connect(tcp_addr); + TEST_ASSERT_EQUAL(0, err); + + iomutex.lock(); + printf("HTTP: Connected to %s:%d\r\n", + tcp_addr.get_ip_address(), tcp_addr.get_port()); + printf("tx_buffer buffer size: %u\r\n", sizeof(tx_buffer)); + printf("rx_buffer buffer size: %u\r\n", sizeof(rx_buffer)); + iomutex.unlock(); + + prep_buffer(tx_buffer, sizeof(tx_buffer)); + sock.send(tx_buffer, sizeof(tx_buffer)); + + // Server will respond with HTTP GET's success code + const int ret = sock.recv(rx_buffer, sizeof(rx_buffer)); + bool result = !memcmp(tx_buffer, rx_buffer, sizeof(tx_buffer)); + TEST_ASSERT_EQUAL(ret, sizeof(rx_buffer)); + TEST_ASSERT_EQUAL(true, result); + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } +}; + +Echo *echoers[MBED_CFG_TCP_CLIENT_ECHO_THREADS]; + + +void test_tcp_echo_parallel() { + int err = net.connect(STRINGIZE(MBED_CFG_WIZFI310_SSID), STRINGIZE(MBED_CFG_WIZFI310_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: TCPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + tcp_addr.set_ip_address(ipbuf); + tcp_addr.set_port(port); + + // Startup echo threads in parallel + for (int i = 0; i < MBED_CFG_TCP_CLIENT_ECHO_THREADS; i++) { + echoers[i] = new Echo; + echoers[i]->start(); + } + + for (int i = 0; i < MBED_CFG_TCP_CLIENT_ECHO_THREADS; i++) { + echoers[i]->join(); + delete echoers[i]; + } + + net.disconnect(); +} + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "tcp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP echo parallel", test_tcp_echo_parallel), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/tcp_hello_world/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/tcp_hello_world/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,115 @@ +#include <algorithm> +#include "mbed.h" +#include "WizFi310Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +#ifndef MBED_CFG_WIZFI310_TX +#define MBED_CFG_WIZFI310_TX D1 +#endif + +#ifndef MBED_CFG_WIZFI310_RX +#define MBED_CFG_WIZFI310_RX D0 +#endif + +#ifndef MBED_CFG_WIZFI310_DEBUG +#define MBED_CFG_WIZFI310_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +namespace { + // Test connection information + const char *HTTP_SERVER_NAME = "os.mbed.com"; + const char *HTTP_SERVER_FILE_PATH = "/media/uploads/mbed_official/hello.txt"; + const int HTTP_SERVER_PORT = 80; +#if defined(TARGET_VK_RZ_A1H) + const int RECV_BUFFER_SIZE = 300; +#else + const int RECV_BUFFER_SIZE = 512; +#endif + // Test related data + const char *HTTP_OK_STR = "200 OK"; + const char *HTTP_HELLO_STR = "Hello world!"; + + // Test buffers + char buffer[RECV_BUFFER_SIZE] = {0}; +} + +bool find_substring(const char *first, const char *last, const char *s_first, const char *s_last) { + const char *f = std::search(first, last, s_first, s_last); + return (f != last); +} + +void test_tcp_hello_world() { + bool result = false; + WizFi310Interface net(MBED_CFG_WIZFI310_TX, MBED_CFG_WIZFI310_RX, MBED_CFG_WIZFI310_DEBUG); + net.connect(STRINGIZE(MBED_CFG_WIZFI310_SSID), STRINGIZE(MBED_CFG_WIZFI310_PASS)); + printf("TCP client IP Address is %s\r\n", net.get_ip_address()); + + TCPSocket sock(&net); + printf("HTTP: Connection to %s:%d\r\n", HTTP_SERVER_NAME, HTTP_SERVER_PORT); + if (sock.connect(HTTP_SERVER_NAME, HTTP_SERVER_PORT) == 0) { + printf("HTTP: OK\r\n"); + + // We are constructing GET command like this: + // GET http://os.mbed.com/media/uploads/mbed_official/hello.txt HTTP/1.0\n\n + strcpy(buffer, "GET http://"); + strcat(buffer, HTTP_SERVER_NAME); + strcat(buffer, HTTP_SERVER_FILE_PATH); + strcat(buffer, " HTTP/1.0\n\n"); + // Send GET command + sock.send(buffer, strlen(buffer)); + + // Server will respond with HTTP GET's success code + const int ret = sock.recv(buffer, sizeof(buffer) - 1); + buffer[ret] = '\0'; + + // Find 200 OK HTTP status in reply + bool found_200_ok = find_substring(buffer, buffer + ret, HTTP_OK_STR, HTTP_OK_STR + strlen(HTTP_OK_STR)); + // Find "Hello World!" string in reply + bool found_hello = find_substring(buffer, buffer + ret, HTTP_HELLO_STR, HTTP_HELLO_STR + strlen(HTTP_HELLO_STR)); + + TEST_ASSERT_TRUE(found_200_ok); + TEST_ASSERT_TRUE(found_hello); + + if (found_200_ok && found_hello) result = true; + + printf("HTTP: Received %d chars from server\r\n", ret); + printf("HTTP: Received 200 OK status ... %s\r\n", found_200_ok ? "[OK]" : "[FAIL]"); + printf("HTTP: Received '%s' status ... %s\r\n", HTTP_HELLO_STR, found_hello ? "[OK]" : "[FAIL]"); + printf("HTTP: Received message:\r\n"); + printf("%s", buffer); + sock.close(); + } else { + printf("HTTP: ERROR\r\n"); + } + + net.disconnect(); + printf("Network disconnected\r\n"); + TEST_ASSERT_EQUAL(true, result); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP hello world", test_tcp_hello_world), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/tcp_packet_pressure/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/tcp_packet_pressure/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,253 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Pressure tests are not supported by default +#endif + +#include "mbed.h" +#include "WizFi310Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN 64 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX 0x80000 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG false +#endif + +#ifndef MBED_CFG_WIZFI310_TX +#define MBED_CFG_WIZFI310_TX D1 +#endif + +#ifndef MBED_CFG_WIZFI310_RX +#define MBED_CFG_WIZFI310_RX D0 +#endif + +#ifndef MBED_CFG_WIZFI310_DEBUG +#define MBED_CFG_WIZFI310_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Simple xorshift pseudorandom number generator +class RandSeq { +private: + uint32_t x; + uint32_t y; + static const int A = 15; + static const int B = 18; + static const int C = 11; + +public: + RandSeq(uint32_t seed=MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED) + : x(seed), y(seed) {} + + uint32_t next(void) { + x ^= x << A; + x ^= x >> B; + x ^= y ^ (y >> C); + return x + y; + } + + void skip(size_t size) { + for (size_t i = 0; i < size; i++) { + next(); + } + } + + void buffer(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + buffer[i] = lookahead.next() & 0xff; + } + } + + int cmp(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + int diff = buffer[i] - (lookahead.next() & 0xff); + if (diff != 0) { + return diff; + } + } + return 0; + } +}; + +// Shared buffer for network transactions +uint8_t *buffer; +size_t buffer_size; + +// Tries to get the biggest buffer possible on the device. Exponentially +// grows a buffer until heap runs out of space, and uses half to leave +// space for the rest of the program +void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) { + size_t i = min; + while (i < max) { + void *b = malloc(i); + if (!b) { + i /= 4; + if (i < min) { + i = min; + } + break; + } + free(b); + i *= 2; + } + + *buffer = (uint8_t *)malloc(i); + *size = i; + TEST_ASSERT(buffer); +} + + +void test_tcp_packet_pressure() { + generate_buffer(&buffer, &buffer_size, + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN, + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX); + printf("MBED: Generated buffer %d\r\n", buffer_size); + + WizFi310Interface net(MBED_CFG_WIZFI310_TX, MBED_CFG_WIZFI310_RX, MBED_CFG_WIZFI310_DEBUG); + int err = net.connect(STRINGIZE(MBED_CFG_WIZFI310_SSID), STRINGIZE(MBED_CFG_WIZFI310_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: TCPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + + TCPSocket sock; + SocketAddress tcp_addr(ipbuf, port); + + Timer timer; + timer.start(); + + // Tests exponentially growing sequences + for (size_t size = MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN; + size < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX; + size *= 2) { + err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + err = sock.connect(tcp_addr); + TEST_ASSERT_EQUAL(0, err); + printf("TCP: %s:%d streaming %d bytes\r\n", ipbuf, port, size); + + sock.set_blocking(false); + + // Loop to send/recv all data + RandSeq tx_seq; + RandSeq rx_seq; + size_t rx_count = 0; + size_t tx_count = 0; + size_t window = buffer_size; + + while (tx_count < size || rx_count < size) { + // Send out data + if (tx_count < size) { + size_t chunk_size = size - tx_count; + if (chunk_size > window) { + chunk_size = window; + } + + tx_seq.buffer(buffer, chunk_size); + int td = sock.send(buffer, chunk_size); + + if (td > 0) { + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("TCP: tx -> %d\r\n", td); + } + tx_seq.skip(td); + tx_count += td; + } else if (td != NSAPI_ERROR_WOULD_BLOCK) { + // We may fail to send because of buffering issues, + // cut buffer in half + if (window > MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("TCP: Not sent (%d), window = %d\r\n", td, window); + } + } + } + + // Verify recieved data + while (rx_count < size) { + int rd = sock.recv(buffer, buffer_size); + TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK); + if (rd > 0) { + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("TCP: rx <- %d\r\n", rd); + } + int diff = rx_seq.cmp(buffer, rd); + TEST_ASSERT_EQUAL(0, diff); + rx_seq.skip(rd); + rx_count += rd; + } else if (rd == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } + + timer.stop(); + printf("MBED: Time taken: %fs\r\n", timer.read()); + printf("MBED: Speed: %.3fkb/s\r\n", + 8*(2*MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX - + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); + + net.disconnect(); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "tcp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP packet pressure", test_tcp_packet_pressure), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/tcp_packet_pressure_parallel/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/tcp_packet_pressure_parallel/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,315 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Parallel pressure tests are not supported by default +#endif + +#include "mbed.h" +#include "WizFi310Interface.h" +#include "TCPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN 64 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX 0x80000 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS 3 +#endif + +#ifndef MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG +#define MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG false +#endif + +#ifndef MBED_CFG_WIZFI310_TX +#define MBED_CFG_WIZFI310_TX D1 +#endif + +#ifndef MBED_CFG_WIZFI310_RX +#define MBED_CFG_WIZFI310_RX D0 +#endif + +#ifndef MBED_CFG_WIZFI310_DEBUG +#define MBED_CFG_WIZFI310_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Simple xorshift pseudorandom number generator +class RandSeq { +private: + uint32_t x; + uint32_t y; + static const int A = 15; + static const int B = 18; + static const int C = 11; + +public: + RandSeq(uint32_t seed=MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_SEED) + : x(seed), y(seed) {} + + uint32_t next(void) { + x ^= x << A; + x ^= x >> B; + x ^= y ^ (y >> C); + return x + y; + } + + void skip(size_t size) { + for (size_t i = 0; i < size; i++) { + next(); + } + } + + void buffer(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + buffer[i] = lookahead.next() & 0xff; + } + } + + int cmp(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + int diff = buffer[i] - (lookahead.next() & 0xff); + if (diff != 0) { + return diff; + } + } + return 0; + } +}; + + +// Tries to get the biggest buffer possible on the device. Exponentially +// grows a buffer until heap runs out of space, and uses half to leave +// space for the rest of the program +void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) { + size_t i = min; + while (i < max) { + void *b = malloc(i); + if (!b) { + i /= 4; + if (i < min) { + i = min; + } + break; + } + free(b); + i *= 2; + } + + *buffer = (uint8_t *)malloc(i); + *size = i; + TEST_ASSERT(buffer); +} + + +// Global variables shared between pressure tests +WizFi310Interface net(MBED_CFG_WIZFI310_TX, MBED_CFG_WIZFI310_RX, MBED_CFG_WIZFI310_DEBUG); +SocketAddress tcp_addr; +Timer timer; +Mutex iomutex; + +// Single instance of a pressure test +class PressureTest { +private: + uint8_t *buffer; + size_t buffer_size; + + TCPSocket sock; + Thread thread; + +public: + PressureTest(uint8_t *buffer, size_t buffer_size) + : buffer(buffer), buffer_size(buffer_size) { + } + + void start() { + osStatus status = thread.start(callback(this, &PressureTest::run)); + TEST_ASSERT_EQUAL(osOK, status); + } + + void join() { + osStatus status = thread.join(); + TEST_ASSERT_EQUAL(osOK, status); + } + + void run() { + // Tests exponentially growing sequences + for (size_t size = MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN; + size < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX; + size *= 2) { + int err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + err = sock.connect(tcp_addr); + TEST_ASSERT_EQUAL(0, err); + iomutex.lock(); + printf("TCP: %s:%d streaming %d bytes\r\n", + tcp_addr.get_ip_address(), tcp_addr.get_port(), size); + iomutex.unlock(); + + sock.set_blocking(false); + + // Loop to send/recv all data + RandSeq tx_seq; + RandSeq rx_seq; + size_t rx_count = 0; + size_t tx_count = 0; + size_t window = buffer_size; + + while (tx_count < size || rx_count < size) { + // Send out data + if (tx_count < size) { + size_t chunk_size = size - tx_count; + if (chunk_size > window) { + chunk_size = window; + } + + tx_seq.buffer(buffer, chunk_size); + int td = sock.send(buffer, chunk_size); + + if (td > 0) { + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("TCP: tx -> %d\r\n", td); + iomutex.unlock(); + } + tx_seq.skip(td); + tx_count += td; + } else if (td != NSAPI_ERROR_WOULD_BLOCK) { + // We may fail to send because of buffering issues, + // cut buffer in half + if (window > MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("TCP: Not sent (%d), window = %d\r\n", td, window); + iomutex.unlock(); + } + } + } + + // Verify recieved data + while (rx_count < size) { + int rd = sock.recv(buffer, buffer_size); + TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK); + if (rd > 0) { + if (MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("TCP: rx <- %d\r\n", rd); + iomutex.unlock(); + } + int diff = rx_seq.cmp(buffer, rd); + TEST_ASSERT_EQUAL(0, diff); + rx_seq.skip(rd); + rx_count += rd; + } else if (rd == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } + } +}; + +PressureTest *pressure_tests[MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS]; + + +void test_tcp_packet_pressure_parallel() { + uint8_t *buffer; + size_t buffer_size; + generate_buffer(&buffer, &buffer_size, + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN, + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX); + + size_t buffer_subsize = buffer_size / MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; + printf("MBED: Generated buffer %d\r\n", buffer_size); + printf("MBED: Split into %d buffers %d\r\n", + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS, + buffer_subsize); + + int err = net.connect(STRINGIZE(MBED_CFG_WIZFI310_SSID), STRINGIZE(MBED_CFG_WIZFI310_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: TCPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: TCPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + tcp_addr.set_ip_address(ipbuf); + tcp_addr.set_port(port); + + timer.start(); + + // Startup pressure tests in parallel + for (int i = 0; i < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; i++) { + pressure_tests[i] = new PressureTest(&buffer[i*buffer_subsize], buffer_subsize); + pressure_tests[i]->start(); + } + + for (int i = 0; i < MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS; i++) { + pressure_tests[i]->join(); + delete pressure_tests[i]; + } + + timer.stop(); + printf("MBED: Time taken: %fs\r\n", timer.read()); + printf("MBED: Speed: %.3fkb/s\r\n", + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_THREADS* + 8*(2*MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MAX - + MBED_CFG_TCP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); + + net.disconnect(); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "tcp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("TCP packet pressure parallel", test_tcp_packet_pressure_parallel), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/udp_dtls_handshake/.main.cpp.swp Binary file easy-connect/wizfi310-driver/TESTS/net/udp_dtls_handshake/.main.cpp.swp has changed
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/udp_dtls_handshake/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/udp_dtls_handshake/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,159 @@ +#include "mbed.h" +#include "WizFi310Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_BUFFER_SIZE +#define MBED_CFG_UDP_DTLS_HANDSHAKE_BUFFER_SIZE 512 +#endif + +#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_RETRIES +#define MBED_CFG_UDP_DTLS_HANDSHAKE_RETRIES 16 +#endif + +#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_PATTERN +#define MBED_CFG_UDP_DTLS_HANDSHAKE_PATTERN 112, 384, 200, 219, 25 +#endif + +#ifndef MBED_CFG_UDP_DTLS_HANDSHAKE_TIMEOUT +#define MBED_CFG_UDP_DTLS_HANDSHAKE_TIMEOUT 1500 +#endif + +#ifndef MBED_CFG_WIZFI310_TX +#define MBED_CFG_WIZFI310_TX D1 +#endif + +#ifndef MBED_CFG_WIZFI310_RX +#define MBED_CFG_WIZFI310_RX D0 +#endif + +#ifndef MBED_CFG_WIZFI310_DEBUG +#define MBED_CFG_WIZFI310_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + +uint8_t buffer[MBED_CFG_UDP_DTLS_HANDSHAKE_BUFFER_SIZE] = {0}; +int udp_dtls_handshake_pattern[] = {MBED_CFG_UDP_DTLS_HANDSHAKE_PATTERN}; +const int udp_dtls_handshake_count = sizeof(udp_dtls_handshake_pattern) / sizeof(int); + +void test_udp_dtls_handshake() { + WizFi310Interface net(MBED_CFG_WIZFI310_TX, MBED_CFG_WIZFI310_RX, MBED_CFG_WIZFI310_DEBUG); + int err = net.connect(STRINGIZE(MBED_CFG_WIZFI310_SSID), STRINGIZE(MBED_CFG_WIZFI310_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: UDPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: UDPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + bool result = false; + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: UDP Server IP address received: %s:%d \n", ipbuf, port); + + // align each size to 4-bits + for (int i = 0; i < udp_dtls_handshake_count; i++) { + udp_dtls_handshake_pattern[i] = (~0xf & udp_dtls_handshake_pattern[i]) + 0x10; + } + + printf("MBED: DTLS pattern ["); + for (int i = 0; i < udp_dtls_handshake_count; i++) { + printf("%d", udp_dtls_handshake_pattern[i]); + if (i != udp_dtls_handshake_count-1) { + printf(", "); + } + } + printf("]\r\n"); + + UDPSocket sock; + SocketAddress udp_addr(ipbuf, port); + sock.set_timeout(MBED_CFG_UDP_DTLS_HANDSHAKE_TIMEOUT); + + for (int attempt = 0; attempt < MBED_CFG_UDP_DTLS_HANDSHAKE_RETRIES; attempt++) { + err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + + for (int i = 0; i < udp_dtls_handshake_count; i++) { + buffer[i] = udp_dtls_handshake_pattern[i] >> 4; + } + + err = sock.sendto(udp_addr, buffer, udp_dtls_handshake_count); + printf("UDP: tx -> %d\r\n", err); + TEST_ASSERT_EQUAL(udp_dtls_handshake_count, err); + + int step = 0; + while (step < udp_dtls_handshake_count) { + err = sock.recvfrom(NULL, buffer, sizeof(buffer)); + printf("UDP: rx <- %d ", err); + + // check length + if (err != udp_dtls_handshake_pattern[step]) { + printf("x (expected %d)\r\n", udp_dtls_handshake_pattern[step]); + break; + } + + // check quick xor of packet + uint8_t check = 0; + for (int j = 0; j < udp_dtls_handshake_pattern[step]; j++) { + check ^= buffer[j]; + } + + if (check != 0) { + printf("x (checksum 0x%02x)\r\n", check); + break; + } + + // successfully got a packet + printf("\r\n"); + step += 1; + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + + // got through all steps, test passed + if (step == udp_dtls_handshake_count) { + result = true; + break; + } + } + + net.disconnect(); + TEST_ASSERT_EQUAL(true, result); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_shotgun"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP DTLS handshake", test_udp_dtls_handshake), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/udp_echo/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/udp_echo/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,151 @@ +#include "mbed.h" +#include "WizFi310Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE +#define MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE 64 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT +#define MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT 500 +#endif + +#ifndef MBED_CFG_WIZFI310_TX +#define MBED_CFG_WIZFI310_TX D1 +#endif + +#ifndef MBED_CFG_WIZFI310_RX +#define MBED_CFG_WIZFI310_RX D0 +#endif + +#ifndef MBED_CFG_WIZFI310_DEBUG +#define MBED_CFG_WIZFI310_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +namespace { + char tx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE] = {0}; + char rx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE] = {0}; + const char ASCII_MAX = '~' - ' '; + const int ECHO_LOOPS = 16; + char uuid[48] = {0}; +} + +void prep_buffer(char *uuid, char *tx_buffer, size_t tx_size) { + size_t i = 0; + + memcpy(tx_buffer, uuid, strlen(uuid)); + i += strlen(uuid); + + tx_buffer[i++] = ' '; + + for (; i<tx_size; ++i) { + tx_buffer[i] = (rand() % 10) + '0'; + } +} + +void test_udp_echo() { + WizFi310Interface net(MBED_CFG_WIZFI310_TX, MBED_CFG_WIZFI310_RX, MBED_CFG_WIZFI310_DEBUG); + + int err = net.connect(STRINGIZE(MBED_CFG_WIZFI310_SSID), STRINGIZE(MBED_CFG_WIZFI310_PASS)); + TEST_ASSERT_EQUAL(0, err); + + if (err) { + printf("MBED: failed to connect with an error of %d\r\n", err); + TEST_ASSERT_EQUAL(0, err); + } + + printf("UDP client IP Address is %s\n", net.get_ip_address()); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + UDPSocket sock; + sock.open(&net); + sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT); + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: UDP Server IP address received: %s:%d \n", ipbuf, port); + SocketAddress udp_addr(ipbuf, port); + + int success = 0; + for (int i = 0; success < ECHO_LOOPS; i++) { + prep_buffer(uuid, tx_buffer, sizeof(tx_buffer)); + const int ret = sock.sendto(udp_addr, tx_buffer, sizeof(tx_buffer)); + if (ret >= 0) { + printf("[%02d] sent %d bytes - %.*s \n", i, ret, ret, tx_buffer); + } else { + printf("[%02d] Network error %d\n", i, ret); + continue; + } + + SocketAddress temp_addr; + const int n = sock.recvfrom(&temp_addr, rx_buffer, sizeof(rx_buffer)); + if (n >= 0) { + printf("[%02d] recv %d bytes - %.*s \n", i, n, n, tx_buffer); + } else { + printf("[%02d] Network error %d\n", i, n); + continue; + } + + if ((temp_addr == udp_addr && + n == sizeof(tx_buffer) && + memcmp(rx_buffer, tx_buffer, sizeof(rx_buffer)) == 0)) { + success += 1; + + printf("[%02d] success #%d\n", i, success); + continue; + } + + // failed, clean out any remaining bad packets + sock.set_timeout(0); + while (true) { + err = sock.recvfrom(NULL, NULL, 0); + if (err == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT); + } + + sock.close(); + net.disconnect(); + TEST_ASSERT_EQUAL(ECHO_LOOPS, success); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP echo", test_udp_echo), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/udp_echo_parallel/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/udp_echo_parallel/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,231 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Parallel tests are not supported by default +#endif + +#include "mbed.h" +#include "ESP8266Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE +#define MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE 64 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT +#define MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT 500 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_ECHO_THREADS +#define MBED_CFG_UDP_CLIENT_ECHO_THREADS 3 +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +const int ECHO_LOOPS = 16; +ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); +SocketAddress udp_addr; +Mutex iomutex; +char uuid[48] = {0}; + +// NOTE: assuming that "id" stays in the single digits +void prep_buffer(int id, char *uuid, char *tx_buffer, size_t tx_size) { + size_t i = 0; + + tx_buffer[i++] = '0' + id; + tx_buffer[i++] = ' '; + + memcpy(tx_buffer+i, uuid, strlen(uuid)); + i += strlen(uuid); + + tx_buffer[i++] = ' '; + + for (; i<tx_size; ++i) { + tx_buffer[i] = (rand() % 10) + '0'; + } +} + + +// Each echo class is in charge of one parallel transaction +class Echo { +private: + char tx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE]; + char rx_buffer[MBED_CFG_UDP_CLIENT_ECHO_BUFFER_SIZE]; + + UDPSocket sock; + Thread thread; + bool result; + int id; + char *uuid; + +public: + // Limiting stack size to 1k + Echo(): thread(osPriorityNormal, 1024), result(false) { + } + + void start(int id, char *uuid) { + this->id = id; + this->uuid = uuid; + osStatus status = thread.start(callback(this, &Echo::echo)); + } + + void join() { + osStatus status = thread.join(); + TEST_ASSERT_EQUAL(osOK, status); + } + + void echo() { + int success = 0; + + int err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + + sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT); + + for (int i = 0; success < ECHO_LOOPS; i++) { + prep_buffer(id, uuid, tx_buffer, sizeof(tx_buffer)); + const int ret = sock.sendto(udp_addr, tx_buffer, sizeof(tx_buffer)); + if (ret >= 0) { + iomutex.lock(); + printf("[ID:%01d][%02d] sent %d bytes - %.*s \n", id, i, ret, ret, tx_buffer); + iomutex.unlock(); + } else { + iomutex.lock(); + printf("[ID:%01d][%02d] Network error %d\n", id, i, ret); + iomutex.unlock(); + continue; + } + + SocketAddress temp_addr; + const int n = sock.recvfrom(&temp_addr, rx_buffer, sizeof(rx_buffer)); + if (n >= 0) { + iomutex.lock(); + printf("[ID:%01d][%02d] recv %d bytes - %.*s \n", id, i, n, n, tx_buffer); + iomutex.unlock(); + } else { + iomutex.lock(); + printf("[ID:%01d][%02d] Network error %d\n", id, i, n); + iomutex.unlock(); + continue; + } + + if ((temp_addr == udp_addr && + n == sizeof(tx_buffer) && + memcmp(rx_buffer, tx_buffer, sizeof(rx_buffer)) == 0)) { + success += 1; + iomutex.lock(); + printf("[ID:%01d][%02d] success #%d\n", id, i, success); + iomutex.unlock(); + continue; + } + + // failed, clean out any remaining bad packets + sock.set_timeout(0); + while (true) { + err = sock.recvfrom(NULL, NULL, 0); + if (err == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + sock.set_timeout(MBED_CFG_UDP_CLIENT_ECHO_TIMEOUT); + } + + result = success == ECHO_LOOPS; + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + if (err) { + result = false; + } + } + + bool get_result() { + return result; + } +}; + +Echo *echoers[MBED_CFG_UDP_CLIENT_ECHO_THREADS]; + + +void test_udp_echo_parallel() { + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + if (err) { + printf("MBED: failed to connect with an error of %d\r\n", err); + GREENTEA_TESTSUITE_RESULT(false); + } else { + printf("UDP client IP Address is %s\n", net.get_ip_address()); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: UDP Server IP address received: %s:%d \n", ipbuf, port); + udp_addr.set_ip_address(ipbuf); + udp_addr.set_port(port); + + // Startup echo threads in parallel + for (int i = 0; i < MBED_CFG_UDP_CLIENT_ECHO_THREADS; i++) { + echoers[i] = new Echo; + echoers[i]->start(i, uuid); + } + + bool result = true; + + for (int i = 0; i < MBED_CFG_UDP_CLIENT_ECHO_THREADS; i++) { + echoers[i]->join(); + result = result && echoers[i]->get_result(); + delete echoers[i]; + } + + net.disconnect(); + TEST_ASSERT_EQUAL(true, result); + } +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP echo parallel", test_udp_echo_parallel), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/udp_packet_pressure/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/udp_packet_pressure/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,276 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Pressure tests are not supported by default +#endif + +#include "mbed.h" +#include "ESP8266Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN 64 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX 0x80000 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 100 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG false +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Simple xorshift pseudorandom number generator +class RandSeq { +private: + uint32_t x; + uint32_t y; + static const int A = 15; + static const int B = 18; + static const int C = 11; + +public: + RandSeq(uint32_t seed=MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED) + : x(seed), y(seed) {} + + uint32_t next(void) { + x ^= x << A; + x ^= x >> B; + x ^= y ^ (y >> C); + return x + y; + } + + void skip(size_t size) { + for (size_t i = 0; i < size; i++) { + next(); + } + } + + void buffer(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + buffer[i] = lookahead.next() & 0xff; + } + } + + int cmp(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + int diff = buffer[i] - (lookahead.next() & 0xff); + if (diff != 0) { + return diff; + } + } + return 0; + } +}; + +// Shared buffer for network transactions +uint8_t *buffer; +size_t buffer_size; + +// Tries to get the biggest buffer possible on the device. Exponentially +// grows a buffer until heap runs out of space, and uses half to leave +// space for the rest of the program +void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) { + size_t i = min; + while (i < max) { + void *b = malloc(i); + if (!b) { + i /= 4; + if (i < min) { + i = min; + } + break; + } + free(b); + i *= 2; + } + + *buffer = (uint8_t *)malloc(i); + *size = i; + TEST_ASSERT(buffer); +} + +void test_udp_packet_pressure() { + generate_buffer(&buffer, &buffer_size, + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN, + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX); + printf("MBED: Generated buffer %d\r\n", buffer_size); + + ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: UDPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: UDPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + + UDPSocket sock; + SocketAddress udp_addr(ipbuf, port); + + Timer timer; + timer.start(); + + // Tests exponentially growing sequences + for (size_t size = MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; + size < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX; + size *= 2) { + err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + printf("UDP: %s:%d streaming %d bytes\r\n", ipbuf, port, size); + + sock.set_blocking(false); + + // Loop to send/recv all data + RandSeq tx_seq; + RandSeq rx_seq; + size_t rx_count = 0; + size_t tx_count = 0; + int known_time = timer.read_ms(); + size_t window = buffer_size; + + while (tx_count < size || rx_count < size) { + // Send out packets + if (tx_count < size) { + size_t chunk_size = size - tx_count; + if (chunk_size > window) { + chunk_size = window; + } + + tx_seq.buffer(buffer, chunk_size); + int td = sock.sendto(udp_addr, buffer, chunk_size); + + if (td > 0) { + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("UDP: tx -> %d\r\n", td); + } + tx_seq.skip(td); + tx_count += td; + } else if (td != NSAPI_ERROR_WOULD_BLOCK) { + // We may fail to send because of buffering issues, revert to + // last good sequence and cut buffer in half + if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("UDP: Not sent (%d), window = %d\r\n", td, window); + } + } + } + + // Prioritize recieving over sending packets to avoid flooding + // the network while handling erronous packets + while (rx_count < size) { + int rd = sock.recvfrom(NULL, buffer, buffer_size); + TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK); + + if (rd > 0) { + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("UDP: rx <- %d\r\n", rd); + } + + if (rx_seq.cmp(buffer, rd) == 0) { + rx_seq.skip(rd); + rx_count += rd; + known_time = timer.read_ms(); + if (window < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX) { + window += MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; + } + } + } else if (timer.read_ms() - known_time > + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) { + // Dropped packet or out of order, revert to last good sequence + // and cut buffer in half + tx_seq = rx_seq; + tx_count = rx_count; + known_time = timer.read_ms(); + if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + printf("UDP: Dropped, window = %d\r\n", window); + } + } else if (rd == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } + + timer.stop(); + printf("MBED: Time taken: %fs\r\n", timer.read()); + printf("MBED: Speed: %.3fkb/s\r\n", + 8*(2*MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX - + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); + + net.disconnect(); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP packet pressure", test_udp_packet_pressure), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/TESTS/net/udp_packet_pressure_parallel/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/TESTS/net/udp_packet_pressure_parallel/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,341 @@ +#ifndef MBED_EXTENDED_TESTS + #error [NOT_SUPPORTED] Parallel pressure tests are not supported by default +#endif + +#include "mbed.h" +#include "ESP8266Interface.h" +#include "UDPSocket.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN 64 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX 0x80000 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT 100 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED 0x6d626564 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS 3 +#endif + +#ifndef MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG +#define MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG false +#endif + +#ifndef MBED_CFG_ESP8266_TX +#define MBED_CFG_ESP8266_TX D1 +#endif + +#ifndef MBED_CFG_ESP8266_RX +#define MBED_CFG_ESP8266_RX D0 +#endif + +#ifndef MBED_CFG_ESP8266_DEBUG +#define MBED_CFG_ESP8266_DEBUG false +#endif + +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x + + +// Simple xorshift pseudorandom number generator +class RandSeq { +private: + uint32_t x; + uint32_t y; + static const int A = 15; + static const int B = 18; + static const int C = 11; + +public: + RandSeq(uint32_t seed=MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_SEED) + : x(seed), y(seed) {} + + uint32_t next(void) { + x ^= x << A; + x ^= x >> B; + x ^= y ^ (y >> C); + return x + y; + } + + void skip(size_t size) { + for (size_t i = 0; i < size; i++) { + next(); + } + } + + void buffer(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + buffer[i] = lookahead.next() & 0xff; + } + } + + int cmp(uint8_t *buffer, size_t size) { + RandSeq lookahead = *this; + + for (size_t i = 0; i < size; i++) { + int diff = buffer[i] - (lookahead.next() & 0xff); + if (diff != 0) { + return diff; + } + } + return 0; + } +}; + +// Tries to get the biggest buffer possible on the device. Exponentially +// grows a buffer until heap runs out of space, and uses half to leave +// space for the rest of the program +void generate_buffer(uint8_t **buffer, size_t *size, size_t min, size_t max) { + size_t i = min; + while (i < max) { + void *b = malloc(i); + if (!b) { + i /= 8; + if (i < min) { + i = min; + } + break; + } + free(b); + i *= 2; + } + + *buffer = (uint8_t *)malloc(i); + *size = i; + TEST_ASSERT(buffer); +} + + +// Global variables shared between pressure tests +ESP8266Interface net(MBED_CFG_ESP8266_TX, MBED_CFG_ESP8266_RX, MBED_CFG_ESP8266_DEBUG); +SocketAddress udp_addr; +Timer timer; +Mutex iomutex; + +// Single instance of a pressure test +class PressureTest { +private: + uint8_t *buffer; + size_t buffer_size; + + UDPSocket sock; + Thread thread; + +public: + PressureTest(uint8_t *buffer, size_t buffer_size) + : buffer(buffer), buffer_size(buffer_size) { + } + + void start() { + osStatus status = thread.start(callback(this, &PressureTest::run)); + TEST_ASSERT_EQUAL(osOK, status); + } + + void join() { + osStatus status = thread.join(); + TEST_ASSERT_EQUAL(osOK, status); + } + + void run() { + // Tests exponentially growing sequences + for (size_t size = MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; + size < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX; + size *= 2) { + int err = sock.open(&net); + TEST_ASSERT_EQUAL(0, err); + iomutex.lock(); + printf("UDP: %s:%d streaming %d bytes\r\n", + udp_addr.get_ip_address(), udp_addr.get_port(), size); + iomutex.unlock(); + + sock.set_blocking(false); + + // Loop to send/recv all data + RandSeq tx_seq; + RandSeq rx_seq; + size_t rx_count = 0; + size_t tx_count = 0; + int known_time = timer.read_ms(); + size_t window = buffer_size; + + while (tx_count < size || rx_count < size) { + // Send out packets + if (tx_count < size) { + size_t chunk_size = size - tx_count; + if (chunk_size > window) { + chunk_size = window; + } + + tx_seq.buffer(buffer, chunk_size); + int td = sock.sendto(udp_addr, buffer, chunk_size); + + if (td > 0) { + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("UDP: tx -> %d\r\n", td); + iomutex.unlock(); + } + tx_seq.skip(td); + tx_count += td; + } else if (td != NSAPI_ERROR_WOULD_BLOCK) { + // We may fail to send because of buffering issues, revert to + // last good sequence and cut buffer in half + if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("UDP: Not sent (%d), window = %d\r\n", td, window); + iomutex.unlock(); + } + } + } + + // Prioritize recieving over sending packets to avoid flooding + // the network while handling erronous packets + while (rx_count < size) { + int rd = sock.recvfrom(NULL, buffer, buffer_size); + TEST_ASSERT(rd > 0 || rd == NSAPI_ERROR_WOULD_BLOCK); + + if (rd > 0) { + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("UDP: rx <- %d\r\n", rd); + iomutex.unlock(); + } + + if (rx_seq.cmp(buffer, rd) == 0) { + rx_seq.skip(rd); + rx_count += rd; + known_time = timer.read_ms(); + if (window < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX) { + window += MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN; + } + } + } else if (timer.read_ms() - known_time > + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_TIMEOUT) { + // Dropped packet or out of order, revert to last good sequence + // and cut buffer in half + tx_seq = rx_seq; + tx_count = rx_count; + known_time = timer.read_ms(); + if (window > MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) { + window /= 2; + } + + if (MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_DEBUG) { + iomutex.lock(); + printf("UDP: Dropped, window = %d\r\n", window); + iomutex.unlock(); + } + } else if (rd == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + } + + err = sock.close(); + TEST_ASSERT_EQUAL(0, err); + } + } +}; + +PressureTest *pressure_tests[MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS]; + + +void test_udp_packet_pressure_parallel() { + uint8_t *buffer; + size_t buffer_size; + generate_buffer(&buffer, &buffer_size, + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN, + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX); + + size_t buffer_subsize = buffer_size / MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; + printf("MBED: Generated buffer %d\r\n", buffer_size); + printf("MBED: Split into %d buffers %d\r\n", + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS, + buffer_subsize); + + int err = net.connect(STRINGIZE(MBED_CFG_ESP8266_SSID), STRINGIZE(MBED_CFG_ESP8266_PASS)); + TEST_ASSERT_EQUAL(0, err); + + printf("MBED: UDPClient IP address is '%s'\n", net.get_ip_address()); + printf("MBED: UDPClient waiting for server IP and port...\n"); + + greentea_send_kv("target_ip", net.get_ip_address()); + + char recv_key[] = "host_port"; + char ipbuf[60] = {0}; + char portbuf[16] = {0}; + unsigned int port = 0; + + greentea_send_kv("host_ip", " "); + greentea_parse_kv(recv_key, ipbuf, sizeof(recv_key), sizeof(ipbuf)); + + greentea_send_kv("host_port", " "); + greentea_parse_kv(recv_key, portbuf, sizeof(recv_key), sizeof(ipbuf)); + sscanf(portbuf, "%u", &port); + + printf("MBED: Server IP address received: %s:%d \n", ipbuf, port); + udp_addr.set_ip_address(ipbuf); + udp_addr.set_port(port); + + timer.start(); + + // Startup pressure tests in parallel + for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) { + pressure_tests[i] = new PressureTest(&buffer[i*buffer_subsize], buffer_subsize); + pressure_tests[i]->start(); + } + + for (int i = 0; i < MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS; i++) { + pressure_tests[i]->join(); + delete pressure_tests[i]; + } + + timer.stop(); + printf("MBED: Time taken: %fs\r\n", timer.read()); + printf("MBED: Speed: %.3fkb/s\r\n", + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_THREADS* + 8*(2*MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MAX - + MBED_CFG_UDP_CLIENT_PACKET_PRESSURE_MIN) / (1000*timer.read())); + + net.disconnect(); +} + + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "udp_echo"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("UDP packet pressure parallel", test_udp_packet_pressure_parallel), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} + +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/WizFi310/WizFi310.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/WizFi310/WizFi310.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + ****************************************************************************** + * @file WizFi310.cpp + * @author Gateway Team + * @brief Implementation file of the WizFi310 WiFi Device + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, WIZnet SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2017 WIZnet Co.,Ltd.</center></h2> + ****************************************************************************** + */ + +#include "WizFi310.h" +#define WIZFI310_DEFAULT_BAUD_RATE 115200 + +#define AT_CMD_PARSER_DEFAULT_TIMEOUT 500 +#define AT_CMD_PARSER_INIT_TIMEOUT 1000 +#define AT_CMD_PARSER_RECV_TIMEOUT 20000 + +WizFi310::WizFi310(PinName tx, PinName rx, bool debug) + : _serial(tx, rx, WIZFI310_DEFAULT_BAUD_RATE), + _parser(&_serial), + _packets(0), + _packets_end(&_packets) +{ + _serial.set_baud( WIZFI310_DEFAULT_BAUD_RATE ); + _parser.debug_on(debug); + _parser.set_delimiter("\r\n"); + + setTimeout(AT_CMD_PARSER_INIT_TIMEOUT); + for(int i=0; i<10; i++) + { + if( _parser.send("AT") && _parser.recv("[OK]") ) + { + _parser.send("AT+MECHO=0"); + _parser.recv("[OK]"); + _parser.send("AT+MPROF=S"); + _parser.recv("[OK]"); + _parser.send("AT+MRESET"); + _parser.recv("[OK]"); + break; + } + } + + _parser.recv("WizFi310 Version %s (WIZnet Co.Ltd)", _firmware_version); +} + +const char* WizFi310::get_firmware_version() +{ + if( strlen(_firmware_version) != 0 ) + { + return _firmware_version; + } + + _parser.send("AT+MINFO"); + if( _parser.recv("%s/WizFi310 Rev", _firmware_version) ) + { + return _firmware_version; + } + + return 0; +} + +bool WizFi310::startup(int mode) +{ + if( mode != 0 && mode != 1 ) + { + return false; + } + _op_mode = mode; + + _parser.oob("{", callback(this, &WizFi310::_packet_handler)); + //_parser.oob("\n{", callback(this, &WizFi310::_packet_handler)); + return true; +} + +bool WizFi310::reset(void) +{ + for (int i=0; i<2; i++) + { + if(_parser.send("AT+MRESET") + && _parser.recv("[OK]")) + { + return true; + } + } + + return false; +} + +bool WizFi310::dhcp(bool enabled) +{ + _dhcp = enabled; + return _dhcp; +} + +bool WizFi310::connect(const char *ap, const char *passPhrase, const char *sec) +{ + if ( !(_parser.send("AT+WSET=0,%s", ap) && _parser.recv("[OK]")) ) + { + return false; + } + + //if ( !(_parser.send("AT+WSEC=0,%s,%s", sec, passPhrase) && _parser.recv("[OK]")) ) + if ( !(_parser.send("AT+WSEC=0,,%s", passPhrase) && _parser.recv("[OK]")) ) + { + return false; + } + + if (_dhcp) + { + if ( !(_parser.send("AT+WNET=1") && _parser.recv("[OK]")) ) + { + return false; + } + } + else + { + if ( !(_parser.send("AT+WNET=0,%s,%s,%s",_ip_buffer,_netmask_buffer,_gateway_buffer) + && _parser.recv("[OK]")) ) + { + return false; + } + } + + if ( !(_parser.send("AT+WJOIN") && _parser.recv("[Link-Up Event]") + && _parser.recv(" IP Addr : %[^\n]\r\n",_ip_buffer) + && _parser.recv(" Gateway : %[^\n]\r\n",_gateway_buffer) + && _parser.recv("[OK]")) ) + { + return false; + } + + return true; +} + +bool WizFi310::disconnect(void) +{ + return _parser.send("AT+WLEAVE") && _parser.recv("[OK]"); +} + +const char *WizFi310::getIPAddress(void) +{ + if (!(_parser.send("AT+WSTATUS") && _parser.recv("IF/SSID/IP-Addr/Gateway/MAC/TxPower(dBm)/RSSI(-dBm)") + && _parser.recv("%*[^/]/%*[^/]/%15[^/]/",_ip_buffer) + && _parser.recv("[OK]")) ) + { + return 0; + } + + return _ip_buffer; +} + +const char *WizFi310::getMACAddress(void) +{ + if (!(_parser.send("AT+MMAC=?") + && _parser.recv("%[^\n]\r\n",_mac_buffer) + && _parser.recv("[OK]"))) { + return 0; + } + + return _mac_buffer; +} + +const char *WizFi310::getGateway() +{ + return _gateway_buffer; +} + +const char *WizFi310::getNetmask() +{ + return _netmask_buffer; +} + +int8_t WizFi310::getRSSI() +{ + char rssi[3]; + + if (!(_parser.send("AT+WSTATUS") && _parser.recv("IF/SSID/IP-Addr/Gateway/MAC/TxPower(dBm)/RSSI(-dBm)") + //&& _parser.recv("%*[^/]/%*[^/]/%*[^/]/%*[^/]/%*[^/]/%*[^/]/%[^\n]\r\n",&rssi) + && _parser.recv("%*[^/]/%*[^/]/%*[^/]/%*[^/]/%*[^/]//%[^\n]\r\n",rssi) + && _parser.recv("[OK]")) ) + { + return 0; + } + + return atoi(rssi); +} + +bool WizFi310::isConnected(void) +{ + return getIPAddress() != 0; +} + +int WizFi310::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned int cnt = 0; + nsapi_wifi_ap_t ap; + + // Scan Time out : 50ms + if (!(_parser.send("AT+WSCAN=,,,50") + && _parser.recv("Index/SSID/BSSID/RSSI(-dBm)/MaxDataRate(Mbps)/Security/RadioBand(GHz)/Channel"))) + { + return NSAPI_ERROR_DEVICE_ERROR; + } + + while (recv_ap(&ap)) { + if (cnt < limit) + { + res[cnt] = WiFiAccessPoint(ap); + } + cnt++; + if (limit != 0 && cnt >= limit) + { + break; + } + } + + return cnt; +} + +bool WizFi310::open(const char *type, int id, const char* addr, int port) +{ + int created_sock_id; + + //IDs only 0-7 + if(id > 7) { + return false; + } + + if( !(_parser.send("AT+SCON=O,%s,%s,%d,,0",type,addr,port) && _parser.recv("[OK]") + && _parser.recv("[CONNECT %d]",&created_sock_id))) { + return false; + } + + if( created_sock_id != id ) { + close(created_sock_id); + return false; + } + + return true; +} + +bool WizFi310::dns_lookup(const char* name, char* ip) +{ + return (_parser.send("AT+FDNS=%s,5000", name) && _parser.recv("%[^\n]\r\n",ip) && _parser.recv("[OK]")); +} + +bool WizFi310::send(int id, const void *data, uint32_t amount) +{ + char str_result[20]; + + if(id > 8) { + return false; + } + + sprintf(str_result,"[%d,,,%d]",id,(int)amount); + + // Using _parser.printf because MCU can't send CR LF + if( _parser.printf("AT+SSEND=%d,,,%d\r",id, (int)amount) + && _parser.recv(str_result) + && _parser.write((char*)data, (int)amount) >= 0 + && _parser.recv("[OK]") ){ + return true; + } + + return false; +} + +void WizFi310::_packet_handler() +{ + int id; + char ip_addr[16]; + int port; + uint32_t amount; + + // parse out the packet + _parser.set_timeout(AT_CMD_PARSER_RECV_TIMEOUT); + if (!_parser.recv("%d,%[^,],%d,%d}",&id, ip_addr,&port, &amount) ) { + setTimeout(_timeout_ms); + return; + } + + struct packet *packet = new struct packet; + if (!packet) { + return; + } + + packet->id = id; + packet->len = amount; + packet->next = 0; + packet->data = (char*)malloc(amount); + + + if (!(_parser.read((char*)packet->data, amount))) { + free(packet); + setTimeout(_timeout_ms); + return; + } + setTimeout(_timeout_ms); + + *_packets_end = packet; + _packets_end = &packet->next; +} + +int32_t WizFi310::recv(int id, void *data, uint32_t amount) +{ + while (true) { + // check if any packets are ready for us + for (struct packet **p = &_packets; *p; p = &(*p)->next) { + if ((*p)->id == id) { + struct packet *q = *p; + + if (q->len <= amount) { + memcpy(data,q->data, q->len); + + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + + uint32_t len = q->len; + free(q); + return len; + } else { // return only partial packet + memcpy(data, q->data, amount); + + q->len -= amount; + memmove(q->data, (uint8_t*)(q->data) + amount, q->len); + return amount; + } + } + } + + // check for inbound packets + if (!_parser.process_oob()) { + return -1; + } + } +} + +bool WizFi310::close(int id) +{ + char sock_event_msg[15]; + + if(id > 7) { + return false; + } + + if (_parser.send("AT+SMGMT=%d", id) && _parser.recv(sock_event_msg) && _parser.recv("[OK]") ) + { + return true; + } + + return false; +} + +void WizFi310::setTimeout(uint32_t timeout_ms) +{ + _parser.set_timeout(timeout_ms); + _timeout_ms = timeout_ms; +} + +bool WizFi310::readable() +{ + return _serial.FileHandle::readable(); +} + +bool WizFi310::writeable() +{ + return _serial.FileHandle::writable(); +} + +void WizFi310::attach(Callback<void()> func) +{ + _serial.sigio(func); +} + +bool WizFi310::recv_ap(nsapi_wifi_ap_t *ap) +{ + char scan_result[100]; + char sec[10]; + char bssid[32]; + char* idx_ptr; + char* bssid_ptr; + + _parser.recv("%s\r\n",scan_result); + if( strcmp(scan_result,"[OK]") == 0 ) + { + return false; + } + + idx_ptr = strtok((char*)scan_result, "/"); // index + + idx_ptr = strtok( NULL, "/" ); // ssid + strncpy(ap->ssid,idx_ptr,strlen(idx_ptr)); + ap->ssid[strlen(idx_ptr)] = '\0'; + + idx_ptr = strtok( NULL, "/" ); // bssid + strncpy(bssid,idx_ptr,strlen(idx_ptr)); + bssid[strlen(idx_ptr)] = '\0'; + + idx_ptr = strtok( NULL, "/" ); // RSSI + ap->rssi = atoi(idx_ptr); + + //idx_ptr = strtok( NULL, "/" ); // DataRate + + idx_ptr = strtok( NULL, "/" ); // Security + strncpy(sec,idx_ptr,strlen(idx_ptr)); + sec[strlen(idx_ptr)] = '\0'; + ap->security = str2sec(sec); + + idx_ptr = strtok( NULL, "/" ); // RadioBand + + idx_ptr = strtok( NULL, "/" ); // Channel + ap->channel = atoi(idx_ptr); + + // Set BSSID + bssid_ptr = strtok( (char*)bssid, ":"); + ap->bssid[0] = hex_str_to_int(bssid_ptr); + + for(int i=1; i<6; i++) + { + bssid_ptr = strtok( NULL, ":"); + ap->bssid[i] = hex_str_to_int(bssid_ptr); + } + + return true; +} + +nsapi_security_t WizFi310::str2sec(const char *str_sec) +{ + if( strcmp(str_sec,"Open") == 0 ) + { + return NSAPI_SECURITY_NONE; + } + else if( strcmp(str_sec,"WEP") == 0 ) + { + return NSAPI_SECURITY_WEP; + } + else if( strcmp(str_sec,"WPA") == 0 ) + { + return NSAPI_SECURITY_WPA; + } + else if( strcmp(str_sec,"WPA2") == 0 ) + { + return NSAPI_SECURITY_WPA2; + } + else if( strcmp(str_sec,"WPAWPA2") == 0 ) + { + return NSAPI_SECURITY_WPA_WPA2; + } + + return NSAPI_SECURITY_UNKNOWN; +} + +int WizFi310::hex_str_to_int(const char* hex_str) +{ + int n = 0; + uint32_t value = 0; + int shift = 7; + while (hex_str[n] != '\0' && n < 8) + { + if ( hex_str[n] > 0x21 && hex_str[n] < 0x40 ) + { + value |= (hex_str[n] & 0x0f) << (shift << 2); + } + else if ( (hex_str[n] >= 'a' && hex_str[n] <= 'f') || (hex_str[n] >= 'A' && hex_str[n] <= 'F') ) + { + value |= ((hex_str[n] & 0x0f) + 9) << (shift << 2); + } + else + { + break; + } + n++; + shift--; + } + + return (value >> ((shift + 1) << 2)); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/WizFi310/WizFi310.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/WizFi310/WizFi310.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + ****************************************************************************** + * @file WizFi310.h + * @author Gateway Team + * @brief Header file of the WizFi310 WiFi Device + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, WIZnet SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2017 WIZnet Co.,Ltd.</center></h2> + ****************************************************************************** + */ + +#ifndef WIZFI310_H_ +#define WIZFI310_H_ + +#include "ATCmdParser.h" + +/** WizFi310Interface class. + This is an interface to a WizFi310Interface radio. +*/ +class WizFi310 +{ +public: + WizFi310(PinName tx, PinName rx, bool debug=false); + + /** + * Check firmware version of WizFi310 + * + * @return character array firmware version or 0 if firmware query command gives outdated response + */ + const char* get_firmware_version(void); + + /** + * Startup the WizFi310 + * + * @param mode mode of WIFI 0-client, 1-host + * @return true only if WizFi310 was setup correctly + */ + bool startup(int mode); + + /** + * Reset WizFi310 + * + * @return true only if WizFi310 resets successfully + */ + bool reset(void); + + /** + * Enable/Disable DHCP + * + * @param enabled DHCP enabled when true + * @return true only if WizFi310 enables/disables DHCP successfully + */ + bool dhcp(bool enabled); + + /** + * Connect WizFi310 to AP + * + * @param ap the name of the AP + * @param passPhrase the password of AP + * @param security type of AP + * @return true only if WizFi310 is connected successfully + */ + bool connect(const char *ap, const char *passPhrase, const char *sec); + + /** + * Disconnect WizFi310 from AP + * + * @return true only if WizFi310 is disconnected successfully + */ + bool disconnect(void); + + /** + * Get the IP address of WizFi310 + * + * @return null-teriminated IP address or null if no IP address is assigned + */ + const char *getIPAddress(void); + + /** + * Get the MAC address of WizFi310 + * + * @return null-terminated MAC address or null if no MAC address is assigned + */ + const char *getMACAddress(void); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been recieved + */ + const char *getGateway(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been recieved + */ + const char *getNetmask(); + + /* Return RSSI for active connection + * + * @return Measured RSSI + */ + int8_t getRSSI(); + + /** + * Check if WizFi310 is conenected + * + * @return true only if the chip has an IP address + */ + bool isConnected(void); + + /** Scan for available networks + * + * @param ap Pointer to allocated array to store discovered AP + * @param limit Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + int scan(WiFiAccessPoint *res, unsigned limit); + + /**Perform a dns query + * + * @param name Hostname to resolve + * @param ip Buffer to store IP address + * @return 0 true on success, false on failure + */ + bool dns_lookup(const char *name, char *ip); + + /** + * Open a socketed connection + * + * @param type the type of socket to open "UDP" or "TCP" + * @param id id to give the new socket, valid 0-4 + * @param port port to open connection with + * @param addr the IP address of the destination + * @return true only if socket opened successfully + */ + bool open(const char *type, int id, const char* addr, int port); + + /** + * Sends data to an open socket + * + * @param id id of socket to send to + * @param data data to be sent + * @param amount amount of data to be sent - max 1024 + * @return true only if data sent successfully + */ + bool send(int id, const void *data, uint32_t amount); + + /** + * Receives data from an open socket + * + * @param id id to receive from + * @param data placeholder for returned information + * @param amount number of bytes to be received + * @return the number of bytes received + */ + int32_t recv(int id, void *data, uint32_t amount); + + /** + * Closes a socket + * + * @param id id of socket to close, valid only 0-4 + * @return true only if socket is closed successfully + */ + bool close(int id); + + /** + * Allows timeout to be changed between commands + * + * @param timeout_ms timeout of the connection + */ + void setTimeout(uint32_t timeout_ms); + + /** + * Checks if data is available + */ + bool readable(); + + /** + * Checks if data can be written + */ + bool writeable(); + + /** + * Attach a function to call whenever network state has changed + * + * @param func A pointer to a void function, or 0 to set as none + */ + void attach(Callback<void()> func); + + /** + * Attach a function to call whenever network state has changed + * + * @param obj pointer to the object to call the member function on + * @param method pointer to the member function to call + */ + template <typename T, typename M> + void attach(T *obj, M method) { + attach(Callback<void()>(obj, method)); + } + +private: + UARTSerial _serial; + ATCmdParser _parser; + + struct packet { + struct packet *next; + int id; + uint32_t len; + // data follows + char *data; + } *_packets, **_packets_end; + void _packet_handler(); + //void _socket_close_handler(); + bool recv_ap(nsapi_wifi_ap_t *ap); + nsapi_security_t str2sec(const char *str_sec); + int hex_str_to_int(const char* hex_str); + + char _ip_buffer[16]; + char _gateway_buffer[16]; + char _netmask_buffer[16]; + char _mac_buffer[18]; + char _firmware_version[8]; + + int _op_mode; // 0 : Station Mode, 1 : AP Mode + bool _dhcp; + uint32_t _timeout_ms; +}; + +#endif
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/WizFi310Interface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/WizFi310Interface.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,384 @@ +/* WizFi310 implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + ****************************************************************************** + * @file WizFi310Interface.h + * @author Gateway Team + * @brief Implementation file of the NetworkStack for the WizFi310 WiFi Device + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, WIZnet SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2017 WIZnet Co.,Ltd.</center></h2> + ****************************************************************************** + */ + +#include <string.h> +#include "WizFi310Interface.h" +#include "mbed_debug.h" + +// Various timeouts for different WizFi310 operations +#ifndef WIZFI310_CONNECT_TIMEOUT +#define WIZFI310_CONNECT_TIMEOUT 15000 +#endif +#ifndef WIZFI310_SEND_TIMEOUT +#define WIZFI310_SEND_TIMEOUT 500 +#endif +#ifndef WIZFI310_RECV_TIMEOUT +#define WIZFI310_RECV_TIMEOUT 0 +#endif +#ifndef WIZFI310_MISC_TIMEOUT +#define WIZFI310_MISC_TIMEOUT 500 +#endif +#ifndef WIZFI310_OPEN_TIMEOUT +#define WIZFI310_OPEN_TIMEOUT 10000 +#endif +#ifndef WIZFI310_CLOSE_TIMEOUT +#define WIZFI310_CLOSE_TIMEOUT 500 +#endif + +#ifndef WIZFI310_MAX_CONNECT_COUNT +#define WIZFI310_MAX_CONNECT 2 +#endif + +#ifndef WIZFI310_DELAY_MS +#define WIZFI310_DELAY_MS 300 +#endif + +// WizFi310Interface implementation +WizFi310Interface::WizFi310Interface(PinName tx, PinName rx, bool debug) + : _wizfi310(tx, rx, debug) +{ + memset(_ids, 0, sizeof(_ids)); + memset(_cbs, 0, sizeof(_cbs)); + + _wizfi310.attach(this, &WizFi310Interface::event); +} + +int WizFi310Interface::connect(const char *ssid, const char *pass, nsapi_security_t security, + uint8_t channel) +{ + if (channel != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + + set_credentials(ssid, pass, security); + + return connect(); +} + +int WizFi310Interface::connect() +{ + char sec[10]; + int i; + + _wizfi310.setTimeout(WIZFI310_CONNECT_TIMEOUT); + + _wizfi310.startup(0); + + if( !_wizfi310.dhcp(true) ) + { + return NSAPI_ERROR_DHCP_FAILURE; + } + + if( ap_sec == NSAPI_SECURITY_NONE && (strlen(ap_pass) > 0) ) + { + ap_sec = NSAPI_SECURITY_UNKNOWN; + } + + switch( ap_sec ) + { + case NSAPI_SECURITY_NONE: + strncpy(sec,"OPEN",strlen("OPEN")+1); + break; + case NSAPI_SECURITY_WEP: + strncpy(sec,"WEP",strlen("WEP")+1); + break; + case NSAPI_SECURITY_WPA: + strncpy(sec,"WPA",strlen("WPA")+1); + break; + case NSAPI_SECURITY_WPA2: + strncpy(sec,"WPA2",strlen("WPA2")+1); + break; + case NSAPI_SECURITY_WPA_WPA2: + strncpy(sec,"WPAWPA2",strlen("WPAWPA2")+1); + break; + default: + strncpy(sec,"",strlen("")+1); + break; + } + + for( i=0; i<WIZFI310_MAX_CONNECT; i++ ) + { + if( _wizfi310.connect(ap_ssid, ap_pass, sec) ) { + break; + } + + _wizfi310.reset(); + } + + if( i > WIZFI310_MAX_CONNECT ){ + return NSAPI_ERROR_NO_CONNECTION; + } + + if( !_wizfi310.getIPAddress() ) + { + return NSAPI_ERROR_DHCP_FAILURE; + } + + return NSAPI_ERROR_OK; +} + + +int WizFi310Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + memset(ap_ssid, 0, sizeof(ap_ssid)); + strncpy(ap_ssid, ssid, sizeof(ap_ssid)); + + memset(ap_pass, 0, sizeof(ap_pass)); + strncpy(ap_pass, pass, sizeof(ap_pass)); + + ap_sec = security; + return 0; +} + + +int WizFi310Interface::set_channel(uint8_t channel) +{ + return 0; +} + +int WizFi310Interface::disconnect() +{ + _wizfi310.setTimeout(WIZFI310_MISC_TIMEOUT); + + if (!_wizfi310.disconnect()) + { + return NSAPI_ERROR_DEVICE_ERROR; + } + return NSAPI_ERROR_OK; +} + +const char *WizFi310Interface::get_ip_address() +{ + return _wizfi310.getIPAddress(); +} + +const char *WizFi310Interface::get_mac_address() +{ + return _wizfi310.getMACAddress(); +} + +const char *WizFi310Interface::get_gateway() +{ + return _wizfi310.getGateway(); +} + +const char *WizFi310Interface::get_netmask() +{ + return _wizfi310.getNetmask(); +} + +int8_t WizFi310Interface::get_rssi() +{ + return _wizfi310.getRSSI(); +} + +int WizFi310Interface::scan(WiFiAccessPoint *res, unsigned count) +{ + return _wizfi310.scan(res, count); +} + +nsapi_error_t WizFi310Interface::gethostbyname(const char *host, + SocketAddress *address, nsapi_version_t version) +{ + char host_ip[16]; + + if( !_wizfi310.dns_lookup(host,host_ip) ){ + return NSAPI_ERROR_DNS_FAILURE; + } + if ( !address->set_ip_address(host_ip) ){ + return NSAPI_ERROR_DNS_FAILURE; + } + + return NSAPI_ERROR_OK; +} + +struct wizfi310_socket { + int id; + nsapi_protocol_t proto; + bool connected; + SocketAddress addr; +}; + + +int WizFi310Interface::socket_open(void **handle, nsapi_protocol_t proto) +{ + // Look for an unused socket + int id = -1; + + for (int i=0; i<WIZFI310_SOCKET_COUNT; i++) { + if (!_ids[i]){ + id = i; + //_ids[i] = true; + break; + } + } + + if (id == -1){ + return NSAPI_ERROR_NO_SOCKET; + } + + struct wizfi310_socket *socket = new struct wizfi310_socket; + if (!socket){ + return NSAPI_ERROR_NO_SOCKET; + } + + socket->id = id; + socket->proto = proto; + socket->connected = false; + *handle = socket; + + return 0; +} + +int WizFi310Interface::socket_close(void *handle) +{ + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + int err = 0; + _wizfi310.setTimeout(WIZFI310_CLOSE_TIMEOUT); + + if (socket->connected && !_wizfi310.close(socket->id)) { + err = NSAPI_ERROR_DEVICE_ERROR; + } + + socket->connected = false; + _ids[socket->id] = false; + delete socket; + return err; +} + +int WizFi310Interface::socket_bind(void *handle, const SocketAddress &address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int WizFi310Interface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int WizFi310Interface::socket_connect(void *handle, const SocketAddress &addr) +{ + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + _wizfi310.setTimeout(WIZFI310_OPEN_TIMEOUT); + + const char *proto = (socket->proto == NSAPI_UDP) ? "UCN" : "TCN"; + if (!_wizfi310.open(proto, socket->id, addr.get_ip_address(), addr.get_port())) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + socket->connected = true; + _ids[socket->id] = true; + return 0; +} + +int WizFi310Interface::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int WizFi310Interface::socket_send(void *handle, const void *data, unsigned size) +{ + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + _wizfi310.setTimeout(WIZFI310_SEND_TIMEOUT); + + if (!_wizfi310.send(socket->id, data, size)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + return size; +} + +int WizFi310Interface::socket_recv(void *handle, void *data, unsigned size) +{ + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + _wizfi310.setTimeout(WIZFI310_RECV_TIMEOUT); + + int32_t recv = _wizfi310.recv(socket->id, data, size); + if (recv < 0) { + return NSAPI_ERROR_WOULD_BLOCK; + } + + return recv; +} + +int WizFi310Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) +{ + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + + if (socket->connected && socket->addr != addr) { + _wizfi310.setTimeout(WIZFI310_MISC_TIMEOUT); + if (!_wizfi310.close(socket->id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + socket->connected = false; + } + + if (!socket->connected) { + int err = socket_connect(socket, addr); + if (err < 0 ) { + return err; + } + socket->addr = addr; + } + + return socket_send(socket, data, size); +} + +int WizFi310Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + int ret = socket_recv(socket, data, size); + if (ret >= 0 && addr) { + *addr = socket->addr; + } + + return ret; +} + +void WizFi310Interface::socket_attach(void *handle, void (*callback)(void *), void *data) +{ + struct wizfi310_socket *socket = (struct wizfi310_socket *)handle; + _cbs[socket->id].callback = callback; + _cbs[socket->id].data = data; +} + +void WizFi310Interface::event() +{ + for(int i=0; i<WIZFI310_SOCKET_COUNT; i++){ + if (_cbs[i].callback) { + _cbs[i].callback(_cbs[i].data); + } + } +}
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/WizFi310Interface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/WizFi310Interface.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,298 @@ +/* WizFi310 implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + ****************************************************************************** + * @file WizFi310Interface.h + * @author Gateway Team + * @brief Header file of the NetworkStack for the WizFi310 WiFi Device + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, WIZnet SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2017 WIZnet Co.,Ltd.</center></h2> + ****************************************************************************** + */ + +#ifndef WIZFI310_INTERFACE_H +#define WIZFI310_INTERFACE_H + +#include "WiFiInterface.h" +#include "WizFi310.h" + +#define WIZFI310_SOCKET_COUNT 8 + +#define WIZFI310_RTS_PIN NC +#define WIZFI310_CTS_PIN NC +#define WIZFI310_RESET_PIN NC +#define WIZFI310_ALARM_PIN NC + +/** WizFi310Interface class + * Implementation of the NetworkStack for the WizFi310 + */ +class WizFi310Interface : public NetworkStack, public WiFiInterface +{ +public: + /* WizFi310Interface constructor + */ + + WizFi310Interface(PinName tx, PinName rx, bool debug = false); + + /** Start the interface + * + * Attempts to connect to a WiFi network. Requires ssid and passphrase to be set. + * If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned. + * + * @return 0 on success, negative error code on failure + */ + virtual int connect(); + + /** Start the interface + * + * Attempts to connect to a WiFi network. + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE) + * @param channel This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED + * @return 0 on success, or error code on failure + */ + virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE, + uint8_t channel = 0); + + /** Set the WiFi network credentials + * + * @param ssid Name of the network to connect to + * @param pass Security passphrase to connect to the network + * @param security Type of encryption for connection + * (defaults to NSAPI_SECURITY_NONE) + * @return 0 on success, or error code on failure + */ + virtual int set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE); + + /** Set the WiFi network channel - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0) + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual int set_channel(uint8_t channel); + + /** Stop the interface + * @return 0 on success, negative on failure + */ + virtual int disconnect(); + + /** Get the internally stored IP address + * @return IP address of the interface or null if not yet connected + */ + virtual const char *get_ip_address(); + + /** Get the internally stored MAC address + * @return MAC address of the interface + */ + virtual const char *get_mac_address(); + + /** Get the local gateway + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been recieved + */ + virtual const char *get_gateway(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been recieved + */ + virtual const char *get_netmask(); + + /** Gets the current radio signal strength for active connection + * + * @return Connection strength in dBm (negative value) + */ + virtual int8_t get_rssi(); + + /** Scan for available networks + * + * This function will block. + * + * @param ap Pointer to allocated array to store discovered AP + * @param count Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error + * see @a nsapi_error + */ + virtual int scan(WiFiAccessPoint *res, unsigned count); + + /** Translates a hostname to an IP address with specific version + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * + * @param address Destination for the host SocketAddress + * @param host Hostname to resolve + * @param version IP version of address to resolve, NSAPI_UNSPEC indicates + * version is chosen by the stack (defaults to NSAPI_UNSPEC) + * @return 0 on success, negative error code on failure + */ + //using NetworkInterface::gethostbyname; + virtual nsapi_error_t gethostbyname(const char *host, + SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC); + + /** Add a domain name server to list of servers to query + * + * @param addr Destination for the host address + * @return 0 on success, negative error code on failure + */ + using NetworkInterface::add_dns_server; + +protected: + /** Open a socket + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure + */ + virtual int socket_open(void **handle, nsapi_protocol_t proto); + + /** Close the socket + * @param handle Socket handle + * @return 0 on success, negative on failure + * @note On failure, any memory associated with the socket must still + * be cleaned up + */ + virtual int socket_close(void *handle); + + /** Bind a server socket to a specific port + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return 0 on success, negative on failure. + */ + virtual int socket_bind(void *handle, const SocketAddress &address); + + /** Start listening for incoming connections + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return 0 on success, negative on failure + */ + virtual int socket_listen(void *handle, int backlog); + + /** Connects this TCP socket to the server + * @param handle Socket handle + * @param address SocketAddress to connect to + * @return 0 on success, negative on failure + */ + virtual int socket_connect(void *handle, const SocketAddress &address); + + /** Accept a new connection. + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return 0 on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_accept(void *handle, void **socket, SocketAddress *address); + + /** Send data to the remote host + * @param handle Socket handle + * @param data The buffer to send to the host + * @param size The length of the buffer to send + * @return Number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_send(void *handle, const void *data, unsigned size); + + /** Receive data from the remote host + * @param handle Socket handle + * @param data The buffer in which to store the data received from the host + * @param size The maximum length of the buffer + * @return Number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_recv(void *handle, void *data, unsigned size); + + /** Send a packet to a remote endpoint + * @param handle Socket handle + * @param address The remote SocketAddress + * @param data The packet to be sent + * @param size The length of the packet to be sent + * @return The number of written bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size); + + /** Receive a packet from a remote endpoint + * @param handle Socket handle + * @param address Destination for the remote SocketAddress or null + * @param buffer The buffer for storing the incoming packet data + * If a packet is too long to fit in the supplied buffer, + * excess bytes are discarded + * @param size The length of the buffer + * @return The number of received bytes on success, negative on failure + * @note This call is not-blocking, if this call would block, must + * immediately return NSAPI_ERROR_WOULD_WAIT + */ + virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); + + /** Register a callback on state change of the socket + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + * @note Callback may be called in an interrupt context. + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); + + /** Provide access to the NetworkStack object + * + * @return The underlying NetworkStack object + */ + virtual NetworkStack *get_stack() + { + return this; + } + +private: + WizFi310 _wizfi310; + bool _ids[WIZFI310_SOCKET_COUNT]; + + char ap_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */ + nsapi_security_t ap_sec; + uint8_t ap_ch; + char ap_pass[64]; /* The longest allowed passphrase */ + + void event(); + + struct { + void (*callback)(void *); + void *data; + } _cbs[WIZFI310_SOCKET_COUNT]; +}; + +#endif +
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/compile_test.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/compile_test.bat Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +mbed test -t GCC_ARM -m NUCLEO_L073RZ -n tests-net-udp_echo --compile -DMBED_CFG_WIZFI310_SSID=Dap -DMBED_CFG_WIZFI310_PASS=00001111 -DMBED_CFG_WIZFI310_TX=D8 -DMBED_CFG_WIZFI310_RX=D2 -DMBED_CFG_WIZFI310_DEBUG=true -DMBED_CONF_DRIVERS_UART_SERIAL_RXBUF_SIZE=512 -DMBED_CONF_DRIVERS_UART_SERIAL_TXBUF_SIZE=512 -c
diff -r 000000000000 -r 119624335925 easy-connect/wizfi310-driver/run_test.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wizfi310-driver/run_test.bat Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +mbed test -t GCC_ARM -m NUCLEO_L073RZ -n tests-net* --run --verbose --parallel 1
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/Avnet/wnc14a2a-driver/#90928b81747ef4b0fb4fdd94705142175e014b30
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +90928b81747ef4b0fb4fdd94705142175e014b30
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/Avnet/wnc14a2a-driver/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/index Binary file easy-connect/wnc14a2a-driver/.git/index has changed
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 90928b81747ef4b0fb4fdd94705142175e014b30 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322740 +0000 clone: from https://github.com/Avnet/wnc14a2a-driver/ +90928b81747ef4b0fb4fdd94705142175e014b30 90928b81747ef4b0fb4fdd94705142175e014b30 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322740 +0000 checkout: moving from master to 90928b81747ef4b0fb4fdd94705142175e014b30 +90928b81747ef4b0fb4fdd94705142175e014b30 90928b81747ef4b0fb4fdd94705142175e014b30 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322740 +0000 checkout: moving from 90928b81747ef4b0fb4fdd94705142175e014b30 to master
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 90928b81747ef4b0fb4fdd94705142175e014b30 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322740 +0000 clone: from https://github.com/Avnet/wnc14a2a-driver/
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 90928b81747ef4b0fb4fdd94705142175e014b30 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322740 +0000 clone: from https://github.com/Avnet/wnc14a2a-driver/
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/objects/pack/pack-d1da25a6125e922b0dd6edf286190273a308427d.idx Binary file easy-connect/wnc14a2a-driver/.git/objects/pack/pack-d1da25a6125e922b0dd6edf286190273a308427d.idx has changed
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/objects/pack/pack-d1da25a6125e922b0dd6edf286190273a308427d.pack Binary file easy-connect/wnc14a2a-driver/.git/objects/pack/pack-d1da25a6125e922b0dd6edf286190273a308427d.pack has changed
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +# pack-refs with: peeled +90928b81747ef4b0fb4fdd94705142175e014b30 refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +90928b81747ef4b0fb4fdd94705142175e014b30
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ + +# Easy Connect with the wnc14a2a-library + +## Specifying the connectivity method + +Add the following to your `mbed_app.json` file: + +```json +{ + "config": { + "network-interface":{ + "help": "options are ETHERNET, WIFI_ESP8266, WIFI_IDW0XX1, WIFI_ODIN, WIFI_RTW, WIFI_WIZFI310, WIFI_ISM43362, MESH_LOWPAN_ND, MESH_THREAD, CELLULAR_ONBOARD, CELLULAR_WNC14A2A", + "value": "CELLULAR_WNC14A2A" + } + }, + } +} +``` + +## Debug settings +You may also want to specify the following to obtain debug output. This is added to the "config" section: + +```json + "config": { + "wnc_debug": { + "help" : "enable or disable WNC debug messages.", + "value": 0 + }, + "wnc_debug_setting": { + "help" : "bit value 1 and/or 2 enable WncController debug output, bit value 4 enables mbed driver debug output.", + "value": "4" + } + } +``` + +where the wnc_debug is either 'true' or 'false' to enable or disable debug output and the `wnc_debug_setting` variable is a +bit-field with the following settings: + 0x01 - Basic WNC driver debug output + 0x02 - Comprehensive WNC driver debug output + 0x04 - Driver Enter/Exit debug information + 0x08 - Driver Event Queue debug information + 0x10 - SMS debug information + 0x20 - Dump Driver Arrays + +## Overriding settings +You need to increase the size of the Tx and Rx buffers used when communicating to the WNC device by adding (increas the buffer +size to 4KB from 256 Bytes): + + +```json + "target_overrides": { + "*": { + "drivers.uart-serial-txbuf-size": 4096, + "drivers.uart-serial-rxbuf-size": 4096 + } +``` +
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/WNC14A2AInterface/WNC14A2AInterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/WNC14A2AInterface/WNC14A2AInterface.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,957 @@ +/** +* copyright (c) 2017-2018, James Flynn +* SPDX-License-Identifier: Apache-2.0 +*/ + +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** +* @file WNC14A2AInterface.cpp +* @brief WNC14A2A implementation of NetworkInterfaceAPI for Mbed OS +* +* @author James Flynn +* +* @date 1-Feb-2018 +*/ + +#include "WNC14A2AInterface.h" +#include <Thread.h> +#include "mbed_events.h" +#include "WNCIO.h" + +#include <string> +#include <ctype.h> + +#define WNC_DEBUG 0 //1=enable the WNC startup debug output + //0=disable the WNC startup debug output +#define STOP_ON_FE 1 //1=hang forever if a fatal error occurs + //0=simply return failed response for all socket calls +#define DISPLAY_FE 1 //1 to display the fatal error when it occurs + //0 to NOT display the fatal error +#define RESETON_FE 0 //1 to cause the MCU to reset on fatal error + //0 to NOT reset the MCU + +/** Error Handling macros & data +* @brief The macros CHK_WNCFE is used to check if a fatal error has occured. If it has +* then execute the action specified: fail, void, null, resume +* +* CHK_WNCFE( condition-to-check, fail|void|null|resume ) +* +* 'fail' if you want FATAL_WNC_ERROR to be called. +* 'void' if you want to execute a void return +* 'null' if you want to execute a null return +* 'resume' if you simply want to resume program execution +* +* There are several settings that control how FATAL_WNC_ERROR behaves: +* 1) RESETON_FE determines if the system will reset or hang. +* 2) DISPLAY_FE determine if an error message is generated or not +* +* The DISPLAY_FE setting determines if a failure message is displayed. +* If set to 1, user sees this messageo: +* +* WNC FAILED @ source-file-name:source-file-line-number +* +* if not set, nothing is displayed. +*/ + +#define FATAL_FLAG WncController::WNC_NO_RESPONSE +#define WNC_GOOD WncController::WNC_ON + +#define RETfail return -1 +#define RETvoid return +#define RETnull return NULL +#define RETresume + +#define DORET(x) RET##x + +#define TOSTR(x) #x +#define INTSTR(x) TOSTR(x) +#define FATAL_STR (char*)(__FILE__ ":" INTSTR(__LINE__)) + +#if RESETON_FE == 1 //reset on fatal error +#define MCURESET ((*((volatile unsigned long *)0xE000ED0CU))=(unsigned long)((0x5fa<<16) | 0x04L)) +#define RSTMSG "RESET MCU! " +#else +#define MCURESET +#define RSTMSG "" +#endif + +#if DISPLAY_FE == 1 //display fatal error message +#define PFE {if(_debugUart)_debugUart->printf((char*)RSTMSG "\r\n>>WNC FAILED @ %s\r\n", FATAL_STR);} +#else +#define PFE +#endif + +#if STOP_ON_FE == 1 //halt cpu on fatal error +#define FATAL_WNC_ERROR(v) {_fatal_err_loc=FATAL_STR;PFE;MCURESET;while(1);} +#else +#define FATAL_WNC_ERROR(v) {_fatal_err_loc=FATAL_STR;PFE;DORET(v);} +#endif + +#define CHK_WNCFE(x,y) if( x ){FATAL_WNC_ERROR(y);} + +// +// Define different levels of debug output +// +#define DBGMSG_DRV 0x04 //driver enter/exit info +#define DBGMSG_EQ 0x08 //driver event queue info +#define DBGMSG_SMS 0x10 //driver SMS info +#define DBGMSG_ARRY 0x20 //dump driver arrays + +#define WNC14A2A_READ_TIMEOUTMS 4000 //duration to read no data to receive in MS +#define WNC14A2A_COMMUNICATION_TIMEOUT 100 //how long (ms) to wait for a WNC14A2A connect response +#define WNC_BUFF_SIZE 1500 //total number of bytes in a single WNC call +#define UART_BUFF_SIZE 4096 //size of our internal uart buffer.. define in *.json file + +#define EQ_FREQ 250 //frequency in ms to check for Tx/Rx data +#define EQ_FREQ_SLOW 2000 //frequency in ms to check when in slow monitor mode + +// +// The WNC device does not generate interrutps on received data, so this software polls +// for data availablility. To implement a non-blocking mode, simulate interrupts using +// mbed OS Event Queues. These Constants are used to manage the Rx/Tx states. +// +#define READ_INIT 10 +#define READ_START 11 +#define READ_ACTIVE 12 +#define DATA_AVAILABLE 13 +#define TX_IDLE 20 +#define TX_STARTING 21 +#define TX_ACTIVE 22 +#define TX_COMPLETE 23 + +#if MBED_CONF_APP_WNC_DEBUG == true +#define debugOutput(...) WNC14A2AInterface::_dbOut(__VA_ARGS__) +#define debugDump_arry(...) WNC14A2AInterface::_dbDump_arry(__VA_ARGS__) +#else +#define debugOutput(...) {/* __VA_ARGS__ */} +#define debugDump_arry(...) {/* __VA_ARGS__ */} +#endif + +/* Constructor +* +* @brief May be invoked with or without the debug pointer. +* @note After the constructor has completed, call check +* m_errors to determine if any errors occured. Possible values: +* NSAPI_ERROR_UNSUPPORTED +* NSAPI_ERROR_DEVICE_ERROR +*/ +WNC14A2AInterface::WNC14A2AInterface(WNCDebug *dbg) : + m_wncpoweredup(0), + m_debug(0), + m_pwnc(NULL), + m_errors(NSAPI_ERROR_OK), + m_smsmoning(0), + _active_socket(0), + mdmUart(MBED_CONF_WNC14A2A_LIBRARY_WNC_TXD,MBED_CONF_WNC14A2A_LIBRARY_WNC_RXD,115200), + wnc_io(&mdmUart) +{ + _debugUart = dbg; + memset(_mac_address,0x00,sizeof(_mac_address)); + memset(_socTxS,0x00,sizeof(_socTxS)); + memset(_socRxS,0x00,sizeof(_socRxS)); + for( unsigned int i=0; i<WNC14A2A_SOCKET_COUNT; i++ ) { + _sockets[i].socket = i; + _sockets[i].addr = NULL; + _sockets[i].opened=false; + + _sockets[i].connected=false; + _sockets[i].proto=1; + _socRxS[i].m_rx_socket=i; + _socTxS[i].m_tx_socket=i; + } +} + +//! Standard destructor +WNC14A2AInterface::~WNC14A2AInterface() +{ + if( m_pwnc ) + delete m_pwnc; //free the existing WncControllerK64F object +} + +// - - - - - - - +// SMS Functions +// - - - - - - - + +char* WNC14A2AInterface::getSMSnbr( void ) +{ + char * ret=NULL; + string iccid_str; + static string msisdn_str; + + if( !m_pwnc ) { + m_errors=NSAPI_ERROR_DEVICE_ERROR; + return NULL; + } + CHK_WNCFE(( m_pwnc->getWncStatus() == FATAL_FLAG ), null); + + _pwnc_mutex.lock(); + if( !m_pwnc->getICCID(&iccid_str) ) { + _pwnc_mutex.unlock(); + return ret; + } + + if( m_pwnc->convertICCIDtoMSISDN(iccid_str, &msisdn_str) ) + ret = (char*)msisdn_str.c_str(); + _pwnc_mutex.unlock(); + return ret; +} + +void WNC14A2AInterface::sms_attach(void (*callback)(IOTSMS *)) +{ + debugOutput("ENTER/EXIT sms_attach()"); + _sms_cb = callback; +} + +void WNC14A2AInterface::sms_start(void) +{ + _pwnc_mutex.lock(); + m_pwnc->deleteSMSTextFromMem('*'); + _pwnc_mutex.unlock(); +} + +void WNC14A2AInterface::sms_listen(uint16_t pp) +{ + debugOutput("ENTER sms_listen(%d)",pp); + + if( m_smsmoning ) + m_smsmoning = false; + if( pp < 1) + pp = 30; + + debugOutput("setup sms_listen event queue"); + _smsThread.start(callback(&sms_queue,&EventQueue::dispatch_forever)); + + sms_start(); + sms_queue.call_every(pp*1000, mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::handle_sms_event)); + + m_smsmoning = true; + debugOutput("EXIT sms_listen()"); +} + +void WNC14A2AInterface::handle_sms_event() +{ + int msgs_available; + debugOutput("ENTER handle_sms_event()"); + + if ( _sms_cb && m_smsmoning ) { + _pwnc_mutex.lock(); + msgs_available = m_pwnc->readUnreadSMSText(&m_smsmsgs, true); + _pwnc_mutex.unlock(); + if( msgs_available ) { + debugOutput("Have %d unread texts present",m_smsmsgs.msgCount); + for( int i=0; i< m_smsmsgs.msgCount; i++ ) { + m_MsgText.number = m_smsmsgs.e[i].number; + m_MsgText.date = m_smsmsgs.e[i].date; + m_MsgText.time = m_smsmsgs.e[i].time; + m_MsgText.msg = m_smsmsgs.e[i].msg; + _sms_cb(&m_MsgText); + } + } + } + debugOutput("EXIT handle_sms_event"); +} + +int WNC14A2AInterface::getSMS(IOTSMS **pmsg) +{ + int msgs_available=0; + + debugOutput("ENTER getSMS()"); + if( !m_pwnc ) + m_errors=NSAPI_ERROR_DEVICE_ERROR; + else{ + CHK_WNCFE((m_pwnc->getWncStatus()==FATAL_FLAG), fail); + _pwnc_mutex.lock(); + msgs_available = m_pwnc->readUnreadSMSText(&m_smsmsgs, true); + _pwnc_mutex.unlock(); + } + + if( msgs_available ) { + debugOutput("Have %d unread texts present",m_smsmsgs.msgCount); + for( int i=0; i< m_smsmsgs.msgCount; i++ ) { + m_MsgText_array[i].number = m_smsmsgs.e[i].number; + m_MsgText_array[i].date = m_smsmsgs.e[i].date; + m_MsgText_array[i].time = m_smsmsgs.e[i].time; + m_MsgText_array[i].msg = m_smsmsgs.e[i].msg; + pmsg[i] = (IOTSMS*)&m_MsgText_array[i]; + } + msgs_available = m_smsmsgs.msgCount; + } + debugOutput("EXIT getSMS"); + return msgs_available; +} + + +int WNC14A2AInterface::sendIOTSms(const string& number, const string& message) +{ + debugOutput("ENTER sendIOTSms(%s,%s)",number.c_str(), message.c_str()); + + if( !m_pwnc ) + return (m_errors=NSAPI_ERROR_DEVICE_ERROR); + CHK_WNCFE((m_pwnc->getWncStatus()==FATAL_FLAG), fail); + + _pwnc_mutex.lock(); + int i = m_pwnc->sendSMSText((char*)number.c_str(), message.c_str()); + _pwnc_mutex.unlock(); + + debugOutput("EXIT sendIOTSms(%s,%s)",number.c_str(), message.c_str()); + return i; +} + + +// - - - - - - - - - - - +// WNC Control Functions +// - - - - - - - - - - - + +nsapi_error_t WNC14A2AInterface::connect() //can be called with no arguments or with arguments +{ + debugOutput("ENTER connect(void)"); + return connect(NULL,NULL,NULL); +} + +nsapi_error_t WNC14A2AInterface::connect(const char *apn, const char *username, const char *password) +{ + // + // GPIO Pins used to initialize the WNC parts on the Avnet WNC Shield + // + // on powerup, 0 = boot mode, 1 = normal boot + // 0=let modem sleep, 1=keep modem awake -- Note: pulled high on shield + // active high + // 0 = disabled (all signals high impedence, 1 = translation active + // WNC doesn't utilize RTS/CTS but the pin is connected + + static DigitalOut mdm_uart2_rx_boot_mode_sel(MBED_CONF_WNC14A2A_LIBRARY_WNC_RX_BOOT_SEL); + static DigitalOut mdm_power_on(MBED_CONF_WNC14A2A_LIBRARY_WNC_POWER_ON); + static DigitalOut mdm_wakeup_in(MBED_CONF_WNC14A2A_LIBRARY_WNC_WAKEUP); + static DigitalOut mdm_reset(MBED_CONF_WNC14A2A_LIBRARY_WNC_RESET); + static DigitalOut shield_3v3_1v8_sig_trans_ena(MBED_CONF_WNC14A2A_LIBRARY_WNC_LVLTRANSLATOR); + static DigitalOut mdm_uart1_cts(MBED_CONF_WNC14A2A_LIBRARY_WNC_CTS); + + //! associations for the controller class to use. Order of pins is critical. + static WncControllerK64F_fk::WncGpioPinListK64F wncPinList = { + &mdm_uart2_rx_boot_mode_sel, + &mdm_power_on, + &mdm_wakeup_in, + &mdm_reset, + &shield_3v3_1v8_sig_trans_ena, + &mdm_uart1_cts + }; + + debugOutput("ENTER connect(apn,user,pass)"); + + if( m_pwnc == NULL ) { + m_pwnc = new WncControllerK64F_fk::WncControllerK64F(&wncPinList, &wnc_io, _debugUart); + if( !m_pwnc ) { + debugOutput("FAILED to open WncControllerK64!"); + m_errors = NSAPI_ERROR_DEVICE_ERROR; + return NSAPI_ERROR_NO_MEMORY; + } + CHK_WNCFE((m_pwnc->getWncStatus()==FATAL_FLAG), fail); + #if MBED_CONF_APP_WNC_DEBUG == true + m_pwnc->enableDebug( (MBED_CONF_APP_WNC_DEBUG_SETTING&1), (MBED_CONF_APP_WNC_DEBUG_SETTING&2) ); + #endif + } + + _eqThread.start(callback(&wnc_queue,&EventQueue::dispatch_forever)); + + if (!apn) + apn = "m2m.com.attz"; + + _pwnc_mutex.lock(); + if (!m_wncpoweredup) { + debugOutput("call powerWncOn(%s,40)",apn); + m_wncpoweredup=m_pwnc->powerWncOn(apn,40); + m_errors = m_wncpoweredup? 1:0; + } + else { //powerWncOn already called, set a new APN + debugOutput("set APN=%s",apn); + m_errors = m_pwnc->setApnName(apn)? 1:0; + } + + m_errors |= m_pwnc->getWncNetworkingStats(&myNetStats)? 2:0; + _pwnc_mutex.unlock(); + + debugOutput("EXIT connect (%02X)",m_errors); + return (!m_errors)? NSAPI_ERROR_NO_CONNECTION : NSAPI_ERROR_OK; +} + +const char* WNC14A2AInterface::getWNCRev(void) +{ + if( m_pwnc ) { + const char * str = m_pwnc->getFirmRev(); + return &str[12]; + } + else + return NULL; +} + + +const char *WNC14A2AInterface::get_ip_address() +{ + const char *ptr=NULL; + + if( !m_pwnc ) { + m_errors=NSAPI_ERROR_DEVICE_ERROR; + return ptr; + } + CHK_WNCFE((m_pwnc->getWncStatus()==FATAL_FLAG), null); + + _pwnc_mutex.lock(); + if ( m_pwnc->getWncNetworkingStats(&myNetStats) ) { + _pwnc_mutex.unlock(); + ptr = &myNetStats.ip[0]; + } + else{ + _pwnc_mutex.unlock(); + m_errors=NSAPI_ERROR_NO_CONNECTION; + } + return ptr; +} + +const char *WNC14A2AInterface::get_mac_address() +{ + string mac, str; + debugOutput("ENTER get_mac_address()"); + + if( m_pwnc ) { + CHK_WNCFE((m_pwnc->getWncStatus()==FATAL_FLAG), null); + _pwnc_mutex.lock(); + if( m_pwnc->getICCID(&str) ) { + _pwnc_mutex.unlock(); + mac = str.substr(3,20); + mac[2]=mac[5]=mac[8]=mac[11]=mac[14]=':'; + strncpy(_mac_address, mac.c_str(), mac.length()); + debugOutput("EXIT get_mac_address() - %s",_mac_address); + return _mac_address; + } + _pwnc_mutex.unlock(); + } + debugOutput("EXIT get_mac_address() - NULL"); + return NULL; +} + +NetworkStack *WNC14A2AInterface::get_stack() { + debugOutput("ENTER/EXIT get_stack()"); + return this; +} + +nsapi_error_t WNC14A2AInterface::disconnect() +{ + debugOutput("ENTER/EXIT disconnect()"); + return NSAPI_ERROR_OK; +} + +nsapi_error_t WNC14A2AInterface::set_credentials(const char *apn, const char *username, const char *password) +{ + + m_errors=NSAPI_ERROR_OK; + debugOutput("ENTER set_credentials()"); + + if( !m_pwnc ) + return (m_errors=NSAPI_ERROR_DEVICE_ERROR); + CHK_WNCFE((m_pwnc->getWncStatus()==FATAL_FLAG), fail); + + if( !apn ) + return (m_errors=NSAPI_ERROR_PARAMETER); + + _pwnc_mutex.lock(); + if( !m_pwnc->setApnName(apn) ) + m_errors=NSAPI_ERROR_DEVICE_ERROR; + _pwnc_mutex.unlock(); + debugOutput("EXIT set_credentials()"); + return m_errors; +} + +bool WNC14A2AInterface::registered() +{ + debugOutput("ENTER registered()"); + m_errors=NSAPI_ERROR_OK; + + if( !m_pwnc ) { + return (m_errors=NSAPI_ERROR_DEVICE_ERROR); + } + CHK_WNCFE((m_pwnc->getWncStatus()==FATAL_FLAG), fail); + + _pwnc_mutex.lock(); + if ( m_pwnc->getWncStatus() != WNC_GOOD ) + m_errors=NSAPI_ERROR_NO_CONNECTION; + _pwnc_mutex.unlock(); + + debugOutput("EXIT registered()"); + return (m_errors==NSAPI_ERROR_OK); +} + + +void WNC14A2AInterface::doDebug( int v ) +{ + #if MBED_CONF_APP_WNC_DEBUG == true + m_debug= v; + debugOutput("SET debug flag to 0x%02X",v); + #endif +} + +/** function to dump a user provided array. +* +* @author James Flynn +* @param data pointer to the data array to dump +* @param size number of bytes to dump +* @return void +* @date 1-Feb-2018 +*/ +void WNC14A2AInterface::_dbDump_arry( const uint8_t* data, unsigned int size ) +{ + #if MBED_CONF_APP_WNC_DEBUG == true + char buffer[256]; + unsigned int i, k; + + if( _debugUart != NULL && (m_debug & DBGMSG_ARRY) ) { + for (i=0; i<size; i+=16) { + sprintf(buffer,"[WNC Driver]:0x%04X: ",i); + _debugUart->puts(buffer); + for (k=0; k<16; k++) { + sprintf(buffer, "%02X ", data[i+k]); + _debugUart->puts(buffer); + } + _debugUart->puts(" -- "); + for (k=0; k<16; k++) { + sprintf(buffer, "%2c", isprint(data[i+k])? data[i+k]:'.'); + _debugUart->puts(buffer); + } + _debugUart->puts("\n\r"); + } + } + #endif +} + +void WNC14A2AInterface::_dbOut(const char *format, ...) +{ + #if MBED_CONF_APP_WNC_DEBUG == true + char buffer[256]; + + sprintf(buffer,"[WNC Driver]: "); + if( _debugUart != NULL && (m_debug & (DBGMSG_DRV|DBGMSG_EQ|DBGMSG_SMS)) ) { + va_list args; + va_start (args, format); + _debugUart->puts(buffer); + if( m_debug & DBGMSG_DRV ) + vsnprintf(buffer, sizeof(buffer), format, args); + if( m_debug & DBGMSG_EQ ) + vsnprintf(buffer, sizeof(buffer), format, args); + if( m_debug & DBGMSG_SMS ) + vsnprintf(buffer, sizeof(buffer), format, args); + _debugUart->puts(buffer); + _debugUart->putc('\n'); + va_end (args); + } + #endif +} + +// - - - - - - - - - - - - - - - +// WNC Socket Based operatioins +// - - - - - - - - - - - - - - - + +nsapi_error_t WNC14A2AInterface::gethostbyname(const char* name, SocketAddress *address, nsapi_version_t version) +{ + nsapi_error_t ret = NSAPI_ERROR_OK; + char ipAddrStr[25]; + + debugOutput("ENTER gethostbyname(); IP=%s; PORT=%d; URL=%s;", address->get_ip_address(), address->get_port(), name); + + if( !m_pwnc ) + return (m_errors=NSAPI_ERROR_DEVICE_ERROR); + CHK_WNCFE((m_pwnc->getWncStatus()==FATAL_FLAG), fail); + + memset(ipAddrStr,0x00,sizeof(ipAddrStr)); + + //Execute DNS query. + _pwnc_mutex.lock(); + if( !m_pwnc->resolveUrl(_active_socket, name) ) + ret = m_errors = NSAPI_ERROR_DEVICE_ERROR; + + //Get IP address that the URL was resolved to + if( !m_pwnc->getIpAddr(_active_socket, ipAddrStr) ) + ret = m_errors = NSAPI_ERROR_DEVICE_ERROR; + _pwnc_mutex.unlock(); + + address->set_ip_address(ipAddrStr); + + debugOutput("EXIT gethostbyname(); IP=%s; PORT=%d; URL=%s;", address->get_ip_address(), address->get_port(), name); + return (m_errors = ret); +} + +int WNC14A2AInterface::socket_open(void **handle, nsapi_protocol_t proto) +{ + unsigned int i; + + debugOutput("ENTER socket_open()"); + + //find the next available socket... + for( i=0; i<WNC14A2A_SOCKET_COUNT; i++ ) + if( !_sockets[i].opened ) + break; + + if( i == WNC14A2A_SOCKET_COUNT ) { + m_errors=NSAPI_ERROR_NO_SOCKET; + return -1; + } + + _sockets[i].socket = i; //save index later + _sockets[i].opened = true; + _sockets[i].connected=false; + _sockets[i].proto = (proto==NSAPI_UDP)?0:1; + _sockets[i]._callback = NULL; + _sockets[i]._cb_data = NULL; + + _socRxS[i].m_rx_wnc_state = READ_START; + _socRxS[i].m_rx_disTO = false; + _socTxS[i].m_tx_wnc_state = TX_IDLE; + + *handle = &_sockets[i]; + + debugOutput("EXIT socket_open; Socket=%d, OPEN=%s, protocol =%s", + i, _sockets[i].opened?"YES":"NO", (!_sockets[i].proto)?"UDP":"TCP"); + + return (m_errors = NSAPI_ERROR_OK); +} + +int WNC14A2AInterface::socket_connect(void *handle, const SocketAddress &address) +{ + WNCSOCKET *wnc = (WNCSOCKET *)handle; + int err = 0; + + debugOutput("ENTER socket_connect(); Socket=%d; IP=%s; PORT=%d;", wnc->socket, address.get_ip_address(), address.get_port()); + + if (!wnc->opened ) + return (m_errors = NSAPI_ERROR_NO_SOCKET); + + wnc->addr = address; + + _pwnc_mutex.lock(); + if( wnc->url.empty() ) + err = !m_pwnc->openSocketIpAddr(wnc->socket, address.get_ip_address(), address.get_port(), wnc->proto, WNC14A2A_COMMUNICATION_TIMEOUT); + else + err = !m_pwnc->openSocketUrl(wnc->socket, wnc->url.c_str(), wnc->addr.get_port(), wnc->proto); + _pwnc_mutex.unlock(); + + if( !err ) { + wnc->connected = true; + _socRxS[wnc->socket].m_rx_wnc_state = READ_START; + _socTxS[wnc->socket].m_tx_wnc_state = TX_IDLE; + + if( wnc->_callback != NULL ) + wnc->_callback( wnc->_cb_data ); + } + + return err; +} + +int WNC14A2AInterface::socket_close(void *handle) +{ + WNCSOCKET *wnc = (WNCSOCKET*)handle; + RXEVENT *rxsock; + TXEVENT *txsock; + bool err = false; + + debugOutput("ENTER socket_close()"); + + rxsock = &_socRxS[wnc->socket]; + txsock = &_socTxS[wnc->socket]; + + txsock->m_tx_wnc_state = TX_IDLE; //reset TX state + if( rxsock->m_rx_wnc_state != READ_START ) { //reset RX state + rxsock->m_rx_disTO=false; + while( rxsock->m_rx_wnc_state != DATA_AVAILABLE ) + wait(1); //someone called close while a read was happening + } + + _pwnc_mutex.lock(); + if( !m_pwnc->closeSocket(wnc->socket) ) { + m_errors = NSAPI_ERROR_DEVICE_ERROR; + err = true; + } + _pwnc_mutex.unlock(); + + if( !err ) { + wnc->opened = false; //no longer in use + wnc->addr = NULL; //not open + wnc->connected= false; + wnc->proto = 1; //assume TCP for now + m_errors = NSAPI_ERROR_OK; + wnc->_cb_data = NULL; + wnc->_callback= NULL; + } + + debugOutput("EXIT socket_close()"); + return err; +} + + +void WNC14A2AInterface::socket_attach(void *handle, void (*callback)(void *), void *data) +{ + WNCSOCKET *wnc = (WNCSOCKET *)handle; + + debugOutput("ENTER/EXIT socket_attach()"); + wnc->_callback = callback; + wnc->_cb_data = data; +} + +int WNC14A2AInterface::socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size) +{ + WNCSOCKET *wnc = (WNCSOCKET *)handle; + + debugOutput("ENTER socket_sendto()"); + + if (!wnc->connected) { + int err = socket_connect(wnc, address); + if (err < 0) + return err; + } + wnc->addr = address; + + debugOutput("EXIT socket_sendto()"); + return socket_send(wnc, data, size); +} + +int WNC14A2AInterface::socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size) +{ + WNCSOCKET *wnc = (WNCSOCKET *)handle; + debugOutput("ENTER socket_recvfrom()"); + + if (!wnc->connected) { + debugOutput("need to open a WNC socket first"); + int err = socket_connect(wnc, *address); + if (err < 0) + return err; + } + + int ret = socket_recv(wnc, (char *)buffer, size); + if (ret >= 0 && address) + *address = wnc->addr; + debugOutput("EXIT socket_recvfrom()"); + return ret; +} + + +int inline WNC14A2AInterface::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address) +{ + debugOutput("ENTER/EXIT socket_accept() -- not supported"); + m_errors = NSAPI_ERROR_UNSUPPORTED; + return -1; +} + +int inline WNC14A2AInterface::socket_bind(void *handle, const SocketAddress &address) +{ + WNCSOCKET *wnc = (WNCSOCKET *)handle; + + debugOutput("ENTER/EXIT socket_bind(), use address '%s', port %d", address.get_ip_address(),address.get_port()); + _socRxS[wnc->socket].m_rx_disTO=true; //for us, simply disable the Rx timeout to keep monitoring for data + return (m_errors = NSAPI_ERROR_OK); +} + + +int inline WNC14A2AInterface::socket_listen(void *handle, int backlog) +{ + debugOutput("ENTER/EXIT socket_listen() -- not supported"); + m_errors = NSAPI_ERROR_UNSUPPORTED; + return -1; +} + + +int WNC14A2AInterface::socket_send(void *handle, const void *data, unsigned size) +{ + WNCSOCKET *wnc = (WNCSOCKET *)handle; + TXEVENT *txsock; + + debugOutput("ENTER socket_send() send %d bytes",size); + txsock = &_socTxS[wnc->socket]; + + if( size < 1 || data == NULL ) // should never happen but have seen it + return 0; + + switch( txsock->m_tx_wnc_state ) { + case TX_IDLE: + txsock->m_tx_wnc_state = TX_STARTING; + debugDump_arry((const uint8_t*)data,size); + txsock->m_tx_dptr = (uint8_t*)data; + txsock->m_tx_orig_size = size; + txsock->m_tx_req_size = (uint32_t)size; + txsock->m_tx_total_sent= 0; + txsock->m_tx_callback = wnc->_callback; + txsock->m_tx_cb_data = wnc->_cb_data; + + if( txsock->m_tx_req_size > UART_BUFF_SIZE ) + txsock->m_tx_req_size= UART_BUFF_SIZE; + + if( !tx_event(txsock) ) { //if we didn't sent all the data at once, continue in background + txsock->m_tx_wnc_state = TX_ACTIVE; + wnc_queue.call_in(EQ_FREQ,mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::wnc_eq_event)); + return NSAPI_ERROR_WOULD_BLOCK; + } + // fall through + + case TX_COMPLETE: + debugOutput("EXIT socket_send(), sent %d bytes", txsock->m_tx_total_sent); + txsock->m_tx_wnc_state = TX_IDLE; + return txsock->m_tx_total_sent; + + case TX_ACTIVE: + case TX_STARTING: + return NSAPI_ERROR_WOULD_BLOCK; + + default: + debugOutput("EXIT socket_send(), NSAPI_ERROR_DEVICE_ERROR"); + return (m_errors = NSAPI_ERROR_DEVICE_ERROR); + } +} + +int WNC14A2AInterface::tx_event(TXEVENT *ptr) +{ + debugOutput("ENTER tx_event(), socket %d",ptr->m_tx_socket); + + _pwnc_mutex.lock(); + if( m_pwnc->write(ptr->m_tx_socket, ptr->m_tx_dptr, ptr->m_tx_req_size) ) + ptr->m_tx_total_sent += ptr->m_tx_req_size; + _pwnc_mutex.unlock(); + + if( ptr->m_tx_total_sent < ptr->m_tx_orig_size ) { + ptr->m_tx_dptr += ptr->m_tx_req_size; + ptr->m_tx_req_size = ptr->m_tx_orig_size-ptr->m_tx_total_sent; + + if( ptr->m_tx_req_size > UART_BUFF_SIZE) + ptr->m_tx_req_size= UART_BUFF_SIZE; + + debugOutput("EXIT tx_event(), send %d more bytes.",ptr->m_tx_req_size); + return 0; + } + debugOutput("EXIT tx_event, socket %d, data sent",ptr->m_tx_socket); + ptr->m_tx_wnc_state = TX_COMPLETE; + if( ptr->m_tx_callback != NULL ) + ptr->m_tx_callback( ptr->m_tx_cb_data ); + ptr->m_tx_cb_data = NULL; + ptr->m_tx_callback = NULL; + + return 1; +} + +int WNC14A2AInterface::socket_recv(void *handle, void *data, unsigned size) +{ + WNCSOCKET *wnc = (WNCSOCKET *)handle; + RXEVENT *rxsock; + + rxsock = &_socRxS[wnc->socket]; + debugOutput("ENTER socket_recv(), socket %d, request %d bytes",wnc->socket, size); + + if( size < 1 || data == NULL ) { // should never happen + return 0; + } + + switch( rxsock->m_rx_wnc_state ) { + case READ_START: //need to start a read sequence of events + rxsock->m_rx_wnc_state= READ_INIT; + rxsock->m_rx_dptr = (uint8_t*)data; + rxsock->m_rx_req_size = (uint32_t)size; + rxsock->m_rx_total_cnt= 0; + rxsock->m_rx_timer = 0; + rxsock->m_rx_return_cnt=0; + + if( rxsock->m_rx_req_size > WNC_BUFF_SIZE) + rxsock->m_rx_req_size= WNC_BUFF_SIZE; + + rxsock->m_rx_callback = wnc->_callback; + rxsock->m_rx_cb_data = wnc->_cb_data; + + if( !rx_event(rxsock) ){ + rxsock->m_rx_wnc_state = READ_ACTIVE; + wnc_queue.call_in(EQ_FREQ,mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::wnc_eq_event)); + return NSAPI_ERROR_WOULD_BLOCK; + } + // fall through + + case DATA_AVAILABLE: + debugOutput("EXIT socket_recv(),socket %d, return %d bytes",wnc->socket, rxsock->m_rx_return_cnt); + debugDump_arry((const uint8_t*)data,rxsock->m_rx_return_cnt); + rxsock->m_rx_wnc_state = READ_START; + return rxsock->m_rx_return_cnt; + + case READ_ACTIVE: + case READ_INIT: + rxsock->m_rx_timer = 0; //reset the time-out timer + return NSAPI_ERROR_WOULD_BLOCK; + + default: + debugOutput("EXIT socket_recv(), NSAPI_ERROR_DEVICE_ERROR"); + return (m_errors = NSAPI_ERROR_DEVICE_ERROR); + } +} + + +int WNC14A2AInterface::rx_event(RXEVENT *ptr) +{ + debugOutput("ENTER rx_event() for socket %d", ptr->m_rx_socket); + _pwnc_mutex.lock(); + int cnt = m_pwnc->read(ptr->m_rx_socket, ptr->m_rx_dptr, ptr->m_rx_req_size); + _pwnc_mutex.unlock(); + + if( cnt ) { //got data, return it to the caller + debugOutput("data received on socket %d, cnt=%d", ptr->m_rx_socket,cnt); + ptr->m_rx_wnc_state = DATA_AVAILABLE; + ptr->m_rx_return_cnt = cnt; + if( ptr->m_rx_callback != NULL ) + ptr->m_rx_callback( ptr->m_rx_cb_data ); + ptr->m_rx_cb_data = NULL; + ptr->m_rx_callback = NULL; + return 1; + } + if( ++ptr->m_rx_timer > (WNC14A2A_READ_TIMEOUTMS/EQ_FREQ) && !ptr->m_rx_disTO ) { //timed out waiting, return 0 to caller + debugOutput("EXIT rx_event(), rx data TIME-OUT!"); + ptr->m_rx_wnc_state = DATA_AVAILABLE; + ptr->m_rx_return_cnt = 0; + if( ptr->m_rx_callback != NULL ) + ptr->m_rx_callback( ptr->m_rx_cb_data ); + ptr->m_rx_cb_data = NULL; + ptr->m_rx_callback = NULL; + return 1; + } + + debugOutput("EXIT rx_event(), socket %d, sechedule for more data.",ptr->m_rx_socket); + return 0; +} + +void WNC14A2AInterface::wnc_eq_event() +{ + int done = 1; + bool goSlow = true; + + for( unsigned int i=0; i<WNC14A2A_SOCKET_COUNT; i++ ) { + if( _socRxS[i].m_rx_wnc_state == READ_ACTIVE || _socRxS[i].m_rx_disTO) { + done &= rx_event(&_socRxS[i]); + goSlow &= ( _socRxS[i].m_rx_timer > ((WNC14A2A_READ_TIMEOUTMS/EQ_FREQ)*(EQ_FREQ_SLOW/EQ_FREQ)) ); + + if( goSlow ) + _socRxS[i].m_rx_timer = (WNC14A2A_READ_TIMEOUTMS/EQ_FREQ)*(EQ_FREQ_SLOW/EQ_FREQ); + } + + if( _socTxS[i].m_tx_wnc_state == TX_ACTIVE ) { + goSlow = false; + debugOutput("CALL TX_event() for socket %d", i); + done &= tx_event(&_socTxS[i]); + } + } + + if( !done ) + wnc_queue.call_in((goSlow?EQ_FREQ_SLOW:EQ_FREQ),mbed::Callback<void()>((WNC14A2AInterface*)this,&WNC14A2AInterface::wnc_eq_event)); +}
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/WNC14A2AInterface/WNC14A2AInterface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/WNC14A2AInterface/WNC14A2AInterface.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,508 @@ +/** +* copyright (c) 2017-2018, James Flynn +* SPDX-License-Identifier: Apache-2.0 +*/ + +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* @file WNC14A2AInterface.h +* @brief Implements a standard NetworkInterface class for use with WNC M14A2A +* data module. +* +* @author James Flynn +* +* @date 1-Feb-2018 +* +*/ + +#ifndef WNC14A2A_INTERFACE_H +#define WNC14A2A_INTERFACE_H + +#include <stdint.h> + +#include "mbed.h" +#include "Callback.h" +#include "WNCDebug.h" +#include "WncControllerK64F/WncControllerK64F.h" + +#define WNC14A2A_SOCKET_COUNT WncController::MAX_NUM_WNC_SOCKETS + +// If target board does not support Arduino pins, define pins as Not Connected +#if defined(TARGET_FF_ARDUINO) +#if !defined(MBED_CONF_WNC14A2A_LIBRARY_WNC_RX_BOOT_SEL) +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_RX_BOOT_SEL D1 +#endif +#if !defined(MBED_CONF_WNC14A2A_LIBRARY_WNC_POWER_ON) +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_POWER_ON D2 +#endif +#if !defined(MBED_CONF_WNC14A2A_LIBRARY_WNC_WAKEUP) +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_WAKEUP D6 +#endif +#if !defined(MBED_CONF_WNC14A2A_LIBRARY_WNC_RESET) +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_RESET D8 +#endif +#if !defined(MBED_CONF_WNC14A2A_LIBRARY_WNC_LVLTRANSLATOR) +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_LVLTRANSLATOR D9 +#endif +#if !defined(MBED_CONF_WNC14A2A_LIBRARY_WNC_CTS) +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_CTS D10 +#endif +#if !defined(MBED_CONF_WNC14A2A_LIBRARY_WNC_RXD) +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_RXD D11 +#endif +#if !defined(MBED_CONF_WNC14A2A_LIBRARY_WNC_TXD) +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_TXD D12 +#endif +#else // !defined(TARGET_FF_ARDUINO) +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_RX_BOOT_SEL NC +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_POWER_ON NC +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_WAKEUP NC +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_RESET NC +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_LVLTRANSLATOR NC +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_CTS NC +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_RXD NC +#define MBED_CONF_WNC14A2A_LIBRARY_WNC_TXD NC +#endif // !defined(TARGET_FF_ARDUINO) + +typedef struct smsmsg_t { + string number; + string date; + string time; + string msg; + } IOTSMS; + +typedef struct socket_t { + int socket; //index of this socket + string url; + SocketAddress addr; //address info for this socket + bool opened; //is the socket opened + bool connected; //is the socket connected + int proto; //this is a TCP or UDP socket + void (*_callback)(void*); //callback used with attach + void *_cb_data; //callback data to be returned + } WNCSOCKET; + +typedef struct rx_event_t { + int m_rx_wnc_state; //state of the socket receive + int m_rx_socket; //which socket is being rcvd on + uint8_t *m_rx_dptr; //pointer to the users data buffer + uint32_t m_rx_req_size; //Requested number of bytes to receive + uint32_t m_rx_total_cnt; //Total number of bytes received + int m_rx_timer; //Rx Timeout Timer + int m_rx_disTO; //Flag to disable Timeout Timer + void (*m_rx_callback)(void*); //callback used with attach + void *m_rx_cb_data; //callback data to be returned + uint32_t m_rx_return_cnt; //number of bytes the Event Queue is returning + } RXEVENT; + +typedef struct tx_event_t { + // Transmit Interrupt simulation to enabled non-blocking operation + int m_tx_wnc_state; + int m_tx_socket; + uint8_t *m_tx_dptr; + unsigned m_tx_orig_size; + uint32_t m_tx_req_size; + uint32_t m_tx_total_sent; + void (*m_tx_callback)(void*); + void *m_tx_cb_data; + } TXEVENT; + +#define WNC_DEBUG 0 //1=enable the WNC startup debug output + //0=disable the WNC startup debug output +#define STOP_ON_FE 1 //1=hang forever if a fatal error occurs + //0=simply return failed response for all socket calls +#define DISPLAY_FE 1 //1 to display the fatal error when it occurs + //0 to NOT display the fatal error +#define RESETON_FE 0 //1 to cause the MCU to reset on fatal error + //0 to NOT reset the MCU + +#define APN_DEFAULT "m2m.com.attz" + +/** Error Handling macros & data +* @brief The macros CHK_WNCFE is used to check if a fatal error has occured. If it has +* then execute the action specified: fail, void, null, resume +* +* CHK_WNCFE( condition-to-check, fail|void|null|resume ) +* +* 'fail' if you want FATAL_WNC_ERROR to be called. +* 'void' if you want to execute a void return +* 'null' if you want to execute a null return +* 'resume' if you simply want to resume program execution +* +* There are several settings that control how FATAL_WNC_ERROR behaves: +* 1) RESETON_FE determines if the system will reset or hang. +* 2) DISPLAY_FE determine if an error message is generated or not +* +* The DISPLAY_FE setting determines if a failure message is displayed. +* If set to 1, user sees this messageo: +* +* WNC FAILED @ source-file-name:source-file-line-number +* +* if not set, nothing is displayed. +*/ + +#define FATAL_FLAG WncController::WNC_NO_RESPONSE +#define WNC_GOOD WncController::WNC_ON + +#define RETfail return -1 +#define RETvoid return +#define RETnull return NULL +#define RETresume + +#define DORET(x) RET##x + +#define TOSTR(x) #x +#define INTSTR(x) TOSTR(x) +#define FATAL_STR (char*)(__FILE__ ":" INTSTR(__LINE__)) + +#if RESETON_FE == 1 //reset on fatal error +#define MCURESET ((*((volatile unsigned long *)0xE000ED0CU))=(unsigned long)((0x5fa<<16) | 0x04L)) +#define RSTMSG "RESET MCU! " +#else +#define MCURESET +#define RSTMSG "" +#endif + +#if DISPLAY_FE == 1 //display fatal error message +#define PFE {if(_debugUart)_debugUart->printf((char*)RSTMSG "\r\n>>WNC FAILED @ %s\r\n", FATAL_STR);} +#else +#define PFE +#endif + +#if STOP_ON_FE == 1 //halt cpu on fatal error +#define FATAL_WNC_ERROR(v) {_fatal_err_loc=FATAL_STR;PFE;MCURESET;while(1);} +#else +#define FATAL_WNC_ERROR(v) {_fatal_err_loc=FATAL_STR;PFE;DORET(v);} +#endif + +#define CHK_WNCFE(x,y) if( x ){FATAL_WNC_ERROR(y);} + +#define FIRMWARE_REV(x) (((WNC14A2AInterface*)x)->getWNCRev()) +#define DBGMSG_DRV 0x04 +#define DBGMSG_EQ 0x08 +#define DBGMSG_SMS 0x10 +#define DBGMSG_ARRY 0x20 + +#define MAX_SMS_MSGS 3 + +using namespace WncController_fk; + +/** WNC14A2AInterface class + * Implementation of the NetworkInterface for WNC14A2A + */ +class WNC14A2AInterface : public NetworkStack, public NetworkInterface +{ +public: + + /** WNC14A2AInterface Constructor. + * @param optionally include a pointer to WNCDEBUG object for + * debug information to be displayed. + */ + WNC14A2AInterface(WNCDebug *_dbgUart = NULL); + virtual ~WNC14A2AInterface(); + + /** Set the cellular network credentials + * + * @param apn Optional, APN of network + * @param user Optional, username --not used-- + * @param pass Optional, password --not used-- + * @return nsapi_error_t + */ + virtual nsapi_error_t set_credentials(const char *apn = 0, + const char *username = 0, const char *password = 0); + + /** Connect to the network + * + * @param apn Optional, APN of network + * @param user Optional, username --not used-- + * @param pass Optional, password --not used-- + * @return nsapi_error_t + */ + virtual nsapi_error_t connect(const char *apn, + const char *username = 0, const char *password = 0); + + /** Connect to the network (no parameters) + * + * @return nsapi_error_t + */ + virtual nsapi_error_t connect(); + + /** disconnect from the network + * + * provided for completness, but function does nothing becase + * WNC part can not disconnect from network once connected. + * + * @return nsapi_error_t + */ + virtual nsapi_error_t disconnect(); + + /** Get the IP address of WNC device. From NetworkStack Class + * + * @return IP address string or null + */ + virtual const char *get_ip_address(); + + /** Get the network assigned IP address. + * + * @return IP address or null + */ + const char *get_my_ip_address(); + + /** Get the MAC address of the WNC device. + * + * @return MAC address of the interface + */ + virtual const char *get_mac_address(); + + /** Attach a callback function for when a SMS is recevied + * + * @param function pointer to call + */ + void sms_attach(void (*callback)(IOTSMS *)); + + /** Set the level of Debug output + * + * @param bit field + * basic AT command info= 0x01 + * more AT command info = 0x02 + * mbed driver info = 0x04 + * dump buffers = 0x08 + * all debug = 0x0f + */ + void doDebug(int v); + + /** Return the WNC reported Firmware Revision + * + * @param none. + */ + const char* getWNCRev(void); + + /** Query registered state of WNC + * + * @return true if registerd, false if not + */ + bool registered(); + + /** Start the SMS monitoring service + */ + void sms_start(void); + + /** start listening for incomming SMS messages + * + * @param time in msec to check + */ + void sms_listen(uint16_t=1000); // Configure device to listen for text messages + + /** retrieve a SMS message + * + * @param pointer to an array of IOTSMS messages + */ + int getSMS(IOTSMS **msg); + + /** send a SMS message + * + * @param a string containing number to send message to + * @param a string containing message to send + * @return true on success, 0 on failure + */ + int sendIOTSms(const string&, const string&); + + /** return this devices SMS number + * + * @brief The IOTSMS number used, isn't phone number, it is device ICCID. + * + * @return this devices IOTSMS number + */ + char* getSMSnbr(); + + +protected: + + /** Get Host IP by name. + * + * @return nsapi_error_t + */ + virtual nsapi_error_t gethostbyname(const char* name, SocketAddress *address, nsapi_version_t version); + + + /** return a pointer to the NetworkStack object + * + * @return The underlying NetworkStack object + */ + virtual NetworkStack *get_stack(); + + /** Open a socket. + * + * @param handle Handle in which to store new socket + * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative on failure + */ + virtual int socket_open(void **handle, nsapi_protocol_t proto); + + /** Close the socket. + * + * @param handle Socket handle + * @return 0 on success, negative on failure + */ + virtual int socket_close(void *handle); + + /** Bind a server socket to a specific port. + * + * @brief Bind the socket to a specific port + * @param handle Socket handle + * @param address address to listen for + * @return 0; + */ + virtual int socket_bind(void *handle, const SocketAddress &address); + + /** Start listening for incoming connections. + * + * @brief NOT SUPPORTED + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return NSAPI_ERROR_UNSUPPORTED; + * @note This function causes the receive time-out to be ignored resulting in continuous + * monitoring of received data. This is non-standard behaviour but it is how the + * mbed-cloud servcies use it... + */ + virtual int socket_listen(void *handle, int backlog); + + /** Accept a new connection. + * + * @brief NOT SUPPORTED + * @return NSAPI_ERROR_UNSUPPORTED; + */ + virtual int socket_accept(nsapi_socket_t server, + nsapi_socket_t *handle, SocketAddress *address=0); + + /** Connects this socket to the server. + * + * @param handle Socket handle + * @param address SocketAddress + * @return 0 on success, negative on failure + */ + virtual int socket_connect(void *handle, const SocketAddress &address); + + /** Send data to the remote host. + * + * @param handle Socket handle + * @param data buffer to send + * @param size length of buffer + * @return Number of bytes written or negative on failure + * + * @note This call is blocking. + */ + virtual int socket_send(void *handle, const void *data, unsigned size); + + /** Receive data from the remote host. + * + * @param handle Socket handle + * @param data buffer to store the recived data + * @param size bytes to receive + * @return received bytes received, negative on failure + * + * @note This call is not-blocking + */ + virtual int socket_recv(void *handle, void *data, unsigned size); + + /** Send a packet to a remote endpoint. + * + * @param handle Socket handle + * @param address SocketAddress + * @param data data to send + * @param size number of bytes to send + * @return the number of bytes sent or negative on failure + * + * @note This call is blocking. + */ + virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size); + + /** Receive packet remote endpoint + * + * @param handle Socket handle + * @param address SocketAddress + * @param buffer buffer to store data to + * @param size number of bytes to receive + * @return the number bytes received or negative on failure + * + * @note This call is not-blocking. + */ + virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size); + + /** Register a callback on state change of the socket + * + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + * + * @note Callback may be called in an interrupt context. + */ + virtual void socket_attach(void *handle, void (*callback)(void *), void *data); + + /** get the status of internal errors + * + * @brief Called after any WNC14A2A operation to determine error specifics + * @param none. + */ + uint16_t wnc14a2a_chk_error(void) { return m_errors; } + +private: + + //! WncController Class for interacting with the 14A2a hardware + friend class WncControllerK64F; + + bool m_wncpoweredup; //track if WNC has been power-up + unsigned m_debug; + + WncIpStats myNetStats; //maintaint the network statistics + WncControllerK64F_fk::WncControllerK64F *m_pwnc; //pointer to the WncController instance + + WNCDebug *_debugUart; // Serial object for parser to communicate with radio + char *_fatal_err_loc; // holds string containing location of fatal error + nsapi_error_t m_errors; + + bool m_smsmoning; // Track if the SMS monitoring thread is running + EventQueue sms_queue; // Queue used to schedule for SMS checks + void (*_sms_cb)(IOTSMS *); // Callback when text message is received. User must define this as + // a static function because I'm not handling an object offset + IOTSMS m_MsgText, m_MsgText_array[MAX_SMS_MSGS]; // Used to pass SMS message to the user + struct WncController::WncSmsList m_smsmsgs; //use the WncSmsList structure to hold messages + + EventQueue wnc_queue; // Queue used to schedule for receiving data + void handle_sms_event(); // SMS tx/rx handler + void wnc_eq_event(); // Simulated ISR + int rx_event(RXEVENT *); // receive data handler + int tx_event(TXEVENT *); // tx data handler + + char _mac_address[NSAPI_MAC_SIZE]; // local Mac + void _dbOut(const char *format, ...); + void _dbDump_arry( const uint8_t* data, unsigned int size ); + + WNCSOCKET _sockets[WNC14A2A_SOCKET_COUNT]; //WNC supports 8 open sockets but driver only supports 1 currently + TXEVENT _socTxS[WNC14A2A_SOCKET_COUNT]; + RXEVENT _socRxS[WNC14A2A_SOCKET_COUNT]; + Thread _smsThread, _eqThread; //Event Queue thread for SMS and Rx/Tx data + Mutex _pwnc_mutex; + int _active_socket; + + UARTSerial mdmUart; + WncIO wnc_io; +}; + +#endif +
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/WNC14A2AInterface/WNCDebug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/WNC14A2AInterface/WNCDebug.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,99 @@ +/** +* copyright (c) 2017-2018, James Flynn +* SPDX-License-Identifier: Apache-2.0 +*/ + +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* @file WNCDebug.h +* @brief A debug class that coordinates the output of debug messages to +* either stdio or a serial port based on instantiation. +* +* @author James Flynn +* +* @date 1-Feb-2018 +* +*/ + +#ifndef __WNCDEBUG__ +#define __WNCDEBUG__ +#include <stdio.h> +#include "WNCIO.h" + +/** WNCDebug class +* Used to write debug data to the user designated IO. Currently +* The class expects either a stdio element (defaults to stderr) or +* a pointer to a WncIO object. +*/ + +class WNCDebug +{ +public: + //! Create class with either stdio or a pointer to a uart + WNCDebug( FILE * fd = stderr ): m_puart(NULL) {m_stdiofp=fd;}; + WNCDebug( WncIO * uart): m_stdiofp(NULL) {m_puart=uart;}; + ~WNCDebug() {}; + + //! standard printf() functionallity + int printf( char * fmt, ...) { + char buffer[256]; + int ret=0; + va_list args; + va_start (args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + prt.lock(); + if( m_stdiofp ) + ret=fputs(buffer,m_stdiofp); + else + ret=m_puart->puts(buffer); + prt.unlock(); + va_end (args); + return ret; + } + + //! standard putc() functionallity + int putc( int c ) { + int ret=0; + prt.lock(); + if( m_stdiofp ) + ret=fputc(c, m_stdiofp); + else + ret=m_puart->putc(c); + prt.unlock(); + return ret; + } + + //! standard puts() functionallity + int puts( const char * str ) { + int ret=0; + prt.lock(); + if( m_stdiofp ) + ret=fputs(str,m_stdiofp); + else + ret=m_puart->puts(str); + prt.unlock(); + return ret; + } + +private: + std::FILE *m_stdiofp; + WncIO *m_puart; + Mutex prt; +}; + +#endif +
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/WNC14A2AInterface/WNCIO.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/WNC14A2AInterface/WNCIO.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,102 @@ +/** +* copyright (c) 2017-2018, James Flynn +* SPDX-License-Identifier: Apache-2.0 +*/ + +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* @file WNCIO.h +* @brief A class that WNCInterface uses for input/output +* +* @author James Flynn +* +* @date 1-Feb-2018 +* +*/ + +#ifndef __WNCIO__ +#define __WNCIO__ +#include <stdio.h> +#include "mbed.h" + +/** WncIO class +* Used to read/write the WNC UART using FILE I/O. +*/ + +class WncIO +{ +public: + //! Create class with either stdio or a pointer to a uart + WncIO( UARTSerial * uart): m_puart(uart) {;} + ~WncIO() {}; + + //! standard printf() functionallity + int printf( char * fmt, ...) { + char buffer[256]; + int ret=0; + va_list args; + va_start (args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + prt.lock(); + ret=m_puart->write(buffer,strlen(buffer)); + prt.unlock(); + va_end (args); + return ret; + } + + //! standard putc() functionallity + int putc( int c ) { + int ret=0; + prt.lock(); + ret=m_puart->write((const void*)&c,1); + prt.unlock(); + return ret; + } + + //! standard puts() functionallity + int puts( const char * str ) { + int ret=0; + prt.lock(); + ret=m_puart->write(str,strlen(str)); + prt.unlock(); + return ret; + } + + //! return true when data is available, false otherwise + bool readable( void ) { + return m_puart->readable(); + } + + //! get the next character available from the uart + int getc( void ) { + char c; + m_puart->read( &c, 1 ); + return c; + } + + //! set the uart baud rate + void baud( int baud ) { + m_puart->set_baud(baud); + } + +private: + UARTSerial *m_puart; + Mutex prt; +}; + +#endif +
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/WNC14A2AInterface/WncControllerK64F/WncController/WncController.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/WNC14A2AInterface/WncControllerK64F/WncController/WncController.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2154 @@ +/* + Copyright (c) 2016 Fred Kellerman + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file WncController.cpp + @purpose Controls WNC 14A2A Cellular Modem + @version 1.0 + @date July 2016 + @author Fred Kellerman + + + An Example of usage: + + WncControllerK64F mdm(&wncPinList, &mdmUart, &debugUart); + + mdm.enableDebug(true, true); + + if (false == mdm.powerWncOn("m2m.com.attz", 60)) { + while(1); + } + + // ICCID and MSISDN + string iccid; string msisdn; + if (mdm.getICCID(&iccid) == true) { + if (mdm.convertICCIDtoMSISDN(iccid, &msisdn) == true) { + // Send an SMS message (must use 15-digit MISDN number!) + mdm.sendSMSText(msisdn.c_str(), "Hello from WNC Kit -> from WNC"); + } + } + + // Get an IP address setup for the socket #1 (0 indexed)) + if (true == mdm.resolveUrl(0, "www.att.com")) + { + // Report server IP + if (true == mdm.getIpAddr(0, ipAddrStr)) { + debugUart.puts("Server IP: "); + debugUart.puts(ipAddrStr); + debugUart.puts("\r\n"); + } + + // Open Socket #1, TCP=true resolved IP on port 80: + if (true == mdm.openSocket(0, 80, true)) { + // Write some data + const uint8_t * dataStr = "GET /index.html HTTP/1.0\r\nFrom: someuser@someuser.com\r\nUser-Agent: HTTPTool/1.0\r\n\r\n"; + if (true == mdm.write(0, dataStr, strlen((const char *)dataStr))) + { + const uint8_t * myBuf; + mdm.setReadRetries(0, 20); + uint32_t n = mdm.read(0, &myBuf); + if (n > 0) + debugUart.printf("Read %d chars: %s\r\n", n, myBuf); + else + debugUart.puts("No read data!\r\n"); + } + } + } + +*/ + + +#include <cstdlib> +#include <cctype> +#include <string.h> +#include "WncController.h" + +namespace WncController_fk { + +///////////////////////////////////////////////////// +// Static initializers +///////////////////////////////////////////////////// +WncController::WncSocketInfo_s WncController::m_sSock[MAX_NUM_WNC_SOCKETS]; +const WncController::WncSocketInfo_s WncController::defaultSockStruct = { 0, false, "192.168.0.1", 80, 0, 25, true, 30 }; + +WncController::WncState_e WncController::m_sState = WNC_OFF; +uint16_t WncController::m_sCmdTimeoutMs = WNC_CMD_TIMEOUT_MS; +string WncController::m_sApnStr = "NULL"; +string WncController::m_sWncStr; +string WncController::m_FirmwareRevision; +uint8_t WncController::m_sPowerUpTimeoutSecs = MAX_POWERUP_TIMEOUT; +bool WncController::m_sDebugEnabled = false; +bool WncController::m_sMoreDebugEnabled = false; +bool WncController::m_sCheckNetStatus = false; // Turn on internet status check between every command +const char * const WncController::INVALID_IP_STR = ""; +bool WncController::m_sReadyForSMS = false; + + +/** + * C++ version 0.4 char* style "itoa": + * Written by Lukás Chmela + * Released under GPLv3. + */ +static char* itoa(int64_t value, char* result, int base) +{ + // check that the base is valid + if ( base < 2 || base > 36 ) { + *result = '\0'; + return result; + } + + char* ptr = result, *ptr1 = result, tmp_char; + int64_t tmp_value; + + do { + tmp_value = value; + value /= base; + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - value * base)]; + } while ( value ); + + // Apply negative sign + if ( tmp_value < 0 ) + *ptr++ = '-'; + + *ptr-- = '\0'; + + while ( ptr1 < ptr ) { + tmp_char = *ptr; + *ptr-- = *ptr1; + *ptr1++ = tmp_char; + } + + return result; +} + +const char * WncController::_to_string(int64_t value) +{ + static char str[21]; // room for signed 64-bit + null + itoa(value, str, 10); + return (str); +} + +const char * WncController::_to_hex_string(uint8_t value) +{ + static char str[3]; // room for 8-bit + null + itoa(value, str, 16); + return (str); +} + +WncController::WncController(void) +{ + for(unsigned i=0; i<MAX_NUM_WNC_SOCKETS; i++) + m_sSock[i] = defaultSockStruct; +} + +WncController::~WncController(void) {}; + +const char* WncController::getFirmRev(void) +{ + return m_FirmwareRevision.c_str(); +} + +void WncController::enableDebug(bool on, bool moreDebugOn) +{ + m_sDebugEnabled = on; + m_sMoreDebugEnabled = moreDebugOn; +} + +WncController::WncState_e WncController::getWncStatus(void) +{ + return (m_sState); +} + +int16_t WncController::getDbmRssi(void) +{ + int16_t rssi, ber; + if (at_getrssiber_wnc(&rssi, &ber) == true) + return (rssi); + else + return (99); +} + +int16_t WncController::get3gBer(void) +{ + int16_t rssi, ber; + if (at_getrssiber_wnc(&rssi, &ber) == true) + return (ber); + else + return (99); +} + +bool WncController::powerWncOn(const char * const apn, uint8_t powerUpTimeoutSecs) +{ + dbgPuts("Waiting for WNC to Initialize..."); + m_sPowerUpTimeoutSecs = powerUpTimeoutSecs; + m_sState = WNC_ON_NO_CELL_LINK; // Turn soft on to allow "AT" for init to be sent! + if (initWncModem(powerUpTimeoutSecs) == true) { + // Set the Apn + setApnName(apn); + if (false == softwareInitMdm()) { + dbgPuts("Software init failed!"); + m_sState = WNC_OFF; + } + } + else { + dbgPuts("Power up failed!"); + m_sState = WNC_OFF; + } + + return ((m_sState == WNC_ON) || (m_sState == WNC_ON_NO_CELL_LINK)); +} + +size_t WncController::sendCustomCmd(const char * cmd, char * resp, size_t sizeRespBuf, int ms_timeout) +{ + string * respStr; + + if (sizeRespBuf > 0) { + at_send_wnc_cmd(cmd, &respStr, ms_timeout); + strncpy(resp, respStr->c_str(), sizeRespBuf); + if (respStr->size() > sizeRespBuf) + dbgPuts("sendCustomCmd truncated!"); + + return (respStr->size()); + } + + dbgPuts("sendCustomCmd: would have overrun!"); + + return (0); +} + +bool WncController::pingUrl(const char * url) +{ + string ipAddr; + + if (true == at_dnsresolve_wnc(url, &ipAddr)) + return (pingIp(ipAddr.c_str())); + else + dbgPuts("pingUrl DNS resolve: failed!"); + + return (false); +} + +bool WncController::pingIp(const char * ip) +{ + if (true == at_ping_wnc(ip)) + return (true); + else + dbgPuts("pingIp: failed!"); + + return (false); +} + +bool WncController::getWncNetworkingStats(WncIpStats * s) +{ + return (at_get_wnc_net_stats(s)); +} + +bool WncController::getIpAddr(uint16_t numSock, char myIpAddr[MAX_LEN_IP_STR]) +{ + if (numSock < MAX_NUM_WNC_SOCKETS) { + strncpy(myIpAddr, m_sSock[numSock].myIpAddressStr.c_str(), MAX_LEN_IP_STR); + myIpAddr[MAX_LEN_IP_STR - 1] = '\0'; + return (true); + } + else { + myIpAddr[0] = '\0'; + return (false); + } +} + +bool WncController::setApnName(const char * const apnStr) +{ + if (at_setapn_wnc(apnStr) == true) + { + m_sApnStr = apnStr; + return (true); + } + else + return (false); +} + +bool WncController::resolveUrl(uint16_t numSock, const char * url) +{ + bool cmdRes; + + if (numSock < MAX_NUM_WNC_SOCKETS) { + if (strlen(url) > 0) { + cmdRes = at_dnsresolve_wnc(url, &m_sSock[numSock].myIpAddressStr); + if (cmdRes == false) + dbgPuts("Cannot resolve URL!"); + return (cmdRes); + } + else + dbgPuts("Invalid URL"); + } + else + dbgPuts("Invalid Sock num!"); + + return (false); +} + +bool WncController::setIpAddr(uint16_t numSock, const char * ipStr) +{ + if (numSock < MAX_NUM_WNC_SOCKETS) { + m_sSock[numSock].myIpAddressStr = ipStr; + return (true); + } + else { + dbgPuts("Bad socket num!"); + return (false); + } +} + +void WncController::setWncCmdTimeout(uint16_t toMs) +{ + m_sCmdTimeoutMs = toMs; +} + +bool WncController::openSocketUrl(uint16_t numSock, const char * url, uint16_t port, bool tcp, uint16_t timeOutSec) +{ + if (resolveUrl(numSock, url) == true) + return (openSocket(numSock, port, tcp, timeOutSec)); + + return (false); +} + +bool WncController::openSocketIpAddr(uint16_t numSock, const char * ipAddr, uint16_t port, bool tcp, uint16_t timeOutSec) +{ + if (setIpAddr(numSock, ipAddr) == true) + return (openSocket(numSock, port, tcp, timeOutSec)); + + return (false); +} + +bool WncController::openSocket(uint16_t numSock, uint16_t port, bool tcp, uint16_t timeOutSec) +{ + if (numSock < MAX_NUM_WNC_SOCKETS) { + // IPV4 ip addr sanity check! + size_t lenIpStr = m_sSock[numSock].myIpAddressStr.size(); + if (lenIpStr < 7 || lenIpStr > 15) { + dbgPuts("Invalid IP Address!"); + return (false); + } + + // Already open ? Must close if want to re-open with new settings. + if (m_sSock[numSock].open == true) { + dbgPuts("Socket already open, close then re-open!"); + if (true == at_sockclose_wnc(m_sSock[numSock].numWncSock)) + m_sSock[numSock].open = false; + else + return (false); + } + + m_sSock[numSock].myPort = port; + m_sSock[numSock].isTcp = tcp; + m_sSock[numSock].timeOutSec = timeOutSec; + + int16_t numWncSock = at_sockopen_wnc(m_sSock[numSock].myIpAddressStr.c_str(), port, numSock, tcp, timeOutSec); + m_sSock[numSock].numWncSock = numWncSock; + if (numWncSock > 0 && numWncSock <= (uint16_t)MAX_NUM_WNC_SOCKETS) + m_sSock[numSock].open = true; + else { + m_sSock[numSock].open = false; + dbgPuts("Socket open fail!!!!"); + + // If the modem is not responding don't bother it. + if (WNC_NO_RESPONSE != getWncStatus()) { + // Work-around. If the sock open fails it needs to be told + // to close. If 6 sock opens happen with a fail, it further + // crashes the WNC. Not sure why the sock won't open. + at_sockclose_wnc(m_sSock[numSock].numWncSock); + } + } + } + else { + dbgPuts("Bad socket num or IP!"); + return (false); + } + + return (m_sSock[numSock].open); +} + +bool WncController::sockWrite(const uint8_t * const s, uint16_t n, uint16_t numSock, bool isTcp) +{ + bool result = true; + + AtCmdErr_e cmdRes = at_sockwrite_wnc(s, n, m_sSock[numSock].numWncSock, isTcp); + if (cmdRes != WNC_AT_CMD_OK) { + if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME)) + { + // This may throw away any data that hasn't been written out of the WNC + // but at this point with the way the WNC currently works we have + // no choice. + closeOpenSocket(numSock); + } + result = false; + } + + return (result); +} + +bool WncController::write(uint16_t numSock, const uint8_t * s, uint32_t n) +{ + bool result; + + if (numSock < MAX_NUM_WNC_SOCKETS) { + if (m_sSock[numSock].open == true) { + if (n <= MAX_WNC_WRITE_BYTES) { + result = sockWrite(s, n, numSock, m_sSock[numSock].isTcp); + } + else { + uint16_t rem = n % MAX_WNC_WRITE_BYTES; + while (n >= MAX_WNC_WRITE_BYTES) { + n -= MAX_WNC_WRITE_BYTES; + result = sockWrite(s, MAX_WNC_WRITE_BYTES, numSock, m_sSock[numSock].isTcp); + if (result == false) { + n = 0; + rem = 0; + dbgPuts("Sock write fail!"); + } + else + s += MAX_WNC_WRITE_BYTES; + } + if (rem > 0) + result = sockWrite(s, rem, numSock, m_sSock[numSock].isTcp); + } + } + else { + dbgPuts("Socket is closed for write!"); + result = false; + } + } + else { + dbgPuts("Bad socket num!"); + result = false; + } + + return (result); +} + +size_t WncController::read(uint16_t numSock, const uint8_t ** readBuf) +{ + static string theBuf; + string readStr; + + theBuf.erase(); // Clean-up from last time + + if (numSock < MAX_NUM_WNC_SOCKETS) { + if (m_sSock[numSock].open == true) { + uint8_t i = m_sSock[numSock].readRetries; + uint16_t to = m_sSock[numSock].readRetryWaitMs; + bool foundData = false; + do { + AtCmdErr_e cmdRes; + cmdRes = at_sockread_wnc(&readStr, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp); + if (WNC_AT_CMD_OK == cmdRes) { + // This will let this loop read until the socket data is + // empty. If no data, then wait the retry amount of time. + if (readStr.size() > 0) { + theBuf += readStr; + foundData = true; + i = 1; + } + else { + // Once data is found start returning it asap + if (foundData == false) + waitMs(to); + } + } + else { + theBuf += readStr; // Append what if any we got before it errored. + dbgPuts("Sockread failed!"); + if (WNC_NO_RESPONSE == getWncStatus()) { + i = 0; + } + else if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME)) + { + // This may throw away any data that hasn't been read out of the WNC + // but at this point with the way the WNC currently works we have + // no choice. + closeOpenSocket(numSock); + i = 0; + } + else + waitMs(to); + } + } while (i-- > 0); + } + else { + dbgPuts("Socket is closed for read"); + } + } + else { + dbgPuts("Bad socket num!"); + } + + *readBuf = (const uint8_t *)theBuf.c_str(); + + return (theBuf.size()); +} + +size_t WncController::read(uint16_t numSock, uint8_t * readBuf, uint32_t maxReadBufLen) +{ + uint32_t numCopied = 0; + + if (numSock < MAX_NUM_WNC_SOCKETS) { + if (m_sSock[numSock].open == true) { + uint8_t i = m_sSock[numSock].readRetries; + uint16_t to = m_sSock[numSock].readRetryWaitMs; + bool foundData = false; + uint16_t numRead; + do { + AtCmdErr_e cmdRes; + if (maxReadBufLen < MAX_WNC_READ_BYTES) + cmdRes = at_sockread_wnc(readBuf, &numRead, maxReadBufLen, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp); + else + cmdRes = at_sockread_wnc(readBuf, &numRead, MAX_WNC_READ_BYTES, m_sSock[numSock].numWncSock, m_sSock[numSock].isTcp); + + if (WNC_AT_CMD_OK == cmdRes) { + // This will let this loop read until the socket data is + // empty. If no data, then wait the retry amount of time. + if (numRead > 0) { + foundData = true; + i = 1; + if (numRead <= maxReadBufLen) { + maxReadBufLen -= numRead; + numCopied += numRead; + readBuf += numRead; + } + else { + i = 0; // No more room for data! + dbgPutsNoTime("No more room for read data!"); + } + } + else { + // Once data is found start returning it asap + if (foundData == false) + waitMs(to); + } + } + else { + dbgPuts("Sockread failed!"); + if (WNC_NO_RESPONSE == getWncStatus()) { + i = 0; + } + else if ((cmdRes == WNC_AT_CMD_ERREXT) || (cmdRes == WNC_AT_CMD_ERRCME)) + { + // This may throw away any data that hasn't been read out of the WNC + // but at this point with the way the WNC currently works we have + // no choice. + closeOpenSocket(numSock); + i = 0; + } + else + waitMs(to); + } + } while ((i-- > 0) && (maxReadBufLen > 0)); + } + else { + dbgPuts("Socket is closed for read"); + } + } + else { + dbgPuts("Bad socket num!"); + } + + return (numCopied); +} + +void WncController::setReadRetries(uint16_t numSock, uint16_t retries) +{ + if (numSock < MAX_NUM_WNC_SOCKETS) + m_sSock[numSock].readRetries = retries; + else + dbgPuts("Bad socket num!"); +} + +void WncController::setReadRetryWait(uint16_t numSock, uint16_t readRetryWaitMs) +{ + if (numSock < MAX_NUM_WNC_SOCKETS) + m_sSock[numSock].readRetryWaitMs = readRetryWaitMs; + else + dbgPuts("Bad socket num!"); +} + +bool WncController::closeSocket(uint16_t numSock) +{ + if (numSock < MAX_NUM_WNC_SOCKETS) { + + if (false == at_sockclose_wnc(m_sSock[numSock].numWncSock)) + dbgPuts("Sock close may not have closed!"); + + // Even with an error the socket could have closed, + // can't tell for sure so just soft close it for now. + m_sSock[numSock].open = false; + } + else { + dbgPuts("Bad socket num!"); + } + + return (m_sSock[numSock].open == false); +} + +size_t WncController::mdmGetline(string * buff, int timeout_ms) +{ + char chin = '\0'; + char chin_last; + size_t len = 0; + + startTimerB(); + while ((len <= MAX_LEN_WNC_CMD_RESPONSE) && (getTimerTicksB_mS() < timeout_ms)) { + if (charReady()) { + chin_last = chin; + chin = getc(); + if (isprint(chin)) { + *buff += chin; + len++; // Bound the copy length to something reaonable just in case + continue; + } + else if ((('\r' == chin_last) && ('\n' == chin)) || (('\n' == chin_last) && ('\r' == chin))) { + break; + } + } + } + stopTimerB(); + + if (len > MAX_LEN_WNC_CMD_RESPONSE) + dbgPuts("Max cmd length reply exceeded!"); + + return (len); +} + +bool WncController::softwareInitMdm(void) +{ + static bool reportStatus = true; + unsigned i; + + if (checkCellLink() == true) { + if (reportStatus == false) { + dbgPuts("Re-connected to cellular network!"); + reportStatus = true; + } + + // WNC has SIM and registered on network so + // soft initialize the WNC. + for (i = 0; i < WNC_SOFT_INIT_RETRY_COUNT; i++) + if (at_init_wnc() == true) + break; + + // If it did not respond try a hardware init + if (i == WNC_SOFT_INIT_RETRY_COUNT) + { + at_reinitialize_mdm(); + return (at_init_wnc(true)); // Hard reset occurred so make it go through the software init(); + } + else + return (true); + } + else + { + if (reportStatus == true) { + dbgPuts("Not connected to cellular network!"); + reportStatus = false; + } + return (false); + } +} + +WncController::AtCmdErr_e WncController::sendWncCmd(const char * const s, string ** r, int ms_timeout) +{ + if (checkCellLink() == false) { + static string noRespStr; + + // Save some run-time! + if (m_sDebugEnabled) + { + dbgPuts("FAIL send cmd: ", false); + if (m_sMoreDebugEnabled && m_sDebugEnabled) { + dbgPutsNoTime(s); + } + else { + size_t n = strlen(s); + if (n <= WNC_TRUNC_DEBUG_LENGTH) { + dbgPutsNoTime(s); + } + else { + string truncStr(s,WNC_TRUNC_DEBUG_LENGTH/2); + truncStr += ".."; + truncStr += &s[n-(WNC_TRUNC_DEBUG_LENGTH/2)]; + dbgPutsNoTime(truncStr.c_str()); + } + } + } + + noRespStr.erase(); + *r = &noRespStr; + + return (WNC_AT_CMD_NO_CELL_LINK); + } + + if (m_sCheckNetStatus) + { + if (m_sMoreDebugEnabled) + dbgPuts("[---------- Network Status -------------"); + string * pRespStr; + at_send_wnc_cmd("AT@SOCKDIAL?", &pRespStr, m_sCmdTimeoutMs); + if (m_sMoreDebugEnabled) + dbgPuts("---------------------------------------]"); + } + + // If WNC ready, send user command + return (at_send_wnc_cmd(s, r, ms_timeout)); +} + +WncController::AtCmdErr_e WncController::at_send_wnc_cmd(const char * s, string ** r, int ms_timeout) +{ + // Save some run-time! + if (m_sDebugEnabled) + { + if (m_sMoreDebugEnabled) { + dbgPuts("TX: ", false); dbgPutsNoTime(s); + } + else { + if (m_sDebugEnabled) { // Save some run-time! + size_t n = strlen(s); + if (n <= WNC_TRUNC_DEBUG_LENGTH) { + dbgPuts("TX: ", false); dbgPutsNoTime(s); + } + else { + string truncStr(s,WNC_TRUNC_DEBUG_LENGTH/2); + truncStr += ".."; + truncStr += &s[n - (WNC_TRUNC_DEBUG_LENGTH/2)]; + dbgPuts("TX: ", false); dbgPutsNoTime(truncStr.c_str()); + } + } + } + } + + AtCmdErr_e atResult = mdmSendAtCmdRsp(s, ms_timeout, &m_sWncStr); + *r = &m_sWncStr; // Return a pointer to the static string + + if (atResult != WNC_AT_CMD_TIMEOUT) { + // If a prior command timed out but a new one works then + // change the state back to ON. We don't know here in this + // method if the Cell Link is good so assume it is. When a command + // that depends on the cell link is made it will update the state. + if (m_sState == WNC_NO_RESPONSE) + m_sState = WNC_ON; + + // Save some run-time! + if (m_sDebugEnabled) + { + dbgPuts("RX: ", false); + if (m_sMoreDebugEnabled) { + dbgPutsNoTime(m_sWncStr.c_str()); + } + else { + if (m_sWncStr.size() <= WNC_TRUNC_DEBUG_LENGTH) { + dbgPutsNoTime(m_sWncStr.c_str()); + } + else { + string truncStr = m_sWncStr.substr(0,WNC_TRUNC_DEBUG_LENGTH/2) + ".."; + truncStr += m_sWncStr.substr(m_sWncStr.size() - (WNC_TRUNC_DEBUG_LENGTH/2), WNC_TRUNC_DEBUG_LENGTH/2); + dbgPutsNoTime(truncStr.c_str()); + } + } + } + } + else { + m_sState = WNC_NO_RESPONSE; + dbgPuts("AT Cmd TIMEOUT!"); + dbgPuts("RX: ", false); dbgPutsNoTime(m_sWncStr.c_str()); + } + + return (atResult); +} + +void WncController::closeOpenSocket(uint16_t numSock) +{ + // Try to open and close the socket + do { + dbgPuts("Try to close and re-open socket"); + if (false == at_sockclose_wnc(m_sSock[numSock].numWncSock)) { + if (WNC_NO_RESPONSE == getWncStatus()) { + dbgPuts("No response for closeOpenSocket1"); + return ; + } + } + + int numWncSock = at_sockopen_wnc(m_sSock[numSock].myIpAddressStr.c_str(), m_sSock[numSock].myPort, numSock, m_sSock[numSock].isTcp, m_sSock[numSock].timeOutSec); + m_sSock[numSock].numWncSock = numWncSock; + if (numWncSock > 0 && numWncSock <= (int)MAX_NUM_WNC_SOCKETS) + m_sSock[numSock].open = true; + else { + m_sSock[numSock].open = false; + dbgPuts("Failed to re-open socket!"); + } + + if (WNC_NO_RESPONSE == getWncStatus()) { + dbgPuts("No response for closeOpenSocket2"); + return ; + } + } while (m_sSock[numSock].open == false); +} + +bool WncController::getICCID(string * iccid) +{ + if (at_geticcid_wnc(iccid) == false) { + dbgPuts("getICCID error!"); + return (false); + } + + return (true); +} + +bool WncController::at_geticcid_wnc(string * iccid) +{ + string * respStr; + + iccid->erase(); + + AtCmdErr_e r = at_send_wnc_cmd("AT%CCID", &respStr, m_sCmdTimeoutMs); + + if (r != WNC_AT_CMD_OK || respStr->size() == 0) + return (false); + + // New Firmware versions respond to the %CCID command with "%CCID:" + // but old version respond with "AT%CCID", so check to see which we have + size_t pos = respStr->find(":"); + if (pos == string::npos) + pos = respStr->find("AT%CCID"); + else + pos = respStr->find("%CCID"); + + if (pos == string::npos) + return (false); + + pos += 7; // Advanced to the number + + size_t posOK = respStr->rfind("OK"); + if (posOK == string::npos) + return (false); + + *iccid = respStr->substr(pos, posOK - pos); + + return (true); +} + +bool WncController::convertICCIDtoMSISDN(const string & iccid, string * msisdn) +{ + msisdn->erase(); + + if (iccid.size() != 20 && iccid.size() != 19) { + dbgPuts("Invalid ICCID length!"); + return (false); + } + + *msisdn = "882350"; + + if (iccid.size() == 20) + *msisdn += iccid.substr(10,iccid.size() - 11); + else + *msisdn += iccid.substr(10,iccid.size() - 10); + + return (true); +} + +bool WncController::sendSMSText(const char * const phoneNum, const char * const text) +{ + if (at_sendSMStext_wnc(phoneNum, text) == true) + return (true); + else { + dbgPuts("sendSMSText: Failed!"); + return (false); + } +} + +bool WncController::readSMSLog(struct WncSmsList * log) +{ + string * logStr; + uint16_t i; + + if (at_readSMSlog_wnc(&logStr) == false) { + dbgPuts("readSMSLog: Failed!"); + return (false); + } + + // Clean slate + log->msgCount = 0; + + if (logStr->size() == 0) + return (false); + + // Pick out the stuff from the string and convert to struct + string s; + size_t pos2; + size_t pos = logStr->find("+CMGL:"); + + for(i=0; i<MAX_WNC_SMS_MSG_SLOTS; i++) { + // Start with a clean slate, let parsing fill out later. + log->e[i].unread = false; + log->e[i].incoming = false; + log->e[i].unsent = false; + log->e[i].pduMode = false; + log->e[i].msgReceipt = false; + + log->e[i].idx = logStr->at(pos + 7); + if (pos == string::npos) + return (false); + pos2 = logStr->find(",\"", pos); + if (pos2 == string::npos) { + // If the WNC acts wrong and receives a PDU mode + // SMS there will not be any quotes in the response, + // just take the whole reply and make it the message body for + // now, mark it as an unread message, set the pdu flag! + log->e[log->msgCount].unread = true; + log->e[log->msgCount].pduMode = true; + log->msgCount++; + + pos2 = logStr->find("+CMGL", pos + 5); + if (pos2 == string::npos) { + pos2 = logStr->find("OK", pos + 5); + if (pos2 == string::npos) { + dbgPuts("Strange SMS Log Ending!"); + return (false); + } + i = MAX_WNC_SMS_MSG_SLOTS; + } + log->e[log->msgCount].msg = logStr->substr(0, pos2 - pos); + pos = pos2; // for loop starts off expecting pos to point to next log msg + continue; + } + pos += 2; // Advance to the text we want + pos2 = logStr->find("\",", pos); + if ((pos2 == string::npos) || (pos >= pos2)) + return (false); + + // Setup attributes + s = logStr->substr(pos, pos2 - pos); + if (s.find("REC READ") != string::npos) + log->e[i].incoming = true; + if (s.find("REC UNREAD") != string::npos) { + log->e[i].unread = true; + log->e[i].incoming = true; + } + if (s.find("STO UNSENT") != string::npos) + log->e[i].unsent = true; + if (logStr->find(",,") == string::npos) + log->e[i].msgReceipt = true; + + // Tele number + pos2 = logStr->find(",\"", pos2); + if (pos2 == string::npos) + return (false); + pos2 += 2; // Advance to next field + pos = logStr->find("\",", pos2); + if ((pos == string::npos) || (pos2 > pos)) + return (false); + if (pos == pos2) + log->e[i].number.erase(); + else + log->e[i].number = logStr->substr(pos2, pos - pos2); + + // Date + pos = logStr->find(",\"", pos); + if (pos == string::npos) + return (false); + pos += 2; // Beginning of date field + pos2 = logStr->find(",", pos); // End of timestamp field + if ((pos2 == string::npos) || (pos > pos2)) + return (false); + if (pos == pos2) + log->e[i].date.erase(); + else + log->e[i].date = logStr->substr(pos, pos2 - pos); + + // Timestamp + pos = logStr->find("\",", pos2); // End of timestamp + if (pos == string::npos) + return (false); + pos2 += 1; // Beginning of time field + if (pos < pos2) + return (false); + if (pos == pos2) + log->e[i].time.erase(); + else + log->e[i].time = logStr->substr(pos2, pos - pos2); + + // Message field + + // We don't know how many messages we have so the next search + // could end with +CMGL or OK. + pos += 2; // Advanced to message text + pos2 = logStr->find("+CMGL", pos); + if (pos2 == string::npos) { + pos2 = logStr->find("OK", pos); + if (pos2 == string::npos) { + dbgPuts("Strange SMS Log Ending!"); + return (false); + } + i = MAX_WNC_SMS_MSG_SLOTS; // break + } + if (pos > pos2) + return (false); + if (pos == pos2) + log->e[log->msgCount].msg.erase(); + else + log->e[log->msgCount].msg = logStr->substr(pos, pos2 - pos); + + log->msgCount++; // Message complete + } + + return (true); +} + +bool WncController::readUnreadSMSText(struct WncSmsList * w, bool deleteRead) +{ + struct WncController::WncSmsList tmp; + + if (readSMSLog(&tmp) == false) + return (false); + + w->msgCount = 0; + for(uint16_t i = 0; i < tmp.msgCount; i++) { + if (tmp.e[i].unread == true) { + w->e[w->msgCount] = tmp.e[i]; + w->msgCount++; + if (deleteRead == true) { + // Clean up message that was copied out and read + deleteSMSTextFromMem(w->e[i].idx); + } + } + } + + return (w->msgCount > 0); +} + +size_t WncController::getSignalQuality(const char ** log) +{ + size_t n; + + n = at_getSignalQuality_wnc(log); + if (n == 0) + dbgPuts("readSMSText: Failed!"); + + return (n); +} + +size_t WncController::at_getSignalQuality_wnc(const char ** log) +{ + string * pRespStr; + static string logStr; + + logStr.erase(); + + if (at_send_wnc_cmd("AT%MEAS=\"0\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { + logStr = *pRespStr; + logStr += "\r\n"; + } + else + dbgPuts("AT%MEAS=0: failed!"); + + if (at_send_wnc_cmd("AT%MEAS=\"1\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { + logStr += *pRespStr; + logStr += "\r\n"; + } + else + dbgPuts("AT%MEAS=1: failed!"); + + if (at_send_wnc_cmd("AT%MEAS=\"2\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { + logStr += *pRespStr; + logStr += "\r\n"; + } + else + dbgPuts("AT%MEAS=2: failed!"); + + if (at_send_wnc_cmd("AT%MEAS=\"3\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { + logStr += *pRespStr; + logStr += "\r\n"; + } + else + dbgPuts("AT%MEAS=3: failed!"); + + if (at_send_wnc_cmd("AT%MEAS=\"4\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { + logStr += *pRespStr; + logStr += "\r\n"; + } + else + dbgPuts("AT%MEAS=4: failed!"); + + if (at_send_wnc_cmd("AT%MEAS=\"5\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { + logStr += *pRespStr; + logStr += "\r\n"; + } + else + dbgPuts("AT%MEAS=5: failed!"); + + if (at_send_wnc_cmd("AT%MEAS=\"8\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { + logStr += *pRespStr; + logStr += "\r\n"; + } + else + dbgPuts("AT%MEAS=8: failed!"); + + if (at_send_wnc_cmd("AT%MEAS=\"98\"", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { + logStr += *pRespStr; + logStr += "\r\n"; + } + else + dbgPuts("AT%MEAS=98: failed!"); + + *log = logStr.c_str(); + + return (logStr.size()); +} + +bool WncController::getTimeDate(struct WncDateTime * tod) +{ + if (at_gettimedate_wnc(tod) == true) + return (true); + else { + dbgPuts("Get time date failed!"); + return (false); + } +} + +bool WncController::at_ping_wnc(const char * ip) +{ + string * pRespStr; + string cmdStr = "AT@PINGREQ=\""; + cmdStr += ip; + cmdStr += "\""; + return (at_send_wnc_cmd(cmdStr.c_str(), &pRespStr, WNC_PING_CMD_TIMEOUT_MS) == WNC_AT_CMD_OK); +} + +bool WncController::at_gettimedate_wnc(struct WncDateTime * tod) +{ + string * pRespStr; + char * pEnd; + + if (at_send_wnc_cmd("AT+CCLK?", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) { + if (pRespStr->size() > 0) { + size_t pos1 = pRespStr->find("+CCLK:"); + if (pos1 != string::npos) { + pEnd = (char *)pRespStr->c_str() + pos1 + 8; + tod->year = strtol(pEnd, &pEnd, 10); + tod->month = strtol(pEnd+1, &pEnd, 10); + tod->day = strtol(pEnd+1, &pEnd, 10); + tod->hour = strtol(pEnd+1, &pEnd, 10); + tod->min = strtol(pEnd+1, &pEnd, 10); + tod->sec = strtol(pEnd+1, &pEnd, 10); + return (true); + } + } + } + + return (false); +} + +bool WncController::at_get_wnc_net_stats(WncIpStats * s) +{ + string * pRespStr; + AtCmdErr_e cmdRes = at_send_wnc_cmd("AT+CGCONTRDP=1", &pRespStr, m_sCmdTimeoutMs); + + if (WNC_AT_CMD_OK == cmdRes) { + if (pRespStr->size() > 0) { + memset((void*)s, '\0', sizeof(*s)); // Clean-up + string ss; + size_t pe; + size_t ps = pRespStr->rfind("\""); + if (ps != string::npos) { + ps += 2; // Skip the , after the " + pe = ps; + + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + + ss = pRespStr->substr(ps, pe - 1 - ps); + strncpy(s->ip, ss.c_str(), MAX_LEN_IP_STR); + s->ip[MAX_LEN_IP_STR - 1] = '\0'; + ps = pe; + + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(",", pe); + + ss = pRespStr->substr(ps, pe - ps); + strncpy(s->mask, ss.c_str(), MAX_LEN_IP_STR); + s->mask[MAX_LEN_IP_STR - 1] = '\0'; + ps = pe + 1; + + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(",", pe); + + ss = pRespStr->substr(ps, pe - ps); + strncpy(s->gateway, ss.c_str(), MAX_LEN_IP_STR); + s->gateway[MAX_LEN_IP_STR - 1] = '\0'; + ps = pe + 1; + + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(",", pe); + + + ss = pRespStr->substr(ps, pe - ps); + strncpy(s->dnsPrimary, ss.c_str(), MAX_LEN_IP_STR); + s->dnsPrimary[MAX_LEN_IP_STR - 1] = '\0'; + ps = pe + 1; + + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(".", pe); + if (pe == string::npos) + return (false); + else + pe += 1; + pe = pRespStr->find(",", pe); + + + ss = pRespStr->substr(ps, pe - ps); + strncpy(s->dnsSecondary, ss.c_str(), MAX_LEN_IP_STR); + s->dnsSecondary[MAX_LEN_IP_STR - 1] = '\0'; + + dbgPuts("~~~~~~~~~~ WNC IP Stats ~~~~~~~~~~~~"); + dbgPuts("ip: ", false); dbgPutsNoTime(s->ip); + dbgPuts("mask: ", false); dbgPutsNoTime(s->mask); + dbgPuts("gateway: ", false); dbgPutsNoTime(s->gateway); + dbgPuts("dns pri: ", false); dbgPutsNoTime(s->dnsPrimary); + dbgPuts("dns sec: ", false); dbgPutsNoTime(s->dnsSecondary); + dbgPuts("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + + return (true); + } + } + } + + return (false); +} + +bool WncController::deleteSMSTextFromMem(char msgIdx) +{ + const char * err = "deleteSMSTextFromMem: Failed!"; + + switch (msgIdx) + { + case '*': + at_deleteSMSTextFromMem_wnc('1'); + at_deleteSMSTextFromMem_wnc('2'); + at_deleteSMSTextFromMem_wnc('3'); + return (true); // WNC may error if slot empty, just ignore! + + case '1': + case '2': + case '3': + if (true == at_deleteSMSTextFromMem_wnc(msgIdx)) + return (true); + else { + dbgPuts(err); + return (false); + } + + default: + dbgPuts(err); + return (false); + } +} + +bool WncController::sendSMSTextFromMem(char msgIdx) +{ + const char * err = "deleteSMSTextFromMem: Failed!"; + + switch (msgIdx) + { + case '*': + at_sendSMStextMem_wnc('1'); + at_sendSMStextMem_wnc('2'); + at_sendSMStextMem_wnc('3'); + return (true); // WNC may error if slot is empty, just ignore! + + case '1': + case '2': + case '3': + if (at_sendSMStextMem_wnc(msgIdx) == true) + return (true); + else { + dbgPuts(err); + return (false); + } + + default: + dbgPuts(err); + return (false); + } +} + +bool WncController::at_deleteSMSTextFromMem_wnc(char n) +{ + string cmdStr, respStr; + // Message is stored in WNC, now send it! + cmdStr = "AT+CMGD="; + cmdStr += n; + cmdStr += "\r\n"; + dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str(), false); + AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), m_sCmdTimeoutMs, &respStr); + dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); + return (r == WNC_AT_CMD_OK); +} + +bool WncController::at_sendSMStextMem_wnc(char n) +{ + string cmdStr, respStr; + // Message is stored in WNC, now send it! + cmdStr = "AT+CMSS="; + cmdStr += n; + cmdStr += "\r\n"; + dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str(), false); + AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), m_sCmdTimeoutMs, &respStr); + dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); + return (r == WNC_AT_CMD_OK); +} + +bool WncController::at_sendSMStext_wnc(const char * const phoneNum, const char * const text) +{ + string respStr; + string * pRespStr; + size_t l = strlen(text); + + if (l <= MAX_WNC_SMS_LENGTH) + { + // Check to see if the SMS service is available + checkCellLink(); + if (m_sReadyForSMS == true) { + at_send_wnc_cmd("AT+CMGF=1", &pRespStr, m_sCmdTimeoutMs); + string cmdStr("AT+CMGS=\""); + cmdStr += phoneNum; + cmdStr += "\""; + dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); + cmdStr += "\x0d"; // x0d = <ENTER> + // Send raw command with short timeout (the timeout will fail cause the WNC is not supposed to reply yet! + // And we want a delay before sending the actual text part of the string! + mdmSendAtCmdRsp(cmdStr.c_str(), 300, &respStr, false); // False turns off auto-addition of CR+LF (the WNC wants nothing here) + dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); + if ((respStr.size() > 0) && (respStr.find("ERROR") == string::npos)) { + // Part 2 of the text, this is the actual text part: + cmdStr = text; + dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); + cmdStr += "\x1A"; // <CTRL>-Z is what tells the WNC the message is complete to send! + AtCmdErr_e r = mdmSendAtCmdRsp(cmdStr.c_str(), 10000, &respStr); + dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); + if (respStr.size() == 0) + return (false); + else + return (r == WNC_AT_CMD_OK); + } + } + } + + return (false); +} + +bool WncController::saveSMSText(const char * const phoneNum, const char * const text, char * msgIdx) +{ + if (at_saveSMStext_wnc(phoneNum, text, msgIdx) == true) + return (true); + else { + dbgPuts("saveSMSTextToMem: failed!\r\n"); + return (false); + } +} + +bool WncController::at_saveSMStext_wnc(const char * const phoneNum, const char * const text, char * msgIdx) +{ + string respStr; + size_t l = strlen(text); + + if (l <= MAX_WNC_SMS_LENGTH) + { + // Check to see if the SMS service is available + checkCellLink(); + if (m_sReadyForSMS == true) { + string cmdStr("AT+CMGW=\""); + cmdStr += phoneNum; + cmdStr += "\""; + dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); + cmdStr += "\x0d"; // x0d = <ENTER> + // Send raw command with short timeout (the timeout will fail cause the WNC is not supposed to reply yet! + // And we want a delay before sending the actual text part of the string! + mdmSendAtCmdRsp(cmdStr.c_str(), 300, &respStr, false); // False turns off auto-addition of CR+LF (the WNC wants nothing here) + dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); + if ((respStr.size() > 0) && (respStr.find("ERROR") == string::npos)) { + // Part 2 of the text, this is the actual text part: + cmdStr = text; + dbgPuts("TX: ", false); dbgPutsNoTime(cmdStr.c_str()); + cmdStr += "\x1A"; // <CTRL>-Z is what tells the WNC the message is complete to save! + mdmSendAtCmdRsp(cmdStr.c_str(), 10000, &respStr); + dbgPuts("RX: ", false); dbgPutsNoTime(respStr.c_str()); + if (respStr.size() > 0) { + // respStr will have the SMS index + size_t pos1 = respStr.find("+CMGW: "); + size_t pos2 = respStr.rfind("OK"); + if (pos1 != string::npos && pos2 != string::npos) { + *msgIdx = *string(respStr.substr(pos1+7, 1)).c_str(); + return (true); + } + else { + *msgIdx = '!'; + } + } + } + } + } + + return (false); +} + +bool WncController::at_readSMSlog_wnc(string ** log) +{ + return (at_send_wnc_cmd("AT+CMGL", log, m_sCmdTimeoutMs) == WNC_AT_CMD_OK); +} + +size_t WncController::at_readSMStext_wnc(const char n, const char ** log) +{ + static string smsReadTxtStr; + string * pRespStr; + string cmdStr; + + smsReadTxtStr.erase(); + cmdStr = "AT+CMGR"; + cmdStr += '1'; + if (at_send_wnc_cmd("AT+CMGR", &pRespStr, m_sCmdTimeoutMs) == WNC_AT_CMD_OK) + *log = pRespStr->c_str(); + else + *log = "\0"; + + return (pRespStr->size()); +} + +bool WncController::at_at_wnc(void) +{ + string * pRespStr; + return (WNC_AT_CMD_OK == at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS)); // Heartbeat? +} + +bool WncController::at_init_wnc(bool hardReset) +{ + string * pRespStr; + AtCmdErr_e cmdRes; + + if (hardReset == true) + dbgPuts("Hard Soft Reset!"); + + dbgPuts("Start AT init of WNC:"); + + // Kick it twice to perhaps remove cued responses from an incomplete + // power cycle. + at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); + at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); + + // Dump the firmware revision on the debug log: + at_send_wnc_cmd("AT+GMR", &pRespStr, m_sCmdTimeoutMs); + + m_FirmwareRevision = pRespStr->c_str(); + + // Quick commands below do not need to check cellular connectivity + at_send_wnc_cmd("ATE0", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Echo Off + at_send_wnc_cmd("AT+CMEE=2", &pRespStr, m_sCmdTimeoutMs); // 2 - verbose error, 1 - numeric error, 0 - just ERROR + + // Setup 3 memory slots in the WNC SIM for SMS usage. + at_send_wnc_cmd("AT+CMGF=1", &pRespStr, m_sCmdTimeoutMs); + at_send_wnc_cmd("AT+CPMS=\"SM\",\"SM\",\"SM\"", &pRespStr, m_sCmdTimeoutMs); + + cmdRes = at_send_wnc_cmd("AT", &pRespStr, WNC_QUICK_CMD_TIMEOUT_MS); // Heartbeat? + + // If the simple commands are not working, no chance of more complex. + // I have seen re-trying commands make it worse. + if (cmdRes != WNC_AT_CMD_OK) + return (false); + + // Disable unsolicited RRCSTATE responses. These are supposed to be off + // by default but have been found to be active. + // This problem introduced in: NQ_MPSS_IMA3_v10.58.174043 LTE-M firmware + cmdRes = at_send_wnc_cmd("AT%NOTIFYEV=\"ALL\",0", &pRespStr, m_sCmdTimeoutMs); + if (cmdRes != WNC_AT_CMD_OK) + return (false); + + cmdRes = at_send_wnc_cmd("AT@INTERNET=1", &pRespStr, m_sCmdTimeoutMs); + if (cmdRes != WNC_AT_CMD_OK) + return (false); + + cmdRes = at_send_wnc_cmd("AT@SOCKDIAL=1", &pRespStr, m_sCmdTimeoutMs); + if (cmdRes != WNC_AT_CMD_OK) + return (false); + + dbgPuts("SUCCESS: AT init of WNC!"); + + return (true); +} + +int16_t WncController::at_sockopen_wnc(const char * const ip, uint16_t port, uint16_t numSock, bool tcp, uint16_t timeOutSec) +{ + string * pRespStr; + string cmd_str("AT@SOCKCREAT="); + AtCmdErr_e res; + + if (tcp) cmd_str += "1"; // TCP + else cmd_str += "2"; // else UDP + + cmd_str += ",0"; + res = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); + if (res == WNC_AT_CMD_OK && pRespStr->size() > 0) + { + size_t pos1 = pRespStr->find("T:"); + size_t pos2 = pRespStr->rfind("OK"); + if ((pos1 != string::npos) && (pos2 != string::npos)) { + size_t numLen = pos2 - (pos1 + 2); + string sockStr = pRespStr->substr(pos1 + 2, numLen); + cmd_str = "AT@SOCKCONN="; + cmd_str += sockStr; + cmd_str += ",\""; + cmd_str += ip; + cmd_str += "\","; + cmd_str += _to_string(port); + cmd_str += ","; + if (timeOutSec < 30) + timeOutSec = 30; + else if (timeOutSec > 360) + timeOutSec = 360; + cmd_str += _to_string(timeOutSec); + res = sendWncCmd(cmd_str.c_str(), &pRespStr, 1000 * timeOutSec + 1000); + if (m_sMoreDebugEnabled) { + at_send_wnc_cmd("AT@SOCKCREAT?", &pRespStr, m_sCmdTimeoutMs); + at_send_wnc_cmd("AT@SOCKCONN?", &pRespStr, m_sCmdTimeoutMs); + } + return (strtol(sockStr.c_str(), NULL, 10)); + } + else { + dbgPuts("Invalid sockcreat response!"); + return (0); + } + } + else + return (0); +} + +bool WncController::at_sockclose_wnc(uint16_t numSock) +{ + string * pRespStr; + string cmd_str("AT@SOCKCLOSE="); + + cmd_str += _to_string(numSock); + + // Don't check the cell status to close the socket + AtCmdErr_e res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); + + if ((res != WNC_AT_CMD_TIMEOUT) && (res != WNC_AT_CMD_OK)) { + for (unsigned i = 0; i < WNC_SOCK_CLOSE_RETRY_CNT; i++) { + res = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); + if ((res == WNC_AT_CMD_TIMEOUT) || (res == WNC_AT_CMD_OK)) + break; + } + } + + return (res == WNC_AT_CMD_OK); +} + +bool WncController::at_dnsresolve_wnc(const char * s, string * ipStr) +{ + string * pRespStr; + string str(s); + AtCmdErr_e r; + + ipStr->erase(); // Clear out string until resolved! + str = "AT@DNSRESVDON=\"" + str; + str += "\""; + r = sendWncCmd(str.c_str(), &pRespStr, WNC_DNS_RESOLVE_WAIT_MS); + if (r == WNC_AT_CMD_OK && pRespStr->size() > 0) { + size_t pos_start = pRespStr->find("ON:\""); + size_t pos_end = pRespStr->find("\"", (pos_start + 4)); + if ((pos_start != string::npos) && (pos_end != string::npos)) { + pos_start += 4; + pos_end -= 1; + + if (pos_end > pos_start) { + // Make a copy for use later (the source string is re-used) + *ipStr = pRespStr->substr(pos_start, pos_end - pos_start + 1); + return (true); + } + } + } + + *ipStr = INVALID_IP_STR; + + return (false); +} + +bool WncController::waitForPowerOnModemToRespond(uint8_t timeoutSecs) +{ + // Now, give the modem x seconds to start responding by + // sending simple 'AT' commands to modem once per second. + if (timeoutSecs > 0) { + do { + timeoutSecs--; + dbgPutsNoTime("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false); + dbgPutsNoTime(" ", false); + AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr); + if (rc == WNC_AT_CMD_OK) { + dbgPutsNoTime(""); // CR LF + return true; //timer.read(); + } + waitMs(500); + } + while (timeoutSecs > 0); + dbgPutsNoTime(""); // CR LF + } + + return (false); +} + +WncController::AtCmdErr_e WncController::at_sockwrite_wnc(const uint8_t * s, uint16_t n, uint16_t numSock, bool isTcp) +{ + AtCmdErr_e result; + + if ((n > 0) && (n <= MAX_WNC_WRITE_BYTES)) { + string * pRespStr; + const char * num2str; + string cmd_str; + + if (isTcp == true) + cmd_str="AT@SOCKWRITE="; + else + cmd_str="AT@SOCKWRITE="; // "AT@SOCKSEND="; + + cmd_str += _to_string(numSock); + cmd_str += ","; + cmd_str += _to_string(n); + cmd_str += ",\""; + while(n > 0) { + n--; + num2str = _to_hex_string(*s++); + // Always 2-digit ascii hex: + if (num2str[1] == '\0') + cmd_str += '0'; + cmd_str += num2str; + } + cmd_str += "\""; + result = sendWncCmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); + } + else { + dbgPuts("sockwrite Err, string len bad!"); + result = WNC_AT_CMD_ERR; + } + + return (result); +} + +WncController::AtCmdErr_e WncController::at_sockread_wnc(string * pS, uint16_t numSock, bool isTcp) +{ + AtCmdErr_e result = WNC_AT_CMD_OK; + + string * pRespStr; + string cmd_str; + size_t pos_start=0, pos_end=0; + int i; + + pS->erase(); // Start with a fresh string + + if (isTcp == true) + cmd_str="AT@SOCKREAD="; + else + cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV="; + + cmd_str += _to_string(numSock); + cmd_str += ","; + cmd_str += _to_string(MAX_WNC_READ_BYTES); + + // Experimental: read should not need to check cell net status + result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); + if (result == WNC_AT_CMD_OK) { + if (pRespStr->size() > 0) { + pos_start = pRespStr->find("\""); + pos_end = pRespStr->rfind("\""); + // Make sure search finds what it's looking for! + if (pos_start != string::npos && pos_end != string::npos) { + pos_start++; + i = pos_end - pos_start; // Num hex chars, 2 per byte + } + else + i = 0; + } + else + i = 0; + + if ((i < 0) || ((i % 2) == 1)) + dbgPuts("Invalid READ string!"); + + if (i > 2*MAX_WNC_READ_BYTES) { + i = 2*MAX_WNC_READ_BYTES; + dbgPuts("DANGER WNC read data does not match length!"); + } + + // If data, convert the hex string into byte values + while (i > 0) { + i -= 2; + *pS += (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16); + pos_start += 2; + } + } + + return (result); +} + +WncController::AtCmdErr_e WncController::at_sockread_wnc(uint8_t * pS, uint16_t * numRead, uint16_t n, uint16_t numSock, bool isTcp) +{ + AtCmdErr_e result = WNC_AT_CMD_OK; + *numRead = 0; + + if ((n > 0) && (n <= MAX_WNC_READ_BYTES)) { + string * pRespStr; + string cmd_str; + size_t pos_start=0, pos_end=0; + int i; + + if (isTcp == true) + cmd_str="AT@SOCKREAD="; + else + cmd_str="AT@SOCKREAD="; // "AT@SOCKRECV="; + + cmd_str += _to_string(numSock); + cmd_str += ","; + cmd_str += _to_string(n); + + // Experimental: read should not need to check cell net status + result = at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, m_sCmdTimeoutMs); + if (result == WNC_AT_CMD_OK) { + if (pRespStr->size() > 0) { + pos_start = pRespStr->find("\""); + pos_end = pRespStr->rfind("\""); + // Make sure search finds what it's looking for! + if (pos_start != string::npos && pos_end != string::npos) { + pos_start++; + i = pos_end - pos_start; // Num hex chars, 2 per byte + } + else + i = 0; + } + else + i = 0; + + if ((i < 0) || ((i % 2) == 1)) + dbgPuts("Invalid READ string!"); + + if (i > 2*n) { + // Bound the ill formated WNC read string! + i = 2*n; + dbgPuts("TRUNCATING read data!"); + } + + // If data, convert the hex string into byte values + i /= 2; + *numRead = i; + while (i > 0) { + i--; + *pS++ = (uint8_t)strtol(pRespStr->substr(pos_start, 2).c_str(), NULL, 16); + pos_start += 2; + } + } + } + else { + dbgPuts("sockread Err, to many to read!"); + result = WNC_AT_CMD_ERR; + } + + return (result); +} + +bool WncController::at_reinitialize_mdm(void) +{ + // Atempt to re-register +// string * pRespStr; +// dbgPuts("Force re-register!"); +// at_send_wnc_cmd("AT+CFUN=0,0", &pRespStr, m_sCmdTimeoutMs); +// waitMs(31000); +// at_send_wnc_cmd("AT+CFUN=1,0", &pRespStr, m_sCmdTimeoutMs); +// waitMs(31000); + + // Initialize the modem + dbgPuts("Modem RE-initializing with SOFT Reset..."); + + string * pRespStr; + at_send_wnc_cmd("AT@DMREBOOT", &pRespStr, m_sCmdTimeoutMs); + waitMs(5000); + + // Now, give the modem time to start responding by + // sending simple 'AT' commands to the modem once per second. + int timeoutSecs = WNC_REINIT_MAX_TIME_MS; + do { + dbgPuts("\rWaiting ", false); dbgPutsNoTime(_to_string(timeoutSecs), false); + AtCmdErr_e rc = mdmSendAtCmdRsp("AT", 500, &m_sWncStr); + if (rc == WNC_AT_CMD_OK) { + dbgPutsNoTime(""); // CR LF + break; + } + waitMs(500); + timeoutSecs--; + } + while (timeoutSecs > 0); + + if (timeoutSecs <= 0) + dbgPuts("\r\nModem RE-init FAILED!"); + else + dbgPuts("\r\nModem RE-init complete!"); + + return (timeoutSecs > 0); +} + +WncController::AtCmdErr_e WncController::mdmSendAtCmdRsp(const char *cmd, int timeout_ms, string * rsp, bool crLf) +{ + rsp->erase(); // Clean up from possible prior cmd response + + // Don't bother the WNC if user hasn't turned it on. + if (m_sState == WNC_OFF) + return (WNC_AT_CMD_WNC_NOT_ON); + + size_t n = strlen(cmd); + + // Wait per WNC advise + waitMs(WNC_WAIT_FOR_AT_CMD_MS); + + if (cmd && n > 0) { + sendCmd(cmd, crLf); +// sendCmd(cmd, n, 1000, crLf); // 3rd arg is micro seconds between chars sent + } + + startTimerA(); + while (getTimerTicksA_mS() < timeout_ms) { + n = mdmGetline(rsp, timeout_ms - getTimerTicksA_mS()); + + if (n == 0) + continue; + + if (rsp->rfind("OK") != string::npos) { + stopTimerA(); + return (WNC_AT_CMD_OK); + } + + if (rsp->rfind("+CME ERROR") != string::npos) { + stopTimerA(); + return (WNC_AT_CMD_ERRCME); + } + + if (rsp->rfind("@EXTERR") != string::npos) { + stopTimerA(); + return (WNC_AT_CMD_ERREXT); + } + + if (rsp->rfind("ERROR") != string::npos) { + stopTimerA(); + return (WNC_AT_CMD_ERR); + } + } + stopTimerA(); + + return (WNC_AT_CMD_TIMEOUT); +} + +bool WncController::at_setapn_wnc(const char * const apnStr) +{ + string * pRespStr; + + string cmd_str("AT%PDNSET=1,"); + cmd_str += apnStr; + cmd_str += ",IP"; + if (WNC_AT_CMD_OK == at_send_wnc_cmd(cmd_str.c_str(), &pRespStr, WNC_APNSET_TIMEOUT_MS)) // Set APN, cmd seems to take a little longer sometimes + return (true); + else + return (false); +} + +bool WncController::at_getrssiber_wnc(int16_t * dBm, int16_t * ber) +{ + string * pRespStr; + AtCmdErr_e cmdRes; + cmdRes = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER + if (cmdRes != WNC_AT_CMD_OK) + return (false); + + if (pRespStr->size() == 0) { + dbgPuts("Strange RSSI result!"); + return (false); + } + else { + size_t pos1 = pRespStr->find("SQ:"); + size_t pos2 = pRespStr->rfind(","); + // Sanity check + if ((pos1 != string::npos) && (pos2 != string::npos) && (pos2 > pos1)) { + string subStr = pRespStr->substr(pos1 + 4, pos2 - pos1 ); + int rawRssi = atoi(subStr.c_str()); + + // Convert WNC RSSI into dBm range: + // 0 - -113 dBm + // 1 - -111 dBm + // 2..30 - -109 to -53 dBm + // 31 - -51dBm or > + // 99 - not known or not detectable + if (rawRssi == 99) + *dBm = -199; + else if (rawRssi == 0) + *dBm = -113; + else if (rawRssi == 1) + *dBm = -111; + else if (rawRssi == 31) + *dBm = -51; + else if (rawRssi >= 2 && rawRssi <= 30) + *dBm = -113 + 2 * rawRssi; + else { + dbgPuts("Invalid RSSI!"); + return (false); + } + // Parse out BER: 0..7 as RXQUAL values in the table 3GPP TS 45.008 subclause 8.2.4 + // 99 - unknown or undetectable + subStr = pRespStr->substr(pos2 + 1, pRespStr->length() - (pos2 + 1)); + *ber = atoi(subStr.c_str()); + } + else { + dbgPuts("Strange RSSI result2!"); + return (false); + } + } + + return (true); +} + +bool WncController::checkCellLink(void) +{ + string * pRespStr; + size_t pos; + int regSts; + int cmdRes1, cmdRes2; + + if (m_sState == WNC_OFF) + return (false); + + m_sState = WNC_ON_NO_CELL_LINK; + + if (m_sMoreDebugEnabled) + dbgPuts("<-------- Begin Cell Status ------------"); + + cmdRes1 = at_send_wnc_cmd("AT+CSQ", &pRespStr, m_sCmdTimeoutMs); // Check RSSI,BER + + // If no response, don't bother with more commands + if (cmdRes1 != WNC_AT_CMD_TIMEOUT) + cmdRes2 = at_send_wnc_cmd("AT+CPIN?", &pRespStr, m_sCmdTimeoutMs); // Check if SIM locked + else { + if (m_sMoreDebugEnabled) + dbgPuts("------------ WNC No Response! --------->"); + + return (false); + } + + if ((cmdRes1 != WNC_AT_CMD_OK) || (cmdRes2 != WNC_AT_CMD_OK) || (pRespStr->size() == 0)) + { + if (m_sMoreDebugEnabled) + { + if ((cmdRes1 == WNC_AT_CMD_TIMEOUT) || (cmdRes2 == WNC_AT_CMD_TIMEOUT)) + dbgPuts("------------ WNC No Response! --------->"); + else + dbgPuts("------------ WNC Cmd Error! ----------->"); + } + + // If by a miracle it responds to the 2nd after the 1st, keep going + if ((cmdRes2 == WNC_AT_CMD_TIMEOUT) || (pRespStr->size() == 0)) + return (false); + } + + // If SIM Card not ready don't bother with commands! + if (pRespStr->find("CPIN: READY") == string::npos) + { + if (m_sMoreDebugEnabled) + dbgPuts("------------ WNC SIM Problem! --------->"); + + return (false); + } + + // SIM card OK, now check for signal and cellular network registration + cmdRes1 = at_send_wnc_cmd("AT+CREG?", &pRespStr, m_sCmdTimeoutMs); // Check if registered on network + if (cmdRes1 != WNC_AT_CMD_OK || pRespStr->size() == 0) + { + if (m_sMoreDebugEnabled) + dbgPuts("------------ WNC +CREG? Fail! --------->"); + + return (false); + } + else + { + pos = pRespStr->find("CREG: "); + if (pos != string::npos) + { + // The registration is the 2nd arg in the comma separated list + *pRespStr = pRespStr->substr(pos+8, 1); + regSts = atoi(pRespStr->c_str()); + switch (regSts) { + case 1: + case 5: + case 6: + case 7: + m_sReadyForSMS = true; + break; + default: + m_sReadyForSMS = false; + dbgPuts("SMS Service Down!"); + } + + // 1 - registered home, 5 - registered roaming + if ((regSts != 1) && (regSts != 5)) + { + if (m_sMoreDebugEnabled) + dbgPuts("------ WNC Cell Link Down for Data! --->"); + + return (false); + } + } + + if (m_sMoreDebugEnabled) + dbgPuts("------------ WNC Ready ---------------->"); + } + + // If we made it this far and the WNC did respond, keep the ON state + if (m_sState != WNC_NO_RESPONSE) + m_sState = WNC_ON; + + return (true); +} + +int WncController::dbgPutsNoTime(const char * s, bool crlf) +{ + if (m_sDebugEnabled == true) { + int r = dbgWriteChars(s); + if (crlf == true) + return (dbgWriteChars("\r\n")); + else + return (r); + } + else + return 0; +}; + +int WncController::dbgPuts(const char * s, bool crlf) +{ + dbgPutsNoTime("[*] ", false); + dbgPutsNoTime(_to_string(getLogTimerTicks()), false); + dbgPutsNoTime(" ", false); + + int r = dbgPutsNoTime(s, false); + + if (crlf == true) + return (dbgPutsNoTime("", true)); + else + return (r); +}; + +void WncController::sendCmd(const char * cmd, bool crLf) +{ + puts(cmd); + if (crLf == true) + puts("\r\n"); +} + +void WncController::sendCmd(const char * cmd, unsigned n, unsigned wait_uS, bool crLf) +{ + while (n--) { + putc(*cmd++); + waitUs(wait_uS); + }; + if (crLf == true) { + putc('\r'); + waitUs(wait_uS); + putc('\n'); + waitUs(wait_uS); + } +} + +}; // End namespace WncController_fk +
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/WNC14A2AInterface/WncControllerK64F/WncController/WncController.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/WNC14A2AInterface/WncControllerK64F/WncController/WncController.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,636 @@ +/** + Copyright (c) 2016 Fred Kellerman + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file WncController.h + @purpose Controls WNC Cellular Modem + @version 1.0 + @date July 2016 + @author Fred Kellerman + + Notes: This code originates from the following mbed repository: + + https://developer.mbed.org/teams/Avnet/code/WncControllerLibrary/ +*/ + + +#ifndef __WNCCONTROLLER_H_ +#define __WNCCONTROLLER_H_ + +#include <string> +#include <stdint.h> + +namespace WncController_fk { + +using namespace std; + +/** @defgroup API The WncControllerLibrary API */ +/** @defgroup MISC Misc WncControllerLibrary functions */ +/** @defgroup INTERNALS WncControllerLibrary Internals */ + +static const uint8_t MAX_LEN_IP_STR = 16; // Length includes room for the extra NULL + +/** \brief Contains info fields for the WNC Internet Attributes */ +struct WncIpStats +{ + string wncMAC; + char ip[MAX_LEN_IP_STR]; + char mask[MAX_LEN_IP_STR]; + char gateway[MAX_LEN_IP_STR]; + char dnsPrimary[MAX_LEN_IP_STR]; + char dnsSecondary[MAX_LEN_IP_STR]; +}; + + +/** + * @author Fred Kellerman + * @see API + * + * <b>WncController</b> This mbed C++ class is for controlling the WNC + * Cellular modem via the serial AT command interface. This was + * developed with respect to version 1.3 of the WNC authored + * unpublished spec. This class is only designed to have 1 instantiation, + * it is also not multi-thread safe. There are no OS specific + * entities being used, there are pure virtual methods that an + * inheriting class must fulfill. That inheriting class will have + * OS and platform specific entities. See WncControllerK64F for an + * example for the NXP K64F Freedom board. + */ +class WncController +{ +public: + + static const unsigned MAX_NUM_WNC_SOCKETS = 5; // Max number of simultaneous sockets that the WNC supports + static const unsigned MAX_POWERUP_TIMEOUT = 60; // How long the powerUp method will try to turn on the WNC Shield + // (this is the default if the user does not over-ride on power-up + + /** Tracks mode of the WNC Shield hardware */ + enum WncState_e { + WNC_OFF = 0, + WNC_ON, // This is intended to mean all systems go, including cell link up but socket may not be open + WNC_ON_NO_CELL_LINK, + WNC_NO_RESPONSE + }; + + /** + * + * Constructor for WncController class, sets up internals. + * @ingroup API + * @return none. + */ + WncController(void); + virtual ~WncController()=0; + + /** + * + * Used internally but also make public for a user of the Class to + * interrogate state as well. + * @ingroup API + * @return the current state of the Wnc hardware. + */ + WncState_e getWncStatus(void); + + /** + * + * Allows a user to set the WNC modem to use the given Cellular APN + * @ingroup API + * @param apnStr - a null terminated c-string + * @return true if the APN set was succesful, else false + */ + bool setApnName(const char * const apnStr); + + /** + * + * Queries the WNC modem for the current RX RSSI in units of coded dBm + * @ingroup API + * @return 0 â -113 dBm or less + * 1 â -111 dBm + * 2...30 â -109 dBm to â53 dBm + * 31 â -51 dBm or greater + * 99 â not known or not detectable + */ + int16_t getDbmRssi(void); + + /** + * + * Queries the WNC modem for the current Bit Error Rate + * @ingroup API + * @return 0...7 â as RXQUAL values in the table in 3GPP TS 45.008 + * subclause 8.2.4 + * 99 â not known or not detectable + */ + int16_t get3gBer(void); + + /** + * + * Powers up the WNC modem + * @ingroup API + * @param apn - the apn c-string to set the WNC modem to use + * @param powerUpTimeoutSecs - the amount of time to wait for the WNC modem to turn on + * @return true if powerup was a success, else false. + */ + bool powerWncOn(const char * const apn, uint8_t powerUpTimeoutSecs = MAX_POWERUP_TIMEOUT); + + /** + * + * Returns the NAT Self, gateway, masks and dns IP + * @ingroup API + * @param s - a pointer to a struct that will contain the IP info. + * @return true if success, else false. + */ + bool getWncNetworkingStats(WncIpStats * s); + + /** + * + * Takes a text URL and converts it internally to an IP address for the + * socket number given. + * @ingroup API + * @param numSock - The number of the socket to lookup the IP address for. + * @param url - a c-string text URL + * @return true if success, else false. + */ + bool resolveUrl(uint16_t numSock, const char * url); + + /** + * + * If you know the IP address you can set the socket up to use it rather + * than using a text URL. + * @ingroup API + * @param numSock - The number of the socket to use the IP address for. + * @param ipStr - a c-string text IP addrese like: 192.168.0.1 + * @return true if success, else false. + */ + bool setIpAddr(uint16_t numSock, const char * ipStr); + + /** + * + * Opens a socket for the given number, port and IP protocol. Before + * using open, you must use either resolveUrl() or setIpAddr(). + * @ingroup API + * @param numSock - The number of the socket to open. + * @param port - the IP port to open + * @param tcp - set true for TCP, false for UDP + * @param timeoutSec - the amount of time in seconds to wait for the open to complete + * @return true if success, else false. + */ + bool openSocket(uint16_t numSock, uint16_t port, bool tcp, uint16_t timeOutSec = 30); + + /** + * + * Opens a socket for the given text URL, number, port and IP protocol. + * @ingroup API + * @param numSock - The number of the socket to open. + * @param url - a c-string text URL, the one to open a socket for. + * @param port - the IP port to open. + * @param tcp - set true for TCP, false for UDP. + * @param timeoutSec - the amount of time in seconds to wait for the open to complete. + * @return true if success, else false. + */ + bool openSocketUrl(uint16_t numSock, const char * url, uint16_t port, bool tcp, uint16_t timeOutSec = 30); + + /** + * + * Opens a socket for the given text IP address, number, port and IP protocol. + * @ingroup API + * @param numSock - The number of the socket to open. + * @param ipAddr - a c-string text IP address like: "192.168.0.1". + * @param port - the IP port to open. + * @param tcp - set true for TCP, false for UDP. + * @param timeoutSec - the amount of time in seconds to wait for the open to complete. + * @return true if success, else false. + */ + bool openSocketIpAddr(uint16_t numSock, const char * ipAddr, uint16_t port, bool tcp, uint16_t timeOutSec = 30); + + + /** + * + * Write data bytes to a Socket, the Socket must already be open. + * @ingroup API + * @param numSock - The number of the socket to open. + * @parma s - an array of bytes to write to the socket. + * @param n - the number of bytes to write. + * @return true if success, else false. + */ + bool write(uint16_t numSock, const uint8_t * s, uint32_t n); + + /** + * + * Poll to read available data bytes from an already open Socket. This method + * will retry reads to what setReadRetries() sets it to and the delay in between + * retries that is set with setReadRetryWait() + * @ingroup API + * @param numSock - The number of the socket to open. + * @parma readBuf - a pointer to where read will put the data. + * @param maxReadBufLen - The number of bytes readBuf has room for. + * @return the number of bytes actually read into readBuf. 0 is a valid value if no data is available. + */ + size_t read(uint16_t numSock, uint8_t * readBuf, uint32_t maxReadBufLen); + + /** + * + * Poll to read available data bytes from an already open Socket. This method + * will retry reads to what setReadRetries() sets it to and the delay in between + * retries that is set with setReadRetryWait() + * @ingroup API + * @param numSock - The number of the socket to open. + * @parma readBuf - a pointer to pointer that will be set to point to an internal byte buffer that contains any read data. + * @return the number of bytes actually read into the pointer that readBuf points to. 0 is a valid value if no data is available. + */ + size_t read(uint16_t numSock, const uint8_t ** readBuf); + + /** + * + * Set the number of retries that the read methods will use. If a read returns 0 data this setting will have the read + * re-read to see if new data is available. + * @ingroup API + * @param numSock - The number of the socket to open. + * @parma retries - the number of retries to perform. + * @return none. + */ + void setReadRetries(uint16_t numSock, uint16_t retries); + + /** + * + * Set the time between retires that the read methods will use. If a read returns 0 data this setting will have the read + * re-read and use this amount of delay in between the re-reads. + * @ingroup API + * @param numSock - The number of the socket to open. + * @parma waitMs - the amount of time in mS to wait between retries. + * @return none. + */ + void setReadRetryWait(uint16_t numSock, uint16_t waitMs); + + /** + * + * Closes an already open Socket. + * @ingroup API + * @param numSock - The number of the socket to open. + * @return true if success else false. + */ + bool closeSocket(uint16_t numSock); + + /** + * + * Sets the amount of time to wait between the raw AT commands that are sent to the WNC modem. + * Generally you don't want to use this but it is here just in case. + * @ingroup API + * @param toMs - num mS to wait between the AT cmds. + * @return none. + */ + void setWncCmdTimeout(uint16_t toMs); + + /** + * + * Gets the IP address of the given socket number. + * @ingroup API + * @param numSock - The number of the socket to open. + * @param myIpAddr - a c-string that contains the socket's IP address. + * @return true if success else false. + */ + bool getIpAddr(uint16_t numSock, char myIpAddr[MAX_LEN_IP_STR]); + + /** + * + * Enables debug output from this class. + * @ingroup API + * @param on - true enables debug output, false disables + * @param moreDebugOn - true enables verbose debug, false truncates debug output. + * @return none. + */ + void enableDebug(bool on, bool moreDebugOn); + + /** + * + * Reports the WNC Firmware Revision info. + * @ingroup API + * @param none. + * @return char * + */ + const char* getFirmRev(void); + + /////////////////////////////////////////// + // SMS messaging + /////////////////////////////////////////// + + static const uint16_t MAX_WNC_SMS_MSG_SLOTS = 3; // How many SMS messages the WNC can store and receive at a time. + static const uint16_t MAX_WNC_SMS_LENGTH = 160; // The maximum length of a 7-bit SMS message the WNC can send and receive. + + /** Struct for SMS messages */ + struct WncSmsInfo + { + // Content + char idx; + string number; + string date; + string time; + string msg; + + // Attributes + bool incoming; + bool unsent; + bool unread; + bool pduMode; + bool msgReceipt; + }; + + /** Struct to contain a list of SMS message structs */ + struct WncSmsList + { + uint8_t msgCount; + WncSmsInfo e[MAX_WNC_SMS_MSG_SLOTS]; + }; + + /** + * + * Sends an SMS text message to someone. + * @ingroup API + * @param phoneNum - c-string 15 digit MSISDN number or ATT Jasper number (standard phone number not supported because ATT IoT SMS does not support it). + * @param text - the c-string text to send to someone. + * @return true if success else false. + */ + bool sendSMSText(const char * const phoneNum, const char * const text); + + /** + * + * Incoming messages are stored in a log in the WNC modem, this will read that + * log. + * @ingroup API + * @param log - the log contents if reading it was successful. + * @return true if success else false. + */ + bool readSMSLog(struct WncSmsList * log); + + /** + * + * Incoming messages are stored in a log in the WNC modem, this will read out + * messages that are unread and also then mark them read. + * @ingroup API + * @param w - a list of SMS messages that unread messages will be put into. + * @param deleteRead - if a message is read and this is set true the message will be deleted from the WNC modem log. + * If it is false the message will remain in the internal log but be marked as read. + * @return true if success else false. + */ + bool readUnreadSMSText(struct WncSmsList * w, bool deleteRead = true); + + /** + * + * Saves a text message into internal SIM card memory of the WNC modem. + * There are only 3 slots available this is for unread, read and saved. + * @ingroup API + * @param phoneNum - c-string 15 digit MSISDN number or ATT Jasper number (standard phone number not supported because ATT IoT SMS does not support it). + * @param text - the c-string text to send to someone. + * @param msgIdx - the slot position to save the message: '1', '2', '3' + * @return true if success else false. + */ + bool saveSMSText(const char * const phoneNum, const char * const text, char * msgIdx); + + /** + * + * Sends a prior stored a text message from internal SIM card memory of the WNC modem. + * If no messages are stored the behaviour of this method is undefined. + * @ingroup API + * @param msgIdx - the slot position to save the message: '1', '2', '3' + * @return true if success else false. + */ + bool sendSMSTextFromMem(char msgIdx); + + /** + * + * Deletes a prior stored a text message from internal SIM card memory of the WNC modem. + * If no messages are stored the behaviour of this method is undefined. + * @ingroup API + * @param msgIdx - the slot position to save the message: '1', '2', '3' or '*' deletes them all. + * @return true if success else false. + */ + bool deleteSMSTextFromMem(char msgIdx); + + /** + * + * Retreives the SIM card ICCID number. + * @ingroup API + * @param iccid - a pointer to C++ string that contains the retrieved number. + * @return true if success else false. + */ + bool getICCID(string * iccid); + + /** + * + * Converts an ICCID number into a MSISDN number. The ATT SMS system for IoT only allows use of the 15-digit MSISDN number. + * @ingroup API + * @param iccid - the number to convert. + * @param msisdn - points to a C++ string that has the converted number. + * @return true if success else false. + */ + bool convertICCIDtoMSISDN(const string & iccid, string * msisdn); + + /////////////////////////////////////////// + // Neighborhood Cell Info + /////////////////////////////////////////// + + /** + * + * Fetches the signal quality log from the WNC modem. + * @ingroup API + * @param log - a pointer to an internal buffer who's contents contain the signal quality metrics. + * @return The number of chars in the log. + */ + size_t getSignalQuality(const char ** log); + + /** A struct for the WNC modem Date and Time */ + struct WncDateTime + { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t min; + uint8_t sec; + }; + + /** + * + * Fetches the cell tower's time and date. The time is accurate when read + * but significant delays exist between the time it is read and returned. + * @ingroup API + * @param tod - User supplies a pointer to a tod struct and this method fills it in. + * @return true if success else false. + */ + bool getTimeDate(struct WncDateTime * tod); + + /** + * + * ICMP Pings a URL, the results are only output to the debug log for now! + * @ingroup API + * @param url - a c-string whose URL is to be pinged. + * @return true if success else false. + */ + bool pingUrl(const char * url); + + /** + * + * ICMP Pings an IP, the results are only output to the debug log for now! + * @ingroup API + * @param ip - a c-string whose IP is to be pinged. + * @return true if success else false. + */ + bool pingIp(const char * ip); + + /** + * + * Allows a user to send a raw AT command to the WNC modem. + * @ingroup API + * @param cmd - the c-string cmd to send like: "AT" + * @param resp - a pointer to the c-string cmd's response. + * @param sizeRespBuf - how large the command response buffer is, sets the max response length. + * @param ms_timeout - how long to wait for the WNC to respond to your command. + * @return the number of characters in the response from the WNC modem. + */ + size_t sendCustomCmd(const char * cmd, char * resp, size_t sizeRespBuf, int ms_timeout); + +protected: + + // Debug output methods + int dbgPutsNoTime(const char * s, bool crlf = true); + int dbgPuts(const char * s, bool crlf = true); + const char * _to_string(int64_t value); + const char * _to_hex_string(uint8_t value); + + // Sends commands to WNC via + enum AtCmdErr_e { + WNC_AT_CMD_OK, + WNC_AT_CMD_ERR, + WNC_AT_CMD_ERREXT, + WNC_AT_CMD_ERRCME, + WNC_AT_CMD_INVALID_RESPONSE, + WNC_AT_CMD_TIMEOUT, + WNC_AT_CMD_NO_CELL_LINK, + WNC_AT_CMD_WNC_NOT_ON + }; + + bool waitForPowerOnModemToRespond(uint8_t powerUpTimeoutSecs); + AtCmdErr_e sendWncCmd(const char * const s, string ** r, int ms_timeout); + + // Users must define these functionalities in the inheriting class: + // General I/O and timing: + virtual int putc(char c) = 0; + virtual int puts(const char * s) = 0; + virtual char getc(void) = 0; + virtual int charReady(void) = 0; + virtual int dbgWriteChar(char b) = 0; + virtual int dbgWriteChars(const char *b) = 0; + virtual void waitMs(int t) = 0; + virtual void waitUs(int t) = 0; + virtual bool initWncModem(uint8_t powerUpTimeoutSecs) = 0; + + // Isolate OS timers + virtual int getLogTimerTicks(void) = 0; + virtual void startTimerA(void) = 0; + virtual void stopTimerA(void) = 0; + virtual int getTimerTicksA_mS(void) = 0; + virtual void startTimerB(void) = 0; + virtual void stopTimerB(void) = 0; + virtual int getTimerTicksB_mS(void) = 0; + +private: + + bool softwareInitMdm(void); + bool checkCellLink(void); + AtCmdErr_e mdmSendAtCmdRsp(const char * cmd, int timeout_ms, string * rsp, bool crLf = true); + size_t mdmGetline(string * buff, int timeout_ms); + bool at_at_wnc(void); + bool at_init_wnc(bool hardReset = false); + int16_t at_sockopen_wnc(const char * const ip, uint16_t port, uint16_t numSock, bool tcp, uint16_t timeOutSec); + bool at_sockclose_wnc(uint16_t numSock); + bool at_dnsresolve_wnc(const char * s, string * ipStr); + AtCmdErr_e at_sockwrite_wnc(const uint8_t * s, uint16_t n, uint16_t numSock, bool isTcp); + AtCmdErr_e at_sockread_wnc(uint8_t * pS, uint16_t * numRead, uint16_t n, uint16_t numSock, bool isTcp); + AtCmdErr_e at_sockread_wnc(string * pS, uint16_t numSock, bool isTcp); + bool at_reinitialize_mdm(void); + AtCmdErr_e at_send_wnc_cmd(const char * s, string ** r, int ms_timeout); + bool at_setapn_wnc(const char * const apnStr); + bool at_sendSMStext_wnc(const char * const phoneNum, const char * const text); + bool at_get_wnc_net_stats(WncIpStats * s); + bool at_readSMSlog_wnc(string ** log); + size_t at_readSMStext_wnc(const char ** log); + size_t at_readSMStext_wnc(const char n, const char ** log); + bool at_getrssiber_wnc(int16_t * dBm, int16_t * ber3g); + void closeOpenSocket(uint16_t numSock); + bool sockWrite(const uint8_t * const s, uint16_t n, uint16_t numSock, bool isTcp); + bool at_sendSMStextMem_wnc(char n); + bool at_deleteSMSTextFromMem_wnc(char n); + bool at_saveSMStext_wnc(const char * const phoneNum, const char * const text, char * msgIdx); + size_t at_getSignalQuality_wnc(const char ** log); + bool at_gettimedate_wnc(struct WncDateTime * tod); + bool at_ping_wnc(const char * ip); + bool at_geticcid_wnc(string * iccid); + + // Utility methods + void sendCmd(const char * cmd, bool crLf); + void sendCmd(const char * cmd, unsigned n, unsigned wait_uS, bool crLf); + inline void rx_char_wait(void) { + // waitUs(1000); + } + + // Important constants + static const uint16_t MAX_WNC_READ_BYTES = 1500; // This bounds the largest amount of data that the WNC read from a socket will return + static const uint16_t MAX_WNC_WRITE_BYTES = MAX_WNC_READ_BYTES; // This is the largest amount of data that the WNC can write per sockwrite. + static const uint16_t MAX_LEN_WNC_CMD_RESPONSE = (MAX_WNC_READ_BYTES * 2 + 100); // Max number of text characters in a WNC AT response *2 because bytes are converted into 2 hex-digits +100 for other AT@ chars. + static const uint16_t WNC_AUTO_POLL_MS = 250; // Sets default (may be overriden with method) poll interval (currently not used, future possible feature. + static const uint16_t WNC_CMD_TIMEOUT_MS = 40000; // Sets default (may be overriden) time that the software waits for an AT response from the WNC. + static const uint16_t WNC_QUICK_CMD_TIMEOUT_MS = 2000; // Used for simple commands that should immediately respond such as "AT", cmds that are quicker than WNC_CMD_TIMEOUT_MS. + static const uint16_t WNC_WAIT_FOR_AT_CMD_MS = 0; // Wait this much between multiple in a row AT commands to the WNC. + static const uint16_t WNC_SOFT_INIT_RETRY_COUNT = 10; // How many times the WNC will be tried to revive if it stops responding. + static const uint16_t WNC_DNS_RESOLVE_WAIT_MS = 60000; // How much time to wait for the WNC to respond to a DNS resolve/lookup. + static const uint16_t WNC_TRUNC_DEBUG_LENGTH = 80; // Always make this an even number, how many chars for the debug output before shortening the debug ouput, this is used when moreDebug = false. + static const uint16_t WNC_APNSET_TIMEOUT_MS = 60000; // How long to wait for the WNC to respond to setting the APN string. + static const uint16_t WNC_PING_CMD_TIMEOUT_MS = 60000; // Amount of time to wait for the WNC to respond to AT@PINGREQ (with cmd default params for timeout, does not change WNC cmd's timeout) + static const int WNC_REINIT_MAX_TIME_MS = 60000; // How long to wait for the WNC to reset after it was already up and running after power-up. + static const uint16_t WNC_SOCK_CLOSE_RETRY_CNT = 3; // How many times to try to close the socket if the WNC gives an error. + static const char * const INVALID_IP_STR; // Just a string set to an IP address when DNS resolve fails. + + struct WncSocketInfo_s { + int16_t numWncSock; + bool open; + string myIpAddressStr; + uint16_t myPort; + uint8_t readRetries; + uint16_t readRetryWaitMs; + bool isTcp; + uint16_t timeOutSec; + }; + + static WncSocketInfo_s m_sSock[MAX_NUM_WNC_SOCKETS]; + static const WncSocketInfo_s defaultSockStruct; + static WncState_e m_sState; + static uint16_t m_sCmdTimeoutMs; + static string m_sApnStr; + static string m_sWncStr; + static string m_FirmwareRevision; + static uint8_t m_sPowerUpTimeoutSecs; + static bool m_sDebugEnabled; + static bool m_sMoreDebugEnabled; + static bool m_sCheckNetStatus; + static bool m_sReadyForSMS; +}; + +}; // End namespace WncController_fk + +#endif +
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/WNC14A2AInterface/WncControllerK64F/WncControllerK64F.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/WNC14A2AInterface/WncControllerK64F/WncControllerK64F.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,206 @@ +/* + Copyright (c) 2016 Fred Kellerman + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file WncControllerK64F.cpp + @purpose Contains K64F and mbed specifics to control the WNC modem using the WncController base class. + @version 1.0 + @date July 2016 + @author Fred Kellerman +*/ + +#include "WncControllerK64F.h" + +using namespace WncControllerK64F_fk; + +WncControllerK64F::WncControllerK64F(struct WncGpioPinListK64F * pPins, WncIO * wnc_uart, WNCDebug * debug_uart) +{ + m_logTimer.start(); // Start the log timer now! + m_pDbgUart = debug_uart; + m_pWncUart = wnc_uart; + m_gpioPinList = *pPins; +} + +bool WncControllerK64F::enterWncTerminalMode(WncIO * pUart, bool echoOn) +{ + if (pUart == NULL) + return (false); // Need a uart! + + string * resp; + AtCmdErr_e r = sendWncCmd("AT", &resp, 500); + if (r == WNC_AT_CMD_TIMEOUT) + return (false); + + pUart->puts("\r\nEntering WNC Terminal Mode - press <CTRL>-Q to exit!\r\n"); + + while (1) { + if (pUart->readable()) { + char c = pUart->getc(); + if (c == '\x11') { + pUart->puts("\r\nExiting WNC Terminal Mode!\r\n"); + // Cleanup in case user doesn't finish command: + sendWncCmd("AT", &resp, 300); + // Above AT may fail but should get WNC back in sync + return (sendWncCmd("AT", &resp, 500) == WNC_AT_CMD_OK); + } + if (echoOn == true) { + pUart->putc(c); + } + m_pWncUart->putc(c); + } + if (m_pWncUart->readable()) + pUart->putc(m_pWncUart->getc()); + } +} + +int WncControllerK64F::putc(char c) +{ + return (m_pWncUart->putc(c)); +} + +int WncControllerK64F::puts(const char * s) +{ + return (m_pWncUart->puts(s)); +} + +char WncControllerK64F::getc(void) +{ + return (m_pWncUart->getc()); +} + +int WncControllerK64F::charReady(void) +{ + return (m_pWncUart->readable()); +} + +int WncControllerK64F::dbgWriteChar(char b) +{ + if (m_pDbgUart != NULL) + return (m_pDbgUart->putc(b)); + else + return (0); +} + +int WncControllerK64F::dbgWriteChars(const char * b) +{ + if (m_pDbgUart != NULL) + return (m_pDbgUart->puts(b)); + else + return (0); +} + +bool WncControllerK64F::initWncModem(uint8_t powerUpTimeoutSecs) +{ + // Hard reset the modem (doesn't go through + // the signal level translator) + *m_gpioPinList.mdm_reset = 0; + + // disable signal level translator (necessary + // for the modem to boot properly). All signals + // except mdm_reset go through the level translator + // and have internal pull-up/down in the module. While + // the level translator is disabled, these pins will + // be in the correct state. + *m_gpioPinList.shield_3v3_1v8_sig_trans_ena = 0; + + // While the level translator is disabled and ouptut pins + // are tristated, make sure the inputs are in the same state + // as the WNC Module pins so that when the level translator is + // enabled, there are no differences. + *m_gpioPinList.mdm_uart2_rx_boot_mode_sel = 1; // UART2_RX should be high + *m_gpioPinList.mdm_power_on = 0; // powr_on should be low + *m_gpioPinList.mdm_wakeup_in = 1; // wake-up should be high + *m_gpioPinList.mdm_uart1_cts = 0; // indicate that it is ok to send + + // Now, wait for the WNC Module to perform its initial boot correctly + waitMs(1000); + + // The WNC module initializes comms at 115200 8N1 so set it up + m_pWncUart->baud(115200); + + //Now, enable the level translator, the input pins should now be the + //same as how the M14A module is driving them with internal pull ups/downs. + //When enabled, there will be no changes in these 4 pins... + *m_gpioPinList.shield_3v3_1v8_sig_trans_ena = 1; + + bool res = waitForPowerOnModemToRespond(powerUpTimeoutSecs); + + // Toggle wakeup to prevent future dropped 'A' of "AT", this was + // suggested by ATT. + if (res == true) { + dbgPuts("\r\nToggling Wakeup..."); + waitMs(20); + *m_gpioPinList.mdm_wakeup_in = 0; + waitMs(2000); + *m_gpioPinList.mdm_wakeup_in = 1; + waitMs(20); + dbgPuts("Toggling complete."); + } + + return (res); +} + +void WncControllerK64F::waitMs(int t) +{ + wait_ms(t); +} + +void WncControllerK64F::waitUs(int t) +{ + wait_ms(t); +} + +int WncControllerK64F::getLogTimerTicks(void) +{ + return (m_logTimer.read_us()); +} + +void WncControllerK64F::startTimerA(void) +{ + m_timerA.start(); + m_timerA.reset(); +} + +void WncControllerK64F::stopTimerA(void) +{ + m_timerA.stop(); +} + +int WncControllerK64F::getTimerTicksA_mS(void) +{ + return (m_timerA.read_ms()); +} + +void WncControllerK64F::startTimerB(void) +{ + m_timerB.start(); + m_timerB.reset(); +} + +void WncControllerK64F::stopTimerB(void) +{ + m_timerB.stop(); +} + +int WncControllerK64F::getTimerTicksB_mS(void) +{ + return (m_timerB.read_ms()); +} +
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/WNC14A2AInterface/WncControllerK64F/WncControllerK64F.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/WNC14A2AInterface/WncControllerK64F/WncControllerK64F.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,131 @@ +/* + Copyright (c) 2016 Fred Kellerman + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + @file WncControllerK64F.h + @purpose Contains K64F and mbed specifics to control the WNC modem using the WncController base class. + @version 1.0 + @date July 2016 + @author Fred Kellerman +*/ + +#ifndef __WNCCONTROLLERK64F_H_ +#define __WNCCONTROLLERK64F_H_ + +#include <string> +#include <stdint.h> +#include "mbed.h" +#include "WNCDebug.h" +#include "WNCIO.h" +#include "WncController.h" + +namespace WncControllerK64F_fk { + +using namespace WncController_fk; +using namespace std; + +/** List of K64F pins that are used to control and setup the ATT IoT Kit WNC Shield */ +struct WncGpioPinListK64F { + ///////////////////////////////////////////////////// + // NXP GPIO Pins that are used to initialize the WNC Shield + ///////////////////////////////////////////////////// + DigitalOut * mdm_uart2_rx_boot_mode_sel; // on powerup, 0 = boot mode, 1 = normal boot + DigitalOut * mdm_power_on; // 0 = turn modem on, 1 = turn modem off (should be held high for >5 seconds to cycle modem) + DigitalOut * mdm_wakeup_in; // 0 = let modem sleep, 1 = keep modem awake -- Note: pulled high on shield + DigitalOut * mdm_reset; // active high + DigitalOut * shield_3v3_1v8_sig_trans_ena; // 0 = disabled (all signals high impedence, 1 = translation active + DigitalOut * mdm_uart1_cts; +}; + + +/** + * @author Fred Kellerman + * @see API + * + * <b>WncControllerK64F</b> This mbed C++ class is for controlling the WNC + * Cellular modem from the NXP K64F Freedom board. It uses the control code + * from it's base class WncController to handle the WNC Modem AT cmds. This + * class fulfills various pure virtual methods of the base class. The point of + * this class is to have the platform specific code in it thus isolating the + * control code logic from any particular platform or OS. + */ +class WncControllerK64F : public WncController +{ +public: + + /** + * + * Sets up the resources to control the WNC modem shield. + * @ingroup API + * @param pPins - pointer to a list of K64F pins that are used to setup and control the ATT IoT Kit's WNC Shield. + * @param wnc_uart - a pointer to the serial uart that is used to communicate with the WNC modem. + * @param debug_uart - a pointer to a serial uart for the debug output to go out of, if NULL debug will not be output. + */ + WncControllerK64F(struct WncGpioPinListK64F * pPins, WncIO * wnc_uart, WNCDebug * debug_uart = NULL); + + /** + * + * Activates a mode where the user can send text to and from the K64F + * debug Serial port directly to the WNC. The mode is entered via this + * call. The mode is exited when the user types CTRL-Q. While in this + * mode all text to and from the WNC is consumed by the debug Serial port. + * No other methods in the class will receive any of the WNC output. + * @ingroup API + * @param pUart - a pointer to a uart to use to collect the user input and put the output from the WNC. + * @param echoOn - set to true to echo what is input back to the output of pUart. + */ + bool enterWncTerminalMode(WncIO *pUart, bool echoOn); + +private: + + // Disallow copy + WncControllerK64F operator=(WncControllerK64F lhs); + + // Users must define these functionalities: + virtual int putc(char c); + virtual int puts(const char * s); + virtual char getc(void); + virtual int charReady(void); + virtual int dbgWriteChar(char b); + virtual int dbgWriteChars(const char *b); + virtual bool initWncModem(uint8_t powerUpTimeoutSecs); + virtual void waitMs(int t); + virtual void waitUs(int t); + + virtual int getLogTimerTicks(void); + virtual void startTimerA(void); + virtual void stopTimerA(void); + virtual int getTimerTicksA_mS(void); + virtual void startTimerB(void); + virtual void stopTimerB(void); + virtual int getTimerTicksB_mS(void); + + WNCDebug * m_pDbgUart; + WncIO * m_pWncUart; + WncGpioPinListK64F m_gpioPinList; + Timer m_logTimer; + Timer m_timerA; + Timer m_timerB; +}; + +}; // End namespace WncController_fk + +#endif +
diff -r 000000000000 -r 119624335925 easy-connect/wnc14a2a-driver/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wnc14a2a-driver/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,13 @@ +{ + "name": "wnc14a2a-library", + "config": { + "wnc-debug": { + "help" : "enable or disable WNC debug messages.", + "value": "false" + }, + "wnc-debug_setting": { + "help" : "bit value 1 and/or 2 enable WncController debug output, bit value 4 enables mbed driver debug output.", + "value": "4" + } + } +}
diff -r 000000000000 -r 119624335925 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,267 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "mbed.h" +#include "mbed-trace/mbed_trace.h" +#include "mbed-trace-helper.h" +#include "simple-mbed-cloud-client.h" +#include "key-config-manager/kcm_status.h" +#include "key-config-manager/key_config_manager.h" +#include "SDBlockDevice.h" +#include "FATFileSystem.h" +//#include "ESP8266Interface.h" +#include "easy-connect.h" +#include "MMA7660.h" +#include "LM75B.h" + +/* The following app uses Mbed Cloud with SD Card storage, button, & led */ + +// Placeholder to hardware that trigger events (timer, button, etc) +//Ticker timer; +/* K64 & K66 */ +InterruptIn sw2(SW2); +DigitalOut led2(LED2); +//ESP8266Interface net(D1, D0); +NetworkInterface *net; + +/* */ + +// Placeholder for storage +/* K64 & K66 */ +SDBlockDevice sd(PTE3, PTE1, PTE2, PTE4); +FATFileSystem fs("sd"); +/* */ + +// Pointers to the resources that will be created in main_application(). +static MbedCloudClientResource* pattern_ptr; +static MbedCloudClientResource* button_ptr; + +// Pointer to mbedClient, used for calling close function. +static SimpleMbedCloudClient *client; + +static bool button_pressed = false; +static int button_count = 0; + +void button_press() { + button_pressed = true; + ++button_count; + button_ptr->set_value(button_count); +} + +void pattern_updated(const char *) { + printf("PUT received, new value: %s\n", pattern_ptr->get_value().c_str()); + // Placeholder for PUT action +} + +void blink_callback(void *) { + String pattern_str = pattern_ptr->get_value(); + const char *pattern = pattern_str.c_str(); + printf("POST received. LED pattern = %s\n", pattern); + // Placeholder for POST action + // The pattern is something like 500:200:500, so parse that. + // LED blinking is done while parsing. + + while (*pattern != '\0') { + //make a short blink on the led + led2 = 0; + wait_ms(20); + led2 = 1; + // Wait for requested time. + wait_ms(atoi(pattern)); + // Search for next value. + pattern = strchr(pattern, ':'); + if(!pattern) { + //we're done, give one last blink to end the pattern + led2 = 0; + wait_ms(20); + led2 = 1; + break; // while + } + pattern++; + } +} + +void button_callback(const M2MBase& object, const NoticationDeliveryStatus status) +{ + printf("Button notification. Callback: (%s)\n", object.uri_path()); + // Placeholder for GET +} + +void accel_callback(const M2MBase& object, const NoticationDeliveryStatus status) +{ + // Do nothing. +} + +void temp_callback(const M2MBase& object, const NoticationDeliveryStatus status) +{ + // Do nothing. +} + + + + +int main(void) +{ + // Requires DAPLink 245+ (https://github.com/ARMmbed/DAPLink/pull/364) + // Older versions: workaround to prevent possible deletion of credentials: + wait(2); + + // Misc OS setup + srand(time(NULL)); + + printf("Start Simple Mbed Cloud Client\n"); + + // Initialize SD card + int status = sd.init(); + if (status != BD_ERROR_OK) { + printf("Failed to init SD card\r\n"); + return -1; + } + + // Mount the file system (reformatting on failure) + status = fs.mount(&sd); + if (status) { + printf("Failed to mount FAT file system, reformatting...\r\n"); + status = fs.reformat(&sd); + if (status) { + printf("Failed to reformat FAT file system\r\n"); + return -1; + } else { + printf("Reformat and mount complete\r\n"); + } + } + + printf("Connecting to the network using Wi-Fi...\n"); + + net = easy_connect(true); +// status = net.connect(WIFI_SSID, WIFI_PSWD, NSAPI_SECURITY_WPA_WPA2); + + SimpleMbedCloudClient mbedClient(net); + // Save pointer to mbedClient so that other functions can access it. + client = &mbedClient; + + status = mbedClient.init(); + if (status) { + return -1; + } + + printf("Client initialized\r\n"); + + // Mbed Cloud Client resource setup + MbedCloudClientResource *button = mbedClient.create_resource("3200/0/5501", "button_resource"); + button->set_value("0"); + button->methods(M2MMethod::GET); + button->observable(true); + button->attach_notification_callback(button_callback); + button_ptr = button; + + MbedCloudClientResource *pattern = mbedClient.create_resource("3201/0/5853", "pattern_resource"); + pattern->set_value("500:500:500:500"); + pattern->methods(M2MMethod::GET | M2MMethod::PUT); + pattern->attach_put_callback(pattern_updated); + pattern_ptr = pattern; + + MbedCloudClientResource *blink = mbedClient.create_resource("3201/0/5850", "blink_resource"); + blink->methods(M2MMethod::POST); + blink->attach_post_callback(blink_callback); + + /* Accelerometer */ + const int NUM_AXIS = 3; + MbedCloudClientResource* accel[NUM_AXIS]; + accel[0] = mbedClient.create_resource("3313/0/5702", "accel_x"); + accel[1] = mbedClient.create_resource("3313/0/5703", "accel_y"); + accel[2] = mbedClient.create_resource("3313/0/5704", "accel_z"); + for (int i=0; i < NUM_AXIS; i++) { + accel[i]->set_value(0); + accel[i]->methods(M2MMethod::GET); + accel[i]->attach_notification_callback(accel_callback); + accel[i]->observable(true); + } + MbedCloudClientResource* acc_unit = mbedClient.create_resource("3313/0/5701", "unit"); + acc_unit->set_value("G"); + + /* Temperature */ + MbedCloudClientResource *temp = mbedClient.create_resource("3303/0/5700", "temperature"); + temp->set_value("0"); + temp->methods(M2MMethod::GET); + temp->attach_notification_callback(temp_callback); + temp->observable(true); + MbedCloudClientResource *temp_unit = mbedClient.create_resource("3303/0/5701", "unit"); + temp_unit->set_value("Cel"); + + mbedClient.register_and_connect(); + + printf("Waiting for register and connect "); + // Wait for client to finish registering + while (!mbedClient.is_client_registered()) { + printf("."); + wait_ms(500); + } + printf("\n\n"); + + // Placeholder for callback to update local resource when GET comes. + //timer.attach(&button_press, 5.0); + sw2.mode(PullUp); + sw2.fall(button_press); + button_count = 0; + + // For sensors + LM75B lm75b(I2C_SDA, I2C_SCL); // temperature + MMA7660 mma7660(I2C_SDA, I2C_SCL); // accel + + const long measurementPeriod = 5; // sec + Timer timer; + timer.start(); + + + // Check if client is registering or registered, if true sleep and repeat. + while (mbedClient.is_register_called()) { + //static int button_count = 0; + + wait_ms(100); + + if (button_pressed) { + button_pressed = false; + //printf("button clicked %d times\r\n", ++button_count); + //button->set_value(button_count); + printf("button clicked %d times\r\n", button_count); + } + if( timer.read() > measurementPeriod) { + timer.reset(); + float temperature, acc[3]; + const unsigned int buf_size = 20; + char buf[buf_size]; + + + mma7660.readData(acc); + for(int i=0; i < NUM_AXIS; i++) { + snprintf(buf, buf_size, "%f", acc[i]); + accel[i]->set_value(buf); + } + printf("acc: %f,%f,%f\n", acc[0], acc[1], acc[2]); + + temperature = lm75b.read(); + snprintf(buf, buf_size, "%f", temperature); + temp->set_value(buf); + printf("temp: %s\n", buf); + } + + } + // Client unregistered, exit program. + return 0; +}
diff -r 000000000000 -r 119624335925 mbed-os.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#caeaa49d68c67ee00275cece10cd88e0ed0f6ed3
diff -r 000000000000 -r 119624335925 mbed_app.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed_app.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +{ + "macros": [ + "MBEDTLS_USER_CONFIG_FILE=\"mbedTLSConfig_mbedOS.h\"", + "MBED_CLIENT_USER_CONFIG_FILE=\"mbed_cloud_client_user_config.h\"", + "MBED_CLOUD_CLIENT_USER_CONFIG_FILE=\"mbed_cloud_client_user_config.h\"", + "PAL_DTLS_PEER_MIN_TIMEOUT=5000", + "MBED_CONF_APP_MAIN_STACK_SIZE=4608" + ], + "target_overrides": { + "*": { + "target.features_add": ["NANOSTACK", "LOWPAN_ROUTER", "COMMON_PAL"], + "platform.stdio-baud-rate": 115200, + "platform.stdio-convert-newlines": true, + "mbed-trace.enable": null + } + }, + "config": { + "developer-mode": { + "help": "Enable Developer mode to skip Factory enrollment", + "value": 1 + }, + "network-interface":{ + "help": "options are ETHERNET, WIFI_ESP8266, WIFI_IDW0XX1, WIFI_ODIN, WIFI_RTW, WIFI_WIZFI310, WIFI_ISM43362, MESH_LOWPAN_ND, MESH_THREAD, CELLULAR_ONBOARD", + "value": "WIFI_ESP8266" + }, + "wifi-ssid": { + "value": "\"SSID\"" + }, + "wifi-password": { + "value": "\"PASSWORD\"" + } + } +}
diff -r 000000000000 -r 119624335925 mbed_cloud_client_user_config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed_cloud_client_user_config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// This file is a template and it's intented to be copied to the application +// Enable this configuration + +#ifndef MBED_CLOUD_CLIENT_USER_CONFIG_H +#define MBED_CLOUD_CLIENT_USER_CONFIG_H + + +#define MBED_CLOUD_CLIENT_ENDPOINT_TYPE "default" + +// Enable either TCP or UDP, but no both +#define MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP +// MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP + +#define MBED_CLOUD_CLIENT_LIFETIME 3600 + +#define MBED_CLOUD_CLIENT_SUPPORT_UPDATE +#define SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE 1024 + +// set flag to enable update support in mbed Cloud client +#define MBED_CLOUD_CLIENT_SUPPORT_UPDATE + +// set download buffer size in bytes (min. 1024 bytes) + +// Use larger buffers in Linux // +#ifdef __linux__ +#define MBED_CLOUD_CLIENT_UPDATE_BUFFER (2 * 1024 * 1024) +#else +#define MBED_CLOUD_CLIENT_UPDATE_BUFFER 2048 +#endif + +// Developer flags for Update feature +#if MBED_CONF_APP_DEVELOPER_MODE == 1 + #define MBED_CLOUD_DEV_UPDATE_CERT + #define MBED_CLOUD_DEV_UPDATE_ID +#endif // MBED_CONF_APP_DEVELOPER_MODE + +#endif // MBED_CLOUD_CLIENT_USER_CONFIG_H +
diff -r 000000000000 -r 119624335925 mbed_cloud_dev_credentials.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed_cloud_dev_credentials.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __MBED_CLOUD_DEV_CREDENTIALS_H__ +#define __MBED_CLOUD_DEV_CREDENTIALS_H__ + +#if MBED_CONF_APP_DEVELOPER_MODE == 1 +#error "Replace mbed_cloud_dev_credentials.c with your own developer cert." +#endif + +#include <inttypes.h> + +const char MBED_CLOUD_DEV_BOOTSTRAP_ENDPOINT_NAME[] = ""; +const char MBED_CLOUD_DEV_ACCOUNT_ID[] = ""; +const char MBED_CLOUD_DEV_BOOTSTRAP_SERVER_URI[] = ""; + +const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE[] = +{ 0x0 }; + +const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE[] = +{ 0x0 }; + +const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY[] = +{ 0x0 }; + +const char MBED_CLOUD_DEV_MANUFACTURER[] = "dev_manufacturer"; + +const char MBED_CLOUD_DEV_MODEL_NUMBER[] = "dev_model_num"; + +const char MBED_CLOUD_DEV_SERIAL_NUMBER[] = "0"; + +const char MBED_CLOUD_DEV_DEVICE_TYPE[] = "dev_device_type"; + +const char MBED_CLOUD_DEV_HARDWARE_VERSION[] = "dev_hardware_version"; + +const uint32_t MBED_CLOUD_DEV_MEMORY_TOTAL_KB = 0; +const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE_SIZE = sizeof(MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE); +const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE_SIZE = sizeof(MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE); +const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY_SIZE = sizeof(MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY); + +#endif //__MBED_CLOUD_DEV_CREDENTIALS_H__
diff -r 000000000000 -r 119624335925 mbed_settings.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed_settings.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,45 @@ +""" +mbed SDK +Copyright (c) 2016 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from os.path import join, abspath, dirname + +#ROOT = abspath(join(dirname(__file__), ".")) + +############################################################################## +# Build System Settings +############################################################################## +#BUILD_DIR = abspath(join(ROOT, "build")) + +# ARM +#ARM_PATH = "C:/Program Files/ARM" + +# GCC ARM +#GCC_ARM_PATH = "" + +# GCC CodeRed +#GCC_CR_PATH = "C:/code_red/RedSuite_4.2.0_349/redsuite/Tools/bin" + +# IAR +#IAR_PATH = "C:/Program Files (x86)/IAR Systems/Embedded Workbench 7.0/arm" + +# Goanna static analyser. Please overload it in private_settings.py +#GOANNA_PATH = "c:/Program Files (x86)/RedLizards/Goanna Central 3.2.3/bin" + +#BUILD_OPTIONS = [] + +# mbed.org username +#MBED_ORG_USER = ""
diff -r 000000000000 -r 119624335925 sd-driver.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/sd-driver/#f4ab55df7768cfcb049b522bebd30218ee729c81
diff -r 000000000000 -r 119624335925 sd-driver/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +f4ab55df7768cfcb049b522bebd30218ee729c81
diff -r 000000000000 -r 119624335925 sd-driver/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +f1bb57ae79bde0743dba046415e86b3201fd8fcf
diff -r 000000000000 -r 119624335925 sd-driver/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/sd-driver/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 sd-driver/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 sd-driver/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 sd-driver/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 sd-driver/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 sd-driver/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 sd-driver/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 sd-driver/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 sd-driver/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 sd-driver/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 sd-driver/.git/index Binary file sd-driver/.git/index has changed
diff -r 000000000000 -r 119624335925 sd-driver/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 sd-driver/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 f1bb57ae79bde0743dba046415e86b3201fd8fcf www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322656 +0000 clone: from https://github.com/ARMmbed/sd-driver/ +f1bb57ae79bde0743dba046415e86b3201fd8fcf f4ab55df7768cfcb049b522bebd30218ee729c81 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322657 +0000 checkout: moving from master to f4ab55df7768cfcb049b522bebd30218ee729c81
diff -r 000000000000 -r 119624335925 sd-driver/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 f1bb57ae79bde0743dba046415e86b3201fd8fcf www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322656 +0000 clone: from https://github.com/ARMmbed/sd-driver/
diff -r 000000000000 -r 119624335925 sd-driver/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 f1bb57ae79bde0743dba046415e86b3201fd8fcf www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322656 +0000 clone: from https://github.com/ARMmbed/sd-driver/
diff -r 000000000000 -r 119624335925 sd-driver/.git/objects/pack/pack-1924ecb08a75de6dd76446df872f514956b02ad5.idx Binary file sd-driver/.git/objects/pack/pack-1924ecb08a75de6dd76446df872f514956b02ad5.idx has changed
diff -r 000000000000 -r 119624335925 sd-driver/.git/objects/pack/pack-1924ecb08a75de6dd76446df872f514956b02ad5.pack Binary file sd-driver/.git/objects/pack/pack-1924ecb08a75de6dd76446df872f514956b02ad5.pack has changed
diff -r 000000000000 -r 119624335925 sd-driver/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,16 @@ +# pack-refs with: peeled +552cd87e6bfd4eeee2c4a26c780da7930c9d3ea4 refs/remotes/origin/JoelHGoodman-patch-1 +685e971c9e7b65af862d47b40e34199317086aad refs/remotes/origin/g-fix-travis +a8c4401a95acd09f2d1342ff43747bef7d8c7145 refs/remotes/origin/jankii-spi-pins +f1bb57ae79bde0743dba046415e86b3201fd8fcf refs/remotes/origin/master +06f562552f44561dae1a6e87b658990b1ee7869c refs/remotes/origin/modules_update +c5a1a88f9ef53c6bca5127acd09393a61b753a13 refs/tags/sd-driver-0.0.1-mbed-os-5.3.4 +^50dd8c39836ccbcd9c1ef7161d88ddc39a0bcaed +b2fb4883764ebd0aa8de63a4490db38692c80b8e refs/tags/sd-driver-0.0.2-mbed-os-5.4.0 +290050ab9847aea143c79b61eca9dec25373754d refs/tags/sd-driver-0.0.3-mbed-os-5.4.1 +^a8c85d30af86a7431d85dee02d133d60dd386406 +88b60ecb5b7cee41b07fbb6bcab82d347a636745 refs/tags/sd-driver-0.1.0-mbed-os-5.5.1 +^29861960ca60298e884e86b89e878b1371209e0b +2d247581c6fd9fdfd641cff3ecc2d9c4192236bd refs/tags/sd-driver-0.1.1-mbed-os-5.5.4 +ae7e7440054c9447f8255bdccbcc523b3f6dffe4 refs/tags/sd-driver-0.1.2-mbed-os-5.6.1 +48bdc8821bbfd9689a647204fdb256723ce46c04 refs/tags/sd-driver-0.1.3-mbed-os-5.8.0
diff -r 000000000000 -r 119624335925 sd-driver/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +f1bb57ae79bde0743dba046415e86b3201fd8fcf
diff -r 000000000000 -r 119624335925 sd-driver/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 sd-driver/.travis.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/.travis.yml Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +script: + # Check that examples compile + - sed -n '/``` cpp/,${/```$/q;/```/d;p}' README.md > main.cpp && + PYTHONPATH=mbed-os python mbed-os/tools/make.py -t GCC_ARM -m K64F + --source=. --build=BUILD/K64F/GCC_ARM -j0 && + rm main.cpp + + # Check that tests compile + - rm -rf BUILD && PYTHONPATH=mbed-os python mbed-os/tools/test.py + -t GCC_ARM -m K64F --source=. --build=BUILD/TESTS/K64F/GCC_ARM -j0 + -n tests* + +python: + - "2.7" + +install: + # Get arm-none-eabi-gcc + - sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded + - sudo apt-get update -qq + - sudo apt-get install -qq gcc-arm-none-eabi --force-yes + # Get dependencies + - git clone https://github.com/armmbed/mbed-os.git + # Install python dependencies + - pip install --user -r mbed-os/requirements.txt
diff -r 000000000000 -r 119624335925 sd-driver/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability.
diff -r 000000000000 -r 119624335925 sd-driver/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,612 @@ +# mbed OS SDCard Driver (sd-driver) for FAT32 Filesystem Support + + +Simon Hughes + +20170329 + +Version 0.1.2 + + +# Executive Summary + +The purpose of this document is to describe how to use the mbed OS SDCard +driver (sd-driver) so applications can read/write +data to flash storage cards using the standard POSIX File API +programming interface. The sd-driver uses the SDCard SPI-mode of operation +which is a subset of possible SDCard functionality. + +This repository contains the mbed-os SDCard driver for generic SPI +SDCard support and other resources, as outlined below: + +- `SDBlockDevice.h` and `SDBlockDevice.cpp`. This is the SDCard driver module presenting + a Block Device API (derived from BlockDevice) to the underlying SDCard. +- POSIX File API test cases for testing the FAT32 filesystem on SDCard. + - basic.cpp, a basic set of functional test cases. + - fopen.cpp, more functional tests reading/writing greater volumes of data to SDCard, for example. +- `mbed_lib.json` mbed-os application configuration file with SPI pin configurations for the CI shield and overrides for specific targets. + This file allows the SPI pins to be specified for the target without having to edit the implementation files. +- This README which includes [Summary of POSIX File API Documentation](#summary-posix-api-documentation) + including detailed instruction on how to use the FAT filesystem and SDBlockDevice driver. + +The SDCard driver is maintained in this repository as a component separate from the main mbed OS repository. +Hence the 2 repositories (mbed-os and sd-driver) have to be used together +to deliver the FAT32 Filesystem/SDCard support. This document explains how to do this. + + +# Introduction + +### Overview + +The scope of this document is to describe how applications use the FAT filesystem and sd-driver +components to persistently store data on SDCards. The document is intended to help developers adopt the +mbed OS POSIX File API support, and in particular to help explain: + +- How the software components work together to deliver the storage functionality. +- How to work with the sd-driver and mbed OS to build the examples. The example code can easily + be copied into your new application code. +- How to work with the CI Test Shield, which adds an SDCard slot to those targets that do not have already have one. +- How to run the POSIX File API mbed Greentea test cases, which provide further example code of how to use + the POSIX File API. + +Section 1 provides an Executive Summary, describing the purpose of the sd-driver, the supporting +software, examples, test cases and documentation. + +Section 2 provides an an overview of the material covered including descriptions of the major sections. + +Section 3 provides an overview of the mbed OS filesystem software components, +including the inter-relationships between the application, POSIX file API, the standard c-library, +the mbed OS filesystem and the SDCard driver (sd-driver). + +Section 4 describes how to build and run an example application for reading +and writing data to an SDCard using the POSIX File API. The example begins by describing +the procedure for building and testing on the K64F target. The final sub-sections +describe how to use the test shield to add an SDCard slot to any mbed target, +and hence enable the persistent storage of data on any supported target. + +Section 5 describes an example application which uses the raw +BlockDevice API to read and write data to the SDCard. + +Section 6 describes how to build and run the SDCard POSIX File API mbed Greentea test cases. +There are a number of functional test cases demonstrating how to use the +mbed OS POSIX File API. + +Section 7 describes the POSIX File API and provides links to useful API documentation web pages. + + +### Known mbed-os and sd-driver Compatible Versions + +The following versions of the mbed-os and sd-driver repositories are known to work together: + +- {mbed-os, sd-driver} = {mbed-os-5.4.0-rc2, sd-driver-0.0.1-mbed-os-5.4.0-rc2}. + `K64F`, `NUCLEO_F429ZI` and `UBLOX_EVK_ODIN_W2` fopen and basic filesystem tests working. +- {mbed-os, sd-driver} = {mbed-os-5.4.0, sd-driver-0.0.2-mbed-os-5.4.0}. + `K64F`, `NUCLEO_F429ZI` and `UBLOX_EVK_ODIN_W2` fopen and basic filesystem tests working. +- {mbed-os, sd-driver} = {mbed-os-5.4.1, sd-driver-0.0.3-mbed-os-5.4.1}. +- {mbed-os, sd-driver} = {mbed-os-5.5.1, sd-driver-0.1.0-mbed-os-5.5.1}. +- {mbed-os, sd-driver} = {mbed-os-5.5.4, sd-driver-0.1.1-mbed-os-5.5.4}. +- {mbed-os, sd-driver} = {mbed-os-5.6.1, sd-driver-0.1.2-mbed-os-5.6.1}. + +To find the latest compatible versions, use the following command to see the messages attached to the tags +in the sd-driver repository: + + ex_app7/$ cd sd-driver + ex_app7/sd-driver$ git tag -n + sd-driver-0.0.1-mbed-os-5.3.4 Version compatible with mbed-os-5.3.4, and private_mbedos_filesystems-0.0.1-mbed-os-5.3.4. + sd-driver-0.0.2-mbed-os-5.4.0 Updated README.md to include worked exmaples and restructuring of information. + sd-driver-0.0.3-mbed-os-5.4.1 Version compatible with mbed-os-5.4.1. + sd-driver-0.1.1-mbed-os-5.5.4 Version compatible with mbed-os-5.5.4 + sd-driver-0.1.2-mbed-os-5.6.1 Version compatible with mbed-os-5.6.1 + + +### Known Issues With This Document + +There are no known issues with this document. + + +# Overview of mbed OS Filesystem Software Component Stack + + + ------------------------ + | | + | Application | // This application uses the POSIX File API + | | // to read/write data to persistent storage backends. + ------------------------ + + ------------------------ // POSIX File API (ISO). + + ------------------------ + | | + | libc | // The standard c library implementation + | | // e.g. newlib. + ------------------------ + + ------------------------ // sys_xxx equivalent API. + + ------------------------ + | | + | mbed_retarget.cpp | // Target specific mapping layer. + | | + ------------------------ + + ------------------------ // Filesystem Upper Edge API. + + ------------------------ + | | + | File System | // File system wrappers and implementation. + | | + ------------------------ + + ------------------------ // FS Lower Edge API (Block Store Interface). + + ------------------------ + | Block API | + | Device Driver | // The SDCard driver, for example. + | e.g. sd-driver | + ------------------------ + + ------------------------ // SPI.h interface. + + ------------------------ + | | + | SPI | // SPI subsystem (C++ classes and C-HAL implementation). + | | + ------------------------ + + Figure 1. mbedOS generic architecture of filesystem software stack. + +The figure above shows the mbed OS software component stack used for data +storage on SDCard: + +- At the top level is the application component which uses the standard POSIX File API + to read and write application data to persistent storage. +- The newlib standard library (libc) stdio.h interface (POSIX File API) + implementation is used as it's optimised for resource limited embedded systems. +- mbed_retarget.cpp implements the libc back-end file OS handlers and maps them + to the FileSystem. +- The File System code (hosted in mbed-os) is composed of 2 parts: + - The mbed OS file system wrapper classes (e.g. FileSystem, File, FileBase classes) + which are used to present a consistent API to the retarget module for different + (third-party) file system implementations. + - The FAT filesystem implementation code. + The [FATFS: Generic FAT File System Module](http://elm-chan.org/fsw/ff/00index_e.html) + (ChanFS) has been integrated within mbed-os. +- The Block API Device Driver. The SDCard driver is an example of a persistent storage driver. + It's maintained as a separate component from the mbed OS repository (in this repository). +- The SPI module provides the mbed OS generic SPI API. This functionality is maintained in + mbed OS. + + +# SDCard POSIX File API Example App for Reading/Writing Data + +Refer to [SD driver Example](https://github.com/ARMmbed/mbed-os-example-sd-driver) + + +### <a name="testing-with-an-sdcard-on-target-xyx"></a> Testing with an SDCard on Target XYZ + +The standard way to test is with the mbed CI Test Shield plugged into the +target board. This pin mapping for this configuration is parameterised in +the `mbed_lib.json` file. + +The following is an example of the `mbed_lib.json` file available in the repository: + + { + "config": { + "SPI_CS": "D10", + "SPI_MOSI": "D11", + "SPI_MISO": "D12", + "SPI_CLK": "D13", + "DEVICE_SPI": 1, + "FSFAT_SDCARD_INSTALLED": 1 + }, + "target_overrides": { + "DISCO_F051R8": { + "SPI_MOSI": "SPI_MOSI", + "SPI_MISO": "SPI_MISO", + "SPI_CLK": "SPI_SCK", + "SPI_CS": "SPI_CS" + }, + "KL46Z": { + "SPI_MOSI": "PTD6", + "SPI_MISO": "PTD7", + "SPI_CLK": "PTD5", + "SPI_CS": "PTD4" + }, + "K64F": { + "SPI_MOSI": "PTE3", + "SPI_MISO": "PTE1", + "SPI_CLK": "PTE2", + "SPI_CS": "PTE4" + } + } + +Note the following things about the `mbed_lib.json` file: + +- The `mbed_lib.json` file is used to define target specific symbols for the SPI pins connecting the SDCard slot to the target MCU: + - "SPI\_CS". This is the Chip Select line. + - "SPI\_MOSI". This is the Master Out Slave In data line. + - "SPI\_MISO". This is the Master In Slave Out data line. + - "SPI\_CLK". This is the serial Clock line. +- The default configuration defined in the "config" section is for the standard Arduino header pin mappings for the SPI bus. + The "config" section defines a dictionary mapping functional names to target board Arduino header pins: + - "SPI\_CS": "D10". This causes the MBED\_CONF\_APP\_SPI\_CS symbol to be defined in mbed\_config.h as D10, which is used in the filesystem test implementation. + D10 is defined in the target specific PinNames.h file. + - "SPI\_MOSI": "D11". This causes the MBED\_CONF\_APP\_SPI\_MOSI symbol to be defined in mbed\_config.h. + - "SPI\_MISO": "D12". This causes the MBED\_CONF\_APP\_SPI\_MISO symbol to be defined in mbed\_config.h. + - "SPI\_CLK": "D13". This causes the MBED\_CONF\_APP\_SPI\_CLK symbol to be defined in mbed\_config.h. +- The `"target_overrides"` section is used to override the "SPI\_xxx" symbols for specific target boards, which may have an SDCard slot, for example. + This is the case for the K64F, where the "SPI\_xxx" are mapped to the pin names for the on-board SDCard. + + ``` + "K64F": { + "SPI_MOSI": "PTE3", + "SPI_MISO": "PTE1", + "SPI_CLK": "PTE2", + "SPI_CS": "PTE4" + } + ``` +- Thus, in the absence of any target specific definitions in the `"target_overrides"` section, all boards will default to + using the Arduino header configuration. For those platforms with a `"target_overrides"` section then this configuration + will be used in preference. +- Hence in the case that you want to test a platform with an SDCard inserted into a + fitted CI test shield (rather than the on-board SDCard slot) + and there is a `"target_overrides"` section present in the `mbed_lib.json` file, you must then delete the `"target_overrides"` + section before building. This will result in the default configuration being used (suitable for the CI + Test Shield). +- Note when inserting the v1.0.0 CI Test Shield into the Arduino header of the target platform, the shield pins D0 and + D1 should be bent to be parallel to the shield PCB so they are not inserted into the Arduino header. This is because + some boards use the same UART on DAPLINK and D0/D1, which means the serial debug channel breaks and hence the mbed greentea + test suite will not work correctly. This is mainly on older ST boards and should not be a problem on + `K64F`, `NUCLEO_F429ZI` and `UBLOX_EVK_ODIN_W2`. Note also that the v2.0.0 CI Test Shield doesn't suffer from this + problem and the pins don't need to be bent. +- When inserting the SDCard into the card slot on the CI test shield, make sure the card is fully inserted. + On insertion, there should be a small clicking sound when the card registers, and the back edge of the card + should protrude no more than ~1mm over the edge of the CI test shield PCB. If the SDCard fails to register, + try gently pushing the metal flexible strip in the shape of a spade at the top edge of the SDCard metal slot + casing with a pair of tweezers, bending it a little to lower it into the slot casing. This helps with the + insertion mechanism. + +### Wiring instructions for target NUCLEO_F429ZI with CI Test Shield + + +**Figure 3. The figure shows how to connect the NUCLEO_F429ZI platform with the CI shield.** + +The above figure shows how to connect the NUCLEO_F429ZI with the v1.0.0 CI test shield. Note: + +- To get the SD Card to work with this platform the CI test shield cannot be connected directly to this board, instead follow the instructions above. +- Any SD-card adapter will work as long as you connect all the relevant pins (MOSI, MISO, SCLK, CS, 3.3V and GND) as illustrated in figure 3. +- The SDCard is fully inserted into the slot and overhangs the PCB by ~1mm. + +# SDBlockDevice Example Application + +The following sample code illustrates how to use the sd-driver Block Device API: + +``` cpp +#include "mbed.h" +#include "SDBlockDevice.h" + +// Instantiate the SDBlockDevice by specifying the SPI pins connected to the SDCard +// socket. The PINS are: +// MOSI (Master Out Slave In) +// MISO (Master In Slave Out) +// SCLK (Serial Clock) +// CS (Chip Select) +SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); +uint8_t block[512] = "Hello World!\n"; + +int main() +{ + // call the SDBlockDevice instance initialisation method. + if ( 0 != sd.init()) { + printf("Init failed \n"); + return -1; + } + printf("sd size: %llu\n", sd.size()); + printf("sd read size: %llu\n", sd.get_read_size()); + printf("sd program size: %llu\n", sd.get_program_size()); + printf("sd erase size: %llu\n", sd.get_erase_size()); + + // set the frequency + if ( 0 != sd.frequency(5000000)) { + printf("Error setting frequency \n"); + } + + if ( 0 != sd.erase(0, sd.get_erase_size())) { + printf("Error Erasing block \n"); + } + + // Write some the data block to the device + if ( 0 == sd.program(block, 0, 512)) { + // read the data block from the device + if ( 0 == sd.read(block, 0, 512)) { + // print the contents of the block + printf("%s", block); + } + } + + // call the SDBlockDevice instance de-initialisation method. + sd.deinit(); +} +``` + +# SDCard POSIX File API mbed Greentea Test Cases + +This section describes how to build and run the POSIX file API test cases. +The following steps are covered: + +- [Create the FAT/SDCard Application Project](#create-fat-sdcard-application-project). + This section describes how to git clone the mbed OS and sd-driver repositories containing the + code and test cases of interest. +- [Build the mbed OS Test Cases](#build-the-mbedos-test-cases). This section + describes how to build the mbed OS test cases. +- [Insert a microSD Card Into the K64F for Greentea Testing](#greentea-insert-sdcard-into-k64f).This section + describes how to format (if required) a microSD card prior to running the tests. +- [Run the POSIX File Test Case](#run-the-posix-file-test-cases).This section + describes how to run the POSIX file test cases. + + +### <a name="create-fat-sdcard-application-project"></a> Create the FAT/SDCard Application Project + +This section describes how to create an application project combining the mbed-os and +sd-driver repositories into a single project. +In summary the following steps will be covered in this section: + +- A top level application project directory is created. The directory name is ex_app1. +- In the ex_app1 directory, the mbed-os repository is cloned. +- In the ex_app1 directory at the same level as the mbed-os directory, the sd-driver repository is cloned. +- The `mbed_lib.json` file is copied from the `sd-driver/config/mbed_lib.json` to the ex_app1 directory. + +First create the top level application directory ex_app1 and move into it: + + shell:/d/demo_area$ mkdir ex_app1 + shell:/d/demo_area$ pushd ex_app1 + +Next, get a clone of public mbed OS repository in the following way: + + shell:/d/demo_area/ex_app1$ git clone git@github.com:/armmbed/mbed-os + <trace removed> + shell:/d/demo_area/ex_app1$ + +Next, get a clone of the sd-driver repository: + + shell:/d/demo_area/ex_app1$ git clone git@github.com:/armmbed/sd-driver + <trace removed> + shell:/d/demo_area/ex_app1$ + +Note: The `mbed_lib.json` file specifies the SPI bus pin configuration for different targets, +and is discussed in the [Testing with an SDCard on Target XYZ](#testing-with-an-sdcard-on-target-xyx) section. + +### <a name="build-the-mbedos-test-cases"></a> Build the mbed OS Test Cases + +Build the test cases for the K64F target using the following command: + + shell:/d/demo_area/ex_app1$ mbed -v test --compile -t GCC_ARM -m K64F + <trace removed> + shell:/d/demo_area/ex_app1$ + +The build trace is quite extensive but on a successful build you should see the following output at the end of the log: + + Build successes: + * K64F::GCC_ARM::MBED-BUILD + * K64F::GCC_ARM::MBED-OS-FEATURES-FEATURE_LWIP-TESTS-MBEDMICRO-NET-CONNECTIVITY + <trace removed> + * K64F::GCC_ARM::MBED-OS-FEATURES-TESTS-FILESYSTEM-FAT_FILE_SYSTEM + * K64F::GCC_ARM::MBED-OS-FEATURES-TESTS-FILESYSTEM-HEAP_BLOCK_DEVICE + * K64F::GCC_ARM::MBED-OS-FEATURES-TESTS-FILESYSTEM-UTIL_BLOCK_DEVICE + <trace removed> + * K64F::GCC_ARM::SD-DRIVER-TESTS-BLOCK_DEVICE-BASIC + * K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-BASIC + * K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-DIRS + * K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-FILES + * K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-FOPEN + * K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-PARALLEL + * K64F::GCC_ARM::SD-DRIVER-TESTS-FILESYSTEM-SEEK + + Build skips: + * K64F::GCC_ARM::MBED-OS-FEATURES-FEATURE_LWIP-TESTS-MBEDMICRO-NET-TCP_PACKET_PRESSURE + <trace removed> + + +Notice the following tests in the sd-driver tree are listed above: + +- `SD-DRIVER-TESTS-BLOCK_DEVICE-BASIC` +- `SD-DRIVER-TESTS-FILESYSTEM-BASIC` +- `SD-DRIVER-TESTS-FILESYSTEM-DIRS` +- `SD-DRIVER-TESTS-FILESYSTEM-FILES` +- `SD-DRIVER-TESTS-FILESYSTEM-FOPEN` +- `SD-DRIVER-TESTS-FILESYSTEM-PARALLEL` +- `SD-DRIVER-TESTS-FILESYSTEM-SEEK` + +The FAT32/SDCard test cases are at following locations in the source code tree: + + /d/demo_area/ex_app1/sd-driver/TESTS/filesystem/basic/basic.cpp + /d/demo_area/ex_app1/sd-driver/TESTS/filesystem/fopen/fopen.cpp + /d/demo_area/ex_app1/sd-driver/TESTS/block_device/basic/basic.cpp + /d/demo_area/ex_app1/sd-driver/TESTS/filesystem/dirs/main.cpp + /d/demo_area/ex_app1/sd-driver/TESTS/filesystem/files/main.cpp + /d/demo_area/ex_app1/sd-driver/TESTS/filesystem/parallel/main.cpp + /d/demo_area/ex_app1/sd-driver/TESTS/filesystem/seek/main.cpp + +#### <a name="settting-repos-to-compatible-versions"></a> Setting mbed-os/sd-driver Repositories To Compatible Versions + +The sd-driver master HEAD and the mbed-os master HEAD should be compatible +with one another and therefore no specific tagged versions need to be checked out. +However, in the case that you experience problems building, checkout out the compatible +tagged version of each repository, as shown below: + + shell:/d/demo_area/ex_app1$ pushd mbed-os + shell:/d/demo_area/ex_app1$ git checkout tags/mbed-os-5.4.0 + shell:/d/demo_area/ex_app1$ popd + shell:/d/demo_area/ex_app1$ pushd sd-driver + shell:/d/demo_area/ex_app1$ git checkout tags/sd-driver-0.0.2-mbed-os-5.4.0 + shell:/d/demo_area/ex_app1$ popd + +In the above: + +- `mbed-os-5.4.0` should be replaced with the latest mbed-os release tag. +- For an mbed-os release tag `mbed-os-x.y.z`, use the equivalent sd-driver tag `sd-driver-a.b.c-mbed-os-x.y.z` + where `a.b.c` is the latest version code for the `mbed-os-x.y.z` tag. + +### <a name="greentea-insert-sdcard-into-k64f"></a> Insert SDCard into K64F for Greentea Testing + +See the previous section for [Insert SDCard into K64F](#insert-sdcard-into-k64f) for details. + + +### <a name="run-the-posix-file-test-cases"></a> Run the POSIX File Test Case + +To setup for running the test cases, connect the K64F development board to your +PC using a suitable USB cable. + +All tests can be run using the following command: + + shell:/d/demo_area/ex_app1$ mbedgt -VS + <trace removed> + +However, it's possible to run a particular test case using the following form of the mbedgt command: + + shell:/d/demo_area/ex_app1$ mbedgt -VS --test-by-names=<test-name> + +The names of the tests can be listed using: + + shell:/d/demo_area/ex_app1$ mbedgt -VS --list + +For example, to run the basic test use: + + shell:/d/demo_area/ex_app1$ mbedgt -VS --test-by-names=sd-driver-tests-filesystem-basic + +To run the fopen test use: + + shell:/d/demo_area/ex_app1$ mbedgt -VS --test-by-names=sd-driver-tests-filesystem-fopen + +On a successful run, results similar to the following will be shown: + + mbedgt: test suite report: + +--------------+---------------+-------------------------------------------+--------+--------------------+-------------+ + | target | platform_name | test suite | result | elapsed_time (sec) | copy_method | + +--------------+---------------+-------------------------------------------+--------+--------------------+-------------+ + | K64F-GCC_ARM | K64F | sd-driver-features-tests-filesystem-fopen | OK | 151.46 | shell | + +--------------+---------------+-------------------------------------------+--------+--------------------+-------------+ + mbedgt: test suite results: 1 OK + mbedgt: test case report: + +--------------+---------------+------------------------------------+----------------------------------------------------------------------------------------+--------+--------+--------+--------------------+ + | target | platform_name | test suite | test case | passed | failed | result | elapsed_time (sec) | + +--------------+---------------+------------------------------------+----------------------------------------------------------------------------------------+--------+--------+--------+--------------------+ + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_01: fopen()/fwrite()/fclose() directories/file in multi-dir filepath. | 1 | 0 | OK | 7.57 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_02: fopen(r) pre-existing file try to write it. | 1 | 0 | OK | 0.2 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_03: fopen(w+) pre-existing file try to write it. | 1 | 0 | OK | 0.41 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_04: fopen() with a filename exceeding the maximum length. | 1 | 0 | OK | 0.11 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_06: fopen() with bad filenames (minimal). | 1 | 0 | OK | 0.1 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_07: fopen()/errno handling. | 1 | 0 | OK | 0.07 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_08: ferror()/clearerr()/errno handling. | 1 | 0 | OK | 0.1 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_09: ftell() handling. | 1 | 0 | OK | 0.17 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_10: remove() test. | 1 | 0 | OK | 1.28 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_11: rename(). | 1 | 0 | OK | 2.3 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_12: opendir(), readdir(), closedir() test. | 1 | 0 | OK | 3.57 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_13: mkdir() test. | 1 | 0 | OK | 1.21 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_14: stat() test. | 1 | 0 | OK | 1.47 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_15: format() test. | 1 | 0 | OK | 26.12 | + | K64F-GCC_ARM | K64F | sd-driver-tests-filesystem-fopen | FSFAT_FOPEN_TEST_16: write/check n x 25kB data files. | 1 | 0 | OK | 87.11 | + +--------------+---------------+------------------------------------+----------------------------------------------------------------------------------------+--------+--------+--------+--------------------+ + mbedgt: test case results: 15 OK + mbedgt: completed in 152.35 sec + + +# <a name="summary-posix-api-documentation"></a> Summary of POSIX File API Documentation + +### POSIX File API + +mbed OS supports a subset of the POSIX File API, as outlined below: + +- [clearerr()](https://linux.die.net/man/3/clearerr). + - STATUS: Basic testing implemented. Working. +- [fclose()](https://linux.die.net/man/3/fclose). + - STATUS: Basic testing implemented. Working. +- [ferror()](https://linux.die.net/man/3/clearerr). + - STATUS: Basic testing implemented. + - STATUS: GCC_ARM: Working. + - STATUS: ARMCC: ARMCC has problem with ferror(filep) where filep is NULL. Appears to work for non-NULL pointer. +- [fgetc()](https://linux.die.net/man/3/fgets). + - STATUS: Basic testing implemented. Working. +- [fgets()](https://linux.die.net/man/3/fgets). + - STATUS: Basic testing implemented. Working. +- [fputc()](https://linux.die.net/man/3/fputs). + - STATUS: Unknown. +- [fputs()](https://linux.die.net/man/3/fputs). + - STATUS: Basic testing implemented. Working. +- [fprintf()](https://linux.die.net/man/3/fprintf). + - STATUS: Basic testing implemented. Working. +- [fopen()](https://linux.die.net/man/3/fopen). + - STATUS: Basic testing implemented. Working. +- [freopen()](https://linux.die.net/man/3/fopen). + - STATUS: This is not tested. +- [fread()](https://linux.die.net/man/3/fread). + - STATUS: Basic testing implemented. Working. + - STATUS: n x 25kB stress test working. +- [ftell()](https://linux.die.net/man/3/ftell). + - STATUS: Basic testing implemented. Working. +- [fwrite()](https://linux.die.net/man/3/fwrite). + - STATUS: Basic testing implemented. Working. + - STATUS: n x 25kB stress test working. +- [fseek()](https://linux.die.net/man/3/fseek) + - STATUS: Basic testing implemented. Working. +- [getc()](https://linux.die.net/man/3/fgets). + - STATUS: Basic testing implemented. Working. +- [gets()](https://linux.die.net/man/3/fgets). + - STATUS: Unknown. +- [putc()](https://linux.die.net/man/3/fputs). + - STATUS: Unknown. +- [puts()](https://linux.die.net/man/3/fputs). + - STATUS: Unknown. +- [remove()](https://linux.die.net/man/3/remove) + - STATUS: Basic testing implemented. Working. +- [rewind()](https://linux.die.net/man/3/rewind). + - STATUS: Basic testing implemented. Working. +- [stat()](https://linux.die.net/man/2/stat) + - STATUS: Implemented. Working. + - STATUS: Not supported by ARMCC/IAR libc. +- [tmpfile()](https://linux.die.net/man/3/tmpfile). + - STATUS: Not implemented. +- [tmpnam()](https://linux.die.net/man/3/tmpnam). + - STATUS: Not implemented. + +Supported directory related operations are as follows: + +- [closedir()](https://linux.die.net/man/3/closedir). + - STATUS: Implemented. Working. +- [mkdir()](https://linux.die.net/man/3/mkdir). + - STATUS: Basic testing implemented. Working. +- [opendir()](https://linux.die.net/man/3/opendir). + - STATUS: Implemented. Working. +- [readdir()](https://linux.die.net/man/3/readdir). + - STATUS: Implemented. Working. +- [remove()](https://linux.die.net/man/3/remove). + - STATUS: Basic testing implemented. Working. +- [rename()](https://linux.die.net/man/3/rename). + - STATUS: Implemented. Not tested. +- [rewinddir()](https://linux.die.net/man/3/rewinddir). + - STATUS: Implemented. Found not to work. Test case not present in repo. +- [seekdir()](https://linux.die.net/man/3/seekdir). + - STATUS: Implemented. Found not to work. Test case not present in repo. +- [telldir()](https://linux.die.net/man/3/telldir). + - STATUS: Implemented. Found not to work. Test case not present in repo. + +### errno + +Basic errno reporting is supported, tested and known to be working. + + +# Related Projects Resources + +The following are related mbed storage projects and useful resources: + +- The [mbed-os](https://github.com/ARMmbed/mbed-os) main repository. +- The [mbed-os-example-fat-filesystem](https://github.com/ARMmbed/mbed-os-example-fat-filesystem) repository. + This is an example project for the mbed OS FAT filesystem. +- The [spiflash-driver](https://github.com/armmbed/spiflash-driver) repository. +- The [i2ceeprom-driver](https://github.com/ARMmbed/i2ceeprom-driver.git) repository. +- The [ci-test-shield](https://github.com/ARMmbed/ci-test-shield) repository. This is the project describing + the mbed-os Continuous Integration test shield, together with standard tests. +- The [mbed-HDK](https://github.com/ARMmbed/mbed-HDK) repository containing Hardware Development Kit resources + including the schematics for the CI test shield. +- [POSIX File Interface ISO/IEC 9899:TC2 Documentation](http://www.eng.utah.edu/~cs5785/slides-f10/n1124.pdf). +- [FATFS: Generic FAT File System Module used in mbed OS](http://elm-chan.org/fsw/ff/00index_e.html)
diff -r 000000000000 -r 119624335925 sd-driver/SDBlockDevice.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/SDBlockDevice.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1004 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Introduction + * ------------ + * SD and MMC cards support a number of interfaces, but common to them all + * is one based on SPI. Since we already have the mbed SPI Interface, it will + * be used for SD cards. + * + * The main reference I'm using is Chapter 7, "SPI Mode" of: + * http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf + * + * SPI Startup + * ----------- + * The SD card powers up in SD mode. The start-up procedure is complicated + * by the requirement to support older SDCards in a backwards compatible + * way with the new higher capacity variants SDHC and SDHC. + * + * The following figures from the specification with associated text describe + * the SPI mode initialisation process: + * - Figure 7-1: SD Memory Card State Diagram (SPI mode) + * - Figure 7-2: SPI Mode Initialization Flow + * + * Firstly, a low initial clock should be selected (in the range of 100- + * 400kHZ). After initialisation has been completed, the switch to a + * higher clock speed can be made (e.g. 1MHz). Newer cards will support + * higher speeds than the default _transfer_sck defined here. + * + * Next, note the following from the SDCard specification (note to + * Figure 7-1): + * + * In any of the cases CMD1 is not recommended because it may be difficult for the host + * to distinguish between MultiMediaCard and SD Memory Card + * + * Hence CMD1 is not used for the initialisation sequence. + * + * The SPI interface mode is selected by asserting CS low and sending the + * reset command (CMD0). The card will respond with a (R1) response. + * In practice many cards initially respond with 0xff or invalid data + * which is ignored. Data is read until a valid response is received + * or the number of re-reads has exceeded a maximim count. If a valid + * response is not received then the CMD0 can be retried. This + * has been found to successfully initialise cards where the SPI master + * (on MCU) has been reset but the SDCard has not, so the first + * CMD0 may be lost. + * + * CMD8 is optionally sent to determine the voltage range supported, and + * indirectly determine whether it is a version 1.x SD/non-SD card or + * version 2.x. I'll just ignore this for now. + * + * ACMD41 is repeatedly issued to initialise the card, until "in idle" + * (bit 0) of the R1 response goes to '0', indicating it is initialised. + * + * You should also indicate whether the host supports High Capicity cards, + * and check whether the card is high capacity - i'll also ignore this + * + * SPI Protocol + * ------------ + * The SD SPI protocol is based on transactions made up of 8-bit words, with + * the host starting every bus transaction by asserting the CS signal low. The + * card always responds to commands, data blocks and errors. + * + * The protocol supports a CRC, but by default it is off (except for the + * first reset CMD0, where the CRC can just be pre-calculated, and CMD8) + * I'll leave the CRC off I think! + * + * Standard capacity cards have variable data block sizes, whereas High + * Capacity cards fix the size of data block to 512 bytes. I'll therefore + * just always use the Standard Capacity cards with a block size of 512 bytes. + * This is set with CMD16. + * + * You can read and write single blocks (CMD17, CMD25) or multiple blocks + * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When + * the card gets a read command, it responds with a response token, and then + * a data token or an error. + * + * SPI Command Format + * ------------------ + * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC. + * + * +---------------+------------+------------+-----------+----------+--------------+ + * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 | + * +---------------+------------+------------+-----------+----------+--------------+ + * + * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95) + * + * All Application Specific commands shall be preceded with APP_CMD (CMD55). + * + * SPI Response Format + * ------------------- + * The main response format (R1) is a status byte (normally zero). Key flags: + * idle - 1 if the card is in an idle state/initialising + * cmd - 1 if an illegal command code was detected + * + * +-------------------------------------------------+ + * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle | + * +-------------------------------------------------+ + * + * R1b is the same, except it is followed by a busy signal (zeros) until + * the first non-zero byte when it is ready again. + * + * Data Response Token + * ------------------- + * Every data block written to the card is acknowledged by a byte + * response token + * + * +----------------------+ + * | xxx | 0 | status | 1 | + * +----------------------+ + * 010 - OK! + * 101 - CRC Error + * 110 - Write Error + * + * Single Block Read and Write + * --------------------------- + * + * Block transfers have a byte header, followed by the data, followed + * by a 16-bit CRC. In our case, the data will always be 512 bytes. + * + * +------+---------+---------+- - - -+---------+-----------+----------+ + * | 0xFE | data[0] | data[1] | | data[n] | crc[15:8] | crc[7:0] | + * +------+---------+---------+- - - -+---------+-----------+----------+ + */ + +/* If the target has no SPI support then SDCard is not supported */ +#ifdef DEVICE_SPI + +#include "SDBlockDevice.h" +#include "mbed_debug.h" +#include <errno.h> + +/* Required version: 5.6.1 and above */ +#if defined(MBED_MAJOR_VERSION) && MBED_MAJOR_VERSION >= 5 +#if (MBED_VERSION < MBED_ENCODE_VERSION(5,6,1)) +#error "Incompatible mbed-os version detected! Required 5.6.1 and above" +#endif +#else +#warning "mbed-os version 5.6.1 or above required" +#endif + +#define SD_COMMAND_TIMEOUT 5000 /*!< Timeout in ms for response */ +#define SD_CMD0_GO_IDLE_STATE_RETRIES 5 /*!< Number of retries for sending CMDO */ +#define SD_DBG 0 /*!< 1 - Enable debugging */ +#define SD_CMD_TRACE 0 /*!< 1 - Enable SD command tracing */ + +#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK -5001 /*!< operation would block */ +#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED -5002 /*!< unsupported operation */ +#define SD_BLOCK_DEVICE_ERROR_PARAMETER -5003 /*!< invalid parameter */ +#define SD_BLOCK_DEVICE_ERROR_NO_INIT -5004 /*!< uninitialized */ +#define SD_BLOCK_DEVICE_ERROR_NO_DEVICE -5005 /*!< device is missing or not connected */ +#define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED -5006 /*!< write protected */ +#define SD_BLOCK_DEVICE_ERROR_UNUSABLE -5007 /*!< unusable card */ +#define SD_BLOCK_DEVICE_ERROR_NO_RESPONSE -5008 /*!< No response from device */ +#define SD_BLOCK_DEVICE_ERROR_CRC -5009 /*!< CRC error */ +#define SD_BLOCK_DEVICE_ERROR_ERASE -5010 /*!< Erase error: reset/sequence */ +#define SD_BLOCK_DEVICE_ERROR_WRITE -5011 /*!< SPI Write error: !SPI_DATA_ACCEPTED */ + +#define BLOCK_SIZE_HC 512 /*!< Block size supported for SD card is 512 bytes */ +#define WRITE_BL_PARTIAL 0 /*!< Partial block write - Not supported */ +#define CRC_SUPPORT 0 /*!< CRC - Not supported */ +#define SPI_CMD(x) (0x40 | (x & 0x3f)) + +/* R1 Response Format */ +#define R1_NO_RESPONSE (0xFF) +#define R1_RESPONSE_RECV (0x80) +#define R1_IDLE_STATE (1 << 0) +#define R1_ERASE_RESET (1 << 1) +#define R1_ILLEGAL_COMMAND (1 << 2) +#define R1_COM_CRC_ERROR (1 << 3) +#define R1_ERASE_SEQUENCE_ERROR (1 << 4) +#define R1_ADDRESS_ERROR (1 << 5) +#define R1_PARAMETER_ERROR (1 << 6) + +// Types +#define SDCARD_NONE 0 /**< No card is present */ +#define SDCARD_V1 1 /**< v1.x Standard Capacity */ +#define SDCARD_V2 2 /**< v2.x Standard capacity SD card */ +#define SDCARD_V2HC 3 /**< v2.x High capacity SD card */ +#define CARD_UNKNOWN 4 /**< Unknown or unsupported card */ + +/* SIZE in Bytes */ +#define PACKET_SIZE 6 /*!< SD Packet size CMD+ARG+CRC */ +#define R1_RESPONSE_SIZE 1 /*!< Size of R1 response */ +#define R2_RESPONSE_SIZE 2 /*!< Size of R2 response */ +#define R3_R7_RESPONSE_SIZE 5 /*!< Size of R3/R7 response */ + +/* R1b Response */ +#define DEVICE_BUSY (0x00) + +/* R2 Response Format */ +#define R2_CARD_LOCKED (1 << 0) +#define R2_CMD_FAILED (1 << 1) +#define R2_ERROR (1 << 2) +#define R2_CC_ERROR (1 << 3) +#define R2_CC_FAILED (1 << 4) +#define R2_WP_VIOLATION (1 << 5) +#define R2_ERASE_PARAM (1 << 6) +#define R2_OUT_OF_RANGE (1 << 7) + +/* R3 Response : OCR Register */ +#define OCR_HCS_CCS (0x1 << 30) +#define OCR_LOW_VOLTAGE (0x01 << 24) +#define OCR_3_3V (0x1 << 20) + +/* R7 response pattern for CMD8 */ +#define CMD8_PATTERN (0xAA) + +/* CRC Enable */ +#define CRC_ENABLE (0) /*!< CRC 1 - Enable 0 - Disable */ + +/* Control Tokens */ +#define SPI_DATA_RESPONSE_MASK (0x1F) +#define SPI_DATA_ACCEPTED (0x05) +#define SPI_DATA_CRC_ERROR (0x0B) +#define SPI_DATA_WRITE_ERROR (0x0D) +#define SPI_START_BLOCK (0xFE) /*!< For Single Block Read/Write and Multiple Block Read */ +#define SPI_START_BLK_MUL_WRITE (0xFC) /*!< Start Multi-block write */ +#define SPI_STOP_TRAN (0xFD) /*!< Stop Multi-block write */ + +#define SPI_DATA_READ_ERROR_MASK (0xF) /*!< Data Error Token: 4 LSB bits */ +#define SPI_READ_ERROR (0x1 << 0) /*!< Error */ +#define SPI_READ_ERROR_CC (0x1 << 1) /*!< CC Error*/ +#define SPI_READ_ERROR_ECC_C (0x1 << 2) /*!< Card ECC failed */ +#define SPI_READ_ERROR_OFR (0x1 << 3) /*!< Out of Range */ + +SDBlockDevice::SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs, uint64_t hz) + : _sectors(0), _spi(mosi, miso, sclk), _cs(cs), _is_initialized(0) +{ + _cs = 1; + _card_type = SDCARD_NONE; + + // Set default to 100kHz for initialisation and 1MHz for data transfer + _init_sck = 100000; + _transfer_sck = hz; + + // Only HC block size is supported. + _block_size = BLOCK_SIZE_HC; + _erase_size = BLOCK_SIZE_HC; +} + +SDBlockDevice::~SDBlockDevice() +{ + if (_is_initialized) { + deinit(); + } +} + +int SDBlockDevice::_initialise_card() +{ + // Detail debugging is for commands + _dbg = SD_DBG ? SD_CMD_TRACE : 0; + int32_t status = BD_ERROR_OK; + uint32_t response, arg; + + // Initialize the SPI interface: Card by default is in SD mode + _spi_init(); + + // The card is transitioned from SDCard mode to SPI mode by sending the CMD0 + CS Asserted("0") + if (_go_idle_state() != R1_IDLE_STATE) { + debug_if(SD_DBG, "No disk, or could not put SD card in to SPI idle state\n"); + return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; + } + + // Send CMD8, if the card rejects the command then it's probably using the + // legacy protocol, or is a MMC, or just flat-out broken + status = _cmd8(); + if (BD_ERROR_OK != status && SD_BLOCK_DEVICE_ERROR_UNSUPPORTED != status) { + return status; + } + + // Read OCR - CMD58 Response contains OCR register + if (BD_ERROR_OK != (status = _cmd(CMD58_READ_OCR, 0x0, 0x0, &response))) { + return status; + } + + // Check if card supports voltage range: 3.3V + if (!(response & OCR_3_3V)) { + _card_type = CARD_UNKNOWN; + status = SD_BLOCK_DEVICE_ERROR_UNUSABLE; + return status; + } + + // HCS is set 1 for HC/XC capacity cards for ACMD41, if supported + arg = 0x0; + if (SDCARD_V2 == _card_type) { + arg |= OCR_HCS_CCS; + } + + /* Idle state bit in the R1 response of ACMD41 is used by the card to inform the host + * if initialization of ACMD41 is completed. "1" indicates that the card is still initializing. + * "0" indicates completion of initialization. The host repeatedly issues ACMD41 until + * this bit is set to "0". + */ + _spi_timer.start(); + do { + status = _cmd(ACMD41_SD_SEND_OP_COND, arg, 1, &response); + } while ((response & R1_IDLE_STATE) && (_spi_timer.read_ms() < SD_COMMAND_TIMEOUT)); + _spi_timer.stop(); + + // Initialization complete: ACMD41 successful + if ((BD_ERROR_OK != status) || (0x00 != response)) { + _card_type = CARD_UNKNOWN; + debug_if(SD_DBG, "Timeout waiting for card\n"); + return status; + } + + if (SDCARD_V2 == _card_type) { + // Get the card capacity CCS: CMD58 + if (BD_ERROR_OK == (status = _cmd(CMD58_READ_OCR, 0x0, 0x0, &response))) { + // High Capacity card + if (response & OCR_HCS_CCS) { + _card_type = SDCARD_V2HC; + debug_if(SD_DBG, "Card Initialized: High Capacity Card \n"); + } else { + debug_if(SD_DBG, "Card Initialized: Standard Capacity Card: Version 2.x \n"); + } + } + } else { + _card_type = SDCARD_V1; + debug_if(SD_DBG, "Card Initialized: Version 1.x Card\n"); + } + + // Disable CRC + status = _cmd(CMD59_CRC_ON_OFF, 0); + + return status; +} + + +int SDBlockDevice::init() +{ + lock(); + int err = _initialise_card(); + _is_initialized = (err == BD_ERROR_OK); + if (!_is_initialized) { + debug_if(SD_DBG, "Fail to initialize card\n"); + unlock(); + return err; + } + debug_if(SD_DBG, "init card = %d\n", _is_initialized); + _sectors = _sd_sectors(); + // CMD9 failed + if (0 == _sectors) { + unlock(); + return BD_ERROR_DEVICE_ERROR; + } + + // Set block length to 512 (CMD16) + if (_cmd(CMD16_SET_BLOCKLEN, _block_size) != 0) { + debug_if(SD_DBG, "Set %d-byte block timed out\n", _block_size); + unlock(); + return BD_ERROR_DEVICE_ERROR; + } + + // Set SCK for data transfer + err = _freq(); + if (err) { + unlock(); + return err; + } + unlock(); + return BD_ERROR_OK; +} + +int SDBlockDevice::deinit() +{ + lock(); + _is_initialized = false; + _sectors = 0; + unlock(); + return 0; +} + + +int SDBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) +{ + if (!is_valid_program(addr, size)) { + return SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + lock(); + if (!_is_initialized) { + unlock(); + return SD_BLOCK_DEVICE_ERROR_NO_INIT; + } + + const uint8_t *buffer = static_cast<const uint8_t*>(b); + int status = BD_ERROR_OK; + uint8_t response; + + // Get block count + bd_addr_t blockCnt = size / _block_size; + + // SDSC Card (CCS=0) uses byte unit address + // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit) + if(SDCARD_V2HC == _card_type) { + addr = addr / _block_size; + } + + // Send command to perform write operation + if (blockCnt == 1) { + // Single block write command + if (BD_ERROR_OK != (status = _cmd(CMD24_WRITE_BLOCK, addr))) { + unlock(); + return status; + } + + // Write data + response = _write(buffer, SPI_START_BLOCK, _block_size); + + // Only CRC and general write error are communicated via response token + if ((response == SPI_DATA_CRC_ERROR) || (response == SPI_DATA_WRITE_ERROR)) { + debug_if(SD_DBG, "Single Block Write failed: 0x%x \n", response); + status = SD_BLOCK_DEVICE_ERROR_WRITE; + } + } else { + // Pre-erase setting prior to multiple block write operation + _cmd(ACMD23_SET_WR_BLK_ERASE_COUNT, blockCnt, 1); + + // Multiple block write command + if (BD_ERROR_OK != (status = _cmd(CMD25_WRITE_MULTIPLE_BLOCK, addr))) { + unlock(); + return status; + } + + // Write the data: one block at a time + do { + response = _write(buffer, SPI_START_BLK_MUL_WRITE, _block_size); + if (response != SPI_DATA_ACCEPTED) { + debug_if(SD_DBG, "Multiple Block Write failed: 0x%x \n", response); + break; + } + buffer += _block_size; + }while (--blockCnt); // Receive all blocks of data + + /* In a Multiple Block write operation, the stop transmission will be done by + * sending 'Stop Tran' token instead of 'Start Block' token at the beginning + * of the next block + */ + _spi.write(SPI_STOP_TRAN); + } + + _deselect(); + unlock(); + return status; +} + +int SDBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) +{ + if (!is_valid_read(addr, size)) { + return SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + lock(); + if (!_is_initialized) { + unlock(); + return SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + uint8_t *buffer = static_cast<uint8_t *>(b); + int status = BD_ERROR_OK; + bd_addr_t blockCnt = size / _block_size; + + // SDSC Card (CCS=0) uses byte unit address + // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit) + if (SDCARD_V2HC == _card_type) { + addr = addr / _block_size; + } + + // Write command ro receive data + if (blockCnt > 1) { + status = _cmd(CMD18_READ_MULTIPLE_BLOCK, addr); + } else { + status = _cmd(CMD17_READ_SINGLE_BLOCK, addr); + } + if (BD_ERROR_OK != status) { + unlock(); + return status; + } + + // receive the data : one block at a time + while (blockCnt) { + if (0 != _read(buffer, _block_size)) { + status = SD_BLOCK_DEVICE_ERROR_NO_RESPONSE; + break; + } + buffer += _block_size; + --blockCnt; + } + _deselect(); + + // Send CMD12(0x00000000) to stop the transmission for multi-block transfer + if (size > _block_size) { + status = _cmd(CMD12_STOP_TRANSMISSION, 0x0); + } + unlock(); + return status; +} + +bool SDBlockDevice::_is_valid_trim(bd_addr_t addr, bd_size_t size) +{ + return ( + addr % _erase_size == 0 && + size % _erase_size == 0 && + addr + size <= this->size()); +} + +int SDBlockDevice::trim(bd_addr_t addr, bd_size_t size) +{ + if (!_is_valid_trim(addr, size)) { + return SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + lock(); + if (!_is_initialized) { + unlock(); + return SD_BLOCK_DEVICE_ERROR_NO_INIT; + } + int status = BD_ERROR_OK; + + size -= _block_size; + // SDSC Card (CCS=0) uses byte unit address + // SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit) + if (SDCARD_V2HC == _card_type) { + size = size / _block_size; + addr = addr / _block_size; + } + + // Start lba sent in start command + if (BD_ERROR_OK != (status = _cmd(CMD32_ERASE_WR_BLK_START_ADDR, addr))) { + unlock(); + return status; + } + + // End lba = addr+size sent in end addr command + if (BD_ERROR_OK != (status = _cmd(CMD33_ERASE_WR_BLK_END_ADDR, addr+size))) { + unlock(); + return status; + } + status = _cmd(CMD38_ERASE, 0x0); + unlock(); + return status; +} + +bd_size_t SDBlockDevice::get_read_size() const +{ + return _block_size; +} + +bd_size_t SDBlockDevice::get_program_size() const +{ + return _block_size; +} + +bd_size_t SDBlockDevice::size() const +{ + return _block_size*_sectors; +} + +void SDBlockDevice::debug(bool dbg) +{ + _dbg = dbg; +} + +int SDBlockDevice::frequency(uint64_t freq) +{ + lock(); + _transfer_sck = freq; + int err = _freq(); + unlock(); + return err; +} + +// PRIVATE FUNCTIONS +int SDBlockDevice::_freq(void) +{ + // Max frequency supported is 25MHZ + if (_transfer_sck <= 25000000) { + _spi.frequency(_transfer_sck); + return 0; + } else { // TODO: Switch function to be implemented for higher frequency + _transfer_sck = 25000000; + _spi.frequency(_transfer_sck); + return -EINVAL; + } +} + +uint8_t SDBlockDevice::_cmd_spi(SDBlockDevice::cmdSupported cmd, uint32_t arg) { + uint8_t response; + char cmdPacket[PACKET_SIZE]; + + // Prepare the command packet + cmdPacket[0] = SPI_CMD(cmd); + cmdPacket[1] = (arg >> 24); + cmdPacket[2] = (arg >> 16); + cmdPacket[3] = (arg >> 8); + cmdPacket[4] = (arg >> 0); + // CMD0 is executed in SD mode, hence should have correct CRC + // CMD8 CRC verification is always enabled + switch(cmd) { + case CMD0_GO_IDLE_STATE: + cmdPacket[5] = 0x95; + break; + case CMD8_SEND_IF_COND: + cmdPacket[5] = 0x87; + break; + default: + cmdPacket[5] = 0xFF; // Make sure bit 0-End bit is high + break; + } + + // send a command + for (int i = 0; i < PACKET_SIZE; i++) { + _spi.write(cmdPacket[i]); + } + + // The received byte immediataly following CMD12 is a stuff byte, + // it should be discarded before receive the response of the CMD12. + if (CMD12_STOP_TRANSMISSION == cmd) { + _spi.write(SPI_FILL_CHAR); + } + + // Loop for response: Response is sent back within command response time (NCR), 0 to 8 bytes for SDC + for (int i = 0; i < 0x10; i++) { + response = _spi.write(SPI_FILL_CHAR); + // Got the response + if (!(response & R1_RESPONSE_RECV)) { + break; + } + } + return response; +} + +int SDBlockDevice::_cmd(SDBlockDevice::cmdSupported cmd, uint32_t arg, bool isAcmd, uint32_t *resp) { + int32_t status = BD_ERROR_OK; + uint32_t response; + + // Select card and wait for card to be ready before sending next command + // Note: next command will fail if card is not ready + _select(); + + // No need to wait for card to be ready when sending the stop command + if (CMD12_STOP_TRANSMISSION != cmd) { + if (false == _wait_ready(SD_COMMAND_TIMEOUT)) { + debug_if(SD_DBG, "Card not ready yet \n"); + } + } + + // Re-try command + for(int i = 0; i < 3; i++) { + // Send CMD55 for APP command first + if (isAcmd) { + response = _cmd_spi(CMD55_APP_CMD, 0x0); + // Wait for card to be ready after CMD55 + if (false == _wait_ready(SD_COMMAND_TIMEOUT)) { + debug_if(SD_DBG, "Card not ready yet \n"); + } + } + + // Send command over SPI interface + response = _cmd_spi(cmd, arg); + if (R1_NO_RESPONSE == response) { + debug_if(SD_DBG, "No response CMD:%d \n", cmd); + continue; + } + break; + } + + // Pass the response to the command call if required + if (NULL != resp) { + *resp = response; + } + + // Process the response R1 : Exit on CRC/Illegal command error/No response + if (R1_NO_RESPONSE == response) { + _deselect(); + debug_if(SD_DBG, "No response CMD:%d response: 0x%x\n",cmd, response); + return SD_BLOCK_DEVICE_ERROR_NO_DEVICE; // No device + } + if (response & R1_COM_CRC_ERROR) { + _deselect(); + debug_if(SD_DBG, "CRC error CMD:%d response 0x%x \n",cmd, response); + return SD_BLOCK_DEVICE_ERROR_CRC; // CRC error + } + if (response & R1_ILLEGAL_COMMAND) { + _deselect(); + debug_if(SD_DBG, "Illegal command CMD:%d response 0x%x\n",cmd, response); + if (CMD8_SEND_IF_COND == cmd) { // Illegal command is for Ver1 or not SD Card + _card_type = CARD_UNKNOWN; + } + return SD_BLOCK_DEVICE_ERROR_UNSUPPORTED; // Command not supported + } + + debug_if(_dbg, "CMD:%d \t arg:0x%x \t Response:0x%x \n", cmd, arg, response); + // Set status for other errors + if ((response & R1_ERASE_RESET) || (response & R1_ERASE_SEQUENCE_ERROR)) { + status = SD_BLOCK_DEVICE_ERROR_ERASE; // Erase error + }else if ((response & R1_ADDRESS_ERROR) || (response & R1_PARAMETER_ERROR)) { + // Misaligned address / invalid address block length + status = SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + // Get rest of the response part for other commands + switch(cmd) { + case CMD8_SEND_IF_COND: // Response R7 + debug_if(_dbg, "V2-Version Card\n"); + _card_type = SDCARD_V2; + // Note: No break here, need to read rest of the response + case CMD58_READ_OCR: // Response R3 + response = (_spi.write(SPI_FILL_CHAR) << 24); + response |= (_spi.write(SPI_FILL_CHAR) << 16); + response |= (_spi.write(SPI_FILL_CHAR) << 8); + response |= _spi.write(SPI_FILL_CHAR); + debug_if(_dbg, "R3/R7: 0x%x \n", response); + break; + + case CMD12_STOP_TRANSMISSION: // Response R1b + case CMD38_ERASE: + _wait_ready(SD_COMMAND_TIMEOUT); + break; + + case ACMD13_SD_STATUS: // Response R2 + response = _spi.write(SPI_FILL_CHAR); + debug_if(_dbg, "R2: 0x%x \n", response); + break; + + default: // Response R1 + break; + } + + // Pass the updated response to the command + if (NULL != resp) { + *resp = response; + } + + // Do not deselect card if read is in progress. + if (((CMD9_SEND_CSD == cmd) || (ACMD22_SEND_NUM_WR_BLOCKS == cmd) || + (CMD24_WRITE_BLOCK == cmd) || (CMD25_WRITE_MULTIPLE_BLOCK == cmd) || + (CMD17_READ_SINGLE_BLOCK == cmd) || (CMD18_READ_MULTIPLE_BLOCK == cmd)) + && (BD_ERROR_OK == status)) { + return BD_ERROR_OK; + } + // Deselect card + _deselect(); + return status; +} + +int SDBlockDevice::_cmd8() { + uint32_t arg = (CMD8_PATTERN << 0); // [7:0]check pattern + uint32_t response = 0; + int32_t status = BD_ERROR_OK; + + arg |= (0x1 << 8); // 2.7-3.6V // [11:8]supply voltage(VHS) + + status = _cmd(CMD8_SEND_IF_COND, arg, 0x0, &response); + // Verify voltage and pattern for V2 version of card + if ((BD_ERROR_OK == status) && (SDCARD_V2 == _card_type)) { + // If check pattern is not matched, CMD8 communication is not valid + if((response & 0xFFF) != arg) + { + debug_if(SD_DBG, "CMD8 Pattern mismatch 0x%x : 0x%x\n", arg, response); + _card_type = CARD_UNKNOWN; + status = SD_BLOCK_DEVICE_ERROR_UNUSABLE; + } + } + return status; +} + +uint32_t SDBlockDevice::_go_idle_state() { + uint32_t response; + + /* Reseting the MCU SPI master may not reset the on-board SDCard, in which + * case when MCU power-on occurs the SDCard will resume operations as + * though there was no reset. In this scenario the first CMD0 will + * not be interpreted as a command and get lost. For some cards retrying + * the command overcomes this situation. */ + for (int i = 0; i < SD_CMD0_GO_IDLE_STATE_RETRIES; i++) { + _cmd(CMD0_GO_IDLE_STATE, 0x0, 0x0, &response); + if (R1_IDLE_STATE == response) + break; + wait_ms(1); + } + return response; +} + +int SDBlockDevice::_read_bytes(uint8_t *buffer, uint32_t length) { + uint16_t crc; + + // read until start byte (0xFE) + if (false == _wait_token(SPI_START_BLOCK)) { + debug_if(SD_DBG, "Read timeout\n"); + _deselect(); + return SD_BLOCK_DEVICE_ERROR_NO_RESPONSE; + } + + // read data + for (uint32_t i = 0; i < length; i++) { + buffer[i] = _spi.write(SPI_FILL_CHAR); + } + + // Read the CRC16 checksum for the data block + crc = (_spi.write(SPI_FILL_CHAR) << 8); + crc |= _spi.write(SPI_FILL_CHAR); + + _deselect(); + return 0; +} + +int SDBlockDevice::_read(uint8_t *buffer, uint32_t length) { + uint16_t crc; + + // read until start byte (0xFE) + if (false == _wait_token(SPI_START_BLOCK)) { + debug_if(SD_DBG, "Read timeout\n"); + _deselect(); + return SD_BLOCK_DEVICE_ERROR_NO_RESPONSE; + } + + // read data + _spi.write(NULL, 0, (char*)buffer, length); + + // Read the CRC16 checksum for the data block + crc = (_spi.write(SPI_FILL_CHAR) << 8); + crc |= _spi.write(SPI_FILL_CHAR); + + return 0; +} + +uint8_t SDBlockDevice::_write(const uint8_t *buffer, uint8_t token, uint32_t length) { + uint16_t crc = 0xFFFF; + uint8_t response = 0xFF; + + // indicate start of block + _spi.write(token); + + // write the data + _spi.write((char*)buffer, length, NULL, 0); + + // write the checksum CRC16 + _spi.write(crc >> 8); + _spi.write(crc); + + // check the response token + response = _spi.write(SPI_FILL_CHAR); + + // Wait for last block to be written + if (false == _wait_ready(SD_COMMAND_TIMEOUT)) { + debug_if(SD_DBG, "Card not ready yet \n"); + } + + return (response & SPI_DATA_RESPONSE_MASK); +} + +static uint32_t ext_bits(unsigned char *data, int msb, int lsb) { + uint32_t bits = 0; + uint32_t size = 1 + msb - lsb; + for (uint32_t i = 0; i < size; i++) { + uint32_t position = lsb + i; + uint32_t byte = 15 - (position >> 3); + uint32_t bit = position & 0x7; + uint32_t value = (data[byte] >> bit) & 1; + bits |= value << i; + } + return bits; +} + +bd_size_t SDBlockDevice::_sd_sectors() { + uint32_t c_size, c_size_mult, read_bl_len; + uint32_t block_len, mult, blocknr; + uint32_t hc_c_size; + bd_size_t blocks = 0, capacity = 0; + + // CMD9, Response R2 (R1 byte + 16-byte block read) + if (_cmd(CMD9_SEND_CSD, 0x0) != 0x0) { + debug_if(SD_DBG, "Didn't get a response from the disk\n"); + return 0; + } + uint8_t csd[16]; + if (_read_bytes(csd, 16) != 0) { + debug_if(SD_DBG, "Couldn't read csd response from disk\n"); + return 0; + } + + // csd_structure : csd[127:126] + int csd_structure = ext_bits(csd, 127, 126); + switch (csd_structure) { + case 0: + c_size = ext_bits(csd, 73, 62); // c_size : csd[73:62] + c_size_mult = ext_bits(csd, 49, 47); // c_size_mult : csd[49:47] + read_bl_len = ext_bits(csd, 83, 80); // read_bl_len : csd[83:80] - the *maximum* read block length + block_len = 1 << read_bl_len; // BLOCK_LEN = 2^READ_BL_LEN + mult = 1 << (c_size_mult + 2); // MULT = 2^C_SIZE_MULT+2 (C_SIZE_MULT < 8) + blocknr = (c_size + 1) * mult; // BLOCKNR = (C_SIZE+1) * MULT + capacity = blocknr * block_len; // memory capacity = BLOCKNR * BLOCK_LEN + blocks = capacity / _block_size; + debug_if(SD_DBG, "Standard Capacity: c_size: %d \n", c_size); + debug_if(SD_DBG, "Sectors: 0x%x : %llu\n", blocks, blocks); + debug_if(SD_DBG, "Capacity: 0x%x : %llu MB\n", capacity, (capacity/(1024U*1024U))); + + // ERASE_BLK_EN = 1: Erase in multiple of 512 bytes supported + if (ext_bits(csd, 46, 46)) { + _erase_size = BLOCK_SIZE_HC; + } else { + // ERASE_BLK_EN = 1: Erase in multiple of SECTOR_SIZE supported + _erase_size = BLOCK_SIZE_HC * (ext_bits(csd, 45, 39) + 1); + } + break; + + case 1: + hc_c_size = ext_bits(csd, 69, 48); // device size : C_SIZE : [69:48] + blocks = (hc_c_size+1) << 10; // block count = C_SIZE+1) * 1K byte (512B is block size) + debug_if(SD_DBG, "SDHC/SDXC Card: hc_c_size: %d \n", hc_c_size); + debug_if(SD_DBG, "Sectors: 0x%x : %llu\n", blocks, blocks); + debug_if(SD_DBG, "Capacity: %llu MB\n", (blocks/(2048U))); + // ERASE_BLK_EN is fixed to 1, which means host can erase one or multiple of 512 bytes. + _erase_size = BLOCK_SIZE_HC; + break; + + default: + debug_if(SD_DBG, "CSD struct unsupported\r\n"); + return 0; + }; + return blocks; +} + +// SPI function to wait till chip is ready and sends start token +bool SDBlockDevice::_wait_token(uint8_t token) { + _spi_timer.reset(); + _spi_timer.start(); + + do { + if (token == _spi.write(SPI_FILL_CHAR)) { + _spi_timer.stop(); + return true; + } + } while (_spi_timer.read_ms() < 300); // Wait for 300 msec for start token + _spi_timer.stop(); + debug_if(SD_DBG, "_wait_token: timeout\n"); + return false; +} + +// SPI function to wait till chip is ready +// The host controller should wait for end of the process until DO goes high (a 0xFF is received). +bool SDBlockDevice::_wait_ready(uint16_t ms) { + uint8_t response; + _spi_timer.reset(); + _spi_timer.start(); + do { + response = _spi.write(SPI_FILL_CHAR); + if (response == 0xFF) { + _spi_timer.stop(); + return true; + } + } while (_spi_timer.read_ms() < ms); + _spi_timer.stop(); + return false; +} + +// SPI function to wait for count +void SDBlockDevice::_spi_wait(uint8_t count) +{ + for (uint8_t i = 0; i < count; ++i) { + _spi.write(SPI_FILL_CHAR); + } +} + +void SDBlockDevice::_spi_init() { + _spi.lock(); + // Set to SCK for initialization, and clock card with cs = 1 + _spi.frequency(_init_sck); + _spi.format(8, 0); + _spi.set_default_write_value(SPI_FILL_CHAR); + // Initial 74 cycles required for few cards, before selecting SPI mode + _cs = 1; + _spi_wait(10); + _spi.unlock(); +} + +void SDBlockDevice::_select() { + _spi.lock(); + _spi.write(SPI_FILL_CHAR); + _cs = 0; +} + +void SDBlockDevice::_deselect() { + _cs = 1; + _spi.write(SPI_FILL_CHAR); + _spi.unlock(); +} + +#endif /* DEVICE_SPI */
diff -r 000000000000 -r 119624335925 sd-driver/SDBlockDevice.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/SDBlockDevice.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,232 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_SD_BLOCK_DEVICE_H +#define MBED_SD_BLOCK_DEVICE_H + +/* If the target has no SPI support then SDCard is not supported */ +#ifdef DEVICE_SPI + +#include "BlockDevice.h" +#include "mbed.h" +#include "platform/PlatformMutex.h" + +/** Access an SD Card using SPI + * + * @code + * #include "mbed.h" + * #include "SDBlockDevice.h" + * + * SDBlockDevice sd(p5, p6, p7, p12); // mosi, miso, sclk, cs + * uint8_t block[512] = "Hello World!\n"; + * + * int main() { + * sd.init(); + * sd.write(block, 0, 512); + * sd.read(block, 0, 512); + * printf("%s", block); + * sd.deinit(); + * } + */ +class SDBlockDevice : public BlockDevice { +public: + /** Lifetime of an SD card + */ + SDBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs, uint64_t hz=1000000); + virtual ~SDBlockDevice(); + + /** Initialize a block device + * + * @return 0 on success or a negative error code on failure + */ + virtual int init(); + + /** Deinitialize a block device + * + * @return 0 on success or a negative error code on failure + */ + virtual int deinit(); + + /** Read blocks from a block device + * + * @param buffer Buffer to write blocks to + * @param addr Address of block to begin reading from + * @param size Size to read in bytes, must be a multiple of read block size + * @return 0 on success, negative error code on failure + */ + virtual int read(void *buffer, bd_addr_t addr, bd_size_t size); + + /** Program blocks to a block device + * + * The blocks must have been erased prior to being programmed + * + * @param buffer Buffer of data to write to blocks + * @param addr Address of block to begin writing to + * @param size Size to write in bytes, must be a multiple of program block size + * @return 0 on success, negative error code on failure + */ + virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size); + + /** Mark blocks as no longer in use + * + * This function provides a hint to the underlying block device that a region of blocks + * is no longer in use and may be erased without side effects. Erase must still be called + * before programming, but trimming allows flash-translation-layers to schedule erases when + * the device is not busy. + * + * @param addr Address of block to mark as unused + * @param size Size to mark as unused in bytes, must be a multiple of erase block size + * @return 0 on success, negative error code on failure + */ + virtual int trim(bd_addr_t addr, bd_size_t size); + + /** Get the size of a readable block + * + * @return Size of a readable block in bytes + */ + virtual bd_size_t get_read_size() const; + + /** Get the size of a programable block + * + * @return Size of a programable block in bytes + * @note Must be a multiple of the read size + */ + virtual bd_size_t get_program_size() const; + + /** Get the total size of the underlying device + * + * @return Size of the underlying device in bytes + */ + virtual bd_size_t size() const; + + /** Enable or disable debugging + * + * @param State of debugging + */ + virtual void debug(bool dbg); + + /** Set the transfer frequency + * + * @param Transfer frequency + * @note Max frequency supported is 25MHZ + */ + virtual int frequency(uint64_t freq); + + +private: + /* Commands : Listed below are commands supported + * in SPI mode for SD card : Only Mandatory ones + */ + enum cmdSupported { + CMD_NOT_SUPPORTED = -1, /**< Command not supported error */ + CMD0_GO_IDLE_STATE = 0, /**< Resets the SD Memory Card */ + CMD1_SEND_OP_COND = 1, /**< Sends host capacity support */ + CMD6_SWITCH_FUNC = 6, /**< Check and Switches card function */ + CMD8_SEND_IF_COND = 8, /**< Supply voltage info */ + CMD9_SEND_CSD = 9, /**< Provides Card Specific data */ + CMD10_SEND_CID = 10, /**< Provides Card Identification */ + CMD12_STOP_TRANSMISSION = 12, /**< Forces the card to stop transmission */ + CMD13_SEND_STATUS = 13, /**< Card responds with status */ + CMD16_SET_BLOCKLEN = 16, /**< Length for SC card is set */ + CMD17_READ_SINGLE_BLOCK = 17, /**< Read single block of data */ + CMD18_READ_MULTIPLE_BLOCK = 18, /**< Card transfers data blocks to host until interrupted + by a STOP_TRANSMISSION command */ + CMD24_WRITE_BLOCK = 24, /**< Write single block of data */ + CMD25_WRITE_MULTIPLE_BLOCK = 25, /**< Continuously writes blocks of data until + 'Stop Tran' token is sent */ + CMD27_PROGRAM_CSD = 27, /**< Programming bits of CSD */ + CMD32_ERASE_WR_BLK_START_ADDR = 32, /**< Sets the address of the first write + block to be erased. */ + CMD33_ERASE_WR_BLK_END_ADDR = 33, /**< Sets the address of the last write + block of the continuous range to be erased.*/ + CMD38_ERASE = 38, /**< Erases all previously selected write blocks */ + CMD55_APP_CMD = 55, /**< Extend to Applications specific commands */ + CMD56_GEN_CMD = 56, /**< General Purpose Command */ + CMD58_READ_OCR = 58, /**< Read OCR register of card */ + CMD59_CRC_ON_OFF = 59, /**< Turns the CRC option on or off*/ + // App Commands + ACMD6_SET_BUS_WIDTH = 6, + ACMD13_SD_STATUS = 13, + ACMD22_SEND_NUM_WR_BLOCKS = 22, + ACMD23_SET_WR_BLK_ERASE_COUNT = 23, + ACMD41_SD_SEND_OP_COND = 41, + ACMD42_SET_CLR_CARD_DETECT = 42, + ACMD51_SEND_SCR = 51, + }; + + uint8_t _card_type; + int _cmd(SDBlockDevice::cmdSupported cmd, uint32_t arg, bool isAcmd=0, uint32_t *resp=NULL); + int _cmd8(); + + /* Move the SDCard into the SPI Mode idle state + * + * The card is transitioned from SDCard mode to SPI mode by sending the + * CMD0 (GO_IDLE_STATE) command with CS asserted. See the notes in the + * "SPI Startup" section of the comments at the head of the + * implementation file for further details and specification references. + * + * @return Response form the card. R1_IDLE_STATE (0x1), the successful + * response from CMD0. R1_XXX_XXX for more response + */ + uint32_t _go_idle_state(); + int _initialise_card(); + + bd_size_t _sectors; + bd_size_t _sd_sectors(); + + bool _is_valid_trim(bd_addr_t addr, bd_size_t size); + + /* SPI functions */ + Timer _spi_timer; /**< Timer Class object used for busy wait */ + uint32_t _init_sck; /**< Intial SPI frequency */ + uint32_t _transfer_sck; /**< SPI frequency during data transfer/after initialization */ + SPI _spi; /**< SPI Class object */ + + /* SPI initialization function */ + void _spi_init(); + uint8_t _cmd_spi(SDBlockDevice::cmdSupported cmd, uint32_t arg); + void _spi_wait(uint8_t count); + + bool _wait_token(uint8_t token); /**< Wait for token */ + bool _wait_ready(uint16_t ms=300); /**< 300ms default wait for card to be ready */ + int _read(uint8_t * buffer, uint32_t length); + int _read_bytes(uint8_t * buffer, uint32_t length); + uint8_t _write(const uint8_t *buffer,uint8_t token, uint32_t length); + int _freq(void); + + /* Chip Select and SPI mode select */ + DigitalOut _cs; + void _select(); + void _deselect(); + + virtual void lock() { + _mutex.lock(); + } + + virtual void unlock() { + _mutex.unlock(); + } + + PlatformMutex _mutex; + bd_size_t _block_size; + bd_size_t _erase_size; + bool _is_initialized; + bool _dbg; +}; + +#endif /* DEVICE_SPI */ + +#endif /* MBED_SD_BLOCK_DEVICE_H */
diff -r 000000000000 -r 119624335925 sd-driver/TESTS/block_device/basic/basic.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/TESTS/block_device/basic/basic.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,179 @@ +/* + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* The following copyright notice is reproduced from the glibc project + * REF_LICENCE_GLIBC + * + * Copyright (C) 1991, 1992 Free Software Foundation, Inc. + * This file is part of the GNU C Library. + * + * The GNU C Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The GNU C Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the GNU C Library; see the file COPYING.LIB. If + * not, write to the Free Software Foundation, Inc., 675 Mass Ave, + * Cambridge, MA 02139, USA. + */ + + +/** @file main.cpp Basic SD Driver Test + */ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" + +#include "SDBlockDevice.h" +#include <stdlib.h> + +using namespace utest::v1; + +#define TEST_BLOCK_COUNT 10 +#define TEST_ERROR_MASK 16 +#define TEST_BLOCK_SIZE 2048 + +const struct { + const char *name; + bd_size_t (BlockDevice::*method)() const; +} ATTRS[] = { + {"read size", &BlockDevice::get_read_size}, + {"program size", &BlockDevice::get_program_size}, + {"erase size", &BlockDevice::get_erase_size}, + {"total size", &BlockDevice::size}, +}; + +void test_read_write() { + SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); + + int err = sd.init(); + TEST_ASSERT_EQUAL(0, err); + + err = sd.frequency(8000000); + TEST_ASSERT_EQUAL(0, err); + + for (unsigned a = 0; a < sizeof(ATTRS)/sizeof(ATTRS[0]); a++) { + static const char *prefixes[] = {"", "k", "M", "G"}; + for (int i = 3; i >= 0; i--) { + bd_size_t size = (sd.*ATTRS[a].method)(); + if (size >= (1ULL << 10*i)) { + printf("%s: %llu%sbytes (%llubytes)\n", + ATTRS[a].name, size >> 10*i, prefixes[i], size); + break; + } + } + } + + bd_size_t erase_size = sd.get_erase_size(); + bd_size_t block_size = erase_size > TEST_BLOCK_SIZE ? erase_size : TEST_BLOCK_SIZE; + + uint8_t *write_block = new uint8_t[block_size]; + uint8_t *read_block = new uint8_t[block_size]; + uint8_t *error_mask = new uint8_t[TEST_ERROR_MASK]; + unsigned addrwidth = ceil(log(float(sd.size()-1)) / log(float(16)))+1; + + for (int b = 0; b < TEST_BLOCK_COUNT; b++) { + // Find a random block + bd_addr_t block = (rand()*block_size) % sd.size(); + + // Use next random number as temporary seed to keep + // the address progressing in the pseudorandom sequence + unsigned seed = rand(); + + // Fill with random sequence + srand(seed); + for (bd_size_t i = 0; i < block_size; i++) { + write_block[i] = 0xff & rand(); + } + + // Write, sync, and read the block + printf("test %0*llx:%llu...\n", addrwidth, block, block_size); + + err = sd.trim(block, block_size); + TEST_ASSERT_EQUAL(0, err); + + err = sd.program(write_block, block, block_size); + TEST_ASSERT_EQUAL(0, err); + + printf("write %0*llx:%llu ", addrwidth, block, block_size); + for (int i = 0; i < 16; i++) { + printf("%02x", write_block[i]); + } + printf("...\n"); + + err = sd.read(read_block, block, block_size); + TEST_ASSERT_EQUAL(0, err); + + printf("read %0*llx:%llu ", addrwidth, block, block_size); + for (int i = 0; i < 16; i++) { + printf("%02x", read_block[i]); + } + printf("...\n"); + + // Find error mask for debugging + memset(error_mask, 0, TEST_ERROR_MASK); + bd_size_t error_scale = block_size / (TEST_ERROR_MASK*8); + + srand(seed); + for (bd_size_t i = 0; i < TEST_ERROR_MASK*8; i++) { + for (bd_size_t j = 0; j < error_scale; j++) { + if ((0xff & rand()) != read_block[i*error_scale + j]) { + error_mask[i/8] |= 1 << (i%8); + } + } + } + + printf("error %0*llx:%llu ", addrwidth, block, block_size); + for (int i = 0; i < 16; i++) { + printf("%02x", error_mask[i]); + } + printf("\n"); + + // Check that the data was unmodified + srand(seed); + for (bd_size_t i = 0; i < block_size; i++) { + TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]); + } + } + + err = sd.deinit(); + TEST_ASSERT_EQUAL(0, err); +} + +// Test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(120, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Testing read write random blocks", test_read_write), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 sd-driver/TESTS/filesystem/basic/basic.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/TESTS/filesystem/basic/basic.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,933 @@ +/* + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* The following copyright notice is reproduced from the glibc project + * REF_LICENCE_GLIBC + * + * Copyright (C) 1991, 1992 Free Software Foundation, Inc. + * This file is part of the GNU C Library. + * + * The GNU C Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The GNU C Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the GNU C Library; see the file COPYING.LIB. If + * not, write to the Free Software Foundation, Inc., 675 Mass Ave, + * Cambridge, MA 02139, USA. + */ + + +/** @file basic.cpp POSIX File API (stdio) test cases + * + * Consult the documentation under the test-case functions for + * a description of the individual test case. + * + * this file includes ports for the mbed 2 test cases from the following locations: + * - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/dir_sd/main.cpp. + * - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/file/main.cpp. + * - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/sd/main.cpp + * - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_handle/main.cpp + * - https://github.com:/armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_stdio/main.cpp. + */ + +#include "mbed.h" +#include "mbed_config.h" +#include "FATFileSystem.h" +#include "SDBlockDevice.h" +#include "test_env.h" +#include "fsfat_debug.h" +#include "fsfat_test.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <algorithm> +/* retarget.h is included after errno.h so symbols are mapped to + * consistent values for all toolchains */ +#include "platform/mbed_retarget.h" + +using namespace utest::v1; + +/* DEVICE_SPI + * This symbol is defined in targets.json if the target has a SPI interface, which is required for SDCard support. + * + * MBED_CONF_APP_FSFAT_SDCARD_INSTALLED + * For testing purposes, an SDCard must be installed on the target for the test cases in this file to succeed. + * If the target has an SD card installed then the MBED_CONF_APP_FSFAT_SDCARD_INSTALLED will be generated + * from the mbed_app.json, which includes the line + * { + * "config": { + * "UART_RX": "D0", + * <<< lines removed >>> + * "DEVICE_SPI": 1, + * "MBED_CONF_APP_FSFAT_SDCARD_INSTALLED": 1 + * }, + * <<< lines removed >>> + */ +#if defined(DEVICE_SPI) && ( defined(MBED_CONF_APP_FSFAT_SDCARD_INSTALLED) || (MBED_CONF_SD_FSFAT_SDCARD_INSTALLED)) + +#define FSFAT_BASIC_TEST_00 fsfat_basic_test_00 +#define FSFAT_BASIC_TEST_01 fsfat_basic_test_01 +#define FSFAT_BASIC_TEST_02 fsfat_basic_test_02 +#define FSFAT_BASIC_TEST_03 fsfat_basic_test_03 +#define FSFAT_BASIC_TEST_04 fsfat_basic_test_04 +#define FSFAT_BASIC_TEST_05 fsfat_basic_test_05 +#define FSFAT_BASIC_TEST_06 fsfat_basic_test_06 +#define FSFAT_BASIC_TEST_07 fsfat_basic_test_07 +#define FSFAT_BASIC_TEST_08 fsfat_basic_test_08 +#define FSFAT_BASIC_TEST_09 fsfat_basic_test_09 +#define FSFAT_BASIC_TEST_10 fsfat_basic_test_10 + +#define FSFAT_BASIC_MSG_BUF_SIZE 256 +#define FSFAT_BASIC_TEST_05_TEST_STRING "Hello World!" + +static const char *sd_file_path = "/sd/out.txt"; +static const char *sd_mount_pt = "sd"; +static const int FSFAT_BASIC_DATA_SIZE = 256; +static char fsfat_basic_msg_g[FSFAT_BASIC_MSG_BUF_SIZE]; +static char fsfat_basic_buffer[1024]; +static const int FSFAT_BASIC_KIB_RW = 128; +static Timer fsfat_basic_timer; +static const char *fsfat_basic_bin_filename = "/sd/testfile.bin"; +static const char *fsfat_basic_bin_filename_test_08 = "testfile.bin"; +static const char *fsfat_basic_bin_filename_test_10 = "0:testfile.bin"; + + + +SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); +FATFileSystem fs(sd_mount_pt, &sd); + +#define FSFAT_BASIC_MSG(_buf, _max_len, _fmt, ...) \ + do \ + { \ + snprintf((_buf), (_max_len), (_fmt), __VA_ARGS__); \ + }while(0); + +/** @brief fopen test case + * + * - open a file + * - generate random data items, write the item to the file and store a coy in a buffer for later use. + * - close the file. + * - open the file. + * - read the data items from the file and check they are the same as write. + * - close the file. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_00() +{ + + uint8_t data_written[FSFAT_BASIC_DATA_SIZE] = { 0 }; + bool read_result = false; + bool write_result = false; + + // Fill data_written buffer with random data + // Write these data into the file + FSFAT_FENTRYLOG("%s:entered\n", __func__); + { + FSFAT_DBGLOG("%s:SD: Writing ... ", __func__); + FILE *f = fopen(sd_file_path, "w"); + if (f) { + for (int i = 0; i < FSFAT_BASIC_DATA_SIZE; i++) { + data_written[i] = rand() % 0XFF; + fprintf(f, "%c", data_written[i]); + } + write_result = true; + fclose(f); + } + FSFAT_DBGLOG("[%s]\n", write_result ? "OK" : "FAIL"); + } + TEST_ASSERT_MESSAGE(write_result == true, "Error: write_result is set to false."); + + // Read back the data from the file and store them in data_read + { + FSFAT_DBGLOG("%s:SD: Reading data ... ", __func__); + FILE *f = fopen(sd_file_path, "r"); + if (f) { + read_result = true; + for (int i = 0; i < FSFAT_BASIC_DATA_SIZE; i++) { + uint8_t data = fgetc(f); + if (data != data_written[i]) { + read_result = false; + break; + } + } + fclose(f); + } + FSFAT_DBGLOG("[%s]\n", read_result ? "OK" : "FAIL"); + } + TEST_ASSERT_MESSAGE(read_result == true, "Error: read_result is set to false."); + return CaseNext; +} + + +/** @brief test-fseek.c test ported from glibc project. See the licence at REF_LICENCE_GLIBC. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_01() +{ + FILE *fp, *fp1; + int i, j; + int ret = 0; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + fp = fopen (sd_file_path, "w+"); + if (fp == NULL) { + FSFAT_DBGLOG("errno=%d\n", errno); + TEST_ASSERT_MESSAGE(false, "error"); + return CaseNext; + } + + for (i = 0; i < 256; i++) { + putc (i, fp); + } + /* FIXME: freopen() should open the specified file closing the first stream. As can be seen from the + * code below, the old file descriptor fp can still be used, and this should not happen. + */ + fp1 = freopen (sd_file_path, "r", fp); + TEST_ASSERT_MESSAGE(fp1 == fp, "Error: cannot open file for reading"); + + for (i = 1; i <= 255; i++) { + ret = fseek (fp, (long) -i, SEEK_END); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s:Error: fseek() failed (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + + if ((j = getc (fp)) != 256 - i) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: SEEK_END failed (j=%d)\n", __func__, j); + TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g); + } + ret = fseek (fp, (long) i, SEEK_SET); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_SET (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + + if ((j = getc (fp)) != i) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_SET (j=%d).\n", __func__, j); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + } + if ((ret = fseek (fp, (long) i, SEEK_SET))) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_SET (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + } + if ((ret = fseek (fp, (long) (i >= 128 ? -128 : 128), SEEK_CUR))) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_CUR (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + } + if ((j = getc (fp)) != (i >= 128 ? i - 128 : i + 128)) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot SEEK_CUR (j=%d).\n", __func__, j); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + } + } + fclose (fp); + remove(sd_file_path); + return CaseNext; +} + + +/** @brief test_rdwr.c test ported from glibc project. See the licence at REF_LICENCE_GLIBC. + * + * WARNING: this test does not currently work. See WARNING comments below. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_02() +{ + static const char hello[] = "Hello, world.\n"; + static const char replace[] = "Hewwo, world.\n"; + static const size_t replace_from = 2, replace_to = 4; + const char *filename = sd_file_path; + char buf[BUFSIZ]; + FILE *f; + int lose = 0; + int32_t ret = 0; + char *rets = NULL; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + f = fopen(filename, "w+"); + if (f == NULL) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Cannot open file for writing (filename=%s).\n", __func__, filename); + TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g); + } + + ret = fputs(hello, f); + if (ret == EOF) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fputs() failed to write string to file (filename=%s, string=%s).\n", __func__, filename, hello); + TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g); + } + + rewind(f); + rets = fgets(buf, sizeof(buf), f); + if (rets == NULL) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fgets() failed to get string from file (filename=%s).\n", __func__, filename); + TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g); + } + rets = NULL; + + rewind(f); + ret = fputs(buf, f); + if (ret == EOF) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fputs() failed to write string to file (filename=%s, string=%s).\n", __func__, filename, buf); + TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g); + } + + rewind(f); + { + register size_t i; + for (i = 0; i < replace_from; ++i) + { + int c = getc(f); + if (c == EOF) + { + FSFAT_DBGLOG("EOF at %u.\n", i); + lose = 1; + break; + } + else if (c != hello[i]) + { + FSFAT_DBGLOG("Got '%c' instead of '%c' at %u.\n", + (unsigned char) c, hello[i], i); + lose = 1; + break; + } + } + } + /* WARNING: printf("%s: here1. (lose = %d)\n", __func__, lose); */ + { + long int where = ftell(f); + if (where == replace_from) + { + register size_t i; + for (i = replace_from; i < replace_to; ++i) { + if (putc(replace[i], f) == EOF) { + FSFAT_DBGLOG("putc('%c') got %s at %u.\n", + replace[i], strerror(errno), i); + lose = 1; + break; + } + /* WARNING: The problem seems to be that putc() is not writing the 'w' chars into the file + * FSFAT_DBGLOG("%s: here1.5. (char = %c, char as int=%d, ret=%d) \n", __func__, replace[i], (int) replace[i], ret); + */ + } + } + else if (where == -1L) + { + FSFAT_DBGLOG("ftell got %s (should be at %u).\n", + strerror(errno), replace_from); + lose = 1; + } + else + { + FSFAT_DBGLOG("ftell returns %ld; should be %u.\n", where, replace_from); + lose = 1; + } + } + + if (!lose) + { + rewind(f); + memset(buf, 0, BUFSIZ); + if (fgets(buf, sizeof(buf), f) == NULL) + { + FSFAT_DBGLOG("fgets got %s.\n", strerror(errno)); + lose = 1; + } + else if (strcmp(buf, replace)) + { + FSFAT_DBGLOG("Read \"%s\" instead of \"%s\".\n", buf, replace); + lose = 1; + } + } + + if (lose) { + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: Test Failed. Losing file (filename=%s).\n", __func__, filename); + TEST_ASSERT_MESSAGE(false, fsfat_basic_msg_g); + } + remove(filename); + return CaseNext; +} + +/** @brief temptest.c test ported from glibc project. See the licence at REF_LICENCE_GLIBC. + * + * tmpnam() is currently not implemented + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_03() +{ + char *fn = NULL; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + fn = tmpnam((char *) NULL); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: appeared to generate a filename when function is not implemented.\n", __func__); + TEST_ASSERT_MESSAGE(fn == NULL, fsfat_basic_msg_g); + return CaseNext; +} + + +static bool fsfat_basic_fileno_check(const char *name, FILE *stream, int fd) +{ + /* ARMCC stdio.h currently does not define fileno() */ +#ifndef __ARMCC_VERSION + int sfd = fileno (stream); + FSFAT_DBGLOG("(fileno (%s) = %d) %c= %d\n", name, sfd, sfd == fd ? '=' : '!', fd); + + if (sfd == fd) { + return true; + } else { + return false; + } +#else + /* For ARMCC behave as though test had passed. */ + return true; +#endif /* __ARMCC_VERSION */ +} + +/* defines for next test case */ +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + + +/** @brief tst-fileno.c test ported from glibc project. See the licence at REF_LICENCE_GLIBC. + * + * WARNING: this test does not currently work. See WARNING comments below. + * + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_04() +{ + /* ARMCC stdio.h currently does not define fileno() */ +#ifndef __ARMCC_VERSION + int ret = -1; + ret = fsfat_basic_fileno_check("stdin", stdin, STDIN_FILENO); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: stdin does not have expected file number (expected=%d, fileno=%d.\n", __func__, (int) stdin, fileno(stdin)); + TEST_ASSERT_MESSAGE(ret == true, fsfat_basic_msg_g); + + ret = fsfat_basic_fileno_check("stdout", stdout, STDOUT_FILENO); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: stdout does not have expected file number (expected=%d, fileno=%d.\n", __func__, (int) stdout, fileno(stdout)); + TEST_ASSERT_MESSAGE(ret == true, fsfat_basic_msg_g); + + ret = fsfat_basic_fileno_check("stderr", stderr, STDERR_FILENO); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: stderr does not have expected file number (expected=%d, fileno=%d.\n", __func__, (int) stderr, fileno(stderr)); + TEST_ASSERT_MESSAGE(ret == true, fsfat_basic_msg_g); +#endif /* __ARMCC_VERSION */ + return CaseNext; +} + + +/** @brief basic test to opendir() on a directory. + * + * This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/dir_sd/main.cpp. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_05() +{ + FILE *f; + const char *str = FSFAT_BASIC_TEST_05_TEST_STRING; + int ret = 0; + + FSFAT_DBGLOG("%s:Write files\n", __func__); + char filename[32]; + for (int i = 0; i < 10; i++) { + sprintf(filename, "/sd/test_%d.txt", i); + FSFAT_DBGLOG("Creating file: %s\n", filename); + f = fopen(filename, "w"); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fopen() failed.\n", __func__); + TEST_ASSERT_MESSAGE(f != NULL, fsfat_basic_msg_g); + + ret = fprintf(f, str); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: writing file.\n", __func__); + TEST_ASSERT_MESSAGE(ret == (int) strlen(str), fsfat_basic_msg_g); + + ret = fclose(f); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fclose() failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + } + + FSFAT_DBGLOG("%s:List files:\n", __func__); + DIR *d = opendir("/sd"); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: opendir() failed.\n", __func__); + TEST_ASSERT_MESSAGE(d != NULL, fsfat_basic_msg_g); + + struct dirent *p; + while ((p = readdir(d)) != NULL) + FSFAT_DBGLOG("%s\n", p->d_name); + closedir(d); + + return CaseNext; +} + + +/** @brief basic test to write a file to sd card, and read it back again + * + * This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/file/main.cpp. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_06() +{ + int ret = -1; + char mac[16]; + mbed_mac_address(mac); + FSFAT_DBGLOG("mac address: %02x,%02x,%02x,%02x,%02x,%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + FILE *f; + const char *str = FSFAT_BASIC_TEST_05_TEST_STRING; + int str_len = strlen(FSFAT_BASIC_TEST_05_TEST_STRING); + + f = fopen(sd_file_path, "w"); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fopen() failed.\n", __func__); + TEST_ASSERT_MESSAGE(f != NULL, fsfat_basic_msg_g); + + ret = fprintf(f, str); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: writing file.\n", __func__); + TEST_ASSERT_MESSAGE(ret == (int) strlen(str), fsfat_basic_msg_g); + + ret = fclose(f); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fclose() failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + + // Read + f = fopen(sd_file_path, "r"); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fopen() failed.\n", __func__); + TEST_ASSERT_MESSAGE(f != NULL, fsfat_basic_msg_g); + + int n = fread(fsfat_basic_buffer, sizeof(unsigned char), str_len, f); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fread() failed.\n", __func__); + TEST_ASSERT_MESSAGE(n == str_len, fsfat_basic_msg_g); + + ret = fclose(f); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: fclose() failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + + return CaseNext; +} + + +/** @brief basic test to write a file to sd card. + * + * This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/sd/main.cpp. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_07() +{ + uint8_t data_written[FSFAT_BASIC_DATA_SIZE] = { 0 }; + + // Fill data_written buffer with random data + // Write these data into the file + bool write_result = false; + { + FSFAT_DBGLOG("%s:SD: Writing ... ", __func__); + FILE *f = fopen(sd_file_path, "w"); + if (f) { + for (int i = 0; i < FSFAT_BASIC_DATA_SIZE; i++) { + data_written[i] = rand() % 0XFF; + fprintf(f, "%c", data_written[i]); + } + write_result = true; + fclose(f); + } + FSFAT_DBGLOG("[%s]\n", write_result ? "OK" : "FAIL"); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: unexpected write failure.\n", __func__); + TEST_ASSERT_MESSAGE(write_result == true, fsfat_basic_msg_g); + } + + // Read back the data from the file and store them in data_read + bool read_result = false; + { + FSFAT_DBGLOG("%s:SD: Reading data ... ", __func__); + FILE *f = fopen(sd_file_path, "r"); + if (f) { + read_result = true; + for (int i = 0; i < FSFAT_BASIC_DATA_SIZE; i++) { + uint8_t data = fgetc(f); + if (data != data_written[i]) { + read_result = false; + break; + } + } + fclose(f); + } + FSFAT_DBGLOG("[%s]\n", read_result ? "OK" : "FAIL"); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: unexpected read failure.\n", __func__); + TEST_ASSERT_MESSAGE(read_result == true, fsfat_basic_msg_g); + } + return CaseNext; +} + + +static bool fsfat_basic_test_file_write_fhandle(const char *filename, const int kib_rw) +{ + int ret = -1; + File file; + + ret = file.open(&fs, filename, O_WRONLY | O_CREAT | O_TRUNC); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + + int byte_write = 0; + fsfat_basic_timer.start(); + for (int i = 0; i < kib_rw; i++) { + ret = file.write(fsfat_basic_buffer, sizeof(fsfat_basic_buffer)); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to write to file.\n", __func__); + TEST_ASSERT_MESSAGE(ret == sizeof(fsfat_basic_buffer), fsfat_basic_msg_g); + byte_write++; + } + fsfat_basic_timer.stop(); + file.close(); +#ifdef FSFAT_DEBUG + double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0; + double speed = kib_rw / test_time_sec; + FSFAT_DBGLOG("%d KiB write in %.3f sec with speed of %.4f KiB/s\n", byte_write, test_time_sec, speed); +#endif + fsfat_basic_timer.reset(); + return true; +} + + +static bool fsfat_basic_test_file_read_fhandle(const char *filename, const int kib_rw) +{ + int ret = -1; + File file; + ret = file.open(&fs, filename, O_RDONLY); + + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_basic_msg_g); + + fsfat_basic_timer.start(); + int byte_read = 0; + while (file.read(fsfat_basic_buffer, sizeof(fsfat_basic_buffer)) == sizeof(fsfat_basic_buffer)) { + byte_read++; + } + fsfat_basic_timer.stop(); + file.close(); +#ifdef FSFAT_DEBUG + double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0; + double speed = kib_rw / test_time_sec; + FSFAT_DBGLOG("%d KiB read in %.3f sec with speed of %.4f KiB/s\n", byte_read, test_time_sec, speed); +#endif + fsfat_basic_timer.reset(); + return true; +} + + +static char fsfat_basic_test_random_char() +{ + return rand() % 100; +} + + +/** @brief basic sd card performance test + * + * This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_handle/main.cpp. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_08() +{ + // Test header + FSFAT_DBGLOG("\n%s:SD Card FileHandle Performance Test\n", __func__); + FSFAT_DBGLOG("File name: %s\n", fsfat_basic_bin_filename); + FSFAT_DBGLOG("Buffer size: %d KiB\n", (FSFAT_BASIC_KIB_RW * sizeof(fsfat_basic_buffer)) / 1024); + + // Initialize buffer + srand(0); + char *buffer_end = fsfat_basic_buffer + sizeof(fsfat_basic_buffer); + std::generate (fsfat_basic_buffer, buffer_end, fsfat_basic_test_random_char); + + bool result = true; + for (;;) { + FSFAT_DBGLOG("%s:Write test...\n", __func__); + if (fsfat_basic_test_file_write_fhandle(fsfat_basic_bin_filename_test_08, FSFAT_BASIC_KIB_RW) == false) { + result = false; + break; + } + + FSFAT_DBGLOG("%s:Read test...\n", __func__); + if (fsfat_basic_test_file_read_fhandle(fsfat_basic_bin_filename_test_08, FSFAT_BASIC_KIB_RW) == false) { + result = false; + break; + } + break; + } + TEST_ASSERT_MESSAGE(result == true, "something went wrong"); + return CaseNext; +} + + +bool fsfat_basic_test_sf_file_write_stdio(const char *filename, const int kib_rw) +{ + int ret = -1; + FILE* file = fopen(filename, "w"); + + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__); + TEST_ASSERT_MESSAGE(file != NULL, fsfat_basic_msg_g); + + int byte_write = 0; + fsfat_basic_timer.start(); + for (int i = 0; i < kib_rw; i++) { + ret = fwrite(fsfat_basic_buffer, sizeof(char), sizeof(fsfat_basic_buffer), file); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to write to file.\n", __func__); + TEST_ASSERT_MESSAGE(ret == sizeof(fsfat_basic_buffer), fsfat_basic_msg_g); + byte_write++; + } + fsfat_basic_timer.stop(); + fclose(file); +#ifdef FSFAT_DEBUG + double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0; + double speed = kib_rw / test_time_sec; + FSFAT_DBGLOG("%d KiB write in %.3f sec with speed of %.4f KiB/s\n", byte_write, test_time_sec, speed); +#endif + fsfat_basic_timer.reset(); + return true; +} + + +bool fsfat_basic_test_sf_file_read_stdio(const char *filename, const int kib_rw) +{ + FILE* file = fopen(filename, "r"); + + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__); + TEST_ASSERT_MESSAGE(file != NULL, fsfat_basic_msg_g); + fsfat_basic_timer.start(); + int byte_read = 0; + while (fread(fsfat_basic_buffer, sizeof(char), sizeof(fsfat_basic_buffer), file) == sizeof(fsfat_basic_buffer)) { + byte_read++; + } + fsfat_basic_timer.stop(); + fclose(file); +#ifdef FSFAT_DEBUG + double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0; + double speed = kib_rw / test_time_sec; + FSFAT_DBGLOG("%d KiB read in %.3f sec with speed of %.4f KiB/s\n", byte_read, test_time_sec, speed); +#endif + fsfat_basic_timer.reset(); + return true; +} + + +/** @brief basic test to write a file to sd card. + * + * This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_stdio/main.cpp. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_09() +{ + // Test header + FSFAT_DBGLOG("\n%s:SD Card Stdio Performance Test\n", __func__); + FSFAT_DBGLOG("File name: %s\n", fsfat_basic_bin_filename); + FSFAT_DBGLOG("Buffer size: %d KiB\n", (FSFAT_BASIC_KIB_RW * sizeof(fsfat_basic_buffer)) / 1024); + + // Initialize buffer + srand(0); + char *buffer_end = fsfat_basic_buffer + sizeof(fsfat_basic_buffer); + std::generate (fsfat_basic_buffer, buffer_end, fsfat_basic_test_random_char); + + bool result = true; + for (;;) { + FSFAT_DBGLOG("%s:Write test...\n", __func__); + if (fsfat_basic_test_sf_file_write_stdio(fsfat_basic_bin_filename, FSFAT_BASIC_KIB_RW) == false) { + result = false; + break; + } + + FSFAT_DBGLOG("%s:Read test...\n", __func__); + if (fsfat_basic_test_sf_file_read_stdio(fsfat_basic_bin_filename, FSFAT_BASIC_KIB_RW) == false) { + result = false; + break; + } + break; + } + TEST_ASSERT_MESSAGE(result == true, "Expected true result not found"); + return CaseNext; +} + + +bool fsfat_basic_test_file_write_fatfs(const char *filename, const int kib_rw) +{ + FIL file; + FRESULT res = f_open(&file, filename, FA_WRITE | FA_CREATE_ALWAYS); + + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__); + TEST_ASSERT_MESSAGE(res == FR_OK, fsfat_basic_msg_g); + + int byte_write = 0; + unsigned int bytes = 0; + fsfat_basic_timer.start(); + for (int i = 0; i < kib_rw; i++) { + res = f_write(&file, fsfat_basic_buffer, sizeof(fsfat_basic_buffer), &bytes); + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to write to file.\n", __func__); + TEST_ASSERT_MESSAGE(res == FR_OK, fsfat_basic_msg_g); + byte_write++; + } + fsfat_basic_timer.stop(); + f_close(&file); +#ifdef FSFAT_DEBUG + double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0; + double speed = kib_rw / test_time_sec; + FSFAT_DBGLOG("%d KiB write in %.3f sec with speed of %.4f KiB/s\n", byte_write, test_time_sec, speed); +#endif + fsfat_basic_timer.reset(); + return true; +} + +bool fsfat_basic_test_file_read_fatfs(const char *filename, const int kib_rw) +{ + FIL file; + FRESULT res = f_open(&file, filename, FA_READ | FA_OPEN_EXISTING); + + FSFAT_BASIC_MSG(fsfat_basic_msg_g, FSFAT_BASIC_MSG_BUF_SIZE, "%s: Error: failed to open file.\n", __func__); + TEST_ASSERT_MESSAGE(res == FR_OK, fsfat_basic_msg_g); + + fsfat_basic_timer.start(); + int byte_read = 0; + unsigned int bytes = 0; + do { + res = f_read(&file, fsfat_basic_buffer, sizeof(fsfat_basic_buffer), &bytes); + byte_read++; + } while (res == FR_OK && bytes == sizeof(fsfat_basic_buffer)); + fsfat_basic_timer.stop(); + f_close(&file); +#ifdef FSFAT_DEBUG + double test_time_sec = fsfat_basic_timer.read_us() / 1000000.0; + double speed = kib_rw / test_time_sec; + FSFAT_DBGLOG("%d KiB read in %.3f sec with speed of %.4f KiB/s\n", byte_read, test_time_sec, speed); +#endif + fsfat_basic_timer.reset(); + return true; +} + +/** @brief basic test to write a file to sd card. + * + * This test has been ported from armmbed/mbed-os/features/unsupported/tests/mbed/sd_perf_stdio/main.cpp. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_basic_test_10() +{ + // Test header + FSFAT_DBGLOG("\n%sSD Card FatFS Performance Test\n", __func__); + FSFAT_DBGLOG("File name: %s\n", fsfat_basic_bin_filename_test_10); + FSFAT_DBGLOG("Buffer size: %d KiB\n", (FSFAT_BASIC_KIB_RW * sizeof(fsfat_basic_buffer)) / 1024); + + // Initialize buffer + srand(1); + char *buffer_end = fsfat_basic_buffer + sizeof(fsfat_basic_buffer); + std::generate (fsfat_basic_buffer, buffer_end, fsfat_basic_test_random_char); + + bool result = true; + for (;;) { + FSFAT_DBGLOG("%s:Write test...\n", __func__); + if (fsfat_basic_test_file_write_fatfs(fsfat_basic_bin_filename_test_10, FSFAT_BASIC_KIB_RW) == false) { + result = false; + break; + } + + FSFAT_DBGLOG("%s:Read test...\n", __func__); + if (fsfat_basic_test_file_read_fatfs(fsfat_basic_bin_filename_test_10, FSFAT_BASIC_KIB_RW) == false) { + result = false; + break; + } + break; + } + TEST_ASSERT_MESSAGE(result == true, "Expected true result not found"); + return CaseNext; +} + +#else + +#define FSFAT_BASIC_TEST_00 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_01 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_02 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_03 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_04 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_05 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_06 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_07 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_08 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_09 fsfat_basic_test_dummy +#define FSFAT_BASIC_TEST_10 fsfat_basic_test_dummy + + +/** @brief fsfat_basic_test_dummy Dummy test case for testing when platform doesnt have an SDCard installed. + * + * @return success always + */ +static control_t fsfat_basic_test_dummy() +{ + printf("Null test\n"); + return CaseNext; +} + +#endif + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(300, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FSFAT_BASIC_TEST_00: fopen()/fgetc()/fprintf()/fclose() test.", FSFAT_BASIC_TEST_00), + Case("FSFAT_BASIC_TEST_01: fopen()/fseek()/fclose() test.", FSFAT_BASIC_TEST_01), + /* WARNING: Test case not working but currently not required for PAL support + * Case("FSFAT_BASIC_TEST_02: fopen()/fgets()/fputs()/ftell()/rewind()/remove() test.", FSFAT_BASIC_TEST_02) */ + Case("FSFAT_BASIC_TEST_03: tmpnam() test.", FSFAT_BASIC_TEST_03), + Case("FSFAT_BASIC_TEST_04: fileno() test.", FSFAT_BASIC_TEST_04), + Case("FSFAT_BASIC_TEST_05: opendir() basic test.", FSFAT_BASIC_TEST_05), + Case("FSFAT_BASIC_TEST_06: fread()/fwrite() file to sdcard.", FSFAT_BASIC_TEST_06), + Case("FSFAT_BASIC_TEST_07: sdcard fwrite() file test.", FSFAT_BASIC_TEST_07), + Case("FSFAT_BASIC_TEST_08: FATFileSystem::read()/write() test.", FSFAT_BASIC_TEST_08), + Case("FSFAT_BASIC_TEST_09: POSIX FILE API fread()/fwrite() test.", FSFAT_BASIC_TEST_09), + Case("FSFAT_BASIC_TEST_10: ChanFS read()/write()) test.", FSFAT_BASIC_TEST_10), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 sd-driver/TESTS/filesystem/dirs/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/TESTS/filesystem/dirs/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,472 @@ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include <stdlib.h> +#include <errno.h> + +using namespace utest::v1; + +// test configuration +#ifndef MBED_TEST_FILESYSTEM +#define MBED_TEST_FILESYSTEM FATFileSystem +#endif + +#ifndef MBED_TEST_FILESYSTEM_DECL +#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") +#endif + +#ifndef MBED_TEST_BLOCKDEVICE +#define MBED_TEST_BLOCKDEVICE SDBlockDevice +#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); +#endif + +#ifndef MBED_TEST_BLOCKDEVICE_DECL +#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd +#endif + +#ifndef MBED_TEST_FILES +#define MBED_TEST_FILES 4 +#endif + +#ifndef MBED_TEST_DIRS +#define MBED_TEST_DIRS 4 +#endif + +#ifndef MBED_TEST_BUFFER +#define MBED_TEST_BUFFER 8192 +#endif + +#ifndef MBED_TEST_TIMEOUT +#define MBED_TEST_TIMEOUT 120 +#endif + + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_FILESYSTEM) +#include INCLUDE(MBED_TEST_BLOCKDEVICE) + +MBED_TEST_FILESYSTEM_DECL; +MBED_TEST_BLOCKDEVICE_DECL; + +Dir dir[MBED_TEST_DIRS]; +File file[MBED_TEST_FILES]; +DIR *dd[MBED_TEST_DIRS]; +FILE *fd[MBED_TEST_FILES]; +struct dirent ent; +struct dirent *ed; +size_t size; +uint8_t buffer[MBED_TEST_BUFFER]; +uint8_t rbuffer[MBED_TEST_BUFFER]; +uint8_t wbuffer[MBED_TEST_BUFFER]; + + +// tests + +void test_directory_tests() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = MBED_TEST_FILESYSTEM::format(&bd); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_root_directory() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_directory_creation() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_file_creation() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "burito", O_CREAT | O_WRONLY); + TEST_ASSERT_EQUAL(0, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void dir_file_check(char *list[], uint32_t elements) { + int res; + while(1) { + res = dir[0].read(&ent); + if (0 == res) { + break; + } + for (int i = 0; i < elements ; i++) { + res = strcmp(ent.d_name, list[i]); + if (0 == res) { + res = ent.d_type; + if ((DT_DIR != res) && (DT_REG != res)) { + TEST_ASSERT(1); + } + break; + } + else if( i == elements) { + TEST_ASSERT_EQUAL(0, res); + } + } + } +} + +void test_directory_iteration() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"potato", "burito", ".", ".."}; + + dir_file_check(dir_list, (sizeof(dir_list)/sizeof(dir_list[0]))); + + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_directory_failures() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato", 0777); + TEST_ASSERT_EQUAL(-EEXIST, res); + res = dir[0].open(&fs, "tomato"); + TEST_ASSERT_EQUAL(-ENOENT, res); + res = dir[0].open(&fs, "burito"); + TEST_ASSERT_NOT_EQUAL(0, res); + res = file[0].open(&fs, "tomato", O_RDONLY); + TEST_ASSERT_EQUAL(-ENOENT, res); + res = file[0].open(&fs, "potato", O_RDONLY); + TEST_ASSERT_NOT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_nested_directories() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato/baked", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato/sweet", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("potato/fried", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"potato", "baked", "sweet", "fried", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list)/sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_multi_block_directory() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("cactus", 0777); + TEST_ASSERT_EQUAL(0, res); + for (int i = 0; i < 128; i++) { + sprintf((char*)buffer, "cactus/test%d", i); + res = fs.mkdir((char*)buffer, 0777); + TEST_ASSERT_EQUAL(0, res); + } + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "cactus"); + TEST_ASSERT_EQUAL(0, res); + +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + char *dir_list[] = {".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list)/sizeof(dir_list[0]))); +#endif + + for (int i = 0; i < 128; i++) { + sprintf((char*)buffer, "test%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char*)buffer); + TEST_ASSERT_EQUAL(0, res); + } + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_directory_remove() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("potato"); + TEST_ASSERT_NOT_EQUAL(0, res); + res = fs.remove("potato/sweet"); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("potato/baked"); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("potato/fried"); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "potato"); + TEST_ASSERT_EQUAL(0, res); + +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + char *dir_list[] = {".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list)/sizeof(dir_list[0]))); +#endif + + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("potato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"burito", "cactus", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list)/sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_directory_rename() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato/baked", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato/sweet", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato/fried", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("coldpotato", "hotpotato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "hotpotato"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"baked", "sweet", "fried", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list)/sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("warmpotato", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("warmpotato/mushy", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("hotpotato", "warmpotato"); + TEST_ASSERT_NOT_EQUAL(0, res); + res = fs.remove("warmpotato/mushy"); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("warmpotato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("hotpotato", "warmpotato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "warmpotato"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"baked", "sweet", "fried", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list)/sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("coldpotato", 0777); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("warmpotato/baked", "coldpotato/baked"); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("warmpotato/sweet", "coldpotato/sweet"); + TEST_ASSERT_EQUAL(0, res); + res = fs.rename("warmpotato/fried", "coldpotato/fried"); + TEST_ASSERT_EQUAL(0, res); + res = fs.remove("coldpotato"); + TEST_ASSERT_NOT_EQUAL(0, res); + res = fs.remove("warmpotato"); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "coldpotato"); + TEST_ASSERT_EQUAL(0, res); + char *dir_list[] = {"baked", "sweet", "fried", ".", ".."}; + dir_file_check(dir_list, (sizeof(dir_list)/sizeof(dir_list[0]))); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + + + +// test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Directory tests", test_directory_tests), + Case("Root directory", test_root_directory), + Case("Directory creation", test_directory_creation), + Case("File creation", test_file_creation), + Case("Directory iteration", test_directory_iteration), + Case("Directory failures", test_directory_failures), + Case("Nested directories", test_nested_directories), + Case("Multi-block directory", test_multi_block_directory), + Case("Directory remove", test_directory_remove), + Case("Directory rename", test_directory_rename), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 sd-driver/TESTS/filesystem/files/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/TESTS/filesystem/files/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,314 @@ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include <stdlib.h> +#include <errno.h> + +using namespace utest::v1; + +// test configuration +#ifndef MBED_TEST_FILESYSTEM +#define MBED_TEST_FILESYSTEM FATFileSystem +#endif + +#ifndef MBED_TEST_FILESYSTEM_DECL +#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") +#endif + +#ifndef MBED_TEST_BLOCKDEVICE +#define MBED_TEST_BLOCKDEVICE SDBlockDevice +#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); +#endif + +#ifndef MBED_TEST_BLOCKDEVICE_DECL +#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd +#endif + +#ifndef MBED_TEST_FILES +#define MBED_TEST_FILES 4 +#endif + +#ifndef MBED_TEST_DIRS +#define MBED_TEST_DIRS 4 +#endif + +#ifndef MBED_TEST_BUFFER +#define MBED_TEST_BUFFER 8192 +#endif + +#ifndef MBED_TEST_TIMEOUT +#define MBED_TEST_TIMEOUT 120 +#endif + + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_FILESYSTEM) +#include INCLUDE(MBED_TEST_BLOCKDEVICE) + +MBED_TEST_FILESYSTEM_DECL; +MBED_TEST_BLOCKDEVICE_DECL; + +Dir dir[MBED_TEST_DIRS]; +File file[MBED_TEST_FILES]; +DIR *dd[MBED_TEST_DIRS]; +FILE *fd[MBED_TEST_FILES]; +struct dirent ent; +struct dirent *ed; +size_t size; +uint8_t buffer[MBED_TEST_BUFFER]; +uint8_t rbuffer[MBED_TEST_BUFFER]; +uint8_t wbuffer[MBED_TEST_BUFFER]; + +static char file_counter = 0; +const char *filenames[] = {"smallavacado", "mediumavacado", "largeavacado", + "blockfile", "bigblockfile", "hello", ".", ".."}; + +// tests + +void test_file_tests() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = MBED_TEST_FILESYSTEM::format(&bd); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_simple_file_test() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello", O_WRONLY | O_CREAT); + TEST_ASSERT_EQUAL(0, res); + size = strlen("Hello World!\n"); + memcpy(wbuffer, "Hello World!\n", size); + res = file[0].write(wbuffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + size = strlen("Hello World!\n"); + res = file[0].read(rbuffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(rbuffer, wbuffer, size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +template <int file_size, int write_size, int read_size> +void test_write_file_test() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + size_t size = file_size; + size_t chunk = write_size; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, filenames[file_counter], O_WRONLY | O_CREAT); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + for (size_t b = 0; b < chunk; b++) { + buffer[b] = rand() & 0xff; + } + res = file[0].write(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + size_t size = file_size; + size_t chunk = read_size; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, filenames[file_counter], O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + res = file[0].read(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + for (size_t b = 0; b < chunk && i+b < size; b++) { + res = buffer[b]; + TEST_ASSERT_EQUAL(rand() & 0xff, res); + } + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + file_counter++; + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_non_overlap_check() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + size_t size = 32; + size_t chunk = 29; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "smallavacado", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + res = file[0].read(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + for (size_t b = 0; b < chunk && i+b < size; b++) { + res = buffer[b]; + TEST_ASSERT_EQUAL(rand() & 0xff, res); + } + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + size_t size = 8192; + size_t chunk = 29; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "mediumavacado", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + res = file[0].read(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + for (size_t b = 0; b < chunk && i+b < size; b++) { + res = buffer[b]; + TEST_ASSERT_EQUAL(rand() & 0xff, res); + } + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + { + size_t size = 262144; + size_t chunk = 29; + srand(0); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "largeavacado", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + for (size_t i = 0; i < size; i += chunk) { + chunk = (chunk < size - i) ? chunk : size - i; + res = file[0].read(buffer, chunk); + TEST_ASSERT_EQUAL(chunk, res); + for (size_t b = 0; b < chunk && i+b < size; b++) { + res = buffer[b]; + TEST_ASSERT_EQUAL(rand() & 0xff, res); + } + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_dir_check() { + + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "/"); + TEST_ASSERT_EQUAL(0, res); + int numFiles = sizeof(filenames)/sizeof(filenames[0]); + // Check the filenames in directory + while(1) { + res = dir[0].read(&ent); + if (0 == res) { + break; + } + for (int i=0; i < numFiles ; i++) { + res = strcmp(ent.d_name, filenames[i]); + if (0 == res) { + res = ent.d_type; + if ((DT_REG != res) && (DT_DIR != res)) { + TEST_ASSERT(1); + } + break; + } + else if( i == numFiles) { + TEST_ASSERT_EQUAL(0, res); + } + } + } + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + + +// test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("File tests", test_file_tests), + Case("Simple file test", test_simple_file_test), + Case("Small file test", test_write_file_test<32, 31, 29>), + Case("Medium file test", test_write_file_test<8192, 31, 29>), + Case("Large file test", test_write_file_test<262144, 31, 29>), + Case("Block Size file test", test_write_file_test<9000, 512, 512>), + Case("Multiple block size file test", test_write_file_test<26215, MBED_TEST_BUFFER, MBED_TEST_BUFFER>), + Case("Non-overlap check", test_non_overlap_check), + Case("Dir check", test_dir_check), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 sd-driver/TESTS/filesystem/fopen/fopen.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/TESTS/filesystem/fopen/fopen.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1519 @@ +/* + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @file fopen.cpp Test cases to POSIX file fopen() interface. + * + * Please consult the documentation under the test-case functions for + * a description of the individual test case. + */ + +#include "mbed.h" +#include "mbed_config.h" +#include "SDBlockDevice.h" +#include "FATFileSystem.h" +#include "fsfat_debug.h" +#include "fsfat_test.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> /*rand()*/ +#include <inttypes.h> +#include <errno.h> +/* mbed_retarget.h is included after errno.h so symbols are mapped to + * consistent values for all toolchains */ +#include "platform/mbed_retarget.h" + +using namespace utest::v1; + +/// @cond FSFAT_DOXYGEN_DISABLE +#ifdef FSFAT_DEBUG +#define FSFAT_FOPEN_GREENTEA_TIMEOUT_S 3000 +#else +#define FSFAT_FOPEN_GREENTEA_TIMEOUT_S 1000 +#endif +/// @endcond + + +/* DEVICE_SPI + * This symbol is defined in targets.json if the target has a SPI interface, which is required for SDCard support. + * + * MBED_CONF_APP_FSFAT_SDCARD_INSTALLED + * For testing purposes, an SDCard must be installed on the target for the test cases in this file to succeed. + * If the target has an SD card installed then the MBED_CONF_APP_FSFAT_SDCARD_INSTALLED will be generated + * from the mbed_app.json, which includes the line + * { + * "config": { + * "UART_RX": "D0", + * <<< lines removed >>> + * "DEVICE_SPI": 1, + * "FSFAT_SDCARD_INSTALLED": 1 + * }, + * <<< lines removed >>> + */ + +#if defined(DEVICE_SPI) && ( defined(MBED_CONF_APP_FSFAT_SDCARD_INSTALLED) || (MBED_CONF_SD_FSFAT_SDCARD_INSTALLED)) +static char fsfat_fopen_utest_msg_g[FSFAT_UTEST_MSG_BUF_SIZE]; +#define FSFAT_FOPEN_TEST_MOUNT_PT_NAME "sd" +#define FSFAT_FOPEN_TEST_MOUNT_PT_PATH "/" FSFAT_FOPEN_TEST_MOUNT_PT_NAME +#define FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1 64 +#define FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH 20 +static const char *sd_badfile_path = "/sd/badfile.txt"; +static const char *sd_testfile_path = "/sd/test.txt"; + +SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); +FATFileSystem fs("sd", &sd); + +#define FSFAT_FOPEN_TEST_01 fsfat_fopen_test_01 +#define FSFAT_FOPEN_TEST_02 fsfat_fopen_test_02 +#define FSFAT_FOPEN_TEST_03 fsfat_fopen_test_03 +#define FSFAT_FOPEN_TEST_04 fsfat_fopen_test_04 +#define FSFAT_FOPEN_TEST_05 fsfat_fopen_test_05 +#define FSFAT_FOPEN_TEST_06 fsfat_fopen_test_06 +#define FSFAT_FOPEN_TEST_07 fsfat_fopen_test_07 +#define FSFAT_FOPEN_TEST_08 fsfat_fopen_test_08 +#define FSFAT_FOPEN_TEST_09 fsfat_fopen_test_09 +#define FSFAT_FOPEN_TEST_10 fsfat_fopen_test_10 +#define FSFAT_FOPEN_TEST_11 fsfat_fopen_test_11 +#define FSFAT_FOPEN_TEST_12 fsfat_fopen_test_12 +#define FSFAT_FOPEN_TEST_13 fsfat_fopen_test_13 +#define FSFAT_FOPEN_TEST_14 fsfat_fopen_test_14 +#define FSFAT_FOPEN_TEST_15 fsfat_fopen_test_15 +#define FSFAT_FOPEN_TEST_16 fsfat_fopen_test_16 +#define FSFAT_FOPEN_TEST_17 fsfat_fopen_test_17 +#define FSFAT_FOPEN_TEST_18 fsfat_fopen_test_18 +#define FSFAT_FOPEN_TEST_19 fsfat_fopen_test_19 +#define FSFAT_FOPEN_TEST_20 fsfat_fopen_test_20 +#define FSFAT_FOPEN_TEST_21 fsfat_fopen_test_21 +#define FSFAT_FOPEN_TEST_22 fsfat_fopen_test_22 +#define FSFAT_FOPEN_TEST_23 fsfat_fopen_test_23 +#define FSFAT_FOPEN_TEST_24 fsfat_fopen_test_24 +#define FSFAT_FOPEN_TEST_25 fsfat_fopen_test_25 +#define FSFAT_FOPEN_TEST_26 fsfat_fopen_test_26 +#define FSFAT_FOPEN_TEST_27 fsfat_fopen_test_27 +#define FSFAT_FOPEN_TEST_28 fsfat_fopen_test_28 +#define FSFAT_FOPEN_TEST_29 fsfat_fopen_test_29 +#define FSFAT_FOPEN_TEST_30 fsfat_fopen_test_30 + + +/* support functions */ + +/* + * open tests that focus on testing fopen() + * fsfat_handle_t fopen(const char* filename, char* data, size_t* len, fsfat_key_desc_t* kdesc) + */ + +/* file data for test_01 */ +static fsfat_kv_data_t fsfat_fopen_test_01_kv_data[] = { + { "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt", "missing"}, + { NULL, NULL}, +}; + + +/** @brief + * Split a file path into its component parts, setting '/' characters to '\0', and returning + * pointers to the file path components in the parts array. For example, if + * filepath = "/sd/fopentst/hello/world/animal/wobbly/dog/foot/frontlft.txt" then + * *parts[0] = "sd" + * *parts[1] = "fopentst" + * *parts[2] = "hello" + * *parts[3] = "world" + * *parts[4] = "animal" + * *parts[5] = "wobbly" + * *parts[6] = "dog" + * *parts[7] = "foot" + * *parts[8] = "frontlft.txt" + * parts[9] = NULL + * + * ARGUMENTS + * @param filepath IN file path string to split into component parts. Expected to start with '/' + * @param parts IN OUT array to hold pointers to parts + * @param num IN number of components available in parts + * + * @return On success, this returns the number of components in the filepath Returns number of compoee + */ +static int32_t fsfat_filepath_split(char* filepath, char* parts[], uint32_t num) +{ + uint32_t i = 0; + int32_t ret = -1; + char* z = filepath; + + while (i < num && *z != '\0') { + if (*z == '/' ) { + *z = '\0'; + parts[i] = ++z; + i++; + } else { + z++; + } + } + if (*z == '\0' && i > 0) { + ret = (int32_t) i; + } + return ret; +} + + +/** @brief + * remove all directories and file in the given filepath + * + * ARGUMENTS + * @param filepath IN file path string to split into component parts. Expected to start with '/' + * + * @return On success, this returns 0, otherwise < 0 is returned; + */ +int32_t fsfat_filepath_remove_all(char* filepath) +{ + int32_t ret = -1; + int32_t len = 0; + char *fpathbuf = NULL; + char *pos = NULL; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + len = strlen(filepath); + fpathbuf = (char*) malloc(len+1); + if (fpathbuf == NULL) { + FSFAT_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__); + return ret; + } + memset(fpathbuf, 0, len+1); + memcpy(fpathbuf, filepath, len); + + /* delete the leaf node first, and then successively parent directories. */ + pos = fpathbuf + strlen(fpathbuf); + while (pos != fpathbuf) { + /* If the remaining file path is the mount point path then finish as the mount point cannot be removed */ + if (strlen(fpathbuf) == strlen(FSFAT_FOPEN_TEST_MOUNT_PT_PATH)) { + if( strncmp(fpathbuf, FSFAT_FOPEN_TEST_MOUNT_PT_PATH, strlen(fpathbuf)) == 0) { + break; + } + } + ret = remove(fpathbuf); + pos = strrchr(fpathbuf, '/'); + *pos = '\0'; + } + if (fpathbuf) { + free(fpathbuf); + } + return ret; +} + + +/** @brief + * make all directories in the given filepath. Do not create the file if present at end of filepath + * + * ARGUMENTS + * @param filepath IN file path containing directories and file + * @param do_asserts IN set to true if function should assert on errors + * + * @return On success, this returns 0, otherwise < 0 is returned; + */ +static int32_t fsfat_filepath_make_dirs(char* filepath, bool do_asserts) +{ + int32_t i = 0; + int32_t num_parts = 0; + int32_t len = 0; + int32_t ret = -1; + char *fpathbuf = NULL; + char *buf = NULL; + int pos = 0; + char *parts[FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH]; + + FSFAT_DBGLOG("%s:entered\n", __func__); + /* find the dirs to create*/ + memset(parts, 0, sizeof(parts)); + len = strlen(filepath); + fpathbuf = (char*) malloc(len+1); + if (fpathbuf == NULL) { + FSFAT_DBGLOG("%s: failed to duplicate string (out of memory)\n", __func__); + return ret; + } + memset(fpathbuf, 0, len+1); + memcpy(fpathbuf, filepath, len); + num_parts = fsfat_filepath_split(fpathbuf, parts, FSFAT_FOPEN_TEST_FILEPATH_MAX_DEPTH); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to split filepath (filename=\"%s\", num_parts=%d)\n", __func__, filepath, (int) num_parts); + TEST_ASSERT_MESSAGE(num_parts > 0, fsfat_fopen_utest_msg_g); + + /* Now create the directories on the directory path. + * Skip creating dir for "/sd" which must be present */ + buf = (char*) malloc(strlen(filepath)+1); + memset(buf, 0, strlen(filepath)+1); + pos = sprintf(buf, "/%s", parts[0]); + for (i = 1; i < num_parts - 1; i++) { + pos += sprintf(buf+pos, "/%s", parts[i]); + FSFAT_DBGLOG("mkdir(%s)\n", buf); + ret = mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (do_asserts == true) { + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create directory (filepath2=\"%s\", ret=%d, errno=%d)\n", __func__, buf, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + } + } + + if (buf) { + free(buf); + } + if (fpathbuf) { + free(fpathbuf); + } + return ret; +} + + +/* FIX ME: errno not set correctly when error occurs. This indicates a problem with the implementation. */ + +/** @brief + * Basic fopen test which does the following: + * - creates file and writes some data to the value blob. + * - closes the newly created file. + * - opens the file (r-only) + * - reads the file data and checks its the same as the previously created data. + * - closes the opened file + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +static control_t fsfat_fopen_test_01(const size_t call_count) +{ + char* read_buf; + int32_t ret = 0; + size_t len = 0; + fsfat_kv_data_t *node; + FILE *fp = NULL; + + FSFAT_DBGLOG("%s:entered\n", __func__); + (void) call_count; + node = fsfat_fopen_test_01_kv_data; + + /* remove file and directory from a previous failed test run, if present */ + fsfat_filepath_remove_all((char*) node->filename); + + /* create dirs */ + ret = fsfat_filepath_make_dirs((char*) node->filename, true); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + FSFAT_DBGLOG("%s:About to create new file (filename=\"%s\", data=\"%s\")\n", __func__, node->filename, node->value); + fp = fopen(node->filename, "w+"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (filename=\"%s\", data=\"%s\")(ret=%d, errno=%d)\n", __func__, node->filename, node->value, (int) ret, errno); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + FSFAT_DBGLOG("%s:length of file=%d (filename=\"%s\", data=\"%s\")\n", __func__, (int) len, node->filename, node->value); + len = strlen(node->value); + ret = fwrite((const void*) node->value, len, 1, fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write file (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename, node->value, (int) ret); + TEST_ASSERT_MESSAGE(ret == 1, fsfat_fopen_utest_msg_g); + + FSFAT_DBGLOG("Created file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value); + ret = fclose(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* now open the newly created key */ + fp = NULL; + fp = fopen(node->filename, "r"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file for reading (filename=\"%s\", data=\"%s\")(ret=%d)\n", __func__, node->filename, node->value, (int) ret); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + len = strlen(node->value) + 1; + read_buf = (char*) malloc(len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to allocated read buffer \n", __func__); + TEST_ASSERT_MESSAGE(read_buf != NULL, fsfat_fopen_utest_msg_g); + + FSFAT_DBGLOG("Opened file successfully (filename=\"%s\", data=\"%s\")\n", node->filename, node->value); + memset(read_buf, 0, len); + ret = fread((void*) read_buf, len, 1, fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read file (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n", __func__, node->filename, node->value, read_buf, (int) ret); + /* FIX ME: fread should return the number of items read, not 0 when an item is read successfully. + * This indicates a problem with the implementation, as the correct data is read. The correct assert should be: + * TEST_ASSERT_MESSAGE(ret == 1, fsfat_fopen_utest_msg_g); + * The following assert is curerntly used until the implementation is fixed + */ + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* check read data is as expected */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: read value data (%s) != expected value data (filename=\"%s\", data=\"%s\", read_buf=\"%s\", ret=%d)\n", __func__, read_buf, node->filename, node->value, read_buf, (int) ret); + TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, fsfat_fopen_utest_msg_g); + + if(read_buf){ + free(read_buf); + } + ret = fclose(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed (ret=%d, errno=%d).\n", __func__, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + return CaseNext; +} + +static fsfat_kv_data_t fsfat_fopen_test_02_data[] = { + FSFAT_INIT_1_TABLE_MID_NODE, + { NULL, NULL}, +}; + +/** + * @brief test to fopen() a pre-existing key and try to write it, which should fail + * as by default pre-existing keys are opened read-only + * + * Basic open test which does the following: + * - creates file with default rw perms and writes some data to the value blob. + * - closes the newly created file. + * - opens the file with the default permissions (read-only) + * - tries to write the file data which should fail because file was not opened with write flag set. + * - closes the opened key + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_02(const size_t call_count) +{ + int32_t ret = -1; + size_t len = 0; + FILE *fp = NULL; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char*) fsfat_fopen_test_02_data[0].value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + /* by default, owner of key opens with read-only permissions*/ + fp = fopen(fsfat_fopen_test_02_data[0].filename, "r"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file (filename=\"%s\", ret=%d)\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fwrite((const void*) fsfat_fopen_test_02_data[0].value, len, 1, fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: call to fwrite() succeeded when should have failed for read-only file (filename=\"%s\")(ret=%d).\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(ret <= 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(fclose(fp) == 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/** + * @brief test to fopen() a pre-existing file and try to write it, which should succeed + * because the key was opened read-write permissions explicitly + * + * Basic open test which does the following: + * - creates file with default rw perms and writes some data to the value blob. + * - closes the newly created file. + * - opens the file with the rw permissions (non default) + * - tries to write the file data which should succeeds because file was opened with write flag set. + * - closes the opened key + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_03(const size_t call_count) +{ + int32_t ret = -1; + size_t len = 0; + FILE *fp = NULL; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char*) fsfat_fopen_test_02_data[0].value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file in store (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + /* opens with read-write permissions*/ + fp = fopen(fsfat_fopen_test_02_data[0].filename, "w+"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file (filename=\"%s\")(ret=%d)\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fwrite((const void*) fsfat_fopen_test_02_data[0].value, len, 1, fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: call to fwrite() failed when should have succeeded (filename=\"%s\", ret=%d).\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fclose() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(fclose(fp) >= 0, fsfat_fopen_utest_msg_g); + + /* clean-up */ + ret = remove(fsfat_fopen_test_02_data[0].filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unable to delete file (filename=%s, ret=%d) .\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/** @brief test to call fopen() with a filename string that exceeds the maximum length + * - chanFS supports the exFAT format which should support 255 char filenames + * - check that filenames of this length can be created + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_04(const size_t call_count) +{ + char filename_good[FSFAT_FILENAME_MAX_LENGTH+1]; + char filename_bad[FSFAT_FILENAME_MAX_LENGTH+2]; + int32_t ret = -1; + size_t len = 0; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + memset(filename_good, 0, FSFAT_FILENAME_MAX_LENGTH+1); + memset(filename_bad, 0, FSFAT_FILENAME_MAX_LENGTH+2); + ret = fsfat_test_filename_gen(filename_good, FSFAT_FILENAME_MAX_LENGTH); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate filename_good.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: filename_good is not the correct length (filename_good=%s, len=%d, expected=%d).\n", __func__, filename_good, (int) strlen(filename_good), (int) FSFAT_FILENAME_MAX_LENGTH); + TEST_ASSERT_MESSAGE(strlen(filename_good) == FSFAT_FILENAME_MAX_LENGTH, fsfat_fopen_utest_msg_g); + + ret = fsfat_test_filename_gen(filename_bad, FSFAT_FILENAME_MAX_LENGTH+1); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate filename_bad.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: filename_bad is not the correct length (len=%d, expected=%d).\n", __func__, (int) strlen(filename_bad), (int) FSFAT_FILENAME_MAX_LENGTH+1); + TEST_ASSERT_MESSAGE(strlen(filename_bad) == FSFAT_FILENAME_MAX_LENGTH+1, fsfat_fopen_utest_msg_g); + + len = strlen(filename_good); + ret = fsfat_test_create(filename_good, filename_good, len); + /* FIXME: + * The current implementation can create file with a filename with 9 chars (more than the 8 restriction of FAT32 Short File Names). + * However, the exFAT 255 char filesnames is not supported and hence the following is commented out. Find out what is + * the supported max filename length and change this testcase according. + * + * FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (filename=%s, ret=%d).\n", __func__, filename_good, (int) ret); + * TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + */ + + len = strlen(filename_bad); + ret = fsfat_test_create(filename_bad, filename_bad, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: created file in store for filename_bad when should have failed (filename=%s, ret=%d).\n", __func__, filename_bad, (int) ret); + TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g); + return CaseNext; +} + + +/// @cond FSFAT_DOXYGEN_DISABLE +typedef struct fsfat_fopen_kv_name_ascii_node { + uint32_t code; + uint32_t f_allowed : 1; +} fsfat_fopen_kv_name_ascii_node; +/// @endcond + +static const uint32_t fsfat_fopen_kv_name_ascii_table_code_sentinel_g = 256; + +/*@brief table recording ascii character codes permitted in kv names */ +static fsfat_fopen_kv_name_ascii_node fsfat_fopen_kv_name_ascii_table[] = +{ + {0 , true}, /* code 0-33 allowed*/ + {34, false}, /* '"' not allowed */ + {35, true}, /* allowed */ + {42, false}, /* '*' not allowed */ + {43, true}, /* allowed */ + {47, false}, /* '/' not allowed */ + {48, true}, /* allowed */ + {58, false}, /* ':' not allowed */ + {59, true}, /* allowed */ + {60, false}, /* '<' not allowed */ + {61, true}, /* allowed */ + {62, false}, /* '?', '>' not allowed */ + {64, true}, /* allowed */ + {92, false}, /* '\' not allowed */ + {93, true}, /* allowed */ + {124, false}, /* '!' not allowed */ + {125, true}, /* allowed */ + {127, false}, /* DEL not allowed */ + {128, true}, /* allowed */ + {fsfat_fopen_kv_name_ascii_table_code_sentinel_g, false}, /* sentinel */ +}; + + +/// @cond FSFAT_DOXYGEN_DISABLE +enum fsfat_fopen_kv_name_pos { + fsfat_fopen_kv_name_pos_start = 0x0, + fsfat_fopen_kv_name_pos_mid, + fsfat_fopen_kv_name_pos_end, + fsfat_fopen_kv_name_pos_max +}; +/// @endcond + +/** @brief test to call fopen() with filename that in includes illegal characters + * - the character(s) can be at the beginning of the filename + * - the character(s) can be at the end of the filename + * - the character(s) can be somewhere within the filename string + * - a max-length string of random characters (legal and illegal) + * - a max-length string of random illegal characters only + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_05(const size_t call_count) +{ + bool f_allowed = false; + const char *mnt_pt = FSFAT_FOPEN_TEST_MOUNT_PT_PATH; + const char *basename = "goodfile"; + const char *extname = "txt"; + const size_t basename_len = strlen(basename); + const size_t filename_len = strlen(mnt_pt)+strlen(basename)+strlen(extname)+2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */ + char filename[FSFAT_BUF_MAX_LENGTH]; + size_t len = 0; + uint32_t j = 0; + int32_t ret = 0; + fsfat_fopen_kv_name_ascii_node* node = NULL; + uint32_t pos; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + +#ifdef FSFAT_DEBUG + /* symbol only used why debug is enabled */ + const char* pos_str = NULL; +#endif + + /* create bad keyname strings with invalid character code at start of keyname */ + node = fsfat_fopen_kv_name_ascii_table; + memset(filename, 0, FSFAT_BUF_MAX_LENGTH); + while(node->code != fsfat_fopen_kv_name_ascii_table_code_sentinel_g) + { + /* loop over range */ + for(j = node->code; j < (node+1)->code; j++) + { + if( (j >= 48 && j <= 57) || (j >= 65 && j <= 90) || (j >= 97 && j <= 122)) { + FSFAT_DBGLOG("%s: skipping alpha-numeric ascii character code %d (%c).\n", __func__, (int) j, (char) j); + continue; + } + + /* set the start, mid, last character of the name to the test char code */ + for(pos = (uint32_t) fsfat_fopen_kv_name_pos_start; pos < (uint32_t) fsfat_fopen_kv_name_pos_max; pos++) + { + len = snprintf(filename, filename_len+1, "%s/%s.%s", mnt_pt, basename, extname); + /* overwrite a char at the pos start, mid, end of the filename with an ascii char code (both illegal and legal)*/ + switch(pos) + { + case fsfat_fopen_kv_name_pos_start: + filename[5] = (char) j; /* 5 so at to write the second basename char (bad chars as first char not accepted)*/ + break; + case fsfat_fopen_kv_name_pos_mid: + /* create bad keyname strings with invalid character code in the middle of keyname */ + filename[5+basename_len/2] = (char) j; + break; + case fsfat_fopen_kv_name_pos_end: + /* create bad keyname strings with invalid character code at end of keyname */ + filename[5+basename_len-1] = (char) j; + break; + default: + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected value of pos (pos=%d).\n", __func__, (int) pos); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + break; + } + +#ifdef FSFAT_DEBUG + /* processing only required when debug trace enabled */ + switch(pos) + { + case fsfat_fopen_kv_name_pos_start: + pos_str = "start"; + break; + case fsfat_fopen_kv_name_pos_mid: + pos_str = "middle"; + break; + case fsfat_fopen_kv_name_pos_end: + pos_str = "end"; + break; + default: + break; + } +#endif + ret = fsfat_test_create(filename, (const char*) filename, len); + + /* special cases */ + switch(j) + { + //case 0 : + //case 46 : + // switch(pos) + // { + // /* for code = 0 (null terminator). permitted at mid and end of string */ + // /* for code = 46 ('.'). permitted at mid and end of string but not at start */ + // case fsfat_fopen_kv_name_pos_start: + // f_allowed = false; + // break; + // case fsfat_fopen_kv_name_pos_mid: + // case fsfat_fopen_kv_name_pos_end: + // default: + // f_allowed = true; + // break; + // } + // break; + default: + f_allowed = node->f_allowed; + break; + } + if(f_allowed == true) + { + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file in store when filename contains valid characters (code=%d, ret=%d).\n", __func__, (int) j, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + /* revert FSFAT_LOG for more trace */ + FSFAT_DBGLOG("Successfully created a file with valid keyname containing ascii character code %d (%c) at the %s of the keyname.\n", (int) j, (int) j, pos_str); + FSFAT_LOG("%c", '.'); + + ret = fsfat_test_delete(filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete file previously created (code=%d, ret=%d).\n", __func__, (int) j, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + } + else + { /*node->f_allowed == false => not allowed to create kv name with ascii code */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: created file in store when filename contains an invalid character (code=%d, ret=%d).\n", __func__, (int) j, (int) ret); + TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g); + /* revert FSFAT_LOG for more trace */ + FSFAT_DBGLOG("Successfully failed to create a file with an invalid keyname containing ascii character code %d at the %s of the keyname.\n", (int) j, pos_str); + FSFAT_LOG("%c", '.'); + } + } + } + node++; + } + + FSFAT_LOG("%c", '\n'); + return CaseNext; +} + + +static const char fsfat_fopen_ascii_illegal_buf_g[] = "\"�'*+,./:;<=>?[\\]|"; + +/** @brief test to call fopen() with filename that in includes + * illegal characters + * - a max-length string of random illegal characters only + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_06(const size_t call_count) +{ + const char *mnt_pt = FSFAT_FOPEN_TEST_MOUNT_PT_PATH; + const char *extname = "txt"; + const size_t filename_len = strlen(mnt_pt)+FSFAT_MAX_FILE_BASENAME+strlen(extname)+2; /* extra 2 chars for '/' and '.' in "/sd/goodfile.txt" */ + char filename[FSFAT_BUF_MAX_LENGTH]; + int32_t i = 0; + int32_t j = 0; + uint32_t pos = 0; + uint32_t len = 0; + int32_t ret = -1; + size_t buf_data_max = 0; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + memset(filename, 0, FSFAT_BUF_MAX_LENGTH); + /* create bad keyname strings with invalid character code at start of keyname */ + buf_data_max = strlen(fsfat_fopen_ascii_illegal_buf_g); + + /* generate a number of illegal filenames */ + for (j = 0; i < FSFAT_MAX_FILE_BASENAME; j++) { + /* generate a kv name of illegal chars*/ + len = snprintf(filename, filename_len+1, "%s/", mnt_pt); + for (i = 0; i < FSFAT_MAX_FILE_BASENAME; i++) { + pos = rand() % (buf_data_max+1); + len += snprintf(filename+len, filename_len+1, "%c", fsfat_fopen_ascii_illegal_buf_g[pos]); + + } + len += snprintf(filename+len, filename_len+1, ".%s", extname); + ret = fsfat_test_create(filename, filename, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: created file when filename contains invalid characters (filename=%s, ret=%d).\n", __func__, filename, (int) ret); + TEST_ASSERT_MESSAGE(ret < 0, fsfat_fopen_utest_msg_g); + } + return CaseNext; +} + + +/** @brief test for errno reporting on a failed fopen()call + * + * This test does the following: + * - tries to open a file that does not exist for reading, and checks that a NULL pointer is returned. + * - checks that errno is not 0 as there is an error. + * - checks that ferror() returns 1 indicating an error exists. + * + * Note: see NOTE_1 below. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_07(const size_t call_count) +{ + FILE *f = NULL; + int ret = -1; + int errno_val = 0; + const char *filename = sd_badfile_path; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + errno = 0; + /* this is expect to fail as the file doesnt exist */ + f = fopen(filename,"r"); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: opened non-existent file for reading (filename=%s, f=%p).\n", __func__, filename, f); + TEST_ASSERT_MESSAGE(f == NULL, fsfat_fopen_utest_msg_g); + + /* check errno is set correctly */ +#if ! defined(__ARMCC_VERSION) && defined(__GNUC__) + /* Store errno so the current value set is not changed by new function call */ + errno_val = errno; + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: errno has unexpected value (errno != 0 expected) (filename=%s, errno=%d).\n", __func__, filename, errno); + TEST_ASSERT_MESSAGE(errno_val != 0, fsfat_fopen_utest_msg_g); +#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */ + return CaseNext; +} + + +/** @brief test for operation of clearerr() and ferror() + * + * The test does the following: + * - opens and then closes a file, but keeps a copy of the FILE pointer fp. + * - set errno to 0. + * - write to the close file with fwrite(fp) which should return 0 (no writes) and set the errno. + * - check the error condition is set with ferror(). + * - clear the error with clearerr(). + * - check the error condition is reset with ferror(). + * + * NOTE_1: GCC/ARMCC support for setting errno + * - Documentation (e.g. fwrite() man page) does not explicity say fwrite() sets errno + * (e.g. for an fwrite() on a read-only file). + * - GCC libc fwrite() appears to set errno as expected. + * - ARMCC & IAR libc fwrite() appears not to set errno. + * + * The following ARMCC documents are silent on whether fwrite() sets errno: + * - "ARM C and C++ Libraries and Floating-Point Support". + * - "RL-ARM User Guide fwrite() section". + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_08(const size_t call_count) +{ + FILE *fp = NULL; + int ret = -1; + int ret_ferror = -1; + const char *filename = sd_testfile_path; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + errno = 0; + fp = fopen(filename,"w+"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file (filename=%s, f=%p).\n", __func__, filename, fp); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + /* close the fp but then try to read or write it */ + ret = fclose(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* open file */ + errno = 0; + fp = fopen(filename, "r"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file for reading (filename=\"%s\", ret=%d)\n", __func__, filename, (int) ret); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + /* Perform fwrite() operation that will fail. */ + errno = 0; + ret = fwrite("42!", 4, 1, fp); + + ret_ferror = ferror(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: ferror() failed to report error (filename=%s, ret_ferror=%d).\n", __func__, filename, (int) ret_ferror); + TEST_ASSERT_MESSAGE(ret_ferror != 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fwrite successfully wrote to read-only file (filename=%s, ret=%d).\n", __func__, filename, (int) ret); + /* the fwrite() should fail and return 0. */ + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + +#if ! defined(__ARMCC_VERSION) && defined(__GNUC__) + /* check that errno is set. ARMCC appears not to set errno for fwrite() failure. */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected zero value for errno (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(errno != 0, fsfat_fopen_utest_msg_g); + + /* check that errno is set to the expected value (this may change differ for different libc's) */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: errno != EBADF (filename=%s, ret=%d, errno=%d).\n", __func__, filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(errno == EBADF, fsfat_fopen_utest_msg_g); +#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */ + + /* check clearerr() return clears the error */ + clearerr(fp); + ret = ferror(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: ferror() did not return zero value when error has been cleared (filename=%s, ret=%d).\n", __func__, filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + fclose(fp); + return CaseNext; +} + + +/** @brief test for operation of ftell() + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_09(const size_t call_count) +{ + FILE *fp = NULL; + int ret = -1; + int32_t len = 0; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + /* create a file of a certain length */ + len = strlen(fsfat_fopen_test_02_data[0].value); + ret = fsfat_test_create(fsfat_fopen_test_02_data[0].filename, (char*) fsfat_fopen_test_02_data[0].value, len); + + errno = 0; + /* Open the file for reading so the file is not truncated to 0 length. */ + fp = fopen(fsfat_fopen_test_02_data[0].filename, "r"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open file (filename=%s, fp=%p, errno=%d).\n", __func__, fsfat_fopen_test_02_data[0].filename, fp, errno); + TEST_ASSERT_MESSAGE(fp != NULL, fsfat_fopen_utest_msg_g); + + errno = 0; + ret = fseek(fp, 0, SEEK_END); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: fseek() failed to SEEK_END (filename=%s, ret=%d, errno=%d).\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + errno = 0; + ret = ftell(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: ftell() failed to report correct offset value (filename=%s, ret=%d, errno=%d).\n", __func__, fsfat_fopen_test_02_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == len, fsfat_fopen_utest_msg_g); + + errno = 0; + ret = fclose(fp); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close file (ret=%d, errno=%d)\n", __func__, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/* file data for test_10 */ +static fsfat_kv_data_t fsfat_fopen_test_10_kv_data[] = { + { "/sd/test_10/testfile.txt", "test_data"}, + { NULL, NULL}, +}; + +/** @brief test for operation of remove() + * + * Performs the following tests: + * 1. test remove() on a file that exists. This should succeed. + * 2. test remove() on a dir that exists. This should succeed. + * 3. test remove() on a file that doesnt exist. This should fail. check errno set. + * 4. test remove() on a dir that doesnt exist. This should fail. check errno set. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_10(const size_t call_count) +{ + char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1]; + char *pos = NULL; + int32_t ret = -1; + size_t len = 0; + fsfat_kv_data_t *node = fsfat_fopen_test_10_kv_data; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + + /* start from a known state i.e. directory to be created in not present */ + fsfat_filepath_remove_all((char*) node->filename); + + /* (1) */ + errno = 0; + ret = fsfat_filepath_make_dirs((char*) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + len = strlen(node->value); + ret = fsfat_test_create(node->filename, (char*) node->value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + ret = remove(node->filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: delete file operation failed (filename=%s, ret=%d) .\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* (3) */ + ret = remove(node->filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: deleted a file that doesn't exist (filename=%s, ret=%d, errno=%d) .\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g); + + /* (2) */ + memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + memcpy(buf, node->filename, strlen(node->filename)); + pos = strrchr(buf, '/'); + *pos = '\0'; + ret = remove(buf); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: delete directory operation failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* (4) */ + ret = remove(buf); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: deleted a directory that doesn't exist (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/* file data for test_11 */ +static fsfat_kv_data_t fsfat_fopen_test_11_kv_data[] = { + { "/sd/test_11/step0.txt", "test_data"}, + { "/sd/test_11/step1.txt", "test_data"}, + { "/sd/test_11/subdir/step3.txt", "test_data"}, + { NULL, NULL}, +}; + +/** @brief test for operation of rename() + * + * This test does the following: + * 1) test rename() on a file that exists to a new filename within the same directory. + * 2) test rename() on a file that exists to a new filename within a different directory. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_11(const size_t call_count) +{ + int32_t ret = -1; + size_t len = 0; + fsfat_kv_data_t *node = fsfat_fopen_test_11_kv_data; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + + /* start from a known state i.e. directory to be created in not present, files not present */ + while(node->filename != NULL) { + fsfat_filepath_remove_all((char*) node->filename); + node++; + } + + /* create file and directories ready for rename() tests */ + errno = 0; + node = fsfat_fopen_test_11_kv_data; + ret = fsfat_filepath_make_dirs((char*) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + len = strlen(node->value); + ret = fsfat_test_create(node->filename, (char*) node->value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + errno = 0; + node = &fsfat_fopen_test_11_kv_data[2]; + ret = fsfat_filepath_make_dirs((char*) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* (1) */ + ret = rename(fsfat_fopen_test_11_kv_data[0].filename, fsfat_fopen_test_11_kv_data[1].filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__, fsfat_fopen_test_11_kv_data[0].filename, fsfat_fopen_test_11_kv_data[1].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* (2) */ + ret = rename(fsfat_fopen_test_11_kv_data[1].filename, fsfat_fopen_test_11_kv_data[2].filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unable to rename file from (%s) to (%s) (ret=%d, errno=%d).\n", __func__, fsfat_fopen_test_11_kv_data[1].filename, fsfat_fopen_test_11_kv_data[2].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + + +/* file data for test_12 */ +static fsfat_kv_data_t fsfat_fopen_test_12_kv_data[] = { + { "/sd/test_12/subdir/testfil1.txt", "testfil1.txt"}, + { "/sd/test_12/testfil2.txt", "testfil2.txt"}, + { "/sd/test_12/testfil3.txt", "testfil3.txt"}, + { "/sd/test_12/testfil4.txt", "testfil4.txt"}, + { "/sd/test_12/testfil5.txt", "testfil5.txt"}, + { NULL, NULL}, +}; + +/** @brief test for operation of readdir(). + * + * Note, rewinddir(), telldir() and seekdir() dont appear to work reliably. + * opendir() not available on ARM/IAR toolchains. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_12(const size_t call_count) +{ + char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1]; + char *pos = NULL; + int32_t count = 0; + int32_t ret = -1; + size_t len = 0; + DIR *dir; + struct dirent *dp; + fsfat_kv_data_t *node = fsfat_fopen_test_12_kv_data; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + +#if ! defined(__ARMCC_VERSION) && defined(__GNUC__) + + /* start from a known state i.e. directory to be created in not present */ + while(node->filename != NULL) { + fsfat_filepath_remove_all((char*) node->filename); + node++; + } + + /* create a file */ + node = fsfat_fopen_test_12_kv_data; + errno = 0; + ret = fsfat_filepath_make_dirs((char*) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + node = fsfat_fopen_test_12_kv_data; + while(node->filename != NULL) { + len = strlen(node->value); + ret = fsfat_test_create(node->filename, (char*) node->value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + node++; + } + + node = fsfat_fopen_test_12_kv_data; + memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + memcpy(buf, node->filename, strlen(node->filename)); + pos = strrchr(buf, '/'); + *pos = '\0'; + dir = opendir(buf); + + while ((dp = readdir(dir)) != NULL) { + FSFAT_DBGLOG("%s: filename: \"%s\"\n", __func__, dp->d_name); + TEST_ASSERT_MESSAGE(dp != 0, "Error: readdir() failed\n"); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected object name (name=%s, expected=%s).\n", __func__, dp->d_name, fsfat_fopen_test_12_kv_data[count].value); + TEST_ASSERT_MESSAGE(strncmp(dp->d_name, fsfat_fopen_test_12_kv_data[count].value, strlen(fsfat_fopen_test_12_kv_data[count].value)) == 0, fsfat_fopen_utest_msg_g); + count++; + } + closedir(dir); + + /* cleanup */ + node = fsfat_fopen_test_12_kv_data; + while(node->filename != NULL) { + fsfat_filepath_remove_all((char*) node->filename); + node++; + } +#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */ + return CaseNext; +} + + +/* file data for test_13 */ +static fsfat_kv_data_t fsfat_fopen_test_13_kv_data[] = { + /* a file is included in the filepath even though its not created by the test, + * as the fsfat_filepath_make_dirs() works with it present. */ + { "/sd/test_13/dummy.txt", "testdir"}, + { NULL, NULL}, +}; +/** @brief test for operation of mkdir()/remove() + * + * This test checks that: + * - The mkdir() function successfully creates a directory that is not already present. + * - The mkdir() function returns EEXIST when trying to create a directory thats already present. + * - The remove() function successfully removes a directory that is present. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_13(const size_t call_count) +{ + int32_t ret = 0; + + FSFAT_DBGLOG("%s:entered\n", __func__); + (void) call_count; + + /* start from a known state i.e. directory to be created in not present */ + fsfat_filepath_remove_all((char*) fsfat_fopen_test_13_kv_data[0].filename); + + errno = 0; + ret = fsfat_filepath_make_dirs((char*) fsfat_fopen_test_13_kv_data[0].filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + /* check that get a suitable error when try to create it again.*/ + errno = 0; + ret = fsfat_filepath_make_dirs((char*) fsfat_fopen_test_13_kv_data[0].filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: permitted to create directory when already exists (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret != 0, fsfat_fopen_utest_msg_g); + + /* check errno is as expected */ + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: errno != EEXIST (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(errno == EEXIST, fsfat_fopen_utest_msg_g); + + ret = fsfat_filepath_remove_all((char*) fsfat_fopen_test_13_kv_data[0].filename); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to remove directory (dirname=%s, ret=%d, errno=%d)\n", __func__, fsfat_fopen_test_13_kv_data[0].filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + return CaseNext; +} + +/* file data for test_14 */ +static fsfat_kv_data_t fsfat_fopen_test_14_kv_data[] = { + /* a file is included in the filepath even though its not created by the test, + * as the fsfat_filepath_make_dirs() works with it present. */ + { "/sd/test_14/testfile.txt", "testdata"}, + { NULL, NULL}, +}; + +/** @brief test for operation of stat() + * + * stat() is currently no supported by ARMCC and IAR toolchains libc. + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_14(const size_t call_count) +{ +#if ! defined(__ARMCC_VERSION) && defined(__GNUC__) + + char buf[FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1]; + char *pos = NULL; + int32_t ret = -1; + size_t len = 0; + struct stat file_stat; + fsfat_kv_data_t *node = fsfat_fopen_test_14_kv_data; + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + TEST_ASSERT(strlen(node->filename) < FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + + /* start from a known state i.e. directory to be created in not present */ + fsfat_filepath_remove_all((char*) node->filename); + + /* Create file in a directory. */ + errno = 0; + ret = fsfat_filepath_make_dirs((char*) node->filename, false); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dir (dirname=%s, ret=%d, errno=%d)\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + len = strlen(node->value); + ret = fsfat_test_create(node->filename, (char*) node->value, len); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create file (ret=%d).\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= 0, fsfat_fopen_utest_msg_g); + + /* Test stat() on the file returns the correct attribute set */ + memset(&file_stat, 0, sizeof(file_stat)); + ret = stat(node->filename, &file_stat); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: stat() operation on file failed (filename=%s, ret=%d, errno=%d).\n", __func__, node->filename, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: expected st_mode S_IFREG flag not set (filename=%s).\n", __func__, node->filename); + TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) == S_IFREG, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected st_mode S_IFDIR flag set (filename=%s).\n", __func__, node->filename); + TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) != S_IFDIR, fsfat_fopen_utest_msg_g); + + /* Test stat() on the directory returns the correct attribute set */ + memset(&file_stat, 0, sizeof(file_stat)); + memset(buf, 0, FSFAT_FOPEN_TEST_WORK_BUF_SIZE_1); + memcpy(buf, node->filename, strlen(node->filename)); + pos = strrchr(buf, '/'); + *pos = '\0'; + ret = stat(buf, &file_stat); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: stat() operation on directory failed (directory name=%s, ret=%d, errno=%d).\n", __func__, buf, (int) ret, errno); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected st_mode S_IFREG flag set (directory name=%s).\n", __func__, buf); + TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFREG) != S_IFREG, fsfat_fopen_utest_msg_g); + + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: expected st_mode S_IFDIR flag not set (directory name=%s).\n", __func__, buf); + TEST_ASSERT_MESSAGE((file_stat.st_mode & S_IFDIR) == S_IFDIR, fsfat_fopen_utest_msg_g); + + /* clean up after successful test */ + fsfat_filepath_remove_all((char*) node->filename); + +#endif /* ! defined(__ARMCC_VERSION) && defined(__GNUC__) */ + return CaseNext; +} + +/** @brief test for operation of SDFileSystem::format() + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_15(const size_t call_count) +{ + + FSFAT_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + int32_t ret = -1; + + /* the allocation_unit of 0 means chanFS will use the default for the card (varies according to capacity). */ + fs.unmount(); + ret = fs.format(&sd); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to format sdcard (ret=%d)\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + fs.mount(&sd); + return CaseNext; +} + + +/* @brief test utility function to create a file of a given size. + * + * A reference data table is used of so that the data file can be later be + * checked with fsfat_test_check_data_file(). + * + * @param filename name of the file including path + * @param data data to store in file + * @param len number of bytes of data present in the data buffer. + */ +int32_t fsfat_test_create_data_file(const char* filename, size_t len) +{ + int32_t ret = -1; + FILE *fp = NULL; + size_t write_len = 0; + size_t written_len = 0; + int32_t exp = 0; + const int32_t exp_max = 8; /* so as not to exceed FSFAT_TEST_BYTE_DATA_TABLE_SIZE/2 */ + + FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len); + TEST_ASSERT(len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE == 0); + fp = fopen(filename, "a"); + if(fp == NULL){ + return ret; + } + + while(written_len < len) { + /* write fsfat_test_byte_data_table or part thereof, in 9 writes of sizes + * 1, 2, 4, 8, 16, 32, 64, 128, 1, totalling 256 bytes len permitting. */ + for(exp = 0; (exp <= exp_max) && (written_len < len); exp++){ + write_len = 0x1 << (exp % exp_max); + write_len = len - written_len > write_len ? write_len : len - written_len; + ret = fwrite((const void*) &fsfat_test_byte_data_table[written_len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE], write_len, 1, fp); + written_len += write_len; + if(ret != 1){ + FSFAT_DBGLOG("%s:Error: fwrite() failed (ret=%d)\n", __func__, (int) ret); + ret = -1; + goto out0; + } + } + } + if(written_len == len) { + ret = 0; + } else { + ret = -1; + } +out0: + fclose(fp); + return ret; +} + + +/* @brief test utility function to check the data in the specified file is correct. + * + * The data read from the file is check that it agrees with the data written by + * fsfat_test_create_data_file(). + * + * @param filename name of the file including path + * @param data data to store in file + * @param len number of bytes of data present in the data buffer. + */ +int32_t fsfat_test_check_data_file(const char* filename, size_t len) +{ + int32_t ret = -1; + FILE *fp = NULL; + size_t read_len = 0; + uint8_t buf[FSFAT_TEST_BYTE_DATA_TABLE_SIZE]; + + FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len); + TEST_ASSERT(len % FSFAT_TEST_BYTE_DATA_TABLE_SIZE == 0); + fp = fopen(filename, "r"); + if(fp == NULL){ + return ret; + } + + while(read_len < len) { + ret = fread((void*) buf, FSFAT_TEST_BYTE_DATA_TABLE_SIZE, 1, fp); + read_len += FSFAT_TEST_BYTE_DATA_TABLE_SIZE; + if(ret == 0){ + /* end of read*/ + FSFAT_DBGLOG("%s:unable to read data\n", __func__); + break; + } + if(memcmp(buf, fsfat_test_byte_data_table, FSFAT_TEST_BYTE_DATA_TABLE_SIZE) != 0) { + FSFAT_DBGLOG("%s:Error: read data not as expected (0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x, 0x%2x\n", __func__, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); + ret = -1; + goto out0; + } + } + if(read_len == len) { + ret = 0; + } +out0: + fclose(fp); + return ret; +} + +/* file data for test_16 */ +static fsfat_kv_data_t fsfat_fopen_test_16_kv_data[] = { + { "/sd/tst16_0/testfil0.txt", "dummy_data"}, + { "/sd/tst16_1/subdir0/testfil0.txt", "dummy_data"}, + { "/sd/tst16_2/subdir0/subdir1/testfil0.txt", "dummy_data"}, + { "/sd/tst16_3/subdir0/subdir1/subdir2/subdir3/testfil0.txt", "dummy_data"}, + { "/sd/tst16_4/subdir0/subdir1/subdir2/subdir3/subdir4/testfil0.txt", "dummy_data"}, + { "/sd/tst16_5/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/testfil0.txt", "dummy_data"}, + { "/sd/tst16_6/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/testfil0.txt", "dummy_data"}, + { "/sd/tst16_7/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/testfil0.txt", "dummy_data"}, + { "/sd/tst16_8/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/testfil0.txt", "dummy_data"}, + { "/sd/tst16_9/subdir0/subdir1/subdir2/subdir3/subdir4/subdir5/subdir6/subdir7/subdir8/subdir9/testfil0.txt", "dummy_data"}, + { NULL, NULL}, +}; + + +/** @brief stress test to write data to fs + * + * @return on success returns CaseNext to continue to next test case, otherwise will assert on errors. + */ +control_t fsfat_fopen_test_16(const size_t call_count) +{ + int32_t ret = 0; + fsfat_kv_data_t *node = fsfat_fopen_test_16_kv_data; + const int32_t num_blocks = 100; /* each file ~25kB */ + + FSFAT_DBGLOG("%s:entered\n", __func__); + (void) call_count; + + /* remove file and directory from a previous failed test run, if present */ + while(node->filename != NULL) { + fsfat_filepath_remove_all((char*) node->filename); + node++; + } + + /* create dirs */ + node = fsfat_fopen_test_16_kv_data; + while(node->filename != NULL) { + ret = fsfat_filepath_make_dirs((char*) node->filename, true); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create dirs for filename (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + node++; + } + + /* create the data files */ + node = fsfat_fopen_test_16_kv_data; + while(node->filename != NULL) { + ret = fsfat_test_create_data_file(node->filename, num_blocks * FSFAT_TEST_BYTE_DATA_TABLE_SIZE); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + node++; + } + + /* read the data back and check its as expected */ + node = fsfat_fopen_test_16_kv_data; + while(node->filename != NULL) { + ret = fsfat_test_check_data_file(node->filename, num_blocks * FSFAT_TEST_BYTE_DATA_TABLE_SIZE); + FSFAT_TEST_UTEST_MESSAGE(fsfat_fopen_utest_msg_g, FSFAT_UTEST_MSG_BUF_SIZE, "%s:Error: failed to check data file (filename=\"%s\")(ret=%d)\n", __func__, node->filename, (int) ret); + TEST_ASSERT_MESSAGE(ret == 0, fsfat_fopen_utest_msg_g); + node++; + } + + /* clean up */ + node = fsfat_fopen_test_16_kv_data; + while(node->filename != NULL) { + fsfat_filepath_remove_all((char*) node->filename); + node++; + } + return CaseNext; +} + + +#else + + +#define FSFAT_FOPEN_TEST_01 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_02 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_03 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_04 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_05 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_06 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_07 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_08 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_09 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_10 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_11 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_12 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_13 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_14 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_15 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_16 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_17 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_18 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_19 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_20 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_21 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_22 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_23 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_24 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_25 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_26 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_27 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_28 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_29 fsfat_fopen_test_dummy +#define FSFAT_FOPEN_TEST_30 fsfat_fopen_test_dummy + +/** @brief fsfat_fopen_test_dummy Dummy test case for testing when platform doesnt have an SDCard installed. + * + * @return success always + */ +static control_t fsfat_fopen_test_dummy() +{ + printf("Null test\n"); + return CaseNext; +} + +#endif + + +/// @cond FSFAT_DOXYGEN_DISABLE +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(FSFAT_FOPEN_GREENTEA_TIMEOUT_S, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FSFAT_FOPEN_TEST_01: fopen()/fwrite()/fclose() directories/file in multi-dir filepath.", FSFAT_FOPEN_TEST_01), + Case("FSFAT_FOPEN_TEST_02: fopen(r) pre-existing file try to write it.", FSFAT_FOPEN_TEST_02), + Case("FSFAT_FOPEN_TEST_03: fopen(w+) pre-existing file try to write it.", FSFAT_FOPEN_TEST_03), + Case("FSFAT_FOPEN_TEST_04: fopen() with a filename exceeding the maximum length.", FSFAT_FOPEN_TEST_04), +#ifdef FOPEN_EXTENDED_TESTING + Case("FSFAT_FOPEN_TEST_05: fopen() with bad filenames (extended).", FSFAT_FOPEN_TEST_05), +#endif + Case("FSFAT_FOPEN_TEST_06: fopen() with bad filenames (minimal).", FSFAT_FOPEN_TEST_06), + Case("FSFAT_FOPEN_TEST_07: fopen()/errno handling.", FSFAT_FOPEN_TEST_07), + Case("FSFAT_FOPEN_TEST_08: ferror()/clearerr()/errno handling.", FSFAT_FOPEN_TEST_08), + Case("FSFAT_FOPEN_TEST_09: ftell() handling.", FSFAT_FOPEN_TEST_09), + Case("FSFAT_FOPEN_TEST_10: remove() test.", FSFAT_FOPEN_TEST_10), + Case("FSFAT_FOPEN_TEST_11: rename().", FSFAT_FOPEN_TEST_11), + Case("FSFAT_FOPEN_TEST_12: opendir(), readdir(), closedir() test.", FSFAT_FOPEN_TEST_12), + Case("FSFAT_FOPEN_TEST_13: mkdir() test.", FSFAT_FOPEN_TEST_13), + Case("FSFAT_FOPEN_TEST_14: stat() test.", FSFAT_FOPEN_TEST_14), + Case("FSFAT_FOPEN_TEST_15: format() test.", FSFAT_FOPEN_TEST_15), + Case("FSFAT_FOPEN_TEST_16: write/check n x 25kB data files.", FSFAT_FOPEN_TEST_16), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} +/// @endcond
diff -r 000000000000 -r 119624335925 sd-driver/TESTS/filesystem/parallel/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/TESTS/filesystem/parallel/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,184 @@ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include <stdlib.h> +#include <errno.h> + +using namespace utest::v1; + +// test configuration +#ifndef MBED_TEST_FILESYSTEM +#define MBED_TEST_FILESYSTEM FATFileSystem +#endif + +#ifndef MBED_TEST_FILESYSTEM_DECL +#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") +#endif + +#ifndef MBED_TEST_BLOCKDEVICE +#define MBED_TEST_BLOCKDEVICE SDBlockDevice +#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); +#endif + +#ifndef MBED_TEST_BLOCKDEVICE_DECL +#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd +#endif + +#ifndef MBED_TEST_FILES +#define MBED_TEST_FILES 4 +#endif + +#ifndef MBED_TEST_DIRS +#define MBED_TEST_DIRS 4 +#endif + +#ifndef MBED_TEST_BUFFER +#define MBED_TEST_BUFFER 512 +#endif + +#ifndef MBED_TEST_TIMEOUT +#define MBED_TEST_TIMEOUT 120 +#endif + +#ifndef MBED_THREAD_COUNT +#define MBED_THREAD_COUNT MBED_TEST_FILES +#endif + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_FILESYSTEM) +#include INCLUDE(MBED_TEST_BLOCKDEVICE) + +MBED_TEST_FILESYSTEM_DECL; +MBED_TEST_BLOCKDEVICE_DECL; + +Dir dir[MBED_TEST_DIRS]; +File file[MBED_TEST_FILES]; +DIR *dd[MBED_TEST_DIRS]; +FILE *fd[MBED_TEST_FILES]; +struct dirent ent; +struct dirent *ed; + +volatile bool count_done = 0; + +// tests + +void test_file_tests() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = MBED_TEST_FILESYSTEM::format(&bd); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void write_file_data (char count) { + + char filename[10]; + uint8_t wbuffer[MBED_TEST_BUFFER]; + int res; + + sprintf(filename, "%s%d", "data", count); + res = file[count].open(&fs, filename, O_WRONLY | O_CREAT); + TEST_ASSERT_EQUAL(0, res); + + char letter = 'A'+ count; + for (uint32_t i = 0; i < MBED_TEST_BUFFER; i++) { + wbuffer[i] = letter++; + if ('z' == letter) { + letter = 'A' + count; + } + } + + for (uint32_t i = 0; i < 5; i++) { + res = file[count].write(wbuffer, MBED_TEST_BUFFER); + TEST_ASSERT_EQUAL(MBED_TEST_BUFFER, res); + } + + res = file[count].close(); + TEST_ASSERT_EQUAL(0, res); +} + +void read_file_data (char count) { + char filename[10]; + uint8_t rbuffer[MBED_TEST_BUFFER]; + int res; + + sprintf(filename, "%s%d", "data", count); + res = file[count].open(&fs, filename, O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + + for (uint32_t i = 0; i < 5; i++) { + res = file[count].read(rbuffer, MBED_TEST_BUFFER); + TEST_ASSERT_EQUAL(MBED_TEST_BUFFER, res); + char letter = 'A' + count; + for (uint32_t i = 0; i < MBED_TEST_BUFFER; i++) { + res = rbuffer[i]; + TEST_ASSERT_EQUAL(letter++, res); + if ('z' == letter) { + letter = 'A' + count; + } + } + } + + res = file[count].close(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_thread_access_test() { + + Thread *data[MBED_THREAD_COUNT]; + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + + // Write threads in parallel + for (char thread_count = 0; thread_count < MBED_THREAD_COUNT; thread_count++) { + data[thread_count] = new Thread(osPriorityNormal); + data[thread_count]->start(callback((void(*)(void*))write_file_data, (void*)thread_count)); + } + + // Wait for write thread to join before creating read thread + for (char thread_count = 0; thread_count < MBED_THREAD_COUNT; thread_count++) { + data[thread_count]->join(); + delete data[thread_count]; + data[thread_count] = new Thread(osPriorityNormal); + data[thread_count]->start(callback((void(*)(void*))read_file_data, (void*)thread_count)); + } + + // Wait for read threads to join + for (char thread_count = 0; thread_count < MBED_THREAD_COUNT; thread_count++) { + data[thread_count]->join(); + delete data[thread_count]; + } + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +// test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("File tests", test_file_tests), + Case("Filesystem access from multiple threads", test_thread_access_test), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 sd-driver/TESTS/filesystem/seek/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/TESTS/filesystem/seek/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,629 @@ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include <stdlib.h> +#include <errno.h> + +using namespace utest::v1; + +// test configuration +#ifndef MBED_TEST_FILESYSTEM +#define MBED_TEST_FILESYSTEM FATFileSystem +#endif + +#ifndef MBED_TEST_FILESYSTEM_DECL +#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") +#endif + +#ifndef MBED_TEST_BLOCKDEVICE +#define MBED_TEST_BLOCKDEVICE SDBlockDevice +#define MBED_TEST_BLOCKDEVICE_DECL SDBlockDevice bd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); +#endif + +#ifndef MBED_TEST_BLOCKDEVICE_DECL +#define MBED_TEST_BLOCKDEVICE_DECL MBED_TEST_BLOCKDEVICE bd +#endif + +#ifndef MBED_TEST_FILES +#define MBED_TEST_FILES 4 +#endif + +#ifndef MBED_TEST_DIRS +#define MBED_TEST_DIRS 4 +#endif + +#ifndef MBED_TEST_BUFFER +#define MBED_TEST_BUFFER 8192 +#endif + +#ifndef MBED_TEST_TIMEOUT +#define MBED_TEST_TIMEOUT 120 +#endif + + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_FILESYSTEM) +#include INCLUDE(MBED_TEST_BLOCKDEVICE) + +MBED_TEST_FILESYSTEM_DECL; +MBED_TEST_BLOCKDEVICE_DECL; + +Dir dir[MBED_TEST_DIRS]; +File file[MBED_TEST_FILES]; +DIR *dd[MBED_TEST_DIRS]; +FILE *fd[MBED_TEST_FILES]; +struct dirent ent; +struct dirent *ed; +size_t size; +uint8_t buffer[MBED_TEST_BUFFER]; +uint8_t rbuffer[MBED_TEST_BUFFER]; +uint8_t wbuffer[MBED_TEST_BUFFER]; + + +// tests + +void test_seek_tests() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = MBED_TEST_FILESYSTEM::format(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = fs.mkdir("hello", 0777); + TEST_ASSERT_EQUAL(0, res); + for (int i = 0; i < 132; i++) { + sprintf((char*)buffer, "hello/kitty%d", i); + res = file[0].open(&fs, (char*)buffer, + O_WRONLY | O_CREAT | O_APPEND); + TEST_ASSERT_EQUAL(0, res); + + size = strlen("kittycatcat"); + memcpy(buffer, "kittycatcat", size); + for (int j = 0; j < 132; j++) { + file[0].write(buffer, size); + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + } + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_simple_dir_seek() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "hello"); + TEST_ASSERT_EQUAL(0, res); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, "."); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, ".."); + TEST_ASSERT_EQUAL(0, res); +#endif + + off_t pos; + int i; + for (i = 0; i < 4; i++) { + sprintf((char*)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char*)buffer); + TEST_ASSERT_EQUAL(0, res); + pos = dir[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + + dir[0].seek(pos); + sprintf((char*)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char*)buffer); + TEST_ASSERT_EQUAL(0, res); + + dir[0].rewind(); + sprintf((char*)buffer, "kitty%d", 0); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, "."); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, ".."); + TEST_ASSERT_EQUAL(0, res); +#endif + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char*)buffer); + TEST_ASSERT_EQUAL(0, res); + + dir[0].seek(pos); + sprintf((char*)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char*)buffer); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_large_dir_seek() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].open(&fs, "hello"); + TEST_ASSERT_EQUAL(0, res); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, "."); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, ".."); + TEST_ASSERT_EQUAL(0, res); +#endif + + off_t pos; + int i; + for (i = 0; i < 128; i++) { + sprintf((char*)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char*)buffer); + TEST_ASSERT_EQUAL(0, res); + pos = dir[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + + dir[0].seek(pos); + sprintf((char*)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char*)buffer); + TEST_ASSERT_EQUAL(0, res); + + dir[0].rewind(); + sprintf((char*)buffer, "kitty%d", 0); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, "."); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, ".."); + TEST_ASSERT_EQUAL(0, res); +#endif + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char*)buffer); + TEST_ASSERT_EQUAL(0, res); + + dir[0].seek(pos); + sprintf((char*)buffer, "kitty%d", i); + res = dir[0].read(&ent); + TEST_ASSERT_EQUAL(1, res); + res = strcmp(ent.d_name, (char*)buffer); + TEST_ASSERT_EQUAL(0, res); + res = dir[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_simple_file_seek() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + + off_t pos; + size = strlen("kittycatcat"); + for (int i = 0; i < 4; i++) { + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + pos = file[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + file[0].rewind(); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_CUR); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_END) >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + size_t size = file[0].size(); + res = file[0].seek(0, SEEK_CUR); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_large_file_seek() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDONLY); + TEST_ASSERT_EQUAL(0, res); + + off_t pos; + size = strlen("kittycatcat"); + for (int i = 0; i < 128; i++) { + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + pos = file[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + file[0].rewind(); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_CUR); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_END) >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + size_t size = file[0].size(); + res = file[0].seek(0, SEEK_CUR); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_simple_file_seek_and_write() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDWR); + TEST_ASSERT_EQUAL(0, res); + + off_t pos; + size = strlen("kittycatcat"); + for (int i = 0; i < 4; i++) { + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + pos = file[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + + memcpy(buffer, "doggodogdog", size); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].write(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "doggodogdog", size); + TEST_ASSERT_EQUAL(0, res); + + file[0].rewind(); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "doggodogdog", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_END) >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + size_t size = file[0].size(); + res = file[0].seek(0, SEEK_CUR); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_large_file_seek_and_write() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDWR); + TEST_ASSERT_EQUAL(0, res); + + off_t pos; + size = strlen("kittycatcat"); + for (int i = 0; i < 128; i++) { + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + if (i != 4) { + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + } + pos = file[0].tell(); + } + res = pos >= 0; + TEST_ASSERT_EQUAL(1, res); + + memcpy(buffer, "doggodogdog", size); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].write(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "doggodogdog", size); + TEST_ASSERT_EQUAL(0, res); + + file[0].rewind(); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(pos, SEEK_SET); + TEST_ASSERT_EQUAL(pos, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "doggodogdog", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(-size, SEEK_END) >= 0; + TEST_ASSERT_EQUAL(1, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + + size_t size = file[0].size(); + res = file[0].seek(0, SEEK_CUR); + TEST_ASSERT_EQUAL(size, res); + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_boundary_seek_and_write() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDWR); + TEST_ASSERT_EQUAL(0, res); + + size = strlen("hedgehoghog"); + const off_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; + + for (int i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { + off_t off = offsets[i]; + memcpy(buffer, "hedgehoghog", size); + res = file[0].seek(off, SEEK_SET); + TEST_ASSERT_EQUAL(off, res); + res = file[0].write(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].seek(off, SEEK_SET); + TEST_ASSERT_EQUAL(off, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "hedgehoghog", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(0, SEEK_SET); + TEST_ASSERT_EQUAL(0, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "kittycatcat", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].sync(); + TEST_ASSERT_EQUAL(0, res); + } + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + +void test_out_of_bounds_seek() { + int res = bd.init(); + TEST_ASSERT_EQUAL(0, res); + + { + res = fs.mount(&bd); + TEST_ASSERT_EQUAL(0, res); + res = file[0].open(&fs, "hello/kitty42", O_RDWR); + TEST_ASSERT_EQUAL(0, res); + + size = strlen("kittycatcat"); + res = file[0].size(); + TEST_ASSERT_EQUAL(132*size, res); + res = file[0].seek((132+4)*size, + SEEK_SET); + TEST_ASSERT_EQUAL((132+4)*size, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(0, res); + + memcpy(buffer, "porcupineee", size); + res = file[0].write(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = file[0].seek((132+4)*size, + SEEK_SET); + TEST_ASSERT_EQUAL((132+4)*size, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); + res = memcmp(buffer, "porcupineee", size); + TEST_ASSERT_EQUAL(0, res); + res = file[0].seek(132*size, + SEEK_SET); + TEST_ASSERT_EQUAL(132*size, res); + res = file[0].read(buffer, size); + TEST_ASSERT_EQUAL(size, res); +#if (MBED_TEST_FILESYSTEM != FATFileSystem) + // FatFs does not guarantee empty expanded buffer + res = memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size); + TEST_ASSERT_EQUAL(0, res); +#endif + res = file[0].close(); + TEST_ASSERT_EQUAL(0, res); + res = fs.unmount(); + TEST_ASSERT_EQUAL(0, res); + } + + res = bd.deinit(); + TEST_ASSERT_EQUAL(0, res); +} + + + +// test setup +utest::v1::status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(MBED_TEST_TIMEOUT, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Seek tests", test_seek_tests), + Case("Simple dir seek", test_simple_dir_seek), + Case("Large dir seek", test_large_dir_seek), + Case("Simple file seek", test_simple_file_seek), + Case("Large file seek", test_large_file_seek), + Case("Simple file seek and write", test_simple_file_seek_and_write), + Case("Large file seek and write", test_large_file_seek_and_write), + Case("Boundary seek and write", test_boundary_seek_and_write), + Case("Out-of-bounds seek", test_out_of_bounds_seek), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 sd-driver/config/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/config/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,145 @@ +{ + "name": "sd", + "config": { + "SPI_CS": "D10", + "SPI_MOSI": "D11", + "SPI_MISO": "D12", + "SPI_CLK": "D13", + "DEVICE_SPI": 1, + "FSFAT_SDCARD_INSTALLED": 1 + }, + "target_overrides": { + "DISCO_F051R8": { + "SPI_MOSI": "SPI_MOSI", + "SPI_MISO": "SPI_MISO", + "SPI_CLK": "SPI_SCK", + "SPI_CS": "SPI_CS" + }, + "DISCO_L476VG": { + "SPI_MOSI": "PE_15", + "SPI_MISO": "PE_14", + "SPI_CLK": "PE_13", + "SPI_CS": "PE_12" + }, + "K20D50M": { + "SPI_MOSI": "PTD2", + "SPI_MISO": "PTD3", + "SPI_CLK": "PTD1", + "SPI_CS": "PTC2" + }, + "KL22F": { + "SPI_MOSI": "PTD6", + "SPI_MISO": "PTD7", + "SPI_CLK": "PTD5", + "SPI_CS": "PTD4" + }, + "KL25Z": { + "SPI_MOSI": "PTD2", + "SPI_MISO": "PTD3", + "SPI_CLK": "PTD1", + "SPI_CS": "PTD0" + }, + "KL43Z": { + "SPI_MOSI": "PTD6", + "SPI_MISO": "PTD7", + "SPI_CLK": "PTD5", + "SPI_CS": "PTD4" + }, + "KL46Z": { + "SPI_MOSI": "PTD6", + "SPI_MISO": "PTD7", + "SPI_CLK": "PTD5", + "SPI_CS": "PTD4" + }, + "K64F": { + "SPI_MOSI": "PTE3", + "SPI_MISO": "PTE1", + "SPI_CLK": "PTE2", + "SPI_CS": "PTE4" + }, + "K66F": { + "SPI_MOSI": "PTE3", + "SPI_MISO": "PTE1", + "SPI_CLK": "PTE2", + "SPI_CS": "PTE4" + }, + "LPC11U37H_401": { + "SPI_MOSI": "SDMOSI", + "SPI_MISO": "SDMISO", + "SPI_CLK": "SDSCLK", + "SPI_CS": "SDSSEL" + }, + "LPC2368": { + "SPI_MOSI": "p11", + "SPI_MISO": "p12", + "SPI_CLK": "p13", + "SPI_CS": "p14" + }, + "NUCLEO_F429ZI": { + "SPI_MOSI": "PC_12", + "SPI_MISO": "PC_11", + "SPI_CLK": "PC_10", + "SPI_CS": "PA_15" + }, + "DISCO_F429ZI": { + "SPI_MOSI": "PC_12", + "SPI_MISO": "PC_11", + "SPI_CLK": "PC_10", + "SPI_CS": "PA_15" + }, + "NUCLEO_L031K6": { + "SPI_MOSI": "SPI_MOSI", + "SPI_MISO": "SPI_MISO", + "SPI_CLK": "SPI_SCK", + "SPI_CS": "SPI_CS" + }, + "NUMAKER_PFM_M453": { + "SPI_MOSI": "PD_13", + "SPI_MISO": "PD_14", + "SPI_CLK": "PD_15", + "SPI_CS": "PD_12" + }, + "NUMAKER_PFM_NUC472": { + "SPI_MOSI": "PF_0", + "SPI_MISO": "PD_15", + "SPI_CLK": "PD_14", + "SPI_CS": "PD_13" + }, + "nRF51822": { + "SPI_MOSI": "p12", + "SPI_MISO": "p13", + "SPI_CLK": "p15", + "SPI_CS": "p14" + }, + "UBLOX_EVK_ODIN_W2": { + "SPI_CS": "D9", + "SPI_MOSI": "D11", + "SPI_MISO": "D12", + "SPI_CLK": "D13" + }, + "RZ_A1H": { + "SPI_MOSI": "P8_5", + "SPI_MISO": "P8_6", + "SPI_CLK": "P8_3", + "SPI_CS": "P8_4" + }, + "GR_LYCHEE": { + "SPI_MOSI": "P5_6", + "SPI_MISO": "P5_7", + "SPI_CLK": "P5_4", + "SPI_CS": "P5_5" + }, + "HEXIWEAR": { + "SPI_MOSI": "PTE3", + "SPI_MISO": "PTE1", + "SPI_CLK": "PTE2", + "SPI_CS": "PTE4" + }, + "TB_SENSE_12": { + "SPI_MOSI": "PC6", + "SPI_MISO": "PC7", + "SPI_CLK": "PC8", + "SPI_CS": "PC9" + } + } +}
diff -r 000000000000 -r 119624335925 sd-driver/docs/pics/NUCLEO_F429ZI_wiring_with_ci_test_shield.png Binary file sd-driver/docs/pics/NUCLEO_F429ZI_wiring_with_ci_test_shield.png has changed
diff -r 000000000000 -r 119624335925 sd-driver/util/fsfat_debug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/util/fsfat_debug.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,88 @@ +/** @file fsfat_debug.h + * + * component debug header file. + */ + + +#ifndef __FSFAT_DEBUG +#define __FSFAT_DEBUG + +#include <stdint.h> +#include <assert.h> +#include <stdio.h> + + +/* Debug Support */ + +#define FSFAT_LOG_NONE 0 +#define FSFAT_LOG_ERR 1 +#define FSFAT_LOG_WARN 2 +#define FSFAT_LOG_NOTICE 3 +#define FSFAT_LOG_INFO 4 +#define FSFAT_LOG_DEBUG 5 +#define FSFAT_LOG_FENTRY 6 + +#define FSFAT_LOG(_fmt, ...) \ + do \ + { \ + printf(_fmt, __VA_ARGS__); \ + }while(0); + +#define noFSFAT_DEBUG +#ifdef FSFAT_DEBUG + +extern uint32_t fsfat_optDebug_g; +extern uint32_t fsfat_optLogLevel_g; + + +/* uncomment for asserts to work */ +/* #undef NDEBUG */ +// todo: port to mbedOSV3++ #include <core-util/assert.h> + +#define FSFAT_INLINE +// todo: port to mbedOSV3++ #define FSFAT_ASSERT CORE_UTIL_ASSERT +#define FSFAT_ASSERT(...) + +#define FSFAT_DBGLOG(_fmt, ...) \ + do \ + { \ + if(fsfat_optDebug_g && (fsfat_optLogLevel_g >= FSFAT_LOG_DEBUG)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + }while(0); + + +#define FSFAT_ERRLOG(_fmt, ...) \ + do \ + { \ + if(fsfat_optDebug_g && (fsfat_optLogLevel_g >= FSFAT_LOG_ERR)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + }while(0); + + +#define FSFAT_FENTRYLOG(_fmt, ...) \ + do \ + { \ + if(fsfat_optDebug_g && (fsfat_optLogLevel_g >= FSFAT_LOG_FENTRY)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + }while(0); + + + + + +#else +#define FSFAT_ASSERT(_x) do { } while(0) +#define FSFAT_INLINE inline +#define FSFAT_DBGLOG(_fmt, ...) do { } while(0) +#define FSFAT_ERRLOG(_fmt, ...) do { } while(0) +#define FSFAT_FENTRYLOG(_fmt, ...) do { } while(0) +#endif /* FSFAT_DEBUG */ + + +#endif /*__FSFAT_DEBUG*/
diff -r 000000000000 -r 119624335925 sd-driver/util/fsfat_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/util/fsfat_test.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,117 @@ +/* @file fsfat_test.c + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * test support code implementation file. + */ + +#include "fsfat_debug.h" +#include "fsfat_test.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <inttypes.h> +#include <ctype.h> + + +#ifdef FSFAT_DEBUG +uint32_t fsfat_optDebug_g = 1; +uint32_t fsfat_optLogLevel_g = FSFAT_LOG_NONE; /*FSFAT_LOG_NONE|FSFAT_LOG_ERR|FSFAT_LOG_DEBUG|FSFAT_LOG_FENTRY; */ +#endif + +/* ruler for measuring text strings */ +/* 1 1 1 1 1 1 1 1 1 1 2 2 2 */ +/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 */ +/* 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */ + +const uint8_t fsfat_test_byte_data_table[FSFAT_TEST_BYTE_DATA_TABLE_SIZE] = { + 0x2d, 0xf3, 0x31, 0x4c, 0x11, 0x4f, 0xde, 0x0d, 0xbd, 0xbc, 0xa6, 0x78, 0x36, 0x5c, 0x1d, 0x28, + 0x5f, 0xa9, 0x10, 0x65, 0x54, 0x45, 0x21, 0x1a, 0x88, 0xfe, 0x76, 0x45, 0xb9, 0xac, 0x65, 0x9a, + 0x34, 0x9d, 0x73, 0x10, 0xb4, 0xa9, 0x2e, 0x90, 0x95, 0x68, 0xac, 0xfe, 0xc5, 0x2d, 0x15, 0x03, + 0x34, 0x70, 0xf1, 0x1d, 0x48, 0xa1, 0xa0, 0xed, 0x5c, 0x2f, 0xf5, 0x2b, 0xb9, 0x84, 0xbb, 0x45, + 0x32, 0xdd, 0xb1, 0x33, 0x95, 0x2a, 0xbc, 0x26, 0xf0, 0x89, 0xba, 0xf4, 0xbd, 0xf9, 0x5d, 0x2e, + 0x6e, 0x11, 0xc6, 0xa7, 0x78, 0xfc, 0xc9, 0x0e, 0x6b, 0x38, 0xba, 0x14, 0x1b, 0xab, 0x4c, 0x20, + 0x91, 0xe4, 0xb0, 0xf1, 0x2b, 0x14, 0x07, 0x6b, 0xb5, 0xcd, 0xe3, 0x49, 0x75, 0xac, 0xe8, 0x98, + 0xf1, 0x58, 0x8f, 0xd9, 0xc4, 0x8f, 0x00, 0x17, 0xb5, 0x06, 0x6a, 0x33, 0xbd, 0xa7, 0x40, 0x5a, + 0xbf, 0x49, 0xf7, 0x27, 0x1b, 0x4c, 0x3e, 0x6f, 0xe3, 0x08, 0x1f, 0xfd, 0xa6, 0xd4, 0xc7, 0x5f, + 0xa4, 0xa6, 0x82, 0xad, 0x19, 0xd5, 0x5c, 0xd8, 0x3a, 0x49, 0x85, 0xc9, 0x21, 0x83, 0xf6, 0xc6, + 0x84, 0xf9, 0x76, 0x89, 0xf3, 0x2d, 0x17, 0x50, 0x97, 0x38, 0x48, 0x9a, 0xe1, 0x82, 0xcd, 0xac, + 0xa8, 0x1d, 0xd7, 0x96, 0x5e, 0xb3, 0x08, 0xa8, 0x3a, 0xc7, 0x2b, 0x05, 0xaf, 0xdc, 0x16, 0xdf, + 0x48, 0x0f, 0x2a, 0x7e, 0x3a, 0x82, 0xd7, 0x80, 0xd6, 0x49, 0x27, 0x5d, 0xe3, 0x07, 0x62, 0xb3, + 0xc3, 0x6c, 0xba, 0xb2, 0xaa, 0x9f, 0xd9, 0x03, 0x0d, 0x27, 0xa8, 0xe0, 0xd6, 0xee, 0x79, 0x4b, + 0xd6, 0x97, 0x99, 0xb7, 0x11, 0xd6, 0x0d, 0x34, 0xae, 0x99, 0x4a, 0x93, 0x95, 0xd0, 0x5a, 0x34, + 0x19, 0xa2, 0x69, 0x57, 0xcf, 0x7c, 0x3d, 0x98, 0x88, 0x5d, 0x04, 0xf2, 0xd7, 0xac, 0xa5, 0x63 +}; + + +/* @brief test utility function to delete the file identified by filename + */ +int32_t fsfat_test_delete(const char* filename) +{ + FSFAT_FENTRYLOG("%s:entered.\r\n", __func__); + return remove(filename); +} + + +/* @brief test utility function to create a file + * + * @param filename name of the file including path + * @param data data to store in file + * @param len number of bytes of data present in the data buffer. + */ +int32_t fsfat_test_create(const char* filename, const char* data, size_t len) +{ + int32_t ret = -1; + FILE *fp = NULL; + + FSFAT_FENTRYLOG("%s:entered (filename=%s, len=%d).\n", __func__, filename, (int) len); + fp = fopen(filename, "w+"); + if(fp == NULL){ + return ret; + } + ret = fwrite((const void*) data, len, 1, fp); + if(ret < 0){ + fclose(fp); + return ret; + } + fclose(fp); + return ret; +} + + +/* @brief support function for generating a kv_name + * @param name buffer to hold kv name + * @param len length of kv name to generate + * + */ +int32_t fsfat_test_filename_gen(char* name, const size_t len) +{ + size_t i; + uint32_t pos = 0; + + const char* buf = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!$-_@"; + const int buf_len = strlen(buf); + FSFAT_FENTRYLOG("%s:entered\n", __func__); + for(i = 0; i < len; i++) + { + pos = rand() % (buf_len); + name[i] = buf[pos]; + } + return 0; +} +
diff -r 000000000000 -r 119624335925 sd-driver/util/fsfat_test.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sd-driver/util/fsfat_test.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,74 @@ +/** @file fsfat_test.h + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Header file for test support data structures and function API. + */ +#ifndef __FSFAT_TEST_H +#define __FSFAT_TEST_H + +#include <stdint.h> +#include <stdlib.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Defines */ +//#define FSFAT_INIT_1_TABLE_HEAD { "a", ""} +#define FSFAT_INIT_1_TABLE_MID_NODE { "/sd/01234567.txt", "abcdefghijklmnopqrstuvwxyz"} +//#define FSFAT_INIT_1_TABLE_TAIL { "/sd/fopentst/hello/world/animal/wobbly/dog/foot/backrght.txt", "present"} +#define FSFAT_TEST_RW_TABLE_SENTINEL 0xffffffff +#define FSFAT_TEST_BYTE_DATA_TABLE_SIZE 256 +#define FSFAT_UTEST_MSG_BUF_SIZE 256 +#define FSFAT_UTEST_DEFAULT_TIMEOUT_MS 10000 +#define FSFAT_MBED_HOSTTEST_TIMEOUT 60 +#define FSFAT_MAX_FILE_BASENAME 8 +#define FSFAT_MAX_FILE_EXTNAME 3 +#define FSFAT_BUF_MAX_LENGTH 64 +#define FSFAT_FILENAME_MAX_LENGTH 255 + + +/* support macro for make string for utest _MESSAGE macros, which dont support formatted output */ +#define FSFAT_TEST_UTEST_MESSAGE(_buf, _max_len, _fmt, ...) \ + do \ + { \ + snprintf((_buf), (_max_len), (_fmt), __VA_ARGS__); \ + }while(0); + + +/* + * Structures + */ + +/* kv data for test */ +typedef struct fsfat_kv_data_t { + const char* filename; + const char* value; +} fsfat_kv_data_t; + + +extern const uint8_t fsfat_test_byte_data_table[FSFAT_TEST_BYTE_DATA_TABLE_SIZE]; + +int32_t fsfat_test_create(const char* filename, const char* data, size_t len); +int32_t fsfat_test_delete(const char* key_name); +int32_t fsfat_test_filename_gen(char* name, const size_t len); +#ifdef __cplusplus +} +#endif + +#endif /* __FSFAT_TEST_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/simple-mbed-cloud-client/#2cabb6ba035e130093f0de193db1fed5eff9df43
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +2cabb6ba035e130093f0de193db1fed5eff9df43
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +9f05156e8386f7ef27a0194d12546b8397c0c564
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + fetch = +refs/heads/*:refs/remotes/origin/* + url = https://github.com/ARMmbed/simple-mbed-cloud-client/ +[branch "master"] + remote = origin + merge = refs/heads/master
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/index Binary file simple-mbed-cloud-client/.git/index has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,26 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores +mbed-cloud-client \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 9f05156e8386f7ef27a0194d12546b8397c0c564 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322661 +0000 clone: from https://github.com/ARMmbed/simple-mbed-cloud-client/ +9f05156e8386f7ef27a0194d12546b8397c0c564 2cabb6ba035e130093f0de193db1fed5eff9df43 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322662 +0000 checkout: moving from master to 2cabb6ba035e130093f0de193db1fed5eff9df43
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/logs/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/logs/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 9f05156e8386f7ef27a0194d12546b8397c0c564 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322661 +0000 clone: from https://github.com/ARMmbed/simple-mbed-cloud-client/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/logs/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/logs/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 9f05156e8386f7ef27a0194d12546b8397c0c564 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322661 +0000 clone: from https://github.com/ARMmbed/simple-mbed-cloud-client/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/objects/pack/pack-43d3f6af622a145b37cb57f4a3566724adde3426.idx Binary file simple-mbed-cloud-client/.git/objects/pack/pack-43d3f6af622a145b37cb57f4a3566724adde3426.idx has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/objects/pack/pack-43d3f6af622a145b37cb57f4a3566724adde3426.pack Binary file simple-mbed-cloud-client/.git/objects/pack/pack-43d3f6af622a145b37cb57f4a3566724adde3426.pack has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,7 @@ +# pack-refs with: peeled +9f05156e8386f7ef27a0194d12546b8397c0c564 refs/remotes/origin/dev +9f05156e8386f7ef27a0194d12546b8397c0c564 refs/remotes/origin/master +4ad472819a315ce78ce48d5c0b6d5722b7c61209 refs/tags/v1.3.0 +^3b72d712ccdb1fbdfa1bdec5209b52f5b813d819 +b1308c14348b42208adf995dcf60ce9a242396ba refs/tags/v1.3.3 +^9f05156e8386f7ef27a0194d12546b8397c0c564
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/refs/heads/master --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/refs/heads/master Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +9f05156e8386f7ef27a0194d12546b8397c0c564
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.git/refs/remotes/origin/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.git/refs/remotes/origin/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +ref: refs/remotes/origin/master
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/.msub --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/.msub Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +mbed-cloud-client = https://github.com/ARMmbed/mbed-cloud-client-restricted/#10:4ae59f9e38574ea8df2a76d903b7268b70722450
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +# simple-mbed-cloud-client +Simple interface for Mbed Cloud CLient
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client.lib Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-cloud-client-restricted/#4ae59f9e38574ea8df2a76d903b7268b70722450
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +4ae59f9e38574ea8df2a76d903b7268b70722450
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/ORIG_HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/ORIG_HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +3d309247835c297c30e057ddef489c5b79ece328
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/config Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false +[remote "origin"] + url = https://github.com/ARMmbed/mbed-cloud-client-restricted/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/description --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/description Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/applypatch-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/applypatch-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/post-update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/post-update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/pre-applypatch.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/pre-applypatch.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/pre-commit.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/pre-commit.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/pre-rebase.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/pre-rebase.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/prepare-commit-msg.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/prepare-commit-msg.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/update.sample --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/hooks/update.sample Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/index Binary file simple-mbed-cloud-client/mbed-cloud-client/.git/index has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/info/exclude --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/info/exclude Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +.hg +.git +.svn +.CVS +.cvs +*.orig +.build +.export +.msub +.meta +.ctags* +*.uvproj +*.uvopt +*.project +*.cproject +*.launch +*.ewp +*.eww +Makefile +Debug +*.htm +*.settings +mbed_settings.py +*.py[cod] +# subrepo ignores \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/logs/HEAD --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/logs/HEAD Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +3d309247835c297c30e057ddef489c5b79ece328 4ae59f9e38574ea8df2a76d903b7268b70722450 www-data <www-data@developer-sjc-indigo-compiler.local.mbed.org> 1530322690 +0000 checkout: moving from master to 4ae59f9e38574ea8df2a76d903b7268b70722450
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/objects/pack/pack-069afc0047a5bbd39c3c5c141301a420c9923972.idx Binary file simple-mbed-cloud-client/mbed-cloud-client/.git/objects/pack/pack-069afc0047a5bbd39c3c5c141301a420c9923972.idx has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/objects/pack/pack-069afc0047a5bbd39c3c5c141301a420c9923972.pack Binary file simple-mbed-cloud-client/mbed-cloud-client/.git/objects/pack/pack-069afc0047a5bbd39c3c5c141301a420c9923972.pack has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.git/packed-refs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.git/packed-refs Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,30 @@ +# pack-refs with: peeled +3d309247835c297c30e057ddef489c5b79ece328 refs/heads/master +88f92e7ec96f3d42ce6834350e4684024ea76e48 refs/tags/1.3.0 +^b91c18dfe9815d3d7cd2e1dcdf8d87d817273e4d +563b3085d8b4cc3d8c89970f7222465f6c295672 refs/tags/1.3.0-GA +^b91c18dfe9815d3d7cd2e1dcdf8d87d817273e4d +b69b319d6c51ed9e74c8e948b35a6c7995097303 refs/tags/1.3.1 +^6f24159dcce954eeb9c50ab814b8f259ca12be52 +751343d680638de8f206a616bba1fa55062509bc refs/tags/1.3.1.1 +^785e84c2a92390a13563ade74f2f0a3622ea5675 +9412fc4c90fbed7a3a26dbb97484acbdc8f4ceb5 refs/tags/1.3.2 +^4cd9b7ccd40661949bc75e27b1f3c4ba5e821e04 +164d678512c20dc6ce8cc20306d4cbd493d91440 refs/tags/1.3.3 +^3d309247835c297c30e057ddef489c5b79ece328 +7c6f6f79eb5dfd960f8bc7b400b7e022e20e00a6 refs/tags/R1.2.4-LA +^0fe22e50dc52da38070f2d3cf4b2e0afd3315200 +579bc472fe44c001754ca09a5258d60702bf7d87 refs/tags/R1.2.4-LA-docs +2b44712e0b9caf4608640e11f04c0c3478687a60 refs/tags/R1.2.5-LA +^91da33c332b3aaf2a913c5ff2a5f59ff7bbab3c5 +ce207ee1a48d44d7066272937623a7b2753b0857 refs/tags/R1.2.6-LA +^4ae59f9e38574ea8df2a76d903b7268b70722450 +90407739b5f908699f6b568bee601d0462fedc32 refs/tags/R1.3.0-LA +^b91c18dfe9815d3d7cd2e1dcdf8d87d817273e4d +e6271c53d1fe38ea1e655492fe64c482f71ff6f9 refs/tags/RR1.2.0-EA +^c4e8012f1972f0e7da02d24186a43ea6cddaeb21 +5858cdf62e4d2683196878d3dd363054ef8f1272 refs/tags/RR1.2.1-EA +^f9b3113105775fdcfde3a2075e953f6b70bfbcbe +1f228138dfff5e8a100a0869d1f5376a9354ab0e refs/tags/RR1.2.1-EA-docs +6ba798f05473c22971d228aa841a933e1ed37c72 refs/tags/RR1.2.2-EA +^c0c6a4c0b68487ea82881553b1904ebeba90041b
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.gitattributes --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.gitattributes Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,37 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.c text +*.h text +*.cpp text +*.sh text +*.py text +*.md text +*.java text +*.yml text +*.cmake text +*.lib text +*.ref text + +# Declare files that will always have CRLF line endings on checkout. +*.sln text eol=crlf +*.bat text eol=crlf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.pdf binary +*.mpp binary +*.doc binary +*.docx binary +*.xls binary +*.xlsx binary +*.ppt binary +*.pptx binary +*.tar binary +*.gzip binary +*.zip binary +*.7z binary +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +mbed-client-randlib/* +mbed-coap/* +mbed-trace/* +nanostack-libservice/* +ns-hal-pal/* +sal-stack-nanostack-eventloop/* +unittests/* +test_modules/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/CMakeLists.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,231 @@ +INCLUDE(CMakeForceCompiler) +# CROSS COMPILER SETTING +cmake_minimum_required (VERSION 2.8) +SET(CMAKE_SYSTEM_NAME Generic) + +add_definitions(-DTARGET_LIKE_POSIX) + +if (${OS_BRAND} MATCHES Linux) + add_definitions(-DMBED_CONF_NS_HAL_PAL_EVENT_LOOP_THREAD_STACK_SIZE=102400) +else() + add_definitions(-DMBED_CONF_NS_HAL_PAL_EVENT_LOOP_THREAD_STACK_SIZE=8000) +endif() + + +SET(MBED_CLOUD_CLIENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/mbed-cloud-client) + +add_definitions(-DMBED_CONF_NANOSTACK_EVENTLOOP_EXCLUDE_HIGHRES_TIMER) +add_definitions(-DMBED_CONF_NANOSTACK_EVENTLOOP_USE_PLATFORM_TICK_TIMER) + +project(mbedCloudClient) + +# mbed-cloud-client + +ADD_GLOBALDIR( ${CMAKE_CURRENT_SOURCE_DIR}) +ADD_GLOBALDIR( ${CMAKE_CURRENT_SOURCE_DIR}/source) +ADD_GLOBALDIR( ${CMAKE_CURRENT_SOURCE_DIR}/source/include) +ADD_GLOBALDIR( ${CMAKE_CURRENT_SOURCE_DIR}/mbed-cloud-client) +ADD_GLOBALDIR( ${CMAKE_CURRENT_SOURCE_DIR}/mbed-client) + +# mbed-client + +SET(MBED_CLIENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/mbed-client) + +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/source) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/source/include) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/mbed-client) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/mbed-client-c) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/mbed-client-c/nsdl-c) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/mbed-client-c/source/include) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/mbed-client-classic) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/mbed-client-classic/mbed-client-classic) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/mbed-client-mbed-tls) +ADD_GLOBALDIR(${MBED_CLIENT_SOURCE_DIR}/mbed-client-mbed-tls/mbed-client-mbedtls) + +# pal headers + +SET(PAL_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/mbed-client-pal/Source) +ADD_GLOBALDIR(${PAL_SOURCE_DIR}/PAL-Impl/Services-API) +ADD_GLOBALDIR(${PAL_SOURCE_DIR}/Port/Platform-API) + +# common components + +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/mbed-coap) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/mbed-coap/mbed-coap) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/mbed-coap/source/include) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/mbed-trace) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/mbed-trace/mbed-trace) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/mbed-client-randlib) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/mbed-client-randlib/mbed-client-randlib) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/mbed-client-randlib/mbed-client-randlib/platform) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice/mbed-client-libservice) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice/mbed-client-libservice/platform) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/sal-stack-nanostack-eventloop) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/sal-stack-nanostack-eventloop/nanostack-event-loop) +ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/ns-hal-pal) + +# factory-client + +SET(FACTORY_CLIENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/factory-configurator-client) +ADD_GLOBALDIR(${FACTORY_CLIENT_SOURCE_DIR}/factory-configurator-client) + +SET(FCC_MODULES + ftcd-comm-base + ftcd-comm-socket + crypto-service + key-config-manager + factory-configurator-client + fcc-bundle-handler + secsrv-cbor + logger + storage + utils + mbed-trace-helper + fcc-output-info-handler + mbed-client-esfs +) + +# includes +FOREACH(module ${FCC_MODULES}) + ADD_GLOBALDIR(${FACTORY_CLIENT_SOURCE_DIR}/${module}/${module}) + ADD_GLOBALDIR(${FACTORY_CLIENT_SOURCE_DIR}/${module}/source/include) +ENDFOREACH() + +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/factory-configurator-client/source/include) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/factory-configurator-client/factory-configurator-client) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/fc_protocol_handler/fc_protocol_handler) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/fc_protocol_handler/source/include) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/secure_store) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/secure_store/secure_store) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/storage) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/storage/storage) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/key-config-manager) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/key-config-manager/source/include) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/utils) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/utils/utils) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/logger) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/logger/logger) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/mbed-client-esfs/source/include) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/mbed-client-esfs/source-pal/api) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/mbed-client-esfs/source-pal/linux) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/crypto-service/crypto-service) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/crypto-service/source/include) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/secsrv-cbor/secsrv-cbor) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/fcc-bundle-handler/fcc-bundle-handler) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/fcc-bundle-handler/source/include) +include_directories(${FACTORY_CLIENT_SOURCE_DIR}/fcc-output-info-handler/fcc-output-info-handler) + +# update-client + +SET(UPDATE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/update-client-hub) + +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/update-client-hub) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/atomic-queue) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/atomic-queue/atomic-queue) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/common) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/common/update-client-common) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/control-center) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/control-center/update-client-control-center) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/device-identity) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/device-identity/pal4life-device-identity) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/firmware-manager) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/firmware-manager/update-client-firmware-manager) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/lwm2m-mbed) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/lwm2m-mbed/update-client-lwm2m) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/manifest-manager) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/manifest-manager/update-client-manifest-manager) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/manifest-manager/source) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/monitor) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/monitor/update-client-monitor) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/paal-update-api) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/paal-update-api/paal-update-api) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/source) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/source/update-client-source) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/source-http) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/source-http/update-client-source-http) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/source-http-socket) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/source-http-socket/update-client-source-http-socket) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/source-manager) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/source-manager/update-client-source-manager) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/paal) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/paal/update-client-paal) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/pal-filesystem) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/pal-filesystem/update-client-pal-filesystem) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/pal-flashiap) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/pal-flashiap/update-client-pal-flashiap) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/pal-linux) +ADD_GLOBALDIR(${UPDATE_SOURCE_DIR}/modules/pal-linux/update-client-pal-linux) + +FILE(GLOB MBED_CLOUD_CLIENT_SRC + "${CMAKE_CURRENT_SOURCE_DIR}/source/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp" + "${MBED_CLIENT_SOURCE_DIR}/source/*.cpp" + "${MBED_CLIENT_SOURCE_DIR}/mbed-client-c/source/*.c" + "${MBED_CLIENT_SOURCE_DIR}/mbed-client-classic/source/*.cpp" + "${MBED_CLIENT_SOURCE_DIR}/mbed-client-mbed-tls/source/*.cpp" + + "${CMAKE_CURRENT_SOURCE_DIR}/mbed-coap/source/*.c" + + "${CMAKE_CURRENT_SOURCE_DIR}/mbed-client-randlib/source/*.c" + + "${CMAKE_CURRENT_SOURCE_DIR}/sal-stack-nanostack-eventloop/source/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/sal-stack-nanostack-eventloop/source/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/sal-stack-nanostack-eventloop/source/*.cpp" + + "${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice/source/libBits/common_functions.c" + "${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice/source/libList/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice/source/nsdynmemLIB/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice/source/libip6string/ip6tos.c" + + "${CMAKE_CURRENT_SOURCE_DIR}/ns-hal-pal/ns_event_loop.c" +if ((${OS_BRAND} MATCHES "FreeRTOS")) + "${CMAKE_CURRENT_SOURCE_DIR}/ns-hal-pal/arm_hal_random.c" +endif() + "${CMAKE_CURRENT_SOURCE_DIR}/ns-hal-pal/ns_hal_init.c" + "${CMAKE_CURRENT_SOURCE_DIR}/ns-hal-pal/arm_hal_interrupt.c" + "${CMAKE_CURRENT_SOURCE_DIR}/ns-hal-pal/arm_hal_timer.cpp" + "${FACTORY_CLIENT_SOURCE_DIR}/source/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/storage/source/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/secure_store/source/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/key-config-manager/source/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/utils/source/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/logger/source/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/mbed-client-esfs/source/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/mbed-client-esfs/source-pal/linux/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/mbed-client-esfs/source-pal/linux/*.cpp" + "${FACTORY_CLIENT_SOURCE_DIR}/crypto-service/source/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/fcc-bundle-handler/source/*.c" + "${FACTORY_CLIENT_SOURCE_DIR}/fcc-output-info-handler/source/*.c" + ) + +if ((${OS_BRAND} MATCHES "Linux")) + FILE(GLOB UPDATE_SRC + "${UPDATE_SOURCE_DIR}/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/atomic-queue/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/common/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/control-center/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/device-identity/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/firmware-manager/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/lwm2m-mbed/source/*.cpp" + "${UPDATE_SOURCE_DIR}/modules/manifest-manager/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/source-http/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/source-http-socket/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/source-manager/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/paal/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/pal-filesystem/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/pal-flashiap/source/*.c" + "${UPDATE_SOURCE_DIR}/modules/pal-flashiap/source/*.cpp" + "${UPDATE_SOURCE_DIR}/modules/pal-linux/source/*.c" + ) +endif() + +list(APPEND MBED_CLOUD_CLIENT_SRC ${UPDATE_SRC}) +message(status "Mbed Cloud Client sources = \n ${MBED_CLOUD_CLIENT_SRC}") + +CREATE_LIBRARY(mbedCloudClient "${MBED_CLOUD_CLIENT_SRC}" "") +add_dependencies(mbedCloudClient mbedtls) + +ADDSUBDIRS()
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/DOXYGEN_FRONTPAGE.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/DOXYGEN_FRONTPAGE.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,17 @@ +mbed Cloud Client API +===================== + +This is the Doxygen generated API documentation of mbed Cloud Client. See the [Files](files.html) section to find the documentation about a specific API. It should be used together with the [mbed Cloud documentation](https://cloud.mbed.com/docs/latest). + +The mbed Cloud Client high-level APIs allow mbed Cloud developers to create client side applications that connect to the mbed Cloud service, with LwM2M features as described in the [Lightweight Machine to Machine Technical Specification](http://technical.openmobilealliance.org/Technical/technical-information/release-program/current-releases/oma-lightweightm2m-v1-0). + +mbed Cloud Client is an extension of the existing [mbed Client API](http://cloud.mbed.com/docs/v1.2/mbed-client/index.html). It provides an additional feature of creating a unique identity for the client on the Cloud service and also provides functionality to update Client's software through the mbed Cloud service. + +- Use a factory flashed or developer credentials to create a unique device identity. +- Securely communicate with internet services over the industry standard TLS/DTLS. +- Manage devices on mbed Cloud service. +- Fully control the endpoint and application logic from the service side. +- Provide functionality to update the devices over the air remotely controlled from the service side. +- Have a unified porting layer for porting to different platforms. + +The API is in C++ to allow quick application development.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/README.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,5 @@ +# mbed-cloud-client +This repository contains ARM mbed Cloud Client: a library that connects devices to mbed Cloud Service and to mbed-enabled cloud services from our partners. + +The documentation is collected under the docs directory and it is also hosted [here](https://cloud.mbed.com/docs/v1.2/connecting/index.html). +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/contributions.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/contributions.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,12 @@ +# How to contribute and report issues + +This directory structure contains sources that are copied from internal development source repositories. + +## Pull Request policy +Pull Requests against this repository will be evaluated and the decision to take the change in will be communicated through the same PR. +However, it will not be merged directly but will enter into subsequent release through internal repositories and the tagged release will be updated in PR before closing it. + +## Issue tracking +You can create Github issues directly againt the repository, the resolution of the issue will be tracked under it. +If the issue requires code fix it will be provided through subsequent releases and the release tag will be updated there. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/doxygen/mbedcloudclient_doxy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/doxygen/mbedcloudclient_doxy Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1846 @@ +# Doxyfile 1.8.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = mbed-cloud-client + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "mbed Cloud Client C++ library" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../api_docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 16 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = YES + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 18 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../mbed-cloud-client + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 44 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/CMakeLists.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.6) +project("fcc") + +include(common_includes.cmake) + + +# esfs +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbed-client-esfs/source-pal/api) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbed-client-esfs/source-pal/linux) + +# mbed-tace +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbed-trace) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbed-trace/mbed-trace) + +# nanostack +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice/mbed-client-libservice) + +SET(SOURCE_LIST "") + +FOREACH(module ${MODULES}) + # sources + LIST(APPEND SOURCE_LIST "${CMAKE_CURRENT_SOURCE_DIR}/${module}/${module}/*.h") + LIST(APPEND SOURCE_LIST "${CMAKE_CURRENT_SOURCE_DIR}/${module}/source/*.c") + LIST(APPEND SOURCE_LIST "${CMAKE_CURRENT_SOURCE_DIR}/${module}/source/*.cpp") +ENDFOREACH() + + +FILE(GLOB factory-configurator-client ${SOURCE_LIST}) + +message ("*********************************************************************") +message ("factory-configurator-client = [[${factory-configurator-client}]]") +message ("*********************************************************************") + +CREATE_LIBRARY(factory-configurator-client "${factory-configurator-client}" "") +ADDSUBDIRS()
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/DOXYGEN_FRONTPAGE.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/DOXYGEN_FRONTPAGE.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,34 @@ +factory configurator client API +=============================== + +This is the Doxygen generated documentation of factory configurator client (FCC) and Key and Configuration Manager (KCM). +It should be used together with the [mbed Cloud documentation](https://cloud.mbed.com/docs/latest). See the [Files](files.html) section to find documentation about a specific API + +## FCC + +The FCC APIs initialize the factory flow, store the factory configurations using KCM APIs or FCC bundle handler and +verify that the device is ready for mbed Cloud connection. + +The FCC APIs allow the following operations: + +- Initiating and finalizing of the FCC flow. +- After items injection, verifying that the device is ready for mbed Cloud connection. +- Retrieving errors and warnings during the injection process. +- Cleaning all data that was injected to the device. + +In developer mode, you do not need to use the factory configurator utility (FCU). + +## FCC bundle handler + +The FCC bundle handler processes the bundle (in CBOR format) created by factory client utility (FCU) and transferred to the device by the Factory Tool. The device creates a response CBOR message with status and warning details and sends it back to the Factory Tool and the FCU. During the processing, the device stores all relevant factory configuration data to the device's storage. + +## KCM + +The KCM APIs store parameters, keys and certificates (items) in the device's secure storage and allows other applications (customer or mbed) to access these parameters. + +The KCM APIs allow the following operations on items: + + - Verification and storing items into a secure storage. + - Retrieving the item data size from the secure storage. + - Retrieving item data from the secure storage. + - Deleting items from the secure storage. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/common_includes.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/common_includes.cmake Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,40 @@ + + +SET(MODULES + ftcd-comm-base + ftcd-comm-socket + crypto-service + key-config-manager + factory-configurator-client + fcc-bundle-handler + secsrv-cbor + logger + storage + utils + mbed-trace-helper + fcc-output-info-handler +) + + +# includes +FOREACH(module ${MODULES}) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/${module}/${module}) +ENDFOREACH() + +# factory-configurator-client internal includes +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/crypto/source/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/crypto-service/source/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/key-config-manager/source/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbed-client-esfs/source/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/factory-configurator-client/source/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/logger/source/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/fcc-bundle-handler/source/include) + +# mbed-client-pal +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbed-client-pal/Source/PAL-Impl/Services-API) + +# mbed-trace +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbed-trace) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbed-trace/mbed-trace) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/nanostack-libservice/mbed-client-libservice) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/logger/logger) \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/crypto-service/cs_der_certs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/crypto-service/cs_der_certs.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,158 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __CS_DER_CERTS_H__ +#define __CS_DER_CERTS_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> +#include "kcm_status.h" + +/* +* Types certificate's attributes +*/ +typedef enum cs_certificate_attribute_type_ { + CS_CN_ATTRIBUTE_TYPE, + CS_VALID_FROM_ATTRIBUTE_TYPE, + CS_VALID_TO_ATTRIBUTE_TYPE, + CS_OU_ATTRIBUTE_TYPE, + CS_SUBJECT_ATTRIBUTE_TYPE, + CS_ISSUER_ATTRIBUTE_TYPE, + CS_MAX_ATTRIBUTE_TYPE +} cs_certificate_attribute_type_e; + + + +/** Verify handle of x509 formatted certificate using certificate chain handle. +* +* In case one of certificate handle is NULLPTR the API returns an error. +* +* @param[in] x509_cert - A handle holding the parsed certificate. +* @param[in] x509_cert_chain - The pointer to the handle of chain to verify the X509 certificate : Optional +* +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ +kcm_status_e cs_verify_x509_cert(palX509Handle_t x509_cert, palX509Handle_t x509_cert_chain); + +/**Parse x509 certificate in DER format. +* The API parses der certificate and during the parsing checks basic fields structure of the certificate. +* +*@cert[in] - DER format certificate. +*@cert_length[in] - certificate length +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ +kcm_status_e cs_parse_der_x509_cert(const uint8_t *cert, size_t cert_length); + +/**Parse and create handle for x509 der certificate. +* In case certificate is NULL , return empty initialized handle. +* +*@cert[in] - DER format certificate. +*@cert_length[in] - certificate length +*@x509_cert_handle[out] - certificate handle +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ +kcm_status_e cs_create_handle_from_der_x509_cert(const uint8_t *cert, size_t cert_length, palX509Handle_t *x509_cert_handle); + + +/**Add certificate to chain handle. +* Parse x509 der certificate and add to the chain handle. +* +*@cert[in] - DER format certificate. +*@cert_length[in] - certificate length +*@x509_chain_handle[out] - certificate chain handle +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ +kcm_status_e cs_add_to_chain_x509_cert(const uint8_t *cert, size_t cert_length, palX509Handle_t x509_chain_handle); + +/**Close created x509 handle certificate. +* +*@x509_cert_handle[in/out] handle of parsed x509 certificate. +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ +kcm_status_e cs_close_handle_x509_cert(palX509Handle_t *x509_cert_handle); + +/**Verify that x509 certificate is self-signed. +* +*@x509_cert[in] - x509 certificate handle. +*@is_self_signed[out] - if the value is true the certificate is self-signed, otherwise not self-signed +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ +kcm_status_e cs_is_self_signed_x509_cert(palX509Handle_t x509_cert, bool* is_self_signed); + + +/**Gets current attribute from certificate +* +*@x509_cert[in] - x509 certificate handle. +*@cs_attribute_type[in] - certificate attribute type +*@attribute_output_buffer[out] -pointer to output attribute buffer. +*@max_size_of_attribute_output_buffer[in] -size of output attribute buffer. +*@actual_size_of_attribute_output_buffer[out] -actual size of attribute. +* +* note in case of "KCM_STATUS_INSUFFICIENT_BUFFER" error the required size will be assigned into the "actual_size_of_output" parameter. +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ +kcm_status_e cs_attr_get_data_x509_cert(palX509Handle_t x509_cert, + cs_certificate_attribute_type_e cs_attribute_type, + uint8_t *attribute_output_buffer, + size_t max_size_of_attribute_output_buffer, + size_t *actual_size_of_attribute_output_buffer); + +/**Gets current attribute size from certificate +* +*@x509_cert[in] - x509 certificate handle. +*@cs_attribute_type[in] - certificate attribute type +*@size_of_attribute[out] - size of attribute. +* +*@return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ +kcm_status_e cs_attr_get_data_size_x509_cert(palX509Handle_t x509_cert, + cs_certificate_attribute_type_e cs_attribute_type, + size_t *size_of_attribute); + +/**Checks signature using x509 certificate +* +*@x509_cert[in] - handle of x509 certificate. +*@hash[in] - hash digest for verification +*@hash_size[in] - size of hash digest. +*@signature[in] - pointer to signature. +*@signature_size[in] -signature size. +* +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ + +kcm_status_e cs_x509_cert_verify_signature(palX509Handle_t x509_cert, + const unsigned char *hash, + size_t hash_size, + const unsigned char *signature, + size_t signature_size); + + +#ifdef __cplusplus +} +#endif + +#endif // __CS_DER_CERTS_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/crypto-service/cs_der_keys.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/crypto-service/cs_der_keys.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,81 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __CS_DER_KEYS_H__ +#define __CS_DER_KEYS_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> + +#include "kcm_status.h" + +typedef enum { + CS_SECP256R1 +} cs_curve_name_e; + + +#define CS_SECP256R1_SIZE_IN_BITS 256 +/*The max size of ecdsa signature defined according ecdsa.h file of mbedtls : + * The "sig" buffer must be at least as large as twice the + * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit + * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. + * The reason of adding of additional 9 bytes is according to RFC 4492 page 20 + * used in mbedtls for signature serialization. + */ +#define CS_ECDSA_SECP256R1_MAX_SIGNATURE_SIZE_IN_BYTES (CS_SECP256R1_SIZE_IN_BITS/8)*2 + 10 //74 bytes + +/**Verify private Key In DER format. For now only EC keys supported +* +*@key_data DER format private key data. +*@key_data_length key data size +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ + +kcm_status_e cs_der_priv_key_verify(const uint8_t* key, size_t key_length); + +/**Verify public Key In DER format. For now only EC keys supported +* +*@key_data DER format puclic key data. +*@key_data_length key data size +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ + +kcm_status_e cs_der_public_key_verify(const uint8_t* key, size_t key_length); + +/**Calculate signature on hash digest using ecdsa private key. +* +*@der_priv_key[in] - DER private key data. +*@der_priv_key_length[in] - key data size +*@hash_dgst[in] - hash digest buffer +*@size_of_hash_dgst[in] - size of hash digest buffer +*@out_sign[in/out] - output buffer for calculated signature +*@signature_data_max_size[in] - size of signature buffer +*@signature_data_act_size_out[out] - actual size of output signature buffer +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ +kcm_status_e cs_ecdsa_sign(const uint8_t *der_priv_key, size_t der_priv_key_length, const uint8_t *hash_dgst, size_t size_of_hash_dgst, uint8_t *out_sign, size_t signature_data_max_size, size_t * signature_data_act_size_out); + + +#ifdef __cplusplus +} +#endif + +#endif //__CS_DER_KEYS_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/crypto-service/cs_hash.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/crypto-service/cs_hash.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,60 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __CS_HASH_H__ +#define __CS_HASH_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> + +#include "kcm_status.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + CS_SHA256,//not supported : MD2, MD5, SHA, SHA512, SHA384,SHA512 +} cs_hash_mode_e; + +typedef enum { + CS_SHA256_SIZE = 32, +} cs_hash_size_e; + + +/**Calculate hash on input data +* + +*@mode hash mode as defined in hash_mode enum. +*@data data to calculate hash on it +*@data_size data size +*@digest calculated digest output +*@digest_size the size of hash output buffer, should be equal or bigger than current mode hash size in +* hash_size enum.The actual size of hash result is as defined in hash_size enum. +* @return +* KCM_STATUS_SUCCESS on success, otherwise appropriate error from kcm_status_e. +*/ + +kcm_status_e cs_hash(cs_hash_mode_e mode, const uint8_t *data, size_t data_size, uint8_t *digest, size_t digest_size); + +#ifdef __cplusplus +} +#endif + +#endif // __CS_HASH_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/cs_der_certs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/cs_der_certs.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,273 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "pv_error_handling.h" +#include "cs_der_certs.h" +#include "cs_der_keys.h" +#include "cs_hash.h" +#include "pal.h" +#include "cs_utils.h" +#include "stdbool.h" +#include "fcc_malloc.h" + + +static kcm_status_e cs_get_x509_cert_attribute_type(cs_certificate_attribute_type_e cs_attribute_type, palX509Attr_t *attribute_type) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + + + switch (cs_attribute_type) { + case CS_CN_ATTRIBUTE_TYPE: + *attribute_type = PAL_X509_CN_ATTR; + break; + case CS_VALID_TO_ATTRIBUTE_TYPE: + *attribute_type = PAL_X509_VALID_TO; + break; + case CS_VALID_FROM_ATTRIBUTE_TYPE: + *attribute_type = PAL_X509_VALID_FROM; + break; + case CS_OU_ATTRIBUTE_TYPE: + *attribute_type = PAL_X509_OU_ATTR; + break; + case CS_SUBJECT_ATTRIBUTE_TYPE: + *attribute_type = PAL_X509_SUBJECT_ATTR; + break; + case CS_ISSUER_ATTRIBUTE_TYPE: + *attribute_type = PAL_X509_ISSUER_ATTR; + break; + default: + SA_PV_ERR_RECOVERABLE_RETURN_IF((true), KCM_CRYPTO_STATUS_INVALID_X509_ATTR, "Invalid cert attribute"); + } + + return kcm_status; +} + +kcm_status_e cs_is_self_signed_x509_cert(palX509Handle_t x509_cert, bool *is_self_signed) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + + uint8_t *cert_subject = NULL; + uint8_t *cert_issuer = NULL; + size_t subject_size = 0, issuer_size = 0; + + //Self-signed certificate is certificate with subject attribute = issuer attribute + //get and check issuer and subject sizes + kcm_status = cs_attr_get_data_size_x509_cert(x509_cert, CS_SUBJECT_ATTRIBUTE_TYPE, &subject_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "get size PAL_X509_SUBJECT_ATTR failed"); + + kcm_status = cs_attr_get_data_size_x509_cert(x509_cert, CS_ISSUER_ATTRIBUTE_TYPE, &issuer_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "get size PAL_X509_ISSUER_ATTR failed"); + + //If issuer and subject attributes have different length it is not self-signed certificate + if (subject_size != issuer_size) { + *is_self_signed = false; + return KCM_STATUS_SUCCESS; + } + + //Get and check attributes values + cert_subject = fcc_malloc(subject_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((cert_subject == NULL), kcm_status = KCM_STATUS_OUT_OF_MEMORY, exit, "Allocate subject attribute failed"); + + pal_status = pal_x509CertGetAttribute(x509_cert, PAL_X509_SUBJECT_ATTR, cert_subject, subject_size, &subject_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((pal_status != PAL_SUCCESS), kcm_status = cs_error_handler(pal_status), exit,"pal_x509CertGetAttribute PAL_X509_SUBJECT_ATTR failed %d ", (int)cs_error_handler(pal_status)); + + cert_issuer = fcc_malloc(issuer_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((cert_subject == NULL), kcm_status = KCM_STATUS_OUT_OF_MEMORY, exit, "Allocate issuer attribute failed"); + + pal_status = pal_x509CertGetAttribute(x509_cert, PAL_X509_ISSUER_ATTR, cert_issuer, issuer_size, &issuer_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((pal_status != PAL_SUCCESS), kcm_status = cs_error_handler(pal_status), exit, "pal_x509CertGetAttribute PAL_X509_ISSUER_ATTR failed %d", (int)kcm_status); + + if (memcmp(cert_issuer, cert_subject, issuer_size) == 0) { + *is_self_signed = true; + } else { + *is_self_signed = false; + } + +exit: + fcc_free(cert_subject); + fcc_free(cert_issuer); + + return kcm_status; +} + +kcm_status_e cs_create_handle_from_der_x509_cert(const uint8_t *cert, size_t cert_length, palX509Handle_t *x509_cert_handle) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert != NULL && cert_length == 0), KCM_STATUS_INVALID_PARAMETER, "Invalid cert_length"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((x509_cert_handle == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid x509_cert_handler"); + + //Allocate and Init certificate handler + pal_status = pal_x509Initiate(x509_cert_handle); + SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status != PAL_SUCCESS), cs_error_handler(pal_status), "pal_x509Initiate failed"); + + if (cert != NULL) { + //Parse Certificate. + pal_status = pal_x509CertParse(*x509_cert_handle, cert, cert_length); + SA_PV_ERR_RECOVERABLE_GOTO_IF((pal_status != PAL_SUCCESS), kcm_status = cs_error_handler(pal_status), exit, "pal_x509CertParse failed"); + } + +exit: + if (pal_status != PAL_SUCCESS) { + pal_x509Free(x509_cert_handle); + } + + return kcm_status; +} +kcm_status_e cs_add_to_chain_x509_cert(const uint8_t *cert, size_t cert_length, palX509Handle_t x509_chain_handle) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid cert pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert_length <= 0), KCM_STATUS_INVALID_PARAMETER, "Invalid cert_length"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((x509_chain_handle == NULLPTR), KCM_STATUS_INVALID_PARAMETER, "Invalid x509_chain_handle"); + + //Parse Certificate. + pal_status = pal_x509CertParse(x509_chain_handle, cert, cert_length); + SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status != PAL_SUCCESS), kcm_status = cs_error_handler(pal_status), "pal_x509CertParse failed"); + + return kcm_status; +} +kcm_status_e cs_close_handle_x509_cert(palX509Handle_t *x509_cert_handle) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + + pal_status = pal_x509Free(x509_cert_handle); + SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status != PAL_SUCCESS), kcm_status = cs_error_handler(pal_status), "pal_x509Free failed"); + + return kcm_status; +} +kcm_status_e cs_parse_der_x509_cert(const uint8_t *cert, size_t cert_length) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + palX509Handle_t x509_cert = NULLPTR; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid cert pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert_length <= 0), KCM_STATUS_INVALID_PARAMETER, "Invalid cert_length"); + + //Allocate and Init certificate handler + pal_status = pal_x509Initiate(&x509_cert); + SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status != PAL_SUCCESS), cs_error_handler(pal_status), "pal_x509Initiate failed"); + + //Parse Certificate. + pal_status = pal_x509CertParse(x509_cert, cert, cert_length); + SA_PV_ERR_RECOVERABLE_GOTO_IF((pal_status != PAL_SUCCESS), kcm_status = cs_error_handler(pal_status), exit, "pal_x509CertParse failed"); + +exit: + pal_x509Free(&x509_cert); + return kcm_status; +} + +kcm_status_e cs_verify_x509_cert(palX509Handle_t x509_cert,palX509Handle_t x509_cert_chain) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + bool is_self_signed = false; + palX509Handle_t x509_ca_cert = NULLPTR; + + + SA_PV_ERR_RECOVERABLE_RETURN_IF((x509_cert == NULLPTR), KCM_STATUS_INVALID_PARAMETER, "Invalid cert handle"); + + kcm_status = cs_is_self_signed_x509_cert(x509_cert, &is_self_signed); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status = kcm_status, exit, "Self signed verification failed"); + + if (is_self_signed && x509_cert_chain == NULLPTR) { // Send the certificate itself as trusted chain + x509_ca_cert = x509_cert; + } else { + x509_ca_cert = x509_cert_chain; + } + + //Verify certificate using created certificate chain + pal_status = pal_x509CertVerify(x509_cert, x509_ca_cert); + SA_PV_ERR_RECOVERABLE_GOTO_IF((pal_status != PAL_SUCCESS), kcm_status = cs_error_handler(pal_status), exit, "pal_x509CertVerify failed %" PRIu32 "", pal_status); + +exit: + return kcm_status; +} + +kcm_status_e cs_attr_get_data_size_x509_cert(palX509Handle_t x509_cert, + cs_certificate_attribute_type_e cs_attribute_type, + size_t *size_of_attribute) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palX509Attr_t attribute_type; + palStatus_t pal_status = PAL_SUCCESS; + uint8_t output_buffer; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((x509_cert == NULLPTR), KCM_STATUS_INVALID_PARAMETER, "Invalid x509_cert"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((size_of_attribute == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid size_of_attribute pointer"); + + kcm_status = cs_get_x509_cert_attribute_type(cs_attribute_type, &attribute_type); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "cs_get_x509_cert_attribute_type failed"); + + //Get the attribute size + pal_status = pal_x509CertGetAttribute(x509_cert, attribute_type, &output_buffer, 0, size_of_attribute); + SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status == PAL_SUCCESS), KCM_STATUS_ERROR, "Attribute size is 0"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status != PAL_ERR_BUFFER_TOO_SMALL), kcm_status = cs_error_handler(pal_status), "Failed to get attribute size"); + + return KCM_STATUS_SUCCESS; +}; + +kcm_status_e cs_attr_get_data_x509_cert(palX509Handle_t x509_cert, + cs_certificate_attribute_type_e cs_attribute_type, + uint8_t *attribute_output_buffer, + size_t max_size_of_attribute_output_buffer, + size_t *actual_size_of_attribute_output_buffer) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palX509Attr_t attribute_type; + palStatus_t pal_status = PAL_SUCCESS; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((x509_cert == NULLPTR), KCM_STATUS_INVALID_PARAMETER, "Invalid x509_cert"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((attribute_output_buffer == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid output pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((actual_size_of_attribute_output_buffer == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid actual_size_of_output pointer"); + + kcm_status = cs_get_x509_cert_attribute_type(cs_attribute_type, &attribute_type); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "cs_get_x509_cert_attribute_type failed"); + + //Get the attribute + pal_status = pal_x509CertGetAttribute(x509_cert, attribute_type, attribute_output_buffer, max_size_of_attribute_output_buffer, actual_size_of_attribute_output_buffer); + SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status != PAL_SUCCESS), kcm_status = cs_error_handler(pal_status), "pal_x509CertGetAttribute failed"); + + return kcm_status; +}; + +kcm_status_e cs_x509_cert_verify_signature(palX509Handle_t x509_cert, const unsigned char *hash, size_t hash_size, const unsigned char *signature, size_t signature_size) +{ + + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((x509_cert == NULLPTR), KCM_STATUS_INVALID_PARAMETER, "Invalid x509_cert"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((hash == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid hash pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((hash_size != CS_SHA256_SIZE), KCM_STATUS_INVALID_PARAMETER, "Invalid hash digest size"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((signature == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid signature pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((signature_size == 0), KCM_STATUS_INVALID_PARAMETER, "Invalid signature size"); + + //Verify signature + pal_status = pal_verifySignature(x509_cert, PAL_SHA256, hash, hash_size, signature, signature_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status != PAL_SUCCESS), kcm_status = cs_error_handler(pal_status), "pal_verifySignature failed"); + + return kcm_status; +} + + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/cs_der_keys.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/cs_der_keys.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,147 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "pv_error_handling.h" +#include "cs_der_keys.h" +#include "pal.h" +#include "cs_utils.h" +#include "cs_hash.h" + +//For now only EC keys supported!!! +static kcm_status_e der_key_verify(const uint8_t *der_key, size_t der_key_length, palKeyToCheck_t key_type) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + palECKeyHandle_t key_handle = NULLPTR; + palCurveHandle_t grp = NULLPTR; + palGroupIndex_t pal_grp_idx; + bool verified = false; + + + SA_PV_ERR_RECOVERABLE_RETURN_IF((der_key == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid der_key pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((der_key_length <= 0), KCM_STATUS_INVALID_PARAMETER, "Invalid der_key_length"); + + //Create new key handler + pal_status = pal_ECKeyNew(&key_handle); + SA_PV_ERR_RECOVERABLE_RETURN_IF((PAL_SUCCESS != pal_status), cs_error_handler(pal_status), "pal_ECKeyNew failed "); + + //Parse the key from DER format + if (key_type == PAL_CHECK_PRIVATE_KEY) { + pal_status = pal_parseECPrivateKeyFromDER(der_key, der_key_length, key_handle); + SA_PV_ERR_RECOVERABLE_GOTO_IF((PAL_SUCCESS != pal_status), kcm_status = cs_error_handler(pal_status), exit, "pal_parseECPrivateKeyFromDER failed "); + } else { + pal_status = pal_parseECPublicKeyFromDER(der_key, der_key_length, key_handle); + SA_PV_ERR_RECOVERABLE_GOTO_IF((PAL_SUCCESS != pal_status), kcm_status = cs_error_handler(pal_status), exit, "pal_parseECPublicKeyFromDER failed "); + } + + //retrieve key curve from key handle + pal_status = pal_ECKeyGetCurve(key_handle, &pal_grp_idx); + SA_PV_ERR_RECOVERABLE_GOTO_IF((PAL_SUCCESS != pal_status), kcm_status = cs_error_handler(pal_status), exit, "pal_ECKeyGetCurve failed "); + + //Allocate curve handler + pal_status = pal_ECGroupInitAndLoad(&grp, pal_grp_idx); + SA_PV_ERR_RECOVERABLE_GOTO_IF((PAL_SUCCESS != pal_status), kcm_status = cs_error_handler(pal_status), exit, "pal_parseECPrivateKeyFromDER failed "); + + //Perform key verification + pal_status = pal_ECCheckKey(grp, key_handle, key_type, &verified); + SA_PV_ERR_RECOVERABLE_GOTO_IF(((PAL_SUCCESS != pal_status) || (verified != true)), kcm_status = cs_error_handler(pal_status), exit, "pal_ECCheckKey failed "); + + +exit: + //Free curve handle + (void)pal_ECGroupFree(&grp); + //Free key handler + (void)pal_ECKeyFree(&key_handle); + + if (kcm_status == KCM_STATUS_SUCCESS) { + SA_PV_ERR_RECOVERABLE_RETURN_IF((grp != NULLPTR || key_handle != NULLPTR), KCM_STATUS_ERROR, "Free handle failed "); + } + + return kcm_status; +} + +kcm_status_e cs_der_priv_key_verify(const uint8_t *key, size_t key_length) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + + kcm_status = der_key_verify(key, key_length, PAL_CHECK_PRIVATE_KEY); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Private key verification failed"); + + return kcm_status; +} + +kcm_status_e cs_der_public_key_verify(const uint8_t *der_key, size_t der_key_length) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + + kcm_status = der_key_verify(der_key, der_key_length, PAL_CHECK_PUBLIC_KEY); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Public key verification failed"); + + return kcm_status; +} + +kcm_status_e cs_ecdsa_sign(const uint8_t *der_priv_key, size_t der_priv_key_length,const uint8_t *hash_dgst,size_t size_of_hash_dgst, uint8_t *out_sign, size_t signature_data_max_size,size_t * signature_data_act_size_out) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + palECKeyHandle_t key_handle = NULLPTR; + palCurveHandle_t grp = NULLPTR; + palGroupIndex_t pal_grp_idx; + palMDType_t md_type = PAL_SHA256; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((der_priv_key == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid private key pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((der_priv_key_length <= 0), KCM_STATUS_INVALID_PARAMETER, "Invalid private key length"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((hash_dgst == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid hash digest pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((size_of_hash_dgst != CS_SHA256_SIZE), KCM_STATUS_INVALID_PARAMETER, "Invalid hash digest size"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((out_sign == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid out signature pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((signature_data_act_size_out == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid signature_data_act_size_out pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((signature_data_max_size < CS_ECDSA_SECP256R1_MAX_SIGNATURE_SIZE_IN_BYTES), KCM_STATUS_INVALID_PARAMETER, "Invalid size of signature buffer"); + + + + //Create new key handler + pal_status = pal_ECKeyNew(&key_handle); + SA_PV_ERR_RECOVERABLE_RETURN_IF((PAL_SUCCESS != pal_status), cs_error_handler(pal_status), "pal_ECKeyNew failed "); + + //Parse der private key + pal_status = pal_parseECPrivateKeyFromDER(der_priv_key, der_priv_key_length, key_handle); + SA_PV_ERR_RECOVERABLE_GOTO_IF((PAL_SUCCESS != pal_status), kcm_status = cs_error_handler(pal_status), exit, "pal_parseECPrivateKeyFromDER failed "); + + //retrieve key curve from key handle + pal_status = pal_ECKeyGetCurve(key_handle, &pal_grp_idx); + SA_PV_ERR_RECOVERABLE_GOTO_IF((PAL_SUCCESS != pal_status), kcm_status = cs_error_handler(pal_status), exit, "pal_ECKeyGetCurve failed "); + + //Load the key curve + pal_status = pal_ECGroupInitAndLoad(&grp, pal_grp_idx); + SA_PV_ERR_RECOVERABLE_GOTO_IF((PAL_SUCCESS != pal_status), kcm_status = cs_error_handler(pal_status), exit, "pal_ECGroupInitAndLoad failed "); + + *signature_data_act_size_out = signature_data_max_size; + //Sign on hash digest + pal_status = pal_ECDSASign(grp, md_type, key_handle, (unsigned char*)hash_dgst, (uint32_t)size_of_hash_dgst, out_sign, signature_data_act_size_out); + SA_PV_ERR_RECOVERABLE_GOTO_IF((PAL_SUCCESS != pal_status), kcm_status = cs_error_handler(pal_status), exit, "pal_ECDSASign failed "); + +exit: + + //Free curve handler + (void)pal_ECGroupFree(&grp); + //Free key handler + (void)pal_ECKeyFree(&key_handle); + + if (kcm_status == KCM_STATUS_SUCCESS) { + SA_PV_ERR_RECOVERABLE_RETURN_IF((grp != NULLPTR || key_handle != NULLPTR), KCM_STATUS_ERROR, "Free handle failed "); + } + return kcm_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/cs_hash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/cs_hash.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,39 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "pv_error_handling.h" +#include "cs_hash.h" +#include "pal_Crypto.h" +#include "cs_utils.h" + +kcm_status_e cs_hash(cs_hash_mode_e mode, const uint8_t *data, size_t data_size, uint8_t *digest, size_t digest_size) +{ + palStatus_t pal_status = PAL_SUCCESS; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((data == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid data pointer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((digest == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid digest pointer"); + + switch (mode) { + case CS_SHA256: + SA_PV_ERR_RECOVERABLE_RETURN_IF((digest_size != CS_SHA256_SIZE), KCM_STATUS_INVALID_PARAMETER, "Invalid digest size"); + pal_status = pal_sha256(data, data_size, digest); + break; + default: + SA_PV_ERR_RECOVERABLE_RETURN_IF((true), KCM_CRYPTO_STATUS_UNSUPPORTED_HASH_MODE, "Hash mode not supported"); + } + + return cs_error_handler(pal_status); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/cs_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/cs_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,115 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- +#include <stdio.h> +#include "pv_log.h" +#include "cs_hash.h" +#include "cs_der_keys.h" +#include "cs_der_certs.h" +#include "pal_Crypto.h" +#include "pal_errors.h" +#include "pv_error_handling.h" + + +kcm_status_e cs_error_handler(palStatus_t pal_status) +{ + switch (pal_status) { + case PAL_SUCCESS: + return KCM_STATUS_SUCCESS; + case PAL_ERR_NOT_SUPPORTED_CURVE: + return KCM_CRYPTO_STATUS_UNSUPPORTED_CURVE; + case PAL_ERR_INVALID_ARGUMENT: + return KCM_STATUS_INVALID_PARAMETER; + case PAL_ERR_CREATION_FAILED: + return KCM_STATUS_OUT_OF_MEMORY; + case PAL_ERR_CERT_PARSING_FAILED: + return KCM_CRYPTO_STATUS_PARSING_DER_CERT; + case PAL_ERR_X509_BADCERT_EXPIRED: + return KCM_CRYPTO_STATUS_CERT_EXPIRED; + case PAL_ERR_X509_BADCERT_FUTURE: + return KCM_CRYPTO_STATUS_CERT_FUTURE; + case PAL_ERR_X509_BADCERT_BAD_MD: + return KCM_CRYPTO_STATUS_CERT_MD_ALG; + case PAL_ERR_X509_BADCERT_BAD_PK: + return KCM_CRYPTO_STATUS_CERT_PUB_KEY_TYPE; + case PAL_ERR_X509_BADCERT_NOT_TRUSTED: + return KCM_CRYPTO_STATUS_CERT_NOT_TRUSTED; + case PAL_ERR_X509_BADCERT_BAD_KEY: + return KCM_CRYPTO_STATUS_CERT_PUB_KEY; + case PAL_ERR_PARSING_PUBLIC_KEY: + return KCM_CRYPTO_STATUS_PARSING_DER_PUBLIC_KEY; + case PAL_ERR_PARSING_PRIVATE_KEY: + return KCM_CRYPTO_STATUS_PARSING_DER_PRIVATE_KEY; + case PAL_ERR_PRIVATE_KEY_VARIFICATION_FAILED: + return KCM_CRYPTO_STATUS_PRIVATE_KEY_VERIFICATION_FAILED; + case PAL_ERR_PUBLIC_KEY_VARIFICATION_FAILED: + return KCM_CRYPTO_STATUS_PUBLIC_KEY_VERIFICATION_FAILED; + case PAL_ERR_PK_UNKNOWN_PK_ALG: + return KCM_CRYPTO_STATUS_PK_UNKNOWN_PK_ALG; + case PAL_ERR_PK_KEY_INVALID_FORMAT: + return KCM_CRYPTO_STATUS_PK_KEY_INVALID_FORMAT; + case PAL_ERR_PK_INVALID_PUBKEY_AND_ASN1_LEN_MISMATCH: + return KCM_CRYPTO_STATUS_INVALID_PK_PUBKEY; + case PAL_ERR_ECP_INVALID_KEY: + return KCM_CRYPTO_STATUS_ECP_INVALID_KEY; + case PAL_ERR_PK_KEY_INVALID_VERSION: + return KCM_CRYPTO_STATUS_PK_KEY_INVALID_VERSION; + case PAL_ERR_PK_PASSWORD_REQUIRED: + return KCM_CRYPTO_STATUS_PK_PASSWORD_REQUIRED; + case PAL_ERR_NO_MEMORY: + return KCM_STATUS_OUT_OF_MEMORY; + case PAL_ERR_BUFFER_TOO_SMALL: + return KCM_STATUS_INSUFFICIENT_BUFFER; + case PAL_ERR_INVALID_X509_ATTR: + return KCM_CRYPTO_STATUS_INVALID_X509_ATTR; + case PAL_ERR_PK_SIG_VERIFY_FAILED: + return KCM_CRYPTO_STATUS_VERIFY_SIGNATURE_FAILED; + case PAL_ERR_FAILED_TO_COPY_KEYPAIR: + return KCM_CRYPTO_STATUS_ECP_INVALID_KEY; + case PAL_ERR_FAILED_TO_COPY_GROUP: + return KCM_CRYPTO_STATUS_UNSUPPORTED_CURVE; + case PAL_ERR_INVALID_MD_TYPE: + return KCM_CRYPTO_STATUS_INVALID_MD_TYPE; + case PAL_ERR_FAILED_TO_WRITE_SIGNATURE: + return KCM_CRYPTO_STATUS_FAILED_TO_WRITE_SIGNATURE; + default: + return KCM_STATUS_ERROR; + } +} + + +/* The function checks private and certificate's public key correlation +*/ +kcm_status_e cs_check_certifcate_public_key(palX509Handle_t x509_cert, const uint8_t *private_key_data, size_t size_of_private_key_data) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + uint8_t out_sign[CS_ECDSA_SECP256R1_MAX_SIGNATURE_SIZE_IN_BYTES] = { 0 }; + size_t size_of_sign = sizeof(out_sign); + size_t act_size_of_sign = 0; + const uint8_t hash_digest[] = + { 0x34, 0x70, 0xCD, 0x54, 0x7B, 0x0A, 0x11, 0x5F, 0xE0, 0x5C, 0xEB, 0xBC, 0x07, 0xBA, 0x91, 0x88, + 0x27, 0x20, 0x25, 0x6B, 0xB2, 0x7A, 0x66, 0x89, 0x1A, 0x4B, 0xB7, 0x17, 0x11, 0x04, 0x86, 0x6F }; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + kcm_status = cs_ecdsa_sign(private_key_data, size_of_private_key_data, hash_digest, sizeof(hash_digest), out_sign, size_of_sign, &act_size_of_sign); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "cs_ecdsa_sign failed"); + + kcm_status = cs_x509_cert_verify_signature(x509_cert, hash_digest, sizeof(hash_digest), out_sign, act_size_of_sign); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "cs_x509_cert_verify_signature failed"); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return kcm_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/include/cs_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/crypto-service/source/include/cs_utils.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,58 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __CS_UTILS_H__ +#define __CS_UTILS_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include "pal.h" +#include "kcm_status.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/**Convert pal status to crypto service status +* +*@pal_status pal status as returned from PAL API. +* +*@return +* Status from kcm_status_e corresponding to pal status. +*/ +kcm_status_e cs_error_handler(palStatus_t pal_status); + +/**Checks correlation between certificate's public key and private key +* +*@x509_cert[in] - handle of x509 certificate. +*@size_of_device_cert[in] - size of certificate data. +*@private_key_data[in] - pointer to private key der data. +*@size_of_private_key_data[in] - size of private key data. +* +*@return +* Status from kcm_status_e corresponding to pal status. +*/ +kcm_status_e cs_check_certifcate_public_key(palX509Handle_t x509_cert, + const uint8_t *private_key_data, + size_t size_of_private_key_data); + + +#ifdef __cplusplus +} +#endif + +#endif //__CS_UTILS_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/factory-configurator-client/factory_configurator_client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/factory-configurator-client/factory_configurator_client.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,201 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FACTORY_CONFIGURATOR_CLIENT_H__ +#define __FACTORY_CONFIGURATOR_CLIENT_H__ + +#include <stdlib.h> +#include <inttypes.h> +#include "fcc_status.h" +#include "fcc_output_info_handler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @file factory_configurator_client.h +* \brief factory configurator client APIs. +*/ + +/* === Defines === */ +#define FCC_ENTROPY_SIZE 56 +#define FCC_ROT_SIZE 24 + +/* === Initialization and Finalization === */ + +/** Initiates the FCC module. +* +* @returns +* FCC_STATUS_SUCCESS in case of success or one of the `::fcc_status_e` errors otherwise. +*/ +fcc_status_e fcc_init(void); + + +/** Finalizes the FCC module. +* Finalizes and frees file storage resources. +* +* @returns +* FCC_STATUS_SUCCESS in case of success or one of the `::fcc_status_e` errors otherwise. +*/ + +fcc_status_e fcc_finalize(void); + +/* === Factory clean operation === */ + +/** Cleans from the device all data that was saved during the factory process. +* Should be called if the process failed and needs to be executed again. +* +* @returns +* FCC_STATUS_SUCCESS in case of success or one of the `::fcc_status_e` errors otherwise. +*/ +fcc_status_e fcc_storage_delete(void); + + +/* === Warning and errors data operations === */ + +/** The function retrieves pointer to warning and errors structure. +* Should be called after fcc_verify_device_configured_4mbed_cloud, when possible warning and errors was +* stored in the structure. +* The structure contains data of last fcc_verify_device_configured_4mbed_cloud run.* +* @returns pointer to fcc_output_info_s structure. +*/ +fcc_output_info_s* fcc_get_error_and_warning_data(void); + +/* === Verification === */ + +/** Verifies that all mandatory fields needed to connect to mbed Cloud are in place on the device. + * Should be called in the end of the factory process + * + * @returns + * FCC_STATUS_SUCCESS in case of success or one of the `::fcc_status_e` errors otherwise. + */ +fcc_status_e fcc_verify_device_configured_4mbed_cloud(void); + + +/* === Developer flow === */ + +/** This API is for developers only. +* You can download the `mbed_cloud_dev_credentials.c` file from the portal and thus, skip running FCU on PC side. +* The API reads all credentials from the `mbed_cloud_dev_credentials.c` file and stores them in the KCM. +* RoT, Entropy and Time configurations are not a part of fcc_developer_flow() API. Devices that need to set RoT or Entropy +* should call `fcc_rot_set()`/`fcc_entropy_set()` APIs before fcc_developer_flow(). +* If device does not have it's own time configuration and `fcc_secure_time_set()` was not called before fcc_developer_flow(), +* during fcc_verify_device_configured_4mbed_cloud() certificate time validity will not be checked. +* +* +* @returns +* FCC_STATUS_SUCCESS in case of success or one of the `::fcc_status_e` errors otherwise. +*/ +fcc_status_e fcc_developer_flow(void); + +#ifndef __DOXYGEN__ //Not implemented features + +/* === Secure Time === */ + +/** Sets Secure time. This function will set the secure time to what the user provides. +* Secure time must be set in order to enable certificate expiration validations. +* +* @param time The secure time to set. +* +* @returns +* Operation status. +*/ +fcc_status_e fcc_secure_time_set(uint64_t time); + +/* === Entropy and RoT injection === */ +/** Sets Entropy. +* If user wishes to set his own entropy, this function must be called after fcc_init() and prior to any other FCC or KCM functions. +* +* @param buf The buffer containing the entropy. +* @param buf_size The size of buf in bytes. Must be exactly FCC_ENTROPY_SIZE. +* +* @returns +* Operation status. +*/ +fcc_status_e fcc_entropy_set(const uint8_t *buf, size_t buf_size); + +/** Sets root of trust +* If user wishes to set his own root of trust, this function must be called after fcc_init() and fcc_entropy_set() (if user sets his own entropy), +and prior to any other FCC or KCM functions. +* +* @param buf The buffer containing the root of trust. +* @param buf_size The size of buf in bytes. Must be exactly FCC_ROT_SIZE. +* +* @returns +* Operation status. +*/ +fcc_status_e fcc_rot_set(const uint8_t *buf, size_t buf_size); + + +/* === Factory flow disable === */ +/** Sets Factory disabled flag to disable further use of the factory flow. +* +* @returns +* Operation status. +*/ +fcc_status_e fcc_factory_disable(void); + +/** Returns true if the factory flow was disabled by calling fcc_factory_disable() API, outherwise +* returns false. +* +* - If the factory flow is already disabled any FCC API(s) will fail. +* +* @param fcc_factory_disable An output parameter, will be set to "true" in case factory +* flow is already disabled, "false" otherwise. +* +* @returns +* FCC_STATUS_SUCCESS in case of success or one of the `::fcc_status_e` errors otherwise. +*/ +fcc_status_e fcc_is_factory_disabled(bool *fcc_factory_disable); + +/* === CSR generation === */ + +/** Generates bootstrap CSR from a given private and public keys in DER encoding scheme. +* Further design is needed +* +* @param key_name The key name to fetch from storage(public/private). +* @param key_name_len The key name len. +* @param bootstrap_csr_out Pointer to generated bootstrap CSR. +* @param bootstrap_csr_size_out Size of the CSR. +* +* @returns +* Operation status. +*/ +fcc_status_e fcc_bootstrap_csr_generate(const uint8_t *key_name, size_t key_name_len, + uint8_t **bootstrap_csr_out, size_t *bootstrap_csr_size_out); + + +/** Generates E2E CSR from a given private and public keys +* Further design is needed +* +* @param key_name The key name to fetch from storage(public/private). +* @param key_name_len The key name len. +* @param e2e_csr_out Pointer to generated E2E CSR. +* @param e2e_csr_size_out Size of the E2E CSR. +* +* @returns +* Operation status. +*/ +fcc_status_e fcc_e2e_csr_generate(const uint8_t *key_name, size_t key_name_len, + uint8_t **e2e_csr_out, size_t *e2e_csr_size_out); + +#endif +#ifdef __cplusplus +} +#endif + +#endif //__FACTORY_CONFIGURATOR_CLIENT_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/factory-configurator-client/fcc_defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/factory-configurator-client/fcc_defs.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,174 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_DEFS_H__ +#define __FCC_DEFS_H__ + + +#ifdef __cplusplus +extern "C" { +#endif +/** +* @file fcc_defs.h +* \brief factory configurator client defines. +* Contains the names of all parameters needed to configure the device to work with mbed Cloud. +*/ +/* +* Warnings linked list structure +*/ +struct fcc_warning_info_ { + //Example for warning_info_string - "Certificate is self signed:mbed.BootstrapServerCACert" + char *warning_info_string;// pattern of the warning string - warning_string:item_name + struct fcc_warning_info_ *next; +}; +typedef struct fcc_warning_info_ fcc_warning_info_s; +/** +* Output info structure +*/ +typedef struct fcc_output_info_ { + //Example for error_string_info - "Invalid certificate:mbed.BootstrapServerCACert" + char *error_string_info; // pattern of the error string - error_string:failed_item_name. Only one error string is possible. + size_t size_of_warning_info_list; // size of warning_info_list + struct fcc_warning_info_ *head_of_warning_list; //The head of warning list + struct fcc_warning_info_ *tail_of_warning_list; //The tail of warning list +} fcc_output_info_s; +/*=== Device general information ===*/ + +/** +* Bootstrap mode parameter name. +*/ +extern const char g_fcc_use_bootstrap_parameter_name[]; + +/** +* Endpoint parameter name. +*/ +extern const char g_fcc_endpoint_parameter_name[]; + +/** +* First to claim parameter name. +*/ +extern const char g_fcc_first_to_claim_parameter_name[]; + +/*=== Device meta data ===*/ + +/** +* Manufacturer parameter name. +*/ +extern const char g_fcc_manufacturer_parameter_name[]; + +/** +* Model number parameter name. +*/ +extern const char g_fcc_model_number_parameter_name[]; + +/** +* Device type parameter name. +*/ +extern const char g_fcc_device_type_parameter_name[]; + +/** +* Hardware version parameter name. +*/ +extern const char g_fcc_hardware_version_parameter_name[]; + +/** +* Memory size parameter name. +*/ +extern const char g_fcc_memory_size_parameter_name[]; + +/** +* Device serial number parameter name. +*/ +extern const char g_fcc_device_serial_number_parameter_name[]; + +/** +* Device current time parameter name. +*/ +extern const char g_fcc_current_time_parameter_name[]; +/** +* Device time zone name. +*/ +extern const char g_fcc_device_time_zone_parameter_name[]; +/** +* Offset of the device timezone from UTC name. +*/ +extern const char g_fcc_offset_from_utc_parameter_name[]; + +/*=== Bootstrap configuration ===*/ + +/** +* Bootstrap server CA certificate parameter name. +*/ +extern const char g_fcc_bootstrap_server_ca_certificate_name[]; + +/** +* Bootstrap server CRL parameter name. +*/ +extern const char g_fcc_bootstrap_server_crl_name[]; + +/** +* Bootstrap server URI parameter name. +*/ +extern const char g_fcc_bootstrap_server_uri_name[]; + +/** +* Bootstrap device certificate parameter name. +*/ +extern const char g_fcc_bootstrap_device_certificate_name[]; + +/** +* Bootstrap device private key parameter name. +*/ +extern const char g_fcc_bootstrap_device_private_key_name[]; + +/*=== LWM2M configuration ===*/ + +/** +* LWM2M server CA certificate parameter name. +*/ +extern const char g_fcc_lwm2m_server_ca_certificate_name[]; + +/** +* LWM2M server CRL parameter name. +*/ +extern const char g_fcc_lwm2m_server_crl_name[]; + +/** +* LWM2M server URI parameter name. +*/ +extern const char g_fcc_lwm2m_server_uri_name[]; + +/** +* LWM2M device certificate parameter name. +*/ +extern const char g_fcc_lwm2m_device_certificate_name[]; + +/** +* LWM2M device private key parameter name. +*/ +extern const char g_fcc_lwm2m_device_private_key_name[]; + + +/** +* Firmware update authentication certificate parameter name. +*/ +extern const char g_fcc_update_authentication_certificate_name[]; + +#ifdef __cplusplus +} +#endif + +#endif //__FCC_DEFS_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/factory-configurator-client/fcc_status.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/factory-configurator-client/fcc_status.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,67 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_STATUS_H__ +#define __FCC_STATUS_H__ + +#ifdef __cplusplus +extern "C" { +#endif +/** +* @file fcc_status.h +* \brief factory configurator client status/error codes. +* This list may grow as needed. +*/ +typedef enum fcc_status_ { + FCC_STATUS_SUCCESS, //!< Operation completed successfully. + FCC_STATUS_ERROR, //!< Operation ended with an unspecified error. + FCC_STATUS_MEMORY_OUT, //!< An out-of-memory condition occurred. + FCC_STATUS_INVALID_PARAMETER, //!< A parameter provided to the function was invalid. + FCC_STATUS_ENTROPY_ERROR, //!< Entropy wasn't initialized correct. + FCC_STATUS_FACTORY_DISABLED_ERROR, //!< FCC flow was disabled - denial of service error. + FCC_STATUS_INVALID_CERTIFICATE, //!< Invalid certificate found. + FCC_STATUS_INVALID_CERT_ATTRIBUTE, //!< Operation failed to get an attribute. + FCC_STATUS_INVALID_CA_CERT_SIGNATURE, //!< Invalid ca signature. + FCC_STATUS_EXPIRED_CERTIFICATE, //!< Certificate is expired. + FCC_STATUS_INVALID_LWM2M_CN_ATTR, //!< Invalid CN field of certificate. + FCC_STATUS_KCM_ERROR, //!< KCM basic functionality failed. + FCC_STATUS_KCM_STORAGE_ERROR, //!< KCM failed to read, write or get size of item from/to storage. + FCC_STATUS_KCM_FILE_EXIST_ERROR, //!< KCM tried to create existing storage item. + FCC_STATUS_KCM_CRYPTO_ERROR, //!< KCM returned error upon cryptographic check of an certificate or key. + FCC_STATUS_NOT_INITIALIZED, //!< FCC failed or did not initialized. + FCC_STATUS_BUNDLE_ERROR, //!< Protocol layer general error. + FCC_STATUS_BUNDLE_RESPONSE_ERROR, //!< Protocol layer failed to create response buffer. + FCC_STATUS_BUNDLE_UNSUPPORTED_GROUP, //!< Protocol layer detected unsupported group was found in a message. + FCC_STATUS_BUNDLE_INVALID_GROUP, //!< Protocol layer detected invalid group in a message. + FCC_STATUS_BUNDLE_INVALID_SCHEME, //!< The scheme version of a message in the protocol layer is wrong. + FCC_STATUS_ITEM_NOT_EXIST, //!< Current item wasn't found in the storage + FCC_STATUS_EMPTY_ITEM, //!< Current item's size is 0 + FCC_STATUS_WRONG_ITEM_DATA_SIZE, //!< Current item's size is different then expected + FCC_STATUS_URI_WRONG_FORMAT, //!< Current URI is different than expected. + FCC_STATUS_FIRST_TO_CLAIM_NOT_ALLOWED, //!< Can't use first to claim without bootstrap or with account ID + FCC_STATUS_BOOTSTRAP_MODE_ERROR, //!< Wrong value of bootstrapUse mode. + FCC_STATUS_OUTPUT_INFO_ERROR, //!< The process failed in output info creation. + FCC_STATUS_WARNING_CREATE_ERROR, //!< The process failed in output info creation. + FCC_STATUS_UTC_OFFSET_WRONG_FORMAT, //!< Current UTC is wrong. + FCC_STATUS_CERTIFICATE_PUBLIC_KEY_CORRELATION_ERROR, //!< Certificate's public key failed do not matches to corresponding private key + FCC_MAX_STATUS, +} fcc_status_e; + +#ifdef __cplusplus +} +#endif + +#endif //__FCC_STATUS_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/factory_configurator_client.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/factory_configurator_client.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,259 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "factory_configurator_client.h" +#include "fcc_sotp.h" +#include "key_config_manager.h" +#include "pv_error_handling.h" +#include "fcc_verification.h" +#include "storage.h" +#include "fcc_defs.h" + +/** +* Device general info +*/ +const char g_fcc_use_bootstrap_parameter_name[] = "mbed.UseBootstrap"; +const char g_fcc_endpoint_parameter_name[] = "mbed.EndpointName"; +const char g_fcc_account_id_parameter_name[] = "mbed.AccountID"; +const char g_fcc_first_to_claim_parameter_name[] = "mbed.FirstToClaim"; + +/** +* Device meta data +*/ +const char g_fcc_manufacturer_parameter_name[] = "mbed.Manufacturer"; +const char g_fcc_model_number_parameter_name[] = "mbed.ModelNumber"; +const char g_fcc_device_type_parameter_name[] = "mbed.DeviceType"; +const char g_fcc_hardware_version_parameter_name[] = "mbed.HardwareVersion"; +const char g_fcc_memory_size_parameter_name[] = "mbed.MemoryTotalKB"; +const char g_fcc_device_serial_number_parameter_name[] = "mbed.SerialNumber"; +/** +* Time Synchronization +*/ +const char g_fcc_current_time_parameter_name[] = "mbed.CurrentTime"; +const char g_fcc_device_time_zone_parameter_name[] = "mbed.Timezone"; +const char g_fcc_offset_from_utc_parameter_name[] = "mbed.UTCOffset"; +/** +* Bootstrap configuration +*/ +const char g_fcc_bootstrap_server_ca_certificate_name[] = "mbed.BootstrapServerCACert"; +const char g_fcc_bootstrap_server_crl_name[] = "mbed.BootstrapServerCRL"; +const char g_fcc_bootstrap_server_uri_name[] = "mbed.BootstrapServerURI"; +const char g_fcc_bootstrap_device_certificate_name[] = "mbed.BootstrapDeviceCert"; +const char g_fcc_bootstrap_device_private_key_name[] = "mbed.BootstrapDevicePrivateKey"; +/** +* LWm2m configuration +*/ +const char g_fcc_lwm2m_server_ca_certificate_name[] = "mbed.LwM2MServerCACert"; +const char g_fcc_lwm2m_server_crl_name[] = "mbed.LwM2MServerCRL"; +const char g_fcc_lwm2m_server_uri_name[] = "mbed.LwM2MServerURI"; +const char g_fcc_lwm2m_device_certificate_name[] = "mbed.LwM2MDeviceCert"; +const char g_fcc_lwm2m_device_private_key_name[] = "mbed.LwM2MDevicePrivateKey"; +/** +* Firmware update +*/ +const char g_fcc_update_authentication_certificate_name[] = "mbed.UpdateAuthCert"; + +static bool g_is_fcc_initialized = false; + + +fcc_status_e fcc_init(void) +{ + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + if (g_is_fcc_initialized) { + // No need for second initialization + return FCC_STATUS_SUCCESS; + } + + //Initialize output info handler + fcc_init_output_info_handler(); + + g_is_fcc_initialized = true; + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + return FCC_STATUS_SUCCESS; +} + +fcc_status_e fcc_finalize(void) +{ + kcm_status_e status; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((!g_is_fcc_initialized), FCC_STATUS_NOT_INITIALIZED, "FCC not initialized"); + + //FIXME: add relevant error handling - general task for all APIs. + status = kcm_finalize(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status == KCM_STATUS_NOT_INITIALIZED), FCC_STATUS_NOT_INITIALIZED, "Failed finalize KCM\n"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != KCM_STATUS_SUCCESS), FCC_STATUS_ERROR, "Failed finalize KCM"); + + //Finalize output info handler + fcc_clean_output_info_handler(); + + g_is_fcc_initialized = false; + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + return FCC_STATUS_SUCCESS; +} + +fcc_status_e fcc_storage_delete() +{ + kcm_status_e status = KCM_STATUS_SUCCESS; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((!g_is_fcc_initialized), FCC_STATUS_NOT_INITIALIZED, "FCC not initialized"); + + status = storage_reset(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status == KCM_STATUS_ESFS_ERROR), FCC_STATUS_KCM_STORAGE_ERROR, "Failed init KCM. got ESFS error"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != KCM_STATUS_SUCCESS), FCC_STATUS_ERROR, "Failed storage reset"); + + // FIXME: remove this TestOnly function when SOTP will be implemented + // The storage_reset() should reset also the SOTP + SOTP_TestOnly_reset(); + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return FCC_STATUS_SUCCESS; +} + +fcc_output_info_s* fcc_get_error_and_warning_data(void) +{ + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((!g_is_fcc_initialized), NULL, "FCC not initialized"); + + return get_output_info(); +} + +fcc_status_e fcc_verify_device_configured_4mbed_cloud(void) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + bool use_bootstrap = false; + bool success = false; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((!g_is_fcc_initialized), FCC_STATUS_NOT_INITIALIZED, "FCC not initialized"); + + /*Initialize fcc_output_info_s structure. + In case output indo struct is not empty in the beginning of the verify process we will clean it.*/ + fcc_clean_output_info_handler(); + + //Check entropy initialization + success = fcc_is_entropy_initialized(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((success != true), fcc_status = FCC_STATUS_ENTROPY_ERROR, "Entropy is not initialized"); + + //Check time synchronization + fcc_status = fcc_check_time_synchronization(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to check time synhronization"); + + //Get bootstrap mode + fcc_status = fcc_get_bootstrap_mode(&use_bootstrap); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to get bootstrap mode"); + + // Check general info + fcc_status = fcc_check_device_general_info(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to check general info"); + + //Check device meta-data + fcc_status = fcc_check_device_meta_data(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to check configuration parameters"); + + //Check device security objects + fcc_status = fcc_check_device_security_objects(use_bootstrap); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to check device security objects"); + + //Check firmware integrity + fcc_status = fcc_check_firmware_update_integrity(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to check device security objects"); + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + return fcc_status; +} + +fcc_status_e fcc_entropy_set(const uint8_t *buf, size_t buf_size) +{ + fcc_status_e fcc_status; + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + fcc_status = fcc_sotp_data_store(buf, buf_size, FCC_SOTP_TYPE_ENTROPY); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to set entropy"); + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return FCC_STATUS_SUCCESS; +} + +fcc_status_e fcc_rot_set(const uint8_t *buf, size_t buf_size) +{ + fcc_status_e fcc_status; + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + fcc_status = fcc_sotp_data_store(buf, buf_size, FCC_SOTP_TYPE_ROT); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to set RoT"); + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return FCC_STATUS_SUCCESS; +} + +fcc_status_e fcc_secure_time_set(uint64_t time) +{ + palStatus_t pal_status; + + //FIXME: Should be replaced by some other ESFS API that will handle situations where time is already set + pal_status = pal_osSetTime(time); + SA_PV_ERR_RECOVERABLE_RETURN_IF((pal_status != PAL_SUCCESS), FCC_STATUS_ERROR, "Failed to set new EPOCH time (pal_status = %" PRIu32 ")", pal_status); + + return FCC_STATUS_SUCCESS; +} + +fcc_status_e fcc_factory_disable(void) +{ + fcc_status_e fcc_status; + int64_t factory_disable_flag = 1; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + fcc_status = fcc_sotp_data_store((uint8_t *)(&factory_disable_flag), sizeof(factory_disable_flag), FCC_SOTP_TYPE_FACTORY_DISABLE); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed for fcc_sotp_buffer_store"); + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return FCC_STATUS_SUCCESS; +} + +fcc_status_e fcc_is_factory_disabled(bool *is_factory_disabled) +{ + fcc_status_e fcc_status; + int64_t factory_disable_flag = 0; + size_t data_actual_size_out = 0; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((is_factory_disabled == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid param is_factory_disabled"); + + fcc_status = fcc_sotp_data_retrieve((uint8_t *)(&factory_disable_flag), sizeof(factory_disable_flag), &data_actual_size_out, FCC_SOTP_TYPE_FACTORY_DISABLE); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed for fcc_sotp_buffer_retrieve"); + SA_PV_ERR_RECOVERABLE_RETURN_IF(((factory_disable_flag != 0) && (factory_disable_flag != 1)), FCC_STATUS_FACTORY_DISABLED_ERROR, "Failed for fcc_sotp_buffer_retrieve"); + + // If we get here - it must be either "0" or "1" + *is_factory_disabled = (factory_disable_flag == 1) ? true : false; + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return FCC_STATUS_SUCCESS; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/fcc_dev_flow.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/fcc_dev_flow.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,102 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "factory_configurator_client.h" +#include "key_config_manager.h" +#include "fcc_defs.h" +#include "pv_error_handling.h" +#include "fcc_utils.h" + +typedef struct fcc_deloveper_mode_item_params { + const char *item_name; + kcm_item_type_e item_kcm_type; + const uint8_t *item_data; + const uint32_t item_data_size; +} fcc_deloveper_mode_item_params_s; + +//bootstrap endpoint name +extern const char MBED_CLOUD_DEV_BOOTSTRAP_ENDPOINT_NAME[]; +//bootstrap server uri +extern const char MBED_CLOUD_DEV_BOOTSTRAP_SERVER_URI[]; +//bootstrap device certificate +extern const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE[]; +extern const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE_SIZE; +//bootstrap server root ca certificate +extern const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE[]; +extern const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE_SIZE; +//bootstrap device private key +extern const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY[]; +extern const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY_SIZE; +//device manufacturer +extern const char MBED_CLOUD_DEV_MANUFACTURER[]; +//device model number +extern const char MBED_CLOUD_DEV_MODEL_NUMBER[]; +//device serial number +extern const char MBED_CLOUD_DEV_SERIAL_NUMBER[]; +//device type +extern const char MBED_CLOUD_DEV_DEVICE_TYPE[]; +//device hw version +extern const char MBED_CLOUD_DEV_HARDWARE_VERSION[]; +//device total memory +extern const uint32_t MBED_CLOUD_DEV_MEMORY_TOTAL_KB; + + +fcc_status_e fcc_developer_flow(void) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + const bool is_factory_item = true; + static const uint32_t is_bootstrap_mode = 1; + const fcc_deloveper_mode_item_params_s fcc_deloveper_mode_item_params_table[] = { + + //param name //param kcm type //param data //param data_size + //Device general info + { g_fcc_use_bootstrap_parameter_name, KCM_CONFIG_ITEM, (const uint8_t*)&is_bootstrap_mode, sizeof(uint32_t) }, + { g_fcc_endpoint_parameter_name, KCM_CONFIG_ITEM, (const uint8_t*)MBED_CLOUD_DEV_BOOTSTRAP_ENDPOINT_NAME, strlen((char*)MBED_CLOUD_DEV_BOOTSTRAP_ENDPOINT_NAME) }, + //Bootstrap configuration + { g_fcc_bootstrap_device_certificate_name, KCM_CERTIFICATE_ITEM, MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE, MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE_SIZE }, + { g_fcc_bootstrap_server_ca_certificate_name, KCM_CERTIFICATE_ITEM, MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE, MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE_SIZE }, + { g_fcc_bootstrap_device_private_key_name, KCM_PRIVATE_KEY_ITEM, MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY, MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY_SIZE }, + { g_fcc_bootstrap_server_uri_name, KCM_CONFIG_ITEM, (const uint8_t*)MBED_CLOUD_DEV_BOOTSTRAP_SERVER_URI, strlen((char*)MBED_CLOUD_DEV_BOOTSTRAP_SERVER_URI) }, + //device meta data + { g_fcc_manufacturer_parameter_name, KCM_CONFIG_ITEM, (const uint8_t*)MBED_CLOUD_DEV_MANUFACTURER, strlen((char*)MBED_CLOUD_DEV_MANUFACTURER) }, + { g_fcc_model_number_parameter_name, KCM_CONFIG_ITEM, (const uint8_t*)MBED_CLOUD_DEV_MODEL_NUMBER, strlen((char*)MBED_CLOUD_DEV_MODEL_NUMBER) }, + { g_fcc_device_serial_number_parameter_name, KCM_CONFIG_ITEM, (const uint8_t*)MBED_CLOUD_DEV_SERIAL_NUMBER, strlen((char*)MBED_CLOUD_DEV_SERIAL_NUMBER) }, + { g_fcc_device_type_parameter_name, KCM_CONFIG_ITEM, (const uint8_t*)MBED_CLOUD_DEV_DEVICE_TYPE, strlen((char*)MBED_CLOUD_DEV_DEVICE_TYPE) }, + { g_fcc_hardware_version_parameter_name, KCM_CONFIG_ITEM, (const uint8_t*)MBED_CLOUD_DEV_HARDWARE_VERSION, strlen((char*)MBED_CLOUD_DEV_HARDWARE_VERSION) }, + { g_fcc_memory_size_parameter_name, KCM_CONFIG_ITEM, (const uint8_t*)&MBED_CLOUD_DEV_MEMORY_TOTAL_KB, sizeof(uint32_t) }, + + //last item + { NULL, KCM_LAST_ITEM, NULL, 0}, + }; + + const fcc_deloveper_mode_item_params_s* mandatory_items_iter = &fcc_deloveper_mode_item_params_table[0]; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + for (; mandatory_items_iter->item_name!= NULL; mandatory_items_iter++) { + + kcm_status = kcm_item_store((const uint8_t*)(mandatory_items_iter->item_name), strlen(mandatory_items_iter->item_name), mandatory_items_iter->item_kcm_type, is_factory_item, + (const uint8_t*)(mandatory_items_iter->item_data), mandatory_items_iter->item_data_size, NULL); + + //FIXME : add relevant error translation. + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_convert_kcm_to_fcc_status(kcm_status), "Store status: %d, Failed to store %s", kcm_status, mandatory_items_iter->item_name); + } + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + return fcc_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/fcc_sotp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/fcc_sotp.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,199 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <string.h> +#include "fcc_sotp.h" +#include "pv_error_handling.h" + + +static bool get_sotp_type(fcc_sotp_type_e sotp_type, size_t *required_size_out) +{ + size_t required_size; + + switch (sotp_type) { + case FCC_SOTP_TYPE_ROT: + required_size = FCC_ROT_SIZE; + break; + case FCC_SOTP_TYPE_FACTORY_DISABLE: + required_size = FCC_FACTORY_DISABLE_FLAG_SIZE; + break; + case FCC_SOTP_TYPE_ENTROPY: + required_size = FCC_ENTROPY_SIZE; + break; + default: + SA_PV_LOG_ERR("Non existant sotp_type provided"); + return false; + } + + // Success + *required_size_out = required_size; + + return true; +} + +fcc_status_e fcc_sotp_data_store(const uint8_t *data, size_t data_size, fcc_sotp_type_e sotp_type) +{ + bool success; + size_t required_size = 0; + int64_t aligned_8_bytes_buffer[MAX_SOTP_BUFFER_SIZE / 8]; + + SA_PV_LOG_INFO_FUNC_ENTER("data_size = %" PRIu32 " sotp_type = %d", (uint32_t)data_size, (int)sotp_type); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((data == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid param data"); + + success = get_sotp_type(sotp_type, &required_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((!success), FCC_STATUS_ERROR, "Failed for get_sotp_type()"); + + // Assert that buffer provided is of correct size + SA_PV_ERR_RECOVERABLE_RETURN_IF((data_size != required_size), FCC_STATUS_ERROR, "Wrong buf_size provided. Must be size of exactly %" PRIu32 " bytes", (uint32_t)required_size); + + // Write buf to SOTP. Cast is OK since size must be divisible by 8 + + /* + * Copy from data (uint8_t*) to aligned_8_bytes_buffer (uint64_t*) to make sure that data is 8 byte aligned. + * Since SOTP_Set() gets a pointer to int64_t, if it is not aligned, and we just cast it to uint8_t*, + * ARMCC functions like memcpy will assume 8 byte alignment resulting in possible access of unallocated memory. + */ + memcpy(aligned_8_bytes_buffer, data, data_size); + + success = SOTP_Set((uint8_t)sotp_type, (data_size >> 3), aligned_8_bytes_buffer); + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + // FIXME: When SOTP returns real status - we must translate the error + return success ? FCC_STATUS_SUCCESS : FCC_STATUS_ERROR; +} + +fcc_status_e fcc_sotp_data_retrieve(uint8_t *data_out, size_t data_size_max, size_t *data_actual_size_out, fcc_sotp_type_e sotp_type) +{ + bool success; + size_t required_size = 0; + int64_t aligned_8_bytes_buffer[MAX_SOTP_BUFFER_SIZE / 8]; + + uint8_t data_size_as_array_of_int64; /* store as array of int64_t */ + + SA_PV_LOG_INFO_FUNC_ENTER("data_out = %" PRIu32 " sotp_type = %d", (uint32_t)data_size_max, (int)sotp_type); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((data_out == NULL), FCC_STATUS_INVALID_PARAMETER, "invalid param data_out"); + + success = get_sotp_type(sotp_type, &required_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((!success), FCC_STATUS_ERROR, "Failed for get_sotp_type()"); + + // Assert that buffer provided is of correct size + SA_PV_ERR_RECOVERABLE_RETURN_IF((data_size_max < required_size), FCC_STATUS_ERROR, "Wrong data_size provided. Must be size of exactly %" PRIu32 " bytes", (uint32_t)required_size); + + // Retrieve buf from SOTP. Cast is OK since size must be multiple of 8 + // FIXME: When SOTP returns real status - we must translate the error + success = SOTP_Get((uint8_t)sotp_type, aligned_8_bytes_buffer, &data_size_as_array_of_int64); + SA_PV_ERR_RECOVERABLE_RETURN_IF((!success), FCC_STATUS_ERROR, "SOTP_Get failed"); + + // Copy from aligned buffer to callers uint8_t* buffer + memcpy(data_out, aligned_8_bytes_buffer, data_size_as_array_of_int64 * sizeof(int64_t)); + + // Convert back to bytes + *data_actual_size_out = (size_t)(data_size_as_array_of_int64 << 3); + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + // FIXME: When SOTP returns real status - we must translate the error + return FCC_STATUS_SUCCESS; +} + + + + + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FIXME: All code from here on should be removed once SOTP APIs are implemented +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* +* These globals mock the SOTP storage. +* Should be removed once SOTP is implemented. +*/ +sotp_entree_s g_sotp_rot = { 0 }; +sotp_entree_s g_sotp_factory_disabled = { 0 }; +sotp_entree_s g_sotp_entropy = { 0 }; + +// API that mocks future SOTP_Set() +bool SOTP_Set(uint8_t type, uint8_t size, const int64_t *data) +{ + sotp_entree_s entree; + + entree.data_size_in_bytes = (size << 3); + memcpy(entree.data, data, entree.data_size_in_bytes); + entree.type = type; + entree.write_disabled = true; + + switch (type) { + case FCC_SOTP_TYPE_ENTROPY: + if (!g_sotp_entropy.write_disabled) { + g_sotp_entropy = entree; + } else { + return false; + } + break; + case FCC_SOTP_TYPE_ROT: + if (!g_sotp_rot.write_disabled) { + g_sotp_rot = entree; + } else { + return false; + } + break; + case FCC_SOTP_TYPE_FACTORY_DISABLE: + if (!g_sotp_factory_disabled.write_disabled) { + g_sotp_factory_disabled = entree; + } else { + return false; + } + break; + default: + return false; + } + + return true; +} + +// API that mocks future SOTP_Get() +bool SOTP_Get(uint8_t type, int64_t *data_out, uint8_t *data_size_out) +{ + switch (type) { + case FCC_SOTP_TYPE_ENTROPY: + *data_size_out = g_sotp_entropy.data_size_in_bytes >> 3; + memcpy(data_out, g_sotp_entropy.data, g_sotp_entropy.data_size_in_bytes); + break; + case FCC_SOTP_TYPE_ROT: + *data_size_out = g_sotp_rot.data_size_in_bytes >> 3; + memcpy(data_out, g_sotp_rot.data, g_sotp_rot.data_size_in_bytes); + break; + case FCC_SOTP_TYPE_FACTORY_DISABLE: + *data_size_out = g_sotp_factory_disabled.data_size_in_bytes >> 3; + memcpy(data_out, g_sotp_factory_disabled.data, g_sotp_factory_disabled.data_size_in_bytes); + break; + default: + return false; + } + + return true; +} + +void SOTP_TestOnly_reset() +{ + memset(&g_sotp_entropy, 0, sizeof(g_sotp_entropy)); + memset(&g_sotp_rot, 0, sizeof(g_sotp_rot)); + memset(&g_sotp_factory_disabled, 0, sizeof(g_sotp_factory_disabled)); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/fcc_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/fcc_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,68 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "factory_configurator_client.h" +#include "fcc_status.h" +#include "fcc_utils.h" +#include "key_config_manager.h" +#include "pv_error_handling.h" + + +fcc_status_e fcc_convert_kcm_to_fcc_status(kcm_status_e kcm_result) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + + switch (kcm_result) { + case (KCM_STATUS_SUCCESS): + fcc_status = FCC_STATUS_SUCCESS; + break; + case (KCM_STATUS_ERROR): + case (KCM_STATUS_INVALID_PARAMETER): + case (KCM_STATUS_OUT_OF_MEMORY): + case (KCM_STATUS_INSUFFICIENT_BUFFER): + fcc_status = FCC_STATUS_KCM_ERROR; + break; + case (KCM_STATUS_ITEM_NOT_FOUND): + fcc_status = FCC_STATUS_ITEM_NOT_EXIST; + break; + case (KCM_STATUS_STORAGE_ERROR): + fcc_status = FCC_STATUS_KCM_STORAGE_ERROR; + break; + case (KCM_STATUS_FILE_EXIST): + fcc_status = FCC_STATUS_KCM_FILE_EXIST_ERROR; + break; + case (KCM_CRYPTO_STATUS_UNSUPPORTED_HASH_MODE): + case (KCM_CRYPTO_STATUS_PARSING_DER_PRIVATE_KEY): + case (KCM_CRYPTO_STATUS_PARSING_DER_PUBLIC_KEY): + case (KCM_CRYPTO_STATUS_PRIVATE_KEY_VERIFICATION_FAILED): + case (KCM_CRYPTO_STATUS_PUBLIC_KEY_VERIFICATION_FAILED): + case (KCM_CRYPTO_STATUS_UNSUPPORTED_CURVE): + case (KCM_CRYPTO_STATUS_CERT_EXPIRED): + case (KCM_CRYPTO_STATUS_CERT_FUTURE): + case (KCM_CRYPTO_STATUS_CERT_MD_ALG): + case (KCM_CRYPTO_STATUS_CERT_PUB_KEY_TYPE): + case (KCM_CRYPTO_STATUS_CERT_PUB_KEY): + case (KCM_CRYPTO_STATUS_CERT_NOT_TRUSTED): + case (KCM_CRYPTO_STATUS_INVALID_X509_ATTR): + fcc_status = FCC_STATUS_KCM_CRYPTO_ERROR; + break; + default: + SA_PV_LOG_INFO("Invalid kcm_result result (%u)!", kcm_result); + fcc_status = FCC_STATUS_ERROR; + break; + } + return fcc_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/fcc_verification.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/fcc_verification.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,955 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "factory_configurator_client.h" +#include "fcc_status.h" +#include "fcc_verification.h" +#include "key_config_manager.h" +#include "pv_error_handling.h" +#include "cs_der_certs.h" +#include "cs_utils.h" +#include "fcc_output_info_handler.h" +#include "fcc_malloc.h" +#include "time.h" +#include "cs_der_keys.h" +#include "cs_utils.h" +#define FCC_10_YEARS_IN_SECONDS 315360000//10*365*24*60*60 + +/* +* The function checks that UTC offset value is inside defined range of valid offsets :-12:00 - +14:00 +*/ +static bool check_utc_offset_data(char *utc_offset_data, size_t utc_data_size) +{ + uint8_t symbol_index = 0; + uint8_t first_digit_of_hour = 1; + uint8_t second_digit_of_hour = 2; + uint8_t first_digit_of_minutes = 4; + uint8_t second_digit_of_minutes = 5; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + /* + The range of UTC offsets taken from https://en.wikipedia.org/wiki/List_of_UTC_time_offsets + We check only that the offset is -xx:yy or +xx:yy and that the offset is in range of offsets : -12:00 - +14:00 + but we check only that UTC contain restricted symbols(-,+,:_) and numbers at xx or yy. + */ + //The first char must be '+' or '-' + if ((utc_offset_data[symbol_index] != '+') && (utc_offset_data[symbol_index] != '-')) { + return false; + } + + //The format of utc offset should be -xx:xx or +xx:xx + if (utc_offset_data[3] != ':') { + return false; + } + + //Check that all numbers of hours and minutes are valid + if (utc_offset_data[first_digit_of_hour] < '0' || utc_offset_data[first_digit_of_hour] > '9') { + return false; + } + if (utc_offset_data[second_digit_of_hour] < '0' || utc_offset_data[second_digit_of_hour] > '9') { + return false; + } + if (utc_offset_data[first_digit_of_minutes] < '0' || utc_offset_data[first_digit_of_minutes] > '9') { + return false; + } + if (utc_offset_data[second_digit_of_minutes] < '0' || utc_offset_data[second_digit_of_minutes] > '9') { + return false; + } + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return true; +} + +/** The function checks bootstrap server uri data contents. +* +* @param uri_data_buffer[in] The bootstrap uri data. +* @param size_of_uri_data_buffer[in] The bootstrap uri data size. +* @return +* fcc_status_e. +*/ +static fcc_status_e fcc_check_uri_contents(bool use_bootstrap, uint8_t* uri_data_buffer, size_t size_of_uri_data_buffer) +{ + const char uri_coap_prefix[] = "coap://"; + const char uri_coaps_prefix[] = "coaps://"; + const char uri_aid_1[] = "?aid="; + const char uri_aid_2[] = "&aid="; + bool has_uri_aid = false; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + char *uri_string = NULL; + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + bool is_first_to_claim_mode = false; + uint32_t first_to_claim = 0; + size_t act_config_param_size = 0; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + // get first to claim + kcm_status = kcm_item_get_data((const uint8_t*)g_fcc_first_to_claim_parameter_name, + strlen(g_fcc_first_to_claim_parameter_name), + KCM_CONFIG_ITEM, + (uint8_t*)&first_to_claim, + sizeof(uint32_t), + &act_config_param_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS && kcm_status != KCM_STATUS_ITEM_NOT_FOUND), FCC_STATUS_KCM_ERROR, "Failed to get first to claim config parameter"); + if (kcm_status == KCM_STATUS_SUCCESS) { + SA_PV_ERR_RECOVERABLE_RETURN_IF((act_config_param_size != sizeof(uint32_t)), FCC_STATUS_WRONG_ITEM_DATA_SIZE, "Size of first to claim mode parameter is wrong "); + is_first_to_claim_mode = (first_to_claim == 1); + } + + //Allocate buffer for uri string creation + uri_string = fcc_malloc(size_of_uri_data_buffer + 1); + SA_PV_ERR_RECOVERABLE_RETURN_IF((uri_string == NULL), FCC_STATUS_MEMORY_OUT, "Failed to allocate memory for URI string"); + + //Copy data and create null terminated string + memcpy(uri_string, uri_data_buffer, size_of_uri_data_buffer); + (*(uri_string + size_of_uri_data_buffer)) = '\0'; + + // Check that uri_string has correct prefix + if (memcmp(uri_string, uri_coap_prefix, strlen(uri_coap_prefix)) != 0 && memcmp(uri_string, uri_coaps_prefix, strlen(uri_coaps_prefix)) != 0) { + SA_PV_ERR_RECOVERABLE_GOTO_IF(true, fcc_status = FCC_STATUS_URI_WRONG_FORMAT, exit, "Wrong uri prefix"); + } + + // Check if uri_string contains uri_aid (indicate the uri contains AccountId) + if ((strstr(uri_string, uri_aid_1) != NULL) || (strstr(uri_string, uri_aid_2) != NULL)) { + has_uri_aid = true; + } + + if (is_first_to_claim_mode == true) { + SA_PV_ERR_RECOVERABLE_GOTO_IF(use_bootstrap == false, fcc_status = FCC_STATUS_FIRST_TO_CLAIM_NOT_ALLOWED, exit, "First to claim not allowed in lwm2m mode"); + SA_PV_ERR_RECOVERABLE_GOTO_IF(has_uri_aid == true, fcc_status = FCC_STATUS_FIRST_TO_CLAIM_NOT_ALLOWED, exit, "First to claim not allowed if account ID exist"); + } else { + SA_PV_ERR_RECOVERABLE_GOTO_IF(has_uri_aid == false, fcc_status = FCC_STATUS_URI_WRONG_FORMAT, exit, "Wrong uri data"); + } + +exit: + fcc_free(uri_string); + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +/**This function retrives kcm data buffer and its size according to the given name. +* +* @param parameter_name[in] buffer of parameter name. +* @param size_of_parameter_name[in] size of parameter name. +* @kcm_type[in] type of kcm data to retrieve +* @param kcm_data[out] pointer to kcm data. +* @param kcm_data_size[out] size of kcm data. +* fcc_status_e status. +*/ +static fcc_status_e fcc_get_kcm_data(const uint8_t *parameter_name, size_t size_of_parameter_name, kcm_item_type_e kcm_type, uint8_t **kcm_data, size_t *kcm_data_size) +{ + + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + + //Get size of kcm data + kcm_status = kcm_item_get_data_size(parameter_name, + size_of_parameter_name, + kcm_type, + kcm_data_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status == KCM_STATUS_ITEM_NOT_FOUND), fcc_status = FCC_STATUS_ITEM_NOT_EXIST, "KCM is not found"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((*kcm_data_size == 0), fcc_status = FCC_STATUS_EMPTY_ITEM, "KCM item is empty"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_KCM_STORAGE_ERROR, "Failed to get kcm data size"); + + //Alocate memory and get device certificate data + *kcm_data = fcc_malloc(*kcm_data_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((*kcm_data == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, "Failed to allocate buffer for kcm data"); + + kcm_status = kcm_item_get_data(parameter_name, + size_of_parameter_name, + kcm_type, + *kcm_data, *kcm_data_size, kcm_data_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status == KCM_STATUS_ITEM_NOT_FOUND), fcc_status = FCC_STATUS_ITEM_NOT_EXIST, exit, "KCM is not found"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_KCM_STORAGE_ERROR, exit, "Failed to get device certificate data"); + + return fcc_status; +exit: + fcc_free(*kcm_data); + *kcm_data = NULL; + return fcc_status; +} + +/**This function retrives certificate's attribute and it's size according to its type. +* +* @param certificate_data[in] buffer of certificate. +* @param size_of_certificate_data[in] size of certificate data. +* @attribute_type[in] type of attribute to retrieve. +* @param size_of_certificate_data[out] attribute data buffer. +* @param size_of_certificate_data[out] size of attribute data buffer. +* fcc_status_e status. +*/ +static fcc_status_e fcc_get_certificate_attribute(palX509Handle_t x509_cert, cs_certificate_attribute_type_e attribute_type, uint8_t **attribute_data, size_t *attribute_size) +{ + + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + + + + //Get attribute size + kcm_status = cs_attr_get_data_size_x509_cert(x509_cert, + attribute_type, + attribute_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_INVALID_CERT_ATTRIBUTE, "Failed to get size of attribute"); + + *attribute_data = fcc_malloc(*attribute_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((*attribute_data == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, "Failed to allocate memory for attribute"); + + //Get data of "CN" attribute + kcm_status = cs_attr_get_data_x509_cert(x509_cert, + attribute_type, + *attribute_data, + *attribute_size, + attribute_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS || *attribute_size == 0), fcc_status = FCC_STATUS_INVALID_CERT_ATTRIBUTE, exit, "Failed to get attribute data"); + + return fcc_status; +exit: + fcc_free(*attribute_data); + *attribute_data = NULL; + return fcc_status; +} +/* The function verifies if current item exists and checks the result with is_should_be_present flag. +* In case of unsuitability of the flag and existence of the item, the function sets warning with relevant message. +*/ +static fcc_status_e verify_existence_and_set_warning(const uint8_t *parameter_name, size_t size_of_parameter_name, kcm_item_type_e parameter_type, bool is_should_be_present) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + size_t item_size = 0; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + //Check that second mode server uri is not present + kcm_status = kcm_item_get_data_size(parameter_name, + size_of_parameter_name, + parameter_type, + &item_size); + + if (kcm_status == KCM_STATUS_SUCCESS && is_should_be_present == false) { + output_info_fcc_status = fcc_store_warning_info((const uint8_t*)parameter_name, size_of_parameter_name, g_fcc_redundant_item_warning_str); + } + if (kcm_status != KCM_STATUS_SUCCESS && is_should_be_present == true) { + output_info_fcc_status = fcc_store_warning_info((const uint8_t*)parameter_name, size_of_parameter_name, g_fcc_item_not_set_warning_str); + } + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, + "Failed to create warning"); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} +/**This function verifies certificate expiration according to +* +* @param certificate_data[in] buffer of certificate. +* @param size_of_certificate_data[in] size of certificate data. +* @param certificate_name[in] buffer of certificate name. +* @param size_of_certificate_name[in] size of certificate name buffer. +* @returns +* fcc_status_e status. +*/ +static fcc_status_e verify_certificate_expiration(palX509Handle_t x509_cert, const uint8_t *certificate_name, size_t size_of_certificate_name) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + size_t size_of_valid_from_attr = 0; + size_t size_of_valid_until_attr = 0; + uint64_t *valid_from_attr = NULL; + uint64_t time = 0; + uint64_t diff_time = 60; //seconds. This value used to reduce time adjustment + uint64_t *valid_until_attr = NULL; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + //Get "valid_from" certificate attribute + fcc_status = fcc_get_certificate_attribute(x509_cert, CS_VALID_FROM_ATTRIBUTE_TYPE, (uint8_t**)&valid_from_attr, &size_of_valid_from_attr); + SA_PV_ERR_RECOVERABLE_GOTO_IF(fcc_status != FCC_STATUS_SUCCESS || size_of_valid_from_attr != sizeof(uint64_t), fcc_status = fcc_status, exit, "Failed to get size of valid_from attribute"); + + //Get "valid_until" certificate attribute + fcc_status = fcc_get_certificate_attribute(x509_cert, CS_VALID_TO_ATTRIBUTE_TYPE, (uint8_t**)&valid_until_attr, &size_of_valid_until_attr); + SA_PV_ERR_RECOVERABLE_GOTO_IF(fcc_status != FCC_STATUS_SUCCESS || size_of_valid_from_attr != sizeof(uint64_t), fcc_status = fcc_status, exit, "Failed to get size of valid_until attribute"); + + + //Check device time + time = pal_osGetTime(); + if (time == 0) { + output_info_fcc_status = fcc_store_warning_info((const uint8_t*)certificate_name, size_of_certificate_name, g_fcc_cert_time_validity_warning_str); + SA_PV_LOG_ERR("time is (%" PRIuMAX ") ", (uint64_t)time); + SA_PV_ERR_RECOVERABLE_GOTO_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, exit, "Failed to create warning"); + } else { + //Check that the certificate is not expired + SA_PV_ERR_RECOVERABLE_GOTO_IF((time > (*valid_until_attr)), fcc_status = FCC_STATUS_EXPIRED_CERTIFICATE, exit, "The certificate is expired"); + + //Check that start of validity is less than current time + if (time + diff_time < (*valid_from_attr)) { + SA_PV_LOG_ERR("valid_from_attr is (%" PRIuMAX ") ", (uint64_t)(*valid_from_attr)); + SA_PV_LOG_ERR("time is (%" PRIuMAX ") ", (uint64_t)time); + output_info_fcc_status = fcc_store_warning_info((const uint8_t*)certificate_name, size_of_certificate_name, g_fcc_cert_time_validity_warning_str); + SA_PV_ERR_RECOVERABLE_GOTO_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, exit, "Failed to create warning"); + } + + //Check that the certificate is valid at least for 10 years + if ((*valid_until_attr) - time < FCC_10_YEARS_IN_SECONDS) { + output_info_fcc_status = fcc_store_warning_info((const uint8_t*)certificate_name, size_of_certificate_name, g_fcc_cert_validity_less_10_years_warning_str); + SA_PV_ERR_RECOVERABLE_GOTO_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, exit, "Failed to create warning"); + } + + } +exit: + fcc_free(valid_from_attr); + fcc_free(valid_until_attr); + if (fcc_status != FCC_STATUS_SUCCESS) { + output_info_fcc_status = fcc_store_error_info((const uint8_t*)certificate_name, size_of_certificate_name, fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, "Failed to create output fcc_status error %d", fcc_status); + } + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} +/**This function verifies lwm2m certificate ou attribute is equal to aid from server link. +* +* @param certificate_data[in] buffer of certificate. +* @param size_of_certificate_data[in] size of certificate data. +* fcc_status_e status. +*/ +static fcc_status_e compare_ou_with_aid_server(palX509Handle_t x509_cert) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + uint8_t *ou_attribute_data = NULL; + size_t ou_attribute_size = 0; + uint8_t *parameter_name = (uint8_t*)g_fcc_lwm2m_server_uri_name; + size_t size_of_parameter_name = strlen(g_fcc_lwm2m_server_uri_name); + uint8_t *server_uri_buffer = NULL; + size_t item_size = 0; + char *uri_string = NULL; + char *aid_substring = NULL; + size_t aid_substring_size = 0; + int result = 0; + int len_of_aid_sub_string = strlen("&aid="); + + //Get OU certificate attribute + fcc_status = fcc_get_certificate_attribute(x509_cert, CS_OU_ATTRIBUTE_TYPE, &ou_attribute_data, &ou_attribute_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF(fcc_status != FCC_STATUS_SUCCESS, fcc_status = fcc_status, "Failed to get size OU attribute"); + + //Get aid data + fcc_status = fcc_get_kcm_data(parameter_name, size_of_parameter_name, KCM_CONFIG_ITEM, &server_uri_buffer, &item_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, exit, "Failed to get kcm data server url"); + + uri_string = fcc_malloc(item_size + 1); + SA_PV_ERR_RECOVERABLE_GOTO_IF((uri_string == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, exit, "Failed to get kcm data server url"); + + memcpy(uri_string, server_uri_buffer, item_size); + (*(uri_string + item_size)) = '\0'; + + aid_substring = strstr(uri_string, "&aid="); + if (aid_substring == NULL) { + aid_substring = strstr(uri_string, "?aid="); + SA_PV_ERR_RECOVERABLE_GOTO_IF((aid_substring == NULL), fcc_status = FCC_STATUS_URI_WRONG_FORMAT, exit, "URI format is wrong"); + } + + aid_substring_size = strlen(aid_substring); + aid_substring_size = aid_substring_size - len_of_aid_sub_string; + SA_PV_ERR_RECOVERABLE_GOTO_IF((aid_substring_size < ou_attribute_size - 1), fcc_status = FCC_STATUS_URI_WRONG_FORMAT, exit, "URI format is wrong"); + + result = memcmp(&(aid_substring[len_of_aid_sub_string]), ou_attribute_data, ou_attribute_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((result != 0), fcc_status = FCC_STATUS_INVALID_LWM2M_CN_ATTR, exit, "CN of LWM2M different from endpoint name"); + +exit: + fcc_free(ou_attribute_data); + fcc_free(server_uri_buffer); + fcc_free(uri_string); + return fcc_status; +} +/**This function verifies certificate's cn attribute is equal to endpoint name. +* +* @param certificate_data[in] buffer of certificate. +* @param size_of_certificate_data[in] size of certificate data. +* fcc_status_e status. +*/ +static fcc_status_e compare_cn_with_endpoint(palX509Handle_t x509_cert) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + //fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + size_t size_of_cn_attr = 0; + uint8_t *cn_attribute_data = NULL; + size_t endpoint_name_size; + uint8_t *endpoint_name_data = NULL; + int result = 0; + + //Get CN certificate attribute + fcc_status = fcc_get_certificate_attribute(x509_cert, CS_CN_ATTRIBUTE_TYPE, &cn_attribute_data, &size_of_cn_attr); + SA_PV_ERR_RECOVERABLE_RETURN_IF(fcc_status != FCC_STATUS_SUCCESS, fcc_status = fcc_status, "Failed to get size CN attribute"); + + //Get attribute returns size of string including "\0" + size_of_cn_attr = size_of_cn_attr - 1; + + //Get endpoint name size + fcc_status = fcc_get_kcm_data((const uint8_t*)g_fcc_endpoint_parameter_name, strlen(g_fcc_endpoint_parameter_name), KCM_CONFIG_ITEM, &endpoint_name_data, &endpoint_name_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, exit, "Failed to get endpoint name"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((size_of_cn_attr != endpoint_name_size), fcc_status = FCC_STATUS_INVALID_LWM2M_CN_ATTR, exit, "Wrong size of CN"); + + result = memcmp(endpoint_name_data, cn_attribute_data, size_of_cn_attr); + SA_PV_ERR_RECOVERABLE_GOTO_IF((result != 0), fcc_status = FCC_STATUS_INVALID_LWM2M_CN_ATTR, exit, "CN of the certificate is different from endpoint name"); + +exit: + fcc_free(cn_attribute_data); + fcc_free(endpoint_name_data); + return fcc_status; +} +/** The function checks validity of bootstrap server uri parameter +* +* The function checks the item's size, gets its data and checks it. +* +* @param bootrstrap_server_uri_name[in] The bootstrap uri name. +* @param size_of_bootrstrap_server_uri_name[in] The size of bootstrap uri name. +* @return +* fcc_status_e. +*/ +static fcc_status_e verify_server_uri(bool use_bootstrap) +{ + + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + size_t item_size = 0; + uint8_t *server_uri_buffer = NULL; + uint8_t *parameter_name = NULL; + size_t size_of_parameter_name = 0; + uint8_t *second_mode_parameter_name = NULL; + size_t size_of_second_mode_parameter_name = 0; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + //Set server uri parameter names of current and second mode according to bootstrap mode + if (use_bootstrap == true) { + parameter_name = (uint8_t*)g_fcc_bootstrap_server_uri_name; + size_of_parameter_name = strlen(g_fcc_bootstrap_server_uri_name); + second_mode_parameter_name = (uint8_t*)g_fcc_lwm2m_server_uri_name; + size_of_second_mode_parameter_name = strlen(g_fcc_lwm2m_server_uri_name); + } else { + parameter_name = (uint8_t*)g_fcc_lwm2m_server_uri_name; + size_of_parameter_name = strlen(g_fcc_lwm2m_server_uri_name); + second_mode_parameter_name = (uint8_t*)g_fcc_bootstrap_server_uri_name; + size_of_second_mode_parameter_name = strlen(g_fcc_bootstrap_server_uri_name); + } + fcc_status = fcc_get_kcm_data(parameter_name, size_of_parameter_name, KCM_CONFIG_ITEM, &server_uri_buffer, &item_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, exit, "Failed to get kcm data server url"); + + //Check that server uri of second mode is not present, if yes - set warning + fcc_status = verify_existence_and_set_warning(second_mode_parameter_name, size_of_second_mode_parameter_name, KCM_CONFIG_ITEM, false); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, exit, "Failed to verify_existence_and_set_warning"); + + //Check server uri data + fcc_status = fcc_check_uri_contents(use_bootstrap, server_uri_buffer, item_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, exit, "Failed to check bootstrap uri data"); + +exit: + fcc_free(server_uri_buffer); + //In case kcm or fcc error, record the error with parameter name + if (kcm_status != KCM_STATUS_SUCCESS || fcc_status != FCC_STATUS_SUCCESS) { + if (fcc_status == FCC_STATUS_FIRST_TO_CLAIM_NOT_ALLOWED && parameter_name == (uint8_t*)g_fcc_lwm2m_server_uri_name) + { + // In case that using lwm2m and first to claim on, change the parameter_name + parameter_name = (uint8_t*)g_fcc_first_to_claim_parameter_name; + size_of_parameter_name = strlen(g_fcc_first_to_claim_parameter_name); + } + output_info_fcc_status = fcc_store_error_info(parameter_name, size_of_parameter_name, fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output fcc_status error %d", + fcc_status); + } + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +/* The function checks UTC offset. +*/ +static fcc_status_e check_utc_offset(void) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e fcc_output_status = FCC_STATUS_SUCCESS; + uint8_t *parameter_name = (uint8_t*)g_fcc_offset_from_utc_parameter_name; + size_t size_of_parameter_name = strlen(g_fcc_offset_from_utc_parameter_name); + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + size_t item_size = 0; + + uint8_t *utc_offset_data = NULL; + bool status = false; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + fcc_status = fcc_get_kcm_data(parameter_name, size_of_parameter_name, KCM_CONFIG_ITEM, &utc_offset_data, &item_size); + + //If the item is missing or empty, write warning + if (fcc_status == FCC_STATUS_ITEM_NOT_EXIST || fcc_status == FCC_STATUS_EMPTY_ITEM) { + fcc_output_status = fcc_store_warning_info(parameter_name, size_of_parameter_name, g_fcc_item_not_set_warning_str); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_output_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, + exit, + "Failed to create output warning %s", + g_fcc_item_not_set_warning_str); + fcc_status = FCC_STATUS_SUCCESS; + } else { + //If get kcm data returned error, exit with error + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, exit, "Failed to get utc data"); + + status = check_utc_offset_data((char*)utc_offset_data, item_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), fcc_status = FCC_STATUS_UTC_OFFSET_WRONG_FORMAT, exit, "Failed to check utc offset"); + } + +exit: + fcc_free(utc_offset_data); + if (fcc_status != FCC_STATUS_SUCCESS) { + output_info_fcc_status = fcc_store_error_info(parameter_name, size_of_parameter_name, fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output fcc_status error %d", + fcc_status); + } + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} +/**This function checks Root CA certificate. +* +* @param device_objects[in] Structure with set of device security object data. +* @param use_bootstrap[in] Bootstrap mode. +* @returns +* fcc_status_e status. +*/ +static fcc_status_e verify_root_ca_certificate(bool use_bootstrap) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + size_t item_size = 0; + uint8_t *parameter_name = NULL; + size_t size_of_parameter_name = 0; + uint8_t *second_mode_parameter_name = NULL; + size_t size_of_second_mode_parameter_name = 0; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + //Set CA certificate names of current and second mode + if (use_bootstrap == true) { + //Set bootstrap root ca certificate name + parameter_name = (uint8_t*)g_fcc_bootstrap_server_ca_certificate_name; + size_of_parameter_name = strlen(g_fcc_bootstrap_server_ca_certificate_name); + second_mode_parameter_name = (uint8_t*)g_fcc_lwm2m_server_ca_certificate_name; + size_of_second_mode_parameter_name = strlen(g_fcc_lwm2m_server_ca_certificate_name); + } else { + //Set lwm2m root ca certificate name + parameter_name = (uint8_t*)g_fcc_lwm2m_server_ca_certificate_name; + size_of_parameter_name = strlen(g_fcc_lwm2m_server_ca_certificate_name); + second_mode_parameter_name = (uint8_t*)g_fcc_bootstrap_server_ca_certificate_name; + size_of_second_mode_parameter_name = strlen(g_fcc_bootstrap_server_ca_certificate_name); + } + + //Check that ca certificate of current mode is present + kcm_status = kcm_item_get_data_size((const uint8_t*)parameter_name, + size_of_parameter_name, + KCM_CERTIFICATE_ITEM, + &item_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_ITEM_NOT_EXIST, store_error_and_exit, "Failed to get size bootstrap root ca certificate size"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((item_size == 0), fcc_status = FCC_STATUS_EMPTY_ITEM, store_error_and_exit, "Empty root CA certificate"); + + //Check that ca certificate of second mode is not present, if yes - set warning + fcc_status = verify_existence_and_set_warning(second_mode_parameter_name, size_of_second_mode_parameter_name, KCM_CERTIFICATE_ITEM, false); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, store_error_and_exit, "Failed in verify_existence_and_set_warning"); + + //TBD : check of mbed crypto scheme IOTPREQ-1417 +store_error_and_exit: + if (fcc_status != FCC_STATUS_SUCCESS) { + output_info_fcc_status = fcc_store_error_info(parameter_name, size_of_parameter_name, fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output fcc_status error %d", + fcc_status); + } + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} +/**This function checks device private key. +* +* @param use_bootstrap[in] Bootstrap mode. +* @returns +* fcc_status_e status. +*/ +static fcc_status_e verify_device_certificate_and_private_key(bool use_bootstrap) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + size_t size_of_device_cert = 0; + uint8_t *device_cert = NULL; + bool is_self_signed = false; + uint8_t *parameter_name = NULL; + size_t size_of_parameter_name = 0; + uint8_t *second_mode_parameter_name = NULL; + size_t size_of_second_mode_parameter_name = 0; + uint8_t *private_key_data = NULL; + size_t size_of_private_key_data = 0; + palX509Handle_t x509_cert_handle = NULLPTR; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + //Set device privat key names of current and second modes + if (use_bootstrap == true) { + parameter_name = (uint8_t*)g_fcc_bootstrap_device_private_key_name; + size_of_parameter_name = strlen(g_fcc_bootstrap_device_private_key_name); + second_mode_parameter_name = (uint8_t*)g_fcc_lwm2m_device_private_key_name; + size_of_second_mode_parameter_name = strlen(g_fcc_lwm2m_device_private_key_name); + } else { + parameter_name = (uint8_t*)g_fcc_lwm2m_device_private_key_name; + size_of_parameter_name = strlen(g_fcc_lwm2m_device_private_key_name); + second_mode_parameter_name = (uint8_t*)g_fcc_bootstrap_device_private_key_name; + size_of_second_mode_parameter_name = strlen(g_fcc_bootstrap_device_private_key_name); + } + + fcc_status = fcc_get_kcm_data(parameter_name, size_of_parameter_name, KCM_PRIVATE_KEY_ITEM, &private_key_data, &size_of_private_key_data); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, store_error_and_exit, "Failed to get device certificate"); + + //Check that device private key of second mode is not present, if yes - set warning + fcc_status = verify_existence_and_set_warning(second_mode_parameter_name, size_of_second_mode_parameter_name, KCM_PRIVATE_KEY_ITEM, false); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, store_error_and_exit, "Failed in verify_existence_and_set_warning"); + + + //Set parameter names of device certificate according to mode + if (use_bootstrap == true) { + //Set bootstrap root ca certificate name + parameter_name = (uint8_t*)g_fcc_bootstrap_device_certificate_name; + size_of_parameter_name = strlen(g_fcc_bootstrap_device_certificate_name); + second_mode_parameter_name = (uint8_t*)g_fcc_lwm2m_device_certificate_name; + size_of_second_mode_parameter_name = strlen(g_fcc_lwm2m_device_certificate_name); + } else { + //Set lwm2m device certificate name + parameter_name = (uint8_t*)g_fcc_lwm2m_device_certificate_name; + size_of_parameter_name = strlen(g_fcc_lwm2m_device_certificate_name); + second_mode_parameter_name = (uint8_t*)g_fcc_bootstrap_device_certificate_name; + size_of_second_mode_parameter_name = strlen(g_fcc_bootstrap_device_certificate_name); + } + + fcc_status = fcc_get_kcm_data(parameter_name, size_of_parameter_name, KCM_CERTIFICATE_ITEM, &device_cert, &size_of_device_cert); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, store_error_and_exit, "Failed to get device certificate"); + + //Create device certificate handle + kcm_status = cs_create_handle_from_der_x509_cert(device_cert, size_of_device_cert, &x509_cert_handle); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_INVALID_CERTIFICATE, store_error_and_exit, "Failed to get device certificate descriptor"); + + //Check device certificate public key + kcm_status = cs_check_certifcate_public_key(x509_cert_handle, private_key_data, size_of_private_key_data); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_CERTIFICATE_PUBLIC_KEY_CORRELATION_ERROR, store_error_and_exit, "Failed to check device certificate public key"); + + //Check if the certificate of second mode exists, if yes - set warning + fcc_status = verify_existence_and_set_warning(second_mode_parameter_name, size_of_second_mode_parameter_name, KCM_CERTIFICATE_ITEM, false); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, store_error_and_exit, "Failed to verify_existence_and_set_warning"); + + //Compare device certificate's CN attribute with endpoint name + fcc_status = compare_cn_with_endpoint(x509_cert_handle); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, store_error_and_exit, "Failed to compare_cn_with_endpoint"); + + //In case LWM2M certificate check it's OU attribute with aid of server link + if (strcmp((const char*)parameter_name, g_fcc_lwm2m_device_certificate_name) == 0) { + fcc_status = compare_ou_with_aid_server(x509_cert_handle); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, store_error_and_exit, "Failed to compare_ou_with_aid_server"); + } + + //Check that device certificate not self-signed + kcm_status = cs_is_self_signed_x509_cert(x509_cert_handle, &is_self_signed); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_INVALID_CERTIFICATE, store_error_and_exit, "Failed to check if device certificate is self-signed"); + if (is_self_signed == true) { + output_info_fcc_status = fcc_store_warning_info(parameter_name, size_of_parameter_name, g_fcc_self_signed_warning_str); + SA_PV_ERR_RECOVERABLE_GOTO_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, + store_error_and_exit, + "Failed to create warning %s", + g_fcc_self_signed_warning_str); + } + //Check device certificate attributes + fcc_status = verify_certificate_expiration(x509_cert_handle, parameter_name, size_of_parameter_name); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, store_error_and_exit, "Failed to verify_certificate_validity"); + +store_error_and_exit: + fcc_free(private_key_data); + fcc_free(device_cert); + cs_close_handle_x509_cert(&x509_cert_handle); + if (fcc_status != FCC_STATUS_SUCCESS) { + output_info_fcc_status = fcc_store_error_info(parameter_name, size_of_parameter_name, fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output fcc_status error %d", + fcc_status); + } + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +/* The function checks firmware integrity ca and firmware integrity certificates +*/ +static fcc_status_e verify_firmware_update_certificate(void) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e fcc_output_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + uint8_t *parameter_name = (uint8_t*)g_fcc_update_authentication_certificate_name; + size_t size_of_parameter_name = strlen(g_fcc_update_authentication_certificate_name); + size_t certificate_data_size = 0; + uint8_t *certificate_data = NULL; + palX509Handle_t x509_cert_handle = NULLPTR; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + fcc_status = fcc_get_kcm_data(parameter_name, size_of_parameter_name, KCM_CERTIFICATE_ITEM, &certificate_data, &certificate_data_size); + + if (fcc_status == FCC_STATUS_ITEM_NOT_EXIST || fcc_status == FCC_STATUS_EMPTY_ITEM) { + fcc_output_status = fcc_store_warning_info((const uint8_t*)parameter_name, size_of_parameter_name, g_fcc_item_not_set_warning_str); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_output_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, + exit, + "Failed to create output warning %s", + g_fcc_item_not_set_warning_str); + fcc_status = FCC_STATUS_SUCCESS; + } else { + //If get kcm data returned error, exit with error + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, exit, "Failed to get update certificate data"); + + //Create ca firmware integrity certificate handle + kcm_status = cs_create_handle_from_der_x509_cert(certificate_data, certificate_data_size, &x509_cert_handle); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_INVALID_CERTIFICATE, exit, "Failed to get device certificate descriptor"); + + //Check firmware update certificate expiration + fcc_status = verify_certificate_expiration(x509_cert_handle, parameter_name, size_of_parameter_name); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, exit, "Failed to verify_certificate_validity"); + } + +exit: + + fcc_free(certificate_data); + cs_close_handle_x509_cert(&x509_cert_handle); + if (fcc_status != FCC_STATUS_SUCCESS) { + output_info_fcc_status = fcc_store_error_info(parameter_name, size_of_parameter_name, fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output fcc_status error %d", + fcc_status); + } + return fcc_status; +} +//FIXME : once init entropy API will be ready,add fcc_is_entropy_initialized implementation +bool fcc_is_entropy_initialized(void) +{ + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return true; +} +fcc_status_e fcc_check_time_synchronization() +{ + + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + uint64_t time = 0; + uint8_t *parameter_name = (uint8_t*)g_fcc_device_time_zone_parameter_name; + size_t size_of_parameter_name = strlen(g_fcc_device_time_zone_parameter_name); + size_t item_size = 0; + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + /* + Time zone defines - https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + */ + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + //Check device time + time = pal_osGetTime(); + if (time == 0) { + output_info_fcc_status = fcc_store_warning_info((const uint8_t*)g_fcc_current_time_parameter_name, strlen(g_fcc_current_time_parameter_name), g_fcc_item_not_set_warning_str); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, "Failed to create warning"); + } + + //Check device time zone + kcm_status = kcm_item_get_data_size((const uint8_t*)parameter_name, + size_of_parameter_name, + KCM_CONFIG_ITEM, + &item_size); + //Store warning in case time zone is missing or empty + if (kcm_status != KCM_STATUS_SUCCESS || item_size == 0) { + output_info_fcc_status = fcc_store_warning_info(parameter_name, size_of_parameter_name, g_fcc_item_not_set_warning_str); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, + "Failed to create output warning %s", + g_fcc_item_not_set_warning_str); + } + + //Check UTC offset + fcc_status = check_utc_offset(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed in check_utc_offset"); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +fcc_status_e fcc_check_device_general_info() +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + size_t config_param_size = 0; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + //Check FCC_ENDPOINT_NAME_CONFIG_PARAM_NAME + kcm_status = kcm_item_get_data_size((const uint8_t*)&g_fcc_endpoint_parameter_name, + strlen(g_fcc_endpoint_parameter_name), + KCM_CONFIG_ITEM, + &config_param_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_ITEM_NOT_EXIST, exit, "Failed to get size of %s ", g_fcc_endpoint_parameter_name); + SA_PV_ERR_RECOVERABLE_GOTO_IF((config_param_size == 0), fcc_status = FCC_STATUS_EMPTY_ITEM, exit, "Size of %s is 0 ", g_fcc_endpoint_parameter_name); + +exit: + if (fcc_status != FCC_STATUS_SUCCESS) { + output_info_fcc_status = fcc_store_error_info((const uint8_t*)g_fcc_endpoint_parameter_name, strlen(g_fcc_endpoint_parameter_name), fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output fcc_status error %d", + fcc_status); + } + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +fcc_status_e fcc_check_device_meta_data(void) +{ + int config_param_index = 0; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + size_t config_param_size = 0; + uint8_t *parameter_name = NULL; + size_t size_of_parameter_name = 0; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + for (config_param_index = 0; config_param_index < FCC_MAX_CONFIG_PARAM_TYPE; config_param_index++) { + + //Set current configuration parameter to local variable + parameter_name = (uint8_t*)fcc_config_param_lookup_table[config_param_index].config_param_name; + size_of_parameter_name = strlen(fcc_config_param_lookup_table[config_param_index].config_param_name); + + //Check that current configuration parameter is present + kcm_status = kcm_item_get_data_size((const uint8_t*)parameter_name, + size_of_parameter_name, + KCM_CONFIG_ITEM, + &config_param_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_ITEM_NOT_EXIST, exit, "Failed to get size of %s ", fcc_config_param_lookup_table[config_param_index].config_param_name); + } + +exit: + if (fcc_status != FCC_STATUS_SUCCESS) { + output_info_fcc_status = fcc_store_error_info(parameter_name, size_of_parameter_name, fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output fcc_status error %d", + fcc_status); + } + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +fcc_status_e fcc_get_bootstrap_mode(bool *use_bootstrap) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + size_t config_param_size = sizeof(uint32_t); + size_t act_config_param_size = 0; + uint32_t bootstrap; + uint8_t *parameter_name = (uint8_t*)g_fcc_use_bootstrap_parameter_name; + size_t size_of_parameter_name = strlen(g_fcc_use_bootstrap_parameter_name); + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + //Get configuration parameter + kcm_status = kcm_item_get_data((const uint8_t*)parameter_name, + size_of_parameter_name, + KCM_CONFIG_ITEM, + (uint8_t*)&bootstrap, + config_param_size, + &act_config_param_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_ITEM_NOT_EXIST, exit, "Failed to get data bootstrap mode parameter"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((act_config_param_size != sizeof(uint32_t)), fcc_status = FCC_STATUS_WRONG_ITEM_DATA_SIZE, exit, "Size of bootstrap mode parameter is wrong "); + + if (bootstrap != 0 && bootstrap != 1) { + SA_PV_ERR_RECOVERABLE_GOTO_IF((true), fcc_status = FCC_STATUS_BOOTSTRAP_MODE_ERROR, exit, "Invalid bootstrap mode"); + } + if (bootstrap == 0) { + *use_bootstrap = false; + output_info_fcc_status = fcc_store_warning_info(parameter_name, size_of_parameter_name, g_fcc_bootstrap_mode_false_warning_str); + SA_PV_ERR_RECOVERABLE_GOTO_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_WARNING_CREATE_ERROR, + exit, + "Failed to create output warning %s", + g_fcc_bootstrap_mode_false_warning_str); + } else { + *use_bootstrap = true; + } + +exit: + if (fcc_status != FCC_STATUS_SUCCESS) { + output_info_fcc_status = fcc_store_error_info(parameter_name, size_of_parameter_name, fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output fcc_status error %d", + fcc_status); + } + SA_PV_LOG_TRACE_FUNC_EXIT("use_bootstrap is %d", *use_bootstrap); + return fcc_status; +} + +fcc_status_e fcc_check_device_security_objects(bool use_bootstrap) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + fcc_status = verify_root_ca_certificate(use_bootstrap); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to verify root CA certificate"); + + //Check bootstrap server URI + fcc_status = verify_server_uri(use_bootstrap); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to verify server URI"); + + //Check device certificate and private key + fcc_status = verify_device_certificate_and_private_key(use_bootstrap); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to verify device certificate and private key"); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +fcc_status_e fcc_check_firmware_update_integrity(void) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + fcc_status = verify_firmware_update_certificate(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status, "Failed to verify integrity CA certificate"); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/include/fcc_sotp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/include/fcc_sotp.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,99 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_SOTP_H__ +#define __FCC_SOTP_H__ + +#include "factory_configurator_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enum representing the different types of data that can be stored in SOTP */ +typedef enum fcc_sotp_type_ { + FCC_SOTP_TYPE_ROT = 1, + FCC_SOTP_TYPE_FACTORY_DISABLE = 2, + FCC_SOTP_TYPE_ENTROPY = 5 // Note that the values 3 and 4 are reserved for backward time and secure time - not used by us. +} fcc_sotp_type_e; + + +// Size of factory disabled flag in SOTP - internal use only. +#define FCC_FACTORY_DISABLE_FLAG_SIZE sizeof(int64_t) + +/** Writes data to SOTP +* +* @param data[in] The data to store in SOTP. +* @param data_size[in] The size of buf in bytes. Must be divisible by 8, and less than or equal to 1024. Must be according to sotp_type. +* @param sotp_type[in] Enum representing the type of the item to be stored in SOTP. +* +* @return +* FCC_STATUS_SUCCESS for success or one of the `::fcc_status_e` errors otherwise. +*/ +fcc_status_e fcc_sotp_data_store(const uint8_t *data, size_t data_size, fcc_sotp_type_e sotp_type); + +/** Reads data from SOTP +* +* @param data_out[out] A buffer to retrieve data from SOTP. +* @param data_size_max[in] The size of data_out max. bytes. +* @param data_actual_size_out[out] The actual size of bytes returned by this function, should be less or equal to data_size_max. +* @param sotp_type[in] Enum representing the type of the item to be stored in SOTP. +* +* @return +* FCC_STATUS_SUCCESS for success or one of the `::fcc_status_e` errors otherwise. +*/ +fcc_status_e fcc_sotp_data_retrieve(uint8_t *data_out, size_t data_size_max, size_t *data_actual_size_out, fcc_sotp_type_e sotp_type); + + +// FIXME: The following should all be removed once SOTP APIs are implemented +#define MAX_SOTP_BUFFER_SIZE FCC_ENTROPY_SIZE + +typedef struct sotp_entree_ { + bool write_disabled; + uint8_t type; + int64_t data[MAX_SOTP_BUFFER_SIZE / 8]; + size_t data_size_in_bytes; +} sotp_entree_s; + +extern sotp_entree_s g_sotp_rot; +extern sotp_entree_s g_sotp_factory_disabled; +extern sotp_entree_s g_sotp_entropy; + +bool SOTP_Set(uint8_t type, uint8_t size, const int64_t *data); + + +/** Gets the soft OTP's info by the given owner and type. +* +* @param owner [in] The module owner. +* @param type [in] Type specific to the given owner +* @param revision_out [out] The revision number (none zero value) +* @param data_out [out] Array of int64 represents the data stored in the SOTP +* @param data_size_out [out] Size of data, must be in the range of 0-128 +* +* @returns +* status true/false. +*/ +bool SOTP_Get(uint8_t type, int64_t *data_out, uint8_t *data_size_out); + +// FIXME: remove this TestOnly function when SOTP will be implemented +// The storage_reset() should reset also the SOTP +void SOTP_TestOnly_reset(void); + +#ifdef __cplusplus +} +#endif + +#endif //__FCC_SOTP_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/include/fcc_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/include/fcc_utils.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,43 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_UTILS_H__ +#define __FCC_UTILS_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include "key_config_manager.h" +#include "factory_configurator_client.h" +#include "fcc_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Converts kcm error status to appropriate fcc error. +* +* @param kcm_result[in/out] The kcm error status +* @returns +* fcc_status_e status. +*/ +fcc_status_e fcc_convert_kcm_to_fcc_status(kcm_status_e kcm_result); + +#ifdef __cplusplus +} +#endif + +#endif //__FCC_UTILS_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/include/fcc_verification.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/factory-configurator-client/source/include/fcc_verification.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,122 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_VERIFICATION_H__ +#define __FCC_VERIFICATION_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include "key_config_manager.h" +#include "factory_configurator_client.h" +#include "fcc_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Types of configuration parameter +*/ +typedef enum fcc_config_param_type_ { + FCC_MANUFACTURER_NAME_CONFIG_PARAM_TYPE, + FCC_MODEL_NUMBER_CONFIG_PARAM_TYPE, + FCC_DEVICE_TYPE_CONFIG_PARAM_TYPE, + FCC_HARDWARE_VERSION_CONFIG_PARAM_TYPE, + FCC_MEMORY_TOTAL_SIZE_CONFIG_PARAM_TYPE, + FCC_DEVICE_SERIAL_NUMBER_CONFIG_PARAM_TYPE, + FCC_MAX_CONFIG_PARAM_TYPE +} fcc_config_param_type_e; + +/** +* Configuration parameters lookup record, correlating parameter's type and name +*/ +typedef struct fcc_config_param_lookup_record_ { + fcc_config_param_type_e config_param_type; + const char *config_param_name; +} fcc_config_param_lookup_record_s; + +/** +* Group lookup table, correlating for each group its type and name +*/ +static const fcc_config_param_lookup_record_s fcc_config_param_lookup_table[FCC_MAX_CONFIG_PARAM_TYPE] = { + { FCC_MANUFACTURER_NAME_CONFIG_PARAM_TYPE, g_fcc_manufacturer_parameter_name }, + { FCC_MODEL_NUMBER_CONFIG_PARAM_TYPE, g_fcc_model_number_parameter_name }, + { FCC_DEVICE_TYPE_CONFIG_PARAM_TYPE, g_fcc_device_type_parameter_name }, + { FCC_HARDWARE_VERSION_CONFIG_PARAM_TYPE, g_fcc_hardware_version_parameter_name }, + { FCC_MEMORY_TOTAL_SIZE_CONFIG_PARAM_TYPE, g_fcc_memory_size_parameter_name }, + { FCC_DEVICE_SERIAL_NUMBER_CONFIG_PARAM_TYPE, g_fcc_device_serial_number_parameter_name }, +}; + + +/** Checks entropy initialization +* +* @returns +* entropy status true/false. +*/ +bool fcc_is_entropy_initialized(void); + +/** Checks that all mandatory device meta data is present +* +* @returns +* fcc_status_e status. +*/ +fcc_status_e fcc_check_device_meta_data(void); + +/** Gets current bootstrap mode +* +* @param use_bootstrap[in/out] The bootstrap mode +* @returns +* fcc_status_e status. +*/ +fcc_status_e fcc_get_bootstrap_mode(bool *use_bootstrap); + +/**Function that checks all time synchronization parameters. +* +* @returns +* fcc_status_e status. +*/ +fcc_status_e fcc_check_time_synchronization(void); + +/** Checks mandatory device general info - endpoint name. Does not check bootstrap_mode (checked with fcc_get_bootstrap_mode()). +* +* @returns +* fcc_status_e status. +*/ +fcc_status_e fcc_check_device_general_info( void ); + +/** Checks device security objects : root ca certificate, device certificate, device private key and server URL. +* +* @param device_objects[in] Structure with set of device security object names. +* @param use_bootstrap[in] Bootstrap mode. +* @returns +* fcc_status_e status. +*/ +fcc_status_e fcc_check_device_security_objects(bool use_bootstrap); + + +/** Checks firmware update integrity objects +* +* @returns +* fcc_status_e status. +*/ +fcc_status_e fcc_check_firmware_update_integrity( void ); + +#ifdef __cplusplus +} +#endif + +#endif //__FCC_VERIFICATION_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/fcc-bundle-handler/fcc_bundle_handler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/fcc-bundle-handler/fcc_bundle_handler.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,110 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_BUNDLE_HANDLER_H__ +#define __FCC_BUNDLE_HANDLER_H__ + +#include <stdlib.h> +#include <inttypes.h> +#include "fcc_status.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @file fcc_bundle_handler.h +* \brief The fcc bundle handler APIs. +* This layer handles a device configuration bundle created by factory configurator utility (FCU). +*/ +/** +* Name of keys group. +*/ +#define FCC_KEY_GROUP_NAME "Keys" +/** +* Name of certificates group +*/ +#define FCC_CERTIFICATE_GROUP_NAME "Certificates" +/** +* Name of CSRs group. +*/ +#define FCC_CSR_GROUP_NAME "Csrs" +/** +* Name of configuration parameters group. +*/ +#define FCC_CONFIG_PARAM_GROUP_NAME "ConfigParams" +/** +* Name of certificate chain group. +*/ +#define FCC_CERTIFICATE_CHAIN_GROUP_NAME "CertificateChains" +/** +* Name of scheme version group. +*/ +#define FCC_BUNDLE_SCHEME_GROUP_NAME "SchemeVersion" +/** +* Name of Entropy group. +*/ +#define FCC_ENTROPY_NAME "Entropy" +/** +* Name of RoT group. +*/ +#define FCC_ROT_NAME "ROT" +/** +* Name of device verify readiness group. +*/ +#define FCC_VERIFY_DEVICE_IS_READY_GROUP_NAME "Verify" +/** +* Name of device verify readiness group. +*/ +#define FCC_FACTORY_DISABLE_GROUP_NAME "Disable" + +/** +* Name of error info group. +*/ +//Fixme : rename "infoMessage" to ErrorInfo" when Factory tool will be ready for the change +#define FCC_ERROR_INFO_GROUP_NAME "InfoMessage" +/** +* Name of return status group. +*/ +#define FCC_RETURN_STATUS_GROUP_NAME "ReturnStatus" +/** +* Name of warning info group. +*/ +#define FCC_WARNING_INFO_GROUP_NAME "WarningInfo" + +/** Decodes and processes an inbound device configuration bundle created by FCU. +* Also creates an outbound bundle that should be sent to FCU. +* The function assumes that the bundle includes four groups represented as cbor maps. +* The names of the groups are `SchemeVersion`, `Keys`, `Certificates` and `ConfigParams`. +* Each group contains a list of items, and for each item, there are a number of relevant parameters. +* +* @param encoded_bundle The encoded FCU bundle that is written into a secure storage. +* @param encoded_blob_size The encoded FCU bundle size in bytes. +* @param bundle_response_out The encoded outbound bundle. It may contain data such as CSR and different types of key schemes. +* The response associates a descriptive error in case of a fault. Will be NULL if response not created successfully. +* @param bundle_response_size_out The encoded outbound bundle size in bytes. +* +* @return +* FCC_STATUS_SUCCESS in case of success or one of the `::fcc_status_e` errors otherwise. +*/ +fcc_status_e fcc_bundle_handler(const uint8_t *encoded_bundle, size_t encoded_bundle_size, uint8_t **bundle_response_out, size_t *bundle_response_size_out); + + +#ifdef __cplusplus +} +#endif + +#endif //__FCC_BUNDLE_HANDLER_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_certificate_chain_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_certificate_chain_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,144 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "fcc_bundle_handler.h" +#include "cn-cbor.h" +#include "pv_error_handling.h" +#include "fcc_bundle_utils.h" +#include "key_config_manager.h" +#include "fcc_output_info_handler.h" +#include "fcc_malloc.h" +#include "fcc_time_profiling.h" + + +static bool get_certificate_suffix(char *suff, uint32_t index) +{ + char letters[26] = "abcdefghijklmnopqrstuvwxyz"; + + if (index > 25) + return false; + + *suff = letters[index]; + return true; +} +static bool add_suffix_to_name(const uint8_t *cert_name, size_t cert_name_len, const char *suff, uint8_t **buffer_out, size_t *buffer_size_allocated_out) +{ + size_t suff_length; + + + suff_length = 1; + + *buffer_out = (uint8_t *)fcc_malloc(cert_name_len + suff_length +1); + SA_PV_ERR_RECOVERABLE_RETURN_IF((*buffer_out == NULL), false, "Failed allocating buffer_out"); + + /* Append suffix and name to allocated buffer */ + memcpy(*buffer_out, (uint8_t *)cert_name, cert_name_len); + memcpy(*buffer_out + cert_name_len, (uint8_t *)suff, suff_length); + (*(*buffer_out+ cert_name_len + suff_length)) = '\0'; + *buffer_size_allocated_out = cert_name_len + suff_length + 1; + + return true; +} + +/** Processes certificate chain list. +* The function extracts data parameters for each certificate chain and stores it. +* +* @param cert_chains_list_cb[in] The cbor structure with certificate chain list. +* +* @return +* true for success, false otherwise. +*/ +fcc_status_e fcc_bundle_process_certificate_chains(const cn_cbor *cert_chains_list_cb) +{ + bool status = false; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + kcm_status_e kcm_result = KCM_STATUS_SUCCESS; + uint32_t cert_chain_index = 0; + uint32_t cert_index = 0; + cn_cbor *cert_chain_cb = NULL; + cn_cbor *cert_cb = NULL; + fcc_bundle_data_param_s certificate_chain; + uint8_t *certificate_data; + size_t certificate_data_size = 0; + char suff; + uint8_t *cert_complete_name = NULL; + size_t cert_complete_name_size; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert_chains_list_cb == NULL), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Invalid cert_chains_list_cb pointer"); + + //Initialize data struct + memset(&certificate_chain, 0, sizeof(fcc_bundle_data_param_s)); + + for (cert_chain_index = 0; cert_chain_index < (uint32_t)cert_chains_list_cb->length; cert_chain_index++) { + + FCC_SET_START_TIMER(fcc_certificate_chain_timer); + + certificate_data = NULL; + + fcc_bundle_clean_and_free_data_param(&certificate_chain); + + + //Get certificate chain CBOR struct at index cert_chain_index + cert_chain_cb = cn_cbor_index(cert_chains_list_cb, cert_chain_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert_chain_cb == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get certificate chain at index (%" PRIu32 ") ", cert_chain_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert_chain_cb->type != CN_CBOR_MAP), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Wrong type of certificate chain CBOR struct at index (%" PRIu32 ") ", cert_chain_index); + + status = fcc_bundle_get_data_param(cert_chain_cb, &certificate_chain); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != true), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get certificate chain data at index (%" PRIu32 ") ", cert_chain_index); + + //Get all certificates if certificate chain and store it + for (cert_index = 0; cert_index < (uint32_t)certificate_chain.array_cn->length ; cert_index++) { + + cert_cb = cn_cbor_index(certificate_chain.array_cn, (unsigned int)cert_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert_cb == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get cert cbor at index (%" PRIu32 ") ", cert_index); + + status = get_data_buffer_from_cbor(cert_cb, &certificate_data, &certificate_data_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false || certificate_data == NULL || certificate_data_size == 0), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get cert data at index (%" PRIu32 ") ", cert_index); + + status = get_certificate_suffix(&suff, cert_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get cert prefix at index (%" PRIu32 ") ", cert_index); + + status = add_suffix_to_name(certificate_chain.name, certificate_chain.name_len, &suff, &cert_complete_name, &cert_complete_name_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to set cert complete name at index (%" PRIu32 ") ", cert_index); + + kcm_result = kcm_item_store(cert_complete_name, cert_complete_name_size, KCM_CERTIFICATE_ITEM, true, certificate_data, certificate_data_size, certificate_chain.acl); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_result != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_KCM_ERROR, exit, "Failed to store certificate chain at index (%" PRIu32 ") ", cert_chain_index); + + FCC_END_TIMER((char*)cert_complete_name, cert_complete_name_size, fcc_certificate_chain_timer); + + fcc_free(cert_complete_name); + cert_complete_name_size = 0; + + + + } + } + +exit: + + if (kcm_result != KCM_STATUS_SUCCESS) { + fcc_free(cert_complete_name); + output_info_fcc_status = fcc_bundle_store_error_info(certificate_chain.name, certificate_chain.name_len, kcm_result); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output kcm_status error %d", kcm_result); + } + fcc_bundle_clean_and_free_data_param(&certificate_chain); + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_certificate_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_certificate_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,80 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "fcc_bundle_handler.h" +#include "cn-cbor.h" +#include "pv_error_handling.h" +#include "fcc_bundle_utils.h" +#include "key_config_manager.h" +#include "fcc_output_info_handler.h" +#include "fcc_time_profiling.h" + + +/** Processes certificate list. +* The function extracts data parameters for each certificate and stores it. +* +* @param certs_list_cb[in] The cbor structure with certificate list. +* +* @return +* true for success, false otherwise. +*/ +fcc_status_e fcc_bundle_process_certificates(const cn_cbor *certs_list_cb) +{ + bool status = false; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + kcm_status_e kcm_result = KCM_STATUS_SUCCESS; + uint32_t cert_index = 0; + cn_cbor *cert_cb; + fcc_bundle_data_param_s certificate; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((certs_list_cb == NULL), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Invalid certs_list_cb pointer"); + + //Initialize data struct + memset(&certificate, 0, sizeof(fcc_bundle_data_param_s)); + + for (cert_index = 0; cert_index < (uint32_t)certs_list_cb->length; cert_index++) { + + FCC_SET_START_TIMER(fcc_certificate_timer); + + fcc_bundle_clean_and_free_data_param(&certificate); + + //Get key CBOR struct at index key_index + cert_cb = cn_cbor_index(certs_list_cb, cert_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert_cb == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get certificate at index (%" PRIu32 ") ", cert_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cert_cb->type != CN_CBOR_MAP), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Wrong type of certificate CBOR struct at index (%" PRIu32 ") ", cert_index); + + status = fcc_bundle_get_data_param(cert_cb, &certificate); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != true), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get certificate data at index (%" PRIu32 ") ", cert_index); + + kcm_result = kcm_item_store(certificate.name, certificate.name_len, KCM_CERTIFICATE_ITEM, true, certificate.data, certificate.data_size, certificate.acl); + FCC_END_TIMER((char*)certificate.name, certificate.name_len,fcc_certificate_timer); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_result != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_KCM_ERROR, exit,"Failed to store certificate at index (%" PRIu32 ") ", cert_index); + + } + +exit: + if (kcm_result != KCM_STATUS_SUCCESS) { + output_info_fcc_status = fcc_bundle_store_error_info(certificate.name, certificate.name_len, kcm_result); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output kcm_status error %d", kcm_result); + } + fcc_bundle_clean_and_free_data_param(&certificate); + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_common_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_common_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,222 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "fcc_bundle_handler.h" +#include "cn-cbor.h" +#include "pv_error_handling.h" +#include "fcc_bundle_utils.h" +#include "fcc_malloc.h" +#include "general_utils.h" + +#define FCC_MAX_SIZE_OF_STRING 512 + +/** Gets name from cbor struct. +* +* @param text_cb[in] The cbor text structure +* @param name_out[out] The out buffer for string data +* @param name_len_out[out] The actual size of output buffer +* +* @return +* true for success, false otherwise. +*/ +static bool get_data_name(const cn_cbor *text_cb, uint8_t **name_out, size_t *name_len_out) +{ + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((text_cb == NULL), false, "Cbor pointer is NULL"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((name_out == NULL), false, "Invalid pointer for name"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((name_len_out == NULL), false, "Invalid pointer for name_len"); + + *name_out = (uint8_t*)fcc_malloc((size_t)(text_cb->length)); + SA_PV_ERR_RECOVERABLE_RETURN_IF((*name_out == NULL), false, "Failed to allocate buffer for name"); + + memcpy(*name_out, text_cb->v.bytes, (size_t)text_cb->length); + *name_len_out = (size_t)text_cb->length; + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return true; +} + +/** Gets data format from cbor struct +* +* The function goes over all formats and compares it with format from cbor structure. +* +* @param data_cb[in] The cbor text structure +* @param data_format[out] The format of data +* +* @return +* true for success, false otherwise. +*/ +static bool get_data_format(const cn_cbor *data_cb, fcc_bundle_data_format_e *data_format) +{ + + int data_format_index; + bool res; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((data_cb == NULL), false, "data_cb is null"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((data_format == NULL), false, "data_format is null"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((*data_format != FCC_INVALID_DATA_FORMAT), false, "wrong data format value"); + + for (data_format_index = 0; data_format_index < FCC_MAX_DATA_FORMAT -1; data_format_index++) { + res = is_memory_equal(fcc_bundle_data_format_lookup_table[data_format_index].data_format_name, + strlen(fcc_bundle_data_format_lookup_table[data_format_index].data_format_name), + data_cb->v.bytes, + data_cb->length); + if (res) { + *data_format = fcc_bundle_data_format_lookup_table[data_format_index].data_format_type; + return true; + } + } + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return false; +} + +bool get_data_buffer_from_cbor(const cn_cbor *data_cb, uint8_t **out_data_buffer, size_t *out_size) +{ + + cn_cbor_type cb_type; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((data_cb == NULL), false, "key_data_cb is null"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((out_size == NULL), false, "Size buffer is null "); + SA_PV_ERR_RECOVERABLE_RETURN_IF((out_data_buffer == NULL), false, "Data buffer is null"); + cb_type = data_cb->type; + + switch (cb_type) { + case CN_CBOR_TAG: + *out_data_buffer = (uint8_t*)data_cb->first_child->v.bytes; + *out_size = (size_t)data_cb->first_child->length; + break; + case CN_CBOR_TEXT: + case CN_CBOR_BYTES: + *out_data_buffer = (uint8_t*)data_cb->v.bytes; + *out_size = data_cb->length; + break; + case CN_CBOR_UINT: + *out_data_buffer = (uint8_t*)(&(data_cb->v.uint)); + *out_size = data_cb->length; + break; + case CN_CBOR_INT: + *out_data_buffer = (uint8_t*)(&(data_cb->v.sint)); + *out_size = data_cb->length; + break; + default: + SA_PV_LOG_ERR("Invalid cbor data type (%u)!", data_cb->type); + return false; + } + SA_PV_LOG_TRACE_FUNC_EXIT("out_size=%" PRIu32 "", (uint32_t)*out_size); + return true; +} +/** Frees all allocated memory of data parameter struct and sets initial values. +* +* @param data_param[in/out] The data parameter structure +*/ +void fcc_bundle_clean_and_free_data_param(fcc_bundle_data_param_s *data_param) +{ + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + if (data_param->name != NULL) { + fcc_free(data_param->name); + data_param->name = NULL; + } + + data_param->array_cn = NULL; + + //FIXME - in case we will support pem, add additional pointer data_der, that will point to allocated + // memory and will always released in case not NULL nad data pointer will relate to user buffer allways. + /*if (data_param->data_der != NULL) { + fcc_stats_free(data_param->data_der); + data_param->data_der = NULL; + }*/ + + memset(data_param, 0, sizeof(fcc_bundle_data_param_s)); + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + +} +bool fcc_bundle_get_data_param(const cn_cbor *data_param_cb, fcc_bundle_data_param_s *data_param) +{ + bool status = false; + int data_param_index = 0; + cn_cbor *data_param_value_cb; + fcc_bundle_data_param_type_e data_param_type; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + //Prepare key struct + fcc_bundle_clean_and_free_data_param(data_param); + + //Go over all key's parameters and extract it to appropriate key struct member + for (data_param_index = FCC_BUNDLE_DATA_PARAM_NAME_TYPE; data_param_index < FCC_BUNDLE_DATA_PARAM_MAX_TYPE; data_param_index++) { + + //Get value of parameter + data_param_value_cb = cn_cbor_mapget_string(data_param_cb, fcc_bundle_data_param_lookup_table[data_param_index].data_param_name); + + if (data_param_value_cb != NULL) { + //Get type of parameter + data_param_type = fcc_bundle_data_param_lookup_table[data_param_index].data_param_type; + + switch (data_param_type) { + + case FCC_BUNDLE_DATA_PARAM_NAME_TYPE: + status = get_data_name(data_param_value_cb, &(data_param->name), &(data_param->name_len)); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, error_exit, "Failed to get data parameter name"); + break; + + case FCC_BUNDLE_DATA_PARAM_SCHEME_TYPE: + status = fcc_bundle_get_key_type(data_param_value_cb, (fcc_bundle_key_type_e*)&(data_param->type)); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, error_exit, "Failed to get parameter type"); + break; + + case FCC_BUNDLE_DATA_PARAM_FORMAT_TYPE: + status = get_data_format(data_param_value_cb, (fcc_bundle_data_format_e*)&(data_param->format)); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, error_exit, "Failed to get key format"); + break; + + case FCC_BUNDLE_DATA_PARAM_DATA_TYPE: + status = get_data_buffer_from_cbor(data_param_value_cb, &(data_param->data), &(data_param->data_size)); + data_param->data_type = FCC_EXTERNAL_BUFFER_TYPE; + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, error_exit, "Failed to get parameter data"); + break; + case FCC_BUNDLE_DATA_PARAM_ARRAY_TYPE: + data_param->array_cn = data_param_value_cb; + break; + case FCC_BUNDLE_DATA_PARAM_ACL_TYPE: + status = get_data_buffer_from_cbor(data_param_value_cb, &(data_param->acl), &data_param->acl_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, error_exit, "Failed to get acl data"); + break; + default: + SA_PV_ERR_RECOVERABLE_GOTO_IF((true), status = false, error_exit, "Parameter's field name is illegal"); + }//switch + }//if + }//for + + //FIXME: should be uncommented if PEM format is supported. + /* + if (data_param->format == FCC_PEM_DATA_FORMAT) { + //status = convert_certificate_from_pem_to_der((uint8_t**)&(data_param->data), &(data_param->data_size)); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, error_exit, "Failed to convert the key from pem to der"); + //key->data_type = FCC_INTERNAL_BUFFER_TYPE; + } + */ + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return status; + +error_exit: + fcc_bundle_clean_and_free_data_param(data_param); + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return false; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_config_params_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_config_params_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,99 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "fcc_bundle_handler.h" +#include "cn-cbor.h" +#include "pv_error_handling.h" +#include "fcc_bundle_utils.h" +#include "key_config_manager.h" +#include "fcc_defs.h" +#include "fcc_output_info_handler.h" +#include "factory_configurator_client.h" +#include "general_utils.h" +#include "fcc_time_profiling.h" + +static fcc_status_e set_time_from_config_param(const fcc_bundle_data_param_s *current_time) +{ + fcc_status_e status; + uint64_t time = 0; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((current_time == NULL), FCC_STATUS_INVALID_PARAMETER, "Got invalid or corrupted 'current_time' pointer"); + + // Check given time length before copying + SA_PV_ERR_RECOVERABLE_RETURN_IF((current_time->data_size > sizeof(uint64_t)), FCC_STATUS_MEMORY_OUT, "Time length (%" PRIu32 "B) too long (corrupted format?)", (uint32_t)current_time->data_size); + memcpy(&time, current_time->data, current_time->data_size); + + status = fcc_secure_time_set(time); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != FCC_STATUS_SUCCESS), FCC_STATUS_ERROR, "fcc_secure_time_set failed"); + + return FCC_STATUS_SUCCESS; +} + +fcc_status_e fcc_bundle_process_config_params(const cn_cbor *config_params_list_cb) +{ + + bool success = false; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + kcm_status_e kcm_result = KCM_STATUS_SUCCESS; + uint32_t config_param_index = 0; + cn_cbor *config_param_cb; + fcc_bundle_data_param_s config_param; + int currentTimeLength = strlen(g_fcc_current_time_parameter_name); + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((config_params_list_cb == NULL), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Invalid config_params_list_cb pointer"); + + //Initialize data struct + memset(&config_param, 0, sizeof(config_param)); + + for (config_param_index = 0; config_param_index < (uint32_t)config_params_list_cb->length; config_param_index++) { + + FCC_SET_START_TIMER(fcc_config_param_timer); + + fcc_bundle_clean_and_free_data_param(&config_param); + + //Get key CBOR struct at index key_index + config_param_cb = cn_cbor_index(config_params_list_cb, config_param_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((config_param_cb == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get certificate at index (%" PRIu32 ") ", config_param_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((config_param_cb->type != CN_CBOR_MAP), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Wrong type of config param CBOR struct at index (%" PRIu32 ")", config_param_index); + + success = fcc_bundle_get_data_param(config_param_cb, &config_param); + SA_PV_ERR_RECOVERABLE_RETURN_IF((success != true), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get config param data at index (%" PRIu32 ") ", config_param_index); + + // Sets the time + if (is_memory_equal(config_param.name, config_param.name_len, g_fcc_current_time_parameter_name, currentTimeLength)) { + fcc_status = set_time_from_config_param(&config_param); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, exit, "set_time_from_config_param failed"); + } else { + kcm_result = kcm_item_store(config_param.name, config_param.name_len, KCM_CONFIG_ITEM, true, config_param.data, config_param.data_size, config_param.acl); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_result != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_KCM_ERROR, exit, "Failed to store configuration parameter at index (%" PRIu32 ") ", (uint32_t)config_param_index); + } + FCC_END_TIMER((char*)config_param.name, config_param.name_len, fcc_config_param_timer); + } + +exit: + if (kcm_result != KCM_STATUS_SUCCESS) { + output_info_fcc_status = fcc_bundle_store_error_info(config_param.name, config_param.name_len, kcm_result); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output kcm_status error %d", kcm_result); + } + fcc_bundle_clean_and_free_data_param(&config_param); + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return fcc_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_handler.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_handler.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,466 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- +#include "fcc_bundle_handler.h" +#include "cn-cbor.h" +#include "pv_error_handling.h" +#include "factory_configurator_client.h" +#include "fcc_bundle_utils.h" +#include "fcc_output_info_handler.h" +#include "fcc_malloc.h" +#include "fcc_sotp.h" +#include "general_utils.h" +#include "fcc_time_profiling.h" + +/** +* Defines for cbor layer +*/ +#ifdef USE_CBOR_CONTEXT +#define CONTEXT_NULL , NULL +#define CONTEXT_NULL_COMMA NULL, +#else +#define CONTEXT_NULL +#define CONTEXT_NULL_COMMA +#endif + +/** +* Definition of size and value of current protocol scheme version +*/ +#define FCC_SIZE_OF_VERSION_FIELD 5 +const char fcc_bundle_scheme_version[] = "0.0.1"; +/** +* Types of configuration parameter groups +*/ +typedef enum fcc_bundle_param_group_type_ { + FCC_KEY_GROUP_TYPE, //!< Key group type + FCC_CERTIFICATE_GROUP_TYPE, //!< Certificate group type + FCC_CSR_GROUP_TYPE, //!< CSR group type + FCC_CONFIG_PARAM_GROUP_TYPE, //!< Configuration parameter group type + FCC_CERTIFICATE_CHAIN_GROUP_TYPE, //!< Certificate chain group type + FCC_SCHEME_VERSION_TYPE, //!< Scheme version group type + FCC_ENTROPY_TYPE, //!< Entropy group type + FCC_ROT_TYPE, //!< Root of trust group type + FCC_VERIFY_DEVICE_IS_READY_TYPE, //!< Verify device readiness type + FCC_FACTORY_DISABLE_TYPE, //!< Disable FCC flow type + FCC_MAX_CONFIG_PARAM_GROUP_TYPE //!< Max group type +} fcc_bundle_param_group_type_e; +/** +* Group lookup record, correlating group's type and name +*/ +typedef struct fcc_bundle_group_lookup_record_ { + fcc_bundle_param_group_type_e group_type; + const char *group_name; +} fcc_bundle_group_lookup_record_s; +/** +* Group lookup table, correlating for each group its type and name. +* Order is important - it is the order that fcc_bundle_handler() reads the cbor fields. +* FCC_ENTROPY_TYPE and FCC_ROT_TYPE Must be processed first and second respectively. +*/ +static const fcc_bundle_group_lookup_record_s fcc_groups_lookup_table[FCC_MAX_CONFIG_PARAM_GROUP_TYPE] = { + { FCC_SCHEME_VERSION_TYPE, FCC_BUNDLE_SCHEME_GROUP_NAME }, + { FCC_ENTROPY_TYPE, FCC_ENTROPY_NAME }, + { FCC_ROT_TYPE, FCC_ROT_NAME }, + { FCC_KEY_GROUP_TYPE, FCC_KEY_GROUP_NAME }, + { FCC_CERTIFICATE_GROUP_TYPE, FCC_CERTIFICATE_GROUP_NAME }, + { FCC_CSR_GROUP_TYPE, FCC_CSR_GROUP_NAME }, + { FCC_CONFIG_PARAM_GROUP_TYPE, FCC_CONFIG_PARAM_GROUP_NAME }, + { FCC_CERTIFICATE_CHAIN_GROUP_TYPE, FCC_CERTIFICATE_CHAIN_GROUP_NAME }, + { FCC_VERIFY_DEVICE_IS_READY_TYPE, FCC_VERIFY_DEVICE_IS_READY_GROUP_NAME }, + { FCC_FACTORY_DISABLE_TYPE, FCC_FACTORY_DISABLE_GROUP_NAME }, +}; + +/** Prepare a response message +* +* The function prepare response buffer according to result of bundle buffer processing. +* In case of failure, the function prepare buffer with status,scheme version and error logs, +* in case of success - only the status and scheme version. +* +* @param bundle_response_out[in/out] The pointer to response buffer. +* @param bundle_response_size_out[out/out] The size of response buffer. +* @param fcc_status[in] The result of bundle buffer processing. +* @return +* true for success, false otherwise. +*/ +static bool prepare_reponse_message(uint8_t **bundle_response_out, size_t *bundle_response_size_out, fcc_status_e fcc_status) +{ + bool status = false; + cn_cbor_errback err; + cn_cbor *cb_map = NULL; + cn_cbor *cbor_struct_cb = NULL; + int size_of_cbor_buffer = 0; + int size_of_out_buffer = 0; + uint8_t *out_buffer = NULL; + char *error_string_info = NULL; + char *warning_string_info = NULL; + const char success_message[] = { "The Factory process succeeded\n" }; + *bundle_response_out = NULL; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + cb_map = cn_cbor_map_create(CONTEXT_NULL_COMMA &err); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cb_map == NULL), false, "Failed to create cbor map"); + + /** + * Create cbor with return status + */ + cbor_struct_cb = cn_cbor_int_create(fcc_status CONTEXT_NULL, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create return_status_cb "); + + //Put the cbor return status in cbor map with string key "ReturnStatus" + status = cn_cbor_mapput_string(cb_map, FCC_RETURN_STATUS_GROUP_NAME, cbor_struct_cb CONTEXT_NULL, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put return status to cbor map"); + + /** + * Create cbor with scheme version + */ + cbor_struct_cb = NULL; + cbor_struct_cb = cn_cbor_data_create((const uint8_t *)fcc_bundle_scheme_version,sizeof(fcc_bundle_scheme_version) CONTEXT_NULL, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create scheme_version_cb "); + + //Put the cbor return status in cbor map with string key "SchemeVersion" + status = cn_cbor_mapput_string(cb_map, FCC_BUNDLE_SCHEME_GROUP_NAME, cbor_struct_cb CONTEXT_NULL, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put return status to cbor map"); + + /** + * Create cbor with error info + */ + cbor_struct_cb = NULL; + if (fcc_status == FCC_STATUS_SUCCESS) { + cbor_struct_cb = cn_cbor_data_create((const uint8_t*)success_message, strlen(success_message) CONTEXT_NULL, &err); + } else { + error_string_info = fcc_get_output_error_info(); + if (error_string_info == NULL) { + cbor_struct_cb = cn_cbor_data_create((const uint8_t*)g_fcc_general_status_error_str, strlen(g_fcc_general_status_error_str) CONTEXT_NULL, &err); + } else { + cbor_struct_cb = cn_cbor_data_create((const uint8_t*)error_string_info, strlen(error_string_info) CONTEXT_NULL, &err); + } + } + SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create cbor_struct_cb "); + + //Put the cbor info message in cbor map with string key "infoMessage" + status = cn_cbor_mapput_string(cb_map, FCC_ERROR_INFO_GROUP_NAME, cbor_struct_cb CONTEXT_NULL, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put cbor_struct_cb to cbor map"); + + /** + * Create cbor with warning info + */ + cbor_struct_cb = NULL; + status = fcc_get_warning_status(); + warning_string_info = fcc_get_output_warning_info(); + SA_PV_ERR_RECOVERABLE_GOTO_IF(status == true && warning_string_info == NULL, status = false, exit, "Failed to get created warnings"); + if (warning_string_info != NULL) { + cbor_struct_cb = cn_cbor_data_create((const uint8_t *)warning_string_info, strlen(warning_string_info) CONTEXT_NULL, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((cbor_struct_cb == NULL), status = false, exit, "Failed to create warning_message_cb "); + + //Put the cbor info message in cbor map with string key "WarningInfo" + status = cn_cbor_mapput_string(cb_map, FCC_WARNING_INFO_GROUP_NAME, cbor_struct_cb CONTEXT_NULL, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), status = false, exit, "Failed top put warning_message_cb to cbor map"); + } + + status = true; + //Get size of encoded cbor buffer + size_of_cbor_buffer = cn_cbor_get_encoded_size(cb_map, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((size_of_cbor_buffer == -1), status = false, exit, "Failed to get cbor buffer size"); + + //Allocate out buffer + out_buffer = fcc_malloc(size_of_cbor_buffer); + SA_PV_ERR_RECOVERABLE_GOTO_IF((out_buffer == NULL), status = false, exit, "Failed to allocate memory for out buffer"); + + //Write cbor blob to output buffer + size_of_out_buffer = cn_cbor_encoder_write(cb_map, out_buffer, size_of_cbor_buffer, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((size_of_out_buffer == -1), status = false, exit_without_out_buffer, "Failed to write cbor buffer to output buffer"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((size_of_out_buffer != size_of_cbor_buffer), status = false, exit_without_out_buffer, "Wrong written size for outbut buffer"); + + //Update pointer and size of output buffer + *bundle_response_out = out_buffer; + *bundle_response_size_out = (size_t)size_of_out_buffer; + goto exit; + +exit_without_out_buffer: + fcc_free(out_buffer); + + // Nullify pointer so that the user cannot accidentally double free it. + *bundle_response_out = NULL; +exit: + fcc_free(warning_string_info); + if (cb_map != NULL) { + cn_cbor_free(cb_map CONTEXT_NULL); + } + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return status; +} + +/** Checks bundle scheme version +* +* @param cbor_blob[in] The pointer to main cbor blob. +* @return +* true for success, false otherwise. +*/ +static bool check_scheme_version(cn_cbor *cbor_blob) +{ + cn_cbor *scheme_version_cb = NULL; + int result; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_blob == NULL), false, "Invalid cbor_blob"); + + scheme_version_cb = cn_cbor_mapget_string(cbor_blob, FCC_BUNDLE_SCHEME_GROUP_NAME); + SA_PV_ERR_RECOVERABLE_RETURN_IF((scheme_version_cb == NULL), false, "Failed to find scheme version group"); + + result = is_memory_equal(scheme_version_cb->v.bytes, scheme_version_cb->length, fcc_bundle_scheme_version, strlen(fcc_bundle_scheme_version)); + SA_PV_ERR_RECOVERABLE_RETURN_IF((!result), false, "Wrong scheme version"); + + return true; +} + +/** Writes buffer to SOTP +* +* @param cbor_bytes[in] The pointer to a cn_cbor object of type CN_CBOR_BYTES. +* @param sotp_type[in] enum representing the type of the item to be stored in SOTP. +* @return +* true for success, false otherwise. +*/ + +static fcc_status_e fcc_bundle_process_sotp_buffer(cn_cbor *cbor_bytes, fcc_sotp_type_e sotp_type) +{ + uint8_t *buf; + size_t buf_size; + fcc_status_e fcc_status; + bool status; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_bytes->type != CN_CBOR_BYTES), FCC_STATUS_BUNDLE_ERROR, "cn_cbor object of incorrect type"); + + status = get_data_buffer_from_cbor(cbor_bytes, &buf, &buf_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status == false), FCC_STATUS_BUNDLE_ERROR, "Unable to retrieve data from cn_cbor"); + + fcc_status = fcc_sotp_data_store(buf, buf_size, sotp_type); + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +/** Checks the FCC_VERIFY_DEVICE_IS_READY_GROUP_NAME group value +* +* - if value is '0' - do NOT process device verification flow +* - if value is '1' - process device verification flow +* +* @param cbor_blob[in] The pointer to main CBOR blob. +* +* @return +* One of FCC_STATUS_* error codes +*/ +static fcc_status_e process_fcc_verify(const cn_cbor *cbor_blob) +{ + uint8_t *buff = NULL; + size_t buff_size; + uint32_t fcc_verify_value; + bool status; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_blob == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid param cbor_blob"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_blob->type != CN_CBOR_UINT), FCC_STATUS_SUCCESS, "Unexpected CBOR type"); + + status = get_data_buffer_from_cbor(cbor_blob, &buff, &buff_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((!status), FCC_STATUS_BUNDLE_ERROR, "Unable to retrieve data from cn_cbor"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((buff_size != sizeof(fcc_verify_value)), FCC_STATUS_BUNDLE_ERROR, "Incorrect buffer size for device disable"); + + memcpy(&fcc_verify_value, buff, buff_size); + + SA_PV_ERR_RECOVERABLE_RETURN_IF(((fcc_verify_value != 0) && (fcc_verify_value != 1)), FCC_STATUS_BUNDLE_ERROR, "Unexpected value, should be either 0 or 1"); + + if (fcc_verify_value == 1) { + return fcc_verify_device_configured_4mbed_cloud(); + } + + // Getting here means, VERIFY group exist but set off + return FCC_STATUS_SUCCESS; +} + + +/** Checks the FCC_FACTORY_DISABLE_GROUP_NAME group value +* +* - if value is '0' - do NOT process device disable flow +* - if value is '1' - process device disable flow +* +* @param cbor_blob[in] The pointer to main CBOR blob. +* +* @return +* One of FCC_STATUS_* error codes +*/ +static fcc_status_e process_fcc_disable(const cn_cbor *cbor_blob) +{ + uint8_t *buff = NULL; + size_t buff_size; + uint32_t fcc_disable_value; + bool status; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_blob == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid param cbor_blob"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((cbor_blob->type != CN_CBOR_UINT), FCC_STATUS_SUCCESS, "Unexpected CBOR type"); + + status = get_data_buffer_from_cbor(cbor_blob, &buff, &buff_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((!status), FCC_STATUS_BUNDLE_ERROR, "Unable to retrieve data from cn_cbor"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((buff_size != sizeof(fcc_disable_value)), FCC_STATUS_BUNDLE_ERROR, "Incorrect buffer size for device disable"); + + memcpy(&fcc_disable_value, buff, buff_size); + + SA_PV_ERR_RECOVERABLE_RETURN_IF(((fcc_disable_value != 0) && (fcc_disable_value != 1)), FCC_STATUS_BUNDLE_ERROR, "Unexpected value, should be either 0 or 1"); + + if (fcc_disable_value == 1) { + return fcc_factory_disable(); + } + + // Getting here means, DISABLE group exist but set off + return FCC_STATUS_SUCCESS; +} + +fcc_status_e fcc_bundle_handler(const uint8_t *encoded_blob, size_t encoded_blob_size, uint8_t **bundle_response_out, size_t *bundle_response_size_out) +{ + bool status = false; + bool is_fcc_factory_disabled; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + cn_cbor *main_list_cb = NULL; + cn_cbor *group_value_cb = NULL; + cn_cbor_errback err; + size_t group_index; + fcc_bundle_param_group_type_e group_type; + size_t num_of_groups_in_message = 0; + + // (false) group is 'N/A', hasn't been seen in the inbound CBOR blob) + // (true) group has been seen and processed in the given inbound CBOR blob + bool is_device_verify_group_exist = false; // mark as not exist (default value) + + // if true, device verify is redundant + bool device_is_already_disabled = false; + + FCC_SET_START_TIMER(fcc_bundle_timer); + + SA_PV_LOG_INFO_FUNC_ENTER("encoded_blob_size = %" PRIu32 "", (uint32_t)encoded_blob_size); + + // Check if factory flow is disabled, if yes, do not proceed + fcc_status = fcc_is_factory_disabled(&is_fcc_factory_disabled); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != FCC_STATUS_SUCCESS), fcc_status, "Failed for fcc_is_factory_disabled"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((is_fcc_factory_disabled), FCC_STATUS_FACTORY_DISABLED_ERROR, "FCC is disabled, service not available"); + + // Check params + SA_PV_ERR_RECOVERABLE_RETURN_IF((bundle_response_out == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid bundle_response_out"); + // Set to NULL so that the user does not accidentally free a non NULL pointer after the function returns. + *bundle_response_out = NULL; + + SA_PV_ERR_RECOVERABLE_RETURN_IF((bundle_response_size_out == NULL), FCC_STATUS_INVALID_PARAMETER, "Invalid bundle_response_size_out"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((encoded_blob == NULL), fcc_status = FCC_STATUS_INVALID_PARAMETER, exit, "Invalid encoded_blob"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((encoded_blob_size == 0), fcc_status = FCC_STATUS_INVALID_PARAMETER, exit, "Invalid encoded_blob_size"); + + /*Initialize fcc_output_info_s structure , in case of error during store process the + function will exit without fcc_verify_device_configured_4mbed_cloud where we perform additional fcc_clean_output_info_handler*/ + fcc_clean_output_info_handler(); + + /* Decode CBOR message + Check the size of the CBOR structure */ + main_list_cb = cn_cbor_decode(encoded_blob, encoded_blob_size CONTEXT_NULL, &err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((main_list_cb == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, exit, "cn_cbor_decode failed (%" PRIu32 ")", (uint32_t)err.err); + SA_PV_ERR_RECOVERABLE_GOTO_IF((main_list_cb->type != CN_CBOR_MAP), fcc_status = FCC_STATUS_BUNDLE_ERROR, free_cbor_list_and_out, "Wrong CBOR structure type"); + SA_PV_ERR_RECOVERABLE_GOTO_IF((main_list_cb->length <= 0 || main_list_cb->length > FCC_MAX_CONFIG_PARAM_GROUP_TYPE *FCC_CBOR_MAP_LENGTH), fcc_status = FCC_STATUS_BUNDLE_ERROR, free_cbor_list_and_out, "Wrong CBOR structure size"); + + /* Check scheme version*/ + status = check_scheme_version(main_list_cb); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != true), fcc_status = FCC_STATUS_BUNDLE_INVALID_SCHEME, free_cbor_list_and_out, "check_scheme_version failed"); + + //Go over parameter groups + for (group_index = 0; group_index < FCC_MAX_CONFIG_PARAM_GROUP_TYPE; group_index++) { + //Get content of current group (value of map, when key of map is name of group and value is list of params of current group) + SA_PV_LOG_INFO(" fcc_groups_lookup_table[group_index].group_name is %s", fcc_groups_lookup_table[group_index].group_name); + group_value_cb = cn_cbor_mapget_string(main_list_cb, fcc_groups_lookup_table[group_index].group_name); + + if (group_value_cb != NULL) { + //Get type of group + group_type = fcc_groups_lookup_table[group_index].group_type; + num_of_groups_in_message++; + + switch (group_type) { + case FCC_SCHEME_VERSION_TYPE: + break; + case FCC_KEY_GROUP_TYPE: + FCC_SET_START_TIMER(fcc_gen_timer); + fcc_status = fcc_bundle_process_keys(group_value_cb); + FCC_END_TIMER("Total keys process", 0 ,fcc_gen_timer); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_keys failed"); + break; + case FCC_CERTIFICATE_GROUP_TYPE: + FCC_SET_START_TIMER(fcc_gen_timer); + fcc_status = fcc_bundle_process_certificates(group_value_cb); + FCC_END_TIMER("Total certificates process", 0, fcc_gen_timer); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_certificates failed"); + break; + case FCC_CONFIG_PARAM_GROUP_TYPE: + FCC_SET_START_TIMER(fcc_gen_timer); + fcc_status = fcc_bundle_process_config_params(group_value_cb); + FCC_END_TIMER("Total config params process", 0, fcc_gen_timer); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_config_params failed"); + break; + case FCC_CERTIFICATE_CHAIN_GROUP_TYPE: + FCC_SET_START_TIMER(fcc_gen_timer); + fcc_status = fcc_bundle_process_certificate_chains(group_value_cb); + FCC_END_TIMER("Total certificate chains process", 0, fcc_gen_timer); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_certificate_chains failed"); + break; + case FCC_ENTROPY_TYPE: // Entropy for random generator + fcc_status = fcc_bundle_process_sotp_buffer(group_value_cb, FCC_SOTP_TYPE_ENTROPY); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_sotp_buffer failed for entropy"); + break; + case FCC_ROT_TYPE: // Key for ESFS + fcc_status = fcc_bundle_process_sotp_buffer(group_value_cb, FCC_SOTP_TYPE_ROT); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_bundle_process_sotp_buffer failed for ROT"); + break; + case FCC_VERIFY_DEVICE_IS_READY_TYPE: + is_device_verify_group_exist = true; + fcc_status = process_fcc_verify(group_value_cb); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "process_device_verify failed"); + break; + case FCC_FACTORY_DISABLE_TYPE: + device_is_already_disabled = true; + fcc_status = process_fcc_disable(group_value_cb); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_factory_disable failed"); + break; + default: + fcc_status = FCC_STATUS_BUNDLE_UNSUPPORTED_GROUP; + SA_PV_LOG_ERR("Wrong group type"); + goto free_cbor_list_and_out; + } + } + } + + SA_PV_ERR_RECOVERABLE_GOTO_IF((num_of_groups_in_message == 0), fcc_status = FCC_STATUS_INVALID_PARAMETER, free_cbor_list_and_out, "No groups in message"); + SA_PV_ERR_RECOVERABLE_GOTO_IF(((size_t)(main_list_cb->length/FCC_CBOR_MAP_LENGTH)!= num_of_groups_in_message), fcc_status = FCC_STATUS_BUNDLE_INVALID_GROUP, free_cbor_list_and_out, "One ore more names of groups are invalid"); + + if (!is_device_verify_group_exist && !device_is_already_disabled) { + // device VERIFY group does NOT exist in the CBOR message and device is NOT disabled. + // Perform device verification to keep backward compatibility. + FCC_SET_START_TIMER(fcc_gen_timer); + fcc_status = fcc_verify_device_configured_4mbed_cloud(); + FCC_END_TIMER("Total verify device", 0, fcc_gen_timer); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = fcc_status, free_cbor_list_and_out, "fcc_verify_device_configured_4mbed_cloud failed"); + } + +free_cbor_list_and_out: + cn_cbor_free(main_list_cb CONTEXT_NULL); + +exit: + //Prepare bundle response message + status = prepare_reponse_message(bundle_response_out, bundle_response_size_out, fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != true), FCC_STATUS_BUNDLE_RESPONSE_ERROR, "Failed to prepare out response"); + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + FCC_END_TIMER("Total fcc_bundle_handler device", 0, fcc_bundle_timer); + return fcc_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_key_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/fcc_bundle_key_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,162 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "fcc_bundle_handler.h" +#include "cn-cbor.h" +#include "pv_error_handling.h" +#include "fcc_bundle_utils.h" +#include "key_config_manager.h" +#include "fcc_output_info_handler.h" +#include "general_utils.h" +#include "fcc_time_profiling.h" + +#define FCC_MAX_PEM_KEY_SIZE 1024*2 +/** +* Names of key types +*/ +#define FCC_ECC_PRIVATE_KEY_TYPE_NAME "ECCPrivate" +#define FCC_ECC_PUBLIC_KEY_TYPE_NAME "ECCPublic" +#define FCC_RSA_PRIVATE_KEY_TYPE_NAME "RSAPrivate" +#define FCC_RSA_PUBLIC_KEY_TYPE_NAME "RSAPublic" +#define FCC_SYMMETRIC_KEY_TYPE_NAME "Symmetric" +/** +* Group lookup record, correlating group's type and name +*/ +typedef struct fcc_bundle_key_type_lookup_record_ { + fcc_bundle_key_type_e key_type; + const char *key_type_name; +} fcc_bundle_key_type_lookup_record_s; +/** +* Group lookup table, correlating for each group its type and name +*/ +static const fcc_bundle_key_type_lookup_record_s fcc_bundle_key_type_lookup_table[FCC_MAX_KEY_TYPE] = { + { FCC_ECC_PRIVATE_KEY_TYPE, FCC_ECC_PRIVATE_KEY_TYPE_NAME }, + { FCC_ECC_PUBLIC_KEY_TYPE, FCC_ECC_PUBLIC_KEY_TYPE_NAME }, + { FCC_RSA_PRIVATE_KEY_TYPE, FCC_RSA_PRIVATE_KEY_TYPE_NAME }, + { FCC_RSA_PUBLIC_KEY_TYPE, FCC_RSA_PUBLIC_KEY_TYPE_NAME }, + { FCC_SYM_KEY_TYPE, FCC_SYMMETRIC_KEY_TYPE_NAME } +}; +/** Gets type of key form cbor structure +* +* The function goes over all key types and compares it with type inside cbor structure. +* +* @param key_type_cb[in] The cbor structure with key type data. +* @param key_type[out] The key type +* +* @return +* true for success, false otherwise. +*/ +bool fcc_bundle_get_key_type(const cn_cbor *key_type_cb, fcc_bundle_key_type_e *key_type) +{ + + int key_type_index; + bool res; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((key_type_cb == NULL), false, "key_type_cb is null"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((key_type == NULL), false, "key_type is null"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((*key_type != FCC_INVALID_KEY_TYPE), false, "wrong key type value"); + + for (key_type_index = 0; key_type_index < FCC_MAX_KEY_TYPE -1; key_type_index++) { + res = is_memory_equal(fcc_bundle_key_type_lookup_table[key_type_index].key_type_name, + strlen(fcc_bundle_key_type_lookup_table[key_type_index].key_type_name), + key_type_cb->v.bytes, + (size_t)key_type_cb->length); + if (res) { + *key_type = fcc_bundle_key_type_lookup_table[key_type_index].key_type; + return true; + } + } + SA_PV_LOG_TRACE_FUNC_EXIT("key_type is %d", (int)(*key_type)); + return false; + +} + +/** Processes keys list. +* The function extracts data parameters for each key and stores its according to it type. +* +* @param keys_list_cb[in] The cbor structure with keys list. +* +* @return +* true for success, false otherwise. +*/ +fcc_status_e fcc_bundle_process_keys(const cn_cbor *keys_list_cb) +{ + + bool status = false; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_status_e output_info_fcc_status = FCC_STATUS_SUCCESS; + kcm_status_e kcm_result = KCM_STATUS_SUCCESS; + uint32_t key_index = 0; + cn_cbor *key_cb; + fcc_bundle_data_param_s key; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((keys_list_cb == NULL), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Invalid keys_list_cb pointer"); + + //Initialize data struct + memset(&key,0,sizeof(fcc_bundle_data_param_s)); + + for (key_index = 0; key_index < (uint32_t)keys_list_cb->length; key_index++) { + + FCC_SET_START_TIMER(fcc_key_timer); + + fcc_bundle_clean_and_free_data_param(&key); + + //Get key CBOR struct at index key_index + key_cb = cn_cbor_index(keys_list_cb, key_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((key_cb == NULL), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get key at index (%" PRIu32 ") ", key_index); + SA_PV_ERR_RECOVERABLE_RETURN_IF((key_cb->type != CN_CBOR_MAP), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Wrong type of key CBOR struct at index (%" PRIu32 ")", key_index); + + status = fcc_bundle_get_data_param(key_cb, &key); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != true), fcc_status = FCC_STATUS_BUNDLE_ERROR, "Failed to get key data at index (%" PRIu32 ") ", key_index); + + switch (key.type) { + case FCC_ECC_PRIVATE_KEY_TYPE: + case FCC_RSA_PRIVATE_KEY_TYPE: + kcm_result = kcm_item_store(key.name, key.name_len, KCM_PRIVATE_KEY_ITEM, true, key.data, key.data_size, key.acl); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_result != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_KCM_ERROR, exit, "Failed to store key private at index (%" PRIu32 ") ", key_index); + break; + + case FCC_ECC_PUBLIC_KEY_TYPE: + case FCC_RSA_PUBLIC_KEY_TYPE: + kcm_result = kcm_item_store(key.name, key.name_len, KCM_PUBLIC_KEY_ITEM, true, key.data, key.data_size, key.acl); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_result != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_KCM_ERROR, exit, "Failed to store key public at index (%" PRIu32 ") ", key_index); + break; + + case (FCC_SYM_KEY_TYPE): + kcm_result = kcm_item_store(key.name, key.name_len, KCM_SYMMETRIC_KEY_ITEM, true, key.data, key.data_size, key.acl); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_result != KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_KCM_ERROR, exit, "Failed to store symmetric key at index (%" PRIu32 ") ", key_index); + break; + default: + SA_PV_LOG_ERR("Invalid key type (%u)!", key.type); + goto exit; + } + FCC_END_TIMER((char*)key.name, key.name_len, fcc_key_timer); + } + +exit: + if (kcm_result != KCM_STATUS_SUCCESS) { + output_info_fcc_status = fcc_bundle_store_error_info(key.name, key.name_len, kcm_result); + SA_PV_ERR_RECOVERABLE_RETURN_IF((output_info_fcc_status != FCC_STATUS_SUCCESS), + fcc_status = FCC_STATUS_OUTPUT_INFO_ERROR, + "Failed to create output kcm_status error %d", kcm_result); + } + fcc_bundle_clean_and_free_data_param(&key); + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/include/fcc_bundle_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-bundle-handler/source/include/fcc_bundle_utils.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,233 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_BUNDLE_UTILS_H__ +#define __FCC_BUNDLE_UTILS_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> + +#include "fcc_status.h" +#include "key_config_manager.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FCC_CBOR_MAP_LENGTH 2 + +/** +* Names of key parameters +*/ +#define FCC_BUNDLE_DATA_PARAMETER_NAME "Name" +#define FCC_BUNDLE_DATA_PARAMETER_SCHEME "Type" +#define FCC_BUNDLE_DATA_PARAMETER_FORMAT "Format" +#define FCC_BUNDLE_DATA_PARAMETER_DATA "Data" +#define FCC_BUNDLE_DATA_PARAMETER_ACL "ACL" +#define FCC_BUNDLE_DATA_PARAMETER_ARRAY "DataArray" + +/** +* Types of key parameters +*/ +typedef enum fcc_bundle_data_param_type_ { + FCC_BUNDLE_DATA_PARAM_NAME_TYPE, + FCC_BUNDLE_DATA_PARAM_SCHEME_TYPE, + FCC_BUNDLE_DATA_PARAM_FORMAT_TYPE, + FCC_BUNDLE_DATA_PARAM_DATA_TYPE, + FCC_BUNDLE_DATA_PARAM_ACL_TYPE, + FCC_BUNDLE_DATA_PARAM_ARRAY_TYPE, + FCC_BUNDLE_DATA_PARAM_MAX_TYPE +} fcc_bundle_data_param_type_e; + +/** +* Key lookup record, correlating key's param type and name +*/ +typedef struct fcc_bundle_data_param_lookup_record_ { + fcc_bundle_data_param_type_e data_param_type; + const char *data_param_name; +} fcc_bundle_data_param_lookup_record_s; + +/** +* Key lookup table, correlating for each key its param type and param name +*/ +static const fcc_bundle_data_param_lookup_record_s fcc_bundle_data_param_lookup_table[FCC_BUNDLE_DATA_PARAM_MAX_TYPE] = { + { FCC_BUNDLE_DATA_PARAM_NAME_TYPE, FCC_BUNDLE_DATA_PARAMETER_NAME }, + { FCC_BUNDLE_DATA_PARAM_SCHEME_TYPE, FCC_BUNDLE_DATA_PARAMETER_SCHEME }, + { FCC_BUNDLE_DATA_PARAM_FORMAT_TYPE, FCC_BUNDLE_DATA_PARAMETER_FORMAT }, + { FCC_BUNDLE_DATA_PARAM_DATA_TYPE, FCC_BUNDLE_DATA_PARAMETER_DATA }, + { FCC_BUNDLE_DATA_PARAM_ACL_TYPE, FCC_BUNDLE_DATA_PARAMETER_ACL }, + { FCC_BUNDLE_DATA_PARAM_ARRAY_TYPE, FCC_BUNDLE_DATA_PARAMETER_ARRAY } +}; + +/** +* Source type of buffer +*/ +typedef enum fcc_bundle_buffer_type_ { + FCC_EXTERNAL_BUFFER_TYPE, + FCC_INTERNAL_BUFFER_TYPE, + FCC_MAX_BUFFER_TYPE +} fcc_bundle_buffer_type_e; + +/** +* Data formats supported by FC +*/ +typedef enum fcc_bundle_data_format_ { + FCC_INVALID_DATA_FORMAT, + FCC_DER_DATA_FORMAT, + FCC_PEM_DATA_FORMAT, + FCC_MAX_DATA_FORMAT +} fcc_bundle_data_format_e; + +/** +* Names of data formats +*/ +#define FCC_BUNDLE_DER_DATA_FORMAT_NAME "der" +#define FCC_BUNDLE_PEM_DATA_FORMAT_NAME "pem" + +/** +* Group lookup record, correlating group's type and name +*/ +typedef struct fcc_bundle_data_format_lookup_record_ { + fcc_bundle_data_format_e data_format_type; + const char *data_format_name; +} fcc_bundle_data_format_lookup_record_s; + +/** +* Group lookup table, correlating for each group its type and name +*/ +static const fcc_bundle_data_format_lookup_record_s fcc_bundle_data_format_lookup_table[FCC_MAX_DATA_FORMAT] = { + { FCC_DER_DATA_FORMAT, FCC_BUNDLE_DER_DATA_FORMAT_NAME }, + { FCC_PEM_DATA_FORMAT, FCC_BUNDLE_PEM_DATA_FORMAT_NAME }, +}; + +/** +* Key types supported by FC +*/ +typedef enum fcc_bundle_key_type_ { + FCC_INVALID_KEY_TYPE, + FCC_ECC_PRIVATE_KEY_TYPE,//do not change this type's place.FCC_ECC_PRIVATE_KEY_TYPE should be at first place. + FCC_ECC_PUBLIC_KEY_TYPE, + FCC_RSA_PRIVATE_KEY_TYPE, + FCC_RSA_PUBLIC_KEY_TYPE, + FCC_SYM_KEY_TYPE, + FCC_MAX_KEY_TYPE +} fcc_bundle_key_type_e; + +typedef struct fcc_bundle_data_param_ { + uint8_t *name; + size_t name_len; + fcc_bundle_data_format_e format; + fcc_bundle_key_type_e type; + uint8_t *data; + size_t data_size; + uint8_t *data_der; + size_t data_der_size; + fcc_bundle_buffer_type_e data_type; + uint8_t *acl; + size_t acl_size; + cn_cbor *array_cn; +} fcc_bundle_data_param_s; + + +/** Frees all allocated memory of data parameter struct and sets initial values. +* +* @param data_param[in/out] The data parameter structure +*/ +void fcc_bundle_clean_and_free_data_param(fcc_bundle_data_param_s *data_param); + +/** Gets data buffer from cbor struct. +* +* @param data_cb[in] The cbor text structure +* @param out_data_buffer[out] The out buffer for string data +* @param out_size[out] The actual size of output buffer +* +* @return +* true for success, false otherwise. +*/ +bool get_data_buffer_from_cbor(const cn_cbor *data_cb, uint8_t **out_data_buffer, size_t *out_size); + +/** Processes keys list. +* The function extracts data parameters for each key and stores its according to it type. +* +* @param keys_list_cb[in] The cbor structure with keys list. +* +* @return +* fcc_status_e status. +*/ +fcc_status_e fcc_bundle_process_keys(const cn_cbor *keys_list_cb); + +/** Processes certificate list. +* The function extracts data parameters for each certificate and stores it. +* +* @param certs_list_cb[in] The cbor structure with certificate list. +* +* @return +* fcc_status_e status. +*/ +fcc_status_e fcc_bundle_process_certificates(const cn_cbor *certs_list_cb); +/** Processes certificate chain list. +* The function extracts data parameters for each certificate chain and stores it. +* +* @param certs_list_cb[in] The cbor structure with certificate chain list. +* +* @return +* fcc_status_e status. +*/ +fcc_status_e fcc_bundle_process_certificate_chains(const cn_cbor *cert_chains_list_cb); + +/** Processes configuration parameters list. +* The function extracts data parameters for each config param and stores it. +* +* @param config_params_list_cb[in] The cbor structure with config param list. +* +* @return +* fcc_status_e status. +*/ +fcc_status_e fcc_bundle_process_config_params(const cn_cbor *config_params_list_cb); + +/** Gets data parameters. +* +* The function goes over all existing parameters (name,type,format,data,acl and etc) and +* tries to find correlating parameter in cbor structure and saves it to data parameter structure. +* +* @param data_param_cb[in] The cbor structure with relevant data parameters. +* @param data_param[out] The data parameter structure +* +* @return +* true for success, false otherwise. +*/ +bool fcc_bundle_get_data_param(const cn_cbor *data_param_list_cb, fcc_bundle_data_param_s *data_param); + +/** Gets type of key form cbor structure +* +* The function goes over all key types and compares it with type inside cbor structure. +* +* @param key_type_cb[in] The cbor structure with key type data. +* @param key_type[out] The key type +* +* @return +* true for success, false otherwise. +*/ +bool fcc_bundle_get_key_type(const cn_cbor *key_type_cb, fcc_bundle_key_type_e *key_type); + + + +#ifdef __cplusplus +} +#endif + +#endif //__FCC_BUNDLE_UTILS_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-output-info-handler/fcc-output-info-handler/fcc_output_info_handler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-output-info-handler/fcc-output-info-handler/fcc_output_info_handler.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,124 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_OUTPUT_INFO_HANDLER_H__ +#define __FCC_OUTPUT_INFO_HANDLER_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include "kcm_status.h" +#include "fcc_output_info_handler_defines.h" +#include "fcc_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Initializes resources of output info handler +*/ +void fcc_init_output_info_handler( void ); + +/** +* Finalizes resources of output info handler +*/ +void fcc_clean_output_info_handler( void ); + +/** +* Returns true if FCC was initialized false otherwise +*/ +bool is_fcc_initialized(void); + +/** The function stores the name of failed item and kcm error string in global variables +* The error returned by fcc_bundle_handler API. +* +* @param failed_item_name[in] The name of failed item +* @param failed_item_name_size[in] The size of failed item name. +* @param kcm_status[in] The kcm status value. +* +* @return +* true for success, false otherwise. +*/ +fcc_status_e fcc_bundle_store_error_info(const uint8_t *failed_item_name, size_t failed_item_name_size, kcm_status_e kcm_status); + +/** The function stores the name of failed item and fcc error string in global variables +*The error returned by fcc_verify_device_configured_4mbed_cloud API. + +* @param failed_item_name[in] The name of failed item +* @param failed_item_name_size[in] The size of failed item name. +* @param fcc_status[in] The fcc status value. +* +* @return +* true for success, false otherwise. +*/ +fcc_status_e fcc_store_error_info(const uint8_t *failed_item_name, size_t failed_item_name_size, fcc_status_e fcc_status); + +/** The function stores the all collected warnings and relevant item names during fcc_verify_device_configured_4mbed_cloud API. +* +* @param failed_item_name[in] The name of failed item +* @param failed_item_name_size[in] The size of failed item name. +* @param fcc_status[in] The fcc status value. +* +* @return +* true for success, false otherwise. +*/ +fcc_status_e fcc_store_warning_info(const uint8_t *failed_item_name, size_t failed_item_name_size, const char *warning_string); +/** The function return saved failed item name +* +* @return +* NULL if no errors or char* pointer to the saved item name +*/ +char* fcc_get_output_error_info( void ); +/** The function return saved warnings as single string +* +* @return +* NULL if no warnings exist or char* pointer to the string of all warnings +*/ +char* fcc_get_output_warning_info(void); + +/** The function returns relevant pointer to string of passed fcc_status. +* +* @return +* string /NULL in case the fcc_status string wasn't found +*/ +char* fcc_get_fcc_error_string(fcc_status_e fcc_status); + +/** The function returns relevant pointer to string of passed kcm_status. +* +* @return +* string /NULL in case the kcm_status string wasn't found +*/ +char* fcc_get_kcm_error_string(kcm_status_e kcm_status); + +/** The function gets output info structure +* +* @return +*/ +fcc_output_info_s* get_output_info(void); + +/** The function gets status of warning info +* +* @return +* true - if warnings were stored, false in case of no warning +*/ +bool fcc_get_warning_status(void); + +#ifdef __cplusplus +} +#endif + +#endif //__FCC_OUTPUT_INFO_HANDLER_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-output-info-handler/fcc-output-info-handler/fcc_output_info_handler_defines.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-output-info-handler/fcc-output-info-handler/fcc_output_info_handler_defines.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,85 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_OUTPUT_INFO_HANDLER_DEFINES_H__ +#define __FCC_OUTPUT_INFO_HANDLER_DEFINES_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include "kcm_status.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//General error string +extern const char g_fcc_general_status_error_str[]; + +//fcc error strings +extern const char g_fcc_entropy_error_str[]; +extern const char g_fcc_disabled_error_str[]; +extern const char g_fcc_invalid_certificate_error_str[]; +extern const char g_fcc_item_not_exists_error_str[]; +extern const char g_fcc_wrong_item_size_error_str[]; +extern const char g_fcc_empty_item_error_str[]; +extern const char g_fcc_uri_wrong_format_error_str[]; +extern const char g_fcc_first_to_claim_not_allowed_error_str[]; +extern const char g_fcc_wrong_utc_offset_value_error_str[]; +extern const char g_fcc_wrong_ca_certificate_error_str[]; +extern const char g_fcc_invalid_cn_certificate_error_str[]; +extern const char g_fcc_crypto_public_key_correlation_error_str[]; + +//kcm crypto error strings +extern const char g_fcc_kcm_file_exist_error_str[]; +extern const char g_fcc_crypto_empty_item_error_str[]; +extern const char g_fcc_crypto_unsupported_hash_mode_error_str[]; +extern const char g_fcc_crypto_parsing_der_pivate_key_error_str[]; +extern const char g_fcc_crypto_parsing_der_public_key_error_str[]; +extern const char g_fcc_crypto_verify_private_key_error_str[]; +extern const char g_fcc_crypto_verify_public_key_error_str[]; +extern const char g_fcc_crypto_unsupported_curve_error_str[]; +extern const char g_fcc_crypto_parsing_der_cert_error_str[]; +extern const char g_fcc_crypto_cert_expired_error_str[]; +extern const char g_fcc_crypto_cert_future_error_str[]; +extern const char g_fcc_crypto_cert_md_alg_error_str[]; +extern const char g_fcc_crypto_cert_public_key_type_error_str[]; +extern const char g_fcc_crypto_cert_public_key_error_str[]; +extern const char g_fcc_crypto_cert_not_trusted_error_str[]; +extern const char g_fcc_crypto_invalid_x509_attr_error_str[]; +extern const char g_fcc_wrong_bootstrap_use_value_error_str[]; +extern const char g_fcc_crypto_invalid_pk_key_format_error_str[]; +extern const char g_fcc_crypto_invalid_public_key_error_str[]; +extern const char g_fcc_crypto_ecp_invalid_key_error_str[]; +extern const char g_fcc_crypto_pk_key_invalid_version_error_str[]; +extern const char g_fcc_crypto_pk_password_requerd_error_str[]; +extern const char g_fcc_crypto_unknown_pk_algorithm_error_str[]; + +//warning strings +extern const char g_fcc_item_not_set_warning_str[]; +extern const char g_fcc_bootstrap_mode_false_warning_str[]; +extern const char g_fcc_time_is_not_set_warning_str[]; +extern const char g_fcc_self_signed_warning_str[]; +extern const char g_fcc_item_is_empty_warning_str[]; +extern const char g_fcc_redundant_item_warning_str[]; +extern const char g_fcc_cert_time_validity_warning_str[]; +extern const char g_fcc_cert_validity_less_10_years_warning_str[]; + +#ifdef __cplusplus +} +#endif + +#endif //__FCC_OUTPUT_INFO_HANDLER_DEFINES_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-output-info-handler/source/fcc_output_info_handler.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/fcc-output-info-handler/source/fcc_output_info_handler.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,550 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <stdlib.h> +#include "pv_error_handling.h" +#include "fcc_status.h" +#include "fcc_output_info_handler.h" +#include "fcc_malloc.h" + + +//General error string +const char g_fcc_general_status_error_str[] = "General error:"; + +//fcc error strings +const char g_fcc_entropy_error_str[] = "Entropy error:"; +const char g_fcc_disabled_error_str[] = "Factory disabled error:"; +const char g_fcc_invalid_certificate_error_str[] = "Certificate invalid:"; +const char g_fcc_item_not_exists_error_str[] = "Item does not exist:"; +const char g_fcc_wrong_item_size_error_str[] = "Item size is wrong:"; +const char g_fcc_empty_item_error_str[] = "Item empty:"; +const char g_fcc_uri_wrong_format_error_str[] = "URI format incorrect:"; +const char g_fcc_first_to_claim_not_allowed_error_str[] = "first to claim not allowed:"; +const char g_fcc_wrong_utc_offset_value_error_str[] = "UTC offset incorrect:"; +const char g_fcc_wrong_bootstrap_use_value_error_str[] = "Bootstrap mode value incorrect:"; +const char g_fcc_not_permitted_error_str[] = "Operation not permitted:"; +const char g_fcc_wrong_ca_certificate_error_str[] = "Validation of CA certificate failed:"; +const char g_fcc_invalid_cn_certificate_error_str[] = "Certificate CN attribute invalid:"; +const char g_fcc_crypto_public_key_correlation_error_str[] = "Certificate public key validation failed:"; + +//kcm crypto error strings +const char g_fcc_kcm_file_error_str[] = "File operation general error:"; +const char g_fcc_kcm_invalid_file_version_str[] = "File version invalid:"; +const char g_fcc_kcm_file_data_corrupted_str[] = "File data corrupted:"; +const char g_fcc_kcm_file_name_corrupted_str[] = "File name corrupted:"; +const char g_fcc_kcm_not_initialized_str[] = "KCM not initialized:"; +const char g_fcc_kcm_file_exist_error_str[] = "Data already exists:"; +const char g_fcc_crypto_empty_item_error_str[] = "Item data empty:"; +const char g_fcc_crypto_unsupported_hash_mode_error_str[] = "Hash mode unsupported:"; +const char g_fcc_crypto_parsing_der_pivate_key_error_str[] = "Private key parse failed:"; +const char g_fcc_crypto_parsing_der_public_key_error_str[] = "Public key parse failed:"; +const char g_fcc_crypto_verify_private_key_error_str[] = "Private key verification failed:"; +const char g_fcc_crypto_verify_public_key_error_str[] = "Public key verification failed:"; +const char g_fcc_crypto_unsupported_curve_error_str[] = "Curve unsupported:"; +const char g_fcc_crypto_parsing_der_cert_error_str[] = "Certificate parse failed:"; +const char g_fcc_crypto_cert_expired_error_str[] = "Certificate expired:"; +const char g_fcc_crypto_cert_future_error_str[] = "Certificate will be valid in the future:"; +const char g_fcc_crypto_cert_md_alg_error_str[] = "Certificate MD algorithm error:"; +const char g_fcc_crypto_cert_public_key_type_error_str[] = "Certificate public key type error:"; +const char g_fcc_crypto_cert_public_key_error_str[] = "Certificate public key error:"; +const char g_fcc_crypto_cert_not_trusted_error_str[] = "Certificate not trusted:"; +const char g_fcc_crypto_invalid_x509_attr_error_str[] = "X509 attribute invalid:"; +const char g_fcc_crypto_invalid_pk_key_format_error_str[] = "Public key format invalid:"; +const char g_fcc_crypto_invalid_public_key_error_str[] = "Public key invalid:"; +const char g_fcc_crypto_ecp_invalid_key_error_str[] = "EC key invalid:"; +const char g_fcc_crypto_pk_key_invalid_version_error_str[] = "Public key version invalid:"; +const char g_fcc_crypto_pk_password_requerd_error_str[] = "Public key password required:"; +const char g_fcc_crypto_unknown_pk_algorithm_error_str[] = "Public key algorithm unknown:"; + +//warning strings +const char g_fcc_item_not_set_warning_str[] = "Item not set:"; + +const char g_fcc_bootstrap_mode_false_warning_str[] = "Bootstrap mode not activated:"; +const char g_fcc_self_signed_warning_str[] = "Certificate is self signed:"; +const char g_fcc_item_is_empty_warning_str[] = "Item empty:"; +const char g_fcc_redundant_item_warning_str[] = "Item redundant:"; +const char g_fcc_cert_time_validity_warning_str[] = "Certificate validity cannot be checked:"; +const char g_fcc_cert_validity_less_10_years_warning_str[] = "Certificate validity is less than 10 years:"; + +fcc_output_info_s g_output_info; + + +/** The function frees all allocated buffers +* @param output_warning_info[in] The pointer to created fcc_warning_info_s structure +*/ +static void fcc_free_list_of_warnings(fcc_warning_info_s *output_warning_info) +{ + fcc_warning_info_s *current_node = output_warning_info; + fcc_warning_info_s *next_node = output_warning_info->next; + + while (current_node != NULL) { + if (current_node->warning_info_string != NULL) { + fcc_free(current_node->warning_info_string); + } + fcc_free(current_node); + current_node = next_node; + if (current_node != NULL) { + next_node = current_node->next; + } + } +} +/** The function combines message string info and failed item, and sets it to passed pointer. +* @param message_string[in] The message string - error or warning +* @param failed_item_name[in] The name of item. +* @param failed_item_name_size[in] The size of item's name. +* @param out_string[in/out] The output string where the combined message should be copied. +*/ +static fcc_status_e fcc_set_output_string_info(const char *message_string, const uint8_t *failed_item_name, size_t failed_item_name_size, char **out_string) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + //Allocate memory for error info + *out_string = fcc_malloc(strlen(message_string) + failed_item_name_size + 1); // 1 char for '\0' + SA_PV_ERR_RECOVERABLE_RETURN_IF((out_string == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, "Failed to allocate buffer for output info"); + + //Copy to the global structure error string info + strcpy((*out_string), message_string); + + //Copy to the global structure the name of failed item if it exists. + if (failed_item_name != NULL) { + memcpy((uint8_t*)(*out_string) + strlen(message_string), failed_item_name, failed_item_name_size); + //Set '\0' in the end of error string info + (*out_string)[strlen(message_string) + failed_item_name_size] = '\0'; + } + + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +static size_t fcc_get_size_of_all_warning_strings() +{ + fcc_warning_info_s *current_node = g_output_info.head_of_warning_list; + size_t size_of_all_warning_strings = 0; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + while (current_node != NULL) { + size_of_all_warning_strings += strlen(current_node->warning_info_string); + current_node = current_node->next; + } + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return size_of_all_warning_strings; +} + +static bool copy_all_warning_to_buffer(char *out_warning_string, size_t size_of_out_warning_string) +{ + fcc_warning_info_s *current_node = g_output_info.head_of_warning_list; + size_t length_of_iterated_strings = 0; + + memset(out_warning_string, 0, size_of_out_warning_string); + + while (current_node != NULL) { + //Calculate size of current warning + if (length_of_iterated_strings + strlen(current_node->warning_info_string) + 1 > size_of_out_warning_string) { + return false; + } + strcpy(out_warning_string + length_of_iterated_strings, current_node->warning_info_string); + //Set '\n' in the end of warning string info + (out_warning_string)[length_of_iterated_strings + strlen(current_node->warning_info_string)] = '\n'; + length_of_iterated_strings += strlen(current_node->warning_info_string) + 1; + current_node = current_node->next; + } + //Increase the size for '\0' + if (length_of_iterated_strings >= size_of_out_warning_string) { + return false; + } + (out_warning_string)[length_of_iterated_strings] = '\0'; + + return true; +} +/** The function returns error string according to passed fcc_status. +* @param fcc_status[in] The fcc_status +* +*/ +char* fcc_get_fcc_error_string(fcc_status_e fcc_status) +{ + SA_PV_LOG_TRACE_FUNC_ENTER("fcc_status is %d", fcc_status); + char *fcc_error_string = NULL; + + switch (fcc_status) { + case FCC_STATUS_ERROR: + case FCC_STATUS_MEMORY_OUT: + case FCC_STATUS_INVALID_PARAMETER: + case FCC_STATUS_KCM_ERROR: + case FCC_STATUS_BUNDLE_ERROR: + case FCC_STATUS_BUNDLE_RESPONSE_ERROR: + case FCC_STATUS_BUNDLE_UNSUPPORTED_GROUP: + case FCC_STATUS_BUNDLE_INVALID_SCHEME: + case FCC_STATUS_BUNDLE_INVALID_GROUP: + case FCC_STATUS_KCM_STORAGE_ERROR: + case FCC_STATUS_KCM_FILE_EXIST_ERROR: + case FCC_STATUS_KCM_CRYPTO_ERROR: + case FCC_STATUS_NOT_INITIALIZED: + case FCC_STATUS_OUTPUT_INFO_ERROR: + case FCC_STATUS_WARNING_CREATE_ERROR: + case FCC_STATUS_INVALID_CERT_ATTRIBUTE: + fcc_error_string = (char*)g_fcc_general_status_error_str; + break; + case FCC_STATUS_INVALID_CERTIFICATE: + fcc_error_string = (char*)g_fcc_invalid_certificate_error_str; + break; + case FCC_STATUS_INVALID_LWM2M_CN_ATTR: + fcc_error_string = (char*)g_fcc_invalid_cn_certificate_error_str; + break; + case FCC_STATUS_ENTROPY_ERROR: + fcc_error_string = (char*)g_fcc_entropy_error_str; + break; + case FCC_STATUS_FACTORY_DISABLED_ERROR: + fcc_error_string = (char*)g_fcc_disabled_error_str; + break; + case FCC_STATUS_ITEM_NOT_EXIST: + fcc_error_string = (char*)g_fcc_item_not_exists_error_str; + break; + case FCC_STATUS_WRONG_ITEM_DATA_SIZE: + fcc_error_string = (char*)g_fcc_wrong_item_size_error_str; + break; + case FCC_STATUS_EMPTY_ITEM: + fcc_error_string = (char*)g_fcc_empty_item_error_str; + break; + case FCC_STATUS_URI_WRONG_FORMAT: + fcc_error_string = (char*)g_fcc_uri_wrong_format_error_str; + break; + case FCC_STATUS_FIRST_TO_CLAIM_NOT_ALLOWED: + fcc_error_string = (char*)g_fcc_first_to_claim_not_allowed_error_str; + break; + case FCC_STATUS_BOOTSTRAP_MODE_ERROR: + fcc_error_string = (char*)g_fcc_wrong_bootstrap_use_value_error_str; + break; + case FCC_STATUS_UTC_OFFSET_WRONG_FORMAT: + fcc_error_string = (char*)g_fcc_wrong_utc_offset_value_error_str; + break; + case FCC_STATUS_INVALID_CA_CERT_SIGNATURE: + fcc_error_string = (char*)g_fcc_wrong_ca_certificate_error_str; + break; + case FCC_STATUS_EXPIRED_CERTIFICATE: + fcc_error_string = (char*)g_fcc_crypto_cert_expired_error_str; + break; + case FCC_STATUS_CERTIFICATE_PUBLIC_KEY_CORRELATION_ERROR: + fcc_error_string = (char*)g_fcc_crypto_public_key_correlation_error_str; + break; + default: + fcc_error_string = (char*)NULL; + break; + } + SA_PV_LOG_TRACE_FUNC_EXIT("fcc_error_string is %s", fcc_error_string); + return fcc_error_string; +} + +/** The function returns error string according to passed kcm_status. +* @param kcm_status[in] The kcm_status +* +*/ + +char* fcc_get_kcm_error_string(kcm_status_e kcm_status) +{ + SA_PV_LOG_TRACE_FUNC_ENTER("kcm_status is %d", kcm_status); + + char *kcm_error_string = NULL; + + switch (kcm_status) { + case KCM_STATUS_ERROR: + case KCM_STATUS_INVALID_PARAMETER: + case KCM_STATUS_INSUFFICIENT_BUFFER: + case KCM_STATUS_OUT_OF_MEMORY: + case KCM_STATUS_INVALID_FILE_ACCESS_MODE: + case KCM_STATUS_UNKNOWN_STORAGE_ERROR: + case KCM_CRYPTO_STATUS_INVALID_MD_TYPE: + case KCM_CRYPTO_STATUS_FAILED_TO_WRITE_SIGNATURE: + case KCM_CRYPTO_STATUS_VERIFY_SIGNATURE_FAILED: + kcm_error_string = (char*)g_fcc_general_status_error_str; + break; + case KCM_STATUS_STORAGE_ERROR: + kcm_error_string = (char*)g_fcc_kcm_file_error_str; + break; + case KCM_STATUS_INVALID_FILE_VERSION: + kcm_error_string = (char*)g_fcc_kcm_invalid_file_version_str; + break; + case KCM_STATUS_FILE_CORRUPTED: + kcm_error_string = (char*)g_fcc_kcm_file_data_corrupted_str; + break; + case KCM_STATUS_NOT_INITIALIZED: + kcm_error_string = (char*)g_fcc_kcm_not_initialized_str; + break; + case KCM_STATUS_ITEM_NOT_FOUND: + kcm_error_string = (char*)g_fcc_item_not_exists_error_str; + break; + case KCM_STATUS_NOT_PERMITTED: + kcm_error_string = (char*)g_fcc_not_permitted_error_str; + break; + case KCM_STATUS_FILE_EXIST: + kcm_error_string = (char*)g_fcc_kcm_file_exist_error_str; + break; + case KCM_STATUS_FILE_NAME_CORRUPTED: + kcm_error_string = (char*)g_fcc_kcm_file_name_corrupted_str; + break; + case KCM_STATUS_ITEM_IS_EMPTY: + kcm_error_string = (char*)g_fcc_crypto_empty_item_error_str; + break; + case KCM_CRYPTO_STATUS_UNSUPPORTED_HASH_MODE: + kcm_error_string = (char*)g_fcc_crypto_unsupported_hash_mode_error_str; + break; + case KCM_CRYPTO_STATUS_PARSING_DER_PRIVATE_KEY: + kcm_error_string = (char*)g_fcc_crypto_parsing_der_pivate_key_error_str; + break; + case KCM_CRYPTO_STATUS_PARSING_DER_PUBLIC_KEY: + kcm_error_string = (char*)g_fcc_crypto_parsing_der_public_key_error_str; + break; + case KCM_CRYPTO_STATUS_PRIVATE_KEY_VERIFICATION_FAILED: + kcm_error_string = (char*)g_fcc_crypto_verify_private_key_error_str; + break; + case KCM_CRYPTO_STATUS_PUBLIC_KEY_VERIFICATION_FAILED: + kcm_error_string = (char*)g_fcc_crypto_verify_public_key_error_str; + break; + case KCM_CRYPTO_STATUS_UNSUPPORTED_CURVE: + kcm_error_string = (char*)g_fcc_crypto_unsupported_curve_error_str; + break; + case KCM_CRYPTO_STATUS_PARSING_DER_CERT: + kcm_error_string = (char*)g_fcc_crypto_parsing_der_cert_error_str; + break; + case KCM_CRYPTO_STATUS_CERT_EXPIRED: + kcm_error_string = (char*)g_fcc_crypto_cert_expired_error_str; + break; + case KCM_CRYPTO_STATUS_CERT_FUTURE: + kcm_error_string = (char*)g_fcc_crypto_cert_future_error_str; + break; + case KCM_CRYPTO_STATUS_CERT_MD_ALG: + kcm_error_string = (char*)g_fcc_crypto_cert_md_alg_error_str; + break; + case KCM_CRYPTO_STATUS_CERT_PUB_KEY_TYPE: + kcm_error_string = (char*)g_fcc_crypto_cert_public_key_type_error_str; + break; + case KCM_CRYPTO_STATUS_CERT_PUB_KEY: + kcm_error_string = (char*)g_fcc_crypto_cert_public_key_error_str; + break; + case KCM_CRYPTO_STATUS_CERT_NOT_TRUSTED: + kcm_error_string = (char*)g_fcc_crypto_cert_not_trusted_error_str; + break; + case KCM_CRYPTO_STATUS_INVALID_X509_ATTR: + kcm_error_string = (char*)g_fcc_crypto_invalid_x509_attr_error_str; + break; + case KCM_CRYPTO_STATUS_PK_KEY_INVALID_FORMAT: + kcm_error_string = (char*)g_fcc_crypto_invalid_pk_key_format_error_str; + break; + case KCM_CRYPTO_STATUS_INVALID_PK_PUBKEY: + kcm_error_string = (char*)g_fcc_crypto_invalid_public_key_error_str; + break; + case KCM_CRYPTO_STATUS_ECP_INVALID_KEY: + kcm_error_string = (char*)g_fcc_crypto_ecp_invalid_key_error_str; + break; + case KCM_CRYPTO_STATUS_PK_KEY_INVALID_VERSION: + kcm_error_string = (char*)g_fcc_crypto_pk_key_invalid_version_error_str; + break; + case KCM_CRYPTO_STATUS_PK_PASSWORD_REQUIRED: + kcm_error_string = (char*)g_fcc_crypto_pk_password_requerd_error_str; + break; + case KCM_CRYPTO_STATUS_PK_UNKNOWN_PK_ALG: + kcm_error_string = (char*)g_fcc_crypto_unknown_pk_algorithm_error_str; + break; + default: + kcm_error_string = (char*)NULL; + break; + } + + SA_PV_LOG_TRACE_FUNC_EXIT("kcm_error_string is %s", kcm_error_string); + return kcm_error_string; +} + +fcc_output_info_s* get_output_info(void) +{ + return &g_output_info; +} + +void fcc_init_output_info_handler() +{ + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + g_output_info.error_string_info = NULL; + g_output_info.head_of_warning_list = NULL; + g_output_info.tail_of_warning_list = NULL; + g_output_info.size_of_warning_info_list = 0; + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); +} + +void fcc_clean_output_info_handler() +{ + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + fcc_free(g_output_info.error_string_info); + g_output_info.error_string_info = NULL; + + if (g_output_info.head_of_warning_list != NULL) { + fcc_free_list_of_warnings(g_output_info.head_of_warning_list); + } + g_output_info.size_of_warning_info_list = 0; + g_output_info.tail_of_warning_list = NULL; + g_output_info.head_of_warning_list = NULL; + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); +} + +fcc_status_e fcc_store_warning_info(const uint8_t *failed_item_name, size_t failed_item_name_size, const char *warning_string) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + fcc_warning_info_s *new_node = NULL; + + SA_PV_LOG_INFO_FUNC_ENTER("warning_string is %s", warning_string); + //Check parameters (failed_item_name can be NULL) + SA_PV_ERR_RECOVERABLE_RETURN_IF((failed_item_name != NULL && failed_item_name_size == 0), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Wrong failed item name parameters"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((warning_string == NULL), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Warning string is empty"); + + //Allocate new node + new_node = (fcc_warning_info_s*)fcc_malloc(sizeof(fcc_warning_info_s)); + SA_PV_ERR_RECOVERABLE_RETURN_IF((new_node == NULL), fcc_status = FCC_STATUS_MEMORY_OUT, "Failed to allocate memory for new warning list"); + + //Set the new node with warning info (message and item name) + fcc_status = fcc_set_output_string_info(warning_string, failed_item_name, failed_item_name_size, &(new_node->warning_info_string)); + SA_PV_ERR_RECOVERABLE_GOTO_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = FCC_STATUS_ERROR, exit_with_error, "Failed to set warning string info\n"); + + //Update the list + if (g_output_info.head_of_warning_list == NULL) { + //In case this is the first node + g_output_info.head_of_warning_list = g_output_info.tail_of_warning_list = new_node; + } else { + //In case this is an additional node + g_output_info.tail_of_warning_list->next = new_node; + g_output_info.tail_of_warning_list = new_node; + } + g_output_info.tail_of_warning_list->next = NULL; + g_output_info.size_of_warning_info_list++; + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return fcc_status; + +exit_with_error: + fcc_free(new_node); + return fcc_status; +} + +fcc_status_e fcc_bundle_store_error_info(const uint8_t *failed_item_name, size_t failed_item_name_size, kcm_status_e kcm_status) +{ + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + char *error_string_info = NULL; + + SA_PV_LOG_INFO_FUNC_ENTER("kcm_status is %d", kcm_status); + + //Check parameters (failed_item_name can be NULL) + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status == KCM_STATUS_SUCCESS), fcc_status = FCC_STATUS_INVALID_PARAMETER, "The fcc_bundle_store_error_info should not be called with success status"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((failed_item_name != NULL && failed_item_name_size == 0 ), fcc_status = FCC_STATUS_INVALID_PARAMETER, "Wrong failed item name parameters"); + + //Get kcm error string + error_string_info = fcc_get_kcm_error_string(kcm_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((error_string_info == NULL), fcc_status = FCC_STATUS_ERROR, "Failed to get kcm error string"); + + //Store kcm error string with item name + fcc_status = fcc_set_output_string_info(error_string_info, failed_item_name, failed_item_name_size, &(g_output_info.error_string_info)); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status != FCC_STATUS_SUCCESS), fcc_status = FCC_STATUS_ERROR, "Failed to set error string info "); + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return fcc_status; +} + +fcc_status_e fcc_store_error_info(const uint8_t *failed_item_name, size_t failed_item_name_size, fcc_status_e fcc_status) +{ + fcc_status_e fcc_result = FCC_STATUS_SUCCESS; + char *error_string_info = NULL; + + SA_PV_LOG_INFO_FUNC_ENTER("fcc_status is %d", fcc_status); + //Check parameters (failed_item_name can be NULL) + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_status == FCC_STATUS_SUCCESS), FCC_STATUS_INVALID_PARAMETER, "The fcc_store_error_info should not be called with success status"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((failed_item_name != NULL && failed_item_name_size == 0), FCC_STATUS_INVALID_PARAMETER, "Wrong failed item name parameters"); + + //Get fcc error string + error_string_info = fcc_get_fcc_error_string(fcc_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((error_string_info == NULL), FCC_STATUS_ERROR, "Failed to get fcc error string"); + + if (g_output_info.error_string_info == NULL) { + //Store fcc error string with item name + fcc_result = fcc_set_output_string_info(error_string_info, failed_item_name, failed_item_name_size, &(g_output_info.error_string_info)); + SA_PV_ERR_RECOVERABLE_RETURN_IF((fcc_result != FCC_STATUS_SUCCESS), FCC_STATUS_ERROR, "Failed to set error string info "); + } + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return fcc_result; +} + +char* fcc_get_output_error_info() +{ + char *error_info = NULL; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + if (g_output_info.error_string_info != NULL) { + error_info = g_output_info.error_string_info; + } + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return error_info; +} + + +char* fcc_get_output_warning_info() +{ + char *warrning_string_collection = NULL; + size_t size_of_warning_string_collection = 0; + size_t total_size_of_strings_with_delimeters = 0; + bool status = false; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + if (g_output_info.head_of_warning_list == NULL || g_output_info.size_of_warning_info_list == 0) { + return NULL; + } else { + //Get size of all warning + size_of_warning_string_collection = fcc_get_size_of_all_warning_strings(); + + //total_size_of_strings_with_delimeters -size_of_warning_string_collection +add '\n' - as delimiter between the warnings and '\0' in the end + total_size_of_strings_with_delimeters = size_of_warning_string_collection + g_output_info.size_of_warning_info_list + 1; + + //Allocate memory buffer for all warnings + warrning_string_collection = fcc_malloc(total_size_of_strings_with_delimeters); + if (warrning_string_collection == NULL) { + SA_PV_LOG_INFO("Failed to allocate memory for warning strings"); + return warrning_string_collection; + } + status = copy_all_warning_to_buffer(warrning_string_collection, total_size_of_strings_with_delimeters); + if (status != true) { + fcc_free(warrning_string_collection); + return NULL; + } + } + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return warrning_string_collection; +} + +bool fcc_get_warning_status() +{ + if (g_output_info.head_of_warning_list != NULL) { + return true; + } else { + return false; + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-base/ftcd-comm-base/ftcd_comm_base.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-base/ftcd-comm-base/ftcd_comm_base.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,160 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FTCD_COMM_BASE_H__ +#define __FTCD_COMM_BASE_H__ + +#include <stdint.h> + +/** +* @file ftcd_comm_base.h +* +* Token [64bit] : The message identifier. +* Status [32 bit] : Status of message parameters (exists in response messages only) +* Length [32bit] : The blob length in bytes. +* Blob [Length] : A FT message to be processed by protocol handler. +* Signature [32B] : The hash (SHA256) value of the Blob. +*/ + + +/** Unique message identifier +*/ +#define FTCD_MSG_HEADER_TOKEN { 0x6d, 0x62, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x76 } +#define FTCD_MSG_HEADER_TOKEN_SIZE_BYTES 8 + + + + +typedef enum ftcd_comm_status_ { + FTCD_COMM_STATUS_SUCCESS, + FTCD_COMM_STATUS_ERROR, //generic error + FTCD_COMM_INVALID_TOKEN, + FTCD_COMM_FAILED_TO_READ_MESSAGE_SIZE, + FTCD_COMM_FAILED_TO_READ_MESSAGE_BYTES, + FTCD_COMM_FAILED_TO_READ_MESSAGE_SIGNATURE, + FTCD_COMM_FAILED_TO_CALCULATE_MESSAGE_SIGNATURE, + FTCD_COMM_INCONSISTENT_MESSAGE_SIGNATURE, + FTCD_COMM_FAILED_TO_PROCESS_DATA, + FTCD_COMM_FAILED_TO_PROCESS_MESSAGE, + FTCD_COMM_FAILED_TO_SEND_VALID_RESPONSE, + + FTCD_COMM_NETWORK_TIMEOUT, //socket timeout error + FTCD_COMM_NETWORK_CONNECTION_ERROR, //socket error + FTCD_COMM_INTERNAL_ERROR, + + FTCD_COMM_STATUS_MAX_ERROR = 0xFFFFFFFF +} ftcd_comm_status_e; + + +/** +* \brief ::FtcdCommBase implements the logic of processing incoming requests from the remote Factory Tool Demo. +*/ +class FtcdCommBase +{ +public: + + /** Not certain that we need to do anything here, but just in case we need + * to do some clean-up at some point. + */ + virtual ~FtcdCommBase() = 0; + + /** + * Initializes Network interface and opens socket + * Prints IP address + */ + virtual bool init(void); + + /** + * Closes the opened socket + */ + virtual void finish(void); + + + /** Reads an inbound factory message from the communication line medium. + * This function will generate an outbound message with a corresponding response. + * - The inbound message will be ignored if not factory message compliant + * - function may block until a valid message received + * + * @returns + * true upon success, false otherwise + */ + bool process_message(void); + + /** Writes a response message to the communication line medium. + * + * @param response_message The message to send through the communication line medium + * @param encoded_message_size The message size in bytes + * + * @returns + * true upon success, false otherwise + */ + virtual bool send(const uint8_t *response_message, uint32_t response_message_size) = 0; + + /** Detects the message token from the communication line medium. + * + * @returns + * zero, if token detected and different value otherwise + */ + virtual ftcd_comm_status_e is_token_detected(void) = 0; + + /** Reads the message size in bytes from the communication line medium. + * This is the amount of bytes needed to allocate for the upcoming message bytes. + * + * @returns + * The message size in bytes in case of success, zero bytes otherwise. + */ + virtual uint32_t read_message_size(void) = 0; + + /** Reads the message size in bytes from the communication line medium. + * This is the amount of bytes needed to allocate for the upcoming message bytes. + * + * @param message_out The buffer to read into and return to the caller. + * @param message_size The message size in bytes. + * + * @returns + * true upon success, false otherwise + */ + virtual bool read_message(uint8_t *message_out, size_t message_size) = 0; + + /** Reads the message size in bytes from the communication line medium. + * This is the amount of bytes needed to allocate for the upcoming message bytes. + * + * @param sig The buffer to read into and return to the caller. + * @param sig_size The sig buffer size in bytes. + * + * @returns + * The message size in bytes in case of success, zero bytes otherwise. + */ + virtual bool read_message_signature(uint8_t *sig, size_t sig_size) = 0; + +private: + + /** Creates and sends a Factory Message response (in this format - [TOKEN | STATUS | LENGTH | FT-MESSAGE | SIGNATURE]). + * This function gets a FT-MESSAGE, allocates the required amount of bytes and constructs the Factory + * response message accordingly, it sends the message to the remote Factory tool via the given communication line medium. + * + * @param cbor_reponse The CBOR response message. + * @param protocol_response_size The protocol response message size in bytes. + * @param status_code The status of the response message + * + * @returns + * true upon success, false otherwise. + */ + bool _create_and_send_response(const uint8_t *protocol_reponse, uint32_t protocol_response_size, ftcd_comm_status_e status_code); + +}; + +#endif // __FTCD_COMM_BASE_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-base/source/ftcd_comm_base.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-base/source/ftcd_comm_base.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,232 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <stdlib.h> +#include <string.h> +#include "pv_endian.h" +#include "pv_log.h" +#include "ftcd_comm_base.h" +#include "fcc_bundle_handler.h" +#include "cs_hash.h" +#include "fcc_status.h" +#include "fcc_malloc.h" + +#define TRACE_GROUP "fcbs" + +FtcdCommBase::~FtcdCommBase() +{ +} + + +bool FtcdCommBase::init() +{ + return true; +} + +void FtcdCommBase::finish() +{ +} + + +bool FtcdCommBase::process_message() +{ + bool success = false; + ftcd_comm_status_e status_code; + fcc_status_e fcc_status = FCC_STATUS_SUCCESS; + uint8_t *response_protocol_message; + size_t response_protocol_message_size; + + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Factory flow begins...\r"); + +#ifdef TEST_SERIAL_MULTI_MESSAGE + while (true) { +#endif + response_protocol_message = NULL; + response_protocol_message_size = 0; + + do { + //detect token + status_code = is_token_detected(); + if (status_code == FTCD_COMM_NETWORK_TIMEOUT) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Network timeout occurred\r"); + return false; + } else if (status_code == FTCD_COMM_NETWORK_CONNECTION_ERROR) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Network connection error occurred\r"); + return false; + } + + // Read message LENGTH + uint32_t message_size = read_message_size(); + message_size = pv_le32_to_h(message_size); + if (message_size == 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Unable to read message size (got ZERO)\r"); + status_code = FTCD_COMM_FAILED_TO_READ_MESSAGE_SIZE; + break; + } + + //read message + uint8_t *message = (uint8_t *)fcc_malloc(message_size); + success = read_message(message, message_size); + if (!success) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed getting message bytes\r"); + status_code = FTCD_COMM_FAILED_TO_READ_MESSAGE_BYTES; + fcc_free(message); + break; + } + + //read message signature + uint8_t sig_from_message[CS_SHA256_SIZE]; + success = read_message_signature(sig_from_message, sizeof(sig_from_message)); + if (!success) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed getting signature bytes\r"); + status_code = FTCD_COMM_FAILED_TO_READ_MESSAGE_SIGNATURE; + fcc_free(message); + break; + } + + //calculate message signature + uint8_t self_calculated_sig[CS_SHA256_SIZE]; + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + kcm_status = cs_hash(CS_SHA256,message, message_size, self_calculated_sig, sizeof(self_calculated_sig)); + if (kcm_status != KCM_STATUS_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed calculating message signature\r"); + status_code = FTCD_COMM_FAILED_TO_CALCULATE_MESSAGE_SIGNATURE; + fcc_free(message); + break; + } + + //compare signatures + if (memcmp(self_calculated_sig, sig_from_message, CS_SHA256_SIZE) != 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Inconsistent message signature\r"); + status_code = FTCD_COMM_INCONSISTENT_MESSAGE_SIGNATURE; + fcc_free(message); + break; + } + + // process request and get back response + fcc_status = fcc_bundle_handler(message, message_size, &response_protocol_message, &response_protocol_message_size); + if ((fcc_status == FCC_STATUS_BUNDLE_RESPONSE_ERROR) || (response_protocol_message == NULL) || (response_protocol_message_size == 0)) { + status_code = FTCD_COMM_FAILED_TO_PROCESS_DATA; + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed to process data\r"); + fcc_free(message); + break; + } + + fcc_free(message); + status_code = FTCD_COMM_STATUS_SUCCESS; //comm message status OK - passed all checks + + // Success + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Successfully processed comm message\r"); + + } while (0); + + success = _create_and_send_response(response_protocol_message, response_protocol_message_size, status_code); + if (!success) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed sending response message to remote host\r"); + status_code = FTCD_COMM_FAILED_TO_SEND_VALID_RESPONSE; + success = _create_and_send_response(NULL, 0, status_code); + if (!success) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed sending response message to remote host for second time!\r"); + } + } + + fcc_free(response_protocol_message); + +#ifdef TEST_SERIAL_MULTI_MESSAGE + } +#endif + + if (status_code != FTCD_COMM_STATUS_SUCCESS) { + return false; + } + return true; +} + +bool FtcdCommBase::_create_and_send_response(const uint8_t *protocol_reponse, uint32_t protocol_response_size, ftcd_comm_status_e status_code) +{ + bool success = true; + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + + // Construct response + uint8_t token[] = FTCD_MSG_HEADER_TOKEN; + + status_code = static_cast<ftcd_comm_status_e>(pv_h_to_le32(static_cast<uint32_t>(status_code))); + uint32_t response_size = 0; + + if (status_code == FTCD_COMM_STATUS_SUCCESS) { + // Factory message format - [TOKEN | STATUS | LENGTH | FT-MESSAGE | SIGNATURE] + response_size = sizeof(uint64_t) + sizeof(status_code) + sizeof(uint32_t) + protocol_response_size + CS_SHA256_SIZE; + } else { //invalid comm mesage + // Factory message format - [TOKEN | STATUS ] + response_size = sizeof(uint64_t) + sizeof(status_code); + } + + uint8_t *response = (uint8_t *)fcc_malloc(response_size); + + uint32_t offset = 0; + + // TOKEN + memcpy(response, &token, FTCD_MSG_HEADER_TOKEN_SIZE_BYTES); + offset = FTCD_MSG_HEADER_TOKEN_SIZE_BYTES; + + //STATUS + memcpy(response + offset, &status_code, sizeof(status_code)); + offset += sizeof(status_code); + + if (status_code == FTCD_COMM_STATUS_SUCCESS) { + + // Params check + if (protocol_reponse == NULL) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Invalid cbor_reponse\r"); + } + if (protocol_response_size == 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Got an empty CBOR response\r"); + } + + // Calculate FT message signature + uint8_t sig[CS_SHA256_SIZE]; + + uint32_t cbor_msg_size_le = pv_h_to_le32(protocol_response_size); + + kcm_status = cs_hash(CS_SHA256, protocol_reponse, protocol_response_size, sig, sizeof(sig)); + if (kcm_status != KCM_STATUS_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed calculating response message signature\r"); + //construct error packet and send it + fcc_free(response); + return false; + } + + // LENGTH + memcpy(response + offset, &cbor_msg_size_le, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + // FT-MESSAGE + memcpy(response + offset, protocol_reponse, protocol_response_size); + offset += protocol_response_size; + + // SIGNATURE + memcpy(response + offset, sig, sizeof(sig)); + } + + // Send the response... + success = send(response, response_size); + + fcc_free(response); + + return success; +} + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-serial/ftcd-comm-serial/ftcd_comm_serial.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-serial/ftcd-comm-serial/ftcd_comm_serial.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,112 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FTCD_COMM_SERIAL_H__ +#define __FTCD_COMM_SERIAL_H__ + +#include "Serial.h" +#include "ftcd_comm_base.h" +#include <inttypes.h> + + + +class FtcdCommSerial : public mbed::Serial, public FtcdCommBase +{ + +public: + /** Initialise a serial factory injection client, with specified UART pins + * and specified baud rate (115200) + * + * TODO: use the mbed config system to specify the default baud rate? + */ + FtcdCommSerial(PinName TX, PinName RX, uint32_t baud=9600); + + /** Not certain that we need to do anything here, but just in case we need + * to do some clean-up at some point. + */ + virtual ~FtcdCommSerial(); + + /** Detects the message token from the communication line medium. + * + * @returns + * zero, if token detected and different value otherwise + */ + virtual ftcd_comm_status_e is_token_detected(void); + + /** Reads the message size in bytes from the communication line medium. + * This is the amount of bytes needed to allocate for the upcoming message bytes. + * + * @returns + * The message size in bytes in case of success, zero bytes otherwise. + */ + virtual uint32_t read_message_size(void); + + /** Reads the message size in bytes from the communication line medium. + * This is the amount of bytes needed to allocate for the upcoming message bytes. + * + * @param message_out The buffer to read into and return to the caller. + * @param message_size The message size in bytes. + * + * @returns + * true upon success, false otherwise + */ + virtual bool read_message(uint8_t *message_out, size_t message_size); + + /** Reads the message size in bytes from the communication line medium. + * This is the amount of bytes needed to allocate for the upcoming message bytes. + * + * @param sig The buffer to read into and return to the caller. + * @param sig_size The sig buffer size in bytes. + * + * @returns + * The message size in bytes in case of success, zero bytes otherwise. + */ + virtual bool read_message_signature(uint8_t *sig, size_t sig_size); + + /** Writes the given data to the communication line medium. + * + * @param data The bytes to send through the communication line medium + * @param data_size The data size in bytes + * + * @returns + * true upon success, false otherwise + */ + virtual bool send(const uint8_t *data, uint32_t data_size); + +private: + + /** Reads a buffer from the serial line. + * + * @param buff_out A pointer to the buffer to read into, should be allocated by the caller + * @param buff_max_size The max chars to read + * + * @returns + * the number of chars read, zero in case of an error + */ + size_t _serial_read(char *buff_out, size_t buff_max_size); + + /** Writes a buffer to the serial line. + * + * @param buff A buffer to write. + * @param buff_size The number of chars in buffer + * + * @returns + * the number of chars that was written, zero in case of an error + */ + size_t _serial_write(const char *buff, size_t buff_size); +}; + +#endif // __FTCD_COMM_SERIAL_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-serial/source/ftcd_comm_serial.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-serial/source/ftcd_comm_serial.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,149 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include <stdlib.h> +#include "pv_endian.h" +#include "pal.h" +#include "pv_log.h" +#include "ftcd_comm_serial.h" + +#define TRACE_GROUP "fcsr" + +FtcdCommSerial::FtcdCommSerial(PinName TX, PinName RX, uint32_t baud) : mbed::Serial(TX, RX, baud) +{ +} + +FtcdCommSerial::~FtcdCommSerial() +{ +} + +size_t FtcdCommSerial::_serial_read(char *buffOut, size_t buffSize) +{ + size_t count; + //TODO: + //getc is blocking. There is currently no way to check if there is anything left to read. seems readable() us not working + //Once determined, the relevant check should be added to this code. + for (count = 0; count < buffSize; count++) { + buffOut[count] = getc(); + } + return count; +} + +size_t FtcdCommSerial::_serial_write(const char *buff, size_t buffSize) +{ + lock(); + + for (size_t i = 0; i < buffSize; i++) { + putc(buff[i]); + } + + unlock(); + + return buffSize; +} + +ftcd_comm_status_e FtcdCommSerial::is_token_detected() +{ + char c; + char expected_token[] = FTCD_MSG_HEADER_TOKEN; + size_t idx = 0; + + //read char by char to detect token + while (idx < FTCD_MSG_HEADER_TOKEN_SIZE_BYTES) { + _serial_read(&c, 1); + if (c == expected_token[idx]) { + idx++; + } else { + idx = 0; + } + } + return FTCD_COMM_STATUS_SUCCESS; +} + +uint32_t FtcdCommSerial::read_message_size() +{ + uint32_t message_size = 0; + + size_t read_chars = _serial_read(reinterpret_cast<char*>(&message_size), sizeof(message_size)); + if (read_chars != sizeof(message_size)) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed reading message size (read %d bytes out of %d)\r", read_chars, sizeof(message_size)); + return 0; + } + + return message_size; +} + +bool FtcdCommSerial::read_message(uint8_t *message_out, size_t message_size) +{ + if (message_out == NULL) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Invalid message buffer\r"); + return false; + } + + // Read CBOR message bytes + // We assume that LENGTH is NOT bigger than INT_MAX + size_t read_chars = _serial_read(reinterpret_cast<char*>(message_out), message_size); + if (read_chars != message_size) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed reading message bytes (read %d bytes out of %d)\r", read_chars, message_size); + return false; + } + + return true; +} + +bool FtcdCommSerial::read_message_signature(uint8_t *sig, size_t sig_size) +{ + if (sig == NULL) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Invalid sig buffer\r"); + return false; + } + + // Read signature from medium + size_t read_chars = _serial_read(reinterpret_cast<char*>(sig), sig_size); + if (read_chars != sig_size) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed reading message signature bytes (read %d bytes out of %d)\r", read_chars, sig_size); + return false; + } + + return true; +} + +bool FtcdCommSerial::send(const uint8_t *data, uint32_t data_size) +{ + if (data == NULL) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Invalid response_message\r"); + return false; + } + if (data_size == 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Got an empty message\r"); + return false; + } + + // Send data on the serial medium + size_t write_chars = _serial_write(reinterpret_cast<const char*>(data), data_size); + if (write_chars != data_size) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP,"Failed writing message bytes (wrote %" PRIu32 " bytes out of %" PRIu32 ")\r", (uint32_t)write_chars, data_size); + return false; + } + + return true; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-socket/ftcd-comm-socket/ftcd_comm_socket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-socket/ftcd-comm-socket/ftcd_comm_socket.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,158 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FTCD_COMM_SOCKET_H__ +#define __FTCD_COMM_SOCKET_H__ + +#include "ftcd_comm_base.h" +#include "pal.h" +#include <inttypes.h> + +#define INFINITE_SOCKET_TIMEOUT -1 + +/** +* List of supported networks domains. Current supported domain is ipv4 only. +*/ +typedef enum { + FTCD_AF_UNSPEC = 0,//!< Unspecified IP protocol. + FTCD_IPV4 = 2, //!< Internet IP Protocol. +} ftcd_socket_domain_e; + +/** +* Type for sockets. +*/ +typedef void* palSocket_t; +/** +* Structure for Ethernet interface info. +*/ +struct palNetInterfaceInfo; +/** +* Class for Ethernet interface. +*/ +class EthernetInterface; + +/** FtcdCommSocket implements the logic of listening for TCP connections and +* process incoming messages from the Factory Tool. +*/ +class FtcdCommSocket : public FtcdCommBase +{ +public: + + /** + * The Socket Constructor + * Initializes private variables and sets network interface handler, IP and port number. + * If port_num is 0, then random port will be generated. + */ + FtcdCommSocket(const void *interfaceHandler, ftcd_socket_domain_e domain, const uint16_t port_num, int32_t timeout = INFINITE_SOCKET_TIMEOUT); + + /** + * The Socket Destructor + * Closes opened resources and frees allocated memory. + */ + virtual ~FtcdCommSocket(); + + /** + * Initializes Network interface and prints its address. + */ + virtual bool init(void); + + /** + * Closes opened sockets + */ + virtual void finish(void); + + + /** Detects the message token from the communication line medium. + * + * @returns + * true, if token detected and false otherwise + */ + virtual ftcd_comm_status_e is_token_detected(void); + + /** Reads the message size in bytes from the communication line medium. + * This is the amount of bytes needed to allocate for the upcoming message bytes. + * + * @returns + * The message size in bytes in case of success, zero bytes otherwise. + */ + virtual uint32_t read_message_size(void); + + /** Reads the message size in bytes from the communication line medium. + * This is the amount of bytes needed to allocate for the upcoming message bytes. + * + * @param message_out The buffer to read into and return to the caller. + * @param message_size The message size in bytes. + * + * @returns + * true upon success, false otherwise + */ + virtual bool read_message(uint8_t *message_out, size_t message_size); + + /** Reads the message size in bytes from the communication line medium. + * This is the amount of bytes needed to allocate for the upcoming message bytes. + * + * @param sig The buffer to read into and return to the caller. + * @param sig_size The sig buffer size in bytes. + * + * @returns + * The message size in bytes in case of success, zero bytes otherwise. + */ + virtual bool read_message_signature(uint8_t *sig, size_t sig_size); + + /** Writes the given data to the communication line medium. + * + * @param data The bytes to send through the communication line medium + * @param data_size The data size in bytes + * + * @returns + * true upon success, false otherwise + */ + virtual bool send(const uint8_t *data, uint32_t data_size); + +private: + + const void *_interface_handler; + palSocket_t _server_socket; + palSocket_t _client_socket; + palNetInterfaceInfo *_net_interface_info; + uint16_t _port; + ftcd_socket_domain_e _current_domain_type; + ftcd_socket_domain_e _required_domain_type; + uint32_t _interface_index; + int32_t _rcv_timeout; + + /** Starts listening for incoming TCP socket connection + * A single connection allowed at a time + * + * @returns + * true, if listen to the socket succeeded. + */ + bool _listen(void); + + /**Reads a requested amount of bytes from a TCP socket + * + * @param data_out Pre-allocated buffer to be filled + * @param data_out_size Buffer length in bytes + * + * @returns + * 0, if the number of bytes read from the socket were exactly bufferOutSize, error status otherwise. + */ + ftcd_comm_status_e _read_from_socket( void *data_out, int data_out_size); + +}; + + +#endif //__FTCD_COMM_SOCKET_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-socket/source/ftcd_comm_socket.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/ftcd-comm-socket/source/ftcd_comm_socket.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,414 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include <stdlib.h> +#include "pal.h" +#include "pv_log.h" +#include "ftcd_comm_socket.h" +#include "fcc_malloc.h" + +#define NUM_OF_PENDING_CONNECTIONS 1 +#define NUM_OF_TRIES_TO_GET_INTERFACE_INFO 5 +#define TRACE_GROUP "fcsk" +#define RANDOM_PORT_MIN 1024 +#define RANDOM_PORT_MAX 65535 + +FtcdCommSocket::FtcdCommSocket(const void *interface_handler, ftcd_socket_domain_e domain, const uint16_t port_num, int32_t timeout) +{ + _interface_handler = interface_handler; + _required_domain_type = domain; + + /* If port supplied is 0, generate random port similar to UNIX convention. + * Pal currently does not support binding with port 0. + */ + _port = port_num; + if (port_num == 0) { + srand(pal_osKernelSysTick()); + + // Generate random port int the range [RANDOM_PORT_MIN, RANDOM_PORT_MAX - 1] including. + _port = (rand() % (RANDOM_PORT_MAX - RANDOM_PORT_MIN)) + RANDOM_PORT_MIN; + } + + _rcv_timeout = timeout; + _current_domain_type = FTCD_AF_UNSPEC; + _interface_index = 0; + _net_interface_info = NULL; + _server_socket = NULL; + _client_socket = NULL; +} + +FtcdCommSocket::~FtcdCommSocket() +{ + + if (_net_interface_info != NULL) { + fcc_free(_net_interface_info); + } + if (_server_socket != NULL) { + pal_close(&_server_socket); + } + if (_client_socket != NULL) { + pal_close(&_client_socket); + } +} + + +bool FtcdCommSocket::init() +{ + + int retries = NUM_OF_TRIES_TO_GET_INTERFACE_INFO; + palIpV4Addr_t ip_v4_addr; + char ip_and_port_string[32] = { 0 }; + uint32_t index = 0; + + //Call to pal init + palStatus_t result = pal_init(); + if (result != PAL_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Error initializing pal"); + return false; + } + + //Register connected interface handler + result = pal_registerNetworkInterface((void*)_interface_handler, &_interface_index); + if (result != 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n pal_RegisterNetworkInterface Failed"); + return false; + } + + //Allocate memory for interface info + if (_net_interface_info == NULL) { + _net_interface_info = (palNetInterfaceInfo_t*)fcc_malloc(sizeof(palNetInterfaceInfo_t)); + if (_net_interface_info == NULL) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Failed to allocate memory for network interface"); + return false; + } + } + + //Try to get interface info + while (retries--) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Trying receive interface ..."); + result = pal_getNetInterfaceInfo(_interface_index, _net_interface_info); + if (result != 0) { + pal_osDelay(200); + } else {//In case we have interface info we print it + if (_required_domain_type != FTCD_IPV4) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Illegal domain type"); + break; + } + //Update domain type + _current_domain_type = _required_domain_type; + + result = pal_getSockAddrIPV4Addr(&(_net_interface_info->address), ip_v4_addr); + if (result != PAL_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n palGetSockAddrIPV4Addr failed"); + break; + } + memset(ip_and_port_string, 0, sizeof(ip_and_port_string)); + index = 0; + for (uint32_t i = 0; i < sizeof(palIpV4Addr_t); i++) { + if (i < sizeof(palIpV4Addr_t) - 1) { + index += sprintf(&ip_and_port_string[index], "%d.", ip_v4_addr[i]); + } else { + index += sprintf(&ip_and_port_string[index], "%d:", ip_v4_addr[i]); + index += sprintf(&ip_and_port_string[index], "%d\n", _port); + } + } + + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Factory Client IP Address and Port : %s", ip_and_port_string); + //open and listen to socket + if (_listen()) { + return true; + } else { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed to listen to socket"); + } + + } + + } + + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n FCC did not succeed receive network interface !!!!!!"); + //If we couldn't get interface info free allocated memory + fcc_free(_net_interface_info); + _net_interface_info = NULL; + return false; + +} + + +void FtcdCommSocket::finish(void) +{ + if (_server_socket != NULL) { + pal_close(&_server_socket); + _server_socket = NULL; + } + if (_client_socket != NULL) { + pal_close(&_client_socket); + _client_socket = NULL; + } + pal_destroy(); +} + +ftcd_comm_status_e FtcdCommSocket::is_token_detected(void) +{ + char expected_token[] = FTCD_MSG_HEADER_TOKEN; + char c; + int result = PAL_SUCCESS; + size_t idx = 0; + palSocketLength_t addrlen = 0; + palSocketAddress_t address = { 0 }; + + result = pal_accept(_server_socket, &address, &addrlen, &_client_socket); + if (result == PAL_ERR_SOCKET_WOULD_BLOCK) { + return FTCD_COMM_NETWORK_TIMEOUT; + } else if (result != PAL_SUCCESS) { + return FTCD_COMM_NETWORK_CONNECTION_ERROR; + } + + //read char by char to detect token + while (idx < FTCD_MSG_HEADER_TOKEN_SIZE_BYTES) { + result = _read_from_socket(reinterpret_cast<void*>(&c), 1); + if (result == PAL_ERR_SOCKET_WOULD_BLOCK) { + return FTCD_COMM_NETWORK_TIMEOUT; + } else if (result != PAL_SUCCESS) { + return FTCD_COMM_NETWORK_CONNECTION_ERROR; + } + + if (c == expected_token[idx]) { + idx++; + } else { + idx = 0; + } + } + return FTCD_COMM_STATUS_SUCCESS; +} + + +uint32_t FtcdCommSocket::read_message_size(void) +{ + uint32_t message_size = 0; + ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS; + + result = _read_from_socket(reinterpret_cast<void*>(&message_size), sizeof(message_size)); + if (result != FTCD_COMM_STATUS_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message size\r"); + return 0; + } + + return message_size; +} + +bool FtcdCommSocket::read_message(uint8_t *message_out, size_t message_size) +{ + ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS; + + if (message_out == NULL) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid message buffer\r"); + return false; + } + + // Read CBOR message bytes + // We assume that LENGTH is NOT bigger than INT_MAX + result = _read_from_socket(reinterpret_cast<void*>(message_out), message_size); + if (result != FTCD_COMM_STATUS_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message bytes\r"); + return false; + } + return true; +} + + +bool FtcdCommSocket::read_message_signature(uint8_t *sig, size_t sig_size) +{ + ftcd_comm_status_e result = FTCD_COMM_STATUS_SUCCESS; + + if (sig == NULL) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid sig buffer\r"); + return false; + } + + // Read signature from medium + result = _read_from_socket(reinterpret_cast<void*>(sig), sig_size); + if (result != FTCD_COMM_STATUS_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed reading message signature bytes\r"); + return false; + } + return true; +} + + +bool FtcdCommSocket::send(const uint8_t *data, uint32_t data_size) +{ + bool success = true; + palStatus_t result = PAL_SUCCESS; + size_t sent_bytes = 0; + size_t remaind_bytes = (size_t)data_size; + + do { + result = pal_send(_client_socket, data, remaind_bytes, &sent_bytes); + if (result != PAL_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Failed pal_send\r"); + success = false; + break; + } + + if (sent_bytes == 0 || sent_bytes > remaind_bytes) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Sending response message failed"); + success = false; + break; + } + remaind_bytes = remaind_bytes - sent_bytes; + data += sent_bytes; + + } while (remaind_bytes != 0); + + return success; +} + +bool FtcdCommSocket::_listen(void) +{ + int status; + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t address = { 0 }; + palIpV4Addr_t ipv4 = { 0 }; + + //Check port number and domain type + if (_port == 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Wrong port number"); + return false; + } + + if (_current_domain_type != FTCD_IPV4) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "\n Wrong domain type"); + return false; + } + + //Open server and client sockets + result = pal_socket((palSocketDomain_t)_current_domain_type, PAL_SOCK_STREAM_SERVER, false, _interface_index, &_server_socket); + if (result != PAL_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_socket failed"); + return false; + } + + result = pal_socket((palSocketDomain_t)_current_domain_type, PAL_SOCK_STREAM, false, _interface_index, &_client_socket); + if (result != PAL_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_socket failed"); + return false; + } + + //Get ipv4 format address from interface info structure + status = pal_getSockAddrIPV4Addr(&(_net_interface_info->address), ipv4); + if (status != 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot palGetSockAddrIPV4Addr (status %d)", status); + return false; + } + + //Set the retrieved address to pal socket address + status = pal_setSockAddrIPV4Addr(&address, ipv4); + if (status != 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set socket ipv4 address (status %d)", status); + return false; + } + + //Set current port number to pal socket address + status = pal_setSockAddrPort(&address, _port); + if (status != 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set socket port address (status %d)", status); + return false; + } + + //set server socket timeout + if (_rcv_timeout >= 0) { + status = pal_setSocketOptions(_server_socket, PAL_SO_RCVTIMEO, &_rcv_timeout, sizeof(_rcv_timeout)); + if (status != 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Cannot set server socket timeout (status %d)", status); + return false; + } + } + + status = pal_bind(_server_socket, &address, _net_interface_info->addressSize); + if (status != 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_bind failed (status %d)", status); + return false; + } + + status = pal_listen(_server_socket, NUM_OF_PENDING_CONNECTIONS); + if (status != 0) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "pal_listen failed (status %d)", status); + return false; + } + + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Factory Client is waiting for incoming connection..."); + + return true; +} + + +ftcd_comm_status_e FtcdCommSocket::_read_from_socket(void * data_out, int data_out_size) +{ + int status = PAL_SUCCESS; + size_t bytes_received = 0; + + if (data_out == NULL) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Invalid message"); + return FTCD_COMM_INTERNAL_ERROR; + } + + status = pal_recv(_client_socket, data_out, data_out_size, &bytes_received); + if (status == PAL_ERR_SOCKET_WOULD_BLOCK) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket timeout, (status = %i)", status); + return FTCD_COMM_NETWORK_TIMEOUT; + } else if (status != PAL_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket error, (status = %i)", status); + return FTCD_COMM_NETWORK_CONNECTION_ERROR; + } + + /* FIXME: The socket reads up to MSS (Max Segment Size) which is 1460 bytes. + A bigger message would result in a partial message read. A temporary solution + is to loop through until socket emptiness */ + + // The number of bytes we had managed to read so far + int bytes_read_successfully = bytes_received; + + // The remaining bytes left to read + int remaining_bytes = data_out_size - bytes_received; + + // Loop through until nothing left to read + while (remaining_bytes > 0) { + + //Zero bytes_received before next receive + bytes_received = 0; + + status = pal_recv(_client_socket, (uint8_t *)data_out + bytes_read_successfully, remaining_bytes, &bytes_received); + if (status == PAL_ERR_SOCKET_WOULD_BLOCK) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket timeout, (status = %i)", status); + return FTCD_COMM_NETWORK_TIMEOUT; + } else if (status != PAL_SUCCESS) { + mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, "Receive socket error, (status = %i)", status); + return FTCD_COMM_NETWORK_CONNECTION_ERROR; + } + + remaining_bytes -= bytes_received; + bytes_read_successfully += bytes_received; + } + return FTCD_COMM_STATUS_SUCCESS; +} + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/key-config-manager/kcm_chain.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/key-config-manager/kcm_chain.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,157 @@ +#define KCM_MAX_NUMBER_OF_CERTITICATES_IN_CHAIN 5 + +typedef enum kcm_chain_operation_type_ { + KCM_CHAIN_OP_TYPE_CREATE, + KCM_CHAIN_OP_TYPE_OPEN, + KCM_CHAIN_OP_TYPE_MAX +} kcm_chain_operation_type_e; + +/** The chain context used internally only and should not be changed by user. +*/ +typedef struct kcm_cert_chain_context_ { + uint8_t *chain_name; //!< The name of certificate chain. + size_t chain_name_len; //!< The size of certificate chain name. + uint32_t num_of_certificates_in_chain; //!< The number of certificate in the chain. + esfs_file_t current_cert_file_descriptor; //!< Current certificate descriptor iterator. + uint32_t current_cert_descriptor_index; //!< Current descriptor certificate iterator. + uint32_t current_cert_index; //!< Current certificate iterator. + kcm_chain_operation_type_e operation_type;//!< Type of Current operation. +} kcm_chain_context_s; + + + +/** The API initializes chain context for write chain operation, +* This API should be called prior to kcm_cert_chain_add_certificate API. +* +* @param[out] kcm_chain_context pointer to certificate chain context. +* @param[in] kcm_chain_name pointer to certificate chain name. +* @param[in] kcm_chain_name_len length of certificate name buffer. +* @param[in] kcm_chain_len number of certificates in the chain. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_cert_chain_create(kcm_chain_context_s *kcm_chain_context, + const uint8_t *kcm_chain_name, + size_t kcm_chain_name_len, + uint32_t kcm_chain_len); + +/** The API initializes chain context for read chain operation. +* This API should be called prior to kcm_cert_chain_get_next_certificate_size and kcm_cert_chain_get_next_certificate_data APIs +* +* @param[out] kcm_chain_context pointer to certificate chain context. +* @param[in] kcm_chain_name pointer to certificate chain name. +* @param[in] kcm_chain_name_len size of certificate name buffer. +* @param[out] kcm_chain_len length of certificate chain. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_cert_chain_open(kcm_chain_context_s *kcm_chain_context, + const uint8_t *kcm_chain_name, + size_t kcm_chain_name_len, + uint32_t *kcm_chian_len); + +/** This API adds next certificate of chain to the storage. +* The certificates should be added in the order from root of chain, followed by the certificates it signs and so on. +* +* @param[in] kcm_chain_context pointer to certificate chain context. +* @param[in] kcm_cert_data pointer to certificate data in DER format. +* @param[in] kcm_cert_data_size size of certificate data buffer. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_cert_chain_add_next(kcm_chain_context_s *kcm_chain_context, + const uint8_t *kcm_cert_data, + size_t kcm_cert_data_size); + +/** The API deletes all certificates of the chain from the storage. +* +* @param[in] kcm_chain_name pointer to certificate chain name. +* @param[in] kcm_chain_name_len length of certificate chain name. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_cert_chain_delete(const uint8_t *kcm_chain_name, + size_t kcm_chain_name_len); + +/** The API returns size of the next certificate in the chain. +* This API should be called prior to kcm_cert_chain_get_next_data. +* This operation does not increase chain's context iterator. +* +* @param[in] kcm_chain_name pointer to certificate chain context. +* @param[out] kcm_cert_data_size pointer size of next certificate. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_cert_chain_get_next_size(kcm_chain_context_s *kcm_chain_context, + size_t *kcm_cert_data_size); + +/** The API returns data of the next certificate in the chain. +* To get exact size of a next certificate use kcm_cert_chain_get_next_certificate_size. +* In the end of get data operation, chain context points to the next certificate of current chain. +* +* @param[in] kcm_chain_context pointer to certificate chain context. +* @param[in/out] kcm_cert_data pointer to certificate data in DER format. +* @param[in] kcm_max_cert_data_size max size of certificate data buffer. +* @param[out] kcm_actual_cert_data_size actual size of certificate data. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_cert_chain_get_next_data(kcm_chain_context_s *kcm_chain_context, + uint8_t *kcm_cert_data, + size_t kcm_max_cert_data_size, + size_t *kcm_actual_cert_data_size); + + +/** The API releases the context and frees allocated resources. +* When operation type is creation--> if total number of added/stored certificates is not equal to number +* of certificates in the chain, the API will return an error. +* +* @param[in] kcm_chain_context pointer to certificate chain context. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_cert_chain_close(kcm_chain_context_s *kcm_chain_context); + + + +/*Example flow +To create a new chain +kcm_cert_chain_create(context, name, strlen(name), 3); +kcm_cert_chain_add_next(context, der_cert1, sizeof(der_cert1)); +kcm_cert_chain_add_next(context, der_cert2, sizeof(der_cert2)); +kcm_cert_chain_add_next(context, der_cert3, sizeof(der_cert3)); +kcm_cert_chain_finilize(context); + +To open and read an existing chain with size retrieving +kcm_cert_chain_open(context, name, strlen(name)); +kcm_cert_chain_get_next_size(context, &out_size); +out_data1 = fcc_malloc(out_size); +kcm_cert_chain_get_next_data(context, out_data1, out_size, &actual_out_size); +kcm_cert_chain_get_next_size(context, &out_size); +out_data2 = fcc_malloc(out_size); +kcm_cert_chain_get_next_data(context, out_data2, out_size, &actual_out_size); +kcm_cert_chain_get_next_size(context, &out_size); +out_data3 = fcc_malloc(out_size); +kcm_cert_chain_get_next_data(context, out_data3, out_size, &actual_out_size); +kcm_cert_chain_finilize(context); + +To open and read an existing chain without size retrieving (predefined max length) +uint8_t out_data1[1024]; +uint8_t out_data2[1024]; +uint8_t out_data3[1024]; +kcm_cert_chain_open(context, name, strlen(name)); +kcm_cert_chain_get_next_data(context, out_data1, sizeof(out_data1), &actual_out_size); +kcm_cert_chain_get_next_data(context, out_data2, sizeof(out_data2), &actual_out_size); +kcm_cert_chain_get_next_data(context, out_data3, sizeof(out_data3), &actual_out_size); +kcm_cert_chain_finilize(context); + +To delete +kcm_cert_chain_delete(name, strlen(name)); +*/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/key-config-manager/kcm_defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/key-config-manager/kcm_defs.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,63 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __KCM_DEFS_H__ +#define __KCM_DEFS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @file kcm_defs.h +* \brief Keys and configuration manager (KCM) definitions. +*/ + +/** +* KCM item types +*/ +typedef enum { + KCM_PRIVATE_KEY_ITEM, //!< KCM private key item type. KCM Supports ECC keys with curves defined in palGroupIndex_t(pal_Crypto.h) + KCM_PUBLIC_KEY_ITEM, //!< KCM public key item type. KCM Supports ECC keys with curves defined in palGroupIndex_t(pal_Crypto.h) + KCM_SYMMETRIC_KEY_ITEM, //!< KCM symmetric key item type. + KCM_CERTIFICATE_ITEM, //!< KCM certificate item type. Supported x509 certificates in der format. + KCM_CONFIG_ITEM, //!< KCM configuration parameter item type. + KCM_CERTIFICATE_CHAIN_ITEM, //!< KCM certificate chain item type. + KCM_LAST_ITEM //!< KCM not defined item type. +} kcm_item_type_e; + +/** +* Security descriptor - contains different ACLs such as remote ACL, local ACL and audit. +* Currently defined to `void*.` +* May be changed in the future. +*/ +typedef void* kcm_security_desc_s; + +#ifndef __DOXYGEN__ +/** +* CryptoKeyScheme structure. +* Currently defined to void*. +* May be changed in the future. +*/ +typedef void* kcm_crypto_key_scheme_s; + +#endif //#ifndef __DOXYGEN__ + +#ifdef __cplusplus +} +#endif + +#endif //__KCM_DEFS_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/key-config-manager/kcm_status.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/key-config-manager/kcm_status.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,80 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __KCM_STATUS_H__ +#define __KCM_STATUS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @file kcm_status.h +* \brief Keys and configuration manager (KCM) status/error codes. +* This list may grow as needed. +*/ + +typedef enum kcm_status_ { + KCM_STATUS_SUCCESS, //!< Operation completed successfully. + KCM_STATUS_ERROR, //!< Operation ended with an unspecified error. + KCM_STATUS_INVALID_PARAMETER, //!< A parameter provided to the function was invalid. + KCM_STATUS_INSUFFICIENT_BUFFER, //!< The provided buffer size was insufficient for the required output. + KCM_STATUS_OUT_OF_MEMORY, //!< An out-of-memory condition occurred. + KCM_STATUS_ITEM_NOT_FOUND, //!< The item was not found in the storage. + KCM_STATUS_FILE_EXIST, //!< Trying to store an item that is already in the storage. + KCM_STATUS_NOT_PERMITTED, //!< Trying to access an item without proper permissions. + KCM_STATUS_STORAGE_ERROR, //!< File error occurred. + KCM_STATUS_ITEM_IS_EMPTY, //!< The data of current item is empty. + KCM_STATUS_INVALID_FILE_VERSION, //!< Invalid file version, the file can not be read + KCM_STATUS_FILE_CORRUPTED, //!< File data corrupted, the file can not be read + KCM_STATUS_FILE_NAME_CORRUPTED, //!< File name corrupted, the file can not be read + KCM_STATUS_INVALID_FILE_ACCESS_MODE, //!< Invalid file access mode + KCM_STATUS_UNKNOWN_STORAGE_ERROR, //!< KCM can not translate current storage error + KCM_STATUS_NOT_INITIALIZED, //!< KCM did not initialized. + KCM_CRYPTO_STATUS_UNSUPPORTED_HASH_MODE, //!< Operation was called with unsupported hash mode. + KCM_CRYPTO_STATUS_PARSING_DER_PRIVATE_KEY, //!< Operation failed to parse private der key. + KCM_CRYPTO_STATUS_PARSING_DER_PUBLIC_KEY, //!< Operation failed to parse public der key. + KCM_CRYPTO_STATUS_PK_KEY_INVALID_FORMAT, //!< Operation failed due to invalid pk key format. + KCM_CRYPTO_STATUS_INVALID_PK_PUBKEY, //!< Operation failed due to invalid pk public key. + KCM_CRYPTO_STATUS_ECP_INVALID_KEY, //!< Operation failed due to invalid ECP key. + KCM_CRYPTO_STATUS_PK_KEY_INVALID_VERSION, //!< Operation failed due to invalid pk version of key. + KCM_CRYPTO_STATUS_PK_PASSWORD_REQUIRED, //!< Operation failed due to missing password. + KCM_CRYPTO_STATUS_PRIVATE_KEY_VERIFICATION_FAILED, //!< Operation failed to verify private key. + KCM_CRYPTO_STATUS_PUBLIC_KEY_VERIFICATION_FAILED, //!< Operation failed to verify public key. + KCM_CRYPTO_STATUS_PK_UNKNOWN_PK_ALG, //!< Operation failed due to unknown pk algorithm, + KCM_CRYPTO_STATUS_UNSUPPORTED_CURVE, //!< Unsupported curve. + KCM_CRYPTO_STATUS_PARSING_DER_CERT, //!< Operation failed to parse der certificate. + KCM_CRYPTO_STATUS_CERT_EXPIRED, //!< Certificate validity is expired. + KCM_CRYPTO_STATUS_CERT_FUTURE, //!< Certificate validity starts in future. + KCM_CRYPTO_STATUS_CERT_MD_ALG, //!< Certificate with bad MD algorithm. + KCM_CRYPTO_STATUS_CERT_PUB_KEY_TYPE, //!< Certificate with unsupported public key PK type. + KCM_CRYPTO_STATUS_CERT_PUB_KEY, //!< Certificate with bad public key data (size or curve). + KCM_CRYPTO_STATUS_CERT_NOT_TRUSTED, //!< Certificate is not trusted. + KCM_CRYPTO_STATUS_INVALID_X509_ATTR, //!< Certificate with bad x509 attribute + KCM_CRYPTO_STATUS_VERIFY_SIGNATURE_FAILED, //!< Operation failed to check the signature. + KCM_CRYPTO_STATUS_INVALID_MD_TYPE, //!< Operation failed in check of ecc md type. + KCM_CRYPTO_STATUS_FAILED_TO_WRITE_SIGNATURE, //!< Operation failed to calculate signature. + KCM_MAX_STATUS, +} kcm_status_e; + +//The macro defined for backward compatibility. Will be deprecated. +#define KCM_STATUS_ESFS_ERROR KCM_STATUS_STORAGE_ERROR + +#ifdef __cplusplus +} +#endif + +#endif //__KCM_STATUS_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/key-config-manager/key_config_manager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/key-config-manager/key_config_manager.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,181 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __KEYS_CONFIG_MANAGER_H__ +#define __KEYS_CONFIG_MANAGER_H__ + +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include "kcm_status.h" +#include "kcm_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @file key_config_manager.h +* \brief Keys and Configuration Manager (KCM) APIs. +*/ + +/* === Initialization and Finalization === */ + +/** +* Initiate the KCM module. +* Allocates and initializes file storage resources. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_init(void); + +/** +* Finalize the KCM module. +* Finalizes and frees file storage resources. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_finalize(void); + +/* === Keys, Certificates and Configuration data storage === */ + +/** Store the KCM item into a secure storage. +* +* @param[in] kcm_item_name KCM item name. +* @param[in] kcm_item_name_len KCM item name length. +* @param[in] kcm_item_type KCM item type as defined in `::kcm_item_type_e` +* @param[in] kcm_item_is_factory True if the KCM item is a factory item, otherwise false. +* @param[in] kcm_item_data KCM item data buffer. Can be NULL if `kcm_item_data_size` is 0. +* @param[in] kcm_item_data_size KCM item data buffer size in bytes. Can be 0 if you wish to store an empty file. +* @param[in] security_desc Security descriptor. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_item_store(const uint8_t *kcm_item_name, size_t kcm_item_name_len, kcm_item_type_e kcm_item_type, bool kcm_item_is_factory, const uint8_t *kcm_item_data, size_t kcm_item_data_size, const kcm_security_desc_s security_desc); + +/* === Keys, Certificates and Configuration data retrieval === */ + +/** Retrieve the KCM item data size from a secure storage. +* +* @param[in] kcm_item_name KCM item name. +* @param[in] kcm_item_name_len KCM item name length. +* @param[in] kcm_item_type KCM item type as defined in `::kcm_item_type_e` +* @param[out] kcm_item_data_size_out KCM item data size in bytes. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_item_get_data_size(const uint8_t *kcm_item_name, size_t kcm_item_name_len, kcm_item_type_e kcm_item_type, size_t *kcm_item_data_size_out); + +/** Retrieve KCM item data from a secure storage. +* +* @param[in] kcm_item_name KCM item name. +* @param[in] kcm_item_name_len KCM item name length. +* @param[in] kcm_item_type KCM item type as defined in `::kcm_item_type_e` +* @param[out] kcm_item_data_out KCM item data output buffer. Can be NULL if `kcm_item_data_size` is 0. +* @param[in] kcm_item_data_max_size The maximum size of the KCM item data output buffer in bytes. +* @param[out] kcm_item_data_act_size_out Actual KCM item data output buffer size in bytes. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_item_get_data(const uint8_t *kcm_item_name, size_t kcm_item_name_len, kcm_item_type_e kcm_item_type, uint8_t *kcm_item_data_out, size_t kcm_item_data_max_size, size_t * kcm_item_data_act_size_out); + +/* === Keys, Certificates and Configuration update === */ + +/** Update KCM item data in a secure storage. +* +* @param[in] kcm_item_name KCM item name. +* @param[in] kcm_item_name_len KCM item name length. +* @param[in] kcm_item_type KCM item type as defined in `::kcm_item_type_e` +* @param[in] kcm_item_data KCM item data buffer. +* @param[in] kcm_item_data_size KCM item data buffer size in bytes. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_item_update_data(const uint8_t *kcm_item_name, size_t kcm_item_name_len, kcm_item_type_e kcm_item_type, const uint8_t *kcm_item_data, size_t kcm_item_data_size); + +/* === Keys, Certificates and Configuration delete === */ + +/** Delete a KCM item from a secure storage. +* +* @param[in] kcm_item_name KCM item name. +* @param[in] kcm_item_name_len KCM item name length. +* @param[in] kcm_item_type KCM item type as defined in `::kcm_item_type_e` +* +* @returns +* KCM_STATUS_SUCCESS status in case of success or one of ::kcm_status_e errors otherwise. +*/ +kcm_status_e kcm_item_delete(const uint8_t *kcm_item_name, size_t kcm_item_name_len, kcm_item_type_e kcm_item_type); + + +/* === Factory Reset === */ + +/** Reset the KCM secure storage to factory state. +* +* @returns +* KCM_STATUS_SUCCESS in case of success or one of the `::kcm_status_e` errors otherwise. +*/ +kcm_status_e kcm_factory_reset(void); + + + +#ifndef __DOXYGEN__ +/* === Keys and CSR generation === */ + +/** Generate a key pair complying the given crypto scheme DER. +* Saves the private key and exposes the public key. +* +* @param key_scheme The crypto scheme. +* @param key_name The key name for which a key pair is generated. +* @param key_name_len Key name length. +* @param pub_key_der_out Public key to generate in DER format. +* @param pub_key_der_size Public key size in bytes. +* @param priv_key_sec_desc Private key security descriptor. +* @param pub_key_sec_desc Public key security descriptor. +* +* @returns +* Operation status. +*/ +kcm_status_e kcm_key_pair_generate_and_store(kcm_crypto_key_scheme_s key_scheme, const uint8_t *key_name, size_t key_name_len, + uint8_t *pub_key_der_out, size_t pub_key_der_size, + const kcm_security_desc_s priv_key_sec_desc, const kcm_security_desc_s pub_key_sec_desc); + +/** Generate a general CSR from the given private and public keys. +* Further design is needed +* +* @param key_name The key name to fetch from storage(public/private). +* @param key_name_len The key name len. +* @param csr_out Pointer to generated E2E CSR. +* @param csr_size_out Size of the E2E CSR. +* +* @returns +* Operation status. +*/ +kcm_status_e kcm_csr_generate(const uint8_t *key_name, size_t key_name_len, + uint8_t **csr_out, size_t *csr_size_out); +#endif //#ifndef __DOXYGEN__ + +#ifdef __cplusplus +} +#endif + +#endif //__KEYS_CONFIG_MANAGER_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/source/include/kcm_file_prefix_defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/source/include/kcm_file_prefix_defs.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,30 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __KCM_FILE_PREFIX_DEFS_H__ +#define __KCM_FILE_PREFIX_DEFS_H__ + + +/** +* KCM file prefixes defines +*/ +#define KCM_FILE_PREFIX_PRIVATE_KEY "PrvKey_" +#define KCM_FILE_PREFIX_PUBLIC_KEY "PubKey_" +#define KCM_FILE_PREFIX_SYMMETRIC_KEY "SymKey_" +#define KCM_FILE_PREFIX_CERTIFICATE "Cert_" +#define KCM_FILE_PREFIX_CONFIG_PARAM "CfgParam_" +#define KCM_FILE_PREFIX_CERTIFICATE_CHAIN "CertChain_" +#endif //__KCM_FILE_PREFIX_DEFS_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/source/include/kcm_internal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/source/include/kcm_internal.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,65 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef KEYS_CONFIG_MANAGER_INTERNAL_H +#define KEYS_CONFIG_MANAGER_INTERNAL_H + +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include "esfs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* === Definitions and Prototypes === */ + +typedef enum kcm_meta_data_type_ { + KCM_LOCAL_ACL_MD_TYPE, + KCM_REMOTE_ACL_MD_TYPE, + KCM_AUDIT_MD_TYPE, + KCM_NAME_MD_TYPE, + KCM_USAGE_MD_TYPE, + KCM_MD_TYPE_MAX_SIZE +} kcm_meta_data_type_e; + +typedef struct kcm_meta_data_ { + kcm_meta_data_type_e type; + size_t data_size; + uint8_t *data; +} kcm_meta_data_s; + +typedef struct kcm_meta_data_list_ { + // allocate a single meta data for each type + kcm_meta_data_s meta_data[KCM_MD_TYPE_MAX_SIZE]; + size_t meta_data_count; +} kcm_meta_data_list_s; + +typedef struct kcm_ctx_ { + esfs_file_t esfs_file_h; + kcm_meta_data_list_s list; + uint16_t access_flags; // owner, signed, encrypted, factory, extended ACL bit mask + size_t file_size; + bool is_file_size_checked; +} kcm_ctx_s; + +#ifdef __cplusplus +} +#endif + +#endif //KEYS_CONFIG_MANAGER_INTERNAL_H +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/source/key_config_manager.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/key-config-manager/source/key_config_manager.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,331 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- +#include <stdbool.h> +#include "key_config_manager.h" +#include "storage.h" +#include "pv_error_handling.h" +#include "kcm_file_prefix_defs.h" +#include "cs_der_certs.h" +#include "cs_der_keys.h" +#include "fcc_malloc.h" + + +typedef enum { + KCM_PRIVATE_KEY_DATA, + KCM_PUBLIC_KEY_DATA, + KCM_SYMMETRIC_KEY_DATA, + KCM_CERTIFICATE_DATA, + KCM_CONFIG_DATA, +} kcm_data_type; + +static bool kcm_initialized = false; + +static kcm_status_e kcm_add_prefix_to_name(const uint8_t *kcm_name, size_t kcm_name_len, const char *prefix, uint8_t **kcm_buffer_out, size_t *kcm_buffer_size_allocated_out) +{ + size_t prefix_length; + + SA_PV_LOG_TRACE_FUNC_ENTER("name len=%" PRIu32 "", (uint32_t)kcm_name_len); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_buffer_out == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_buffer_out parameter"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_buffer_size_allocated_out == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_buffer_size_allocated_out parameter"); + + prefix_length = strlen(prefix); + + *kcm_buffer_out = (uint8_t *)fcc_malloc(kcm_name_len + prefix_length); + SA_PV_ERR_RECOVERABLE_RETURN_IF((*kcm_buffer_out == NULL), KCM_STATUS_OUT_OF_MEMORY, "Failed allocating kcm_buffer_out"); + + /* Append prefix and name to allocated buffer */ + memcpy(*kcm_buffer_out, (uint8_t *)prefix, prefix_length); + memcpy(*kcm_buffer_out + prefix_length, kcm_name, kcm_name_len); + + *kcm_buffer_size_allocated_out = kcm_name_len + prefix_length; + + SA_PV_LOG_TRACE_FUNC_EXIT("kcm_buffer_size_allocated_out= %" PRIu32 "", (uint32_t)*kcm_buffer_size_allocated_out); + return KCM_STATUS_SUCCESS; +} + + +static kcm_status_e kcm_item_name_get_prefix(kcm_item_type_e kcm_item_type, const char** prefix) +{ + kcm_status_e status = KCM_STATUS_SUCCESS; + + switch (kcm_item_type) { + case KCM_PRIVATE_KEY_ITEM: + *prefix = KCM_FILE_PREFIX_PRIVATE_KEY; + break; + case KCM_PUBLIC_KEY_ITEM: + *prefix = KCM_FILE_PREFIX_PUBLIC_KEY; + break; + case KCM_SYMMETRIC_KEY_ITEM: + *prefix = KCM_FILE_PREFIX_SYMMETRIC_KEY; + break; + case KCM_CERTIFICATE_ITEM: + *prefix = KCM_FILE_PREFIX_CERTIFICATE; + break; + case KCM_CONFIG_ITEM: + *prefix = KCM_FILE_PREFIX_CONFIG_PARAM; + break; + case KCM_CERTIFICATE_CHAIN_ITEM: + *prefix = KCM_FILE_PREFIX_CERTIFICATE_CHAIN; + break; + default: + status = KCM_STATUS_INVALID_PARAMETER; + break; + } + return status; +} + +kcm_status_e kcm_init(void) +{ + kcm_status_e status = KCM_STATUS_SUCCESS; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + if (!kcm_initialized) { + status = storage_init(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != KCM_STATUS_SUCCESS), status, "Failed initializing storage\n"); + kcm_initialized = true; + } + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + return status; +} + +kcm_status_e kcm_finalize(void) +{ + kcm_status_e status = KCM_STATUS_SUCCESS; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + if (kcm_initialized) { + status = storage_finalize(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != KCM_STATUS_SUCCESS), status, "Failed finalizing storage\n"); + kcm_initialized = false; + } + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + return status; +} + +kcm_status_e kcm_item_store(const uint8_t * kcm_item_name, size_t kcm_item_name_len, kcm_item_type_e kcm_item_type, bool kcm_item_is_factory, const uint8_t * kcm_item_data, size_t kcm_item_data_size, const kcm_security_desc_s security_desc) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + kcm_ctx_s ctx; + uint8_t *kcm_complete_name = NULL; // Filename including prefix + size_t kcm_complete_name_size; + const char *prefix; + bool kcm_item_is_encrypted = true; //encrypt by default + + SA_PV_LOG_INFO_FUNC_ENTER("item name = %.*s len=%" PRIu32 ", data size=%" PRIu32 "", (int)kcm_item_name_len, (char*)kcm_item_name, (uint32_t)kcm_item_name_len, (uint32_t)kcm_item_data_size); + + // Check if KCM initialized, if not initialize it + if (!kcm_initialized) { + kcm_status = kcm_init(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "KCM initialization failed\n"); + } + + + // Validate function parameters + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_name == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_name"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_name_len == 0), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_name_len"); + SA_PV_ERR_RECOVERABLE_RETURN_IF(((kcm_item_data == NULL) && (kcm_item_data_size > 0)), KCM_STATUS_INVALID_PARAMETER, "Provided kcm_item_data NULL and kcm_item_data_size greater than 0"); + + //temporary check that security descriptor is NULL + SA_PV_ERR_RECOVERABLE_RETURN_IF((security_desc != NULL), KCM_STATUS_INVALID_PARAMETER, "Security descriptor is not NULL!"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_type != KCM_CONFIG_ITEM && kcm_item_data_size == 0), KCM_STATUS_ITEM_IS_EMPTY, "The data of current item is empty!"); + + switch (kcm_item_type) { + case KCM_PRIVATE_KEY_ITEM: + kcm_status = cs_der_priv_key_verify(kcm_item_data, kcm_item_data_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Private key validation failed"); + break; + case KCM_PUBLIC_KEY_ITEM: + kcm_status = cs_der_public_key_verify(kcm_item_data, kcm_item_data_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Public key validation failed"); + kcm_item_is_encrypted = false; //do not encrypt public key + break; + case KCM_SYMMETRIC_KEY_ITEM: + //currently possible to write a symmetric key of size 0 since we do not check format + break; + case KCM_CERTIFICATE_ITEM: + kcm_status = cs_parse_der_x509_cert(kcm_item_data, kcm_item_data_size); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Certificate validation failed"); + kcm_item_is_encrypted = false; //do not encrypt certificates + break; + case KCM_CONFIG_ITEM: + break; + default: + SA_PV_ERR_RECOVERABLE_RETURN_IF((true), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_type"); + } + + kcm_status = kcm_item_name_get_prefix(kcm_item_type, &prefix); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), (kcm_status = kcm_status), Exit, "Failed during kcm_item_name_get_prefix"); + + kcm_status = kcm_add_prefix_to_name(kcm_item_name, kcm_item_name_len, prefix, &kcm_complete_name, &kcm_complete_name_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), (kcm_status = kcm_status), Exit, "Failed during kcm_add_prefix_to_name"); + + kcm_status = storage_file_write(&ctx, kcm_complete_name, kcm_complete_name_size, kcm_item_data, kcm_item_data_size, kcm_item_is_factory, kcm_item_is_encrypted); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), (kcm_status = kcm_status), Exit, "Failed writing file to storage"); + +Exit: + fcc_free(kcm_complete_name); + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + return kcm_status; +} + + +kcm_status_e kcm_item_get_data_size(const uint8_t *kcm_item_name, size_t kcm_item_name_len, kcm_item_type_e kcm_item_type, size_t *kcm_item_data_size_out) +{ + kcm_status_e status = KCM_STATUS_SUCCESS; + uint8_t *kcm_complete_name = NULL; // Filename including prefix + size_t kcm_complete_name_size; + kcm_ctx_s ctx; + size_t kcm_data_size = 0; + const char *prefix; + + SA_PV_LOG_INFO_FUNC_ENTER("item name = %.*s len=%" PRIu32 "", (int)kcm_item_name_len, (char*)kcm_item_name, (uint32_t)kcm_item_name_len); + + // Check if KCM initialized, if not initialize it + if (!kcm_initialized) { + status = kcm_init(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != KCM_STATUS_SUCCESS), status, "KCM initialization failed\n"); + } + + // Validate function parameters + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_name == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_name"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_name_len == 0), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_name_len"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_type >= KCM_LAST_ITEM), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_type"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_data_size_out == NULL), KCM_STATUS_INVALID_PARAMETER, "Kcm size out pointer is NULL"); + + status = kcm_item_name_get_prefix(kcm_item_type, &prefix); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed during kcm_item_name_get_prefix"); + + status = kcm_add_prefix_to_name(kcm_item_name, kcm_item_name_len, prefix, &kcm_complete_name, &kcm_complete_name_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed during kcm_add_prefix_to_name"); + + status = storage_file_size_get(&ctx, kcm_complete_name, kcm_complete_name_size, &kcm_data_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed in getting file size"); + + *kcm_item_data_size_out = kcm_data_size; + SA_PV_LOG_INFO_FUNC_EXIT("kcm data size = %" PRIu32 "", (uint32_t)*kcm_item_data_size_out); +Exit: + fcc_free(kcm_complete_name); + + return status; +} + + +kcm_status_e kcm_item_get_data(const uint8_t * kcm_item_name, size_t kcm_item_name_len, kcm_item_type_e kcm_item_type, uint8_t * kcm_item_data_out, size_t kcm_item_data_max_size, size_t * kcm_item_data_act_size_out) +{ + kcm_status_e status = KCM_STATUS_SUCCESS; + uint8_t *kcm_complete_name = NULL; // Filename including prefix + size_t kcm_complete_name_size; + kcm_ctx_s ctx; + const char *prefix; + + SA_PV_LOG_INFO_FUNC_ENTER("item name = %.*s len = %" PRIu32 ", data max size = %" PRIu32 "", (int)kcm_item_name_len, (char*)kcm_item_name, (uint32_t)kcm_item_name_len, (uint32_t)kcm_item_data_max_size); + + // Check if KCM initialized, if not initialize it + if (!kcm_initialized) { + status = kcm_init(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != KCM_STATUS_SUCCESS), status, "KCM initialization failed\n"); + } + + // Validate function parameters + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_name == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_name"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_name_len == 0), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_name_len"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_type >= KCM_LAST_ITEM), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_type"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_data_act_size_out == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_data_act_size_out"); + SA_PV_ERR_RECOVERABLE_RETURN_IF(((kcm_item_data_out == NULL) && (kcm_item_data_max_size > 0)), KCM_STATUS_INVALID_PARAMETER, "Provided kcm_item_data NULL and kcm_item_data_size greater than 0"); + + memset(&ctx, 0, sizeof(ctx)); + status = kcm_item_name_get_prefix(kcm_item_type, &prefix); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed during kcm_item_name_get_prefix"); + + status = kcm_add_prefix_to_name(kcm_item_name, kcm_item_name_len, prefix, &kcm_complete_name, &kcm_complete_name_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed during kcm_add_prefix_to_name"); + + status = storage_file_read(&ctx, kcm_complete_name, kcm_complete_name_size, kcm_item_data_out, kcm_item_data_max_size, kcm_item_data_act_size_out); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed reading file from storage (%d)", status); + + SA_PV_LOG_INFO_FUNC_EXIT("kcm data size = %" PRIu32 "", (uint32_t)*kcm_item_data_act_size_out); +Exit: + fcc_free(kcm_complete_name); + + return status; +} + + +kcm_status_e kcm_item_delete(const uint8_t * kcm_item_name, size_t kcm_item_name_len, kcm_item_type_e kcm_item_type) +{ + kcm_status_e status = KCM_STATUS_SUCCESS; + uint8_t *kcm_complete_name = NULL; // Filename including prefix + size_t kcm_complete_name_size; + kcm_ctx_s ctx; // FIXME - Currently not implemented + const char *prefix; + + SA_PV_LOG_INFO_FUNC_ENTER("item name = %.*s len = %" PRIu32 "", (int)kcm_item_name_len, (char*)kcm_item_name, (uint32_t)kcm_item_name_len); + + // Check if KCM initialized, if not initialize it + if (!kcm_initialized) { + status = kcm_init(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != KCM_STATUS_SUCCESS), status, "KCM initialization failed\n"); + } + + // Validate function parameters + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_name == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_name"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_name_len == 0), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_name_len"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_item_type >= KCM_LAST_ITEM), KCM_STATUS_INVALID_PARAMETER, "Invalid kcm_item_type"); + + status = kcm_item_name_get_prefix(kcm_item_type, &prefix); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed during kcm_item_name_get_prefix"); + + status = kcm_add_prefix_to_name(kcm_item_name, kcm_item_name_len, prefix, &kcm_complete_name, &kcm_complete_name_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed during kcm_add_prefix_to_name"); + + status = storage_file_delete(&ctx, kcm_complete_name, kcm_complete_name_size); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed deleting kcm data"); + +Exit: + fcc_free(kcm_complete_name); + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + return status; +} + +kcm_status_e kcm_factory_reset(void) +{ + kcm_status_e status = KCM_STATUS_SUCCESS; + + SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS(); + + // Check if KCM initialized, if not initialize it + if (!kcm_initialized) { + status = kcm_init(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((status != KCM_STATUS_SUCCESS), status, "KCM initialization failed\n"); + } + + status = storage_factory_reset(); + SA_PV_ERR_RECOVERABLE_GOTO_IF((status != KCM_STATUS_SUCCESS), (status = status), Exit, "Failed perform factory reset"); + +Exit: + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + return status; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/logger/logger/pv_log.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/logger/logger/pv_log.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,186 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +/* Logging macros */ + +#ifndef __PV_LOG_H__ +#define __PV_LOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define __PV_LOG_H__INSIDE +#include <stdio.h> +#include <inttypes.h> +#include <string.h> +#include <stdbool.h> +#include "pal.h" +#include "mbed-trace/mbed_trace.h" + + + +#define SA_PV_LOG_LEVEL_CRITICAL_COLOR "\x1B[31m" /* red */ +#define SA_PV_LOG_LEVEL_ERR_COLOR "\x1B[31m" /* red */ +#define SA_PV_LOG_LEVEL_WARN_COLOR "\x1B[33m" /* yellow */ +#define SA_PV_LOG_LEVEL_INFO_COLOR "\x1B[0m" /* normal */ +#define SA_PV_LOG_LEVEL_TRACE_COLOR "\x1B[0m" /* normal */ +#define SA_PV_LOG_LEVEL_DATA_COLOR "\x1B[37m" /* white */ + + +#define __SA_PV_FILE__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +extern palMutexID_t g_pv_logger_mutex; +/** +* Calls to mbed trace print function +* +* - The function sets mbed trace level according to log level, compose buffer with general data (line,color, file..) and message +* and calls to mbed_vtracef. +*/ +void pv_log_trace(int level, const char* filename, int line, const char *func, const char *color, const char *format, ...); +/** +* Print buffer with mbed trace function +* +*/ +void pv_log_trace_buffer(int level, const char* filename, int line, const char *func, const char *color, const char *name, const uint8_t *buff, uint32_t buff_size); + +#define _SA_PV_LOG_FUNC_ENTER(level, filename, line, func, color, format, ...) _SA_PV_LOG(level, filename, line, func, color, "===> " format, ##__VA_ARGS__) + +/** Exit function logging + * + * - Should be called in the end of a function, assuming the function doesn't exit early due to an error. + * - Should display values of output variables (with meaning, no need to print buffers). + * - Usage example (with INFO level): SA_PV_LOG_INFO_FUNC_EXIT("argPointerToInt = %d, argPointerToUnsigned32 = %" PRIu32 "", *argPointerToInt, (uint32_t)*argPointerToUnsigned32); + */ +#define _SA_PV_LOG_FUNC_EXIT(level, filename, line, func, color, format, ...) _SA_PV_LOG(level, filename, line, func, color, "<=== " format, ##__VA_ARGS__) + +// CRITICAL always being output +#define SA_PV_LOG_CRITICAL(format, ...) \ + _SA_PV_LOG(TRACE_LEVEL_CMD, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_CRITICAL_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_BYTE_BUFF_CRITICAL(name, buff, buff_size) \ + _SA_PV_BYTE_BUFF_LOG(TRACE_LEVEL_CMD, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_CRITICAL_COLOR, name, buff, buff_size) +#define SA_PV_LOG_CRITICAL_FUNC_EXIT(format, ...) \ + _SA_PV_LOG_FUNC_EXIT(TRACE_LEVEL_CMD, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_CRITICAL_COLOR, format, ##__VA_ARGS__) + +#if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_ERROR) +#define SA_PV_LOG_ERR(format, ...) \ + _SA_PV_LOG(TRACE_LEVEL_ERROR, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_ERR_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_BYTE_BUFF_ERR(name, buff, buff_size) \ + _SA_PV_BYTE_BUFF_LOG(TRACE_LEVEL_ERROR, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_ERR_COLOR, name, buff, buff_size) +#define SA_PV_LOG_ERR_FUNC_EXIT(format, ...) \ + _SA_PV_LOG_FUNC_EXIT(TRACE_LEVEL_ERROR, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_ERR_COLOR, format, ##__VA_ARGS__) + +#else +#define SA_PV_LOG_ERR(format, arg...) do {} while (0) +#define SA_PV_LOG_BYTE_BUFF_ERR(format, arg...) do {} while (0) +#define SA_PV_LOG_ERR_FUNC_EXIT(format, ...) do {} while (0) +#endif + +#if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_WARN) +#define SA_PV_LOG_WARN(format, ...) \ + _SA_PV_LOG(TRACE_LEVEL_WARN, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_WARN_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_BYTE_BUFF_WARN(name, buff, buff_size) \ + _SA_PV_BYTE_BUFF_LOG(TRACE_LEVEL_WARN, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_WARN_COLOR, name, buff, buff_size) +#define SA_PV_LOG_WARN_FUNC_EXIT(format, ...) \ + _SA_PV_LOG_FUNC_EXIT(TRACE_LEVEL_WARN, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_WARN_COLOR, format, ##__VA_ARGS__) +#else +#define SA_PV_LOG_WARN(format, ...) do {} while (0) +#define SA_PV_LOG_BYTE_BUFF_WARN(format, ...) do {} while (0) +#define SA_PV_LOG_WARN_FUNC_EXIT(format, ...) do {} while (0) +#endif + +#if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_INFO) +#define SA_PV_LOG_INFO(format, ...) \ + _SA_PV_LOG(TRACE_LEVEL_INFO, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_INFO_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_INFO_FUNC_ENTER(format, ...) \ + _SA_PV_LOG_FUNC_ENTER(TRACE_LEVEL_INFO, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_INFO_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS() \ + SA_PV_LOG_INFO_FUNC_ENTER("") +#define SA_PV_LOG_INFO_FUNC_EXIT(format, ...) \ + _SA_PV_LOG_FUNC_EXIT(TRACE_LEVEL_INFO, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_INFO_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS() \ + SA_PV_LOG_INFO_FUNC_EXIT("") +#define SA_PV_LOG_BYTE_BUFF_INFO(name, buff, buff_size) \ + _SA_PV_BYTE_BUFF_LOG(TRACE_LEVEL_INFO, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_INFO_COLOR, name, buff, buff_size) +#else +#define SA_PV_LOG_INFO(format, ...) do {} while (0) +#define SA_PV_LOG_INFO_FUNC_ENTER(format, ...) do {} while (0) +#define SA_PV_LOG_INFO_FUNC_ENTER_NO_ARGS() do {} while (0) +#define SA_PV_LOG_INFO_FUNC_EXIT(format, ...) do {} while (0) +#define SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS() do {} while (0) +#define SA_PV_LOG_BYTE_BUFF_INFO(format, ...) do {} while (0) +#endif + +#if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_DEBUG) +#define SA_PV_LOG_TRACE(format, ...) \ + _SA_PV_LOG(TRACE_LEVEL_DEBUG, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_TRACE_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_TRACE_FUNC_ENTER(format, ...) \ + _SA_PV_LOG_FUNC_ENTER(TRACE_LEVEL_DEBUG, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_TRACE_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS() \ + SA_PV_LOG_TRACE_FUNC_ENTER("") +#define SA_PV_LOG_TRACE_FUNC_EXIT(format, ...) \ + _SA_PV_LOG_FUNC_EXIT(TRACE_LEVEL_DEBUG, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_TRACE_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS() \ + SA_PV_LOG_TRACE_FUNC_EXIT("") +#define SA_PV_LOG_BYTE_BUFF_TRACE(name, buff, buff_size) \ + _SA_PV_BYTE_BUFF_LOG(TRACE_LEVEL_DEBUG, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_TRACE_COLOR, name, buff, buff_size) + +#else +#define SA_PV_LOG_TRACE(format, ...) do {} while (0) +#define SA_PV_LOG_TRACE_FUNC_ENTER(format, ...) do {} while (0) +#define SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS() do {} while (0) +#define SA_PV_LOG_TRACE_FUNC_EXIT(format, ...) do {} while (0) +#define SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS() do {} while (0) +#define SA_PV_LOG_BYTE_BUFF_TRACE(format, ...) do {} while (0) +#endif + +#if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_DEBUG) +#define SA_PV_LOG_DATA(format, ...) \ + _SA_PV_LOG(TRACE_LEVEL_DEBUG, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_DATA_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_DATA_FUNC_ENTER(format, ...) \ + _SA_PV_LOG_FUNC_ENTER(TRACE_LEVEL_DEBUG, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_DATA_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_DATA_FUNC_ENTER_NO_ARGS() \ + SA_PV_LOG_DATA_FUNC_ENTER("") +#define SA_PV_LOG_DATA_FUNC_EXIT(format, ...) \ + _SA_PV_LOG_FUNC_EXIT(TRACE_LEVEL_DEBUG, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_DATA_COLOR, format, ##__VA_ARGS__) +#define SA_PV_LOG_DATA_FUNC_EXIT_NO_ARGS() \ + SA_PV_LOG_DATA_FUNC_EXIT("") +#define SA_PV_LOG_BYTE_BUFF_DATA(name, buff, buff_size) \ + _SA_PV_BYTE_BUFF_LOG(TRACE_LEVEL_DEBUG, __SA_PV_FILE__, __LINE__, __func__, SA_PV_LOG_LEVEL_DATA_COLOR, name, buff, buff_size) +#else +#define SA_PV_LOG_DATA(format, ...) do {} while (0) +#define SA_PV_LOG_DATA_FUNC_ENTER(format, ...) do {} while (0) +#define SA_PV_LOG_DATA_FUNC_ENTER_NO_ARGS() do {} while (0) +#define SA_PV_LOG_DATA_FUNC_EXIT(format, ...) do {} while (0) +#define SA_PV_LOG_DATA_FUNC_EXIT_NO_ARGS() do {} while (0) +#define SA_PV_LOG_BYTE_BUFF_DATA(format, ...) do {} while (0) +#endif + +/* Should only be called once, additional calls do nothing. */ +#define _SA_PV_LOG(level, file, line, func, color, format, ...) \ +do{ \ + mbed_tracef(level, "fcc","%s%s:%d:%s:"format,color, file, line, func, ##__VA_ARGS__);\ +} while (0) + +#define _SA_PV_BYTE_BUFF_LOG(level, file, line, func, color, name, buff, buff_size) ( mbed_tracef(level, "fcc", "%s"name, mbed_trace_array(buff, buff_size))) + +#undef __PV_LOG_H__INSIDE + +#ifdef __cplusplus +} +#endif +#endif /*__PV_LOG_H__*/ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,6 @@ +CMakeFiles/* +Docs/* +Test/* +out/* + +source-pal/linux/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/CMakeLists.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,62 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/source/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/Test/Unity/src) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/Test/Unity/extras/fixture/src) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../mbed-client-pal/Source/PAL-Impl/Services-API) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../mbed-trace) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../nanostack-libservice/mbed-client-libservice) + +# temp workaround +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../mbed-client-pal/Source/Port/Platform-API) + + +set (PAL_TESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../mbed-client-pal/Test/Unitest) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../mbed-client-pal/Examples/PlatformBSP/Include) +include_directories(${PAL_TESTS_SOURCE_DIR}/Includes) + + +FILE( + GLOB_RECURSE + esfs_src + "${CMAKE_CURRENT_SOURCE_DIR}/source/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/source/*.h" +) + +FILE( + GLOB_RECURSE + esfs_test_src + "${CMAKE_CURRENT_SOURCE_DIR}/Test/Unitest/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/Test/Unitest/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Test/Unitest/*.h" + + "${CMAKE_CURRENT_SOURCE_DIR}/Test/linux/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Test/linux/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/Test/linux/*.cpp" + + "${CMAKE_CURRENT_SOURCE_DIR}/Test/Unity/src/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/Test/Unity/src/*.h" + + "${CMAKE_CURRENT_SOURCE_DIR}/Test/Unity/extras/fixture/src/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/Test/Unity/extras/fixture/src/*.h" + + ${PAL_TESTS_SOURCE_DIR}/TestRunner/pal_test${OS_BRAND}.c + +) +message ( "********************************************************************* ") +message ("esfs_src = [[${esfs_src}]]") +message ( "********************************************************************* ") +message ("esfs_test_src = [[${esfs_test_src}]]") +message ( "********************************************************************* ") + + +CREATE_LIBRARY(esfs "${esfs_src}" "") + + +set (ESFS_TEST_FLAGS + -DPAL_RUN_ALL_TESTS +) + + +CREATE_TEST_LIBRARY(esfs_tests "${esfs_test_src}" "${ESFS_TEST_FLAGS}") +ADD_DEPENDENCIES(esfs_tests esfs) +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/Tools/FRDM-K64FfreeRTOS_Create2Partitions Binary file simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/Tools/FRDM-K64FfreeRTOS_Create2Partitions has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/esfs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/esfs.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2582 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +// ----------------------------------------------------------- Includes ----------------------------------------------------------- + + +#include "esfs.h" +#include "esfs_file_name.h" + +#include "mbed-trace/mbed_trace.h" + +#include "pal_rtos.h" +#include "pal_types.h" +#include "pal_Crypto.h" + +#include <string.h> // For memcmp and strncat + + + +// --------------------------------------------------------- Definitions ---------------------------------------------------------- + + +#define TRACE_GROUP "esfs" // Maximum 4 characters + +// We do not really know what other uses (if any) the file system card will have. +// We will assume that it may contain other files and we will keep all cfstore files in one directory. +// A future enhancement could be to put files that are not to be removed at factory reset in a separate directory. +// We prefix with a './' so as to create the files under a folder in the current working directory. +#define ESFS_WORKING_DIRECTORY "WORKING" +#define ESFS_BACKUP_DIRECTORY "BACKUP" +#define FACTORY_RESET_DIR "FR" +#define FACTORY_RESET_FILE "fr_on" + +// We choose a size that does not take up too much stack, but minimizes the number of reads. +#define ESFS_READ_CHUNK_SIZE_IN_BYTES (64) + +#define ESFS_MAX_NAME_LENGTH (1024) + +#define ESFS_BITS_IN_BYTE (8) +#define ESFS_AES_BLOCK_SIZE_BYTES (16) +#define ESFS_AES_IV_SIZE_BYTES (16) +#define ESFS_AES_COUNTER_INDEX_IN_IV ESFS_AES_NONCE_SIZE_BYTES +#define ESFS_AES_COUNTER_SIZE_BYTES (8) +#define ESFS_AES_KEY_SIZE_BYTES (16) +#define ESFS_AES_KEY_SIZE_BITS (ESFS_AES_KEY_SIZE_BYTES * ESFS_BITS_IN_BYTE) + +#define ESFS_AES_BUF_SIZE_BYTES (256) // - To avoid dynamic allocations, we use static buffers for AES encryption / decryption. + // - This macro defines the size in bytes of these static buffers. + // - In case we have to encrypt / decrypt a bigger amount of bytes, we loop over the buffer + // and encrypt / decrypt up to ESFS_AES_BUF_SIZE_BYTES bytes on each step + +// This should be incremented when the file format changes +#define ESFS_FILE_FORMAT_VERSION (1) + +#define ESFS_CMAC_SIZE_IN_BYTES (16) + +#define ESFS_FILE_COPY_CHUNK_SIZE (256) + +#define MAX_FULL_PATH_SIZE (PAL_MAX_FOLDER_DEPTH_CHAR + 1 + PAL_MAX(sizeof(ESFS_BACKUP_DIRECTORY), sizeof(ESFS_WORKING_DIRECTORY)) + PAL_MAX(sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE), ESFS_QUALIFIED_FILE_NAME_LENGTH)) + +static bool esfs_initialize = false; + + + +// -------------------------------------------------- Functions Implementation ---------------------------------------------------- + + +// --------------------------------------------------------------- +// Helper Functions +// --------------------------------------------------------------- + + +esfs_result_e esfs_init(void) +{ + esfs_result_e result = ESFS_SUCCESS; + tr_info("esfs_init - enter"); + if (!esfs_initialize) + { + palStatus_t pal_result = PAL_SUCCESS; + esfs_file_t file_handle = {0}; + char dir_path[MAX_FULL_PATH_SIZE] = { 0 }; + + pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_init() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY)); + + //Looping on first file system operation to work around IOTMORF-914 - sd-driver initialization + for(int i=0 ; i<100; i++) + { + // Create the esfs subfolder working + pal_result = pal_fsMkDir(dir_path); + if ((pal_result == PAL_SUCCESS) || (pal_result == PAL_ERR_FS_NAME_ALREADY_EXIST)) + break; + tr_err("esfs_init() %d", i); + pal_osDelay(50); + + } + + if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST)) + { + tr_err("esfs_init() - pal_fsMkDir() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); + if (pal_result != PAL_SUCCESS) + { + + tr_err("esfs_init() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(dir_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); + + // Create the directory ESFS_BACKUP_DIRECTORY + pal_result = pal_fsMkDir(dir_path); + if (pal_result != PAL_SUCCESS) + { + // Any error apart from file exist returns error. + if (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST) + { + tr_err("esfs_init() - pal_fsMkDir() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + } + + // create the correct path for factory reset file fr_on + strncat(dir_path, "/" FACTORY_RESET_DIR "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE)); + pal_result = pal_fsFopen(dir_path, PAL_FS_FLAG_READONLY, &(file_handle.file)); + // (res == PAL_SUCCESS) : flag file can be opened for reading --> file \FR\fr_on found + // previous factory reset failed during execution + // (res == PAL_ERR_FS_NO_FILE) : flag file was not found --> good scenario + // (res != PAL_ERR_FS_NO_FILE) : file system problem + if (pal_result == PAL_SUCCESS) + { + // Close the file before factory reset + pal_result = pal_fsFclose(&(file_handle.file)); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_init() - unexpected filesystem behavior pal_fsFclose() failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + // previous factory reset failed during execution - therefore we call this factory_reset again + result = esfs_factory_reset(); + if (result != ESFS_SUCCESS) + { + tr_err("esfs_init() - esfs_factory_reset() failed with esfs_result_e = 0x%x", result); + result = ESFS_ERROR; + goto errorExit; + } + } else if (pal_result != PAL_ERR_FS_NO_FILE) + { + tr_err("esfs_init() - unexpected filesystem behavior pal_fsFopen() failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + esfs_initialize = true; + } + return ESFS_SUCCESS; + +errorExit: + return result; + +} + +esfs_result_e esfs_finalize(void) +{ + esfs_initialize = false; + tr_info("esfs_finalize - enter"); + return ESFS_SUCCESS; +} + + +// Validate that a file handle has been initialized by create or open. +static esfs_result_e esfs_validate(esfs_file_t *file_handle) +{ + if(file_handle && file_handle->blob_name_length > 0) + { + return ESFS_SUCCESS; + } + else + { + return ESFS_ERROR; + } +} + + +/********************************************************************************************************************************** +Function : esfs_not_encrypted_file_header_size + +Description: This function returns the size in bytes of the file header without the metadata values part. + This is actually the non-encrypted part of the file header. + It is useful for calculation the file pointer position for AES encryption / decryption which starts only from the + encrypted part of the file. + +Parameters : file_handle - [IN] A pointer to a file handle for which we calculate the size. + +Note : This is a static function so no sanity check is made on arguments + +Return : The size in bytes of the non-encrypted part of the file header +**********************************************************************************************************************************/ +static size_t esfs_not_encrypted_file_header_size(esfs_file_t *file_handle) +{ + esfs_tlv_properties_t *tlv_properties = &(file_handle->tlv_properties); + + return ( file_handle->blob_name_length + // Name length field + sizeof(file_handle->blob_name_length) + // Name field + sizeof(uint16_t) + // Version field + sizeof(uint16_t) + // Mode field + (((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) ? ESFS_AES_NONCE_SIZE_BYTES : 0) + // Nonce field [non mandatory field] + sizeof(tlv_properties->number_of_items) + // Metadata number of elements field + (tlv_properties->number_of_items * sizeof(tlv_properties->tlv_items[0])) // Metadata tlv headers + ); +} + + +// Returns the size in bytes of the file header. +// This can only be called after the header has been read. +static size_t esfs_file_header_size(esfs_file_t *file_handle) +{ + size_t metadata_size = 0; + esfs_tlv_properties_t *tlv_properties = &file_handle->tlv_properties; + + for(int i = 0; i < tlv_properties->number_of_items; i++) + { + metadata_size += tlv_properties->tlv_items[i].length_in_bytes; + } + + return esfs_not_encrypted_file_header_size(file_handle) + metadata_size; +} + + +// Helper function to calculate the cmac on data that is written. +static esfs_result_e esfs_fwrite_and_calc_cmac(const void *pbuf, size_t *num_bytes, esfs_file_t *file_handle) +{ + if(pal_CMACUpdate(file_handle->signature_ctx, pbuf, *num_bytes) != PAL_SUCCESS) + { + tr_err("esfs_fwrite_and_calc_cmac() - pal_CMACUpdate failed"); + return ESFS_ERROR; + } + + if(pal_fsFwrite(&file_handle->file, pbuf, *num_bytes, num_bytes) != PAL_SUCCESS) + { + tr_err("esfs_fwrite_and_calc_cmac() - pal_fsFwrite failed"); + return ESFS_ERROR; + } + + return ESFS_SUCCESS; +} + + +/********************************************************************************************************************************** +Function : esfs_memcpy_reverse + +Description: This function copies the first <len_bytes> bytes from input buffer <src_ptr> to output buffer <dest_ptr> in + reversed order (e.g. '1' '2' '3' data array will be copied as '3' '2' '1'). + Note: The function assumes that the memory areas of the input buffers src_ptr and dest_ptr do not overlap. + +Parameters : dest_ptr - [IN / OUT] A pointer to the destination buffer to which bytes will be copied. + src_ptr - [IN] A pointer to the source buffer from which bytes will be copied. + len_bytes - [IN] Number of bytes to be copied. + +Note : This is a static function so no sanity check is made on arguments + +Return : A pointer to the output buffer <dest_ptr> +**********************************************************************************************************************************/ +static void *esfs_memcpy_reverse(void *dest_ptr, const void *src_ptr, uint32_t len_bytes) +{ + uint8_t *tmp_dest_ptr = (uint8_t *)dest_ptr; + const uint8_t *tmp_src_ptr = (const uint8_t *)src_ptr; + + + // Make the reverse copy + while(len_bytes > 0) + { + *(tmp_dest_ptr++) = *(tmp_src_ptr + len_bytes - 1); + len_bytes--; + } + + return dest_ptr; +} + + + +/********************************************************************************************************************************** +Function : esfs_calc_file_pos_for_aes + +Description: This function calculates the file position for the purpose of AES encrypt / decrypt: + The returned position is relative to the beginning of the encrypted data. + The file is encrypted starting from the meta data part (the meta data values). + +Parameters : file_handle - [IN] A pointer to a file handle on which we calculate the position. + position - [OUT] A pointer to size_t to be filled in with the returned position. + +Note : This is a static function so no sanity check is made on arguments + +Return : ESFS_SUCCESS on success. Error code otherwise +**********************************************************************************************************************************/ +static esfs_result_e esfs_calc_file_pos_for_aes(esfs_file_t *file_handle, size_t *position) +{ + palStatus_t pal_status = PAL_SUCCESS; + + size_t non_encrypt_size = 0; + + + *position = 0; + + // Get current position inside the file + pal_status = pal_fsFtell( &(file_handle->file), (int32_t *)position ); + + if(pal_status != PAL_SUCCESS) + { + tr_err("esfs_calc_file_pos_for_aes() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)pal_status); + return ESFS_ERROR; + } + + // Calculate non_encrypt_size to be subtracted from position + non_encrypt_size = esfs_not_encrypted_file_header_size(file_handle); + + if(*position < non_encrypt_size) + { + tr_err("esfs_calc_file_pos_for_aes() - Error. Position is in non encrypted part."); + return ESFS_ERROR; + } + + + *position -= non_encrypt_size; + + + return ESFS_SUCCESS; +} + + +/********************************************************************************************************************************** +Function : esfs_set_counter_in_iv_by_file_pos + +Description: This function fills in the last 8 bytes of the IV [iv128_arr] with the counter calculated according to + the input position. + +Parameters : position - [IN] The position in the file when count starts from the encrypted data part (the meta data values). + iv128_arr - [IN/OUT] A 16 bytes buffer holding the IV. + First 8 bytes contain the NONCE, and last 8 bytes will be filled in with the counter. + +Note : This is a static function so no sanity check is made on arguments + +Return : ESFS_SUCCESS on success. Error code otherwise +**********************************************************************************************************************************/ +static void esfs_set_counter_in_iv_by_file_pos(size_t position, uint8_t *iv128_arr) +{ + uint64_t counter = 0; + + + // Calculate counter part of IV + counter = (uint64_t)(position / ESFS_AES_BLOCK_SIZE_BYTES); + + + // Copy the counter part to the IV +#if BIG__ENDIAN == 1 + memcpy(iv128_arr + ESFS_AES_COUNTER_INDEX_IN_IV, &counter, ESFS_AES_COUNTER_SIZE_BYTES); +#else + esfs_memcpy_reverse(iv128_arr + ESFS_AES_COUNTER_INDEX_IN_IV, &counter, ESFS_AES_COUNTER_SIZE_BYTES); +#endif +} + + +/********************************************************************************************************************************** +Function : esfs_aes_enc_dec_by_file_pos + +Description: This function encrypts / decrypts data using AES-CTR. + This is the basic function used for AES encrypt / decrypt. + Due to the nature of AES-CTR which works on blocks, special handling is required in case the data in the file is not + on block boundaries. In this case we encrypt / decrypt this "partial block data" in a temporal buffer after copying + the data to the corresponding index inside this buffer. The rest of the data is being encrypted / decrypted normally. + +Parameters : aes_ctx - [IN] The per-initiated AES context. + buf_in - [IN] A buffer containing to data to be encrypted / decrypted. + buf_out - [OUT] A buffer to be filled in with the encrypted / decrypted data. + len_bytes - [IN] Number of bytes to encrypt / decrypt. + position - [IN] The position in the file when count starts from the encrypted data part (the meta data values). + nonce64_ptr - [IN] An 8 bytes buffer holding the NONCE part of the IV. + +Note : This is a static function so no sanity check is made on arguments + +Return : ESFS_SUCCESS on success. Error code otherwise +**********************************************************************************************************************************/ +static esfs_result_e esfs_aes_enc_dec_by_file_pos( palAesHandle_t aes_ctx, + const uint8_t *buf_in, + uint8_t *buf_out, + size_t len_bytes, + size_t position, + uint8_t *nonce64_ptr + ) +{ + palStatus_t pal_status = PAL_SUCCESS; + + uint8_t prev_remainder = 0; // Size in bytes of partial block PREVIOUSLY encrypted / decrypted + uint8_t partial_block_size = 0; // Size in bytes of partial block for NEXT encrypt / decrypt + + uint8_t partial_block_size_temp = 0; + + uint8_t partial_block_in[ESFS_AES_BLOCK_SIZE_BYTES] = {0}; // Will contain data for next partial encrypt / decrypt + uint8_t partial_block_out[ESFS_AES_BLOCK_SIZE_BYTES] = {0}; + + uint8_t iv_arr[ESFS_AES_IV_SIZE_BYTES] = {0}; // Will contain nonce [bytes 0 - 7] and counter [bytes 8 - 15] + +/* + + -------- partial_block_in: Size = block_size [16 bytes] + | + | + \|/ + + ----------------------------------------------------------------------------------------- + | | | | + | 0 ... 0 | Data copied form buf_in | 0 ... 0 | + | | | | + ----------------------------------------------------------------------------------------- + ^ ^ ^ + | | | + | | | + | | | + Size: prev_remainder | Size: might be 0 + | + | + Size: partial_block_size + (might consume the buffer till its end) + + +*/ + + prev_remainder = (position % ESFS_AES_BLOCK_SIZE_BYTES); + + partial_block_size_temp = ESFS_AES_BLOCK_SIZE_BYTES - prev_remainder; + partial_block_size = PAL_MIN(partial_block_size_temp, len_bytes); + + // Prepare partial_block_in: Copy data for next encrypt / decrypt from buf_in to partial_block_in + memcpy(partial_block_in + prev_remainder, buf_in, partial_block_size); + + // Prepare iv_arr: Copy nonce into bytes [0 - 7] of IV buffer + memcpy(iv_arr, nonce64_ptr, ESFS_AES_NONCE_SIZE_BYTES); + + // Prepare iv_arr: Set counter in bytes [8 - 15] of IV buffer + esfs_set_counter_in_iv_by_file_pos(position, iv_arr); + + + // Encrypt / decrypt partial block [run on entire block, and copy later only desired part) + pal_status = pal_aesCTRWithZeroOffset(aes_ctx, partial_block_in, partial_block_out, ESFS_AES_BLOCK_SIZE_BYTES, iv_arr); + + if(pal_status != PAL_SUCCESS) + { + tr_err("esfs_aes_enc_dec_by_file_pos() - pal_aesCTRWithZeroOffset() failed with pal_status = 0x%x", (unsigned int)pal_status); + return ESFS_ERROR; + } + + // Copy partial_block_out to buf_out + memcpy(buf_out, partial_block_out + prev_remainder, partial_block_size); + + + // Encrypt / decrypt the rest of the data + if(len_bytes > partial_block_size) + { + // Set updated counter in bytes [8 - 15] of IV buffer + esfs_set_counter_in_iv_by_file_pos(position + partial_block_size, iv_arr); + + pal_status = pal_aesCTRWithZeroOffset(aes_ctx, buf_in + partial_block_size, buf_out + partial_block_size, len_bytes - partial_block_size, iv_arr); + + if(pal_status != PAL_SUCCESS) + { + tr_err("esfs_aes_enc_dec_by_file_pos() - pal_aesCTRWithZeroOffset() failed with pal_status = 0x%x", (unsigned int)pal_status); + return ESFS_ERROR; + } + } + + + return ESFS_SUCCESS; +} + + +/********************************************************************************************************************************** +Function : esfs_read_and_decrypt + +Description: This function reads encrypted data from a file, decrypts it, and writes it into a buffer. + +Parameters : file_handle - [IN] A pointer to a file handle from which we read data. + buffer - [IN] The buffer to fill in with decrypted file data. + bytes_to_read - [IN] Number of bytes to read from the file. + read_bytes_ptr - [OUT] A pointer to size_t to be filled in with number of bytes actually read from the file. + +Note : This is a static function so no sanity check is made on arguments + +Return : ESFS_SUCCESS on success. Error code otherwise +**********************************************************************************************************************************/ +static esfs_result_e esfs_read_and_decrypt(esfs_file_t *file_handle, void *buffer, size_t bytes_to_read, size_t *read_bytes_ptr) +{ + esfs_result_e result = ESFS_SUCCESS; + palStatus_t pal_status = PAL_SUCCESS; + + size_t position = 0; + + + // Get file pointer position for AES - Must be done before calling pal_fsFread() which modifies the file pointer position + result = esfs_calc_file_pos_for_aes(file_handle, &position); + + if(result != ESFS_SUCCESS) + { + tr_err("esfs_read_and_decrypt() - esfs_calc_file_pos_for_aes() failed with status = 0x%x", result); + return result; + } + + + // Read file's encrypted data into buffer + pal_status = pal_fsFread( &(file_handle->file), buffer, bytes_to_read, read_bytes_ptr ); + + if((pal_status != PAL_SUCCESS) || (*read_bytes_ptr != bytes_to_read)) + { + tr_err("esfs_read_and_decrypt() - pal_fsFread() failed with pal_status = 0x%x", (unsigned int)pal_status); + return ESFS_ERROR; + } + + + // AES decrypt in-place - decrypt the encrypted data inside buffer, into buffer [out parameter] + result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer, buffer, bytes_to_read, position, file_handle->nonce); + + if(result != ESFS_SUCCESS) + { + tr_err("esfs_read_and_decrypt() - esfs_aes_enc_dec_by_file_pos() failed with status = 0x%x", (unsigned int)result); + return result; + } + + + return ESFS_SUCCESS; +} + + +/********************************************************************************************************************************** +Function : esfs_encrypt_fwrite_and_calc_cmac + +Description: This function takes a plain text buffer, encrypts it, writes the encrypted data to a file, and updates the + CMAC signature. + + Since we cannot modify the data of the input buffer (const), this operation cannot be done in-place, so we need + to use another buffer for the encryption result. In order to avoid dynamically allocation, we use a buffer + of size ESFS_AES_BUF_SIZE_BYTES statically allocated on the stack. This forces us to encrypt and write in a loop - + each iteration encrypts and writes maximum size of ESFS_AES_BUF_SIZE_BYTES bytes. + +Parameters : buffer - [IN] The buffer to encrypt and write to the file. + bytes_to_write - [IN/OUT] A pointer to size_t containing the number of bytes to write, and to be to be filled in + with the number of bytes actually been written to the file. + file_handle - [IN] A pointer to a file handle to which we write the data. + +Note : This is a static function so no sanity check is made on arguments + +Return : ESFS_SUCCESS on success. Error code otherwise +**********************************************************************************************************************************/ +static esfs_result_e esfs_encrypt_fwrite_and_calc_cmac(const void *buffer, size_t *bytes_to_write, esfs_file_t *file_handle) +{ + esfs_result_e result = ESFS_SUCCESS; + + size_t position = 0; + size_t write_bytes = 0; + + size_t remaining_bytes_to_write = *bytes_to_write; + + const uint8_t *buffer_tmp_ptr = (uint8_t *)buffer; // Will point to the next reading point in buffer as we read it + + uint8_t encrypted_data[ESFS_AES_BUF_SIZE_BYTES] = {0}; // Will hold encrypted data to be written to the file + + + if(buffer == NULL) + { + tr_err("esfs_encrypt_fwrite_and_calc_cmac() - Bad arguments error. Input buffer is NULL."); + return ESFS_ERROR; + } + + + *bytes_to_write = 0; // Reset out parameter + + // Get file pointer position for AES - Must be done before calling esfs_fwrite_and_calc_cmac() which modifies the file pointer position + result = esfs_calc_file_pos_for_aes(file_handle, &position); + + if(result != ESFS_SUCCESS) + { + tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_calc_file_pos_for_aes failed with result=0x%x", result); + return result; + } + + + // On every iteration in the loop, encrypt ESFS_AES_BUF_SIZE_BYTES bytes, and write them to the file + while(remaining_bytes_to_write >= ESFS_AES_BUF_SIZE_BYTES) + { + // AES encrypt into encrypted_data + result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer_tmp_ptr, encrypted_data, ESFS_AES_BUF_SIZE_BYTES, position, file_handle->nonce); + + if(result != ESFS_SUCCESS) + { + tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_aes_enc_dec_by_file_pos failed with result=0x%x", result); + return result; + } + + write_bytes = ESFS_AES_BUF_SIZE_BYTES; + + // Write the encrypted data to the file + result = esfs_fwrite_and_calc_cmac(encrypted_data, &write_bytes, file_handle); + + if((result != ESFS_SUCCESS) || (write_bytes != ESFS_AES_BUF_SIZE_BYTES)) + { + tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_fwrite_and_calc_cmac() status = 0x%x, written bytes = %zu, expected = %u", + (unsigned int)result, write_bytes, (unsigned int)ESFS_AES_BUF_SIZE_BYTES); + + // esfs_fwrite_and_calc_cmac() failed so we cannot be sure of the state of the file - mark the file as invalid + file_handle->file_invalid = 1; + + return ESFS_ERROR; + } + + (*bytes_to_write) += write_bytes; + + position += ESFS_AES_BUF_SIZE_BYTES; + buffer_tmp_ptr += ESFS_AES_BUF_SIZE_BYTES; + + remaining_bytes_to_write -= ESFS_AES_BUF_SIZE_BYTES; + } + + + // AES encrypt the leftover of buffer + if(remaining_bytes_to_write > 0) + { + // AES encrypt into encrypted_data + result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer_tmp_ptr, encrypted_data, remaining_bytes_to_write, position, file_handle->nonce); + + if(result != ESFS_SUCCESS) + { + tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_aes_enc_dec_by_file_pos failed with result=0x%x", result); + return result; + } + + write_bytes = remaining_bytes_to_write; + + // Write the encrypted data to the file + result = esfs_fwrite_and_calc_cmac(encrypted_data, &write_bytes, file_handle); + + if((result != ESFS_SUCCESS) || (write_bytes != remaining_bytes_to_write)) + { + tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_fwrite_and_calc_cmac() status = 0x%x, written bytes = %zu, expected = %zu", + (unsigned int)result, write_bytes, remaining_bytes_to_write); + + // esfs_fwrite_and_calc_cmac() failed so we cannot be sure of the state of the file - mark the file as invalid + file_handle->file_invalid = 1; + + return ESFS_ERROR; + } + + (*bytes_to_write) += write_bytes; + } + + + return ESFS_SUCCESS; +} + + +esfs_result_e esfs_reset(void) +{ + esfs_result_e result = ESFS_SUCCESS; + palStatus_t pal_result = PAL_SUCCESS; + char dir_path[MAX_FULL_PATH_SIZE] = { 0 }; + tr_info("esfs_reset - enter"); + pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_reset() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY)); + + + // delete the files in working dir + pal_result = pal_fsRmFiles(dir_path); + // the use case is that esfs folder may not exist + if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) + { + tr_err("esfs_reset() - pal_fsRmFiles(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + // delete working directory + pal_result = pal_fsRmDir(dir_path); + if (pal_result != PAL_SUCCESS) + { + // Any error apart from dir not exist returns error. + if ((pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) + { + tr_err("esfs_reset() - pal_fsRmDir(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + } + + pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); + if (pal_result != PAL_SUCCESS) + { + + tr_err("esfs_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(dir_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); + + + // delete the files in backup dir + pal_result = pal_fsRmFiles(dir_path); + // the use case is that esfs folder may not exist + if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) + { + tr_err("esfs_reset() - pal_fsRmFiles(ESFS_BACKUP_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + pal_result = pal_fsRmDir(dir_path); + if (pal_result != PAL_SUCCESS) + { + // Any error apart from dir not exist returns error. + if ((pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) + { + tr_err("esfs_reset() - pal_fsRmDir(ESFS_BACKUP_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + } + + if (esfs_finalize() != ESFS_SUCCESS) + { + tr_err("esfs_reset() - esfs_finalize() failed"); + result = ESFS_ERROR; + goto errorExit; + } + + if (esfs_init() != ESFS_SUCCESS) + { + tr_err("esfs_reset() - esfs_init() failed"); + result = ESFS_ERROR; + goto errorExit; + } + + return ESFS_SUCCESS; + +errorExit: + return result; +} + + +esfs_result_e esfs_factory_reset(void) { + palStatus_t pal_result = PAL_SUCCESS; + esfs_result_e result = ESFS_SUCCESS; + esfs_file_t file_handle = { 0 }; + char working_dir_path[MAX_FULL_PATH_SIZE] = { 0 }; + char full_path_backup_dir[MAX_FULL_PATH_SIZE] = { 0 }; + tr_info("esfs_factory_reset - enter"); + pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); + return ESFS_ERROR; + } + + strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY "/" FACTORY_RESET_DIR, sizeof(ESFS_BACKUP_DIRECTORY) + sizeof(FACTORY_RESET_DIR)); + // Create the factory reset subfolder - FR + pal_result = pal_fsMkDir(full_path_backup_dir); + if (pal_result != PAL_SUCCESS) + { + // Any error apart from file exist returns error. + if (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST) + { + tr_err("esfs_factory_reset() - pal_fsMkDir(ESFS_BACKUP_DIRECTORY/FACTORY_RESET_DIR) failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + } + + strncat(full_path_backup_dir, "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_FILE)); + // Create the fr_on flag file + pal_result = pal_fsFopen(full_path_backup_dir, PAL_FS_FLAG_READWRITEEXCLUSIVE, &(file_handle.file)); + + // (res == PAL_SUCCESS) : factory reset is called on the first time + // (res == PAL_ERR_FS_NAME_ALREADY_EXIST) : factory reset is called again after it was failed + // on the first time and therefore the file exists + if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST)) + { + tr_err("esfs_factory_reset() - unexpected filesystem behavior pal_fsFopen() failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + // close the file only if we opened it + if (pal_result == PAL_SUCCESS) + { + pal_result = pal_fsFclose(&(file_handle.file)); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_factory_reset() - unexpected filesystem behavior pal_fsFclose() failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + } + + pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + // Check if there is a single partition by comparing the primary and secondary mount points. + // This is the only reliable way to do it, since the logic that determines the number of partitions is + // hidden behind the PAL API. + pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + bool is_single_partition = (strcmp(working_dir_path,full_path_backup_dir) == 0); + + strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY)); + + // We can only format the working folder if it is dedicated for exclusive use of esfs and + // it is not the only partition that exists. The assumption here is that if it is the only partition, + // then the backup folder is also on that partition. In that case, formatting would remove the backup partition, + // which we do not want to do! + if (pal_fsIsPrivatePartition(PAL_FS_PARTITION_PRIMARY) && !is_single_partition) + { + pal_result = pal_fsFormat(PAL_FS_PARTITION_PRIMARY); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_factory_reset() - pal_fsFormat() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + pal_result = pal_fsMkDir(working_dir_path); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_factory_reset() - pal_fsMkDir(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + } + else + { + // delete the files in working dir + pal_result = pal_fsRmFiles(working_dir_path); + // the use case is that esfs folder may not exist + if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) + { + tr_err("esfs_factory_reset() - pal_fsRmFiles(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + } + + + + + pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); + return ESFS_ERROR; + } + strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); + + pal_result = pal_fsCpFolder(full_path_backup_dir, working_dir_path); + + if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE)) + { + tr_err("esfs_factory_reset() - pal_fsCpFolder() from backup to working failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(full_path_backup_dir, "/" FACTORY_RESET_DIR "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE)); + // delete the flag file because factory reset flow ended successfully + pal_result = pal_fsUnlink(full_path_backup_dir); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_factory_reset() - pal_fsUnlink(ESFS_BACKUP_DIRECTORY/FACTORY_RESET_DIR/FACTORY_RESET_FILE) failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + return ESFS_SUCCESS; + +errorExit: + return result; +} +// Internal function to check the files validity. +// Checks the name given against the name written in the file. +// Checks the version. +// Initializes some fields of file_handle: blob_name_length, esf_mode +// Assumes that the read position is at the start of the file. +// return esf_success - name matches; +// ESFS_HASH_CONFLICT - name does not match +// ESFS_WRONG_FILE_VERSION - version does not match +// ESFS_ERROR - other problem +// On ESFS_SUCCESS or ESFS_HASH_CONFLICT the read position is set after the name. +// On failure the position is undefined. +static esfs_result_e esfs_check_file_validity(const uint8_t* name, size_t name_length, esfs_file_t *file_handle) +{ + char buffer[ESFS_READ_CHUNK_SIZE_IN_BYTES]; + size_t num_bytes = 0; + int i; + esfs_result_e result = ESFS_ERROR; + palStatus_t res; + uint16_t version; + + // Read the version + num_bytes = sizeof(version); + res = pal_fsFread(&file_handle->file, (void *)( &version ), sizeof(version), &num_bytes); + //tr_info("esfs_open res=0x%x tmp=%d items=%d",(unsigned int)res,(int)tmp,(int)items); + if (res != PAL_SUCCESS || num_bytes != sizeof(version)) + { + tr_err("esfs_check_file_validity() - pal_fsFread() failed with pal result = 0x%x and num_bytes bytes = %zu", + (unsigned int)res, num_bytes); + goto errorExit; + } + if(version != ESFS_FILE_FORMAT_VERSION) + { + tr_err("esfs_check_file_validity() - invalid parameter : pal_fsFread() failed with version = %u", (unsigned int)version); + result = ESFS_INVALID_FILE_VERSION; + goto errorExit; + } + + // Read the mode + res = pal_fsFread(&file_handle->file, (void *)( &file_handle->esfs_mode ), sizeof(file_handle->esfs_mode), &num_bytes); + if (res != PAL_SUCCESS || num_bytes != sizeof(file_handle->esfs_mode)) + { + tr_err("esfs_check_file_validity() - pal_fsFread() failed with pal result = 0x%x and num_bytes bytes = %zu", + (unsigned int)res, num_bytes); + goto errorExit; + } + + // Read the name length + res = pal_fsFread(&file_handle->file, (void *)( &file_handle->blob_name_length ), sizeof(file_handle->blob_name_length), &num_bytes); + if (res != PAL_SUCCESS || num_bytes != sizeof(file_handle->blob_name_length)) + { + tr_err("esfs_check_file_validity() - pal_fsFread() failed with pal result = 0x%x and num_bytes bytes = %zu", + (unsigned int)res, num_bytes); + goto errorExit; + } + if (name_length != file_handle->blob_name_length) + { + tr_err("esfs_check_file_validity() - esfs hash conflict : The hash of the name conflicts with the hash of another name"); + // The hash of the name conflicts with the hash of another name. + result = ESFS_HASH_CONFLICT; + goto errorExit; + } + // Check the name chunk by chunk + for (i = name_length; i > 0; i -= ESFS_READ_CHUNK_SIZE_IN_BYTES) + { + // Read a chunk + num_bytes = 0; + res = pal_fsFread(&file_handle->file, (void *)buffer, PAL_MIN(i, ESFS_READ_CHUNK_SIZE_IN_BYTES), &num_bytes); + if (res != PAL_SUCCESS || num_bytes == 0) + { + tr_err("esfs_check_file_validity() - pal_fsFread() failed with pal result = 0x%x and num_bytes bytes = %zu", + (unsigned int)res, num_bytes); + goto errorExit; + } + // Check that the chunk matches + //tr_info("Comparing %s (%d bytes) name_length=%d", name, (int )num_bytes,(int )name_length); + if (memcmp(buffer, name, num_bytes) != 0) + { + tr_err("esfs_check_file_validity() - esfs hash conflict : The hash of the name conflicts with the hash of another name"); + // The hash of the name conflicts with the hash of another name. + result = ESFS_HASH_CONFLICT; + goto errorExit; + } + name += num_bytes; + } + return ESFS_SUCCESS; +errorExit: + return result; +} + + +// Internal function to check the name against the name written in the file. +// Assume that the read position is set to before the name length. +// return esf_success - name matches; +// ESFS_HASH_CONFLICT - name does not match ; +// ESFS_ERROR - other problem +// On ESFS_SUCCESS or ESFS_HASH_CONFLICT the read position is set after the name. +// On failure the position is undefined. +static esfs_result_e esfs_check_cmac(esfs_file_t *file_handle) +{ + // General purpose reusable buffer. It should be at least 2*ESFS_CMAC_SIZE_IN_BYTES bytes + unsigned char buffer[ESFS_READ_CHUNK_SIZE_IN_BYTES]; + + size_t num_bytes; + int i; + esfs_result_e result = ESFS_ERROR; + palStatus_t res; + int32_t file_size; + int32_t initial_pos; + + palCMACHandle_t signature_ctx; + uint16_t cmac_created = 0; + + // Verify that the at least 2*ESFS_CMAC_SIZE_IN_BYTES bytes + PAL_ASSERT_STATIC(sizeof(buffer) >= (2*ESFS_CMAC_SIZE_IN_BYTES)); + + // Get current position + res = pal_fsFtell(&file_handle->file, &initial_pos); + if(res != PAL_SUCCESS) + { + tr_err("esfs_check_cmac() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + + // Seek to end of file + res = pal_fsFseek(&file_handle->file, 0, PAL_FS_OFFSET_SEEKEND); + if(res != PAL_SUCCESS) + { + tr_err("esfs_check_cmac() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + + // Get new position + res = pal_fsFtell(&file_handle->file, &file_size); + if(res != PAL_SUCCESS) + { + tr_err("esfs_check_cmac() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + + // Set to the start of the file + res = pal_fsFseek(&file_handle->file, 0, PAL_FS_OFFSET_SEEKSET); + if(res != PAL_SUCCESS) + { + tr_err("esfs_check_cmac() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + + + res = pal_osGetDeviceKey128Bit(palOsStorageSignatureKey, &buffer[0], ESFS_CMAC_SIZE_IN_BYTES); // Now first 16 Bytes of buffer contain the key + if(res != PAL_SUCCESS) + { + tr_err("esfs_check_cmac() - pal_osGetDeviceKey128Bit() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + + // Start CMAC with the key + res = pal_CMACStart(&signature_ctx, &buffer[0], 128, PAL_CIPHER_ID_AES); + if(res != PAL_SUCCESS) + { + tr_err("esfs_check_cmac() - pal_CMACStart() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + else + { + cmac_created = 1; + } + + // Iterate over the file in chunks to calculate the cmac + // buffer will contain only data read form the file + for (i = file_size - ESFS_CMAC_SIZE_IN_BYTES; i > 0; i -= ESFS_READ_CHUNK_SIZE_IN_BYTES) + { + // Read a chunk + // Here we read the file as is - plain text or encrypted + res = pal_fsFread(&file_handle->file, buffer, PAL_MIN(i, ESFS_READ_CHUNK_SIZE_IN_BYTES), &num_bytes); + if (res != PAL_SUCCESS || num_bytes == 0) + { + tr_err("esfs_check_cmac() - pal_fsFread() (Iterate over the file in chunks) failed with pal result = 0x%x and num_bytes bytes = %zu", + (unsigned int)res, num_bytes); + goto errorExit; + } + // Update the cmac calculation according to the data that was read. + res = pal_CMACUpdate(signature_ctx, buffer, num_bytes); + if(res != PAL_SUCCESS) + { + tr_err("esfs_check_cmac() - pal_CMACStart() (Iterate over the file in chunks) failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + } + + res = pal_CMACFinish(&signature_ctx, &buffer[0], &num_bytes); // Now first 16 Bytes of buffer contain the CMAC signature + tr_info("esfs_close len=%d", (int)num_bytes); + if(res != PAL_SUCCESS) + { + tr_err("esfs_check_cmac() - pal_CMACFinish() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + cmac_created = 0; + + // Read the signature from the file + res = pal_fsFread(&file_handle->file, &buffer[ESFS_CMAC_SIZE_IN_BYTES], ESFS_CMAC_SIZE_IN_BYTES, &num_bytes); + if (res != PAL_SUCCESS || num_bytes != ESFS_CMAC_SIZE_IN_BYTES) + { + tr_err("esfs_check_cmac() - pal_fsFread() (signature) failed with pal result = 0x%x and num_bytes bytes = %zu", + (unsigned int)res, num_bytes); + goto errorExit; + } + + // Now first 16 Bytes of buffer contain the CMAC calculated signature, + // and next 16 Bytes contain the CMAC signature written at the end of the file + + // Restore initial position + res = pal_fsFseek(&file_handle->file, initial_pos, PAL_FS_OFFSET_SEEKSET); + if(res != PAL_SUCCESS) + { + tr_err("esfs_check_cmac() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + + // Compare the cmac that we read from the file with the one that we calculated. + if(memcmp(&buffer[0], &buffer[ESFS_CMAC_SIZE_IN_BYTES], ESFS_CMAC_SIZE_IN_BYTES) != 0) + { + tr_err("esfs_check_cmac() - cmac that we read from the file does not match the one that we calculated"); + return ESFS_CMAC_DOES_NOT_MATCH; + } + else + { + return ESFS_SUCCESS; + } +errorExit: + if(cmac_created) + { + // Clean up cmac. Ignore error. + (void)pal_CMACFinish(&signature_ctx, &buffer[0], &num_bytes); + } + // No need to restore position on failure. + return result; + +} + + +// Helper function +// Restores current position unless it fails. +// On failure the position is undefined. +static palStatus_t esfs_get_physical_file_size(palFileDescriptor_t* fd, int32_t *file_size) +{ + int32_t current_pos = 0; + palStatus_t res; + + // Get current position + res = pal_fsFtell(fd, ¤t_pos); + if (res != PAL_SUCCESS) + { + tr_err("esfs_get_physical_file_size() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + // Seek to end of file + res = pal_fsFseek(fd, 0, PAL_FS_OFFSET_SEEKEND); + if (res != PAL_SUCCESS) + { + tr_err("esfs_get_physical_file_size() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + // Get new position + res = pal_fsFtell(fd, file_size); + if (res != PAL_SUCCESS) + { + tr_err("esfs_get_physical_file_size() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + // Restore old position + res = pal_fsFseek(fd, current_pos, PAL_FS_OFFSET_SEEKSET); + if (res != PAL_SUCCESS) + { + tr_err("esfs_get_physical_file_size() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + +errorExit: + return res; +} + + +static esfs_result_e esfs_copy_file(const char *src_file, const char *dst_file) +{ + bool is_src_file_opened = false; + bool is_dst_file_opened = false; + esfs_file_t file_handle = { 0 }; + esfs_file_t file_handle_copy = { 0 }; + esfs_result_e result = ESFS_ERROR; + palStatus_t res = PAL_SUCCESS; + size_t bytes_to_read = ESFS_FILE_COPY_CHUNK_SIZE; + size_t num_bytes_read = 0; + size_t num_bytes_write = 0; + uint8_t buffer[ESFS_FILE_COPY_CHUNK_SIZE] = {0}; + int32_t file_size = 0; + int32_t copied_bytes = 0; + // Open src file read only mode + res = pal_fsFopen(src_file, PAL_FS_FLAG_READONLY, &(file_handle.file)); + if (res != PAL_SUCCESS) + { + // File cannot be opened so return an error + tr_err("esfs_copy_file() - pal_fsFopen() src file failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_NOT_EXISTS; + goto errorExit; + } + is_src_file_opened = true; + // Open for reading and writing exclusively, If the file already exists, trunced file + res = pal_fsFopen(dst_file, PAL_FS_FLAG_READWRITETRUNC, &(file_handle_copy.file)); + if (res != PAL_SUCCESS) + { + // File cannot be opened so return an error + tr_err("esfs_copy_file() - pal_fsFopen() dst file failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + is_dst_file_opened = true; + + res = esfs_get_physical_file_size(&(file_handle.file), &file_size); + if (res != PAL_SUCCESS) + { + tr_err("esfs_copy_file() - esfs_get_physical_file_size() failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + while (copied_bytes < file_size) + { + if (copied_bytes + (int32_t)bytes_to_read > file_size) + { + bytes_to_read = file_size - copied_bytes; + } + res = pal_fsFread(&(file_handle.file), buffer, bytes_to_read, &num_bytes_read); + if (res != PAL_SUCCESS) + { + tr_err("esfs_copy_file() - pal_fsFread() failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + + res = pal_fsFwrite(&(file_handle_copy.file), buffer, bytes_to_read, &num_bytes_write); + if ((res != PAL_SUCCESS) || (num_bytes_write != bytes_to_read)) + { + tr_err("esfs_copy_file() - pal_fsFwrite() failed with pal result = 0x%x and num_bytes_write bytes = %zu", + (unsigned int)res, num_bytes_write); + result = ESFS_ERROR; + goto errorExit; + } + + copied_bytes += bytes_to_read; + + } + + + res = pal_fsFclose(&(file_handle.file)); + if (res != PAL_SUCCESS) + { + tr_err("esfs_copy_file() - pal_fsFclose() for src file failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + res = pal_fsFclose(&(file_handle_copy.file)); + if (res != PAL_SUCCESS) + { + tr_err("esfs_copy_file() - pal_fsFclose() for dst file failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + return ESFS_SUCCESS; + +errorExit: + if (is_src_file_opened) + { + // we will not delete the src file + pal_fsFclose(&(file_handle.file)); + } + + if (is_dst_file_opened) + { + pal_fsFclose(&(file_handle_copy.file)); + // Clean up if possible. Ignore return value. + (void)pal_fsUnlink(dst_file); + } + return result; +} + + +// We assume a null terminated name for the time being. +static esfs_result_e esfs_create_internal( const uint8_t *name, + size_t name_length, + const esfs_tlv_item_t *meta_data, + size_t meta_data_qty, + uint16_t esfs_mode, + esfs_file_t *file_handle, + const char* full_path_to_create + ) +{ + uint8_t key[ESFS_CMAC_SIZE_IN_BYTES]; + + esfs_result_e result = ESFS_ERROR; + palStatus_t res = PAL_SUCCESS; + + int32_t position = 0; + size_t num_bytes = 0; + size_t i; + uint16_t file_created = 0; + uint16_t u16; + + + // Create the file + res = pal_fsFopen(full_path_to_create, PAL_FS_FLAG_READWRITEEXCLUSIVE, &file_handle->file); + + if(res != PAL_SUCCESS) + { + if(res == PAL_ERR_FS_NAME_ALREADY_EXIST) + { + result = ESFS_EXISTS; + // Check if there is a different name in the file + // Check that the name written inside the file is the same as that given. If not + // you should choose a different name. + res = pal_fsFopen(full_path_to_create, PAL_FS_FLAG_READONLY, &file_handle->file); + if(res == PAL_SUCCESS) + { + file_handle->esfs_mode = 0; + // result can be ESFS_HASH_CONFLICT or ESFS_WRONG_FILE_VERSION + esfs_result_e check_result = esfs_check_file_validity(name, name_length, file_handle); + if(check_result == ESFS_HASH_CONFLICT || check_result == ESFS_INVALID_FILE_VERSION) + { + result = check_result; + } + pal_fsFclose(&file_handle->file); + } + } + // more informative message will be written after hash conflict will be implemented + tr_err("esfs_create_internal() - pal_fsFopen() failed"); + goto errorExit; + } + + + file_created = 1; + + res = pal_osGetDeviceKey128Bit(palOsStorageSignatureKey, &key[0], ESFS_CMAC_SIZE_IN_BYTES); + if(res != PAL_SUCCESS) + { + tr_err("esfs_create_internal() - pal_osGetDeviceKey128Bit() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + res = pal_CMACStart(&file_handle->signature_ctx, &key[0], 128, PAL_CIPHER_ID_AES); + if(res != PAL_SUCCESS) + { + tr_err("esfs_create_internal() - pal_CMACStart() failed with pal_status = 0x%x", (unsigned int)res); + goto errorExit; + } + + + // Write the version + u16 = ESFS_FILE_FORMAT_VERSION; + num_bytes = sizeof(u16); + result = esfs_fwrite_and_calc_cmac(&u16, &num_bytes, file_handle); + if(result != ESFS_SUCCESS || num_bytes != sizeof(u16)) + { + tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for esfs version failed with esfs result = 0x%x and num_bytes bytes = %zu", + result, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + + // Write the mode + num_bytes = sizeof(esfs_mode); + result = esfs_fwrite_and_calc_cmac(&esfs_mode, &num_bytes, file_handle); + if(result != ESFS_SUCCESS || num_bytes != sizeof(esfs_mode)) + { + tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for esfs_mode failed with esfs result = 0x%x and num_bytes bytes = %zu", + result, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + + // Header + // Write the name length + u16 = (uint16_t)name_length; + num_bytes = sizeof(u16); + result = esfs_fwrite_and_calc_cmac(&u16, &num_bytes, file_handle); + if(result != ESFS_SUCCESS || num_bytes != sizeof(u16)) + { + tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for name_length failed with esfs result = 0x%x and num_bytes bytes = %zu", + result, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + + // Write the name + num_bytes = name_length; + result = esfs_fwrite_and_calc_cmac(name, &num_bytes, file_handle); + if(result != ESFS_SUCCESS || num_bytes != name_length) + { + tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for name failed with esfs result = 0x%x and num_bytes bytes = %zu", + result, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + + // In case of an encrypted esfs, write the AES nonce + if((esfs_mode & ESFS_ENCRYPTED) != 0) + { + num_bytes = ESFS_AES_NONCE_SIZE_BYTES; + + result = esfs_fwrite_and_calc_cmac((void *)(file_handle->nonce), &num_bytes, file_handle); + + if( (result != ESFS_SUCCESS) || (num_bytes != ESFS_AES_NONCE_SIZE_BYTES) ) + { + tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for AES nonce failed with esfs result = 0x%x and num_bytes bytes = %zu", + result, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + } + + // Write the Metadata header + // Write the number of items of meta data + u16 = (uint16_t)meta_data_qty; + num_bytes = sizeof(u16), + result = esfs_fwrite_and_calc_cmac(&u16, &num_bytes, file_handle); + if(result != ESFS_SUCCESS || num_bytes != sizeof(u16)) + { + tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for number of items of meta data failed with esfs result = 0x%x and num_bytes bytes = %zu", + result, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + + if(meta_data_qty != 0) + { + res = pal_fsFtell(&file_handle->file, &position); + if(res != PAL_SUCCESS) + { + tr_err("esfs_create_internal() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + position += (sizeof(file_handle->tlv_properties.tlv_items[0]) * meta_data_qty); + for(i = 0; i < meta_data_qty; i++ ) + { + file_handle->tlv_properties.tlv_items[i].type = meta_data[i].type; + file_handle->tlv_properties.tlv_items[i].length_in_bytes = meta_data[i].length_in_bytes; + file_handle->tlv_properties.tlv_items[i].position = (uint16_t)position; + // Increment position for next iteration + position += meta_data[i].length_in_bytes; + } + + // Write the metadata items + num_bytes = sizeof(file_handle->tlv_properties.tlv_items[0])*meta_data_qty; + result = esfs_fwrite_and_calc_cmac(&file_handle->tlv_properties.tlv_items[0], &num_bytes, file_handle); + if(result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->tlv_properties.tlv_items[0])*meta_data_qty) + { + tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for meta data items failed with esfs result = 0x%x and num_bytes bytes = %zu", + result, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + + // Set the number_of_items field here since it is in use later in this function + // when we calculate the file header size + file_handle->tlv_properties.number_of_items = meta_data_qty; + + // Write the Metadata data values + // If encrypted esfs is requested (by the esfs_mode argument), then this part should be encrypted + for(i = 0; i < meta_data_qty; i++ ) + { + num_bytes = meta_data[i].length_in_bytes; + + if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) + { + result = esfs_encrypt_fwrite_and_calc_cmac(meta_data[i].value, &num_bytes, file_handle); + } + else + { + result = esfs_fwrite_and_calc_cmac(meta_data[i].value, &num_bytes, file_handle); + } + + if(result != ESFS_SUCCESS || num_bytes != meta_data[i].length_in_bytes) + { + tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for meta data item values failed with esfs result = 0x%x and num_bytes bytes = %zu", + result, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + } + } + + + file_handle->file_flag = ESFS_WRITE; + + return ESFS_SUCCESS; + +errorExit: + + if(file_created) + { + pal_fsFclose(&file_handle->file); + // Clean up if possible. Ignore return value. + (void)pal_fsUnlink(full_path_to_create); + } + + return result; +} + + +// --------------------------------------------------------------- +// API Functions +// --------------------------------------------------------------- + + +esfs_result_e esfs_create(const uint8_t *name, size_t name_length, const esfs_tlv_item_t *meta_data, size_t meta_data_qty, uint16_t esfs_mode, esfs_file_t *file_handle) +{ + char file_full_path[MAX_FULL_PATH_SIZE] = { 0 }; + + palStatus_t res = PAL_SUCCESS; + esfs_result_e result = ESFS_ERROR; + + bool is_aes_ctx_created = false; + + uint8_t aes_key[ESFS_AES_KEY_SIZE_BYTES] = {0}; // For AES encryption + + + // Verify that the structure is always packed to six bytes, since we read and write it as a whole. + PAL_ASSERT_STATIC(sizeof(esfs_tlvItem_t) == 6); + + // Verify that the array is always packed without padding, since we read and write it as a whole. + PAL_ASSERT_STATIC(sizeof(esfs_tlvItem_t[ESFS_MAX_TYPE_LENGTH_VALUES]) == ESFS_MAX_TYPE_LENGTH_VALUES * sizeof(esfs_tlvItem_t)); + + tr_info("esfs_create - enter"); + + + // Check parameters + if (!file_handle || !name || name_length == 0 || name_length > ESFS_MAX_NAME_LENGTH || meta_data_qty > ESFS_MAX_TYPE_LENGTH_VALUES) + { + tr_err("esfs_create() failed with bad parameters"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + + for(size_t meta_data_index = 0; meta_data_index < meta_data_qty; meta_data_index++ ) + { + if ((!meta_data[meta_data_index].value) || (meta_data[meta_data_index].length_in_bytes == 0)) + { + tr_err("esfs_create() failed with bad parameters for metadata"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + + } + + res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, file_full_path); + if (res != PAL_SUCCESS) + { + tr_err("esfs_create() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(file_full_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); + + // If esef is in encryption mode, make the required initializations + if((esfs_mode & ESFS_ENCRYPTED) != 0) + { + // ** Create AES context for AES encryption + res = pal_initAes( &(file_handle->aes_ctx) ); + + if(res != PAL_SUCCESS) + { + tr_err("esfs_create() - pal_initAes() failed with pal status 0x%x", (unsigned int)res); + result = ESFS_ERROR ; + goto errorExit; + } + + is_aes_ctx_created = true; + + // ** Get AES key from PAL + // Note: On each call, PAL should return the same 128 bits key + res = pal_osGetDeviceKey128Bit(palOsStorageEncryptionKey, aes_key, ESFS_AES_KEY_SIZE_BYTES); + + if(res != PAL_SUCCESS) + { + tr_err("esfs_create() - pal_osGetDeviceKey128Bit() failed with pal status 0x%x", (unsigned int)res); + result = ESFS_ERROR ; + goto errorExit; + } + + // ** Assign generated AES key to AES context + res = pal_setAesKey( file_handle->aes_ctx, + aes_key, + ESFS_AES_KEY_SIZE_BITS, + PAL_KEY_TARGET_ENCRYPTION + ); + + if(res != PAL_SUCCESS) + { + tr_err("esfs_create() - pal_setAesKey() failed with pal status 0x%x", (unsigned int)res); + result = ESFS_ERROR ; + goto errorExit; + } + + // ** Generate the AES nonce for AES usage + res = pal_osRandomBuffer(file_handle->nonce, ESFS_AES_NONCE_SIZE_BYTES); + + if(res != PAL_SUCCESS) + { + tr_err("esfs_create() - pal_osRandomBuffer() failed with pal status 0x%x", (unsigned int)res); + result = ESFS_ERROR ; + goto errorExit; + } + } + + + // We set the blob_name_length filed here because it is in use later in this function when we calculate the file header size. + // Since this field is also used to check the file handle validity [ esfs_validate() ] we set it to zero on an error exit. + file_handle->blob_name_length = name_length; + + file_handle->esfs_mode = esfs_mode; + + file_handle->file_invalid = 0; + + file_handle->tlv_properties.number_of_items = 0; + + if (esfs_get_name_from_blob(name, name_length, file_handle->short_file_name, ESFS_FILE_NAME_LENGTH) != ESFS_SUCCESS) + { + tr_err("esfs_create() - esfs_get_name_from_blob() failed"); + goto errorExit; + } + strncat(file_full_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); + + // Check if the file exists in esfs working directory + res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READWRITEEXCLUSIVE, &file_handle->file); + if (res != PAL_SUCCESS) + { + if (res == PAL_ERR_FS_NAME_ALREADY_EXIST) + { + result = ESFS_EXISTS; + // Check if there is a different name in the file + // Check that the name written inside the file is the same as that given. If not + // you should choose a different name. + res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READONLY, &file_handle->file); + if (res == PAL_SUCCESS) + { + file_handle->esfs_mode = 0; + // result can be ESFS_HASH_CONFLICT or ESFS_WRONG_FILE_VERSION + esfs_result_e check_result = esfs_check_file_validity(name, name_length, file_handle); + if (check_result == ESFS_HASH_CONFLICT || check_result == ESFS_INVALID_FILE_VERSION) + { + result = check_result; + } + pal_fsFclose(&file_handle->file); + } + } + // more informative message will be written after hash conflict will be implemented + tr_err("esfs_create() - pal_fsFopen() for working dir file failed"); + goto errorExit; + } + + // close the file - it was opened in order to verify whether the file exists or not + res = pal_fsFclose(&file_handle->file); + if (res != PAL_SUCCESS) + { + tr_err("esfs_create() - pal_fsFclose() for working dir file failed with pal status 0x%x", (unsigned int)res); + result = ESFS_ERROR; + // Clean up if possible. Ignore return value. + (void)pal_fsUnlink(file_full_path); + goto errorExit; + } + res = pal_fsUnlink(file_full_path); + if (res != PAL_SUCCESS) + { + tr_err("esfs_create() - pal_fsUnlink() for working dir file failed with pal status 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + + // factory reset file + if (esfs_mode & (uint16_t)ESFS_FACTORY_VAL) + { + + res = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, file_full_path); + if (res != PAL_SUCCESS) + { + + tr_err("esfs_create() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(file_full_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); + + // Create the esfs subfolder for backup + res = pal_fsMkDir(file_full_path); + if (res != PAL_SUCCESS) + { + // Any error apart from file exist returns error. + if (res != PAL_ERR_FS_NAME_ALREADY_EXIST) + { + tr_err("esfs_create() - pal_fsMkDir() for backup dir failed with pal status 0x%x", (unsigned int)res); + goto errorExit; + } + } + strncat(file_full_path, "/", 1); + strncat(file_full_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); + // Check if the file exists in esfs backup directory + res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READWRITEEXCLUSIVE, &file_handle->file); + + // * If res == PAL_SUCCESS: File does not exist and we will create it + // * If res != PAL_SUCCESS && res == PAL_ERR_FS_NAME_ALREADY_EXIST: Update factory reset file + // * If res != PAL_SUCCESS && res != PAL_ERR_FS_NAME_ALREADY_EXIST: Error is returned + if (res != PAL_SUCCESS) + { + if (res == PAL_ERR_FS_NAME_ALREADY_EXIST) + { + // Check if there is a different name in the file + // Check that the name written inside the file is the same as that given. If not + // you should choose a different name. + res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READONLY, &file_handle->file); + if (res == PAL_SUCCESS) + { + file_handle->esfs_mode = 0; + // result can be ESFS_HASH_CONFLICT or ESFS_WRONG_FILE_VERSION + esfs_result_e check_result = esfs_check_file_validity(name, name_length, file_handle); + + if (check_result == ESFS_HASH_CONFLICT || check_result == ESFS_INVALID_FILE_VERSION) + { + tr_err("esfs_create() - esfs_check_file_validity() failed with status 0x%x", check_result); + result = check_result; + goto errorExit; + } + //TODO - here should add hash conflict functionality + // if we reach this point - update factory reset file + // we need to close the file and delete it, follow by creating it again + // creation will be done in esfs_create_internal function + } + else + { + // more informative message will be written after hash conflict will be implemented + tr_err("esfs_create() - pal_fsFopen() failed"); + result = ESFS_ERROR; + goto errorExit; + } + } + else + { + // more informative message will be written after hash conflict will be implemented + tr_err("esfs_create() - pal_fsFopen() for backup dir file failed"); + result = ESFS_ERROR; + goto errorExit; + } + } + + /*closing and deleting the factory reset file that was created*/ + res = pal_fsFclose(&file_handle->file); + if (res != PAL_SUCCESS) + { + tr_err("esfs_create() - pal_fsFclose() for backup dir file failed with pal status 0x%x", (unsigned int)res); + result = ESFS_ERROR; + // Clean up if possible. Ignore return value. + (void)pal_fsUnlink(file_full_path); + goto errorExit; + } + // Delete backup file + res = pal_fsUnlink(file_full_path); + if (res != PAL_SUCCESS) + { + tr_err("esfs_create() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + } + + + // file_full_path contains the correct location (working/backup) + result = esfs_create_internal(name, name_length, meta_data, meta_data_qty, esfs_mode, file_handle, file_full_path); + + if(result != ESFS_SUCCESS) + { + tr_err("esfs_create() - esfs_create_internal() failed with result 0x%x", result); + goto errorExit; + } + + return ESFS_SUCCESS; + +errorExit: + + // Invalidate blob_name_length filed since it is used to check the file handle validity [ esfs_validate() ] + if(file_handle != NULL) + { + file_handle->blob_name_length = 0; + } + + if(is_aes_ctx_created) + { + pal_freeAes( &(file_handle->aes_ctx) ); + } + return result; +} + + +esfs_result_e esfs_open(const uint8_t *name, size_t name_length, uint16_t *esfs_mode, esfs_file_t *file_handle) +{ + char working_dir_path[MAX_FULL_PATH_SIZE] = { 0 }; + esfs_result_e result = ESFS_ERROR; + palStatus_t res = PAL_SUCCESS; + size_t num_bytes = 0; + uint16_t file_opened = 0; + + bool is_aes_ctx_created = false; + + uint8_t aes_key[ESFS_AES_KEY_SIZE_BYTES] = {0}; // For AES decryption + + uint16_t meta_data_qty; + int32_t file_size; + + tr_info("esfs_open - enter"); + // Check parameters + if(!file_handle || !name || name_length == 0 || name_length > ESFS_MAX_NAME_LENGTH) + { + tr_err("esfs_open() failed with bad parameters"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + + res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path); + if (res != PAL_SUCCESS) + { + tr_err("esfs_open() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res); + return ESFS_ERROR; + } + + strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); + + + // This is used to esfs_validate the file handle so we set it to zero here and only when open + // succeeds to the real value. + file_handle->blob_name_length = 0; + + file_handle->file_invalid = 0; + + if(esfs_get_name_from_blob(name, name_length, file_handle->short_file_name, ESFS_FILE_NAME_LENGTH) != ESFS_SUCCESS) + { + tr_err("esfs_open() - esfs_get_name_from_blob() failed"); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(working_dir_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); + + // Open the file read only + res = pal_fsFopen(working_dir_path, PAL_FS_FLAG_READONLY, &file_handle->file); + if(res != PAL_SUCCESS) + { + tr_err("esfs_open() - pal_fsFopen() for working dir file failed with pal_status = 0x%x", (unsigned int)res); + // File cannot be opened so return an error + result = ESFS_NOT_EXISTS; + goto errorExit; + } + + file_opened = 1; + + // Check that the name written inside the file is the same as that given + // Note: After this call, the read position will be set to the point after the "Name Blob" + result = esfs_check_file_validity(name, name_length, file_handle); + if(result != ESFS_SUCCESS) + { + tr_err("esfs_open() - esfs_check_file_validity() failed with status = 0x%x", result); + // File cannot be opened so return an error + goto errorExit; + } + + // Check the signature if required + result = esfs_check_cmac(file_handle); + if(result != ESFS_SUCCESS) + { + tr_err("esfs_open() - esfs_check_cmac() (signature) failed with status = 0x%x", result); + goto errorExit; + } + + if (esfs_mode) + { + *esfs_mode = file_handle->esfs_mode; // file_handle->esfs_mode was set by esfs_check_file_validity() + } + + // If esfs is in encryption mode, make the required initializations + if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) + { + // ** Create AES context for AES decryption + res = pal_initAes( &(file_handle->aes_ctx) ); + + if(res != PAL_SUCCESS) + { + tr_err("esfs_open() - pal_initAes() failed with status 0x%x", (unsigned int)res); + result = ESFS_ERROR ; + goto errorExit; + } + + is_aes_ctx_created = true; + + // ** Get AES key from PAL + // Note: On each call, PAL should return the same 128 bits key + res = pal_osGetDeviceKey128Bit(palOsStorageEncryptionKey, aes_key, ESFS_AES_KEY_SIZE_BYTES); + + if(res != PAL_SUCCESS) + { + tr_err("esfs_open() - pal_osGetDeviceKey128Bit() failed with status 0x%x", (unsigned int)res); + result = ESFS_ERROR ; + goto errorExit; + } + + // ** Assign generated AES key to AES context + res = pal_setAesKey( file_handle->aes_ctx, + aes_key, + ESFS_AES_KEY_SIZE_BITS, + PAL_KEY_TARGET_ENCRYPTION + ); + + if(res != PAL_SUCCESS) + { + tr_err("esfs_open() - pal_setAesKey() failed with status 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + + // ** Read the AES nonce into file_handle->nonce + num_bytes = 0; + + res = pal_fsFread(&(file_handle->file), file_handle->nonce, ESFS_AES_NONCE_SIZE_BYTES, &num_bytes); + + if((res != PAL_SUCCESS) || (num_bytes != ESFS_AES_NONCE_SIZE_BYTES)) + { + tr_err("esfs_open() - pal_fsFread() (AES nonce) failed with pal result = 0x%x and num_bytes bytes = %zu", + (unsigned int)res, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + } + + file_handle->tlv_properties.number_of_items = 0; + + // Read the number of items of meta data + num_bytes = 0; + res = pal_fsFread(&file_handle->file, (void *)( &meta_data_qty ), sizeof(meta_data_qty), &num_bytes); + if(res != PAL_SUCCESS || num_bytes != sizeof(meta_data_qty)) + { + tr_err("esfs_open() - pal_fsFread() (number of items of meta data) failed with pal result = 0x%x and num_bytes bytes = %zu", + (unsigned int)res, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + + // Read the metadata properties if there are any + if(meta_data_qty != 0) + { + num_bytes = 0; + res = pal_fsFread( &file_handle->file, + (void *) ( &(file_handle->tlv_properties.tlv_items[0]) ), + (sizeof(file_handle->tlv_properties.tlv_items[0]) * meta_data_qty), + &num_bytes + ); + + if(res != PAL_SUCCESS || num_bytes != sizeof(file_handle->tlv_properties.tlv_items[0])*meta_data_qty) + { + tr_err("esfs_open() - pal_fsFread() (metadata properties) failed with pal result = 0x%x and num_bytes bytes = %zu", + (unsigned int)res, num_bytes); + result = ESFS_ERROR; + goto errorExit; + } + + // Skip to the start of the data by calculating the last metadata position plus its length + esfs_tlvItem_t *ptypeLengthValueItem = &file_handle->tlv_properties.tlv_items[meta_data_qty - 1]; + + res = pal_fsFseek(&file_handle->file, + ptypeLengthValueItem->position + ptypeLengthValueItem->length_in_bytes, + PAL_FS_OFFSET_SEEKSET + ); + + if(res != PAL_SUCCESS) + { + tr_err("esfs_open() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + } + + file_handle->tlv_properties.number_of_items = meta_data_qty; + + // We are at the start of the data section + file_handle->current_read_pos = 0; + + // Calculate the size of the data only by getting the file size and deducting the header and cmac + res = esfs_get_physical_file_size(&file_handle->file, &file_size); + if (res != PAL_SUCCESS) + { + tr_err("esfs_open() - esfs_get_physical_file_size() failed with status 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + + file_handle->data_size = file_size - esfs_file_header_size(file_handle); + + // We deduct the cmac bytes at the end of the file since they are not part of the data + file_handle->data_size -= ESFS_CMAC_SIZE_IN_BYTES; + + file_handle->file_flag = ESFS_READ; + file_handle->blob_name_length = name_length; + + return ESFS_SUCCESS; + +errorExit: + if(file_opened) + { + pal_fsFclose(&file_handle->file); + } + + if(is_aes_ctx_created) + { + pal_freeAes( &(file_handle->aes_ctx) ); + } + + return result; +} + +esfs_result_e esfs_write(esfs_file_t *file_handle, const void *buffer, size_t bytes_to_write) +{ + esfs_result_e result = ESFS_ERROR; + + size_t num_bytes; + tr_info("esfs_write - enter"); + if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!buffer) || (bytes_to_write == 0)) + { + tr_err("esfs_write() failed with bad parameters"); + return ESFS_INVALID_PARAMETER; + } + + if(file_handle->file_flag == ESFS_READ) + { + tr_err("esfs_write() write failed - file is opened for read only"); + result = ESFS_FILE_OPEN_FOR_READ; + goto errorExit; + } + else + { + // Write data + // If encrypted esfs is requested (file_handle->esfs_mode), then this part should be encrypted + num_bytes = bytes_to_write; + + // The data should be encrypted if the encrypted esfs is requested by the esfs_mode argument + if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) + { + result = esfs_encrypt_fwrite_and_calc_cmac(buffer, &num_bytes, file_handle); + } + else + { + result = esfs_fwrite_and_calc_cmac(buffer, &num_bytes, file_handle); + } + + if(result != ESFS_SUCCESS || num_bytes != bytes_to_write) + { + tr_err("esfs_write() - esfs_fwrite_and_calc_cmac()/esfs_encrypt_fwrite_and_calc_cmac() for data failed with esfs result = 0x%x and num_bytes bytes = %zu", + result, num_bytes); + // Since the write failed, we cannot be sure of the state of the file, so we mark it as invalid. + file_handle->file_invalid = 1; + result = ESFS_ERROR; + goto errorExit; + } + } + + return ESFS_SUCCESS; + +errorExit: + return result; +} + +esfs_result_e esfs_read(esfs_file_t *file_handle, void *buffer, size_t bytes_to_read, size_t *read_bytes) +{ + size_t num_bytes = 0; + esfs_result_e result = ESFS_ERROR; + tr_info("esfs_read - enter"); + if(esfs_validate(file_handle) != ESFS_SUCCESS || read_bytes == NULL || !buffer) + { + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + + if(file_handle->file_flag != ESFS_READ) + { + result = ESFS_FILE_OPEN_FOR_WRITE; + goto errorExit; + } + else + { + // Limit how many bytes we can actually read depending on the size of the data section. + size_t remaining_bytes = file_handle->data_size - file_handle->current_read_pos; + bytes_to_read = PAL_MIN(remaining_bytes, bytes_to_read); + + // Read data + // If required according to esfs_mode, the read data will be decrypted + if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) + { + if(esfs_read_and_decrypt(file_handle, buffer, bytes_to_read, &num_bytes) != ESFS_SUCCESS) + { + goto errorExit; + } + } + else + { + if(pal_fsFread( &(file_handle->file), buffer, bytes_to_read, &num_bytes ) != PAL_SUCCESS) + { + goto errorExit; + } + } + + *read_bytes = num_bytes; + + // Update the current position + file_handle->current_read_pos += num_bytes; + } + + return ESFS_SUCCESS; + +errorExit: + tr_err("esfs_read errorExit result=0x%x", result); + return result; +} + +esfs_result_e esfs_seek(esfs_file_t *file_handle, int32_t offset, esfs_seek_origin_e whence, uint32_t *position) +{ + palStatus_t res; + esfs_result_e result = ESFS_ERROR; + tr_info("esfs_seek - enter"); + if(esfs_validate(file_handle) != ESFS_SUCCESS) + { + tr_err("esfs_seek() failed with bad parameters"); + return ESFS_INVALID_PARAMETER; + } + + if(file_handle->file_flag != ESFS_READ) + { + tr_err("esfs_seek() seek failed - file is opened for write only"); + result = ESFS_FILE_OPEN_FOR_WRITE; + goto errorExit; + } + else + { + pal_fsOffset_t pal_whence; + // ESFS whence enum values are in sync with those of pal + if(whence == ESFS_SEEK_SET) + { + if(offset > (int32_t)file_handle->data_size || offset < 0) + { + tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_SET"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + // Add the offset to the start of the data + offset += esfs_file_header_size(file_handle); + pal_whence = PAL_FS_OFFSET_SEEKSET; + } + else if(whence == ESFS_SEEK_END) + { + if(offset < -(int32_t)file_handle->data_size || offset > 0) + { + tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_END"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + // Deduct the cmac size from the offset because it is located after the data section. + offset -= ESFS_CMAC_SIZE_IN_BYTES; + pal_whence = PAL_FS_OFFSET_SEEKEND; + } + else if(whence == ESFS_SEEK_CUR) + { + if(offset + file_handle->current_read_pos > (int32_t)file_handle->data_size || offset + (int32_t)file_handle->current_read_pos < 0) + { + tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_CUR"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + pal_whence = PAL_FS_OFFSET_SEEKCUR; + } + else + { + tr_err("esfs_seek() failed with bad parameters - wrong whence"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + res = pal_fsFseek(&file_handle->file, offset, pal_whence); + if(res != PAL_SUCCESS) + { + tr_err("esfs_seek() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); + goto errorExit; + } + } + // Get current position if position is not NULL + if(position) + { + res = pal_fsFtell(&file_handle->file, (int32_t *)position); + if(res != PAL_SUCCESS) + { + tr_err("esfs_seek() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res); + goto errorExit; + } + + // Ignore the file header data + *position -= esfs_file_header_size(file_handle); + + // Update the current position + file_handle->current_read_pos = *position; + } + + return ESFS_SUCCESS; + +errorExit: + return result; +} + + +esfs_result_e esfs_file_size(esfs_file_t *file_handle, size_t *size_in_bytes) +{ + palStatus_t res = PAL_SUCCESS; + int32_t file_size; + esfs_result_e result = ESFS_ERROR; + + tr_info("esfs_file_size - enter"); + if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!size_in_bytes)) + { + tr_err("esfs_file_size() failed with bad parameters"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + + res = esfs_get_physical_file_size(&file_handle->file, &file_size); + if (res != PAL_SUCCESS) { + tr_err("esfs_file_size() - esfs_get_physical_file_size() failed with status 0x%x", (unsigned int)res); + goto errorExit; + } + + // Deduct header size + *size_in_bytes = file_size - esfs_file_header_size(file_handle); + + // Deduct signature size (128 bits) only if it has been written already. Since it is written on + // esfs_close it will only be there for files that have been opened with esfs_open. + if(file_handle->file_flag == ESFS_READ) + { + *size_in_bytes -= ESFS_CMAC_SIZE_IN_BYTES; + } + + return ESFS_SUCCESS; + +errorExit: + return result; +} + +esfs_result_e esfs_close(esfs_file_t *file_handle) +{ + char full_path_working_dir[MAX_FULL_PATH_SIZE] = { 0 }; + size_t len; + size_t bytes_written; + unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES]; + palStatus_t res; + uint16_t failed_to_write_CMAC = 0; + uint16_t file_esfs_mode = 0; + esfs_file_flag_e esfs_file_flag = 0; + char esfs_short_file_name[ESFS_QUALIFIED_FILE_NAME_LENGTH] = {0}; + esfs_result_e result = ESFS_ERROR; + + tr_info("esfs_close - enter"); + if(esfs_validate(file_handle) != ESFS_SUCCESS) + { + tr_err("esfs_close() failed with bad parameters"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + + res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_working_dir); + if (res != PAL_SUCCESS) + { + tr_err("esfs_close() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(full_path_working_dir, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); + + + // Close AES context if needed + if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) + { + pal_freeAes( &(file_handle->aes_ctx) ); + } + + esfs_file_flag = file_handle->file_flag; + file_esfs_mode = file_handle->esfs_mode; + strncpy(esfs_short_file_name, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); + + if(file_handle->file_flag == ESFS_WRITE) + { + // Finish signature calculation + res = pal_CMACFinish(&file_handle->signature_ctx, &cmac[0], &len); + tr_info("esfs_close len=%d", (int)len); + if(res != PAL_SUCCESS) + { + tr_err("esfs_close() - pal_CMACFinish() failed with pal status 0x%x", (unsigned int)res); + goto errorExit; + } + // Write signature + res = pal_fsFwrite(&file_handle->file, cmac, len, &bytes_written); + if(res != PAL_SUCCESS || len != bytes_written) + { + tr_err("esfs_close() - pal_fsFwrite() (signature) failed with pal result = 0x%x and bytes_written bytes = %zu", + (unsigned int)res, bytes_written); + // mark the file invalid on a failed write + file_handle->file_invalid = 1; + // Continue so that we delete the file, but we should return failure later + failed_to_write_CMAC = 1; + } + } + + res = pal_fsFclose(&file_handle->file); + if(res == PAL_SUCCESS) + { + // Remove a file that is invalid. It may have become invalid due to a failed write. + if(file_handle->file_invalid) + { + strncat(full_path_working_dir,file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); + + res = pal_fsUnlink(full_path_working_dir); + if(res != PAL_SUCCESS) + { + tr_err("esfs_close() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)res); + goto errorExit; + } + } + } + else + { + tr_err("esfs_close() - pal_fsFclose() failed with pal status 0x%x", (unsigned int)res); + goto errorExit; + } + + if(failed_to_write_CMAC) + { + goto errorExit; + } + + + if ((file_esfs_mode & ESFS_FACTORY_VAL) && (esfs_file_flag == ESFS_WRITE) && !(file_handle->file_invalid)) + { + char full_path_backup_dir[MAX_FULL_PATH_SIZE] = { 0 }; + + res = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); + if (res != PAL_SUCCESS) + { + tr_err("esfs_close() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)res); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY "/", sizeof(ESFS_BACKUP_DIRECTORY) + 1); + + strncat(full_path_working_dir, esfs_short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH -1); + strncat(full_path_backup_dir, esfs_short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); + + if (esfs_copy_file(full_path_backup_dir, full_path_working_dir) != ESFS_SUCCESS) + { + tr_err("esfs_close() - esfs_copy_file() failed"); + goto errorExit; + } + } + + return ESFS_SUCCESS; +errorExit: + return result; +} + +esfs_result_e esfs_delete(const uint8_t *name, size_t name_length) +{ + + palStatus_t pal_result = PAL_SUCCESS; + char working_dir_path[MAX_FULL_PATH_SIZE] = { 0 }; + char short_file_name[ESFS_QUALIFIED_FILE_NAME_LENGTH]; + esfs_result_e result = ESFS_ERROR; + + tr_info("esfs_delete - enter"); + // Check parameters + if(!name || name_length == 0) + { + tr_err("esfs_delete() failed with bad parameters"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + if(esfs_get_name_from_blob(name, name_length, short_file_name, ESFS_FILE_NAME_LENGTH ) != ESFS_SUCCESS) + { + tr_err("esfs_delete() - esfs_get_name_from_blob() failed"); + goto errorExit; + } + tr_info("esfs_delete %s", short_file_name); + + pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path); + if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_delete() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); + result = ESFS_ERROR; + goto errorExit; + } + + strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); + + // We do not verify that name is the actual name in the file because currently we do not allow the situation of hash + // clash to arise. + + strncat(working_dir_path,short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); + + tr_info("esfs_delete %s", working_dir_path); + pal_result = pal_fsUnlink(working_dir_path); + + if ((pal_result == PAL_ERR_FS_NO_FILE) || (pal_result == PAL_ERR_FS_NO_PATH)) + { + tr_err("esfs_delete() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)pal_result); + result = ESFS_NOT_EXISTS; + goto errorExit; + } + else if (pal_result != PAL_SUCCESS) + { + tr_err("esfs_delete() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)pal_result); + goto errorExit; + } + + return ESFS_SUCCESS; +errorExit: + return result; +} + +esfs_result_e esfs_get_meta_data_properties(esfs_file_t *file_handle, esfs_tlv_properties_t **meta_data_properties) +{ + esfs_result_e result = ESFS_ERROR; + tr_info("esfs_get_meta_data_properties - enter"); + if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!meta_data_properties)) + { + tr_err("esfs_get_meta_data_properties() failed with bad parameters"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + + if (file_handle->file_flag != ESFS_READ) + { + tr_err("esfs_get_meta_data_properties() failed - file is opened for write only"); + result = ESFS_FILE_OPEN_FOR_WRITE; + goto errorExit; + } + + *meta_data_properties = &file_handle->tlv_properties; + return ESFS_SUCCESS; +errorExit: + return result; +} + + +esfs_result_e esfs_read_meta_data(esfs_file_t *file_handle, uint32_t index, esfs_tlv_item_t *meta_data) +{ + int32_t current_pos = 0; + int32_t offset_to_restore; + size_t num_bytes = 0; + palStatus_t res; + esfs_result_e result = ESFS_ERROR; + bool is_read_error = false; + + tr_info("esfs_read_meta_data - enter"); + if(esfs_validate(file_handle) != ESFS_SUCCESS || index >= ESFS_MAX_TYPE_LENGTH_VALUES || !meta_data || (file_handle->tlv_properties.tlv_items[index].length_in_bytes == 0)) + { + tr_err("esfs_read_meta_data() failed with bad parameters"); + result = ESFS_INVALID_PARAMETER; + goto errorExit; + } + + if(file_handle->file_flag != ESFS_READ) + { + tr_err("esfs_read_meta_data() failed - file is opened for write only"); + result = ESFS_FILE_OPEN_FOR_WRITE; + goto errorExit; + } + // Get current position + res = pal_fsFtell(&file_handle->file, ¤t_pos); + if(res != PAL_SUCCESS) + { + tr_err("esfs_read_meta_data() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res); + goto errorExit; + } + + + // Jump to position of TLV + res = pal_fsFseek(&file_handle->file, file_handle->tlv_properties.tlv_items[index].position, PAL_FS_OFFSET_SEEKSET); + if(res != PAL_SUCCESS) + { + tr_err("esfs_read_meta_data() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); + goto errorExit; + } + + // Read data + // If required according to esfs_mode, the read data will be decrypted + if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) + { + if(esfs_read_and_decrypt( file_handle, + meta_data->value, + file_handle->tlv_properties.tlv_items[index].length_in_bytes, + &num_bytes + ) != ESFS_SUCCESS) + { + is_read_error = true; + } + } + else + { + if(pal_fsFread( &(file_handle->file), + meta_data->value, + file_handle->tlv_properties.tlv_items[index].length_in_bytes, + &num_bytes + ) != PAL_SUCCESS) + { + is_read_error = true; + } + } + + if(is_read_error || (num_bytes != file_handle->tlv_properties.tlv_items[index].length_in_bytes)) + { + tr_err("esfs_read_meta_data() - read data failed is_read_error = %s and num_bytes = %zu", + is_read_error ? "true" : "false", num_bytes); + goto errorExit; + } + + + // Before restoring old position, make sure offset_to_restore is not a negative number + offset_to_restore = current_pos; + if(offset_to_restore < 0) + { + tr_err("esfs_read_meta_data() failed - current_pos is negative"); + goto errorExit; + } + + // Restore old position + res = pal_fsFseek(&file_handle->file, offset_to_restore, PAL_FS_OFFSET_SEEKSET); + if(res != PAL_SUCCESS) + { + tr_err("esfs_read_meta_data() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); + goto errorExit; + } + // Update meta_data fields + meta_data->type = file_handle->tlv_properties.tlv_items[index].type; + meta_data->length_in_bytes = file_handle->tlv_properties.tlv_items[index].length_in_bytes; + + return ESFS_SUCCESS; + +errorExit: + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/esfs_file_name.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/esfs_file_name.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,98 @@ +/* +* Copyright (c) 2017 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "pal_Crypto.h" +#include <string.h> +#include "esfs.h" + + +static char IntToBase64Char(uint8_t intVal) +{ + const char* base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#_"; + return base64Digits[intVal & 0x3F]; +} +esfs_result_e esfs_EncodeBase64(const void* buffer, uint32_t bufferSize, char* string, uint32_t stringSize) +{ + uint32_t bitOffset = 0; + + const uint8_t* readPtr = (const uint8_t*)buffer; + const uint8_t* bufferEnd = (const uint8_t*)buffer + bufferSize; + + char* writePtr = string; + char* stringEnd = string + stringSize - 1; + + if ((NULL == string) || (NULL == buffer) || (stringSize == 0)) + return ESFS_INVALID_PARAMETER; + + stringSize--; + while(readPtr < bufferEnd && writePtr < stringEnd) + { + uint8_t tempVal = 0; + switch (bitOffset) + { + case 0: + *writePtr++ = IntToBase64Char(*readPtr >> 2); // take upper 6 bits + break; + case 6: + tempVal = *readPtr++ << 4; + if (readPtr < bufferEnd) + tempVal |= *readPtr >> 4; + *writePtr++ = IntToBase64Char(tempVal); + break; + case 4: + tempVal = *readPtr++ << 2; + if (readPtr < bufferEnd) + tempVal |= *readPtr >> 6; + *writePtr++ = IntToBase64Char(tempVal); + break; + case 2: + *writePtr++ = IntToBase64Char(*readPtr++); + break; + default: + return ESFS_INTERNAL_ERROR; // we should never reach this code. + } + bitOffset = (bitOffset + 6) & 0x7; + } + while (bitOffset > 0 && writePtr < stringEnd) + { + *writePtr++ = '!'; + bitOffset = (bitOffset + 6) & 0x7; + } + *writePtr = 0; + + if ((readPtr < bufferEnd) || (bitOffset != 0)) + return (ESFS_BUFFER_TOO_SMALL); + + return(ESFS_SUCCESS); +} + +/* size_of_file_name should should include the null at the end of the string. In our case 9*/ +esfs_result_e esfs_get_name_from_blob(const uint8_t *blob, uint32_t blob_length,char *file_name, uint32_t size_of_file_name) +{ +unsigned char output[32] = {0}; + palStatus_t pal_result; + esfs_result_e esfs_result; + pal_result = pal_sha256(blob, blob_length, output); + if (PAL_SUCCESS != pal_result) + return ESFS_INTERNAL_ERROR; + esfs_result = esfs_EncodeBase64(output, (size_of_file_name - 1)*6/8, file_name, size_of_file_name); + return (esfs_result); + + +} + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/esfs_performance.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/esfs_performance.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <string.h> +#include "esfs_performance.h" + +#ifdef ESFS_PERFOMANCE_TEST // Allow disabling calls to performance + +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "esfs" // Maximum 4 characters +#define TICKS_PER_MICROSEC 120 // FIXME Replace with pal_osKernelSysMilliSecTick when it will work + +static performance_record_t performance_array[PERFORMANCE_ARRAY_SIZE]={{{0}, 0}}; +static unsigned long performance_index = 0; + +void print_performance() +{ +unsigned long i; +char type_title[10]; + for (i=0;i<performance_index;i++) + { + if (performance_array[i].type == ESFS_PERFORMANCE_END) + { + strcpy(type_title,"end "); + tr_cmdline("\nPerformance %s %s %lu %lu", + performance_array[i].title, + type_title, + performance_array[i].mark, + performance_array[i].total); + } + else + { + strcpy(type_title,"start "); + tr_cmdline("\nPerformance %s %s %lu", + performance_array[i].title, + type_title, + performance_array[i].total); + } + } + performance_index = 0; + tr_cmdline("\nIndex=%lu",performance_index); + +} +void add_performance_mark(const char * title, esfs_performance_type_e type) +{ + unsigned long mark = (unsigned long)(pal_osKernelSysTick()/TICKS_PER_MICROSEC); + performance_array[performance_index].mark = mark; + strncpy(performance_array[performance_index].title, title, TITLE_MAX); + performance_array[performance_index].total=0; + performance_array[performance_index].type=type; + if (type == ESFS_PERFORMANCE_END) + { + // find the start mark + for (unsigned long j=performance_index-1;j>=0;j--) + { + if (!strncmp(performance_array[j].title,title,TITLE_MAX)) + { + performance_array[performance_index].total = mark - performance_array[j].mark; + break; + } + } + } + + if (performance_index++ >= (PERFORMANCE_ARRAY_SIZE-1)) + { + print_performance(); + } +} + + +#endif // ESFS_PERFOMANCE_TEST + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/include/esfs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/include/esfs.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ESFS_H +#define __ESFS_H + +#include <stdint.h> +#include "pal_types.h" +#include "pal_errors.h" +#include "pal_macros.h" +#include "pal_fileSystem.h" +#include "pal_Crypto.h" + + + +#define ESFS_AES_NONCE_SIZE_BYTES (8) + +// This value can be reduced to 0 in order to save stack space, if no meta data is required. +// Beware that changing the values affects the format of the file. +#define ESFS_MAX_TYPE_LENGTH_VALUES (3) + +#define ESFS_FILE_NAME_LENGTH (9) + +// ESFS_FILE_NAME_LENGTH + dot + extension (for example: 123456789.txt) +#define ESFS_QUALIFIED_FILE_NAME_LENGTH (ESFS_FILE_NAME_LENGTH + 4) + + +typedef enum { + ESFS_SUCCESS = 0, + ESFS_INVALID_PARAMETER = 1, + ESFS_INTERNAL_ERROR = 2, + ESFS_BUFFER_TOO_SMALL = 3, + ESFS_ERROR = 4 , + ESFS_EXISTS = 5, + ESFS_NOT_EXISTS = 6, + ESFS_HASH_CONFLICT = 7, + ESFS_FILE_OPEN_FOR_READ = 8, + ESFS_FILE_OPEN_FOR_WRITE = 9, + ESFS_INVALID_FILE_VERSION = 10, + ESFS_CMAC_DOES_NOT_MATCH = 11, + ESFS_ERROR_MAXVAL = 0xFFFF +}esfs_result_e; + +typedef enum { + ESFS_USER_READ = 0x0001, + ESFS_USER_WRITE = 0x0002, + ESFS_USER_DELETE = 0x0004, + ESFS_USER_EXECUTE = 0x0008, + ESFS_OTHER_READ = 0x0010, + ESFS_OTHER_WRITE = 0x0020, + ESFS_OTHER_DELETE = 0x0040, + ESFS_OTHER_EXECUTE = 0x0080, + ESFS_ENCRYPTED = 0x0100, + ESFS_FACTORY_VAL = 0x0200, + ESFS_EXTENDED_ACL = 0x0400, + ESFS_MAXVAL = 0xFFFF +}esfs_mode_e; + +typedef enum { + ESFS_READ = 1, // This is the same as the standard "O_RDONLY" + ESFS_WRITE = 2 // This is the same as the standard "O_WRONLY & O_APPEND" +}esfs_file_flag_e; + +typedef struct { + uint16_t type; + uint16_t length_in_bytes; + void *value; +} esfs_tlv_item_t; + +typedef struct { + uint16_t type; + uint16_t length_in_bytes; + // Position in bytes from start of file. + uint16_t position; +} esfs_tlvItem_t; + +typedef struct { + uint16_t number_of_items; + esfs_tlvItem_t tlv_items[ESFS_MAX_TYPE_LENGTH_VALUES]; +}esfs_tlv_properties_t; + + +typedef struct { + palFileDescriptor_t file; + esfs_file_flag_e file_flag; + palAesHandle_t aes_ctx; + uint8_t nonce[ESFS_AES_NONCE_SIZE_BYTES]; + uint16_t esfs_mode; + uint16_t blob_name_length; + char short_file_name[ESFS_QUALIFIED_FILE_NAME_LENGTH]; + esfs_tlv_properties_t tlv_properties; + uint8_t file_invalid; + palCMACHandle_t signature_ctx; + // These are valid for files that are opened not created. + long current_read_pos; // byte position from the start of the data. + size_t data_size; // size in bytes of the data only +}esfs_file_t; + +// ESFS whence enum values are in sync with those of pal +typedef enum { + ESFS_SEEK_SET = PAL_FS_OFFSET_SEEKSET, // Offset will be relative to the beginning of the file + ESFS_SEEK_CUR = PAL_FS_OFFSET_SEEKCUR, // Ofset will be relative to the last position read + ESFS_SEEK_END = PAL_FS_OFFSET_SEEKEND // Offset will be relative to the end of the file and must be zero or a negative number +}esfs_seek_origin_e; + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* @brief esfs_init Must be called once after boot +* Initializes the file system so that it can be used. +* It creates working and backup folders if they do not exist. +* In case a factory_reset operation was not completed, esfs_init will continue the operation. +* +* @returns a ESFS_SUCCESS or error code +* +*/ +esfs_result_e esfs_init(void); + + +/** +* @brief esfs_finalize should be called before calling esfs_init again +* @returns a ESFS_SUCCESS +* +*/ +esfs_result_e esfs_finalize(void); + + +/** +* @brief esfs_factory_reset removes the files existing in the working folder +* and creates a copy of the files that were creted with ESFS_FACTORY_VAL set in the esfs_mode parameter in the working folder. +* If the device is rebooted during factory reset operation, esfs will resume the operation when calling esfs_init after the reboot. +* +* @returns ESFS_SUCCESS or ESFS_ERROR +* +*/ +esfs_result_e esfs_factory_reset(void); + + +/** + * @brief esfs_reset resets esfs to an empty state + Initialize file system and formats SD card if required and initialize internal structures + * + * @returns ESFS_SUCCESS or error code + * + */ +esfs_result_e esfs_reset(void); + +/** + * @brief Creates a new file and open it for writing. Returns error if file exists. + * + * + * @param [in] name + * A binary blob that uniquely identifies the file. + * + * @param [in] name_length + * size in bytes of the name. + * + * @param [in] meta_data + * A pointer to an array of TLVs structures with meta_data_qty members + * + * @param [in] meta_data_qty + * number of tlvs in the array pointed by meta_data parameter + * + * @param [in] esfs_mode + * a bit map combination of values from enum EsfsMode. + * + * @param [out] esfs_file_t file_handle Handle to the just created file and open for write. + * + * @returns ESFS_SUCCESS The file handle can be used in other esfs functions. It must be closed to release it. + * ESFS_INVALID_PARAMETER if name, name_length, file_handle, meta_data_qty are not valid + * ESFS_EXISTS if file with the same blob exists in the file system + * ESFS_HASH_CONFLICT if two different blobs result in the same short name + * + * + */ +esfs_result_e esfs_create(const uint8_t * name, size_t name_length, const esfs_tlv_item_t *meta_data, size_t meta_data_qty, uint16_t esfs_mode, esfs_file_t *file_handle); + +/** + * @brief Opens a file for read. + * + * + * @param [in] name + * A binary blob that uniquely identifies the file. + * + * @param [in] name_length + * size in bytes of the name. + * + * @param [out] esfs_mode + * pointer to get the actual mode bits passed on file creation (see EfsFlags for bit values) + * + * + * @param [out] file_handle Handle to the file for future use + * + * @returns ESFS_SUCCESS or error code + * ESFS_INVALID_PARAMETER if name, name_length, file_handle are not valid + * ESFS_HASH_CONFLICT - A file of the same file name but a different name exists. + * ESFS_CMAC_DOES_NOT_MATCH - The CMAC does not match. The file has possible been tampered with. + * ESFS_WRONG_FILE_VERSION - The format of the file may have changed. + * ESFS_NOT_EXISTS if file does not exist. + * If successful the file handle can be used in other esfs functions. + * It must be closed to release it. + * + * + */ +esfs_result_e esfs_open(const uint8_t * name, size_t name_length, uint16_t * esfs_mode, esfs_file_t *file_handle); + +/** + * @brief Close the file and invalidate the file handle. + * + * @param [in] file_handle Handle + * + * @returns ESFS_SUCCESS or error code + * ESFS_INVALID_PARAMETER in case file_handle is not correct + * ESFS_HASH_CONFLICT - Trying to open a file of the same file name but a different name. + */ +esfs_result_e esfs_close(esfs_file_t *file_handle); + +/** + * @brief Reads data from a previously open file with parameter esfs_mode=EfsRead. Decrypt if required + * + * + * @param [in] file_handle + * Handle obtained from a call to esfs_open. + * + * + * @param [in] buffer + * pointer to memory buffer where data will be read from the file + * + * @param [in] bytes_to_read + * Number of bytes to be read. Buffer must be big enough to contain this size. + * + * + * @param [out] read_bytes + pointer to return the number of bytes actually read. Will be equal or smaller than bytes_to_read. + * + * @returns ESFS_SUCCESS + * ESFS_INVALID_PARAMETER in case file_handle is not correct, buffer is null or read_bytes is null + * ESFS_FILE_OPEN_FOR_WRITE if file is after esfs_create and before esfs_close + * + */ +esfs_result_e esfs_read(esfs_file_t *file_handle, void *buffer, size_t bytes_to_read, size_t *read_bytes); + +/** + * @brief returns the meta data properties (tlvs) associated with the file. * + * + * @param [in] file_handle + * Handle obtained from a call to esfs_open. + * + * @param [out] meta_data_properties + * pointer to return the meta properties + * + * @returns ESFS_SUCCESS + * ESFS_INVALID_PARAMETER if file_handle is not valid or meta_data_properties is null + * ESFS_FILE_OPEN_FOR_WRITE if file is after esfs_create and before esfs_close + * + */ +esfs_result_e esfs_get_meta_data_properties(esfs_file_t *file_handle, esfs_tlv_properties_t **meta_data_properties); +/** + * @brief Reads a single meta data entry into a tlv + * + * @param [in] file_handle + * Handle obtained from a call to esfs_open. + * + * @param [in] index + * the index of the meta data if more than one meta data entry with the same type is present. 0 is the first one. + * The index refers to an imaginary array that holds meta data entries of the same type only. + * + * @param [in,out] meta_data + * pointer to a esfs_tlv_item_t structure with a valid *value pointing to a buffer aligned and big enough to hold the metadata. + * The type and length_in_bytes fields of the tlv should be filled before calling the function with the right values for the required meta data. + * The function will check the correctness of the fields. + * (see esfs_get_meta_data_buffer_size to calculate the required size) + * + * + *@returns ESFS_SUCCESS + * ESFS_INVALID_PARAMETER if file_handle or meta_data is not valid or index is out of bounds + * ESFS_FILE_OPEN_FOR_WRITE if file is after esfs_create and before esfs_close + * + */ +esfs_result_e esfs_read_meta_data(esfs_file_t *file_handle, uint32_t index, esfs_tlv_item_t *meta_data); + +/** + * @brief Change the current position for read. This function will return an error if used on a file open with EfsWrite mode + * or the resulting position is out of the data range of the file. + * + *@param [in] file_handle + * Handle obtained from a call to esfs_open. + * + * + * @param [in] offset + * The number of bytes to move the read position (can be negative) + * + * @param [in] whence + * The position to relate the calculation of the new position for read. Use EfsSEEK_SET to seek the read position offset bytes from the beginning of the file and + * EfsSEEK_CUR to change the read position offset bytes from the last read. Last read is at the beginning of the file after open. + * + * @param [out] position + * pointer to an integer that will hold the read position after the seek. The pointer may be NULL if the position is not desired. + * + *@returns ESFS_SUCCESS + * ESFS_INVALID_PARAMETER if file_handle is not valid or offset is out of bounds + * ESFS_FILE_OPEN_FOR_WRITE if file is after esfs_create and before esfs_close + * + * + */ +esfs_result_e esfs_seek(esfs_file_t *file_handle, int32_t offset, esfs_seek_origin_e whence, uint32_t *position); + +/** + * @brief Removes the file from the file system + * + * + *@param [in] name + * A binary blob that uniquely identifies the file. + * + * @param [in] name_length + * size in bytes of the name. + * @returns ESFS_SUCCESS + * ESFS_NOT_EXISTS if does not exist. + * ESFS_INVALID_PARAMETER if name, name_length, file_handle are not valid + */ +esfs_result_e esfs_delete(const uint8_t * name, size_t name_length); + +/** + * @brief Write data to the file. Encrypt if required + * This may leave the file in an unpredictable state on failure. If that happens the file + * will be deleted by efs_close. + * Data is only guaranteed to be flushed to the media on efs_close. + + * + * + * @param [in] file_handle + * Handle obtained from a call to esfs_open. + * + * @param [in] buffer + * pointer to memory buffer with the data to write + * + * @param [in] bytes_to_write + * Number of bytes to write from the buffer. + * + * @returns ESFS_SUCCESS + * ESFS_FILE_OPEN_FOR_READ if called after esfs_open (file opened for read) + * ESFS_INVALID_PARAMETER in case file_handle is not correct, buffer is null or bytes_to_write == 0 + * + * + */ +esfs_result_e esfs_write(esfs_file_t *file_handle, const void *buffer, size_t bytes_to_write); + +/** + * @brief returns the size of the data in the file + * + * @param [in] file_handle + * Handle obtained from a call to esfs_open. + * + * @param [out] size_in_bytes + * pointer to hold the size of the data in the file + * + * + * @returns ESFS_SUCCESS + * ESFS_INVALID_PARAMETER if file_handle is not valid + * + * + */ +esfs_result_e esfs_file_size(esfs_file_t *file_handle, size_t *size_in_bytes); + +#ifdef __cplusplus +} +#endif + +#endif + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/include/esfs_file_name.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/include/esfs_file_name.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ESFS_FILE_NAME_H +#define __ESFS_FILE_NAME_H + +#ifdef __cplusplus +extern "C" { +#endif + +esfs_result_e esfs_get_name_from_blob(const uint8_t *blob, uint32_t blob_length,char *file_name, uint32_t size_of_file_name); + + +#ifdef __cplusplus +} +#endif + + +#endif + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/include/esfs_performance.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-client-esfs/source/include/esfs_performance.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ESFS_SOURCE_INCLUDE_ESFS_PERFORMANCE_H_ +#define ESFS_SOURCE_INCLUDE_ESFS_PERFORMANCE_H_ + +#include <stdint.h> + +//#define ESFS_PERFOMANCE_TEST // Allow enabling and disabling calls to performance. Define it on compilation + +#define TITLE_MAX 30 +#define PERFORMANCE_ARRAY_SIZE 100 +typedef enum esfs_performance_type +{ + ESFS_PERFORMANCE_START, + ESFS_PERFORMANCE_END +}esfs_performance_type_e; + +typedef struct performance_record +{ + char title[TITLE_MAX+1]; + unsigned long mark; + unsigned long total; + esfs_performance_type_e type; +}performance_record_t; + + +#ifdef ESFS_PERFOMANCE_TEST // If not defined ESFS_PERFOMANCE_TEST functions will be removed + +void print_performance(); +void add_performance_mark(const char * title, esfs_performance_type_e type); + + + +#else + +#define print_performance() +#define add_performance_mark(title, type) + +#endif + +#endif /* ESFS_SOURCE_INCLUDE_ESFS_PERFORMANCE_H_ */ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-trace-helper/mbed-trace-helper/mbed-trace-helper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-trace-helper/mbed-trace-helper/mbed-trace-helper.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,66 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- +/* Logging macros */ + +#ifndef __MBED_TRACE_HELPER_H__ +#define __MBED_TRACE_HELPER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <inttypes.h> +#include <string.h> +#include <stdbool.h> +/** +* Function used in mbed-trace to set trace print +*/ +void mbed_trace_helper_print(const char* format); +/** +* Function used in mbed-trace to set wait mutex function +*/ +void mbed_trace_helper_mutex_wait( void ); +/** +* Function used in mbed-trace to set release mutex function +*/ +void mbed_trace_helper_mutex_release( void ); +/** +* This function creates mutex +*/ +bool mbed_trace_helper_create_mutex( void ); +/** +* Deletes mutex +*/ +void mbed_trace_helper_delete_mutex(void); +/** +* Check activated trace level according to MBED_TRACE_MAX_LEVEL and used level in mbed_trace_config_set. +* In case the activated level is higher then MBED_TRACE_MAX_LEVEL, the function prints warning. +*/ +uint8_t mbed_trace_helper_check_activated_trace_level( void ); +/** +* The function calls to configuration functions of mbed_trace_helper according to passed parameters and initializes mbed-trace +*/ +bool mbed_trace_helper_init(uint8_t config, bool is_mutex_used); +/** +* The function terminats thred and mbed-trace +*/ +void mbed_trace_helper_finish( void ); +#ifdef __cplusplus +} +#endif +#endif /*__TRACE_HELPER_H__*/ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-trace-helper/source/mbed-trace-helper.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/mbed-trace-helper/source/mbed-trace-helper.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,143 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "pv_log.h" +#include <stdarg.h> +#include <inttypes.h> +#include <stdlib.h> +#include "pal.h" +#include "pv_error_handling.h" +#include "mbed-trace/mbed_trace.h" +/** +* Mutex for printing logs in a thread safe manner. +*/ +palMutexID_t g_pv_logger_mutex = NULLPTR; + +void mbed_trace_helper_print(const char* format) +{ + fprintf(stdout, "%s\n", format); +} + +void mbed_trace_helper_mutex_wait() +{ + pal_osMutexWait(g_pv_logger_mutex, PAL_RTOS_WAIT_FOREVER); +} + +void mbed_trace_helper_mutex_release() +{ + pal_osMutexRelease(g_pv_logger_mutex); +} +/** +* Creates mutex +*/ +bool mbed_trace_helper_create_mutex(void) +{ + palStatus_t status; + + // g_pv_logger_mutex already created - no need to recreate it. + if (g_pv_logger_mutex) { + goto exit; + } + + status = pal_osMutexCreate(&g_pv_logger_mutex); + if (status != PAL_SUCCESS) { + SA_PV_LOG_INFO("Error creating g_pv_logger_mutex (pal err = %d)", (int)status); + return false; + } + +exit: + return true; +} + +/** +* Deletes mutex +*/ +void mbed_trace_helper_delete_mutex(void) +{ + // g_pv_logger_mutex already created - no need to recreate it. + if (g_pv_logger_mutex == NULLPTR) { + return; + } + + pal_osMutexDelete(&g_pv_logger_mutex); + g_pv_logger_mutex = NULLPTR; +} + +uint8_t mbed_trace_helper_check_activated_trace_level() +{ + uint8_t config_active_level = 0; + uint8_t activated_level = 0; + + SA_PV_LOG_INFO_FUNC_ENTER("MBED_TRACE_MAX_LEVEL = %d", MBED_TRACE_MAX_LEVEL); + + config_active_level = mbed_trace_config_get() & TRACE_MASK_LEVEL; + SA_PV_LOG_INFO("config_active_level is %d", config_active_level); + + activated_level = config_active_level & MBED_TRACE_MAX_LEVEL; + SA_PV_LOG_INFO("activated_level is %d", activated_level); + + if (activated_level == 0) { + SA_PV_LOG_CRITICAL("The compiled maximum trace level %d, is higher than activated trace level", MBED_TRACE_MAX_LEVEL); + SA_PV_LOG_CRITICAL("If you want to use the requested log level, please change MBED_TRACE_MAX_LEVEL compilation flag and recompile the code"); + } + + SA_PV_LOG_INFO_FUNC_EXIT_NO_ARGS(); + + return activated_level; +} + +bool mbed_trace_helper_init(uint8_t config, bool is_mutex_used) +{ + bool success = true; + int rc = 0; + + (void)mbed_trace_init(); + //FIXME : return result assigning to rc after https://jira.arm.com/browse/IOTCLT-1860 will be resolved + if (rc != 0) { + return false; + } + + if (is_mutex_used) { + // Create mutex + success = mbed_trace_helper_create_mutex(); + if (success != true) { + mbed_trace_free(); + return false; + } + } + // Set trace level, TRACE_MODE_PLAIN used to ignore mbed trace print pattern ([trace_level] [trace_group] format) + mbed_trace_config_set(config); + + // Set trace print function + mbed_trace_print_function_set(mbed_trace_helper_print); + + if (is_mutex_used) { + // Set mutex wait function for mbed trace + mbed_trace_mutex_wait_function_set(mbed_trace_helper_mutex_wait); + // Set mutex release function for mbed trace + mbed_trace_mutex_release_function_set(mbed_trace_helper_mutex_release); + } + return true; +} + +void mbed_trace_helper_finish() +{ + mbed_trace_helper_delete_mutex(); + mbed_trace_free(); +} + + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/CMakeLists.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,18 @@ + +# includes +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/secsrv-cbor) + +FILE( + GLOB_RECURSE + cbor + + "${CMAKE_CURRENT_SOURCE_DIR}/secsrv-cbor/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/source/*.c" +) + +message ("*********************************************************************") +message ("cbor = [[${cbor}]]") +message ("*********************************************************************") + +CREATE_LIBRARY(cn-cbor "${cbor}" "") +ADDSUBDIRS() \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Carsten Bormann <cabo@tzi.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/ORIGIN.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/ORIGIN.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,7 @@ +Source code is taken from Cborg git - https://github.com/quartzjer/cborg. +List of changes: +* Chagne the tests to fit unit tests format. +* Changed representation of CN_CBOR_UINT in the union v in struct cn_cbor from unsigned long to uint64_t as fix for platforms where unsigned long is represented in only 32 bits. +* Same thing done for CN_CBOR_INT changed from long to int64_t. +* Changed encoding lib function and added a lib function that gets the length of the buffer to encode into. +Updated to revision be86408ca8554719ba54f3f6ede0dc98be17d58a (from 19-Nov-2016).
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/secsrv-cbor/cbor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/secsrv-cbor/cbor.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,118 @@ +#ifndef CBOR_PROTOCOL_H__ +#define CBOR_PROTOCOL_H__ + +/* The 8 major types */ +#define MT_UNSIGNED 0 +#define MT_NEGATIVE 1 +#define MT_BYTES 2 +#define MT_TEXT 3 +#define MT_ARRAY 4 +#define MT_MAP 5 +#define MT_TAG 6 +#define MT_PRIM 7 + +/* The initial bytes resulting from those */ +#define IB_UNSIGNED (MT_UNSIGNED << 5) +#define IB_NEGATIVE (MT_NEGATIVE << 5) +#define IB_BYTES (MT_BYTES << 5) +#define IB_TEXT (MT_TEXT << 5) +#define IB_ARRAY (MT_ARRAY << 5) +#define IB_MAP (MT_MAP << 5) +#define IB_TAG (MT_TAG << 5) +#define IB_PRIM (MT_PRIM << 5) + +#define IB_NEGFLAG (IB_NEGATIVE - IB_UNSIGNED) +#define IB_NEGFLAG_AS_BIT(ib) ((ib) >> 5) +#define IB_TEXTFLAG (IB_TEXT - IB_BYTES) + +#define IB_AI(ib) ((ib) & 0x1F) +#define IB_MT(ib) ((ib) >> 5) + +/* Tag numbers handled by this implementation */ +#define TAG_TIME_EPOCH 1 +#define TAG_BIGNUM 2 +#define TAG_BIGNUM_NEG 3 +#define TAG_URI 32 +#define TAG_RE 35 + +/* Initial bytes of those tag numbers */ +#define IB_TIME_EPOCH (IB_TAG | TAG_TIME_EPOCH) +#define IB_BIGNUM (IB_TAG | TAG_BIGNUM) +#define IB_BIGNUM_NEG (IB_TAG | TAG_BIGNUM_NEG) +/* TAG_URI and TAG_RE are non-immediate tags */ + +/* Simple values handled by this implementation */ +#define VAL_FALSE 20 +#define VAL_TRUE 21 +#define VAL_NIL 22 +#define VAL_UNDEF 23 + +/* Initial bytes of those simple values */ +#define IB_FALSE (IB_PRIM | VAL_FALSE) +#define IB_TRUE (IB_PRIM | VAL_TRUE) +#define IB_NIL (IB_PRIM | VAL_NIL) +#define IB_UNDEF (IB_PRIM | VAL_UNDEF) + +/* AI values with more data in head */ +#define AI_1 24 +#define AI_2 25 +#define AI_4 26 +#define AI_8 27 +#define AI_INDEF 31 +#define IB_BREAK (IB_PRIM | AI_INDEF) +/* For */ +#define IB_UNUSED (IB_TAG | AI_INDEF) + +/* Floating point initial bytes */ +#define IB_FLOAT2 (IB_PRIM | AI_2) +#define IB_FLOAT4 (IB_PRIM | AI_4) +#define IB_FLOAT8 (IB_PRIM | AI_8) + +// These definitions are here because they aren't required for the public +// interface, and they were quite confusing in cn-cbor.h + +#ifdef USE_CBOR_CONTEXT +/** + * Allocate enough space for 1 `cn_cbor` structure. + * + * @param[in] ctx The allocation context, or NULL for calloc. + * @return A pointer to a `cn_cbor` or NULL on failure + */ +#define CN_CALLOC(ctx) ((ctx) && (ctx)->calloc_func) ? \ + (ctx)->calloc_func(1, sizeof(cn_cbor), (ctx)->context) : \ + calloc(1, sizeof(cn_cbor)); + +/** + * Free a + * @param free_func [description] + * @return [description] + */ +#define CN_FREE(ptr, ctx) ((ctx) && (ctx)->free_func) ? \ + (ctx)->free_func((ptr), (ctx)->context) : \ + free((ptr)); + +#define CBOR_CONTEXT_PARAM , context +#define CN_CALLOC_CONTEXT() CN_CALLOC(context) +#define CN_CBOR_FREE_CONTEXT(p) CN_FREE(p, context) + +#else + +#define CBOR_CONTEXT_PARAM +#define CN_CALLOC_CONTEXT() CN_CALLOC +#define CN_CBOR_FREE_CONTEXT(p) CN_FREE(p) + +#ifndef CN_CALLOC +#define CN_CALLOC calloc(1, sizeof(cn_cbor)) +#endif + +#ifndef CN_FREE +#define CN_FREE free +#endif + +#endif // USE_CBOR_CONTEXT + +#ifndef UNUSED_PARAM +#define UNUSED_PARAM(p) ((void)&(p)) +#endif + +#endif // CBOR_PROTOCOL_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/secsrv-cbor/cn-cbor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/secsrv-cbor/cn-cbor.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,419 @@ +/** + * \file + * \brief + * CBOR parsing + */ + +#ifndef CN_CBOR_H +#define CN_CBOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +//typedef int ssize_t; + +#ifdef EMACS_INDENTATION_HELPER +} /* Duh. */ +#endif + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> + +//typedef ssize_t int; +//#include <unistd.h> + +/** + * All of the different kinds of CBOR values. + */ +typedef enum cn_cbor_type { + /** false */ + CN_CBOR_FALSE, + /** true */ + CN_CBOR_TRUE, + /** null */ + CN_CBOR_NULL, + /** undefined */ + CN_CBOR_UNDEF, + /** Positive integers */ + CN_CBOR_UINT, + /** Negative integers */ + CN_CBOR_INT, + /** Byte string */ + CN_CBOR_BYTES, + /** UTF-8 string */ + CN_CBOR_TEXT, + /** Byte string, in chunks. Each chunk is a child. */ + CN_CBOR_BYTES_CHUNKED, + /** UTF-8 string, in chunks. Each chunk is a child */ + CN_CBOR_TEXT_CHUNKED, + /** Array of CBOR values. Each array element is a child, in order */ + CN_CBOR_ARRAY, + /** Map of key/value pairs. Each key and value is a child, alternating. */ + CN_CBOR_MAP, + /** Tag describing the next value. The next value is the single child. */ + CN_CBOR_TAG, + /** Simple value, other than the defined ones */ + CN_CBOR_SIMPLE, + /** Doubles, floats, and half-floats */ + CN_CBOR_DOUBLE, + /** An error has occurred */ + CN_CBOR_INVALID +} cn_cbor_type; + +/** + * Flags used during parsing. Not useful for consumers of the + * `cn_cbor` structure. + */ +typedef enum cn_cbor_flags { + /** The count field will be used for parsing */ + CN_CBOR_FL_COUNT = 1, + /** An indefinite number of children */ + CN_CBOR_FL_INDEF = 2, + /** Not used yet; the structure must free the v.str pointer when the + structure is freed */ + CN_CBOR_FL_OWNER = 0x80, /* of str */ +} cn_cbor_flags; + +/** + * A CBOR value + */ +typedef struct cn_cbor { + /** The type of value */ + cn_cbor_type type; + /** Flags used at parse time */ + cn_cbor_flags flags; + /** Data associated with the value; different branches of the union are + used depending on the `type` field. */ + union { + /** CN_CBOR_BYTES */ + const uint8_t* bytes; + /** CN_CBOR_TEXT */ + const char* str; + /** CN_CBOR_INT */ + int64_t sint; + /** CN_CBOR_UINT */ + uint64_t uint; + /** CN_CBOR_DOUBLE */ + double dbl; + /** for use during parsing */ + unsigned long count; + } v; /* TBD: optimize immediate */ + /** Number of children. + * @note: for maps, this is 2x the number of entries */ + int length; + /** The first child value */ + struct cn_cbor* first_child; + /** The last child value */ + struct cn_cbor* last_child; + /** The sibling after this one, or NULL if this is the last */ + struct cn_cbor* next; + /** The parent of this value, or NULL if this is the root */ + struct cn_cbor* parent; +} cn_cbor; + +/** + * All of the different kinds of errors + */ +typedef enum cn_cbor_error { + /** No error has occurred */ + CN_CBOR_NO_ERROR, + /** More data was expected while parsing */ + CN_CBOR_ERR_OUT_OF_DATA, + /** Some extra data was left over at the end of parsing */ + CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED, + /** A map should be alternating keys and values. A break was found + when a value was expected */ + CN_CBOR_ERR_ODD_SIZE_INDEF_MAP, + /** A break was found where it wasn't expected */ + CN_CBOR_ERR_BREAK_OUTSIDE_INDEF, + /** Indefinite encoding works for bstrs, strings, arrays, and maps. + A different major type tried to use it. */ + CN_CBOR_ERR_MT_UNDEF_FOR_INDEF, + /** Additional Information values 28-30 are reserved */ + CN_CBOR_ERR_RESERVED_AI, + /** A chunked encoding was used for a string or bstr, and one of the elements + wasn't the expected (string/bstr) type */ + CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING, + /** An invalid parameter was passed to a function */ + CN_CBOR_ERR_INVALID_PARAMETER, + /** Allocation failed */ + CN_CBOR_ERR_OUT_OF_MEMORY, + /** A float was encountered during parse but the library was built without + support for float types. */ + CN_CBOR_ERR_FLOAT_NOT_SUPPORTED, + /** Encoder was unable to encode the cn_cbor object that was provided */ + CN_CBOR_ERR_ENCODER +} cn_cbor_error; + +/** + * Strings matching the `cn_cbor_error` conditions. + * + * @todo: turn into a function to make the type safety more clear? + */ +extern const char *cn_cbor_error_str[]; + +/** + * Errors + */ +typedef struct cn_cbor_errback { + /** The position in the input where the erorr happened */ + int pos; + /** The error, or CN_CBOR_NO_ERROR if none */ + cn_cbor_error err; +} cn_cbor_errback; + +#ifdef USE_CBOR_CONTEXT + +/** + * Allocate and zero out memory. `count` elements of `size` are required, + * as for `calloc(3)`. The `context` is the `cn_cbor_context` passed in + * earlier to the CBOR routine. + * + * @param[in] count The number of items to allocate + * @param[in] size The size of each item + * @param[in] context The allocation context + */ +typedef void* (*cn_calloc_func)(size_t count, size_t size, void *context); + +/** + * Free memory previously allocated with a context. If using a pool allocator, + * this function will often be a no-op, but it must be supplied in order to + * prevent the CBOR library from calling `free(3)`. + * + * @note: it may be that this is never needed; if so, it will be removed for + * clarity and speed. + * + * @param context [description] + * @return [description] + */ +typedef void (*cn_free_func)(void *ptr, void *context); + +/** + * The allocation context. + */ +typedef struct cn_cbor_context { + /** The pool `calloc` routine. Must allocate and zero. */ + cn_calloc_func calloc_func; + /** The pool `free` routine. Often a no-op, but required. */ + cn_free_func free_func; + /** Typically, the pool object, to be used when calling `calloc_func` + * and `free_func` */ + void *context; +} cn_cbor_context; + +/** When USE_CBOR_CONTEXT is defined, many functions take an extra `context` + * parameter */ +#define CBOR_CONTEXT , cn_cbor_context *context +/** When USE_CBOR_CONTEXT is defined, some functions take an extra `context` + * parameter at the beginning */ +#define CBOR_CONTEXT_COMMA cn_cbor_context *context, + +#else + +#define CBOR_CONTEXT +#define CBOR_CONTEXT_COMMA + +#endif + +/** + * Decode an array of CBOR bytes into structures. + * + * @param[in] buf The array of bytes to parse + * @param[in] len The number of bytes in the array + * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) + * @param[out] errp Error, if NULL is returned + * @return The parsed CBOR structure, or NULL on error + */ +cn_cbor* cn_cbor_decode(const uint8_t *buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp); + +/** + * Get a value from a CBOR map that has the given string as a key. + * + * @param[in] cb The CBOR map + * @param[in] key The string to look up in the map + * @return The matching value, or NULL if the key is not found + */ +cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key); + +/** + * Get a value from a CBOR map that has the given integer as a key. + * + * @param[in] cb The CBOR map + * @param[in] key The int to look up in the map + * @return The matching value, or NULL if the key is not found + */ +cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key); + +/** + * Get the item with the given index from a CBOR array. + * + * @param[in] cb The CBOR map + * @param[in] idx The array index + * @return The matching value, or NULL if the index is invalid + */ +cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx); + +/** + * Free the given CBOR structure. + * You MUST NOT try to free a cn_cbor structure with a parent (i.e., one + * that is not a root in the tree). + * + * @param[in] cb The CBOR value to free. May be NULL, or a root object. + * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) + */ +void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT); + +/** +* Get the size of the buffer that must be provided to cn_cbor_encoder_write(). +* This is the size of the CBOR that will be encoded. +* +* @param[in] cb Pointer to a cn_cbor structure, which the user wishes to encode. +* @param[out] err Error, if -1 is returned. +* @return -1 on fail, or number size of the allocated buffer containing the encoded data. +*/ + +int cn_cbor_get_encoded_size(const cn_cbor *cb, cn_cbor_errback *err); + +/** + * Write a CBOR value and all of the child values. + * Allocates a buffer of the correct size and fills it with the encoded CBOR. + * User must free the buffer. + * + * @param[in] cb Pointer to a cn_cbor structure, which the user wishes to encode. + * @param[out] bufOut Pointer a buffer which will be filled with the encoded data. + * @param[in] bufSize Size of the provided buffer in bytes. + * @param[out] err Error, if -1 is returned. + * @return -1 on fail, or number encoded bytes written to the provided buffer. + */ + +int cn_cbor_encoder_write(const cn_cbor *cb, uint8_t *bufOut, int bufSize, cn_cbor_errback *err); + +/** + * Create a CBOR map. + * + * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) + * @param[out] errp Error, if NULL is returned + * @return The created map, or NULL on error + */ +cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp); + +/** + * Create a CBOR byte string. The data in the byte string is *not* owned + * by the CBOR object, so it is not freed automatically. + * + * @param[in] data The data + * @param[in] len The number of bytes of data + * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) + * @param[out] errp Error, if NULL is returned + * @return The created object, or NULL on error + */ +cn_cbor* cn_cbor_data_create(const uint8_t* data, int len + CBOR_CONTEXT, + cn_cbor_errback *errp); + +/** + * Create a CBOR UTF-8 string. The data is not checked for UTF-8 correctness. + * The data being stored in the string is *not* owned the CBOR object, so it is + * not freed automatically. + * + * @note: Do NOT use this function with untrusted data. It calls strlen, and + * relies on proper NULL-termination. + * + * @param[in] data NULL-terminated UTF-8 string + * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) + * @param[out] errp Error, if NULL is returned + * @return The created object, or NULL on error + */ +cn_cbor* cn_cbor_string_create(const char* data + CBOR_CONTEXT, + cn_cbor_errback *errp); + +/** + * Create a CBOR integer (either positive or negative). + * + * @param[in] value the value of the integer + * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) + * @param[out] errp Error, if NULL is returned + * @return The created object, or NULL on error + */ +cn_cbor* cn_cbor_int_create(int64_t value + CBOR_CONTEXT, + cn_cbor_errback *errp); + +/** + * Put a CBOR object into a map with a CBOR object key. Duplicate checks are NOT + * currently performed. + * + * @param[in] cb_map The map to insert into + * @param[in] key The key + * @param[in] cb_value The value + * @param[out] errp Error + * @return True on success + */ +bool cn_cbor_map_put(cn_cbor* cb_map, + cn_cbor *cb_key, cn_cbor *cb_value, + cn_cbor_errback *errp); + +/** + * Put a CBOR object into a map with an integer key. Duplicate checks are NOT + * currently performed. + * + * @param[in] cb_map The map to insert into + * @param[in] key The integer key + * @param[in] cb_value The value + * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) + * @param[out] errp Error + * @return True on success + */ +bool cn_cbor_mapput_int(cn_cbor* cb_map, + int64_t key, cn_cbor* cb_value + CBOR_CONTEXT, + cn_cbor_errback *errp); + +/** + * Put a CBOR object into a map with a string key. Duplicate checks are NOT + * currently performed. + * + * @note: do not call this routine with untrusted string data. It calls + * strlen, and requires a properly NULL-terminated key. + * + * @param[in] cb_map The map to insert into + * @param[in] key The string key + * @param[in] cb_value The value + * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) + * @param[out] errp Error + * @return True on success + */ +bool cn_cbor_mapput_string(cn_cbor* cb_map, + const char* key, cn_cbor* cb_value + CBOR_CONTEXT, + cn_cbor_errback *errp); + +/** + * Create a CBOR array + * + * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) + * @param[out] errp Error, if NULL is returned + * @return The created object, or NULL on error + */ +cn_cbor* cn_cbor_array_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp); + +/** + * Append an item to the end of a CBOR array. + * + * @param[in] cb_array The array into which to insert + * @param[in] cb_value The value to insert + * @param[out] errp Error + * @return True on success + */ +bool cn_cbor_array_append(cn_cbor* cb_array, + cn_cbor* cb_value, + cn_cbor_errback *errp); + +#ifdef __cplusplus +} +#endif + +#endif /* CN_CBOR_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-cbor.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-cbor.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,319 @@ +#ifndef CN_CBOR_C +#define CN_CBOR_C + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef EMACS_INDENTATION_HELPER +} /* Duh. */ +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> +#include <math.h> +#ifdef CBOR_CAN_DO_UNALIGNED_READS +#include <arpa/inet.h> // needed for ntohl (e.g.) on Linux +#endif + +#include "cn-cbor.h" +#include "cbor.h" + +#define CN_CBOR_FAIL(code) do { pb->err = code; goto fail; } while(0) + +void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT) { + cn_cbor* p = cb; + assert(!p || !p->parent); + while (p) { + cn_cbor* p1; + while ((p1 = p->first_child)) { /* go down */ + p = p1; + } + if (!(p1 = p->next)) { /* go up next */ + if ((p1 = p->parent)) + p1->first_child = 0; + } + CN_CBOR_FREE_CONTEXT(p); + p = p1; + } +} + +#ifndef CBOR_NO_FLOAT +static double decode_half(int half) { + int exp = (half >> 10) & 0x1f; + int mant = half & 0x3ff; + double val = 0; + if (exp == 0) { + val = ldexp(mant, -24); + } else if (exp != 31) { + val = ldexp(mant + 1024, exp - 25); + } else { + if (mant == 0) { + val = INFINITY; + } else { + val = NAN; + } + } + return half & 0x8000 ? -val : val; +} +#endif /* CBOR_NO_FLOAT */ + +/* Fix these if you can't do non-aligned reads */ +#define ntoh8p(p) (*(unsigned char*)(p)) +#ifdef CBOR_CAN_DO_UNALIGNED_READS +#define ntoh16p(p) (ntohs(*(unsigned short*)(p))) +#define ntoh32p(p) (ntohl(*(unsigned long*)(p))) +#else +static uint16_t ntoh16p(unsigned char *p) { + uint16_t ret = ntoh8p(p); + ret <<= 8; + ret += ntoh8p(p+1); + return ret; +} +static uint32_t ntoh32p(unsigned char *p) { + uint64_t ret = ntoh16p(p); + ret <<= 16; + ret += ntoh16p(p+2); + return ret; +} +#endif +static uint64_t ntoh64p(unsigned char *p) { + uint64_t ret = ntoh32p(p); + ret <<= 32; + ret += ntoh32p(p+4); + return ret; +} + +static cn_cbor_type mt_trans[] = { + CN_CBOR_UINT, CN_CBOR_INT, + CN_CBOR_BYTES, CN_CBOR_TEXT, + CN_CBOR_ARRAY, CN_CBOR_MAP, + CN_CBOR_TAG, CN_CBOR_SIMPLE, +}; + +struct parse_buf { + unsigned char *buf; + unsigned char *ebuf; + cn_cbor_error err; +}; + +#define TAKE(pos, ebuf, n, stmt) \ + if (n > (size_t)(ebuf - pos)) \ + CN_CBOR_FAIL(CN_CBOR_ERR_OUT_OF_DATA); \ + stmt; \ + pos += n; + +static cn_cbor *decode_item (struct parse_buf *pb CBOR_CONTEXT, cn_cbor* top_parent) { + unsigned char *pos = pb->buf; + unsigned char *ebuf = pb->ebuf; + cn_cbor* parent = top_parent; + int ib; + unsigned int mt; + int ai; + uint64_t val; + cn_cbor* cb = NULL; +#ifndef CBOR_NO_FLOAT + union { + float f; + uint32_t u; + } u32; + union { + double d; + uint64_t u; + } u64; +#endif /* CBOR_NO_FLOAT */ + +again: + TAKE(pos, ebuf, 1, ib = ntoh8p(pos) ); + if (ib == IB_BREAK) { + if (!(parent->flags & CN_CBOR_FL_INDEF)) + CN_CBOR_FAIL(CN_CBOR_ERR_BREAK_OUTSIDE_INDEF); + switch (parent->type) { + case CN_CBOR_BYTES: case CN_CBOR_TEXT: + parent->type += 2; /* CN_CBOR_* -> CN_CBOR_*_CHUNKED */ + break; + case CN_CBOR_MAP: + if (parent->length & 1) + CN_CBOR_FAIL(CN_CBOR_ERR_ODD_SIZE_INDEF_MAP); + default:; + } + goto complete; + } + mt = ib >> 5; + ai = ib & 0x1f; + val = ai; + + cb = CN_CALLOC_CONTEXT(); + if (!cb) + CN_CBOR_FAIL(CN_CBOR_ERR_OUT_OF_MEMORY); + + cb->type = mt_trans[mt]; + + cb->parent = parent; + if (parent->last_child) { + parent->last_child->next = cb; + } else { + parent->first_child = cb; + } + parent->last_child = cb; + parent->length++; + + switch (ai) { + case AI_1: TAKE(pos, ebuf, 1, val = ntoh8p(pos)) ; cb->length = 1; break; + case AI_2: TAKE(pos, ebuf, 2, val = ntoh16p(pos)) ; cb->length = 2; break; + case AI_4: TAKE(pos, ebuf, 4, val = ntoh32p(pos)) ; cb->length = 4; break; + case AI_8: TAKE(pos, ebuf, 8, val = ntoh64p(pos)) ; cb->length = 8; break; + + case 28: case 29: case 30: CN_CBOR_FAIL(CN_CBOR_ERR_RESERVED_AI); + case AI_INDEF: + if ((mt - MT_BYTES) <= MT_MAP) { + cb->flags |= CN_CBOR_FL_INDEF; + goto push; + } else { + CN_CBOR_FAIL(CN_CBOR_ERR_MT_UNDEF_FOR_INDEF); + } + } + // process content + switch (mt) { + case MT_UNSIGNED: + cb->v.uint = val; /* to do: Overflow check */ + /* + if the integer itsef is used (ai=0..23), set the length to 4, for compliance + with the definition that integer values of mbed.UseBootstrap and mbed.MemoryTotalKB + is 4 bytes. + This implementation might cause bugs with other parameters that has no such requirement, + so the code should be changed in the future + */ + if (cb->length == 0) { + cb->length = 4; + } + break; + case MT_NEGATIVE: + cb->v.sint = ~val; /* to do: Overflow check */ + /* + if the integer itsef is used (ai=0..23), set the length to 4, for compliance + with the definition that integer values of mbed.UseBootstrap and mbed.MemoryTotalKB + is 4 bytes. + This implementation might cause bugs with other parameters that has no such requirement, + so the code should be changed in the future + */ + if (cb->length == 0) { + cb->length = 4; + } + break; + case MT_BYTES: case MT_TEXT: + cb->v.str = (char *) pos; + cb->length = val; + TAKE(pos, ebuf, val, ;); + break; + case MT_MAP: + val <<= 1; + /* fall through */ + case MT_ARRAY: + if ((cb->v.count = val)) { + cb->flags |= CN_CBOR_FL_COUNT; + goto push; + } + break; + case MT_TAG: + cb->v.uint = val; + goto push; + case MT_PRIM: + switch (ai) { + case VAL_FALSE: cb->type = CN_CBOR_FALSE; break; + case VAL_TRUE: cb->type = CN_CBOR_TRUE; break; + case VAL_NIL: cb->type = CN_CBOR_NULL; break; + case VAL_UNDEF: cb->type = CN_CBOR_UNDEF; break; + case AI_2: +#ifndef CBOR_NO_FLOAT + cb->type = CN_CBOR_DOUBLE; + cb->v.dbl = decode_half(val); +#else /* CBOR_NO_FLOAT */ + CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); +#endif /* CBOR_NO_FLOAT */ + break; + case AI_4: +#ifndef CBOR_NO_FLOAT + cb->type = CN_CBOR_DOUBLE; + u32.u = val; + cb->v.dbl = u32.f; +#else /* CBOR_NO_FLOAT */ + CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); +#endif /* CBOR_NO_FLOAT */ + break; + case AI_8: +#ifndef CBOR_NO_FLOAT + cb->type = CN_CBOR_DOUBLE; + u64.u = val; + cb->v.dbl = u64.d; +#else /* CBOR_NO_FLOAT */ + CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); +#endif /* CBOR_NO_FLOAT */ + break; + default: cb->v.uint = val; + } + } +fill: /* emulate loops */ + if (parent->flags & CN_CBOR_FL_INDEF) { + if (parent->type == CN_CBOR_BYTES || parent->type == CN_CBOR_TEXT) + if (cb->type != parent->type) + CN_CBOR_FAIL(CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING); + goto again; + } + if (parent->flags & CN_CBOR_FL_COUNT) { + if (--parent->v.count) + goto again; + } + /* so we are done filling parent. */ +complete: /* emulate return from call */ + if (parent == top_parent) { + if (pos != ebuf) /* XXX do this outside */ + CN_CBOR_FAIL(CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED); + pb->buf = pos; + return cb; + } + cb = parent; + parent = parent->parent; + goto fill; +push: /* emulate recursive call */ + parent = cb; + goto again; +fail: + pb->buf = pos; + return 0; +} + +cn_cbor* cn_cbor_decode(const unsigned char* buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp) { + cn_cbor catcher = {CN_CBOR_INVALID, 0, {0}, 0, NULL, NULL, NULL, NULL}; + struct parse_buf pb; + cn_cbor* ret; + + pb.buf = (unsigned char *)buf; + pb.ebuf = (unsigned char *)buf+len; + pb.err = CN_CBOR_NO_ERROR; + ret = decode_item(&pb CBOR_CONTEXT_PARAM, &catcher); + if (ret != NULL) { + /* mark as top node */ + ret->parent = NULL; + } else { + + if (catcher.first_child) { + catcher.first_child->parent = 0; + cn_cbor_free(catcher.first_child CBOR_CONTEXT_PARAM); + } +//fail: + if (errp) { + errp->err = pb.err; + errp->pos = pb.buf - (unsigned char *)buf; + } + return NULL; + } + return ret; +} + +#ifdef __cplusplus +} +#endif + +#endif /* CN_CBOR_C */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-create.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-create.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,184 @@ +#ifndef CN_CREATE_C +#define CN_CREATE_C + +#ifdef __cplusplus +extern "C" { +#endif + +#include <string.h> +#include <stdlib.h> + +#include "cn-cbor.h" +#include "cbor.h" + +#define INIT_CB(v) \ + if (errp) {errp->err = CN_CBOR_NO_ERROR;} \ + (v) = CN_CALLOC_CONTEXT(); \ + if (!(v)) { if (errp) {errp->err = CN_CBOR_ERR_OUT_OF_MEMORY;} return NULL; } + +cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp) +{ + cn_cbor* ret; + INIT_CB(ret); + + ret->type = CN_CBOR_MAP; + ret->flags |= CN_CBOR_FL_COUNT; + + return ret; +} + +cn_cbor* cn_cbor_data_create(const uint8_t* data, int len + CBOR_CONTEXT, + cn_cbor_errback *errp) +{ + cn_cbor* ret; + INIT_CB(ret); + + ret->type = CN_CBOR_BYTES; + ret->length = len; + ret->v.str = (const char*) data; // TODO: add v.ustr to the union? + + return ret; +} + +cn_cbor* cn_cbor_string_create(const char* data + CBOR_CONTEXT, + cn_cbor_errback *errp) +{ + cn_cbor* ret; + INIT_CB(ret); + + ret->type = CN_CBOR_TEXT; + ret->length = strlen(data); + ret->v.str = data; + + return ret; +} + +cn_cbor* cn_cbor_int_create(int64_t value + CBOR_CONTEXT, + cn_cbor_errback *errp) +{ + cn_cbor* ret; + INIT_CB(ret); + + if (value<0) { + ret->type = CN_CBOR_INT; + ret->v.sint = value; + } else { + ret->type = CN_CBOR_UINT; + ret->v.uint = value; + } + + return ret; +} + +static bool _append_kv(cn_cbor *cb_map, cn_cbor *key, cn_cbor *val) +{ + //Connect key and value and insert them into the map. + key->parent = cb_map; + key->next = val; + val->parent = cb_map; + val->next = NULL; + + if(cb_map->last_child) { + cb_map->last_child->next = key; + } else { + cb_map->first_child = key; + } + cb_map->last_child = val; + cb_map->length += 2; + return true; +} + +bool cn_cbor_map_put(cn_cbor* cb_map, + cn_cbor *cb_key, cn_cbor *cb_value, + cn_cbor_errback *errp) +{ + //Make sure input is a map. Otherwise + if(!cb_map || !cb_key || !cb_value || cb_map->type != CN_CBOR_MAP) + { + if (errp) {errp->err = CN_CBOR_ERR_INVALID_PARAMETER;} + return false; + } + + return _append_kv(cb_map, cb_key, cb_value); +} + +bool cn_cbor_mapput_int(cn_cbor* cb_map, + int64_t key, cn_cbor* cb_value + CBOR_CONTEXT, + cn_cbor_errback *errp) +{ + cn_cbor* cb_key; + + //Make sure input is a map. Otherwise + if(!cb_map || !cb_value || cb_map->type != CN_CBOR_MAP) + { + if (errp) {errp->err = CN_CBOR_ERR_INVALID_PARAMETER;} + return false; + } + + cb_key = cn_cbor_int_create(key CBOR_CONTEXT_PARAM, errp); + if (!cb_key) { return false; } + return _append_kv(cb_map, cb_key, cb_value); +} + +bool cn_cbor_mapput_string(cn_cbor* cb_map, + const char* key, cn_cbor* cb_value + CBOR_CONTEXT, + cn_cbor_errback *errp) +{ + cn_cbor* cb_key; + + //Make sure input is a map. Otherwise + if(!cb_map || !cb_value || cb_map->type != CN_CBOR_MAP) + { + if (errp) {errp->err = CN_CBOR_ERR_INVALID_PARAMETER;} + return false; + } + + cb_key = cn_cbor_string_create(key CBOR_CONTEXT_PARAM, errp); + if (!cb_key) { return false; } + return _append_kv(cb_map, cb_key, cb_value); +} + +cn_cbor* cn_cbor_array_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp) +{ + cn_cbor* ret; + INIT_CB(ret); + + ret->type = CN_CBOR_ARRAY; + ret->flags |= CN_CBOR_FL_COUNT; + + return ret; +} + +bool cn_cbor_array_append(cn_cbor* cb_array, + cn_cbor* cb_value, + cn_cbor_errback *errp) +{ + //Make sure input is an array. + if(!cb_array || !cb_value || cb_array->type != CN_CBOR_ARRAY) + { + if (errp) {errp->err = CN_CBOR_ERR_INVALID_PARAMETER;} + return false; + } + + cb_value->parent = cb_array; + cb_value->next = NULL; + if(cb_array->last_child) { + cb_array->last_child->next = cb_value; + } else { + cb_array->first_child = cb_value; + } + cb_array->last_child = cb_value; + cb_array->length++; + return true; +} + +#ifdef __cplusplus +} +#endif + +#endif /* CN_CBOR_C */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-encoder.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-encoder.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,407 @@ +#ifndef CN_ENCODER_C +#define CN_ENCODER_C + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef EMACS_INDENTATION_HELPER +} /* Duh. */ +#endif + +#include <string.h> +#include <stdbool.h> +#include <assert.h> +#include <limits.h> +#include <math.h> +#include "cn-cbor.h" +#include "cbor.h" + +// Provide our own implementation of htons() and htonl() to avoid inclusion of inet.h or arpa/inet,h, +// which can create unintended depedencies. + +static uint16_t htons(const uint16_t host16) { + uint16_t be16; + uint8_t *be16_ptr = (uint8_t*)&be16; + + be16_ptr[0] = (host16 >> 8) & 0xff; + be16_ptr[1] = (host16 >> 0) & 0xff; + + return be16; +} + +static uint32_t htonl(const uint32_t host32) { + uint32_t be32; + uint8_t *be32_ptr = (uint8_t*)&be32; + + be32_ptr[0] = (host32 >> 24) & 0xff; + be32_ptr[1] = (host32 >> 16) & 0xff; + be32_ptr[2] = (host32 >> 8) & 0xff; + be32_ptr[3] = (host32 >> 0) & 0xff; + + return be32; +} + +#define hton8p(p) (*(uint8_t*)(p)) +#define hton16p(p) (htons(*(uint16_t*)(p))) +#define hton32p(p) (htonl(*(uint32_t*)(p))) +static uint64_t hton64p(const uint8_t *p) { + /* TODO: does this work on both BE and LE systems? */ + uint64_t ret = hton32p(p); + ret <<= 32; + ret |= hton32p(p+4); + return ret; +} + +typedef struct _write_state +{ + uint8_t *buf; + int offset; + int size; +} cn_write_state; + +#define ensure_writable(sz) if ((ws->offset<0) || (ws->offset + (sz) > ws->size)) { \ + ws->offset = -1; \ + return; \ +} + +#define write_byte_and_data(b, data, sz) \ +if (ws->buf == NULL) { ws->offset += sz + 1; } \ +else { \ +ws->buf[ws->offset++] = (b); \ +memcpy(ws->buf + ws->offset, (data), (sz)); \ +ws->offset += sz; \ +} + +#define write_byte(b) \ +if (ws->buf == NULL) { ws->offset++; } \ +else { ws->buf[ws->offset++] = (b); } \ + +#define write_byte_ensured(b) \ +ensure_writable(1); \ +write_byte(b); \ + +static uint8_t _xlate[] = { + IB_FALSE, /* CN_CBOR_FALSE */ + IB_TRUE, /* CN_CBOR_TRUE */ + IB_NIL, /* CN_CBOR_NULL */ + IB_UNDEF, /* CN_CBOR_UNDEF */ + IB_UNSIGNED, /* CN_CBOR_UINT */ + IB_NEGATIVE, /* CN_CBOR_INT */ + IB_BYTES, /* CN_CBOR_BYTES */ + IB_TEXT, /* CN_CBOR_TEXT */ + IB_BYTES, /* CN_CBOR_BYTES_CHUNKED */ + IB_TEXT, /* CN_CBOR_TEXT_CHUNKED */ + IB_ARRAY, /* CN_CBOR_ARRAY */ + IB_MAP, /* CN_CBOR_MAP */ + IB_TAG, /* CN_CBOR_TAG */ + IB_PRIM, /* CN_CBOR_SIMPLE */ + 0xFF, /* CN_CBOR_DOUBLE */ + 0xFF /* CN_CBOR_INVALID */ +}; + +static inline bool is_indefinite(const cn_cbor *cb) +{ + return (cb->flags & CN_CBOR_FL_INDEF) != 0; +} + +static void _write_positive(cn_write_state *ws, cn_cbor_type typ, uint64_t val) { + uint8_t ib; + assert((size_t)typ < sizeof(_xlate)); + + ib = _xlate[typ]; + if (ib == 0xFF) { + ws->offset = -1; + return; + } + + if (val < 24) { + ensure_writable(1); + write_byte(ib | val); + } else if (val < 256) { + ensure_writable(2); + write_byte(ib | 24); + write_byte((uint8_t)val); + } else if (val < 65536) { + uint16_t be16 = (uint16_t)val; + ensure_writable(3); + be16 = hton16p(&be16); + write_byte_and_data(ib | 25, (const void*)&be16, 2); + } else if (val < 0x100000000L) { + uint32_t be32 = (uint32_t)val; + ensure_writable(5); + be32 = hton32p(&be32); + write_byte_and_data(ib | 26, (const void*)&be32, 4); + } else { + uint64_t be64; + ensure_writable(9); + be64 = hton64p((const uint8_t*)&val); + write_byte_and_data(ib | 27, (const void*)&be64, 8); + } +} + +#ifndef CBOR_NO_FLOAT +static void _write_double(cn_write_state *ws, double val) +{ + float float_val = val; + + /* NOTE - the following code block assures portability across + different OSs, it is even necessary when running + different OSs under same toolchain. */ + if (isnan(val)) { + float_val = NAN; + } else if (isinf(val) && isgreater(val, 0)) { + float_val = INFINITY; + } else if (isinf(val) && isless(val, 0)) { + float_val = -INFINITY; + } + + if (((float_val == val) && !isnan(val)) || (isinf(val) && isinf(float_val))) { /* 32 bits is enough and we aren't NaN or INFINITY */ + uint32_t be32; + uint16_t be16, u16; + union { + float f; + uint32_t u; + } u32; + u32.f = float_val; + if ((u32.u & 0x1FFF) == 0) { /* worth trying half */ + int s16 = (u32.u >> 16) & 0x8000; + int exp = (u32.u >> 23) & 0xff; + int mant = u32.u & 0x7fffff; + if (exp == 0 && mant == 0) + ; /* 0.0, -0.0 */ + else if (exp >= 113 && exp <= 142) /* normalized */ + s16 += ((exp - 112) << 10) + (mant >> 13); + else if (exp >= 103 && exp < 113) { /* denorm, exp16 = 0 */ + if (mant & ((1 << (126 - exp)) - 1)) + goto float32; /* loss of precision */ + s16 += ((mant + 0x800000) >> (126 - exp)); + } else if (exp == 255 && mant == 0) { /* Inf */ + s16 += 0x7c00; + } else + goto float32; /* loss of range */ + + ensure_writable(3); + u16 = s16; + be16 = hton16p((const uint8_t*)&u16); + + write_byte_and_data(IB_PRIM | 25, (const void*)&be16, 2); + return; + } + float32: + ensure_writable(5); + be32 = hton32p((const uint8_t*)&u32.u); + + write_byte_and_data(IB_PRIM | 26, (const void*)&be32, 4); + + } else if (isnan(val)) { /* NaN -- we always write a half NaN*/ + ensure_writable(3); + write_byte_and_data(IB_PRIM | 25, (const void*)"\x7e\x00", 2); + } else { + uint64_t be64; + /* Copy the same problematic implementation from the decoder. */ + union { + double d; + uint64_t u; + } u64; + + u64.d = val; + + ensure_writable(9); + be64 = hton64p((const uint8_t*)&u64.u); + + write_byte_and_data(IB_PRIM | 27, (const void*)&be64, 8); + + } +} +#endif /* CBOR_NO_FLOAT */ + +// TODO: make public? +typedef void (*cn_visit_func)(const cn_cbor *cb, int depth, void *context); +static void _visit(const cn_cbor *cb, + cn_visit_func visitor, + cn_visit_func breaker, + void *context) +{ + const cn_cbor *p = cb; + int depth = 0; + while (p) + { + visit: + + visitor(p, depth, context); + + if (p->first_child) { + + p = p->first_child; + depth++; + } else{ + + // Empty indefinite + if (is_indefinite(p)) { + + breaker(p->parent, depth, context); + } + if (p->next) { + p = p->next; + } else { + while (p->parent) { + depth--; + if (is_indefinite(p->parent)) { + breaker(p->parent, depth, context); + } + if (p->parent->next) { + p = p->parent->next; + goto visit; + } + p = p->parent; + } + return; + } + } + } +} + +#define CHECK(st) (st); \ +if (ws->offset < 0) {return;} + +void _encoder_visitor(const cn_cbor *cb, int depth, void *context) +{ + cn_write_state *ws = context; + UNUSED_PARAM(depth); + + switch (cb->type) { + case CN_CBOR_ARRAY: + if (is_indefinite(cb)) { + write_byte_ensured(IB_ARRAY | AI_INDEF); + } else { + CHECK(_write_positive(ws, CN_CBOR_ARRAY, cb->length)); + } + break; + case CN_CBOR_MAP: + if (is_indefinite(cb)) { + write_byte_ensured(IB_MAP | AI_INDEF); + } else { + CHECK(_write_positive(ws, CN_CBOR_MAP, cb->length/2)); + } + break; + case CN_CBOR_BYTES_CHUNKED: + case CN_CBOR_TEXT_CHUNKED: + write_byte_ensured(_xlate[cb->type] | AI_INDEF); + break; + + case CN_CBOR_TEXT: + case CN_CBOR_BYTES: + CHECK(_write_positive(ws, cb->type, cb->length)); + ensure_writable(cb->length); + if (ws->buf != NULL) + { + memcpy(ws->buf + ws->offset, cb->v.str, cb->length); + } + + ws->offset += cb->length; + + break; + + case CN_CBOR_FALSE: + case CN_CBOR_TRUE: + case CN_CBOR_NULL: + case CN_CBOR_UNDEF: + write_byte_ensured(_xlate[cb->type]); + break; + + case CN_CBOR_TAG: + case CN_CBOR_UINT: + case CN_CBOR_SIMPLE: + CHECK(_write_positive(ws, cb->type, cb->v.uint)); + break; + + case CN_CBOR_INT: + assert(cb->v.sint < 0); + CHECK(_write_positive(ws, CN_CBOR_INT, ~(cb->v.sint))); + break; + + case CN_CBOR_DOUBLE: +#ifndef CBOR_NO_FLOAT + CHECK(_write_double(ws, cb->v.dbl)); +#endif /* CBOR_NO_FLOAT */ + break; + + case CN_CBOR_INVALID: + ws->offset = -1; + break; + } +} + +void _encoder_breaker(const cn_cbor *cb, int depth, void *context) +{ + cn_write_state *ws = context; + UNUSED_PARAM(cb); + UNUSED_PARAM(depth); + write_byte_ensured(IB_BREAK); +} + +/* +If called with a NULL buf, will run as usual but will not copy any data. +This is done in order to acquire the size of the buffer we will allocate for the decoded buffer. +*/ +static int cn_cbor_encoder(uint8_t *buf, + size_t buf_offset, + size_t buf_size, + const cn_cbor *cb) +{ + int ret; + cn_write_state ws = { buf, buf_offset, buf_size }; + _visit(cb, _encoder_visitor, _encoder_breaker, &ws); + + if (ws.offset < 0) { return -1; } + ret = ws.offset - buf_offset; + return ret; +} + +int cn_cbor_get_encoded_size(const cn_cbor *cb, cn_cbor_errback *err) +{ + int ret; + + if (cb == NULL) { + err->err = CN_CBOR_ERR_INVALID_PARAMETER; + return -1; + } + + ret = cn_cbor_encoder(NULL, 0, INT_MAX, cb); + if (ret <= 0) { + err->err = CN_CBOR_ERR_ENCODER; + return -1; + } + + err->err = CN_CBOR_NO_ERROR; + return ret; +} + +int cn_cbor_encoder_write(const cn_cbor *cb, uint8_t *bufOut, int bufSize, cn_cbor_errback *err) +{ + int bytesWritten; + + if (bufOut == NULL) { + err->err = CN_CBOR_ERR_INVALID_PARAMETER; + return -1; + } + + bytesWritten = cn_cbor_encoder(bufOut, 0, bufSize, cb); + if (bytesWritten <= 0) + { + err->err = CN_CBOR_ERR_ENCODER; + } + else + { + err->err = CN_CBOR_NO_ERROR; + + } + + return bytesWritten; +} + +#ifdef __cplusplus +} +#endif + +#endif /* CN_CBOR_C */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-error.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-error.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +const char *cn_cbor_error_str[] = { + "CN_CBOR_NO_ERROR", + "CN_CBOR_ERR_OUT_OF_DATA", + "CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED", + "CN_CBOR_ERR_ODD_SIZE_INDEF_MAP", + "CN_CBOR_ERR_BREAK_OUTSIDE_INDEF", + "CN_CBOR_ERR_MT_UNDEF_FOR_INDEF", + "CN_CBOR_ERR_RESERVED_AI", + "CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING", + "CN_CBOR_ERR_INVALID_PARAMETER", + "CN_CBOR_ERR_OUT_OF_MEMORY", + "CN_CBOR_ERR_FLOAT_NOT_SUPPORTED", + "CN_CBOR_ERR_ENCODER" +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-get.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/secsrv-cbor/source/cn-get.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,63 @@ +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "cn-cbor.h" + +cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key) { + cn_cbor* cp; + assert(cb); + for (cp = cb->first_child; cp && cp->next; cp = cp->next->next) { + switch(cp->type) { + case CN_CBOR_UINT: + if (cp->v.uint == (unsigned long)key) { + return cp->next; + } + break; + case CN_CBOR_INT: + if (cp->v.sint == (long)key) { + return cp->next; + } + break; + default: + ; // skip non-integer keys + } + } + return NULL; +} + +cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key) { + cn_cbor *cp; + int keylen; + assert(cb); + assert(key); + keylen = strlen(key); + for (cp = cb->first_child; cp && cp->next; cp = cp->next->next) { + switch(cp->type) { + case CN_CBOR_TEXT: // fall-through + case CN_CBOR_BYTES: + if (keylen != cp->length) { + continue; + } + if (memcmp(key, cp->v.str, keylen) == 0) { + return cp->next; + } + default: + ; // skip non-string keys + } + } + return NULL; +} + +cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx) { + cn_cbor *cp; + unsigned int i = 0; + assert(cb); + for (cp = cb->first_child; cp; cp = cp->next) { + if (i == idx) { + return cp; + } + i++; + } + return NULL; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/storage/source/storage.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/storage/source/storage.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,407 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <stdbool.h> +#include "pv_error_handling.h" +#include "storage.h" +#include "esfs.h" + +static kcm_status_e error_handler(esfs_result_e esfs_status) +{ + switch (esfs_status) { + case ESFS_SUCCESS: + return KCM_STATUS_SUCCESS; + case ESFS_INVALID_PARAMETER: + return KCM_STATUS_INVALID_PARAMETER; + case ESFS_BUFFER_TOO_SMALL: + return KCM_STATUS_INSUFFICIENT_BUFFER; + case ESFS_EXISTS: + return KCM_STATUS_FILE_EXIST; + case ESFS_NOT_EXISTS: + return KCM_STATUS_ITEM_NOT_FOUND; + case ESFS_INVALID_FILE_VERSION: + return KCM_STATUS_INVALID_FILE_VERSION; + case ESFS_CMAC_DOES_NOT_MATCH: + return KCM_STATUS_FILE_CORRUPTED; + case ESFS_ERROR: + return KCM_STATUS_STORAGE_ERROR; + case ESFS_HASH_CONFLICT: + return KCM_STATUS_FILE_NAME_CORRUPTED; + case ESFS_FILE_OPEN_FOR_READ: + case ESFS_FILE_OPEN_FOR_WRITE: + return KCM_STATUS_INVALID_FILE_ACCESS_MODE; + default: + return KCM_STATUS_UNKNOWN_STORAGE_ERROR; + } +} + + +static bool is_file_accessible(const kcm_ctx_s *ctx) +{ + // FIXME - We need to check file access availability by comparing KCM context TLVs vs the target file header stored in ESFS that contains + // TLVs and access rights. In order to retrieve ESFS file TLVs and access rights we should use the following methods + // that are currently not implemented: + // - esfs_get_meta_data_qty + // - esfs_get_meta_data_types + // - esfs_get_meta_data_buffer_size + // - esfs_read_meta_data + // - esfs_get_meta_data_qty + + ctx = ctx; // currently unused + + return true; +} + +kcm_status_e storage_init() +{ + esfs_result_e esfs_status; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + esfs_status = esfs_init(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed initializing ESFS (esfs_status %d)", esfs_status); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; +} + +kcm_status_e storage_finalize() +{ + esfs_result_e esfs_status; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + esfs_status = esfs_finalize(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed finalizing ESFS (esfs_status %d)", esfs_status); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; +} + +kcm_status_e storage_reset() +{ + esfs_result_e esfs_status; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + esfs_status = esfs_reset(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed reset ESFS (esfs_status %d)", esfs_status); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; +} + + +kcm_status_e storage_factory_reset() +{ + esfs_result_e esfs_status; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + esfs_status = esfs_factory_reset(); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed factory reset ESFS (esfs_status %d)", esfs_status); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; +} + +kcm_status_e storage_file_write(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length, const uint8_t *data, size_t data_length, bool is_factory, bool is_encrypted) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + kcm_status_e close_file_status = KCM_STATUS_SUCCESS; + + kcm_status = storage_file_create(ctx, file_name, file_name_length, is_factory, is_encrypted); + SA_PV_ERR_RECOVERABLE_RETURN_IF(kcm_status != KCM_STATUS_SUCCESS, kcm_status, "Failed to create new file"); + + kcm_status = storage_file_write_with_ctx(ctx, data, data_length);// we don't check error because we need to close the file in any case + + // Data is only guaranteed to be flushed to the media on efs_close. + close_file_status = storage_file_close(ctx); + + if (kcm_status != KCM_STATUS_SUCCESS) { // delete the file if didn't succeed to write + (void)storage_file_delete(ctx, file_name, file_name_length); + SA_PV_ERR_RECOVERABLE_RETURN_IF(kcm_status != KCM_STATUS_SUCCESS, kcm_status, "Failed to write data"); + } + + SA_PV_ERR_RECOVERABLE_RETURN_IF(close_file_status != KCM_STATUS_SUCCESS, close_file_status, "Failed to close file"); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return kcm_status; +} + +kcm_status_e storage_file_size_get(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length, size_t *file_size_out) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + kcm_status_e close_staus = KCM_STATUS_SUCCESS; + + SA_PV_LOG_TRACE_FUNC_ENTER("file_name_length=%" PRIu32 "", (uint32_t)file_name_length); + + kcm_status = storage_file_open(ctx, file_name, file_name_length); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed to open the given file"); + + kcm_status = storage_file_size_get_with_ctx(ctx, file_size_out); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status = kcm_status, exit, "Failed getting file size"); + +exit: + close_staus = storage_file_close(ctx); + if (kcm_status == KCM_STATUS_SUCCESS) { + kcm_status = close_staus; + } + + return kcm_status; +} + +kcm_status_e storage_file_read(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length, uint8_t *buffer_out, size_t buffer_size, size_t *buffer_actual_size_out) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + kcm_status_e close_status = KCM_STATUS_SUCCESS; + + kcm_status = storage_file_open(ctx, file_name, file_name_length); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed to open the given file"); + + kcm_status = storage_file_read_with_ctx(ctx, buffer_out, buffer_size, buffer_actual_size_out); + SA_PV_ERR_RECOVERABLE_GOTO_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status = kcm_status, exit, "Failed ti read file"); + +exit: + close_status = storage_file_close(ctx); + if (kcm_status == KCM_STATUS_SUCCESS) { + kcm_status = close_status; + } + + return kcm_status; +} + +kcm_status_e storage_file_delete(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length) +{ + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + esfs_result_e esfs_status; + uint16_t esfs_mode = 0; // FIXME - Unused, yet implemented + bool success; + + SA_PV_LOG_TRACE_FUNC_ENTER("file_name_length=%" PRIu32 "", (uint32_t)file_name_length); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((file_name == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid file name context"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((file_name_length == 0), KCM_STATUS_INVALID_PARAMETER, "Got empty file name"); + + esfs_status = esfs_open(file_name, file_name_length, &esfs_mode, &ctx->esfs_file_h); + + //file does not exists, exit from delete function + if (esfs_status == ESFS_NOT_EXISTS) { + return error_handler(esfs_status); + } + + if (esfs_status != ESFS_SUCCESS) { //file exists but there is some corruption. We will delete the file without checking it's permissions + SA_PV_LOG_ERR("The file exists but corrupted. Delete it without checking permissions"); + esfs_status = ESFS_SUCCESS; + + } else { // check permissions + success = is_file_accessible(ctx); + if (!success) { + SA_PV_LOG_ERR("Caller has no access rights to the given file"); + kcm_status = KCM_STATUS_NOT_PERMITTED; + } + + esfs_status = esfs_close(&ctx->esfs_file_h); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed closing file (esfs_status %d)", esfs_status); + + if (kcm_status == KCM_STATUS_NOT_PERMITTED) { + return kcm_status; + } + } + + // Delete the file + esfs_status = esfs_delete(file_name, file_name_length); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed deleting file (esfs_status %d)", esfs_status); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return kcm_status; +} + + +kcm_status_e storage_file_create(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length, bool is_factory, bool is_encrypted) +{ + esfs_result_e esfs_status; + esfs_tlv_item_t esfs_meta_data[1]; // FIXME - Unused, yet implemented + + SA_PV_LOG_TRACE_FUNC_ENTER("file_name_length=%" PRIu32 " ", (uint32_t)file_name_length); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((ctx == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid context"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((file_name == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid file name context"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((file_name_length == 0), KCM_STATUS_INVALID_PARAMETER, "Got empty file name"); + + memset(ctx, 0, sizeof(kcm_ctx_s)); + + if (is_factory) { + ctx->access_flags |= ESFS_FACTORY_VAL; + } + if (is_encrypted) { + ctx->access_flags |= ESFS_ENCRYPTED; + } + + esfs_status = esfs_create(file_name, file_name_length, &esfs_meta_data[0], 0, ctx->access_flags, &ctx->esfs_file_h); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status == ESFS_EXISTS), KCM_STATUS_FILE_EXIST, "File already exist in ESFS (esfs_status %" PRIu32 ")", (uint32_t)esfs_status); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed creating file (esfs_status %" PRIu32 ")", (uint32_t)esfs_status); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; +} + +/** Open existing file +* +* @param ctx KCM operation context. +* @param file_name A binary blob that uniquely identifies the file +* @param file_name_length The binary blob length in bytes. +@param is_factory True if KCM item is factory item, or false otherwise +@param is_encrypted True if KCM item should be encrypted, or false otherwise +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_open(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length) +{ + + kcm_status_e kcm_status = KCM_STATUS_SUCCESS; + esfs_result_e esfs_status; + uint16_t esfs_mode = 0; // FIXME - Unused, yet implemented + bool success; + + SA_PV_LOG_TRACE_FUNC_ENTER("file_name_length=%" PRIu32 "", (uint32_t)file_name_length); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((ctx == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid context"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((file_name == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid file name context"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((file_name_length == 0), KCM_STATUS_INVALID_PARAMETER, "Got empty file name"); + + memset(ctx, 0, sizeof(kcm_ctx_s)); + + esfs_status = esfs_open(file_name, file_name_length, &esfs_mode, &ctx->esfs_file_h); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed opening file (esfs_status %d)", esfs_status); + + success = is_file_accessible(ctx); + if (!success) { + kcm_status = KCM_STATUS_NOT_PERMITTED; + esfs_close(&ctx->esfs_file_h); + memset(ctx, 0, sizeof(kcm_ctx_s)); + } + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Caller has no access rights to the given file"); + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; +} + +/** Close file in storage +* +* @param ctx KCM operation context. +@param is_factory True if KCM item is factory item, or false otherwise +@param is_encrypted True if KCM item should be encrypted, or false otherwise +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_close(kcm_ctx_s *ctx) +{ + esfs_result_e esfs_status; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((ctx == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid context"); + + // Data is only guaranteed to be flushed to the media on efs_close. + esfs_status = esfs_close(&ctx->esfs_file_h); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed closing file (esfs_status %d)", esfs_status); + + memset(ctx, 0, sizeof(ctx)); + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; +} + + +kcm_status_e storage_file_write_with_ctx(kcm_ctx_s *ctx, const uint8_t *data, size_t data_length) +{ + esfs_result_e esfs_status; + + SA_PV_LOG_TRACE_FUNC_ENTER("data_length=%" PRIu32 "", (uint32_t)data_length); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((ctx == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid context"); + SA_PV_ERR_RECOVERABLE_RETURN_IF(((data == NULL) && (data_length > 0)), KCM_STATUS_INVALID_PARAMETER, "Provided NULL data buffer and data_length greater than 0"); + + if (data_length != 0) { + esfs_status = esfs_write(&ctx->esfs_file_h, data, data_length); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed writing (%" PRIu32 " B) size to file (esfs_status %" PRIu32 ")", (uint32_t)data_length, (uint32_t)esfs_status); + } + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; + +} + +kcm_status_e storage_file_size_get_with_ctx(kcm_ctx_s *ctx, size_t *file_size_out) +{ + esfs_result_e esfs_status; + + SA_PV_LOG_TRACE_FUNC_ENTER_NO_ARGS(); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((ctx == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid context"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((file_size_out == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid pointer to file size"); + + esfs_status = esfs_file_size(&ctx->esfs_file_h, file_size_out); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed getting file size (esfs_status %d)", esfs_status); + + ctx->is_file_size_checked = true; + ctx->file_size = *file_size_out; + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; +} + + +kcm_status_e storage_file_read_with_ctx(kcm_ctx_s *ctx, uint8_t *buffer_out, size_t buffer_size, size_t *buffer_actual_size_out) +{ + esfs_result_e esfs_status; + kcm_status_e kcm_status; + + SA_PV_LOG_TRACE_FUNC_ENTER("buffer_size=%" PRIu32 "", (uint32_t)buffer_size); + + SA_PV_ERR_RECOVERABLE_RETURN_IF((ctx == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid context"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((buffer_out == NULL && buffer_size !=0 ), KCM_STATUS_INVALID_PARAMETER, "Invalid pointer to read buffer"); + SA_PV_ERR_RECOVERABLE_RETURN_IF((buffer_actual_size_out == NULL), KCM_STATUS_INVALID_PARAMETER, "Invalid pointer to output size"); + + if (ctx->is_file_size_checked == false) { + kcm_status = storage_file_size_get_with_ctx(ctx, buffer_actual_size_out); + SA_PV_ERR_RECOVERABLE_RETURN_IF((kcm_status != KCM_STATUS_SUCCESS), kcm_status, "Failed getting file data size (kcm_status %d)", kcm_status); + } + + SA_PV_ERR_RECOVERABLE_RETURN_IF((buffer_size < ctx->file_size), KCM_STATUS_INSUFFICIENT_BUFFER, "Buffer too small"); + + if (ctx->file_size != 0) { + esfs_status = esfs_read(&ctx->esfs_file_h, buffer_out, buffer_size, buffer_actual_size_out); + SA_PV_ERR_RECOVERABLE_RETURN_IF((esfs_status != ESFS_SUCCESS), error_handler(esfs_status), "Failed reading file data (esfs_status %d)", esfs_status); + } + + SA_PV_LOG_TRACE_FUNC_EXIT_NO_ARGS(); + + return KCM_STATUS_SUCCESS; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/storage/storage/storage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/storage/storage/storage.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,191 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __STORAGE_H__ +#define __STORAGE_H__ + +#include <inttypes.h> +#include "key_config_manager.h" +#include "kcm_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* === Initialization and Finalization === */ + +/** Initializes storage so that it can be used. +* Must be called once after boot. +* Existing data in storage would not compromised. +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_init(void); + + +/** Finalize storage. +* Must be called once to close all storage resources. +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_finalize(void); + +/** Resets storage to an empty state. +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_reset(void); + + +/** Resets storage to a factory state. +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_factory_reset(void); + + +/* === File Operations === */ + +/** Create a new file +* +* @param KCM operation context. +* @param file_name A binary blob that uniquely identifies the file +* @param file_name_length The binary blob length in bytes. +* @param is_factory A factory flag. +* @param is_encrypted Encryption flag +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_create(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length, bool is_factory, bool is_encrypted); + +/** Open existing file +* +* @param KCM operation context. +* @param file_name A binary blob that uniquely identifies the file +* @param file_name_length The binary blob length in bytes. +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_open(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length); + +/** Close file in storage +* +* @param ctx KCM operation context. +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_close(kcm_ctx_s *ctx); + +/** Write data to previously opened file in storage +* +* @param ctx KCM operation context. +* @param data A pointer to memory with the data to write into the newly created file. Can be NULL if data_length is 0. +* @param data_length The data length in bytes. Can be 0 if we wish to write an empty file. +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_write_with_ctx(kcm_ctx_s *ctx, const uint8_t *data, size_t data_length); + + +/** Writes a new file to storage +* +* @param ctx KCM operation context. +* @param file_name A binary blob that uniquely identifies the file +* @param file_name_length The binary blob length in bytes. +* @param data A pointer to memory with the data to write into the newly created file. Can be NULL if data_length is 0. +* @param data_length The data length in bytes. Can be 0 if we wish to write an empty file. + @param is_factory True if KCM item is factory item, or false otherwise + @param is_encrypted True if KCM item should be encrypted, or false otherwise +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_write(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length, const uint8_t *data, size_t data_length, bool is_factory, bool is_encrypted); + + +/** Returns the size of the data in a file +* +* @param ctx KCM operation context. +* @param file_name A binary blob that uniquely identifies the file +* @param file_name_length The binary blob length in bytes +* @param file_size_out A pointer to hold the size of the data in the file +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_size_get(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length, size_t *file_size_out); + +/** Reads data from a file. +* +* @param ctx KCM operation context. +* @param file_name A binary blob that uniquely identifies the file +* @param file_name_length The binary blob length in bytes +* @param buffer_out A pointer to memory buffer where the data will be read from the file. Can be NULL if buffer_size is 0. +* @param buffer_size The number of bytes to be read. Buffer must be big enough to contain this size. Can be 0 if we wish to read an empty file. +* @param buffer_actual_size_out The effective bytes size read from the file. +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_read(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length, uint8_t *buffer_out, size_t buffer_size, size_t *buffer_actual_size_out); + +/** Returns the size of the data in a file. The file should be opened by storage_file_open() +* +* @param ctx KCM operation context. +* @param file_size_out A pointer to hold the size of the data in the file +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_size_get_with_ctx(kcm_ctx_s *ctx, size_t *file_size_out); + +/** Reads data from a file. The file should be opened by storage_file_open(). +* +* @param ctx KCM operation context. +* @param buffer_out A pointer to memory buffer where the data will be read from the file. Can be NULL if buffer_size is 0. +* @param buffer_size The number of bytes to be read. Buffer must be big enough to contain this size. Can be 0 if we wish to read an empty file. +* @param buffer_actual_size_out The effective bytes size read from the file. +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_read_with_ctx(kcm_ctx_s *ctx, uint8_t *buffer_out, size_t buffer_size, size_t *buffer_actual_size_out); +/** Deletes the file from storage +* +* @param ctx KCM operation context. +* @param file_name A binary blob that uniquely identifies the file +* @param file_name_length The binary blob length in bytes +* +* @returns +* KCM_STATUS_SUCCESS in case of success otherwise one of kcm_status_e errors +*/ +kcm_status_e storage_file_delete(kcm_ctx_s *ctx, const uint8_t *file_name, size_t file_name_length); + + +#ifdef __cplusplus +} +#endif + +#endif //__STORAGE_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/source/fcc_stats.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/source/fcc_stats.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,90 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifdef FCC_MEM_STATS_ENABLED + +#include <stdlib.h> +#include <inttypes.h> + +#include "fcc_malloc.h" +#include "fcc_malloc.h" +#include "pv_log.h" + +typedef struct { + uint32_t current_size; /* Bytes allocated currently */ + uint32_t total_size; /* Cumulative sum of bytes ever allocated. */ + uint32_t max_peak_size; /* Max peak allocated at a certain time (e.g.: getting worst case memory usage) */ + uint32_t alloc_cnt; /* Current number of allocations. */ + uint32_t free_cnt; /* Current number of frees. */ + uint32_t alloc_fail_cnt; /* Number of failed allocations. */ +} stats_heap_t; + +/* Size must be a multiple of 8 to keep alignment */ +typedef struct { + uint32_t size; + uint32_t pad; +} alloc_info_t; + +static stats_heap_t g_fcc_heap_stats = { 0, 0, 0, 0, 0, 0 }; + +void *fcc_malloc(size_t size) +{ + void *ptr = NULL; + alloc_info_t *alloc_info = (alloc_info_t *)malloc(sizeof(alloc_info_t) + size); + + if (alloc_info != NULL) { + alloc_info->size = size; + ptr = (void *)(alloc_info + 1); + + g_fcc_heap_stats.current_size += size; + g_fcc_heap_stats.total_size += size; + g_fcc_heap_stats.alloc_cnt += 1; + + if (g_fcc_heap_stats.current_size > g_fcc_heap_stats.max_peak_size) { + g_fcc_heap_stats.max_peak_size = g_fcc_heap_stats.current_size; + } + } else { + g_fcc_heap_stats.alloc_fail_cnt += 1; + } + + return ptr; +} + +void fcc_free(void *ptr) +{ + alloc_info_t *alloc_info = NULL; + + if (ptr != NULL) { + alloc_info = ((alloc_info_t *)ptr) - 1; + g_fcc_heap_stats.current_size -= alloc_info->size; + g_fcc_heap_stats.free_cnt += 1; + free(alloc_info); + } +} + +void fcc_stats_print_summary(void) +{ + // Use printf since this is printed after mbed trace has been destroyed. + printf(" ********* FCC Heap Statistics *********\n"); + printf(" * Total bytes allocated: %" PRIu32 "\n", g_fcc_heap_stats.total_size); + printf(" * Max peak ever allocated: %" PRIu32 "\n", g_fcc_heap_stats.max_peak_size); + printf(" * Number of allocation succeeded: %" PRIu32 "\n", g_fcc_heap_stats.alloc_cnt); + printf(" * Number of frees succeeded: %" PRIu32 "\n", g_fcc_heap_stats.free_cnt); + printf(" * Number of allocation failed: %" PRIu32 "\n", g_fcc_heap_stats.alloc_fail_cnt); + printf(" ***************************************\n"); +} + +#endif //FCC_MEM_STATS_ENABLED
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/source/fcc_time_profiling.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/source/fcc_time_profiling.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,29 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + + +#include "fcc_time_profiling.h" + +#ifdef FCC_TIME_PROFILING + +uint64_t fcc_gen_timer = 0; +uint64_t fcc_bundle_timer = 0; +uint64_t fcc_key_timer = 0; +uint64_t fcc_certificate_timer = 0; +uint64_t fcc_config_param_timer = 0; +uint64_t fcc_certificate_chain_timer = 0; +#endif +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/source/general_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/source/general_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,23 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <stdbool.h> +#include <string.h> + +bool is_memory_equal(const void *buf1, size_t size_of_buf1, const void *buf2, size_t size_of_buf2) +{ + return ((size_of_buf1 == size_of_buf2) && !memcmp(buf1, buf2, size_of_buf1)); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/source/pv_error_handling.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/source/pv_error_handling.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + + +#include "stdbool.h" +#include "pv_error_handling.h" + +static bool g_pv_is_error_occured = false; + +void pv_error_occured(void) +{ + g_pv_is_error_occured = true; +} + +bool pv_error_is_error_occured(void) +{ + return g_pv_is_error_occured; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/fcc_malloc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/fcc_malloc.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,58 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_STATS_H__ +#define __FCC_STATS_H__ + +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/** +* Allocate the requested amount of bytes and log heap statistics. +* - It is assumed FCC running in a single thread (no thread safety) +* - This function does not allows re-entrance +* +* @param size The amount of bytes to allocate on the heap memory +* +* @returns +* If allocation succeeded - a valid pointer to the beginning of the allocated heap memory +* If allocation failed - a NULL pointer will be returned +*/ +void *fcc_malloc(size_t size); + +/** +* Free the heap bytes followed by the given pointer and log heap statistics. +* - It is assumed FCC running in a single thread (no thread safety) +* - This function does not allows re-entrance +* +* @param ptr A pointer to the beginning of bytes allocated on the heap memory +*/ +void fcc_free(void *ptr); + +#ifndef FCC_MEM_STATS_ENABLED +#define fcc_malloc(size) malloc( (size) ) +#define fcc_free(ptr) free( (ptr) ) +#endif + +#ifdef __cplusplus +} +#endif + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/fcc_stats.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/fcc_stats.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,40 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_STATS_H__ +#define __FCC_STATS_H__ + +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Prints heap statistics results. +* - Usually user will call this function at program end. +*/ +void fcc_stats_print_summary(void); + +#ifndef FCC_MEM_STATS_ENABLED +#define fcc_stats_print_summary() +#endif + +#ifdef __cplusplus +} +#endif + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/fcc_time_profiling.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/fcc_time_profiling.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,99 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __FCC_TIME_PROFILING_H__ +#define __FCC_TIME_PROFILING_H__ + +#include <inttypes.h> +#include <stdbool.h> +#include <string.h> +#include "mbed_trace.h" +#include "pal.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef FCC_TIME_PROFILING + +extern uint64_t fcc_gen_timer; +extern uint64_t fcc_bundle_timer; +extern uint64_t fcc_key_timer; +extern uint64_t fcc_certificate_timer; +extern uint64_t fcc_config_param_timer; +extern uint64_t fcc_certificate_chain_timer; + +#define TRACE_GROUP "fcc" + +/** +* Init timer +*/ +#define FCC_INIT_TIMER(ticks) calculate_time("",0,pal_osKernelSysTick() - ticks) +/** +* Start timer +*/ +#define FCC_SET_START_TIMER(ticks) ticks=pal_osKernelSysTick(); + +/** +* End timer, print label and the calculated result. +* If the label is string "size" should be 0, and if the label is buffer - "size" should be the size of buffer to print. +*/ +#define FCC_END_TIMER(label,size, ticks) calculate_time(label,size,pal_osKernelSysTick() - ticks) +/** +* The function calculates time from started timer, prints the label as string or as buffer with size and the calulated time. +**/ + +static inline void calculate_time(const char *label, int size, uint64_t ticks) +{ + static double ticks_persecond = 0.0; + static double ticks_permillisecond = 0.0; + static double ticks_permicrosecond = 0.0; + + // Since the tick conversion to time functions on some of the reference platforms give incorrect results, + // we use pal_osDelay() to estimate how many ticks per second. We do this once and then base all + // subsequent calculations on the values that we store in static variables. + // For new platforms the accuracy of pal_osDelay() should be verified before accepting the time results. + if (ticks_persecond == 0.0) + { + // Calculate how many ticks per second + uint64_t tick1 = pal_osKernelSysTick(); + // One second delay + pal_osDelay(1000); + uint64_t tick2 = pal_osKernelSysTick(); + ticks_persecond = tick2 - tick1; + ticks_permillisecond = ticks_persecond / 1000.0; + ticks_permicrosecond = ticks_persecond / 1000000.0; + } + if (size == 0) { + //Print string + mbed_tracef(TRACE_LEVEL_ERROR, TRACE_GROUP, "%s: %20lu ticks, %10.2lf milli, %10.2lf micro\n", (char*)label, (long unsigned int)ticks, (double)(ticks / ticks_permillisecond), (double)(ticks / ticks_permicrosecond)); + } else { + //Print buffer with size "size" + mbed_tracef(TRACE_LEVEL_ERROR, TRACE_GROUP, "%.*s: %20lu ticks, %10.2lf milli, %10.2lf micro\n",size, label, (long unsigned int)ticks, (double)(ticks / ticks_permillisecond), (double)(ticks / ticks_permicrosecond)); + } +} +#else +#define FCC_INIT_TIMER(ticks) do {} while (0) +#define FCC_SET_START_TIMER(ticks) do {} while (0) +#define FCC_END_TIMER(label, size, ticks) do {} while (0) +#endif +#ifdef __cplusplus +} +#endif + +#endif // __PV_MACROS_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/general_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/general_utils.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,20 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <stdbool.h> + +bool is_memory_equal(const void *buf1, size_t size_of_buf1, const void *buf2, size_t size_of_buf2); +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/pv_endian.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/pv_endian.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,118 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __PV_ENDIAN_H__ +#define __PV_ENDIAN_H__ + +#include <inttypes.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file pv_endian.h + * + * Utility functions that treats endianness. + */ + + +/** Converts a little endian 32 bit integer to the host endianness, in a platform independent manner. + * + * @param le32 [in] 32 bit integer in little endian format. + * + * @returns + * 32 bit integer in host endianness format. + */ +static inline uint32_t pv_le32_to_h(uint32_t le32) +{ + const uint8_t* le32ptr = (uint8_t*)&le32; + return (le32ptr[0] << 0) + + (le32ptr[1] << 8) + + (le32ptr[2] << 16) + + (le32ptr[3] << 24); +} + +/** Converts a big endian 32 bit integer to the host endianness, in a platform independent manner. + * + * @param be32 [in] 32 bit integer in big endian format. + * + * @returns + * 32 bit integer in host endianness format. + */ +static inline uint32_t pv_be32_to_h(uint32_t be32) +{ + const uint8_t* be32ptr = (uint8_t*)&be32; + return (be32ptr[0] << 24) + + (be32ptr[1] << 16) + + (be32ptr[2] << 8) + + (be32ptr[3] << 0); +} + + +/** Converts a host endianness 32 bit integer to little endian, in a platform independent manner. + * + * @param host32 [in] 32 bit integer in host endianness format + * + * @returns + * 32 bit integer in little endian format. + */ +static inline uint32_t pv_h_to_le32(uint32_t host32) +{ + uint32_t le32; + uint8_t *le32_ptr = (uint8_t*)&le32; + + le32_ptr[0] = (host32 >> 0) & 0xff; + le32_ptr[1] = (host32 >> 8) & 0xff; + le32_ptr[2] = (host32 >> 16) & 0xff; + le32_ptr[3] = (host32 >> 24) & 0xff; + + /*@-usedef@*/ + // le32 is being initialized through a pointer. + return le32; + /*@+usedef@*/ +} + + +/** Converts a host endianness 32 bit integer to big endian, in a platform independent manner. + * + * @param host32 [in] 32 bit integer in host endianness format + * + * @returns + * 32 bit integer in big endian format. + */ +static inline uint32_t pv_h_to_be32(uint32_t host32) +{ + uint32_t be32; + uint8_t *be32_ptr = (uint8_t*)&be32; + + be32_ptr[0] = (host32 >> 24) & 0xff; + be32_ptr[1] = (host32 >> 16) & 0xff; + be32_ptr[2] = (host32 >> 8) & 0xff; + be32_ptr[3] = (host32 >> 0) & 0xff; + + /*@-usedef@*/ + // be32 is being initialized through a pointer. + return be32; + /*@+usedef@*/ +} + +#ifdef __cplusplus +} +#endif + +#endif // __PV_ENDIAN_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/pv_error_handling.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/pv_error_handling.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,291 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __PV_ERROR_HANDLING_H__ +#define __PV_ERROR_HANDLING_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +#include <assert.h> +#include <stdbool.h> + +#include "pv_log.h" + + +/** The following are macros to enable different error handling in development + * environment and production environment: + * On development environment, in oredr to speed up bug fixing we might want + * to assert or disable CK services. On production we shall not halt since + * we might get the whole device stuck. + * The errors are devided into 2 categories: + * 1. recoverable errors - like invalid parameter to API function + * 2. non-recoverable errors - like allocation failures + * default values for production is to not halt in any case, + * for development the default is to halt in non-recovrable error only + * since recoverable error may occure in negative tests + */ +#ifdef DEVELOPMENT_ENV +#define HALT_ON_RECOVERABLE_ERRORS() 0 +#define HALT_ON_UNRECOVERABLE_ERRORS() 0 +#else //if PRODUCTION_ENV +#define HALT_ON_RECOVERABLE_ERRORS() 0 +#define HALT_ON_UNRECOVERABLE_ERRORS() 0 +#endif + +/** Set this to 1 to immediately assert when an unrecoverable error is + * detected in PC environment. + * While it can be nice to get an immediate assert, often seeing the + * call trace is more useful - so the default is NOT to assert. + */ +#define ASSERT_IN_PC_ENV() 0 + +// Currently, this flag is defined in makefile errors.mk +// Set this to 1 in order to completely ignore unrecoverable errors - +// condition won't be checked, nothing would be printed. +// This should only be used in situations where memory is very tight, +// and would render debugging very complicated! +//#define IGNORE_UNRECOVERABLE_ERRORS 0 + + +void pv_error_occured(void); +bool pv_error_is_error_occured(void); + +#if ((HALT_ON_RECOVERABLE_ERRORS()) || (HALT_ON_UNRECOVERABLE_ERRORS())) +#define SA_PV_IS_PREV_ERROR_OCCURED() (pv_error_is_error_occured()) +#else +#define SA_PV_IS_PREV_ERROR_OCCURED() (false) +#endif + + + +#define _SA_PV_ERR_ASSERT_UPON_ERROR(cond, return_code, ...) {\ + if (cond) { \ + SA_PV_LOG_ERR_FUNC_EXIT(__VA_ARGS__);\ + assert(!(cond));\ + (void)return_code; /* Mention explicitly to fail compilation if return_code is not compilable. */ \ + abort();\ + }\ +} + +#define _SA_PV_ERR_ASSERT_UPON_ERROR_GOTO(cond, return_code_assignment, goto_label, ...) {\ + if (cond) {\ + SA_PV_LOG_ERR(__VA_ARGS__);\ + assert(!(cond));\ + abort();\ + return_code_assignment; /* Mention explicitly to fail compilation if return_code_assignment is not compilable. */ \ + goto goto_label;\ + }\ +} + +#define _SA_PV_ERR_OCCURED_AND_RETURN_UPON_ERROR(cond, return_code, ...) {\ + if (cond) {\ + SA_PV_LOG_ERR_FUNC_EXIT(__VA_ARGS__); \ + pv_error_occured();\ + return return_code;\ + }\ +} + +#define _SA_PV_RETURN_UPON_ERROR(level, cond, return_code, ...) {\ + if (cond) {\ + SA_PV_LOG_ ## level ## _FUNC_EXIT(__VA_ARGS__);\ + return return_code;\ + }\ +} +#define _SA_PV_ERR_OCCURED_AND_GOTO_UPON_ERROR(cond, return_code_assignment, goto_label, ...) {\ + if (cond) {\ + SA_PV_LOG_ERR(__VA_ARGS__);\ + pv_error_occured();\ + return_code_assignment;\ + goto goto_label;\ + }\ +} + +#define _SA_PV_GOTO_UPON_ERROR(level, cond, return_code_assignment, goto_label, ...) {\ + if (cond) {\ + SA_PV_LOG_ ## level(__VA_ARGS__); \ + return_code_assignment;\ + goto goto_label;\ + }\ +} + + +/** For non-recoverable errors, if condition fails: + * log error message + * if in development and running on PC - assert + * if in development but not PC - disable further processing with CK and return error code + * if in case in production (default behavior), just return error code + */ +#if HALT_ON_UNRECOVERABLE_ERRORS() +#if defined(SA_PV_PC_ENV) && ASSERT_IN_PC_ENV() +#ifndef IGNORE_UNRECOVERABLE_ERRORS +#define SA_PV_ERR_UNRECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_ERR_ASSERT_UPON_ERROR((cond), (return_code), ##__VA_ARGS__) +#else +#define SA_PV_ERR_UNRECOVERABLE_RETURN_IF(cond, return_code, ...) \ + if (false && (cond)) {} /* Dummy use of the condition to avoid compiler warnings */ +#endif +#else +#ifndef IGNORE_UNRECOVERABLE_ERRORS +#define SA_PV_ERR_UNRECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_ERR_OCCURED_AND_RETURN_UPON_ERROR((cond), (return_code), ##__VA_ARGS__) +#else +#define SA_PV_ERR_UNRECOVERABLE_RETURN_IF(cond, return_code, ...) \ + if (false && (cond)) {} /* Dummy use of the condition to avoid compiler warnings */ +#endif +#endif +#else // HALT_ON_UNRECOVERABLE_ERRORS +#ifndef IGNORE_UNRECOVERABLE_ERRORS +#define SA_PV_ERR_UNRECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_RETURN_UPON_ERROR(ERR, (cond), (return_code), ##__VA_ARGS__) +#else +#define SA_PV_ERR_UNRECOVERABLE_RETURN_IF(cond, return_code, ...) \ + if (false && (cond)) {} /* Dummy use of the condition to avoid compiler warnings */ +#endif +#endif // HALT_ON_UNRECOVERABLE_ERRORS + +/** For non-recoverable errors, if condition fails: + * log error message + * if in development and running on PC - assert + * if in development but not PC - disable further processing with CK and assign error code and goto label + * if in case in production (default behavior), just assign error code and goto label + */ +#if HALT_ON_UNRECOVERABLE_ERRORS() +#if defined(SA_PV_PC_ENV) && ASSERT_IN_PC_ENV() +#ifndef IGNORE_UNRECOVERABLE_ERRORS +#define SA_PV_ERR_UNRECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_ERR_ASSERT_UPON_ERROR_GOTO((cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +#else +#define SA_PV_ERR_UNRECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + if (false && (cond)) { /* Dummy use of the condition to avoid compiler warnings */ \ + return_code_assignment; /* Dummy use of the assignment to avoid compiler warnings */ \ + goto goto_label; /* Dummy use of the goto label to avoid compiler warnings. */ \ + } +#endif +#else +#ifndef IGNORE_UNRECOVERABLE_ERRORS +#define SA_PV_ERR_UNRECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_ERR_OCCURED_AND_GOTO_UPON_ERROR((cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +#else +#define SA_PV_ERR_UNRECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + if (false && (cond)) { /* Dummy use of the condition to avoid compiler warnings */ \ + return_code_assignment; /* Dummy use of the assignment to avoid compiler warnings */ \ + goto goto_label; /* Dummy use of the goto label to avoid compiler warnings. */ \ + } +#endif +#endif +#else // HALT_ON_UNRECOVERABLE_ERRORS +#ifndef IGNORE_UNRECOVERABLE_ERRORS +#define SA_PV_ERR_UNRECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_GOTO_UPON_ERROR(ERR, (cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +#else +#define SA_PV_ERR_UNRECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + if (false && (cond)) { /* Dummy use of the condition to avoid compiler warnings */ \ + return_code_assignment; /* Dummy use of the assignment to avoid compiler warnings */ \ + goto goto_label; /* Dummy use of the goto label to avoid compiler warnings. */ \ + } +#endif +#endif // HALT_ON_UNRECOVERABLE_ERRORS + + +/** Recoverable errors handling + * For recoverable errors, if condition fails: + * log error message + * if in development and running on PC - assert + * if in development but not PC - disable further processing with CK and return error code + * if in case in production (default behavior), just log and return error code + * this is all only regarding errors. INFO, TRACE, etc. will not cause halt, will just log and return error code + */ +#if HALT_ON_RECOVERABLE_ERRORS() +#if defined(SA_PV_PC_ENV) && ASSERT_IN_PC_ENV() +#define SA_PV_ERR_RECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_ERR_ASSERT_UPON_ERROR((cond), return_code, ##__VA_ARGS__) +#else +#define SA_PV_ERR_RECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_ERR_OCCURED_AND_RETURN_UPON_ERROR((cond), (return_code), ##__VA_ARGS__) +#endif +#else // HALT_ON_RECOVERABLE_ERRORS +#define SA_PV_ERR_RECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_RETURN_UPON_ERROR(ERR, (cond), (return_code), ##__VA_ARGS__) +#endif // HALT_ON_RECOVERABLE_ERRORS + +// if the condition is true: +// Theses macros return with return_code and perform the exit function log (if the log level is appropriate). + +// FIXME: This is partial solution, for critical level, also unrecoverable return should be treated and +// the macros for different flags should be implemented (HALT_ON_RECOVERABLE_ERRORS etc.) +#define SA_PV_CRITICAL_RECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_RETURN_UPON_ERROR(CRITICAL, (cond), (return_code), ##__VA_ARGS__) +// used in errors that are not critical (such as failure to read data from a socket - a retry is scheduled) +#define SA_PV_WARN_RECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_RETURN_UPON_ERROR(WARN, (cond), (return_code), ##__VA_ARGS__) +// used in external APIs +#define SA_PV_INFO_RECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_RETURN_UPON_ERROR(INFO, (cond), (return_code), ##__VA_ARGS__) +// used in internal APIs +#define SA_PV_TRACE_RECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_RETURN_UPON_ERROR(TRACE, (cond), (return_code), ##__VA_ARGS__) +#define SA_PV_DATA_RECOVERABLE_RETURN_IF(cond, return_code, ...) \ + _SA_PV_RETURN_UPON_ERROR(DATA, (cond), (return_code), ##__VA_ARGS__) + +/** For recoverable errors, if condition fails: + * log error message + * if in development and running on PC - assert + * if in development but not PC - disable further processing with CK and assign error code and goto label + * if in case in production (default behavior), just log, assign error code and goto label + * this is all only regarding errors. INFO, TRACE, etc. will not cause halt, will just log, assign error code and goto label + */ +#if HALT_ON_RECOVERABLE_ERRORS() +#if defined(SA_PV_PC_ENV) && ASSERT_IN_PC_ENV() +#define SA_PV_ERR_RECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_ERR_ASSERT_UPON_ERROR_GOTO((cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +#else +#define SA_PV_ERR_RECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_ERR_OCCURED_AND_GOTO_UPON_ERROR((cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +#endif +#else // HALT_ON_RECOVERABLE_ERRORS +#define SA_PV_ERR_RECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_GOTO_UPON_ERROR(ERR, (cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +#endif // HALT_ON_RECOVERABLE_ERRORS + +// if the condition is true: +// Theses macros jump to goto_label with return_code and perform log (if the log level is appropriate). + +// FIXME: This is partial solution, for critical level, also unrecoverable goto should be treated and +// the macros for differnet flags should be implemented (HALT_ON_RECOVERABLE_ERRORS etc.) +#define SA_PV_CRITICAL_RECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_GOTO_UPON_ERROR(CRITICAL, (cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +// used in errors that are not critical (such as failure to read data from a socket - a retry is scheduled) +#define SA_PV_WARN_RECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_GOTO_UPON_ERROR(WARN, (cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +// used in external APIs +#define SA_PV_INFO_RECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_GOTO_UPON_ERROR(INFO, (cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +// used in internal APIs +#define SA_PV_TRACE_RECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_GOTO_UPON_ERROR(TRACE, (cond), (return_code_assignment), goto_label, ##__VA_ARGS__) +// used in functions that are called many times and we don't necessary want to see all its logging even in TRACE mode +#define SA_PV_DATA_RECOVERABLE_GOTO_IF(cond, return_code_assignment, goto_label, ...) \ + _SA_PV_GOTO_UPON_ERROR(DATA, (cond), (return_code_assignment), goto_label, ##__VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif // __PV_ERROR_HANDLING_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/pv_macros.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/factory-configurator-client/utils/utils/pv_macros.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,179 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __PV_MACROS_H__ +#define __PV_MACROS_H__ + +#include <inttypes.h> +#include <stdbool.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ignore a pointer parameter */ +#define PV_IGNORE_PARAM_PTR NULL + +/* Ignore parameter value */ +#define PV_IGNORE_PARAM_VAL 0 + +/* This parameter is temporarily muted or unused for good resons */ +#define PV_UNUSED_PARAM(param) \ + (void)(param) + +/* Variable used only for DEBUG targets (like prints or macros +* which are effective only in debug mode) */ +#define PV_DEBUG_USE(var) \ + PV_UNUSED_PARAM(var) + + +/* Compile time assertion (we do not have static_assert support). */ +#define PV_ASSERT_CONCAT_(a, b) a##b +#define PV_ASSERT_CONCAT(a, b) PV_ASSERT_CONCAT_(a, b) +#define PV_CASSERT(cond, message) \ + enum { PV_ASSERT_CONCAT(assert_line_, __LINE__) = 1 / (int)(!!(cond)) } + +/* Returns the amount of elements in an array. */ +#define PV_ARRAY_LENGTH(array) (sizeof(array)/sizeof((array)[0])) + +/*Returns number in range between max and min */ +#define PV_NUMBER_LIMIT(number, max, min ) ((number % (max - min + 1)) + min) + + +/** + * Returns the size of a member in a struct. + */ +#define PV_SIZEOF_MEMBER(struct_type, member_name) sizeof(((struct_type *)0)->member_name) + +/** + * Checks alignment of val to uint32_t +*/ +#ifndef SA_PV_PLAT_PC +#define PV_IS_ALIGNED(val) \ + ((val & ((sizeof(uint32_t) - 1))) == 0) +#else +#define PV_IS_ALIGNED(val) \ + ((sizeof(uint32_t) & ((sizeof(uint32_t) - 1))) == 0) +#endif + + +/** Reads a uint32_t from a potentially unaligned uint8_t pointer. + * As we cannot know if unaligned access is allowed, using this approach is the + * only way to guarantee correct behavior. + * + * @param buf + * + * @returns + * 32 bit number + */ +static inline uint32_t pv_read_uint32(const uint8_t *buf) +{ + uint32_t number; + memcpy(&number, buf, sizeof(number)); + return number; +} + + + +/** Reads a uint64_t from a potentially unaligned uint8_t pointer. +* As we cannot know if unaligned access is allowed, using this approach is the +* only way to guarantee correct behavior. +* +* @param buf +* +* @returns +* 64 bit number +*/ +static inline uint64_t pv_read_uint64(const uint8_t *buf) +{ + uint64_t number; + memcpy(&number, buf, sizeof(number)); + return number; +} + + +/** Writes a uint32_t to a potentially unaligned uint8_t pointer. + * As we cannot know if unaligned access is allowed, using this approach is the + * only way to guarantee correct behavior. + * + * @param buf + * @param number + * + */ +static inline void pv_write_uint32(uint8_t *buf, uint32_t number) +{ + memcpy(buf, &number, sizeof(number)); +} + + +/** Calculates the length of a string. + * + * @param str [in] - A pointer to an input string. If NULL, 0 will be returned. + * + * @returns + * the number of characters in a string without counting the null termination character. + * There is no strnlen in libC. It's posix extension that also exists in mbed-os, but may not exist in other OS + */ +static inline uint32_t pv_str_n_len(const char* str, uint32_t max_size) +{ + uint32_t i = 0; + if (str == NULL) { + return 0; + } + + while (i < max_size && str[i] != '\0') { + i++; + } + + return i; +} + + +/** Compares strings (source with target) + * + * @param str1 [in] - First string to compare + * @param str2 [in] - Second string to compare + * @param a_max_size [in] - Max number of characters to compare + * + * @returns + * true - if strings are identical. + * false -if strings are not identical + */ +static inline bool pv_str_equals(const char* str1, const char* str2, uint32_t a_max_size) +{ + uint32_t str_size = pv_str_n_len(str1, a_max_size); + + if (str_size == a_max_size) { + return false; + } + if (str_size != pv_str_n_len(str2, a_max_size)) { + return false; + } + + if (strncmp(str1, str2, a_max_size) != 0) { + return false; + } + + return true; +} + +#ifdef __cplusplus +} +#endif + +#endif // __PV_MACROS_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,4 @@ +Docs/* +Examples/* +Test/* +out/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/CMakeLists.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +if(NOT YOTTA_TARGET) + INCLUDE(CMakeForceCompiler) + # CROSS COMPILER SETTING + cmake_minimum_required (VERSION 2.8) + SET(CMAKE_SYSTEM_NAME Generic) + + project(mbedPal) + + + + SET (PAL_VERSION ${PAL_VERSION_MAJOR}.${PAL_VERSION_MINOR}.${PAL_VERSION_PATCH}) + + # configure a header file generator .in to pass some of the CMake settings + # to the source code + configure_file ( + "${PROJECT_SOURCE_DIR}/pal_version.h.in" + "${PROJECT_BINARY_DIR}/pal_version.h" + ) + + if ((${OS_BRAND} MATCHES "Linux")) + add_definitions(-DPAL_LINUX) + endif() + + ADD_GLOBALDIR(${CMAKE_CURRENT_SOURCE_DIR}/Configs/pal_config) + + # add the binary tree to the search path for include files + # so that we will find TutorialConfig.h???????????????????????????????????????????????????????????????????????????? + ADDSUBDIRS() +else() + set(OS_BRAND "Linux") + set(TLS_LIBRARY "mbedTLS") + set(PAL_MODULE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Source) + + # find source files from the relavent directories + set(PAL_IMPL_SOURCE_DIR ${PAL_MODULE_SOURCE_DIR}/PAL-Impl) + set(PAL_PORT_SOURCE_DIR ${PAL_MODULE_SOURCE_DIR}/Port/Reference-Impl/OS_Specific/${OS_BRAND}) + set(PAL_TLS_SOURCE_DIR ${PAL_MODULE_SOURCE_DIR}/Port/Reference-Impl/Lib_Specific/${TLS_LIBRARY}) + set(PAL_EXAMPLE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Examples/PlatformBSP) + + file(GLOB_RECURSE PAL_SRCS "${PAL_IMPL_SOURCE_DIR}/*.c" + "${PAL_PORT_SOURCE_DIR}/Storage/FileSystem/*.c" + "${PAL_PORT_SOURCE_DIR}/Storage/Flash/*.c" + "${PAL_PORT_SOURCE_DIR}/Networking/*.c" + "${PAL_PORT_SOURCE_DIR}/RTOS/*.c" + "${PAL_PORT_SOURCE_DIR}/Update/*.c" + "${PAL_PORT_SOURCE_DIR}/Board_Specific/${PAL_TARGET_DEVICE}/*.c" + "${PAL_EXAMPLE_DIR}/pal_insecure_ROT.c" + "${PAL_TLS_SOURCE_DIR}/*.c") + + add_library(${YOTTA_MODULE_NAME} ${PAL_SRCS}) + + # need to specify the yotta dependency here, otherwise yotta won't consider them when linking against this library + target_link_libraries(${YOTTA_MODULE_NAME} mbedtls mbed-trace) + + # includes are taken care of via the module.json extraIncludes mechanism in order to be global + # link libraries are handled by the module.josn dependencies mechanism +endif()
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/mbedTLS/mbedTLSConfig_FreeRTOS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/mbedTLS/mbedTLSConfig_FreeRTOS.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2563 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + */ +#ifndef KSDK_MBEDTLS_CONFIG_H +#define KSDK_MBEDTLS_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/**************************** KSDK ********************************************/ + +#include "fsl_device_registers.h" + +/* Enable LTC use in library if there is LTC on chip. */ +#if defined(FSL_FEATURE_SOC_LTC_COUNT) && (FSL_FEATURE_SOC_LTC_COUNT > 0) + #include "fsl_ltc.h" + + #define LTC_INSTANCE LTC0 /* LTC base register.*/ + + #if defined(FSL_FEATURE_LTC_HAS_DES) && FSL_FEATURE_LTC_HAS_DES + #define MBEDTLS_FREESCALE_LTC_DES /* Enable use of LTC DES.*/ + #endif + #define MBEDTLS_FREESCALE_LTC_AES /* Enable use of LTC AES.*/ + #if defined(FSL_FEATURE_LTC_HAS_GCM) && FSL_FEATURE_LTC_HAS_GCM + #define MBEDTLS_FREESCALE_LTC_AES_GCM /* Enable use of LTC AES GCM.*/ + #endif + #if defined(FSL_FEATURE_LTC_HAS_PKHA) && FSL_FEATURE_LTC_HAS_PKHA + #define MBEDTLS_FREESCALE_LTC_PKHA /* Enable use of LTC PKHA.*/ + #endif +#endif + +/* Enable MMCAU use in library if there is MMCAU on chip. */ +#if defined(FSL_FEATURE_SOC_MMCAU_COUNT) && (FSL_FEATURE_SOC_MMCAU_COUNT > 0) + #include "fsl_mmcau.h" + + #define MBEDTLS_FREESCALE_MMCAU_MD5 /* Enable use of MMCAU MD5.*/ + #define MBEDTLS_FREESCALE_MMCAU_SHA1 /* Enable use of MMCAU SHA1.*/ + #define MBEDTLS_FREESCALE_MMCAU_SHA256 /* Enable use of MMCAU SHA256.*/ + #define MBEDTLS_FREESCALE_MMCAU_DES /* Enable use of MMCAU DES, when LTC is disabled.*/ + #define MBEDTLS_FREESCALE_MMCAU_AES /* Enable use of MMCAU AES, when LTC is disabled.*/ +#endif + +/* Define ALT MMCAU & LTC functions. Do not change it. */ +#if defined(MBEDTLS_FREESCALE_MMCAU_DES) || defined(MBEDTLS_FREESCALE_LTC_DES) + #define MBEDTLS_DES_SETKEY_ENC_ALT + #define MBEDTLS_DES_SETKEY_DEC_ALT + #define MBEDTLS_DES_CRYPT_ECB_ALT + #define MBEDTLS_DES3_CRYPT_ECB_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_DES) + #define MBEDTLS_DES_CRYPT_CBC_ALT + #define MBEDTLS_DES3_CRYPT_CBC_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_AES) || defined(MBEDTLS_FREESCALE_MMCAU_AES) + #define MBEDTLS_AES_SETKEY_ENC_ALT + #define MBEDTLS_AES_SETKEY_DEC_ALT + #define MBEDTLS_AES_ENCRYPT_ALT + #define MBEDTLS_AES_DECRYPT_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_AES) + #define MBEDTLS_AES_CRYPT_CBC_ALT + #define MBEDTLS_AES_CRYPT_CTR_ALT + #define MBEDTLS_CCM_CRYPT_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_AES_GCM) + #define MBEDTLS_GCM_CRYPT_ALT +#endif +#if defined(MBEDTLS_FREESCALE_LTC_PKHA) + #define MBEDTLS_MPI_ADD_ABS_ALT + #define MBEDTLS_MPI_SUB_ABS_ALT + #define MBEDTLS_MPI_MUL_MPI_ALT + #define MBEDTLS_MPI_MOD_MPI_ALT + #define MBEDTLS_MPI_EXP_MOD_ALT + #define MBEDTLS_MPI_GCD_ALT + #define MBEDTLS_MPI_INV_MOD_ALT + #define MBEDTLS_MPI_IS_PRIME_ALT + #define MBEDTLS_ECP_MUL_COMB_ALT + #define MBEDTLS_ECP_ADD_ALT +#endif +#if defined(MBEDTLS_FREESCALE_MMCAU_MD5) + #define MBEDTLS_MD5_PROCESS_ALT +#endif +#if defined(MBEDTLS_FREESCALE_MMCAU_SHA1) + #define MBEDTLS_SHA1_PROCESS_ALT +#endif +#if defined(MBEDTLS_FREESCALE_MMCAU_SHA256) + #define MBEDTLS_SHA256_PROCESS_ALT +#endif +/**************************** KSDK end ****************************************/ + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/mbedtls/bn_mul.h + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_HAVE_SSE2 + * + * CPU supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + */ +//#define MBEDTLS_HAVE_SSE2 + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Comment if your system does not support time functions + */ +//#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_HAVE_TIME_DATE + * + * System has time.h and time(), gmtime() and the clock is correct. + * The time needs to be correct (not necesarily very accurate, but at least + * the date should be correct). This is used to verify the validity period of + * X.509 certificates. + * + * Comment if your system does not have a correct clock. + */ +//#define MBEDTLS_HAVE_TIME_DATE +//#define MBEDTLS_PLATFORM_TIME_ALT +/** + * \def MBEDTLS_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default mbed TLS uses the system-provided calloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling MBEDTLS_PLATFORM_MEMORY without the + * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide + * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and + * free() function pointer at runtime. + * + * Enabling MBEDTLS_PLATFORM_MEMORY and specifying + * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the + * alternate function at compile time. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +//#define MBEDTLS_PLATFORM_MEMORY + +/** + * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. calloc() to + * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a + * MBEDTLS_PLATFORM_XXX_MACRO. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def MBEDTLS_PLATFORM_XXX_ALT + * + * Uncomment a macro to let mbed TLS support the function in the platform + * abstraction layer. + * + * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will + * provide a function "mbedtls_platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require MBEDTLS_PLATFORM_C to be defined! + * + * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; + * it will be enabled automatically by check_config.h + * + * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as + * MBEDTLS_PLATFORM_XXX_MACRO! + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define MBEDTLS_PLATFORM_EXIT_ALT +//#define MBEDTLS_PLATFORM_FPRINTF_ALT +//#define MBEDTLS_PLATFORM_PRINTF_ALT +//#define MBEDTLS_PLATFORM_SNPRINTF_ALT + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions so that they generate a warning if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * This only works with GCC and Clang. With other compilers, you may want to + * use MBEDTLS_DEPRECATED_REMOVED + * + * Uncomment to get warnings on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_WARNING + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions so that they generate an error if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * Uncomment to get errors on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_REMOVED + +/* \} name SECTION: System support */ + +/** + * \name SECTION: mbed TLS feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def MBEDTLS_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), + * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() + * + * Only works if you have MBEDTLS_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define MBEDTLS_TIMING_ALT + +/** + * \def MBEDTLS__MODULE_NAME__ALT + * + * Uncomment a macro to let mbed TLS use your alternate core implementation of + * a symmetric crypto or hash module (e.g. platform specific assembly + * optimized implementations). Keep in mind that the function prototypes + * should remain the same. + * + * This replaces the whole module. If you only want to replace one of the + * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer + * provide the "struct mbedtls_aes_context" definition and omit the base function + * declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * module. + */ +//#define MBEDTLS_AES_ALT +//#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_BLOWFISH_ALT +//#define MBEDTLS_CAMELLIA_ALT +//#define MBEDTLS_DES_ALT +//#define MBEDTLS_XTEA_ALT +//#define MBEDTLS_MD2_ALT +//#define MBEDTLS_MD4_ALT +//#define MBEDTLS_MD5_ALT +//#define MBEDTLS_RIPEMD160_ALT +//#define MBEDTLS_SHA1_ALT +//#define MBEDTLS_SHA256_ALT +//#define MBEDTLS_SHA512_ALT + +/** + * \def MBEDTLS__FUNCTION_NAME__ALT + * + * Uncomment a macro to let mbed TLS use you alternate core implementation of + * symmetric crypto or hash function. Keep in mind that function prototypes + * should remain the same. + * + * This replaces only one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will + * no longer provide the mbedtls_sha1_process() function, but it will still provide + * the other function (using your mbedtls_sha1_process() function) and the definition + * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible + * with this definition. + * + * Note: if you use the AES_xxx_ALT macros, then is is recommended to also set + * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES + * tables. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +//#define MBEDTLS_MD2_PROCESS_ALT +//#define MBEDTLS_MD4_PROCESS_ALT +//#define MBEDTLS_MD5_PROCESS_ALT +//#define MBEDTLS_RIPEMD160_PROCESS_ALT +//#define MBEDTLS_SHA1_PROCESS_ALT +//#define MBEDTLS_SHA256_PROCESS_ALT +//#define MBEDTLS_SHA512_PROCESS_ALT +//#define MBEDTLS_DES_SETKEY_ALT +//#define MBEDTLS_DES_CRYPT_ECB_ALT +//#define MBEDTLS_DES3_CRYPT_ECB_ALT +//#define MBEDTLS_AES_SETKEY_ENC_ALT +//#define MBEDTLS_AES_SETKEY_DEC_ALT +//#define MBEDTLS_AES_ENCRYPT_ALT +//#define MBEDTLS_AES_DECRYPT_ALT + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT + * + * Uncomment this macro to let mbed TLS use your own implementation of a + * hardware entropy collector. + * + * Your function must be called \c mbedtls_hardware_poll(), have the same + * prototype as declared in entropy_poll.h, and accept NULL as first argument. + * + * Uncomment to use your own hardware entropy collector. + */ +//#define MBEDTLS_ENTROPY_HARDWARE_ALT + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + */ +//#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_CAMELLIA_SMALL_MEMORY + * + * Use less ROM for the Camellia implementation (saves about 768 bytes). + * + * Uncomment this macro to use less memory for Camellia. + */ +//#define MBEDTLS_CAMELLIA_SMALL_MEMORY + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +//#define MBEDTLS_CIPHER_MODE_CFB + +/** + * \def MBEDTLS_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CTR + +/** + * \def MBEDTLS_CIPHER_NULL_CIPHER + * + * Enable NULL cipher. + * Warning: Only do so when you know what you are doing. This allows for + * encryption or channels without any security! + * + * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable + * the following ciphersuites: + * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define MBEDTLS_CIPHER_NULL_CIPHER + +/** + * \def MBEDTLS_CIPHER_PADDING_XXX + * + * Uncomment or comment macros to add support for specific padding modes + * in the cipher layer with cipher modes that support padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +//#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +//#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +//#define MBEDTLS_CIPHER_PADDING_ZEROS + +/** + * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * + * Enable weak ciphersuites in SSL / TLS. + * Warning: Only do so when you know what you are doing. This allows for + * channels with virtually no security at all! + * + * This enables the following ciphersuites: + * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA + * + * Uncomment this macro to enable weak ciphersuites + */ +//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_XXXX_ENABLED + * + * Enables specific curves within the Elliptic Curve module. + * By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +//#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +//#ifndef MBEDTLS_FREESCALE_LTC_PKHA /* PKHA suports only <=512 */ +//#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +//#endif +//#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +//#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +//#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +//#define MBEDTLS_ECP_DP_BP256R1_ENABLED +//#define MBEDTLS_ECP_DP_BP384R1_ENABLED +//#define MBEDTLS_ECP_DP_BP512R1_ENABLED +//#define MBEDTLS_ECP_DP_CURVE25519_ENABLED + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: MBEDTLS_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +#define MBEDTLS_ECDSA_DETERMINISTIC + +/** + * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + */ +//#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +//#define MBEDTLS_PK_PARSE_EC_EXTENDED + +/** + * \def MBEDTLS_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of mbedtls_strerror() in + * third party libraries easier when MBEDTLS_ERROR_C is disabled + * (no effect when MBEDTLS_ERROR_C is enabled). + * + * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're + * not using mbedtls_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * mbedtls_strerror() + */ +//#define MBEDTLS_ERROR_STRERROR_DUMMY + +/** + * \def MBEDTLS_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: MBEDTLS_BIGNUM_C + */ +//#define MBEDTLS_GENPRIME + +/** + * \def MBEDTLS_FS_IO + * + * Enable functions that use the filesystem. + */ +//#define MBEDTLS_FS_IO + +/** + * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * mbedtls_timing_hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. + */ +//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + +/** + * \def MBEDTLS_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. + */ +#define MBEDTLS_NO_PLATFORM_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: MBEDTLS_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both MBEDTLS_SHA256_C and + * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. + */ +//#define MBEDTLS_ENTROPY_FORCE_SHA256 + +/** + * \def MBEDTLS_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define MBEDTLS_MEMORY_DEBUG + +/** + * \def MBEDTLS_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define MBEDTLS_MEMORY_BACKTRACE + +/** + * \def MBEDTLS_PK_RSA_ALT_SUPPORT + * + * Support external private RSA keys (eg from a HSM) in the PK layer. + * + * Comment this macro to disable support for external private RSA keys. + */ +//#define MBEDTLS_PK_RSA_ALT_SUPPORT + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * + */ +//#define MBEDTLS_RSA_NO_CRT + +/** + * \def MBEDTLS_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +//#define MBEDTLS_SELF_TEST + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +//#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_AEAD_RANDOM_IV + * + * Generate a random IV rather than using the record sequence number as a + * nonce for ciphersuites using and AEAD algorithm (GCM or CCM). + * + * Using the sequence number is generally recommended. + * + * Uncomment this macro to always use random IVs with AEAD ciphersuites. + */ +//#define MBEDTLS_SSL_AEAD_RANDOM_IV + +/** + * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES + * + * Enable sending of alert messages in case of encountered errors as per RFC. + * If you choose not to send the alert messages, mbed TLS can still communicate + * with other servers, only debugging of failures is harder. + * + * The advantage of not sending alert messages, is that no information is given + * about reasons for failures thus preventing adversaries of gaining intel. + * + * Enable sending of all alert messages + */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/** + * \def MBEDTLS_SSL_DEBUG_ALL + * + * Enable the debug messages in SSL module for all issues. + * Debug messages have been disabled in some places to prevent timing + * attacks due to (unbalanced) debugging function calls. + * + * If you need all error reporting you should enable this during debugging, + * but remove this for production servers that should log as well. + * + * Uncomment this macro to report all debug messages on errors introducing + * a timing side-channel. + * + */ +//#define MBEDTLS_SSL_DEBUG_ALL + +/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC + * + * Enable support for Encrypt-then-MAC, RFC 7366. + * + * This allows peers that both support it to use a more robust protection for + * ciphersuites using CBC, providing deep resistance against timing attacks + * on the padding or underlying cipher. + * + * This only affects CBC ciphersuites, and is useless if none is defined. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Encrypt-then-MAC + */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC + +/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET + * + * Enable support for Extended Master Secret, aka Session Hash + * (draft-ietf-tls-session-hash-02). + * + * This was introduced as "the proper fix" to the Triple Handshake familiy of + * attacks, but it is recommended to always use it (even if you disable + * renegotiation), since it actually fixes a more fundamental issue in the + * original SSL/TLS design, and has implications beyond Triple Handshake. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Extended Master Secret. + */ +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +/** + * \def MBEDTLS_SSL_FALLBACK_SCSV + * + * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00). + * + * For servers, it is recommended to always enable this, unless you support + * only one version of TLS, or know for sure that none of your clients + * implements a fallback strategy. + * + * For clients, you only need this if you're using a fallback strategy, which + * is not recommended in the first place, unless you absolutely need it to + * interoperate with buggy (version-intolerant) servers. + * + * Comment this macro to disable support for FALLBACK_SCSV + */ +//#define MBEDTLS_SSL_FALLBACK_SCSV + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * Uncomment this macro to enable hooking functions. + */ +//#define MBEDTLS_SSL_HW_RECORD_ACCEL + +/** + * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING + * + * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0. + * + * This is a countermeasure to the BEAST attack, which also minimizes the risk + * of interoperability issues compared to sending 0-length records. + * + * Comment this macro to disable 1/n-1 record splitting. + */ +//#define MBEDTLS_SSL_CBC_RECORD_SPLITTING + +/** + * \def MBEDTLS_SSL_RENEGOTIATION + * + * Disable support for TLS renegotiation. + * + * The two main uses of renegotiation are (1) refresh keys on long-lived + * connections and (2) client authentication after the initial handshake. + * If you don't need renegotiation, it's probably better to disable it, since + * it has been associated with security issues in the past and is easy to + * misuse/misunderstand. + * + * Comment this to disable support for renegotiation. + */ +#define MBEDTLS_SSL_RENEGOTIATION + +/** + * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + * + * Enable support for receiving and parsing SSLv2 Client Hello messages for the + * SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to enable support for SSLv2 Client Hello messages. + */ +//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +//#define MBEDTLS_SSL_PROTO_SSL3 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +//#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +//#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_PROTO_DTLS + * + * Enable support for DTLS (all available versions). + * + * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0, + * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_1 + * or MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for DTLS + */ +#define MBEDTLS_SSL_PROTO_DTLS + +/** + * \def MBEDTLS_SSL_ALPN + * + * Enable support for RFC 7301 Application Layer Protocol Negotiation. + * + * Comment this macro to disable support for ALPN. + */ +#define MBEDTLS_SSL_ALPN + +/** + * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY + * + * Enable support for the anti-replay mechanism in DTLS. + * + * Requires: MBEDTLS_SSL_TLS_C + * MBEDTLS_SSL_PROTO_DTLS + * + * \warning Disabling this is often a security risk! + * See mbedtls_ssl_conf_dtls_anti_replay() for details. + * + * Comment this to disable anti-replay in DTLS. + */ +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY + +/** + * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Enable support for HelloVerifyRequest on DTLS servers. + * + * This feature is highly recommended to prevent DTLS servers being used as + * amplifiers in DoS attacks against other hosts. It should always be enabled + * unless you know for sure amplification cannot be a problem in the + * environment in which your server operates. + * + * \warning Disabling this can ba a security risk! (see above) + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Comment this to disable support for HelloVerifyRequest. + */ +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY + +/** + * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + * + * Enable server-side support for clients that reconnect from the same port. + * + * Some clients unexpectedly close the connection and try to reconnect using the + * same source port. This needs special support from the server to handle the + * new connection securely, as described in section 4.2.8 of RFC 6347. This + * flag enables that support. + * + * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Comment this to disable support for clients reusing the source port. + */ +#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + +/** + * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT + * + * Enable support for a limit of records with bad MAC. + * + * See mbedtls_ssl_conf_dtls_badmac_limit(). + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + */ +#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT + +/** + * \def MBEDTLS_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * Client-side, provides full support for session tickets (maintainance of a + * session store remains the responsibility of the application, though). + * Server-side, you also need to provide callbacks for writing and parsing + * tickets, including authenticated encryption and key management. Example + * callbacks are provided by MBEDTLS_SSL_TICKET_C. + * + * Comment this macro to disable support for SSL session tickets + */ +#define MBEDTLS_SSL_SESSION_TICKETS + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +//#define MBEDTLS_SSL_TRUNCATED_HMAC + +/** + * \def MBEDTLS_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +//#define MBEDTLS_THREADING_ALT + +/** + * \def MBEDTLS_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define MBEDTLS_THREADING_PTHREAD + +/** + * \def MBEDTLS_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via mbedtls_version_check_feature(). + * + * Requires: MBEDTLS_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +//#define MBEDTLS_VERSION_FEATURES + +/** + * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def MBEDTLS_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define MBEDTLS_X509_CHECK_KEY_USAGE + +/** + * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +//#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +/** + * \def MBEDTLS_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be a applicable to your use case. + * + * \note Currently compression can't be used with DTLS. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB + */ +//#define MBEDTLS_ZLIB_SUPPORT +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +//#define MBEDTLS_AESNI_C + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_ARC4_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +//#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_BLOWFISH_C + * + * Enable the Blowfish block cipher. + * + * Module: library/blowfish.c + */ +//#define MBEDTLS_BLOWFISH_C + +/** + * \def MBEDTLS_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +//#define MBEDTLS_CAMELLIA_C + +/** + * \def MBEDTLS_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +#define MBEDTLS_CCM_C + +/** + * \def MBEDTLS_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +//#define MBEDTLS_CERTS_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CMAC_C + * + * Enable the CMAC (Cipher-based Message Authentication Code) mode for block + * ciphers. + * + * Module: library/cmac.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_DES_C + * + */ +#define MBEDTLS_CMAC_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +//#define MBEDTLS_DEBUG_C + +/** + * \def MBEDTLS_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/pem.c + * library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + */ +//#define MBEDTLS_DES_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +//#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables mbedtls_strerror(). + */ +//#define MBEDTLS_ERROR_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +//#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: MBEDTLS_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define MBEDTLS_HAVEGE_C + +/** + * \def MBEDTLS_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +#define MBEDTLS_HMAC_DRBG_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/mbedtls_md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD2_C + * + * Enable the MD2 hash algorithm. + * + * Module: library/mbedtls_md2.c + * Caller: + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + */ +//#define MBEDTLS_MD2_C + +/** + * \def MBEDTLS_MD4_C + * + * Enable the MD4 hash algorithm. + * + * Module: library/mbedtls_md4.c + * Caller: + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + */ +//#define MBEDTLS_MD4_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/mbedtls_md5.c + * Caller: library/mbedtls_md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +//#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: MBEDTLS_PLATFORM_C + * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C + +/** + * \def MBEDTLS_NET_C + * + * Enable the TCP/IP networking routines. + * + * Module: library/net.c + * + * This module provides TCP/IP networking routines. + */ +//#define MBEDTLS_NET_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the VIA PadLock on x86. + */ +//#define MBEDTLS_PADLOCK_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +//#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +//#define MBEDTLS_PEM_WRITE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key write functions. + */ +#define MBEDTLS_PK_WRITE_C + +/** + * \def MBEDTLS_PKCS5_C + * + * Enable PKCS#5 functions. + * + * Module: library/pkcs5.c + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the PKCS#5 functions. + */ +//#define MBEDTLS_PKCS5_C + +/** + * \def MBEDTLS_PKCS11_C + * + * Enable wrapper for PKCS#11 smartcard support. + * + * Module: library/pkcs11.c + * Caller: library/pk.c + * + * Requires: MBEDTLS_PK_C + * + * This module enables SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) + */ +//#define MBEDTLS_PKCS11_C + +/** + * \def MBEDTLS_PKCS12_C + * + * Enable PKCS#12 PBE functions. + * Adds algorithms for parsing PKCS#8 encrypted private keys + * + * Module: library/pkcs12.c + * Caller: library/pkparse.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * Can use: MBEDTLS_ARC4_C + * + * This module enables PKCS#12 functions. + */ +//#define MBEDTLS_PKCS12_C + +/** + * \def MBEDTLS_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit(). + * + * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT + * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned + * above to be specified at runtime or compile time respectively. + * + * \note This abstraction layer must be enabled on Windows (including MSYS2) + * as other module rely on it for a fixed snprintf implementation. + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define MBEDTLS_PLATFORM_C + +/** + * \def MBEDTLS_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/mbedtls_ripemd160.c + * Caller: library/mbedtls_md.c + * + */ +//#define MBEDTLS_RIPEMD160_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +//#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/mbedtls_sha1.c + * Caller: library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +//#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/mbedtls_sha256.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/mbedtls_sha512.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +//#define MBEDTLS_SHA512_C + +/** + * \def MBEDTLS_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: MBEDTLS_SSL_CACHE_C + */ +#define MBEDTLS_SSL_CACHE_C + +/** + * \def MBEDTLS_SSL_COOKIE_C + * + * Enable basic implementation of DTLS cookies for hello verification. + * + * Module: library/ssl_cookie.c + * Caller: + */ +#define MBEDTLS_SSL_COOKIE_C + +/** + * \def MBEDTLS_SSL_TICKET_C + * + * Enable an implementation of TLS server-side callbacks for session tickets. + * + * Module: library/ssl_ticket.c + * Caller: + * + * Requires: MBEDTLS_CIPHER_C + */ +#define MBEDTLS_SSL_TICKET_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +//#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_THREADING_C + * + * Enable the threading abstraction layer. + * By default mbed TLS assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either MBEDTLS_THREADING_ALT or + * MBEDTLS_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within mbed TLS + */ +//#define MBEDTLS_THREADING_C + +/** + * \def MBEDTLS_TIMING_C + * + * Enable the portable timing interface. + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +//#define MBEDTLS_TIMING_C + +/** + * \def MBEDTLS_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define MBEDTLS_VERSION_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/mbedtls_x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/** + * \def MBEDTLS_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/mbedtls_x509_crl.c + * Caller: library/mbedtls_x509_crt.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define MBEDTLS_X509_CRL_PARSE_C + +/** + * \def MBEDTLS_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/mbedtls_x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +#define MBEDTLS_X509_CSR_PARSE_C + +/** + * \def MBEDTLS_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +#define MBEDTLS_X509_CREATE_C + +/** + * \def MBEDTLS_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +//#define MBEDTLS_X509_CRT_WRITE_C + +/** + * \def MBEDTLS_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +#define MBEDTLS_X509_CSR_WRITE_C + +/** + * \def MBEDTLS_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +//#define MBEDTLS_XTEA_C + +/* \} name SECTION: mbed TLS modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* HMAC_DRBG options */ +//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ + +/* Memory buffer allocator options */ +//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define MBEDTLS_PLATFORM_STD_MEM_HDR <stdlib.h> /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ + +/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ +/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ +//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ + +/* SSL Cache options */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ + +#define MBEDTLS_SSL_MAX_CONTENT_LEN 4096 + +//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ +//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, \ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, \ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, \ + MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, \ + MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, \ + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 +/* X509 options */ +//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ + +/* \} name SECTION: Module configuration options */ + +#if defined(TARGET_LIKE_MBED) +#include "mbedtls/target_config.h" +#endif + +/* + * Allow user to override any previous default. + * + * Use two macro names for that, as: + * - with yotta the prefix YOTTA_CFG_ is forced + * - without yotta is looks weird to have a YOTTA prefix. + */ +#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE +#elif defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include "mbedtls/check_config.h" + +#endif /* KSDK_MBEDTLS_CONFIG_H */ \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/mbedTLS/mbedTLSConfig_Linux.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/mbedTLS/mbedTLSConfig_Linux.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2660 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/mbedtls/bn_mul.h + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_HAVE_SSE2 + * + * CPU supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + */ +//#define MBEDTLS_HAVE_SSE2 + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT, + * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and + * MBEDTLS_PLATFORM_STD_TIME. + * + * Comment if your system does not support time functions + */ +#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_HAVE_TIME_DATE + * + * System has time.h and time(), gmtime() and the clock is correct. + * The time needs to be correct (not necesarily very accurate, but at least + * the date should be correct). This is used to verify the validity period of + * X.509 certificates. + * + * Comment if your system does not have a correct clock. + */ +//#define MBEDTLS_HAVE_TIME_DATE + +/** + * \def MBEDTLS_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default mbed TLS uses the system-provided calloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling MBEDTLS_PLATFORM_MEMORY without the + * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide + * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and + * free() function pointer at runtime. + * + * Enabling MBEDTLS_PLATFORM_MEMORY and specifying + * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the + * alternate function at compile time. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +//#define MBEDTLS_PLATFORM_MEMORY + +/** + * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. calloc() to + * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a + * MBEDTLS_PLATFORM_XXX_MACRO. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def MBEDTLS_PLATFORM_EXIT_ALT + * + * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the + * function in the platform abstraction layer. + * + * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will + * provide a function "mbedtls_platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require MBEDTLS_PLATFORM_C to be defined! + * + * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; + * it will be enabled automatically by check_config.h + * + * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as + * MBEDTLS_PLATFORM_XXX_MACRO! + * + * Requires: MBEDTLS_PLATFORM_TIME_ALT requires MBEDTLS_HAVE_TIME + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define MBEDTLS_PLATFORM_EXIT_ALT +//#define MBEDTLS_PLATFORM_TIME_ALT +//#define MBEDTLS_PLATFORM_FPRINTF_ALT +//#define MBEDTLS_PLATFORM_PRINTF_ALT +//#define MBEDTLS_PLATFORM_SNPRINTF_ALT +//#define MBEDTLS_PLATFORM_NV_SEED_ALT + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions so that they generate a warning if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * This only works with GCC and Clang. With other compilers, you may want to + * use MBEDTLS_DEPRECATED_REMOVED + * + * Uncomment to get warnings on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_WARNING + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions so that they generate an error if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * Uncomment to get errors on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_REMOVED + +/* \} name SECTION: System support */ + +/** + * \name SECTION: mbed TLS feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def MBEDTLS_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), + * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() + * + * Only works if you have MBEDTLS_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define MBEDTLS_TIMING_ALT + +/** + * \def MBEDTLS_AES_ALT + * + * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternate core implementation of a symmetric crypto, an arithmetic or hash + * module (e.g. platform specific assembly optimized implementations). Keep + * in mind that the function prototypes should remain the same. + * + * This replaces the whole module. If you only want to replace one of the + * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer + * provide the "struct mbedtls_aes_context" definition and omit the base + * function declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * module. + */ +//#define MBEDTLS_AES_ALT +//#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_BLOWFISH_ALT +//#define MBEDTLS_CAMELLIA_ALT +//#define MBEDTLS_DES_ALT +//#define MBEDTLS_XTEA_ALT +//#define MBEDTLS_MD2_ALT +//#define MBEDTLS_MD4_ALT +//#define MBEDTLS_MD5_ALT +//#define MBEDTLS_RIPEMD160_ALT +//#define MBEDTLS_SHA1_ALT +//#define MBEDTLS_SHA256_ALT +//#define MBEDTLS_SHA512_ALT +/* + * When replacing the elliptic curve module, pleace consider, that it is + * implemented with two .c files: + * - ecp.c + * - ecp_curves.c + * You can replace them very much like all the other MBEDTLS__MODULE_NAME__ALT + * macros as described above. The only difference is that you have to make sure + * that you provide functionality for both .c files. + */ +//#define MBEDTLS_ECP_ALT + +/** + * \def MBEDTLS_MD2_PROCESS_ALT + * + * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you + * alternate core implementation of symmetric crypto or hash function. Keep in + * mind that function prototypes should remain the same. + * + * This replaces only one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will + * no longer provide the mbedtls_sha1_process() function, but it will still provide + * the other function (using your mbedtls_sha1_process() function) and the definition + * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible + * with this definition. + * + * Note: if you use the AES_xxx_ALT macros, then is is recommended to also set + * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES + * tables. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +//#define MBEDTLS_MD2_PROCESS_ALT +//#define MBEDTLS_MD4_PROCESS_ALT +//#define MBEDTLS_MD5_PROCESS_ALT +//#define MBEDTLS_RIPEMD160_PROCESS_ALT +//#define MBEDTLS_SHA1_PROCESS_ALT +//#define MBEDTLS_SHA256_PROCESS_ALT +//#define MBEDTLS_SHA512_PROCESS_ALT +//#define MBEDTLS_DES_SETKEY_ALT +//#define MBEDTLS_DES_CRYPT_ECB_ALT +//#define MBEDTLS_DES3_CRYPT_ECB_ALT +//#define MBEDTLS_AES_SETKEY_ENC_ALT +//#define MBEDTLS_AES_SETKEY_DEC_ALT +//#define MBEDTLS_AES_ENCRYPT_ALT +//#define MBEDTLS_AES_DECRYPT_ALT + +/** + * \def MBEDTLS_ECP_INTERNAL_ALT + * + * Expose a part of the internal interface of the Elliptic Curve Point module. + * + * MBEDTLS_ECP__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternative core implementation of elliptic curve arithmetic. Keep in mind + * that function prototypes should remain the same. + * + * This partially replaces one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS_ECP_ALT flag. The original implementation + * is still present and it is used for group structures not supported by the + * alternative. + * + * Any of these options become available by defining MBEDTLS_ECP_INTERNAL_ALT + * and implementing the following functions: + * unsigned char mbedtls_internal_ecp_grp_capable( + * const mbedtls_ecp_group *grp ) + * int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) + * void mbedtls_internal_ecp_deinit( const mbedtls_ecp_group *grp ) + * The mbedtls_internal_ecp_grp_capable function should return 1 if the + * replacement functions implement arithmetic for the given group and 0 + * otherwise. + * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_deinit are + * called before and after each point operation and provide an opportunity to + * implement optimized set up and tear down instructions. + * + * Example: In case you uncomment MBEDTLS_ECP_INTERNAL_ALT and + * MBEDTLS_ECP_DOUBLE_JAC_ALT, mbed TLS will still provide the ecp_double_jac + * function, but will use your mbedtls_internal_ecp_double_jac if the group is + * supported (your mbedtls_internal_ecp_grp_capable function returns 1 when + * receives it as an argument). If the group is not supported then the original + * implementation is used. The other functions and the definition of + * mbedtls_ecp_group and mbedtls_ecp_point will not change, so your + * implementation of mbedtls_internal_ecp_double_jac and + * mbedtls_internal_ecp_grp_capable must be compatible with this definition. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +/* Required for all the functions in this section */ +//#define MBEDTLS_ECP_INTERNAL_ALT +/* Support for Weierstrass curves with Jacobi representation */ +//#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT +//#define MBEDTLS_ECP_ADD_MIXED_ALT +//#define MBEDTLS_ECP_DOUBLE_JAC_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +/* Support for curves with Montgomery arithmetic */ +//#define MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT +//#define MBEDTLS_ECP_RANDOMIZE_MXZ_ALT +//#define MBEDTLS_ECP_NORMALIZE_MXZ_ALT + +/** + * \def MBEDTLS_TEST_NULL_ENTROPY + * + * Enables testing and use of mbed TLS without any configured entropy sources. + * This permits use of the library on platforms before an entropy source has + * been integrated (see for example the MBEDTLS_ENTROPY_HARDWARE_ALT or the + * MBEDTLS_ENTROPY_NV_SEED switches). + * + * WARNING! This switch MUST be disabled in production builds, and is suitable + * only for development. + * Enabling the switch negates any security provided by the library. + * + * Requires MBEDTLS_ENTROPY_C, MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + */ +//#define MBEDTLS_TEST_NULL_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT + * + * Uncomment this macro to let mbed TLS use your own implementation of a + * hardware entropy collector. + * + * Your function must be called \c mbedtls_hardware_poll(), have the same + * prototype as declared in entropy_poll.h, and accept NULL as first argument. + * + * Uncomment to use your own hardware entropy collector. + */ +//#define MBEDTLS_ENTROPY_HARDWARE_ALT + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + */ +//#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_CAMELLIA_SMALL_MEMORY + * + * Use less ROM for the Camellia implementation (saves about 768 bytes). + * + * Uncomment this macro to use less memory for Camellia. + */ +//#define MBEDTLS_CAMELLIA_SMALL_MEMORY + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +//#define MBEDTLS_CIPHER_MODE_CFB + +/** + * \def MBEDTLS_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CTR + +/** + * \def MBEDTLS_CIPHER_NULL_CIPHER + * + * Enable NULL cipher. + * Warning: Only do so when you know what you are doing. This allows for + * encryption or channels without any security! + * + * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable + * the following ciphersuites: + * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define MBEDTLS_CIPHER_NULL_CIPHER + +/** + * \def MBEDTLS_CIPHER_PADDING_PKCS7 + * + * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for + * specific padding modes in the cipher layer with cipher modes that support + * padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +//#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +//#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +//#define MBEDTLS_CIPHER_PADDING_ZEROS + +/** + * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * + * Enable weak ciphersuites in SSL / TLS. + * Warning: Only do so when you know what you are doing. This allows for + * channels with virtually no security at all! + * + * This enables the following ciphersuites: + * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA + * + * Uncomment this macro to enable weak ciphersuites + */ +//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +//#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +//#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +//#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +//#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +//#define MBEDTLS_ECP_DP_BP256R1_ENABLED +//#define MBEDTLS_ECP_DP_BP384R1_ENABLED +//#define MBEDTLS_ECP_DP_BP512R1_ENABLED +//#define MBEDTLS_ECP_DP_CURVE25519_ENABLED + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: MBEDTLS_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +#define MBEDTLS_ECDSA_DETERMINISTIC + +/** + * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + */ +//#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + * + * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Requires: MBEDTLS_ECJPAKE_C + * MBEDTLS_SHA256_C + * MBEDTLS_ECP_DP_SECP256R1_ENABLED + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + +/** + * \def MBEDTLS_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +//#define MBEDTLS_PK_PARSE_EC_EXTENDED + +/** + * \def MBEDTLS_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of mbedtls_strerror() in + * third party libraries easier when MBEDTLS_ERROR_C is disabled + * (no effect when MBEDTLS_ERROR_C is enabled). + * + * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're + * not using mbedtls_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * mbedtls_strerror() + */ +//#define MBEDTLS_ERROR_STRERROR_DUMMY + +/** + * \def MBEDTLS_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: MBEDTLS_BIGNUM_C + */ +//#define MBEDTLS_GENPRIME + +/** + * \def MBEDTLS_FS_IO + * + * Enable functions that use the filesystem. + */ +//#define MBEDTLS_FS_IO + +/** + * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * mbedtls_timing_hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. + */ +//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + +/** + * \def MBEDTLS_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. + */ +//#define MBEDTLS_NO_PLATFORM_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: MBEDTLS_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both MBEDTLS_SHA256_C and + * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. + */ +//#define MBEDTLS_ENTROPY_FORCE_SHA256 + +/** + * \def MBEDTLS_ENTROPY_NV_SEED + * + * Enable the non-volatile (NV) seed file-based entropy source. + * (Also enables the NV seed read/write functions in the platform layer) + * + * This is crucial (if not required) on systems that do not have a + * cryptographic entropy source (in hardware or kernel) available. + * + * Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C + * + * \note The read/write functions that are used by the entropy source are + * determined in the platform layer, and can be modified at runtime and/or + * compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used. + * + * \note If you use the default implementation functions that read a seedfile + * with regular fopen(), please make sure you make a seedfile with the + * proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at + * least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from + * and written to or you will get an entropy source error! The default + * implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE + * bytes from the file. + * + * \note The entropy collector will write to the seed file before entropy is + * given to an external source, to update it. + */ +//#define MBEDTLS_ENTROPY_NV_SEED + +/** + * \def MBEDTLS_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define MBEDTLS_MEMORY_DEBUG + +/** + * \def MBEDTLS_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define MBEDTLS_MEMORY_BACKTRACE + +/** + * \def MBEDTLS_PK_RSA_ALT_SUPPORT + * + * Support external private RSA keys (eg from a HSM) in the PK layer. + * + * Comment this macro to disable support for external private RSA keys. + */ +//#define MBEDTLS_PK_RSA_ALT_SUPPORT + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * + */ +//#define MBEDTLS_RSA_NO_CRT + +/** + * \def MBEDTLS_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +//#define MBEDTLS_SELF_TEST + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +//#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES + * + * Enable sending of alert messages in case of encountered errors as per RFC. + * If you choose not to send the alert messages, mbed TLS can still communicate + * with other servers, only debugging of failures is harder. + * + * The advantage of not sending alert messages, is that no information is given + * about reasons for failures thus preventing adversaries of gaining intel. + * + * Enable sending of all alert messages + */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/** + * \def MBEDTLS_SSL_DEBUG_ALL + * + * Enable the debug messages in SSL module for all issues. + * Debug messages have been disabled in some places to prevent timing + * attacks due to (unbalanced) debugging function calls. + * + * If you need all error reporting you should enable this during debugging, + * but remove this for production servers that should log as well. + * + * Uncomment this macro to report all debug messages on errors introducing + * a timing side-channel. + * + */ +//#define MBEDTLS_SSL_DEBUG_ALL + +/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC + * + * Enable support for Encrypt-then-MAC, RFC 7366. + * + * This allows peers that both support it to use a more robust protection for + * ciphersuites using CBC, providing deep resistance against timing attacks + * on the padding or underlying cipher. + * + * This only affects CBC ciphersuites, and is useless if none is defined. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Encrypt-then-MAC + */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC + +/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET + * + * Enable support for Extended Master Secret, aka Session Hash + * (draft-ietf-tls-session-hash-02). + * + * This was introduced as "the proper fix" to the Triple Handshake familiy of + * attacks, but it is recommended to always use it (even if you disable + * renegotiation), since it actually fixes a more fundamental issue in the + * original SSL/TLS design, and has implications beyond Triple Handshake. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Extended Master Secret. + */ +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +/** + * \def MBEDTLS_SSL_FALLBACK_SCSV + * + * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00). + * + * For servers, it is recommended to always enable this, unless you support + * only one version of TLS, or know for sure that none of your clients + * implements a fallback strategy. + * + * For clients, you only need this if you're using a fallback strategy, which + * is not recommended in the first place, unless you absolutely need it to + * interoperate with buggy (version-intolerant) servers. + * + * Comment this macro to disable support for FALLBACK_SCSV + */ +//#define MBEDTLS_SSL_FALLBACK_SCSV + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * Uncomment this macro to enable hooking functions. + */ +//#define MBEDTLS_SSL_HW_RECORD_ACCEL + +/** + * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING + * + * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0. + * + * This is a countermeasure to the BEAST attack, which also minimizes the risk + * of interoperability issues compared to sending 0-length records. + * + * Comment this macro to disable 1/n-1 record splitting. + */ +//#define MBEDTLS_SSL_CBC_RECORD_SPLITTING + +/** + * \def MBEDTLS_SSL_RENEGOTIATION + * + * Disable support for TLS renegotiation. + * + * The two main uses of renegotiation are (1) refresh keys on long-lived + * connections and (2) client authentication after the initial handshake. + * If you don't need renegotiation, it's probably better to disable it, since + * it has been associated with security issues in the past and is easy to + * misuse/misunderstand. + * + * Comment this to disable support for renegotiation. + */ +#define MBEDTLS_SSL_RENEGOTIATION + +/** + * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + * + * Enable support for receiving and parsing SSLv2 Client Hello messages for the + * SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to enable support for SSLv2 Client Hello messages. + */ +//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +//#define MBEDTLS_SSL_PROTO_SSL3 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +//#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +//#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_PROTO_DTLS + * + * Enable support for DTLS (all available versions). + * + * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0, + * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_1 + * or MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for DTLS + */ +#define MBEDTLS_SSL_PROTO_DTLS + +/** + * \def MBEDTLS_SSL_ALPN + * + * Enable support for RFC 7301 Application Layer Protocol Negotiation. + * + * Comment this macro to disable support for ALPN. + */ +#define MBEDTLS_SSL_ALPN + +/** + * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY + * + * Enable support for the anti-replay mechanism in DTLS. + * + * Requires: MBEDTLS_SSL_TLS_C + * MBEDTLS_SSL_PROTO_DTLS + * + * \warning Disabling this is often a security risk! + * See mbedtls_ssl_conf_dtls_anti_replay() for details. + * + * Comment this to disable anti-replay in DTLS. + */ +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY + +/** + * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Enable support for HelloVerifyRequest on DTLS servers. + * + * This feature is highly recommended to prevent DTLS servers being used as + * amplifiers in DoS attacks against other hosts. It should always be enabled + * unless you know for sure amplification cannot be a problem in the + * environment in which your server operates. + * + * \warning Disabling this can ba a security risk! (see above) + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Comment this to disable support for HelloVerifyRequest. + */ +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY + +/** + * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + * + * Enable server-side support for clients that reconnect from the same port. + * + * Some clients unexpectedly close the connection and try to reconnect using the + * same source port. This needs special support from the server to handle the + * new connection securely, as described in section 4.2.8 of RFC 6347. This + * flag enables that support. + * + * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Comment this to disable support for clients reusing the source port. + */ +#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + +/** + * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT + * + * Enable support for a limit of records with bad MAC. + * + * See mbedtls_ssl_conf_dtls_badmac_limit(). + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + */ +#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT + +/** + * \def MBEDTLS_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * Client-side, provides full support for session tickets (maintainance of a + * session store remains the responsibility of the application, though). + * Server-side, you also need to provide callbacks for writing and parsing + * tickets, including authenticated encryption and key management. Example + * callbacks are provided by MBEDTLS_SSL_TICKET_C. + * + * Comment this macro to disable support for SSL session tickets + */ +#define MBEDTLS_SSL_SESSION_TICKETS + +/** + * \def MBEDTLS_SSL_EXPORT_KEYS + * + * Enable support for exporting key block and master secret. + * This is required for certain users of TLS, e.g. EAP-TLS. + * + * Comment this macro to disable support for key export + */ +#define MBEDTLS_SSL_EXPORT_KEYS + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +//#define MBEDTLS_SSL_TRUNCATED_HMAC + +/** + * \def MBEDTLS_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +//#define MBEDTLS_THREADING_ALT + +/** + * \def MBEDTLS_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define MBEDTLS_THREADING_PTHREAD + +/** + * \def MBEDTLS_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via mbedtls_version_check_feature(). + * + * Requires: MBEDTLS_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +//#define MBEDTLS_VERSION_FEATURES + +/** + * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * \warning Depending on your PKI use, enabling this can be a security risk! + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def MBEDTLS_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define MBEDTLS_X509_CHECK_KEY_USAGE + +/** + * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +//#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +/** + * \def MBEDTLS_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be a applicable to your use case. + * + * \note Currently compression can't be used with DTLS. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB + */ +//#define MBEDTLS_ZLIB_SUPPORT +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +//#define MBEDTLS_AESNI_C + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +//#define MBEDTLS_ARC4_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +//#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_BLOWFISH_C + * + * Enable the Blowfish block cipher. + * + * Module: library/blowfish.c + */ +//#define MBEDTLS_BLOWFISH_C + +/** + * \def MBEDTLS_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +//#define MBEDTLS_CAMELLIA_C + +/** + * \def MBEDTLS_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +#define MBEDTLS_CCM_C + +/** + * \def MBEDTLS_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +//#define MBEDTLS_CERTS_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CMAC_C + * + * Enable the CMAC (Cipher-based Message Authentication Code) mode for block + * ciphers. + * + * Module: library/cmac.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_DES_C + * + */ +#define MBEDTLS_CMAC_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +//#define MBEDTLS_DEBUG_C + +/** + * \def MBEDTLS_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/pem.c + * library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + */ +//#define MBEDTLS_DES_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +//#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECJPAKE_C + * + * Enable the elliptic curve J-PAKE library. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Module: library/ecjpake.c + * Caller: + * + * This module is used by the following key exchanges: + * ECJPAKE + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C + */ +//#define MBEDTLS_ECJPAKE_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables mbedtls_strerror(). + */ +//#define MBEDTLS_ERROR_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +//#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: MBEDTLS_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define MBEDTLS_HAVEGE_C + +/** + * \def MBEDTLS_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +#define MBEDTLS_HMAC_DRBG_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD2_C + * + * Enable the MD2 hash algorithm. + * + * Module: library/md2.c + * Caller: + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + */ +//#define MBEDTLS_MD2_C + +/** + * \def MBEDTLS_MD4_C + * + * Enable the MD4 hash algorithm. + * + * Module: library/md4.c + * Caller: + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + */ +//#define MBEDTLS_MD4_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/md5.c + * Caller: library/md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +//#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: MBEDTLS_PLATFORM_C + * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C + +/** + * \def MBEDTLS_NET_C + * + * Enable the TCP and UDP over IPv6/IPv4 networking routines. + * + * \note This module only works on POSIX/Unix (including Linux, BSD and OS X) + * and Windows. For other platforms, you'll want to disable it, and write your + * own networking callbacks to be passed to \c mbedtls_ssl_set_bio(). + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/net_sockets.c + * + * This module provides networking routines. + */ +//#define MBEDTLS_NET_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the VIA PadLock on x86. + */ +//#define MBEDTLS_PADLOCK_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +//#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +//#define MBEDTLS_PEM_WRITE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key write functions. + */ +#define MBEDTLS_PK_WRITE_C + +/** + * \def MBEDTLS_PKCS5_C + * + * Enable PKCS#5 functions. + * + * Module: library/pkcs5.c + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the PKCS#5 functions. + */ +//#define MBEDTLS_PKCS5_C + +/** + * \def MBEDTLS_PKCS11_C + * + * Enable wrapper for PKCS#11 smartcard support. + * + * Module: library/pkcs11.c + * Caller: library/pk.c + * + * Requires: MBEDTLS_PK_C + * + * This module enables SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) + */ +//#define MBEDTLS_PKCS11_C + +/** + * \def MBEDTLS_PKCS12_C + * + * Enable PKCS#12 PBE functions. + * Adds algorithms for parsing PKCS#8 encrypted private keys + * + * Module: library/pkcs12.c + * Caller: library/pkparse.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * Can use: MBEDTLS_ARC4_C + * + * This module enables PKCS#12 functions. + */ +//#define MBEDTLS_PKCS12_C + +/** + * \def MBEDTLS_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit(). + * + * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT + * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned + * above to be specified at runtime or compile time respectively. + * + * \note This abstraction layer must be enabled on Windows (including MSYS2) + * as other module rely on it for a fixed snprintf implementation. + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define MBEDTLS_PLATFORM_C + +/** + * \def MBEDTLS_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/ripemd160.c + * Caller: library/md.c + * + */ +//#define MBEDTLS_RIPEMD160_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +//#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +//#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/sha256.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/sha512.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +//#define MBEDTLS_SHA512_C + +/** + * \def MBEDTLS_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: MBEDTLS_SSL_CACHE_C + */ +#define MBEDTLS_SSL_CACHE_C + +/** + * \def MBEDTLS_SSL_COOKIE_C + * + * Enable basic implementation of DTLS cookies for hello verification. + * + * Module: library/ssl_cookie.c + * Caller: + */ +#define MBEDTLS_SSL_COOKIE_C + +/** + * \def MBEDTLS_SSL_TICKET_C + * + * Enable an implementation of TLS server-side callbacks for session tickets. + * + * Module: library/ssl_ticket.c + * Caller: + * + * Requires: MBEDTLS_CIPHER_C + */ +#define MBEDTLS_SSL_TICKET_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +//#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_THREADING_C + * + * Enable the threading abstraction layer. + * By default mbed TLS assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. See also our Knowledge Base article about threading: + * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either MBEDTLS_THREADING_ALT or + * MBEDTLS_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within mbed TLS + */ +//#define MBEDTLS_THREADING_C + +/** + * \def MBEDTLS_TIMING_C + * + * Enable the semi-portable timing interface. + * + * \note The provided implementation only works on POSIX/Unix (including Linux, + * BSD and OS X) and Windows. On other platforms, you can either disable that + * module and provide your own implementations of the callbacks needed by + * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide + * your own implementation of the whole module by setting + * \c MBEDTLS_TIMING_ALT in the current file. + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +//#define MBEDTLS_TIMING_C + +/** + * \def MBEDTLS_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define MBEDTLS_VERSION_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/** + * \def MBEDTLS_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/x509_crl.c + * Caller: library/x509_crt.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define MBEDTLS_X509_CRL_PARSE_C + +/** + * \def MBEDTLS_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +#define MBEDTLS_X509_CSR_PARSE_C + +/** + * \def MBEDTLS_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +#define MBEDTLS_X509_CREATE_C + +/** + * \def MBEDTLS_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +//#define MBEDTLS_X509_CRT_WRITE_C + +/** + * \def MBEDTLS_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +#define MBEDTLS_X509_CSR_WRITE_C + +/** + * \def MBEDTLS_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +//#define MBEDTLS_XTEA_C + +/* \} name SECTION: mbed TLS modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* HMAC_DRBG options */ +//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +//#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */ + +/* Memory buffer allocator options */ +//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define MBEDTLS_PLATFORM_STD_MEM_HDR <stdlib.h> /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" /**< Seed file to read/write with default implementation */ + +/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ +/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ +//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ + +/* SSL Cache options */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ +#define MBEDTLS_SSL_MAX_CONTENT_LEN 4096 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ +//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, \ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, \ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, \ + MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, \ + MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, \ + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 +/* X509 options */ +//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ +//#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */ + +/* \} name SECTION: Customisation configuration options */ + +/* Target and application specific configurations */ +//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "mbedtls/target_config.h" + +#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE +#endif + + +#include "check_config.h" + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) +#warning "MBEDTLS_TEST_NULL_ENTROPY has been enabled. This " \ + "configuration is not secure and is not suitable for production use" +#endif + +#endif /* MBEDTLS_CONFIG_H */ \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/mbedTLS/mbedTLSConfig_mbedOS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/mbedTLS/mbedTLSConfig_mbedOS.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,247 @@ +//---------------------------------------------------------------------------- +// The confidential and proprietary information contained in this file may +// only be used by a person authorised under and to the extent permitted +// by a subsisting licensing agreement from ARM Limited or its affiliates. +// +// (C) COPYRIGHT 2016 ARM Limited or its affiliates. +// ALL RIGHTS RESERVED +// +// This entire notice must be reproduced on all copies of this file +// and copies of this file may only be made by a person if such person is +// permitted to do so under the terms of a subsisting license agreement +// from ARM Limited or its affiliates. +//---------------------------------------------------------------------------- + +#ifndef PAL_MBEDTLS_USER_CONFIG_H +#define PAL_MBEDTLS_USER_CONFIG_H + +/*! All of the following definitions are mandatory requirements for correct +* fucntionality of PAL TLS and Crypto components. +* Please do not disable them. +*/ + +/* System support */ +#ifndef MBEDTLS_HAVE_ASM + #define MBEDTLS_HAVE_ASM +#endif //MBEDTLS_HAVE_ASM + +/* mbed TLS feature support */ +#ifndef MBEDTLS_ECP_DP_SECP256R1_ENABLED + #define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#endif //MBEDTLS_ECP_DP_SECP256R1_ENABLED + + +#ifndef MBEDTLS_ECP_NIST_OPTIM + #define MBEDTLS_ECP_NIST_OPTIM +#endif //MBEDTLS_ECP_NIST_OPTIM + +#ifndef MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + #define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#endif //MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +#ifndef MBEDTLS_SSL_PROTO_TLS1_2 + #define MBEDTLS_SSL_PROTO_TLS1_2 +#endif //MBEDTLS_SSL_PROTO_TLS1_2 + +#ifndef MBEDTLS_SSL_PROTO_DTLS + #define MBEDTLS_SSL_PROTO_DTLS +#endif //MBEDTLS_SSL_PROTO_DTLS + +#ifndef MBEDTLS_SSL_DTLS_ANTI_REPLAY + #define MBEDTLS_SSL_DTLS_ANTI_REPLAY +#endif //MBEDTLS_SSL_DTLS_ANTI_REPLAY + +#ifndef MBEDTLS_SSL_DTLS_HELLO_VERIFY + #define MBEDTLS_SSL_DTLS_HELLO_VERIFY +#endif //MBEDTLS_SSL_DTLS_HELLO_VERIFY + +#ifndef MBEDTLS_SSL_EXPORT_KEYS + #define MBEDTLS_SSL_EXPORT_KEYS +#endif //MBEDTLS_SSL_EXPORT_KEYS + +/* mbed TLS modules */ +#ifndef MBEDTLS_AES_C + #define MBEDTLS_AES_C +#endif //MBEDTLS_AES_C + +#ifndef MBEDTLS_ASN1_PARSE_C + #define MBEDTLS_ASN1_PARSE_C +#endif //MBEDTLS_ASN1_PARSE_C + +#ifndef MBEDTLS_ASN1_WRITE_C + #define MBEDTLS_ASN1_WRITE_C +#endif //MBEDTLS_ASN1_WRITE_C + +#ifndef MBEDTLS_BIGNUM_C + #define MBEDTLS_BIGNUM_C +#endif //MBEDTLS_BIGNUM_C + +#ifndef MBEDTLS_CIPHER_C + #define MBEDTLS_CIPHER_C +#endif //MBEDTLS_CIPHER_C + +#ifndef MBEDTLS_CTR_DRBG_C + #define MBEDTLS_CTR_DRBG_C +#endif //MBEDTLS_CTR_DRBG_C + +#ifndef MBEDTLS_ECP_C + #define MBEDTLS_ECP_C +#endif //MBEDTLS_ECP_C + +#ifndef MBEDTLS_ENTROPY_C + #define MBEDTLS_ENTROPY_C +#endif //MBEDTLS_ENTROPY_C + +#ifndef MBEDTLS_MD_C + #define MBEDTLS_MD_C +#endif //MBEDTLS_MD_C + +#ifndef MBEDTLS_OID_C + #define MBEDTLS_OID_C +#endif //MBEDTLS_OID_C + +#ifndef MBEDTLS_PK_C + #define MBEDTLS_PK_C +#endif //MBEDTLS_PK_C + +#ifndef MBEDTLS_PK_PARSE_C + #define MBEDTLS_PK_PARSE_C +#endif //MBEDTLS_PK_PARSE_C + +#ifndef MBEDTLS_SHA256_C + #define MBEDTLS_SHA256_C +#endif //MBEDTLS_SHA256_C + +#ifndef MBEDTLS_SSL_COOKIE_C + #define MBEDTLS_SSL_COOKIE_C +#endif //MBEDTLS_SSL_COOKIE_C + +#ifndef MBEDTLS_SSL_CLI_C + #define MBEDTLS_SSL_CLI_C +#endif //MBEDTLS_SSL_CLI_C + +#ifndef MBEDTLS_SSL_TLS_C + #define MBEDTLS_SSL_TLS_C +#endif //MBEDTLS_SSL_TLS_C + +// XXX mbedclient needs these: mbedtls_x509_crt_free, mbedtls_x509_crt_init, mbedtls_x509_crt_parse +#ifndef MBEDTLS_X509_USE_C + #define MBEDTLS_X509_USE_C +#endif //MBEDTLS_X509_USE_C + +#ifndef MBEDTLS_X509_CRT_PARSE_C + #define MBEDTLS_X509_CRT_PARSE_C +#endif //MBEDTLS_X509_CRT_PARSE_C +// a bit wrong way to get mbedtls_ssl_conf_psk: + +#ifndef MBEDTLS_CMAC_C + #define MBEDTLS_CMAC_C +#endif //MBEDTLS_CMAC_C + +#ifndef MBEDTLS_ECDH_C + #define MBEDTLS_ECDH_C +#endif //MBEDTLS_ECDH_C + +#ifndef MBEDTLS_ECDSA_C + #define MBEDTLS_ECDSA_C +#endif //MBEDTLS_ECDSA_C + +#ifndef MBEDTLS_X509_CRT_PARSE_C + #define MBEDTLS_X509_CRT_PARSE_C +#endif //MBEDTLS_X509_CRT_PARSE_C + +#ifndef MBEDTLS_X509_CSR_PARSE_C + #define MBEDTLS_X509_CSR_PARSE_C +#endif //MBEDTLS_X509_CSR_PARSE_C + +#ifndef MBEDTLS_X509_CREATE_C + #define MBEDTLS_X509_CREATE_C +#endif //MBEDTLS_X509_CREATE_C + +#ifndef MBEDTLS_X509_CSR_WRITE_C + #define MBEDTLS_X509_CSR_WRITE_C +#endif //MBEDTLS_X509_CSR_WRITE_C + +#ifndef MBEDTLS_CTR_DRBG_MAX_REQUEST + #define MBEDTLS_CTR_DRBG_MAX_REQUEST 2048 +#endif //MBEDTLS_CTR_DRBG_MAX_REQUEST + +// Needed by update +#ifndef MBEDTLS_CIPHER_MODE_CTR + #define MBEDTLS_CIPHER_MODE_CTR +#endif //MBEDTLS_CIPHER_MODE_CTR + +// Save ROM and a few bytes of RAM by specifying our own ciphersuite list +#ifndef MBEDTLS_SSL_CIPHERSUITES + #define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, \ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, \ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, \ + MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, \ + MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, \ + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 +#endif //MBEDTLS_SSL_CIPHERSUITES + +/*! All of the following definitions are optimizations (reduce mbedTLS memory usage and size), +* changing them is on the user responsibility since they can enlarge +* the binary footprint and the memory usage +*/ + +// define to save 8KB RAM at the expense of ROM +#ifndef MBEDTLS_AES_ROM_TABLES + #define MBEDTLS_AES_ROM_TABLES +#endif //MBEDTLS_AES_ROM_TABLES + +// Reduce IO buffer to save RAM, default is 16KB +#ifndef MBEDTLS_SSL_MAX_CONTENT_LEN + #define MBEDTLS_SSL_MAX_CONTENT_LEN 4096 +#endif //MBEDTLS_SSL_MAX_CONTENT_LEN + +// Needed by provisioning +#undef MBEDTLS_PEM_WRITE_C + +#undef MBEDTLS_ECP_DP_CURVE25519_ENABLED + +// Remove RSA, save 20KB at total +#undef MBEDTLS_RSA_C + +#undef MBEDTLS_PK_RSA_ALT_SUPPORT + +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +#undef MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +#undef MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +#undef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +// Remove error messages, save 10KB of ROM +#undef MBEDTLS_ERROR_C + +// Remove selftesting and save 11KB of ROM +#undef MBEDTLS_SELF_TEST + +#undef MBEDTLS_CERTS_C + +// Reduces ROM size by 30 kB +#undef MBEDTLS_ERROR_STRERROR_DUMMY + +#undef MBEDTLS_VERSION_FEATURES + +#undef MBEDTLS_DEBUG_C + +// needed for parsing the certificates +#undef MBEDTLS_PEM_PARSE_C + +#undef MBEDTLS_GCM_C + +// dep of the previous +#undef MBEDTLS_BASE64_C + +#undef MBEDTLS_SHA512_C + +#undef MBEDTLS_SSL_SRV_C + + +#include "mbedtls/check_config.h" + +#endif /* PAL_MBEDTLS_USER_CONFIG_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/pal_config/palInclude_FreeRTOS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/pal_config/palInclude_FreeRTOS.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,73 @@ +/* + * pal_mbedOS_configuration.h + * + * Created on: Sep 4, 2017 + * Author: pal + */ + +#ifndef PAL_FREERTOS_CONFIGURATION_H_ +/*! \brief This file sets configuration for PAL porting on FreeRTOS. + \note All configurations that are configured in this file overwrite their defaults values + \note Default Values can be found at Sources/PAL-impl/Services-API/pal_configuration.h + \note + */ + + +//!< Number partitions on SD card used by PAL File System; +#ifndef PAL_NUMBER_OF_PARTITIONS + #define PAL_NUMBER_OF_PARTITIONS 1 +#endif + +//!< Mount point for primary file system partition +#ifndef PAL_FS_MOUNT_POINT_PRIMARY + #if (PAL_NUMBER_OF_PARTITIONS == 0) + #define PAL_FS_MOUNT_POINT_PRIMARY "2:" + #elif (PAL_NUMBER_OF_PARTITIONS == 1) + #define PAL_FS_MOUNT_POINT_PRIMARY "0:" + #else + #define PAL_FS_MOUNT_POINT_PRIMARY "0:" + #endif +#endif + +//!< Mount point for secondary file system partition +#ifndef PAL_FS_MOUNT_POINT_SECONDARY + #if (PAL_NUMBER_OF_PARTITIONS == 0) + #define PAL_FS_MOUNT_POINT_SECONDARY "2:" + #elif (PAL_NUMBER_OF_PARTITIONS == 1) + #define PAL_FS_MOUNT_POINT_SECONDARY "0:" + #else + #define PAL_FS_MOUNT_POINT_SECONDARY "1:" + #endif +#endif + + //!< Max number of allowed timer +#ifndef PAL_MAX_NUM_OF_TIMERS + #define PAL_MAX_NUM_OF_TIMERS 5 +#endif + +//!< Max given token for a semaphore +#ifndef PAL_SEMAPHORE_MAX_COUNT + #define PAL_SEMAPHORE_MAX_COUNT 255 +#endif + + /*\brief Starting Address for section 1 Minimum requirement size is 1KB and section must be consecutive sectors*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_1_ADDRESS + #define PAL_INTERNAL_FLASH_SECTION_1_ADDRESS 0xFE000 +#endif + +/*\brief Starting Address for section 2 Minimum requirement size is 1KB and section must be consecutive sectors*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_2_ADDRESS + #define PAL_INTERNAL_FLASH_SECTION_2_ADDRESS 0xFF000 +#endif + +/*\brief Size for section 1*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_1_SIZE + #define PAL_INTERNAL_FLASH_SECTION_1_SIZE 0x1000 +#endif + +/*\brief Size for section 2*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_2_SIZE + #define PAL_INTERNAL_FLASH_SECTION_2_SIZE 0x1000 +#endif + +#endif /* PAL_FREERTOS_CONFIGURATION_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/pal_config/palInclude_Linux.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/pal_config/palInclude_Linux.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,100 @@ +/* + * pal_mbedOS_configuration.h + * + * Created on: Sep 4, 2017 + * Author: pal + */ +#ifndef PAL_MBEDOS_CONFIGURATION_H_ +/*! \brief This file sets configuration for PAL porting on Linux. + \note All configurations that are configured in this file overwrite their defaults values + \note Default Values can be found at Sources/PAL-impl/Services-API/pal_configuration.h + \note + */ + +//!< Number partitions on SD card used by PAL File System +#ifndef PAL_NUMBER_OF_PARTITIONS + #define PAL_NUMBER_OF_PARTITIONS 1 +#endif + +//!< User should change this for the his working folder +#ifndef PAL_FS_MOUNT_POINT_PRIMARY + #if (PAL_NUMBER_OF_PARTITIONS == 2) + #define PAL_FS_MOUNT_POINT_PRIMARY "./pal_pri" + #else + #define PAL_FS_MOUNT_POINT_PRIMARY "./pal" + #endif +#endif + + //!< User should change this for the his working folder +#ifndef PAL_FS_MOUNT_POINT_SECONDARY + #if (PAL_NUMBER_OF_PARTITIONS == 2) + #define PAL_FS_MOUNT_POINT_SECONDARY "./pal_sec" + #else + #define PAL_FS_MOUNT_POINT_SECONDARY "./pal" + #endif +#endif + +#ifndef PAL_NET_MAX_IF_NAME_LENGTH + #define PAL_NET_MAX_IF_NAME_LENGTH 16 //15 + '\0' +#endif + +#ifndef PAL_NET_TEST_MAX_ASYNC_SOCKETS + #define PAL_NET_TEST_MAX_ASYNC_SOCKETS 5 +#endif + +#ifndef PAL_NET_TEST_ASYNC_SOCKET_MANAGER_THREAD_STACK_SIZE + #define PAL_NET_TEST_ASYNC_SOCKET_MANAGER_THREAD_STACK_SIZE (1024*4) +#endif + +#ifndef PAL_RTOS_HIGH_RES_TIMER_THREAD_STACK_SIZE + #define PAL_RTOS_HIGH_RES_TIMER_THREAD_STACK_SIZE (4096*4) +#endif + +#ifndef PAL_FORMAT_CMD_MAX_LENGTH + #define PAL_FORMAT_CMD_MAX_LENGTH 256 +#endif + +#ifndef PAL_DEVICE_NAME_MAX_LENGTH + #define PAL_DEVICE_NAME_MAX_LENGTH 128 +#endif + +#ifndef PAL_PARTITION_FORMAT_TYPE + #define PAL_PARTITION_FORMAT_TYPE "ext4" +#endif + +/*\brief overwrite format command with remove all file and directory*/ +#ifndef PAL_FS_RM_INSTEAD_OF_FORMAT + #define PAL_FS_RM_INSTEAD_OF_FORMAT 0 +#endif + +#ifndef PAL_FS_FORMAT_COMMAND + #define PAL_FS_FORMAT_COMMAND "mkfs -F -t %s %s" +#endif + + +#ifndef PARTITION_FORMAT_ADDITIONAL_PARAMS + #define PARTITION_FORMAT_ADDITIONAL_PARAMS NULL +#endif + + /*\brief Starting Address for section 1 Minimum requirement size is 1KB and section must be consecutive sectors*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_1_ADDRESS + #define PAL_INTERNAL_FLASH_SECTION_1_ADDRESS 0 +#endif + +/*\brief Starting Address for section 2 Minimum requirement size is 1KB and section must be consecutive sectors*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_2_ADDRESS + #define PAL_INTERNAL_FLASH_SECTION_2_ADDRESS 0 +#endif + +/*\brief Size for section 1*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_1_SIZE + #define PAL_INTERNAL_FLASH_SECTION_1_SIZE 0 +#endif + +/*\brief Size for section 2*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_2_SIZE + #define PAL_INTERNAL_FLASH_SECTION_2_SIZE 0 +#endif + + +#endif /* PAL_MBEDOS_CONFIGURATION_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/pal_config/palInclude_mbedOS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/pal_config/palInclude_mbedOS.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,100 @@ +/* + * pal_mbedOS_configuration.h + * + * Created on: Sep 4, 2017 + * Author: pal + */ + +#ifndef PAL_MBEDOS_CONFIGURATION_H_ +/*! \brief This file sets configuration for PAL porting on mbedOS. + \note All configurations that are configured in this file overwrite their defaults values + \note Default Values can be found at Sources/PAL-impl/Services-API/pal_configuration.h + \note + */ + +#include "cmsis_os.h" + +//!< Number partitions on SD card used by PAL File System +#ifndef PAL_NUMBER_OF_PARTITIONS + #define PAL_NUMBER_OF_PARTITIONS 1 +#endif + +//!< Mount point for primary file system partition +#ifndef PAL_FS_MOUNT_POINT_PRIMARY + #if (PAL_NUMBER_OF_PARTITIONS == 2) + #define PAL_FS_MOUNT_POINT_PRIMARY "/sd" //!< User should change this for the his working folder + #else + #define PAL_FS_MOUNT_POINT_PRIMARY "/sd" + #endif +#endif + +//!< Mount point for secondary file system partition +#ifndef PAL_FS_MOUNT_POINT_SECONDARY + #if (PAL_NUMBER_OF_PARTITIONS == 2) + #define PAL_FS_MOUNT_POINT_SECONDARY "/sd2" + #else + #define PAL_FS_MOUNT_POINT_SECONDARY "/sd" //!< User should change this for the his working folder + #endif +#endif + + //!< Change the default value to CMSIS wait forever +#ifndef PAL_RTOS_WAIT_FOREVER + #define PAL_RTOS_WAIT_FOREVER osWaitForever +#endif + +#if defined(TARGET_K64F) + /*\brief Starting Address for section 1 Minimum requirement size is 1KB and section must be consecutive sectors*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_1_ADDRESS + #define PAL_INTERNAL_FLASH_SECTION_1_ADDRESS 0xFE000 +#endif + +/*\brief Starting Address for section 2 Minimum requirement size is 1KB and section must be consecutive sectors*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_2_ADDRESS + #define PAL_INTERNAL_FLASH_SECTION_2_ADDRESS 0xFF000 +#endif + +/*\brief Size for section 1*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_1_SIZE + #define PAL_INTERNAL_FLASH_SECTION_1_SIZE 0x1000 +#endif + +/*\brief Size for section 2*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_2_SIZE + #define PAL_INTERNAL_FLASH_SECTION_2_SIZE 0x1000 +#endif + +#else// defined(TARGET_K64F) + +/*\brief Starting Address for section 1 Minimum requirement size is 1KB and section must be consecutive sectors*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_1_ADDRESS + #define PAL_INTERNAL_FLASH_SECTION_1_ADDRESS 0x080C0000 +#endif + +/*\brief Starting Address for section 2 Minimum requirement size is 1KB and section must be consecutive sectors*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_2_ADDRESS + #define PAL_INTERNAL_FLASH_SECTION_2_ADDRESS 0x080E0000 +#endif + +/*\brief Size for section 1*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_1_SIZE + #define PAL_INTERNAL_FLASH_SECTION_1_SIZE 0x20000 +#endif + +/*\brief Size for section 2*/ +#ifndef PAL_INTERNAL_FLASH_SECTION_2_SIZE + #define PAL_INTERNAL_FLASH_SECTION_2_SIZE 0x20000 +#endif + +#endif// defined(TARGET_K64F) + +#ifndef PAL_NUM_OF_THREAD_INSTANCES + #define PAL_NUM_OF_THREAD_INSTANCES 1 +#endif + +//!< Max given token for a semaphore +#ifndef PAL_MAX_SEMAPHORE_COUNT + #define PAL_MAX_SEMAPHORE_COUNT 1024 +#endif + + +#endif /* PAL_MBEDOS_CONFIGURATION_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/pal_ext_configs.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Configs/pal_ext_configs.cmake Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,17 @@ +SET(PAL_BSP_DIR ${NEW_CMAKE_SOURCE_DIR}/mbed-client-pal/Configs/) +SET(PAL_TLS_BSP_DIR ${PAL_BSP_DIR}/${TLS_LIBRARY}) +SET(PAL_PLATFORM_BSP_DIR ${PAL_BSP_DIR}/pal_config) + + +if (${TLS_LIBRARY} MATCHES mbedTLS) + # PAL specific configurations for mbedTLS + if (NOT (${OS_BRAND} MATCHES "FreeRTOS")) + add_definitions(-DMBEDTLS_CONFIG_FILE="\\"${PAL_TLS_BSP_DIR}/mbedTLSConfig_${OS_BRAND}.h"\\") + else() + add_definitions(-DMBEDTLS_CONFIG_FILE=\"${PAL_TLS_BSP_DIR}/mbedTLSConfig_${OS_BRAND}.h\") + endif() + message("PAL_TLS_BSP_DIR ${PAL_TLS_BSP_DIR}/pal_${OS_BRAND}.h") +endif() + + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/DOXYGEN_FRONTPAGE.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/DOXYGEN_FRONTPAGE.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +Mbed Platform Abstraction Layer (PAL) +================= + +The Mbed Platform Abstraction Layer (PAL) connects Mbed Cloud Client with the underlying platform. + +The main purpose of PAL is to enable easy and fast Mbed Cloud Client services portability, allowing them to operate over wide range of Arm Cortex-based platforms running different operating systems with various libraries (networking, for example). + +PAL has two layers: + +- **Service API layer**: provides the PAL APIs for Mbed Cloud Client code. The APIs are identical for all platforms and operating systems, and you should not modify them. +- **Platform API layer**: provides a standard set of baseline requirements for the platform. To allow Mbed Cloud Client to run on the target platform, you need to implement all requirements when you port. The implementation may be different for each target operating system or library; PAL provides reference implementations for several operating systems, including Mbed OS. + +See the [Files](files.html) section to review the documentation for specific APIs. + +See the [full documentation and porting guide for PAL](/docs/v1.2/porting/index.html).
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,5 @@ +Yocto_Generic_Linux/* +MK64F_FreeRTOS/* +x86_x64_Linux/* +OpenWRT_Generic_Linux/* +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/Include/PlatIncludes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/Include/PlatIncludes.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,72 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef K64_BSPINCLUDES_H_ +#define K64_BSPINCLUDES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \brief This function initialized the network interface +* +* @param None +* +* \return void +* +*/ +void networkInit(void *arg); + +/*! \brief This function return the interface context +* +* @param None +* +* \return void * +* +*/ +void* palTestGetNetWorkInterfaceContext(void); + + +/*! \brief This function initialized the Board interface +* +* @param None +* +* \return void +* +*/ +void boardInit(); + + +/*! \brief This function initialized the FileSystem interface +* +* @param None +* +* \return void +* +*/ +void fileSystemMountDrive(void); + +#ifdef PAL_MEMORY_STATISTICS +void printMemoryStats(void); +#define PRINT_MEMORY_STATS printMemoryStats(); +#else //PAL_MEMORY_STATISTICS +#define PRINT_MEMORY_STATS +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* K64_BSPINCLUDES_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_FreeRTOS/BoardInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_FreeRTOS/BoardInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,73 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "board.h" +#include "fsl_device_registers.h" +#include "pin_mux.h" +#include "clock_config.h" +#include "FreeRTOS.h" +#include "task.h" + +// TRNG Function for K64F device +#include "fsl_common.h" +#include "fsl_clock.h" + +#define APP_DEBUG_UART_BAUDRATE 115200 /* Debug console baud rate. */ +#define APP_DEBUG_UART_CLKSRC_NAME kCLOCK_CoreSysClk /* System clock. */ + +//This stack overflow hook can catch stack overflow errors in FreeRTOS. +//You must enable define of configCHECK_FOR_STACK_OVERFLOW in FreeRTOSConfig.h +void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) +{ + return; +} + +//This MallocFailedHook can catch memory allocation errors in FreeRTOS. +//You must enable define of configUSE_MALLOC_FAILED_HOOK in FreeRTOSConfig.h +void vApplicationMallocFailedHook( void ) +{ + return; +} + + +static void APP_InitPlatformTRNG() +{ + CLOCK_EnableClock(kCLOCK_Rnga0); + CLOCK_DisableClock(kCLOCK_Rnga0); + CLOCK_EnableClock(kCLOCK_Rnga0); +} + +#if 0 +static void APP_StopPlatformTRNG() +{ + CLOCK_DisableClock(kCLOCK_Rnga0); +} + +void StopFreeRtosBoard() +{ + APP_StopPlatformTRNG(); +} +#endif //0 +void boardInit() +{ + MPU_Type *base = MPU; + BOARD_InitPins(); + BOARD_BootClockRUN(); + BOARD_InitDebugConsole(); + APP_InitPlatformTRNG(); + /* Disable MPU. */ + base->CESR &= ~MPU_CESR_VLD_MASK; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_FreeRTOS/FileSystemInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_FreeRTOS/FileSystemInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,290 @@ +#include "pal.h" +#include "FreeRTOS.h" +#include "task.h" +#include "fsl_mpu.h" +#include "ff.h" +#include "diskio.h" +#include "sdhc_config.h" +#include "fsl_debug_console.h" + + +//uncomment this to create the partitions +//#define PAL_EXAMPLE_GENERATE_PARTITION 1 + +#if (PAL_NUMBER_OF_PARTITIONS > 0) + +#ifndef _MULTI_PARTITION +#error "Please Define _MULTI_PARTITION in ffconf.h" +#endif + +#if ((PAL_NUMBER_OF_PARTITIONS > 2) || (PAL_NUMBER_OF_PARTITIONS < 0)) +#error "Pal partition number is not supported, please set to a number between 0 and 2" +#endif + +PARTITION VolToPart[] = { +#if (PAL_NUMBER_OF_PARTITIONS > 0) + {SDDISK,1}, /* 0: */ +#endif +#if (PAL_NUMBER_OF_PARTITIONS > 1) + {SDDISK,2} /* 1: */ +#endif +}; +#endif + +bool FileSystemInit = false; +#define MAX_SD_READ_RETRIES 5 +#define LABEL_LENGTH 66 +/*! + * @brief Get event instance. + * @param eventType The event type + * @return The event instance's pointer. + */ +PAL_PRIVATE volatile uint32_t *EVENT_GetInstance(event_t eventType); + +/*! @brief Transfer complete event. */ +PAL_PRIVATE volatile uint32_t g_eventTransferComplete; + +PAL_PRIVATE volatile uint32_t g_eventSDReady; + +/*! @brief Time variable unites as milliseconds. */ +PAL_PRIVATE volatile uint32_t g_timeMilliseconds; + +/*! @brief Preallocated Work area (file system object) for logical drive, should NOT be free or lost*/ +PAL_PRIVATE FATFS fileSystem[2]; + +/*! \brief CallBack function for SD card initialization + * Set systick reload value to generate 1ms interrupt + * @param void + * + * \return void + * + */ +void EVENT_InitTimer(void) +{ + /* Set systick reload value to generate 1ms interrupt */ + SysTick_Config(CLOCK_GetFreq(kCLOCK_CoreSysClk) / 1000U); +} + + +/*! \brief CallBack function for SD card initialization + * + * @param void + * + * \return pointer to the requested instance + * + */ +PAL_PRIVATE volatile uint32_t *EVENT_GetInstance(event_t eventType) +{ + volatile uint32_t *event; + + switch (eventType) + { + case kEVENT_TransferComplete: + event = &g_eventTransferComplete; + break; + default: + event = NULL; + break; + } + + return event; +} + +/*! \brief CallBack function for SD card initialization + * + * @param event_t + * + * \return TRUE if instance was found + * + */ +bool EVENT_Create(event_t eventType) +{ + volatile uint32_t *event = EVENT_GetInstance(eventType); + + if (event) + { + *event = 0; + return true; + } + else + { + return false; + } +} + +/*! \brief blockDelay - Blocks the task and count the number of ticks given + * + * @param void + * + * \return TRUE - on success + * + */ +void blockDelay(uint32_t Ticks) +{ + uint32_t tickCounts = 0; + for(tickCounts = 0; tickCounts < Ticks; tickCounts++){} +} + + +/*! \brief CallBack function for SD card initialization + * + * @param void + * + * \return TRUE - on success + * + */ +bool EVENT_Wait(event_t eventType, uint32_t timeoutMilliseconds) +{ + uint32_t startTime; + uint32_t elapsedTime; + + volatile uint32_t *event = EVENT_GetInstance(eventType); + + if (timeoutMilliseconds && event) + { + startTime = g_timeMilliseconds; + do + { + elapsedTime = (g_timeMilliseconds - startTime); + } while ((*event == 0U) && (elapsedTime < timeoutMilliseconds)); + *event = 0U; + + return ((elapsedTime < timeoutMilliseconds) ? true : false); + } + else + { + return false; + } +} + +/*! \brief CallBack function for SD card initialization + * + * @param eventType + * + * \return TRUE if instance was found + * + */ +bool EVENT_Notify(event_t eventType) +{ + volatile uint32_t *event = EVENT_GetInstance(eventType); + + if (event) + { + *event = 1U; + return true; + } + else + { + return false; + } +} + +/*! \brief CallBack function for SD card initialization + * + * @param eventType + * + * \return void + * + */ +void EVENT_Delete(event_t eventType) +{ + volatile uint32_t *event = EVENT_GetInstance(eventType); + + if (event) + { + *event = 0U; + } +} + + +/*! \brief This function mount the fatfs on and SD card + * + * @param void + * + * \return palStatus_t - PAL_SUCCESS when mount point succeeded + * + */ + +void fileSystemMountDrive(void) +{ + char folder1[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + char folder2[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + PRINTF("%s : Creating FileSystem SetUp thread!\r\n",__FUNCTION__); + FRESULT fatResult; + int count = 0; + palStatus_t status = PAL_SUCCESS; + + if (FileSystemInit == false) + { + //Detected SD card inserted + while (!(GPIO_ReadPinInput(BOARD_SDHC_CD_GPIO_BASE, BOARD_SDHC_CD_GPIO_PIN))) + { + blockDelay(1000U); + if (count++ > MAX_SD_READ_RETRIES) + { + break; + } + } + + if(count < MAX_SD_READ_RETRIES) + { + /* Delay some time to make card stable. */ + blockDelay(10000000U); +#ifdef PAL_EXAMPLE_GENERATE_PARTITION +#if (PAL_NUMBER_OF_PARTITIONS == 1) + DWORD plist[] = {100,0,0,0}; +#elif (PAL_NUMBER_OF_PARTITIONS == 2) //else of (PAL_NUMBER_OF_PARTITIONS == 1) + DWORD plist[] = {50,50,0,0}; +#endif //(PAL_NUMBER_OF_PARTITIONS == 1) + BYTE work[_MAX_SS]; + + fatResult= f_fdisk(SDDISK,plist, work); + PRINTF("f_fdisk fatResult=%d\r\n",fatResult); + if (FR_OK != fatResult) + { + PRINTF("Failed to create partitions in disk\r\n"); + } +#endif //PAL_EXAMPLE_GENERATE_PARTITION + + + status = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY,PAL_MAX_FILE_AND_FOLDER_LENGTH,folder1); + if (PAL_SUCCESS == status) + { + fatResult = f_mount(&fileSystem[0], folder1, 1U); + if (FR_OK != fatResult) + { + PRINTF("Failed to mount partition %s in disk\r\n",folder1); + } + } + else + { + PRINTF("Failed to get mount point for primary partition\r\n"); + } + + status = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY,PAL_MAX_FILE_AND_FOLDER_LENGTH,folder2); + if (PAL_SUCCESS == status) + { + //if there is a different root folder for partition 1 and 2, mount the 2nd partition + if (strncmp(folder1,folder2,PAL_MAX_FILE_AND_FOLDER_LENGTH)) + { + fatResult = f_mount(&fileSystem[1], folder2, 1U); + if (FR_OK != fatResult) + { + PRINTF("Failed to mount partition %s in disk\r\n",folder2); + } + } + } + else + { + PRINTF("Failed to get mount point for secondary partition\r\n"); + } + + if (fatResult == FR_OK) + { + FileSystemInit = true; + PRINTF("%s : Exit FileSystem SetUp thread!\r\n",__FUNCTION__); + } + } + } + vTaskDelete( NULL ); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_FreeRTOS/NetworkInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_FreeRTOS/NetworkInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,144 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/arch.h" +#include "lwip/api.h" +#include "lwip/tcpip.h" +#include "netif/etharp.h" +#include "lwip/dhcp.h" +#include "ethernetif.h" +#include "lwip/inet.h" + + +struct netif fsl_netif0; +ip_addr_t fsl_netif0_ipaddr, fsl_netif0_netmask, fsl_netif0_gw; + +#ifndef PAL_NETWORK_BRINGUP +#define PAL_NETWORK_BRINGUP 1 +#endif + +bool dhcp_done = false; + +#define configIP_ADDR0 0 +#define configIP_ADDR1 0 +#define configIP_ADDR2 0 +#define configIP_ADDR3 0 + +/* Netmask configuration. */ +#define configNET_MASK0 0 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* Default gateway address configuration */ +#define configGW_ADDR0 0 +#define configGW_ADDR1 0 +#define configGW_ADDR2 0 +#define configGW_ADDR3 0 + +#ifndef HTTPD_STACKSIZE +#define HTTPD_STACKSIZE 3000 +#endif + +#ifndef HTTPD_DEBUG +#define HTTPD_DEBUG LWIP_DBG_ON +#endif + + +void networkInit(void *arg) +{ + PRINTF("%s : Starting HTTP thread! \r\n", __FUNCTION__); + if (PAL_NETWORK_BRINGUP) + { + err_t err = 0; + LWIP_UNUSED_ARG(arg); + + ///// MAC + fsl_netif0.hwaddr_len = 6; + + // Fetch word 0 + uint32_t word0 = *(uint32_t *)0x40048060; + // Fetch word 1 + // we only want bottom 16 bits of word1 (MAC bits 32-47) + // and bit 9 forced to 1, bit 8 forced to 0 + // Locally administered MAC, reduced conflicts + // http://en.wikipedia.org/wiki/MAC_address + uint32_t word1 = *(uint32_t *)0x4004805C; + word1 |= 0x00000200; + word1 &= 0x0000FEFF; + + fsl_netif0.hwaddr[0] = (word1 & 0x000000ff); + fsl_netif0.hwaddr[1] = (word1 & 0x0000ff00) >> 8; + fsl_netif0.hwaddr[2] = (word0 & 0xff000000) >> 24; + fsl_netif0.hwaddr[3] = (word0 & 0x00ff0000) >> 16; + fsl_netif0.hwaddr[4] = (word0 & 0x0000ff00) >> 8; + fsl_netif0.hwaddr[5] = (word0 & 0x000000ff); + //// + + tcpip_init(NULL, NULL); + LWIP_DEBUGF(HTTPD_DEBUG, ("TCP/IP initialized.\r\n")); + IP4_ADDR(&fsl_netif0_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3); + IP4_ADDR(&fsl_netif0_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3); + IP4_ADDR(&fsl_netif0_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3); + + netif_add(&fsl_netif0, &fsl_netif0_ipaddr, &fsl_netif0_netmask, &fsl_netif0_gw, NULL, ethernetif_init, tcpip_input); + netif_set_default(&fsl_netif0); + + PRINTF("%s : Starting DCHP request\r\n", __FUNCTION__); + /* obtain the IP address, default gateway and subnet mask by using DHCP*/ + err = dhcp_start(&fsl_netif0); + PRINTF("%s : Started DCHP request (%s)\r\n", __FUNCTION__, lwip_strerr(err)); + for(int i=0; i < 40 && fsl_netif0.dhcp->state != DHCP_BOUND; i++) + { + PRINTF("%s : Current DHCP State : %d\r\n", __FUNCTION__, fsl_netif0.dhcp->state); + vTaskDelay(1000/portTICK_PERIOD_MS); + } + + /**/ + PRINTF("%s : DHCP state, activating interface (%d)\r\n", __FUNCTION__,fsl_netif0.dhcp->state); + if (fsl_netif0.dhcp->state != DHCP_BOUND) + { + PRINTF("%s : DHCP state, TIMEOUT (%d)\r\n", __FUNCTION__,fsl_netif0.dhcp->state); + } + + LWIP_DEBUGF(HTTPD_DEBUG, ("http_server_netconn_thread: init interface START!")); + netif_set_up(&fsl_netif0); + LWIP_DEBUGF(HTTPD_DEBUG, ("http_server_netconn_thread: init interface END!")); + + PRINTF("%s : Interface is up : %d\r\n", __FUNCTION__, fsl_netif0.dhcp->state); + PRINTF("%s : IP %s\r\n", __FUNCTION__, ipaddr_ntoa(&fsl_netif0.ip_addr)); + PRINTF("%s : NM %s\r\n", __FUNCTION__, ipaddr_ntoa(&fsl_netif0.netmask)); + PRINTF("%s : GW %s\r\n", __FUNCTION__, ipaddr_ntoa(&fsl_netif0.gw)); + } + PRINTF("before run tests: \r\n"); + dhcp_done = true; + + vTaskDelete( NULL ); + +} + +// Currently we support only one interface +void* palTestGetNetWorkInterfaceContext() +{ + return (void *)&fsl_netif0; +} + + + + + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_mbedOS/FileSystemInit.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_mbedOS/FileSystemInit.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "pal.h" +#include "mbed.h" +#include "FATFileSystem.h" +#include "SDBlockDevice.h" + +#include "MBRBlockDevice.h" + +#ifndef PRIMARY_PARTITION_NUMBER +#define PRIMARY_PARTITION_NUMBER 1 +#endif + +#ifndef PRIMARY_PARTITION_START +#define PRIMARY_PARTITION_START 0 +#endif + +#ifndef PRIMARY_PARTITION_SIZE +#define PRIMARY_PARTITION_SIZE 512*1024 +#endif + +#ifndef SECONDARY_PARTITION_NUMBER +#define SECONDARY_PARTITION_NUMBER 2 +#endif + +#ifndef SECONDARY_PARTITION_START +#define SECONDARY_PARTITION_START PRIMARY_PARTITION_SIZE +#endif + +#ifndef SECONDARY_PARTITION_SIZE +#define SECONDARY_PARTITION_SIZE PRIMARY_PARTITION_SIZE +#endif + +/*MBED_LIBRARY_VERSION 129 stands for mbed-os 5.2.2*/ +#ifdef MBED_LIBRARY_VERSION +#if (MBED_LIBRARY_VERSION < 129) +#endif +#endif //MBED_LIBRARY_VERSION + + +//uncomment this to create the partitions +#define PAL_EXAMPLE_GENERATE_PARTITION 1 + +// +// See the mbed_lib.json in the sd-driver library for the definitions. +// See the sd-driver library README.md for details with CI-shield etc. +// Add also new boards/exceptions there rather than in code directly +// OR +// alternatively overload via your mbed_app.json (MBED_CONF_APP...) +// + +#if defined (MBED_CONF_APP_SPI_MOSI) && defined (MBED_CONF_APP_SPI_MISO) && defined (MBED_CONF_APP_SPI_CLK) && defined (MBED_CONF_APP_SPI_CS) + SDBlockDevice sd(MBED_CONF_APP_SPI_MOSI, MBED_CONF_APP_SPI_MISO, MBED_CONF_APP_SPI_CLK, MBED_CONF_APP_SPI_CS); +#else + SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); +#endif + +//This trick (the adding of 1) is to skip the '/' that is needed for FS but not needed to init +FATFileSystem fat1(((char*)PAL_FS_MOUNT_POINT_PRIMARY+1)); + +#if (PAL_NUMBER_OF_PARTITIONS > 0) +MBRBlockDevice part1(&sd,1); +#if (PAL_NUMBER_OF_PARTITIONS == 2) +MBRBlockDevice part2(&sd,2); +//This trick (the adding of 1) is to skip the '/' that is needed for FS but not needed to init +FATFileSystem fat2(((char*)PAL_FS_MOUNT_POINT_SECONDARY+1)); +#endif +#endif + + +static int initPartition(uint8_t partitionNumber, BlockDevice* bd,FATFileSystem* fs) +{ + int err = bd->init(); + if (err < 0) + { + printf("Failed to initialize 1st partition cause %d\r\n",err); +#ifdef PAL_EXAMPLE_GENERATE_PARTITION + printf("Trying to create the partition\r\n"); + if (PRIMARY_PARTITION_NUMBER == partitionNumber) + { + err = MBRBlockDevice::partition(&sd, PRIMARY_PARTITION_NUMBER, 0x83, PRIMARY_PARTITION_START, PRIMARY_PARTITION_START + PRIMARY_PARTITION_SIZE); + } + else if (SECONDARY_PARTITION_NUMBER == partitionNumber) + { + err = MBRBlockDevice::partition(&sd, SECONDARY_PARTITION_NUMBER, 0x83, SECONDARY_PARTITION_START, SECONDARY_PARTITION_START + SECONDARY_PARTITION_SIZE); + } + else + { + printf("Wrong partition number %d\r\n",partitionNumber); + err = -1; + } + if (err < 0) + { + printf("Failed to create the partition cause %d\r\n",err); + } + else + { + err = bd->init(); + } +#endif + } + if (!err) + { + err = fs->mount(bd); + if (err < 0) + { + err = FATFileSystem::format(bd); + if (err < 0) + { + printf("failed to format part cause %d\r\n",err); + } + else + { + err = fs->mount(bd); + if (err < 0) + { + printf("failed to mount cause %d\r\n",err); + } + } + } + } + return err; +} + +int initSDcardAndFileSystem(void) +{ + printf("Initializing the file system\r\n"); +#if (PAL_NUMBER_OF_PARTITIONS == 0 ) + int err = initPartition(0, &sd, &fat1); + if (err < 0) + { + printf("Failed to initialize primary partition\r\n"); + } +#elif (PAL_NUMBER_OF_PARTITIONS > 0) // create and mount an additional partition + int err = initPartition(PRIMARY_PARTITION_NUMBER, &part1,&fat1); + if (err < 0) + { + printf("Failed to initialize primary partition\r\n"); + } +#if (PAL_NUMBER_OF_PARTITIONS == 2) + else + { + err = initPartition(SECONDARY_PARTITION_NUMBER, &part2,&fat2); + if (err < 0) + { + printf("Failed to initialize secondary partition\r\n"); + } + } +#endif +#endif + return err; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_mbedOS/NetworkInit.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/MK64F_mbedOS/NetworkInit.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,44 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "mbed.h" +#include "EthernetInterface.h" + +bool dhcp_done = true; +static EthernetInterface* netInterface = NULL; +extern "C" { + void* palTestGetNetWorkInterfaceContext(void) + { + nsapi_error_t status = NSAPI_ERROR_OK; + if (NULL == netInterface) + { + netInterface = new EthernetInterface(); + printf("new interface created\r\n"); + status = netInterface->connect(); + if (NSAPI_ERROR_OK == status) + { + printf("interface registered : OK \r\n"); + } + else //connect failed + { + printf("interface registered : FAILED! \r\n"); + delete netInterface; + netInterface = NULL; + } + } + return netInterface; + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/OpenWRT_Generic_Linux/BoardInit.c
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/OpenWRT_Generic_Linux/FileSystemInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/OpenWRT_Generic_Linux/FileSystemInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,96 @@ +#include "pal.h" +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mount.h> + +#ifndef PRIMARY_PARTITION_NAME +#define PRIMARY_PARTITION_NAME "/dev/mmcblk0p3" +#endif + +#ifndef SECONDARY_PARTITION_NAME +#define SECONDARY_PARTITION_NAME "/dev/mmcblk0p4" +#endif + +#ifndef PAL_PARTITION_FORMAT_TYPE +#define PAL_PARTITION_FORMAT_TYPE "ext4" +#endif + +#ifndef PARTITION_FORMAT_ADDITIONAL_PARAMS +#define PARTITION_FORMAT_ADDITIONAL_PARAMS NULL +#endif +// Desktop Linux +// In order for tests to pass for all partition configurations we need to simulate the case of multiple +// partitions using a single folder. We do this by creating one or two different sub-folders, depending on +// the configuration. +palStatus_t fileSystemCreateRootFolders(void) +{ + palStatus_t status = PAL_SUCCESS; + char folder[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + + // Get default mount point. + status = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FILE_AND_FOLDER_LENGTH, folder); + if(status != PAL_SUCCESS) + { + return PAL_ERR_GENERIC_FAILURE; + } + printf("Mount point for primary partition: %s\r\n",folder); + // Make the sub-folder + int res = mkdir(folder,0744); + if(res) + { + // Ignore error if it exists + if( errno != EEXIST) + { + printf("mkdir failed errno= %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + + res = mount(PRIMARY_PARTITION_NAME, folder, PAL_PARTITION_FORMAT_TYPE, 0 ,PARTITION_FORMAT_ADDITIONAL_PARAMS); + if (res) + { + if( errno != EBUSY) + { + printf("mounting failed %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + // Get default mount point. + memset(folder,0,sizeof(folder)); + status = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FILE_AND_FOLDER_LENGTH, folder); + printf("Mount point for secondary partition: %s\r\n",folder); + if(status != PAL_SUCCESS) + { + return PAL_ERR_GENERIC_FAILURE; + } + + // Make the sub-folder + res = mkdir(folder,0744); + if(res) + { + // Ignore error if it exists + if( errno != EEXIST) + { + printf("mkdir failed errno= %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + + res = mount(SECONDARY_PARTITION_NAME, folder,PAL_PARTITION_FORMAT_TYPE ,0 ,PARTITION_FORMAT_ADDITIONAL_PARAMS); + if (res) + { + if( errno != EBUSY) + { + printf("mounting failed %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + + if(status != PAL_SUCCESS) + { + return PAL_ERR_GENERIC_FAILURE; + } + + return PAL_SUCCESS; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/OpenWRT_Generic_Linux/NetworkInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/OpenWRT_Generic_Linux/NetworkInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,32 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#include <inttypes.h> + +#ifndef PAL_LINUX_ETH +#define PAL_LINUX_ETH "eth0" +#endif + +bool dhcp_done = true; + +void* palTestGetNetWorkInterfaceContext(void){ + static const char interface[] = PAL_LINUX_ETH; + return (void *)&interface[0]; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/Yocto_Generic_Linux/BoardInit.c
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/Yocto_Generic_Linux/FileSystemInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/Yocto_Generic_Linux/FileSystemInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,96 @@ +#include "pal.h" +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/mount.h> + +#ifndef PRIMARY_PARTITION_NAME +#define PRIMARY_PARTITION_NAME "/dev/mmcblk0p3" +#endif + +#ifndef SECONDARY_PARTITION_NAME +#define SECONDARY_PARTITION_NAME "/dev/mmcblk0p4" +#endif + +#ifndef PAL_PARTITION_FORMAT_TYPE +#define PAL_PARTITION_FORMAT_TYPE "ext4" +#endif + +#ifndef PARTITION_FORMAT_ADDITIONAL_PARAMS +#define PARTITION_FORMAT_ADDITIONAL_PARAMS NULL +#endif +// Desktop Linux +// In order for tests to pass for all partition configurations we need to simulate the case of multiple +// partitions using a single folder. We do this by creating one or two different sub-folders, depending on +// the configuration. +palStatus_t fileSystemCreateRootFolders(void) +{ + palStatus_t status = PAL_SUCCESS; + char folder[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + + // Get default mount point. + status = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FILE_AND_FOLDER_LENGTH, folder); + if(status != PAL_SUCCESS) + { + return PAL_ERR_GENERIC_FAILURE; + } + printf("Mount point for primary partition: %s\r\n",folder); + // Make the sub-folder + int res = mkdir(folder,0744); + if(res) + { + // Ignore error if it exists + if( errno != EEXIST) + { + printf("mkdir failed errno= %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + + res = mount(PRIMARY_PARTITION_NAME, folder, PAL_PARTITION_FORMAT_TYPE, 0 ,PARTITION_FORMAT_ADDITIONAL_PARAMS); + if (res) + { + if( errno != EBUSY) + { + printf("mounting failed %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + // Get default mount point. + memset(folder,0,sizeof(folder)); + status = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FILE_AND_FOLDER_LENGTH, folder); + printf("Mount point for secondary partition: %s\r\n",folder); + if(status != PAL_SUCCESS) + { + return PAL_ERR_GENERIC_FAILURE; + } + + // Make the sub-folder + res = mkdir(folder,0744); + if(res) + { + // Ignore error if it exists + if( errno != EEXIST) + { + printf("mkdir failed errno= %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + + res = mount(SECONDARY_PARTITION_NAME, folder,PAL_PARTITION_FORMAT_TYPE ,0 ,PARTITION_FORMAT_ADDITIONAL_PARAMS); + if (res) + { + if( errno != EBUSY) + { + printf("mounting failed %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + + if(status != PAL_SUCCESS) + { + return PAL_ERR_GENERIC_FAILURE; + } + + return PAL_SUCCESS; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/Yocto_Generic_Linux/NetworkInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/Yocto_Generic_Linux/NetworkInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,32 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#include <inttypes.h> + +#ifndef PAL_LINUX_ETH +#define PAL_LINUX_ETH "eth0" +#endif + +bool dhcp_done = true; + +void* palTestGetNetWorkInterfaceContext(void){ + static const char interface[] = PAL_LINUX_ETH; + return (void *)&interface[0]; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/pal_insecure_ROT.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/pal_insecure_ROT.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,31 @@ +#include "pal.h" +#define PAL_DEVICE_KEY_SIZE_IN_BYTES 16 + +//THIS CODE IS FOR TESTING PURPOSES ONLY. DO NOT USE IN PRODUCTION ENVIRONMENTS. REPLACE WITH A PROPER IMPLEMENTATION BEFORE USE +palStatus_t __attribute__((weak)) pal_plat_osGetRoT128Bit(uint8_t *keyBuf, size_t keyLenBytes) + +{ + #if defined (__CC_ARM) /* ARM compiler. */ + #warning("PAL_INSECURE- You are using insecure Root Of Trust implementation, DO NOT USE IN PRODUCTION ENVIRONMENTS. REPLACE WITH A PROPER IMPLEMENTATION BEFORE USE") + #else + #pragma message ("You are using insecure Root Of Trust implementation, DO NOT USE IN PRODUCTION ENVIRONMENTS. REPLACE WITH A PROPER IMPLEMENTATION BEFORE USE") + #endif + + PAL_LOG(WARN, "You are using insecure Root Of Trust implementation"); + + if (keyLenBytes < PAL_DEVICE_KEY_SIZE_IN_BYTES) + { + return PAL_ERR_BUFFER_TOO_SMALL; + } + + if (NULL == keyBuf) + { + return PAL_ERR_NULL_POINTER; + } + + for (int i=0; i < PAL_DEVICE_KEY_SIZE_IN_BYTES; i++) + { + keyBuf[i] = i; + } + return PAL_SUCCESS; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/x86_x64_Linux/BoardInit.c
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/x86_x64_Linux/FileSystemInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/x86_x64_Linux/FileSystemInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +#include "pal.h" +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> + + +// Desktop Linux +// In order for tests to pass for all partition configurations we need to simulate the case of multiple +// partitions using a single folder. We do this by creating one or two different sub-folders, depending on +// the configuration. +palStatus_t fileSystemCreateRootFolders(void) +{ + palStatus_t status = PAL_SUCCESS; + char folder[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + + // Get default mount point. + status = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FILE_AND_FOLDER_LENGTH, folder); + if(status != PAL_SUCCESS) + { + return PAL_ERR_GENERIC_FAILURE; + } + printf("Mount point for primary partition: %s\r\n",folder); + // Make the sub-folder + int res = mkdir(folder,0744); + if(res) + { + // Ignore error if it exists + if( errno != EEXIST) + { + printf("mkdir failed errno= %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + + // Get default mount point. + memset(folder,0,sizeof(folder)); + status = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FILE_AND_FOLDER_LENGTH, folder); + printf("Mount point for secondary partition: %s\r\n",folder); + if(status != PAL_SUCCESS) + { + return PAL_ERR_GENERIC_FAILURE; + } + + // Make the sub-folder + res = mkdir(folder,0744); + if(res) + { + // Ignore error if it exists + if( errno != EEXIST) + { + printf("mkdir failed errno= %d\r\n",errno); + return PAL_ERR_GENERIC_FAILURE; + } + } + + return status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/x86_x64_Linux/NetworkInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Examples/PlatformBSP/x86_x64_Linux/NetworkInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,32 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#include <inttypes.h> + +#ifndef PAL_LINUX_ETH +#define PAL_LINUX_ETH "eth0" +#endif + +bool dhcp_done = true; + +void* palTestGetNetWorkInterfaceContext(void){ + static const char interface[] = PAL_LINUX_ETH; + return (void *)&interface[0]; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/CMakeLists.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,32 @@ +include_directories(Port/Platform-API) +ADD_GLOBALDIR( ${CMAKE_CURRENT_SOURCE_DIR}/PAL-Impl/Services-API) + +set (PAL_MODULES_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/PAL-Impl/Modules) +set (PAL_PORT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Port/Reference-Impl/OS_Specific/${OS_BRAND}) + +set(PAL_SRCS + ${PAL_PORT_SOURCE_DIR}/Networking/${NETWORK_STACK}/pal_plat_network.c + ${PAL_PORT_SOURCE_DIR}/RTOS/pal_plat_rtos.c + ${PAL_PORT_SOURCE_DIR}/../../Lib_Specific/${TLS_LIBRARY}/TLS/pal_plat_TLS.c + ${PAL_PORT_SOURCE_DIR}/../../Lib_Specific/${TLS_LIBRARY}/Crypto/pal_plat_Crypto.c + ${PAL_PORT_SOURCE_DIR}/Update/pal_plat_update.c + ${PAL_PORT_SOURCE_DIR}/Storage/FileSystem/pal_plat_fileSystem.c + ${PAL_PORT_SOURCE_DIR}/Storage/Flash/pal_plat_internalFlash.c + ${PAL_PORT_SOURCE_DIR}/Board_Specific/TARGET_${MBED_CLOUD_CLIENT_DEVICE}/pal_plat_${MBED_CLOUD_CLIENT_DEVICE}.c + + + ${PAL_MODULES_SOURCE_DIR}/Networking/pal_network.c + ${PAL_MODULES_SOURCE_DIR}/RTOS/pal_rtos.c + ${PAL_MODULES_SOURCE_DIR}/TLS/pal_TLS.c + ${PAL_MODULES_SOURCE_DIR}/Crypto/pal_Crypto.c + ${PAL_MODULES_SOURCE_DIR}/Update/pal_update.c + ${PAL_MODULES_SOURCE_DIR}/Storage/FileSystem/pal_fileSystem.c + ${PAL_MODULES_SOURCE_DIR}/Storage/Flash/pal_internalFlash.c + + + ${CMAKE_CURRENT_SOURCE_DIR}/PAL-Impl/pal_init.c +) + + + +CREATE_LIBRARY(pal "${PAL_SRCS}" "")
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Crypto/pal_Crypto.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Crypto/pal_Crypto.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,733 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "pal.h" +#include "pal_plat_Crypto.h" + + +palStatus_t pal_initAes(palAesHandle_t *aes) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == aes) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_initAes(aes); + return status; +} + +palStatus_t pal_freeAes(palAesHandle_t *aes) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == aes || (uintptr_t)NULL == *aes) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_freeAes(aes); + return status; +} + +palStatus_t pal_setAesKey(palAesHandle_t aes, const unsigned char* key, uint32_t keybits, palAesKeyType_t keyTarget) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == aes || NULL == key) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_setAesKey(aes, key, keybits, keyTarget); + return status; +} + +palStatus_t pal_aesCTR(palAesHandle_t aes, const unsigned char* input, unsigned char* output, size_t inLen, unsigned char iv[16]) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == aes || NULL == input || NULL == output || NULL == iv) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_aesCTR(aes, input, output, inLen, iv, false); + return status; +} + +palStatus_t pal_aesCTRWithZeroOffset(palAesHandle_t aes, const unsigned char* input, unsigned char* output, size_t inLen, unsigned char iv[16]) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == aes || NULL == input || NULL == output || NULL == iv) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_aesCTR(aes, input, output, inLen, iv, true); + return status; +} + +palStatus_t pal_aesECB(palAesHandle_t aes, const unsigned char input[PAL_CRYPT_BLOCK_SIZE], unsigned char output[PAL_CRYPT_BLOCK_SIZE], palAesMode_t mode) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == aes || NULL == input || NULL == output) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_aesECB(aes, input, output, mode); + return status; +} + +palStatus_t pal_sha256(const unsigned char* input, size_t inLen, unsigned char* output) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == input || NULL == output) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_sha256(input, inLen, output); + return status; +} + +palStatus_t pal_x509Initiate(palX509Handle_t* x509Cert) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == x509Cert) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509Initiate(x509Cert); + return status; +} + +palStatus_t pal_x509CertParse(palX509Handle_t x509Cert, const unsigned char* input, size_t inLen) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509Cert || NULL == input) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CertParse(x509Cert, input, inLen); + return status; +} + +palStatus_t pal_x509CertGetAttribute(palX509Handle_t x509Cert, palX509Attr_t attr, void* output, size_t outLenBytes, size_t* actualOutLenBytes) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509Cert || NULL == output || NULL == actualOutLenBytes) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CertGetAttribute(x509Cert, attr, output, outLenBytes, actualOutLenBytes); + return status; +} + +palStatus_t pal_x509CertVerify(palX509Handle_t x509Cert, palX509Handle_t x509CertChain) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509Cert) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CertVerify(x509Cert, x509CertChain); + return status; +} + +palStatus_t pal_x509Free(palX509Handle_t* x509Cert) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509Cert || NULLPTR == *x509Cert) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509Free(x509Cert); + return status; +} + +palStatus_t pal_mdInit(palMDHandle_t* md, palMDType_t mdType) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == md) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_mdInit(md, mdType); + return status; +} + +palStatus_t pal_mdUpdate(palMDHandle_t md, const unsigned char* input, size_t inLen) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == md || NULL == input) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_mdUpdate(md, input, inLen); + return status; +} + +palStatus_t pal_mdGetOutputSize(palMDHandle_t md, size_t* bufferSize) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == md || NULL == bufferSize) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_mdGetOutputSize(md, bufferSize); + return status; +} + +palStatus_t pal_mdFinal(palMDHandle_t md, unsigned char* output) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == md || NULL == output) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_mdFinal(md, output); + return status; +} + +palStatus_t pal_mdFree(palMDHandle_t* md) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == md || NULLPTR == *md) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_mdFree(md); + return status; +} + +palStatus_t pal_verifySignature(palX509Handle_t x509, palMDType_t mdType, const unsigned char *hash, size_t hashLen, const unsigned char *sig, size_t sigLen) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509 || NULL == hash || NULL == sig) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_verifySignature(x509, mdType, hash, hashLen, sig, sigLen); + return status; +} + +palStatus_t pal_ASN1GetTag(unsigned char **position, const unsigned char *end, size_t *len, uint8_t tag ) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == position || NULL == end || NULL == len) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ASN1GetTag(position, end, len, tag); + return status; +} + +palStatus_t pal_CCMInit(palCCMHandle_t* ctx) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == ctx) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CCMInit(ctx); + return status; +} + +palStatus_t pal_CCMFree(palCCMHandle_t* ctx) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == ctx || NULLPTR == *ctx) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CCMFree(ctx); + return status; +} + +palStatus_t pal_CCMSetKey(palCCMHandle_t ctx, const unsigned char *key, uint32_t keybits, palCipherID_t id) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == ctx || NULL == key) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CCMSetKey(ctx, id, key, keybits); + return status; +} + +palStatus_t pal_CCMDecrypt(palCCMHandle_t ctx, unsigned char* input, size_t inLen, + unsigned char* iv, size_t ivLen, unsigned char* add, + size_t addLen, unsigned char* tag, size_t tagLen, + unsigned char* output) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == ctx || NULL == input || NULL == iv || NULL == add || NULL == tag || NULL == output) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CCMDecrypt(ctx, input, inLen, iv, ivLen, add, addLen, tag, tagLen, output); + return status; +} + +palStatus_t pal_CCMEncrypt(palCCMHandle_t ctx, unsigned char* input, + size_t inLen, unsigned char* iv, size_t ivLen, + unsigned char* add, size_t addLen, unsigned char* output, + unsigned char* tag, size_t tagLen) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == ctx || NULL == input || NULL == iv || NULL == add || NULL == tag || NULL == output) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CCMEncrypt(ctx, input, inLen, iv, ivLen, add, addLen, output, tag, tagLen); + return status; +} + +palStatus_t pal_CtrDRBGInit(palCtrDrbgCtxHandle_t* ctx, const void* seed, size_t len) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == ctx || NULL == seed) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CtrDRBGInit(ctx); + if (PAL_SUCCESS == status) + { + status = pal_plat_CtrDRBGSeed(*ctx, seed, len); + } + + return status; +} + +palStatus_t pal_CtrDRBGGenerate(palCtrDrbgCtxHandle_t ctx, unsigned char* out, size_t len) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == ctx || NULL == out) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CtrDRBGGenerate(ctx, out, len); + return status; +} + +palStatus_t pal_CtrDRBGFree(palCtrDrbgCtxHandle_t* ctx) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == ctx || NULLPTR == *ctx) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CtrDRBGFree(ctx); + return status; +} + +palStatus_t pal_cipherCMAC(const unsigned char *key, size_t keyLenInBits, const unsigned char *input, size_t inputLenInBytes, unsigned char *output) +{ + palStatus_t status = PAL_SUCCESS; + if (NULL == key || NULL == input || NULL == output) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_cipherCMAC(key, keyLenInBits, input, inputLenInBytes, output); + return status; +} + +palStatus_t pal_CMACStart(palCMACHandle_t *ctx, const unsigned char *key, size_t keyLenBits, palCipherID_t cipherID) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == ctx || NULL == key) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CMACStart(ctx, key, keyLenBits, cipherID); + return status; +} + +palStatus_t pal_CMACUpdate(palCMACHandle_t ctx, const unsigned char *input, size_t inLen) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == ctx || NULL == input) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CMACUpdate(ctx, input, inLen); + return status; +} + +palStatus_t pal_CMACFinish(palCMACHandle_t *ctx, unsigned char *output, size_t* outLen) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == ctx || NULLPTR == *ctx || NULL == output || NULL == outLen) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_CMACFinish(ctx, output, outLen); + return status; +} + +palStatus_t pal_mdHmacSha256(const unsigned char *key, size_t keyLenInBytes, const unsigned char *input, size_t inputLenInBytes, unsigned char *output, size_t* outputLenInBytes) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == key || NULL == input || NULL == output) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_mdHmacSha256(key, keyLenInBytes, input, inputLenInBytes, output, outputLenInBytes); + return status; +} + +palStatus_t pal_ECCheckKey(palCurveHandle_t grp, palECKeyHandle_t key, uint32_t type, bool *verified) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == grp || NULLPTR == key || NULL == verified) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECCheckKey(grp, key, type, verified); + return status; +} + +palStatus_t pal_ECKeyNew(palECKeyHandle_t* key) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == key) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECKeyNew(key); + return status; +} + +palStatus_t pal_ECKeyFree(palECKeyHandle_t* key) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == key || NULLPTR == *key) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECKeyFree(key); + return status; +} + +palStatus_t pal_parseECPrivateKeyFromDER(const unsigned char* prvDERKey, size_t keyLen, palECKeyHandle_t key) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == prvDERKey || NULLPTR == key) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_parseECPrivateKeyFromDER(prvDERKey, keyLen, key); + return status; +} + +palStatus_t pal_parseECPublicKeyFromDER(const unsigned char* pubDERKey, size_t keyLen, palECKeyHandle_t key) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == pubDERKey || NULLPTR == key) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_parseECPublicKeyFromDER(pubDERKey, keyLen, key); + return status; +} + +palStatus_t pal_writePrivateKeyToDer(palECKeyHandle_t key, unsigned char* derBuffer, size_t bufferSize, size_t* actualSize) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == key || NULL == derBuffer || NULL == actualSize) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_writePrivateKeyToDer(key, derBuffer, bufferSize, actualSize); + return status; +} + +palStatus_t pal_writePublicKeyToDer(palECKeyHandle_t key, unsigned char* derBuffer, size_t bufferSize, size_t* actualSize) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == key || NULL == derBuffer || NULL == actualSize) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_writePublicKeyToDer(key, derBuffer, bufferSize, actualSize); + return status; +} +palStatus_t pal_ECGroupInitAndLoad(palCurveHandle_t* grp, palGroupIndex_t index) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == grp) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECGroupInitAndLoad(grp, index); + return status; +} + +palStatus_t pal_ECGroupFree(palCurveHandle_t* grp) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == grp || NULLPTR == *grp) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECGroupFree(grp); + return status; +} + +palStatus_t pal_ECKeyGenerateKey(palGroupIndex_t grpID, palECKeyHandle_t key) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == key) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECKeyGenerateKey(grpID, key); + return status; +} + +palStatus_t pal_ECKeyGetCurve(palECKeyHandle_t key, palGroupIndex_t* grpID) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == key || NULL == grpID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECKeyGetCurve(key, grpID); + return status; +} + +palStatus_t pal_x509CSRInit(palx509CSRHandle_t *x509CSR) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == x509CSR) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CSRInit(x509CSR); + return status; +} + +palStatus_t pal_x509CSRSetSubject(palx509CSRHandle_t x509CSR, const char* subjectName) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509CSR || NULL == subjectName) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CSRSetSubject(x509CSR, subjectName); + return status; +} + +palStatus_t pal_x509CSRSetKey(palx509CSRHandle_t x509CSR, palECKeyHandle_t pubKey, palECKeyHandle_t prvKey) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509CSR || NULLPTR == pubKey) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CSRSetKey(x509CSR, pubKey, prvKey); + return status; +} + +palStatus_t pal_x509CSRSetMD(palx509CSRHandle_t x509CSR, palMDType_t mdType) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509CSR) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CSRSetMD(x509CSR, mdType); + return status; +} + +palStatus_t pal_x509CSRSetKeyUsage(palx509CSRHandle_t x509CSR, uint32_t keyUsage) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509CSR) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CSRSetKeyUsage(x509CSR, keyUsage); + return status; +} + +palStatus_t pal_x509CSRSetExtension(palx509CSRHandle_t x509CSR,const char* oid, size_t oidLen, const unsigned char* value, size_t valueLen) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509CSR || NULL == oid || NULL == value) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CSRSetExtension(x509CSR, oid, oidLen, value, valueLen); + return status; +} + +palStatus_t pal_x509CSRWriteDER(palx509CSRHandle_t x509CSR, unsigned char* derBuf, size_t derBufLen, size_t* actualDerLen) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == x509CSR || NULL == derBuf) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CSRWriteDER(x509CSR, derBuf, derBufLen, actualDerLen); + return status; +} + +palStatus_t pal_x509CSRFree(palx509CSRHandle_t *x509CSR) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == x509CSR || NULLPTR == *x509CSR) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_x509CSRFree(x509CSR); + return status; +} + +palStatus_t pal_ECDHComputeKey(const palCurveHandle_t grp, const palECKeyHandle_t peerPublicKey, + const palECKeyHandle_t privateKey, palECKeyHandle_t outKey) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == grp || NULLPTR == peerPublicKey || NULLPTR == privateKey || NULLPTR == outKey) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECDHComputeKey(grp, peerPublicKey, privateKey, outKey); + return status; +} + +palStatus_t pal_ECDSASign(palCurveHandle_t grp, palMDType_t mdType, palECKeyHandle_t prvKey, unsigned char* dgst, + uint32_t dgstLen, unsigned char *sig, size_t *sigLen) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == grp || NULLPTR == prvKey || NULL == dgst || NULL == sig || NULL == sigLen) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECDSASign(grp, mdType, prvKey, dgst, dgstLen, sig, sigLen); + return status; +} + +palStatus_t pal_ECDSAVerify(palECKeyHandle_t pubKey, unsigned char* dgst, uint32_t dgstLen, + unsigned char* sig, size_t sigLen, bool* verified) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == pubKey || NULL == dgst || NULL == sig || NULL == verified) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_ECDSAVerify(pubKey, dgst, dgstLen, sig, sigLen, verified); + return status; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Networking/pal_network.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Networking/pal_network.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,429 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#include "pal.h" +#include "pal_network.h" +#include "pal_plat_network.h" + +typedef struct pal_in_addr { + uint32_t s_addr; // that's a 32-bit int (4 bytes) +} pal_in_addr_t; + +typedef struct pal_socketAddressInternal { + short int pal_sin_family; // address family + unsigned short int pal_sin_port; // port + pal_in_addr_t pal_sin_addr; // ipv4 address + unsigned char pal_sin_zero[8]; // +} pal_socketAddressInternal_t; + +typedef struct pal_socketAddressInternal6{ + uint16_t pal_sin6_family; // address family, + uint16_t pal_sin6_port; // port number, Network Byte Order + uint32_t pal_sin6_flowinfo; // IPv6 flow information + palIpV6Addr_t pal_sin6_addr; // IPv6 address + uint32_t pal_sin6_scope_id; // Scope ID +} pal_socketAddressInternal6_t; + + + +palStatus_t pal_registerNetworkInterface(void* networkInterfaceContext, uint32_t* interfaceIndex) +{ + palStatus_t result = PAL_SUCCESS; + if (networkInterfaceContext != NULL && interfaceIndex != NULL) + { + result = pal_plat_registerNetworkInterface(networkInterfaceContext, interfaceIndex); + } + else + { + result = PAL_ERR_INVALID_ARGUMENT; + } + + return result; +} + +palStatus_t pal_setSockAddrPort(palSocketAddress_t* address, uint16_t port) +{ + palStatus_t result = PAL_SUCCESS; + if (NULL == address) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (address->addressType == PAL_AF_INET) + { + pal_socketAddressInternal_t* innerAddr = (pal_socketAddressInternal_t*)address; + // Set Linux format + innerAddr->pal_sin_port = PAL_HTONS(port); + } + else if (address->addressType == PAL_AF_INET6) + { + pal_socketAddressInternal6_t * innerAddr = (pal_socketAddressInternal6_t*)address; + // Set Linux format + innerAddr->pal_sin6_port = PAL_HTONS(port); + } + else + { + result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY; + } + + return result; +} + + +palStatus_t pal_setSockAddrIPV4Addr(palSocketAddress_t* address, palIpV4Addr_t ipV4Addr) +{ + if ((NULL == address) || (NULL == ipV4Addr)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + pal_socketAddressInternal_t* innerAddr = (pal_socketAddressInternal_t*)address; + innerAddr->pal_sin_family = PAL_AF_INET; + innerAddr->pal_sin_addr.s_addr = (ipV4Addr[0]) | (ipV4Addr[1] << 8) | (ipV4Addr[2] << 16) | (ipV4Addr[3] << 24); + return PAL_SUCCESS; +} + + +palStatus_t pal_setSockAddrIPV6Addr(palSocketAddress_t* address, palIpV6Addr_t ipV6Addr) +{ + int index; + + if ((NULL == address) || (NULL == ipV6Addr)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + pal_socketAddressInternal6_t* innerAddr = (pal_socketAddressInternal6_t*)address; + innerAddr->pal_sin6_family = PAL_AF_INET6; + for (index = 0; index < PAL_IPV6_ADDRESS_SIZE; index++) // TODO: use mem copy? + { + innerAddr->pal_sin6_addr[index] = ipV6Addr[index]; + } + return PAL_SUCCESS; +} + + +palStatus_t pal_getSockAddrIPV4Addr(const palSocketAddress_t* address, palIpV4Addr_t ipV4Addr) +{ + palStatus_t result = PAL_SUCCESS; + if (NULL == address) + { + return PAL_ERR_INVALID_ARGUMENT; + } + if (address->addressType == PAL_AF_INET) + { + pal_socketAddressInternal_t* innerAddr = (pal_socketAddressInternal_t*)address; + ipV4Addr[0] = (innerAddr->pal_sin_addr.s_addr) & 0xFF; + ipV4Addr[1] = (innerAddr->pal_sin_addr.s_addr >> 8) & 0xFF; + ipV4Addr[2] = (innerAddr->pal_sin_addr.s_addr >> 16) & 0xFF; + ipV4Addr[3] = (innerAddr->pal_sin_addr.s_addr >> 24) & 0xFF; + + } + else + { + result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY; + } + return result; +} + + +palStatus_t pal_getSockAddrIPV6Addr(const palSocketAddress_t* address, palIpV6Addr_t ipV6Addr) +{ + palStatus_t result = PAL_SUCCESS; + int index = 0; + if (address->addressType == PAL_AF_INET6) + { + pal_socketAddressInternal6_t * innerAddr = (pal_socketAddressInternal6_t*)address; + for (index = 0; index < PAL_IPV6_ADDRESS_SIZE; index++) // TODO: use mem copy? + { + ipV6Addr[index] = innerAddr->pal_sin6_addr[index]; + } + } + else + { + result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY; + } + return result; +} + + +palStatus_t pal_getSockAddrPort(const palSocketAddress_t* address, uint16_t* port) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == address) || (NULL == port)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (address->addressType == PAL_AF_INET) + { + pal_socketAddressInternal_t* innerAddr = (pal_socketAddressInternal_t*)address; + // Set numeric formal + *port = PAL_NTOHS(innerAddr->pal_sin_port); + } + else if (address->addressType == PAL_AF_INET6) + { + pal_socketAddressInternal6_t * innerAddr = (pal_socketAddressInternal6_t*)address; + // Set numeric formal + *port = PAL_NTOHS(innerAddr->pal_sin6_port); + } + else + { + result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY; + } + + return result; +} + + +palStatus_t pal_socket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palSocket_t* socket) +{ + palStatus_t result = PAL_SUCCESS; + if (NULL == socket) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_socket(domain, type, nonBlockingSocket, interfaceNum, socket); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_getSocketOptions(palSocket_t socket, palSocketOptionName_t optionName, void* optionValue, palSocketLength_t* optionLength) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == optionValue) || (NULL == optionLength)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_getSocketOptions(socket, optionName, optionValue, optionLength); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_setSocketOptions(palSocket_t socket, int optionName, const void* optionValue, palSocketLength_t optionLength) +{ + palStatus_t result = PAL_SUCCESS; + if (NULL == optionValue) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_setSocketOptions( socket, optionName, optionValue, optionLength); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + +palStatus_t pal_isNonBlocking(palSocket_t socket, bool* isNonBlocking) +{ + palStatus_t result = PAL_SUCCESS; + if (NULL == isNonBlocking) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_isNonBlocking(socket, isNonBlocking); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_bind(palSocket_t socket, palSocketAddress_t* myAddress, palSocketLength_t addressLength) +{ + palStatus_t result = PAL_SUCCESS; + if (NULL == myAddress) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_bind(socket, myAddress, addressLength); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_receiveFrom(palSocket_t socket, void* buffer, size_t length, palSocketAddress_t* from, palSocketLength_t* fromLength, size_t* bytesReceived) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == buffer) || (NULL == bytesReceived)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_receiveFrom(socket, buffer, length, from, fromLength, bytesReceived); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_sendTo(palSocket_t socket, const void* buffer, size_t length, const palSocketAddress_t* to, palSocketLength_t toLength, size_t* bytesSent) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == buffer) || (NULL == bytesSent) || (NULL == to)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_sendTo(socket, buffer, length, to, toLength, bytesSent); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_close(palSocket_t* socket) +{ + palStatus_t result = PAL_SUCCESS; + if (NULL == socket ) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_close(socket); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_getNumberOfNetInterfaces( uint32_t* numInterfaces) +{ + palStatus_t result = PAL_SUCCESS; + if (NULL == numInterfaces) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_getNumberOfNetInterfaces(numInterfaces); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_getNetInterfaceInfo(uint32_t interfaceNum, palNetInterfaceInfo_t * interfaceInfo) +{ + palStatus_t result = PAL_SUCCESS; + + if (NULL == interfaceInfo) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_getNetInterfaceInfo(interfaceNum, interfaceInfo); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_socketMiniSelect(const palSocket_t socketsToCheck[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t numberOfSockets, + pal_timeVal_t* timeout, uint8_t palSocketStatus[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t * numberOfSocketsSet) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == socketsToCheck) || (NULL == numberOfSocketsSet) || (PAL_NET_SOCKET_SELECT_MAX_SOCKETS < numberOfSockets)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_socketMiniSelect(socketsToCheck, numberOfSockets, timeout, palSocketStatus, numberOfSocketsSet); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +#if PAL_NET_TCP_AND_TLS_SUPPORT // functionality below supported only in case TCP is supported. + +palStatus_t pal_listen(palSocket_t socket, int backlog) +{ + palStatus_t result = PAL_SUCCESS; + result = pal_plat_listen(socket, backlog); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_accept(palSocket_t socket, palSocketAddress_t* address, palSocketLength_t* addressLen, palSocket_t* acceptedSocket) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == acceptedSocket) || (NULL == address)|| (NULL == addressLen)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_accept(socket, address, addressLen, acceptedSocket); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_connect(palSocket_t socket, const palSocketAddress_t* address, palSocketLength_t addressLen) +{ + palStatus_t result = PAL_SUCCESS; + if (NULL == address) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_connect( socket, address, addressLen); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_recv(palSocket_t socket, void* buf, size_t len, size_t* recievedDataSize) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == recievedDataSize) || (NULL == buf)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_recv(socket, buf, len, recievedDataSize); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_send(palSocket_t socket, const void* buf, size_t len, size_t* sentDataSize) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == buf) || (NULL == sentDataSize)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_send( socket, buf, len, sentDataSize); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + +palStatus_t pal_asynchronousSocket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t callback, palSocket_t* socket) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == socket) || (NULL == callback)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_asynchronousSocket(domain, type, nonBlockingSocket, interfaceNum, callback, NULL, socket); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + +palStatus_t pal_asynchronousSocketWithArgument(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t callback, void* callbackArgument, palSocket_t* socket) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == socket) || (NULL == callback)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_asynchronousSocket(domain, type, nonBlockingSocket, interfaceNum, callback, callbackArgument, socket); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + +#endif + +#if PAL_NET_DNS_SUPPORT + +palStatus_t pal_getAddressInfo(const char *url, palSocketAddress_t *address, palSocketLength_t* addressLength) +{ + palStatus_t result = PAL_SUCCESS; + if ((NULL == url) || (NULL == address) || (NULL == addressLength)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + result = pal_plat_getAddressInfo(url, address, addressLength); + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + +#endif + + + + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/RTOS/pal_rtos.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/RTOS/pal_rtos.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,558 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#include "pal_rtos.h" +#include "pal_plat_rtos.h" +#include "pal_Crypto.h" + + +#if PAL_UNIQUE_THREAD_PRIORITY +//! Threads priorities array. +uint32_t g_palThreadPriorities[PAL_NUMBER_OF_THREADS_PRIORITIES] = {0}; +#endif //PAL_UNIQUE_THREAD_PRIORITY + +palMutexID_t g_palThreadInitMutex = NULLPTR; + +//! static variables for Random functionality. +//! CTR-DRBG context to be used for generating random numbers from given seed +static palCtrDrbgCtxHandle_t s_ctrDRBGCtx = NULLPTR; + + +static uint64_t g_palDeviceBootTimeInSec = 0; + +/* + * Here we define const keys for RoT derivation algorithm. + * Must be 16 characters or less + */ +#define PAL_STORAGE_SIGNATURE_128_BIT_KEY "RoTStorageSgn128" +#define PAL_STORAGE_ENCRYPTION_128_BIT_KEY "RoTStorageEnc128" +#define PAL_STORAGE_ENCRYPTION_256_BIT_KEY "StorageEnc256HMACSHA256SIGNATURE" + +static bool palRTOSInitialized = false; + +palStatus_t pal_RTOSInitialize(void* opaqueContext) +{ + palStatus_t status = PAL_SUCCESS; + + if (palRTOSInitialized) + { + return PAL_SUCCESS; + } + memset(g_palThreadPriorities, 0, sizeof(g_palThreadPriorities)); + status = pal_osMutexCreate(&g_palThreadInitMutex); + if(PAL_SUCCESS == status) + { + status = pal_plat_RTOSInitialize(opaqueContext); + if(PAL_SUCCESS == status) + { + palRTOSInitialized = true; + } + } + + return status; +} + +palStatus_t pal_RTOSDestroy(void) +{ + palStatus_t status = PAL_SUCCESS; + int i = 0; + + if(palRTOSInitialized == true) + { + for (i = 0; i < PAL_MAX_NUMBER_OF_THREADS; ++i) + { + palThreadID_t tempID = i; + pal_osThreadTerminate(&tempID); + } + palRTOSInitialized = false; + + status = pal_osMutexDelete(&g_palThreadInitMutex); + if ((NULLPTR != s_ctrDRBGCtx) && (PAL_SUCCESS == status)) + { + status = pal_CtrDRBGFree(&s_ctrDRBGCtx); + } + if (PAL_SUCCESS == status) + { + status = pal_plat_RTOSDestroy(); + } + + } + else + { + status = PAL_ERR_NOT_INITIALIZED; + } + return status; +} + +void pal_osReboot(void) +{ + pal_plat_osReboot(); +} + +uint64_t pal_osKernelSysTick(void) +{ + static uint64_t lastValue = 0; + static uint64_t wraparoundsDetected = 0; + const uint64_t one = 1; + uint64_t tics = pal_plat_osKernelSysTick(); + uint64_t tmp = tics + (wraparoundsDetected << 32); + + if (tmp < lastValue) //erez's "wraparound algorithm" if we detect a wrap around add 1 to the higher 32 bits + { + tmp = tmp + (one << 32); + wraparoundsDetected++; + } + lastValue = tmp; + return (uint64_t)tmp; +} + + +uint64_t pal_osKernelSysTickMicroSec(uint64_t microseconds) +{ + uint64_t result; + result = pal_plat_osKernelSysTickMicroSec(microseconds); + return result; +} + +uint64_t pal_osKernelSysMilliSecTick(uint64_t sysTicks) +{ + uint64_t result = 0; + uint64_t osTickFreq = pal_plat_osKernelSysTickFrequency(); + if ((sysTicks) && (osTickFreq)) // > 0 + { + result = (uint64_t)((sysTicks) / osTickFreq * PAL_TICK_TO_MILLI_FACTOR); //convert ticks per second to milliseconds + } + + return result; +} + +uint64_t pal_osKernelSysTickFrequency(void) +{ + uint64_t result; + result = pal_plat_osKernelSysTickFrequency(); + return result; +} + +palStatus_t pal_osThreadCreate(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, uint32_t* stackPtr, palThreadLocalStore_t* store, palThreadID_t* threadID) +{ + palStatus_t status = PAL_SUCCESS; + //! check if the priority have been used by other thread before + if(PAL_osPriorityError == priority) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + +#if PAL_UNIQUE_THREAD_PRIORITY + uint32_t incrementedPriorityNum = pal_osAtomicIncrement((int32_t*)&(g_palThreadPriorities[priority+PRIORITY_INDEX_OFFSET]),1); + // if incrementedPriorityNum != 1 the cell is already occupied by other thread with the same priority. + if (incrementedPriorityNum != 1) + { + *threadID = NULLPTR; + status = PAL_ERR_RTOS_PRIORITY; + } +#endif //PAL_IGNORE_UNIQUE_THREAD_PRIORITY + + if (PAL_SUCCESS == status) + { + status = pal_plat_osThreadCreate(function, funcArgument, priority, stackSize, NULL, store, threadID); + #if PAL_UNIQUE_THREAD_PRIORITY + if (PAL_SUCCESS != status) + { + g_palThreadPriorities[priority+PRIORITY_INDEX_OFFSET]= 0 ; + } + #endif //PAL_IGNORE_UNIQUE_THREAD_PRIORITY + } + + return status; +} + +palStatus_t pal_osThreadCreateWithAlloc(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, palThreadLocalStore_t* store, palThreadID_t* threadID) +{ + palStatus_t status = PAL_SUCCESS; + + //! check if the priority have been used by other thread before + if(PAL_osPriorityError == priority) + { + return PAL_ERR_INVALID_ARGUMENT; + } + +#if PAL_UNIQUE_THREAD_PRIORITY + uint32_t incrementedPriorityNum = pal_osAtomicIncrement((int32_t*)&(g_palThreadPriorities[priority+PRIORITY_INDEX_OFFSET]),1); + // if incrementedPriorityNum != 1 the cell is already occupied by other thread with the same priority. + if (incrementedPriorityNum != 1) + { + *threadID = NULLPTR; + status = PAL_ERR_RTOS_PRIORITY; + } +#endif //PAL_IGNORE_UNIQUE_THREAD_PRIORITY + + if (PAL_SUCCESS == status) + { + status = pal_plat_osThreadCreate(function, funcArgument, priority, stackSize, NULL, store, threadID); + #if PAL_UNIQUE_THREAD_PRIORITY + if (PAL_SUCCESS != status) + { + g_palThreadPriorities[priority+PRIORITY_INDEX_OFFSET]= 0 ; + } + #endif //PAL_IGNORE_UNIQUE_THREAD_PRIORITY + } + + return status; +} + + +palStatus_t pal_osThreadTerminate(palThreadID_t* threadID) +{ + palStatus_t status; + if ((NULL == threadID) || (PAL_INVALID_THREAD == *threadID)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + status = pal_plat_osThreadTerminate(threadID); + return status; +} + +palThreadID_t pal_osThreadGetId(void) +{ + palThreadID_t result; + result = pal_plat_osThreadGetId(); + return result; +} + +palThreadLocalStore_t* pal_osThreadGetLocalStore(void) +{ + void* result; + result = pal_plat_osThreadGetLocalStore(); + return result; +} + +palStatus_t pal_osDelay(uint32_t milliseconds) +{ + palStatus_t status; + status = pal_plat_osDelay(milliseconds); + return status; +} + + +palStatus_t pal_osTimerCreate(palTimerFuncPtr function, void* funcArgument, palTimerType_t timerType, palTimerID_t* timerID) +{ + palStatus_t status; + status = pal_plat_osTimerCreate(function, funcArgument, timerType, timerID); + return status; +} + +palStatus_t pal_osTimerStart(palTimerID_t timerID, uint32_t millisec) +{ + palStatus_t status; + if (0 == millisec) + { + return PAL_ERR_RTOS_VALUE; + } + status = pal_plat_osTimerStart(timerID, millisec); + return status; +} + +palStatus_t pal_osTimerStop(palTimerID_t timerID) +{ + palStatus_t status; + status = pal_plat_osTimerStop(timerID); + return status; +} + +palStatus_t pal_osTimerDelete(palTimerID_t* timerID) +{ + palStatus_t status; + status = pal_plat_osTimerDelete(timerID); + return status; +} + +palStatus_t pal_osMutexCreate(palMutexID_t* mutexID) +{ + palStatus_t status; + status = pal_plat_osMutexCreate(mutexID); + return status; +} + +palStatus_t pal_osMutexWait(palMutexID_t mutexID, uint32_t millisec) +{ + palStatus_t status; + status = pal_plat_osMutexWait(mutexID, millisec); + return status; +} + +palStatus_t pal_osMutexRelease(palMutexID_t mutexID) +{ + palStatus_t status; + status = pal_plat_osMutexRelease(mutexID); + return status; +} + +palStatus_t pal_osMutexDelete(palMutexID_t* mutexID) +{ + palStatus_t status; + status = pal_plat_osMutexDelete(mutexID); + return status; +} +palStatus_t pal_osSemaphoreCreate(uint32_t count, palSemaphoreID_t* semaphoreID) +{ + palStatus_t status; + status = pal_plat_osSemaphoreCreate(count, semaphoreID); + return status; +} + +palStatus_t pal_osSemaphoreWait(palSemaphoreID_t semaphoreID, uint32_t millisec, int32_t* countersAvailable) +{ + palStatus_t status; + status = pal_plat_osSemaphoreWait(semaphoreID, millisec, countersAvailable); + return status; +} + +palStatus_t pal_osSemaphoreRelease(palSemaphoreID_t semaphoreID) +{ + palStatus_t status; + status = pal_plat_osSemaphoreRelease(semaphoreID); + return status; +} + +palStatus_t pal_osSemaphoreDelete(palSemaphoreID_t* semaphoreID) +{ + palStatus_t status; + status = pal_plat_osSemaphoreDelete(semaphoreID); + return status; +} + +palStatus_t pal_osPoolCreate(uint32_t blockSize, uint32_t blockCount, palMemoryPoolID_t* memoryPoolID) +{ + palStatus_t status; + status = pal_plat_osPoolCreate(blockSize, blockCount, memoryPoolID); + return status; +} + +void* pal_osPoolAlloc(palMemoryPoolID_t memoryPoolID) +{ + void* result; + result = pal_plat_osPoolAlloc(memoryPoolID); + return result; +} + +void* pal_osPoolCAlloc(palMemoryPoolID_t memoryPoolID) +{ + void* result; + //TODO(nirson01): debug print in case of failed alloc? + result = pal_plat_osPoolCAlloc(memoryPoolID); + return result; +} + +palStatus_t pal_osPoolFree(palMemoryPoolID_t memoryPoolID, void* block) +{ + palStatus_t status; + //TODO(nirson01): debug print in case of failed alloc? + status = pal_plat_osPoolFree(memoryPoolID, block); + return status; +} + +palStatus_t pal_osPoolDestroy(palMemoryPoolID_t* memoryPoolID) +{ + palStatus_t status; + status = pal_plat_osPoolDestroy(memoryPoolID); + return status; +} + +palStatus_t pal_osMessageQueueCreate(uint32_t messageQCount, palMessageQID_t* messageQID) +{ + palStatus_t status; + status = pal_plat_osMessageQueueCreate(messageQCount, messageQID); + return status; +} + +palStatus_t pal_osMessagePut(palMessageQID_t messageQID, uint32_t info, uint32_t timeout) +{ + palStatus_t status; + status = pal_plat_osMessagePut(messageQID, info, timeout); + return status; +} + +palStatus_t pal_osMessageGet(palMessageQID_t messageQID, uint32_t timeout, uint32_t* messageValue) +{ + palStatus_t status; + status = pal_plat_osMessageGet(messageQID, timeout, messageValue); + return status; +} + +palStatus_t pal_osMessageQueueDestroy(palMessageQID_t* messageQID) +{ + palStatus_t status; + status = pal_plat_osMessageQueueDestroy(messageQID); + return status; +} + +int32_t pal_osAtomicIncrement(int32_t* valuePtr, int32_t increment) +{ + int32_t result; + result = pal_plat_osAtomicIncrement(valuePtr, increment); + return result; +} + +inline PAL_PRIVATE uint64_t pal_sysTickTimeToSec() +{ + uint64_t sysTicksFromBoot = pal_osKernelSysTick(); + uint64_t secFromBoot = pal_osKernelSysMilliSecTick(sysTicksFromBoot) / PAL_MILLI_PER_SECOND; + + return secFromBoot; +} + +uint64_t pal_osGetTime(void) +{ + uint64_t curSysTimeInSec = 0; + if (0 < g_palDeviceBootTimeInSec) //time was previously set + { + uint64_t secFromBoot = pal_sysTickTimeToSec(); + curSysTimeInSec = g_palDeviceBootTimeInSec + secFromBoot; //boot time in sec + sec passed since boot + } + + return curSysTimeInSec; +} + +palStatus_t pal_osSetTime(uint64_t seconds) +{ + palStatus_t status = PAL_SUCCESS; + if (seconds < (uint64_t)PAL_MIN_SEC_FROM_EPOCH) + { + status = PAL_ERR_INVALID_TIME; + } + else + { + uint64_t secFromBoot = pal_sysTickTimeToSec(); + g_palDeviceBootTimeInSec = seconds - secFromBoot; //update device boot time + } + + return status; +} + +palStatus_t pal_osRandom32bit(uint32_t *random) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == random) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_osRandomBuffer((uint8_t*)random, sizeof(uint32_t)); + return status; +} + +palStatus_t pal_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == randomBuf) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (NULLPTR == s_ctrDRBGCtx) + { + uint8_t seed[PAL_INITIAL_RANDOM_SIZE] = {0}; //in order to get 128-bits initial seed + status = pal_plat_osRandomBuffer(seed, sizeof(seed)); + if (PAL_SUCCESS != status) + { + goto finish; + } + status = pal_CtrDRBGInit(&s_ctrDRBGCtx, (void*)seed, sizeof(seed)); + if (PAL_SUCCESS != status) + { + goto finish; + } + } + + status = pal_CtrDRBGGenerate(s_ctrDRBGCtx, (unsigned char*)randomBuf, bufSizeBytes); + +finish: + return status; +} + +//As mentioned in the header file, this function ignores the upperBound parameter +//in this stage, in the future it will be supported. (Erez) +palStatus_t pal_osRandomUniform(uint32_t upperBound, uint32_t *random) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULL == random) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_osRandomBuffer((uint8_t*)random, sizeof(uint32_t)); + //*random = random % upperBound; + return status; +} + +palStatus_t pal_osGetDeviceKey(palDevKeyType_t keyType, uint8_t *key, size_t keyLenBytes) +{ + palStatus_t status = PAL_SUCCESS; + unsigned char rot[PAL_DEVICE_KEY_SIZE_IN_BYTES] = {0}; + + if ((keyLenBytes < PAL_DEVICE_KEY_SIZE_IN_BYTES) || ((palOsStorageHmacSha256 == keyType) && (keyLenBytes < PAL_SHA256_DEVICE_KEY_SIZE_IN_BYTES))) + { + return PAL_ERR_BUFFER_TOO_SMALL; + } + if (NULL == key) + { + return PAL_ERR_NULL_POINTER; + } + + status = pal_plat_osGetRoT128Bit(rot, PAL_DEVICE_KEY_SIZE_IN_BYTES); + if (PAL_SUCCESS == status) + { // Logic of RoT according to key type using 128 bit strong Key Derivation Algorithm + switch(keyType) + { + case palOsStorageEncryptionKey128Bit: + { + //USE strong KDF here! + status = pal_cipherCMAC((const unsigned char*)PAL_STORAGE_ENCRYPTION_128_BIT_KEY, PAL_DEVICE_KEY_SIZE_IN_BITS, (const unsigned char *)rot, PAL_DEVICE_KEY_SIZE_IN_BYTES, key); + break; + } + case palOsStorageSignatureKey128Bit: + { + //USE strong KDF here! + status = pal_cipherCMAC((const unsigned char*)PAL_STORAGE_SIGNATURE_128_BIT_KEY, PAL_DEVICE_KEY_SIZE_IN_BITS, (const unsigned char *)rot, PAL_DEVICE_KEY_SIZE_IN_BYTES, key); + break; + } + case palOsStorageHmacSha256: + { + size_t outputLenInBytes = 0; + status = pal_mdHmacSha256((const unsigned char *)PAL_STORAGE_ENCRYPTION_256_BIT_KEY, PAL_SHA256_DEVICE_KEY_SIZE_IN_BYTES, (const unsigned char*)rot, PAL_DEVICE_KEY_SIZE_IN_BYTES, key, &outputLenInBytes); + break; + } + default: + status = PAL_ERR_GET_DEV_KEY; + + } + + } // outer if + else + { + status = PAL_ERR_GET_DEV_KEY; + } + memset(rot, 0, PAL_DEVICE_KEY_SIZE_IN_BYTES); + + return status; + +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Storage/FileSystem/pal_fileSystem.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Storage/FileSystem/pal_fileSystem.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,366 @@ +/* + * 2.c + * + * Created on: 22 Jan 2017 + * Author: alonof01 + */ + +#include "pal.h" +#include "pal_fileSystem.h" +#include "pal_plat_fileSystem.h" + +PAL_PRIVATE char* g_RootFolder[PAL_FS_PARTITION_LAST] = { NULL , NULL }; //!< global var that holds the root folder +PAL_PRIVATE bool g_RootFolderIsSet[PAL_FS_PARTITION_LAST] = { false, false }; //!< global var that holds the state root folder + + +void pal_fsCleanup() +{ + if (NULL != g_RootFolder[PAL_FS_PARTITION_PRIMARY]) + { + free(g_RootFolder[PAL_FS_PARTITION_PRIMARY]); + g_RootFolder[PAL_FS_PARTITION_PRIMARY] = NULL; + } + + if (NULL != g_RootFolder[PAL_FS_PARTITION_SECONDARY]) + { + free(g_RootFolder[PAL_FS_PARTITION_SECONDARY]); + g_RootFolder[PAL_FS_PARTITION_SECONDARY] = NULL; + } + + g_RootFolder[PAL_FS_PARTITION_SECONDARY] = NULL; + g_RootFolderIsSet[PAL_FS_PARTITION_PRIMARY] = false; + g_RootFolderIsSet[PAL_FS_PARTITION_SECONDARY] = false; +} + + + +palStatus_t pal_fsMkDir(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + if (pathName == NULL) + { + ret = PAL_ERR_FS_INVALID_FILE_NAME; + } + else if (pal_plat_fsSizeCheck(pathName) >= PAL_MAX_FOLDER_DEPTH_CHAR) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else + { + ret = pal_plat_fsMkdir(pathName); + if ((PAL_SUCCESS != ret) && (PAL_ERR_FS_NAME_ALREADY_EXIST != ret)) + { + PAL_LOG(ERR, "Failed to create folder, was the storage properly initialized?"); + } + } + return ret; +} + + + +palStatus_t pal_fsRmDir(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + if (pathName == NULL) + { + ret = PAL_ERR_FS_INVALID_FILE_NAME; + } + else if (pal_plat_fsSizeCheck(pathName) >= PAL_MAX_FOLDER_DEPTH_CHAR) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else + { + ret = pal_plat_fsRmdir(pathName); + } + return ret; +} + +palStatus_t pal_fsFopen(const char *pathName, pal_fsFileMode_t mode, palFileDescriptor_t *fd) +{ + palStatus_t ret = PAL_SUCCESS; + if (fd == NULL) + { + return PAL_ERR_FS_INVALID_ARGUMENT; + } + if (pathName == NULL) + { + ret = PAL_ERR_FS_INVALID_FILE_NAME; + } + else if (pal_plat_fsSizeCheck(pathName) >= PAL_MAX_FULL_FILE_NAME) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else if (!((mode > PAL_FS_FLAG_KEEP_FIRST) && (mode < PAL_FS_FLAG_KEEP_LAST))) + { + ret = PAL_ERR_FS_INVALID_OPEN_FLAGS; + } + else + { + ret = pal_plat_fsFopen(pathName, mode, fd); + } + if (ret != PAL_SUCCESS) + { + PAL_LOG(ERR, "Failed to open/create file, was the storage properly initialized?"); + *fd = 0; + } + return ret; +} + + +palStatus_t pal_fsFclose(palFileDescriptor_t *fd) +{ + palStatus_t ret = PAL_SUCCESS; + if (fd == NULL) + { + return PAL_ERR_FS_INVALID_ARGUMENT; + } + if (*fd == 0) + { + ret = PAL_ERR_FS_BAD_FD; + } + else + { + ret = pal_plat_fsFclose(fd); + *fd = 0; + } + return ret; +} + + +palStatus_t pal_fsFread(palFileDescriptor_t *fd, void * buffer, size_t numOfBytes, size_t *numberOfBytesRead) +{ + palStatus_t ret = PAL_SUCCESS; + *numberOfBytesRead = 0; + if (*fd == 0) + { + ret = PAL_ERR_FS_BAD_FD; + } + + else if (buffer == NULL) + { + ret = PAL_ERR_FS_BUFFER_ERROR; + } + else + { + ret = pal_plat_fsFread(fd, buffer, numOfBytes, numberOfBytesRead); + } + return ret; +} + + +palStatus_t pal_fsFwrite(palFileDescriptor_t *fd, const void * buffer, size_t numOfBytes, size_t *numberOfBytesWritten) +{ + palStatus_t ret = PAL_SUCCESS; + *numberOfBytesWritten = 0; + if (*fd == 0) + { + ret = PAL_ERR_FS_BAD_FD; + } + else if (numOfBytes == 0) + { + ret = PAL_ERR_FS_LENGTH_ERROR; + } + else if (buffer == NULL) + { + ret = PAL_ERR_FS_BUFFER_ERROR; + } + else + { + ret = pal_plat_fsFwrite(fd, buffer, numOfBytes, numberOfBytesWritten); + } + return ret; +} + + +palStatus_t pal_fsFseek(palFileDescriptor_t *fd, int32_t offset, pal_fsOffset_t whence) +{ + palStatus_t ret = PAL_SUCCESS; + if (*fd == 0) + { + ret = PAL_ERR_FS_BAD_FD; + } + else if (!((whence < PAL_FS_OFFSET_KEEP_LAST) && (whence > PAL_FS_OFFSET_KEEP_FIRST))) + { + ret = PAL_ERR_FS_OFFSET_ERROR; + } + else + { + ret = pal_plat_fsFseek(fd, offset, whence); + } + return ret; +} + + +palStatus_t pal_fsFtell(palFileDescriptor_t *fd, int32_t *pos) +{ + palStatus_t ret = PAL_SUCCESS; + if (*fd == 0) + { + ret = PAL_ERR_FS_BAD_FD; + } + else + { + ret = pal_plat_fsFtell(fd, pos); + } + return ret; +} + +palStatus_t pal_fsUnlink(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + if (pathName == NULL) + { + ret = PAL_ERR_FS_INVALID_FILE_NAME; + } + else if (pal_plat_fsSizeCheck(pathName) >= PAL_MAX_FULL_FILE_NAME) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else + { + ret = pal_plat_fsUnlink(pathName); + } + return ret; +} + + + +palStatus_t pal_fsRmFiles(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + if (pathName == NULL) + { + ret = PAL_ERR_FS_INVALID_FILE_NAME; + } + else if (pal_plat_fsSizeCheck(pathName) >= PAL_MAX_FOLDER_DEPTH_CHAR) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else + { + ret = pal_plat_fsRmFiles(pathName); + } + return ret; +} + + +palStatus_t pal_fsCpFolder(const char *pathNameSrc, char *pathNameDest) +{ + palStatus_t ret = PAL_SUCCESS; + if ((pathNameSrc == NULL) || ((pathNameDest == NULL))) + { + ret = PAL_ERR_FS_INVALID_FILE_NAME; + } + else if ((pal_plat_fsSizeCheck(pathNameSrc) >= PAL_MAX_FOLDER_DEPTH_CHAR) || (pal_plat_fsSizeCheck(pathNameDest) >= PAL_MAX_FOLDER_DEPTH_CHAR)) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else + { + ret = pal_plat_fsCpFolder(pathNameSrc, pathNameDest); + } + return ret; +} + + + +palStatus_t pal_fsSetMountPoint(pal_fsStorageID_t dataID, const char *path) +{ + palStatus_t ret = PAL_SUCCESS; + if ((dataID >= PAL_FS_PARTITION_LAST) || (NULL == path)) + { + ret = PAL_ERR_FS_INVALID_FILE_NAME; + } + else if (pal_plat_fsSizeCheck(path) >= PAL_MAX_FOLDER_DEPTH_CHAR) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else + { + if (g_RootFolderIsSet[dataID]) + { + ret = PAL_ERR_FS_ERROR; + } + else + { + if (NULL == g_RootFolder[dataID]) + { + g_RootFolder[dataID] = (char*)malloc(PAL_MAX_FOLDER_DEPTH_CHAR); + if (NULL == g_RootFolder[dataID]) + { + return PAL_ERR_NO_MEMORY; + } + g_RootFolder[dataID][0] = NULLPTR; + } + strncat( g_RootFolder[dataID], path, PAL_MAX_FOLDER_DEPTH_CHAR - pal_plat_fsSizeCheck(g_RootFolder[dataID]));// same buffer is used for active backup root dirs using indexing + g_RootFolderIsSet[dataID] = true; + } + } + return ret; +} + +palStatus_t pal_fsGetMountPoint(pal_fsStorageID_t dataID, size_t length, char *path) +{ + palStatus_t ret = PAL_SUCCESS; + + if (dataID >= PAL_FS_PARTITION_LAST) + { + return PAL_ERR_INVALID_ARGUMENT; + } + if (length < PAL_MAX_FOLDER_DEPTH_CHAR) + { + return PAL_ERR_FS_LENGTH_ERROR; + } + + if (path) + { + if (false == g_RootFolderIsSet[dataID]) + { + strncpy(path, pal_plat_fsGetDefaultRootFolder(dataID), length); + } + else + { + strncpy(path, g_RootFolder[dataID], length); // same buffer is used for active backup root dirs using indexing + } + + } + else + { + ret = PAL_ERR_FS_BUFFER_ERROR; + } + return ret; +} + + +palStatus_t pal_fsFormat(pal_fsStorageID_t dataID) +{ + palStatus_t ret = PAL_SUCCESS; + int32_t opCode = (int32_t)dataID; + if ((opCode < PAL_FS_PARTITION_PRIMARY) || (opCode >= PAL_FS_PARTITION_LAST)) + { + ret = PAL_ERR_INVALID_ARGUMENT; + } + else + { + ret = pal_plat_fsFormat(dataID); + } + return ret; +} + + + + +bool pal_fsIsPrivatePartition(pal_fsStorageID_t dataID) +{ + bool isPrivate; + if (PAL_FS_PARTITION_PRIMARY == dataID) + { + isPrivate = PAL_PRIMARY_PARTITION_PRIVATE; + } + else + { + isPrivate = PAL_SECONDARY_PARTITION_PRIVATE; + } + return isPrivate; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Storage/Flash/pal_internalFlash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Storage/Flash/pal_internalFlash.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pal.h" +#include "pal_plat_internalFlash.h" + +#define BITS_ALIGNED_TO_32 0x3 +#define PAL_MAX_PAGE_SIZE 16 + +PAL_PRIVATE palMutexID_t g_flashMutex = NULLPTR; + + +size_t pal_internalFlashGetPageSize(void) +{ + size_t ret = pal_plat_internalFlashGetPageSize(); + if(ret > PAL_MAX_PAGE_SIZE) + { + ret = PAL_MAX_PAGE_SIZE; + } + return ret; +} + +size_t pal_internalFlashGetSectorSize(uint32_t address) +{ + size_t ret = pal_plat_internalFlashGetSectorSize(address); + return ret; +} + + +palStatus_t pal_internalFlashInit(void) +{ + palStatus_t ret = PAL_SUCCESS; + if(NULLPTR == g_flashMutex) + { + ret = pal_osMutexCreate(&g_flashMutex); + } + + if(PAL_SUCCESS == ret) + { + ret = pal_plat_internalFlashInit(); + } + return ret; +} + +palStatus_t pal_internalFlashDeInit(void) +{ + palStatus_t ret = PAL_SUCCESS; + if(NULLPTR != g_flashMutex) + { + ret = pal_osMutexDelete(&g_flashMutex); + g_flashMutex = NULLPTR; + } + + if(PAL_SUCCESS == ret) + { + ret = pal_plat_internalFlashDeInit(); + } + return ret; +} + +palStatus_t pal_internalFlashWrite(const size_t size, const uint32_t address, const uint32_t * buffer) +{ + palStatus_t ret = PAL_SUCCESS; + uint32_t pageSize = 0, sectorSize = 0, alignmentLeft = 0; + + if (buffer == NULL) + { + return PAL_ERR_INTERNAL_FLASH_NULL_PTR_RECEIVED; + } + else if (address & BITS_ALIGNED_TO_32) + { + return PAL_ERR_INTERNAL_FLASH_BUFFER_ADDRESS_NOT_ALIGNED; + } + else if (size == 0) + { + return PAL_ERR_INTERNAL_FLASH_WRONG_SIZE; + } + + pageSize = pal_internalFlashGetPageSize(); + sectorSize = pal_internalFlashGetSectorSize(address); + if ((0 == pageSize) || (sectorSize == 0)) + { + return PAL_ERR_INTERNAL_FLASH_FLASH_ZERO_SIZE; + } + + if (address % pageSize) + { + ret = PAL_ERR_INTERNAL_FLASH_ADDRESS_NOT_ALIGNED; + } + else if (((address % sectorSize) + size) > sectorSize) + { + ret = PAL_ERR_INTERNAL_FLASH_CROSSING_SECTORS; + } + else + { + palStatus_t mutexRet = PAL_SUCCESS; + ret = pal_osMutexWait(g_flashMutex, PAL_RTOS_WAIT_FOREVER); + if (ret == PAL_SUCCESS) + { + alignmentLeft = size % pageSize; //Keep the leftover to be copied separately + if (size > pageSize) + { + ret = pal_plat_internalFlashWrite(size - alignmentLeft, address, buffer); + } + + if ((ret == PAL_SUCCESS) && (alignmentLeft != 0)) + { + uint32_t * pageBuffer = (uint32_t *)malloc(pageSize); + if (pageBuffer == NULL) + { + ret = PAL_ERR_NO_MEMORY; + } + else + { + memset(pageBuffer, 0xFF, pageSize); + memcpy(pageBuffer, (uint8_t*)buffer + (size - alignmentLeft), alignmentLeft); + ret = pal_plat_internalFlashWrite(pageSize, address + (size - alignmentLeft), pageBuffer); + free(pageBuffer); + } + } + mutexRet = pal_osMutexRelease(g_flashMutex); + if(PAL_SUCCESS != mutexRet) + { + ret = PAL_ERR_INTERNAL_FLASH_MUTEX_RELEASE_ERROR; + } + } + } + return ret; +} + +palStatus_t pal_internalFlashRead(const size_t size, const uint32_t address, uint32_t * buffer) +{ + palStatus_t ret = PAL_SUCCESS; + + if (buffer == NULL) + { + return PAL_ERR_INTERNAL_FLASH_NULL_PTR_RECEIVED; + } + + if (size == 0) + { + return PAL_ERR_INTERNAL_FLASH_WRONG_SIZE; + } + + ret = pal_osMutexWait(g_flashMutex, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS == ret) + { + palStatus_t mutexRet = PAL_SUCCESS; + ret = pal_plat_internalFlashRead(size, address, buffer); + mutexRet = pal_osMutexRelease(g_flashMutex); + if(PAL_SUCCESS != mutexRet) + { + ret = PAL_ERR_INTERNAL_FLASH_MUTEX_RELEASE_ERROR; + } + } + + return ret; +} + +palStatus_t pal_internalFlashErase(uint32_t address, size_t size) +{ + palStatus_t ret = PAL_SUCCESS; + if (size == 0) + { + return PAL_ERR_INTERNAL_FLASH_WRONG_SIZE; + } + + if (address & 0x3) + { + return PAL_ERR_INTERNAL_FLASH_BUFFER_ADDRESS_NOT_ALIGNED; + } + + ret = pal_osMutexWait(g_flashMutex, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS == ret) + { + palStatus_t mutexRet = PAL_SUCCESS; + ret = pal_plat_internalFlashErase(address, size); + mutexRet = pal_osMutexRelease(g_flashMutex); + if(PAL_SUCCESS != mutexRet) + { + ret = PAL_ERR_INTERNAL_FLASH_MUTEX_RELEASE_ERROR; + } + } + return ret; +} + +palStatus_t pal_internalFlashGetAreaInfo(bool section, palSotpAreaData_t *data) +{ + palStatus_t ret = PAL_SUCCESS; + const palSotpAreaData_t internalFlashArea[] = + { + {PAL_INTERNAL_FLASH_SECTION_1_ADDRESS, PAL_INTERNAL_FLASH_SECTION_1_SIZE}, + {PAL_INTERNAL_FLASH_SECTION_2_ADDRESS, PAL_INTERNAL_FLASH_SECTION_2_SIZE} + }; + + if(data == NULL) + { + ret = PAL_ERR_INTERNAL_FLASH_NULL_PTR_RECEIVED; + } + else + { + data->address = internalFlashArea[section].address; + data->size = internalFlashArea[section].size; + } + + return ret; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/TLS/pal_TLS.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/TLS/pal_TLS.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,177 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#include "pal_TLS.h" +#include "pal_plat_TLS.h" +#include "pal_configuration.h" + +palStatus_t pal_initTLS(palTLSConfHandle_t palTLSConf, palTLSHandle_t* palTLSHandle) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_initTLS(palTLSConf, palTLSHandle); + return status; +} + + +palStatus_t pal_freeTLS(palTLSHandle_t* palTLSHandle) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_freeTLS(palTLSHandle); + return status; +} + + +palStatus_t pal_initTLSConfiguration(palTLSConfHandle_t* palTLSConf, palTLSTransportMode_t transportationMode) +{ + palStatus_t status = PAL_SUCCESS; + + status = pal_plat_initTLSConf(palTLSConf, transportationMode, PAL_TLS_IS_CLIENT); + if (PAL_SUCCESS != status) + { + goto finish; + } + + status = pal_plat_setAuthenticationMode(*palTLSConf, PAL_TLS_VERIFY_REQUIRED); + if (PAL_SUCCESS != status) + { + goto finish; + } +//#define PAL_TLS_SUPPORT_ALL_AVAILABLE_SUITES 1 +#if (PAL_TLS_CIPHER_SUITE & PAL_TLS_PSK_WITH_AES_128_CBC_SHA256_SUITE) + status = pal_plat_setCipherSuites(*palTLSConf, PAL_TLS_PSK_WITH_AES_128_CBC_SHA256); +#elif (PAL_TLS_CIPHER_SUITE & PAL_TLS_PSK_WITH_AES_128_CCM_8_SUITE) + status = pal_plat_setCipherSuites(*palTLSConf, PAL_TLS_PSK_WITH_AES_128_CCM_8); +#elif (PAL_TLS_CIPHER_SUITE & PAL_TLS_PSK_WITH_AES_256_CCM_8_SUITE) + status = pal_plat_setCipherSuites(*palTLSConf, PAL_TLS_PSK_WITH_AES_256_CCM_8); +#elif (PAL_TLS_CIPHER_SUITE & PAL_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_SUITE) + status = pal_plat_setCipherSuites(*palTLSConf, PAL_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); +#elif (PAL_TLS_CIPHER_SUITE & PAL_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_SUITE) + status = pal_plat_setCipherSuites(*palTLSConf, PAL_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); +#elif (PAL_TLS_CIPHER_SUITE & PAL_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_SUITE) + status = pal_plat_setCipherSuites(*palTLSConf, PAL_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); +#elif PAL_TLS_SUPPORT_ALL_AVAILABLE_SUITES + status = PAL_SUCCESS; +#else + #error : No CipherSuite was defined! +#endif + if (PAL_SUCCESS != status) + { + goto finish; + } +finish: + return status; +} + + +palStatus_t pal_tlsConfigurationFree(palTLSConfHandle_t* palTLSConf) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_tlsConfigurationFree(palTLSConf); + return status; +} + + +palStatus_t pal_addEntropySource(palEntropySource_f entropyCallback) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_addEntropySource(entropyCallback); + return status; +} + +palStatus_t pal_setOwnCertAndPrivateKey(palTLSConfHandle_t palTLSConf, palX509_t* ownCert, palPrivateKey_t* privateKey) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_setOwnCertAndPrivateKey(palTLSConf, ownCert, privateKey); + return status; +} + + +palStatus_t pal_setCAChain(palTLSConfHandle_t palTLSConf, palX509_t* caChain, palX509CRL_t* caCRL) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_setCAChain(palTLSConf, caChain, caCRL); + return status; +} + + +palStatus_t pal_setPSK(palTLSConfHandle_t palTLSConf, const unsigned char *identity, uint32_t maxIdentityLenInBytes, const unsigned char *psk, uint32_t maxPskLenInBytes) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_setPSK(palTLSConf, identity, maxIdentityLenInBytes, psk, maxPskLenInBytes); + return status; +} + + +palStatus_t pal_tlsSetSocket(palTLSConfHandle_t palTLSConf, palTLSSocket_t* socket) +{ //palSocket_t depend on the library (socket or bio pointer) + palStatus_t status = PAL_SUCCESS; + status = pal_plat_tlsSetSocket(palTLSConf, socket); + return status; +} + + +palStatus_t pal_handShake(palTLSHandle_t palTLSHandle, palTLSConfHandle_t palTLSConf) +{ + palStatus_t status = PAL_SUCCESS; + + status = pal_plat_sslSetup(palTLSHandle, palTLSConf); + if (PAL_SUCCESS == status) + { + status = pal_plat_handShake(palTLSHandle); + } + return status; +} + + +palStatus_t pal_sslGetVerifyResult(palTLSHandle_t palTLSHandle) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_sslGetVerifyResult(palTLSHandle); + return status; +} + + +palStatus_t pal_setHandShakeTimeOut(palTLSConfHandle_t palTLSConf, uint32_t timeoutInMilliSec) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_setHandShakeTimeOut(palTLSConf, timeoutInMilliSec); + return status; +} + + +palStatus_t pal_sslRead(palTLSHandle_t palTLSHandle, void *buffer, uint32_t len, uint32_t* actualLen) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_sslRead(palTLSHandle, buffer, len, actualLen); + return status; +} + + +palStatus_t pal_sslWrite(palTLSHandle_t palTLSHandle, const void *buffer, uint32_t len, uint32_t *bytesWritten) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_sslWrite(palTLSHandle, buffer, len, bytesWritten); + return status; +} + +palStatus_t pal_sslDebugging(uint8_t turnOn) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_plat_sslDebugging(turnOn); + return status; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Update/pal_update.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Modules/Update/pal_update.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,709 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <pal.h> +#include "pal_plat_update.h" +#include "pal_update.h" +#include "pal_macros.h" + +PAL_PRIVATE uint8_t palUpdateInitFlag = 0; + +#define PAL_KILOBYTE 1024 + +#ifndef PAL_UPDATE_IMAGE_LOCATION +#error "Please definee PAL_UPDATE_IMAGE_LOCATION to UPDATE_USE_FLASH (value 1) or UPDATE_USE_FS(2)" +#endif + +#if (PAL_UPDATE_IMAGE_LOCATION == PAL_UPDATE_USE_FS) +#define SEEK_POS_INVALID 0xFFFFFFFF +PAL_PRIVATE FirmwareHeader_t pal_pi_mbed_firmware_header; +PAL_PRIVATE palImageSignalEvent_t g_palUpdateServiceCBfunc; +PAL_PRIVATE palFileDescriptor_t image_file[IMAGE_COUNT_MAX]; +PAL_PRIVATE bool last_read_nwrite[IMAGE_COUNT_MAX]; +PAL_PRIVATE uint32_t last_seek_pos[IMAGE_COUNT_MAX]; +PAL_PRIVATE bool valid_index(uint32_t index); +PAL_PRIVATE size_t safe_read(uint32_t index, size_t offset, uint8_t *buffer, uint32_t size); +PAL_PRIVATE size_t safe_write(uint32_t index, size_t offset, const uint8_t *buffer, uint32_t size); +PAL_PRIVATE bool open_if_necessary(uint32_t index, bool read_nwrite); +PAL_PRIVATE bool seek_if_necessary(uint32_t index, size_t offset, bool read_nwrite); +PAL_PRIVATE bool close_if_necessary(uint32_t index); +PAL_PRIVATE const char *image_path_alloc_from_index(uint32_t index); +PAL_PRIVATE const char *header_path_alloc_from_index(uint32_t index); +PAL_PRIVATE const char *path_join_and_alloc(const char * const * path_list); + +PAL_PRIVATE palStatus_t pal_set_fw_header(palImageId_t index, FirmwareHeader_t *headerP); +PAL_PRIVATE uint32_t internal_crc32(const uint8_t* buffer, uint32_t length); + + +char* pal_imageGetFolder(void) +{ + return PAL_UPDATE_FIRMWARE_DIR; +} + + +palStatus_t pal_imageInitAPI(palImageSignalEvent_t CBfunction) +{ + palStatus_t status = PAL_SUCCESS; + //printf("pal_imageInitAPI\r\n"); + PAL_MODULE_INIT(palUpdateInitFlag); + + // create absolute path. + + + pal_fsMkDir(PAL_UPDATE_FIRMWARE_DIR); + + g_palUpdateServiceCBfunc = CBfunction; + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_INIT); + return status; +} + +palStatus_t pal_imageDeInit(void) +{ + //printf("pal_plat_imageDeInit\r\n"); + PAL_MODULE_DEINIT(palUpdateInitFlag); + + for (int i = 0; i < IMAGE_COUNT_MAX; i++) + { + close_if_necessary(i); + } + + return PAL_SUCCESS; +} + +palStatus_t pal_imagePrepare(palImageId_t imageId, palImageHeaderDeails_t *headerDetails) +{ + //printf("pal_imagePrepare(imageId=%lu, size=%lu)\r\n", imageId, headerDetails->imageSize); + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t ret; + uint8_t *buffer; + + // write the image header to file system + memset(&pal_pi_mbed_firmware_header,0,sizeof(pal_pi_mbed_firmware_header)); + pal_pi_mbed_firmware_header.totalSize = headerDetails->imageSize; + pal_pi_mbed_firmware_header.magic = FIRMWARE_HEADER_MAGIC; + pal_pi_mbed_firmware_header.version = FIRMWARE_HEADER_VERSION; + pal_pi_mbed_firmware_header.firmwareVersion = headerDetails->version; + memcpy(pal_pi_mbed_firmware_header.firmwareSHA256,headerDetails->hash.buffer,SIZEOF_SHA256); + + pal_pi_mbed_firmware_header.checksum = internal_crc32((uint8_t *) &pal_pi_mbed_firmware_header, + sizeof(pal_pi_mbed_firmware_header)); + + ret = pal_set_fw_header(imageId, &pal_pi_mbed_firmware_header); + + /*Check that the size of the image is valid and reserve space for it*/ + + if (ret == PAL_SUCCESS) + { + buffer = malloc(PAL_KILOBYTE); + if (NULL != buffer) + { + uint32_t writeCounter = headerDetails->imageSize; + memset(buffer,0,PAL_KILOBYTE); + while(writeCounter + PAL_KILOBYTE <= headerDetails->imageSize) + { + ret = safe_write(imageId,0,buffer,PAL_KILOBYTE); + if (PAL_SUCCESS != ret) + { + break; + } + } + if ((PAL_SUCCESS == ret) && (writeCounter < headerDetails->imageSize)) + { + //writing the last bytes + ret = safe_write(imageId,0,buffer,(headerDetails->imageSize - writeCounter)); + } + free(buffer); + if (PAL_SUCCESS == ret) + { + ret = pal_fsFseek(&(image_file[imageId]),0,PAL_FS_OFFSET_SEEKSET); + } + else + { + pal_fsUnlink(image_path_alloc_from_index(imageId)); + } + } + else + { + ret = PAL_ERR_NO_MEMORY; + } + } + + if (PAL_SUCCESS == ret) + { + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_PREPARE); + } + else + { + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_ERROR); + } + + + return ret; +} + +palStatus_t pal_imageWrite(palImageId_t imageId, size_t offset, palConstBuffer_t *chunk) +{ + //printf("pal_imageWrite(imageId=%lu, offset=%lu)\r\n", imageId, offset); + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t ret = PAL_ERR_UPDATE_ERROR; + + int xfer_size_or_error = safe_write(imageId, offset, chunk->buffer, chunk->bufferLength); + if ((xfer_size_or_error < 0) || ((uint32_t)xfer_size_or_error != chunk->bufferLength)) + { + //printf("Error writing to file\r\n"); + } + else + { + ret = PAL_SUCCESS; + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_WRITE); + } + + return ret; +} + +palStatus_t pal_imageFinalize(palImageId_t imageId) +{ + //printf("pal_imageFinalize(id=%i)\r\n", imageId); + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t ret = PAL_ERR_UPDATE_ERROR; + + if (close_if_necessary(imageId)) + { + ret = PAL_SUCCESS; + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_FINALIZE); + } + + return ret; +} + +palStatus_t pal_imageGetDirectMemoryAccess(palImageId_t imageId, void** imagePtr, size_t* imageSizeInBytes) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageGetDirectMemAccess(imageId, imagePtr, imageSizeInBytes); + return status; +} + +palStatus_t pal_imageReadToBuffer(palImageId_t imageId, size_t offset, palBuffer_t *chunk) +{ + //printf("pal_imageReadToBuffer(imageId=%lu, offset=%lu)\r\n", imageId, offset); + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t ret = PAL_ERR_UPDATE_ERROR; + + int xfer_size_or_error = safe_read(imageId, offset, chunk->buffer, chunk->maxBufferLength); + if (xfer_size_or_error < 0) + { + //printf("Error reading from file\r\n"); + } + else + { + chunk->bufferLength = xfer_size_or_error; + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_READTOBUFFER); + ret = PAL_SUCCESS; + } + + return ret; +} + +palStatus_t pal_imageActivate(palImageId_t imageId) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageActivate(imageId); + return status; +} + +palStatus_t pal_imageGetFirmwareHeaderData(palImageId_t imageId, palBuffer_t *headerData) +{ + palStatus_t ret = PAL_SUCCESS; + palFileDescriptor_t file = 0; + size_t xfer_size; + if (NULL == headerData) + { + return PAL_ERR_NULL_POINTER; + } + if (headerData->maxBufferLength < sizeof(palFirmwareHeader_t)) + { + PAL_LOG(ERR, "Firmware header buffer size is too small(is %" PRIu32 " needs to be at least %zu)\r\n" + ,headerData->maxBufferLength, sizeof(palFirmwareHeader_t)); + return PAL_ERR_INVALID_ARGUMENT; + } + + const char *file_path = header_path_alloc_from_index(imageId); + if (file_path) + { + ret = pal_fsFopen(file_path, PAL_FS_FLAG_READONLY, &file); + if (ret == PAL_SUCCESS) + { + ret = pal_fsFread(&file, headerData->buffer, sizeof(palFirmwareHeader_t), &xfer_size); + if (PAL_SUCCESS == ret) + { + headerData->bufferLength = xfer_size; + } + pal_fsFclose(&file); + } + free((void*)file_path); + } + else + { + ret = PAL_ERR_NO_MEMORY; + } + return ret; +} + +palStatus_t pal_imageGetActiveHash(palBuffer_t *hash) +{ + //printf("pal_imageGetActiveHash\r\n"); + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t ret; + + if (hash->maxBufferLength < SIZEOF_SHA256) + { + ret = PAL_ERR_BUFFER_TOO_SMALL; + goto exit; + } + + hash->bufferLength = 0; + memset(hash->buffer, 0, hash->maxBufferLength); + + ret = pal_plat_imageGetActiveHash(hash); + if (ret == PAL_SUCCESS) + { + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_GETACTIVEHASH); + } + +exit: + return ret; +} + +palStatus_t pal_imageGetActiveVersion(palBuffer_t *version) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageGetActiveVersion(version); + return status; +} + +palStatus_t pal_imageWriteDataToMemory(palImagePlatformData_t dataId, const palConstBuffer_t * const dataBuffer) +{ + palStatus_t status = PAL_SUCCESS; + PAL_MODULE_IS_INIT(palUpdateInitFlag); + // this switch is for further use when there will be more options + switch(dataId) + { + case PAL_IMAGE_DATA_HASH: + status = pal_plat_imageWriteHashToMemory(dataBuffer); + break; + default: + { + PAL_LOG(ERR, "Update image write to memory error"); + status = PAL_ERR_GENERIC_FAILURE; + } + } + return status; +} + +PAL_PRIVATE palStatus_t pal_set_fw_header(palImageId_t index, FirmwareHeader_t *headerP) +{ + palStatus_t ret; + palFileDescriptor_t file = 0; + size_t xfer_size; + + const char *file_path = header_path_alloc_from_index(index); + ret = pal_fsFopen(file_path, PAL_FS_FLAG_READWRITETRUNC, &file); + if (ret != PAL_SUCCESS) + { + //printf("pal_fsFopen returned 0x%x\r\n", ret); + goto exit; + } + + ret = pal_fsFwrite(&file, headerP, sizeof(FirmwareHeader_t), &xfer_size); + if (ret != PAL_SUCCESS) + { + //printf("pal_fsFread returned 0x%x\r\n", ret); + goto exit; + } + else if (xfer_size != sizeof(FirmwareHeader_t)) + { + //printf("Size written %lu expected %lu\r\n", xfer_size, sizeof(FirmwareHeader_t)); + goto exit; + } + + ret = PAL_SUCCESS; + +exit: + if (file != 0) + { + ret = pal_fsFclose(&file); + if (ret != PAL_SUCCESS) + { + //printf("Error closing file %s\r\n", file_path); + ret = PAL_ERR_UPDATE_ERROR; + } + } + free((void*)file_path); + + return ret; +} + +/** + * @brief Bitwise CRC32 calculation + * @details Modified from ARM Keil code: + * http://www.keil.com/appnotes/docs/apnt_277.asp + * + * @param buffer Input byte array. + * @param length Number of bytes in array. + * + * @return CRC32 + */ +PAL_PRIVATE uint32_t internal_crc32(const uint8_t* buffer, + uint32_t length) +{ + const uint8_t* current = buffer; + uint32_t crc = 0xFFFFFFFF; + + while (length--) + { + crc ^= *current++; + + for (uint32_t counter = 0; counter < 8; counter++) + { + if (crc & 1) + { + crc = (crc >> 1) ^ 0xEDB88320; + } + else + { + crc = crc >> 1; + } + } + } + + return (crc ^ 0xFFFFFFFF); +} + +PAL_PRIVATE bool valid_index(uint32_t index) +{ + return (index <= IMAGE_COUNT_MAX); +} + +PAL_PRIVATE size_t safe_read(uint32_t index, size_t offset, uint8_t *buffer, uint32_t size) +{ + const bool read_nwrite = true; + size_t xfer_size = 0; + palStatus_t status; + + if ((!valid_index(index)) || (!open_if_necessary(index, read_nwrite)) || (!seek_if_necessary(index, offset, read_nwrite))) + { + return 0; + } + + status = pal_fsFread(&(image_file[index]), buffer, size, &xfer_size); + if (status == PAL_SUCCESS) + { + last_read_nwrite[index] = read_nwrite; + last_seek_pos[index] += xfer_size; + } + + return xfer_size; +} + +PAL_PRIVATE size_t safe_write(uint32_t index, size_t offset, const uint8_t *buffer, uint32_t size) +{ + const bool read_nwrite = false; + size_t xfer_size = 0; + palStatus_t status; + + if ((!valid_index(index)) || (!open_if_necessary(index, read_nwrite)) || (!seek_if_necessary(index, offset, read_nwrite))) + { + return 0; + } + status = pal_fsFseek(&(image_file[index]), offset, PAL_FS_OFFSET_SEEKSET); + if (status == PAL_SUCCESS) + { + status = pal_fsFwrite(&(image_file[index]), buffer, size, &xfer_size); + if (status == PAL_SUCCESS) + { + last_read_nwrite[index] = read_nwrite; + last_seek_pos[index] += xfer_size; + + if (size != xfer_size) + { + //printf("WRONG SIZE expected %u got %lu\r\n", size, xfer_size); + return 0; + } + + } + } + + return xfer_size; +} + +PAL_PRIVATE bool open_if_necessary(uint32_t index, bool read_nwrite) +{ + if (!valid_index(index)) + { + return false; + } + + if ( (unsigned int*)image_file[index] == NULL ) + { + const char *file_path = image_path_alloc_from_index(index); + pal_fsFileMode_t mode = read_nwrite ? PAL_FS_FLAG_READWRITE : PAL_FS_FLAG_READWRITETRUNC; + + palStatus_t ret = pal_fsFopen(file_path, mode, &(image_file[index])); + free((void*)file_path); + last_seek_pos[index] = 0; + if (ret != PAL_SUCCESS) + { + return false; + } + } + + return true; +} + +PAL_PRIVATE bool seek_if_necessary(uint32_t index, size_t offset, bool read_nwrite) +{ + if (!valid_index(index)) + { + return false; + } + + if ((read_nwrite != last_read_nwrite[index]) || + (offset != last_seek_pos[index])) + { + palStatus_t ret = pal_fsFseek(&(image_file[index]), offset, PAL_FS_OFFSET_SEEKSET); + if (ret != PAL_SUCCESS) + { + last_seek_pos[index] = SEEK_POS_INVALID; + return false; + } + } + + last_read_nwrite[index] = read_nwrite; + last_seek_pos[index] = offset; + + return true; +} + +PAL_PRIVATE bool close_if_necessary(uint32_t index) +{ + if (!valid_index(index)) + { + return false; + } + + palFileDescriptor_t file = image_file[index]; + image_file[index] = 0; + last_seek_pos[index] = SEEK_POS_INVALID; + + if (file != 0) + { + palStatus_t ret = pal_fsFclose(&file); + if (ret != 0) + { + return false; + } + } + + return true; +} + +PAL_PRIVATE const char *image_path_alloc_from_index(uint32_t index) +{ + char file_name[32] = {0}; + snprintf(file_name, sizeof(file_name)-1, "image_%" PRIu32 ".bin", index); + file_name[sizeof(file_name) - 1] = 0; + const char * const path_list[] = { + (char*)PAL_UPDATE_FIRMWARE_DIR, + file_name, + NULL + }; + + return path_join_and_alloc(path_list); +} + +PAL_PRIVATE const char *header_path_alloc_from_index(uint32_t index) +{ + char file_name[32] = {0}; + + if (ACTIVE_IMAGE_INDEX == index) + { + snprintf(file_name, sizeof(file_name)-1, "header_active.bin"); + } + else + { + snprintf(file_name, sizeof(file_name)-1, "header_%" PRIu32 ".bin", index); + } + + const char * const path_list[] = { + (char*)PAL_UPDATE_FIRMWARE_DIR, + file_name, + NULL + }; + + return path_join_and_alloc(path_list); +} + + +PAL_PRIVATE const char *path_join_and_alloc(const char * const * path_list) +{ + uint32_t string_size = 1; + uint32_t pos = 0; + + // Determine size of string to return + while (path_list[pos] != NULL) + { + // Size of string and space for separator + string_size += strlen(path_list[pos]) + 1; + pos++; + } + + // Allocate and initialize memory + char *path = (char*)malloc(string_size); + if (NULL != path) + { + memset(path, 0, string_size); + // Write joined path + pos = 0; + while (path_list[pos] != NULL) + { + bool has_slash = '/' == path_list[pos][strlen(path_list[pos]) - 1]; + bool is_last = NULL == path_list[pos + 1]; + strncat(path, path_list[pos], string_size - strlen(path) - 1); + if (!has_slash && !is_last) + { + strncat(path, "/", string_size - strlen(path) - 1); + } + pos++; + } + } + return path; +} + + + + +#elif (PAL_UPDATE_IMAGE_LOCATION == PAL_UPDATE_USE_FLASH) + +palStatus_t pal_imageInitAPI(palImageSignalEvent_t CBfunction) +{ + PAL_MODULE_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageInitAPI(CBfunction); + return status; +} + +palStatus_t pal_imageDeInit(void) +{ + PAL_MODULE_DEINIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageDeInit(); + return status; +} + + + +palStatus_t pal_imagePrepare(palImageId_t imageId, palImageHeaderDeails_t *headerDetails) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + pal_plat_imageSetHeader(imageId,headerDetails); + status = pal_plat_imageReserveSpace(imageId, headerDetails->imageSize); + + return status; +} + +palStatus_t pal_imageWrite (palImageId_t imageId, size_t offset, palConstBuffer_t *chunk) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageWrite(imageId, offset, chunk); + return status; +} + +palStatus_t pal_imageFinalize(palImageId_t imageId) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageFlush(imageId); + return status; +} + +palStatus_t pal_imageGetDirectMemoryAccess(palImageId_t imageId, void** imagePtr, size_t* imageSizeInBytes) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageGetDirectMemAccess(imageId, imagePtr, imageSizeInBytes); + return status; +} + +palStatus_t pal_imageReadToBuffer(palImageId_t imageId, size_t offset, palBuffer_t *chunk) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + + status = pal_plat_imageReadToBuffer(imageId,offset,chunk); + return status; +} + +palStatus_t pal_imageActivate(palImageId_t imageId) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageActivate(imageId); + return status; +} + +palStatus_t pal_imageGetActiveHash(palBuffer_t *hash) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageGetActiveHash(hash); + return status; +} + +palStatus_t pal_imageGetActiveVersion(palBuffer_t *version) +{ + PAL_MODULE_IS_INIT(palUpdateInitFlag); + palStatus_t status = PAL_SUCCESS; + status = pal_plat_imageGetActiveVersion(version); + return status; +} + +palStatus_t pal_imageWriteDataToMemory(palImagePlatformData_t dataId, const palConstBuffer_t * const dataBuffer) +{ + palStatus_t status = PAL_SUCCESS; + PAL_MODULE_IS_INIT(palUpdateInitFlag); + // this switch is for further use when there will be more options + switch(dataId) + { + case PAL_IMAGE_DATA_HASH: + status = pal_plat_imageWriteHashToMemory(dataBuffer); + break; + default: + { + PAL_LOG(ERR, "Update write data to mem status %d", (int)dataId); + status = PAL_ERR_GENERIC_FAILURE; + } + } + return status; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef _PAL_H +#define _PAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +//includes for common headers in PAL +#include "pal_macros.h" +#include "pal_configuration.h" +#include "pal_errors.h" +#include "pal_types.h" + +//includes for modules headers. +#include "pal_fileSystem.h" +#include "pal_rtos.h" +#include "pal_network.h" +#include "pal_TLS.h" +#include "pal_Crypto.h" +#include "pal_update.h" +#include "pal_internalFlash.h" + +/*! \file pal.h +* \brief PAL. +* This file contains the general API to initiate and destroy the PAL component. +* This is part of the PAL service API. +*/ + + +//declarations for global init and destroy of PAL + +/*! PAL initialization +* This function calls each module's initialization function (if exist) +* to allocate required resources and initiate them. +* \return PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_init(void); + +/*! PAL destruction. +* This function calls each module's destroy function (if exist) +* to free resources. +*/ +int32_t pal_destroy(void); + + +#ifdef __cplusplus +} +#endif +#endif //_PAL_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_Crypto.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_Crypto.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,719 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef _PAL_CRYPTO_H_ +#define _PAL_CRYPTO_H_ + +/*! \file pal_Crypto.h +* \brief PAL cryptographic. +* This file contains cryptographic APIs and is part of the PAL service API. +* It contains a variety of cryptographic APIs, such as: +* - AES-CTR + - AES-DRBG + - CMAC + - Message Digest +*/ + +typedef uintptr_t palAesHandle_t; +typedef uintptr_t palX509Handle_t; +typedef uintptr_t palMDHandle_t; +typedef uintptr_t palCCMHandle_t; +typedef uintptr_t palCMACHandle_t; +typedef uintptr_t palCtrDrbgCtxHandle_t; +typedef uintptr_t palCurveHandle_t; +typedef uintptr_t palGroupIDHandle_t; +typedef uintptr_t palECKeyHandle_t; +typedef uintptr_t palSignatureHandle_t; +typedef uintptr_t palx509CSRHandle_t; + +//! Key types to be set to the AES engine. +typedef enum palAesKeyType{ + PAL_KEY_TARGET_ENCRYPTION, + PAL_KEY_TARGET_DECRYPTION +}palAesKeyType_t; + +//! Message digest algorithms supported by PAL. +typedef enum palMDType{ + PAL_SHA256 +}palMDType_t; + +//! AES mode for ECB encryption/decryption. +typedef enum palAesMode{ + PAL_AES_ENCRYPT, + PAL_AES_DECRYPT +}palAesMode_t; + +//! The supported enum tags by PAL for ASN1. +typedef enum palASNTag{ + PAL_ASN1_BOOLEAN = 0x01, + PAL_ASN1_INTEGER = 0x02, + PAL_ASN1_BIT_STRING = 0x03, + PAL_ASN1_OCTET_STRING = 0x04, + PAL_ASN1_NULL = 0x05, + PAL_ASN1_OID = 0x06, + PAL_ASN1_UTF8_STRING = 0x0C, + PAL_ASN1_SEQUENCE = 0x10, + PAL_ASN1_SET = 0x11, + PAL_ASN1_PRINTABLE_STRING = 0x13, + PAL_ASN1_T61_STRING = 0x14, + PAL_ASN1_IA5_STRING = 0x16, + PAL_ASN1_UTC_TIME = 0x17, + PAL_ASN1_GENERALIZED_TIME = 0x18, + PAL_ASN1_UNIVERSAL_STRING = 0x1C, + PAL_ASN1_BMP_STRING = 0x1E, + PAL_ASN1_PRIMITIVE = 0x00, + PAL_ASN1_CONSTRUCTED = 0x20, + PAL_ASN1_CONTEXT_SPECIFIC = 0x80, +}palASNTag_t; + +#define PAL_ASN1_CLASS_BITS 0xC0 +#define PAL_ASN1_TAG_BITS 0x1F +#define PAL_CRYPT_BLOCK_SIZE 16 +#define PAL_SHA256_SIZE 32 + +typedef enum palFormat{ + PAL_POINT_CONVERSION_UNCOMPRESSED + /*PAL_POINT_CONVERSION_COMPRESSED*/ +}palFormat_t; + +typedef enum palCipherID{ + PAL_CIPHER_ID_AES + /*PAL_CIPHER_ID_DES*/ +}palCipherID_t; + +//! Supported curves. +typedef enum palGroupIndex{ + PAL_ECP_DP_NONE, + PAL_ECP_DP_SECP256R1 +}palGroupIndex_t; + +typedef enum palKeyUsage{ + PAL_X509_KU_DIGITAL_SIGNATURE = 0x1, + PAL_X509_KU_NON_REPUDIATION = 0x2, + PAL_X509_KU_KEY_CERT_SIGN = 0x4 +}palKeyUsage_t; + +//! Key check options. +typedef enum palKeyToCheck{ + PAL_CHECK_PRIVATE_KEY = 0x01, + PAL_CHECK_PUBLIC_KEY = 0x10, + PAL_CHECK_BOTH_KEYS = 0x11 +}palKeyToCheck_t; + +//! Attributes to be retrieved from the x509 cert. +typedef enum palX509Attr{ + PAL_X509_ISSUER_ATTR, + PAL_X509_SUBJECT_ATTR, + PAL_X509_CN_ATTR, + PAL_X509_OU_ATTR, + PAL_X509_VALID_FROM, + PAL_X509_VALID_TO +}palX509Attr_t; + + +/***************************************************/ +/**** PAL Crypto Client APIs ***********************/ +/***************************************************/ + +/*! Initialize AES context + * + * @param[in,out] aes: The AES context to be initialized. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_initAes(palAesHandle_t *aes); + +/*! Free AES context. + * + * @param[in,out] aes: The AES context to be deallocated. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_freeAes(palAesHandle_t *aes); + +/*! Set AES key context for encryption or decryption. + * + * @param[in] aes: The AES context. + * @param[in] key: The AES key. + * @param[in] keybits: The size of the key in bits. + * @param[in] keyTarget: The key target (encryption/decryption). + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_setAesKey(palAesHandle_t aes, const unsigned char* key, uint32_t keybits, palAesKeyType_t keyTarget); + +/*! AES-CTR buffer encryption/decryption. + * + * @param[in] aes: The AES context. + * @param[in] input: The input data buffer. + * @param[out] output: The output data buffer. + * @param[in] inLen: The input data length. + * @param[in] iv: The initialization vector for AES-CTR. + * + \note Due to the nature of CTR, you should use the same key schedule for + * both encryption and decryption. So before calling this function, you MUST set the key + * by calling `pal_setAesKey()` with key target PAL_KEY_TARGET_ENCRYPTION. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_aesCTR(palAesHandle_t aes, const unsigned char* input, unsigned char* output, size_t inLen, unsigned char iv[16]); + +/*! AES-CTR buffer encryption/decryption with zero offset. + * + * @param[in] aes: The AES context. + * @param[in] input: The input data buffer. + * @param[out] output: The output data buffer. + * @param[in] inLen: The input data length. + * @param[in] iv: The initialization vector for AES-CTR. + * + \note Due to the nature of CTR, you should use the same key schedule for + * both encryption and decryption. So before calling this function, you MUST set the key + * by calling `pal_setAesKey()` with key target PAL_KEY_TARGET_ENCRYPTION. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_aesCTRWithZeroOffset(palAesHandle_t aes, const unsigned char* input, unsigned char* output, size_t inLen, unsigned char iv[16]); + + +/*! AES-ECB block encryption/decryption. + * + * @param[in] aes: The AES context. + * @param[in] input: A 16-byte input block. + * @param[out] output: A 16-byte output block. + * @param[in] mode: PAL_AES_ENCRYPT or PAL_AES_DECRYPT. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_aesECB(palAesHandle_t aes, const unsigned char input[PAL_CRYPT_BLOCK_SIZE], unsigned char output[PAL_CRYPT_BLOCK_SIZE], palAesMode_t mode); + +/*! Process SHA256 over the input buffer. + * + * @param[in] input: A buffer for the input data. + * @param[in] inLen: The length of the input data. + * @param[out] output: The SHA256 checksum result. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_sha256(const unsigned char* input, size_t inLen, unsigned char output[PAL_SHA256_SIZE]); + +/*! Initialize a certificate (chain) context. + * + * @param[in,out] x509Cert: The certificate chain to initialize. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_x509Initiate(palX509Handle_t* x509Cert); + +/*! Parse one or more certificates and add them to the chained list. + * + * @param[in] x509Cert: The beginning of the chain. + * @param[in] input: A buffer holding the certificate data in PEM or DER format. + * @param[in] inLen: The size of the input buffer. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_x509CertParse(palX509Handle_t x509Cert, const unsigned char* input, size_t inLen); + +/*! Get attributes from the parsed certificate. +* +* @param[in] x509Cert: The parsed certificate. +* @param[in] attr: The required attribute. +* @param[out] output: A buffer to hold the attribute value. +* @param[in] outLenBytes: The size of the allocated buffer. +* @param[out] actualOutLenBytes: The actual size of the attribute. +* +\note In case of PAL_ERR_BUFFER_TOO_SMALL, the required size is assigned into the `actualOutLen` parameter. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_x509CertGetAttribute(palX509Handle_t x509Cert, palX509Attr_t attr, void* output, size_t outLenBytes, size_t* actualOutLenBytes); + +/*! Verify one or more X509 DER formatted certificates. + * + * @param[in] x509Cert: A handle holding the parsed certificate. + * @param[in] x509Cert: The beginning of the chain to verify the X509 DER certificate with. (Optional) + * + \return PAL_SUCCESS on success. In case of failure: + * - PAL_ERR_X509_BADCERT_EXPIRED + * - PAL_ERR_X509_BADCERT_FUTURE + * - PAL_ERR_X509_BADCERT_BAD_MD + * - PAL_ERR_X509_BADCERT_BAD_PK + * - PAL_ERR_X509_BADCERT_NOT_TRUSTED + * - PAL_ERR_X509_BADCERT_BAD_KEY + */ +palStatus_t pal_x509CertVerify(palX509Handle_t x509Cert, palX509Handle_t x509CertChain); + +/*! Deallocate all certificate data. + * + * @param[in,out] x509Cert: The certificate chain to free. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_x509Free(palX509Handle_t* x509Cert); + +/*! Initialize the MD context and set up the required data according to the given algorithm. + * + * @param[in,out] md: The MD context to be initialized. + * @param[in] mdType: The MD algorithm. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_mdInit(palMDHandle_t* md, palMDType_t mdType); + +/*! Generic message digest process buffer. + * + * @param[in] md: The MD context. + * @param[in] input: A buffer holding the input data. + * @param[in] inLen: The length of the input data. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_mdUpdate(palMDHandle_t md, const unsigned char* input, size_t inLen); + +/*! Generic message digest output buffer size getter. + * + * @param[in] md: The MD context. + * @param[out] bufferSize: A pointer to hold the output size of the `pal_mdFinal()` for the given handle. + * + \note This function SHOULD be called before calling `pal_mdFinal()`. + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_mdGetOutputSize(palMDHandle_t md, size_t* bufferSize); + +/*! Generic message digest final calculation. + * + * @param[in] md: The MD context. + * @param[out] ouput: The checksum result of the generic message digest. + * + \note `pal_mdGetOutputSize()` SHOULD be called before calling `pal_mdFinal()` to get the needed size for the ouptut. + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_mdFinal(palMDHandle_t md, unsigned char* output); + +/*! Free and clear the MD context. + * + * @param[in,out] md: The MD context to be free. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_mdFree(palMDHandle_t* md); + +/*! Verify the signature. + * + * @param[in] x509: The certificate context that holds the PK data. + * @param[in] mdType: The MD algorithm used. + * @param[in] hash: The hash of the message to sign. + * @param[in] hashLen: The hash length. + * @param[in] sig: The signature to verify. + * @param[in] sigLen: The signature length. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_verifySignature(palX509Handle_t x509, palMDType_t mdType, const unsigned char *hash, size_t hashLen, const unsigned char *sig, size_t sigLen); + +/*! Get the tag and length of the tag, check for the requested tag. \n +* Updates the pointer to immediately after the tag and length. + * + * @param[in,out] position: The position in the ASN.1 data. + * @param[in] end: The end of data. + * @param[out] len: The tag length. + * @param[in] tag: The expected tag. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_ASN1GetTag(unsigned char **position, const unsigned char *end, size_t *len, uint8_t tag); + +/*! CCM initialization. +* +* @param[in] ctx: The CCM context to be initialized. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CCMInit(palCCMHandle_t* ctx); + +/*! CCM destruction. +* +* @param[in] ctx: The CCM context to destroy. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CCMFree(palCCMHandle_t* ctx); + +/*! CCM set key. +* +* @param[in] ctx: The CCM context to be initialized. +* @param[in] id: The cipher to use (a 128-bit block cipher). +* @param[in] key: The encryption key. +* @param[in] keybits: The key size in bits (must be acceptable by the cipher). +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CCMSetKey(palCCMHandle_t ctx, const unsigned char *key, uint32_t keybits, palCipherID_t id); + +/*! CCM buffer authenticated decryption. +* +* @param[in] ctx: The CCM context to be initialized. +* @param[in] input A buffer holding the input data. +* @param[in] inLen: The length of the input data. +* @param[in] iv: The initialization vector. +* @param[in] ivLen: The length of IV. +* @param[in] add: Additional data. +* @param[in] addLen: The length of additional data. +* @param[in] tag: A buffer holding the tag. +* @param[in] tag_len: The length of the tag. +* @param[out] output: A buffer for holding the output data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CCMDecrypt(palCCMHandle_t ctx, unsigned char* input, size_t inLen, + unsigned char* iv, size_t ivLen, unsigned char* add, + size_t addLen, unsigned char* tag, size_t tagLen, + unsigned char* output); + +/*! CCM buffer encryption. +* +* @param[in] ctx: The CCM context to be initialized. +* @param[in] input A buffer holding the input data. +* @param[in] inLen: The length of the input data. +* @param[in] iv: The initialization vector. +* @param[in] ivLen: The length of IV. +* @param[in] add: Additional data. +* @param[in] addLen: The length of additional data. +* @param[out] output: A buffer for holding the output data, must be at least `inLen` bytes wide. +* @param[out] tag: A buffer for holding the tag. +* @param[out] tagLen: The length of the tag to generate in bytes. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CCMEncrypt(palCCMHandle_t ctx, unsigned char* input, + size_t inLen, unsigned char* iv, size_t ivLen, + unsigned char* add, size_t addLen, unsigned char* output, + unsigned char* tag, size_t tagLen); + +/*! Initiate CTR_DRBG context with given seed. +* +* @param[in] ctx: The CTR_DRBG context to be seeded. +* @param[in] seed: The seed data. +* @param[in] len: The seed data length.. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CtrDRBGInit(palCtrDrbgCtxHandle_t* ctx, const void* seed, size_t len); + +/*! CTR_DRBG pseudo random generation. +* +* @param[in] ctx: The CTR_DRBG context. +* @param[out] output: The buffer to fill. +* @param[in] len: The length of the buffer. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CtrDRBGGenerate(palCtrDrbgCtxHandle_t ctx, unsigned char* out, size_t len); + +/*! CTR_DRBG destroy +* +* @param[in] ctx: The CTR_DRBG context to destroy. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CtrDRBGFree(palCtrDrbgCtxHandle_t* ctx); + + +/*! One shot AES cipher CMAC. +* +* @param[in] ctx: The CMAC context to initialize. +* @param[in] key: The encryption key. +* @param[in] keyLenInBits: The key size in bits. +* @param[in] input: A buffer for the input data. +* @param[in] inputLenInBytes: The input data length in bytes. +* @param[out] output: The generic CMAC result. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_cipherCMAC(const unsigned char *key, size_t keyLenInBits, const unsigned char *input, size_t inputLenInBytes, unsigned char *output); + +/*! Iterative cipher CMAC start +* +* @param[in] ctx: The CMAC context. +* @param[in] key: The CMAC key. +* @param[in] keyLenBits: The key size in bits. +* @param[in] cipherID: A buffer for the input data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CMACStart(palCMACHandle_t *ctx, const unsigned char *key, size_t keyLenBits, palCipherID_t cipherID); + +/*! Iterative cipher CMAC update. +* +* @param[in] ctx: The CMAC context. +* @param[in] input: A buffer for the input data. +* @param[in] inputLen: The input data length. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CMACUpdate(palCMACHandle_t ctx, const unsigned char *input, size_t inLen); + +/*! Iterative cipher CMAC finish. +* +* @param[in] ctx: The CMAC context. +* @param[out] output: A buffer for the output data. +* @param[out] outLen: The output data length. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_CMACFinish(palCMACHandle_t *ctx, unsigned char *output, size_t* outLen); + +/*! One shot md HMAC. +* +* @param[in] key: The encryption key. +* @param[in] keyLenInBytes: The key size in bytes. +* @param[in] input: A buffer for the input data. +* @param[in] inputLenInBytes: The input data length in bytes. +* @param[out] output: The generic HMAC result. +* @param[out] outputLenInBytes: Size of the HMAC result (optional). +* +\note Expects output to be 32 bytes long +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_mdHmacSha256(const unsigned char *key, size_t keyLenInBytes, const unsigned char *input, size_t inputLenInBytes, unsigned char *output, size_t* outputLenInBytes); + + +/*! Check that the private and/or public key is a valid and the public key is on this curve. +* +* @param[in] grp: The curve/group that the point should belong to. +* @param[in] key: A pointer to a struct holding the raw data of the keys to check. +* @param[in] type: PAL_CHECK_PRIVATE_KEY/PAL_CHECK_PUBLIC_KEY/PAL_CHECK_BOTH_KEYS from `palKeyToCheck_t`. +* @param[out] verified: The result of verification. +* +\note The key can contain only private or public key or both. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECCheckKey(palCurveHandle_t grp, palECKeyHandle_t key, uint32_t type, bool *verified); + +/*! Allocate key context and initialize a key pair (as an invalid one). +* +* @param[in] key: The key to initialize. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECKeyNew(palECKeyHandle_t* key); + +/*! Release private/public key context related memory. +* +* @param[in] key: A handle for the key context to be freed. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECKeyFree(palECKeyHandle_t* key); + +/*! Parse DER encoded private key. +* +* @param[in] prvDERKey: A buffer that holds the DER encoded private key. +* @param[in] keyLen: The key length. +* @param[out] key: A handle for the context that holds the parsed key. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_parseECPrivateKeyFromDER(const unsigned char* prvDERKey, size_t keyLen, palECKeyHandle_t key); + +/*! Parse DER encoded public key. +* +* @param[in] pubDERKey: A buffer that holds the DER encoded public key. +* @param[in] keyLen: The key length. +* @param[out] key: A handle for the context that holds the parsed key. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_parseECPublicKeyFromDER(const unsigned char* pubDERKey, size_t keyLen, palECKeyHandle_t key); + +/*! Encode given private key from key handle to DER buffer. +* +* @param[in] key: A handle to the private key. +* @param[out] derBuffer: A buffer to hold the result of the DER encoding. +* @param[in] bufferSize: The size of the allocated buffer. +* @param[out] actualSize: The actual size of the written data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_writePrivateKeyToDer(palECKeyHandle_t key, unsigned char* derBuffer, size_t bufferSize, size_t* actualSize); + +/*! Encode given public key from key handle to DER buffer. +* +* @param[in] key: A handle to the public key. +* @param[out] derBuffer: A buffer to hold the result of the DER encoding. +* @param[in] bufferSize: The size of the allocated buffer. +* @param[out] actualSize: The actual size of the written data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_writePublicKeyToDer(palECKeyHandle_t key, unsigned char* derBuffer, size_t bufferSize, size_t* actualSize); + +/*! Generate a key pair for a given curve. +* +* @param[in] grpID: The ECP group identifier. +* @param[in,out] key: The destination key pair handle. +* +\note The `key` parameter must be first allocated by `pal_ECKeyNew()`. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECKeyGenerateKey(palGroupIndex_t grpID, palECKeyHandle_t key); + +/*! Retrieve the curve ID if it exists in the given key. +* +* @param[in] key: The key to retrieve its curve. +* @param[out] grpID: The curve/group ID for the given key. In case of error, this pointer contains PAL_ECP_DP_NONE. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECKeyGetCurve(palECKeyHandle_t key, palGroupIndex_t* grpID); + +/*! ECP group initialize and set a group using well-known domain parameters. +* +* @param[in] grp: The destination group. +* @param[in] index: The index in the list of well-known domain parameters. +* +\return PAL_SUCCESS on success, negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECGroupInitAndLoad(palCurveHandle_t* grp, palGroupIndex_t index); + +/*! Free the ECP group context. +* +* @param[in] grp: The curve/group to free. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECGroupFree(palCurveHandle_t* grp); + +/*! Allocate and initialize x509 CSR context. +* +* @param[in] x509CSR: The CSR context to allocate and initialize. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_x509CSRInit(palx509CSRHandle_t *x509CSR); + +/*! Set the subject name for a CSR. Subject names should contain a comma-separated list of OIDs and values. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] subjectName: The subject name to set +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_x509CSRSetSubject(palx509CSRHandle_t x509CSR, const char* subjectName); + +/*! Set the MD algorithm to use for the signature. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] mdType: The MD algorithm to use. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_x509CSRSetMD(palx509CSRHandle_t x509CSR, palMDType_t mdType); + +/*! Set the key for a CSR. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] pubKey: The public key to include. To use a key pair handle, see the note. +* @param[in] prvKey: The public key to sign with. +* +\note To use key pair, send it as `pubKey` and NULL as `prvKey`. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_x509CSRSetKey(palx509CSRHandle_t x509CSR, palECKeyHandle_t pubKey, palECKeyHandle_t prvKey); + +/*! Set the key usage extension flags. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] keyUsage: The key usage flags, should be taken from `palKeyUsage_t`. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_x509CSRSetKeyUsage(palx509CSRHandle_t x509CSR, uint32_t keyUsage); + +/*! Generic function to add to the CSR. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] oid: The OID of the extension. +* @param[in] oidLen: The OID length. +* @param[in] value: The value of the extension OCTET STRING. +* @param[in] valueLen: The value length. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_x509CSRSetExtension(palx509CSRHandle_t x509CSR,const char* oid, size_t oidLen, + const unsigned char* value, size_t valueLen); + +/*! Write a CSR to a DER structure +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] derBuf: A buffer to write to. +* @param[in] derBufLen: The buffer length. +* @param[in] actualDerLen: The actual length of the written data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_x509CSRWriteDER(palx509CSRHandle_t x509CSR, unsigned char* derBuf, size_t derBufLen, size_t* actualDerLen); + +/*! Free the x509 CSR context. +* +* @param[in] x509CSR: The CSR context to free. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_x509CSRFree(palx509CSRHandle_t *x509CSR); + +/*! Compute the shared secret using elliptic curve DiffieâHellman. +* +* @param[in] grp: The ECP group. +* @param[in] peerPublicKey: The public key from a peer. +* @param[in] key: The private key. +* @param[out] out: The shared secret. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECDHComputeKey(const palCurveHandle_t grp, const palECKeyHandle_t peerPublicKey, + const palECKeyHandle_t privateKey, palECKeyHandle_t outKey); + +/*! Compute the ECDSA signature of a previously hashed message. +* +* @param[in] grp: The ECP group. +* @param[in] prvKey: The private signing key. +* @param[in] dgst: The message hash. +* @param[in] dgstLen: The length ofthe message buffer. +* @param[out] sig: A buffer to hold the computed signature. +* @param[out] sigLen: The length of the computed signature. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECDSASign(palCurveHandle_t grp, palMDType_t mdType, palECKeyHandle_t prvKey, unsigned char* dgst, + uint32_t dgstLen, unsigned char *sig, size_t *sigLen); + +/*! Verify the ECDSA signature of a previously hashed message. +* +* @param[in] pubKey: The public key for verification. +* @param[in] dgst: The message hash. +* @param[in] dgstLen: The length of the message buffer. +* @param[in] sign: The signature. +* @param[in] sig: A buffer to hold the computed signature. +* @param[in] sigLen: The length of the computed signature. +* @param[out] verified: A boolean to hold the verification result. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_ECDSAVerify(palECKeyHandle_t pubKey, unsigned char* dgst, uint32_t dgstLen, + unsigned char* sig, size_t sigLen, bool* verified); + + +#endif //_PAL_CRYPTO_H_
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_TLS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_TLS.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,217 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef _PAL_DTLS_H_ +#define _PAL_DTLS_H_ + +#include "pal_macros.h" +#include "pal_network.h" +#include "pal_types.h" + +/*! \file pal_TLS.h +* \brief PAL TLS/DTLS. +* This file contains TLS/DTLS APIs and is a part of the PAL service API. +* It provides TLS/DTLS handshake functionalities, read/write from peer in a secure way. +*/ + +/***************************************************/ +/**** PAL DTLS data structures *********************/ +/***************************************************/ + +// Index in the static array of the TLSs. +typedef uintptr_t palTLSHandle_t; +typedef uintptr_t palTLSConfHandle_t; + +typedef enum palTLSTranportMode{ +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + PAL_TLS_MODE, //(STREAM) +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + PAL_DTLS_MODE //(DATAGRAM) +}palTLSTransportMode_t; + +typedef struct palTLSSocket{ + palSocket_t socket; + palSocketAddress_t* socketAddress; + palSocketLength_t addressLength; + palTLSTransportMode_t transportationMode; +}palTLSSocket_t; + + +typedef struct palTLSBuffer{ + const void* buffer; + uint32_t size; +}palTLSBuffer_t; + +typedef palTLSBuffer_t palX509_t; +typedef palTLSBuffer_t palX509CRL_t; +typedef palTLSBuffer_t palPrivateKey_t; + +//! This callback is useful ONLY when mbed TLS used as TLS platform library. In other platforms, +//! you should NOT use this callback in the code. The related function is not supported in other +//! platforms than mbedTLS. +typedef int(*palEntropySource_f)(void *data, unsigned char *output, size_t len, size_t *olen); + +/***************************************************/ +/**** PAL DTLS Client APIs *************************/ +/***************************************************/ + +/*! Initiate a new TLS context. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[out] palTLSHandle: The index to the TLS context. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_initTLS(palTLSConfHandle_t palTLSConf, palTLSHandle_t* palTLSHandle); + +/*! Destroy and free resources for the TLS context. +* +* @param[in] palTLSHandle: The index to the TLS context. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_freeTLS(palTLSHandle_t* palTLSHandle); + +/*! Add entropy source to the TLS/DTLS library. (This API may NOT be available in all TLS/DTLS platforms, see note.) +* +* @param[in] entropyCallback: The entropy callback to be used in TLS/DTLS handshake. +* +\note This function is available ONLY when the TLS/DTLS platform supports this functionality. In other platforms, + PAL_ERR_NOT_SUPPORTED should be returned. +\note This function MUST be called (if needed) before calling the `pal_initTLSConfiguration()` function. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure, or PAL_ERR_NOT_SUPPORTED. +*/ +palStatus_t pal_addEntropySource(palEntropySource_f entropyCallback); + +/*! Initiate a new configuration context. +* +* @param[out] palTLSConf: The context that holds the TLS configuration. +* @param[in] transportationMode: The connection type (TLS OR DTLS). See `palTranportVersion_t`. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_initTLSConfiguration(palTLSConfHandle_t* palTLSConf, palTLSTransportMode_t transportationMode); + +/*! Destroy and free resources for the TLS configurtion context. +* +* @param[in] palTLSConf: The TLS configuration context to free. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_tlsConfigurationFree(palTLSConfHandle_t* palTLSConf); + +/*! Set your own certificate chain and private key. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] ownCert: Your own public certificate chain. +* @param[in] privateKey: Your own private key. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_setOwnCertAndPrivateKey(palTLSConfHandle_t palTLSConf, palX509_t* ownCert, palPrivateKey_t* privateKey); + +/*! Set the data required to verify the peer certificate. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] caChain: The trusted CA chain. +* @param[in] caCRL: The trusted CA CRLs. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_setCAChain(palTLSConfHandle_t palTLSConf, palX509_t* caChain, palX509CRL_t* caCRL); + +/*! Set the Pre-Shared Key (PSK) and the expected identity name. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] identity: A pointer to the pre-shared key identity. +* @param[in] maxIdentityLenInBytes: The length of the key identity. +* @param[in] psk: A pointer to the pre-shared key. +* @param[in] maxPskLenInBytes: The length of the pre-shared key. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_setPSK(palTLSConfHandle_t palTLSConf, const unsigned char *identity, uint32_t maxIdentityLenInBytes, const unsigned char *psk, uint32_t maxPskLenInBytes); + +/*! Set the socket used by the TLS configuration context. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] socket: The socket to be used by the TLS context. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_tlsSetSocket(palTLSConfHandle_t palTLSConf, palTLSSocket_t* socket); + +/*! Perform the TLS handshake (blocking). +* +* This function sets the TLS configuration context into the TLS context and performs the handshake +* with the peer. +* @param[in] palTLSHandle: The TLS context. +* @param[in] palTLSConf: The TLS configuration context. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_handShake(palTLSHandle_t palTLSHandle, palTLSConfHandle_t palTLSConf); + +/*! Set the retransmit timeout values for the DTLS handshake. +* (DTLS only, no effect on TLS.) +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] timeoutInMilliSec: The timeout value in seconds. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_setHandShakeTimeOut(palTLSConfHandle_t palTLSConf, uint32_t timeoutInMilliSec); + +/*! Return the result of the certificate verification. +* +* @param[in] ssl: The SSL context. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_sslGetVerifyResult(palTLSHandle_t palTLSHandle); + +/*! Read the application data bytes (the max number of bytes). +* +* @param[in] palTLSHandle: The TLS context. +* @param[out] buffer: A buffer that holds the data. +* @param[in] len: The maximum number of bytes to read. +* @param[out] actualLen: The the actual number of bytes read. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_sslRead(palTLSHandle_t palTLSHandle, void *buffer, uint32_t len, uint32_t* actualLen); + +/*! Write the exact length of application data bytes. +* +* @param[in] palTLSHandle: The TLS context. +* @param[in] buffer: A buffer holding the data. +* @param[in] len: The number of bytes to be written. +* @param[out] bytesWritten: The number of bytes actually written. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_sslWrite(palTLSHandle_t palTLSHandle, const void *buffer, uint32_t len, uint32_t *bytesWritten); + +/*! Turn on/off debugging from the TLS library. The logs are sent via the mbedTrace. +* In case of release mode, an error will be returned. +* +* @param[in] turnOn +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_sslDebugging(uint8_t turnOn); + +#endif // _PAL_DTLS_H_
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_configuration.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_configuration.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,218 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef _PAL_COFIGURATION_H +#define _PAL_COFIGURATION_H +#include "limits.h" + + +#ifdef PAL_USER_DEFINED_CONFIGURATION + #include PAL_USER_DEFINED_CONFIGURATION +#endif + +/*! \brief let the user choose its platform configuration file. + \note if the user does not specify a platform configuration file, + \note PAL uses a default configuration set that can be found at \b Configs/pal_config folder + */ + +#ifdef PAL_PLATFORM_DEFINED_CONFIGURATION + #include PAL_PLATFORM_DEFINED_CONFIGURATION +#elif defined(__LINUX__) + #include "palInclude_Linux.h" +#elif defined(__FREERTOS__) + #include "palInclude_FreeRTOS.h" +#elif defined(__MBED__) + #include "palInclude_mbedOS.h" +#else + #error "Please specify the platform PAL_PLATFORM_DEFINED_CONFIGURATION" +#endif + +/*! \file pal_configuration.h +* \brief PAL Configuration. +* This file contains PAL configuration information including the following: +* 1. The flags to enable or disable features. +* 2. The configuration of the number of objects provided by PAL (such as the number of threads supported) or their sizes. +* 3. The configuration of supported cipher suites. +* 4. The configuration for flash memory usage. +* 5. The configuration for the root of trust. +*/ + + +/* + * Network configuration + */ +//! PAL configuration options +#ifndef PAL_NET_TCP_AND_TLS_SUPPORT + #define PAL_NET_TCP_AND_TLS_SUPPORT true/* Add PAL support for TCP. */ +#endif + +#ifndef PAL_NET_ASYNCHRONOUS_SOCKET_API + #define PAL_NET_ASYNCHRONOUS_SOCKET_API true/* Add PAL support for asynchronous sockets. */ +#endif + +#ifndef PAL_NET_DNS_SUPPORT + #define PAL_NET_DNS_SUPPORT true/* Add PAL support for DNS lookup. */ +#endif + +//values for PAL_NET_DNS_IP_SUPPORT +#define PAL_NET_DNS_ANY 0 /* if PAL_NET_DNS_IP_SUPPORT is set to PAL_NET_DNS_ANY pal_getAddressInfo will return the first available IPV4 or IPV6 address*/ +#define PAL_NET_DNS_IPV4_ONLY 2 /* if PAL_NET_DNS_IP_SUPPORT is set to PAL_NET_DNS_IPV4_ONLY pal_getAddressInfo will return the first available IPV4 address*/ +#define PAL_NET_DNS_IPV6_ONLY 4 /* if PAL_NET_DNS_IP_SUPPORT is set to PAL_NET_DNS_IPV6_ONLY pal_getAddressInfo will return the first available IPV6 address*/ + +#ifndef PAL_NET_DNS_IP_SUPPORT + #define PAL_NET_DNS_IP_SUPPORT 0 /* sets the type of IP addresses returned by pal_getAddressInfo*/ +#endif + +//! The maximum number of interfaces that can be supported at a time. +#ifndef PAL_MAX_SUPORTED_NET_INTERFACES + #define PAL_MAX_SUPORTED_NET_INTERFACES 10 +#endif + +/* + * RTOS configuration + */ + +#ifndef PAL_IGNORE_UNIQUE_THREAD_PRIORITY + #define PAL_UNIQUE_THREAD_PRIORITY true +#endif + +//! The number of valid priorities limits the number of threads. If priorities are added this value should be increased. +#ifndef PAL_MAX_NUMBER_OF_THREADS + #define PAL_MAX_NUMBER_OF_THREADS 7 +#endif + +//! initial time until thread stack cleanup (mbedOs only). This is the amount of time we wait before checking that a thread has completed so we can free it's stack. +#ifndef PAL_RTOS_THREAD_CLEANUP_TIMER_MILISEC + #define PAL_RTOS_THREAD_CLEANUP_TIMER_MILISEC 200 +#endif + +//! This define is used to determine the size of the initial random buffer (in bytes) held by PAL for random the algorithm. +#ifndef PAL_INITIAL_RANDOM_SIZE + #define PAL_INITIAL_RANDOM_SIZE 48 +#endif + +#ifndef PAL_RTOS_WAIT_FOREVER + #define PAL_RTOS_WAIT_FOREVER UINT_MAX +#endif + +/* + * TLS configuration + */ +//! The the maximum number of TLS contexts supported. +#ifndef PAL_MAX_NUM_OF_TLS_CTX + #define PAL_MAX_NUM_OF_TLS_CTX 1 +#endif + +//! The maximum number of supported cipher suites. +#ifndef PAL_MAX_ALLOWED_CIPHER_SUITES + #define PAL_MAX_ALLOWED_CIPHER_SUITES 1 +#endif + +//! This value is in milliseconds. 1000 = 1 second. +#ifndef PAL_DTLS_PEER_MIN_TIMEOUT + #define PAL_DTLS_PEER_MIN_TIMEOUT 1000 +#endif + +//! The debug threshold for TLS API. +#ifndef PAL_TLS_DEBUG_THRESHOLD + #define PAL_TLS_DEBUG_THRESHOLD 5 +#endif + +//! Define the cipher suites for TLS (only one cipher suite per device available). +#define PAL_TLS_PSK_WITH_AES_128_CBC_SHA256_SUITE 0x01 +#define PAL_TLS_PSK_WITH_AES_128_CCM_8_SUITE 0x02 +#define PAL_TLS_PSK_WITH_AES_256_CCM_8_SUITE 0x04 +#define PAL_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_SUITE 0x08 +#define PAL_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_SUITE 0x10 +#define PAL_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_SUITE 0x20 + +//! Use the default cipher suite for TLS/DTLS operations +#define PAL_TLS_CIPHER_SUITE PAL_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_SUITE + +/* + * UPDATE configuration + */ + +#define PAL_UPDATE_USE_FLASH 1 +#define PAL_UPDATE_USE_FS 2 + +#ifndef PAL_UPDATE_IMAGE_LOCATION + #define PAL_UPDATE_IMAGE_LOCATION PAL_UPDATE_USE_FS //!< Choose the storage correct Storage option, File System or Flash +#endif + +//! Certificate date validation in Unix time format. +#ifndef PAL_CRYPTO_CERT_DATE_LENGTH + #define PAL_CRYPTO_CERT_DATE_LENGTH sizeof(uint64_t) +#endif + + +/* + * FS configuration + */ + + +/* !\brief file system configurations + * PAL_NUMBER_OF_PARTITIONS + * 0 - Default behavior for the platform (Described by either 1 or 2 below). + * 1 - There is a single partition in which the ARM client applications create and remove files (but do not format it). + * 2 - There are two partitions in which ARM client applications may format or create and remove files, + * depending on PAL_PRIMARY_PARTITION_PRIVATE and PAL_SECONDARY_PARTITION_PRIVATE + */ +#ifndef PAL_NUMBER_OF_PARTITIONS + #define PAL_NUMBER_OF_PARTITIONS 1 // Default partitions +#endif + +#if (PAL_NUMBER_OF_PARTITIONS > 2) +#error "PAL_NUMBER_OF_PARTITIONS cannot be more then 2" +#endif + +// PAL_PRIMARY_PARTITION_PRIVATE +// 1 if the primary partition is exclusively dedicated to the ARM client applications. +// 0 if the primary partition is used for storing other files as well. +#ifndef PAL_PRIMARY_PARTITION_PRIVATE + #define PAL_PRIMARY_PARTITION_PRIVATE 0 +#endif + +//! PAL_SECONDARY_PARTITION_PRIVATE +//! 1 if the secondary partition is exclusively dedicated to the ARM client applications. +//! 0 if the secondary partition is used for storing other files as well. +#ifndef PAL_SECONDARY_PARTITION_PRIVATE + #define PAL_SECONDARY_PARTITION_PRIVATE 0 +#endif + +//! This define is the location of the primary mount point for the file system +#ifndef PAL_FS_MOUNT_POINT_PRIMARY + #define PAL_FS_MOUNT_POINT_PRIMARY "" +#endif + +//! This define is the location of the secondary mount point for the file system +#ifndef PAL_FS_MOUNT_POINT_SECONDARY + #define PAL_FS_MOUNT_POINT_SECONDARY "" +#endif + + +// Update + +#ifndef PAL_UPDATE_FIRMWARE_MOUNT_POINT + #define PAL_UPDATE_FIRMWARE_MOUNT_POINT PAL_FS_MOUNT_POINT_PRIMARY +#endif +//! The location of the firmware update folder +#ifndef PAL_UPDATE_FIRMWARE_DIR + #define PAL_UPDATE_FIRMWARE_DIR PAL_UPDATE_FIRMWARE_MOUNT_POINT "/firmware" +#endif + +#endif //_PAL_COFIGURATION_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_errors.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_errors.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _PAL_ERRORS_H +#define _PAL_ERRORS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pal_types.h" + +/*! \file pal_errors.h + * \brief PAL errors. + * This file contains PAL errors enumeration. These errors are returned to the service layer. + */ + +#define PAL_ERR_MODULE_GENERAL_BASE ((int32_t)0xFFFFFFF0) // -1 << 0x4 +#define PAL_ERR_MODULE_PAL_BASE ((int32_t)0xFFFFFFC0) // -1 << 0x6 +#define PAL_ERR_MODULE_C_BASE ((int32_t)0xFFFFFF00) // -1 << 0x8, +#define PAL_ERR_MODULE_RTOS_BASE ((int32_t)0xFFFFF000) // -1 << 0xC, +#define PAL_ERR_MODULE_NET_BASE ((int32_t)0xFFFF0000) // -1 << 0x10, +#define PAL_ERR_MODULE_TLS_BASE ((int32_t)0xFFF00000) // -1 << 0x14, +#define PAL_ERR_MODULE_CRYPTO_BASE ((int32_t)0xFF000000) // -1 << 0x18, +#define PAL_ERR_MODULE_FILESYSTEM_BASE ((int32_t)0xFC000000) +#define PAL_ERR_MODULE_INTERNAL_FLASH_BASE ((int32_t)0xFC000500) +#define PAL_ERR_MODULE_UPDATE_BASE ((int32_t)0xF0000000) // -1 << 0x1C, + + +typedef enum { + //Success Codes are positive + PAL_SUCCESS = 0, + + //All errors are Negative + // generic errors + PAL_ERR_GENERAL_BASE = PAL_ERR_MODULE_GENERAL_BASE, + PAL_ERR_GENERIC_FAILURE = PAL_ERR_GENERAL_BASE, /*! Generic failure*/ // Try to use a more specific error message whenever possible. */ + PAL_ERR_INVALID_ARGUMENT = PAL_ERR_GENERAL_BASE + 1, /*! One or more of the function arguments is invalid. */ + PAL_ERR_NO_MEMORY = PAL_ERR_GENERAL_BASE + 2, /*! Failure due to a failed attempt to allocate memory. */ + PAL_ERR_BUFFER_TOO_SMALL = PAL_ERR_GENERAL_BASE + 3, /*! The buffer given is too small. */ + PAL_ERR_NOT_SUPPORTED = PAL_ERR_GENERAL_BASE + 4, /*! The operation is not supported by PAL for the current configuration. */ + PAL_ERR_TIMEOUT_EXPIRED = PAL_ERR_GENERAL_BASE + 5, /*! The timeout for the operation has expired. */ + PAL_ERR_NOT_INITIALIZED = PAL_ERR_GENERAL_BASE + 6, /*! The timeout for the operation has expired. */ + PAL_ERR_NULL_POINTER = PAL_ERR_GENERAL_BASE + 7, /*! Received a null pointer when it should be initialized. */ + PAL_ERR_CREATION_FAILED = PAL_ERR_GENERAL_BASE + 8, /*! Failure in creation of the given type, such as mutex or thread. */ + PAL_ERR_END_OF_FILE = PAL_ERR_GENERAL_BASE + 9, /*! The reading process finished since end of file reached. */ + PAL_ERR_INVALID_TIME = PAL_ERR_GENERAL_BASE + 10, /*! Invalid time value. */ + PAL_ERR_GET_DEV_KEY = PAL_ERR_GENERAL_BASE + 11, /*! Failure deriving the key from RoT. */ + PAL_ERR_TIME_TRANSLATE = PAL_ERR_GENERAL_BASE + 12, /*! Failure to translate the time from "struct tm" to epoch time. */ + PAL_ERR_SYSCALL_FAILED = PAL_ERR_GENERAL_BASE + 13, /*! Failure of calling a system call using system, popen, exec and ect.*/ + // pal errors + PAL_ERR_NOT_IMPLEMENTED = PAL_ERR_MODULE_PAL_BASE, /*! Currently not implemented. */ + // c errors + // RTOS errors + PAL_ERR_RTOS_ERROR_BASE = PAL_ERR_MODULE_RTOS_BASE, /*! A generic failure in the RTOS module*/ // Try to use a more specific error message whenever possible. */ + PAL_ERR_RTOS_TRNG_FAILED = PAL_ERR_MODULE_RTOS_BASE + 1, + PAL_ERR_RTOS_PARAMETER = PAL_ERR_RTOS_ERROR_BASE + 0x80,/*! PAL mapping of CMSIS error `osErrorParameter`: A parameter error: A mandatory parameter was missing or specified an incorrect object. */ + PAL_ERR_RTOS_RESOURCE = PAL_ERR_RTOS_ERROR_BASE + 0x81,/*! PAL mapping of CMSIS error `osErrorResource`: Resource not available: The specified resource was not available. */ + PAL_ERR_RTOS_TIMEOUT = PAL_ERR_RTOS_ERROR_BASE + 0xC1,/*! PAL mapping of CMSIS error `osErrorTimeoutResource`: Resource not available within the given time: A specified resource was not available within the timeout period. */ + PAL_ERR_RTOS_ISR = PAL_ERR_RTOS_ERROR_BASE + 0x82,/*! PAL mapping of CMSIS error `osErrorISR`: Not allowed in ISR context: The function cannot be called from interrupt service routines. */ + PAL_ERR_RTOS_ISR_RECURSIVE = PAL_ERR_RTOS_ERROR_BASE + 0x83,/*! PAL mapping of CMSIS error `osErrorISRRecursive`: Function called multiple times from ISR with same `object.c` */ + PAL_ERR_RTOS_PRIORITY = PAL_ERR_RTOS_ERROR_BASE + 0x84,/*! PAL mapping of CMSIS error `osErrorPriority`: The system cannot determine the priority or the thread has illegal priority. */ + PAL_ERR_RTOS_NO_MEMORY = PAL_ERR_RTOS_ERROR_BASE + 0x85,/*! PAL mapping of CMSIS error `osErrorNoMemory`: The system is out of memory: It was impossible to allocate or reserve memory for the operation. */ + PAL_ERR_RTOS_VALUE = PAL_ERR_RTOS_ERROR_BASE + 0x86,/*! PAL mapping of CMSIS error `osErrorValue`: The value of a parameter is out of range. */ + PAL_ERR_RTOS_TASK = PAL_ERR_RTOS_ERROR_BASE + 0x87,/*! PAL mapping - Cannot kill own task. */ + PAL_ERR_NO_HIGH_RES_TIMER_LEFT = PAL_ERR_RTOS_ERROR_BASE + 0x88,/*! only one high resolution timer at a time is supported by pal */ + PAL_ERR_RTOS_OS = PAL_ERR_RTOS_ERROR_BASE + 0xFF,/*! PAL mapping of CMSIS error `osErrorOS`: An unspecified RTOS error: Run-time error but no other error message fits. */ + + // Network errors. + PAL_ERR_SOCKET_ERROR_BASE = PAL_ERR_MODULE_NET_BASE, /*! Generic socket error. */ + PAL_ERR_SOCKET_GENERIC = PAL_ERR_SOCKET_ERROR_BASE, /*! Generic socket error */ + PAL_ERR_SOCKET_NO_BUFFERS = PAL_ERR_SOCKET_ERROR_BASE + 1, /*! No buffers - PAL mapping of Posix error ENOBUFS. */ + PAL_ERR_SOCKET_HOST_UNREACHABLE = PAL_ERR_SOCKET_ERROR_BASE + 2, /*! Host unreachable (routing error) - PAL mapping of Posix error EHOSTUNREACH. */ + PAL_ERR_SOCKET_IN_PROGRES = PAL_ERR_SOCKET_ERROR_BASE + 3, /*! In progress - PAL mapping of Posix error EINPROGRESS. */ + PAL_ERR_SOCKET_INVALID_VALUE = PAL_ERR_SOCKET_ERROR_BASE + 4, /*! Invalid value - PAL mapping of Posix error EINVAL*/ + PAL_ERR_SOCKET_WOULD_BLOCK = PAL_ERR_SOCKET_ERROR_BASE + 5, /*! Would block - PAL mapping of Posix error EWOULDBLOCK. */ + PAL_ERR_SOCKET_ADDRESS_IN_USE = PAL_ERR_SOCKET_ERROR_BASE + 6, /*! Address in use - PAL mapping of Posix error EADDRINUSE. */ + PAL_ERR_SOCKET_ALREADY_CONNECTED = PAL_ERR_SOCKET_ERROR_BASE + 7, /*! Already connected - PAL mapping of Posix error EALREADY. */ + PAL_ERR_SOCKET_CONNECTION_ABORTED = PAL_ERR_SOCKET_ERROR_BASE + 8, /*! Connection aborted - PAL mapping of Posix error ECONNABORTED. */ + PAL_ERR_SOCKET_CONNECTION_RESET = PAL_ERR_SOCKET_ERROR_BASE + 9, /*! Connection reset - PAL mapping of Posix error ECONNRESET. */ + PAL_ERR_SOCKET_NOT_CONNECTED = PAL_ERR_SOCKET_ERROR_BASE + 10, /*! Not connected - PAL mapping of Posix error ENOTCONN. */ + PAL_ERR_SOCKET_INPUT_OUTPUT_ERROR = PAL_ERR_SOCKET_ERROR_BASE + 11, /*! I/O error - PAL mapping of Posix error EIO. */ + PAL_ERR_SOCKET_CONNECTION_CLOSED = PAL_ERR_SOCKET_ERROR_BASE + 12, /*! Connection closed. */ + PAL_ERR_SOCKET_FAILED_TO_SET_SOCKET_TO_NON_BLOCKING = PAL_ERR_SOCKET_ERROR_BASE + 13, /*! Failed to set the socket to non-blocking. */ + PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY = PAL_ERR_SOCKET_ERROR_BASE + 14, /*! Invalid Address family field. */ + PAL_ERR_SOCKET_INVALID_ADDRESS = PAL_ERR_SOCKET_ERROR_BASE + 15, /*! Address given was not valid/found. */ + PAL_ERR_SOCKET_DNS_ERROR = PAL_ERR_SOCKET_ERROR_BASE + 16, /*! DNS lookup error. */ + PAL_ERR_SOCKET_HDCP_ERROR = PAL_ERR_SOCKET_ERROR_BASE + 17, /*! HDCP error. */ + PAL_ERR_SOCKET_AUTH_ERROR = PAL_ERR_SOCKET_ERROR_BASE + 18, /*! Authentication error. */ + PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED = PAL_ERR_SOCKET_ERROR_BASE + 19, /*! Socket option not supported. */ + PAL_ERR_SOCKET_SEND_BUFFER_TOO_BIG = PAL_ERR_SOCKET_ERROR_BASE + 20, /*! Buffer sent too large (over supported MTU). */ + PAL_ERR_SOCKET_ALLOCATION_FAILED = PAL_ERR_SOCKET_ERROR_BASE + 21, /*! Failed to allocate the socket. */ + PAL_ERR_SOCKET_OPERATION_NOT_PERMITTED = PAL_ERR_SOCKET_ERROR_BASE + 22, /*! operation not permitted */ + PAL_ERR_SOCKET_MAX_NUMBER_OF_INTERFACES_REACHED = PAL_ERR_SOCKET_ERROR_BASE + 23, /*! Failed to register the new interface. */ + PAL_ERR_SOCKET_INTERRUPTED = PAL_ERR_SOCKET_ERROR_BASE + 24, /*! Function call interrupted. */ + //TLS Errors + PAL_ERR_TLS_ERROR_BASE = PAL_ERR_MODULE_TLS_BASE, + PAL_ERR_TLS_INIT = PAL_ERR_TLS_ERROR_BASE, + PAL_ERR_TLS_RESOURCE = PAL_ERR_TLS_ERROR_BASE + 1, + PAL_ERR_TLS_CONFIG_INIT = PAL_ERR_TLS_ERROR_BASE + 2, + PAL_ERR_TLS_CONTEXT_NOT_INITIALIZED = PAL_ERR_TLS_ERROR_BASE + 3, + PAL_ERR_TLS_INVALID_CIPHER = PAL_ERR_TLS_ERROR_BASE + 4, + PAL_ERR_TLS_WANT_READ = PAL_ERR_TLS_ERROR_BASE + 5, + PAL_ERR_TLS_WANT_WRITE = PAL_ERR_TLS_ERROR_BASE + 6, + PAL_ERR_TLS_CLIENT_RECONNECT = PAL_ERR_TLS_ERROR_BASE + 7, + PAL_ERR_TLS_BAD_INPUT_DATA = PAL_ERR_TLS_ERROR_BASE + 8, + PAL_ERR_TLS_HELLO_VERIFY_REQUIRED = PAL_ERR_TLS_ERROR_BASE + 9, + PAL_ERR_TLS_FAILED_TO_PARSE_CERT = PAL_ERR_TLS_ERROR_BASE + 10, + PAL_ERR_TLS_FAILED_TO_PARSE_KEY = PAL_ERR_TLS_ERROR_BASE + 11, + PAL_ERR_TLS_FAILED_TO_SET_CERT = PAL_ERR_TLS_ERROR_BASE + 12, + PAL_ERR_TLS_PEER_CLOSE_NOTIFY = PAL_ERR_TLS_ERROR_BASE + 13, + //update Error + PAL_ERR_UPDATE_ERROR_BASE = PAL_ERR_MODULE_UPDATE_BASE, /*! Generic error. */ + PAL_ERR_UPDATE_ERROR = PAL_ERR_UPDATE_ERROR_BASE, /*! Unknown error. */ + PAL_ERR_UPDATE_BUSY = PAL_ERR_UPDATE_ERROR_BASE + 1, /*! Unknown error. */ + PAL_ERR_UPDATE_TIMEOUT = PAL_ERR_UPDATE_ERROR_BASE + 2, /*! Unknown error. */ + PAL_ERR_UPDATE_OUT_OF_BOUNDS = PAL_ERR_UPDATE_ERROR_BASE + 3, /*! Unknown error. */ + PAL_ERR_UPDATE_PALFROM_API = PAL_ERR_UPDATE_ERROR_BASE + 4, /*! Unknown error. */ + PAL_ERR_UPDATE_PALFROM_IO = PAL_ERR_UPDATE_ERROR_BASE + 5, /*! Unknown error. */ + PAL_ERR_UPDATE_END_OF_IMAGE = PAL_ERR_UPDATE_ERROR_BASE + 6, /*! Unknown error. */ + PAL_ERR_UPDATE_CHUNK_TO_SMALL = PAL_ERR_UPDATE_ERROR_BASE + 7, /*! Unknown error. */ + //Crypto Errors + PAL_ERR_CRYPTO_ERROR_BASE = PAL_ERR_MODULE_CRYPTO_BASE, + PAL_ERR_AES_INVALID_KEY_LENGTH = PAL_ERR_CRYPTO_ERROR_BASE, + PAL_ERR_CERT_PARSING_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 1, + PAL_ERR_INVALID_MD_TYPE = PAL_ERR_CRYPTO_ERROR_BASE + 2, + PAL_ERR_MD_BAD_INPUT_DATA = PAL_ERR_CRYPTO_ERROR_BASE + 3, + PAL_ERR_PK_SIG_VERIFY_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 4, + PAL_ERR_ASN1_UNEXPECTED_TAG = PAL_ERR_CRYPTO_ERROR_BASE + 5, + PAL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 6, + PAL_ERR_CTR_DRBG_REQUEST_TOO_BIG = PAL_ERR_CRYPTO_ERROR_BASE + 7, + PAL_ERR_ECP_BAD_INPUT_DATA = PAL_ERR_CRYPTO_ERROR_BASE + 8, + PAL_ERR_MPI_ALLOC_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 9, + PAL_ERR_ECP_FEATURE_UNAVAILABLE = PAL_ERR_CRYPTO_ERROR_BASE + 10, + PAL_ERR_ECP_BUFFER_TOO_SMALL = PAL_ERR_CRYPTO_ERROR_BASE + 11, + PAL_ERR_MPI_BUFFER_TOO_SMALL = PAL_ERR_CRYPTO_ERROR_BASE + 12, + PAL_ERR_CMAC_GENERIC_FAILURE = PAL_ERR_CRYPTO_ERROR_BASE + 13, + PAL_ERR_NOT_SUPPORTED_ASN_TAG = PAL_ERR_CRYPTO_ERROR_BASE + 14, + PAL_ERR_PRIVATE_KEY_BAD_DATA = PAL_ERR_CRYPTO_ERROR_BASE + 15, + PAL_ERR_PRIVATE_KEY_VARIFICATION_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 16, + PAL_ERR_PUBLIC_KEY_BAD_DATA = PAL_ERR_CRYPTO_ERROR_BASE + 17, + PAL_ERR_PUBLIC_KEY_VARIFICATION_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 18, + PAL_ERR_NOT_SUPPORTED_CURVE = PAL_ERR_CRYPTO_ERROR_BASE + 19, + PAL_ERR_GROUP_LOAD_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 20, + PAL_ERR_X509_BADCERT_EXPIRED = PAL_ERR_CRYPTO_ERROR_BASE + 21, + PAL_ERR_X509_BADCERT_FUTURE = PAL_ERR_CRYPTO_ERROR_BASE + 22, + PAL_ERR_X509_BADCERT_BAD_MD = PAL_ERR_CRYPTO_ERROR_BASE + 23, + PAL_ERR_X509_BADCERT_BAD_PK = PAL_ERR_CRYPTO_ERROR_BASE + 24, + PAL_ERR_X509_BADCERT_NOT_TRUSTED = PAL_ERR_CRYPTO_ERROR_BASE + 25, + PAL_ERR_X509_BADCERT_BAD_KEY = PAL_ERR_CRYPTO_ERROR_BASE + 26, + PAL_ERR_PARSING_PRIVATE_KEY = PAL_ERR_CRYPTO_ERROR_BASE + 27, + PAL_ERR_PARSING_PUBLIC_KEY = PAL_ERR_CRYPTO_ERROR_BASE + 28, + PAL_ERR_KEYPAIR_GEN_FAIL = PAL_ERR_CRYPTO_ERROR_BASE + 29, + PAL_ERR_X509_UNKNOWN_OID = PAL_ERR_CRYPTO_ERROR_BASE + 30, + PAL_ERR_X509_INVALID_NAME = PAL_ERR_CRYPTO_ERROR_BASE + 31, + PAL_ERR_FAILED_TO_SET_KEY_USAGE = PAL_ERR_CRYPTO_ERROR_BASE + 32, + PAL_ERR_INVALID_KEY_USAGE = PAL_ERR_CRYPTO_ERROR_BASE + 33, + PAL_ERR_SET_EXTENTION_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 34, + PAL_ERR_CSR_WRITE_DER_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 35, + PAL_ERR_FAILED_TO_COPY_KEYPAIR = PAL_ERR_CRYPTO_ERROR_BASE + 36, + PAL_ERR_FAILED_TO_COPY_GROUP = PAL_ERR_CRYPTO_ERROR_BASE + 37, + PAL_ERR_FAILED_TO_WRITE_SIGNATURE = PAL_ERR_CRYPTO_ERROR_BASE + 38, + PAL_ERR_FAILED_TO_VERIFY_SIGNATURE = PAL_ERR_CRYPTO_ERROR_BASE + 39, + PAL_ERR_FAILED_TO_WRITE_PRIVATE_KEY = PAL_ERR_CRYPTO_ERROR_BASE + 40, + PAL_ERR_FAILED_TO_WRITE_PUBLIC_KEY = PAL_ERR_CRYPTO_ERROR_BASE + 41, + PAL_ERR_FAILED_TO_COMPUTE_SHRED_KEY = PAL_ERR_CRYPTO_ERROR_BASE + 42, + PAL_ERR_INVALID_X509_ATTR = PAL_ERR_CRYPTO_ERROR_BASE + 43, + PAL_ERR_INVALID_CIPHER_ID = PAL_ERR_CRYPTO_ERROR_BASE + 44, + PAL_ERR_CMAC_START_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 45, + PAL_ERR_CMAC_UPDATE_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 46, + PAL_ERR_CMAC_FINISH_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 47, + PAL_ERR_INVALID_IOD = PAL_ERR_CRYPTO_ERROR_BASE + 48, + PAL_ERR_PK_UNKNOWN_PK_ALG = PAL_ERR_CRYPTO_ERROR_BASE + 49, + PAL_ERR_PK_KEY_INVALID_VERSION = PAL_ERR_CRYPTO_ERROR_BASE + 50, + PAL_ERR_PK_KEY_INVALID_FORMAT = PAL_ERR_CRYPTO_ERROR_BASE + 51, + PAL_ERR_PK_PASSWORD_REQUIRED = PAL_ERR_CRYPTO_ERROR_BASE + 52, + PAL_ERR_PK_INVALID_PUBKEY_AND_ASN1_LEN_MISMATCH = PAL_ERR_CRYPTO_ERROR_BASE + 53, + PAL_ERR_ECP_INVALID_KEY = PAL_ERR_CRYPTO_ERROR_BASE + 55, + PAL_ERR_FAILED_SET_TIME_CB = PAL_ERR_CRYPTO_ERROR_BASE + 56, + PAL_ERR_HMAC_GENERIC_FAILURE = PAL_ERR_CRYPTO_ERROR_BASE + 57, + PAL_ERR_X509_CERT_VERIFY_FAILED = PAL_ERR_CRYPTO_ERROR_BASE + 58, + + PAL_ERR_FILESYSTEM_ERROR_BASE = PAL_ERR_MODULE_FILESYSTEM_BASE, + PAL_ERR_FS_OFFSET_ERROR = PAL_ERR_FILESYSTEM_ERROR_BASE + 1, //!< Offset given is greater than the EOF. + PAL_ERR_FS_ACCESS_DENIED = PAL_ERR_FILESYSTEM_ERROR_BASE + 2, //!< No permission to execute the command due to Permission, file in use. + PAL_ERR_FS_NAME_ALREADY_EXIST = PAL_ERR_FILESYSTEM_ERROR_BASE + 3, //!< Pathname or filename already exists. + PAL_ERR_FS_INSUFFICIENT_SPACE = PAL_ERR_FILESYSTEM_ERROR_BASE + 4, //!< Insufficient space to execute the command. + PAL_ERR_FS_INVALID_FILE_NAME = PAL_ERR_FILESYSTEM_ERROR_BASE + 5, //!< File name not valid. + PAL_ERR_FS_BAD_FD = PAL_ERR_FILESYSTEM_ERROR_BASE + 6, //!< Bad file descriptor pointer. + PAL_ERR_FS_INVALID_ARGUMENT = PAL_ERR_FILESYSTEM_ERROR_BASE + 7, //!< Invalid argument in calling function. + PAL_ERR_FS_NO_FILE = PAL_ERR_FILESYSTEM_ERROR_BASE + 8, //!< Could not find the file. + PAL_ERR_FS_NO_PATH = PAL_ERR_FILESYSTEM_ERROR_BASE + 9, //!< Could not find the path. + PAL_ERR_FS_DIR_NOT_EMPTY = PAL_ERR_FILESYSTEM_ERROR_BASE + 10, //!< Directory not empty. + PAL_ERR_FS_INVALID_FS = PAL_ERR_FILESYSTEM_ERROR_BASE + 11, //!< Invalid file system mounting or drive. + PAL_ERR_FS_TOO_MANY_OPEN_FD = PAL_ERR_FILESYSTEM_ERROR_BASE + 12, //!< Too many open file descriptors simultaneously. + PAL_ERR_FS_FILENAME_LENGTH = PAL_ERR_FILESYSTEM_ERROR_BASE + 13, //!< File name is too long or invalid. + PAL_ERR_FS_LENGTH_ERROR = PAL_ERR_FILESYSTEM_ERROR_BASE + 14, //!< Given length to read/write is wrong. + PAL_ERR_FS_BUFFER_ERROR = PAL_ERR_FILESYSTEM_ERROR_BASE + 15, //!< Given buffer is not initialized. + PAL_ERR_FS_ERROR = PAL_ERR_FILESYSTEM_ERROR_BASE + 16, //!< Generic file system error. + PAL_ERR_FS_BUSY = PAL_ERR_FILESYSTEM_ERROR_BASE + 17, //!< File/directory is open. + PAL_ERR_FS_INVALID_OPEN_FLAGS = PAL_ERR_FILESYSTEM_ERROR_BASE + 18, //!< File open mode is invalid. + PAL_ERR_FS_FILE_IS_DIR = PAL_ERR_FILESYSTEM_ERROR_BASE + 19, //!< File path given is a directory, not a file. + PAL_ERR_FS_ERROR_IN_SEARCHING = PAL_ERR_FILESYSTEM_ERROR_BASE + 20, //!< Next file in directory could not be found. + + + PAL_ERR_INTERNAL_FLASH_ERROR_BASE = PAL_ERR_MODULE_INTERNAL_FLASH_BASE, + PAL_ERR_INTERNAL_FLASH_GENERIC_FAILURE = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x01, + PAL_ERR_INTERNAL_FLASH_SECTOR_NOT_ALIGNED = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x02, + PAL_ERR_INTERNAL_FLASH_ADDRESS_NOT_ALIGNED = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x03, + PAL_ERR_INTERNAL_FLASH_CROSSING_SECTORS = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x04, + PAL_ERR_INTERNAL_FLASH_NULL_PTR_RECEIVED = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x05, + PAL_ERR_INTERNAL_FLASH_WRONG_SIZE = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x06, + PAL_ERR_INTERNAL_FLASH_BUFFER_ADDRESS_NOT_ALIGNED = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x07, + PAL_ERR_INTERNAL_FLASH_INIT_ERROR = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x08, + PAL_ERR_INTERNAL_FLASH_WRITE_ERROR = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x09, + PAL_ERR_INTERNAL_FLASH_BUFFER_SIZE_NOT_ALIGNED = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x0A, + PAL_ERR_INTERNAL_FLASH_ERASE_ERROR = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x0B, + PAL_ERR_INTERNAL_FLASH_NOT_INIT_ERROR = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x0C, + PAL_ERR_INTERNAL_FLASH_MUTEX_RELEASE_ERROR = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x0D, //!< Mutex release or/and read/write/erase commands failed + PAL_ERR_INTERNAL_FLASH_FLASH_ZERO_SIZE = PAL_ERR_MODULE_INTERNAL_FLASH_BASE + 0x0E, + +} palError_t; /*! errors returned by the pal service API */ + + +#ifdef __cplusplus +} +#endif +#endif //_PAL_ERRORS
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_fileSystem.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_fileSystem.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,431 @@ +#ifndef PAL_FILE_SYSTEM_H +#define PAL_FILE_SYSTEM_H + +/*! \file pal_fileSystem.h + * \brief PAL pal_fileSystem. +* This file contains the file system APIs. This is part of the PAL service API. +* It provides APIs to create/remove directories and open/read/write to files. + */ + +/*! \mainpage + * + *\section file_sec File System + * + *\subsection rev_hist Revision History + * 19-Jan-2017 Created and First Draft\n + * 25-Jan-2017 Updated Design according to DR meeting \n + * 02-Jan-2017 Minor implementation Changes \n + * + * + * + * \subsection int_sec Introduction +* This file gives the user an abstraction layer for POSIX like file systems. + * + * + * \subsection req_sec Requirements + * The requirements for PAL Version 1.2 are to support the following POSIX like APIs: + * + * + * + *\b Folder \b Operations \n + * -# mkdir <a href="linkURL"> http://man7.org/linux/man-pages/man2/mkdir.2.html</a> \n + * -# rmdir() <a href="linkURL"> http://man7.org/linux/man-pages/man2/rmdir.2.html</a> \n + * + * + *\b File \b Operations \n + * -# fopen() <a href="linkURL"> http://man7.org/linux/man-pages/man3/fopen.3.html</a> \n + * -# fclose() <a href="linkURL"> http://man7.org/linux/man-pages/man3/fclose.3.html</a> \n + * -# fread() <a href="linkURL"> http://man7.org/linux/man-pages/man3/fwrite.3.html</a> \n + * -# fwrite() <a href="linkURL"> http://man7.org/linux/man-pages/man3/fwrite.3.html</a> \n + * -# fseek() <a href="linkURL"> http://man7.org/linux/man-pages/man3/fseek.3.html</a> \n + * -# ftell() <a href="linkURL"> http://man7.org/linux/man-pages/man3/fseek.3.html</a> \n + * -# unlink() <a href="linkURL"> http://man7.org/linux/man-pages/man2/unlink.2.html</a> \n + * + * + *\b Special \b Operations\n + +* -# rmfiles() Delete folder content (files only) (flat deletion). +* -# cpfiles() Copy all files in folder to a different folder (flat copy). + * + * + * \subsection Prerequisites +* User need to set up the file system on your project and mount the proper drive if needed. \n + * + * + * \subsection Limitations +* -# File size: Up to 2 GiB.\n +* -# Filename length: PAL_MAX_FILE_NAME_SIZE.\n +* -# Legal characters for object name: (file/directory name) are, (0-9), (a-z), (A - Z) (_ . # ). \n +* -# System is case-insensitive. \n +* -# The root folder can manage a maximum of 512 entries +* -# Max path length is 66 Characters. +* -# Folder shall be separated with "/" +* -# All folder Paths shall end with "/" + + * + * + * \subsection References + * PAL_FileSystemSpecification.doc + */ + +/*! @defgroup PAL_GROUP_FS + * + * + */ +/** + @defgroup PAL_DEFINES PAL Services Defined Symbols & Macros + @ingroup PAL_GROUP_FS + */ + +/** + @defgroup PAL_ENUM PAL Services Enumerated Data Types + @ingroup PAL_GROUP_FS + */ + +/** + @defgroup PAL_PUBLIC_FUNCTION PAL Services Public Functions + @ingroup PAL_GROUP_FS + */ + +/** + @addtogroup PAL_DEFINES + @{*/ + + +#define PAL_MAX_FILE_NAME_SIZE 8 //!< Max length for file name received by user. +#define PAL_MAX_FILE_NAME_SUFFIX 3 //!< Max length for file name suffix. +#define PAL_MAX_FOLDER_DEPTH_CHAR 66 //!< Max folder length in chars. +#define PAL_MAX_FILE_AND_FOLDER_LENGTH (PAL_MAX_FILE_NAME_SIZE + PAL_MAX_FILE_NAME_SUFFIX + PAL_MAX_FOLDER_DEPTH_CHAR + 1) //plus 1 is for "." +#define PAL_MAX_FULL_FILE_NAME (PAL_MAX_FILE_NAME_SUFFIX + PAL_MAX_FOLDER_DEPTH_CHAR + 1) //plus 1 is for ".") + +typedef uintptr_t palFileDescriptor_t; //!< Pointer to a generic File Descriptor object + +/** + @} */ +/** + @addtogroup PAL_ENUM + @{*/ + +/** \brief Enum for `fseek()` relative options. */ +typedef enum { + PAL_FS_OFFSET_KEEP_FIRST = 0, + PAL_FS_OFFSET_SEEKSET, //!< Relative to the start of the file. + PAL_FS_OFFSET_SEEKCUR, //!< The current position indicator. + PAL_FS_OFFSET_SEEKEND, //!< End-of-file. + PAL_FS_OFFSET_KEEP_LAST, + +} pal_fsOffset_t; + +/** \brief Enum for fopen() permission options*/ +typedef enum { + PAL_FS_FLAG_KEEP_FIRST = 0, + PAL_FS_FLAG_READONLY, //!< Open file for reading. The stream is positioned at the beginning of the file (file must exist), same as "r".\n + PAL_FS_FLAG_READWRITE, //!< Open for reading and writing. The stream is positioned at the beginning of the file (file must exist), same as "r+ ".\n + PAL_FS_FLAG_READWRITEEXCLUSIVE, //!< Open for reading and writing exclusively. If the file already exists, `fopen()` fails. The stream is positioned at the beginning of the file. same as "w+x"\n + PAL_FS_FLAG_READWRITETRUNC, //!< Open for reading and writing exclusively. If the file already exists, trunced file. The stream is positioned at the beginning of the file. same as "w+"\n + PAL_FS_FLAG_KEEP_LAST, +} pal_fsFileMode_t; +/** + @} */ + + +/** \brief Enum for partition access. */ +typedef enum { + PAL_FS_PARTITION_PRIMARY = 0, //!< Primary partition.\n + PAL_FS_PARTITION_SECONDARY, //!< Seconday partition.\n + PAL_FS_PARTITION_LAST +} pal_fsStorageID_t; + + +/** + @addtogroup PAL_PUBLIC_FUNCTION + @{*/ + +/*! \brief This function attempts to create a directory named \c pathName. + * + +* @param[in] *pathName A pointer to the null-terminated string that specifies the directory name to create. + + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * +* \note To remove a directory, use \c PAL_ERR_FS_rmdir. + * + *\b Example + \code{.cpp} + palStatus_t ret; + ret = PAL_ERR_FS_mkdir("Dir1"); + if(!ret) + { + //Error + } + \endcode + */ +palStatus_t pal_fsMkDir(const char *pathName); + +/*! \brief This function deletes a directory + * + +* @param[in] *pathName A pointer to the null-terminated string that specifies the directory name to be deleted. + + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * + +* \note The deleted directory \b must \b be \b empty and \b closed and the +* folder path shall end with "/". + + * + *\b Example + \code{.cpp} + palStatus_t ret; + ret = PAL_ERR_FS_mkdir("Dir1"); //Create folder name "Dir1" + if(!ret) + { + //Error + } + ret = PAL_ERR_FS_rmdir("Dir1); //Remove directory from partition + if(!ret) + { + //Error + } + \endcode + */ +palStatus_t pal_fsRmDir(const char *pathName); + + +/*!\brief This function opens the file whose name is specified in the parameter `pathName` and associates it with a stream +* that can be identified in future operations by the `fd` pointer returned. + * +* @param[out] fd The file descriptor to the file entered in the `pathName`. +* @param[in] *pathName A pointer to the null-terminated string that specifies the file name to open or create. +* @param[in] mode A mode flag that specifies the type of access and open method for the file. + + * + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * + +* \note The folder path shall end with "/". + + * + *\b Example + \code{.cpp} + //Copy File from "File1" to "File2" + palStatus_t ret; + palFileDescriptor_t fd1 = NULL,fd2 = NULL ; // File Object 1 & 2 + uint8 buffer[1024]; + size_t bytes_read = 0, Bytes_wrote = 0; + + //Open first file with Read permission + ret = PAL_ERR_FS_fopen(&fd1, "File1", PAL_ERR_FS_READWRITEEXCLUSIVE); + if(ret) {//Error} + + //Create second file with Read/Write permissions + ret = PAL_ERR_FS_fopen(&fd2, "File2", PAL_ERR_FS_READWRITEEXCLUSIVE); + if(ret) {//Error} + + // Copy source to destination + for (;;) + { + ret = PAL_ERR_FS_read(&fd1, buffer, sizeof(buffer), &bytes_read); // Read a chunk of source file + if (ret || bytes_read == 0) break; // error or EOF + ret = PAL_ERR_FS_write(&fd2, buffer, sizeof(buffer), &Bytes_wrote); // Write it to the destination file + if (ret || Bytes_wrote < bytes_read) break; // error or disk full + } + + PAL_ERR_FS_close(&fd1); + PAL_ERR_FS_close(&fd2); + } + \endcode + */ +palStatus_t pal_fsFopen(const char *pathName, pal_fsFileMode_t mode, + palFileDescriptor_t *fd); + +/*! \brief This function closes an open file object. + * +* @param[in] fd A pointer to the open file object structure to be closed. + * + * +* \return PAL_SUCCESS upon successful operation. \n +* PAL_FILE_SYSTEM_ERROR - see error code \c palError_t. + * +* \note When the function has completed successfully, the file object is no longer valid and it can be discarded. + * + */ +palStatus_t pal_fsFclose(palFileDescriptor_t *fd); + + +/*! \brief This function reads an array of bytes from the stream and stores it in the block of memory +* specified by buffer. The position indicator of the stream is advanced by the total amount of bytes read. + * +* @param[in] fd A pointer to the open file object structure. +* @param[in] buffer The buffer to store the read data. +* @param[in] numOfBytes The number of bytes to read. +* @param[out] numberOfBytesRead The number of bytes read. + + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * +* \note When the function has completed successfully, +* `numberOfBytesRead` should be checked to detect end of the file. +* If `numberOfBytesRead` is less than `numOfBytes`, +* the read/write pointer has reached the end of the file during the read operation or there is an error. + * + */ +palStatus_t pal_fsFread(palFileDescriptor_t *fd, void * buffer, + size_t numOfBytes, size_t *numberOfBytesRead); + +/*! \brief This function starts to write data from \c buffer to the file at the position pointed by the read/write pointer. + * + +* @param[in] fd A pointer to the open file object structure. +* @param[in] buffer A pointer to the data to be written. +* @param[in] numOfBytes The number of bytes to write. +* @param[out] numberOfBytesWritten The number of bytes written. + * +* \return PAL_SUCCESS upon successful operation. \n +* PAL_FILE_SYSTEM_ERROR - see error code \c palError_t. + * +* \note The read/write pointer advances as number of bytes written. When the function has completed successfully, +* \note `numberOfBytesWritten` should be checked to detect the whether the disk is full. +* If `numberOfBytesWritten` is less than `numOfBytes`, the volume got full during the write operation. + + * + */ +palStatus_t pal_fsFwrite(palFileDescriptor_t *fd, const void * buffer, + size_t numOfBytes, size_t *numberOfBytesWritten); + + +/*! \brief This function moves the file read/write pointer without any read/write operation to the file. + * +* @param[in] fd A pointer to the open file object structure. +* @param[in] offset The byte offset from the top of the file to set the read/write pointer. +* @param[out] whence Where the offset is relative to. + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * +* \note The `whence` options are: \n +* -# PAL_ERR_FS_SEEKSET - Relative to the start of the file. +* -# PAL_ERR_FS_SEEKCUR - The current position indicator. +* -# PAL_ERR_FS_SEEKEND - End-of-file. + * + *\b Example + \code{.cpp} + palStatus_t ret; + palFileDescriptor_t fd1 = NULL; // File Object 1 + uint8 buffer[1024]; + size_t bytes_read = 0, Bytes_wrote = 0; + + //Open file with Read permission + ret = PAL_ERR_FS_fopen(&fd1, "File1", PAL_ERR_FS_READ); + if(ret) {//Error} + + ret = PAL_ERR_FS_fseek(&fd1, 500, PAL_ERR_FS_SEEKSET) + + \endcode + */ +palStatus_t pal_fsFseek(palFileDescriptor_t *fd, int32_t offset, + pal_fsOffset_t whence); + +/*! \brief This function gets the current read/write pointer of a file. + * +* @param[in] fd A pointer to the open file object structure. + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * + */ +palStatus_t pal_fsFtell(palFileDescriptor_t *fd, int32_t *pos); + +/*! \brief This function deletes a \b single file from the file system. + * +* @param[in] pathName A pointer to a null-terminated string that specifies the \b file to be removed. + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * +* \note The file \b must \b not \b be \b open. + * + */ +palStatus_t pal_fsUnlink(const char *pathName); + +/*! \brief This function deletes \b all files and folders in a folder from the file system (FLAT remove only). + * +* @param[in] pathName A pointer to a null-terminated string that specifies the folder. + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * +* \note The folder \b must \b not \b be \b open and the folder path must end with "/". + */ +palStatus_t pal_fsRmFiles(const char *pathName); + +/*! \brief This function copies \b all files from the source folder to the destination folder (FLAT copy only). + * +* @param[in] pathNameSrc A pointer to a null-terminated string that specifies the source folder. +* @param[in] pathNameDest A pointer to a null-terminated string that specifies the destination folder (MUST exist). + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * +* \note Both folders \b must \b not \b be \b open. If the folders do not exist, the function fails. + * + * + */ +palStatus_t pal_fsCpFolder(const char *pathNameSrc, char *pathNameDest); + +/*! \brief This function sets the mount directory for the given storage ID (primary or secondary), + * +* @param[in] Path A pointer to a null-terminated string that specifies the root folder. + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * +*\note If called with NULL, the ESFS root folder is set to default PAL_SOURCE_FOLDER. +*\note The folder path must end with "/". + */ +palStatus_t pal_fsSetMountPoint(pal_fsStorageID_t dataID, const char *Path); + +/*! \brief This function gets the mount directory for the given storage ID (primary or secondary), The function copies the path to the user pre allocated buffer. + * +* @param[in] length The length of the buffer. +* @param[out] Path A pointer to \b pre-allocated \b buffer with \b size \c PAL_MAX_FOLDER_DEPTH_CHAR + 1 chars. + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. + * +* \note The plus 1 is for the '\0' terminator at the end of the buffer. + */ +palStatus_t pal_fsGetMountPoint(pal_fsStorageID_t dataID, size_t length, char *Path); + + +/*! \brief This function formats the SD partition indentified by the `partitionID` parameter. + * +* @param[in] partitionID The ID of the partition to be formatted. (**Note:** The actual partition values mapped to the IDs is determined by the porting layer.) + * + * \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t. \n +* PAL_ERR_INVALID_ARGUMENT - an invalid `partitionID`. + */ +palStatus_t pal_fsFormat(pal_fsStorageID_t dataID); + + +/*! \brief This function will return if the partition used by pal only or not + * + * @param[in] dataID - the ID of the data to be cleared (Note: the actual partition values mapped the IDs will be determined by the porting layer) + * + * \return true - if partition is used only by pal.\n + * false - if partition is used by other component then pal.\n + */ +bool pal_fsIsPrivatePartition(pal_fsStorageID_t dataID); + +/** + @} */ + +#endif//test
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_internalFlash.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_internalFlash.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,111 @@ +#ifndef PAL_FLASH_H +#define PAL_FLASH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \brief This function initialized the flash API module, + * And should be called prior flash APIs calls + * + * \return PAL_SUCCESS upon successful operation. \n + * PAL_FILE_SYSTEM_ERROR - see error code \c palError_t. + * + * \note should be called only once unless \c pal_internalFlashDeinit function is called + * \note This function is Blocking till completion!! + * + */ +palStatus_t pal_internalFlashInit(void); + +/*! \brief This function destroy the flash module + * + * \return PAL_SUCCESS upon successful operation. \n + * PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. + * + * \note Should be called only after \c pal_internalFlashinit() is called. + * \note Flash APIs will not work after calling this function + * \note This function is Blocking till completion!! + * + */ +palStatus_t pal_internalFlashDeInit(void); + +/*! \brief This function writes to the internal flash +* +* @param[in] buffer - pointer to the buffer to be written +* @param[in] size - the size of the buffer in bytes. +* @param[in] address - the address of the internal flash, must be aligned to minimum writing unit (page size). +* +* \return PAL_SUCCESS upon successful operation. \n +* PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. +* +* \note ALL address can be written to!! No protection to boot loader, program or other... +* \note This function is Blocking till completion!! +* \note This function is Thread Safe!! +*/ +palStatus_t pal_internalFlashWrite(const size_t size, const uint32_t address, const uint32_t * buffer); + +/*! \brief This function copies the memory data into the user given buffer +* +* @param[in] size - the size of the buffer in bytes. +* @param[in] address - the address of the internal flash. +* @param[out] buffer - pointer to the buffer to write to +* +* \return PAL_SUCCESS upon successful operation. \n +* PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. +* \note This function is Blocking till completion!! +* \note This function is Thread Safe!! +* +*/ +palStatus_t pal_internalFlashRead(const size_t size, const uint32_t address, uint32_t * buffer); + +/*! \brief This function Erase the sector +* +* @param[in] size - the size to be erased +* @param[in] address - sector start address to be erased, must be align to sector. +* +* \return PAL_SUCCESS upon successful operation. \n +* PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. +* +* \note ALL sectors can be erased!! No protection to bootloader, program or other... +* \note This function is Blocking till completion!! +* \note Only one sector can be erased in each function call +* \note This function is Thread Safe!! +*/ +palStatus_t pal_internalFlashErase(uint32_t address, size_t size); + + +/*! \brief This function returns the minimum writing unit to the flash +* +* \return size_t the 2, 4, 8.... +*/ +size_t pal_internalFlashGetPageSize(void); + + +/*! \brief This function returns the sector size for the given address + * +* @param[in] the starting address of the sector is question +* +* \return size of sector, 0 if error +*/ +size_t pal_internalFlashGetSectorSize(uint32_t address); + + +/////////////////////////////////////////////////////////////// +////-------------------SOTP functions------------------------// +/////////////////////////////////////////////////////////////// + +/*! \brief This function return the SOTP section data +* +* @param[in] section - the section number (0 or 1) +* @param[out] data - the information about the section +* +* \return PAL_SUCCESS upon successful operation. \n +* PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. +* +*/ +palStatus_t pal_internalFlashGetAreaInfo(bool section, palSotpAreaData_t * data); + +#ifdef __cplusplus +} +#endif +#endif //PAL_FLASH_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_macros.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_macros.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,245 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef _PAL_MACROS_H +#define _PAL_MACROS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pal_errors.h" +#include "pal_types.h" // is needed for PRIu types +//for PAL_LOG prints +#include "mbed-trace/mbed_trace.h" +#include "assert.h" +/*! \file pal_macros.h +* \brief PAL macros. +* This file contains macros defined by PAL for constant values and network purposes. +*/ + +// Maximum integer types. +#define PAL_MAX_UINT8 0xFFU +#define PAL_MAX_UINT16 0xFFFFU +#define PAL_MAX_UINT32 0xFFFFFFFFUL +#define PAL_MAX_INT32 0x7FFFFFFFL +#define PAL_MIN_INT32 0x80000000L +#define PAL_MAX_UINT64 0xFFFFFFFFFFFFFFFFULL +#define PAL_MAX_INT64 0x7FFFFFFFFFFFFFFFLL + +// Useful macros. + +#define PAL_MAX(a,b) ((a) > (b) ? (a) : (b)) + +#define PAL_MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define PAL_DIVIDE_ROUND_UP(num, divider) (((num) + (divider) - 1) / (divider)) + +#if PAL_COMPILATION_ENDIANITY == 1 +#define BIG__ENDIAN 1 +#elif PAL_COMPILATION_ENDIANITY == 0 +#define LITTLE__ENDIAN 1 +#else +#error neither BIG__ENDIAN nor LITTLE__ENDIAN defined, cannot compile +#endif + +// Endianity macros. +#ifdef LITTLE__ENDIAN + +#define PAL_HTONS(x) (((((unsigned short)(x)) >> 8) & 0xff) | \ + ((((unsigned short)(x)) & 0xff) << 8)) +#define PAL_NTOHS(x) (((((unsigned short)(x)) >> 8) & 0xff) | \ + ((((unsigned short)(x)) & 0xff) << 8) ) +#define PAL_HTONL(x) ((((x)>>24) & 0xffL) | (((x)>>8) & 0xff00L) | \ + (((x)<<8) & 0xff0000L) | (((x)<<24) & 0xff000000L)) +#define PAL_NTOHL(x) ((((x)>>24) & 0xffL) | (((x)>>8) & 0xff00L) | \ + (((x)<<8) & 0xff0000L) | (((x)<<24) & 0xff000000L)) + +#elif defined(BIG__ENDIAN) + +#define PAL_HTONS(x) (x) +#define PAL_NTOHS(x) (x) +#define PAL_HTONL(x) (x) +#define PAL_NTOHL(x) (x) +#else +#error neither BIG__ENDIAN nor LITTLE__ENDIAN defined, cannot compile +#endif + + +#define PAL_GET_LOWER_8BITS(x) (x & 0xFF) +#define PAL_GET_THREAD_INDEX(x) (PAL_GET_LOWER_8BITS(x)) + +#define PAL_INVERSE_UINT16_BYTES( val ) \ + ( ((val) << 8) | (((val) & 0x0000FF00) >> 8)) + +#define PAL_INVERSE_UINT32_BYTES( val ) \ + ( ((val) >> 24) | (((val) & 0x00FF0000) >> 8) | (((val) & 0x0000FF00) << 8) | (((val) & 0x000000FF) << 24) ) + +#define PAL_INVERSE_UINT64_BYTES( val ) \ + ((PAL_INVERSE_UINT32_BYTES( ((val >> 16) >> 16)) &0xffffffff) | ((((uint64_t)PAL_INVERSE_UINT32_BYTES(val & 0xffffffff))<<16)<<16)) + +/* Set of Macros similar to the HTONS/L, NTOHS/L ones but converting to/from little endian instead of big endian. */ +#ifdef LITTLE__ENDIAN +#define PAL_LITTLE_ENDIAN_TO_HOST_16BIT(x) (x) +#define PAL_LITTLE_ENDIAN_TO_HOST_32BIT(x) (x) +#define PAL_LITTLE_ENDIAN_TO_HOST_64BIT(x) (x) +#define PAL_HOST_TO_LITTLE_ENDIAN_16BIT(x) (x) +#define PAL_HOST_TO_LITTLE_ENDIAN_32BIT(x) (x) +#define PAL_HOST_TO_LITTLE_ENDIAN_64BIT(x) (x) + + + +#if defined(__arm__) || defined(__IAR_SYSTEMS_ICC__) // Compile with ARMCC, GCC_ARM or IAR compilers. + #define PAL_TARGET_POINTER_SIZE __sizeof_ptr + #ifdef __BIG_ENDIAN + #define PAL_COMPILATION_ENDIANITY 1 // Define PAL compilation endian (0 is little endian, 1 is big endian). + #else + #define PAL_COMPILATION_ENDIANITY 0 // Define PAL compilation endian (0 is little endian, 1 is big endian). + #endif +#elif defined(__GNUC__) // Compiling with GCC. + #define PAL_TARGET_POINTER_SIZE __SIZEOF_POINTER__ + #ifdef __BYTE_ORDER + #if __BYTE_ORDER == __BIG_ENDIAN // If both are not defined it is TRUE! + #define PAL_COMPILATION_ENDIANITY 1 // Define PAL compilation endian (0 is little endian, 1 is big endian). + #elif __BYTE_ORDER == __LITTLE_ENDIAN + #define PAL_COMPILATION_ENDIANITY 0// Define PAL compilation endian (0 is little endian, 1 is big endian). + #else + #error missing endiantiy defintion for GCC + #endif + #endif +#else + #error neither ARM target compilers nor GCC used for compilation - not supported +#endif + + + +#elif defined(BIG__ENDIAN) +#define PAL_LITTLE_ENDIAN_TO_HOST_16BIT(x) (PAL_INVERSE_UINT16_BYTES(((uint16_t)x))) +#define PAL_LITTLE_ENDIAN_TO_HOST_32BIT(x) (PAL_INVERSE_UINT32_BYTES(((uint32_t)x))) +#define PAL_LITTLE_ENDIAN_TO_HOST_64BIT(x) (PAL_INVERSE_UINT64_BYTES(((uint64_t)x))) +#define PAL_HOST_TO_LITTLE_ENDIAN_16BIT(x) (PAL_INVERSE_UINT16_BYTES(((uint16_t)x))) +#define PAL_HOST_TO_LITTLE_ENDIAN_32BIT(x) (PAL_INVERSE_UINT32_BYTES(((uint32_t)x))) +#define PAL_HOST_TO_LITTLE_ENDIAN_64BIT(x) (PAL_INVERSE_UINT64_BYTES(((uint64_t)x))) + +#else +#error neither BIG__ENDIAN nor LITTLE__ENDIAN defined, cannot compile +#endif + + +#define PAL_MODULE_INIT(INIT) INIT= 1 +#define PAL_MODULE_DEINIT(INIT) INIT= 0 + +//!< Time utility values +#define PAL_SECONDS_PER_MIN 60 +#define PAL_SECONDS_PER_HOUR 3600 +#define PAL_SECONDS_PER_DAY 86400 +#define PAL_FEB_MONTH 2 +#define PAL_MILLI_PER_SECOND 1000 +#define PAL_NANO_PER_MILLI 1000000L +#define PAL_NANO_PER_SECOND 1000000000L +#define PAL_MILLI_TO_NANO(x) (((x) % PAL_MILLI_PER_SECOND) * PAL_NANO_PER_MILLI) +#define PAL_MIN_SEC_FROM_EPOCH 1487015542 ////at least 47 years passed from 1.1.1970 in seconds + +//!< Define static function and inline function. +#if defined (__CC_ARM) /* ARM compiler. */ + #define PAL_INLINE __inline +#elif defined (__GNUC__) /* GNU compiler. */ + #define PAL_INLINE __attribute__((always_inline)) __inline +#else + #define PAL_INLINE //!< User should provide the compiler inline function command. +#endif + +#define PAL_PRIVATE static + +#if defined (__CC_ARM) /* ARM compiler. */ +#define PAL_PRAGMA(x) +#define PAL_DEPRECATED(x) +#else +#define PAL_PRAGMA(x) _Pragma (#x) +#define PAL_DEPRECATED(x) PAL_PRAGMA(message ("!!! PAL DEPRECATED CODE- " #x)) +#endif + +#ifdef DEBUG + +#define PAL_MODULE_IS_INIT(INIT) if(!INIT) return PAL_ERR_NOT_INITIALIZED; + + +#else +#define PAL_MODULE_IS_INIT(INIT) (void)INIT + +#endif //DEBUG + +// Compile time assert. +#define PAL_ASSERT_STATIC(e) \ + do { \ + enum { assert_static__ = 1/(e) }; \ + } while (0) + +#define PAL_UNUSED_ARG(x) (void)(x) + + + + + +//for non recoverable errors +#define PAL_LOG_ASSERT( ARGS...) \ +{ \ + tr_err(ARGS); \ + assert(0);\ +} + + + +#define PAL_LOG_ERR_FUNC tr_err +#define PAL_LOG_WARN_FUNC tr_warn +#define PAL_LOG_INFO_FUNC tr_info +#define PAL_LOG_DBG_FUNC tr_debug + +// Little trick with mbed-trace error level is equal to function name handling the same level of log output +#define PAL_LOG_LEVEL_ERR TRACE_LEVEL_ERROR +#define PAL_LOG_LEVEL_WARN TRACE_LEVEL_WARN +#define PAL_LOG_LEVEL_INFO TRACE_LEVEL_INFO +#define PAL_LOG_LEVEL_DBG TRACE_LEVEL_DEBUG + +#define PAL_LOG_ERR( ARGS...) PAL_LOG_ERR_FUNC(ARGS); +#define PAL_LOG_WARN( ARGS...) PAL_LOG_WARN_FUNC(ARGS); +#define PAL_LOG_INFO( ARGS...) PAL_LOG_INFO_FUNC(ARGS); +#define PAL_LOG_DBG( ARGS...) PAL_LOG_DBG_FUNC(ARGS); + + +#define PAL_LOG(LOG_LEVEL, ARGS...) tracef(PAL_LOG_LEVEL_##LOG_LEVEL, "PAL" , ARGS); + + +#ifdef DEBUG +#ifdef VERBOSE +#define PAL_PRINTF( ARGS...) \ + #define PAL_PRINTF(fmt, ...) PAL_LOG(DBG, "%s:%d: " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); +#else +#define PAL_PRINTF( ARGS...) \ + PAL_LOG(DBG, ARGS); +#endif +#else + #define PAL_PRINTF( ARGS...) +#endif + +#define DEBUG_PRINT(ARGS...) PAL_PRINTF(ARGS) + + +#ifdef __cplusplus +} +#endif +#endif //_PAL_MACROS_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_network.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_network.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,350 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef _PAL_SOCKET_H +#define _PAL_SOCKET_H + +#include "pal_rtos.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \file pal_network.h +* \brief PAL network. +* This file contains the network APIs and it is a part of the PAL service API. +* It provides network functionalities for UDP and TCP sockets and connections. +*/ + +//! PAL network socket API \n +//! PAL network sockets configurations options: \n +//! Set PAL_NET_TCP_AND_TLS_SUPPORT to true if TCP is supported by the platform and is required. \n +//! Set PAL_NET_ASYNCHRONOUS_SOCKET_API to true if asynchronous socket API is supported by the platform and is required: Currently MANDATORY. +//! Set PAL_NET_DNS_SUPPORT to true if DNS URL lookup API is supported. + +typedef uint32_t palSocketLength_t; /*! The length of data. */ +typedef void* palSocket_t; /*! PAL socket handle type. */ + +#define PAL_NET_MAX_ADDR_SIZE 32 // check if we can make this more efficient + +typedef struct palSocketAddress { + unsigned short addressType; /*! Address family for the socket. */ + char addressData[PAL_NET_MAX_ADDR_SIZE]; /*! Address (based on protocol). */ +} palSocketAddress_t; /*! Address data structure with enough room to support IPV4 and IPV6. */ + +typedef struct palNetInterfaceInfo{ + char interfaceName[16]; //15 + â\0â + palSocketAddress_t address; + uint32_t addressSize; +} palNetInterfaceInfo_t; + +typedef enum { + PAL_AF_UNSPEC = 0, + PAL_AF_INET = 2, /*! Internet IP Protocol. */ + PAL_AF_INET6 = 10, /*! IP version 6. */ +} palSocketDomain_t;/*! Network domains supported by PAL. */ + +typedef enum { +#if PAL_NET_TCP_AND_TLS_SUPPORT + PAL_SOCK_STREAM = 1, /*! Stream socket. */ + PAL_SOCK_STREAM_SERVER = 99, /*! Stream socket. */ +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + PAL_SOCK_DGRAM = 2 /*! Datagram socket. */ +} palSocketType_t;/*! Socket types supported by PAL. */ + + +typedef enum { + PAL_SO_REUSEADDR = 0x0004, /*! Allow local address reuse. */ +#if PAL_NET_TCP_AND_TLS_SUPPORT // Socket options below supported only if TCP is supported. + PAL_SO_KEEPALIVE = 0x0008, /*! Keep TCP connection open even if idle using periodic messages. */ + PAL_SO_KEEPIDLE = 0x0009, /*! The time (in seconds) the connection needs to remain idle before TCP starts sending keepalive probes, if the socket option SO_KEEPALIVE has been set on this socket. */ + PAL_SO_KEEPINTVL = 0x0010, /*! The time (in seconds) between individual keepalive probes */ +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + PAL_SO_SNDTIMEO = 0x1005, /*! Send timeout. */ + PAL_SO_RCVTIMEO = 0x1006, /*! Receive timeout. */ +} palSocketOptionName_t;/*! Socket options supported by PAL. */ + +#define PAL_NET_DEFAULT_INTERFACE 0xFFFFFFFF + +#define PAL_IPV4_ADDRESS_SIZE 4 +#define PAL_IPV6_ADDRESS_SIZE 16 + +typedef uint8_t palIpV4Addr_t[PAL_IPV4_ADDRESS_SIZE]; +typedef uint8_t palIpV6Addr_t[PAL_IPV6_ADDRESS_SIZE]; + + +/*! Register a network interface for use with PAL sockets. Must be called before other socket functions. Most APIs will not work before a single interface is added. +* @param[in] networkInterfaceContext The network interface to be added (OS specific. For example in mbed OS, this is the `NetworkInterface` object pointer for the network adapter [**Note:** We assume that connect has already been called on this]). If not available use NULL. +* @param[out] interfaceIndex Contains the index assigned to the interface in case it has been assigned successfully. This index can be used, when creating a socket, to bind the socket to the interface. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_registerNetworkInterface(void* networkInterfaceContext, uint32_t* interfaceIndex); + +/*! Set a port to `palSocketAddress_t`. \n +* You can set it either directly or via the `palSetSockAddrIPV4Addr` or `palSetSockAddrIPV6Addr` functions. +* @param[in,out] address The address to set. +* @param[in] port The port number to set. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +\note To set the socket correctly, the `addressType` field of the address must be set correctly. +*/ +palStatus_t pal_setSockAddrPort(palSocketAddress_t* address, uint16_t port); + +/*! Set an IPv4 address to `palSocketAddress_t` and `addressType` to IPv4. +* @param[in,out] address The address to set. +* @param[in] ipV4Addr The address value to set. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_setSockAddrIPV4Addr(palSocketAddress_t* address, palIpV4Addr_t ipV4Addr); + +/*! Set an IPv6 address to `palSocketAddress_t` and the `addressType` to IPv6. +* @param[in,out] address The address to set. +* @param[in] ipV6Addr The address value to set. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_setSockAddrIPV6Addr(palSocketAddress_t* address, palIpV6Addr_t ipV6Addr); + +/*! Get an IPv4 address from `palSocketAddress_t`. +* @param[in] address The address to set. +* @param[out] ipV4Addr The address that is set in `address`. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_getSockAddrIPV4Addr(const palSocketAddress_t* address, palIpV4Addr_t ipV4Addr); + +/*! Get an IPv6 address from `palSocketAddress_t`. +* @param[in] address The address to set. +* @param[out] ipV6Addr The address that is set in `address`. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_getSockAddrIPV6Addr(const palSocketAddress_t* address, palIpV6Addr_t ipV6Addr); + +/*! Get a port from `palSocketAddress_t`. +* @param[in] address The address to set. +* @param[out] port The port that is set in `address`. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_getSockAddrPort(const palSocketAddress_t* address, uint16_t* port); + +/*! Get a network socket. +* @param[in] domain The domain for the created socket (see `palSocketDomain_t` for supported types). +* @param[in] type The type of the created socket (see `palSocketType_t` for supported types). +* @param[in] nonBlockingSocket If true, the socket is created as non-blocking (with O_NONBLOCK set). +* @param[in] interfaceNum The number of the network interface used for this socket (info in interfaces supported via `pal_getNumberOfNetInterfaces` and `pal_getNetInterfaceInfo`). Select PAL_NET_DEFAULT_INTERFACE for the default interface. +* @param[out] socket The socket is returned through this output parameter. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_socket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palSocket_t* socket); + +/*! Get the value for a given socket option on a given network socket. +* @param[in] socket The socket for which to get options. +* @param[in] optionName The identification of the socket option for which we are getting the value (see enum palSocketOptionName_t for supported types). +* @param[out] optionValue A buffer holding the option value returned by the function. +* @param[in, out] optionLength The size of the buffer provided for `optionValue` when calling the function. After the call, it contains the length of data actually written to the `optionValue` buffer. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_getSocketOptions(palSocket_t socket, palSocketOptionName_t optionName, void* optionValue, palSocketLength_t* optionLength); + +/*! Set the value for a given socket option on a given network socket. +* @param[in] socket The socket for which to get options. +* @param[in] optionName The identification of the socket option for which we are getting the value (see enum palSocketOptionName_t for supported types). +* @param[in] optionValue The buffer holding the option value to set for the given option. +* @param[in] optionLength The size of the buffer provided for `optionValue`. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_setSocketOptions(palSocket_t socket, int optionName, const void* optionValue, palSocketLength_t optionLength); + +/*! Check if a given socket is non-blocking. +* @param[in] socket The socket to check. +* @param[out] isNonBlocking True if the socket is non-blocking, otherwise false. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_isNonBlocking(palSocket_t socket, bool* isNonBlocking); + + +/*! Bind a given socket to a local address. +* @param[in] socket The socket to bind. +* @param[in] myAddress The address to bind to. +* @param[in] addressLength The length of the address passed in `myAddress`. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_bind(palSocket_t socket, palSocketAddress_t* myAddress, palSocketLength_t addressLength); + +/*! Receive a payload from the given socket. +* @param[in] socket The socket to receive from. [The sockets passed to this function should be of type PAL_SOCK_DGRAM (the implementation may support other types as well).] +* @param[out] buffer The buffer for the payload data. +* @param[in] length The length of the buffer for the payload data. +* @param[out] from The address that sent the payload. +* @param[in, out] fromLength The length of the `from` address. Contains the amount of data actually written to the `from` address. +* @param[out] bytesReceived The actual amount of payload data received in the buffer. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_receiveFrom(palSocket_t socket, void* buffer, size_t length, palSocketAddress_t* from, palSocketLength_t* fromLength, size_t* bytesReceived); + +/*! Send a payload to the given address using the given socket. +* @param[in] socket The socket to use for sending the payload. [The sockets passed to this function should be of type PAL_SOCK_DGRAM (the implementation may support other types as well).] +* @param[in] buffer The buffer for the payload data. +* @param[in] length The length of the buffer for the payload data. +* @param[in] to The address to which the payload should be sent. +* @param[in] toLength The length of the `to` address. +* @param[out] bytesSent The actual amount of payload data sent. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_sendTo(palSocket_t socket, const void* buffer, size_t length, const palSocketAddress_t* to, palSocketLength_t toLength, size_t* bytesSent); + +/*! Close a network socket. +* @param[in,out] The socket to be closed. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +\note Receives `palSocket_t*`, NOT `palSocket_t`, so that it can zero the socket to avoid re-use. +*/ +palStatus_t pal_close(palSocket_t* socket); + +/*! Get the number of current network interfaces. +* @param[out] numInterfaces The number of interfaces. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_getNumberOfNetInterfaces(uint32_t* numInterfaces); + +/*! Get information regarding the socket at the index/interface number given (this number is returned when registering the socket). +* @param[in] interfaceNum The number of the interface to get information for. +* @param[out] interfaceInfo Set to the information for the given interface number. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_getNetInterfaceInfo(uint32_t interfaceNum, palNetInterfaceInfo_t* interfaceInfo); + + +#define PAL_NET_SOCKET_SELECT_MAX_SOCKETS 8 +#define PAL_NET_SOCKET_SELECT_RX_BIT (1) +#define PAL_NET_SOCKET_SELECT_TX_BIT (2) +#define PAL_NET_SOCKET_SELECT_ERR_BIT (4) + +#define PAL_NET_SELECT_IS_RX(socketStatus, index) ((socketStatus[index] & PAL_NET_SOCKET_SELECT_RX_BIT) != 0) /*! Check if RX bit is set in select result for a given socket index. */ +#define PAL_NET_SELECT_IS_TX(socketStatus, index) ((socketStatus[index] & PAL_NET_SOCKET_SELECT_TX_BIT) != 0) /*! Check if TX bit is set in select result for a given socket index. */ +#define PAL_NET_SELECT_IS_ERR(socketStatus, index) ((socketStatus[index] & PAL_NET_SOCKET_SELECT_ERR_BIT) != 0) /*! Check if ERR bit is set in select result for a given socket index. */ + +/*! Check if one or more (up to PAL_NET_SOCKET_SELECT_MAX_SOCKETS) sockets given has data available for reading/writing/error. The function will block until data is available for one of the given sockets or the timeout expires. \n +To use the function, set the sockets you want to check in the `socketsToCheck` array and set a timeout. When it returns the `socketStatus` output indicates the status of each socket passed in. \n +\note If the timeout expires, the returned `palStatus_t` is PAL_SUCCESS and `numberOfSocketsSet` is 0. +* @param[in] socketsToCheck On input, the array of up to 8 sockets handles to check. +* @param[in] numberOfSockets The number of sockets set in the input `socketsToCheck` array. +* @param[in] timeout The amount of time until timeout if no socket activity is detected +* @param[out] socketStatus Information on each socket in the input array, indicating which event was set (none, rx, tx, err). Check the desired event using macros. +* @param[out] numberOfSocketsSet The total number of sockets set in all three data sets (tx, rx, err). +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +\note The entry in index x in the `socketStatus` array corresponds to the socket at index x in the sockets to check array. +*/ +palStatus_t pal_socketMiniSelect(const palSocket_t socketsToCheck[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t numberOfSockets, pal_timeVal_t* timeout, + uint8_t palSocketStatus[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t* numberOfSocketsSet); + + +#if PAL_NET_TCP_AND_TLS_SUPPORT // The functionality below is supported only if TCP is supported. + + +/*! Use the given socket to listen for incoming connections. This may also limit the queue of incoming connections. +* @param[in] socket The socket to listen to. [The sockets passed to this function should be of type PAL_SOCK_STREAM_SERVER (the implementation may support other types as well).] +* @param[in] backlog The amount of pending connections that can be saved for the socket. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_listen(palSocket_t socket, int backlog); + +/*! Accept a connection on the given socket. +* @param[in] socket The socket on which to accept the connection. (The socket must be already created and bound and listen has must have been called on it.) [The sockets passed to this function should be of type PAL_SOCK_STREAM_SERVER (the implementation may support other types as well).] +* @param[out] address The source address of the incoming connection. +* @param[in, out] addressLen The length of the address field on input, the length of the data returned on output. +* @param[out] acceptedSocket The socket of the accepted connection. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_accept(palSocket_t socket, palSocketAddress_t* address, palSocketLength_t* addressLen, palSocket_t* acceptedSocket); + +/*! Open a connection from the given socket to the given address. +* @param[in] socket The socket to use for connection to the given address. [The sockets passed to this function should be of type PAL_SOCK_STREAM (the implementation may support other types as well).] +* @param[in] address The destination address of the connection. +* @param[in] addressLen The length of the address field. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_connect(palSocket_t socket, const palSocketAddress_t* address, palSocketLength_t addressLen); + +/*! Receive data from the given connected socket. +* @param[in] socket The connected socket on which to receive data. [The sockets passed to this function should be of type PAL_SOCK_STREAM (the implementation may support other types as well).] +* @param[out] buf The output buffer for the message data. +* @param[in] len The length of the input data buffer. +* @param[out] recievedDataSize The length of the data actually received. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_recv(palSocket_t socket, void* buf, size_t len, size_t* recievedDataSize); + +/*! Send a given buffer via the given connected socket. +* @param[in] socket The connected socket on which to send data. [The sockets passed to this function should be of type PAL_SOCK_STREAM (the implementation may support other types as well).] +* @param[in] buf The output buffer for the message data. +* @param[in] len The length of the input data buffer. +* @param[out] sentDataSize The length of the data sent. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_send(palSocket_t socket, const void* buf, size_t len, size_t* sentDataSize); + + +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + +/*! The type of the callback funciton passed when creating asynchronous sockets. +* @param[in] argument The user provided argument passed to the callback function. +*/ +typedef void(*palAsyncSocketCallback_t)(void*); + +/*! Get an asynchronous network socket. +* @param[in] domain The domain for the created socket (see enum `palSocketDomain_t` for supported types). +* @param[in] type The type for the created socket (see enum `palSocketType_t` for supported types). +* @param[in] nonBlockingSocket If true, the socket is created as non-blocking (with O_NONBLOCK set). +* @param[in] interfaceNum The number of the network interface used for this socket (info in interfaces supported via `pal_getNumberOfNetInterfaces` and `pal_getNetInterfaceInfo`). Select PAL_NET_DEFAULT_INTERFACE for the default interface. +* @param[in] callback A callback function that is called when any supported event happens in the given asynchronous socket (see `palAsyncSocketCallbackType` enum for the types of events supported). +* @param[out] socket The socket is returned through this output parameter. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_asynchronousSocket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t callback, palSocket_t* socket); + +/*! Get an asynchronous network socket that passes the provided `callbackArgument` to the provided callback on callback events. +* @param[in] domain The domain for the created socket (see enum `palSocketDomain_t` for supported types). +* @param[in] type The type for the created socket (see enum `palSocketType_t` for supported types). +* @param[in] nonBlockingSocket If true, the socket is created as non-blocking (with O_NONBLOCK set). +* @param[in] interfaceNum The number of the network interface used for this socket (info in interfaces supported via `pal_getNumberOfNetInterfaces` and `pal_getNetInterfaceInfo`). Select PAL_NET_DEFAULT_INTERFACE for the default interface. +* @param[in] callback A callback function that is called when any supported event happens in the given asynchronous socket. +* @param[in] callbackArgument The argument with which the callback function is called when any supported event happens in the given asynchronous socket. +* @param[out] socket The socket is returned through this output parameter. +\return PAL_SUCCESS (0) in case of success or a specific negative error code in case of failure. +*/ +palStatus_t pal_asynchronousSocketWithArgument(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t callback,void* callbackArgument, palSocket_t* socket); + + + +#endif + +#if PAL_NET_DNS_SUPPORT + +/*! This function translates from a URL to `palSocketAddress_t` which can be used with PAL sockets. It supports both IP address as strings and URLs (using DNS lookup). +* @param[in] url The URL (or IP address string) to be translated to a `palSocketAddress_t`. +* @param[out] address The address for the output of the translation. +*/ +palStatus_t pal_getAddressInfo(const char* url, palSocketAddress_t* address, palSocketLength_t* addressLength); + +#endif + +#ifdef __cplusplus +} +#endif +#endif //_PAL_SOCKET_H + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_rtos.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_rtos.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,510 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef _PAL_RTOS_H +#define _PAL_RTOS_H + +#include <stdint.h> +#include <string.h> //memcpy + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pal_macros.h" +#include "pal_types.h" +#include "pal_configuration.h" //added for PAL_INITIAL_RANDOM_SIZE value + +/*! \file pal_rtos.h +* \brief PAL RTOS. +* This file contains the real-time OS APIs and is a part of the PAL service API. +* It provides thread, timers, semaphores, mutexes and memory pool management APIs. +* Random API and ROT (root of trust) are also provided. +*/ + + +//! Wait forever define. Used for semaphores and mutexes. +#define PAL_TICK_TO_MILLI_FACTOR 1000 + +//! Primitive ID type declarations. +typedef uintptr_t palThreadID_t; +typedef uintptr_t palTimerID_t; +typedef uintptr_t palMutexID_t; +typedef uintptr_t palSemaphoreID_t; +typedef uintptr_t palMemoryPoolID_t; +typedef uintptr_t palMessageQID_t; + +//! Timer types supported in PAL. +typedef enum palTimerType { + palOsTimerOnce = 0, /*! One shot timer. */ + palOsTimerPeriodic = 1 /*! Periodic (repeating) timer. */ +} palTimerType_t; + + +PAL_DEPRECATED(palOsStorageEncryptionKey and palOsStorageSignatureKey are deprecated please use palOsStorageEncryptionKey128Bit palOsStorageSignatureKey128Bit) +#define palOsStorageEncryptionKey palOsStorageEncryptionKey128Bit +#define palOsStorageSignatureKey palOsStorageSignatureKey128Bit + + +//! Device key types supported in PAL. +typedef enum palDeviceKeyType { + palOsStorageEncryptionKey128Bit = 0, /*! 128bit storage encryption key derived from RoT. */ + palOsStorageSignatureKey128Bit = 1, /*! 128bit storage signature key derived from RoT. */ + palOsStorageHmacSha256 = 2 +} palDevKeyType_t; + +//! PAL timer function prototype. +typedef void(*palTimerFuncPtr)(void const *funcArgument); + +//! PAL thread function prototype. +typedef void(*palThreadFuncPtr)(void const *funcArgument); + +#define PAL_NUMBER_OF_THREADS_PRIORITIES (PAL_osPrioritylast-PAL_osPriorityFirst+1) +//! Available priorities in PAL implementation, each priority can appear only once. +typedef enum pal_osPriority { + PAL_osPriorityFirst = -3, + PAL_osPriorityIdle = PAL_osPriorityFirst, + PAL_osPriorityLow = -2, + PAL_osPriorityBelowNormal = -1, + PAL_osPriorityNormal = 0, + PAL_osPriorityAboveNormal = +1, + PAL_osPriorityHigh = +2, + PAL_osPriorityRealtime = +3, + PAL_osPrioritylast = PAL_osPriorityRealtime, + PAL_osPriorityError = 0x84 +} palThreadPriority_t; /*! Thread priority levels for PAL threads - each thread must have a different priority. */ + +//! Thread local store struct. +//! Can be used to hold for example state and configurations inside the thread. +typedef struct pal_threadLocalStore{ + void* storeData; +} palThreadLocalStore_t; + +typedef struct pal_timeVal{ + int32_t pal_tv_sec; /*! Seconds. */ + int32_t pal_tv_usec; /*! Microseconds. */ +} pal_timeVal_t; + + +//------- system general functions +/*! Initiates a system reboot. +*/ +void pal_osReboot(void); + +//------- system tick functions +/*! Get the RTOS kernel system timer counter. +* \note The system needs to supply a 64-bit tick counter. If only a 32-bit counter is supported, +* \note the counter wraps around very often (for example, once every 42 sec for 100Mhz). +* \return The RTOS kernel system timer counter. +*/ +uint64_t pal_osKernelSysTick(void); + + +/*! Converts a value from microseconds to kernel system ticks. +* +* @param[in] microseconds The number of microseconds to convert into system ticks. +* +* \return Converted value in system ticks. +*/ +uint64_t pal_osKernelSysTickMicroSec(uint64_t microseconds); + +/*! Converts value from kernel system ticks to milliseconds. +* +* @param[in] sysTicks The number of kernel system ticks to convert into milliseconds. +* +* \return Converted value in system milliseconds. +*/ +uint64_t pal_osKernelSysMilliSecTick(uint64_t sysTicks); + +/*! Get the system tick frequency. +* \return The system tick frequency. +* +* \note The system tick frequency MUST be more than 1KHz (at least one tick per millisecond). +*/ +uint64_t pal_osKernelSysTickFrequency(void); + + +/*! Get the system time. +* \return The system 64-bit counter indicating the current system time in seconds on success. +* Zero value when the time is not set in the system. +*/ +uint64_t pal_osGetTime(void); + +/*! \brief Set the current system time by accepting seconds since January 1st 1970 UTC+0. +* +* @param[in] seconds Seconds from January 1st 1970 UTC+0. +* +* \return PAL_SUCCESS when the time was set successfully. \n +* PAL_ERR_INVALID_TIME when there is a failure setting the system time. +*/ +palStatus_t pal_osSetTime(uint64_t seconds); + + +/*! \brief <b>-----This function shall be deprecated in the next PAL release!!------ </b> +* This function creates and starts the thread function (inside the PAL platform wrapper function). +* @param[in] function A function pointer to the thread callback function. +* @param[in] funcArgument An argument for the thread function. +* @param[in] priority The priority of the thread. +* @param[in] stackSize The stack size of the thread, can NOT be 0. +* @param[in] stackPtr A pointer to the thread's stack. <b> ----Shall not be used, The user need to free this resource------ </b> +* @param[in] store A pointer to thread's local store, can be NULL. +* @param[out] threadID The created thread ID handle. In case of error, this value is NULL. +* +* \return PAL_SUCCESS when the thread was created successfully. \n +* PAL_ERR_RTOS_PRIORITY when the given priority is already used in the system. +* +* \note Each thread MUST have a unique priority. +* \note When the priority of the created thread function is higher than the current running thread, the +* created thread function starts instantly and becomes the new running thread. +*/ +palStatus_t pal_osThreadCreate(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, uint32_t* stackPtr, palThreadLocalStore_t* store, palThreadID_t* threadID); + +/*! \brief Allocates memory for the thread stack, creates and starts the thread function (inside the PAL platform wrapper function). +* +* @param[in] function A function pointer to the thread callback function. +* @param[in] funcArgument An argument for the thread function. +* @param[in] priority The priority of the thread. +* @param[in] stackSize The stack size of the thread, can NOT be 0. +* @param[in] store A pointer to thread's local store, can be NULL. +* @param[out] threadID: The created thread ID handle. In case of error, this value is NULL. +* +* \return PAL_SUCCESS when the thread was created successfully. \n +* PAL_ERR_RTOS_PRIORITY when the given priority is already used in the system. +* +* \note Each thread MUST have a unique priority. +* \note When the priority of the created thread function is higher than the current running thread, the +* created thread function starts instantly and becomes the new running thread. +* \note Calling \c pal_osThreadTerminate() releases the thread stack. +*/ +palStatus_t pal_osThreadCreateWithAlloc(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, palThreadLocalStore_t* store, palThreadID_t* threadID); + +/*! Terminate and free allocated data for the thread. +* +* @param[in] threadID The thread ID to stop and terminate. +* +* \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. \n +* PAL_ERR_RTOS_RESOURCE if the thread ID is not correct. +* \note pal_osThreadTerminate is a non blocking operation, pal_osThreadTerminate sends cancellation request to the thread, +* usually the thread exits immediately, but the system does not always guarantee this +*/ +palStatus_t pal_osThreadTerminate(palThreadID_t* threadID); + +/*! Get the ID of the current thread. +* \return The ID of the current thread. In case of error, return PAL_MAX_UINT32. +* \note For a thread with real time priority, the function always returns PAL_MAX_UINT32. +*/ +palThreadID_t pal_osThreadGetId(void); + +/*! Get the storage of the current thread. +* \return The storage of the current thread. +*/ +palThreadLocalStore_t* pal_osThreadGetLocalStore(void); + +/*! Wait for a specified time period in milliseconds. +* +* @param[in] milliseconds The number of milliseconds to wait before proceeding. +* +* \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osDelay(uint32_t milliseconds); + +/*! Create a timer. +* +* @param[in] function A function pointer to the timer callback function. +* @param[in] funcArgument An argument for the timer callback function. +* @param[in] timerType The timer type to be created, periodic or oneShot. +* @param[out] timerID The created timer ID handle. In case of error, this value is NULL. +* +* \return PAL_SUCCESS when the timer was created successfully. \n +* PAL_ERR_NO_MEMORY when there is no memory resource available to create a timer object. +* +* \note The timer function runs according to the platform resources of stack-size and priority. +*/ +palStatus_t pal_osTimerCreate(palTimerFuncPtr function, void* funcArgument, palTimerType_t timerType, palTimerID_t* timerID); + +/*! Start or restart a timer. +* +* @param[in] timerID The handle for the timer to start. +* @param[in] millisec The amount of time in milliseconds to set the timer to. MUST be larger than 0. +* In case of 0 value, the error PAL_ERR_RTOS_VALUE is returned. +* +* \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osTimerStart(palTimerID_t timerID, uint32_t millisec); + +/*! Stop a timer. +* @param[in] timerID The handle for the timer to stop. +* \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osTimerStop(palTimerID_t timerID); + +/*! Delete the timer object. +* +* @param[inout] timerID The handle for the timer to delete. In success, `*timerID` = NULL. +* +* \return PAL_SUCCESS when timer was deleted successfully. \n +* PAL_ERR_RTOS_PARAMETER when the `timerID` is incorrect. +*/ +palStatus_t pal_osTimerDelete(palTimerID_t* timerID); + +/*! Create and initialize a mutex object. +* +* @param[out] mutexID The created mutex ID handle. In case of error, this value is NULL. +* +* \return PAL_SUCCESS when the mutex was created successfully. \n +* PAL_ERR_NO_MEMORY when there is no memory resource available to create a mutex object. +*/ +palStatus_t pal_osMutexCreate(palMutexID_t* mutexID); + +/*! Wait until a mutex becomes available. +* +* @param[in] mutexID The handle for the mutex. +* @param[in] millisec The timeout for waiting to the mutex to be available. PAL_RTOS_WAIT_FOREVER can be used as a parameter. +* +* \return PAL_SUCCESS(0) in case of success or one of the following error codes in case of failure: \n +* PAL_ERR_RTOS_RESOURCE - mutex was not availabe but no timeout was set. \n +* PAL_ERR_RTOS_TIMEOUT - mutex was not available until the timeout. \n +* PAL_ERR_RTOS_PARAMETER - mutex ID is invalid. \n +* PAL_ERR_RTOS_ISR - cannot be called from the interrupt service routines. +*/ +palStatus_t pal_osMutexWait(palMutexID_t mutexID, uint32_t millisec); + +/*! Release a mutex that was obtained by `osMutexWait`. +* +* @param[in] mutexID The handle for the mutex. +* \return PAL_SUCCESS(0) in case of success and another negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osMutexRelease(palMutexID_t mutexID); + +/*!Delete a mutex object. +* +* @param[inout] mutexID The mutex handle to delete. In success, `*mutexID` = NULL. +* +* \return PAL_SUCCESS when the mutex was deleted successfully. \n +* PAL_ERR_RTOS_RESOURCE - mutex is already released. \n +* PAL_ERR_RTOS_PARAMETER - mutex ID is invalid. \n +* PAL_ERR_RTOS_ISR - cannot be called from the interrupt service routines. \n +* \note After this call, the `mutex_id` is no longer valid and cannot be used. +*/ +palStatus_t pal_osMutexDelete(palMutexID_t* mutexID); + +/*! Create and initialize a semaphore object. +* +* @param[in] count The number of available resources. +* @param[out] semaphoreID The created semaphore ID handle. In case of error, this value is NULL. +* +* \return PAL_SUCCESS when the semaphore was created successfully. \n +* PAL_ERR_NO_MEMORY when there is no memory resource available to create a semaphore object. +*/ +palStatus_t pal_osSemaphoreCreate(uint32_t count, palSemaphoreID_t* semaphoreID); + +/*! Wait until a semaphore token becomes available. +* +* @param[in] semaphoreID The handle for the semaphore. +* @param[in] millisec The timeout for the waiting operation if the timeout + expires before the semaphore is released and error is + returned from the function. PAL_RTOS_WAIT_FOREVER can be used. +* @param[out] countersAvailable The number of semaphores available at the call if a + semaphore is available. If the semaphore is not available (timeout/error) zero is returned. This parameter can be NULL +* \return PAL_SUCCESS(0) in case of success and one of the following error codes in case of failure: \n +* PAL_ERR_RTOS_TIMEOUT - the semaphore was not available until timeout. \n +* PAL_ERR_RTOS_PARAMETER - the semaphore ID is invalid. +*/ +palStatus_t pal_osSemaphoreWait(palSemaphoreID_t semaphoreID, uint32_t millisec, int32_t* countersAvailable); + +/*! Release a semaphore token. +* +* @param[in] semaphoreID The handle for the semaphore +* +* \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osSemaphoreRelease(palSemaphoreID_t semaphoreID); + +/*! Delete a semaphore object. +* +* @param[inout] semaphoreID The semaphore handle to delete. In success, `*semaphoreID` = NULL. +* +* \return PAL_SUCCESS when the semaphore was deleted successfully. \n +* PAL_ERR_RTOS_RESOURCE - the semaphore was already released. \n +* PAL_ERR_RTOS_PARAMETER - the semaphore ID is invalid. +* \note After this call, the `semaphore_id` is no longer valid and cannot be used. +*/ +palStatus_t pal_osSemaphoreDelete(palSemaphoreID_t* semaphoreID); + +/*! Create and initialize a memory pool. +* +* @param[in] blockSize The size of a single block in bytes. +* @param[in] blockCount The maximum number of blocks in the memory pool. +* @param[out] memoryPoolID The created memory pool ID handle. In case of error, this value is NULL. +* +* \return PAL_SUCCESS when the memory pool was created successfully. \n +* PAL_ERR_NO_MEMORY when there is no memory resource available to create a memory pool object. +*/ +palStatus_t pal_osPoolCreate(uint32_t blockSize, uint32_t blockCount, palMemoryPoolID_t* memoryPoolID); + +/*! Allocate a single memory block from the memory pool. +* +* @param[in] memoryPoolID The handle for the memory pool. +* +* \return A pointer to a single allocated memory from the pool or NULL in case of failure. +*/ +void* pal_osPoolAlloc(palMemoryPoolID_t memoryPoolID); + +/*! Allocate a single memory block from the memory pool and set it to zero. +* +* @param[in] memoryPoolID The handle for the memory pool. +* +* \return A pointer to a single allocated memory from the pool or NULL in case of failure. +*/ +void* pal_osPoolCAlloc(palMemoryPoolID_t memoryPoolID); + +/*! Return a memory block back to a specific memory pool. +* +* @param[in] memoryPoolHandle The handle for the memory pool. +* @param[in] block The block to free. +* +* \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osPoolFree(palMemoryPoolID_t memoryPoolID, void* block); + +/*! Delete a memory pool object. +* +* @param[inout] memoryPoolID The handle for the memory pool. In success, `*memoryPoolID` = NULL. +* +* \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osPoolDestroy(palMemoryPoolID_t* memoryPoolID); + + +/*! Create and initialize a message queue of `uint32_t` messages. +* +* @param[in] messageQCount The maximum number of messages in the queue. +* @param[out] messageQID: The created message queue ID handle. In case of error, this value is NULL. +* +* \return PAL_SUCCESS when the message queue was created successfully. \n +* PAL_ERR_NO_MEMORY when there is no memory resource available to create a message queue object. +*/ +palStatus_t pal_osMessageQueueCreate(uint32_t messageQCount, palMessageQID_t* messageQID); + +/*! Put a message to a queue. +* +* @param[in] messageQID The handle for the message queue. +* @param[in] info The data to send. +* @param[in] timeout The timeout in milliseconds. Value zero means that the function returns instantly. \n + The value PAL_RTOS_WAIT_FOREVER means that the function waits for an infinite time until the message can be put to the queue. +* +* \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osMessagePut(palMessageQID_t messageQID, uint32_t info, uint32_t timeout); + +/*! Get a message or wait for a message from a queue. +* +* @param[in] messageQID The handle for the memory pool. +* @param[in] timeout The timeout in milliseconds. Value zero means that the function returns instantly \n + The value PAL_RTOS_WAIT_FOREVER means that the funtion waits for an infinite time until message can be put to the queue. +* @param[out] messageValue The message value from the message queue. +* +* \return PAL_SUCCESS(0) in case of success and one of the following error codes in case of failure: \n +* PAL_ERR_RTOS_TIMEOUT - no message arrived during the given timeout period. Can also be returned in case of timeout zero value, which means that there are no messages in the queue. +*/ +palStatus_t pal_osMessageGet(palMessageQID_t messageQID, uint32_t timeout, uint32_t* messageValue); + +/*! Delete a message queue object. +* +* @param[in,out] messageQID The handle for the message queue. In success, `*messageQID` = NULL. +* +* \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osMessageQueueDestroy(palMessageQID_t* messageQID); + +/*! Perform an atomic increment for a signed 32-bit value. +* +* @param[in,out] valuePtr The address of the value to increment. +* @param[in] increment The number by which to increment. +* +* \return The value of `valuePtr` after the increment operation. +*/ +int32_t pal_osAtomicIncrement(int32_t* valuePtr, int32_t increment); + +/*! Generate a 32-bit random number. +* +* @param[out] random A 32-bit buffer to hold the generated number. +* +\note `pal_init()` MUST be called before this function. +\return PAL_SUCCESS on success, a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osRandom32bit(uint32_t *random); + +/*! Generate random number into given buffer with given size in bytes. +* +* @param[out] randomBuf A buffer to hold the generated number. +* @param[in] bufSizeBytes The size of the buffer and the size of the required random number to generate. +* +\note `pal_init()` MUST be called before this function +\return PAL_SUCCESS on success, a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes); + +/*! Generate a 32-bit random number uniformly distributed less than `upperBound`. +* +* @param[out] random A pointer to a 32-bit buffer to hold the generated number. +* +\note `pal_init()` MUST be called before this function +\note For the first phase, the `upperBound` parameter is ignored. +\return PAL_SUCCESS on success, a negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_osRandomUniform(uint32_t upperBound, uint32_t *random); + +/*! Return a device unique key derived from the root of trust. +* +* @param[in] keyType The type of key to derive. +* @param[in,out] key A 128-bit OR 256-bit buffer to hold the derived key, size is defined according to the `keyType`. +* @param[in] keyLenBytes The size of buffer to hold the 128-bit OR 256-bit key. +* \return PAL_SUCCESS in case of success and one of the following error codes in case of failure: \n +* PAL_ERR_GET_DEV_KEY - an error in key derivation. +*/ +PAL_DEPRECATED(pal_osGetDeviceKey128Bit is deprecated please use pal_osGetDeviceKey) +#define pal_osGetDeviceKey128Bit pal_osGetDeviceKey + +palStatus_t pal_osGetDeviceKey(palDevKeyType_t keyType, uint8_t *key, size_t keyLenBytes); + + +/*! Initialize the RTOS module for PAL. + * This function can be called only once before running the system. + * To remove PAL from the system, call `pal_RTOSDestroy`. + * After calling `pal_RTOSDestroy`, you can call `pal_RTOSInitialize` again. +* +* @param[in] opaqueContext: context to be passed to the platform if needed. +* +* \return PAL_SUCCESS upon success. +*/ +palStatus_t pal_RTOSInitialize(void* opaqueContext); + + +/*! This function removes PAL from the system and can be called after `pal_RTOSInitialize`. +** +* \return PAL_SUCCESS upon success. \n +* PAL_ERR_NOT_INITIALIZED - if the user did not call `pal_RTOSInitialize()` first. +*/ +palStatus_t pal_RTOSDestroy(void); + + + +#ifdef __cplusplus +} +#endif +#endif //_PAL_RTOS_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_types.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,77 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef _PAL_TYPES_H +#define _PAL_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#if defined __cplusplus && !defined __STDC_FORMAT_MACROS + #define UNDEF__STDC_FORMAT_MACROS + #define __STDC_FORMAT_MACROS +#endif +#include <inttypes.h> +#ifdef UNDEF__STDC_FORMAT_MACROS + #undef UNDEF__STDC_FORMAT_MACROS + #undef __STDC_FORMAT_MACROS +#endif +#include <stdlib.h> + +/*! \file pal_types.h +* \brief PAL types. +* This file contains PAL generic types. +*/ + + +#define NULLPTR 0 + +#define TRUE 1 +#define FALSE 0 + +#define PAL_INVALID_THREAD 0xFFFFFFFF + +typedef int32_t palStatus_t; + +typedef struct _palBuffer_t +{ + uint32_t maxBufferLength; + uint32_t bufferLength; + uint8_t *buffer; +} palBuffer_t; + +typedef struct _palConstBuffer_t +{ + const uint32_t maxBufferLength; + const uint32_t bufferLength; + const uint8_t *buffer; +} palConstBuffer_t; + +typedef struct sotpAreaData +{ + uint32_t address; /*\brief the address of the starting sector for the given area*/ + size_t size; /*\brief the size of the area*/ +}palSotpAreaData_t; + + +#ifdef __cplusplus +} +#endif +#endif //_PAL_TYPES_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_update.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/Services-API/pal_update.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,199 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef SOURCE_PAL_IMPL_SERVICES_API_PAL_UPDATE_H_ +#define SOURCE_PAL_IMPL_SERVICES_API_PAL_UPDATE_H_ + +#include "pal_macros.h" +#include "pal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \file pal_update.h +* \brief PAL update. +* This file contains the firmware update APIs and is a part of the PAL service API. +* It provides the read/write and activation functionalities for the firmware. +*/ + + +typedef uint32_t palImageId_t; + +typedef struct _palImageHeaderDeails_t +{ + size_t imageSize; + palBuffer_t hash; + uint64_t version; +} palImageHeaderDeails_t; + +typedef enum _palImagePlatformData_t +{ + PAL_IMAGE_DATA_FIRST = 0, + PAL_IMAGE_DATA_HASH = PAL_IMAGE_DATA_FIRST, + PAL_IMAGE_DATA_LAST +} palImagePlatformData_t; + +typedef enum _palImageEvents_t +{ + PAL_IMAGE_EVENT_FIRST = -1, + PAL_IMAGE_EVENT_ERROR = PAL_IMAGE_EVENT_FIRST, + PAL_IMAGE_EVENT_INIT , + PAL_IMAGE_EVENT_PREPARE, + PAL_IMAGE_EVENT_WRITE, + PAL_IMAGE_EVENT_FINALIZE, + PAL_IMAGE_EVENT_READTOBUFFER, + PAL_IMAGE_EVENT_ACTIVATE, + PAL_IMAGE_EVENT_ACTIVATE_ERROR, + PAL_IMAGE_EVENT_GETACTIVEHASH, + PAL_IMAGE_EVENT_GETACTIVEVERSION, + PAL_IMAGE_EVENT_WRITEDATATOMEMORY, + PAL_IMAGE_EVENT_LAST +} palImageEvents_t; + +typedef void (*palImageSignalEvent_t)( palImageEvents_t event); + +#define SIZEOF_SHA256 256/8 +#define FIRMWARE_HEADER_MAGIC 0x5a51b3d4UL +#define FIRMWARE_HEADER_VERSION 1 +#define IMAGE_COUNT_MAX 1 +#define ACTIVE_IMAGE_INDEX 0xFFFFFFFF + +typedef struct FirmwareHeader { + uint32_t magic; /** Metadata-header specific magic code. */ + uint32_t version; /** Revision number for this generic metadata header. */ + uint32_t checksum; /** A checksum of this header. This field should be considered to be zeroed out for + * the sake of computing the checksum. */ + uint32_t totalSize; /** Total space (in bytes) occupied by the firmware BLOB, including headers and any padding. */ + uint64_t firmwareVersion; /** Version number for the accompanying firmware. Larger numbers imply more preferred (recent) + * versions. This defines the selection order when multiple versions are available. */ + uint8_t firmwareSHA256[SIZEOF_SHA256]; /** A SHA-2 using a block-size of 256-bits of the firmware, including any firmware-padding. */ +} FirmwareHeader_t; + + +typedef FirmwareHeader_t palFirmwareHeader_t; +/*! Sets the callback function that is called before the end of each API (except `imageGetDirectMemAccess`). + * + * WARNING: Do not change this function! + * This function loads a callback function received from the upper layer (service). + * The callback should be called at the end of each function (except `pal_plat_imageGetDirectMemAccess`). + * The callback receives the event type that just occurred, defined by the ENUM `palImageEvents_t`. + * + * If you do not call the callback at the end, the service behaviour will be undefined. + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * + * @param[in] CBfunction A pointer to the callback function. + * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_imageInitAPI(palImageSignalEvent_t CBfunction); + + +/*! Clears all the resources used by the `pal_update` APIs. + * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_imageDeInit(void); + +/*! Prepares to write an image with an ID (`imageId`) and size (`imageSize`) in a suitable memory region. The space available is verified and reserved. + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * @param[in] imageId The image ID. + * @param[in] headerDetails The size of the image. + * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_imagePrepare(palImageId_t imageId, palImageHeaderDeails_t* headerDetails); + +/*! Writes the data to the chunk buffer with the chunk `bufferLength` in the location of `imageId` adding the relative offset. + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * @param[in] imageId The image ID. + * @param[in] offset The offset to write the data into. + * @param[in] chunk A pointer to struct containing the data and the data length to write. + * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_imageWrite (palImageId_t imageId, size_t offset, palConstBuffer_t *chunk); + +/*! Flushes the image data and sets the version of `imageId` to `imageVersion`. + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * @param[in] imageId The image ID. + * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_imageFinalize(palImageId_t imageId); + +/*! Verifies whether the image (`imageId`) is readable and sets `imagePtr` to point to the beginning of the image in the memory and `imageSizeInBytes` to the image size. + * In case of failure, sets `imagePtr` to NULL and returns the relevant `palStatus_t` error. + * @param[in] imageId The image ID. + * @param[out] imagePtr A pointer to the beginning of the image. + * @param[out] imageSizeInBytes The size of the image. + * \return PAL_SUCCESS(0) in case of success and a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_imageGetDirectMemoryAccess(palImageId_t imageId, void** imagePtr, size_t *imageSizeInBytes); + +/*! Reads the maximum of chunk (`maxBufferLength`) bytes from the image (`imageId`) with relative offset and stores it in the chunk buffer. + * Also sets the chunk `bufferLength` value to the actual number of bytes read. + * \note Use this API in the case image is not directly accessible via the `imageGetDirectMemAccess` function. + * + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * + * @param[in] imageId The image ID. + * @param[in] offset The offset to start reading from. + * @param[out] chunk A struct containing the data and actual bytes read. + */ +palStatus_t pal_imageReadToBuffer(palImageId_t imageId, size_t offset, palBuffer_t* chunk); + +/*! Sets an image (`imageId`) as the active image (after the device reset). + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * + * @param[in] imageId The image ID. + */ +palStatus_t pal_imageActivate(palImageId_t imageId); + +/*! Retrieves the hash value of the active image to the hash buffer with the max size hash (`maxBufferLength`) and sets the hash size to hash `bufferLength`. + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * @param[out] hash A struct containing the hash and actual size of hash read. + */ +palStatus_t pal_imageGetActiveHash(palBuffer_t* hash); + + +/*! Retrieves the data value of the image header. + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * @param[in] imageId The image ID. + * @param[out] headerData A struct containing the headerData and actual size of header. + */ +palStatus_t pal_imageGetFirmwareHeaderData(palImageId_t imageId, palBuffer_t *headerData); + + +/*! Retrieves the version of the active image to the version buffer with the size set to version `bufferLength`. + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * @param[out] version A struct containing the version and actual size of version read. + */ +palStatus_t pal_imageGetActiveVersion(palBuffer_t* version); + +/*! Writes the data of `dataId` stored in `dataBuffer` to a memory accessible to the bootloader. Currently, only hash is available. + * The function must call `g_palUpdateServiceCBfunc` before completing an event. + * @param[in] dataId One of the members of the `palImagePlatformData_t` enum. + * @param[in] dataBuffer A struct containing the data and actual bytes to be written. + */ +palStatus_t pal_imageWriteDataToMemory(palImagePlatformData_t dataId, const palConstBuffer_t* const dataBuffer); + + +/*! \brief This function gets the firmware working directory. + * + * \return full path of the firmware working folder + */ +char* pal_imageGetFolder(void); + +#ifdef __cplusplus +} +#endif +#endif /* SOURCE_PAL_IMPL_SERVICES_API_PAL_UPDATE_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/pal_init.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/PAL-Impl/pal_init.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,122 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#include "pal.h" +#include "pal_plat_network.h" +#include "pal_plat_TLS.h" +#include "pal_plat_Crypto.h" +#include "pal_macros.h" + + + +//this variable must be a int32_t for using atomic increment +PAL_PRIVATE int32_t g_palIntialized = 0; + + +PAL_PRIVATE void pal_modulesCleanup(void) +{ + DEBUG_PRINT("Destroying modules\r\n"); + pal_plat_cleanupTLS(); + pal_plat_socketsTerminate(NULL); + pal_RTOSDestroy(); + pal_plat_cleanupCrypto(); + pal_internalFlashDeInit(); +} + + +palStatus_t pal_init(void) +{ + + palStatus_t status = PAL_SUCCESS; + int32_t currentInitValue; + // get the return value of g_palIntialized+1 to save it locally + currentInitValue = pal_osAtomicIncrement(&g_palIntialized,1); + // if increased for the 1st time + if (1 == currentInitValue) + { + DEBUG_PRINT("\nInit for the 1st time, initializing the modules\r\n"); + status = pal_RTOSInitialize(NULL); + if (PAL_SUCCESS == status) + { + DEBUG_PRINT("\n1. Network init\r\n"); + status = pal_plat_socketsInit(NULL); + if (PAL_SUCCESS != status) + { + DEBUG_PRINT("init of network module has failed with status %" PRIu32 "\r\n",status); + } + else //socket init succeeded + { + DEBUG_PRINT("\n2. TLS init\r\n"); + status = pal_plat_initTLSLibrary(); + if (PAL_SUCCESS != status) + { + DEBUG_PRINT("init of tls module has failed with status %" PRIu32 "\r\n",status); + } + else + { + DEBUG_PRINT("\n3. Crypto init\r\n"); + status = pal_plat_initCrypto(); + if (PAL_SUCCESS != status) + { + DEBUG_PRINT("init of crypto module has failed with status %" PRIu32 "\r\n",status); + } + else + { + DEBUG_PRINT("\n4. Internal Flash init\r\n"); + status = pal_internalFlashInit(); + if (PAL_SUCCESS != status) + { + DEBUG_PRINT("init of Internal Flash module has failed with status %" PRIu32 "\r\n",status); + } + } + } + } + } + else + { + DEBUG_PRINT("init of RTOS module has failed with status %" PRIu32 "\r\n",status); + } + + // if failed decrease the value of g_palIntialized + if (PAL_SUCCESS != status) + { + pal_modulesCleanup(); + pal_osAtomicIncrement(&g_palIntialized, -1); + PAL_LOG(ERR,"\nInit failed\r\n"); + } + } + + + return status; +} + + +int32_t pal_destroy(void) +{ + int32_t currentInitValue; + // get the current value of g_palIntialized locally + currentInitValue = pal_osAtomicIncrement(&g_palIntialized, 0); + if(currentInitValue != 0) + { + currentInitValue = pal_osAtomicIncrement(&g_palIntialized, -1); + if (0 == currentInitValue) + { + pal_modulesCleanup(); + } + } + return currentInitValue; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_Crypto.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_Crypto.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,608 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef _PAL_PLAT_CRYPTO_H_ +#define _PAL_PLAT_CRYPTO_H_ + +#include "pal_Crypto.h" + +/*! \file pal_plat_Crypto.h +* \brief PAL cryptographic - platform. +* This file contains cryptographic APIs that need to be implemented in the platform layer. +*/ + +/*! Initiate the Crypto library. Initialization may not be required for some crypto libraries. In such + * cases, the implementation may be empty. + * +\note This function must be called in the general PAL initializtion function. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_initCrypto(void); + +/*! Free resources for the Crypto library. +* +\note This function must be called in the general PAL cleanup function. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_cleanupCrypto(void); + +/*! Initialize AES context. + * + * @param[in,out] aes: AES context to be initialized. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_initAes(palAesHandle_t *aes); + +/*! Free AES context. + * + * @param[in,out] aes: AES context to be deallocated. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_freeAes(palAesHandle_t *aes); + +/*! Set AES key context for encryption or decryption. + * + * @param[in] aes: AES context. + * @param[in] key: AES key. + * @param[in] keybits: The size of the key in bits. + * @param[in] keyTarget: The key target (encryption/decryption). + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_setAesKey(palAesHandle_t aes, const unsigned char* key, uint32_t keybits, palAesKeyType_t keyTarget); + +/*! AES-CTR buffer encryption/decryption. + * + * @param[in] aes: AES context. + * @param[in] input: The input data buffer. + * @param[out] output: The output data buffer. + * @param[in] inLen: The length of the input data. + * @param[in] iv: The initialization vector for AES-CTR. + * @param[in] zeroOffset: Send offset value zero to platform function. + * + \note Due to the nature of CTR you should use the same key schedule for both encryption and decryption. + * So before calling this function you MUST call `pal_setAesKey()` with the key target PAL_KEY_TARGET_ENCRYPTION to set the key. + * + * \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_aesCTR(palAesHandle_t aes, const unsigned char* input, unsigned char* output, size_t inLen, unsigned char iv[16], bool zeroOffset); + +/*! AES-ECB block encryption/decryption. + * + * @param[in] aes: AES context. + * @param[in] input: A 16-byte input block. + * @param[out] output: A 16-byte output block. + * @param[in] mode: PAL_AES_ENCRYPT or PAL_AES_DECRYPT + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_aesECB(palAesHandle_t aes, const unsigned char input[PAL_CRYPT_BLOCK_SIZE], unsigned char output[PAL_CRYPT_BLOCK_SIZE], palAesMode_t mode); + +/*! Process SHA256 over the input buffer. + * + * @param[in] input: A buffer for the input data. + * @param[in] inLen: The length of the input data. + * @param[out] output: SHA256 checksum result. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_sha256(const unsigned char* input, size_t inLen, unsigned char* output); + +/*! Initialize a certificate (chain) context. + * + * @param[in,out] x509Cert: The certificate chain to initialize. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_x509Initiate(palX509Handle_t* x509); + +/*! Parse one or more certificates and add them to the chained list. + * + * @param[in] x509Cert: The start of the chain. + * @param[in] input: A buffer holding the certificate data in PEM or DER format. + * @param[in] inLen: The size of the input buffer. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_x509CertParse(palX509Handle_t x509, const unsigned char* input, size_t inLen); + +/*! Get attributes from the parsed certificate. +* +* @param[in] x509Cert: The parsed certificate. +* @param[in] attr: The required attribute. +* @param[out] output: A buffer to hold the attribute value. +* @param[in] outLenBytes: The size of the allocated buffer. +* @param[out] actualOutLenBytes: The actual size of the attribute. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_x509CertGetAttribute(palX509Handle_t x509Cert, palX509Attr_t attr, void* output, size_t outLenBytes, size_t* actualOutLenBytes); + +/*! Verify one or more X509 DER formatted certificates. + * + * @param[in] x509Cert: A handle holding the parsed certificate. + * @param[in] x509CertChain: The start of the chain to verify the X509 DER certificate with. (Optional) + * + \return PAL_SUCCESS on success. In case of failure, one of the following: +* +* - PAL_ERR_X509_BADCERT_EXPIRED +* - PAL_ERR_X509_BADCERT_FUTURE +* - PAL_ERR_X509_BADCERT_BAD_MD +* - PAL_ERR_X509_BADCERT_BAD_PK +* - PAL_ERR_X509_BADCERT_NOT_TRUSTED +* - PAL_ERR_X509_BADCERT_BAD_KEY +*/ +palStatus_t pal_plat_x509CertVerify(palX509Handle_t x509Cert, palX509Handle_t x509CertChain); + +/*! Deallocate all certificate data. + * + * @param[in,out] x509: The certificate chain to free. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_x509Free(palX509Handle_t* x509); + +/*! Initialize an MD context and set up the required data according to the given algorithm. + * + * @param[in,out] md: The MD context to be initialized. + * @param[in] mdType: The MD algorithm. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_mdInit(palMDHandle_t* md, palMDType_t mdType); + +/*! Generic message digest process buffer. + * + * @param[in] md: The MD context. + * @param[in] input: A buffer holding the input data. + * @param[in] inLen: The length of the input data. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_mdUpdate(palMDHandle_t md, const unsigned char* input, size_t inLen); + +/*! Generic message digest output buffer size getter. + * + * @param[in] md: The MD context. + * @param[out] bufferSize: A pointer to hold the output size of the` pal_mdFinal()` for the given handle. + * + \note You SHOULD call this function before calling `pal_mdFinal()`. + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_mdGetOutputSize(palMDHandle_t md, size_t* bufferSize); + +/*! Generic message digest final digest. + * + * @param[in] md: The MD context. + * @param[in] output: The generic message digest checksum result. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_mdFinal(palMDHandle_t md, unsigned char* output); + +/*! Free and clear the MD context. + * + * @param[in,out] md: The AES context to be freed. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_mdFree(palMDHandle_t* md); + +/*! Verify the signature. + * + * @param[in] x509: The certificate context that holds the PK data. + * @param[in] mdType: The MD algorithm used. + * @param[in] hash: The hash of the message to sign. + * @param[in] hashLen: The hash length. + * @param[in] sig: The signature to verify. + * @param[in] sigLen: The signature length. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_verifySignature(palX509Handle_t x509, palMDType_t mdType, const unsigned char *hash, size_t hashLen, const unsigned char *sig, size_t sigLen ); + +/*! Get the tag and its length, check for the requested tag. +* Updates the pointer to immediately after the tag and length. + * + * @param[in,out] position: The position in the ASN.1 data. + * @param[in] end: The end of data. + * @param[out] len: The tag length. + * @param[in] tag: The expected tag. + * + \return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_ASN1GetTag(unsigned char **position, const unsigned char *end, size_t *len, uint8_t tag ); + +/*! CCM initialization. +* +* @param[in] ctx: The CCM context to be initialized. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CCMInit(palCCMHandle_t* ctx); + +/*! CCM destruction. +* +* @param[in] ctx: The CCM context to destroy. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CCMFree(palCCMHandle_t* ctx); + +/*! CCM set key. +* +* @param[in] ctx: The CCM context. +* @param[in] id: The cipher to use (a 128-bit block cipher). +* @param[in] key: The encryption key. +* @param[in] keybits: The key size in bits (must be acceptable by the cipher). +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CCMSetKey(palCCMHandle_t ctx, palCipherID_t id, const unsigned char *key, unsigned int keybits); + +/*! CCM buffer authenticated decryption. +* +* @param[in] ctx: The CCM context. +* @param[in] input A buffer holding the input data. +* @param[in] inLen: The length of the input data. +* @param[in] iv: The initialization vector. +* @param[in] ivLen: The length of the IV. +* @param[in] add: Additional data. +* @param[in] addLen: The length of additional data. +* @param[in] tag: A buffer holding the tag. +* @param[in] tag_len: The length of the tag. +* @param[out] output: A buffer for holding the output data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CCMDecrypt(palCCMHandle_t ctx, unsigned char* input, size_t inLen, unsigned char* iv, size_t ivLen, unsigned char* add, size_t addLen, unsigned char* tag, size_t tagLen, unsigned char* output); + +/*! CCM buffer encryption. +* +* @param[in] ctx: The CCM context. +* @param[in] input A buffer holding the input data. +* @param[in] inLen: The length of the input data. +* @param[in] iv: The initialization vector. +* @param[in] ivLen: The length of the IV. +* @param[in] add: Additional data. +* @param[in] addLen: The length of additional data. +* @param[out] output: A buffer for holding the output data, must be at least 'inLen' bytes wide. +* @param[out] tag: A buffer for holding the tag. +* @param[out] tag_len: The length of the tag to generate in bytes. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CCMEncrypt(palCCMHandle_t ctx, unsigned char* input, size_t inLen, unsigned char* iv, size_t ivLen, unsigned char* add, size_t addLen, unsigned char* output, unsigned char* tag, size_t tagLen); + +/*! CTR_DRBG initialization. +* +* @param[in] ctx: The CTR_DRBG context to be initialized. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CtrDRBGInit(palCtrDrbgCtxHandle_t* ctx); + +/*! CTR_DRBG destroy. +* +* @param[in] ctx: The CTR_DRBG context to destroy. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CtrDRBGFree(palCtrDrbgCtxHandle_t* ctx); + +/*! CTR_DRBG initial seeding. +* +* @param[in] ctx: The CTR_DRBG context to be seeded. +* @param[in] seed: The seed data. +* @param[in] len: The seed data length. +* +\return PAL_SUCCESS on success, negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CtrDRBGSeed(palCtrDrbgCtxHandle_t ctx, const void* seed, size_t len); + +/*! CTR_DRBG generate random. +* +* @param[in] ctx: The CTR_DRBG context. +* @param[in] out: The buffer to fill. +* @param[in] len: The length of the buffer. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CtrDRBGGenerate(palCtrDrbgCtxHandle_t ctx, unsigned char* out, size_t len); + +/*! AES cipher CMAC. +* +* @param[in] ctx: The CMAC context to initialize. +* @param[in] key: The encryption key. +* @param[in] keyLenInBits: The key size in bits. +* @param[in] input: A buffer for the input data. +* @param[in] inputLenInBytes: The input data length in bytes. +* @param[out] output: Generic CMAC result. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_cipherCMAC(const unsigned char *key, size_t keyLenInBits, const unsigned char *input, size_t inputLenInBytes, unsigned char *output); + +/*! Iterative cipher CMAC start. +* +* @param[in] ctx: The CMAC context to initialize. +* @param[in] key: The CMAC key. +* @param[in] keyLenBits: The key size in bits. +* @param[in] cipherID: A buffer for the input data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CMACStart(palCMACHandle_t *ctx, const unsigned char *key, size_t keyLenBits, palCipherID_t cipherID); + +/*! Iterative cipher CMAC update. +* +* @param[in] ctx: The CMAC context to initialize. +* @param[in] input: A buffer for the input data. +* @param[in] inputLen: The input data length. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CMACUpdate(palCMACHandle_t ctx, const unsigned char *input, size_t inLen); + +/*! Iterative cipher CMAC finish. +* +* @param[in] ctx: The CMAC context to initialize. +* @param[out] output: A buffer for the output data. +* @param[out] outLen: The output data length. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_CMACFinish(palCMACHandle_t *ctx, unsigned char *output, size_t* outLen); + +/*! One shot md HMAC. +* +* @param[in] key: The encryption key. +* @param[in] keyLenInBytes: The key size in bytes. +* @param[in] input: A buffer for the input data. +* @param[in] inputLenInBytes: The input data length in bytes. +* @param[out] output: The generic HMAC result. +* @param[out] outputLenInBytes: Size of the HMAC result (optional). +* +\note Expects output to be 32 bytes long +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_mdHmacSha256(const unsigned char *key, size_t keyLenInBytes, const unsigned char *input, size_t inputLenInBytes, unsigned char *output, size_t* outputLenInBytes); + + +/*! Check that the private and/or public key is a valid key and the public key is on this curve. +* +* @param[in] grp: The curve/group the point should belong to. +* @param[in] key: A pointer to the struct that holds the keys to check. +* @param[in] type: PAL_CHECK_PRIVATE_KEY/PAL_CHECK_PUBLIC_KEY/PAL_CHECK_BOTH_KEYS +* @param[out] verified: The result of the verification. +* +\note The key can contain only private or public key or both. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECCheckKey(palCurveHandle_t grp, palECKeyHandle_t key, uint32_t type, bool *verified); + +/*! Allocate key context and initialize a key pair (as an invalid one). +* +* @Param[in] key: The key pair context to initialize +* +\return PAL_SUCCESS on success, negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECKeyNew(palECKeyHandle_t* key); + +/*! Free the components of a key pair. +* +* @param[in] key: The key to free. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECKeyFree(palECKeyHandle_t* key); + +/*! Parse a DER encoded private key. +* +* @param[in] prvDERKey: A buffer that holds the DER encoded private key. +* @param[in] keyLen: The key length. +* @param[out] key: A handle for the context that holds the parsed key. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_parseECPrivateKeyFromDER(const unsigned char* prvDERKey, size_t keyLen, palECKeyHandle_t key); + +/*! Parse a DER encoded public key. +* +* @param[in] pubDERKey: A buffer that holds the DER encoded public key. +* @param[in] keyLen: The key length. +* @param[out] key: A handle for the context that holds the parsed key. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_parseECPublicKeyFromDER(const unsigned char* pubDERKey, size_t keyLen, palECKeyHandle_t key); + +/*! Encode the given private key from the key handle to the DER buffer. +* +* @param[in] key: A handle to the private key. +* @param[out] derBuffer: A buffer to hold the result of the DER encoding. +* @param[in] bufferSize: The size of the allocated buffer. +* @param[out] actualSize: The actual size of the written data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_writePrivateKeyToDer(palECKeyHandle_t key, unsigned char* derBuffer, size_t bufferSize, size_t* actualSize); + +/*! Encode the given public key from the key handle to the DER buffer. +* +* @param[in] key: A handle to the public key. +* @param[out] derBuffer: A buffer to hold the result of the DER encoding. +* @param[in] bufferSize: The size of the allocated buffer. +* @param[out] actualSize: The actual size of the written data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_writePublicKeyToDer(palECKeyHandle_t key, unsigned char* derBuffer, size_t bufferSize, size_t* actualSize); + +/*! Generate a keypair. +* +* @param[in] grpID: The ECP group identifier. +* @param[in] key: A handle to the destination keypair. +* +\note The `key` parameter must be first allocated by `pal_ECKeyNew()`. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECKeyGenerateKey(palGroupIndex_t grpID, palECKeyHandle_t key); + +/*! Retrieve the curve ID if it exists in the given key. +* +* @param[in] key: The key to retrieve its curve. +* @param[out] grpID: The curve/group ID for the given key. In case of error, this pointer contains "PAL_ECP_DP_NONE". +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECKeyGetCurve(palECKeyHandle_t key, palGroupIndex_t* grpID); + +/*! Allocate and initialize the x509 CSR context. +* +* @param[in] x509CSR: The CSR context to allocate and initialize. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_x509CSRInit(palx509CSRHandle_t *x509CSR); + +/*! Set the subject name for a CSR. The subject names should contain a comma-separated list of OIDs and values. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] subjectName: The subject name to set. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_x509CSRSetSubject(palx509CSRHandle_t x509CSR, const char* subjectName); + +/*! Set the MD algorithm to use for the signature. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] mdType: The MD algorithm to use. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_x509CSRSetMD(palx509CSRHandle_t x509CSR, palMDType_t mdType); + +/*! Set the key for a CSR. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] pubKey: The public key to include. To use the keypair handle, see the note. +* @param[in] prvKey: The public key to sign with. +* +\note To use the keypair, please send it as `pubKey` and NULL as `prvKey`. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_x509CSRSetKey(palx509CSRHandle_t x509CSR, palECKeyHandle_t pubKey, palECKeyHandle_t prvKey); + +/*! Set the key usage extension flags. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] keyUsage: The key usage flags that should be taken from `palKeyUsage_t`. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_x509CSRSetKeyUsage(palx509CSRHandle_t x509CSR, uint32_t keyUsage); + +/*! Generic function to add to the CSR. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] oid: The OID of the extension. +* @param[in] oidLen: The OID length. +* @param[in] value: The value of the extension OCTET STRING. +* @param[in] valueLen: The value length. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_x509CSRSetExtension(palx509CSRHandle_t x509CSR,const char* oid, size_t oidLen, const unsigned char* value, size_t valueLen); + +/*! Write a CSR to a DER structure. +* +* @param[in] x509CSR: The CSR context to use. +* @param[in] derBuf: A buffer to write to. +* @param[in] derBufLen: The buffer length. +* @param[in] actualDerLen: The actual length of the written data. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_x509CSRWriteDER(palx509CSRHandle_t x509CSR, unsigned char* derBuf, size_t derBufLen, size_t* actualDerLen); + +/*! Free the x509 CSR context. +* +* @param[in] x509CSR: The CSR context to free. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_x509CSRFree(palx509CSRHandle_t *x509CSR); + +/*! Compute a shared secret. +* +* @param[in] grp: The ECP group. +* @param[in] peerPublicKey: The public key from a peer. +* @param[in] privateKey: The private key. +* @param[out] outKey: The shared secret. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECDHComputeKey(const palCurveHandle_t grp, const palECKeyHandle_t peerPublicKey, const palECKeyHandle_t privateKey, palECKeyHandle_t outKey); + +/*! Compute the ECDSA signature of a previously hashed message. +* +* @param[in] grp: The ECP group. +* @param[in] prvKey: The private signing key- +* @param[in] dgst: The message hash. +* @param[in] dgstLen: The length of the message buffer. +* @param[out] sig: A buffer to hold the computed signature. +* @param[out] sigLen: The length of the computed signature. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECDSASign(palCurveHandle_t grp, palMDType_t mdType, palECKeyHandle_t prvKey, unsigned char* dgst, uint32_t dgstLen, unsigned char *sig, size_t *sigLen); + +/*! Verify the ECDSA signature of a previously hashed message. +* +* @param[in] pubKey: The public key for verification. +* @param[in] dgst: The message hash. +* @param[in] dgstLen: The length of the message buffer. +* @param[in] sign: The signature. +* @param[in] sig: A buffer to hold the computed signature. +* @param[in] sigLen: The length of the computed signature. +* @param[out] verified: The boolean to hold the verification result. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECDSAVerify(palECKeyHandle_t pubKey, unsigned char* dgst, uint32_t dgstLen, unsigned char* sig, size_t sigLen, bool* verified); + +/*! Free the components of an ECP group. +* +* @param[in] grp: The curve/group to free. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECGroupFree(palCurveHandle_t* grp); + +/*! ECP group initialize and set a group using well-known domain parameters. +* +* @param[in] grp: The destination group. +* @param[in] index: The index in the list of well-known domain parameters. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_ECGroupInitAndLoad(palCurveHandle_t* grp, palGroupIndex_t index); + +#endif //_PAL_PLAT_CRYPTO_H_
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_TLS.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_TLS.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,285 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef _PAL_PLAT_TLS_H_ +#define _PAL_PLAT_TLS_H_ +#include "pal_TLS.h" + +/*! \file pal_plat_TLS.h +* \brief PAL TLS/DTLS - platform. +* This file contains TLS/DTLS APIs that need to be implemented in the platform layer. +*/ + +/***************************************************/ +/**** PAL DTLS internal data structures ************/ +/***************************************************/ +typedef enum palDTLSSide{ +#ifdef PAL_TLS_SUPPORT_SERVER_MODE + PAL_TLS_IS_SERVER, +#endif // PAL_TLS_SUPPORT_SERVER_MODE + PAL_TLS_IS_CLIENT +} palDTLSSide_t; + +typedef enum palTLSAuthMode{ + PAL_TLS_VERIFY_NONE, //! Server mode: The peer certificate is not verified. For client mode, this is insecure! + PAL_TLS_VERIFY_OPTIONAL, //! The peer certificate verification can be failed and handshake continues. + PAL_TLS_VERIFY_REQUIRED //! The peer certificate verification MUST pass. +}palTLSAuthMode_t; + +//! This is the list of the available cipher suites, this code MUST be +//! defined in the `pal_plat_TLS.c` with the proper values for the SSL platform: +typedef enum palTLSSuites{ + PAL_TLS_PSK_WITH_AES_128_CBC_SHA256, + PAL_TLS_PSK_WITH_AES_128_CCM_8, + PAL_TLS_PSK_WITH_AES_256_CCM_8, + PAL_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + PAL_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + PAL_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 +}palTLSSuites_t; + +typedef void* palTLSSocketHandle_t; +typedef void* palTimerCtx_t; + +//! This prototype can be re-defined by the platform side. +//! Consider moving them to separate header. +typedef int (*palBIOSend_f)(palTLSSocketHandle_t socket, const unsigned char *buf, size_t len); +typedef int (*palBIORecv_f)(palTLSSocketHandle_t socket, unsigned char *buf, size_t len); +typedef int (*palVerifyCallback_f)(void *, void *, int, uint32_t *); +typedef void (*palSetTimer_f)( void *data, uint32_t intMs, uint32_t finMs ); +typedef int (*palGetTimer_f)(void* data); +typedef void (*palLogFunc_f)(void *context, int debugLevel, const char *fileName, int line, const char *message); + + +/*! Initiate the TLS library. This API is not required for each TLS library. +* For example for mbed TLS, it will be an empty function. +* +\note You must call this function in the general PAL initializtion function. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_initTLSLibrary(void); + +/*! Free resources for the TLS library. +* +\note You must call this function in the general PAL cleanup function. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_cleanupTLS(void); + +/*! Initiate new configuration context. +* +* @param[out] palTLSConf: The TLS configuration context. +* @param[in] tranportVersion: The `palTLSTransportMode_t` type deciding the transportation version (for example tlsv1.2). +* @param[in] methodType: The `palDTLSSide_t` type deciding the endpoint type (server or client). +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_initTLSConf(palTLSConfHandle_t* confCtx, palTLSTransportMode_t transportVersion, palDTLSSide_t methodType); + +/*! Destroy and release resources for the TLS configuration context. +* +* @param[inout] palTLSConf: The TLS configuration context to free. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_tlsConfigurationFree(palTLSConfHandle_t* palTLSConf); + +/*! Initiate a new TLS context. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[out] palTLSHandle: The index to the TLS context. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_initTLS(palTLSConfHandle_t palTLSConf, palTLSHandle_t* palTLSHandle); + +/*! Destroy and release resources for the TLS context. +* +* @param[inout] ssl: The TLS context to free. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_freeTLS(palTLSHandle_t* palTLSHandle); + +/*! Add an entropy source to the TLS/DTLS library (this API may NOT be available in all TLS/DTLS platforms, see the note). +* +* @param[in] entropyCallback: The entropy callback to be used in the TLS/DTLS handshake. +* +\note This function is available ONLY when the TLS/DTLS platform supports this functionality. In other platforms, + PAL_ERR_NOT_SUPPORTED should be returned. +\return PAL_SUCCESS on success. A negative value indicating a specific error code or PAL_ERR_NOT_SUPPORTED in case of failure. +*/ +palStatus_t pal_plat_addEntropySource(palEntropySource_f entropyCallback); + +/*! Set the supported cipher suites to the configuration context. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] palSuites: The supported cipher suites to be added. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_setCipherSuites(palTLSConfHandle_t sslConf, palTLSSuites_t palSuite); + +/*! Return the result of the certificate verification. The handshake API calls this. +* +* @param[in] ssl: The TLS context. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_sslGetVerifyResult(palTLSHandle_t palTLSHandle); + +/*! Read at most 'len' application data bytes. +* +* @param[in] ssl: The TLS context. +* @param[out] buffer: A buffer holding the data. +* @param[in] len: The maximum number of bytes to read. +* @param[out] actualLen: The actual number of bytes read. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_sslRead(palTLSHandle_t palTLSHandle, void *buffer, uint32_t len, uint32_t* actualLen); + +/*! Try to write exactly 'len' application data bytes. +* +* @param[in] ssl: The TLS context. +* @param[in] buffer: A buffer holding the data. +* @param[in] len: The number of bytes to be written. +* @param[out] bytesWritten: The number of bytes actually written. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_sslWrite(palTLSHandle_t palTLSHandle, const void *buffer, uint32_t len, uint32_t *bytesWritten); + +/*! Set the retransmit timeout values for the DTLS handshake. +* (DTLS only, no effect on TLS.) +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] timeoutInMilliSec: The maximum timeout value in milliseconds. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_setHandShakeTimeOut(palTLSConfHandle_t palTLSConf, uint32_t timeoutInMilliSec); + +/*! Set up a TLS context for use. +* +* @param[in/out] ssl: The TLS context. +* @param[in] palTLSConf: The TLS configuration context. +* +\return The function returns `palTLSHandle_t`, the index to the TLS context. +*/ +palStatus_t pal_plat_sslSetup(palTLSHandle_t palTLSHandle, palTLSConfHandle_t palTLSConf); + +/*! Perform the TLS handshake (blocking). +* +* @param[in] ssl: The TLS context. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_handShake(palTLSHandle_t palTLSHandle); + +/*! Set the socket for the TLS configuration context. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] socket: The socket for the TLS context. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_tlsSetSocket(palTLSConfHandle_t palTLSConf, palTLSSocket_t* socket); + +/*! Set your own certificate chain and private key. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] ownCert: Your own public certificate chain. +* @param[in] privateKey: Your own private key. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_setOwnCertAndPrivateKey(palTLSConfHandle_t palTLSConf, palX509_t* ownCert, palPrivateKey_t* privateKey); + +/*! Set the data required to verify a peer certificate. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] caChain: The trusted CA chain. +* @param[in] caCRL: The trusted CA CRLs. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_setCAChain(palTLSConfHandle_t palTLSConf, palX509_t* caChain, palX509CRL_t* caCRL); + +/*! Set the Pre-Shared Key (PSK) and the expected identity name. +* +* @param[in] sslConf: The TLS configuration context. +* @param[in] identity: A pointer to the pre-shared key identity. +* @param[in] maxIdentityLenInBytes: The maximum length of the identity key. +* @param[in] psk: A pointer to the pre-shared key. +* @param[in] maxPskLenInBytes: The maximum length of the pre-shared key. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_setPSK(palTLSConfHandle_t sslConf, const unsigned char *identity, uint32_t maxIdentityLenInBytes, const unsigned char *psk, uint32_t maxPskLenInBytes); + + +/*! Set the certificate verification mode. +* +* @param[in] sslConf: The TLS configuration context. +* @param[in] authMode: The authentication mode. +* +\note In some platforms, a verification callback MAY be needed. In this case, it must be provided by the porting side. +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_setAuthenticationMode(palTLSConfHandle_t sslConf, palTLSAuthMode_t authMode); + +/*! Turn on or off debugging from the TLS library. If the debugging is on, the logs will be sent via the PAL Logger (mbedTrace?!). +* In release mode, an error will be returned. +* +* @param[in] turnOn: Sets the status of the debugging prints. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_sslDebugging(uint8_t turnOn); + +/*! Set the IO callbacks for the TLS context. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] palIOCtx: The shared context by BIO callbacks. +* @param[in] palBIOSend: A pointer to send BIO function. +* @param[in] palBIORecv: A pointer to receive BIO function. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_sslSetIOCallBacks(palTLSConfHandle_t palTLSConf, palTLSSocket_t* palIOCtx, palBIOSend_f palBIOSend, palBIORecv_f palBIORecv); + +/*! Set the timer callbacks. +* +* @param[in] palTLSHandle: The TLS context. +* @param[in] timerCtx: The shared context by BIO callbacks. +* @param[in] setTimer: The set timer callback. +* @param[in] getTimer: The get timer callback. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_setTimeCB(palTLSHandle_t* palTLSHandle, palTimerCtx_t timerCtx, palSetTimer_f setTimer, palGetTimer_f getTimer); + +/*! Set the logging function. +* +* @param[in] palTLSConf: The TLS configuration context. +* @param[in] palLogFunction: A pointer to the logging function. +* @param[in] logContext: The context for the logging function. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_SetLoggingCb(palTLSConfHandle_t palTLSConf, palLogFunc_f palLogFunction, void *logContext); + +#endif //_PAL_PLAT_TLS_H_
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_fileSystem.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_fileSystem.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,277 @@ +#ifndef PAL_PALT_FILE_SYSTEM_H +#define PAL_PALT_FILE_SYSTEM_H + +#include "pal_fileSystem.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \file pal_plat_fileSystem.h +* \brief PAL file system - platform. +* This file contains the file system APIs that need to be implemented in the platform layer. +*/ + +/*! @defgroup PAL_PLAT_GROUP_FS +* \note You need to add the prefix of the ESFS folder root stored in \c g_esfsRootFolder to all files and folders. +* To change this, call \c pal_plat_fsSetEsfsRootFolder(). +* +*/ + +/** +@defgroup PAL_PLAT_PUBLIC_FUNCTION PAL Platform Public Functions +@ingroup PAL_PLAT_GROUP_FS +*/ + +/** +@addtogroup PAL_PLAT_PUBLIC_FUNCTION +@{*/ + +/*! \brief This function attempts to create a directory named \c pathName. +* +* @param[in] *pathName A pointer to the null-terminated string that specifies the directory name to create. +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +* \note To remove a directory use \c PAL_ERR_FS_rmdir. +* +*\b Example +\code{.cpp} + palStatus_t ret; + ret = PAL_ERR_FS_mkdir("Dir1"); + if(!ret) + { + //Error + } +\endcode +*/ +palStatus_t pal_plat_fsMkdir(const char *pathName); + + + +/*! \brief This function deletes a directory. +* +* @param[in] *pathName A pointer to the null-terminated string that specifies the name of the directory to be deleted. +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +* \note The directory to be deleted \b must \b be \b Empty and \b closed. +* The folder path must end with "/". +* If given "..", the function changes the root directory to one directory down and deletes the working directory. +*/ +palStatus_t pal_plat_fsRmdir(const char *pathName); + + + +/*!\brief This function opens the file whose name is specified in the parameter `pathName` and associates it with a stream +* that can be identified in future operations by the `fd` pointer returned. +* +* @param[out] fd A file descriptor for the file entered in the `pathName`. +* @param[in] *pathName A pointer to the null-terminated string that specifies the file name to open or create. +* @param[in] mode A mode flag that specifies the type of access and open method for the file. +* +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +* \note The folder path must end with "/". +* \note If necessary, the platform layer \b allocates \b memory for the file descriptor. The structure +* \c pal_plat_fclose() shall free that buffer. +* \note The mode flags sent to this function are normalized to the \c pal_fsFileMode_t and each platform needs to replace them with the proper values. +* +*/ +palStatus_t pal_plat_fsFopen(const char *pathName, pal_fsFileMode_t mode, palFileDescriptor_t *fd); + + + +/*! \brief This function closes an open file object. +* +* @param[in] fd A pointer to the open file object structure to be closed. +* +* \return PAL_SUCCESS upon a successful operation. \n +* PAL_FILE_SYSTEM_ERROR - see the error code \c palError_t.a +* +* \note After successful execution of the function, the file object is no longer valid and it can be discarded. +* \note In some platforms, this function needs to \b free the file descriptor memory. +*/ +palStatus_t pal_plat_fsFclose(palFileDescriptor_t *fd); + + + +/*! \brief This function reads an array of bytes from the stream and stores them in the block of memory +* specified by the buffer. The position indicator of the stream is advanced by the total amount of bytes read. +* +* @param[in] fd A pointer to the open file object structure. +* @param[in] buffer A buffer for storing the read data. +* @param[in] numOfBytes The number of bytes to read. +* @param[out] numberOfBytesRead The number of bytes read. +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +* \note After successful execution of the function, +* `numberOfBytesRead` should be checked to detect end of the file. +* If `numberOfBytesRead` is less than `numOfBytes`, +* the read/write pointer has reached the end of the file during the read operation or an error has occurred. +* +*/ +palStatus_t pal_plat_fsFread(palFileDescriptor_t *fd, void * buffer, size_t numOfBytes, size_t *numberOfBytesRead); + + + +/*! \brief This function starts to write data from the \c buffer to the file at the position pointed by the read/write pointer. +* +* @param[in] fd A pointer to the open file object structure. +* @param[in] buffer A pointer to the data to be written. +* @param[in] numOfBytes The number of bytes to write. +* @param[out] numberOfBytesWritten The number of bytes written. +* +* \return PAL_SUCCESS upon a successful operation. \n +* PAL_FILE_SYSTEM_ERROR - see the error code \c palError_t. +* +* \note The read/write pointer advances as number of bytes written. After successful execution of the function, +* \note `numberOfBytesWritten` should be checked to detect if the disk is full. +* If `numberOfBytesWritten` is less than `numOfBytes`, the volume got full during the write operation. +* +*/ +palStatus_t pal_plat_fsFwrite(palFileDescriptor_t *fd, const void *buffer, size_t numOfBytes, size_t *numberOfBytesWritten); + + +/*! \brief This function moves the file read/write pointer without any read/write operation to the file. +* +* @param[in] fd A pointer to the open file object structure. +* @param[in] offset The byte offset from top of the file to set the read/write pointer. +* @param[out] whence The offset is relative to this. +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +* \note - The `whence` options are: +* -# \c PAL_ERR_FS_SEEKSET - relative to the start of the file. +* -# \c PAL_ERR_FS_SEEKCUR - relative to the current position indicator. +* -# \c PAL_ERR_FS_SEEKEND - relative to the end-of-file. +* +* \note In some systems, there is no \c whence argument. +* If you need to implement the `whence` argument:\n +* \b PAL_ERR_FS_SEEKEND - The function first finds the length of the file, then subtracts the file length from the position to find the relative path from the beginning.\n +* \b PAL_ERR_FS_SEEKCUR - The function finds the current stream position and calculates the relative path from the file start.\n +* +* In both options, \c fseek() needs to verify that the offset is smaller than the file end or start. +* +*/ +palStatus_t pal_plat_fsFseek(palFileDescriptor_t *fd, int32_t offset, pal_fsOffset_t whence); + + + +/*! \brief This function gets the current read/write pointer of a file. +* +* @param[in] fd A pointer to the open file object structure. +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +*/ +palStatus_t pal_plat_fsFtell(palFileDescriptor_t *fd, int32_t * pos); + + + +/*! \brief This function deletes a \b single file from the file system. +* +* @param[in] pathName A pointer to a null-terminated string that specifies the \b file to be removed. +* @param[in] buildRelativeDirectory Needed to add a working directory to give \c pathName. +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +* \note The file \b must \b not \b be \b opened +* +*/ +palStatus_t pal_plat_fsUnlink(const char *pathName); + + + +/*! \brief This function deletes \b all files in a folder from the file system (FLAT remove only). +* +* @param[in] pathName A pointer to a null-terminated string that specifies the \b folder. +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +* \note The folder \b must \b not \b be \b open and the folder path must end with "/". +* \note The process deletes one file at a time by calling \c pal_plat_fsUnlink until all files are removed. +* \note The function does not remove the directory found in the path. +*/ +palStatus_t pal_plat_fsRmFiles(const char *pathName); + + + +/*! \brief This function copies \b all files from a source folder to a destination folder (FLAT copy only). +* +* @param[in] pathNameSrc A pointer to a null-terminated string that specifies the source folder. +* @param[in] pathNameDest A pointer to a null-terminated string that specifies the destination folder (MUST exist). +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +* \note Both folders \b must \b not \b be \b open. If a folder does not exist the function fails. +* \note The process copies one file at a time until all files are copied. +* \note The function does not copy a directory found in the path. +*/ +palStatus_t pal_plat_fsCpFolder(const char *pathNameSrc, char *pathNameDest); + + +/*! \brief This function gets the default value for root directory (primary) +* +* @param[in] dataID - id of the data to ge the root folder for. +* +* \return pointer to the default path. +* +*/ +const char* pal_plat_fsGetDefaultRootFolder(pal_fsStorageID_t dataID); + + + +/*! \brief This function finds the length of the string received. +* +* +* @param[in] stringToChk A pointer to the string received with a null terminator. +* +* \return The size of the string. +* +*/ +size_t pal_plat_fsSizeCheck(const char *stringToChk); + + + +/*! \brief This function sets up the mount point. +* +* +* @param void +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +*/ +palStatus_t pal_plat_fsMountSystem(void); +/** +@} */ + + +/*! \brief This function formats the SD partition indicated by `partitionID` (mapping the ID to an actual partition is done in the porting layer). +* +* +* @param[in] partitionID The ID of the partition to be formatted. +* +* \return PAL_SUCCESS upon a successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see the error code description \c palError_t. +* +*/ +palStatus_t pal_plat_fsFormat(pal_fsStorageID_t dataID); + + +#ifdef __cplusplus +} +#endif +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_internalFlash.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_internalFlash.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,113 @@ +#ifndef PAL_PLAT_FLASH_H_ +#define PAL_PLAT_FLASH_H_ + +#include "pal_internalFlash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \brief This function initialized the flash API module, + * And should be called prior flash APIs calls + * + * \return PAL_SUCCESS upon successful operation. \n + * PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. + * + * \note should be called only once unless \c pal_InternalFlashDeinit function is called + * \note This function is Blocking till completion!! + * + */ +palStatus_t pal_plat_internalFlashInit(void); + +/*! \brief This function destroy the flash module + * + * \return PAL_SUCCESS upon successful operation. \n + * PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. + * + * \note Should be called only after \c pal_InternalFlashinit() is called. + * \note Flash APIs will not work after calling this function + * \note This function is Blocking till completion!! + * + */ +palStatus_t pal_plat_internalFlashDeInit(void); + +/*! \brief This function writes to the internal flash +* +* @param[in] buffer - pointer to the buffer to be written +* @param[in] size - the size of the buffer in bytes, must be aligned to minimum writing unit (page size). +* @param[in] address - the address of the internal flash. +* +* \return PAL_SUCCESS upon successful operation. \n +* PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. +* +* \note This function is Blocking till completion!! +* \note This function is Thread Safe!! +*/ +palStatus_t pal_plat_internalFlashWrite(const size_t size, const uint32_t address, const uint32_t * buffer); + +/*! \brief This function copies the memory data into the user given buffer +* +* @param[in] size - the size of the buffer in bytes. +* @param[in] address - the address of the internal flash. +* @param[out] buffer - pointer to the buffer to write to +* +* \return PAL_SUCCESS upon successful operation. \n +* PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. +* \note This function is Blocking till completion!! +* \note This function is Thread Safe!! +* +*/ +palStatus_t pal_plat_internalFlashRead(const size_t size, const uint32_t address, uint32_t * buffer); + +/*! \brief This function Erase the sector +* +* @param[in] size - the size to be erased, must be align to sector. +* @param[in] address - sector start address to be erased, must be align to sector. +* +* \return PAL_SUCCESS upon successful operation. \n +* PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. +* +* \note ALL sectors can be erased!! No protection to bootloader, program or other... +* \note This function is Blocking till completion!! +* \note Only one sector can be erased in each function call +* \note This function is Thread Safe!! +*/ +palStatus_t pal_plat_internalFlashErase(uint32_t address, size_t size); + +/*! \brief This function returns the minimum writing unit to the flash +* +* \return size_t the 2, 4, 8.... +*/ +size_t pal_plat_internalFlashGetPageSize(void); + + +/*! \brief This function returns the sector size + * +* @param[in] address - the starting address of the sector is question +* +* \return size of sector, 0 if error +*/ +size_t pal_plat_internalFlashGetSectorSize(uint32_t address); + + + +/////////////////////////////////////////////////////////////// +////-------------------SOTP functions------------------------// +/////////////////////////////////////////////////////////////// +/*! \brief This function return the SOTP section data +* +* @param[in] section - the section number (0 or 1) +* @param[out] data - the information about the section +* +* \return PAL_SUCCESS upon successful operation. \n +* PAL_ERR_INTERNAL_FLASH_ERROR - see error code \c palError_t. +* +*/ +palStatus_t pal_plat_internalFlashGetAreaInfo(bool section, palSotpAreaData_t *data); + + +#ifdef __cplusplus +} +#endif + +#endif /* PAL_PLAT_FLASH_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_network.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_network.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,236 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef _PAL_PLAT_SOCKET_H +#define _PAL_PLAT_SOCKET_H + +#include "pal.h" +#include "pal_network.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \file pal_plat_network.h +* \brief PAL network - platform. +* This file contains the network APIs that need to be implemented in the platform layer. +*/ + +//! PAL network socket API /n +//! PAL network socket configuration options: +//! - define PAL_NET_TCP_AND_TLS_SUPPORT if TCP is supported by the platform and is required. +//! - define PAL_NET_ASYNCHRONOUS_SOCKET_API if asynchronous socket API is supported by the platform. Currently MANDATORY. +//! - define PAL_NET_DNS_SUPPORT if DNS name resolution is supported. + +/*! Initialize sockets - must be called before other socket functions (is called from PAL init). +* @param[in] context Optional context - if not available/applicable use NULL. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_socketsInit(void* context); + +/*! Register a network interface for use with PAL sockets - must be called before other socket functions - most APIs will not work before a single interface is added. +* @param[in] networkInterfaceContext The context of the network interface to be added (OS specific. In mbed OS, this is the NetworkInterface object pointer for the network adapter [**note:** We assume connect has already been called on this]). - if not available use NULL (may not be required on some OSs). +* @param[out] interfaceIndex Contains the index assigned to the interface if it has been assigned successfully. This index can be used when creating a socket to bind the socket to the interface. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_registerNetworkInterface(void* networkInterfaceContext, uint32_t* interfaceIndex); + +/*! Initialize terminate - can be called when sockets are no longer needed to free socket resources allocated by init. +* @param[in] context Optional context - if not available use NULL. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_socketsTerminate(void* context); + +/*! Get a network socket. +* @param[in] domain The domain of the created socket (see `palSocketDomain_t` for supported types). +* @param[in] type The type of the created socket (see `palSocketType_t` for supported types). +* @param[in] nonBlockingSocket If true, the socket is non-blocking (with O_NONBLOCK set). +* @param[in] interfaceNum The number of the network interface used for this socket (info in interfaces supported via `pal_getNumberOfNetInterfaces` and `pal_getNetInterfaceInfo`), select PAL_NET_DEFAULT_INTERFACE as the default interface. +* @param[out] socket The socket is returned through this output parameter. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_socket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palSocket_t* socket); + +/*! Get options for a given network socket. Only a few options are supported (see `palSocketOptionName_t`). +* @param[in] socket The socket to get options for. +* @param[in] optionName The name to set the option for (see enum palSocketOptionName_t for supported types). +* @param[out] optionValue The buffer holding the option value returned by the function. +* @param[in, out] optionLength The size of the buffer provided for `optionValue` when calling the function. After the call, it contains the length of data actually written to the `optionValue` buffer. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_getSocketOptions(palSocket_t socket, palSocketOptionName_t optionName, void* optionValue, palSocketLength_t* optionLength); + +/*! Set options for a given network socket. Only a few options are supported (see `palSocketOptionName_t`). +* @param[in] socket The socket to get options for. +* @param[in] optionName The name to set the option for (see enum palSocketOptionName_t for supported types). +* @param[in] optionValue The buffer holding the value to set for the given option. +* @param[in] optionLength The size of the buffer provided for `optionValue`. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_setSocketOptions(palSocket_t socket, int optionName, const void* optionValue, palSocketLength_t optionLength); + +/*! Check if the given socket is non-blocking. +* @param[in] socket The socket for which to check non-blocking status. +* @param[out] isNonBlocking The non-blocking status for the socket (true if non-blocking, otherwise false). +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_isNonBlocking(palSocket_t socket, bool* isNonBlocking); + +/*! Bind a given socket to a local address. +* @param[in] socket The socket to bind. +* @param[in] myAddress The address to bind to. +* @param[in] addressLength The length of the address passed in `myAddress`. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_bind(palSocket_t socket, palSocketAddress_t* myAddress, palSocketLength_t addressLength); + +/*! Receive a payload from the given socket. +* @param[in] socket The socket to receive from [sockets passed to this function should be of type PAL_SOCK_DGRAM (the implementation may support other types as well)]. +* @param[out] buffer The buffer for the payload data. +* @param[in] length The length of the buffer for the payload data. +* @param[out] from The address that sent the payload [optional - if not required pass NULL]. +* @param[in, out] fromLength The length of the `from` address. When completed, this contains the amount of data actually written to the `from` address [optional - if not required pass NULL]. +* @param[out] bytesReceived The actual amount of payload data received in the buffer. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_receiveFrom(palSocket_t socket, void* buffer, size_t length, palSocketAddress_t* from, palSocketLength_t* fromLength, size_t* bytesReceived); + +/*! Send a payload to the given address using the given socket. +* @param[in] socket The socket to use for sending the payload [sockets passed to this function should be of type PAL_SOCK_DGRAM (the implementation may support other types as well)]. +* @param[in] buffer The buffer for the payload data. +* @param[in] length The length of the buffer for the payload data. +* @param[in] to The address to which the payload should be sent. +* @param[in] toLength The length of the `to` address. +* @param[out] bytesSent The actual amount of payload data sent. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_sendTo(palSocket_t socket, const void* buffer, size_t length, const palSocketAddress_t* to, palSocketLength_t toLength, size_t* bytesSent); + +/*! Close a network socket. \n +* \note The function recieves `palSocket_t*` and not `palSocket_t` so that it can zero the socket to avoid re-use. +* @param[in,out] socket Release and zero socket pointed to by given pointer. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_close(palSocket_t* socket); + +/*! Get the number of current network interfaces (interfaces that have been registered through). +* @param[out] numInterfaces The number of interfaces after a successful call. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_getNumberOfNetInterfaces(uint32_t* numInterfaces); + +/*! Get information regarding the socket at the index/interface number given (this number is returned when registering the socket). +* @param[in] interfaceNum The number of the interface to get information for. +* @param[out] interfaceInfo The information for the given interface number. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_getNetInterfaceInfo(uint32_t interfaceNum, palNetInterfaceInfo_t* interfaceInfo); + + +/*! Check if one or more (up to PAL_NET_SOCKET_SELECT_MAX_SOCKETS) sockets has data available for reading/writing/error. The function blocks until data is available for one of the given sockets or the timeout expires. \n +* To use the function, set the sockets you want to check in the `socketsToCheck` array and set a timeout. When it returns the `socketStatus` output indicates the status of each socket passed in. \n +* \note The entry in index x in the socketStatus array corresponds to the socket at index x in the sockets to check array. +* If the timeout expires, the returned `palStatus_t` is PAL_SUCCESS and `numberOfSocketsSet` is 0. \n +* @param[in] socketsToCheck The array of up to 8 socket handles to check. +* @param[in] numberOfSockets The number of sockets set in the input `socketsToCheck` array. +* @param[in] timeout The time until timeout if no socket activity is detected. +* @param[out] palSocketStatus Information on each socket in the input array indicating which event was set (none, rx, tx, err). Check for a desired event using macros. +* @param[out] numberOfSocketsSet The total number of sockets set in all three data sets (tx, rx, err) after a completed function. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_socketMiniSelect(const palSocket_t socketsToCheck[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t numberOfSockets, pal_timeVal_t* timeout, + uint8_t palSocketStatus[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t * numberOfSocketsSet); + + +#if PAL_NET_TCP_AND_TLS_SUPPORT // The functionality below is supported only if TCP is supported. + + +/*! Use a socket to listen to incoming connections. You may also limit the queue of incoming connections. +* @param[in] socket The socket to listen to [sockets passed to this function should be of type PAL_SOCK_STREAM_SERVER (the implementation may support other types as well)]. +* @param[in] backlog The number of pending connections that can be saved for the socket. +\return PAL_SUCCESS (0) in case of success. A specific negative error code in case of failure. +*/ +palStatus_t pal_plat_listen(palSocket_t socket, int backlog); + +/*! Accept a connection on the given socket. +* @param[in] socket The socket on which to accept the connection. The socket needs to be created and bound and listen must have been called on it. [sockets passed to this function should be of type PAL_SOCK_STREAM_SERVER (the implementation may support other types as well)]. +* @param[out] address The source address of the incoming connection. +* @param[in, out] addressLen The length of the address field on input, the length of the data returned on output. +* @param[out] acceptedSocket The socket of the accepted connection is returned if the connection is accepted successfully. +\return PAL_SUCCESS (0) in case of success, a specific negative error code in case of failure. +*/ +palStatus_t pal_plat_accept(palSocket_t socket, palSocketAddress_t* address, palSocketLength_t* addressLen, palSocket_t* acceptedSocket); + +/*! Open a connection from the given socket to the given address. +* @param[in] socket The socket to use for the connection to the given address [sockets passed to this function should be of type PAL_SOCK_STREAM (the implementation may support other types as well)]. +* @param[in] address The destination address of the connection. +* @param[in] addressLen The length of the address field. +\return PAL_SUCCESS (0) in case of success, a specific negative error code in case of failure. +*/ +palStatus_t pal_plat_connect(palSocket_t socket, const palSocketAddress_t* address, palSocketLength_t addressLen); + +/*! Receive data from the given connected socket. +* @param[in] socket The connected socket on which to receive data [sockets passed to this function should be of type PAL_SOCK_STREAM (the implementation may support other types as well)]. +* @param[out] buf The output buffer for the message data. +* @param[in] len The length of the input data buffer. +* @param[out] recievedDataSize The length of the data actually received. +\return PAL_SUCCESS (0) in case of success, a specific negative error code in case of failure. +*/ +palStatus_t pal_plat_recv(palSocket_t socket, void* buf, size_t len, size_t* recievedDataSize); + +/*! Send a given buffer via the given connected socket. +* @param[in] socket The connected socket on which to send data [sockets passed to this function should be of type PAL_SOCK_STREAM (the implementation may support other types as well)]. +* @param[in] buf The output buffer for the message data. +* @param[in] len The length of the input data buffer. +* @param[out] sentDataSize The length of the data sent. +\return PAL_SUCCESS (0) in case of success, a specific negative error code in case of failure. +*/ +palStatus_t pal_plat_send(palSocket_t socket, const void* buf, size_t len, size_t* sentDataSize); + + +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + +/*! Get an asynchronous network socket. +* @param[in] domain The domain of the created socket (see enum `palSocketDomain_t` for supported types). +* @param[in] type The type of the created socket (see enum `palSocketType_t` for supported types). +* @param[in] callback A callback function that is called when any supported event takes place in the given asynchronous socket. +* @param[in] callbackArgument the argument with which the callback will be called when any supported event takes place in the given asynchronous socket. +* @param[out] socket This output parameter returns the socket. +\return PAL_SUCCESS (0) in case of success, a specific negative error code in case of failure. +*/ +palStatus_t pal_plat_asynchronousSocket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t callback, void* callbackArgument , palSocket_t* socket); + +#endif + +#if PAL_NET_DNS_SUPPORT + +/*! This function translates the URL to a `palSocketAddress_t` that can be used with PAL sockets. +* @param[in] url The URL to be translated to a `palSocketAddress_t`. +* @param[out] address The address for the output of the translation. +*/ +palStatus_t pal_plat_getAddressInfo(const char* url, palSocketAddress_t* address, palSocketLength_t* addressLength); + +#endif + + +#ifdef __cplusplus +} +#endif +#endif //_PAL_PLAT_SOCKET_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_rtos.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_rtos.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,405 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef _PAL_PLAT_RTOS_H +#define _PAL_PLAT_RTOS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pal_rtos.h" +#include "pal_configuration.h" +#include "pal_types.h" + +/*! \file pal_plat_rtos.h +* \brief PAL RTOS - platform. +* This file contains the real-time OS APIs that need to be implemented in the platform layer. +*/ + +#if PAL_UNIQUE_THREAD_PRIORITY +//! This array holds a counter for each thread priority. +//! If the counter is more than 1, it means that more than +//! one thread has the same priority and this is a forbidden +//! situation. The mapping between the priorities and the index +//! in the array is as follow: +//! +//! PAL_osPriorityIdle --> g_palThreadPriorities[0] +//! PAL_osPriorityLow --> g_palThreadPriorities[1] +//! PAL_osPriorityBelowNormal --> g_palThreadPriorities[2] +//! PAL_osPriorityNormal --> g_palThreadPriorities[3] +//! PAL_osPriorityAboveNormal --> g_palThreadPriorities[4] +//! PAL_osPriorityHigh --> g_palThreadPriorities[5] +//! PAL_osPriorityRealtime --> g_palThreadPriorities[6] + +//! An array of PAL thread priorities. The size of the array is defined in the Service API (`pal_configuration.h`) by PAL_MAX_NUMBER_OF_THREADS. +extern uint32_t g_palThreadPriorities[PAL_NUMBER_OF_THREADS_PRIORITIES]; +extern palMutexID_t g_palThreadInitMutex ; + +#define PRIORITY_INDEX_OFFSET 3 +#endif //PAL_UNIQUE_THREAD_PRIORITY + +#define PAL_SHA256_DEVICE_KEY_SIZE_IN_BYTES 32 +#define PAL_DEVICE_KEY_SIZE_IN_BYTES 16 +#define PAL_DEVICE_KEY_SIZE_IN_BITS (PAL_DEVICE_KEY_SIZE_IN_BYTES * 8) + +/*! Initiate a system reboot. +*/ +void pal_plat_osReboot(void); + +/*! Initialize all data structures (semaphores, mutexes, memory pools, message queues) at system initialization. +* In case of a failure in any of the initializations, the function returns an error and stops the rest of the initializations. +* @param[in] opaqueContext The context passed to the initialization (not required for generic CMSIS, pass NULL in this case). +* \return PAL_SUCCESS(0) in case of success, PAL_ERR_CREATION_FAILED in case of failure. +*/ +palStatus_t pal_plat_RTOSInitialize(void* opaqueContext); + +/*! De-initialize thread objects. +*/ +palStatus_t pal_plat_RTOSDestroy(void); + +/*! Get the RTOS kernel system timer counter. +* +* \return The RTOS kernel system timer counter. +* +* \note The required tick counter is the OS (platform) kernel system tick counter. +* \note If the platform supports 64-bit tick counter, please implement it. If the platform supports only 32 bit, note +* that this counter wraps around very often (for example, once every 42 sec for 100Mhz). +*/ +uint64_t pal_plat_osKernelSysTick(void); + +/*! Convert the value from microseconds to kernel sys ticks. +* This is the same as CMSIS macro `osKernelSysTickMicroSec`. +*/ +uint64_t pal_plat_osKernelSysTickMicroSec(uint64_t microseconds); + +/*! Get the system tick frequency. +* \return The system tick frequency. +* +* \note The system tick frequency MUST be more than 1KHz (at least one tick per millisecond). +*/ +uint64_t pal_plat_osKernelSysTickFrequency(void); + +/*! Create and start a thread function. +* +* @param[in] function A function pointer to the thread callback function. +* @param[in] funcArgument An argument for the thread function. +* @param[in] priority The priority of the thread. +* @param[in] stackSize The stack size of the thread. +* @param[in] stackPtr A pointer to the thread's stack. +* @param[in] store A pointer to thread's local store, can be NULL. +* @param[out] threadID The created thread ID handle, zero indicates an error. +* +* \return The ID of the created thread. In case of error, returns zero. +* \note Each thread MUST have a unique priority. +* \note When the priority of the created thread function is higher than the current running thread, the +* created thread function starts instantly and becomes the new running thread. +* \note The create function MUST not wait for platform resources and it should return PAL_ERR_RTOS_RESOURCE, unless the platform API is blocking. +*/ +palStatus_t pal_plat_osThreadCreate(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, uint32_t* stackPtr, palThreadLocalStore_t* store, palThreadID_t* threadID); + +/*! Terminate and free allocated data for the thread. +* +* @param[in] threadID The ID of the thread to stop and terminate. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osThreadTerminate(palThreadID_t* threadID); + +/*! Get the ID of the current thread. +* \return The ID of the current thread. In case of error, returns PAL_MAX_UINT32. +* \note For a thread with real time priority, the function always returns PAL_MAX_UINT32. +*/ +palThreadID_t pal_plat_osThreadGetId(void); + +/*! Get the storage of the current thread. +* \return The storage of the current thread. +*/ +palThreadLocalStore_t* pal_plat_osThreadGetLocalStore(void); + +/*! Wait for a specified period of time in milliseconds. +* +* @param[in] milliseconds The number of milliseconds to wait before proceeding. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osDelay(uint32_t milliseconds); + +/*! Create a timer. +* +* @param[in] function A function pointer to the timer callback function. +* @param[in] funcArgument An argument for the timer callback function. +* @param[in] timerType The timer type to be created, periodic or `oneShot`. +* @param[out] timerID The ID of the created timer. Zero value indicates an error. +* +* \return PAL_SUCCESS when the timer was created successfully. A specific error in case of failure. \n +* PAL_ERR_NO_MEMORY: No memory resource available to create a timer object. +* +* \note The timer callback function runs according to the platform resources of stack size and priority. +* \note The create function MUST not wait for platform resources and it should return PAL_ERR_RTOS_RESOURCE, unless the platform API is blocking. +*/ +palStatus_t pal_plat_osTimerCreate(palTimerFuncPtr function, void* funcArgument, palTimerType_t timerType, palTimerID_t* timerID); + +/*! Start or restart a timer. +* +* @param[in] timerID The handle for the timer to start. +* @param[in] millisec: The time in milliseconds to set the timer to, MUST be larger than 0. +* In case the value is 0, the error PAL_ERR_RTOS_VALUE will be returned. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osTimerStart(palTimerID_t timerID, uint32_t millisec); + +/*! Stop a timer. +* +* @param[in] timerID The handle for the timer to stop. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osTimerStop(palTimerID_t timerID); + +/*! Delete the timer object. +* +* @param[inout] timerID The handle for the timer to delete. In success, `*timerID` = NULL. +* +* \return PAL_SUCCESS when the timer was deleted successfully. PAL_ERR_RTOS_PARAMETER when the `timerID` is incorrect. +* \note In case of a running timer, `pal_platosTimerDelete()` MUST stop the timer before deletion. +*/ +palStatus_t pal_plat_osTimerDelete(palTimerID_t* timerID); + +/*! Create and initialize a mutex object. +* +* @param[out] mutexID The created mutex ID handle, zero value indicates an error. +* +* \return PAL_SUCCESS when the mutex was created successfully, a specific error in case of failure. \n +* PAL_ERR_NO_MEMORY when there is no memory resource available to create a mutex object. +* \note The create function MUST NOT wait for the platform resources and it should return PAL_ERR_RTOS_RESOURCE, unless the platform API is blocking. +* By default, the mutex is created with a recursive flag set. +*/ +palStatus_t pal_plat_osMutexCreate(palMutexID_t* mutexID); + +/*! Wait until a mutex becomes available. +* +* @param[in] mutexID The handle for the mutex. +* @param[in] millisec The timeout for the waiting operation if the timeout expires before the semaphore is released and an error is returned from the function. +* +* \return PAL_SUCCESS(0) in case of success. One of the following error codes in case of failure: \n +* - PAL_ERR_RTOS_RESOURCE - Mutex not available but no timeout set. \n +* - PAL_ERR_RTOS_TIMEOUT - Mutex was not available until timeout expired. \n +* - PAL_ERR_RTOS_PARAMETER - The mutex ID is invalid. \n +* - PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines. +*/ +palStatus_t pal_plat_osMutexWait(palMutexID_t mutexID, uint32_t millisec); + +/*! Release a mutex that was obtained by `osMutexWait`. +* +* @param[in] mutexID The handle for the mutex. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osMutexRelease(palMutexID_t mutexID); + +/*! Delete a mutex object. +* +* @param[inout] mutexID The ID of the mutex to delete. In success, `*mutexID` = NULL. +* +* \return PAL_SUCCESS when the mutex was deleted successfully, one of the following error codes in case of failure: \n +* - PAL_ERR_RTOS_RESOURCE - Mutex already released. \n +* - PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid. \n +* - PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines. +* \note After this call, `mutex_id` is no longer valid and cannot be used. +*/ +palStatus_t pal_plat_osMutexDelete(palMutexID_t* mutexID); + +/*! Create and initialize a semaphore object. +* +* @param[in] count The number of available resources. +* @param[out] semaphoreID The ID of the created semaphore, zero value indicates an error. +* +* \return PAL_SUCCESS when the semaphore was created successfully, a specific error in case of failure. \n +* PAL_ERR_NO_MEMORY: No memory resource available to create a semaphore object. +* \note The create function MUST not wait for the platform resources and it should return PAL_ERR_RTOS_RESOURCE, unless the platform API is blocking. +*/ +palStatus_t pal_plat_osSemaphoreCreate(uint32_t count, palSemaphoreID_t* semaphoreID); + +/*! Wait until a semaphore token becomes available. +* +* @param[in] semaphoreID The handle for the semaphore. +* @param[in] millisec The timeout for the waiting operation if the timeout expires before the semaphore is released and an error is returned from the function. +* @param[out] countersAvailable The number of semaphores available. If semaphores are not available (timeout/error) zero is returned. +* \return PAL_SUCCESS(0) in case of success. One of the following error codes in case of failure: \n +* - PAL_ERR_RTOS_TIMEOUT - Semaphore was not available until timeout expired. \n +* - PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid. +*/ +palStatus_t pal_plat_osSemaphoreWait(palSemaphoreID_t semaphoreID, uint32_t millisec, int32_t* countersAvailable); + +/*! Release a semaphore token. +* +* @param[in] semaphoreID The handle for the semaphore. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osSemaphoreRelease(palSemaphoreID_t semaphoreID); + +/*! Delete a semaphore object. +* +* @param[inout] semaphoreID: The ID of the semaphore to delete. In success, `*semaphoreID` = NULL. +* +* \return PAL_SUCCESS when the semaphore was deleted successfully. One of the following error codes in case of failure: \n +* PAL_ERR_RTOS_RESOURCE - Semaphore already released. \n +* PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid. +* \note After this call, the `semaphore_id` is no longer valid and cannot be used. +*/ +palStatus_t pal_plat_osSemaphoreDelete(palSemaphoreID_t* semaphoreID); + +/*! Create and initialize a memory pool. +* +* @param[in] blockSize The size of a single block in bytes. +* @param[in] blockCount The maximum number of blocks in the memory pool. +* @param[out] memoryPoolID The ID of the created memory pool. Zero value indicates an error. +* +* \return PAL_SUCCESS when the memory pool was created successfully. A specific error in case of failure. \n +* PAL_ERR_NO_MEMORY when no memory resource is available to create a memory pool object. +* \note The create function MUST NOT wait for the platform resources and it should return PAL_ERR_RTOS_RESOURCE, unless the platform API is blocking. +*/ +palStatus_t pal_plat_osPoolCreate(uint32_t blockSize, uint32_t blockCount, palMemoryPoolID_t* memoryPoolID); + +/*! Allocate a single memory block from a memory pool. +* +* @param[in] memoryPoolID The handle for the memory pool. +* +* \return A pointer to a single allocated memory from the pool, NULL in case of failure. +*/ +void* pal_plat_osPoolAlloc(palMemoryPoolID_t memoryPoolID); + +/*! Allocate a single memory block from a memory pool and set the memory block to zero. +* +* @param[in] memoryPoolID The handle for the memory pool. +* +* \return A pointer to a single allocated memory from the pool, NULL in case of failure. +*/ +void* pal_plat_osPoolCAlloc(palMemoryPoolID_t memoryPoolID); + +/*! Return the memoryPoolID of the memory block back to a specific memory pool. +* +* @param[in] memoryPoolID The handle for the memory pool. +* @param[in] block The block to be freed. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osPoolFree(palMemoryPoolID_t memoryPoolID, void* block); + +/*! Delete a memory pool object. +* +* @param[inout] memoryPoolID The handle for the memory pool. In success, `*memoryPoolID` = NULL. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osPoolDestroy(palMemoryPoolID_t* memoryPoolID); + +/*! Create and initialize a message queue. +* +* @param[in] messageQCount The size of the message queue. +* @param[out] messageQID The ID of the created message queue, zero value indicates an error. +* +* \return PAL_SUCCESS when the message queue was created successfully. A specific error in case of failure. \n +* PAL_ERR_NO_MEMORY when there is no memory resource available to create a message queue object. +* \note The create function MUST NOT wait for the platform resources and it should return PAL_ERR_RTOS_RESOURCE, unless the platform API is blocking. +*/ +palStatus_t pal_plat_osMessageQueueCreate(uint32_t messageQCount, palMessageQID_t* messageQID); + +/*! Put a message to a queue. +* +* @param[in] messageQID The handle for the message queue. +* @param[in] info The data to send. +* @param[in] timeout The timeout in milliseconds. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osMessagePut(palMessageQID_t messageQID, uint32_t info, uint32_t timeout); + +/*! Get a message or wait for a message from a queue. +* +* @param[in] messageQID The handle for the message queue. +* @param[in] timeout The timeout in milliseconds. +* @param[out] messageValue The data to send. +* +* \return PAL_SUCCESS(0) in case of success. One of the following error codes in case of failure: \n +* - PAL_ERR_RTOS_RESOURCE - Semaphore was not available but not due to timeout. \n +* - PAL_ERR_RTOS_TIMEOUT - No message arrived during the timeout period. \n +* - PAL_ERR_RTOS_RESOURCE - No message received and there was no timeout. +*/ +palStatus_t pal_plat_osMessageGet(palMessageQID_t messageQID, uint32_t timeout, uint32_t* messageValue); + +/*! Delete a message queue object. +* +* @param[inout] messageQID The handle for the message queue. In success, `*messageQID` = NULL. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osMessageQueueDestroy(palMessageQID_t* messageQID); + +/*! Perform an atomic increment for a signed32 bit value. +* +* @param[in,out] valuePtr The address of the value to increment. +* @param[in] increment The number by which to increment. +* +* \returns The value of the `valuePtr` after the increment operation. +*/ +int32_t pal_plat_osAtomicIncrement(int32_t* valuePtr, int32_t increment); + +/*! Perform allocation from the heap according to the OS specification. +* +* @param[in] len The length of the buffer to be allocated. +* +* \returns `void *`. The pointer of the malloc received from the OS if NULL error occurred +*/ +void *pal_plat_malloc(size_t len); + +/*! Free memory back to the OS heap. +* +* @param[in] *buffer A pointer to the buffer that should be free. +* +* \returns `void` +*/ + void pal_plat_free(void * buffer); + +/*! Generate a random number into the given buffer with the given size in bytes. +* +* @param[out] randomBuf A buffer to hold the generated number. +* @param[in] bufSizeBytes The size of the buffer and the size of the required random number to generate. +* +\return PAL_SUCCESS on success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes); + + +/*! Retrieve platform Root of Trust certificate +* +* @param[in,out] *keyBuf A pointer to the buffer that holds the RoT. +* @param[in] keyLenBytes The size of the buffer to hold the 128 bit key, must be at least 16 bytes. +* The buffer needs to be able to hold 16 bytes of data. +* +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ + +palStatus_t pal_plat_osGetRoT128Bit(uint8_t *keyBuf, size_t keyLenBytes); + +#ifdef __cplusplus +} +#endif +#endif //_PAL_COMMON_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_update.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Platform-API/pal_plat_update.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,133 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef PAL_PLAT_UPDATE_HEADER +#define PAL_PLAT_UPDATE_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +#include "pal_rtos.h" +#include "pal_update.h" + + +/*! \file pal_plat_update.h +* \brief PAL update - platform. +* This file contains the firmware update APIs that need to be implemented in the platform layer. +*/ + + +/*! Set the callback function that is called before the end of each API (except `imageGetDirectMemAccess`). +* @param[in] CBfunction A pointer to the callback function. +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_imageInitAPI(palImageSignalEvent_t CBfunction); + + +/*! Clear all the resources used by the `pal_update` APIs. + * \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_imageDeInit(void); + +/*! Set the `imageNumber` to the number of available images. You can do this through the hard coded define inside the linker script. +* @param[out] imageNumber The total number of images the system supports. +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_imageGetMaxNumberOfImages(uint8_t* imageNumber); + +/*! Claim space in the relevant storage region for `imageId` with the size of the image. +* @param[in] imageId The image ID. +* @param[in] imageSize The size of the images. +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_imageReserveSpace(palImageId_t imageId, size_t imageSize); + + +/*! Set up the details for the image header. The data is written when the image write is called for the first time. +* @param[in] imageId The image ID. +* @param[in] details The data needed to build the image header. +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_imageSetHeader(palImageId_t imageId,palImageHeaderDeails_t* details); + +/*! Write the data in the chunk buffer with the size written in chunk `bufferLength` in the location of `imageId` adding the relative offset. + * @param[in] imageId The image ID. + * @param[in] offset The relative offset to write the data into. + * @param[in] chunk A pointer to the struct containing the data and the data length to write. + * \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_imageWrite(palImageId_t imageId, size_t offset, palConstBuffer_t* chunk); + +/*! Update the image version of `imageId` to the version written in version buffer with version `bufferLength`. +* @param[in] imageId The image ID. +* @param[in] version The image version and its length. +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. +*/ +palStatus_t pal_plat_imageSetVersion(palImageId_t imageId, const palConstBuffer_t* version); + +/*! Flush the entire image data after writing ends for `imageId`. +* @param[in] imageId The image ID. +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_imageFlush(palImageId_t imageId); + +/*! Verify whether the `imageId` is readable and set `imagePtr` to point to the beginning of the image in the memory and `imageSizeInBytes` to the image size. \n +* @param[in] imageId The image ID. +* @param[out] imagePtr A pointer to the start of the image. +* @param[out] imageSizeInBytes The size of the image. +* \return PAL_SUCCESS(0) in case of success. A negative value indicating a specific error code in case of failure and sets `imagePtr` to NULL. +*/ +palStatus_t pal_plat_imageGetDirectMemAccess(palImageId_t imageId, void** imagePtr, size_t* imageSizeInBytes); + + +/*! Read the max of chunk `maxBufferLength` bytes from the `imageId` with relative offset and store it in chunk buffer. \n +* Set the chunk `bufferLength` value to the actual number of bytes read. +* \note Please use this API in case the image is not directly accessible via the `imageGetDirectMemAccess` function. +* @param[in] imageId The image ID. +* @param[in] offset The offset to start reading from. +* @param[out] chunk The data and actual bytes read. +*/ +palStatus_t pal_plat_imageReadToBuffer(palImageId_t imageId, size_t offset, palBuffer_t* chunk); + +/*! Set the `imageId` to be the active image (after device reset). + * @param[in] imageId The image ID. + */ +palStatus_t pal_plat_imageActivate(palImageId_t imageId); + +/*! Retrieve the hash value of the active image to the hash buffer with the max size hash `maxBufferLength` and set the hash `bufferLength` to the hash size. + * @param[out] hash The hash and actual size of hash read. + */ +palStatus_t pal_plat_imageGetActiveHash(palBuffer_t* hash); + +/*! Retrieve the version of the active image to the version buffer with the size set to version `bufferLength`. + * @param[out] version The version and actual size of version read. + */ +palStatus_t pal_plat_imageGetActiveVersion (palBuffer_t* version); + +/*! Write the `dataId` stored in `dataBuffer` to the memory accessible to the bootloader. Currently, only HASH is available. +* @param[in] hashValue The data and size of the HASH. + */ +palStatus_t pal_plat_imageWriteHashToMemory(const palConstBuffer_t* const hashValue); + + + + +#endif /* SOURCE_PAL_IMPL_MODULES_UPDATE_PAL_PALT_UPDATE_H_ */ +#ifdef __cplusplus +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/Lib_Specific/mbedTLS/Crypto/pal_plat_Crypto.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/Lib_Specific/mbedTLS/Crypto/pal_plat_Crypto.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1888 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "stdlib.h" +#include "string.h" +#include "time.h" +#include "pal.h" +#include "pal_plat_Crypto.h" +#include "pal_plat_rtos.h" +#include "mbedtls/aes.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/sha256.h" +#include "mbedtls/md.h" +#include "mbedtls/ccm.h" +#include "mbedtls/entropy.h" +#include "mbedtls/cmac.h" +#include "mbedtls/asn1.h" +#include "mbedtls/ecp.h" +#include "mbedtls/x509_csr.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_time.h" + + +typedef mbedtls_ccm_context palCCM_t; +typedef mbedtls_ecp_group palECGroup_t; +typedef mbedtls_ecp_point palECPoint_t; +typedef mbedtls_mpi palMP_t; +typedef mbedtls_pk_context palECKey_t; +typedef mbedtls_x509write_csr palx509CSR_t; +typedef mbedtls_cipher_context_t palCipherCtx_t; + + +//! forward declaration +//! This function is based on PAL random algorithm which uses CTR-DRBG algorithm +PAL_PRIVATE int pal_plat_entropySource( void *data, unsigned char *output, size_t len); + +//! forward declarations +//! This function access directly to the plarform entropy source +//! it was added specialy for DRBG reseeding process +PAL_PRIVATE int pal_plat_entropySourceDRBG( void *data, unsigned char *output, size_t len); + + +typedef struct palSign{ + mbedtls_mpi r; + mbedtls_mpi s; +}palSignature_t; + +typedef struct palCtrDrbgCtx{ + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctrDrbgCtx; +}palCtrDrbgCtx_t; + +typedef struct palAes{ + mbedtls_aes_context platCtx; + unsigned char stream_block[PAL_CRYPT_BLOCK_SIZE]; //The saved stream-block for resuming. Is overwritten by the function. + size_t nc_off; //The offset in the current stream_block +}palAes_t; + +typedef struct palX509Ctx{ + mbedtls_x509_crt crt; +}palX509Ctx_t; + + +typedef struct palMD{ + mbedtls_md_context_t md; +}palMD_t; + +#define CRYPTO_PLAT_SUCCESS 0 +#define CRYPTO_PLAT_GENERIC_ERROR (-1) + +palStatus_t pal_plat_initCrypto() +{ + palStatus_t status = PAL_SUCCESS; + return status; +} + +palStatus_t pal_plat_cleanupCrypto() +{ + return PAL_SUCCESS; +} + +palStatus_t pal_plat_initAes(palAesHandle_t *aes) +{ + palStatus_t status = PAL_SUCCESS; + palAes_t* localCtx = NULL; + + localCtx = (palAes_t*)malloc(sizeof(palAes_t)); + if (NULL == localCtx) + { + status = PAL_ERR_CREATION_FAILED; + } + else + { + mbedtls_aes_init(&localCtx->platCtx); + localCtx->nc_off = 0; + memset(localCtx->stream_block, 0, 16); + + *aes = (palAesHandle_t)localCtx; + } + return status; +} + +palStatus_t pal_plat_freeAes(palAesHandle_t *aes) +{ + palStatus_t status = PAL_SUCCESS; + palAes_t* localCtx = NULL; + + localCtx = (palAes_t*)*aes; + + mbedtls_aes_free(&localCtx->platCtx); + free(localCtx); + *aes = NULLPTR; + return status; +} + +palStatus_t pal_plat_setAesKey(palAesHandle_t aes, const unsigned char* key, uint32_t keybits, palAesKeyType_t keyTarget) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palAes_t* localCtx = (palAes_t*)aes; + + if (PAL_KEY_TARGET_ENCRYPTION == keyTarget) + { + platStatus = mbedtls_aes_setkey_enc(&localCtx->platCtx, key, keybits); + } + else + { + platStatus = mbedtls_aes_setkey_dec(&localCtx->platCtx, key, keybits); + } + + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_AES_INVALID_KEY_LENGTH; + } + + return status; +} + +palStatus_t pal_plat_aesCTR(palAesHandle_t aes, const unsigned char* input, unsigned char* output, size_t inLen, unsigned char iv[16], bool zeroOffset) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palAes_t* localCtx = (palAes_t*)aes; + + if (true == zeroOffset) + { + localCtx->nc_off = 0; + memset(localCtx->stream_block, 0, 16); + } + + platStatus = mbedtls_aes_crypt_ctr(&localCtx->platCtx, inLen, &localCtx->nc_off, iv, localCtx->stream_block, input, output); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + PAL_LOG(ERR, "Crypto aes ctr status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + return status; +} + +palStatus_t pal_plat_aesECB(palAesHandle_t aes, const unsigned char input[PAL_CRYPT_BLOCK_SIZE], unsigned char output[PAL_CRYPT_BLOCK_SIZE], palAesMode_t mode) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palAes_t* localCtx = (palAes_t*)aes; + + platStatus = mbedtls_aes_crypt_ecb(&localCtx->platCtx, (PAL_AES_ENCRYPT == mode ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT), input, output); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + PAL_LOG(ERR, "Crypto aes ecb status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + return status; +} + +palStatus_t pal_plat_sha256(const unsigned char* input, size_t inLen, unsigned char* output) +{ + mbedtls_sha256(input, inLen, output, 0); + + return PAL_SUCCESS; +} + +palStatus_t pal_plat_x509Initiate(palX509Handle_t* x509) +{ + palStatus_t status = PAL_SUCCESS; + palX509Ctx_t* localCtx = NULL; + + localCtx = (palX509Ctx_t*)malloc(sizeof(palX509Ctx_t)); + if (NULL == localCtx) + { + status = PAL_ERR_CREATION_FAILED; + } + else + { + mbedtls_x509_crt_init(&localCtx->crt); + *x509 = (uintptr_t)localCtx; + } + + return status; +} + +palStatus_t pal_plat_x509CertParse(palX509Handle_t x509, const unsigned char* input, size_t inLen) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palX509Ctx_t* localCtx = (palX509Ctx_t*)x509; + + platStatus = mbedtls_x509_crt_parse_der(&localCtx->crt, input, inLen); + if (platStatus < CRYPTO_PLAT_SUCCESS) + { + if (MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE == platStatus) + { + status = PAL_ERR_NOT_SUPPORTED_CURVE; + } + + else if (-(MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG) == ((-platStatus) & 0xFF80)) + { + status = PAL_ERR_INVALID_MD_TYPE; + } + + else + { + status = PAL_ERR_CERT_PARSING_FAILED; + } + } + + return status; +} + +PAL_PRIVATE palStatus_t pal_plat_X509GetField(palX509Ctx_t* x509Ctx, const char* fieldName, void* output, size_t outLenBytes, size_t* actualOutLenBytes) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + const char *shortName = NULL; + size_t fieldNameLength = 0; + mbedtls_x509_name *x509Name = &x509Ctx->crt.subject; + + if (NULL == fieldName) // other arguments already checked in service layer. + { + return PAL_ERR_INVALID_ARGUMENT; + } + + fieldNameLength = strlen(fieldName); + while( x509Name ) + { + platStatus = mbedtls_oid_get_attr_short_name(&x509Name->oid, &shortName); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_INVALID_IOD; + break; + } + if (strncmp(shortName, fieldName, fieldNameLength) == 0) + { + if (outLenBytes < (x509Name->val.len + 1)) + { + status = PAL_ERR_BUFFER_TOO_SMALL; + *actualOutLenBytes = x509Name->val.len + 1; + break; + } + memcpy(output, x509Name->val.p, x509Name->val.len); + ((char*)output)[x509Name->val.len] = '\0'; + *actualOutLenBytes = x509Name->val.len + 1; + break; + } + x509Name = x509Name->next; + } + return status; +} + +PAL_PRIVATE bool pal_isLeapYear(uint8_t year) +{ + bool result = false; + if (year % 4 != 0) + { + result = false; + } + else if ((year % 100) != 0) + { + result = true; + } + else + { + result = ((year % 400) == 0); + } + return result; +} + +PAL_PRIVATE palStatus_t pal_timegm( struct tm *tm, uint64_t* outTime) +{ + uint64_t epoc = 0; + uint8_t palMonthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + if (NULL == outTime || tm->tm_year < 1970) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + for (uint16_t y = 1970; y < tm->tm_year; ++y) + { + if (pal_isLeapYear(y)) + { + epoc += 366 * PAL_SECONDS_PER_DAY; + } + else + { + epoc += 365 * PAL_SECONDS_PER_DAY; + } + } + + for (uint8_t m = 1; m < tm->tm_mon; ++m) + { + epoc += palMonthDays[m - 1] * PAL_SECONDS_PER_DAY; + if (m == PAL_FEB_MONTH && pal_isLeapYear(tm->tm_year)) + { + epoc += PAL_SECONDS_PER_DAY; + } + } + + epoc += (tm->tm_mday - 1) * PAL_SECONDS_PER_DAY; + epoc += tm->tm_hour * PAL_SECONDS_PER_HOUR; + epoc += tm->tm_min * PAL_SECONDS_PER_MIN; + epoc += tm->tm_sec; + *outTime = epoc; + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_x509CertGetAttribute(palX509Handle_t x509Cert, palX509Attr_t attr, void* output, size_t outLenBytes, size_t* actualOutLenBytes) +{ + palStatus_t status = PAL_SUCCESS; + palX509Ctx_t* localCtx = (palX509Ctx_t*)x509Cert; + + switch(attr) + { + case PAL_X509_ISSUER_ATTR: + if (localCtx->crt.issuer_raw.len <= outLenBytes) + { + memcpy(output, localCtx->crt.issuer_raw.p, localCtx->crt.issuer_raw.len); + } + else + { + status = PAL_ERR_BUFFER_TOO_SMALL; + } + *actualOutLenBytes = localCtx->crt.issuer_raw.len; + break; + + case PAL_X509_SUBJECT_ATTR: + if (localCtx->crt.subject_raw.len <= outLenBytes) + { + memcpy(output, localCtx->crt.subject_raw.p, localCtx->crt.subject_raw.len); + } + else + { + status = PAL_ERR_BUFFER_TOO_SMALL; + } + *actualOutLenBytes = localCtx->crt.subject_raw.len; + break; + + case PAL_X509_VALID_FROM: + if ( PAL_CRYPTO_CERT_DATE_LENGTH > outLenBytes) + { + status = PAL_ERR_BUFFER_TOO_SMALL; + } + else + { + struct tm time; + uint64_t timeOfDay; + time.tm_year = localCtx->crt.valid_from.year; + time.tm_mon = localCtx->crt.valid_from.mon; + time.tm_mday = localCtx->crt.valid_from.day; + time.tm_hour = localCtx->crt.valid_from.hour; + time.tm_min = localCtx->crt.valid_from.min; + time.tm_sec = localCtx->crt.valid_from.sec; + time.tm_isdst = -1; //unknown DST + status = pal_timegm(&time, &timeOfDay); + if (PAL_SUCCESS != status) + { + status = PAL_ERR_TIME_TRANSLATE; + } + else + { + memcpy(output, &timeOfDay, PAL_CRYPTO_CERT_DATE_LENGTH); + } + } + *actualOutLenBytes = PAL_CRYPTO_CERT_DATE_LENGTH; + break; + + case PAL_X509_VALID_TO: + if ( PAL_CRYPTO_CERT_DATE_LENGTH > outLenBytes) + { + status = PAL_ERR_BUFFER_TOO_SMALL; + } + else + { + struct tm time; + uint64_t timeOfDay; + time.tm_year = localCtx->crt.valid_to.year; + time.tm_mon = localCtx->crt.valid_to.mon; + time.tm_mday = localCtx->crt.valid_to.day; + time.tm_hour = localCtx->crt.valid_to.hour; + time.tm_min = localCtx->crt.valid_to.min; + time.tm_sec = localCtx->crt.valid_to.sec; + time.tm_isdst = -1; //unknown DST + status = pal_timegm(&time, &timeOfDay); + if (PAL_SUCCESS != status) + { + status = PAL_ERR_TIME_TRANSLATE; + } + else + { + memcpy(output, &timeOfDay, PAL_CRYPTO_CERT_DATE_LENGTH); + } + } + *actualOutLenBytes = PAL_CRYPTO_CERT_DATE_LENGTH; + break; + + case PAL_X509_CN_ATTR: + status = pal_plat_X509GetField(localCtx, "CN", output, outLenBytes, actualOutLenBytes); + break; + + case PAL_X509_OU_ATTR: + status = pal_plat_X509GetField(localCtx, "OU", output, outLenBytes, actualOutLenBytes); + break; + default: + status = PAL_ERR_INVALID_X509_ATTR; + } + return status; +} + +PAL_PRIVATE const mbedtls_x509_crt_profile s_PALProfile = +{ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ), + MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECKEY ) | MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ), + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ), + 0x7FFFFFFF // RSA not allowed +}; + + +palStatus_t pal_plat_x509CertVerify(palX509Handle_t x509Cert, palX509Handle_t x509CertChain) +{ + palStatus_t status = PAL_SUCCESS; + palX509Ctx_t* localCert = (palX509Ctx_t*)x509Cert; + palX509Ctx_t* localCAChain = (palX509Ctx_t*)x509CertChain; + //mbedtls_x509_crt_profile profiles = {1,1,1,1}; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + uint32_t flags = 0; + + if (NULL == localCAChain) + { + //platStatus = mbedtls_x509_crt_verify(&localCert->crt, NULL, NULL, NULL, &flags, NULL, NULL); + platStatus = mbedtls_x509_crt_verify_with_profile(&localCert->crt, NULL, NULL, &s_PALProfile, NULL, &flags, NULL, NULL); + } + else + { + //platStatus = mbedtls_x509_crt_verify(&localCert->crt, &localCAChain->crt, NULL, NULL, &flags, NULL, NULL); + platStatus = mbedtls_x509_crt_verify_with_profile(&localCert->crt, &localCAChain->crt, NULL, &s_PALProfile, NULL, &flags, NULL, NULL); + } + + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + //! please DO NOT change errors order + if (MBEDTLS_X509_BADCERT_EXPIRED & flags) + { + status = PAL_ERR_X509_BADCERT_EXPIRED; + goto finish; + } + if (MBEDTLS_X509_BADCERT_FUTURE & flags) + { + status = PAL_ERR_X509_BADCERT_FUTURE; + goto finish; + } + if (MBEDTLS_X509_BADCERT_BAD_MD & flags) + { + status = PAL_ERR_X509_BADCERT_BAD_MD; + goto finish; + } + if (MBEDTLS_X509_BADCERT_BAD_PK & flags) + { + status = PAL_ERR_X509_BADCERT_BAD_PK; + goto finish; + } + if (MBEDTLS_X509_BADCERT_BAD_KEY & flags) + { + status = PAL_ERR_X509_BADCERT_BAD_KEY; + goto finish; + } + if (MBEDTLS_X509_BADCERT_NOT_TRUSTED & flags) + { + status = PAL_ERR_X509_BADCERT_NOT_TRUSTED; + goto finish; + } + } +finish: + return status; +} + +palStatus_t pal_plat_x509Free(palX509Handle_t* x509) +{ + palStatus_t status = PAL_SUCCESS; + palX509Ctx_t* localCtx = NULL; + + localCtx = (palX509Ctx_t*)*x509; + mbedtls_x509_crt_free(&localCtx->crt); + free(localCtx); + *x509 = NULLPTR; + return status; +} + +palStatus_t pal_plat_mdInit(palMDHandle_t* md, palMDType_t mdType) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palMD_t* localCtx = NULL; + const mbedtls_md_info_t* mdInfo = NULL; + mbedtls_md_type_t mdAlg = MBEDTLS_MD_NONE; + + localCtx = (palMD_t*)malloc(sizeof(palMD_t)); + if (NULL == localCtx) + { + status = PAL_ERR_CREATION_FAILED; + goto finish; + } + + + mbedtls_md_init(&localCtx->md); + + switch (mdType) + { + case PAL_SHA256: + mdAlg = MBEDTLS_MD_SHA256; + break; + default: + status = PAL_ERR_INVALID_MD_TYPE; + goto finish; + } + + mdInfo = mbedtls_md_info_from_type(mdAlg); + if (NULL == mdInfo) + { + status = PAL_ERR_INVALID_MD_TYPE; + goto finish; + } + + platStatus = mbedtls_md_setup(&localCtx->md, mdInfo, 0); // 0 because we don't want to use HMAC in mbedTLS to save memory + switch(platStatus) + { + case CRYPTO_PLAT_SUCCESS: + break; + case MBEDTLS_ERR_MD_BAD_INPUT_DATA: + { + status = PAL_ERR_MD_BAD_INPUT_DATA; + goto finish; + } + case MBEDTLS_ERR_MD_ALLOC_FAILED: + { + status = PAL_ERR_CREATION_FAILED; + goto finish; + } + default: + { + PAL_LOG(ERR, "Crypto md start setup %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + goto finish; + } + } + + platStatus = mbedtls_md_starts(&localCtx->md); + switch(platStatus) + { + case CRYPTO_PLAT_SUCCESS: + break; + case MBEDTLS_ERR_MD_BAD_INPUT_DATA: + { + status = PAL_ERR_MD_BAD_INPUT_DATA; + goto finish; + } + default: + { + PAL_LOG(ERR, "Crypto md start status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + goto finish; + } + } + + *md = (uintptr_t)localCtx; +finish: + if (PAL_SUCCESS != status && NULL != localCtx) + { + free(localCtx); + } + return status; +} + +palStatus_t pal_plat_mdUpdate(palMDHandle_t md, const unsigned char* input, size_t inLen) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palMD_t* localCtx = (palMD_t*)md; + + platStatus = mbedtls_md_update(&localCtx->md, input, inLen); + switch(platStatus) + { + case CRYPTO_PLAT_SUCCESS: + break; + case MBEDTLS_ERR_MD_BAD_INPUT_DATA: + status = PAL_ERR_MD_BAD_INPUT_DATA; + break; + default: + { + PAL_LOG(ERR, "Crypto md update status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + } + return status; +} + +palStatus_t pal_plat_mdGetOutputSize(palMDHandle_t md, size_t* bufferSize) +{ + palStatus_t status = PAL_SUCCESS; + palMD_t* localCtx = (palMD_t*)md; + + if (NULL != localCtx->md.md_info) + { + *bufferSize = (size_t)mbedtls_md_get_size(localCtx->md.md_info); + } + else + { + PAL_LOG(ERR, "Crypto md get size error"); + status = PAL_ERR_GENERIC_FAILURE; + } + + return status; +} + +palStatus_t pal_plat_mdFinal(palMDHandle_t md, unsigned char* output) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palMD_t* localCtx = (palMD_t*)md; + + platStatus = mbedtls_md_finish(&localCtx->md, output); + switch(platStatus) + { + case CRYPTO_PLAT_SUCCESS: + break; + case MBEDTLS_ERR_MD_BAD_INPUT_DATA: + status = PAL_ERR_MD_BAD_INPUT_DATA; + break; + default: + { + PAL_LOG(ERR, "Crypto md finish status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + } + return status; +} + +palStatus_t pal_plat_mdFree(palMDHandle_t* md) +{ + palStatus_t status = PAL_SUCCESS; + palMD_t* localCtx = NULL; + + localCtx = (palMD_t*)*md; + mbedtls_md_free(&localCtx->md); + free(localCtx); + *md = NULLPTR; + return status; +} + +palStatus_t pal_plat_verifySignature(palX509Handle_t x509, palMDType_t mdType, const unsigned char *hash, size_t hashLen, const unsigned char *sig, size_t sigLen) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + mbedtls_md_type_t mdAlg = MBEDTLS_MD_NONE; + palX509Ctx_t* localCtx = (palX509Ctx_t*)x509; + + switch (mdType) + { + case PAL_SHA256: + mdAlg = MBEDTLS_MD_SHA256; + break; + default: + status = PAL_ERR_INVALID_MD_TYPE; + goto finish; + } + + platStatus = mbedtls_pk_verify(&localCtx->crt.pk, mdAlg, hash, hashLen, sig, sigLen); + if (platStatus < CRYPTO_PLAT_SUCCESS) + { + status = PAL_ERR_PK_SIG_VERIFY_FAILED; + } +finish: + return status; +} + +palStatus_t pal_plat_ASN1GetTag(unsigned char **position, const unsigned char *end, size_t *len, uint8_t tag ) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + int platTag = 0; + + switch (tag & PAL_ASN1_CLASS_BITS) + { + case 0x00: + //MBEDTLS_ASN1_PRIMITIVE + break; + case PAL_ASN1_CONTEXT_SPECIFIC: + platTag |= MBEDTLS_ASN1_CONTEXT_SPECIFIC; + break; + default: + status = PAL_ERR_NOT_SUPPORTED_ASN_TAG; + goto finish; + } + + if (tag & PAL_ASN1_CONSTRUCTED) + { + platTag |= MBEDTLS_ASN1_CONSTRUCTED; + } + + + switch(tag & PAL_ASN1_TAG_BITS) + { + case PAL_ASN1_BOOLEAN: + platTag |= MBEDTLS_ASN1_BOOLEAN; + break; + case PAL_ASN1_INTEGER: + platTag |= MBEDTLS_ASN1_INTEGER; + break; + case PAL_ASN1_BIT_STRING: + platTag |= MBEDTLS_ASN1_BIT_STRING; + break; + case PAL_ASN1_OCTET_STRING: + platTag |= MBEDTLS_ASN1_OCTET_STRING; + break; + case PAL_ASN1_NULL: + platTag |= MBEDTLS_ASN1_NULL; + break; + case PAL_ASN1_OID: + platTag |= MBEDTLS_ASN1_OID; + break; + case PAL_ASN1_UTF8_STRING: + platTag |= MBEDTLS_ASN1_UTF8_STRING; + break; + case PAL_ASN1_SEQUENCE: + platTag |= MBEDTLS_ASN1_SEQUENCE; + break; + case PAL_ASN1_SET: + platTag |= MBEDTLS_ASN1_SET; + break; + case PAL_ASN1_PRINTABLE_STRING: + platTag |= MBEDTLS_ASN1_PRINTABLE_STRING; + break; + case PAL_ASN1_T61_STRING: + platTag |= MBEDTLS_ASN1_T61_STRING; + break; + case PAL_ASN1_IA5_STRING: + platTag |= MBEDTLS_ASN1_IA5_STRING; + break; + case PAL_ASN1_UTC_TIME: + platTag |= MBEDTLS_ASN1_UTC_TIME; + break; + case PAL_ASN1_GENERALIZED_TIME: + platTag |= MBEDTLS_ASN1_GENERALIZED_TIME; + break; + case PAL_ASN1_UNIVERSAL_STRING: + platTag |= MBEDTLS_ASN1_UNIVERSAL_STRING; + break; + case PAL_ASN1_BMP_STRING: + platTag |= MBEDTLS_ASN1_BMP_STRING; + break; + default: + status = PAL_ERR_NOT_SUPPORTED_ASN_TAG; + goto finish; + } + + platStatus = mbedtls_asn1_get_tag(position, end, len, platTag); + if (platStatus < CRYPTO_PLAT_SUCCESS) + { + status = PAL_ERR_ASN1_UNEXPECTED_TAG; + } +finish: + return status; +} + +palStatus_t pal_plat_CCMInit(palCCMHandle_t* ctx) +{ + palStatus_t status = PAL_SUCCESS; + palCCM_t* ccmCtx = NULL; + + ccmCtx = (palCCM_t*)malloc(sizeof(palCCM_t)); + if (NULL == ccmCtx) + { + status = PAL_ERR_NO_MEMORY; + } + else + { + mbedtls_ccm_init(ccmCtx); + *ctx = (palCCMHandle_t)ccmCtx; + } + + return status; +} + +palStatus_t pal_plat_CCMFree(palCCMHandle_t* ctx) +{ + palStatus_t status = PAL_SUCCESS; + palCCM_t* ccmCtx = (palCCM_t*)*ctx; + + mbedtls_ccm_free(ccmCtx); + free(ccmCtx); + *ctx = NULLPTR; + return status; +} + +palStatus_t pal_plat_CCMSetKey(palCCMHandle_t ctx, palCipherID_t id, const unsigned char *key, unsigned int keybits) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palCCM_t* ccmCtx = (palCCM_t*)ctx; + mbedtls_cipher_id_t mbedtls_cipher_id; + + switch (id) + { + case PAL_CIPHER_ID_AES: + mbedtls_cipher_id = MBEDTLS_CIPHER_ID_AES; + break; + default: + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_ccm_setkey(ccmCtx, mbedtls_cipher_id, key, keybits); + + switch(platStatus) + { + case CRYPTO_PLAT_SUCCESS: + status = PAL_SUCCESS; + break; + default: + { + PAL_LOG(ERR, "Crypto ccm setkey status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + } + return status; +} + +palStatus_t pal_plat_CCMDecrypt(palCCMHandle_t ctx, unsigned char* input, size_t inLen, unsigned char* iv, size_t ivLen, unsigned char* add, size_t addLen, unsigned char* tag, size_t tagLen, unsigned char* output) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palCCM_t* ccmCtx = (palCCM_t*)ctx; + + platStatus = mbedtls_ccm_auth_decrypt(ccmCtx, inLen, iv, ivLen, add, addLen, input, output, tag, tagLen); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + switch(platStatus) + { + default: + { + PAL_LOG(ERR, "Crypto ccm decrypt status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + } + } + return status; +} + +palStatus_t pal_plat_CCMEncrypt(palCCMHandle_t ctx, unsigned char* input, size_t inLen, unsigned char* iv, size_t ivLen, unsigned char* add, size_t addLen, unsigned char* output, unsigned char* tag, size_t tagLen) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palCCM_t* ccmCtx = (palCCM_t*)ctx; + + platStatus = mbedtls_ccm_encrypt_and_tag(ccmCtx, inLen, iv, ivLen, add, addLen, input, output, tag, tagLen); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + switch(platStatus) + { + default: + { + PAL_LOG(ERR, "Crypto ccm encrypt status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + } + } + return status; +} + +palStatus_t pal_plat_CtrDRBGInit(palCtrDrbgCtxHandle_t* ctx) +{ + palStatus_t status = PAL_SUCCESS; + palCtrDrbgCtx_t* palCtrDrbgCtx = NULL; + + palCtrDrbgCtx = (palCtrDrbgCtx_t*)malloc(sizeof(palCtrDrbgCtx_t)); + if (NULL == palCtrDrbgCtx) + { + status = PAL_ERR_NO_MEMORY; + } + else + { + mbedtls_ctr_drbg_init(&palCtrDrbgCtx->ctrDrbgCtx); + mbedtls_entropy_init(&palCtrDrbgCtx->entropy); + *ctx = (palCtrDrbgCtxHandle_t)palCtrDrbgCtx; + } + + return status; +} + +palStatus_t pal_plat_CtrDRBGFree(palCtrDrbgCtxHandle_t* ctx) +{ + palStatus_t status = PAL_SUCCESS; + palCtrDrbgCtx_t* palCtrDrbgCtx = NULL; + + palCtrDrbgCtx = (palCtrDrbgCtx_t*)*ctx; + if (NULL == palCtrDrbgCtx) + { + return PAL_ERR_INVALID_ARGUMENT; + } + mbedtls_ctr_drbg_free(&palCtrDrbgCtx->ctrDrbgCtx); + mbedtls_entropy_free(&palCtrDrbgCtx->entropy); + free(palCtrDrbgCtx); + *ctx = NULLPTR; + + return status; +} + +palStatus_t pal_plat_CtrDRBGSeed(palCtrDrbgCtxHandle_t ctx, const void* seed, size_t len) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palCtrDrbgCtx_t* palCtrDrbgCtx = (palCtrDrbgCtx_t*)ctx; + + if (NULL == palCtrDrbgCtx) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_ctr_drbg_seed(&palCtrDrbgCtx->ctrDrbgCtx, pal_plat_entropySourceDRBG, &palCtrDrbgCtx->entropy, seed, len); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + switch(platStatus) + { + case MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED: + status = PAL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED; + break; + default: + { + PAL_LOG(ERR, "Crypto ctrdrbg seed status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + } + } + return status; +} + +palStatus_t pal_plat_CtrDRBGGenerate(palCtrDrbgCtxHandle_t ctx, unsigned char* out, size_t len) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palCtrDrbgCtx_t* palCtrDrbgCtx = (palCtrDrbgCtx_t*)ctx; + + platStatus = mbedtls_ctr_drbg_random(&palCtrDrbgCtx->ctrDrbgCtx, out, len); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + switch(platStatus) + { + case MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED: + status = PAL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED; + break; + case MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG: + status = PAL_ERR_CTR_DRBG_REQUEST_TOO_BIG; + break; + default: + { + PAL_LOG(ERR, "Crypto ctrdrbg generate status %" PRId32 "", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + } + } + return status; +} + +palStatus_t pal_plat_cipherCMAC(const unsigned char *key, size_t keyLenInBits, const unsigned char *input, size_t inputLenInBytes, unsigned char *output) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + const mbedtls_cipher_info_t *cipherInfo; + + cipherInfo = mbedtls_cipher_info_from_values(MBEDTLS_CIPHER_ID_AES, keyLenInBits, MBEDTLS_MODE_ECB); + if (NULL == cipherInfo) + { + PAL_LOG(ERR, "Crypto cipher cmac error"); + status = PAL_ERR_CMAC_GENERIC_FAILURE; + goto finish; + } + + platStatus = mbedtls_cipher_cmac( cipherInfo, key, keyLenInBits, input, inputLenInBytes, output); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + PAL_LOG(ERR, "Crypto cipher cmac status %" PRId32 "", platStatus); + status = PAL_ERR_CMAC_GENERIC_FAILURE; + } +finish: + return status; +} + +palStatus_t pal_plat_CMACStart(palCMACHandle_t *ctx, const unsigned char *key, size_t keyLenBits, palCipherID_t cipherID) +{ + palStatus_t status = PAL_SUCCESS; + palCipherCtx_t* localCipher = NULL; + const mbedtls_cipher_info_t* cipherInfo = NULL; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + mbedtls_cipher_type_t platType = MBEDTLS_CIPHER_NONE; + + switch(cipherID) + { + case PAL_CIPHER_ID_AES: + platType = MBEDTLS_CIPHER_AES_128_ECB; + break; + default: + status = PAL_ERR_INVALID_CIPHER_ID; + goto finish; + } + + cipherInfo = mbedtls_cipher_info_from_type(platType); + if (NULL == cipherInfo) + { + PAL_LOG(ERR, "Crypto cmac cipher info error"); + status = PAL_ERR_CMAC_GENERIC_FAILURE; + goto finish; + } + + localCipher = (palCipherCtx_t*)malloc(sizeof(palCipherCtx_t)); + if (NULL == localCipher) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + + mbedtls_cipher_init(localCipher); + platStatus = mbedtls_cipher_setup(localCipher, cipherInfo); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + PAL_LOG(ERR, "Crypto cmac cipher setup status %" PRId32 ".", platStatus); + status = PAL_ERR_CMAC_GENERIC_FAILURE; + goto finish; + } + + platStatus = mbedtls_cipher_cmac_starts(localCipher, key, keyLenBits); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_CMAC_START_FAILED; + goto finish; + } + + *ctx = (palCMACHandle_t)localCipher; +finish: + if (PAL_SUCCESS != status && NULL != localCipher) + { + free(localCipher); + } + return status; +} + +palStatus_t pal_plat_CMACUpdate(palCMACHandle_t ctx, const unsigned char *input, size_t inLen) +{ + palStatus_t status = PAL_SUCCESS; + palCipherCtx_t* localCipher = (palCipherCtx_t*)ctx; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + + platStatus = mbedtls_cipher_cmac_update(localCipher, input, inLen); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_CMAC_UPDATE_FAILED; + } + + return status; +} + +palStatus_t pal_plat_CMACFinish(palCMACHandle_t *ctx, unsigned char *output, size_t* outLen) +{ + palStatus_t status = PAL_SUCCESS; + palCipherCtx_t* localCipher = NULL; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + + localCipher = (palCipherCtx_t*)*ctx; + if (NULL == localCipher->cipher_info) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_cipher_cmac_finish(localCipher, output); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_CMAC_FINISH_FAILED; + } + else + { + *outLen = localCipher->cipher_info->block_size; + } + + + + mbedtls_cipher_free(localCipher); + free(localCipher); + *ctx = NULLPTR; + return status; +} + +palStatus_t pal_plat_mdHmacSha256(const unsigned char *key, size_t keyLenInBytes, const unsigned char *input, size_t inputLenInBytes, unsigned char *output, size_t* outputLenInBytes) +{ + const mbedtls_md_info_t *md_info = NULL; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palStatus_t status = PAL_SUCCESS; + + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + if (NULL == md_info) + { + PAL_LOG(ERR, "Crypto hmac sha256 md info error"); + status = PAL_ERR_HMAC_GENERIC_FAILURE; + } + + if (PAL_SUCCESS == status) + { + platStatus = mbedtls_md_hmac(md_info, key, keyLenInBytes, input, inputLenInBytes, output); + if (platStatus != CRYPTO_PLAT_SUCCESS) + { + if (platStatus == MBEDTLS_ERR_MD_BAD_INPUT_DATA) + { + status = PAL_ERR_MD_BAD_INPUT_DATA; + } + else + { + PAL_LOG(ERR, "Crypto hmac status %" PRId32 "", platStatus); + status = PAL_ERR_HMAC_GENERIC_FAILURE; + } + } + } + + if ((NULL != outputLenInBytes) && (PAL_SUCCESS == status)) + { + *outputLenInBytes = (size_t)mbedtls_md_get_size(md_info); + } + + return status; +} + +//! Check EC private key function. +PAL_PRIVATE palStatus_t pal_plat_ECCheckPrivateKey(palECGroup_t* ecpGroup, palECKeyHandle_t key, bool *verified) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palECKey_t* privateKey = (palECKey_t*)key; + mbedtls_mpi* prvMP = NULL; + + if (NULL == ecpGroup || NULL == privateKey || NULL == verified || NULL == (mbedtls_ecp_keypair*)privateKey->pk_ctx) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + prvMP = &((mbedtls_ecp_keypair*)privateKey->pk_ctx)->d; + + platStatus = mbedtls_ecp_check_privkey(ecpGroup, prvMP); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_PRIVATE_KEY_VARIFICATION_FAILED; + } + else + { + *verified = true; + } + + return status; +} + +//! Check EC public key function. +PAL_PRIVATE palStatus_t pal_plat_ECCheckPublicKey(palECGroup_t* ecpGroup, palECKeyHandle_t key, bool *verified) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palECKey_t* publicKey = (palECKey_t*)key; + mbedtls_ecp_point* pubPoint = NULL; + + if (NULL == ecpGroup || NULL == publicKey || NULL == verified || NULL == (mbedtls_ecp_keypair*)publicKey->pk_ctx) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + pubPoint = &((mbedtls_ecp_keypair*)publicKey->pk_ctx)->Q; + + platStatus = mbedtls_ecp_check_pubkey(ecpGroup, pubPoint); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_PUBLIC_KEY_VARIFICATION_FAILED; + } + else + { + *verified = true; + } + + return status; +} + +palStatus_t pal_plat_ECCheckKey(palCurveHandle_t grp, palECKeyHandle_t key, uint32_t type, bool *verified) +{ + palStatus_t status = PAL_SUCCESS; + palECGroup_t* ecpGroup = (palECGroup_t*)grp; + + *verified = false; + + if ((PAL_CHECK_PRIVATE_KEY & type) != 0) + { + status = pal_plat_ECCheckPrivateKey(ecpGroup, key, verified); + } + + if ((PAL_SUCCESS == status) && ((PAL_CHECK_PUBLIC_KEY & type) != 0)) + { + status = pal_plat_ECCheckPublicKey(ecpGroup, key, verified); + } + + return status; +} + + +palStatus_t pal_plat_ECKeyNew(palECKeyHandle_t* key) +{ + palStatus_t status = PAL_SUCCESS; + palECKey_t* localECKey = NULL; + + localECKey = (palECKey_t*)malloc(sizeof(palECKey_t)); + if (NULL == localECKey) + { + status = PAL_ERR_NO_MEMORY; + } + else + { + mbedtls_pk_init(localECKey); + *key = (palECKeyHandle_t)localECKey; + } + + return status; +} + +palStatus_t pal_plat_ECKeyFree(palECKeyHandle_t* key) +{ + palECKey_t* localECKey = NULL; + + localECKey = (palECKey_t*)*key; + mbedtls_pk_free(localECKey); + free(localECKey); + *key = NULLPTR; + return PAL_SUCCESS; +} + +//! Check if the given data is a valid PEM format or not by checking the +//! the header and the footer of the data. +PAL_PRIVATE bool pal_plat_isPEM(const unsigned char* key, size_t keyLen) +{ + bool result = false; + const unsigned char *s1 = NULL; + const unsigned char *s2 = NULL; + + s1 = (unsigned char *) strstr( (const char *) key, "-----BEGIN "); + if (NULL != s1) + { + result = true; + } + else + { + s2 = (unsigned char *) strstr( (const char *) key, "-----END " ); + if (NULL != s2) + { + result = true; + } + } + + return result; +} + +palStatus_t pal_plat_parseECPrivateKeyFromDER(const unsigned char* prvDERKey, size_t keyLen, palECKeyHandle_t key) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palECKey_t* localECKey = (palECKey_t*)key; + + if (pal_plat_isPEM(prvDERKey, keyLen)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_pk_parse_key(localECKey, prvDERKey, keyLen, NULL, 0); + switch(platStatus) + { + case CRYPTO_PLAT_SUCCESS: + break; + case MBEDTLS_ERR_PK_UNKNOWN_PK_ALG: + status = PAL_ERR_PK_UNKNOWN_PK_ALG; + break; + case MBEDTLS_ERR_PK_KEY_INVALID_VERSION: + status = PAL_ERR_PK_KEY_INVALID_VERSION; + break; + case MBEDTLS_ERR_PK_KEY_INVALID_FORMAT: + status = PAL_ERR_PK_KEY_INVALID_FORMAT; + break; + case MBEDTLS_ERR_PK_PASSWORD_REQUIRED: + status = PAL_ERR_PK_PASSWORD_REQUIRED; + break; + default: + status = PAL_ERR_PARSING_PRIVATE_KEY; + } + + return status; +} + +palStatus_t pal_plat_parseECPublicKeyFromDER(const unsigned char* pubDERKey, size_t keyLen, palECKeyHandle_t key) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palECKey_t* localECKey = (palECKey_t*)key; + + if (pal_plat_isPEM(pubDERKey, keyLen)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_pk_parse_public_key(localECKey, pubDERKey, keyLen); + switch(platStatus) + { + case CRYPTO_PLAT_SUCCESS: + break; + case MBEDTLS_ERR_PK_UNKNOWN_PK_ALG: + status = PAL_ERR_PK_UNKNOWN_PK_ALG; + break; + case MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE: + status = PAL_ERR_NOT_SUPPORTED_CURVE; + break; + case MBEDTLS_ERR_PK_KEY_INVALID_FORMAT: + status = PAL_ERR_PK_KEY_INVALID_FORMAT; + break; + case MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH: //This is how mbedTLS returns erros for this function + status = PAL_ERR_PK_INVALID_PUBKEY_AND_ASN1_LEN_MISMATCH; + break; + case MBEDTLS_ERR_ECP_INVALID_KEY: + status = PAL_ERR_ECP_INVALID_KEY; + break; + default: + status = PAL_ERR_PARSING_PUBLIC_KEY; + } + + return status; +} + +//! Move data from the end of the buffer to the begining, this function is needed since mbedTLS +//! write functions write the data at the end of the buffers. +PAL_PRIVATE void moveDataToBufferStart(unsigned char* buffer, size_t bufferSize, size_t actualSize) +{ + size_t j = 0; + size_t i = bufferSize - actualSize; + if (bufferSize == actualSize) + { + return; + } + + for( ; j < actualSize ; ++i , ++j) + { + buffer[j] = buffer[i]; + buffer[i] = (unsigned char)0; + } +} + +palStatus_t pal_plat_writePrivateKeyToDer(palECKeyHandle_t key, unsigned char* derBuffer, size_t bufferSize, size_t* actualSize) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palECKey_t* localECKey = (palECKey_t*)key; + + platStatus = mbedtls_pk_write_key_der(localECKey, derBuffer, bufferSize); + if (CRYPTO_PLAT_SUCCESS < platStatus) + { + *actualSize = platStatus; + moveDataToBufferStart(derBuffer, bufferSize, *actualSize); + } + else + { + status = PAL_ERR_FAILED_TO_WRITE_PRIVATE_KEY; + } + + return status; +} + +palStatus_t pal_plat_writePublicKeyToDer(palECKeyHandle_t key, unsigned char* derBuffer, size_t bufferSize, size_t* actualSize) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palECKey_t* localECKey = (palECKey_t*)key; + + platStatus = mbedtls_pk_write_pubkey_der(localECKey, derBuffer, bufferSize); + if (CRYPTO_PLAT_SUCCESS < platStatus) + { + *actualSize = platStatus; + moveDataToBufferStart(derBuffer, bufferSize, *actualSize); + } + else + { + status = PAL_ERR_FAILED_TO_WRITE_PUBLIC_KEY; + } + + return status; +} + +palStatus_t pal_plat_ECKeyGenerateKey(palGroupIndex_t grpID, palECKeyHandle_t key) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + mbedtls_ecp_group_id platCurve = MBEDTLS_ECP_DP_NONE; + palECKey_t* localECKey = (palECKey_t*)key; + mbedtls_ecp_keypair* keyPair = NULL; + + keyPair = (mbedtls_ecp_keypair*)localECKey->pk_ctx; + + switch(grpID) + { + case PAL_ECP_DP_SECP256R1: + platCurve = MBEDTLS_ECP_DP_SECP256R1; + break; + default: + status = PAL_ERR_NOT_SUPPORTED_CURVE; + goto finish; + } + + platStatus = mbedtls_ecp_gen_key(platCurve, keyPair, pal_plat_entropySource, NULL); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_KEYPAIR_GEN_FAIL; + } + +finish: + return status; +} + +palStatus_t pal_plat_ECKeyGetCurve(palECKeyHandle_t key, palGroupIndex_t* grpID) +{ + palStatus_t status = PAL_SUCCESS; + palECKey_t* localECKey = (palECKey_t*)key; + mbedtls_ecp_keypair* keyPair = NULL; + + if (NULL == (mbedtls_ecp_keypair*)localECKey->pk_ctx) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + keyPair = (mbedtls_ecp_keypair*)localECKey->pk_ctx; + + switch(keyPair->grp.id) + { + case MBEDTLS_ECP_DP_SECP256R1: + *grpID = PAL_ECP_DP_SECP256R1; + break; + default: + *grpID = PAL_ECP_DP_NONE; + status = PAL_ERR_NOT_SUPPORTED_CURVE; + } + return status; +} + +palStatus_t pal_plat_ECGroupFree(palCurveHandle_t* grp) +{ + palStatus_t status = PAL_SUCCESS; + palECGroup_t* localGroup = NULL; + + localGroup = (palECGroup_t*)*grp; + mbedtls_ecp_group_free(localGroup); + free(localGroup); + *grp = NULLPTR; + return status; +} + +palStatus_t pal_plat_ECGroupInitAndLoad(palCurveHandle_t* grp, palGroupIndex_t index) +{ + palStatus_t status = PAL_SUCCESS; + mbedtls_ecp_group_id platCurve = MBEDTLS_ECP_DP_NONE; + palECGroup_t* localGroup = NULL; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + + localGroup = (palECGroup_t*)malloc(sizeof(palECGroup_t)); + if (NULL == localGroup) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + + mbedtls_ecp_group_init(localGroup); + switch(index) + { + case PAL_ECP_DP_SECP256R1: + platCurve = MBEDTLS_ECP_DP_SECP256R1; + break; + default: + status = PAL_ERR_NOT_SUPPORTED_CURVE; + goto finish; + } + + platStatus = mbedtls_ecp_group_load(localGroup ,platCurve); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_GROUP_LOAD_FAILED; + } + else + { + *grp = (palCurveHandle_t)localGroup; + } + +finish: + if (PAL_SUCCESS != status && localGroup != NULL) + { + free(localGroup); + } + + return status; +} + + +palStatus_t pal_plat_ECDHComputeKey(const palCurveHandle_t grp, const palECKeyHandle_t peerPublicKey, const palECKeyHandle_t privateKey, palECKeyHandle_t outKey) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palECGroup_t* ecpGroup = (palECGroup_t*)grp; + mbedtls_ecp_keypair* pubKeyPair = NULL; + mbedtls_ecp_keypair* prvKeyPair = NULL; + mbedtls_ecp_keypair* outKeyPair = NULL; + mbedtls_ctr_drbg_context ctrDrbgCtx; + + mbedtls_ctr_drbg_init(&ctrDrbgCtx); + + pubKeyPair = (mbedtls_ecp_keypair*)((palECKey_t*)peerPublicKey)->pk_ctx; + prvKeyPair = (mbedtls_ecp_keypair*)((palECKey_t*)privateKey)->pk_ctx; + outKeyPair = (mbedtls_ecp_keypair*)((palECKey_t*)outKey)->pk_ctx; + + if (NULL != pubKeyPair && NULL != prvKeyPair && NULL != outKeyPair) + { + platStatus = mbedtls_ecdh_compute_shared(ecpGroup, &outKeyPair->d, &pubKeyPair->Q, &prvKeyPair->d, mbedtls_ctr_drbg_random, (void*)&ctrDrbgCtx); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_FAILED_TO_COMPUTE_SHRED_KEY; + } + } + else + { + status = PAL_ERR_INVALID_ARGUMENT; + } + + + mbedtls_ctr_drbg_free(&ctrDrbgCtx); + + return status; +} + + +palStatus_t pal_plat_ECDSASign(palCurveHandle_t grp, palMDType_t mdType, palECKeyHandle_t prvKey, unsigned char* dgst, uint32_t dgstLen, unsigned char* sig, size_t* sigLen) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palECKey_t* localECKey = (palECKey_t*)prvKey; + mbedtls_ecp_keypair* keyPair = NULL; + mbedtls_ecdsa_context localECDSA; + palECGroup_t* localGroup = (palECGroup_t*)grp; + mbedtls_md_type_t mdAlg = MBEDTLS_MD_NONE; + + keyPair = (mbedtls_ecp_keypair*)localECKey->pk_ctx; + + mbedtls_ecdsa_init(&localECDSA); + platStatus = mbedtls_ecdsa_from_keypair(&localECDSA, keyPair); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_FAILED_TO_COPY_KEYPAIR; + goto finish; + } + + platStatus = mbedtls_ecp_group_copy(&localECDSA.grp, localGroup); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_FAILED_TO_COPY_GROUP; + goto finish; + } + + switch (mdType) + { + case PAL_SHA256: + mdAlg = MBEDTLS_MD_SHA256; + break; + default: + status = PAL_ERR_INVALID_MD_TYPE; + goto finish; + } + + platStatus = mbedtls_ecdsa_write_signature(&localECDSA, mdAlg, dgst, dgstLen, sig, sigLen, NULL, NULL); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_FAILED_TO_WRITE_SIGNATURE; + } + +finish: + mbedtls_ecdsa_free(&localECDSA); + return status; +} + +palStatus_t pal_plat_ECDSAVerify(palECKeyHandle_t pubKey, unsigned char* dgst, uint32_t dgstLen, unsigned char* sig, size_t sigLen, bool* verified) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palECKey_t* localECKey = (palECKey_t*)pubKey; + mbedtls_ecp_keypair* keyPair = NULL; + mbedtls_ecdsa_context localECDSA; + + keyPair = (mbedtls_ecp_keypair*)localECKey->pk_ctx; + + mbedtls_ecdsa_init(&localECDSA); + platStatus = mbedtls_ecdsa_from_keypair(&localECDSA, keyPair); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_FAILED_TO_COPY_KEYPAIR; + goto finish; + } + + platStatus = mbedtls_ecdsa_read_signature(&localECDSA, dgst, dgstLen, sig, sigLen); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_FAILED_TO_VERIFY_SIGNATURE; + *verified = false; + } + else + { + *verified = true; + } +finish: + mbedtls_ecdsa_free(&localECDSA); + return status; +} + +palStatus_t pal_plat_x509CSRInit(palx509CSRHandle_t *x509CSR) +{ + palStatus_t status = PAL_SUCCESS; + palx509CSR_t *localCSR = NULL; + + localCSR = (palx509CSR_t*)malloc(sizeof(palx509CSR_t)); + if (NULL == localCSR) + { + status = PAL_ERR_NO_MEMORY; + } + else + { + mbedtls_x509write_csr_init(localCSR); + *x509CSR = (palx509CSRHandle_t)localCSR; + } + return status; +} + +palStatus_t pal_plat_x509CSRSetSubject(palx509CSRHandle_t x509CSR, const char* subjectName) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + palx509CSR_t *localCSR = (palx509CSR_t*)x509CSR; + + platStatus = mbedtls_x509write_csr_set_subject_name(localCSR, subjectName); + switch (platStatus) + { + case CRYPTO_PLAT_SUCCESS: + status = PAL_SUCCESS; + break; + case MBEDTLS_ERR_X509_UNKNOWN_OID: + status = PAL_ERR_X509_UNKNOWN_OID; + break; + case MBEDTLS_ERR_X509_INVALID_NAME: + status = PAL_ERR_X509_INVALID_NAME; + break; + default: + { + PAL_LOG(ERR, "Crypto x509 CSR set subject status %" PRId32 ".", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + } + + return status; +} + +palStatus_t pal_plat_x509CSRSetKey(palx509CSRHandle_t x509CSR, palECKeyHandle_t pubKey, palECKeyHandle_t prvKey) +{ + palStatus_t status = PAL_SUCCESS; + palx509CSR_t *localCSR = (palx509CSR_t*)x509CSR; + palECKey_t* localPubKey = (palECKey_t*)pubKey; + palECKey_t* localPrvKey = (palECKey_t*)prvKey; + + if (NULL != localPrvKey) + { + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + mbedtls_ecp_keypair* pubKeyPair = NULL; + mbedtls_ecp_keypair* prvKeyPair = NULL; + + pubKeyPair = (mbedtls_ecp_keypair*)localPubKey->pk_ctx; + prvKeyPair = (mbedtls_ecp_keypair*)localPrvKey->pk_ctx; + + if (NULL != pubKeyPair && NULL != prvKeyPair) + { + platStatus = mbedtls_mpi_copy(&(pubKeyPair->d), &(prvKeyPair->d)); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_FAILED_TO_COPY_KEYPAIR; + } + } + else + { + status = PAL_ERR_INVALID_ARGUMENT; + } + } + + if (PAL_SUCCESS == status) + { + mbedtls_x509write_csr_set_key(localCSR, localPubKey); + } + + return status; +} + +palStatus_t pal_plat_x509CSRSetMD(palx509CSRHandle_t x509CSR, palMDType_t mdType) +{ + palStatus_t status = PAL_SUCCESS; + palx509CSR_t *localCSR = (palx509CSR_t*)x509CSR; + mbedtls_md_type_t mdAlg = MBEDTLS_MD_NONE; + + switch (mdType) + { + case PAL_SHA256: + mdAlg = MBEDTLS_MD_SHA256; + break; + default: + status = PAL_ERR_INVALID_MD_TYPE; + goto finish; + } + + mbedtls_x509write_csr_set_md_alg(localCSR, mdAlg); + +finish: + return status; +} + +palStatus_t pal_plat_x509CSRSetKeyUsage(palx509CSRHandle_t x509CSR, uint32_t keyUsage) +{ + palStatus_t status = PAL_SUCCESS; + palx509CSR_t *localCSR = (palx509CSR_t*)x509CSR; + uint8_t localKeyUsage = 0; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + + if (PAL_X509_KU_DIGITAL_SIGNATURE & keyUsage) + { + localKeyUsage |= MBEDTLS_X509_KU_DIGITAL_SIGNATURE; + } + if (PAL_X509_KU_KEY_CERT_SIGN & keyUsage) + { + localKeyUsage |= MBEDTLS_X509_KU_KEY_CERT_SIGN; + } + if (PAL_X509_KU_NON_REPUDIATION & keyUsage) + { + localKeyUsage |= MBEDTLS_X509_KU_NON_REPUDIATION; + } + + if (0 == localKeyUsage) + { + status = PAL_ERR_INVALID_KEY_USAGE; + } + else + { + platStatus = mbedtls_x509write_csr_set_key_usage(localCSR, localKeyUsage); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_FAILED_TO_SET_KEY_USAGE; + } + } + return status; +} + +palStatus_t pal_plat_x509CSRSetExtension(palx509CSRHandle_t x509CSR,const char* oid, size_t oidLen, const unsigned char* value, size_t valueLen) +{ + palStatus_t status = PAL_SUCCESS; + palx509CSR_t *localCSR = (palx509CSR_t*)x509CSR; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + + platStatus = mbedtls_x509write_csr_set_extension(localCSR, oid, oidLen, value, valueLen); + if (CRYPTO_PLAT_SUCCESS != platStatus) + { + status = PAL_ERR_SET_EXTENTION_FAILED; + } + return status; +} + +palStatus_t pal_plat_x509CSRWriteDER(palx509CSRHandle_t x509CSR, unsigned char* derBuf, size_t derBufLen, size_t* actualDerLen) +{ + palStatus_t status = PAL_SUCCESS; + palx509CSR_t *localCSR = (palx509CSR_t*)x509CSR; + int32_t platStatus = CRYPTO_PLAT_SUCCESS; + + platStatus = mbedtls_x509write_csr_der(localCSR, derBuf, derBufLen, pal_plat_entropySource, NULL); + if (CRYPTO_PLAT_SUCCESS >= platStatus) //! mbedtls_x509write_csr_der() returns the size of the written CSR + { //! we need to check if the length larger than zero + status = PAL_ERR_CSR_WRITE_DER_FAILED; + goto finish; + } + + moveDataToBufferStart(derBuf, derBufLen, platStatus); + if (actualDerLen) + { + *actualDerLen = platStatus; + } + finish: + return status; +} + +palStatus_t pal_plat_x509CSRFree(palx509CSRHandle_t *x509CSR) +{ + palStatus_t status = PAL_SUCCESS; + palx509CSR_t* localCSR = (palx509CSR_t*)*x509CSR; + + mbedtls_x509write_csr_free(localCSR); + free(localCSR); + *x509CSR = NULLPTR; + return status; +} + +PAL_PRIVATE int pal_plat_entropySourceDRBG( void *data, unsigned char *output, size_t len) +{ + palStatus_t status = PAL_SUCCESS; + (void)data; + + //! We need to call platform layer function, in order to prevent two things: + //! 1. adding new service layer function for this purpose (only for DRBG seeding for mbedTLS, not sure other Crypto libraries will need it) + //! 2. prevent endless recursive (random->drbg->random) - reseeding scenario. + status = pal_plat_osRandomBuffer((uint8_t*) output, len); + if (PAL_SUCCESS == status) + { + return CRYPTO_PLAT_SUCCESS; + } + else + { + return CRYPTO_PLAT_GENERIC_ERROR; + } +} + +PAL_PRIVATE int pal_plat_entropySource( void *data, unsigned char *output, size_t len) +{ + palStatus_t status = PAL_SUCCESS; + (void)data; + + status = pal_osRandomBuffer((uint8_t*) output, len); + if (PAL_SUCCESS == status) + { + return CRYPTO_PLAT_SUCCESS; + } + else + { + return CRYPTO_PLAT_GENERIC_ERROR; + } +} + + +#ifdef __arm__ // we are compiling using the ARM compiler +/* This function is provided for ARM-CC compiler, since mbedTLS uses it and it returns NULL + * in ARM-CC, we need to provide replacement function to keep correct functionality + * mbedTLS will change the internal implementation which uses gmtime() + */ +struct tm *gmtime(const time_t *timep) +{ + return localtime(timep); +} + +#endif +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/Lib_Specific/mbedTLS/TLS/pal_plat_TLS.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/Lib_Specific/mbedTLS/TLS/pal_plat_TLS.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1099 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "pal_plat_TLS.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "stdlib.h" +#include "string.h" + +#define SSL_LIB_SUCCESS 0 +PAL_PRIVATE PAL_INLINE palStatus_t translateTLSErrToPALError(int32_t error) +{ + palStatus_t status; + switch(error) + { + case SSL_LIB_SUCCESS: + status = PAL_ERR_END_OF_FILE; + break; + case MBEDTLS_ERR_SSL_WANT_READ: + status = PAL_ERR_TLS_WANT_READ; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + status = PAL_ERR_TLS_WANT_WRITE; + break; + case MBEDTLS_ERR_SSL_TIMEOUT: + status = PAL_ERR_TIMEOUT_EXPIRED; + break; + case MBEDTLS_ERR_SSL_BAD_INPUT_DATA: + status = PAL_ERR_TLS_BAD_INPUT_DATA; + break; + case MBEDTLS_ERR_SSL_CLIENT_RECONNECT: + status = PAL_ERR_TLS_CLIENT_RECONNECT; + break; + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + status = PAL_ERR_TLS_PEER_CLOSE_NOTIFY; + break; + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + status = PAL_ERR_X509_CERT_VERIFY_FAILED; + break; + default: + { + status = PAL_ERR_GENERIC_FAILURE; + } + }; + return status; + +} + + +#if defined(MBEDTLS_DEBUG_C) +//! Add forward declaration for the function from mbedTLS +void mbedtls_debug_set_threshold( int threshold ); +#endif + +typedef mbedtls_ssl_context platTlsContext; +typedef mbedtls_ssl_config platTlsConfiguraionContext; + +PAL_PRIVATE mbedtls_entropy_context *g_entropy = NULL; +PAL_PRIVATE bool g_entropyInitiated = false; + +typedef struct palTimingDelayContext +{ + uint64_t start_ticks; + uint32_t int_ms; + uint32_t fin_ms; +} palTimingDelayContext_t; + +//! the full structures will be defined later in the implemetation. +typedef struct palTLSConf{ + platTlsConfiguraionContext* confCtx; + palTLSSocketHandle_t palIOCtx; // which will be used as bio context for mbedTLS + uint32_t tlsIndex; // to help us to get the index of the containing palTLS_t in the array. will be updated in the init + // maybe we need to make this an array, since index can be shared for more than one TLS context + mbedtls_ctr_drbg_context ctrDrbg; + palTimingDelayContext_t timerCtx; + mbedtls_x509_crt owncert; + mbedtls_pk_context pkey; + mbedtls_x509_crt cacert; + bool hasKeys; + bool hasChain; + int cipherSuites[PAL_MAX_ALLOWED_CIPHER_SUITES+1]; // The +1 is for the Zero Termination required by mbedTLS +}palTLSConf_t; + +//! the full structures will be defined later in the implemetation. +typedef struct palTLS{ + platTlsContext tlsCtx; + palTLSConf_t* palConfCtx; + bool tlsInit; + uint32_t tlsIndex; + char* psk; //NULL terminated + char* identity; //NULL terminated + bool wantReadOrWrite; +}palTLS_t; + +//! Forward declaration +PAL_PRIVATE int palBIORecv_timeout(palTLSSocketHandle_t socket, unsigned char *buf, size_t len, uint32_t timeout); +PAL_PRIVATE int palBIORecv(palTLSSocketHandle_t socket, unsigned char *buf, size_t len); +PAL_PRIVATE int palBIOSend(palTLSSocketHandle_t socket, const unsigned char *buf, size_t len); +PAL_PRIVATE void palDebug(void *ctx, int debugLevel, const char *fileName, int line, const char *message); +int pal_plat_entropySourceTLS( void *data, unsigned char *output, size_t len, size_t *olen ); +PAL_PRIVATE int palTimingGetDelay( void *data ); +PAL_PRIVATE void palTimingSetDelay( void *data, uint32_t intMs, uint32_t finMs ); +//! This is the array to hold the TLS context +PAL_PRIVATE palTLS_t *g_palTLSContext = NULL; + +palStatus_t pal_plat_initTLSLibrary(void) +{ + palStatus_t status = PAL_SUCCESS; + + g_palTLSContext = NULL; + + g_entropy = (mbedtls_entropy_context*)malloc(sizeof(mbedtls_entropy_context)); + if (NULL == g_entropy) + { + status = PAL_ERR_NO_MEMORY; + } + else + { + mbedtls_entropy_init(g_entropy); + g_entropyInitiated = false; + } + + return status; +} + + +palStatus_t pal_plat_cleanupTLS(void) +{ + mbedtls_entropy_free(g_entropy); + g_entropyInitiated = false; + free(g_entropy); + g_entropy = NULL; + if (g_palTLSContext) + { + free((void*)g_palTLSContext); + g_palTLSContext = NULL; + } + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_addEntropySource(palEntropySource_f entropyCallback) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = SSL_LIB_SUCCESS; + + if (NULL == entropyCallback) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (!g_entropyInitiated) + { + platStatus = mbedtls_entropy_add_source(g_entropy, entropyCallback, NULL, PAL_INITIAL_RANDOM_SIZE, MBEDTLS_ENTROPY_SOURCE_STRONG ); + if (SSL_LIB_SUCCESS != platStatus) + { + status = PAL_ERR_TLS_CONFIG_INIT; + } + else + { + g_entropyInitiated = true; + } + + } + + return status; +} + + +palStatus_t pal_plat_initTLSConf(palTLSConfHandle_t* palConfCtx, palTLSTransportMode_t transportVersion, palDTLSSide_t methodType) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConf_t* localConfigCtx = NULL; + int32_t platStatus = SSL_LIB_SUCCESS; + int32_t endpoint = 0; + int32_t transport = 0; + + if (NULLPTR == palConfCtx) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + localConfigCtx = (palTLSConf_t*)malloc(sizeof(palTLSConf_t)); + if (NULL == localConfigCtx) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + + localConfigCtx->confCtx = (platTlsConfiguraionContext*)malloc(sizeof(platTlsConfiguraionContext)); + if (NULL == localConfigCtx->confCtx) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + localConfigCtx->tlsIndex = 0; + localConfigCtx->hasKeys = false; + localConfigCtx->hasChain = false; + memset(localConfigCtx->cipherSuites, 0,(sizeof(int)* (PAL_MAX_ALLOWED_CIPHER_SUITES+1)) ); + mbedtls_ssl_config_init(localConfigCtx->confCtx); + + if (PAL_TLS_IS_CLIENT == methodType) + { + endpoint = MBEDTLS_SSL_IS_CLIENT; + } + else + { + endpoint = MBEDTLS_SSL_IS_SERVER; + } + + if (PAL_TLS_MODE == transportVersion) + { + transport = MBEDTLS_SSL_TRANSPORT_STREAM; + } + else + { + transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; + } + platStatus = mbedtls_ssl_config_defaults(localConfigCtx->confCtx, endpoint, transport, MBEDTLS_SSL_PRESET_DEFAULT); + if (SSL_LIB_SUCCESS != platStatus) + { + PAL_LOG(ERR, "TLS Init conf status %" PRId32 ".", platStatus); + status = PAL_ERR_TLS_CONFIG_INIT; + goto finish; + } + + mbedtls_ctr_drbg_init(&localConfigCtx->ctrDrbg); + status = pal_plat_addEntropySource(pal_plat_entropySourceTLS); + if (PAL_SUCCESS != status) + { + goto finish; + } + + platStatus = mbedtls_ctr_drbg_seed(&localConfigCtx->ctrDrbg, mbedtls_entropy_func, g_entropy, NULL, 0); //Custom data can be defined in + //pal_TLS.h header and to be defined by + //Service code. But we need to check if other platform support this + //input! + if (SSL_LIB_SUCCESS != platStatus) + { + status = PAL_ERR_TLS_CONFIG_INIT; + goto finish; + } + + mbedtls_ssl_conf_rng(localConfigCtx->confCtx, mbedtls_ctr_drbg_random, &localConfigCtx->ctrDrbg); + *palConfCtx = (uintptr_t)localConfigCtx; + +finish: + if (PAL_SUCCESS != status && NULL != localConfigCtx) + { + if (NULL != localConfigCtx->confCtx) + { + free(localConfigCtx->confCtx); + } + free(localConfigCtx); + *palConfCtx = NULLPTR; + } + return status; +} + + +palStatus_t pal_plat_tlsConfigurationFree(palTLSConfHandle_t* palTLSConf) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConf_t* localConfigCtx = NULL; + + if (NULLPTR == palTLSConf || NULLPTR == *palTLSConf) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + localConfigCtx = (palTLSConf_t*)*palTLSConf; + + if (true == localConfigCtx->hasKeys) + { + mbedtls_pk_free(&localConfigCtx->pkey); + mbedtls_x509_crt_free(&localConfigCtx->owncert); + } + + if (true == localConfigCtx->hasChain) + { + mbedtls_x509_crt_free(&localConfigCtx->cacert); + } + + mbedtls_ssl_config_free(localConfigCtx->confCtx); + mbedtls_ctr_drbg_free(&localConfigCtx->ctrDrbg); + + free(localConfigCtx->confCtx); + + memset(localConfigCtx, 0, sizeof(palTLSConf_t)); + free(localConfigCtx); + *palTLSConf = NULLPTR; + return status; +} + + +palStatus_t pal_plat_initTLS(palTLSConfHandle_t palTLSConf, palTLSHandle_t* palTLSHandle) +{ + palStatus_t status = PAL_SUCCESS; + uint32_t firstAvailableCtxIndex = PAL_MAX_NUM_OF_TLS_CTX; + palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf; + + + if (NULLPTR == palTLSConf || NULLPTR == palTLSHandle) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (NULL == g_palTLSContext) //We allocate the entire array only for the first time + { + g_palTLSContext = (palTLS_t*)malloc(PAL_MAX_NUM_OF_TLS_CTX * sizeof(palTLS_t)); + if (NULL == g_palTLSContext) + { + status = PAL_ERR_TLS_RESOURCE; + goto finish; + } + memset((void*)g_palTLSContext, 0 ,PAL_MAX_NUM_OF_TLS_CTX * sizeof(palTLS_t)); + } + + for (uint32_t i=0 ; i < PAL_MAX_NUM_OF_TLS_CTX ; ++i) + { + if (false == g_palTLSContext[i].tlsInit) + { + firstAvailableCtxIndex = i; + break; + } + } + + if (firstAvailableCtxIndex >= PAL_MAX_NUM_OF_TLS_CTX) + { + status = PAL_ERR_TLS_RESOURCE; + goto finish; + } + memset(&g_palTLSContext[firstAvailableCtxIndex], 0 , sizeof(palTLS_t)); + mbedtls_ssl_init(&g_palTLSContext[firstAvailableCtxIndex].tlsCtx); + localConfigCtx->tlsIndex = firstAvailableCtxIndex; + g_palTLSContext[firstAvailableCtxIndex].palConfCtx = localConfigCtx; + g_palTLSContext[firstAvailableCtxIndex].tlsIndex = firstAvailableCtxIndex; + g_palTLSContext[firstAvailableCtxIndex].tlsInit = true; + mbedtls_ssl_set_timer_cb(&g_palTLSContext[firstAvailableCtxIndex].tlsCtx, &localConfigCtx->timerCtx, palTimingSetDelay, palTimingGetDelay); + *palTLSHandle = (palTLSHandle_t)&g_palTLSContext[firstAvailableCtxIndex]; + +finish: + return status; +} + + +palStatus_t pal_plat_freeTLS(palTLSHandle_t* palTLSHandle) +{ + palStatus_t status = PAL_SUCCESS; + palTLS_t* localTLSCtx = NULL; + bool foundActiveTLSCtx = false; + + if (NULLPTR == palTLSHandle || NULLPTR == *palTLSHandle) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + localTLSCtx = (palTLS_t*)*palTLSHandle; + if (false == localTLSCtx->tlsInit) + { + status = PAL_ERR_TLS_CONTEXT_NOT_INITIALIZED; + goto finish; + } + + g_palTLSContext[localTLSCtx->tlsIndex].tlsInit = false; + + mbedtls_ssl_free(&localTLSCtx->tlsCtx); + memset(localTLSCtx, 0, sizeof(palTLS_t)); + *palTLSHandle = NULLPTR; + + for (uint32_t i=0 ; i < PAL_MAX_NUM_OF_TLS_CTX ; ++i) //lets see if we need to release the global array + { + if (true == g_palTLSContext[i].tlsInit) + { + foundActiveTLSCtx = true; + break; + } + } + + if (false == foundActiveTLSCtx) // no more contexts, no need to hold the entire ctx array + { + free((void*)g_palTLSContext); + g_palTLSContext = NULL; + } + +finish: + return status; +} + + +palStatus_t pal_plat_setAuthenticationMode(palTLSConfHandle_t sslConf, palTLSAuthMode_t authMode) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platAuthMode; + palTLSConf_t* localConfigCtx = (palTLSConf_t*)sslConf; + + if (NULLPTR == sslConf) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + switch(authMode) + { + case PAL_TLS_VERIFY_NONE: + platAuthMode = MBEDTLS_SSL_VERIFY_NONE; + break; + case PAL_TLS_VERIFY_OPTIONAL: + platAuthMode = MBEDTLS_SSL_VERIFY_OPTIONAL; + break; + case PAL_TLS_VERIFY_REQUIRED: + platAuthMode = MBEDTLS_SSL_VERIFY_REQUIRED; + break; + default: + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + }; + mbedtls_ssl_conf_authmode(localConfigCtx->confCtx, platAuthMode ); + +finish: + return status; +} + +palStatus_t pal_plat_setCipherSuites(palTLSConfHandle_t sslConf, palTLSSuites_t palSuite) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConf_t* localConfigCtx = (palTLSConf_t*)sslConf; + + if (NULLPTR == sslConf) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + switch(palSuite) + { + case PAL_TLS_PSK_WITH_AES_128_CBC_SHA256: + localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256; + break; + case PAL_TLS_PSK_WITH_AES_128_CCM_8: + localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8; + break; + case PAL_TLS_PSK_WITH_AES_256_CCM_8: + localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8; + break; + case PAL_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; + break; + case PAL_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; + break; + case PAL_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + localConfigCtx->cipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; + break; + default: + localConfigCtx->cipherSuites[0] = 0; + status = PAL_ERR_TLS_INVALID_CIPHER; + goto finish; + } + + mbedtls_ssl_conf_ciphersuites(localConfigCtx->confCtx, localConfigCtx->cipherSuites); +finish: + return status; +} + + +palStatus_t pal_plat_sslGetVerifyResult(palTLSHandle_t palTLSHandle) +{ + palStatus_t status = PAL_SUCCESS; + palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle; + int32_t platStatus = SSL_LIB_SUCCESS; + + if (NULLPTR == palTLSHandle) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_ssl_get_verify_result(&localTLSCtx->tlsCtx); + if (SSL_LIB_SUCCESS != platStatus) + { + //This errors handling must be expanded to all possible + //return values from the mbedtls_ssl_get_verify_result() + PAL_LOG(ERR, "SSL Verify result error %" PRId32 ".", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + return status; +} + + +palStatus_t pal_plat_sslRead(palTLSHandle_t palTLSHandle, void *buffer, uint32_t len, uint32_t* actualLen) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = SSL_LIB_SUCCESS; + palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle; + + if (NULLPTR == palTLSHandle || NULL == buffer || NULL == actualLen) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_ssl_read(&localTLSCtx->tlsCtx, (unsigned char*)buffer, len); + if (platStatus > SSL_LIB_SUCCESS) + { + *actualLen = platStatus; + } + else + { + status = translateTLSErrToPALError(platStatus); + PAL_LOG(ERR, "SSL Read return code %" PRId32 ".", platStatus); + } + + return status; +} + + +palStatus_t pal_plat_sslWrite(palTLSHandle_t palTLSHandle, const void *buffer, uint32_t len, uint32_t *bytesWritten) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = SSL_LIB_SUCCESS; + palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle; + + if (NULLPTR == palTLSHandle || NULL == buffer || NULL == bytesWritten) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_ssl_write(&localTLSCtx->tlsCtx, (unsigned char*)buffer, len); + if (platStatus > SSL_LIB_SUCCESS) + { + *bytesWritten = platStatus; + } + else + { + status = translateTLSErrToPALError(platStatus); + PAL_LOG(ERR, "SSL Write platform return code %" PRId32 ".", platStatus); + } + + return status; +} + + +palStatus_t pal_plat_setHandShakeTimeOut(palTLSConfHandle_t palTLSConf, uint32_t timeoutInMilliSec) +{ + palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf; + uint32_t minTimeout = PAL_DTLS_PEER_MIN_TIMEOUT; + uint32_t maxTimeout = timeoutInMilliSec >> 1; //! faster dividing by 2 + //! Since mbedTLS algorithm for UDP handshake algorithm is as follow: + //! wait 'minTimeout' ..=> 'minTimeout = 2*minTimeout' while 'minTimeout < maxTimeout' + //! if 'minTimeout >= maxTimeout' them wait 'maxTimeout'. + //! The whole waiting time is the sum of the different intervals waited. + //! Therefore we need divide the 'timeoutInMilliSec' by 2 to give a close approximation of the desired 'timeoutInMilliSec' + //! 1 + 2 + ... + 'timeoutInMilliSec/2' ~= 'timeoutInMilliSec' + + if (NULLPTR == palTLSConf || 0 == timeoutInMilliSec) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (maxTimeout < PAL_DTLS_PEER_MIN_TIMEOUT) + { + minTimeout = (timeoutInMilliSec+1) >> 1; //to prevent 'minTimeout == 0' + maxTimeout = timeoutInMilliSec; + } + + mbedtls_ssl_conf_handshake_timeout(localConfigCtx->confCtx, minTimeout, maxTimeout); + + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_sslSetup(palTLSHandle_t palTLSHandle, palTLSConfHandle_t palTLSConf) +{ + palStatus_t status = PAL_SUCCESS; + palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle; + palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf; + int32_t platStatus = SSL_LIB_SUCCESS; + + if (NULLPTR == palTLSConf || NULLPTR == palTLSHandle) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (!localTLSCtx->wantReadOrWrite) + { + platStatus = mbedtls_ssl_setup(&localTLSCtx->tlsCtx, localConfigCtx->confCtx); + if (SSL_LIB_SUCCESS != platStatus) + { + if (MBEDTLS_ERR_SSL_ALLOC_FAILED == platStatus) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + PAL_LOG(ERR, "SSL setup return code %" PRId32 ".", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + goto finish; + } + + localTLSCtx->palConfCtx = localConfigCtx; + localConfigCtx->tlsIndex = localTLSCtx->tlsIndex; + } +finish: + return status; +} + + +palStatus_t pal_plat_handShake(palTLSHandle_t palTLSHandle) +{ + palStatus_t status = PAL_SUCCESS; + palTLS_t* localTLSCtx = (palTLS_t*)palTLSHandle; + int32_t platStatus = SSL_LIB_SUCCESS; + + if (NULLPTR == palTLSHandle) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_ssl_handshake(&localTLSCtx->tlsCtx); + switch(platStatus) + { + case SSL_LIB_SUCCESS: + status = PAL_SUCCESS; + localTLSCtx->wantReadOrWrite = false; + break; + case MBEDTLS_ERR_SSL_WANT_READ: + status = PAL_ERR_TLS_WANT_READ; + localTLSCtx->wantReadOrWrite = true; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + status = PAL_ERR_TLS_WANT_WRITE; + localTLSCtx->wantReadOrWrite = true; + break; + case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED: + status = PAL_ERR_TLS_HELLO_VERIFY_REQUIRED; + break; + case MBEDTLS_ERR_SSL_TIMEOUT: + status = PAL_ERR_TIMEOUT_EXPIRED; + break; + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + status = PAL_ERR_TLS_PEER_CLOSE_NOTIFY; + break; + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + status = PAL_ERR_X509_CERT_VERIFY_FAILED; + break; + default: + { + PAL_LOG(ERR, "SSL handshake return code %" PRId32 ".", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } + }; + + return status; +} + + +palStatus_t pal_plat_setOwnCertAndPrivateKey(palTLSConfHandle_t palTLSConf, palX509_t* ownCert, palPrivateKey_t* privateKey) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf; + int32_t platStatus = SSL_LIB_SUCCESS; + + + if (NULLPTR == palTLSConf || NULL == ownCert || NULL == ownCert) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mbedtls_x509_crt_init(&localConfigCtx->owncert); + mbedtls_pk_init(&localConfigCtx->pkey); + + + platStatus = mbedtls_x509_crt_parse_der(&localConfigCtx->owncert, (const unsigned char *)ownCert->buffer, ownCert->size); + if (SSL_LIB_SUCCESS != platStatus) + { + status = PAL_ERR_TLS_FAILED_TO_PARSE_CERT; + goto finish; + } + + platStatus = mbedtls_pk_parse_key(&localConfigCtx->pkey, (const unsigned char *)privateKey->buffer, privateKey->size, NULL, 0 ); + if (SSL_LIB_SUCCESS != platStatus) + { + status = PAL_ERR_TLS_FAILED_TO_PARSE_KEY; + goto finish; + } + + platStatus = mbedtls_ssl_conf_own_cert(localConfigCtx->confCtx, &localConfigCtx->owncert, &localConfigCtx->pkey); + if (SSL_LIB_SUCCESS != platStatus) + { + status = PAL_ERR_TLS_FAILED_TO_SET_CERT; + } + + localConfigCtx->hasKeys = true; + +finish: + PAL_LOG(DBG, "TLS set and parse status %" PRIu32 ".", platStatus); + return status; +} + + +palStatus_t pal_plat_setCAChain(palTLSConfHandle_t palTLSConf, palX509_t* caChain, palX509CRL_t* caCRL) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf; + int32_t platStatus = SSL_LIB_SUCCESS; + + if (NULLPTR == palTLSConf || NULL == caChain) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mbedtls_x509_crt_init(&localConfigCtx->cacert); + + platStatus = mbedtls_x509_crt_parse_der(&localConfigCtx->cacert, (const unsigned char *)caChain->buffer, caChain->size); + if (SSL_LIB_SUCCESS != platStatus) + { + PAL_LOG(ERR, "TLS CA chain status %" PRId32 ".", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + goto finish; + } + mbedtls_ssl_conf_ca_chain(localConfigCtx->confCtx, &localConfigCtx->cacert, NULL ); + + localConfigCtx->hasChain = true; +finish: + return status; +} + +palStatus_t pal_plat_setPSK(palTLSConfHandle_t palTLSConf, const unsigned char *identity, uint32_t maxIdentityLenInBytes, const unsigned char *psk, uint32_t maxPskLenInBytes) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf; + int32_t platStatus = SSL_LIB_SUCCESS; + + if (NULLPTR == palTLSConf || NULL == identity || NULL == psk) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + platStatus = mbedtls_ssl_conf_psk(localConfigCtx->confCtx, psk, maxPskLenInBytes, identity, maxIdentityLenInBytes); + if (SSL_LIB_SUCCESS != platStatus) + { + if (MBEDTLS_ERR_SSL_ALLOC_FAILED == platStatus) + { + status = PAL_ERR_TLS_INIT; + goto finish; + } + PAL_LOG(ERR, "TLS set psk status %" PRId32 ".", platStatus); + status = PAL_ERR_GENERIC_FAILURE; + } +finish: + return status; +} + +palStatus_t pal_plat_tlsSetSocket(palTLSConfHandle_t palTLSConf, palTLSSocket_t* socket) +{ + palStatus_t status = PAL_SUCCESS; + + if (NULLPTR == palTLSConf || NULL == socket) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_plat_sslSetIOCallBacks(palTLSConf, socket, palBIOSend, palBIORecv); + return status; +} + +palStatus_t pal_plat_sslSetIOCallBacks(palTLSConfHandle_t palTLSConf, palTLSSocket_t* palIOCtx, palBIOSend_f palBIOSend, palBIORecv_f palBIORecv) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf; + bool isNonBlocking = false; + + if (NULLPTR == palTLSConf || NULL == palBIOSend || NULL == palBIORecv) + { + return PAL_ERR_INVALID_ARGUMENT; + } + localConfigCtx->palIOCtx = palIOCtx; + + status = pal_isNonBlocking(palIOCtx->socket, &isNonBlocking); + if (PAL_SUCCESS != status) + { + return status; + } + + if (isNonBlocking) + { + mbedtls_ssl_set_bio(&g_palTLSContext[localConfigCtx->tlsIndex].tlsCtx, palIOCtx, palBIOSend, palBIORecv, NULL); + } + else + { + mbedtls_ssl_set_bio(&g_palTLSContext[localConfigCtx->tlsIndex].tlsCtx, palIOCtx, palBIOSend, NULL, palBIORecv_timeout); + } + + return PAL_SUCCESS; +} + +palStatus_t pal_plat_sslDebugging(uint8_t turnOn) +{ + palStatus_t status = PAL_SUCCESS; + palLogFunc_f func = NULL; +#if defined(MBEDTLS_DEBUG_C) + mbedtls_debug_set_threshold(PAL_TLS_DEBUG_THRESHOLD); +#endif + + if (turnOn) + { + func = palDebug; + } + + for (int i=0 ; i < PAL_MAX_NUM_OF_TLS_CTX ; ++i ) + { + if ((g_palTLSContext != NULL) && (g_palTLSContext[i].tlsInit)) + { + status = pal_plat_SetLoggingCb((palTLSConfHandle_t)g_palTLSContext[i].palConfCtx, func, NULL); + } + } + + return status; +} + +palStatus_t pal_plat_SetLoggingCb(palTLSConfHandle_t palTLSConf, palLogFunc_f palLogFunction, void *logContext) +{ + palTLSConf_t* localConfigCtx = (palTLSConf_t*)palTLSConf; + + mbedtls_ssl_conf_dbg(localConfigCtx->confCtx, palLogFunction, logContext); + return PAL_SUCCESS; +} + +PAL_PRIVATE uint64_t palTimingGetTimer(uint64_t *start_ticks, int reset) +{ + uint64_t delta_ms; + uint64_t ticks = pal_osKernelSysTick(); + + if (reset) + { + *start_ticks = ticks; + delta_ms = 0; + } + else + { + delta_ms = pal_osKernelSysMilliSecTick(ticks - *start_ticks); + } + + return delta_ms; +} + + +/* + * Set delays to watch + */ +PAL_PRIVATE void palTimingSetDelay( void *data, uint32_t intMs, uint32_t finMs ) +{ + + palTimingDelayContext_t *ctx = data; + + ctx->int_ms = intMs; + ctx->fin_ms = finMs; + + if( finMs != 0 ) + { + (void) palTimingGetTimer( &ctx->start_ticks, 1 ); + } +} + +/* + * Get number of delays expired + */ +PAL_PRIVATE int palTimingGetDelay( void *data ) +{ + int result = 0; + palTimingDelayContext_t *ctx = data; + uint64_t elapsed_ms; + + if( ctx->fin_ms == 0 ) + { + result = -1; + goto finish; + } + + elapsed_ms = palTimingGetTimer( &ctx->start_ticks, 0 ); + + if( elapsed_ms >= ctx->fin_ms ) + { + result = 2; + goto finish; + } + + if( elapsed_ms >= ctx->int_ms ) + { + result = 1; + goto finish; + } + +finish: + return result; +} + + +int pal_plat_entropySourceTLS( void *data, unsigned char *output, size_t len, size_t *olen ) +{ + palStatus_t status = PAL_SUCCESS; + (void)data; + + status = pal_osRandomBuffer((uint8_t*) output, len); + if (PAL_SUCCESS == status) + { + if (NULL != olen) + { + *olen = len; + } + return 0; + } + else + { + return -1; + } +} + +PAL_PRIVATE int palBIOSend(palTLSSocketHandle_t socket, const unsigned char *buf, size_t len) +{ + palStatus_t status = PAL_SUCCESS; + size_t sentDataSize = 0; + palTLSSocket_t* localSocket = (palTLSSocket_t*)socket; + + if (NULLPTR == socket) + { + status = -1; + goto finish; + } + + if (PAL_TLS_MODE == localSocket->transportationMode) + { + status = pal_send(localSocket->socket, buf, len, &sentDataSize); + } + else if (PAL_DTLS_MODE == localSocket->transportationMode) + { + status = pal_sendTo(localSocket->socket, buf, len, localSocket->socketAddress, localSocket->addressLength, &sentDataSize); + } + else + { + PAL_LOG(ERR, "TLS BIO send error"); + status = PAL_ERR_GENERIC_FAILURE; + } + if (PAL_SUCCESS == status || PAL_ERR_NO_MEMORY == status || PAL_ERR_SOCKET_WOULD_BLOCK == status) + { + if (0 != sentDataSize) + { + status = sentDataSize; + } + else + { + status = MBEDTLS_ERR_SSL_WANT_WRITE; + } + } +finish: + return status; +} + +PAL_PRIVATE int palBIORecv(palTLSSocketHandle_t socket, unsigned char *buf, size_t len) +{ + palStatus_t status = PAL_SUCCESS; + size_t recievedDataSize = 0; + palTLSSocket_t* localSocket = (palTLSSocket_t*)socket; + + if (NULLPTR == socket) + { + status = -1; + goto finish; + } + + if (PAL_TLS_MODE == localSocket->transportationMode) + { + status = pal_recv(localSocket->socket, buf, len, &recievedDataSize); + if (PAL_SUCCESS == status) + { + status = recievedDataSize; + } + else if (PAL_ERR_SOCKET_WOULD_BLOCK == status) + { + status = MBEDTLS_ERR_SSL_WANT_READ; + } + } + else if (PAL_DTLS_MODE == localSocket->transportationMode) + { + status = pal_receiveFrom(localSocket->socket, buf, len, localSocket->socketAddress, &localSocket->addressLength, &recievedDataSize); + if (PAL_SUCCESS == status) + { + if (0 != recievedDataSize) + { + status = recievedDataSize; + } + else + { + status = MBEDTLS_ERR_SSL_WANT_READ; + } + } + else if (PAL_ERR_SOCKET_WOULD_BLOCK == status) + { + status = MBEDTLS_ERR_SSL_WANT_READ; + } + } + else + { + PAL_LOG(ERR, "TLS BIO recv error"); + status = PAL_ERR_GENERIC_FAILURE; + } + +finish: + return status; +} + +PAL_PRIVATE int palBIORecv_timeout(palTLSSocketHandle_t socket, unsigned char *buf, size_t len, uint32_t timeout) +{ + palStatus_t status = PAL_SUCCESS; + size_t recievedDataSize = 0; + uint32_t localTimeOut = timeout; + palTLSSocket_t* localSocket = (palTLSSocket_t*)socket; + bool isNonBlocking = false; + + if (NULLPTR == socket) + { + status = -1; + goto finish; + } + + status = pal_isNonBlocking(localSocket->socket, &isNonBlocking); + if (PAL_SUCCESS != status) + { + goto finish; + } + + if (PAL_TLS_MODE == localSocket->transportationMode) + { + status = pal_recv(localSocket->socket, buf, len, &recievedDataSize); + if (PAL_SUCCESS == status) + { + status = recievedDataSize; + } + else if (PAL_ERR_SOCKET_WOULD_BLOCK == status) + { + status = MBEDTLS_ERR_SSL_WANT_READ; + } + } + else if (PAL_DTLS_MODE == localSocket->transportationMode) + { + if (false == isNonBlocking) // timeout is relevant only if socket is blocking + { + status = pal_setSocketOptions(localSocket->socket, PAL_SO_RCVTIMEO, &localTimeOut, sizeof(localTimeOut)); + if (PAL_SUCCESS != status) + { + goto finish; + } + } + + status = pal_receiveFrom(localSocket->socket, buf, len, localSocket->socketAddress, &localSocket->addressLength, &recievedDataSize); + + if (PAL_SUCCESS == status) + { + if (0 != recievedDataSize) + { + status = recievedDataSize; + } + else + { + status = MBEDTLS_ERR_SSL_WANT_READ; + } + } + else if (PAL_ERR_SOCKET_WOULD_BLOCK == status) + { + status = MBEDTLS_ERR_SSL_TIMEOUT; + } + } + else + { + PAL_LOG(ERR, "TLS BIO recv timeout error"); + status = PAL_ERR_GENERIC_FAILURE; + } + +finish: + return status; +} + +PAL_PRIVATE void palDebug(void *ctx, int debugLevel, const char *fileName, int line, const char *message) +{ + (void)ctx; + DEBUG_PRINT("%s: %d: %s\r\n", fileName, line, message); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +Linux/* +FreeRTOS/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Board_Specific/TARGET_K64F/pal_plat_K64F.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Board_Specific/TARGET_K64F/pal_plat_K64F.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pal_plat_rtos.h" +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" +#include "board.h" + +#include "clock_config.h" + + +/////////////////////////STATIC FUNCTION/////////////////////////// +/*! disable all interrupts in system +* +* @param[in] Void +* \returns void +* +*/ +PAL_PRIVATE PAL_INLINE void pal_plat_DisableIrq(void); +/*! Enable all interrupts in system +* +* @param[in] Void +* \returns void +* +*/ +PAL_PRIVATE PAL_INLINE void pal_plat_EnableIrq(void); + + +/*! get one random byte +* +* @param[out] byte: pointer to one byte to hold the random number +* +* \returns void +*/ +PAL_PRIVATE void getTRNGByte(unsigned char *byte); + +/*! get random number in size of given bytes +* +* @param[out] output: pointer to buffer to hold the random number +* @param[in] length: size of the output buffer +* @param[out] output_length: actual size of the written data +* +* \returns void +*/ +PAL_PRIVATE int getTRNGBytes(uint8_t *output, size_t length, size_t *output_length); + +PAL_PRIVATE PAL_INLINE void pal_plat_DisableIrq(void) +{ + __asm volatile ( " cpsid i " ); +} + +PAL_PRIVATE PAL_INLINE void pal_plat_EnableIrq(void) +{ + __asm volatile ( " cpsie i " ); +} +/////////////////////////END STATIC FUNCTION/////////////////////////// + +#if defined (__CC_ARM) /* ARM Compiler */ + +#pragma push +#pragma O0 + +#if ((defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M)) && !defined(NO_EXCLUSIVE_ACCESS)) +#define __USE_EXCLUSIVE_ACCESS +#else +#undef __USE_EXCLUSIVE_ACCESS +#endif // ARMCC end + +#elif defined (__GNUC__) /* GNU Compiler */ + +#undef __USE_EXCLUSIVE_ACCESS +#pragma GCC push_options +#pragma GCC optimize ("O0") + +#if defined (__CORTEX_M0) +#define __TARGET_ARCH_6S_M +#endif + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) +#define __TARGET_FPU_VFP +#endif +#endif + +int32_t pal_plat_osAtomicIncrement(int32_t* valuePtr, int32_t increment) +{ +#ifdef __USE_EXCLUSIVE_ACCESS + int32_t res; + res = __ldrex(valuePtr) + increment; + do { + } while (__strex(res, valuePtr)); + return (res); +#elif !defined (__CORTEX_M0) + if (valuePtr != NULL) + { + asm volatile( + "try:\n\t" + "LDREX R0, [%[valuePtr]]\n\t" + "ADD R0, %[increment]\n\t" + "CMP R0, R0\n\t" + "ITT EQ\n\t" + "STREXEQ R1, R0, [%[valuePtr]]\n\t" + "CMPEQ R1, #0\n\t" + "BNE try\n\t" + :[valuePtr]"+r"(valuePtr) + :[increment]"r"(increment) + ); + return *valuePtr; + } + else + { + return 0; + } +#else + int32_t res; + pal_plat_DisableIrq(); + res = *valuePtr + increment; + *valuePtr = res; + pal_plat_EnableIrq(); + return (res); +#endif + +} +#if defined (__CC_ARM) /* ARM Compiler */ + +#pragma pop + +#elif defined (__GNUC__) + +#pragma GCC pop_options + +#endif + + +void pal_plat_osReboot() +{ +#define RESET_MASK_FOR_CORTEX_M_SERIES 0x5fa0004 + + volatile unsigned int * AIRCR_REG = (volatile unsigned int *)(0xE000ED0C); //This register address is true for the Cortex M family + *AIRCR_REG = RESET_MASK_FOR_CORTEX_M_SERIES; + while(1); /* wait until reset */ +} + +/* + * Get one byte of entropy from the RNG, assuming it is up and running. + * As recommended (34.1.1), get only one bit of each output. + */ +PAL_INLINE void getTRNGByte(unsigned char *byte) +{ + size_t bit; + + /* 34.5 Steps 3-4-5: poll SR and read from OR when ready */ + for( bit = 0; bit < 8; bit++ ) + { + //! while random-data output is zero, wait in the while, else read the OR (Output Register) + while((RNG->SR & RNG_SR_OREG_LVL_MASK) == 0 ); + *byte |= (RNG->OR & 1) << bit; + } +} + +PAL_PRIVATE int getTRNGBytes(uint8_t *output, size_t length, size_t *output_length) +{ + size_t i; + + /* Set "Interrupt Mask", "High Assurance" and "Go", + * unset "Clear interrupt" and "Sleep" */ + RNG->CR = RNG_CR_INTM_MASK | RNG_CR_HA_MASK | RNG_CR_GO_MASK; + + for (i = 0; i < length; i++) { + getTRNGByte(output + i); + } + + /* Just be extra sure that we didn't do it wrong */ + //! to make sure that no Security Violation has occured. + if ((RNG->SR & RNG_SR_SECV_MASK) != 0) { + return -1; + } + + *output_length = length; + + return 0; +} + +palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = 0; + size_t actualOutputLen = 0; + + platStatus = getTRNGBytes(randomBuf, bufSizeBytes, &actualOutputLen); + if (0 != platStatus || actualOutputLen != bufSizeBytes) + { + status = PAL_ERR_RTOS_TRNG_FAILED; + } + return status; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Networking/LWIP/pal_plat_network.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Networking/LWIP/pal_plat_network.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1267 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "pal_plat_network.h" + +#include "api.h" // include LWIP sockets header +#include "netdb.h" +#include "netif.h" +#include "ip.h" +#include "tcp.h" + + +/* Static arena of sockets */ +//TODO: do we need to protect this agains multitheaded aceess? + typedef struct palLwipSocketNetConnInfo { + bool inUse; + + struct netconn *connection; + struct netbuf *buffer; + uint32_t offset; + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + palAsyncSocketCallback_t callback; + void *callbackArgument; +#endif + } palLwipNetConnInfo_t; + + PAL_PRIVATE palLwipNetConnInfo_t palInternalSocketInfo[MEMP_NUM_NETCONN] = {0}; + + +// number taken from LWIP documentaiton reccomendations (http://www.ece.ualberta.ca/~cmpe401/docs/lwip.pdf) +#define PAL_MAX_SEND_BUFFER_SIZE 1000 + + PAL_PRIVATE void* s_pal_networkInterfacesSupported[PAL_MAX_SUPORTED_NET_INTERFACES] = { 0 }; + + PAL_PRIVATE uint32_t s_pal_numberOFInterfaces = 0; + + + /*! pal_plat_netconReceive + * This function is a workaround for LWIP non block receive, + * When calling netconn_recv() on a non-blocking connection with receive timeout=0 the netconn_recv function will block indefinately (unless data arrives). this is not correct behavior. + * To work around this issue for to a non blocking connections we set the recieve timeout to 1 and set it back to the previous timeout value after the recv call. + * This is only for NON BLOCKING connections!!! all other sockets are left untouched. + * @param[in] netconn* conn handler + * @param[out] *netbuf - output buffer + \return The status form the netconn_recv call. + */ +PAL_PRIVATE int pal_plat_netconReceive(struct netconn* conn, struct netbuf **newBuf) +{ + int backupTimeout; + int result = PAL_SUCCESS; + bool isNonBlocking = netconn_is_nonblocking(conn); + if(isNonBlocking) + { + backupTimeout = netconn_get_recvtimeout(conn); + netconn_set_recvtimeout(conn, 1); + result = netconn_recv(conn, newBuf); + netconn_set_recvtimeout(conn, backupTimeout); + } + else + { + result = netconn_recv(conn, newBuf); + } + + return result; +} + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + +// wrapper for callbacks because function signature is different. +void palNetConAsyncCallback(struct netconn * connection, enum netconn_evt event, u16_t len) +{ + int index = 0; + for (index = 0; index < MEMP_NUM_NETCONN; index++) + { + if ( (true == palInternalSocketInfo[index].inUse ) && (palInternalSocketInfo[index].connection == connection)) + { + if (NULL != palInternalSocketInfo[index].callback) + { + palInternalSocketInfo[index].callback(palInternalSocketInfo[index].callbackArgument); + } + break; + } + } +} +#endif + + + + +palStatus_t pal_plat_socketsInit(void* context) +{ + (void)context; // parameter not used in this case - this avoids the warning + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_registerNetworkInterface(void* context, uint32_t* interfaceIndex) +{ + palStatus_t result = PAL_SUCCESS; + uint32_t index = 0; + bool found = false; + + for (index = 0; index < s_pal_numberOFInterfaces; index++) // if specific context already registered return exisitng index instead of registering again. + { + if (s_pal_networkInterfacesSupported[index] == context) + { + found = true; + *interfaceIndex = index; + break; + } + } + + if (false == found) + { + if (s_pal_numberOFInterfaces < PAL_MAX_SUPORTED_NET_INTERFACES) + { + s_pal_networkInterfacesSupported[s_pal_numberOFInterfaces] = context; + *interfaceIndex = s_pal_numberOFInterfaces; + ++s_pal_numberOFInterfaces; + } + else + { + result = PAL_ERR_SOCKET_MAX_NUMBER_OF_INTERFACES_REACHED; + } + } + + return result; +} + +palStatus_t pal_plat_socketsTerminate(void* context) +{ + (void)context; // replace with macro + // clean up static sockets array ? (close all sockets?) + return PAL_SUCCESS; +} + + +PAL_PRIVATE palStatus_t translateErrnoToPALError(int errnoValue) +{ + palStatus_t status; + switch (errnoValue) + { + case ERR_MEM: + status = PAL_ERR_NO_MEMORY; + break; + case ERR_BUF: + status = PAL_ERR_SOCKET_NO_BUFFERS; + break; + case ERR_TIMEOUT: + status = PAL_ERR_SOCKET_WOULD_BLOCK; + break; + case ERR_RTE: + status = PAL_ERR_SOCKET_HOST_UNREACHABLE; + break; + case ERR_INPROGRESS: + status = PAL_ERR_SOCKET_IN_PROGRES; + break; + case ERR_VAL: + status = PAL_ERR_SOCKET_INVALID_VALUE; + break; + case ERR_WOULDBLOCK: + status = PAL_ERR_SOCKET_WOULD_BLOCK; + break; + case ERR_USE: + status = PAL_ERR_SOCKET_ADDRESS_IN_USE; + break; + case ERR_ISCONN: + status = PAL_ERR_SOCKET_ALREADY_CONNECTED; + break; + case ERR_ABRT: + status = PAL_ERR_SOCKET_CONNECTION_ABORTED; + break; + case ERR_RST: + status = PAL_ERR_SOCKET_CONNECTION_RESET; + break; + case ERR_CONN: + status = PAL_ERR_SOCKET_NOT_CONNECTED; + break; + case ERR_ARG: + status = PAL_ERR_INVALID_ARGUMENT; + break; + case ERR_CLSD: + status = PAL_ERR_SOCKET_CONNECTION_CLOSED; + break; + case ERR_IF: + status = PAL_ERR_SOCKET_INPUT_OUTPUT_ERROR; + break; + + default: + status = PAL_ERR_SOCKET_GENERIC; + break; + } + return status; +} + + +palStatus_t pal_plat_socket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palSocket_t* socket) +{ + int result = PAL_SUCCESS; + enum netconn_type connType = NETCONN_INVALID; + struct netconn * con; + uint32_t numberOfInterfaces = 0; + palLwipNetConnInfo_t* socketInfo = NULL; + uint32_t index = 0; + + + + result = pal_plat_getNumberOfNetInterfaces(&numberOfInterfaces); + if (PAL_SUCCESS != result) + { + return result; + } + + + if (interfaceNum >= numberOfInterfaces && PAL_NET_DEFAULT_INTERFACE != interfaceNum) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (domain != PAL_AF_INET) + { + return PAL_ERR_NOT_IMPLEMENTED; + } + + if ((PAL_SOCK_STREAM == type) || (PAL_SOCK_STREAM_SERVER == type)) + { + connType = NETCONN_TCP; + } + else if (PAL_SOCK_DGRAM == type) + { + connType = NETCONN_UDP; + } + else + { + return PAL_ERR_INVALID_ARGUMENT; + } + + + for (index = 0; index < MEMP_NUM_NETCONN; index++) // allocate socket info structure. + { + if (false == palInternalSocketInfo[index].inUse) + { + palInternalSocketInfo[index].inUse = true; + socketInfo = &palInternalSocketInfo[index]; + break; + } + } + + if (NULL != socketInfo) + { + con = netconn_new(connType); + if (NULL != con) + { + // TODO(nirson01) : add binding to specific network interface (interfaceNum) + if (nonBlockingSocket) + { + netconn_set_nonblocking(con, 1); + } + socketInfo->connection = con; + socketInfo->buffer = NULL; + *socket = (palSocket_t)socketInfo; + } + else + { + result = PAL_ERR_NO_MEMORY; + } + } + else + { + result = PAL_ERR_NO_MEMORY; + } + + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastrucature is finalized) +} + + +palStatus_t pal_plat_getSocketOptions(palSocket_t socket, palSocketOptionName_t optionName, void* optionValue, palSocketLength_t* optionLength) +{ + palStatus_t result = PAL_SUCCESS; + struct netconn* conn = NULL; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + + if (PAL_SO_REUSEADDR == optionName) + { + *((int *)optionValue) = ip_get_option(conn->pcb.ip, SOF_REUSEADDR); + *optionLength = sizeof(int); + } +#if PAL_NET_TCP_AND_TLS_SUPPORT // socket options below supported only if TCP is supported. + else if ((PAL_SO_KEEPALIVE == optionName) && (NETCONN_TCP == conn->type) && (conn->pcb.tcp != NULL)) + { + *((int *)optionValue) = ip_get_option(conn->pcb.ip, SOF_KEEPALIVE); + *optionLength = sizeof(int); + } +#if LWIP_TCP_KEEPALIVE // follwing options only supported if LWIP_TCP_KEEPALIVE is set to 1. + else if ((PAL_SO_KEEPIDLE == optionName) && (NETCONN_TCP == conn->type) && (conn->pcb.tcp != NULL)) + { + *(int*)optionValue = (int)(conn->pcb.tcp->keep_idle/1000); + *optionLength = sizeof(int); + } + else if ((PAL_SO_KEEPINTVL == optionName) && (NETCONN_TCP == conn->type) && (conn->pcb.tcp != NULL)) + { + *(int*)optionValue = (int)(conn->pcb.tcp->keep_intvl/1000); + *optionLength = sizeof(int); + } + +#endif +#endif //PAL_NET_TCP_AND_TLS_SUPPORT +#ifdef LWIP_SO_RCVTIMEO + else if (PAL_SO_SNDTIMEO == optionName) + { + *((int *)optionValue) = netconn_get_recvtimeout(conn); + *optionLength = sizeof(int); + } +#endif +#ifdef LWIP_SO_SNDTIMEO + else if (PAL_SO_RCVTIMEO == optionName) + { + *((int *)optionValue) = netconn_get_sendtimeout(conn); + *optionLength = sizeof(int); + } +#endif + else + { + result = PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED; + } + + //TODO: nirson: add decoding for differnet netcon values + return result ; +} + + +palStatus_t pal_plat_setSocketOptions(palSocket_t socket, int optionName, const void* optionValue, palSocketLength_t optionLength) +{ + palStatus_t result = PAL_SUCCESS; + struct netconn* conn = NULL; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + + if (PAL_SO_REUSEADDR == optionName) + { + ip_set_option(conn->pcb.ip, SOF_REUSEADDR); + } +#if PAL_NET_TCP_AND_TLS_SUPPORT // socket options below supported only if TCP is supported. + else if ((PAL_SO_KEEPALIVE == optionName) && (NETCONN_TCP == conn->type) && (conn->pcb.tcp != NULL)) + { + if (*(int*)optionValue != 0) + { + ip_set_option(conn->pcb.ip, SOF_KEEPALIVE); + } + else + { + ip_reset_option(conn->pcb.ip, SOF_KEEPALIVE); + } + } +#if LWIP_TCP_KEEPALIVE // follwing options only supported if LWIP_TCP_KEEPALIVE is set to 1. + else if ((PAL_SO_KEEPIDLE == optionName) && (NETCONN_TCP == conn->type) && (conn->pcb.tcp != NULL)) + { + conn->pcb.tcp->keep_idle = (*(int*)optionValue) * 1000; + } + else if ((PAL_SO_KEEPINTVL == optionName) && (NETCONN_TCP == conn->type) && (conn->pcb.tcp != NULL)) + { + conn->pcb.tcp->keep_intvl = (*(int*)optionValue) * 1000; + } + +#endif + +#endif //PAL_NET_TCP_AND_TLS_SUPPORT +#ifdef LWIP_SO_SNDTIMEO + else if (PAL_SO_SNDTIMEO == optionName) + { + netconn_set_sendtimeout(conn, *((const int *)optionValue)); + } +#endif +#ifdef LWIP_SO_RCVTIMEO + else if (PAL_SO_RCVTIMEO == optionName) + { + netconn_set_recvtimeout(conn, *((const int *)optionValue)); + } +#endif + else + { + result = PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED; + } + return result; +} + +palStatus_t pal_plat_isNonBlocking(palSocket_t socket, bool* isNonBlocking) +{ + struct netconn* conn = NULL; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + + if (netconn_is_nonblocking(conn)) + { + *isNonBlocking = true; + } + else + { + *isNonBlocking = false; + } + return PAL_SUCCESS; + +} + + +palStatus_t pal_plat_bind(palSocket_t socket, palSocketAddress_t* myAddress, palSocketLength_t addressLength) +{ + int result = PAL_SUCCESS; + struct netconn* conn = NULL; + err_t error = 0; + palIpV4Addr_t ipv4 = {0}; + uint16_t port = 0; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + + + result = pal_getSockAddrIPV4Addr(myAddress, ipv4); + if (PAL_SUCCESS == result) + { + result = pal_getSockAddrPort(myAddress, &port); + if (PAL_SUCCESS == result) + { + + error = netconn_bind(conn, (ip_addr_t *)ipv4, port); + if (ERR_OK != error) + { + result = translateErrnoToPALError(error); + } + } + } + + return result; +} + + +palStatus_t pal_plat_receiveFrom(palSocket_t socket, void* buffer, size_t length, palSocketAddress_t* from, palSocketLength_t* fromLength, size_t* bytesReceived) +{ + int result = PAL_SUCCESS; + struct netbuf *newBuf = NULL; + palLwipNetConnInfo_t* socketInfo = (palLwipNetConnInfo_t*)socket; + struct netconn* conn = NULL; + struct ip_addr* fromAddr; + unsigned short fromPort; + size_t bufferLength = 0; + *bytesReceived = 0; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = socketInfo->connection; + + + if (NULL != socketInfo->buffer) + { + newBuf = socketInfo->buffer; + result = ERR_OK; + } + else + { + result = pal_plat_netconReceive(conn, &newBuf); + if (ERR_OK != result) // Receive data + { + result = translateErrnoToPALError(result); + } + } + + if ((ERR_OK == result) &&(NULL != newBuf) ) + { + + bufferLength = netbuf_len(newBuf); + if (bufferLength <= length) + { + netbuf_copy(newBuf, buffer, bufferLength); + *bytesReceived = bufferLength; + } + else // more data recieved than buffer + { + netbuf_copy(newBuf, buffer, length); + *bytesReceived = length; + } + if (NULL != from) + { + fromAddr = netbuf_fromaddr(newBuf); + fromPort = netbuf_fromport(newBuf); + result = pal_setSockAddrIPV4Addr(from, *((palIpV4Addr_t*)fromAddr)); + if (PAL_SUCCESS == result) + { + result = pal_setSockAddrPort(from, fromPort); + if ((PAL_SUCCESS == result) && (NULL != fromLength)) + { + *fromLength = PAL_IPV4_ADDRESS_SIZE; + } + } + } + } + else if(ERR_OK == result)// if we got NULL this means the conneciton was closed + { + if (NULL != fromLength) + { + *fromLength = 0; + } + result = PAL_ERR_SOCKET_CONNECTION_CLOSED; + } + + if (NULL != socketInfo->buffer) + { + socketInfo->buffer = NULL; + socketInfo->offset = 0; + // deleted below through newBuf + } + + if (NULL !=newBuf ) + netbuf_delete(newBuf); + return result; + +} + +palStatus_t pal_plat_sendTo(palSocket_t socket, const void* buffer, size_t length, const palSocketAddress_t* to, palSocketLength_t toLength, size_t* bytesSent) +{ + int result = 0; + struct netconn* conn = NULL; + struct netbuf *localNetbuf; + struct ip_addr toAddr; + palIpV4Addr_t ipv4; + unsigned short toPort; + *bytesSent = 0; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + + // netconn documentaiton (http://www.ece.ualberta.ca/~cmpe401/docs/lwip.pdf) says buffers over the size of the MTU should nto be sent. since this isn not always known 1000bytes is a good heuristic + + + if (length > PAL_MAX_SEND_BUFFER_SIZE) + { + result = PAL_ERR_SOCKET_SEND_BUFFER_TOO_BIG; + goto finish; + } + + localNetbuf = netbuf_new(); + if (NULL == localNetbuf) + { + result = PAL_ERR_NO_MEMORY; + goto finish; + } + + result = netbuf_ref(localNetbuf, buffer, length); + if (PAL_SUCCESS == result) + { + result = pal_getSockAddrPort(to, &toPort); + if (PAL_SUCCESS == result) + { + result = pal_getSockAddrIPV4Addr(to, ipv4); + if (PAL_SUCCESS == result) + { + toAddr.addr = ipv4[0] | (ipv4[1] << 8) | (ipv4[2] << 16) | (ipv4[3] << 24); + + result = netconn_connect(conn, &toAddr, toPort); + if (ERR_OK == result) + { + result = netconn_send(conn, localNetbuf); + if (ERR_OK != result) + { + result = translateErrnoToPALError(result); + } + } + else + { + result = translateErrnoToPALError(result); + } + } + } + } + + netbuf_delete(localNetbuf); + *bytesSent = length; + +finish: + + return result; +} + +palStatus_t pal_plat_close(palSocket_t* socket) +{ + int result = 0; + palLwipNetConnInfo_t* socketInfo = NULL; + struct netconn* conn = NULL; + + if (NULL == *socket) // socket already closed - return success. + { + PAL_LOG(DBG, "socket close called on socket which was already closed"); + return PAL_SUCCESS; + } + socketInfo = (palLwipNetConnInfo_t*)*socket; + conn = socketInfo->connection; + if (NETCONN_TCP == conn->type) + { + result = netconn_close(conn); + if (ERR_OK == result) + { + + *socket = NULL; + } + else + { + result = translateErrnoToPALError(result); + } + } + else + { + *socket = NULL; + } + + socketInfo->inUse = false; + socketInfo->offset = 0; + socketInfo->connection = NULL; +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + socketInfo->callback = NULL; +#endif + if (NULL != socketInfo->buffer ) + { + netbuf_delete(socketInfo->buffer); + socketInfo->buffer = NULL; + } + netconn_delete(conn); + return result; +} + +palStatus_t pal_plat_getNumberOfNetInterfaces( uint32_t* numInterfaces) +{ + *numInterfaces = s_pal_numberOFInterfaces; + return PAL_SUCCESS; +} + +palStatus_t pal_plat_getNetInterfaceInfo(uint32_t interfaceNum, palNetInterfaceInfo_t * interfaceInfo) +{ + palStatus_t result = PAL_SUCCESS; + + uint16_t port = 0; + uint32_t numInterfaces = 0; + + result = pal_plat_getNumberOfNetInterfaces(&numInterfaces); + if (PAL_SUCCESS != result) + { + return result; + } + if (interfaceNum == -1) // default interface number is 0; + { + interfaceNum = 0; + } + if (interfaceNum <numInterfaces) // only "default" interface supported at this point + { + struct netif* fsl_netif0 = (struct netif*)s_pal_networkInterfacesSupported[interfaceNum] ; + result = pal_setSockAddrIPV4Addr(&interfaceInfo->address, *((palIpV4Addr_t*)&(fsl_netif0->ip_addr.addr))); + if (PAL_SUCCESS == result) + { + result = pal_setSockAddrPort(&interfaceInfo->address, port); + } + } + + return result; +} + +typedef struct palSocketSelectInfo +{ + struct netconn * connection; + uint32_t selectStatus; +} palSocketSelectInfo_t; + +PAL_PRIVATE palSocketSelectInfo_t s_select_state[PAL_NET_SOCKET_SELECT_MAX_SOCKETS] ; +PAL_PRIVATE palSemaphoreID_t s_palSelectSemaphore = 0; +//static bool s_palSelectSemaphoreInited = false; + +void palNetConSelectCallback(struct netconn * connection, enum netconn_evt event, u16_t len) +{ + uint32_t index = 0; +#ifdef PAL_NET_ASYNCHRONOUS_SOCKET_API + for (index = 0; index < MEMP_NUM_NETCONN; index++) + { + if ((palInternalSocketInfo[index].inUse) && (palInternalSocketInfo[index].connection == connection) && (NULL != palInternalSocketInfo[index].callback)) + { + palInternalSocketInfo[index].callback(palInternalSocketInfo[index].callbackArgument); + break; + } + } +#endif + for (index = 0; index < PAL_NET_SOCKET_SELECT_MAX_SOCKETS; index++) + { + if (connection == s_select_state[index].connection) + { + s_select_state[index].selectStatus = 1; // add different flag per event. + /* + NETCONN_EVT_RCVPLUS, + NETCONN_EVT_RCVMINUS, + NETCONN_EVT_SENDPLUS, + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR + */ + break; + } + } + pal_osSemaphoreRelease(s_palSelectSemaphore); +} + + +palStatus_t pal_plat_socketMiniSelect(const palSocket_t socketsToCheck[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t numberOfSockets, pal_timeVal_t* timeout, + uint8_t palSocketStatus[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t * numberOfSocketsSet) +{ + + uint32_t index = 0; + int32_t counter = 0; + uint32_t timeoutInMiliseconds = 0; + palStatus_t result = PAL_SUCCESS; + uint32_t countWithPriorData = 0; + struct netbuf *newBuf = NULL; + + if ((NULL == socketsToCheck) || (NULL == numberOfSocketsSet) || (NULL == timeout)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (0 == numberOfSockets) + { + return PAL_SUCCESS; + } + + for (index = 0; index < numberOfSockets; index++) + { + if (NULL == socketsToCheck[index]) + { + return PAL_ERR_INVALID_ARGUMENT; + } + } + + timeoutInMiliseconds = (timeout->pal_tv_sec * 1000) + (timeout->pal_tv_usec / 1000); + *numberOfSocketsSet = 0; + + + // create semaphore if not initialized before - if it exists ensure count is 0. + if (0 == s_palSelectSemaphore) + { + int32_t counters = 0; + // create semaphore to wait until socket event happens (semaphore will be re-used and is only created once, and never freed - if terminate is added free this resoruce if allocaed) + // ugly workaround for the count == 0 issue in free RTOS, remove when issue fixed. + result = pal_osSemaphoreCreate(1, &s_palSelectSemaphore); // create semaphore to wait until socket event happens (semaphore will be re-used and is only created once, and never freed - if terminate is added free this resoruce if allocaed) + if (PAL_SUCCESS != result) + { + goto finish; + } + result = pal_osSemaphoreWait(s_palSelectSemaphore, 40000, &counters); + if (PAL_SUCCESS != result) + { + goto finish; + } + } + else { + int32_t counters = 0; + result = pal_osSemaphoreWait(s_palSelectSemaphore, 1, &counters); // deplete semaphore count until it is 0. + while ((result != PAL_ERR_RTOS_TIMEOUT) && (counters > 0)) + { + result = pal_osSemaphoreWait(s_palSelectSemaphore, 1, &counters); + } + if (PAL_ERR_RTOS_TIMEOUT != result) // make sure count is actually 0 + { + goto finish; + } + + } + + for (index = 0; index < numberOfSockets; index++) + { + struct netconn* conn = ((palLwipNetConnInfo_t*)socketsToCheck[index])->connection; + bool isNonBlocking = netconn_is_nonblocking(conn); + bool checkRecv = false; + err_t addrStatus = PAL_SUCCESS; + ip_addr_t netconIPAddr = {0}; + u16_t netconPort = 0; + // socket is TCP and connected or socket it UDP and has a remote address (sort of connected). + + if(NULL == conn->pcb.tcp) + { + result = translateErrnoToPALError(conn->last_err); + conn->last_err = 0; + return result; + } + + addrStatus = netconn_getaddr(conn, &netconIPAddr, &netconPort, 0); + + if ((NETCONN_UDP == conn->type) && (ERR_OK == addrStatus) && (netconIPAddr.addr != 0)) + { + checkRecv = true; + } + + if ((NETCONN_TCP == conn->type) && (conn->pcb.tcp != NULL) && (conn->pcb.tcp->state >= 4))//TCP state 4 and above is conn ESTABLISHED or connected + { + checkRecv = true; + } + + if (NULL != ((palLwipNetConnInfo_t*)socketsToCheck[index])->buffer) + { + countWithPriorData++; + palSocketStatus[index] |= PAL_NET_SOCKET_SELECT_RX_BIT | PAL_NET_SOCKET_SELECT_TX_BIT; + } + else if (true == checkRecv) + { + result = pal_plat_netconReceive(conn, &newBuf); + if ((ERR_OK == result) && (NULL != newBuf)) + { + ((palLwipNetConnInfo_t*)socketsToCheck[index])->buffer = newBuf; + ((palLwipNetConnInfo_t*)socketsToCheck[index])->offset = 0; + countWithPriorData++; + palSocketStatus[index] |= PAL_NET_SOCKET_SELECT_RX_BIT | PAL_NET_SOCKET_SELECT_TX_BIT; + } + else + { + countWithPriorData++; + palSocketStatus[index] |= PAL_NET_SOCKET_SELECT_TX_BIT; + } + + if (false == isNonBlocking) + { + netconn_set_nonblocking(conn, false); + } + } + } + + if (countWithPriorData > 0) // some sockets have data ready to read - no need to block just return value. + { + *numberOfSocketsSet = countWithPriorData; + return PAL_SUCCESS; + } + + for (index = 0; index < numberOfSockets; index++) + { + struct netconn* conn = ((palLwipNetConnInfo_t*)socketsToCheck[index])->connection; + s_select_state[index].selectStatus = 0; + s_select_state[index].connection = conn; + palSocketStatus[index] = 0; + conn->callback = palNetConSelectCallback; + } + result = pal_osSemaphoreWait(s_palSelectSemaphore, timeoutInMiliseconds, &counter); + if (result == PAL_SUCCESS) + { + for (index = 0; index < numberOfSockets; index++) + { + if (s_select_state[index].selectStatus > 0) // TODO: return a specific status, based on event. + { + palSocketStatus[index] |= PAL_NET_SOCKET_SELECT_RX_BIT | PAL_NET_SOCKET_SELECT_TX_BIT | PAL_NET_SOCKET_SELECT_ERR_BIT; + *numberOfSocketsSet = *numberOfSocketsSet + 1; + } + } + } + if (result == PAL_ERR_RTOS_TIMEOUT) // to socket callback has been called to free the semaphore -> no socket events happenet untill the timout. + { + *numberOfSocketsSet = 0; // TODO: add debug prints + result = PAL_SUCCESS; // timeout is not actually an error in this case + } + + for (index = 0; index < numberOfSockets; index++) + { + struct netconn* conn = ((palLwipNetConnInfo_t*)socketsToCheck[index])->connection; + conn->callback = NULL; +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + if ( NULL != ((palLwipNetConnInfo_t*)socketsToCheck[index])->callback) + { + conn->callback = palNetConAsyncCallback; + } +#endif + + } + +finish: + return result; +} +#if PAL_NET_TCP_AND_TLS_SUPPORT // functionality below supported only in case TCP is supported. + + +palStatus_t pal_plat_listen(palSocket_t socket, int backlog) +{ + palStatus_t result = PAL_SUCCESS; + struct netconn* conn = NULL; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + result = netconn_listen_with_backlog(conn, backlog); + if (ERR_OK != result ) + { + result = translateErrnoToPALError(result); + } + return result; +} + + +palStatus_t pal_plat_accept(palSocket_t socket, palSocketAddress_t * address, palSocketLength_t* addressLen, palSocket_t* acceptedSocket) +{ + palStatus_t result = PAL_SUCCESS; + struct netconn * new_conn = NULL; + ip_addr_t addr; + uint16_t port; + palLwipNetConnInfo_t* socketInfo = NULL; + uint32_t index = 0; + struct netconn* conn = NULL; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + + + + for (index = 0; index < MEMP_NUM_NETCONN; index++) // allocate socket info structure. + { + if (false == palInternalSocketInfo[index].inUse) + { + palInternalSocketInfo[index].inUse = true; + socketInfo = &palInternalSocketInfo[index]; + break; + } + } + if (NULL == socketInfo) + { + result = PAL_ERR_NO_MEMORY; + } + else + { + result = netconn_accept(conn, &new_conn); + if (ERR_OK != result) + { + palInternalSocketInfo[index].inUse = false; // free resource since accept failed + result = translateErrnoToPALError(result); + } + else + { + + socketInfo->connection = new_conn; + socketInfo->callback = NULL; + socketInfo->buffer = NULL; + *acceptedSocket = (palSocket_t)socketInfo; + + result = netconn_getaddr(new_conn, &addr, &port, 0); + if (ERR_OK != result) // failed to get peer address + { + result = translateErrnoToPALError(result); + } + else + { + result = pal_setSockAddrIPV4Addr(address, *((palIpV4Addr_t*)&(addr.addr))); + if (result == PAL_SUCCESS) + { + pal_setSockAddrPort(address, port); + if (result == PAL_SUCCESS) + { + *addressLen = PAL_IPV6_ADDRESS_SIZE; + } + } + } + } + } + return result; +} + + +palStatus_t pal_plat_connect(palSocket_t socket, const palSocketAddress_t* address, palSocketLength_t addressLen) +{ + int result = 0; + palIpV4Addr_t ipv4; + uint16_t port; + ip_addr_t netconn_address = {0}; + struct netconn* conn = NULL; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + + + if ((NETCONN_TCP == conn->type) && (conn->pcb.tcp != NULL)) // only TRY to connect if socket state is 0.(closed) + { + if ((conn->pcb.tcp->state >= 4))//TCP state 4 and above is conn ESTABLISHED or connected + { + result = PAL_ERR_SOCKET_ALREADY_CONNECTED; + } + else if (conn->pcb.tcp->state > 0)//TCP state 1 and above is connecting + { + result = PAL_ERR_SOCKET_IN_PROGRES; + } + else // socket is not connect or connecting - try to connect. + { + result = pal_getSockAddrIPV4Addr(address, ipv4); + if (PAL_SUCCESS != result) + return result; + result = pal_getSockAddrPort(address, &port); + if (PAL_SUCCESS != result) + return result; + netconn_address.addr = ipv4[0] | (ipv4[1] << 8) | (ipv4[2] << 16) | (ipv4[3] << 24); + + result = netconn_connect(conn, &netconn_address, port); + if (ERR_OK != result) // failed to get peer address + { + result = translateErrnoToPALError(result); + } + } + } +else +{ + result = PAL_ERR_INVALID_ARGUMENT; +} + + return result; +} + + + +palStatus_t pal_plat_recv(palSocket_t socket, void *buf, size_t len, size_t* recievedDataSize) +{ + int result = 0; + struct netbuf *newBuf = NULL; + palLwipNetConnInfo_t* socketInfo = (palLwipNetConnInfo_t*)socket; + size_t bufferSize = 0; + struct netconn* conn = NULL; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + + + if (NULL != socketInfo->buffer) // part of previous buffer not read yet. + { + uint32_t copied = netbuf_copy_partial(socketInfo->buffer, buf, (u16_t)len, socketInfo->offset); + socketInfo->offset += copied; + *recievedDataSize = copied; + } + else + { + result = pal_plat_netconReceive(conn, &newBuf); + if (ERR_OK != result) + { + return translateErrnoToPALError(result); + } + else + { + if (NULL != newBuf) + { + socketInfo->buffer = newBuf; + bufferSize = netbuf_len(newBuf); + + if (bufferSize <= len) + { + *recievedDataSize = bufferSize; + netbuf_copy(newBuf, buf, bufferSize); + socketInfo->offset = bufferSize; + } + else + { + *recievedDataSize = len; + netbuf_copy(newBuf, buf, len); + socketInfo->offset = len; + } + } + else + { + result = PAL_ERR_SOCKET_CONNECTION_CLOSED; + } + + } + } + if ((NULL != socketInfo->buffer) && (socketInfo->offset >= netbuf_len( socketInfo->buffer))) + { + netbuf_delete(socketInfo->buffer); + socketInfo->buffer = NULL; + socketInfo->offset = 0; + } + + return result; +} + + +palStatus_t pal_plat_send(palSocket_t socket, const void *buf, size_t len, size_t* sentDataSize) +{ + int result = 0; + size_t localSent; + size_t* actualSent = sentDataSize; + struct netconn* conn = NULL; + if (NULL == socket) // NULL is not a vlaid socket. + { + return PAL_ERR_INVALID_ARGUMENT; + } + conn = ((palLwipNetConnInfo_t*)socket)->connection; + + if (NULL == actualSent) + { + actualSent = &localSent; + } + + // netconn documentaiton (http://www.ece.ualberta.ca/~cmpe401/docs/lwip.pdf) says buffers over the size of the MTU should not be sent.since this is not always known 1000bytes is a good heuristic + if (len > PAL_MAX_SEND_BUFFER_SIZE) + { + return PAL_ERR_SOCKET_SEND_BUFFER_TOO_BIG; + } + result = netconn_write_partly(conn, buf, len, NETCONN_COPY, actualSent); + if (ERR_OK != result ) + { + result = translateErrnoToPALError(result); + } + else + { + *sentDataSize = len; + } + + return result; +} + +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + +palStatus_t pal_plat_asynchronousSocket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t callback, void* callbackArgument, palSocket_t* socket) +{ + + int result = PAL_SUCCESS; + uint32_t index = 0; + palLwipNetConnInfo_t* socketInfo = NULL; + if (domain != PAL_AF_INET) + return PAL_ERR_NOT_IMPLEMENTED; + enum netconn_type connType = NETCONN_INVALID; + if ((PAL_SOCK_STREAM == type) || (PAL_SOCK_STREAM_SERVER == type)) + { + connType = NETCONN_TCP; + } + else if (PAL_SOCK_DGRAM == type) + { + connType = NETCONN_UDP; + } + else + { + return PAL_ERR_INVALID_ARGUMENT; + } + + for (index = 0; index < MEMP_NUM_NETCONN; index++) // allocate socket info structure. + { + if (false == palInternalSocketInfo[index].inUse) + { + palInternalSocketInfo[index].inUse = true; + palInternalSocketInfo[index].connection = NULL; + palInternalSocketInfo[index].callback = callback; + palInternalSocketInfo[index].callbackArgument = callbackArgument; + socketInfo = &palInternalSocketInfo[index]; + break; + } + } + if (NULL == socketInfo) + { + result = PAL_ERR_NO_MEMORY; + } + + else + { + struct netconn * con = netconn_new_with_callback(connType, palNetConAsyncCallback); + if (NULL == con) + { + result = PAL_ERR_NO_MEMORY; + } + else + { + socketInfo->connection = con; + socketInfo->buffer = NULL; + // TODO(nirson01) : add binding to specific network interface (interfaceNum) + if (nonBlockingSocket) + { + netconn_set_nonblocking(con, 1); + } + *socket = (palSocket_t)socketInfo; + } + } + + + + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastrucature is finalized) +} + +#endif + + + +#if PAL_NET_DNS_SUPPORT + +palStatus_t pal_plat_getAddressInfo(const char *url, palSocketAddress_t *address, palSocketLength_t* length) +{ + + palStatus_t result = PAL_SUCCESS; + ip_addr_t addr = {0}; + + // placeholder: no real ip filderting for DNS is lwip 1.4.1 (should be implmeneted in lwip 2). +#if PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_ANY + result = netconn_gethostbyname(url, &addr); +#elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV4_ONLY + result = netconn_gethostbyname(url, &addr); +#elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV6_ONLY + #error ipv6 filter not supported for lwip 1.4.1 +#else +#error PAL_NET_DNS_IP_SUPPORT is not defined to a valid value. +#endif + + if (ERR_OK != result) + { + result = translateErrnoToPALError(result); + } + else + { + if (0 == addr.addr ) // invalid 0 address + { + result = PAL_ERR_SOCKET_DNS_ERROR; + } + else + { + result = pal_setSockAddrIPV4Addr(address, *(palIpV4Addr_t*)&addr); + if (PAL_SUCCESS == result) + { + result = pal_setSockAddrPort(address, 0); // we have no port fo the lookup - zero it to avoif mistakes. + *length = PAL_NET_MAX_ADDR_SIZE; + } + } + } + return result; + +} + +#endif + + + + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/RTOS/pal_plat_rtos.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/RTOS/pal_plat_rtos.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1147 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* PAL-RTOS porting for FreeRTOS-8.1.2 +* This is porting code for PAL RTOS APIS for +* FreeRTOS-8.1.2 version. +*/ + +#include "board.h" +#include "FreeRTOS.h" +#include "event_groups.h" +#include "semphr.h" +#include "task.h" + + +#include "pal_types.h" +#include "pal_rtos.h" +#include "pal_plat_rtos.h" +#include "pal_errors.h" +#include "stdlib.h" + + +#define PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(cmsisCode)\ + ((int32_t)(cmsisCode + PAL_ERR_RTOS_ERROR_BASE)) + +#define PAL_TICK_TO_MILLI_FACTOR 1000 + + +extern palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes); + +/////////////////////////STATIC FUNCTION/////////////////////////// +/*! Get IPSR Register +* +* @param[in] Void +* \returns uint32 - the content of the IPSR Register. +* +*/ +PAL_PRIVATE PAL_INLINE uint32_t pal_plat_GetIPSR(void); +/////////////////////////END STATIC FUNCTION/////////////////////////// + +typedef struct palThreadFuncWrapper{ + palTimerFuncPtr realThreadFunc; + void* realThreadArgs; + uint32_t threadIndex; +}palThreadFuncWrapper_t; + +//! Thread structure +typedef struct palThread{ + bool initialized; + bool running; + palThreadLocalStore_t* threadStore; //! please see pal_rtos.h for documentation + palThreadFuncWrapper_t threadFuncWrapper; + TaskHandle_t threadID; + uint32_t palThreadID; + EventGroupHandle_t eventGroup; + palThreadPriority_t priority; + bool taskCompleted; //The task has completed and exit +} palThread_t; + +PAL_PRIVATE palThread_t g_palThreads[PAL_MAX_NUMBER_OF_THREADS] = {0}; + +//! Timer structure +typedef struct palTimer{ + palTimerID_t timerID; + // uint32_t internalTimerData[PAL_TIMER_DATA_SIZE]; ///< pointer to internal data + TimerCallbackFunction_t function; + void* functionArgs; + uint32_t timerType; +} palTimer_t; + +//! Mutex structure +typedef struct palMutex{ + palMutexID_t mutexID; +}palMutex_t; + +//! Semaphore structure +typedef struct palSemaphore{ + palSemaphoreID_t semaphoreID; + uint32_t maxCount; +}palSemaphore_t; + +/*! Count number of created threads. Initiate to zero. +*/ +PAL_PRIVATE uint32_t g_threadCounter = 0; + +//! Message Queue structure +typedef struct palMessageQ{ + palMessageQID_t messageQID; +}palMessageQ_t; + +//! Memory Pool structure +typedef struct palMemoryPool +{ + void* start; + uint32_t blockCount; + uint32_t blockSize; + uint8_t* allocated; +} palMemoryPool_t; + + + +PAL_PRIVATE PAL_INLINE uint32_t pal_plat_GetIPSR(void) +{ + uint32_t result; + +#if defined (__CC_ARM) + __asm volatile + { + MRS result, ipsr + } +#elif defined (__GNUC__) + __asm volatile ("MRS %0, ipsr" : "=r" (result) ); +#endif + + return(result); +} + + + +inline PAL_PRIVATE void setDefaultThreadValues(palThread_t* thread) +{ +#if PAL_UNIQUE_THREAD_PRIORITY + g_palThreadPriorities[thread->priority + PRIORITY_INDEX_OFFSET] = 0; +#endif //PAL_UNIQUE_THREAD_PRIORITY + thread->threadStore = NULL; + thread->threadFuncWrapper.realThreadArgs = NULL; + thread->threadFuncWrapper.realThreadFunc = NULL; + thread->threadFuncWrapper.threadIndex = PAL_MAX_NUMBER_OF_THREADS; + thread->threadID = NULL; + thread->taskCompleted = false; + thread->palThreadID = 0; + //! This line should be last thing to be done in this function. + //! in order to prevent double accessing the same index between + //! this function and the threadCreate function. + thread->initialized = false; +} + +/*! Clean thread data from the global thread data base (g_palThreads). Thread Safe API + * + * @param[in] dbPointer: data base pointer. + * @param[in] index: the index in the data base to be cleaned. + */ +PAL_PRIVATE void threadCleanUp(void* dbPointer, uint32_t index) +{ + uint32_t status = PAL_SUCCESS; + palThread_t* threadsDB = (palThread_t*)dbPointer; + uint32_t threadIndex = PAL_GET_THREAD_INDEX(index); + + status = pal_osMutexWait(g_palThreadInitMutex, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS != status) + { + PAL_LOG(ERR,"thread cleanup: mutex wait failed!\n"); + } + else{ + if ((NULL != dbPointer) && (threadIndex < PAL_MAX_NUMBER_OF_THREADS) && (threadsDB[threadIndex].palThreadID == index)) + { + setDefaultThreadValues(&threadsDB[threadIndex]); + } + + status = pal_osMutexRelease(g_palThreadInitMutex); + if (PAL_SUCCESS != status) + { + PAL_LOG(ERR,"thread cleanup: mutex release failed!\n"); + } + } + return; +} + +/*! Thread wrapper function, this function will be set as the thread function (for every thread) + * and it will get as an argument the real data about the thread and call the REAL thread function + * with the REAL argument. Once the REAL thread function finished, \ref pal_threadClean() will be called. + * + * @param[in] arg: data structure which contains the real data about the thread. + */ +PAL_PRIVATE void threadFunctionWrapper(void const* arg) +{ + palThreadFuncWrapper_t* threadWrapper = (palThreadFuncWrapper_t*)arg; + + if (NULL != threadWrapper) + { + if(g_palThreads[threadWrapper->threadIndex].threadID == NULLPTR) + { + g_palThreads[threadWrapper->threadIndex].threadID = xTaskGetCurrentTaskHandle(); + } + + threadWrapper->realThreadFunc(threadWrapper->realThreadArgs); + g_palThreads[threadWrapper->threadIndex].taskCompleted = true; + threadCleanUp(g_palThreads, g_palThreads[threadWrapper->threadIndex].palThreadID); + } + + vTaskDelete( NULL ); +} + + +palStatus_t pal_plat_RTOSInitialize(void* opaqueContext) +{ + palStatus_t status = PAL_SUCCESS; + + //Clean thread tables + memset(g_palThreads,0,sizeof(palThread_t) * PAL_MAX_NUMBER_OF_THREADS); + + //Add implicit the running task as PAL main + g_palThreads[0].initialized = true; + g_palThreads[0].threadID = xTaskGetCurrentTaskHandle(); + + pal_osAtomicIncrement((int32_t*)&g_threadCounter,1); + //palThreadID = 24 bits for thread counter + lower 8 bits for thread index (= 0). + g_palThreads[0].palThreadID = (g_threadCounter << 8 ); + + return status; +} + +palStatus_t pal_plat_RTOSDestroy(void) +{ + return PAL_SUCCESS; +} + +palStatus_t pal_plat_osDelay(uint32_t milliseconds) +{ + vTaskDelay(milliseconds / portTICK_PERIOD_MS); + return PAL_SUCCESS; +} + + +uint64_t pal_plat_osKernelSysTick() +{ + + uint64_t result; + if (pal_plat_GetIPSR() != 0) + { + result = xTaskGetTickCountFromISR(); + } + else + { + result = xTaskGetTickCount(); + } + return result; +} + +uint64_t pal_plat_osKernelSysTickMicroSec(uint64_t microseconds) +{ + uint64_t sysTicks = microseconds * configTICK_RATE_HZ / (PAL_TICK_TO_MILLI_FACTOR * PAL_TICK_TO_MILLI_FACTOR); + return sysTicks; +} + +uint64_t pal_plat_osKernelSysTickFrequency() +{ + return configTICK_RATE_HZ; +} + +palStatus_t pal_plat_osThreadCreate(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, + uint32_t stackSize, uint32_t* stackPtr, palThreadLocalStore_t* store, + palThreadID_t* threadID) +{ + palStatus_t status = PAL_SUCCESS; + BaseType_t res; + uint32_t firstAvailableThreadIndex = PAL_MAX_NUMBER_OF_THREADS; + uint32_t i; + TaskHandle_t osThreadID = NULL; + uint32_t localPalThreadID = 0; + + if((NULL == threadID) || (NULL == function) || (priority > PAL_osPriorityRealtime) || (0 == stackSize)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_osMutexWait(g_palThreadInitMutex, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS == status) + { + for (i = 0; i < PAL_MAX_NUMBER_OF_THREADS; ++i) + { + if (!g_palThreads[i].initialized) + { + g_palThreads[i].initialized = true; + firstAvailableThreadIndex = i; + break; + } + } + + if (firstAvailableThreadIndex >= PAL_MAX_NUMBER_OF_THREADS) + { + status = PAL_ERR_RTOS_RESOURCE; + } + if (PAL_SUCCESS != status) + { + // release mutex if error. + status = pal_osMutexRelease(g_palThreadInitMutex); + } + else + { + g_palThreads[firstAvailableThreadIndex].threadStore = store; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadArgs = funcArgument; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadFunc = function; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.threadIndex = firstAvailableThreadIndex; + g_palThreads[firstAvailableThreadIndex].initialized = true; + g_palThreads[firstAvailableThreadIndex].priority = priority; + g_palThreads[firstAvailableThreadIndex].palThreadID = ((firstAvailableThreadIndex)+((pal_osAtomicIncrement((int32_t*)&g_threadCounter, 1)) << 8)); //palThreadID = 24 bits for thread counter + lower 8 bits for thread index. + localPalThreadID = g_palThreads[firstAvailableThreadIndex].palThreadID; + + // release mutex before thread creation . + status = pal_osMutexRelease(g_palThreadInitMutex); + + if (PAL_SUCCESS == status) + { + //Note: the stack in this API handled as an array of "StackType_t" which can be in different sized for different ports. + // in this specific port of (8.1.2) the "StackType_t" is defined to 4-bytes this is why we divided the "stackSize" parameter on "sizeof(uint32_t)". + // inside freeRTOS code, the size calculated according to this formula: "( size_t ) usStackDepth ) * sizeof( StackType_t )" where "usStackDepth" is + // equal to "stackSize / sizeof(uint32_t)". + res = xTaskGenericCreate((TaskFunction_t)threadFunctionWrapper, + "palTask", + stackSize / sizeof(uint32_t), + &g_palThreads[firstAvailableThreadIndex].threadFuncWrapper, + priority + PRIORITY_INDEX_OFFSET, + &osThreadID, + NULL, //if Stack pointer NULL then allocate stack according to stack size + NULL); + + + if(pdPASS == res) + { + *threadID = localPalThreadID; + g_palThreads[firstAvailableThreadIndex].threadID = osThreadID; + } + else + { + //! in case of error in the thread creation, reset the data of the given index in the threads array. + threadCleanUp(g_palThreads, localPalThreadID); + *threadID = PAL_INVALID_THREAD; + PAL_LOG(ERR, "Rtos thread create failure"); + status = PAL_ERR_GENERIC_FAILURE; + } + } + } + } + return status; +} + +palThreadID_t pal_plat_osThreadGetId(void) +{ + int i = 0; + TaskHandle_t osThreadID =xTaskGetCurrentTaskHandle(); + palThreadID_t ret = PAL_INVALID_THREAD; + + for(i= 0; i < PAL_MAX_NUMBER_OF_THREADS; i++) + { + if(osThreadID == g_palThreads[i].threadID) + { + ret = i; + break; + } + } + return ret; +} + +palStatus_t pal_plat_osThreadTerminate(palThreadID_t* threadID) +{ + palStatus_t status = PAL_SUCCESS; + uint32_t threadIndex = PAL_GET_THREAD_INDEX(*threadID); + + if ((PAL_INVALID_THREAD == *threadID) || (threadIndex >= PAL_MAX_NUMBER_OF_THREADS)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + // if thread exited or was terminated already return success. + if ((g_palThreads[threadIndex].palThreadID == 0) || // thread already exited + (g_palThreads[threadIndex].palThreadID != *threadID) || // thread already exited and a new thread was created at the same index. + (g_palThreads[threadIndex].threadID == (TaskHandle_t)PAL_INVALID_THREAD)) // thread was terminated. + { + return status; + } + + if((xTaskGetCurrentTaskHandle() != g_palThreads[threadIndex].threadID)) + {//Kill only if not trying to kill from running task + if (g_palThreads[threadIndex].initialized) + { + if ((g_palThreads[threadIndex].threadID != NULL) && ( g_palThreads[threadIndex].taskCompleted == false)) + { + vTaskDelete(g_palThreads[threadIndex].threadID); + } + threadCleanUp(g_palThreads, *threadID); + } + *threadID = PAL_INVALID_THREAD; + } + else + { + status = PAL_ERR_RTOS_TASK; + } + + return status; +} + +palThreadLocalStore_t* pal_plat_osThreadGetLocalStore(void) +{ + palThreadLocalStore_t* localStore = NULL; + palThreadID_t id = (uintptr_t)pal_osThreadGetId(); + + if( g_palThreads[id].initialized) + { + localStore = g_palThreads[id].threadStore; + } + return localStore; +} + + +PAL_PRIVATE palTimer_t* s_timerArrays[PAL_MAX_NUM_OF_TIMERS] = {0}; + +PAL_PRIVATE void pal_plat_osTimerWarpperFunction( TimerHandle_t xTimer ) +{ + int i; + palTimer_t* timer = NULL; + for(i=0 ; i< PAL_MAX_NUM_OF_TIMERS ; i++) + { + if (s_timerArrays[i]->timerID == (palTimerID_t)xTimer) + { + timer = s_timerArrays[i]; + timer->function(timer->functionArgs); + + } + } +} + +palStatus_t pal_plat_osTimerCreate(palTimerFuncPtr function, void* funcArgument, palTimerType_t timerType, palTimerID_t* timerID) +{ + palStatus_t status = PAL_SUCCESS; + palTimer_t* timer = NULL; + int i; + if(NULL == timerID || NULL == function) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)malloc(sizeof(palTimer_t)); + + if (NULL == timer) + { + status = PAL_ERR_NO_MEMORY; + } + else + { + memset(timer,0,sizeof(palTimer_t)); + } + + if (PAL_SUCCESS == status) + { + for (i=0; i< PAL_MAX_NUM_OF_TIMERS; i++) + { + if (s_timerArrays[i] == NULL) + { + s_timerArrays[i] = timer; + break; + } + } + if (PAL_MAX_NUM_OF_TIMERS == i) + { + status = PAL_ERR_NO_MEMORY; + } + if (PAL_SUCCESS == status) + { + timer->function = (TimerCallbackFunction_t)function; + timer->functionArgs = funcArgument; + timer->timerType = timerType; + + timer->timerID = (palTimerID_t)xTimerCreate( + "timer", + 1, // xTimerPeriod - cannot be '0' + (const TickType_t)timerType, // 0 = osTimerOnce, 1 = osTimerPeriodic + NULL, + (TimerCallbackFunction_t)pal_plat_osTimerWarpperFunction + ); + } + if (NULLPTR == timer->timerID) + { + free(timer); + timer = NULLPTR; + PAL_LOG(ERR, "Rtos timer create failure"); + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *timerID = (palTimerID_t)timer; + } + } + return status; +} + +palStatus_t pal_plat_osTimerStart(palTimerID_t timerID, uint32_t millisec) +{ + palStatus_t status = PAL_SUCCESS; + palTimer_t* timer = NULL; + + if (NULLPTR == timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)timerID; + + if (pal_plat_GetIPSR() != 0) + { + BaseType_t pxHigherPriorityTaskWoken; + status = xTimerChangePeriodFromISR( + (TimerHandle_t)(timer->timerID), + (millisec / portTICK_PERIOD_MS), + &pxHigherPriorityTaskWoken + ); + } + else + { + status = xTimerChangePeriod((TimerHandle_t)(timer->timerID), (millisec / portTICK_PERIOD_MS), 0); + } + + if (pdPASS != status) + { + status = PAL_ERR_RTOS_PARAMETER; + } + if (pdPASS == status) + { + if (pal_plat_GetIPSR() != 0) + { + BaseType_t pxHigherPriorityTaskWoken; + status = xTimerStartFromISR((TimerHandle_t)(timer->timerID), &pxHigherPriorityTaskWoken); + } + else + { + status = xTimerStart((TimerHandle_t)(timer->timerID), 0); + } + + if (pdPASS != status) + { + status = PAL_ERR_RTOS_PARAMETER; + } + else + { + status = PAL_SUCCESS; + } + } + return status; +} + +palStatus_t pal_plat_osTimerStop(palTimerID_t timerID) +{ + palStatus_t status = PAL_SUCCESS; + palTimer_t* timer = NULL; + + if(NULLPTR == timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)timerID; + + if (pal_plat_GetIPSR() != 0) + { + BaseType_t pxHigherPriorityTaskWoken; + status = xTimerStopFromISR((TimerHandle_t)(timer->timerID), &pxHigherPriorityTaskWoken); + } + else + { + status = xTimerStop((TimerHandle_t)(timer->timerID), 0); + } + + + if (pdPASS != status) + { + status = PAL_ERR_RTOS_PARAMETER; + } + else + { + status = PAL_SUCCESS; + } + return status; +} + +palStatus_t pal_plat_osTimerDelete(palTimerID_t* timerID) +{ + palStatus_t status = PAL_ERR_RTOS_PARAMETER; + palTimer_t* timer = NULL; + int i; + + if(NULL == timerID || NULLPTR == *timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)*timerID; + + if (timer->timerID) + { + for(i=0 ; i< PAL_MAX_NUM_OF_TIMERS ; i++) + { + if (s_timerArrays[i] == timer) + { + status = xTimerDelete((TimerHandle_t)(timer->timerID), 0); + free(timer); + s_timerArrays[i] = NULL; + *timerID = NULLPTR; + break; + } + } + + if (pdPASS == status) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_ERR_RTOS_PARAMETER; + } + } + else + { + status = PAL_ERR_RTOS_PARAMETER; + } + + return status; +} + + +palStatus_t pal_plat_osMutexCreate(palMutexID_t* mutexID) +{ + + palStatus_t status = PAL_SUCCESS; + palMutex_t* mutex = NULL; + if(NULL == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)malloc(sizeof(palMutex_t)); + if (NULL == mutex) + { + status = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == status) + { + + mutex->mutexID = (uintptr_t) xSemaphoreCreateRecursiveMutex(); + if (NULLPTR == mutex->mutexID) + { + free(mutex); + mutex = NULL; + PAL_LOG(ERR, "Rtos mutex create failure"); + status = PAL_ERR_GENERIC_FAILURE; + } + *mutexID = (palMutexID_t)mutex; + } + return status; +} + + +palStatus_t pal_plat_osMutexWait(palMutexID_t mutexID, uint32_t millisec) +{ + + palStatus_t status = PAL_SUCCESS; + palMutex_t* mutex = NULL; + BaseType_t res = pdTRUE; + + if(NULLPTR == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)mutexID; + if (pal_plat_GetIPSR() != 0) + { + BaseType_t pxHigherPriorityTaskWoken; + res = xSemaphoreTakeFromISR(mutex->mutexID, &pxHigherPriorityTaskWoken); + } + else + { + res = xSemaphoreTakeRecursive((QueueHandle_t)(mutex->mutexID), (millisec / portTICK_PERIOD_MS) ); + } + + if (pdTRUE == res) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_ERR_RTOS_TIMEOUT; + } + + return status; +} + + +palStatus_t pal_plat_osMutexRelease(palMutexID_t mutexID) +{ + palStatus_t status = PAL_SUCCESS; + palMutex_t* mutex = NULL; + BaseType_t res = pdTRUE; + + if(NULLPTR == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)mutexID; + if (pal_plat_GetIPSR() != 0) + { + BaseType_t pxHigherPriorityTaskWoken; + res = xSemaphoreGiveFromISR(mutex->mutexID, &pxHigherPriorityTaskWoken); + } + else + { + res = xSemaphoreGiveRecursive((QueueHandle_t)(mutex->mutexID)); + } + + if (pdTRUE == res) + { + status = PAL_SUCCESS; + } + else + { + PAL_LOG(ERR, "Rtos mutex release failure %d", res); + status = PAL_ERR_GENERIC_FAILURE; + } + return status; +} + +palStatus_t pal_plat_osMutexDelete(palMutexID_t* mutexID) +{ + palStatus_t status = PAL_SUCCESS; + palMutex_t* mutex = NULL; + + if(NULL == mutexID || NULLPTR == *mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)*mutexID; + if (NULLPTR != mutex->mutexID) + { + vSemaphoreDelete(mutex->mutexID); + free(mutex); + *mutexID = NULLPTR; + status = PAL_SUCCESS; + } + else + { + PAL_LOG(ERR, "Rtos mutex delete failure"); + status = PAL_ERR_GENERIC_FAILURE; + } + return status; +} + +palStatus_t pal_plat_osSemaphoreCreate(uint32_t count, palSemaphoreID_t* semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + palSemaphore_t* semaphore = NULL; + + if(NULL == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)malloc(sizeof(palSemaphore_t)); + if (NULL == semaphore) + { + status = PAL_ERR_NO_MEMORY; + } + + if(PAL_SUCCESS == status) + { + semaphore->semaphoreID = (uintptr_t)xSemaphoreCreateCounting(PAL_SEMAPHORE_MAX_COUNT, count); + semaphore->maxCount = PAL_SEMAPHORE_MAX_COUNT; + if (NULLPTR == semaphore->semaphoreID) + { + free(semaphore); + semaphore = NULLPTR; + PAL_LOG(ERR, "Rtos semaphore create error"); + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *semaphoreID = (palSemaphoreID_t)semaphore; + } + } + return status; +} + +palStatus_t pal_plat_osSemaphoreWait(palSemaphoreID_t semaphoreID, uint32_t millisec, int32_t* countersAvailable) +{ + palStatus_t status = PAL_SUCCESS; + palSemaphore_t* semaphore = NULL; + int32_t tmpCounters = 0; + BaseType_t res = pdTRUE; + + if(NULLPTR == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)semaphoreID; + if (pal_plat_GetIPSR() != 0) + { + BaseType_t pxHigherPriorityTaskWoken; + res = xSemaphoreTakeFromISR(semaphore->semaphoreID, &pxHigherPriorityTaskWoken); + } + else + { + if (millisec == PAL_RTOS_WAIT_FOREVER) + { + res = xSemaphoreTake(semaphore->semaphoreID, portMAX_DELAY); + } + else + { + res = xSemaphoreTake(semaphore->semaphoreID, millisec / portTICK_PERIOD_MS); + } + } + + if (pdTRUE == res) + { + + tmpCounters = uxQueueMessagesWaiting((QueueHandle_t)(semaphore->semaphoreID)); + } + else + { + tmpCounters = 0; + status = PAL_ERR_RTOS_TIMEOUT; + } + + if (NULL != countersAvailable) + { + //because mbedOS returns the number available BEFORE the current take, we have to add 1 here. + *countersAvailable = tmpCounters; + } + return status; +} + +palStatus_t pal_plat_osSemaphoreRelease(palSemaphoreID_t semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + palSemaphore_t* semaphore = NULL; + BaseType_t res = pdTRUE; + int32_t tmpCounters = 0; + + if(NULLPTR == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)semaphoreID; + + tmpCounters = uxQueueMessagesWaiting((QueueHandle_t)(semaphore->semaphoreID)); + + if(tmpCounters < semaphore->maxCount) + { + if (pal_plat_GetIPSR() != 0) + { + BaseType_t pxHigherPriorityTaskWoken; + res = xSemaphoreGiveFromISR(semaphore->semaphoreID, &pxHigherPriorityTaskWoken); + } + else + { + res = xSemaphoreGive(semaphore->semaphoreID); + } + + if (pdTRUE != res) + { + status = PAL_ERR_RTOS_PARAMETER; + } + } + else + { + status = PAL_ERR_RTOS_RESOURCE; + } + + return status; +} + +palStatus_t pal_plat_osSemaphoreDelete(palSemaphoreID_t* semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + palSemaphore_t* semaphore = NULL; + + if(NULL == semaphoreID || NULLPTR == *semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)*semaphoreID; + if (NULLPTR != semaphore->semaphoreID) + { + vSemaphoreDelete(semaphore->semaphoreID); + free(semaphore); + *semaphoreID = NULLPTR; + status = PAL_SUCCESS; + } + else + { + PAL_LOG(ERR, "Rtos semaphore destroy error"); + status = PAL_ERR_GENERIC_FAILURE; + } + return status; +} + +palStatus_t pal_plat_osPoolCreate(uint32_t blockSize, uint32_t blockCount, palMemoryPoolID_t* memoryPoolID) +{ + palStatus_t status = PAL_SUCCESS; + palMemoryPool_t* mp = NULL; + + if (NULL == memoryPoolID || 0 == blockSize || 0 == blockCount) { + return PAL_ERR_INVALID_ARGUMENT; + } + + mp = (palMemoryPool_t*)malloc(sizeof(palMemoryPool_t)); + if (NULL == mp) + { + status = PAL_ERR_RTOS_NO_MEMORY; + } + + if(PAL_SUCCESS == status) + { + mp->start = malloc(blockCount * blockSize); + if (NULL == mp->start) + { + free(mp); + status = PAL_ERR_RTOS_NO_MEMORY; + } + + if (PAL_SUCCESS == status) + { + mp->blockCount = blockCount; + mp->blockSize = blockSize; + + mp->allocated = (uint8_t*) malloc(blockCount * sizeof(uint8_t)); + if (NULL == mp->allocated) + { + free(mp->start); + free(mp); + status = PAL_ERR_RTOS_NO_MEMORY; + } + else + { + for (uint32_t i = 0; i < blockCount; i++) + { + mp->allocated[i] = false; + } + *memoryPoolID = (palMemoryPoolID_t) mp; + } + } + } + return status; +} + +PAL_PRIVATE void* poolAlloc(palMemoryPoolID_t memoryPoolID, uint8_t zero) +{ + palMemoryPool_t* mp = NULL; + void* result = NULL; + if (NULLPTR == memoryPoolID) + { + return NULL; + } + mp = (palMemoryPool_t*) memoryPoolID; + + for (uint32_t i = 0; i < mp->blockCount; i++) + { + if (false == mp->allocated[i]) + { + mp->allocated[i] = true; + result = (void *)( (uintptr_t)(mp->start) + (uintptr_t)(i * mp->blockSize) ); + if (zero == true) + { + memset(result, 0, mp->blockSize); + } + break; + } + } + //we didn't find any + return result; +} + +void* pal_plat_osPoolAlloc(palMemoryPoolID_t memoryPoolID) +{ + return poolAlloc(memoryPoolID, false); +} + +void* pal_plat_osPoolCAlloc(palMemoryPoolID_t memoryPoolID) +{ + return poolAlloc(memoryPoolID, true); +} + +palStatus_t pal_plat_osPoolFree(palMemoryPoolID_t memoryPoolID, void* block) +{ + palMemoryPool_t* mp = (palMemoryPool_t*)memoryPoolID;; + + if ( (NULL == mp) || + (NULL == block) || + (mp->start > block) || + ( ( (uintptr_t)(mp->start) + (uintptr_t)(mp->blockCount * mp->blockSize) ) < (uintptr_t)block ) || + (0 != ( ( (uintptr_t)block - (uintptr_t)(mp->start) ) % mp->blockSize) ) ) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + int index = (int)( ( (uintptr_t)block - (uintptr_t)(mp->start) ) / mp->blockSize ); + mp->allocated[index] = false; + return PAL_SUCCESS; +} + +palStatus_t pal_plat_osPoolDestroy(palMemoryPoolID_t* memoryPoolID) +{ + if (NULL == memoryPoolID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + palMemoryPool_t* mp = (palMemoryPool_t*)*memoryPoolID; + free(mp->start); + free(mp->allocated); + free(mp); + *memoryPoolID = (palMemoryPoolID_t)NULL; // don't let anyone use it anymore. + return PAL_SUCCESS; +} + +palStatus_t pal_plat_osMessageQueueCreate(uint32_t messageQSize, palMessageQID_t* messageQID) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t* messageQ = NULL; + if(NULL == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)malloc(sizeof(palMessageQ_t)); + if (NULL == messageQ) + { + status = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == status) + { + + messageQ->messageQID = (uintptr_t)xQueueCreate(messageQSize, sizeof(uint32_t)); + if (NULLPTR == messageQ->messageQID) + { + free(messageQ); + messageQ = NULLPTR; + PAL_LOG(ERR, "Rtos message queue create failure"); + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *messageQID = (palMessageQID_t)messageQ; + } + } + return status; +} + +palStatus_t pal_plat_osMessagePut(palMessageQID_t messageQID, uint32_t info, uint32_t timeout) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t* messageQ = NULL; + BaseType_t res = pdTRUE; + + if(NULLPTR == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)messageQID; + res = xQueueSend( (QueueHandle_t)(messageQ->messageQID), &info, timeout ); + if (pdTRUE != res) + { + status = PAL_ERR_RTOS_RESOURCE; + } + return status; +} + +palStatus_t pal_plat_osMessageGet(palMessageQID_t messageQID, uint32_t timeout, uint32_t* messageValue) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t* messageQ = NULL; + BaseType_t res = pdTRUE; + + if(NULLPTR == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)messageQID; + res = xQueueReceive( (QueueHandle_t)(messageQ->messageQID), messageValue, timeout ); + if ((messageValue != NULL) && (pdTRUE == res)) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_ERR_RTOS_TIMEOUT; + } + + return status; + +} + +palStatus_t pal_plat_osMessageQueueDestroy(palMessageQID_t* messageQID) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t* messageQ = NULL; + + if(NULL == messageQID || NULLPTR == *messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)*messageQID; + vQueueDelete( (QueueHandle_t)(messageQ->messageQID) ); + free(messageQ); + *messageQID = NULLPTR; + return status; +} + + +void *pal_plat_malloc(size_t len) +{ + return malloc(len); +} + + +void pal_plat_free(void * buffer) +{ + free(buffer); +} + + +palStatus_t pal_plat_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes) +{ + palStatus_t status = PAL_SUCCESS; + + status = pal_plat_getRandomBufferFromHW(randomBuf, sizeof(randomBuf)); + return status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Storage/FileSystem/pal_plat_fileSystem.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Storage/FileSystem/pal_plat_fileSystem.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,709 @@ +#include "pal.h" +#include "pal_plat_fileSystem.h" +#include "pal_plat_rtos.h" + + +#if defined(__GNUC__) && !defined(__CC_ARM) +#include <sys/stat.h> +#include <sys/types.h> +#endif // defined(__GNUC__) && !defined(__CC_ARM) +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "fsl_mpu.h" +#include "ff.h" +#include "diskio.h" +#include "sdhc_config.h" + + +#define CHK_FD_VALIDITY(x) ((FIL *)x)->fs->id != ((FIL *)x)->id +#define PAL_FS_ALIGNMENT_TO_SIZE 4 //!< This Size control the number of bytes written to the file (bug fix for writing unaligned memory to file) +#define PAL_FS_COPY_BUFFER_SIZE 256 //!< Size of the chunk to copy files +PAL_PRIVATE BYTE g_platOpenModeConvert[] = +{ + 0, + FA_READ | FA_OPEN_EXISTING, //"r" + FA_WRITE | FA_READ| FA_OPEN_EXISTING, //"r+" + FA_WRITE | FA_READ| FA_CREATE_NEW, //"w+x" + FA_WRITE | FA_READ| FA_CREATE_ALWAYS //"w+" +}; //!< platform convert table for \b fopen() modes + + +/*! \brief This function find the next file in a directory + * + * @param[in] *dh - Directory handler to an open DIR + * @param[out] CurrentEntry - entry for the file found in Directory (pre allocated) + * + * \return true - upon successful operation.\n + * + */ +PAL_PRIVATE bool pal_plat_findNextFile(DIR *dh, FILINFO * CurrentEntry); + +/*! \brief This function translate the platform errors opcode to pal error codes + * + * @param[in] errorOpCode - platform opcode to be translated + * + * \return PAL_SUCCESS upon successful operation.\n + */ +PAL_PRIVATE palStatus_t pal_plat_errorTranslation (int errorOpCode); + +/*! \brief This function build the full path name by adding the filename to the working path given in pathName arg + * + * @param[in] *pathName - pointer to the null-terminated string that specifies the directory name. + * @param[in] *fileName - pointer to the file name + * @param[out] *fullPath - pointer to the full path including the filename (pre allocated) + * + * \return PAL_SUCCESS upon successful operation.\n + * PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t + * + */ +PAL_PRIVATE palStatus_t pal_plat_addFileNameToPath(const char *pathName, const char * fileName, char * fullPath); + +/*! \brief This function copy one file from source folder to destination folder + * + * @param[in] pathNameSrc - Pointer to a null-terminated string that specifies the source dir. + * @param[in] pathNameDest - Pointer to a null-terminated string that specifies the destination dir + * @param[in] fileName - pointer the the file name + * + * \return PAL_SUCCESS upon successful operation.\n + * PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t + * + * \note File should not be open.\n + * If the Destination file exist then it shall be truncated + * + */ +PAL_PRIVATE palStatus_t pal_plat_fsCpFile(const char *pathNameSrc, char *pathNameDest, char * fileName); + +palStatus_t pal_plat_fsMkdir(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + FRESULT status = FR_OK; + status = f_mkdir(pathName); + if (status != FR_OK) + { + ret = pal_plat_errorTranslation(status); + } + return ret; +} + + +palStatus_t pal_plat_fsRmdir(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + FRESULT status = FR_OK; + + status = f_unlink(pathName); + if (status != FR_OK) + { + if ( status == FR_DENIED) + { + ret = PAL_ERR_FS_DIR_NOT_EMPTY; + } + else if (status == FR_NO_FILE) + { + ret = PAL_ERR_FS_NO_PATH; + } + else + { + ret = pal_plat_errorTranslation(status); + } + } + + return ret; +} + + +palStatus_t pal_plat_fsFopen(const char *pathName, pal_fsFileMode_t mode, palFileDescriptor_t *fd) +{ + palStatus_t ret = PAL_SUCCESS; + FRESULT status = FR_OK; + FIL * descriptor = NULL; + + descriptor = (FIL *)pal_plat_malloc(sizeof(FIL)); + if (descriptor) + { + *fd = (palFileDescriptor_t)descriptor; + status = f_open((FIL*)*fd, pathName, g_platOpenModeConvert[mode]); + if (FR_OK != status) + { + pal_plat_free(descriptor); + if(FR_NO_PATH == status) + { + ret = PAL_ERR_FS_NO_FILE; + } + else + { + ret = pal_plat_errorTranslation(status); + } + } + } + + return ret; +} + + +palStatus_t pal_plat_fsFclose(palFileDescriptor_t *fd) +{ + FRESULT status = FR_OK; + palStatus_t ret = PAL_SUCCESS; + + + if (CHK_FD_VALIDITY(*fd)) + {//Bad File Descriptor + ret = PAL_ERR_FS_BAD_FD; + return ret; + } + + status = f_close((FIL *)*fd); + if (FR_OK != status) + { + ret = pal_plat_errorTranslation(status); + } + else + { + pal_plat_free((void*)*fd); + } + return ret; +} + + +palStatus_t pal_plat_fsFread(palFileDescriptor_t *fd, void * buffer, size_t numOfBytes, size_t *numberOfBytesRead) +{ + palStatus_t ret = PAL_SUCCESS; + FRESULT status = FR_OK; + uint8_t readaligment[PAL_FS_ALIGNMENT_TO_SIZE] = { 0 }; + uint32_t index = 0; + size_t byteRead = 0; + uint8_t leftover = 0; + + if (CHK_FD_VALIDITY(*fd)) + {//Bad File Descriptor + ret = PAL_ERR_FS_BAD_FD; + return ret; + } + + leftover = numOfBytes % PAL_FS_ALIGNMENT_TO_SIZE; + for(index = 0; index < (numOfBytes / PAL_FS_ALIGNMENT_TO_SIZE); index++) + { + status = f_read((FIL *)*fd, readaligment, PAL_FS_ALIGNMENT_TO_SIZE, &byteRead); + if (FR_OK != status) + { + ret = pal_plat_errorTranslation(status); + break; + } + else + { + memcpy(&((uint8_t *)buffer)[*numberOfBytesRead], readaligment, PAL_FS_ALIGNMENT_TO_SIZE); + *numberOfBytesRead += byteRead; + } + } + + if ((ret == PAL_SUCCESS) && (leftover > 0)) + { + status = f_read((FIL *)*fd, readaligment, PAL_FS_ALIGNMENT_TO_SIZE, &byteRead); + if (FR_OK != status) + { + ret = pal_plat_errorTranslation(status); + } + else + { + memcpy(&((uint8_t *)buffer)[*numberOfBytesRead], readaligment, leftover); + *numberOfBytesRead += leftover; + ret = pal_fsFseek(fd, leftover - PAL_FS_ALIGNMENT_TO_SIZE ,PAL_FS_OFFSET_SEEKCUR); + } + } + + return ret; +} + + +palStatus_t pal_plat_fsFwrite(palFileDescriptor_t *fd, const void *buffer, size_t numOfBytes, size_t *numberOfBytesWritten) +{ + palStatus_t ret = PAL_SUCCESS; + FRESULT status = FR_OK; + uint32_t index = 0; + size_t bytesWritten = 0; + uint8_t leftover = 0; + + if (CHK_FD_VALIDITY(*fd)) + {//Bad File Descriptor + ret = PAL_ERR_FS_BAD_FD; + return ret; + } + + leftover = numOfBytes % PAL_FS_ALIGNMENT_TO_SIZE; + for (index = 0; index < (numOfBytes / PAL_FS_ALIGNMENT_TO_SIZE); index++) + { + status = f_write((FIL *)*fd, ((uint8_t *)buffer + *numberOfBytesWritten), PAL_FS_ALIGNMENT_TO_SIZE, &bytesWritten); + if (FR_OK != status) + { + ret = pal_plat_errorTranslation(status); + break; + } + else if (PAL_FS_ALIGNMENT_TO_SIZE != bytesWritten) + { + ret = PAL_ERR_FS_INSUFFICIENT_SPACE; + } + else + { + *numberOfBytesWritten += bytesWritten; + } + } + + if ((ret == PAL_SUCCESS) && (leftover > 0)) + { + status = f_write((FIL *)*fd, ((uint8_t *)buffer + *numberOfBytesWritten), leftover, &bytesWritten); + if (FR_OK != status) + { + ret = pal_plat_errorTranslation(status); + } + else if (leftover != bytesWritten) + { + ret = PAL_ERR_FS_INSUFFICIENT_SPACE; + } + else + { + *numberOfBytesWritten += bytesWritten; + } + } + + return ret; +} + + +palStatus_t pal_plat_fsFseek(palFileDescriptor_t *fd, int32_t offset, pal_fsOffset_t whence) +{ + palStatus_t ret = PAL_SUCCESS; + FRESULT status = FR_OK; + uint32_t fatFSOffset = 0; + + if (CHK_FD_VALIDITY(*fd)) + {//Bad File Descriptor + ret = PAL_ERR_FS_BAD_FD; + return ret; + } + + + switch(whence) + { + case PAL_FS_OFFSET_SEEKCUR: + if (((-1)*offset > f_tell((FIL*)*fd) && (offset < 0)) || (offset > f_tell((FIL*)*fd) && (offset > 0))) + { + ret = PAL_ERR_FS_ERROR; + } + else + { + fatFSOffset = f_tell((FIL*)*fd) + offset; + } + break; + + case PAL_FS_OFFSET_SEEKEND: + if ((-1)*offset > f_size((FIL*)*fd) || (offset > 0)) + { + ret = PAL_ERR_FS_ERROR; + } + else + { + fatFSOffset = f_size((FIL*)*fd) + offset; + } + break; + + case PAL_FS_OFFSET_SEEKSET: + if (offset > f_size((FIL*)*fd)) + { + ret = PAL_ERR_FS_ERROR; + } + else + { + fatFSOffset = offset; + } + break; + + default: + fatFSOffset = 0; + break; + } + + if (ret == PAL_SUCCESS) + { + status = f_lseek ((FIL *)*fd, fatFSOffset); + if (FR_OK != status) + { + ret = pal_plat_errorTranslation(status); + } + } + return ret; +} + + +palStatus_t pal_plat_fsFtell(palFileDescriptor_t *fd, int32_t * pos) +{ + palStatus_t ret = PAL_SUCCESS; + + if (CHK_FD_VALIDITY(*fd)) + {//Bad File Descriptor + ret = PAL_ERR_FS_BAD_FD; + } + else + { + *pos = f_tell((FIL*)*fd); + } + return ret; +} + + +palStatus_t pal_plat_fsUnlink(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + FRESULT status = FR_OK; + + status = f_unlink(pathName); + if (status != FR_OK) + { + if (status == FR_DENIED) + { + ret = PAL_ERR_FS_DIR_NOT_EMPTY; + } + else + { + ret = pal_plat_errorTranslation(status); + } + } + return ret; +} + + +palStatus_t pal_plat_fsRmFiles(const char *pathName) +{ + DIR dh; //Directory handler + palStatus_t ret = PAL_SUCCESS; + FRESULT status = FR_OK; + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; //Buffer for coping the name and folder + FILINFO currentEntry = { 0 }; //file Entry + + status = f_opendir(&dh, pathName); + if (status != FR_OK) + { + ret = pal_plat_errorTranslation(status); + } + + if (ret == PAL_SUCCESS) + { + while(true) + { + if (!pal_plat_findNextFile(&dh, ¤tEntry)) + { + ret = PAL_ERR_FS_ERROR_IN_SEARCHING; + break; + } + pal_plat_addFileNameToPath(pathName, currentEntry.fname, buffer); + if (currentEntry.fname[0] != '\0') + { + if (currentEntry.fattrib & AM_DIR) + { + ret = pal_fsRmFiles(buffer); + if (ret != PAL_SUCCESS) + { + break; + } + ret = pal_fsRmDir(buffer); + if (PAL_SUCCESS != ret) + { + break; + } + } + else + { + status = f_unlink (buffer); + if (status != FR_OK) + { + ret = pal_plat_errorTranslation(status); + break; + } + } + } + else + {//End of directory reached without errors break, close directory and exit + break; + } + }//while() + + status = f_closedir (&dh); //Close DIR handler + if (status != FR_OK) + { + ret = pal_plat_errorTranslation(status); + } + } + + return ret; +} + + +palStatus_t pal_plat_fsCpFolder(const char *pathNameSrc, char *pathNameDest) +{ + DIR src_dh; //Directory for the source Directory handler + palStatus_t ret = PAL_SUCCESS; + FILINFO currentEntry = { 0 }; //file Entry + FRESULT status = FR_OK; + + + status = f_opendir(&src_dh, pathNameSrc); + if (status != FR_OK) + { + ret = pal_plat_errorTranslation(status); + } + + + if (ret == PAL_SUCCESS) + { + while(true) + { + if (!pal_plat_findNextFile(&src_dh, ¤tEntry)) + { + ret = PAL_ERR_FS_ERROR_IN_SEARCHING; + break; + } + if (currentEntry.fname[0] != 0) + { + if (currentEntry.fattrib & AM_DIR) // skip all folder as this is flat copy only + { + continue; + } + //copy the file to the destination + ret = pal_plat_fsCpFile(pathNameSrc, pathNameDest, currentEntry.fname); + if (ret != PAL_SUCCESS) + { + break; + } + } + else + {//End of directory reached without errors break and close directory and exit + break; + } + }//while() + f_closedir(&src_dh); + } + + return ret; +} + + +PAL_PRIVATE palStatus_t pal_plat_fsCpFile(const char *pathNameSrc, char *pathNameDest, char * fileName) +{ + palStatus_t ret = PAL_SUCCESS; + FIL src_fd, dst_fd; + char * buffer = NULL; + char buffer_name[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; //Buffer for coping the name and folder + size_t bytesCount = 0; + FRESULT status = FR_OK; + + //Add file name to path + pal_plat_addFileNameToPath(pathNameSrc, fileName, buffer_name); + status = f_open(&src_fd, buffer_name, g_platOpenModeConvert[PAL_FS_FLAG_READONLY]); + if (status != FR_OK) + { + ret = pal_plat_errorTranslation(status); + } + else + { + //Add file name to path + pal_plat_addFileNameToPath(pathNameDest, fileName, buffer_name); + status = f_open(&dst_fd, buffer_name, g_platOpenModeConvert[PAL_FS_FLAG_READWRITETRUNC]); + if (status != FR_OK) + { + ret = pal_plat_errorTranslation(status); + } + else + { + buffer = (char*)pal_plat_malloc(PAL_FS_COPY_BUFFER_SIZE); + if (!buffer) + { + ret = PAL_ERR_RTOS_RESOURCE; + } + } + } + + if (ret == PAL_SUCCESS) + { + while (1) + { + status = f_read(&src_fd, buffer, PAL_FS_COPY_BUFFER_SIZE, &bytesCount); + + if (status != FR_OK) + { + break; + } + + //Check if end of file reached + if (bytesCount == 0) + { + break; + } + + status = f_write(&dst_fd, buffer, bytesCount, &bytesCount); + if (status != FR_OK) + { + break; + } + } + if (status != FR_OK) + { + ret = pal_plat_errorTranslation(status); + } + } + + + + f_close(&src_fd); + f_close(&dst_fd); + if (buffer) + { + pal_plat_free(buffer); + } + return ret; +} + +const char* pal_plat_fsGetDefaultRootFolder(pal_fsStorageID_t dataID) +{ + const char* returnedRoot = NULL; + if (PAL_FS_PARTITION_PRIMARY == dataID) + { + returnedRoot = PAL_FS_MOUNT_POINT_PRIMARY; + } + else if (PAL_FS_PARTITION_SECONDARY == dataID) + { + returnedRoot = PAL_FS_MOUNT_POINT_SECONDARY; + } + return returnedRoot; +} + + +PAL_PRIVATE bool pal_plat_findNextFile(DIR *dh, FILINFO *CurrentEntry) +{ + bool ret = true; + bool skip = false; + bool foundFile = false; + FRESULT status; + + do + { + status = f_readdir(dh, CurrentEntry); + if (status == FR_OK) + { + if ((CurrentEntry)->fname[0] == 0) + {//End Of Directory + ret = true; + break; + } + + /* Skip the names "." and ".." as we don't want to remove them. also make sure that the current entry point to REGULER file*/ + skip = (!strcmp((CurrentEntry)->fname, ".")) || (!strcmp((CurrentEntry)->fname, "..")); + if (skip) + { + continue; + } + else + { + foundFile = true; + } + } + else + {//NOT!!! EOF other error + ret = false; + break; //Break from while + } + } + while((!foundFile) && (ret)); //While file has been found or ret is set to false + return ret; +} + +PAL_PRIVATE palStatus_t pal_plat_addFileNameToPath(const char *pathName, const char * fileName, char * fullPath) +{ + palStatus_t ret = PAL_SUCCESS; + + if ((strlen(pathName) >= PAL_MAX_FOLDER_DEPTH_CHAR) || (strlen(fileName) >= PAL_MAX_FULL_FILE_NAME)) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else if (fullPath) + { + strcpy(fullPath, pathName); + strcat(fullPath, "/"); + strcat(fullPath, fileName); + } + else + { + ret = PAL_ERR_RTOS_RESOURCE; + } + return ret; +} + + +PAL_PRIVATE palStatus_t pal_plat_errorTranslation (int errorOpCode) +{ + palStatus_t ret = PAL_SUCCESS; + + switch(errorOpCode) + { + case 0: + break; + case FR_DENIED: + case FR_WRITE_PROTECTED: + case FR_LOCKED: + ret = PAL_ERR_FS_ACCESS_DENIED; + break; + + case FR_NOT_READY : + ret = PAL_ERR_FS_BUSY; + break; + + case FR_EXIST: + ret = PAL_ERR_FS_NAME_ALREADY_EXIST; + break; + + case FR_INVALID_NAME: + case FR_INVALID_OBJECT: + case FR_INVALID_DRIVE: + ret = PAL_ERR_FS_INVALID_ARGUMENT; + break; + + case FR_NO_FILE: + ret = PAL_ERR_FS_NO_FILE; + break; + + case FR_NO_PATH: + ret = PAL_ERR_FS_NO_PATH; + break; + + default: + ret = PAL_ERR_FS_ERROR; + break; + } + return ret; +} + + +size_t pal_plat_fsSizeCheck(const char *stringToChk) +{ + size_t length = 0; + length = strlen(stringToChk); + return length; +} + + + +palStatus_t pal_plat_fsFormat(pal_fsStorageID_t dataID) +{ + const char* partitionNames[] ={ + PAL_FS_MOUNT_POINT_PRIMARY, + PAL_FS_MOUNT_POINT_SECONDARY + }; + palStatus_t result = PAL_SUCCESS; + const char* partName = partitionNames[dataID]; + FRESULT res = f_mkfs(partName, 0, 0); + if (FR_OK != res) + { + result = PAL_ERR_FS_ERROR; + } + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Storage/Flash/pal_plat_internalFlash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Storage/Flash/pal_plat_internalFlash.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,133 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "pal_plat_internalFlash.h" +#include "fsl_flash.h" + +////////////////////////////PRIVATE/////////////////////////////////// +PAL_PRIVATE flash_config_t g_flashDescriptor = {0}; +PAL_PRIVATE bool pal_isAlignedToSector(uint32_t address, size_t size); +////////////////////////////END PRIVATE//////////////////////////////// + +palStatus_t pal_plat_internalFlashInit(void) +{ + status_t status; + palStatus_t ret = PAL_SUCCESS; + status = FLASH_Init(&g_flashDescriptor); + if(kStatus_FLASH_Success != status) + { + ret = PAL_ERR_INTERNAL_FLASH_INIT_ERROR; + } + return ret; +} + + +palStatus_t pal_plat_internalFlashDeInit(void) +{ + memset(&g_flashDescriptor, 0, sizeof(g_flashDescriptor)); + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_internalFlashWrite(const size_t size, const uint32_t address, const uint32_t * buffer) +{ + palStatus_t ret = PAL_SUCCESS; + status_t status = kStatus_Success; + uint32_t page_size = pal_internalFlashGetPageSize(); + + if ((size % page_size) != 0) + { + return PAL_ERR_INTERNAL_FLASH_BUFFER_SIZE_NOT_ALIGNED; + } + else + { + /* We need to prevent flash accesses during program operation */ + __disable_irq(); + status = FLASH_Program(&g_flashDescriptor, address, (uint32_t *)buffer, size); + if (kStatus_Success == status) + { + // Must use kFlashMargin_User, or kFlashMargin_Factory for verify program + status = FLASH_VerifyProgram(&g_flashDescriptor, address, size, (uint32_t *)buffer, kFLASH_marginValueUser, NULL, NULL); + if(kStatus_Success != status) + { + ret = PAL_ERR_INTERNAL_FLASH_WRITE_ERROR; + } + } + __enable_irq(); + } + return ret; +} + +palStatus_t pal_plat_internalFlashRead(const size_t size, const uint32_t address, uint32_t * buffer) +{ + memcpy(buffer, (const void *)address, size); + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_internalFlashErase(uint32_t address, size_t size) +{ + palStatus_t ret = PAL_SUCCESS; + int16_t status = kStatus_Success; + + if(!pal_isAlignedToSector(address,size)) + { + return PAL_ERR_INTERNAL_FLASH_SECTOR_NOT_ALIGNED; //not aligned to sector + } + + __disable_irq(); + status = FLASH_Erase(&g_flashDescriptor, address, pal_plat_internalFlashGetSectorSize(address), kFLASH_apiEraseKey); + if (kStatus_Success == status) + { + status = FLASH_VerifyErase(&g_flashDescriptor, address, pal_plat_internalFlashGetSectorSize(address), kFLASH_marginValueNormal); + } + + if (kStatus_Success != status) + { + ret = PAL_ERR_INTERNAL_FLASH_ERASE_ERROR; + } + __enable_irq(); + return ret; +} + + +size_t pal_plat_internalFlashGetPageSize(void) +{ + return FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE; +} + + +size_t pal_plat_internalFlashGetSectorSize(uint32_t address) +{ + size_t devicesize = 0; + FLASH_GetProperty(&g_flashDescriptor, kFLASH_propertyPflashSectorSize, (uint32_t*)&devicesize); + return devicesize; +} + +PAL_PRIVATE bool pal_isAlignedToSector(uint32_t address, size_t size) +{ + uint32_t currentSectorSize = pal_plat_internalFlashGetSectorSize(address); + if ((size % currentSectorSize) || (address % currentSectorSize)) + { + return false; + } + else + { + return true; + } +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Update/pal_plat_update.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/FreeRTOS/Update/pal_plat_update.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,300 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal_rtos.h" +#include "pal_plat_update.h" + +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" +#include "board.h" +#include "clock_config.h" +#include "fsl_flash.h" + + + + +#define PAL_UPDATE_JOURNAL_SIZE 0x80000UL +#define PAL_UPDATE_JOURNAL_START_OFFSET 0x80000UL + +#if (!defined(PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET)) +#define PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET 0x80000UL +#endif + +#define SIZEOF_SHA256 256/8 +#define FIRMWARE_HEADER_MAGIC 0x5a51b3d4UL +#define FIRMWARE_HEADER_VERSION 1 + +PAL_PRIVATE FirmwareHeader_t g_palFirmwareHeader; +PAL_PRIVATE bool g_headerWasWritten = false; + +PAL_PRIVATE flash_config_t g_flashDriver; + + +/* + * call back functions + * + */ + +PAL_PRIVATE palImageSignalEvent_t g_palUpdateServiceCBfunc; + +/* + * WARNING: please do not change this function! + * this function loads a call back function received from the upper layer (service). + * the call back should be called at the end of each function (except pal_plat_imageGetDirectMemAccess) + * the call back receives the event type that just happened defined by the ENUM palImageEvents_t. + * + * if you will not call the call back at the end the service behaver will be undefined + */ +palStatus_t pal_plat_imageInitAPI(palImageSignalEvent_t CBfunction) +{ + if (!CBfunction) + { + return PAL_ERR_INVALID_ARGUMENT; + } + g_palUpdateServiceCBfunc = CBfunction; + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_INIT); + + return PAL_SUCCESS; +} + +palStatus_t pal_plat_imageDeInit(void) +{ + palStatus_t status = PAL_SUCCESS; + return status; +} + + +palStatus_t pal_plat_imageGetMaxNumberOfImages(uint8_t *imageNumber) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageSetVersion(palImageId_t imageId, const palConstBuffer_t* version) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageGetDirectMemAccess(palImageId_t imageId, void** imagePtr, size_t *imageSizeInBytes) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageActivate(palImageId_t imageId) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + + +palStatus_t pal_plat_imageGetActiveHash(palBuffer_t *hash) +{ + + return PAL_ERR_NOT_IMPLEMENTED; +} + +//Retrieve the version of the active image to version buffer with size set to version bufferLength. +palStatus_t pal_plat_imageGetActiveVersion (palBuffer_t* version) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +//Writing the value of active image hash stored in hashValue to memory +palStatus_t pal_plat_imageWriteHashToMemory(const palConstBuffer_t* const hashValue) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + + +/* + * init apis + */ + + + +//fill the image header data for writing, the writing will occur in the 1st image write +palStatus_t pal_plat_imageSetHeader(palImageId_t imageId,palImageHeaderDeails_t *details) +{ + DEBUG_PRINT(">>%s\r\n",__FUNCTION__); + palStatus_t status = PAL_SUCCESS; + g_headerWasWritten = false; // set that the image was not written yet + memset(&g_palFirmwareHeader,0,sizeof(g_palFirmwareHeader)); + g_palFirmwareHeader.totalSize = details->imageSize + sizeof(FirmwareHeader_t); + g_palFirmwareHeader.magic = FIRMWARE_HEADER_MAGIC; + g_palFirmwareHeader.version = FIRMWARE_HEADER_VERSION; + g_palFirmwareHeader.firmwareVersion = details->version; + + memcpy(g_palFirmwareHeader.firmwareSHA256,details->hash.buffer,SIZEOF_SHA256); + /* + * calculating and setting the checksum of the header. + * Have to call to crcInit before use. + */ + // crcInit(); + // g_palFirmwareHeader.checksum = crcFast((const unsigned char *)&g_palFirmwareHeader, (int)sizeof(g_palFirmwareHeader)); + DEBUG_PRINT("<<%s\r\n",__FUNCTION__); + return status; +} + + + +palStatus_t pal_plat_imageReserveSpace(palImageId_t imageId, size_t imageSize) +{ + DEBUG_PRINT(">>%s imageId = %d imageSize=%d\r\n",__FUNCTION__, imageId, imageSize); + status_t result = PAL_SUCCESS; + memset(&g_flashDriver, 0, sizeof(g_flashDriver)); + result = FLASH_Init(&g_flashDriver); + DEBUG_PRINT("FLASH_Init return %d\r\n",result); + if (kStatus_FLASH_Success != result) + { + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_ERROR); + return PAL_ERR_UPDATE_ERROR; + } + + result = FLASH_Erase(&g_flashDriver, PAL_UPDATE_JOURNAL_START_OFFSET, imageSize, kFLASH_apiEraseKey); + DEBUG_PRINT("FLASH_Erase return %d\r\n",result); + if (kStatus_FLASH_Success != result) + { + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_ERROR); + return PAL_ERR_UPDATE_ERROR; + } + + result = FLASH_VerifyErase(&g_flashDriver, PAL_UPDATE_JOURNAL_START_OFFSET, imageSize, kFLASH_marginValueUser); + DEBUG_PRINT("FLASH_VerifyErase return %d\r\n",result); + if (kStatus_FLASH_Success != result) + { + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_ERROR); + return PAL_ERR_UPDATE_ERROR; + } + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_PREPARE); + DEBUG_PRINT("<<%s\r\n",__FUNCTION__); + + return PAL_SUCCESS; +} + + + + + +/* + * write API + */ + + + + + +palStatus_t pal_plat_imageWrite(palImageId_t imageId, size_t offset, palConstBuffer_t *chunk) +{ + status_t result = PAL_SUCCESS; + uint32_t failAddr, failDat; + DEBUG_PRINT(">>%s\r\n",__FUNCTION__); + DEBUG_PRINT("Param values offset=%d, bufferLength=%d\r\n",offset,chunk->bufferLength); + //if header was not written - write header + if (!g_headerWasWritten) + { + result = FLASH_Program( + &g_flashDriver, + PAL_UPDATE_JOURNAL_START_OFFSET, + (uint32_t *)(&g_palFirmwareHeader), + sizeof(g_palFirmwareHeader) + ); + DEBUG_PRINT("FLASH_Program return %d\r\n", result); + if (kStatus_FLASH_Success != result) + { + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_ERROR); + return PAL_ERR_UPDATE_ERROR; + } + g_headerWasWritten = true; + } + result = FLASH_Program( + &g_flashDriver, + (PAL_UPDATE_JOURNAL_START_OFFSET + sizeof(g_palFirmwareHeader) + offset), + (uint32_t *)(chunk->buffer), + chunk->bufferLength + ); + DEBUG_PRINT("FLASH_Program return %d\r\n",result); + if (kStatus_FLASH_Success != result) + { + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_ERROR); + return PAL_ERR_UPDATE_ERROR; + } + + /* Program Check user margin levels */ + result = FLASH_VerifyProgram( + &g_flashDriver, + (PAL_UPDATE_JOURNAL_START_OFFSET + sizeof(g_palFirmwareHeader) + offset), + chunk->bufferLength, + (const uint32_t *)(chunk->buffer), + kFLASH_marginValueUser, + &failAddr, + &failDat + ); + DEBUG_PRINT("FLASH_VerifyProgram return %d\r\n",result); + if (kStatus_FLASH_Success != result) + { + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_ERROR); + return PAL_ERR_UPDATE_ERROR; + } + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_WRITE); + DEBUG_PRINT("<<%s\r\n",__FUNCTION__); + return PAL_SUCCESS; +} + + +/* + * read APIs + */ + + + + +palStatus_t pal_plat_imageReadToBuffer(palImageId_t imageId, size_t offset, palBuffer_t *chunk) +{ + uint32_t imageSize = g_palFirmwareHeader.totalSize - sizeof(g_palFirmwareHeader); //totalSize - headerSize + DEBUG_PRINT(">>%s\r\n",__FUNCTION__); + DEBUG_PRINT("Param values chunk->buffer=%p, &g_flashDriver=%p\r\n",chunk->buffer, &g_flashDriver); + DEBUG_PRINT(" chunk->maxBufferLength=%d, offset=%d\r\n",chunk->maxBufferLength, offset); + DEBUG_PRINT(" imageSize=%d\r\n",imageSize); + if ((offset + chunk->maxBufferLength) <= imageSize) + { + DEBUG_PRINT("(offset + chunk->maxBufferLength) = %d imageSize = %d\r\n", (offset + chunk->maxBufferLength) ,imageSize); + chunk->bufferLength = chunk->maxBufferLength; + } + else + { + DEBUG_PRINT(" chunk->maxBufferLength) = %d imageSize = %d offset=%d\r\n", (offset + chunk->maxBufferLength) ,imageSize, offset); + chunk->bufferLength =chunk->maxBufferLength + imageSize - offset; + } + DEBUG_PRINT("Coping %d byets\r\n", chunk->bufferLength); + memcpy(chunk->buffer, (void*)(PAL_UPDATE_JOURNAL_START_OFFSET + sizeof(g_palFirmwareHeader) + offset) , chunk->bufferLength); + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_READTOBUFFER); + DEBUG_PRINT("<<%s\r\n",__FUNCTION__); + return PAL_SUCCESS; +} + + + +/* + * commit functions + * */ + + + +palStatus_t pal_plat_imageFlush(palImageId_t package_id) +{ + DEBUG_PRINT(">>%s\r\n",__FUNCTION__); + g_palUpdateServiceCBfunc(PAL_IMAGE_EVENT_FINALIZE); + DEBUG_PRINT("<<%s\r\n",__FUNCTION__); + return PAL_SUCCESS; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Board_Specific/TARGET_OpenWRT_Generic/pal_plat_OpenWRT_Generic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Board_Specific/TARGET_OpenWRT_Generic/pal_plat_OpenWRT_Generic.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pal_plat_rtos.h" +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> // needed to FILE operations +#include <stdlib.h> +#include <string.h> + + +#define TRACE_GROUP "PAL" + + +palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes) +{ + palStatus_t status = PAL_SUCCESS; + FILE *fp; + size_t actualRead = 0; + + fp = fopen("/dev/hwrng", "r"); + if (NULL != fp) + { + actualRead = fread(randomBuf, 1, bufSizeBytes, fp); + if (actualRead != bufSizeBytes) + { + status = PAL_ERR_RTOS_TRNG_FAILED; + } + fclose(fp); + } + else + { + status = PAL_ERR_FS_NO_FILE; + } + return status; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Board_Specific/TARGET_Yocto_Generic/pal_plat_Yocto_Generic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Board_Specific/TARGET_Yocto_Generic/pal_plat_Yocto_Generic.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pal_plat_rtos.h" +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> // needed to FILE operations +#include <stdlib.h> +#include <string.h> + + +#define TRACE_GROUP "PAL" + +palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes) +{ + palStatus_t status = PAL_SUCCESS; + FILE *fp; + size_t actualRead = 0; + + fp = fopen("/dev/hwrng", "r"); + if (NULL != fp) + { + actualRead = fread(randomBuf, 1, bufSizeBytes, fp); + if (actualRead != bufSizeBytes) + { + status = PAL_ERR_RTOS_TRNG_FAILED; + } + fclose(fp); + } + else + { + status = PAL_ERR_FS_NO_FILE; + } + return status; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Board_Specific/TARGET_x86_x64/pal_plat_x86_x64.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Board_Specific/TARGET_x86_x64/pal_plat_x86_x64.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pal_plat_rtos.h" +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> + +palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes) +{ + palStatus_t status = PAL_SUCCESS; + FILE *fp; + size_t actualRead = 0; + + fp = fopen("/dev/random", "r"); + if (NULL != fp) + { + actualRead = fread(randomBuf, 1, bufSizeBytes, fp); + if (actualRead != bufSizeBytes) + { + status = PAL_ERR_RTOS_TRNG_FAILED; + } + fclose(fp); + } + else + { + status = PAL_ERR_FS_NO_FILE; + } + return status; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Networking/pal_plat_network.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Networking/pal_plat_network.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1275 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#define _GNU_SOURCE // This is for ppoll found in poll.h +#include "pal.h" +#include "pal_plat_network.h" +#include "pal_rtos.h" + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <netdb.h> +#include <ifaddrs.h> +#include <errno.h> +#if PAL_NET_ASYNCHRONOUS_SOCKET_API +#include <pthread.h> +#include <poll.h> +#include <signal.h> +#include <fcntl.h> +#include <time.h> +#include <assert.h> +#endif + +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT +#include <netinet/tcp.h> +#endif + +// invalid socket based on posix +#define PAL_LINUX_INVALID_SOCKET (-1) + + +typedef struct palNetInterfaceName{ + char interfaceName[PAL_NET_MAX_IF_NAME_LENGTH]; +} palNetInterfaceName_t; + +PAL_PRIVATE palNetInterfaceName_t s_palNetworkInterfacesSupported[PAL_MAX_SUPORTED_NET_INTERFACES]; + +PAL_PRIVATE uint32_t s_palNumOfInterfaces = 0; +PAL_PRIVATE uint32_t s_pal_network_initialized = 0; + +PAL_PRIVATE palStatus_t translateErrorToPALError(int errnoValue) +{ + palStatus_t status; + switch (errnoValue) + { + case EAI_MEMORY: + status = PAL_ERR_NO_MEMORY; + break; + case EWOULDBLOCK: + status = PAL_ERR_SOCKET_WOULD_BLOCK; + break; + case ENOTSOCK: + status = PAL_ERR_SOCKET_INVALID_VALUE; + break; + case EPERM: + case EACCES: + status = PAL_ERR_SOCKET_OPERATION_NOT_PERMITTED; + break; + case ETIMEDOUT: + status = PAL_ERR_TIMEOUT_EXPIRED; + break; + case EISCONN: + status = PAL_ERR_SOCKET_ALREADY_CONNECTED; + break; + case EINPROGRESS: + status = PAL_ERR_SOCKET_IN_PROGRES; + break; + case EALREADY: + status = PAL_ERR_SOCKET_ALREADY_CONNECTED; + break; + case EINVAL: + status = PAL_ERR_SOCKET_INVALID_VALUE; + break; + case EADDRINUSE: + status = PAL_ERR_SOCKET_ADDRESS_IN_USE; + break; + case ECONNABORTED: + status = PAL_ERR_SOCKET_CONNECTION_ABORTED; + break; + case ENOBUFS: + case ENOMEM: + status = PAL_ERR_SOCKET_NO_BUFFERS; + break; + case EINTR: + status = PAL_ERR_SOCKET_INTERRUPTED; + break; + default: + status = PAL_ERR_SOCKET_GENERIC; + break; + } + return status; +} + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API +static pthread_t s_pollThread; +static palMutexID_t s_mutexSocketCallbacks = 0; +static palMutexID_t s_mutexSocketEventFilter = 0; +static palSemaphoreID_t s_socketCallbackSemaphore = 0; +static palSemaphoreID_t s_socketCallbackSignalSemaphore = 0; + + + +// These must be updated only when protected by s_mutexSocketCallbacks +static palAsyncSocketCallback_t s_callbacks[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0}; +static void* s_callbackArgs[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = { 0 }; +static struct pollfd s_fds[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {{0,0,0}}; +static uint32_t s_callbackFilter[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0}; +static nfds_t s_nfds = 0; + +// The below function is the signal handler API, doing nothing. +// The idea is to signal the asyncSocketManager thread with pthread_kill(s_pollThread, SIGUSR1) command +// which make the ppoll API to be interrupted. + +static uint64_t s_palUSR1Counter =0; +static void sigusr2(int signo) { + (void)signo; + s_palUSR1Counter++; + pal_osSemaphoreRelease(s_socketCallbackSignalSemaphore); +} + +static uint64_t s_palIOCounter =0; + +static void sig_io_handler(int signo) { + (void)signo; + + s_palIOCounter++; + pal_osSemaphoreRelease(s_socketCallbackSignalSemaphore); +} + + +static const unsigned int PAL_SOCKETS_TERMINATE = 10000; + + +PAL_PRIVATE void clearSocketFilter( int socketFD) +{ + palStatus_t result = PAL_SUCCESS; + int i = 0; + result = pal_osMutexWait(s_mutexSocketEventFilter, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS != result) + { + PAL_LOG(ERR, "error waiting for mutex"); // we want to zero the flag even if this fails beacuse it is better to get an extra event than miss one. + } + for (i = 0; i < PAL_NET_TEST_MAX_ASYNC_SOCKETS; i++) + { + + if (s_fds[i].fd == socketFD) + { + s_callbackFilter[i] = 0; + break; + } + } + result = pal_osMutexRelease(s_mutexSocketEventFilter); + if (PAL_SUCCESS != result) + { + PAL_LOG(ERR, "error releasing mutex"); + } +} + + +// Thread function. +static void* asyncSocketManager(void *arg) +{ + PAL_UNUSED_ARG(arg); // unused + int res; + palAsyncSocketCallback_t callbacks[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0}; + void* callbackArgs[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {0}; + struct pollfd fds[PAL_NET_TEST_MAX_ASYNC_SOCKETS] = {{0,0,0}}; + nfds_t nfds = 0; + struct sigaction s; + palStatus_t result = PAL_SUCCESS; + uint64_t lastIOCounter=0; + uint64_t lastUSRCounter=0; + + const struct timespec timeout_zero = {0, 0}; + + // Initialize the signal handler. SIG_IGN and SIG_DFL do not work + s.sa_handler = sigusr2; + sigemptyset(&s.sa_mask); + s.sa_flags = 0; + sigaction(SIGUSR1, &s, NULL); + + s.sa_handler = sig_io_handler; + sigemptyset(&s.sa_mask); + s.sa_flags = SA_RESTART ; + sigaction(SIGIO, &s, NULL); + + // Tell the calling thread that we have finished initialization + result = pal_osSemaphoreRelease(s_socketCallbackSemaphore); + if (result != PAL_SUCCESS) + { + PAL_LOG(ERR, "Error in async socket manager on semaphore release"); + } + + + while (result == PAL_SUCCESS) //As long as all goes well loop forever + { + // block until a SIGIO signal is received + if (lastUSRCounter == s_palUSR1Counter) // no updates to the sockets that need to be polled (wait for next IO) - if there were updates skip waiting and proceeed to poll + { + pal_osSemaphoreWait(s_socketCallbackSignalSemaphore, PAL_RTOS_WAIT_FOREVER, NULL); + } + + // Critical section to update globals + result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS != result) + { + PAL_LOG(ERR, "Error in async socket manager on mutex wait"); + break; + } + + // Check for thread termination request + if(s_nfds == PAL_SOCKETS_TERMINATE) + { + result = pal_osMutexRelease(s_mutexSocketCallbacks); + if (result != PAL_SUCCESS) + { + PAL_LOG(ERR, "Error in async socket manager on mutex release during termination"); + } + s_nfds = 0; // Reset s_ndfs + // Break out of while(1) + break; + } + // Update the list of sockets to watch from the global list + nfds = s_nfds; + if(nfds) + { + memcpy(callbacks, s_callbacks, nfds*sizeof(callbacks[0])); + memcpy(callbackArgs, s_callbackArgs, nfds * sizeof(void*)); + memcpy(fds, s_fds, nfds*sizeof(fds[0])); + + for (int i=0; i < nfds; i++) + { + fds[i].events = POLLIN|POLLOUT|POLLRDHUP|POLLERR; + fds[i].revents = 0; + s_callbackFilter[i] = 0; + } + } + result = pal_osMutexRelease(s_mutexSocketCallbacks); + if (result != PAL_SUCCESS) + { + PAL_LOG(ERR, "Error in async socket manager on mutex release"); + break; + } + + // Wait for a socket event or pthread_kill(s_pollThread, SIGUSR1) event + lastUSRCounter = s_palUSR1Counter; + res = ppoll(&fds[0], nfds, &timeout_zero, &s.sa_mask); + + + // Notes: + // If a POLLIN event occurred and recv from the socket results in 0 bytes being read, it means that + // the remote socket was closed. Unless this is dealt with in the callback (for example by closing the + // socket) the next call to ppoll will also immediately return with the same result. + if(res >0 || errno == EINTR) + { + unsigned int i; + errno = 0; + // Some event was triggered, so iterate over all watched fds's and call the relevant callbacks. + if (lastIOCounter< s_palIOCounter) + { + lastIOCounter = s_palIOCounter; + for( i = 0; i < nfds; i++) + { + if(fds[i].revents) + { + uint32_t filter = POLLOUT|POLLHUP; // filter for specific event that is triggered for non-connected sockets- this event combination shouldn't exist in an active socket. + + + if ((fds[i].revents != filter) && ((fds[i].revents != POLLOUT) || (fds[i].revents != s_callbackFilter[i])) ) // this is handlign for a special scenario when a specific event which shouldnt happen is sent to all unconnected sockets in Linux triggering an unwanted callback. + { + callbacks[i](callbackArgs[i]); + } + result = pal_osMutexWait(s_mutexSocketEventFilter, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS != result) + { + PAL_LOG(ERR, "error waiting for mutex"); + } + else + { + s_callbackFilter[i] = fds[i].revents; + result = pal_osMutexRelease(s_mutexSocketEventFilter); + if (PAL_SUCCESS != result) + { + PAL_LOG(ERR, "error releasing mutex"); + } + } + + + } + } + } + + + } + else if (res == 0) + { + // Timeout + } + else + { + PAL_LOG(ERR, "Error in async socket manager"); + } + } // while + + return NULL; +} +#endif // PAL_NET_ASYNCHRONOUS_SOCKET_API + +PAL_PRIVATE palStatus_t pal_plat_SockAddrToSocketAddress(const palSocketAddress_t* palAddr, struct sockaddr* output) +{ + palStatus_t result = PAL_SUCCESS; + uint16_t port = 0; + + result = pal_getSockAddrPort(palAddr, &port); + if (result != PAL_SUCCESS) + { + return result; + } + + if (PAL_AF_INET == palAddr->addressType) + { + palIpV4Addr_t ipV4Addr = {0}; + struct sockaddr_in* ip4addr = (struct sockaddr_in*)output; + ip4addr->sin_family = AF_INET; + ip4addr->sin_port = PAL_HTONS(port); + result = pal_getSockAddrIPV4Addr(palAddr, ipV4Addr); + if (result == PAL_SUCCESS) + { + memcpy(&ip4addr->sin_addr, ipV4Addr, sizeof(ip4addr->sin_addr)); + } + } + else if (PAL_AF_INET6 == palAddr->addressType) + { + palIpV6Addr_t ipV6Addr = {0}; + struct sockaddr_in6* ip6addr = (struct sockaddr_in6*)output; + ip6addr->sin6_family = AF_INET6; + ip6addr->sin6_scope_id = 0; // we assume there will not be several interfaces with the same IP. + ip6addr->sin6_flowinfo = 0; + ip6addr->sin6_port = PAL_HTONS(port); + result = pal_getSockAddrIPV6Addr(palAddr, ipV6Addr); + if (result == PAL_SUCCESS) + { + memcpy(&ip6addr->sin6_addr, ipV6Addr, sizeof(ip6addr->sin6_addr)); + } + } + + return result; +} + +PAL_PRIVATE palStatus_t pal_plat_socketAddressToPalSockAddr(struct sockaddr* input, palSocketAddress_t* out, palSocketLength_t* length) +{ + palStatus_t result = PAL_SUCCESS; + + if (input->sa_family == AF_INET) + { + palIpV4Addr_t ipV4Addr; + struct sockaddr_in* ip4addr = (struct sockaddr_in*)input; + + memcpy(ipV4Addr, &ip4addr->sin_addr, PAL_IPV4_ADDRESS_SIZE); + result = pal_setSockAddrIPV4Addr(out, ipV4Addr); + if (result == PAL_SUCCESS) + { + result = pal_setSockAddrPort(out, PAL_NTOHS(ip4addr->sin_port)); + } + *length = sizeof(struct sockaddr_in); + } + else if (input->sa_family == AF_INET6) + { + palIpV6Addr_t ipV6Addr; + struct sockaddr_in6* ip6addr = (struct sockaddr_in6*)input; + memcpy(ipV6Addr, &ip6addr->sin6_addr, PAL_IPV6_ADDRESS_SIZE); + result = pal_setSockAddrIPV6Addr(out, ipV6Addr); + if (result == PAL_SUCCESS) + { + result = pal_setSockAddrPort(out, PAL_NTOHS(ip6addr->sin6_port)); + } + *length = sizeof(struct sockaddr_in6); + } + else + { // we got unspeicified in one of the tests, so Don't fail , but don't translate address. + //result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY; + } + + return result; +} + +palStatus_t pal_plat_socketsInit(void* context) +{ + PAL_UNUSED_ARG(context); + palStatus_t result = PAL_SUCCESS; + + if (s_pal_network_initialized == 1) + { + return PAL_SUCCESS; // already initialized. + } + + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + pthread_attr_t attr; + int res; + + result = pal_osMutexCreate(&s_mutexSocketCallbacks); + if (result != PAL_SUCCESS) + { + return result; + } + + result = pal_osMutexCreate(&s_mutexSocketEventFilter); + if (PAL_SUCCESS != result) + { + return result; + } + + + result = pal_osSemaphoreCreate(0, &s_socketCallbackSignalSemaphore); + if (result != PAL_SUCCESS) + { + // todo: clean up the mess created so far + return result; + } + + // Sleep at first wait + result = pal_osSemaphoreCreate(0, &s_socketCallbackSemaphore); + if (result != PAL_SUCCESS) + { + if (pal_osMutexDelete(&s_mutexSocketCallbacks) != PAL_SUCCESS) //cleanup allocated resources + { + // TODO print error using logging mechanism when available. + } + return result; + } + // prepare thread attributes + pthread_attr_init(&attr); + pthread_attr_setstacksize (&attr, PAL_NET_TEST_ASYNC_SOCKET_MANAGER_THREAD_STACK_SIZE); //sets the minimum stack size + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + + // create the thread + res = pthread_create(&s_pollThread, &attr, &asyncSocketManager, 0); + if (res < 0) + { + result = translateErrorToPALError(res); + } + else + { + // Wait here for the thread to be initialized. + result = pal_osSemaphoreWait(s_socketCallbackSemaphore, PAL_RTOS_WAIT_FOREVER, NULL); + if (PAL_SUCCESS != result) + { + goto end; + } + result = pal_osSemaphoreDelete(&s_socketCallbackSemaphore); + if (PAL_SUCCESS != result) + { + goto end; + } + } +#endif + +end: + if (PAL_SUCCESS == result) + { + s_pal_network_initialized = 1; + } + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + pthread_attr_destroy(&attr); +#endif + + return result; +} + +palStatus_t pal_plat_registerNetworkInterface(void* context, uint32_t* interfaceIndex) +{ + palStatus_t result = PAL_SUCCESS; + uint32_t index = 0; + bool found = false; + + for (index = 0; index < s_palNumOfInterfaces; index++) // if specific context already registered return existing index instead of registering again. + { + if (memcmp(s_palNetworkInterfacesSupported[index].interfaceName, (const char *)context, strlen(s_palNetworkInterfacesSupported[index].interfaceName)) == 0) + { + found = true; + *interfaceIndex = index; + break; + } + } + if (false == found) + { + if (s_palNumOfInterfaces < PAL_MAX_SUPORTED_NET_INTERFACES) + { + strncpy(s_palNetworkInterfacesSupported[s_palNumOfInterfaces].interfaceName, (const char *)context, PAL_NET_MAX_IF_NAME_LENGTH-1); + s_palNetworkInterfacesSupported[s_palNumOfInterfaces].interfaceName[PAL_NET_MAX_IF_NAME_LENGTH-1] = '\0'; + *interfaceIndex = s_palNumOfInterfaces; + ++s_palNumOfInterfaces; + } + else + { + result = PAL_ERR_SOCKET_MAX_NUMBER_OF_INTERFACES_REACHED; + } + } + + return result; +} + +palStatus_t pal_plat_socketsTerminate(void* context) +{ + PAL_UNUSED_ARG(context); + palStatus_t result = PAL_SUCCESS; + palStatus_t firstError = PAL_SUCCESS; + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + // Critical section to update globals + result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER); + if (result != PAL_SUCCESS) + { + // TODO print error using logging mechanism when available. + firstError = result; + } + + s_nfds = PAL_SOCKETS_TERMINATE; + result = pal_osSemaphoreRelease(s_socketCallbackSignalSemaphore); + if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError)) + { + // TODO print error using logging mechanism when available. + firstError = result; + } + // Tell the poll thread to interrupt so that it can check for termination. + pthread_kill(s_pollThread, SIGUSR1); + result = pal_osMutexRelease(s_mutexSocketCallbacks); + if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError)) + { + // TODO print error using logging mechanism when available. + firstError = result; + } + + pthread_join(s_pollThread, NULL); + + result = pal_osSemaphoreDelete(&s_socketCallbackSignalSemaphore); + if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError)) + { + // TODO print error using logging mechanism when available. + firstError = result; + } + + result = pal_osMutexDelete(&s_mutexSocketEventFilter); + if ((PAL_SUCCESS != result) && (PAL_SUCCESS == firstError)) + { + // TODO print error using logging mechanism when available. + firstError = result; + } + + result = pal_osMutexDelete(&s_mutexSocketCallbacks); + if ((PAL_SUCCESS != result ) && (PAL_SUCCESS == firstError)) + { + // TODO print error using logging mechanism when available. + firstError = result; + } +#endif // PAL_NET_ASYNCHRONOUS_SOCKET_API + + s_pal_network_initialized = 0; + + return firstError; +} + +/* + * NOTE!!!! + * When creating socket in Linux, we ignore interfaceNum provided. + * The socket should be bound to interface pal_plat_bind API (bind to address reflects the bound between + * socket and interface). + */ +palStatus_t pal_plat_socket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palSocket_t* sockt) +{ + int result = PAL_SUCCESS; + int sockfd; + int sockBehavior = 0; + + if (interfaceNum >= s_palNumOfInterfaces && PAL_NET_DEFAULT_INTERFACE != interfaceNum) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + // These are the same in Linux + if(type == PAL_SOCK_STREAM_SERVER) + { + type = PAL_SOCK_STREAM; + } + + // Compile time check that PAL values are the same as Linux values + PAL_ASSERT_STATIC(AF_INET == PAL_AF_INET); + PAL_ASSERT_STATIC(AF_INET6 == PAL_AF_INET6); + PAL_ASSERT_STATIC(AF_UNSPEC == PAL_AF_UNSPEC); + PAL_ASSERT_STATIC(SOCK_DGRAM == (unsigned int)PAL_SOCK_DGRAM); + PAL_ASSERT_STATIC(SOCK_STREAM == (unsigned int)PAL_SOCK_STREAM); + + if (nonBlockingSocket) + { + sockBehavior = SOCK_NONBLOCK; + } + + // SOCK_NONBLOCK since Linux 2.6.27 + sockfd = socket(domain, type | sockBehavior , 0); + // Note - though it is not an error, if we get sockfd == 0 then we probably (accidentally closed fd 0 somewhere else) + if (sockfd == PAL_LINUX_INVALID_SOCKET) + { + result = translateErrorToPALError(errno); + } + else + { + *sockt = (palSocket_t)sockfd; + } + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_plat_getSocketOptions(palSocket_t socket, palSocketOptionName_t optionName, void* optionValue, palSocketLength_t* optionLength) +{ + int result = PAL_SUCCESS; + int linuxName; + + // TODO moved to shared function + switch ((palSocketOptionName_t)optionName) + { + case PAL_SO_SNDTIMEO: + linuxName = SO_SNDTIMEO ; + break; + case PAL_SO_RCVTIMEO: + linuxName = SO_RCVTIMEO ; + break; +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + case PAL_SO_KEEPALIVE: + linuxName = SO_KEEPALIVE; + break; + case PAL_SO_KEEPIDLE: + linuxName = TCP_KEEPIDLE; + break; + case PAL_SO_KEEPINTVL: + linuxName = TCP_KEEPINTVL; + break; +#endif + case PAL_SO_REUSEADDR: + linuxName = SO_REUSEADDR; + break; + default: + // Unsupported option + result = PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED; + } + + if (result == PAL_SUCCESS) + { + if (PAL_SO_REUSEADDR == optionName || + PAL_SO_SNDTIMEO == optionName || + PAL_SO_RCVTIMEO == optionName) + { + result = getsockopt ((int)socket, SOL_SOCKET, linuxName, optionValue, optionLength); + } +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + else if (PAL_SO_KEEPALIVE == optionName) + { + result = getsockopt((int)socket, SOL_SOCKET, linuxName, optionValue, optionLength); + } + else + { + result = getsockopt((int)socket, SOL_TCP, linuxName, optionValue, optionLength); + } +#endif + + if(result == -1) + { + result = translateErrorToPALError(errno); + } + } + + return result; +} + +// Assume input timeout value is in milliseconds. +palStatus_t pal_plat_setSocketOptions(palSocket_t socket, int optionName, const void* optionValue, palSocketLength_t optionLength) +{ + int result = PAL_SUCCESS; + int linuxName; + PAL_UNUSED_ARG(optionLength); + + + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + switch (optionName) + { + case PAL_SO_SNDTIMEO: + linuxName = SO_SNDTIMEO; + timeout.tv_sec = (*(int *)optionValue)/1000 ; + timeout.tv_usec = ((*(int *)optionValue)%1000)*1000 ; + break; + case PAL_SO_RCVTIMEO: + linuxName = SO_RCVTIMEO; + timeout.tv_sec = (*(int *)optionValue)/1000 ; + timeout.tv_usec = ((*(int *)optionValue)%1000)*1000 ; + break; +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + case PAL_SO_KEEPALIVE: + linuxName = SO_KEEPALIVE; + break; + case PAL_SO_KEEPIDLE: + linuxName = TCP_KEEPIDLE; + break; + case PAL_SO_KEEPINTVL: + linuxName = TCP_KEEPINTVL; + break; +#endif + case PAL_SO_REUSEADDR: + linuxName = SO_REUSEADDR; + break; + default: + // Unsupported option + result = PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED; + } + + if (PAL_SUCCESS == result) + { + if (PAL_SO_SNDTIMEO == optionName || PAL_SO_RCVTIMEO == optionName) + { + result = setsockopt ((int)socket, SOL_SOCKET, linuxName, &timeout, sizeof(timeout)); + } +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + else if (PAL_SO_KEEPIDLE == optionName || PAL_SO_KEEPINTVL == optionName) + { + result = setsockopt ((int)socket, SOL_TCP, linuxName, (int *)optionValue, optionLength); + } +#endif + else + { + result = setsockopt ((int)socket, SOL_SOCKET, linuxName, (int *)optionValue, optionLength); + } + + if(-1 == result) + { + result = translateErrorToPALError(errno); + } + } + + return result; +} + +palStatus_t pal_plat_isNonBlocking(palSocket_t socket, bool* isNonBlocking) +{ + int flags = fcntl((int)socket, F_GETFL); + + if (0 != (flags & O_NONBLOCK)) + { + *isNonBlocking = true; + } + else + { + *isNonBlocking = false; + } + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_bind(palSocket_t socket, palSocketAddress_t* myAddress, palSocketLength_t addressLength) +{ + int result = PAL_SUCCESS; + int res = 0; + struct sockaddr_storage internalAddr = {0} ; + + result = pal_plat_SockAddrToSocketAddress(myAddress, (struct sockaddr *)&internalAddr); + if (result == PAL_SUCCESS) + { + res = bind((int)socket, (struct sockaddr *)&internalAddr, addressLength); + if (res == -1) + { + result = translateErrorToPALError(errno); + } + } + + return result; +} + + +palStatus_t pal_plat_receiveFrom(palSocket_t socket, void* buffer, size_t length, palSocketAddress_t* from, palSocketLength_t* fromLength, size_t* bytesReceived) +{ + palStatus_t result = PAL_SUCCESS; + ssize_t res; + struct sockaddr_storage internalAddr; + socklen_t addrlen; + + clearSocketFilter((int)socket); + addrlen = sizeof(struct sockaddr_storage); + res = recvfrom((int)socket, buffer, length, 0 ,(struct sockaddr *)&internalAddr, &addrlen); + if(res == -1) + { + result = translateErrorToPALError(errno); + } + else // only return address / bytesReceived in case of success + { + if ((NULL != from) && (NULL != fromLength)) + { + result = pal_plat_socketAddressToPalSockAddr((struct sockaddr *)&internalAddr, from, fromLength); + } + *bytesReceived = res; + } + + return result; +} + +palStatus_t pal_plat_sendTo(palSocket_t socket, const void* buffer, size_t length, const palSocketAddress_t* to, palSocketLength_t toLength, size_t* bytesSent) +{ + palStatus_t result = PAL_SUCCESS; + ssize_t res; + + clearSocketFilter((int)socket); + res = sendto((int)socket, buffer, length, 0, (struct sockaddr *)to, toLength); + if(res == -1) + { + result = translateErrorToPALError(errno); + } + else + { + *bytesSent = res; + } + + return result; +} + +palStatus_t pal_plat_close(palSocket_t* socket) +{ + palStatus_t result = PAL_SUCCESS; + int res; + unsigned int i,j; + + if (*socket == (void *)PAL_LINUX_INVALID_SOCKET) // socket already closed - return success. + { + PAL_LOG(DBG, "socket close called on socket which was already closed"); + return result; + } +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + // Critical section to update globals + result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER); + if (result != PAL_SUCCESS) + { + // TODO print error using logging mechanism when available. + return result; + } + + for(i= 0 ; i < s_nfds; i++) + { + // check if we have we found the socket being closed + if (s_fds[i].fd == (int)*socket) + { + // Remove from async socket list + // Close the gap in the socket data structures. + for(j = i; j < s_nfds - 1; j++) + { + s_fds[j].fd = s_fds[j+1].fd; + s_fds[j].events = s_fds[j+1].events; + s_callbacks[j] = s_callbacks[j+1]; + s_callbackArgs[j] = s_callbackArgs[j+1]; + } + // Blank out the last one + s_fds[j].fd = 0; + s_callbacks[j] = 0; + s_callbackArgs[j] = 0; + s_nfds--; + // Tell the poll thread to remove the socket + pthread_kill(s_pollThread, SIGUSR1); + break; + } + } + result = pal_osMutexRelease(s_mutexSocketCallbacks); + if (result != PAL_SUCCESS) + { + // TODO print error using logging mechanism when available. + return result; + } +#endif // PAL_NET_ASYNCHRONOUS_SOCKET_API + // In Linux it is ok to close a socket while it is being polled, but may not be on other os's + res = close((int) *socket); + if(res == -1) + result = translateErrorToPALError(errno); + else + { + *socket = (void *)PAL_LINUX_INVALID_SOCKET; + } + return result; +} + +palStatus_t pal_plat_getNumberOfNetInterfaces( uint32_t* numInterfaces) +{ + *numInterfaces = s_palNumOfInterfaces; + return PAL_SUCCESS; +} + +palStatus_t pal_plat_getNetInterfaceInfo(uint32_t interfaceNum, palNetInterfaceInfo_t * interfaceInfo) +{ + palStatus_t result = PAL_SUCCESS; + struct ifaddrs *ifap,*ifa; + int res,n; + uint32_t found = 0; + + if (interfaceNum >= s_palNumOfInterfaces) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + res = getifaddrs(&ifap); + if(res < 0) + { + result = translateErrorToPALError(errno); + } + else + { + for (ifa = ifap, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) + { + if (ifa->ifa_addr == NULL) + continue; + int family = ifa->ifa_addr->sa_family; + if (strcmp(s_palNetworkInterfacesSupported[interfaceNum].interfaceName, ifa->ifa_name) == 0) + { + if (family == AF_INET || family == AF_INET6) + { + found = 1; + if (family == AF_INET) + { + interfaceInfo->addressSize = sizeof(struct sockaddr_in); + } + else + { + interfaceInfo->addressSize = sizeof(struct sockaddr_in6); + } + + strncpy(interfaceInfo->interfaceName, s_palNetworkInterfacesSupported[interfaceNum].interfaceName, strlen(s_palNetworkInterfacesSupported[interfaceNum].interfaceName)); + + result = pal_plat_socketAddressToPalSockAddr(ifa->ifa_addr, &interfaceInfo->address, &interfaceInfo->addressSize); + + break; + } + } + } + // free what was allocated by getifaddrs + freeifaddrs(ifap); + } + + //interface not found error + if (found != 1 && result == PAL_SUCCESS) + { + PAL_LOG(ERR, "Network failed reading interface info"); + result = PAL_ERR_GENERIC_FAILURE; + } + + return result; +} + + +palStatus_t pal_plat_socketMiniSelect(const palSocket_t socketsToCheck[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t numberOfSockets, pal_timeVal_t* timeout, + uint8_t palSocketStatus[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t * numberOfSocketsSet) +{ + uint32_t index = 0; + palStatus_t result = PAL_SUCCESS; + fd_set readset, writeset, exset; + // Keep a local copy because select in Linux will modify it. + struct timeval tmpTimeout; + int res; + int fd; + int maxfd = 0; + + if ((NULL == socketsToCheck) || (NULL == numberOfSocketsSet) || (NULL == timeout)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + // Copy the values manually as the struct variables may have different sizes. + tmpTimeout.tv_sec = timeout->pal_tv_sec; + tmpTimeout.tv_usec = timeout->pal_tv_usec; + + *numberOfSocketsSet = 0; + + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_ZERO(&exset); + + for(index = 0; index < numberOfSockets; index++) + { + fd = (int)socketsToCheck[index]; + FD_SET(fd, &readset); + // Do not detect writes because they will not block unless something is in the process of being written(Nir) + // XXX: Actually for a nonblocking connect() we need to detect readiness for write + // to find out if the socket is ready. + FD_SET(fd, &writeset); + FD_SET(fd, &exset); + if (fd > maxfd) + { + maxfd = fd; + } + } + + res = select(maxfd + 1, &readset, &writeset, &exset, &tmpTimeout); + if(res == -1) + { + result = translateErrorToPALError(errno); + } + else if (res > 0) // select returns 0 in case timeout expire + { + for(index = 0; index < numberOfSockets; index++) + { + uint8_t socketStatus = 0; + fd = (int)socketsToCheck[index]; + + if(FD_ISSET(fd, &readset)) + { + socketStatus |= PAL_NET_SOCKET_SELECT_RX_BIT; + } + if(FD_ISSET(fd, &writeset)) + { + socketStatus |= PAL_NET_SOCKET_SELECT_TX_BIT; + } + if(FD_ISSET(fd, &exset)) + { + socketStatus |= PAL_NET_SOCKET_SELECT_ERR_BIT; + } + + palSocketStatus[index] = socketStatus; + } + *numberOfSocketsSet = res; + } + + return result ; +} + +#if PAL_NET_TCP_AND_TLS_SUPPORT // functionality below supported only in case TCP is supported. +palStatus_t pal_plat_listen(palSocket_t socket, int backlog) +{ + palStatus_t result = PAL_SUCCESS; + int res; + + res = listen((int)socket,backlog); + if(res == -1) + { + result = translateErrorToPALError(errno); + } + return result; +} + + +palStatus_t pal_plat_accept(palSocket_t socket, palSocketAddress_t * address, palSocketLength_t* addressLen, palSocket_t* acceptedSocket) +{ + int res = 0; + palStatus_t result = PAL_SUCCESS; + struct sockaddr_storage internalAddr = {0} ; + + res = accept((int)socket,(struct sockaddr *)&internalAddr, addressLen); + if(res == -1) + { + result = translateErrorToPALError(errno); + } + else + { + *acceptedSocket = (palSocket_t*)res; + result = pal_plat_socketAddressToPalSockAddr((struct sockaddr *)&internalAddr, address, addressLen); + } + + return result; +} + + +palStatus_t pal_plat_connect(palSocket_t socket, const palSocketAddress_t* address, palSocketLength_t addressLen) +{ + int result = PAL_SUCCESS; + int res; + struct sockaddr_storage internalAddr = {0} ; + + result = pal_plat_SockAddrToSocketAddress(address, (struct sockaddr *)&internalAddr); + if (result == PAL_SUCCESS) + { + res = connect((int)socket,(struct sockaddr *)&internalAddr, addressLen); + if(res == -1) + { + result = translateErrorToPALError(errno); + } + } + + return result; +} + +palStatus_t pal_plat_recv(palSocket_t socket, void *buffer, size_t len, size_t* recievedDataSize) +{ + palStatus_t result = PAL_SUCCESS; + ssize_t res; + + clearSocketFilter((int)socket); + res = recv((int)socket, buffer, len, 0); + if(res == -1) + { + result = translateErrorToPALError(errno); + } + else + { + if (0 == res) + { + result = PAL_ERR_SOCKET_CONNECTION_CLOSED; + } + *recievedDataSize = res; + } + return result; +} + +palStatus_t pal_plat_send(palSocket_t socket, const void *buf, size_t len, size_t *sentDataSize) +{ + palStatus_t result = PAL_SUCCESS; + ssize_t res; + + clearSocketFilter((int)socket); + + res = send((int)socket, buf, len, 0); + if(res == -1) + { + result = translateErrorToPALError(errno); + } + else + { + *sentDataSize = res; + } + + return result; +} + +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + + + + + + + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API +palStatus_t pal_plat_asynchronousSocket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t callback, void* callbackArgument, palSocket_t* socket) +{ + + int err; + int flags; + palStatus_t result = pal_plat_socket(domain, type, nonBlockingSocket, interfaceNum, socket); + + + + // initialize the socket to be ASYNC so we get SIGIO's for it + // XXX: this needs to be conditionalized as the blocking IO might have some use also. + err = fcntl((int)*socket, F_SETOWN, getpid()); + assert(err != -1); + + flags = fcntl((int)*socket, F_GETFL, 0); + assert(flags >= 0); + + flags |= O_ASYNC; + + err = fcntl((int)*socket, F_SETFL, flags); + + if (err == -1) + { + result = translateErrorToPALError(errno); + } + + + if (result == PAL_SUCCESS) + { + // Critical section to update globals + result = pal_osMutexWait(s_mutexSocketCallbacks, PAL_RTOS_WAIT_FOREVER); + if (result != PAL_SUCCESS) + { + // TODO print error using logging mechanism when available. + return result; + } + s_fds[s_nfds].fd = (int)*socket; + s_fds[s_nfds].events = POLLIN|POLLERR; //TODO POLLOUT missing is not documented + s_callbacks[s_nfds] = callback; + s_callbackArgs[s_nfds] = callbackArgument; + s_nfds++; + result = pal_osMutexRelease(s_mutexSocketCallbacks); + if (result != PAL_SUCCESS) + { + // TODO print error using logging mechanism when available. + return result; + } + // Tell the poll thread to add the new socket + pthread_kill(s_pollThread, SIGUSR1); + } + + return result; + +} + +#endif + +#if PAL_NET_DNS_SUPPORT + +palStatus_t pal_plat_getAddressInfo(const char *url, palSocketAddress_t *address, palSocketLength_t* length) +{ + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t localAddress = {0}; + palSocketAddress_t zeroAddress = {0}; + struct addrinfo *pAddrInf = NULL; + struct addrinfo hints = {0}; + int res; + int supportedAddressType1 = 0; + int supportedAddressType2 = 0; + hints.ai_family = AF_UNSPEC; + +#if PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_ANY + supportedAddressType1 = AF_INET; + supportedAddressType2 = AF_INET6; + hints.ai_family = AF_UNSPEC; +#elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV4_ONLY + supportedAddressType1 = AF_INET; + supportedAddressType2 = AF_INET; + hints.ai_family = AF_INET; +#elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV6_ONLY + supportedAddressType1 = AF_INET6; + supportedAddressType2 = AF_INET6; + hints.ai_family = AF_INET6; +#else +#error PAL_NET_DNS_IP_SUPPORT is not defined to a valid value. +#endif + + res = getaddrinfo(url, NULL, &hints, &pAddrInf); + if(res < 0) + { + result = translateErrorToPALError(errno); + } + else + { + if ((pAddrInf != NULL) && (pAddrInf->ai_family == supportedAddressType1 || pAddrInf->ai_family == supportedAddressType2)) + { + result = pal_plat_socketAddressToPalSockAddr((struct sockaddr*)pAddrInf->ai_addr, &localAddress, length); + + if (0 == memcmp(localAddress.addressData, zeroAddress.addressData, PAL_NET_MAX_ADDR_SIZE) ) // invalid 0 address + { + result = PAL_ERR_SOCKET_DNS_ERROR; + } + else + { + *address = localAddress; + } + } + else + { + result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY; + } + + freeaddrinfo(pAddrInf); + } + + return result; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/RTOS/pal_plat_rtos.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/RTOS/pal_plat_rtos.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1739 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define _GNU_SOURCE // This is for ppoll found in poll.h +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <mqueue.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/reboot.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/utsname.h> + +#include "pal.h" +#include "pal_plat_rtos.h" + + + +typedef struct palThreadFuncWrapper +{ + palTimerFuncPtr realThreadFunc; + void* realThreadArgs; + uint32_t threadIndex; +} palThreadFuncWrapper_t; + +//! Thread structure +typedef struct palThread +{ + pthread_t threadID; + uint32_t palThreadID; + bool initialized; + palThreadLocalStore_t* threadStore; //! please see pal_rtos.h for documentation + palThreadFuncWrapper_t threadFuncWrapper; + palThreadPriority_t priority; + uint32_t stackSize; +} palThread_t; + +/*! Count number of created threads. Initiate to zero. +*/ +PAL_PRIVATE uint32_t g_threadCounter = 0; + +palThread_t g_palThreads[PAL_MAX_NUMBER_OF_THREADS]; + +/* + * The realtime clock is in nano seconds resolution. This is too much for us, so we use "longer" ticks. + * Below are relevant defines. + * make sure they all coherent. Can use one at the other, but will add some unneeded calculations. + */ +#define NANOS_PER_TICK 100 +#define TICKS_PER_MICRO 10L +#define TICKS_PER_MILLI TICKS_PER_MICRO * 1000 +#define TICKS_PER_SECOND TICKS_PER_MILLI * 1000 + +// priorities must be positive, so shift all by this margin. we might want to do smarter convert. +#define LINUX_THREAD_PRIORITY_BASE 10 + +// message Queues names related staff: +#define MQ_FILENAME_LEN 10 + +#ifndef CLOCK_MONOTONIC_RAW //a workaround for the operWRT port that missing this include +#define CLOCK_MONOTONIC_RAW 4 //http://elixir.free-electrons.com/linux/latest/source/include/uapi/linux/time.h +#endif + +PAL_PRIVATE char g_mqName[MQ_FILENAME_LEN]; +PAL_PRIVATE int g_mqNextNameNum = 0; + + +extern palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes); + +inline PAL_PRIVATE void nextMessageQName() +{ + g_mqNextNameNum++; + for (int j = 4, divider = 10000; j < 9; j++, divider /= 10) + { + g_mqName[j] = '0' + (g_mqNextNameNum / divider) %10 ; //just to make sure we don't write more then 1 digit. + } + g_mqName[9] = '\0'; +} + + +/*! Initiate a system reboot. + */ +void pal_plat_osReboot(void) +{ + struct utsname buf; + buf.nodename[0] = 0; + // Get the system names. Ignore error for this function call + uname(&buf); + // We assume that it is a desktop if "ubuntu" is returned. + if(!strcmp(buf.nodename,"ubuntu")) + { + // We emulate resetting the device by running the application again. + // Restart the application + int status, timeout; // unused ifdef WAIT_FOR_COMPLETION ; + const char *argv[] = {"0" , 0}; + + //printf("program_invocation_name=%s, __progname=%s",program_invocation_name,__progname); + argv[0] = program_invocation_name; + pid_t my_pid; + + if (0 == (my_pid = fork())) + { + char *const envp[] = { 0 }; + if (-1 == execve(argv[0], (char **)argv , envp)) + { + printf("child process execve failed [%s]",argv[0]); + } + } + timeout = 1000; + + while (0 == waitpid(my_pid , &status , WNOHANG)) + { + if ( --timeout < 0 ) { + perror("timeout"); + //return -1; + } + sleep(1); + } + } + else + { + // Reboot the device + reboot(RB_AUTOBOOT); + } + return; +} + +/*! Initialize all data structures (semaphores, mutexs, memory pools, message queues) at system initialization. + * In case of a failure in any of the initializations, the function returns with an error and stops the rest of the initializations. + * @param[in] opaqueContext The context passed to the initialization (not required for generic CMSIS, pass NULL in this case). + * \return PAL_SUCCESS(0) in case of success, PAL_ERR_CREATION_FAILED in case of failure. + */ +palStatus_t pal_plat_RTOSInitialize(void* opaqueContext) +{ + palStatus_t status = PAL_SUCCESS; + (void) opaqueContext; + strncpy(g_mqName, "/pal00001", MQ_FILENAME_LEN); + g_mqNextNameNum = 1; // used for the next name + + //Clean thread tables + memset(g_palThreads,0,sizeof(palThread_t) * PAL_MAX_NUMBER_OF_THREADS); + + //Add implicit the running task as PAL main + g_palThreads[0].initialized = true; + g_palThreads[0].threadID = pthread_self(); + + pal_osAtomicIncrement((int32_t*)&g_threadCounter,1); + //palThreadID = 24 bits for thread counter + 8 bits for thread index (= 0). + g_palThreads[0].palThreadID = (g_threadCounter << 8 ); + + return status; +} + +/*! De-Initialize thread objects. + */ +palStatus_t pal_plat_RTOSDestroy(void) +{ + return PAL_SUCCESS; +} + + +/*return The RTOS kernel system timer counter, in microseconds + */ + +uint64_t pal_plat_osKernelSysTick(void) // optional API - not part of original CMSIS API. +{ + /*Using clock_gettime is more accurate, but then we have to convert it to ticks. we are using a tick every 100 nanoseconds*/ + struct timespec ts; + uint64_t ticks; + //TODO: error handling + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + + ticks = (uint64_t) (ts.tv_sec * (uint64_t)TICKS_PER_SECOND + + (ts.tv_nsec / NANOS_PER_TICK)); + return ticks; +} + +/* Convert the value from microseconds to kernel sys ticks. + * This is the same as CMSIS macro osKernelSysTickMicroSec. + * since we return microsecods as ticks, just return the value + */ +uint64_t pal_plat_osKernelSysTickMicroSec(uint64_t microseconds) +{ + + //convert to nanoseconds + return microseconds * TICKS_PER_MICRO; +} + +/*! Get the system tick frequency. + * \return The system tick frequency. + */ +inline uint64_t pal_plat_osKernelSysTickFrequency(void) +{ + /* since we use clock_gettime, with resolution of 100 nanosecond per tick*/ + return TICKS_PER_SECOND; +} + +inline PAL_PRIVATE void setDefaultThreadValues(palThread_t* thread) +{ + +#if PAL_UNIQUE_THREAD_PRIORITY + g_palThreadPriorities[thread->priority + PRIORITY_INDEX_OFFSET] = 0; +#endif //PAL_UNIQUE_THREAD_PRIORITY + thread->threadStore = NULL; + thread->threadFuncWrapper.realThreadArgs = NULL; + thread->threadFuncWrapper.realThreadFunc = NULL; + thread->threadFuncWrapper.threadIndex = 0; + thread->priority = PAL_osPriorityError; + thread->stackSize = 0; + thread->threadID = (palThreadID_t)PAL_INVALID_THREAD; + thread->palThreadID = 0; + //! This line should be last thing to be done in this function. + //! in order to prevent double accessing the same index between + //! this function and the threadCreate function. + thread->initialized = false; +} + +/*! Clean thread data from the global thread data base (g_palThreads). Thread Safe API + * + * @param[in] index: the index in the data base to be cleaned. + */ +PAL_PRIVATE void threadCleanUp(uint32_t index) +{ + uint32_t status = PAL_SUCCESS; + uint32_t threadIndex = PAL_GET_THREAD_INDEX(index); + + status = pal_osMutexWait(g_palThreadInitMutex, PAL_RTOS_WAIT_FOREVER); + + if (PAL_SUCCESS != status) + { + PAL_LOG(ERR,"thread cleanup: mutex wait failed!\n"); + } + else{ + if ((threadIndex < PAL_MAX_NUMBER_OF_THREADS) && (g_palThreads[threadIndex].palThreadID == index)) + { + setDefaultThreadValues(&g_palThreads[threadIndex]); + } + + status = pal_osMutexRelease(g_palThreadInitMutex); + if (PAL_SUCCESS != status) + { + PAL_LOG(ERR,"thread cleanup: mutex release failed!\n"); + } + } + return; +} + +/*! Thread wrapper function, this function will be set as the thread function (for every thread) + * and it will get as an argument the real data about the thread and call the REAL thread function + * with the REAL argument. Once the REAL thread function finished, \ref pal_threadClean() will be called. + * + * @param[in] arg: data structure which contains the real data about the thread. + */ +void* threadFunctionWrapper(void* arg) +{ + + palThreadFuncWrapper_t* threadWrapper = (palThreadFuncWrapper_t*) arg; + + if ((NULL != threadWrapper) && (NULL != threadWrapper->realThreadFunc)) + { + if(g_palThreads[threadWrapper->threadIndex].threadID == NULLPTR) + { + g_palThreads[threadWrapper->threadIndex].threadID = pthread_self(); + } + + threadWrapper->realThreadFunc(threadWrapper->realThreadArgs); + threadCleanUp(g_palThreads[threadWrapper->threadIndex].palThreadID); + + } + return NULL; +} + +/*! Create and start a thread function. + * + * @param[in] function A function pointer to the thread callback function. + * @param[in] funcArgument An argument for the thread function. + * @param[in] priority The priority of the thread. + * @param[in] stackSize The stack size of the thread. + * @param[in] stackPtr A pointer to the thread's stack. + * @param[in] store A pointer to thread's local store, can be NULL. + * @param[out] threadID The created thread ID handle, zero indicates an error. + * + * \return The ID of the created thread, in case of error return zero. + * \note Each thread MUST have a unique priority. + * \note When the priority of the created thread function is higher than the current running thread, the + * created thread function starts instantly and becomes the new running thread. + */ +palStatus_t pal_plat_osThreadCreate(palThreadFuncPtr function, + void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, + uint32_t* stackPtr, palThreadLocalStore_t* store, + palThreadID_t* threadID) +{ + uint32_t firstAvailableThreadIndex = PAL_MAX_NUMBER_OF_THREADS; + palStatus_t status = PAL_SUCCESS; + uint32_t localPalThreadID = 0; + + + { + if ((NULL == threadID) || (NULL == function) || (0 == stackSize) || (priority > PAL_osPriorityRealtime)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + status = pal_osMutexWait(g_palThreadInitMutex, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS == status) + { + for (uint32_t i = 0; i < PAL_MAX_NUMBER_OF_THREADS; ++i) + { + if ((!g_palThreads[i].initialized)) + { + g_palThreads[i].initialized = true; + firstAvailableThreadIndex = i; + break; + } + } + + if (firstAvailableThreadIndex >= PAL_MAX_NUMBER_OF_THREADS) + { + *threadID = PAL_INVALID_THREAD; + status = PAL_ERR_RTOS_RESOURCE; + // release mutex if error. + pal_osMutexRelease(g_palThreadInitMutex); + goto finish; + } + + g_palThreads[firstAvailableThreadIndex].threadStore = store; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadArgs = + funcArgument; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadFunc = + function; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.threadIndex = + firstAvailableThreadIndex; + g_palThreads[firstAvailableThreadIndex].priority = priority; + g_palThreads[firstAvailableThreadIndex].stackSize = stackSize; + g_palThreads[firstAvailableThreadIndex].palThreadID = ((firstAvailableThreadIndex)+((pal_osAtomicIncrement((int32_t*)&g_threadCounter, 1)) << 8)); //palThreadID = 24 bits for thread counter + lower 8 bits for thread index. + localPalThreadID = g_palThreads[firstAvailableThreadIndex].palThreadID; + + // release mutex before thread creation . + status = pal_osMutexRelease(g_palThreadInitMutex); + + if (PAL_SUCCESS == status) + { + // prepare thread attributes + pthread_attr_t attr; + pthread_attr_init(&attr); + + int err = pthread_attr_setstacksize(&attr, stackSize);// Replace stack pointer with dynamically allocated from the OS + if (0 != err) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + + if (0 != pthread_attr_setschedpolicy(&attr, SCHED_RR)) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + + //PTHREAD_CREATE_JOINABLE in Linux save the stack TCB until join is call and detach clean every thing upon exit + //Because PAL is not forcing the user to call thread cancel the threads are detached + if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + + struct sched_param schedParam; + schedParam.sched_priority = LINUX_THREAD_PRIORITY_BASE + (int) priority; + if (0 != pthread_attr_setschedparam(&attr, &schedParam)) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + + //create the thread + pthread_t thread = (pthread_t)NULL; + + int retVal = pthread_create(&thread, &attr, threadFunctionWrapper, (void*) &(g_palThreads[firstAvailableThreadIndex].threadFuncWrapper)); + pthread_attr_destroy(&attr); //Destroy the thread attributes object, since it is no longer needed + if (0 != retVal) + { + if (EPERM == retVal) + { + // cannot set the priority + status = PAL_ERR_RTOS_PRIORITY; + } + else + { + status = PAL_ERR_RTOS_RESOURCE; + } + goto finish; + } + + if((thread != (palThreadID_t)PAL_INVALID_THREAD) && (thread != 0)) + { + // if we managed to do it, set in the the array, set threadID, and return + g_palThreads[firstAvailableThreadIndex].threadID = (palThreadID_t) thread; + *threadID = localPalThreadID; + } + } + + } + } + finish: + if (PAL_SUCCESS != status) + { + if (firstAvailableThreadIndex < PAL_MAX_NUMBER_OF_THREADS) + { + threadCleanUp(localPalThreadID); + } + *threadID = PAL_INVALID_THREAD; + } + return status; + +} + +/*! Terminate and free allocated data for the thread. + * + * @param[in] threadID The ID of the thread to stop and terminate. + * + * \return palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osThreadTerminate(palThreadID_t* threadID) +{ + palStatus_t status = PAL_ERR_INVALID_ARGUMENT; + int statusOS = 0; + uint32_t threadIndex = PAL_GET_THREAD_INDEX(*threadID); + + if ((PAL_INVALID_THREAD == *threadID) || (threadIndex >= PAL_MAX_NUMBER_OF_THREADS)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + // if thread exited or was terminated already return success. + if ((g_palThreads[threadIndex].palThreadID == 0) || // thread already exited + (g_palThreads[threadIndex].palThreadID != *threadID) || // thread already exited and a new thread was created at the same index. + (g_palThreads[threadIndex].threadID == (palThreadID_t)PAL_INVALID_THREAD)) // thread was terminsated. + { + return PAL_SUCCESS; + } + + + if((pthread_self() != g_palThreads[threadIndex].threadID)) + {//Kill only if not trying to kill from running task + status = PAL_SUCCESS; + if ((g_palThreads[threadIndex].initialized)) + { + statusOS = pthread_cancel(g_palThreads[threadIndex].threadID); + if((statusOS != 0) && (statusOS != ESRCH)) + { + status = PAL_ERR_RTOS_RESOURCE; + } + } + } + + if(status == PAL_SUCCESS) + { + threadCleanUp(*threadID); + *threadID = PAL_INVALID_THREAD; + } + + return status; +} + +/*! Get the ID of the current thread. + * \return The ID of the current thread, in case of error return PAL_maX_UINT32. + * \note For a thread with real time priority, the function always returns PAL_maX_UINT32. + */ +palThreadID_t pal_plat_osThreadGetId() +{ + int i = 0; + pthread_t osThreadID = pthread_self(); + palThreadID_t ret = PAL_INVALID_THREAD; + + for(i= 0; i < PAL_MAX_NUMBER_OF_THREADS; i++) + { + if(osThreadID == g_palThreads[i].threadID) + { + ret = i; + break; + } + } + return ret; +} + +/*! Get the storage of the current thread. + * \return The storage of the current thread. + */ +palThreadLocalStore_t* pal_plat_osThreadGetLocalStore(void) +{ + palThreadLocalStore_t* localStore = NULL; + palThreadID_t id = pal_osThreadGetId(); + + if( g_palThreads[id].initialized) + { + localStore = g_palThreads[id].threadStore; + } + return localStore; +} + +/*! Wait for a specified period of time in milliseconds. + * + * @param[in] milliseconds The number of milliseconds to wait before proceeding. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osDelay(uint32_t milliseconds) +{ + struct timespec sTime; + struct timespec rTime; // this will return how much sleep time still left in case of interrupted sleep + int stat; + //init rTime, as we will copy it over to stime inside the do-while loop. + rTime.tv_sec = milliseconds / 1000; + rTime.tv_nsec = PAL_MILLI_TO_NANO(milliseconds); + + do + { + sTime.tv_sec = rTime.tv_sec; + sTime.tv_nsec = rTime.tv_nsec; + stat = nanosleep(&sTime, &rTime); + } while ((-1 == stat) && (EINTR ==errno)) ; + return (stat == 0) ? PAL_SUCCESS : PAL_ERR_GENERIC_FAILURE; +} + +/* + * Internal struct to handle timers. + */ + +struct palTimerInfo +{ + timer_t handle; + palTimerFuncPtr function; + void *funcArgs; + palTimerType_t timerType; + bool isHighRes; +}; + +/* + * internal function used to handle timers expiration events. + */ +PAL_PRIVATE void palTimerEventHandler(void* args) +{ + struct palTimerInfo* timer = (struct palTimerInfo *) args; + + if (NULL == timer) + { // no timer anymore, so just return. + return; + } + + //call the callback function + timer->function(timer->funcArgs); +} + + +/* +* Internal struct to handle timers. +*/ + +#define PAL_HIGH_RES_TIMER_THRESHOLD_MS 100 + +typedef struct palHighResTimerThreadContext +{ + palTimerFuncPtr function; + void *funcArgs; + uint32_t intervalMS; +} palHighResTimerThreadContext_t; + + +static pthread_t s_palHighResTimerThreadID = {0}; +static bool s_palHighResTimerThreadInUse = 0; +static palHighResTimerThreadContext_t s_palHighResTimerThreadContext = {0}; + +/* +* callback for handling high precision timer callbacks (currently only one is supported) +*/ + +PAL_PRIVATE void* palHighResTimerThread(void* args) +{ + palHighResTimerThreadContext_t* context = (palHighResTimerThreadContext_t*)args; + uint32_t timer_period_ms = context->intervalMS; + int err = 0; + struct timespec next_timeout_ts; + err = clock_gettime(CLOCK_MONOTONIC, &next_timeout_ts); + assert(err == 0); + + while(1) { + // Determine absolute time we want to sleep until + next_timeout_ts.tv_nsec += PAL_NANO_PER_MILLI * timer_period_ms; + if (next_timeout_ts.tv_nsec >= PAL_NANO_PER_SECOND) + { + next_timeout_ts.tv_nsec = next_timeout_ts.tv_nsec - PAL_NANO_PER_SECOND; + next_timeout_ts.tv_sec += 1; + } + + // Call nanosleep until error or no interrupt, ie. return code is 0 + do { + err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_timeout_ts, NULL); + assert(err == 0 || err == EINTR); + } while(err == EINTR); + + // Done sleeping, call callback + context->function(context->funcArgs); + } + return NULL; +} + +PAL_PRIVATE palStatus_t startHighResTimerThread(palTimerFuncPtr function, void *funcArgs , uint32_t intervalMS) +{ + int retVal = 0; + palStatus_t status = PAL_SUCCESS; + pthread_attr_t attr; + pthread_attr_init(&attr); + + s_palHighResTimerThreadContext.function = function; + s_palHighResTimerThreadContext.funcArgs = funcArgs; + s_palHighResTimerThreadContext.intervalMS = intervalMS; + + retVal = pthread_attr_setstacksize(&attr, PAL_RTOS_HIGH_RES_TIMER_THREAD_STACK_SIZE);//sets the minimum stack size + if (0 != retVal) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + + if (0 != pthread_attr_setschedpolicy(&attr, SCHED_RR)) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + + //PTHREAD_CREATE_JOINABLE in Linux save the stack TCB until join is call and detach clean every thing upon exit + //Because PAL is not forcing the user to call thread cancel the threads are detached + if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + + struct sched_param schedParam; + schedParam.sched_priority = LINUX_THREAD_PRIORITY_BASE + (int)PAL_osPriorityRealtime; + if (0 != pthread_attr_setschedparam(&attr, &schedParam)) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + + retVal = pthread_create(&s_palHighResTimerThreadID, &attr, &palHighResTimerThread, &s_palHighResTimerThreadContext); + if (0 != retVal) + { + if (EPERM == retVal) + { + // cannot set the priority + status = PAL_ERR_RTOS_PRIORITY; + } + else + { + status = PAL_ERR_RTOS_RESOURCE; + } + } + +finish: + pthread_attr_destroy(&attr); //Destroy the thread attributes object, since it is no longer needed + + return status; + +} + + +/*! Create a timer. + * + * @param[in] function A function pointer to the timer callback function. + * @param[in] funcArgument An argument for the timer callback function. + * @param[in] timerType The timer type to be created, periodic or oneShot. + * @param[out] timerID The ID of the created timer, zero value indicates an error. + * + * \return PAL_SUCCESS when the timer was created successfully. A specific error in case of failure. + */ +palStatus_t pal_plat_osTimerCreate(palTimerFuncPtr function, void* funcArgument, + palTimerType_t timerType, palTimerID_t* timerID) +{ + + palStatus_t status = PAL_SUCCESS; + struct palTimerInfo* timerInfo = NULL; + { + struct sigevent sig; + timer_t localTimer; + + if ((NULL == timerID) || (NULL == (void*) function)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timerInfo = (struct palTimerInfo*) malloc(sizeof(struct palTimerInfo)); + if (NULL == timerInfo) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + + timerInfo->function = function; + timerInfo->funcArgs = funcArgument; + timerInfo->timerType = timerType; + timerInfo->isHighRes = false; + + memset(&sig, 0, sizeof(sig)); + + sig.sigev_notify = SIGEV_THREAD; + sig.sigev_signo = 0; + sig.sigev_value.sival_ptr = timerInfo; + sig.sigev_notify_function = (void (*)(union sigval)) palTimerEventHandler; + + int ret = timer_create(CLOCK_MONOTONIC, &sig, &localTimer); + if (-1 == ret) + { + if (EINVAL == errno) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + if (ENOMEM == errno) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + PAL_LOG(ERR, "Rtos timer create error %d", ret); + status = PAL_ERR_GENERIC_FAILURE; + goto finish; + } + + // managed to create the timer - finish up + timerInfo->handle = localTimer; + *timerID = (palTimerID_t) timerInfo; + } + finish: if (PAL_SUCCESS != status) + { + if (NULL != timerInfo) + { + free(timerInfo); + *timerID = (palTimerID_t) NULL; + } + } + return status; +} + +/* Convert milliseconds into seconds and nanoseconds inside a timespec struct + */ +PAL_PRIVATE void convertMilli2Timespec(uint32_t millisec, struct timespec* ts) +{ + ts->tv_sec = millisec / 1000; + ts->tv_nsec = PAL_MILLI_TO_NANO(millisec); +} + +/*! Start or restart a timer. + * + * @param[in] timerID The handle for the timer to start. + * @param[in] millisec The time in milliseconds to set the timer to. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osTimerStart(palTimerID_t timerID, uint32_t millisec) +{ + palStatus_t status = PAL_SUCCESS; + if (NULL == (struct palTimerInfo *) timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID; + struct itimerspec its; + + + if ((millisec <= PAL_HIGH_RES_TIMER_THRESHOLD_MS) && (palOsTimerPeriodic == timerInfo->timerType )) // periodic high res timer - we only support 1 (workaround for issue when lots of threads are created in linux) + { + if (true == s_palHighResTimerThreadInUse) + { + status = PAL_ERR_NO_HIGH_RES_TIMER_LEFT; + } + else + { + status = startHighResTimerThread(timerInfo->function, timerInfo->funcArgs, millisec); + if (PAL_SUCCESS == status) + { + timerInfo->isHighRes = true; + s_palHighResTimerThreadInUse = true; + } + + } + + } + else // otherwise handle normally + { + convertMilli2Timespec(millisec, &(its.it_value)); + + if (palOsTimerPeriodic == timerInfo->timerType) + { + convertMilli2Timespec(millisec, &(its.it_interval)); + } + else + { // one time timer + convertMilli2Timespec(0, &(its.it_interval)); + } + + if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL)) + { + status = PAL_ERR_INVALID_ARGUMENT; + } + } + + return status; +} + +/*! Stop a timer. + * + * @param[in] timerID The handle for the timer to stop. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osTimerStop(palTimerID_t timerID) +{ + palStatus_t status = PAL_SUCCESS; + if (NULL == (struct palTimerInfo *) timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID; + struct itimerspec its; + + if ((true == timerInfo->isHighRes) && (0 != s_palHighResTimerThreadInUse )) // if high res timer clean up thread. + { + int statusOS = pthread_cancel(s_palHighResTimerThreadID); + if ((statusOS != 0) && (statusOS != ESRCH)) + { + return PAL_ERR_RTOS_RESOURCE; + } + else + { + timerInfo->isHighRes = false; + s_palHighResTimerThreadInUse = false; + return PAL_SUCCESS; + } + } + else // otherwise process normally + { + // set timer to 0 to disarm it. + convertMilli2Timespec(0, &(its.it_value)); + + convertMilli2Timespec(0, &(its.it_interval)); + + if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL)) + { + status = PAL_ERR_INVALID_ARGUMENT; + } + } + + return status; +} + +/*! Delete the timer object + * + * @param[inout] timerID The handle for the timer to delete. In success, *timerID = NULL. + * + * \return PAL_SUCCESS when the timer was deleted successfully, PAL_ERR_RTOS_PARAMETER when the timerID is incorrect. + */ +palStatus_t pal_plat_osTimerDelete(palTimerID_t* timerID) +{ + palStatus_t status = PAL_SUCCESS; + if (NULL == timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + struct palTimerInfo* timerInfo = (struct palTimerInfo *) *timerID; + if (NULL == timerInfo) + { + status = PAL_ERR_RTOS_PARAMETER; + } + + if ((true == timerInfo->isHighRes) && (0 != s_palHighResTimerThreadInUse)) // if high res timer delted before stopping => clean up thread. + { + int statusOS = pthread_cancel(s_palHighResTimerThreadID); + if ((statusOS != 0) && (statusOS != ESRCH)) + { + status = PAL_ERR_RTOS_RESOURCE; + } + else + { + timerInfo->isHighRes = false; + s_palHighResTimerThreadInUse = false; + } + } + + if (PAL_SUCCESS == status) + { + timer_t lt = timerInfo->handle; + if (-1 == timer_delete(lt)) + { + status = PAL_ERR_RTOS_RESOURCE; + } + + free(timerInfo); + *timerID = (palTimerID_t) NULL; + } + return status; +} + +/*! Create and initialize a mutex object. + * + * @param[out] mutexID The created mutex ID handle, zero value indicates an error. + * + * \return PAL_SUCCESS when the mutex was created successfully, a specific error in case of failure. + */ +palStatus_t pal_plat_osMutexCreate(palMutexID_t* mutexID) +{ + palStatus_t status = PAL_SUCCESS; + pthread_mutex_t* mutex = NULL; + { + int ret; + if (NULL == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = malloc(sizeof(pthread_mutex_t)); + if (NULL == mutex) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + + pthread_mutexattr_t mutexAttr; + pthread_mutexattr_init(&mutexAttr); + pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE); + ret = pthread_mutex_init(mutex, &mutexAttr); + + if (0 != ret) + { + if (ENOMEM == ret) + { + status = PAL_ERR_NO_MEMORY; + } + else + { + PAL_LOG(ERR, "Rtos mutex create status %d", ret); + status = PAL_ERR_GENERIC_FAILURE; + } + goto finish; + } + *mutexID = (palMutexID_t) mutex; + } + finish: if (PAL_SUCCESS != status) + { + if (NULL != mutex) + { + free(mutex); + } + } + return status; +} + +/* Wait until a mutex becomes available. + * + * @param[in] mutexID The handle for the mutex. + * @param[in] millisec The timeout for the waiting operation if the timeout expires before the semaphore is released and an error is returned from the function. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, one of the following error codes in case of failure: + * PAL_ERR_RTOS_RESOURCE - Mutex not available but no timeout set. + * PAL_ERR_RTOS_TIMEOUT - Mutex was not available until timeout expired. + * PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid. + * PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines. + */ +palStatus_t pal_plat_osMutexWait(palMutexID_t mutexID, uint32_t millisec) +{ + palStatus_t status = PAL_SUCCESS; + int err; + if (NULL == ((pthread_mutex_t*) mutexID)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID; + + if (PAL_RTOS_WAIT_FOREVER != millisec) + { + /* calculate the wait absolute time */ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + ts.tv_sec += (millisec / PAL_MILLI_PER_SECOND); + ts.tv_nsec += PAL_MILLI_TO_NANO(millisec); + ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // if there is some overflow in the addition of nanoseconds. + ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND; + + while ((err = pthread_mutex_timedlock(mutex, &ts)) != 0 && err == EINTR) + { + continue; /* Restart if interrupted by handler */ + } + } + else + { // wait for ever + err = pthread_mutex_lock(mutex); + } + + if (0 != err) + { + if (err == ETIMEDOUT) + { + status = PAL_ERR_RTOS_TIMEOUT; + } + else + { + PAL_LOG(ERR, "Rtos mutex wait status %d", err); + status = PAL_ERR_GENERIC_FAILURE; + } + } + + return status; +} + +/* Release a mutex that was obtained by osMutexWait. + * + * @param[in] mutexID The handle for the mutex. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osMutexRelease(palMutexID_t mutexID) +{ + palStatus_t status = PAL_SUCCESS; + int result = 0; + + pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID; + if (NULL == mutex) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + result = pthread_mutex_unlock(mutex); + if (0 != result) + { + // only reason this might fail - process don't have permission for mutex. + PAL_LOG(ERR, "Rtos mutex release failure - %d",result); + status = PAL_ERR_GENERIC_FAILURE; + } + return status; +} + +/*Delete a mutex object. + * + * @param[inout] mutexID The ID of the mutex to delete. In success, *mutexID = NULL. + * + * \return PAL_SUCCESS when the mutex was deleted successfully, one of the following error codes in case of failure: + * PAL_ERR_RTOS_RESOURCE - Mutex already released. + * PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid. + * PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines. + * \note After this call, mutex_id is no longer valid and cannot be used. + */ +palStatus_t pal_plat_osMutexDelete(palMutexID_t* mutexID) +{ + palStatus_t status = PAL_SUCCESS; + uint32_t ret; + if (NULL == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + pthread_mutex_t* mutex = (pthread_mutex_t*) *mutexID; + + if (NULL == mutex) + { + status = PAL_ERR_RTOS_RESOURCE; + } + ret = pthread_mutex_destroy(mutex); + if ((PAL_SUCCESS == status) && (0 != ret)) + { + PAL_LOG(ERR,"pal_plat_osMutexDelete 0x%x",ret); + status = PAL_ERR_RTOS_RESOURCE; + } + if (NULL != mutex) + { + free(mutex); + } + + *mutexID = (palMutexID_t) NULL; + return status; +} + +/* Create and initialize a semaphore object. + * + * Semaphore is shared between threads, but not process. + * + * @param[in] count The number of available resources. + * @param[out] semaphoreID The ID of the created semaphore, zero value indicates an error. + * + * \return PAL_SUCCESS when the semaphore was created successfully, a specific error in case of failure. + */ +palStatus_t pal_plat_osSemaphoreCreate(uint32_t count, + palSemaphoreID_t* semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + sem_t* semaphore = NULL; + + { + if (NULL == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + semaphore = malloc(sizeof(sem_t)); + if (NULL == semaphore) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + /* create the semaphore as shared between threads */ + int ret = sem_init(semaphore, 0, count); + if (-1 == ret) + { + if (EINVAL == errno) + { + /* count is too big */ + status = PAL_ERR_INVALID_ARGUMENT; + } + else + { + PAL_LOG(ERR, "Rtos semaphore init error %d", ret); + status = PAL_ERR_GENERIC_FAILURE; + } + goto finish; + } + + *semaphoreID = (palSemaphoreID_t) semaphore; + } + finish: if (PAL_SUCCESS != status) + { + if (NULL != semaphore) + { + free(semaphore); + } + *semaphoreID = (palSemaphoreID_t) NULL; + } + return status; +} + +/* Wait until a semaphore token becomes available. + * + * @param[in] semaphoreID The handle for the semaphore. + * @param[in] millisec The timeout for the waiting operation if the timeout expires before the semaphore is released and an error is returned from the function. + * @param[out] countersAvailable The number of semaphores available (before the wait), if semaphores are not available (timeout/error) zero is returned. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, one of the following error codes in case of failure: + * PAL_ERR_RTOS_TIMEOUT - Semaphore was not available until timeout expired. + * PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid. + * PAL_ERR_INVALID_ARGUMENT - countersAvailable is NULL + * + * NOTES: 1. counterAvailable returns 0 in case there are no semaphores available or there are other threads waiting on it. + * Value is not thread safe - it might be changed by the time it is read/returned. + * 2. timed wait is using absolute time. + */ +palStatus_t pal_plat_osSemaphoreWait(palSemaphoreID_t semaphoreID, + uint32_t millisec, int32_t* countersAvailable) +{ + palStatus_t status = PAL_SUCCESS; + int tmpCounters = 0; + { + int err; + sem_t* sem = (sem_t*) semaphoreID; + if ((NULL == sem)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (PAL_RTOS_WAIT_FOREVER != millisec) + { + /* calculate the wait absolute time */ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += millisec / PAL_MILLI_PER_SECOND; + ts.tv_nsec += PAL_MILLI_TO_NANO(millisec); + ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // in case there is overflow in the nanoseconds. + ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND; + + while ((err = sem_timedwait(sem, &ts)) == -1 && errno == EINTR) + continue; /* Restart if interrupted by handler */ + } + else + { // wait for ever + do + { + err = sem_wait(sem); + + /* loop again if the wait was interrupted by a signal */ + } while ((err == -1) && (errno == EINTR)); + } + + if (-1 == err) + { + tmpCounters = 0; + if (errno == ETIMEDOUT) + { + status = PAL_ERR_RTOS_TIMEOUT; + } + else + { /* seems this is not a valid semaphore */ + status = PAL_ERR_RTOS_PARAMETER; + } + goto finish; + } + /* get the counter number, shouldn't fail, as we already know this is valid semaphore */ + sem_getvalue(sem, &tmpCounters); + } + finish: + if (NULL != countersAvailable) + { + *countersAvailable = tmpCounters; + } + return status; +} + +/*! Release a semaphore token. + * + * @param[in] semaphoreID The handle for the semaphore. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osSemaphoreRelease(palSemaphoreID_t semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + sem_t* sem = (sem_t*) semaphoreID; + + if (NULL == sem) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (-1 == sem_post(sem)) + { + if (EINVAL == errno) + { + status = PAL_ERR_RTOS_PARAMETER; + } + else + { /* max value of semaphore exeeded */ + PAL_LOG(ERR, "Rtos semaphore release error %d", errno); + status = PAL_ERR_GENERIC_FAILURE; + } + } + + return status; +} + +/*! Delete a semaphore object. + * + * @param[inout] semaphoreID: The ID of the semaphore to delete. In success, *semaphoreID = NULL. + * + * \return PAL_SUCCESS when the semaphore was deleted successfully, one of the following error codes in case of failure: + * PAL_ERR_RTOS_RESOURCE - Semaphore already released. + * PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid. + * \note After this call, the semaphore_id is no longer valid and cannot be used. + */ +palStatus_t pal_plat_osSemaphoreDelete(palSemaphoreID_t* semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + { + if (NULL == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + sem_t* sem = (sem_t*) (*semaphoreID); + if (NULL == sem) + { + status = PAL_ERR_RTOS_RESOURCE; + goto finish; + } + if (-1 == sem_destroy(sem)) + { + status = PAL_ERR_RTOS_PARAMETER; + goto finish; + } + + if (NULL != sem) + { + free(sem); + } + *semaphoreID = (palSemaphoreID_t) NULL; + } + finish: return status; +} + +typedef struct palMemoryPool +{ + void *start; + uint32_t blockCount; + uint32_t blockSize; + bool* allocated; +} palMemoryPool_t; + +/*! Create and initialize a memory pool. + * + * @param[in] blockSize The size of a single block in bytes. + * @param[in] blockCount The maximum number of blocks in the memory pool. + * @param[out] memoryPoolID The ID of the created memory pool, zero value indicates an error. + * + * \return PAL_SUCCESS when the memory pool was created successfully, a specific error in case of failure. + */ +palStatus_t pal_plat_osPoolCreate(uint32_t blockSize, uint32_t blockCount, palMemoryPoolID_t* memoryPoolID) +{ + palStatus_t status = PAL_SUCCESS; + palMemoryPool_t* mp = NULL; + { + + if ((NULL == memoryPoolID) || (0 == blockSize) || (0 == blockCount)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mp = (palMemoryPool_t*) malloc(sizeof(palMemoryPool_t)); + if (NULL == mp) + { + status = PAL_ERR_RTOS_NO_MEMORY; + goto finish; + } + + mp->blockCount = blockCount; + mp->blockSize = blockSize; + mp->allocated = NULL; + mp->start = malloc((size_t)blockCount * blockSize); + if (NULL == mp->start) + { + status = PAL_ERR_RTOS_NO_MEMORY; + goto finish; + } + + mp->allocated = (bool*) malloc(blockCount * sizeof(bool)); + if (NULL == mp->allocated) + { + status = PAL_ERR_RTOS_NO_MEMORY; + goto finish; + } + for (uint32_t i = 0; i < blockCount; i++) + { + mp->allocated[i] = false; + } + + *memoryPoolID = (palMemoryPoolID_t) mp; + } + + finish: + + if (PAL_SUCCESS != status) + { + if (NULL != mp) + { + if (NULL != mp->start) + { + free(mp->start); + } + if (NULL != mp->allocated) // in current code - we are not supposed to be here. + { + free(mp->allocated); + } + free(mp); + } + } + + return status; +} + +PAL_PRIVATE inline void* poolAlloc(palMemoryPoolID_t memoryPoolID, bool zero) +{ + if (NULL == (palMemoryPool_t*) memoryPoolID) + { + return NULL; + } + + palMemoryPool_t* mp = (palMemoryPool_t*) memoryPoolID; + + for (uint32_t i = 0; i < mp->blockCount; i++) + { + if (mp->allocated[i] == false) + { + mp->allocated[i] = true; + void* block = (mp->start + i * mp->blockSize); + if (zero == true) + { + memset(block, 0, mp->blockSize); + } + return block; + } + } + //we didn't find any + return NULL; +} +/*! Allocate a single memory block from a memory pool. + * + * @param[in] memoryPoolID The handle for the memory pool. + * + * \return A pointer to a single allocated memory from the pool, NULL in case of failure. + */ +void* pal_plat_osPoolAlloc(palMemoryPoolID_t memoryPoolID) +{ + return poolAlloc(memoryPoolID, false); +} + +/*! Allocate a single memory block from a memory pool and set memory block to zero. + * + * @param[in] memoryPoolID The handle for the memory pool. + * + * \return A pointer to a single allocated memory from the pool, NULL in case of failure. + */ +void* pal_plat_osPoolCAlloc(palMemoryPoolID_t memoryPoolID) +{ + return poolAlloc(memoryPoolID, true); +} + +/*! Return the memoryPoolID of the memory block back to a specific memory pool. + * + * @param[in] memoryPoolID The handle for the memory pool. + * @param[in] block The block to be freed. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osPoolFree(palMemoryPoolID_t memoryPoolID, void* block) +{ + palMemoryPool_t* mp = (palMemoryPool_t*) memoryPoolID; + if ((NULL == (palMemoryPool_t*) memoryPoolID) || (NULL == block) + || (mp->start > block) + || ((mp->start + mp->blockCount * mp->blockSize) < block) + || (0 != ((block - mp->start) % mp->blockSize))) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + int index = (block - mp->start) / mp->blockSize; + mp->allocated[index] = false; + return PAL_SUCCESS; +} + +/*! Delete a memory pool object. + * + * @param[inout] memoryPoolID The handle for the memory pool. In success, *memoryPoolID = NULL. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osPoolDestroy(palMemoryPoolID_t* memoryPoolID) +{ + if (NULL == memoryPoolID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + palMemoryPool_t* mp = (palMemoryPool_t*) *memoryPoolID; + *memoryPoolID = (palMemoryPoolID_t) NULL; // don't let anyone use it anymore. + free(mp->start); + free(mp->allocated); + free(mp); + return PAL_SUCCESS; +} + +typedef struct palMessageQ +{ + mqd_t handle; + char name[MQ_FILENAME_LEN]; +} palMessageQ_t; + +/*! Create and initialize a message queue. + * + * @param[in] messageQSize The size of the message queue. + * @param[out] messageQID The ID of the created message queue, zero value indicates an error. + * + * \return PAL_SUCCESS when the message queue was created successfully, a specific error in case of failure. + */ +palStatus_t pal_plat_osMessageQueueCreate(uint32_t messageQSize, palMessageQID_t* messageQID) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t *mq_h = NULL; + { + if (NULL == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + mq_h = malloc(sizeof(palMessageQ_t)); + if (NULL == mq_h) + { + status = PAL_ERR_NO_MEMORY; + goto finish; + } + // copy the name to be used, and advance it. + // Note - not thread safe!! + strncpy(mq_h->name, g_mqName, MQ_FILENAME_LEN-1); + mq_h->name[MQ_FILENAME_LEN-1] = '\0'; + nextMessageQName(); + + // set the attributes for the queue: + struct mq_attr mqAttr; + mqAttr.mq_flags = O_RDWR | O_CREAT | O_EXCL; // if the file for the messageQueue exists - we will fail. + mqAttr.mq_maxmsg = messageQSize; + mqAttr.mq_msgsize = sizeof(uint32_t); + mqAttr.mq_curmsgs = 0; + // create the message Queue. make sure no such filename exists. open with read/write/execute + // for user & group. + + mq_h->handle = mq_open(mq_h->name, O_RDWR | O_CREAT | O_EXCL, + S_IRWXU | S_IRWXG, &mqAttr); + if (-1 == mq_h->handle) + { + status = PAL_ERR_CREATION_FAILED; + goto finish; + } + + *messageQID = (palMessageQID_t) mq_h; + } + finish: + if (PAL_SUCCESS != status) + { + if (NULL != mq_h) + { + free(mq_h); + } + *messageQID = 0; + } + return status; +} + +/*! Put a message to a queue. + * + * @param[in] messageQID The handle for the message queue. + * @param[in] info The data to send. + * @param[in] timeout The timeout in milliseconds. + * + * All messages has the same priority (set as 0). + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osMessagePut(palMessageQID_t messageQID, uint32_t info, + uint32_t timeout) +{ + palStatus_t status = PAL_SUCCESS; + int stat; + + palMessageQ_t* mq = (palMessageQ_t*) messageQID; + if (NULL == mq) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (PAL_RTOS_WAIT_FOREVER != timeout) + { + /* calculate the wait absolute time */ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + ts.tv_sec += timeout / PAL_MILLI_PER_SECOND; + ts.tv_nsec += PAL_MILLI_TO_NANO(timeout); + //in case there is overflow in the nanoseconds. + ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; + ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND; + + while ((-1 + == (stat = mq_timedsend(mq->handle, (const char*) &info, + sizeof(uint32_t), 0, &ts))) && (EINTR == errno)) + { + continue; /* Restart if interrupted by handler */ + } + } + else + { // wait for ever + stat = mq_send(mq->handle, (const char*) &info, sizeof(uint32_t), 0); + } + + if (-1 == stat) + { + if (EBADF == errno) + { + status = PAL_ERR_INVALID_ARGUMENT; + } + else if (ETIMEDOUT == errno) + { + status = PAL_ERR_RTOS_TIMEOUT; + } + else + { + // all other cases - return generic error. + PAL_LOG(ERR, "Rtos put message status %d", stat); + status = PAL_ERR_GENERIC_FAILURE; + } + } + return status; +} + +/*! Get a message or wait for a message from a queue. + * + * @param[in] messageQID The handle for the message queue. + * @param[in] timeout The timeout in milliseconds. + * @param[out] messageValue The data to send. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, one of the following error codes in case of failure: + * PAL_ERR_RTOS_TIMEOUT - No message arrived during the timeout period. + * PAL_ERR_RTOS_RESOURCE - No message received and there was no timeout. + */ +palStatus_t pal_plat_osMessageGet(palMessageQID_t messageQID, uint32_t timeout, + uint32_t* messageValue) +{ + palStatus_t status = PAL_SUCCESS; + int stat; + + palMessageQ_t* mq = (palMessageQ_t*) messageQID; + if ((NULL == mq) || (NULL == messageValue)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (PAL_RTOS_WAIT_FOREVER != timeout) + { + /* calculate the wait absolute time */ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + ts.tv_sec += timeout / PAL_MILLI_PER_SECOND; + ts.tv_nsec += PAL_MILLI_TO_NANO(timeout); + // in case there is an overflow in the nanoseconds + ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; + ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND; + + while ((-1 + == (stat = mq_timedreceive(mq->handle, (char*) messageValue, + sizeof(uint32_t), 0, &ts))) && (EINTR == errno)) + { + continue; /* Restart if interrupted by handler */ + } + } + else + { // wait for ever + stat = mq_receive(mq->handle, (char*) messageValue, sizeof(uint32_t), 0); + } + + if (-1 == stat) + { + if (EBADF == errno) + { + status = PAL_ERR_INVALID_ARGUMENT; + } + else if (ETIMEDOUT == errno) + { + status = PAL_ERR_RTOS_TIMEOUT; + } + else + { + // all other cases - return resource error. + status = PAL_ERR_RTOS_RESOURCE; + } + } + + return status; +} + +/*! Delete a message queue object. + * + * @param[inout] messageQID The handle for the message queue. In success, *messageQID = NULL. + * + * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure. + */ +palStatus_t pal_plat_osMessageQueueDestroy(palMessageQID_t* messageQID) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t *mq = NULL; + { + if (NULL == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + //close the queue + mq = (palMessageQ_t *) *messageQID; + if (-1 == mq_close(mq->handle)) + { + status = PAL_ERR_INVALID_ARGUMENT; + goto finish; + } + + //unlink the file: + if (-1 == mq_unlink(mq->name)) + { + status = PAL_ERR_RTOS_RESOURCE; + goto finish; + } + } + finish: + free(mq); + *messageQID = (palMessageQID_t) NULL; + return status; +} + +/*! Perform an atomic increment for a signed32 bit value. + * + * @param[in,out] valuePtr The address of the value to increment. + * @param[in] increment The number by which to increment. + * + * \returns The value of the valuePtr after the increment operation. + */ +int32_t pal_plat_osAtomicIncrement(int32_t* valuePtr, int32_t increment) +{ + int32_t res = __sync_add_and_fetch(valuePtr, increment); + return res; +} + + +void *pal_plat_malloc(size_t len) +{ + return malloc(len); +} + + +void pal_plat_free(void * buffer) +{ + return free(buffer); +} + +palStatus_t pal_plat_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes) +{ + palStatus_t status = PAL_SUCCESS; + + status = pal_plat_getRandomBufferFromHW(randomBuf, bufSizeBytes); + return status; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Storage/FileSystem/pal_plat_fileSystem.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Storage/FileSystem/pal_plat_fileSystem.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,613 @@ + +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <dirent.h> +#include <stdlib.h> + +//PAL Includes +#include "pal.h" +#include "pal_plat_fileSystem.h" +#include "pal_plat_rtos.h" + + +#define PAL_FS_COPY_BUFFER_SIZE 256 //!< Size of the chunk to copy files + +PAL_PRIVATE const char* g_platOpenModeConvert[] = {"0", "r", "r+", "w+x", "w+"}; //!< platform convert table for \b fopen() modes +PAL_PRIVATE const int g_platSeekWhenceConvert[] = {0, SEEK_SET, SEEK_CUR, SEEK_END}; //!< platform convert table for \b fseek() relative position modes + + + +/*! \brief This function find the next file in a directory + * + * @param[in] *dh - Directory handler to an open DIR + * @param[out] CurrentEntry - entry for the file found in Directory (pre allocated) + * + * \return true - upon successful operation.\n + * + */ +PAL_PRIVATE bool pal_plat_findNextFile(DIR *dh, struct dirent ** CurrentEntry); + +/*! \brief This function translate the platform errors opcode to pal error codes + * + * @param[in] errorOpCode - platform opcode to be translated + * + * \return PAL_SUCCESS upon successful operation.\n + */ +PAL_PRIVATE palStatus_t pal_plat_errorTranslation (int errorOpCode); + + +/*! \brief This function build the full path name by adding the filename to the working path given in pathName arg + * + * @param[in] *pathName - pointer to the null-terminated string that specifies the directory name. + * @param[in] *fileName - pointer to the file name + * @param[out] *fullPath - pointer to the full path including the filename (pre allocated) + * @param[in] fullPathSize - size of fullPath + * + * \return PAL_SUCCESS upon successful operation.\n + * PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t + * + */ +PAL_PRIVATE palStatus_t pal_plat_addFileNameToPath(const char *pathName, const char * fileName, char * fullPath, size_t fullPathSize); + +/*! \brief This function copy one file from source folder to destination folder +* +* @param[in] pathNameSrc - Pointer to a null-terminated string that specifies the source dir. +* @param[in] pathNameDest - Pointer to a null-terminated string that specifies the destination dir +* @param[in] fileName - pointer the the file name +* +* \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t +* +* \note File should not be open.\n +* If the Destination file exist then it shall be truncated +* +*/ +PAL_PRIVATE palStatus_t pal_plat_fsCpFile(const char *pathNameSrc, char *pathNameDest, char * fileName); + +palStatus_t pal_plat_fsMkdir(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + int platStatus = 0; + + platStatus = mkdir(pathName, 0777); + if (platStatus) + { + ret = pal_plat_errorTranslation(errno); + } + return ret; +} + + +palStatus_t pal_plat_fsRmdir(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + + if (rmdir(pathName)) + { + if(errno == ENOENT) + { + ret = PAL_ERR_FS_NO_PATH; + } + else + { + ret = pal_plat_errorTranslation(errno); + } + } + return ret; +} + + +palStatus_t pal_plat_fsFopen(const char *pathName, pal_fsFileMode_t mode, palFileDescriptor_t *fd) +{ + palStatus_t ret = PAL_SUCCESS; + + *fd = (palFileDescriptor_t)fopen(pathName, g_platOpenModeConvert[mode]); + if ((*fd) == NULLPTR) + { + ret = pal_plat_errorTranslation(errno); + } + return ret; +} + + +palStatus_t pal_plat_fsFclose(palFileDescriptor_t *fd) +{ + palStatus_t ret = PAL_SUCCESS; + if (fclose((FILE *)*fd)) + { + ret = pal_plat_errorTranslation(errno); + } + + return ret; +} + + +palStatus_t pal_plat_fsFread(palFileDescriptor_t *fd, void * buffer, size_t numOfBytes, size_t *numberOfBytesRead) +{ + palStatus_t ret = PAL_SUCCESS; + *numberOfBytesRead = fread(buffer, 1, numOfBytes, (FILE *)*fd); + if (*numberOfBytesRead != numOfBytes) + { + if (ferror((FILE *)*fd)) + { + ret = PAL_ERR_FS_ERROR; + } + clearerr((FILE *)*fd); + } + return ret; +} + + +palStatus_t pal_plat_fsFwrite(palFileDescriptor_t *fd, const void *buffer, size_t numOfBytes, size_t *numberOfBytesWritten) +{ + palStatus_t ret = PAL_SUCCESS; + *numberOfBytesWritten = fwrite(buffer, 1, numOfBytes, (FILE *)*fd); + errno = 0; + if (*numberOfBytesWritten != numOfBytes) + { + ret = pal_plat_errorTranslation(errno); + if(ret == PAL_SUCCESS) + { + ret = PAL_ERR_FS_ACCESS_DENIED; + } + } + return ret; +} + + +palStatus_t pal_plat_fsFseek(palFileDescriptor_t *fd, int32_t offset, pal_fsOffset_t whence) +{ + palStatus_t ret = PAL_SUCCESS; + if (fseek((FILE *)*fd, offset, g_platSeekWhenceConvert[whence])) + { + ret = pal_plat_errorTranslation(errno); + } + return ret; +} + + +palStatus_t pal_plat_fsFtell(palFileDescriptor_t *fd, int32_t * pos) +{ + palStatus_t ret = PAL_SUCCESS; + long retPos = 0; + *pos = 0; + retPos = ftell((FILE *)*fd); + if (retPos < 0) + { + ret = pal_plat_errorTranslation(errno); + } + else + { + *pos = retPos; + } + return ret; +} + + +palStatus_t pal_plat_fsUnlink(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + + if (unlink(pathName)) + { + ret = pal_plat_errorTranslation(errno); + } + return ret; +} + + +palStatus_t pal_plat_fsRmFiles(const char *pathName) +{ + DIR *dh = NULL; //Directory handler + palStatus_t ret = PAL_SUCCESS; + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; //Buffer for coping the name and folder + struct dirent * currentEntry = NULL; //file Entry + + + dh = opendir(pathName); + + if (dh) + { + while(true) + { + if (!pal_plat_findNextFile(dh, ¤tEntry)) + { + ret = PAL_ERR_FS_ERROR_IN_SEARCHING; + break; + } + if (currentEntry) + { + pal_plat_addFileNameToPath(pathName, currentEntry->d_name, buffer, sizeof(buffer)); + if (currentEntry->d_type == DT_DIR) + { + pal_fsRmFiles(buffer); + if (rmdir(buffer)) + { + ret = pal_plat_errorTranslation(errno); + break; + } + } + else + { + if (unlink(buffer)) + { + ret = pal_plat_errorTranslation(errno); + break; + } + } + } + else + {//End of directory reached without errors break, close directory and exit + break; + } + }//while() + } + else//if (dh) + { + ret = PAL_ERR_FS_NO_PATH; + } + + if (dh) + { + closedir(dh); //Close DIR handler + } + return ret; +} + + +palStatus_t pal_plat_fsCpFolder(const char *pathNameSrc, char *pathNameDest) +{ + DIR *src_dh = NULL; //Directory for the source Directory handler + palStatus_t ret = PAL_SUCCESS; + struct dirent * currentEntry = NULL; //file Entry + + + src_dh = opendir(pathNameSrc); + if (src_dh == NULL) + { + ret = PAL_ERR_FS_NO_PATH; + } + else + { + while(true) + { + if (!pal_plat_findNextFile(src_dh, ¤tEntry)) + { + ret = PAL_ERR_FS_ERROR_IN_SEARCHING; + break; + } + if (currentEntry) + { + if (currentEntry->d_type == DT_DIR) + { + continue; + } + //copy the file to the destination + ret = pal_plat_fsCpFile(pathNameSrc, pathNameDest, currentEntry->d_name); + if (ret != PAL_SUCCESS) + { + break; + } + } + else + {//End of directory reached without errors break and close directory and exit + break; + } + }//while() + } + + if (src_dh) + { + closedir(src_dh); + } + return ret; +} + + +PAL_PRIVATE palStatus_t pal_plat_fsCpFile(const char *pathNameSrc, char *pathNameDest, char * fileName) +{ + palStatus_t ret = PAL_SUCCESS; + palFileDescriptor_t src_fd = 0; + palFileDescriptor_t dst_fd = 0; + char buffer_name[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; //Buffer for coping the name and folder + char * buffer = NULL; + size_t bytesCount = 0; + + //Add file name to path + pal_plat_addFileNameToPath(pathNameSrc, fileName, buffer_name, sizeof(buffer_name)); + src_fd = (palFileDescriptor_t)fopen(buffer_name, g_platOpenModeConvert[PAL_FS_FLAG_READONLY]); + if (src_fd == 0) + { + ret = pal_plat_errorTranslation(errno); + } + else + { + //Add file name to path + pal_plat_addFileNameToPath(pathNameDest, fileName, buffer_name, sizeof(buffer_name)); + dst_fd = (palFileDescriptor_t)fopen(buffer_name, g_platOpenModeConvert[PAL_FS_FLAG_READWRITETRUNC]); + if (dst_fd == 0) + { + ret = pal_plat_errorTranslation(errno); + } + else + { + buffer = (char*)pal_plat_malloc(PAL_FS_COPY_BUFFER_SIZE); + if (!buffer) + { + ret = PAL_ERR_RTOS_RESOURCE; + } + } + } + + if (ret == PAL_SUCCESS) + { + while (1) + { + ret = pal_fsFread(&src_fd, buffer, PAL_FS_COPY_BUFFER_SIZE, &bytesCount); + if (ret != PAL_SUCCESS) + { + break; + } + + //Check if end of file reached + if (bytesCount == 0) + { + break; + } + + ret = pal_fsFwrite(&dst_fd, buffer, bytesCount, &bytesCount); + if (ret != PAL_SUCCESS) + { + break; + } + } + } + + if (src_fd != 0) + { + pal_fsFclose(&src_fd); + } + if (dst_fd != 0) + { + pal_fsFclose(&dst_fd); + } + if (buffer) + { + pal_plat_free(buffer); + } + return ret; +} + + +const char* pal_plat_fsGetDefaultRootFolder(pal_fsStorageID_t dataID) +{ + const char* returnedRoot = NULL; + if (PAL_FS_PARTITION_PRIMARY == dataID) + { + returnedRoot = PAL_FS_MOUNT_POINT_PRIMARY; + } + else if (PAL_FS_PARTITION_SECONDARY == dataID) + { + returnedRoot = PAL_FS_MOUNT_POINT_SECONDARY; + } + + return returnedRoot; +} + + +PAL_PRIVATE bool pal_plat_findNextFile(DIR *dh, struct dirent ** CurrentEntry) +{ + bool ret = true; + bool skip = false; + bool foundFile = false; + + do + { + errno = 0; + *CurrentEntry = readdir(dh); + if (*CurrentEntry) + { + /* Skip the names "." and ".." as we don't want to remove them. also make sure that the current entry point to REGULER file*/ + skip = (!strcmp((*CurrentEntry)->d_name, ".")) || (!strcmp((*CurrentEntry)->d_name, "..")); + if (skip) + { + continue; + } + else + { + foundFile = true; + } + } + else + {//Check if EOF reached + if (errno) + {//NOT!!! EOF other error + ret = false; + } + break; //Break from while + } + } + while((!foundFile) && (ret)); //While file has been found or ret is set to false + return ret; +} + +PAL_PRIVATE palStatus_t pal_plat_addFileNameToPath(const char *pathName, const char * fileName, char * fullPath, size_t fullPathSize) +{ + palStatus_t ret = PAL_SUCCESS; + if ((strlen(pathName) >= PAL_MAX_FOLDER_DEPTH_CHAR) || (strlen(fileName) >= PAL_MAX_FULL_FILE_NAME)) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else if (fullPath) + { + strncpy(fullPath, pathName, fullPathSize - 1); + fullPath[fullPathSize - 1] = '\0'; + strncat(fullPath, "/", fullPathSize - strlen(fullPath) - 1); + strncat(fullPath, fileName, fullPathSize - strlen(fullPath) - 1); + } + else + { + ret = PAL_ERR_RTOS_RESOURCE; + } + return ret; +} + + + + +PAL_PRIVATE palStatus_t pal_plat_errorTranslation (int errorOpCode) +{ + palStatus_t ret = PAL_SUCCESS; + + switch(errorOpCode) + { + case 0: + break; + case EACCES: + case EFAULT: + case EROFS: + ret = PAL_ERR_FS_ACCESS_DENIED; + break; + + case EBUSY : + ret = PAL_ERR_FS_BUSY; + break; + + case EEXIST: + ret = PAL_ERR_FS_NAME_ALREADY_EXIST; + break; + + case ENAMETOOLONG: + ret = PAL_ERR_FS_FILENAME_LENGTH; + break; + + case EBADF: + ret = PAL_ERR_FS_BAD_FD; + break; + + case EINVAL: + ret = PAL_ERR_FS_INVALID_ARGUMENT; + break; + + case EISDIR: + ret = PAL_ERR_FS_FILE_IS_DIR; + break; + + case ENOTEMPTY: + ret = PAL_ERR_FS_DIR_NOT_EMPTY; + break; + + case ENOENT: + ret = PAL_ERR_FS_NO_FILE; + break; + + default: + ret = PAL_ERR_FS_ERROR; + break; + } + return ret; +} + + +size_t pal_plat_fsSizeCheck(const char *stringToChk) +{ + size_t length = 0; + length = strlen(stringToChk); + return length; +} + + +palStatus_t pal_plat_fsFormat(pal_fsStorageID_t dataID) +{ + char rootFolder[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + palStatus_t result = PAL_SUCCESS; + result = pal_fsGetMountPoint(dataID, PAL_MAX_FILE_AND_FOLDER_LENGTH, rootFolder); + if (PAL_SUCCESS == result) + { +#if PAL_FS_RM_INSTEAD_OF_FORMAT + result = pal_plat_fsRmFiles(rootFolder); + if (PAL_SUCCESS != result) + { + PAL_LOG(ERR,"(%s:%d) pal_plat_fsRmFiles failed ",__FILE__,__LINE__); + } +#else + int ret; + FILE* fp = NULL; + char buffer[PAL_FORMAT_CMD_MAX_LENGTH] = {0}; + char deviceName[PAL_DEVICE_NAME_MAX_LENGTH] = {0}; + + ret = snprintf(buffer, sizeof(buffer),"df -h | grep %s | awk -F\' \' \'{print $1}\' 2>&1",rootFolder); // get the partition name or the error + PAL_LOG(DBG,"system call command is %s ret = %d\r\n",buffer,ret); + if (ret > 0) // snprintf succeeded + { + fp = popen(buffer,"r"); + if (NULL != fp) + { + if(NULL != fgets(deviceName, sizeof(deviceName),fp)) + { + if (deviceName[strnlen(deviceName, sizeof(deviceName))-1] == '\n') + { + deviceName[strnlen(deviceName, sizeof(deviceName))-1] = '\0'; // remove the '\n' if found + } + ret = umount(rootFolder); + if (0 == ret) + { + ret = snprintf(buffer, sizeof(buffer), PAL_FS_FORMAT_COMMAND, PAL_PARTITION_FORMAT_TYPE, deviceName); + if (ret > 0) + { + ret = system(buffer); + if (-1 != ret) + { + ret = mount(deviceName, rootFolder, PAL_PARTITION_FORMAT_TYPE, 0 ,PARTITION_FORMAT_ADDITIONAL_PARAMS); + if (ret < 0) + { + PAL_LOG(ERR,"(%s:%d)cannot mount %s on %s using " PAL_PARTITION_FORMAT_TYPE,__FILE__,__LINE__,deviceName,rootFolder); + result = PAL_ERR_GENERIC_FAILURE; + } + } + else + { + PAL_LOG(ERR,"(%s:%d)system call to format failed ",__FILE__,__LINE__); + result = PAL_ERR_SYSCALL_FAILED; + } + } + else + { + PAL_LOG(ERR,"(%s:%d)cannot create command with snprintf ",__FILE__,__LINE__); + result = PAL_ERR_BUFFER_TOO_SMALL; + } + } + else + { + PAL_LOG(ERR,"(%s:%d)cannot unmount %s",__FILE__,__LINE__,rootFolder); + result = PAL_ERR_GENERIC_FAILURE; + } + } + + else + { + PAL_LOG(ERR,"(%s:%d)cannot read from pipe",__FILE__,__LINE__); + result = PAL_ERR_GENERIC_FAILURE; + } + pclose(fp); + } + else + { + PAL_LOG(ERR,"(%s:%d)popen had failed ",__FILE__,__LINE__); + result = PAL_ERR_SYSCALL_FAILED; + } + } + else + { + PAL_LOG(ERR,"(%s:%d)cannot create command with snprintf ",__FILE__,__LINE__); + result = PAL_ERR_BUFFER_TOO_SMALL; + } +#endif //PAL_FS_RM_INSTEAD_OF_FORMAT + } + return result; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Storage/Flash/pal_plat_internalFlash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Storage/Flash/pal_plat_internalFlash.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "pal_plat_internalFlash.h" + + +////////////////////////////PRIVATE/////////////////////////////////// +////////////////////////////END PRIVATE//////////////////////////////// + +palStatus_t pal_plat_internalFlashInit(void) +{ + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_internalFlashDeInit(void) +{ + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_internalFlashWrite(const size_t size, const uint32_t address, const uint32_t * buffer) +{ + return PAL_ERR_NOT_SUPPORTED; +} + + +palStatus_t pal_plat_internalFlashRead(const size_t size, const uint32_t address, uint32_t * buffer) +{ + return PAL_ERR_NOT_SUPPORTED; +} + + +palStatus_t pal_plat_internalFlashErase(uint32_t address, size_t size) +{ + return PAL_ERR_NOT_SUPPORTED; +} + + +size_t pal_plat_internalFlashGetPageSize(void) +{ + return 0; +} + + +size_t pal_plat_internalFlashGetSectorSize(uint32_t address) +{ + return 0; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Update/pal_plat_update.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/Linux/Update/pal_plat_update.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,90 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal_plat_update.h" + + +palStatus_t pal_plat_imageInitAPI(palImageSignalEvent_t CBfunction) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageDeInit(void) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageGetMaxNumberOfImages(uint8_t *imageNumber) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageSetVersion(palImageId_t imageId, const palConstBuffer_t* version) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageGetDirectMemAccess(palImageId_t imageId, void** imagePtr, size_t *imageSizeInBytes) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageActivate(palImageId_t imageId) +{ + + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageGetActiveHash(palBuffer_t* hash) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageGetActiveVersion (palBuffer_t* version) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageWriteHashToMemory(const palConstBuffer_t* const hashValue) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageSetHeader(palImageId_t imageId, palImageHeaderDeails_t* details) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageReserveSpace(palImageId_t imageId, size_t imageSize) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageWrite(palImageId_t imageId, size_t offset, palConstBuffer_t *chunk) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageReadToBuffer(palImageId_t imageId, size_t offset, palBuffer_t *chunk) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +// +palStatus_t pal_plat_imageFlush(palImageId_t package_id) +{ + return PAL_ERR_NOT_IMPLEMENTED; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/Networking/pal_plat_network.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/Networking/pal_plat_network.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1438 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#include "pal.h" +#include "pal_plat_network.h" + +#include "mbed.h" + +typedef void(*palSelectCallbackFunction_t)(); + +#if defined (__CC_ARM) || defined(__IAR_SYSTEMS_ICC__) + +void palSelectCallbackNull(void* arg) +{ +} + +#define NULL_FUNCTION palSelectCallbackNull + + +#elif defined (__GNUC__) + +#define NULL_FUNCTION NULL + +#endif + + +#define PAL_SOCKET_OPTION_ERROR (-1) + + +typedef enum { + PAL_PLAT_SOCKET_NOT_CONNECTED = 0, + PAL_PLAT_SOCKET_CONNECTING = 1, + PAL_PLAT_SOCKET_CONNECTED = 2 + +} palConnectState; + + +void palConnectCallBack() +{ +} + + class PALSocketWrapper + { + public: + PALSocketWrapper() : initialized(false), activeSocket(NULL), isNonBlockingOnCreation(false), callbackFunction(NULL_FUNCTION), callbackArgument(NULL), selectCallbackFunction(NULL), connectState(PAL_PLAT_SOCKET_NOT_CONNECTED), socketTypeVal(PAL_SOCK_DGRAM), attachCallbackObject(NULL), rxBuffer(0), rxBufferSet(false) + { + + } + nsapi_error_t initialize(Socket* socket, palSocketType_t socketType,bool isNonBlocking, palAsyncSocketCallback_t callback, void* argument); + palAsyncSocketCallback_t getCallback( ) const; + void* getCallbackArgument() const ; + bool isNonBlocking() const ; + bool isConnected() const ; + void attachCallback(); + Socket* getActiveSocket(); + palSocketType_t getSocketType() const; + char getAndResetRxBuffer(); + bool isRxBufferSet() const; + palStatus_t setRxBuffer(char data); + void updateCallback(/*palAsyncSocketCallback_t callback, void* argument,*/ palSelectCallbackFunction_t selectCallback); + virtual ~PALSocketWrapper() + { + if (NULL != activeSocket ) + { + activeSocket->close(); + delete activeSocket; + } + } + + // nsapi socket funcitons exposed: + nsapi_error_t close(); + nsapi_error_t bind(const SocketAddress &address); + void set_blocking(bool blocking); + void set_timeout(int timeout); + nsapi_error_t setsockopt(int level, int optname, const void *optval, unsigned optlen); + nsapi_error_t getsockopt(int level, int optname, void *optval, unsigned *optlen); + void attach(mbed::Callback<void()> func); + //void sigio(mbed::Callback<void()> func); // switch attach to sigio for verison 5.4 + // nsapi UDP socket funcitons exposed: + nsapi_size_or_error_t recvfrom(SocketAddress *address, void *data, nsapi_size_t size); + nsapi_size_or_error_t sendto(const SocketAddress &address, const void *data, nsapi_size_t size); + //nsapi TCP socket funcitons exposed: + nsapi_error_t connect(const SocketAddress &address); + nsapi_size_or_error_t send(const void *data, nsapi_size_t size); + nsapi_size_or_error_t recv(void *data, nsapi_size_t size); + //nsapi TCP server socket funcitons exposed: + nsapi_error_t listen(int backlog = 1); + nsapi_error_t accept(TCPSocket *connection, SocketAddress *address = NULL); + + + private: + bool initialized; + Socket* activeSocket; + bool isNonBlockingOnCreation; + palAsyncSocketCallback_t callbackFunction; + void* callbackArgument; + palSelectCallbackFunction_t selectCallbackFunction; + palConnectState connectState; + palSocketType_t socketTypeVal; + Callback<void()> attachCallbackObject; + events::EventQueue* shared_event_queue; + char rxBuffer; + bool rxBufferSet; + }; + + void PALSocketWrapper::updateCallback( palSelectCallbackFunction_t selectCallback ) + { + bool shouldSetCallback = false; + if ((NULL == selectCallbackFunction) && (NULL == callbackFunction)) //callback already set - no need to set again + { + shouldSetCallback = true; + } + + selectCallbackFunction = selectCallback; + + if ((NULL != selectCallbackFunction) || (NULL != callbackFunction)) + { + if (shouldSetCallback) + { + Callback<void()> mycall(this, &PALSocketWrapper::attachCallback); + activeSocket->sigio(mycall); + } + } + else + { + activeSocket->sigio(NULL); + } + } + + Socket* PALSocketWrapper::getActiveSocket() + { + return activeSocket; + } + + char PALSocketWrapper::getAndResetRxBuffer() + { + rxBufferSet = false; + return rxBuffer; + } + + bool PALSocketWrapper::isRxBufferSet() const + { + return rxBufferSet; + } + + palStatus_t PALSocketWrapper::setRxBuffer( char data) + { + if (true == rxBufferSet) + { + return PAL_ERR_SOCKET_GENERIC; // should never overwrite buffer. + } + rxBuffer = data; + rxBufferSet = true; + + return PAL_SUCCESS; + } + + palAsyncSocketCallback_t PALSocketWrapper::getCallback() const + { + return callbackFunction; + } + + palSocketType_t PALSocketWrapper::getSocketType() const + { + return socketTypeVal; + } + + + void * PALSocketWrapper::getCallbackArgument() const + { + return callbackArgument; + } + + bool PALSocketWrapper::isNonBlocking() const + { + return isNonBlockingOnCreation; + } + + bool PALSocketWrapper::isConnected() const + { + return ((PAL_PLAT_SOCKET_CONNECTED == connectState) && (PAL_SOCK_STREAM == socketTypeVal)); + } + + void PALSocketWrapper::attachCallback() + { + if (NULL != callbackFunction) + { + // Since the socket callback may be called from interrupt context, depending on the + // network interface used, we need to debounce the client callback to happen from + // a thread context to keep client side implementation platform agnostic. + assert(shared_event_queue); + shared_event_queue->call(callbackFunction, callbackArgument); + } + if (NULL != selectCallbackFunction) + { + // Note: this is not tested yet + assert(shared_event_queue); + shared_event_queue->call(selectCallbackFunction); + } + if (PAL_PLAT_SOCKET_CONNECTING == connectState) + { + connectState = PAL_PLAT_SOCKET_CONNECTED;// if we got a callback while connecting assume we are connected + if (palConnectCallBack == selectCallbackFunction) + { + selectCallbackFunction = NULL; + } + } + } + + nsapi_error_t PALSocketWrapper::initialize(Socket* socket, palSocketType_t socketType, bool isNonBlocking, palAsyncSocketCallback_t callback, void* argument) + { + // check that we got a valid socket and the socket type is supported + if ((true == initialized) || (NULL == socket) || ((socketType != PAL_SOCK_STREAM) && (socketType != PAL_SOCK_STREAM_SERVER) && (socketType != PAL_SOCK_DGRAM))) + { + return NSAPI_ERROR_PARAMETER; + } + + // Pre fetch and store the shared queue used for bouncing the callbacks out of interrupt + // context, as the user of it may be ran from interrupt and it can't go and start + // creating worker threads from there. + // Note: the code uses mbed_highprio_event_queue() instead of mbed_event_queue() + // as the high priority queue and its thread is likely there already thanks to + // arm_hal_timer.cpp. Technically the client side does not really care, if the events + // were delayed a bit by other events or not. + shared_event_queue = mbed_highprio_event_queue(); + if (shared_event_queue == NULL) + { + return NSAPI_ERROR_UNSUPPORTED; + } + + Callback<void()> mycall(this, &PALSocketWrapper::attachCallback); + attachCallbackObject = mycall; + activeSocket = socket; + socketTypeVal = socketType; + isNonBlockingOnCreation = isNonBlocking; + activeSocket->set_blocking(!isNonBlocking); + if (NULL != callback) + { + callbackFunction = callback; + callbackArgument = argument; + activeSocket->sigio(attachCallbackObject); + } + + initialized = true; + return NSAPI_ERROR_OK; + } + + nsapi_error_t PALSocketWrapper::close() + { + nsapi_error_t status= NSAPI_ERROR_OK; + if (NULL != activeSocket) + { + status = activeSocket->close(); + delete activeSocket; + activeSocket = NULL; + } + return status; + } + + nsapi_error_t PALSocketWrapper::bind(const SocketAddress &address) + { + nsapi_error_t status = NSAPI_ERROR_OK; + if (false == initialized) + { + return NSAPI_ERROR_PARAMETER; + } + status= activeSocket->bind(address); + return status; + } + void PALSocketWrapper::set_blocking(bool blocking) + { + activeSocket->set_blocking(blocking); + } + void PALSocketWrapper::set_timeout(int timeout) + { + activeSocket->set_timeout(timeout); + } + nsapi_error_t PALSocketWrapper::setsockopt(int level, int optname, const void *optval, unsigned optlen) + { + nsapi_error_t status = NSAPI_ERROR_OK; + if (false == initialized) + { + return NSAPI_ERROR_PARAMETER; + } + status = activeSocket->setsockopt(level, optname, optval, optlen); + return status; + } + nsapi_error_t PALSocketWrapper::getsockopt(int level, int optname, void *optval, unsigned *optlen) + { + nsapi_error_t status = NSAPI_ERROR_OK; + if (false == initialized) + { + return NSAPI_ERROR_PARAMETER; + } + status = activeSocket->getsockopt( level, optname, optval, optlen); + return status; + } + void PALSocketWrapper::attach(mbed::Callback<void()> func) + { + activeSocket->sigio(func); + } + //void sigio(mbed::Callback<void()> func); // switch attach to sigio for verison 5.4 + // nsapi UDP socket funcitons exposed: + nsapi_size_or_error_t PALSocketWrapper::recvfrom(SocketAddress *address, void *data, nsapi_size_t size) + { + nsapi_size_or_error_t status = NSAPI_ERROR_OK; + if ((false == initialized) || (PAL_SOCK_DGRAM != socketTypeVal)) // udp sockets only + { + return NSAPI_ERROR_PARAMETER; + } + status = ((UDPSocket*)activeSocket)->recvfrom(address, data, size); + return status; + } + nsapi_size_or_error_t PALSocketWrapper::sendto(const SocketAddress &address, const void *data, nsapi_size_t size) + { + nsapi_size_or_error_t status = NSAPI_ERROR_OK; + if ((false == initialized) || (PAL_SOCK_DGRAM != socketTypeVal)) // udp sockets only + { + return NSAPI_ERROR_PARAMETER; + } + status = ((UDPSocket*)activeSocket)->sendto(address, data, size); + return status; + } + //nsapi TCP socket funcitons exposed: + nsapi_error_t PALSocketWrapper::connect(const SocketAddress &address) + { + nsapi_error_t status = NSAPI_ERROR_OK; + if ((false == initialized) || (PAL_SOCK_STREAM != socketTypeVal)) // tcp sockets only + { + return NSAPI_ERROR_PARAMETER; + } + connectState = PAL_PLAT_SOCKET_CONNECTING; + updateCallback(palConnectCallBack); // make sure callback is enabled to see if we get callback to signal connections end + status = ((TCPSocket*)activeSocket)->connect(address); + if (status >= 0 || status == NSAPI_ERROR_IS_CONNECTED) + { + connectState = PAL_PLAT_SOCKET_CONNECTED; + updateCallback(NULL); // make sure callback is enabled to see if we get callback to signal connections end + } + else if ((NSAPI_ERROR_WOULD_BLOCK != status) && (NSAPI_ERROR_IN_PROGRESS != status) && (NSAPI_ERROR_ALREADY != status)) + { + connectState = PAL_PLAT_SOCKET_NOT_CONNECTED; + } + return status; + } + nsapi_size_or_error_t PALSocketWrapper::send(const void *data, nsapi_size_t size) + { + nsapi_size_or_error_t status = NSAPI_ERROR_OK; + if ((false == initialized) || (PAL_SOCK_STREAM != socketTypeVal)) // tcp sockets only + { + return NSAPI_ERROR_PARAMETER; + } + status = ((TCPSocket*)activeSocket)->send( data, size); + return status; + } + nsapi_size_or_error_t PALSocketWrapper::recv(void *data, nsapi_size_t size) + { + nsapi_size_or_error_t status = NSAPI_ERROR_OK; + if ((false == initialized) || (PAL_SOCK_STREAM != socketTypeVal)) // tcp sockets only + { + return NSAPI_ERROR_PARAMETER; + } + status = ((TCPSocket*)activeSocket)->recv(data, size); + return status; + } + //nsapi TCP server socket funcitons exposed: + nsapi_error_t PALSocketWrapper::listen(int backlog ) + { + nsapi_error_t status = NSAPI_ERROR_OK; + if ((false == initialized) || (PAL_SOCK_STREAM_SERVER != socketTypeVal)) // udp sockets only + { + return NSAPI_ERROR_PARAMETER; + } + status = ((TCPServer*)activeSocket)->listen(backlog); + return status; + } + nsapi_error_t PALSocketWrapper::accept(TCPSocket *connection, SocketAddress *address) + { + nsapi_error_t status = NSAPI_ERROR_OK; + if ((false == initialized) || (PAL_SOCK_STREAM_SERVER != socketTypeVal)) // udp sockets only + { + return NSAPI_ERROR_PARAMETER; + } + status = ((TCPServer*)activeSocket)->accept(connection, address); + return status; + } + + + + +PAL_PRIVATE NetworkInterface* s_pal_networkInterfacesSupported[PAL_MAX_SUPORTED_NET_INTERFACES] = { 0 }; + +PAL_PRIVATE uint32_t s_pal_numberOFInterfaces = 0; + +PAL_PRIVATE uint32_t s_pal_network_initialized = 0; + +PAL_PRIVATE palStatus_t translateErrorToPALError(int errnoValue) +{ + palStatus_t status; + switch (errnoValue) + { + case NSAPI_ERROR_NO_MEMORY: + status = PAL_ERR_NO_MEMORY; + break; + case NSAPI_ERROR_PARAMETER: + status = PAL_ERR_SOCKET_INVALID_VALUE; + break; + case NSAPI_ERROR_WOULD_BLOCK: + status = PAL_ERR_SOCKET_WOULD_BLOCK; + break; + case NSAPI_ERROR_DNS_FAILURE: + status = PAL_ERR_SOCKET_DNS_ERROR; + break; + case NSAPI_ERROR_DHCP_FAILURE: + status = PAL_ERR_SOCKET_HDCP_ERROR; + break; + case NSAPI_ERROR_AUTH_FAILURE: + status = PAL_ERR_SOCKET_AUTH_ERROR; + break; + case NSAPI_ERROR_NO_ADDRESS: + status = PAL_ERR_SOCKET_INVALID_ADDRESS; + break; + case NSAPI_ERROR_NO_CONNECTION: + status = PAL_ERR_SOCKET_NOT_CONNECTED; + break; + case NSAPI_ERROR_DEVICE_ERROR: + status = PAL_ERR_SOCKET_INPUT_OUTPUT_ERROR; + break; + case NSAPI_ERROR_UNSUPPORTED: + status = PAL_ERR_NOT_SUPPORTED; + break; + case NSAPI_ERROR_NO_SOCKET: + status = PAL_ERR_SOCKET_ALLOCATION_FAILED; + break; + case NSAPI_ERROR_IN_PROGRESS: + case NSAPI_ERROR_ALREADY: + status = PAL_ERR_SOCKET_IN_PROGRES; + break; + case NSAPI_ERROR_IS_CONNECTED: + status = PAL_SUCCESS; + break; + default: + status = PAL_ERR_SOCKET_GENERIC; + break; + } + return status; +} + +palStatus_t pal_plat_socketsInit(void* context) +{ + (void)context; // replace with macro + int result = PAL_SUCCESS; + if (s_pal_network_initialized == 1) + { + return PAL_SUCCESS; // already initialized. + } + + s_pal_network_initialized = 1; + + return result; +} + +palStatus_t pal_plat_registerNetworkInterface(void* context, uint32_t* interfaceIndex) +{ + palStatus_t result = PAL_SUCCESS; + uint32_t index = 0; + bool found = false; + + for (index = 0; index < s_pal_numberOFInterfaces; index++) // if specific context already registered return exisitng index instead of registering again. + { + if (s_pal_networkInterfacesSupported[index] == context) + { + found = true; + *interfaceIndex = index; + break; + } + } + + if (false == found) + { + if (s_pal_numberOFInterfaces < PAL_MAX_SUPORTED_NET_INTERFACES) + { + s_pal_networkInterfacesSupported[s_pal_numberOFInterfaces] = (NetworkInterface*)context; + *interfaceIndex = s_pal_numberOFInterfaces; + ++s_pal_numberOFInterfaces; + } + else + { + result = PAL_ERR_SOCKET_MAX_NUMBER_OF_INTERFACES_REACHED; + } + } + + return result; +} + +palStatus_t pal_plat_socketsTerminate(void* context) +{ + (void)context; // replace with macro + return PAL_SUCCESS; +} + +PAL_PRIVATE int translateNSAPItoPALSocketOption(int option) +{ + int optionVal = PAL_SOCKET_OPTION_ERROR; + switch (option) + { + case PAL_SO_REUSEADDR: + optionVal = NSAPI_REUSEADDR; + break; +#if PAL_NET_TCP_AND_TLS_SUPPORT // socket options below supported only if TCP is supported. + case PAL_SO_KEEPALIVE: + optionVal = NSAPI_KEEPALIVE; + break; + case PAL_SO_KEEPIDLE: + optionVal = NSAPI_KEEPIDLE; + break; + case PAL_SO_KEEPINTVL: + optionVal = NSAPI_KEEPINTVL; + break; +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + case PAL_SO_SNDTIMEO: + case PAL_SO_RCVTIMEO: + default: + optionVal = PAL_SOCKET_OPTION_ERROR; + } + return optionVal; +} + + +PAL_PRIVATE palStatus_t palSockAddrToSocketAddress(const palSocketAddress_t* palAddr, int length, SocketAddress& output) +{ + palStatus_t result = PAL_SUCCESS; + uint16_t port = 0; + nsapi_version_t version = NSAPI_IPv4; + + if (NULL == palAddr) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + result = pal_getSockAddrPort(palAddr, &port); + if (result != PAL_SUCCESS) + { + return result; + } + output.set_port(port); + + if (PAL_AF_INET == palAddr->addressType) + { + palIpV4Addr_t ipV4Addr; + version = NSAPI_IPv4; + result = pal_getSockAddrIPV4Addr(palAddr, ipV4Addr); + if (result == PAL_SUCCESS) + { + output.set_ip_bytes(&ipV4Addr, version); + } + } + else if (PAL_AF_INET6 == palAddr->addressType) + { + palIpV6Addr_t ipV6Addr; + version = NSAPI_IPv6; + result = pal_getSockAddrIPV6Addr(palAddr, ipV6Addr); + if (result == PAL_SUCCESS) + { + output.set_ip_bytes(&ipV6Addr, version); + } + } + + return result; +} + +PAL_PRIVATE palStatus_t socketAddressToPalSockAddr(SocketAddress& input, palSocketAddress_t* out, palSocketLength_t* length) +{ + palStatus_t result = PAL_SUCCESS; + int index = 0; + + if ((NULL == out) && (NULL == length)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (input.get_ip_version() == NSAPI_IPv4) + { + palIpV4Addr_t addr; + const void* tmp = input.get_ip_bytes(); + for (index = 0; index < PAL_IPV4_ADDRESS_SIZE; index++) + { + addr[index] = ((const uint8_t*)tmp)[index]; + } + result = pal_setSockAddrIPV4Addr(out, addr); + *length = PAL_NET_MAX_ADDR_SIZE; // TODO: check + + } + else if (input.get_ip_version() == NSAPI_IPv6) + { + palIpV6Addr_t addr; + const void* tmp = input.get_ip_bytes(); + for (index = 0; index < PAL_IPV6_ADDRESS_SIZE; index++) + { + addr[index] = ((const uint8_t*)tmp)[index]; + } + result = pal_setSockAddrIPV6Addr(out, addr); + *length = PAL_NET_MAX_ADDR_SIZE; // TODO: check + } + else + { + result = PAL_ERR_SOCKET_INVALID_ADDRESS_FAMILY; + } + + if (result == PAL_SUCCESS) + { + result = pal_setSockAddrPort(out, input.get_port()); + } + return result; +} + + + + +palStatus_t pal_plat_socket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palSocket_t* socket) +{ + int result = PAL_SUCCESS; + PALSocketWrapper* socketObj = NULL; + Socket* internalSocket = NULL; + + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (PAL_NET_DEFAULT_INTERFACE == interfaceNum) + { + interfaceNum = 0; + } + + if ((s_pal_numberOFInterfaces > interfaceNum) && (PAL_SOCK_DGRAM == type) && ((PAL_AF_INET == domain) || (PAL_AF_INET6 == domain) || (PAL_AF_UNSPEC == domain))) // check correct parameters for UDP socket + { + internalSocket = new UDPSocket(s_pal_networkInterfacesSupported[interfaceNum]); + } +#if PAL_NET_TCP_AND_TLS_SUPPORT // functionality below supported only in case TCP is supported. + else if ((s_pal_numberOFInterfaces > interfaceNum) && (PAL_SOCK_STREAM == type) && ((PAL_AF_INET == domain) || (PAL_AF_INET6 == domain) || (PAL_AF_UNSPEC == domain))) // check correct parameters for TCP socket + { + internalSocket = new TCPSocket(s_pal_networkInterfacesSupported[interfaceNum]); + } + else if ((s_pal_numberOFInterfaces > interfaceNum) && (PAL_SOCK_STREAM_SERVER == type) && ((PAL_AF_INET == domain) || (PAL_AF_INET6 == domain) || (PAL_AF_UNSPEC == domain))) // check correct parameters for TCP Server socket + { + internalSocket = new TCPServer(s_pal_networkInterfacesSupported[interfaceNum]); + } +#endif + else + { + result = PAL_ERR_INVALID_ARGUMENT; + } + + if ((PAL_SUCCESS == result ) && (NULL == internalSocket)) + { + result = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == result) + { + + socketObj = new PALSocketWrapper(); + if (NULL != socketObj) + { + if (0 == socketObj->initialize(internalSocket, type, nonBlockingSocket, NULL, NULL)) + { + *socket = (palSocket_t)socketObj; + } + else + { + result = PAL_ERR_INVALID_ARGUMENT; + } + + } + else + { + delete internalSocket; + result = PAL_ERR_NO_MEMORY; + } + + } + + if (PAL_SUCCESS != result) //cleanup + { + if (NULL != internalSocket) + { + delete internalSocket; + } + if (NULL != socketObj) + { + delete socketObj; + } + } + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + + +palStatus_t pal_plat_getSocketOptions(palSocket_t socket, palSocketOptionName_t optionName, void* optionValue, palSocketLength_t* optionLength) +{ + int result = PAL_SUCCESS; + unsigned int length = *optionLength; + PALSocketWrapper* socketObj = (PALSocketWrapper*)socket; + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + int socketOption = translateNSAPItoPALSocketOption(optionName); + + if (PAL_SOCKET_OPTION_ERROR != socketOption) + { + result = socketObj->getsockopt(NSAPI_SOCKET, socketOption, optionValue, &length); + if (result < 0) + { + result = translateErrorToPALError(result); + } + else + { + *optionLength = length; + } + + } + else + { + // in MBED socket timeouts are write only via the API - not supported though socket options. + result = PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED; + } + + return result; +} + + +palStatus_t pal_plat_setSocketOptions(palSocket_t socket, int optionName, const void* optionValue, palSocketLength_t optionLength) +{ + int result = PAL_SUCCESS; + PALSocketWrapper* socketObj = (PALSocketWrapper*)socket; + int socketOption = PAL_SOCKET_OPTION_ERROR; + + if (NULL == socket) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + socketOption = translateNSAPItoPALSocketOption(optionName); + if (PAL_SOCKET_OPTION_ERROR != socketOption) + { + if (PAL_SO_REUSEADDR == optionName) + { + result = socketObj->setsockopt(NSAPI_SOCKET, socketOption, optionValue, optionLength); + } +#if PAL_NET_TCP_AND_TLS_SUPPORT + else if (PAL_SO_KEEPIDLE == optionName || + PAL_SO_KEEPINTVL == optionName ) + { + // Timeouts are in milliseconds + uint32_t timeout = (*(int *)optionValue) * 1000; + result = socketObj->setsockopt(NSAPI_SOCKET, socketOption, (void*)&timeout, sizeof(timeout)); + } +#endif + else + { + result = socketObj->setsockopt(NSAPI_SOCKET, socketOption, optionValue, optionLength); + } + + if (result < 0) + { + result = translateErrorToPALError(result); + } + } + else + { + if ((PAL_SO_SNDTIMEO == optionName) || (PAL_SO_RCVTIMEO == optionName)) // timeouts in MBED API are not managed though socket options, bun instead via a different funciton call + { + int timeout = *((int*)optionValue); + // SO_xxxTIMEO should only affect blocking sockets - it only limits the block, + // whereas NSAPI's set_timeout is coupled with the blocking setting + if (!socketObj->isNonBlocking()) { + socketObj->set_timeout(timeout); + } + } + else + { + result = PAL_ERR_SOCKET_OPTION_NOT_SUPPORTED; + } + } + + + return result; +} + +palStatus_t pal_plat_isNonBlocking(palSocket_t socket, bool* isNonBlocking) +{ + PALSocketWrapper* socketObj = NULL; + if (NULL == socket) + { + return PAL_ERR_INVALID_ARGUMENT; + } + socketObj = (PALSocketWrapper*)socket; + + *isNonBlocking = socketObj->isNonBlocking(); + + return PAL_SUCCESS; + +} + +palStatus_t pal_plat_bind(palSocket_t socket, palSocketAddress_t* myAddress, palSocketLength_t addressLength) +{ + int result = PAL_SUCCESS; + PALSocketWrapper* socketObj = (PALSocketWrapper*)socket; + SocketAddress internalAddr; + + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + result = palSockAddrToSocketAddress(myAddress, addressLength, internalAddr); + if (result == 0) + { + result = socketObj->bind(internalAddr); + if (result < 0) + { + result = translateErrorToPALError(result); + } + } + + return result; +} + + +palStatus_t pal_plat_receiveFrom(palSocket_t socket, void* buffer, size_t length, palSocketAddress_t* from, palSocketLength_t* fromLength, size_t* bytesReceived) +{ + int result = PAL_SUCCESS; + int status = 0; + *bytesReceived = 0; + SocketAddress sockAddr; + PALSocketWrapper* socketObj; + uint8_t* internalBufferPtr = (uint8_t*)buffer; + uint32_t bufferUsed = 0; + + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + socketObj = (PALSocketWrapper*)socket; + + if (true == socketObj->isRxBufferSet()) + { + internalBufferPtr[0] = socketObj->getAndResetRxBuffer(); + internalBufferPtr++; + length--; + bufferUsed += 1; + } + + if (length > 0) + { + status = socketObj->recvfrom(&sockAddr, internalBufferPtr, length); + if (status < 0) + { + result = translateErrorToPALError(status); + } + else if (status == 0) + { + result = PAL_ERR_SOCKET_CONNECTION_CLOSED; + } + else // only return address / bytesReceived in case of success + { + if ((NULL != from) && (NULL != fromLength)) + { + result = socketAddressToPalSockAddr(sockAddr, from, fromLength); + } + *bytesReceived = status + bufferUsed; + } + } + else + { + *bytesReceived = bufferUsed; + } + + return result; + +} + +palStatus_t pal_plat_sendTo(palSocket_t socket, const void* buffer, size_t length, const palSocketAddress_t* to, palSocketLength_t toLength, size_t* bytesSent) +{ + int result = PAL_SUCCESS; + int status = 0; + SocketAddress sockAddr; + + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + PALSocketWrapper* socketObj = (PALSocketWrapper*)socket; + + *bytesSent = 0; + result = palSockAddrToSocketAddress(to, toLength, sockAddr); + if (result == 0) + { + status = socketObj->sendto(sockAddr, buffer, length); + if (status < 0) + { + result = translateErrorToPALError(status); + } + else + { + *bytesSent = status; + } + } + + return result; +} + +palStatus_t pal_plat_close(palSocket_t* socket) +{ + int result = PAL_SUCCESS; + if (NULL == *socket) + { + PAL_LOG(DBG, "socket close called on socket which was already closed"); + return result; // socket already closed (or not opened) - no need to close. + } + PALSocketWrapper* socketObj = (PALSocketWrapper*)*socket; + result = socketObj->close(); + if (result < 0) + { + result = translateErrorToPALError(result); + } + delete socketObj; + *socket = NULL; + return result; +} + +palStatus_t pal_plat_getNumberOfNetInterfaces( uint32_t* numInterfaces) +{ + *numInterfaces = s_pal_numberOFInterfaces; + return PAL_SUCCESS; +} + +palStatus_t pal_plat_getNetInterfaceInfo(uint32_t interfaceNum, palNetInterfaceInfo_t * interfaceInfo) +{ + palStatus_t result = PAL_SUCCESS; + const char* address = NULL; + SocketAddress addr; + if ((interfaceNum >= s_pal_numberOFInterfaces) || (NULL == interfaceInfo)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + address = s_pal_networkInterfacesSupported[interfaceNum]->get_ip_address(); // ip address returned is a null terminated string + if (NULL != address) + { + addr.set_ip_address(address); + result = socketAddressToPalSockAddr(addr, &interfaceInfo->address, &interfaceInfo->addressSize); + } + + + return result; +} + +typedef void(*palSelectCallbackFunction_t)(); + +PAL_PRIVATE palSemaphoreID_t s_palSelectSemaphore = 0; +PAL_PRIVATE bool s_palSelectSemaphoreInited = false; +uint32_t s_select_event_happened[PAL_NET_SOCKET_SELECT_MAX_SOCKETS]; + +// select callbacks definition +// TODO: nirson01 change to define these using a macro. +void palSelectCallback0() +{ + s_select_event_happened[0]++; + pal_osSemaphoreRelease(s_palSelectSemaphore); +} +void palSelectCallback1() +{ + s_select_event_happened[1]++; + pal_osSemaphoreRelease(s_palSelectSemaphore); +} +void palSelectCallback2() +{ + s_select_event_happened[2]++; + pal_osSemaphoreRelease(s_palSelectSemaphore); +} +void palSelectCallback3() +{ + s_select_event_happened[3]++; + pal_osSemaphoreRelease(s_palSelectSemaphore); +} +void palSelectCallback4() +{ + s_select_event_happened[4]++; + pal_osSemaphoreRelease(s_palSelectSemaphore); +} +void palSelectCallback5() +{ + s_select_event_happened[5]++; + pal_osSemaphoreRelease(s_palSelectSemaphore); +} +void palSelectCallback6() +{ + s_select_event_happened[6]++; + pal_osSemaphoreRelease(s_palSelectSemaphore); +} +void palSelectCallback7() +{ + s_select_event_happened[7]++; + pal_osSemaphoreRelease(s_palSelectSemaphore); +} + +palSelectCallbackFunction_t s_palSelectPalCallbackFunctions[PAL_NET_SOCKET_SELECT_MAX_SOCKETS] = { palSelectCallback0, palSelectCallback1, palSelectCallback2, palSelectCallback3, palSelectCallback4, palSelectCallback5, palSelectCallback6, palSelectCallback7 }; + + +palStatus_t pal_plat_socketMiniSelect(const palSocket_t socketsToCheck[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t numberOfSockets, pal_timeVal_t* timeout, + uint8_t palSocketStatus[PAL_NET_SOCKET_SELECT_MAX_SOCKETS], uint32_t * numberOfSocketsSet) +{ + uint32_t index = 0; + int32_t counter = 0; + uint32_t timeoutInMiliseconds = 0; + palStatus_t result = PAL_SUCCESS; + uint32_t countWithPriorData = 0; + + if ((NULL == socketsToCheck) || (NULL == numberOfSocketsSet) || (NULL == timeout)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (0 == numberOfSockets) // if no sockets to check return immediately + { + return PAL_SUCCESS; + } + + for (index = 0; index < numberOfSockets; index++) // check that sockets given are valid + { + if (NULL == socketsToCheck[index]) + { + return PAL_ERR_INVALID_ARGUMENT; + } + } + + timeoutInMiliseconds = (timeout->pal_tv_sec * 1000) + (timeout->pal_tv_usec /1000); + *numberOfSocketsSet = 0; + + + // create semaphore if not initialized before - if it exists ensure count is 0. + + if (false == s_palSelectSemaphoreInited) + { + result = pal_osSemaphoreCreate(0, &s_palSelectSemaphore); // create semaphore to wait until socket event happens (semaphore will be re-used and is only created once, and never freed - if terminate is added free this resoruce if allocaed) + if (PAL_SUCCESS != result) + { + goto finish; //single exit ?? + } + s_palSelectSemaphoreInited = true; + } + else { + int32_t counters = 0; + result = pal_osSemaphoreWait(s_palSelectSemaphore, 1, &counters); // deplete semaphore count until it is 0. + while (result != PAL_ERR_RTOS_TIMEOUT) + { + result = pal_osSemaphoreWait(s_palSelectSemaphore, 1, &counters); + } + } + + for (uint32_t index = 0; index < numberOfSockets; index++) // clear socekt data + { + s_select_event_happened[index] = 0; + palSocketStatus[index] = 0; + } + + for (index = 0; index < numberOfSockets; index++) // check if any of the sockets have data ready to read , if so set setatus and return immediately. + { + bool isNonBlocking = false; + char tmpBuffer[1]; + nsapi_size_or_error_t received = 0; + + PALSocketWrapper* socketObj = (PALSocketWrapper*)socketsToCheck[index]; + + if (true == socketObj->isRxBufferSet()) // check if socket already has an RX buffer set + { + countWithPriorData++; + palSocketStatus[index] |= PAL_NET_SOCKET_SELECT_RX_BIT | PAL_NET_SOCKET_SELECT_TX_BIT; + } + else { // otherwise set socket to non-blovking and try to read data (save data in socket buffer for actual reading later). + if (PAL_SOCK_DGRAM == socketObj->getSocketType()) + { + isNonBlocking = socketObj->isNonBlocking(); + socketObj->set_blocking(false); + received = socketObj->recvfrom(NULL, tmpBuffer, 1); + if (NSAPI_ERROR_WOULD_BLOCK != received) + { + if (received > 0) + { + socketObj->setRxBuffer(tmpBuffer[0]); + } + countWithPriorData++; + palSocketStatus[index] |= PAL_NET_SOCKET_SELECT_RX_BIT; + } + socketObj->set_blocking(!isNonBlocking); + } + else if (PAL_SOCK_STREAM == socketObj->getSocketType()) + { + isNonBlocking = socketObj->isNonBlocking(); + socketObj->set_blocking(false); + received = socketObj->recv(tmpBuffer, 1); + if ((0 < received) || (true == socketObj->isConnected())) + { + countWithPriorData++; + if (true == socketObj->isConnected()) + { + palSocketStatus[index] |= PAL_NET_SOCKET_SELECT_TX_BIT; + } + if (0 < received) + { + socketObj->setRxBuffer(tmpBuffer[0]); + palSocketStatus[index] |= PAL_NET_SOCKET_SELECT_RX_BIT; + } + } + socketObj->set_blocking(!isNonBlocking); + } + else if (PAL_SOCK_STREAM_SERVER == socketObj->getSocketType()) + { + // no actual data is exepcted to be recieved on a server socket. + } + else + { + result = PAL_ERR_INVALID_ARGUMENT; // should never happen + goto finish; + } + } + } + if (countWithPriorData > 0) // some sockets have data ready to read - no need to block just return value. + { + *numberOfSocketsSet = countWithPriorData; + result = PAL_SUCCESS; + goto finish; + } + + for (index = 0; index < numberOfSockets; index++) // set callbacks to wake us up during blocking + { + PALSocketWrapper* socketObj = (PALSocketWrapper*)socketsToCheck[index]; + socketObj->updateCallback(s_palSelectPalCallbackFunctions[index]); + } + + result = pal_osSemaphoreWait(s_palSelectSemaphore, timeoutInMiliseconds, &counter); // wait on semaphore with count 0 till timeout happlens or a callback is called. + if (result == PAL_SUCCESS) + { + for (index = 0; index < numberOfSockets; index++) + { + if (s_select_event_happened[index] > 0) //if socket was set modify socket status accordingly. + { + palSocketStatus[index] |= PAL_NET_SOCKET_SELECT_RX_BIT | PAL_NET_SOCKET_SELECT_TX_BIT | PAL_NET_SOCKET_SELECT_ERR_BIT; + *numberOfSocketsSet = *numberOfSocketsSet +1; + } + } + } + if (result == PAL_ERR_RTOS_TIMEOUT) // to socket callback has been called to free the semaphore -> no socket events happenet untill the timout. + { + *numberOfSocketsSet = 0; // TODO: add debug prints + result = PAL_SUCCESS; // timeout is not actually an error in this case + } + + for (index = 0; index < numberOfSockets; index++) // reset socket callbacks to normal. + { + + PALSocketWrapper* socketObj = (PALSocketWrapper*)socketsToCheck[index]; + socketObj->updateCallback(NULL); + } +finish: + return result ; +} + +#if PAL_NET_TCP_AND_TLS_SUPPORT // functionality below supported only in case TCP is supported. + + +palStatus_t pal_plat_listen(palSocket_t socket, int backlog) +{ + int result = PAL_SUCCESS; + + PALSocketWrapper* socketObj = (PALSocketWrapper*)socket; + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + result = socketObj->listen(backlog); + if (result < 0) + { + return translateErrorToPALError(result); + } + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_accept(palSocket_t socket, palSocketAddress_t * address, palSocketLength_t* addressLen, palSocket_t* acceptedSocket) +{ + int result = PAL_SUCCESS; + + SocketAddress incomingAddr; + + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + PALSocketWrapper* socketObj = (PALSocketWrapper*)socket; + result = socketObj->accept( (TCPSocket*)(*(PALSocketWrapper**)acceptedSocket)->getActiveSocket(), &incomingAddr); + if (result < 0) + { + result = translateErrorToPALError(result); + } + else + { + result = socketAddressToPalSockAddr(incomingAddr, address, addressLen); + } + return result; +} + + +palStatus_t pal_plat_connect(palSocket_t socket, const palSocketAddress_t* address, palSocketLength_t addressLen) +{ + int result = PAL_SUCCESS; + SocketAddress internalAddr; + PALSocketWrapper* socketObj = (PALSocketWrapper*)socket; + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + result = palSockAddrToSocketAddress(address, addressLen, internalAddr); + if (result == PAL_SUCCESS) + { + result = socketObj->connect(internalAddr); + if (result < 0) + { + result = translateErrorToPALError(result); + } + } + + return result; +} + +palStatus_t pal_plat_recv(palSocket_t socket, void *buf, size_t len, size_t* recievedDataSize) +{ + int result = PAL_SUCCESS; + int status = 0; + uint8_t* internalBufferPtr = (uint8_t*)buf; + uint32_t bufferUsed = 0; + + PALSocketWrapper* socketObj = (PALSocketWrapper*)socket; + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (true == socketObj->isRxBufferSet()) + { + internalBufferPtr[0] = socketObj->getAndResetRxBuffer(); + internalBufferPtr++; + len--; + bufferUsed += 1; + } + + if (len > 0) + { + status = socketObj->recv(internalBufferPtr, len); + if (status < 0) + { + result = translateErrorToPALError(status); + } + else if (status == 0) { + return PAL_ERR_SOCKET_CONNECTION_CLOSED; + } + } + *recievedDataSize = status + bufferUsed; + return result; +} + +palStatus_t pal_plat_send(palSocket_t socket, const void *buf, size_t len, size_t* sentDataSize) +{ + palStatus_t result = PAL_SUCCESS; + int status = 0; + + PALSocketWrapper* socketObj = (PALSocketWrapper*)socket; + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = socketObj->send(buf, len); + if (status < 0) + { + result = translateErrorToPALError(status); + } + else + { + *sentDataSize = status; + } + return result; +} + +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + + +palStatus_t pal_plat_asynchronousSocket(palSocketDomain_t domain, palSocketType_t type, bool nonBlockingSocket, uint32_t interfaceNum, palAsyncSocketCallback_t callback, void* arg, palSocket_t* socket) +{ + int result = PAL_SUCCESS; + PALSocketWrapper * socketObj = NULL; + Socket* internalSocket = NULL; + + if ((NULL == socket)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + if (PAL_NET_DEFAULT_INTERFACE == interfaceNum) + { + interfaceNum = 0; + } + + if ((s_pal_numberOFInterfaces > interfaceNum) && (PAL_SOCK_DGRAM == type) && ((PAL_AF_INET == domain) || (PAL_AF_INET6 == domain) || (PAL_AF_UNSPEC == domain))) //check that we got correct parameters for UDP socket + { + internalSocket = new UDPSocket(s_pal_networkInterfacesSupported[interfaceNum]); + } +#if PAL_NET_TCP_AND_TLS_SUPPORT // functionality below supported only in case TCP is supported. + else if ((s_pal_numberOFInterfaces > interfaceNum) && (PAL_SOCK_STREAM == type) && ((PAL_AF_INET == domain) || (PAL_AF_INET6 == domain) || (PAL_AF_UNSPEC == domain))) //check that we got correct parameters for TCP socket + { + internalSocket = new TCPSocket(s_pal_networkInterfacesSupported[interfaceNum]); + } + else if ((s_pal_numberOFInterfaces > interfaceNum) && (PAL_SOCK_STREAM_SERVER == type) && ((PAL_AF_INET == domain) || (PAL_AF_INET6 == domain) || (PAL_AF_UNSPEC == domain))) //check that we got correct parameters for TCP Server socket + { + internalSocket = new TCPServer(s_pal_networkInterfacesSupported[interfaceNum]); + } +#endif + else + { + result = PAL_ERR_INVALID_ARGUMENT; + } + + if ((PAL_SUCCESS == result) && (NULL == internalSocket)) + { + result = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == result) + { + socketObj = new PALSocketWrapper(); + if (NULL != socketObj) + { + if (0 == socketObj->initialize(internalSocket, type, nonBlockingSocket, callback, arg)) + { + *socket = (palSocket_t)socketObj; + } + else + { + result = PAL_ERR_INVALID_ARGUMENT; + } + } + else + { + delete internalSocket; + result = PAL_ERR_NO_MEMORY; + } + } + + if (PAL_SUCCESS != result) //cleanup + { + if (NULL != internalSocket) + { + delete internalSocket; + } + if (NULL != socketObj) + { + delete socketObj; + } + } + return result; // TODO(nirson01) ADD debug print for error propagation(once debug print infrastructure is finalized) +} + +#endif + +#if PAL_NET_DNS_SUPPORT + +palStatus_t pal_plat_getAddressInfo(const char *url, palSocketAddress_t *address, palSocketLength_t* length) +{ + palStatus_t result = PAL_SUCCESS; + SocketAddress zeroAddress("0.0.0.0"); // zero address for check + SocketAddress translatedAddress; // by default use the fist supported net interface - TODO: do we need to select a different interface? + + +#if PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_ANY + result = s_pal_networkInterfacesSupported[0]->gethostbyname(url, &translatedAddress); +#elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV4_ONLY + result = s_pal_networkInterfacesSupported[0]->gethostbyname(url, &translatedAddress, NSAPI_IPv4); +#elif PAL_NET_DNS_IP_SUPPORT == PAL_NET_DNS_IPV6_ONLY + result = s_pal_networkInterfacesSupported[0]->gethostbyname(url, &translatedAddress, NSAPI_IPv6); +#else +#error PAL_NET_DNS_IP_SUPPORT is not defined to a valid value. +#endif + + if (result == 0) + { + if (zeroAddress == translatedAddress) // got zero address - return error + { + result = PAL_ERR_SOCKET_DNS_ERROR; + } + else // address ok + { + result = socketAddressToPalSockAddr(translatedAddress, address, length); + } + + } + else // error happened + { + result = translateErrorToPALError(result); + } + return result; +} + +#endif + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/RTOS/pal_plat_rtos.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/RTOS/pal_plat_rtos.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1238 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + + + +#include "pal_types.h" +#include "pal_rtos.h" +#include "pal_plat_rtos.h" +#include "pal_errors.h" +#include "stdlib.h" +#include "string.h" + +#include "mbed.h" + +#include "entropy_poll.h" + + +/* + mbedOS latest version RTOS support +*/ +#if defined(osRtxVersionAPI) && (osRtxVersionAPI >= 20000000) + +#include "cmsis_os2.h" // Revision: V2.1 + + +#define PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(cmsisCode)\ + ((int32_t)((int32_t)cmsisCode + PAL_ERR_RTOS_ERROR_BASE)) + +typedef struct palThreadFuncWrapper{ + palTimerFuncPtr realThreadFunc; + void* realThreadArgs; + uint32_t threadIndex; +}palThreadFuncWrapper_t; + +//! Thread structure +typedef struct palThread{ + palThreadID_t threadID; + uint32_t palThreadID; + bool initialized; + palThreadLocalStore_t* threadStore; //! please see pal_rtos.h for documentation + palThreadFuncWrapper_t threadFuncWrapper; + osThreadAttr_t osThread; + mbed_rtos_storage_thread_t osThreadStorage; +} palThread_t; + +/*! Count number of created threads. Initiate to zero. +*/ +PAL_PRIVATE uint32_t g_threadCounter = 0; +palThread_t g_palThreads[PAL_MAX_NUMBER_OF_THREADS] = {0}; + +//! Timer structure +typedef struct palTimer{ + palTimerID_t timerID; + osTimerAttr_t osTimer; + mbed_rtos_storage_timer_t osTimerStorage; +} palTimer_t; + +//! Mutex structure +typedef struct palMutex{ + palMutexID_t mutexID; + osMutexAttr_t osMutex; + mbed_rtos_storage_mutex_t osMutexStorage; +}palMutex_t; + +//! Semaphore structure +typedef struct palSemaphore{ + palSemaphoreID_t semaphoreID; + osSemaphoreAttr_t osSemaphore; + mbed_rtos_storage_semaphore_t osSemaphoreStorage; +}palSemaphore_t; + +//! Memoey Pool structure +typedef struct palMemPool{ + palMemoryPoolID_t memoryPoolID; + osMemoryPoolAttr_t osPool; + mbed_rtos_storage_mem_pool_t osPoolStorage; + uint32_t blockSize; +}palMemoryPool_t; + +//! Message Queue structure +typedef struct palMessageQ{ + palMessageQID_t messageQID; + osMessageQueueAttr_t osMessageQ; + mbed_rtos_storage_msg_queue_t osMessageQStorage; +}palMessageQ_t; + +//! thread cleanup timer argument structure +typedef struct palThreadCleanupData { + palTimerID_t timerID; + palThreadID_t threadToCleanUp; + void* threadStackMem; +}palThreadCleanupData_t; + + + +inline PAL_PRIVATE int mapThreadPriorityToPlatSpecific(palThreadPriority_t priority) +{ + int adjustedPriority = -1; + + switch (priority) + { + case PAL_osPriorityIdle: + adjustedPriority = osPriorityIdle; + break; + + case PAL_osPriorityLow: + adjustedPriority = osPriorityLow; + break; + + case PAL_osPriorityBelowNormal: + adjustedPriority = osPriorityBelowNormal; + break; + + case PAL_osPriorityNormal: + adjustedPriority = osPriorityNormal; + break; + + case PAL_osPriorityAboveNormal: + adjustedPriority = osPriorityAboveNormal; + break; + + case PAL_osPriorityHigh: + adjustedPriority = osPriorityHigh; + break; + + case PAL_osPriorityRealtime: + adjustedPriority = osPriorityRealtime; + break; + + case PAL_osPriorityError: + adjustedPriority = osPriorityError; + break; + + default: + adjustedPriority = osPriorityNone; + break; + } + + return adjustedPriority; +} + + +inline PAL_PRIVATE palThreadPriority_t mapThreadPriorityToPalGeneric(int priority) +{ + palThreadPriority_t adjustedPriority = PAL_osPriorityError; + + switch (priority) + { + case osPriorityIdle: + adjustedPriority = PAL_osPriorityIdle; + break; + + case osPriorityLow : + adjustedPriority = PAL_osPriorityLow; + break; + + case osPriorityBelowNormal : + adjustedPriority = PAL_osPriorityBelowNormal; + break; + + case osPriorityNormal : + adjustedPriority = PAL_osPriorityNormal; + break; + + case osPriorityAboveNormal : + adjustedPriority = PAL_osPriorityAboveNormal; + break; + + case osPriorityHigh : + adjustedPriority = PAL_osPriorityHigh; + break; + + case osPriorityRealtime : + adjustedPriority = PAL_osPriorityRealtime; + break; + + case osPriorityError: + default: + adjustedPriority = PAL_osPriorityError; + break; + } + + return adjustedPriority; +} + + +inline PAL_PRIVATE void setDefaultThreadValues(palThread_t* thread) +{ +#if PAL_UNIQUE_THREAD_PRIORITY + palThreadPriority_t threadGenericPriority = mapThreadPriorityToPalGeneric(thread->osThread.priority); + g_palThreadPriorities[threadGenericPriority+PRIORITY_INDEX_OFFSET] = 0; +#endif //PAL_UNIQUE_THREAD_PRIORITY + thread->threadStore = NULL; + thread->threadFuncWrapper.realThreadArgs = NULL; + thread->threadFuncWrapper.realThreadFunc = NULL; + thread->threadFuncWrapper.threadIndex = 0; + + thread->threadID = NULLPTR; + thread->palThreadID = 0; + //! This line should be last thing to be done in this function. + //! in order to prevent double accessing the same index between + //! this function and the threadCreate function. + thread->initialized = false; +} + +/*! Clean thread data from the global thread data base (g_palThreads). Thread Safe API +* +* @param[in] index: the index in the data base to be cleaned. +*/ +PAL_PRIVATE void threadCleanUp( uint32_t threadID) +{ + uint32_t status = PAL_SUCCESS; + uint32_t threadIndex = PAL_GET_THREAD_INDEX(threadID); + + status = pal_osMutexWait(g_palThreadInitMutex, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS != status) + { + PAL_LOG(ERR,"thread cleanup: mutex wait failed!\n"); + } + else{ + if ((NULL != g_palThreads) && (threadIndex < PAL_MAX_NUMBER_OF_THREADS) && (g_palThreads[threadIndex].palThreadID == threadID)) + { + setDefaultThreadValues(&g_palThreads[threadIndex]); + } + + status = pal_osMutexRelease(g_palThreadInitMutex); + if (PAL_SUCCESS != status) + { + PAL_LOG(ERR,"thread cleanup: mutex release failed!\n"); + } + } + return; +} + + + +/*! Thread Cleanup timer. This is a timer funciton dedicated to deallocating the thread stack in case if it exits naturally (not via thread Terminate). +* +* @param[in] arg: data structure which contains the data about the thread to clean up. +*/ +PAL_PRIVATE void threadCleanupTimer(const void* arg) +{ + osThreadState_t threadState = osThreadError; + palThreadCleanupData_t* threadCleanupData = (palThreadCleanupData_t*) arg; + palTimerID_t localtimerID = threadCleanupData->timerID; + + threadState = osThreadGetState((osThreadId_t)(threadCleanupData->threadToCleanUp)); + if ((threadState == osThreadTerminated) || (threadState == osThreadInactive)) // thread has ended, can clean up. + { + free(threadCleanupData->threadStackMem); // free the thread stack memory. + free(threadCleanupData); // free the thread cleanup data. + pal_osTimerDelete(&localtimerID); + } + else // Thread not ended yet, wait another PAL_RTOS_THREAD_CLEANUP_TIMER_MILISEC ms. + { + if (osThreadError == threadState) + { + PAL_LOG(DBG,"thread Cleanup Timer: error getting thread status\n"); + } + else + { + palStatus_t status = pal_osTimerStart(threadCleanupData->timerID, PAL_RTOS_THREAD_CLEANUP_TIMER_MILISEC); + if (PAL_SUCCESS != status) + { + PAL_LOG(ERR,"thread Cleanup Timer: timer start failed - thread stack memory leak likely!\n"); + } + } + } + +} + + + +/*! Thread wrapper function, this function will be set as the thread function (for every thread) +* and it will get as an argument the real data about the thread and call the REAL thread function +* with the REAL argument. +* +* @param[in] arg: data structure which contains the real data about the thread. +*/ +PAL_PRIVATE void threadFunctionWrapper(void* arg) +{ + palThreadFuncWrapper_t* threadWrapper = (palThreadFuncWrapper_t*)arg; + palThreadCleanupData_t* threadCleanupData = NULL; + palTimerID_t localTimerID = 0; + + if (NULL != threadWrapper) + { + if(g_palThreads[threadWrapper->threadIndex].threadID == NULLPTR) + { + g_palThreads[threadWrapper->threadIndex].threadID = (palThreadID_t)osThreadGetId(); + } + threadWrapper->realThreadFunc(threadWrapper->realThreadArgs); + + threadCleanupData = (palThreadCleanupData_t*)malloc(sizeof(palThreadCleanupData_t)); + if (NULL == threadCleanupData) + { + PAL_LOG(ERR,"thread cleanup: timer data allocation failed - thread stack memory leak likely!\n"); + } + else + { + palStatus_t status = pal_osTimerCreate(threadCleanupTimer, threadCleanupData, palOsTimerOnce, &localTimerID); + if (PAL_SUCCESS != status) + { + PAL_LOG(ERR,"thread cleanup: timer create failed - thread stack memory leak likely!\n"); + } + else + { + threadCleanupData->timerID = localTimerID; + threadCleanupData->threadToCleanUp = g_palThreads[threadWrapper->threadIndex].threadID; + threadCleanupData->threadStackMem = g_palThreads[threadWrapper->threadIndex].osThread.stack_mem; + status = pal_osTimerStart(localTimerID, PAL_RTOS_THREAD_CLEANUP_TIMER_MILISEC); + if (PAL_SUCCESS != status) + { + PAL_LOG(ERR,"thread cleanup: timer start failed - thread stack memory leak likely!\n"); + } + } + } + + threadCleanUp(g_palThreads[threadWrapper->threadIndex].palThreadID); // clean up everything except deallocating stack + } +} + + +void pal_plat_osReboot() +{ + NVIC_SystemReset(); +} + + +palStatus_t pal_plat_RTOSInitialize(void* opaqueContext) +{ + //Clean thread tables + palStatus_t status = PAL_SUCCESS; + + memset(g_palThreads,0,sizeof(palThread_t) * PAL_MAX_NUMBER_OF_THREADS); + + //Add implicit the running task as PAL main + g_palThreads[0].initialized = true; + g_palThreads[0].threadID = (palThreadID_t)osThreadGetId(); + g_palThreads[0].osThread.stack_mem = NULL; + + pal_osAtomicIncrement((int32_t*)&g_threadCounter,1); + //palThreadID = 24 bits for thread counter + lower 8 bits for thread index (= 0). + g_palThreads[0].palThreadID = (g_threadCounter << 8 ); + + return status; +} + + + +palStatus_t pal_plat_RTOSDestroy(void) +{ + return PAL_SUCCESS; +} + + +palStatus_t pal_plat_osDelay(uint32_t milliseconds) +{ + palStatus_t status; + osStatus_t platStatus = osDelay(milliseconds); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); //TODO(nirson01): error propagation MACRO?? + } + return status; +} + +uint64_t pal_plat_osKernelSysTick(void) +{ + uint64_t result; + result = osKernelGetTickCount(); + return result; +} + +uint64_t pal_plat_osKernelSysTickMicroSec(uint64_t microseconds) +{ + uint64_t result; + result = (((uint64_t)microseconds * (osKernelGetTickFreq())) / 1000000); + + return result; +} + +uint64_t pal_plat_osKernelSysTickFrequency() +{ + return osKernelGetTickFreq(); +} + +palStatus_t pal_plat_osThreadCreate(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, uint32_t* stackPtr, palThreadLocalStore_t* store, palThreadID_t* threadID) +{ + palStatus_t status = PAL_SUCCESS; + uint32_t firstAvailableThreadIndex = PAL_MAX_NUMBER_OF_THREADS; + uint32_t i; + uint32_t *stackAllocPtr = NULL; + osThreadId_t osThreadID = NULL; + uint32_t localPalThreadID = 0; + + + if (NULL == threadID || NULL == function || 0 == stackSize || priority > PAL_osPriorityRealtime) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + status = pal_osMutexWait(g_palThreadInitMutex, PAL_RTOS_WAIT_FOREVER); + if (PAL_SUCCESS == status) + { + for (i = 0; i < PAL_MAX_NUMBER_OF_THREADS; ++i) + { + if (!g_palThreads[i].initialized) + { + g_palThreads[i].initialized = true; + firstAvailableThreadIndex = i; + break; + } + } + + if (firstAvailableThreadIndex >= PAL_MAX_NUMBER_OF_THREADS) + { + status = PAL_ERR_RTOS_RESOURCE; + } + + if (PAL_SUCCESS == status) + { + stackAllocPtr = (uint32_t*)malloc(stackSize); + if(NULL == stackAllocPtr) + { + status = PAL_ERR_RTOS_RESOURCE; + } + } + + if (PAL_SUCCESS != status) + { + // release mutex if error. + status = pal_osMutexRelease(g_palThreadInitMutex); + } + else + { + g_palThreads[firstAvailableThreadIndex].threadStore = store; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadArgs = funcArgument; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadFunc = function; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.threadIndex = firstAvailableThreadIndex; + g_palThreads[firstAvailableThreadIndex].osThread.priority = (osPriority_t)mapThreadPriorityToPlatSpecific(priority); + g_palThreads[firstAvailableThreadIndex].osThread.stack_size = stackSize; + g_palThreads[firstAvailableThreadIndex].osThread.stack_mem = stackAllocPtr; + g_palThreads[firstAvailableThreadIndex].osThread.cb_mem = &(g_palThreads[firstAvailableThreadIndex].osThreadStorage); + g_palThreads[firstAvailableThreadIndex].osThread.cb_size = sizeof(g_palThreads[firstAvailableThreadIndex].osThreadStorage); + g_palThreads[firstAvailableThreadIndex].palThreadID = ((firstAvailableThreadIndex) + ((pal_osAtomicIncrement((int32_t*)&g_threadCounter, 1)) << 8)); //palThreadID = 24 bits for thread counter + lower 8 bits for thread index. + memset(&(g_palThreads[firstAvailableThreadIndex].osThreadStorage), 0, sizeof(g_palThreads[firstAvailableThreadIndex].osThreadStorage)); + + localPalThreadID = g_palThreads[firstAvailableThreadIndex].palThreadID; // save Thread ID value localy in case thread exists (and table is cleared) before funciton completes. + + // release mutex before thread creation . + status = pal_osMutexRelease(g_palThreadInitMutex); + + if (PAL_SUCCESS == status) + { + osThreadID = osThreadNew(threadFunctionWrapper, &g_palThreads[firstAvailableThreadIndex].threadFuncWrapper, &g_palThreads[firstAvailableThreadIndex].osThread); + g_palThreads[firstAvailableThreadIndex].threadID = (palThreadID_t)osThreadID; + if(NULL == osThreadID) + { + //! in case of error in the thread creation, reset the data of the given index in the threads array. + threadCleanUp(g_palThreads[firstAvailableThreadIndex].palThreadID); + + if (NULL != g_palThreads[firstAvailableThreadIndex].osThread.stack_mem) + { + free(g_palThreads[firstAvailableThreadIndex].osThread.stack_mem); + g_palThreads[firstAvailableThreadIndex].osThread.stack_mem = NULL; + } + status = PAL_ERR_GENERIC_FAILURE; + *threadID = PAL_INVALID_THREAD; + } + else + { + *threadID = localPalThreadID; // here we use the thread may have already exited and cleared the table so local copy of ID is used. + } + } + } + } + return status; +} + +palThreadID_t pal_plat_osThreadGetId(void) +{ + int i = 0; + palThreadID_t osThreadID; + palThreadID_t ret = PAL_INVALID_THREAD; + osThreadID = (palThreadID_t)osThreadGetId(); + + for(i= 0; i < PAL_MAX_NUMBER_OF_THREADS; i++) + { + if(osThreadID == g_palThreads[i].threadID) + { + ret = i; + break; + } + } + return ret; +} + +palStatus_t pal_plat_osThreadTerminate(palThreadID_t* threadID) +{ + palStatus_t status = PAL_ERR_INVALID_ARGUMENT; + osStatus_t platStatus = osOK; + osThreadState_t threadState = osThreadError; + uint32_t threadIndex = PAL_GET_THREAD_INDEX(*threadID); + + if ((PAL_INVALID_THREAD == *threadID) || (threadIndex >= PAL_MAX_NUMBER_OF_THREADS)) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + // if thread exited or was terminated already return success. + if ((g_palThreads[threadIndex].palThreadID == 0 ) || // thread already exited + (g_palThreads[threadIndex].palThreadID != *threadID)|| // thread already exited and a new thread was created at the same index. + (g_palThreads[threadIndex].threadID == (palThreadID_t)PAL_INVALID_THREAD)) // thread was terminsated. + { + return PAL_SUCCESS; + } + + if ((palThreadID_t)osThreadGetId() != g_palThreads[threadIndex].threadID) + {//Kill only if not trying to kill from running task + if (g_palThreads[threadIndex].initialized) + { + if (g_palThreads[threadIndex].threadID != NULLPTR) + { + threadState = osThreadGetState((osThreadId_t)(g_palThreads[threadIndex].threadID)); + if ((threadState != osThreadTerminated) && (threadState != osThreadError) && (threadState != osThreadInactive)) + { + platStatus = osThreadTerminate((osThreadId_t)(g_palThreads[threadIndex].threadID)); + } + } + + if (platStatus != osErrorISR) // osErrorISR: osThreadTerminate cannot be called from interrupt service routines. + { + threadCleanUp( *threadID); + if (NULL != g_palThreads[threadIndex].osThread.stack_mem) + { + free(g_palThreads[threadIndex].osThread.stack_mem); + g_palThreads[threadIndex].osThread.stack_mem = NULL; + } + *threadID = PAL_INVALID_THREAD; + status = PAL_SUCCESS; + } + else + { + status = PAL_ERR_RTOS_ISR; + } + } + else + { + // thread already tminated and cleaned up + status = PAL_SUCCESS; + } + } + else + { + status = PAL_ERR_RTOS_TASK; + } + + return status; +} + +palThreadLocalStore_t* pal_plat_osThreadGetLocalStore(void) +{ + palThreadLocalStore_t* localStore = NULL; + palThreadID_t id = (uintptr_t)pal_osThreadGetId(); + + if( g_palThreads[id].initialized) + { + localStore = g_palThreads[id].threadStore; + } + return localStore; +} + + +palStatus_t pal_plat_osTimerCreate(palTimerFuncPtr function, void* funcArgument, palTimerType_t timerType, palTimerID_t* timerID) +{ + palStatus_t status = PAL_SUCCESS; + palTimer_t* timer = NULL; + + if(NULL == timerID || NULL == function) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)malloc(sizeof(palTimer_t)); + if (NULL == timer) + { + status = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == status) + { + timer->osTimer.name = NULL; + timer->osTimer.attr_bits = 0; + timer->osTimer.cb_mem = &timer->osTimerStorage; + timer->osTimer.cb_size = sizeof(timer->osTimerStorage); + memset(&timer->osTimerStorage, 0, sizeof(timer->osTimerStorage)); + + timer->timerID = (uintptr_t)osTimerNew((osTimerFunc_t)function, (osTimerType_t)timerType, funcArgument, &timer->osTimer); + if (NULLPTR == timer->timerID) + { + free(timer); + timer = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *timerID = (palTimerID_t)timer; + } + } + return status; +} + +palStatus_t pal_plat_osTimerStart(palTimerID_t timerID, uint32_t millisec) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palTimer_t* timer = NULL; + + if (NULLPTR == timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)timerID; + platStatus = osTimerStart((osTimerId_t)timer->timerID, millisec); + if (osOK == (osStatus_t)platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osTimerStop(palTimerID_t timerID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palTimer_t* timer = NULL; + + if(NULLPTR == timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)timerID; + platStatus = osTimerStop((osTimerId_t)timer->timerID); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osTimerDelete(palTimerID_t* timerID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palTimer_t* timer = NULL; + + if(NULL == timerID || NULLPTR == *timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)*timerID; + platStatus = osTimerDelete((osTimerId_t)timer->timerID); + if (osOK == platStatus) + { + free(timer); + *timerID = NULLPTR; + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + + +palStatus_t pal_plat_osMutexCreate(palMutexID_t* mutexID) +{ + palStatus_t status = PAL_SUCCESS; + palMutex_t* mutex = NULL; + + if(NULL == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)malloc(sizeof(palMutex_t)); + if (NULL == mutex) + { + status = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == status) + { + mutex->osMutex.name = NULL; + mutex->osMutex.attr_bits = osMutexRecursive | osMutexRobust; + mutex->osMutex.cb_mem = &mutex->osMutexStorage; + mutex->osMutex.cb_size = sizeof(mutex->osMutexStorage); + memset(&mutex->osMutexStorage, 0, sizeof(mutex->osMutexStorage)); + + mutex->mutexID = (uintptr_t)osMutexNew(&mutex->osMutex); + if (NULLPTR == mutex->mutexID) + { + free(mutex); + mutex = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *mutexID = (palMutexID_t)mutex; + } + } + return status; +} + + +palStatus_t pal_plat_osMutexWait(palMutexID_t mutexID, uint32_t millisec) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palMutex_t* mutex = NULL; + + if(NULLPTR == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)mutexID; + platStatus = osMutexAcquire((osMutexId_t)mutex->mutexID, millisec); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + + +palStatus_t pal_plat_osMutexRelease(palMutexID_t mutexID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palMutex_t* mutex = NULL; + + if(NULLPTR == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)mutexID; + platStatus = osMutexRelease((osMutexId_t)mutex->mutexID); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osMutexDelete(palMutexID_t* mutexID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palMutex_t* mutex = NULL; + + if(NULL == mutexID || NULLPTR == *mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)*mutexID; + platStatus = osMutexDelete((osMutexId_t)mutex->mutexID); + if (osOK == platStatus) + { + free(mutex); + *mutexID = NULLPTR; + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osSemaphoreCreate(uint32_t count, palSemaphoreID_t* semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + palSemaphore_t* semaphore = NULL; + if(NULL == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)malloc(sizeof(palSemaphore_t)); + if (NULL == semaphore) + { + status = PAL_ERR_NO_MEMORY; + } + + if(PAL_SUCCESS == status) + { + semaphore->osSemaphore.cb_mem = &semaphore->osSemaphoreStorage; + semaphore->osSemaphore.cb_size = sizeof(semaphore->osSemaphoreStorage); + memset(&semaphore->osSemaphoreStorage, 0, sizeof(semaphore->osSemaphoreStorage)); + + semaphore->semaphoreID = (uintptr_t)osSemaphoreNew(PAL_MAX_SEMAPHORE_COUNT, count, &semaphore->osSemaphore); + if (NULLPTR == semaphore->semaphoreID) + { + free(semaphore); + semaphore = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *semaphoreID = (palSemaphoreID_t)semaphore; + } + } + return status; +} + +palStatus_t pal_plat_osSemaphoreWait(palSemaphoreID_t semaphoreID, uint32_t millisec, int32_t* countersAvailable) +{ + palStatus_t status = PAL_SUCCESS; + palSemaphore_t* semaphore = NULL; + osStatus_t platStatus; + if(NULLPTR == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)semaphoreID; + platStatus = osSemaphoreAcquire((osSemaphoreId_t)semaphore->semaphoreID, millisec); + + if (osErrorTimeout == platStatus) + { + status = PAL_ERR_RTOS_TIMEOUT; + } + else if (platStatus != osOK) + { + status = PAL_ERR_RTOS_PARAMETER; + } + + if (NULL != countersAvailable) + { + *countersAvailable = osSemaphoreGetCount((osSemaphoreId_t)semaphore->semaphoreID); + } + return status; +} + +palStatus_t pal_plat_osSemaphoreRelease(palSemaphoreID_t semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palSemaphore_t* semaphore = NULL; + + if(NULLPTR == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)semaphoreID; + platStatus = osSemaphoreRelease((osSemaphoreId_t)semaphore->semaphoreID); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osSemaphoreDelete(palSemaphoreID_t* semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palSemaphore_t* semaphore = NULL; + + if(NULL == semaphoreID || NULLPTR == *semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)*semaphoreID; + platStatus = osSemaphoreDelete((osSemaphoreId_t)semaphore->semaphoreID); + if (osOK == platStatus) + { + free(semaphore); + *semaphoreID = NULLPTR; + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osPoolCreate(uint32_t blockSize, uint32_t blockCount, palMemoryPoolID_t* memoryPoolID) +{ + palStatus_t status = PAL_SUCCESS; + palMemoryPool_t* memoryPool = NULL; + if(NULL == memoryPoolID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + //! allocate the memory pool structure + memoryPool = (palMemoryPool_t*)malloc(sizeof(palMemoryPool_t)); + if (NULL == memoryPool) + { + status = PAL_ERR_NO_MEMORY; + } + + if(PAL_SUCCESS == status) + { + memoryPool->blockSize = blockSize; + memoryPool->osPool.name = NULL; + memoryPool->osPool.attr_bits = 0; + memoryPool->osPool.cb_mem = &memoryPool->osPoolStorage; + memoryPool->osPool.cb_size = sizeof(memoryPool->osPoolStorage); + memset(&memoryPool->osPoolStorage, 0, sizeof(memoryPool->osPoolStorage)); + memoryPool->osPool.mp_size = blockSize * blockCount; + memoryPool->osPool.mp_mem = (uint32_t*)malloc(memoryPool->osPool.mp_size); + if (NULL == memoryPool->osPool.mp_mem) + { + free(memoryPool); + *memoryPoolID = NULLPTR; + status = PAL_ERR_NO_MEMORY; + } + else + { + memset(memoryPool->osPool.mp_mem, 0, memoryPool->osPool.mp_size); + + memoryPool->memoryPoolID = (uintptr_t)osMemoryPoolNew(blockCount, blockSize, &memoryPool->osPool); + if (NULLPTR == memoryPool->memoryPoolID) + { + free(memoryPool->osPool.mp_mem); + free(memoryPool); + memoryPool = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *memoryPoolID = (palMemoryPoolID_t)memoryPool; + } + } + } + return status; +} + +void* pal_plat_osPoolAlloc(palMemoryPoolID_t memoryPoolID) +{ + void* result = NULL; + palMemoryPool_t* memoryPool = NULL; + + if(NULLPTR == memoryPoolID) + { + return NULL; + } + + memoryPool = (palMemoryPool_t*)memoryPoolID; + result = osMemoryPoolAlloc((osMemoryPoolId_t)memoryPool->memoryPoolID, 0); + + return result; +} + +void* pal_plat_osPoolCAlloc(palMemoryPoolID_t memoryPoolID) +{ + void* result = NULL; + palMemoryPool_t* memoryPool = NULL; + + if(NULLPTR == memoryPoolID) + { + return NULL; + } + + memoryPool = (palMemoryPool_t*)memoryPoolID; + result = osMemoryPoolAlloc((osMemoryPoolId_t)memoryPool->memoryPoolID, 0); + if (NULLPTR != result) + { + memset(result, 0, memoryPool->blockSize); + } + + return result; +} + +palStatus_t pal_plat_osPoolFree(palMemoryPoolID_t memoryPoolID, void* block) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palMemoryPool_t* memoryPool = NULL; + + if(NULLPTR == memoryPoolID || NULL == block) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + memoryPool = (palMemoryPool_t*)memoryPoolID; + platStatus = osMemoryPoolFree((osMemoryPoolId_t)memoryPool->memoryPoolID, block); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osPoolDestroy(palMemoryPoolID_t* memoryPoolID) +{ + palStatus_t status = PAL_SUCCESS; + palMemoryPool_t* memoryPool = NULL; + + if(NULL == memoryPoolID || NULLPTR == *memoryPoolID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + memoryPool = (palMemoryPool_t*)*memoryPoolID; + free(memoryPool->osPool.mp_mem); + free(memoryPool); + *memoryPoolID = NULLPTR; + return status; +} + +palStatus_t pal_plat_osMessageQueueCreate(uint32_t messageQCount, palMessageQID_t* messageQID) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t* messageQ = NULL; + if(NULL == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + //! allocate the message queue structure + messageQ = (palMessageQ_t*)malloc(sizeof(palMessageQ_t)); + if (NULL == messageQ) + { + status = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == status) + { + messageQ->osMessageQ.name = NULL; + messageQ->osMessageQ.attr_bits = 0; + messageQ->osMessageQ.cb_size = sizeof(messageQ->osMessageQStorage); + messageQ->osMessageQ.cb_mem = &messageQ->osMessageQStorage; + memset(&messageQ->osMessageQStorage, 0, sizeof(messageQ->osMessageQStorage)); + messageQ->osMessageQ.mq_size = (sizeof(uint32_t) + sizeof(mbed_rtos_storage_message_t)) * messageQCount ; + messageQ->osMessageQ.mq_mem = (uint32_t*)malloc(messageQ->osMessageQ.mq_size); + if (NULL == messageQ->osMessageQ.mq_mem) + { + free(messageQ); + messageQ = NULL; + status = PAL_ERR_NO_MEMORY; + } + else + { + memset(messageQ->osMessageQ.mq_mem, 0, messageQ->osMessageQ.mq_size); + + messageQ->messageQID = (uintptr_t)osMessageQueueNew(messageQCount, sizeof(uint32_t), &messageQ->osMessageQ); + if (NULLPTR == messageQ->messageQID) + { + free(messageQ->osMessageQ.mq_mem); + free(messageQ); + messageQ = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *messageQID = (palMessageQID_t)messageQ; + } + } + } + return status; +} + +palStatus_t pal_plat_osMessagePut(palMessageQID_t messageQID, uint32_t info, uint32_t timeout) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus = osOK; + palMessageQ_t* messageQ = NULL; + + if(NULLPTR == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)messageQID; + platStatus = osMessageQueuePut((osMessageQueueId_t)messageQ->messageQID, (void *)&info, 0, timeout); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osMessageGet(palMessageQID_t messageQID, uint32_t timeout, uint32_t* messageValue) +{ + palStatus_t status = PAL_SUCCESS; + osStatus_t platStatus; + palMessageQ_t* messageQ = NULL; + + if (NULLPTR == messageQID || NULLPTR == messageValue) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)messageQID; + platStatus = osMessageQueueGet((osMessageQueueId_t)messageQ->messageQID, messageValue, NULL, timeout); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else if (osErrorTimeout == platStatus) + { + status = PAL_ERR_RTOS_TIMEOUT; + } + else if (osOK != platStatus) + { + status = PAL_ERR_RTOS_PARAMETER; + } + + return status; +} + + +palStatus_t pal_plat_osMessageQueueDestroy(palMessageQID_t* messageQID) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t* messageQ = NULL; + + if(NULL == messageQID || NULLPTR == *messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)*messageQID; + free(messageQ->osMessageQ.mq_mem); + free(messageQ); + *messageQID = NULLPTR; + return status; +} + + +int32_t pal_plat_osAtomicIncrement(int32_t* valuePtr, int32_t increment) +{ + if (increment >= 0) + { + return core_util_atomic_incr_u32((uint32_t*)valuePtr, increment); + } + else + { + return core_util_atomic_decr_u32((uint32_t*)valuePtr, 0 - increment); + } +} + + + void *pal_plat_malloc(size_t len) +{ + return malloc(len); +} + + + void pal_plat_free(void * buffer) +{ + return free(buffer); +} + +palStatus_t pal_plat_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = 0; + size_t actualOutputLen = 0; + platStatus = mbedtls_hardware_poll(NULL /*Not used by the function*/, randomBuf, bufSizeBytes, &actualOutputLen); + if ((0 != platStatus) || (actualOutputLen != bufSizeBytes)) + { + status = PAL_ERR_RTOS_TRNG_FAILED; + } + return status; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/RTOS/pal_plat_rtos_legacy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/RTOS/pal_plat_rtos_legacy.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1079 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + + + +#include "pal_types.h" +#include "pal_rtos.h" +#include "pal_plat_rtos.h" +#include "pal_errors.h" +#include "stdlib.h" +#include "string.h" + +#include "mbed.h" + +#include "entropy_poll.h" + + +/******************************************************************************* + mbedOS legacy RTOS support +********************************************************************************/ +#if !(defined(osRtxVersionAPI) && (osRtxVersionAPI >= 20000000)) + +#define PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(cmsisCode)\ + ((int32_t)((int32_t)cmsisCode + PAL_ERR_RTOS_ERROR_BASE)) + +//! the size of the memory to allocate was taken from CMSIS header (cmsis_os.h) +#define PAL_RTOS_MEMORY_POOL_SIZE(blockSize, blockCount)\ + (sizeof(uint32_t)*(3+((blockSize+3)/4)*(blockCount))) + +//! the size of the memory to allocate was taken from CMSIS header (cmsis_os.h) +#define PAL_RTOS_MESSAGE_Q_SIZE(messageQSize)\ + (sizeof(uint32_t)*(4 + messageQSize)) + + +#ifdef PAL_RTOS_WAIT_FOREVER +#undef PAL_RTOS_WAIT_FOREVER +#define PAL_RTOS_WAIT_FOREVER osWaitForever +#endif //PAL_RTOS_WAIT_FOREVER + +//! This definitions should be under #ifdef for different CORTEX-X processors. +//! The current vaules are for cortex-M these are the sizes of the internal data array in definitions arrays +#define PAL_TIMER_DATA_SIZE 6 +#define PAL_MUTEX_DATA_SIZE 4 +#define PAL_SEMAPHORE_DATA_SIZE 2 +#define PAL_NUM_OF_THREAD_INSTANCES 1 + +PAL_PRIVATE uint8_t g_randomBuffer[PAL_INITIAL_RANDOM_SIZE] = {0}; +PAL_PRIVATE bool g_randInitiated = false; + +typedef struct palThreadFuncWrapper{ + palTimerFuncPtr realThreadFunc; + void* realThreadArgs; + uint32_t threadIndex; +}palThreadFuncWrapper_t; + +//! Thread structure +typedef struct palThread{ + palThreadID_t threadID; + bool initialized; + palThreadLocalStore_t* threadStore; //! please see pal_rtos.h for documentation + palThreadFuncWrapper_t threadFuncWrapper; + osThreadDef_t osThread; + bool taskCompleted; //The task has completed and exit +} palThread_t; + + +palThread_t g_palThreads[PAL_MAX_NUMBER_OF_THREADS] = {0}; + +//! Timer structure +typedef struct palTimer{ + palTimerID_t timerID; + uint32_t internalTimerData[PAL_TIMER_DATA_SIZE]; ///< pointer to internal data + osTimerDef_t osTimer; +} palTimer_t; + +//! Mutex structure +typedef struct palMutex{ + palMutexID_t mutexID; + uint32_t internalMutexData[PAL_MUTEX_DATA_SIZE]; + osMutexDef_t osMutex; +}palMutex_t; + +//! Semaphore structure +typedef struct palSemaphore{ + palSemaphoreID_t semaphoreID; + uint32_t internalSemaphoreData[PAL_SEMAPHORE_DATA_SIZE]; + osSemaphoreDef_t osSemaphore; +}palSemaphore_t; + + +//! Memoey Pool structure +typedef struct palMemPool{ + palMemoryPoolID_t memoryPoolID; + osPoolDef_t osPool; +}palMemoryPool_t; + +//! Message Queue structure +typedef struct palMessageQ{ + palMessageQID_t messageQID; + osMessageQDef_t osMessageQ; +}palMessageQ_t; + + +inline PAL_PRIVATE void setDefaultThreadValues(palThread_t* thread) +{ +#if PAL_UNIQUE_THREAD_PRIORITY + g_palThreadPriorities[thread->osThread.tpriority+PRIORITY_INDEX_OFFSET] = false; +#endif //PAL_UNIQUE_THREAD_PRIORITY + thread->threadStore = NULL; + thread->threadFuncWrapper.realThreadArgs = NULL; + thread->threadFuncWrapper.realThreadFunc = NULL; + thread->threadFuncWrapper.threadIndex = 0; + thread->osThread.pthread = NULL; + thread->osThread.tpriority = (osPriority)PAL_osPriorityError; + thread->osThread.instances = PAL_NUM_OF_THREAD_INSTANCES; + thread->osThread.stacksize = 0; +#if __MBED_CMSIS_RTOS_CM + if(thread->osThread.stack_pointer != NULL) + { + free(thread->osThread.stack_pointer); + } +#else + thread->osThread.stack_pointer = NULL; +#endif + thread->threadID = NULLPTR; + thread->taskCompleted = false; + //! This line should be last thing to be done in this function. + //! in order to prevent double accessing the same index between + //! this function and the threadCreate function. + thread->initialized = false; +} + +/*! Clean thread data from the global thread data base (g_palThreads). Thread Safe API +* +* @param[in] dbPointer: data base pointer. +* @param[in] index: the index in the data base to be cleaned. +*/ +PAL_PRIVATE void threadCleanUp(void* dbPointer, uint32_t index) +{ + palThread_t* threadsDB = (palThread_t*)dbPointer; + + if (NULL == dbPointer || index >= PAL_MAX_NUMBER_OF_THREADS) + { + return; + } + setDefaultThreadValues(&threadsDB[index]); +} + +/*! Thread wrapper function, this function will be set as the thread function (for every thread) +* and it will get as an argument the real data about the thread and call the REAL thread function +* with the REAL argument. +* +* @param[in] arg: data structure which contains the real data about the thread. +*/ +PAL_PRIVATE void threadFunctionWrapper(void const* arg) +{ + palThreadFuncWrapper_t* threadWrapper = (palThreadFuncWrapper_t*)arg; + + if (NULL != threadWrapper) + { + if(g_palThreads[threadWrapper->threadIndex].threadID == NULLPTR) + { + g_palThreads[threadWrapper->threadIndex].threadID = (palThreadID_t)osThreadGetId(); + } + threadWrapper->realThreadFunc(threadWrapper->realThreadArgs); + g_palThreads[threadWrapper->threadIndex].taskCompleted = true; + } +} + + +void pal_plat_osReboot() +{ + NVIC_SystemReset(); +} + + +palStatus_t pal_plat_RTOSInitialize(void* opaqueContext) +{ + //Clean thread tables + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = 0; + size_t actualOutputLen = 0; + + memset(g_palThreads,0,sizeof(palThread_t) * PAL_MAX_NUMBER_OF_THREADS); + + //Add implicit the running task as PAL main + g_palThreads[0].initialized = true; + g_palThreads[0].threadID = (palThreadID_t)osThreadGetId(); + g_palThreads[0].osThread.stack_pointer = NULL; + + + platStatus = mbedtls_hardware_poll(NULL /*Not used by the function*/, g_randomBuffer, sizeof(g_randomBuffer), &actualOutputLen); + if (0 != platStatus || actualOutputLen != sizeof(g_randomBuffer)) + { + status = PAL_ERR_RTOS_TRNG_FAILED; + } + else + { + g_randInitiated = true; + } + + return status; +} + + + + + +palStatus_t pal_plat_RTOSDestroy(void) +{ + return PAL_SUCCESS; +} + +palStatus_t pal_plat_osDelay(uint32_t milliseconds) +{ + palStatus_t status; + osStatus platStatus = osDelay(milliseconds); + if (osEventTimeout == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); //TODO(nirson01): error propagation MACRO?? + } + return status; +} + +uint64_t pal_plat_osKernelSysTick(void) +{ + uint64_t result; + result = osKernelSysTick(); + return result; +} + +uint64_t pal_plat_osKernelSysTickMicroSec(uint64_t microseconds) +{ + uint64_t result; + result = osKernelSysTickMicroSec(microseconds); + return result; +} + +uint64_t pal_plat_osKernelSysTickFrequency() +{ + return osKernelSysTickFrequency; +} + +palStatus_t pal_plat_osThreadCreate(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, uint32_t* stackPtr, palThreadLocalStore_t* store, palThreadID_t* threadID) +{ + palStatus_t status = PAL_SUCCESS; + uint32_t firstAvailableThreadIndex = PAL_MAX_NUMBER_OF_THREADS; + uint32_t i; + uint32_t *stackAllocPtr = NULL; + osThreadId osThreadID = NULL; + + if (NULL == threadID || NULL == function || 0 == stackSize || priority > PAL_osPriorityRealtime) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + for (i = 0; i < PAL_MAX_NUMBER_OF_THREADS; ++i) + { + if (!g_palThreads[i].initialized) + { + g_palThreads[i].initialized = true; + firstAvailableThreadIndex = i; + break; + } + } + + if (firstAvailableThreadIndex >= PAL_MAX_NUMBER_OF_THREADS) + { + status = PAL_ERR_RTOS_RESOURCE; + } + +#if __MBED_CMSIS_RTOS_CM + if (PAL_SUCCESS == status) + { + stackAllocPtr = (uint32_t*)malloc(stackSize); + + if(NULL == stackAllocPtr) + { + status = PAL_ERR_RTOS_RESOURCE; + } + } +#endif + if (PAL_SUCCESS == status) + { + g_palThreads[firstAvailableThreadIndex].threadStore = store; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadArgs = funcArgument; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadFunc = function; + g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.threadIndex = firstAvailableThreadIndex; + g_palThreads[firstAvailableThreadIndex].osThread.pthread = threadFunctionWrapper; + g_palThreads[firstAvailableThreadIndex].osThread.tpriority = (osPriority)priority; + g_palThreads[firstAvailableThreadIndex].osThread.instances = PAL_NUM_OF_THREAD_INSTANCES; + g_palThreads[firstAvailableThreadIndex].osThread.stacksize = stackSize; +#if __MBED_CMSIS_RTOS_CM + g_palThreads[firstAvailableThreadIndex].osThread.stack_pointer = stackAllocPtr; +#else + g_palThreads[firstAvailableThreadIndex].osThread.stack_pointer = stackPtr; +#endif + +#if PAL_UNIQUE_THREAD_PRIORITY + g_palThreadPriorities[priority+PRIORITY_INDEX_OFFSET] = true; +#endif //PAL_UNIQUE_THREAD_PRIORITY + + + osThreadID = osThreadCreate(&g_palThreads[firstAvailableThreadIndex].osThread, &g_palThreads[firstAvailableThreadIndex].threadFuncWrapper); + + if(NULL == osThreadID) + { + //! in case of error in the thread creation, reset the data of the given index in the threads array. + threadCleanUp(g_palThreads, firstAvailableThreadIndex); + status = PAL_ERR_GENERIC_FAILURE; + *threadID = PAL_INVALID_THREAD; + } + else + { + *threadID = firstAvailableThreadIndex; + } + + } + return status; +} + +palThreadID_t pal_plat_osThreadGetId(void) +{ + int i = 0; + palThreadID_t osThreadID; + palThreadID_t ret = PAL_INVALID_THREAD; + osThreadID = (palThreadID_t)osThreadGetId(); + + for(i= 0; i < PAL_MAX_NUMBER_OF_THREADS; i++) + { + if(osThreadID == g_palThreads[i].threadID) + { + ret = i; + break; + } + } + return ret; +} + +palStatus_t pal_plat_osThreadTerminate(palThreadID_t* threadID) +{ + palStatus_t status = PAL_ERR_INVALID_ARGUMENT; + osStatus platStatus = osOK; + + if (*threadID >= PAL_MAX_NUMBER_OF_THREADS) + { + return status; + } + + if ((palThreadID_t)osThreadGetId() != g_palThreads[*threadID].threadID) + {//Kill only if not trying to kill from running task + if (g_palThreads[*threadID].initialized) + { + if ((g_palThreads[*threadID].threadID != NULL) && ( g_palThreads[*threadID].taskCompleted == false)) + { + platStatus = osThreadTerminate((osThreadId)(g_palThreads[*threadID].threadID)); + } + if (platStatus != osErrorISR) // osErrorISR: osThreadTerminate cannot be called from interrupt service routines. + { + threadCleanUp(g_palThreads, *threadID); + } + else + { + status = PAL_ERR_RTOS_ISR; + } + } + *threadID = PAL_INVALID_THREAD; + status = PAL_SUCCESS; + } + else + { + status = PAL_ERR_RTOS_TASK; + } + + return status; +} + +palThreadLocalStore_t* pal_plat_osThreadGetLocalStore(void) +{ + palThreadLocalStore_t* localStore = NULL; + palThreadID_t id = (uintptr_t)pal_osThreadGetId(); + + if( g_palThreads[id].initialized) + { + localStore = g_palThreads[id].threadStore; + } + return localStore; +} + + +palStatus_t pal_plat_osTimerCreate(palTimerFuncPtr function, void* funcArgument, palTimerType_t timerType, palTimerID_t* timerID) +{ + palStatus_t status = PAL_SUCCESS; + palTimer_t* timer = NULL; + + if(NULL == timerID || NULL == function) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)malloc(sizeof(palTimer_t)); + if (NULL == timer) + { + status = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == status) + { + timer->osTimer.ptimer = function; + timer->osTimer.timer = timer->internalTimerData; + memset(timer->osTimer.timer, 0, sizeof(uint32_t)*PAL_TIMER_DATA_SIZE); + + timer->timerID = (uintptr_t)osTimerCreate(&timer->osTimer, (os_timer_type)timerType, funcArgument); + if (NULLPTR == timer->timerID) + { + free(timer); + timer = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *timerID = (palTimerID_t)timer; + } + } + return status; +} + +palStatus_t pal_plat_osTimerStart(palTimerID_t timerID, uint32_t millisec) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palTimer_t* timer = NULL; + + if (NULLPTR == timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)timerID; + platStatus = osTimerStart((osTimerId)timer->timerID, millisec); + if (osOK == (osStatus)platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osTimerStop(palTimerID_t timerID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palTimer_t* timer = NULL; + + if(NULLPTR == timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)timerID; + platStatus = osTimerStop((osTimerId)timer->timerID); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osTimerDelete(palTimerID_t* timerID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palTimer_t* timer = NULL; + + if(NULL == timerID || NULLPTR == *timerID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + timer = (palTimer_t*)*timerID; + platStatus = osTimerDelete((osTimerId)timer->timerID); + if (osOK == platStatus) + { + free(timer); + *timerID = NULLPTR; + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + + +palStatus_t pal_plat_osMutexCreate(palMutexID_t* mutexID) +{ + palStatus_t status = PAL_SUCCESS; + palMutex_t* mutex = NULL; + if(NULL == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)malloc(sizeof(palMutex_t)); + if (NULL == mutex) + { + status = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == status) + { + mutex->osMutex.mutex = mutex->internalMutexData; + memset(mutex->osMutex.mutex, 0, sizeof(uint32_t)*PAL_MUTEX_DATA_SIZE); + + mutex->mutexID = (uintptr_t)osMutexCreate(&mutex->osMutex); + if (NULLPTR == mutex->mutexID) + { + free(mutex); + mutex = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *mutexID = (palMutexID_t)mutex; + } + } + return status; +} + + +palStatus_t pal_plat_osMutexWait(palMutexID_t mutexID, uint32_t millisec) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palMutex_t* mutex = NULL; + + if(NULLPTR == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)mutexID; + platStatus = osMutexWait((osMutexId)mutex->mutexID, millisec); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + + +palStatus_t pal_plat_osMutexRelease(palMutexID_t mutexID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palMutex_t* mutex = NULL; + + if(NULLPTR == mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)mutexID; + platStatus = osMutexRelease((osMutexId)mutex->mutexID); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osMutexDelete(palMutexID_t* mutexID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palMutex_t* mutex = NULL; + + if(NULL == mutexID || NULLPTR == *mutexID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + mutex = (palMutex_t*)*mutexID; + platStatus = osMutexDelete((osMutexId)mutex->mutexID); + if (osOK == platStatus) + { + free(mutex); + *mutexID = NULLPTR; + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osSemaphoreCreate(uint32_t count, palSemaphoreID_t* semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + palSemaphore_t* semaphore = NULL; + if(NULL == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)malloc(sizeof(palSemaphore_t)); + if (NULL == semaphore) + { + status = PAL_ERR_NO_MEMORY; + } + + if(PAL_SUCCESS == status) + { + semaphore->osSemaphore.semaphore = semaphore->internalSemaphoreData; + memset(semaphore->osSemaphore.semaphore, 0, sizeof(uint32_t)*PAL_SEMAPHORE_DATA_SIZE); + + semaphore->semaphoreID = (uintptr_t)osSemaphoreCreate(&semaphore->osSemaphore, count); + if (NULLPTR == semaphore->semaphoreID) + { + free(semaphore); + semaphore = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *semaphoreID = (palSemaphoreID_t)semaphore; + } + } + return status; +} + +palStatus_t pal_plat_osSemaphoreWait(palSemaphoreID_t semaphoreID, uint32_t millisec, int32_t* countersAvailable) +{ + palStatus_t status = PAL_SUCCESS; + palSemaphore_t* semaphore = NULL; + int32_t tmpCountersAvailable = 0; + if(NULLPTR == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)semaphoreID; + tmpCountersAvailable = osSemaphoreWait((osSemaphoreId)semaphore->semaphoreID, millisec); + + if (0 == tmpCountersAvailable) + { + status = PAL_ERR_RTOS_TIMEOUT; + } + else if (tmpCountersAvailable < 0) + { + tmpCountersAvailable = 0; + status = PAL_ERR_RTOS_PARAMETER; + } + + if (NULL != countersAvailable) + { + //osSemaphoreWait return the number of available counter + "1" + //The "1" is added because return value "0" is timeout so mbedOS return 1 and this is false + tmpCountersAvailable--; + *countersAvailable = tmpCountersAvailable; + } + return status; +} + +palStatus_t pal_plat_osSemaphoreRelease(palSemaphoreID_t semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palSemaphore_t* semaphore = NULL; + + if(NULLPTR == semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)semaphoreID; + platStatus = osSemaphoreRelease((osSemaphoreId)semaphore->semaphoreID); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osSemaphoreDelete(palSemaphoreID_t* semaphoreID) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palSemaphore_t* semaphore = NULL; + + if(NULL == semaphoreID || NULLPTR == *semaphoreID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + semaphore = (palSemaphore_t*)*semaphoreID; + platStatus = osSemaphoreDelete((osSemaphoreId)semaphore->semaphoreID); + if (osOK == platStatus) + { + free(semaphore); + *semaphoreID = NULLPTR; + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osPoolCreate(uint32_t blockSize, uint32_t blockCount, palMemoryPoolID_t* memoryPoolID) +{ + palStatus_t status = PAL_SUCCESS; + palMemoryPool_t* memoryPool = NULL; + if(NULL == memoryPoolID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + //! allocate the memory pool structure + memoryPool = (palMemoryPool_t*)malloc(sizeof(palMemoryPool_t)); + if (NULL == memoryPool) + { + status = PAL_ERR_NO_MEMORY; + } + + if(PAL_SUCCESS == status) + { + //! allocate the actual memory allocation for the memory pool blocks, the size of the memory + //! to allocate was taken from CMSIS header (cmsis_os.h) + memoryPool->osPool.pool = (uint32_t*)malloc(PAL_RTOS_MEMORY_POOL_SIZE(blockSize, blockCount)); + if (NULL == memoryPool->osPool.pool) + { + free(memoryPool); + *memoryPoolID = NULLPTR; + status = PAL_ERR_NO_MEMORY; + } + else + { + memset(memoryPool->osPool.pool, 0, PAL_RTOS_MEMORY_POOL_SIZE(blockSize, blockCount)); + memoryPool->osPool.pool_sz = blockCount; ///< number of items (elements) in the pool + memoryPool->osPool.item_sz = blockSize; ///< size of an item + + memoryPool->memoryPoolID = (uintptr_t)osPoolCreate(&memoryPool->osPool); + if (NULLPTR == memoryPool->memoryPoolID) + { + free(memoryPool->osPool.pool); + free(memoryPool); + memoryPool = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *memoryPoolID = (palMemoryPoolID_t)memoryPool; + } + } + } + return status; +} + +void* pal_plat_osPoolAlloc(palMemoryPoolID_t memoryPoolID) +{ + void* result = NULL; + palMemoryPool_t* memoryPool = NULL; + + if(NULLPTR == memoryPoolID) + { + return NULL; + } + + memoryPool = (palMemoryPool_t*)memoryPoolID; + result = osPoolAlloc((osPoolId)memoryPool->memoryPoolID); + + return result; +} + +void* pal_plat_osPoolCAlloc(palMemoryPoolID_t memoryPoolID) +{ + void* result = NULL; + palMemoryPool_t* memoryPool = NULL; + + if(NULLPTR == memoryPoolID) + { + return NULL; + } + + memoryPool = (palMemoryPool_t*)memoryPoolID; + result = osPoolCAlloc((osPoolId)memoryPool->memoryPoolID); + + return result; +} + +palStatus_t pal_plat_osPoolFree(palMemoryPoolID_t memoryPoolID, void* block) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palMemoryPool_t* memoryPool = NULL; + + if(NULLPTR == memoryPoolID || NULL == block) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + memoryPool = (palMemoryPool_t*)memoryPoolID; + platStatus = osPoolFree((osPoolId)memoryPool->memoryPoolID, block); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osPoolDestroy(palMemoryPoolID_t* memoryPoolID) +{ + palStatus_t status = PAL_SUCCESS; + palMemoryPool_t* memoryPool = NULL; + + if(NULL == memoryPoolID || NULLPTR == *memoryPoolID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + memoryPool = (palMemoryPool_t*)*memoryPoolID; + free(memoryPool->osPool.pool); + free(memoryPool); + *memoryPoolID = NULLPTR; + return status; +} + +palStatus_t pal_plat_osMessageQueueCreate(uint32_t messageQCount, palMessageQID_t* messageQID) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t* messageQ = NULL; + if(NULL == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + //! allocate the message queue structure + messageQ = (palMessageQ_t*)malloc(sizeof(palMessageQ_t)); + if (NULL == messageQ) + { + status = PAL_ERR_NO_MEMORY; + } + + if (PAL_SUCCESS == status) + { + //! allocate the actual memory allocation for the message queue blocks, the size of the memory + //! to allocate was taken from CMSIS header (cmsis_os.h) + messageQ->osMessageQ.pool = (uint32_t*)malloc(PAL_RTOS_MESSAGE_Q_SIZE(messageQCount)); + if (NULL == messageQ->osMessageQ.pool) + { + free(messageQ); + messageQ = NULL; + status = PAL_ERR_NO_MEMORY; + } + else + { + memset(messageQ->osMessageQ.pool, 0, PAL_RTOS_MESSAGE_Q_SIZE(messageQCount)); + messageQ->osMessageQ.queue_sz = messageQCount; ///< number of items (elements) in the queue + + messageQ->messageQID = (uintptr_t)osMessageCreate(&(messageQ->osMessageQ), NULL); + if (NULLPTR == messageQ->messageQID) + { + free(messageQ->osMessageQ.pool); + free(messageQ); + messageQ = NULL; + status = PAL_ERR_GENERIC_FAILURE; + } + else + { + *messageQID = (palMessageQID_t)messageQ; + } + } + } + return status; +} + +palStatus_t pal_plat_osMessagePut(palMessageQID_t messageQID, uint32_t info, uint32_t timeout) +{ + palStatus_t status = PAL_SUCCESS; + osStatus platStatus = osOK; + palMessageQ_t* messageQ = NULL; + + if(NULLPTR == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)messageQID; + platStatus = osMessagePut((osMessageQId)messageQ->messageQID, info, timeout); + if (osOK == platStatus) + { + status = PAL_SUCCESS; + } + else + { + status = PAL_RTOS_TRANSLATE_CMSIS_ERROR_CODE(platStatus); + } + + return status; +} + +palStatus_t pal_plat_osMessageGet(palMessageQID_t messageQID, uint32_t timeout, uint32_t* messageValue) +{ + palStatus_t status = PAL_SUCCESS; + osEvent event; + palMessageQ_t* messageQ = NULL; + + if (NULLPTR == messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)messageQID; + event = osMessageGet((osMessageQId)messageQ->messageQID, timeout); + + if ((messageValue != NULL) && (osEventMessage == event.status)) + { + *messageValue = event.value.v; + status = PAL_SUCCESS; + } + else if ((osEventTimeout == event.status) || (osOK == event.status)) + { + status = PAL_ERR_RTOS_TIMEOUT; + } + else if (osErrorParameter == event.status) + { + status = PAL_ERR_RTOS_PARAMETER; + } + + return status; +} + + +palStatus_t pal_plat_osMessageQueueDestroy(palMessageQID_t* messageQID) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQ_t* messageQ = NULL; + + if(NULL == messageQID || NULLPTR == *messageQID) + { + return PAL_ERR_INVALID_ARGUMENT; + } + + messageQ = (palMessageQ_t*)*messageQID; + free(messageQ->osMessageQ.pool); + free(messageQ); + *messageQID = NULLPTR; + return status; +} + + +int32_t pal_plat_osAtomicIncrement(int32_t* valuePtr, int32_t increment) +{ + if (increment >= 0) + { + return core_util_atomic_incr_u32((uint32_t*)valuePtr, increment); + } + else + { + return core_util_atomic_decr_u32((uint32_t*)valuePtr, 0 - increment); + } +} + + + void *pal_plat_malloc(size_t len) +{ + return malloc(len); +} + + + void pal_plat_free(void * buffer) +{ + return free(buffer); +} + +palStatus_t pal_plat_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes) +{ + palStatus_t status = PAL_SUCCESS; + int32_t platStatus = 0; + size_t actualOutputLen = 0; + + if (g_randInitiated) + { + if (bufSizeBytes < sizeof(g_randomBuffer)) + { + memcpy(randomBuf, g_randomBuffer, bufSizeBytes); + } + else + { + memcpy(randomBuf, g_randomBuffer, sizeof(g_randomBuffer)); + } + } + else + { + if (bufSizeBytes <= sizeof(g_randomBuffer)) + { + platStatus = mbedtls_hardware_poll(NULL /*Not used by the function*/, g_randomBuffer, sizeof(g_randomBuffer), &actualOutputLen); + if (0 != platStatus || actualOutputLen != sizeof(g_randomBuffer)) + { + status = PAL_ERR_RTOS_TRNG_FAILED; + } + else + { + memcpy(randomBuf, g_randomBuffer, bufSizeBytes); + g_randInitiated = true; + } + } + else + { + platStatus = mbedtls_hardware_poll(NULL /*Not used by the function*/, randomBuf, bufSizeBytes, &actualOutputLen); + if (0 != platStatus || actualOutputLen != bufSizeBytes) + { + status = PAL_ERR_RTOS_TRNG_FAILED; + } + else + { + memcpy(g_randomBuffer, randomBuf, sizeof(g_randomBuffer)); + g_randInitiated = true; + } + } + } + return status; +} + +#endif //mbedOS version
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/Storage/FileSystem/pal_plat_fileSystem.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/Storage/FileSystem/pal_plat_fileSystem.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,599 @@ +#include "mbed.h" + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "FATFileSystem.h" + +#include "FileSystemLike.h" +#include "FilePath.h" + + +//PAL Includes +#include "pal.h" +#include "pal_plat_fileSystem.h" + + +#ifndef EEXIST +#define EEXIST 17 +#endif +#ifndef EACCES +#define EACCES 13 +#endif +#ifndef EFAULT +#define EFAULT 14 +#endif +#ifndef EROFS +#define EROFS 30 +#endif +#ifndef EBUSY +#define EBUSY 16 +#endif +#ifndef ENAMETOOLONG +#define ENAMETOOLONG 36 +#endif +#ifndef EBADF +#define EBADF 9 +#endif +#ifndef EISDIR +#define EISDIR 21 +#endif +#ifndef ENOTEMPTY +#define ENOTEMPTY 39 +#endif +#ifndef ENOENT +#define ENOENT 2 +#endif + + + +#define PAL_FS_COPY_BUFFER_SIZE 256 //!< Size of the chunk to copy files +PAL_PRIVATE const char *g_platOpenModeConvert[] = {"0", "r", "r+", "w+x", "w+"}; //!< platform convert table for \b fopen() modes +PAL_PRIVATE const int g_platSeekWhenceConvert[] = {0, SEEK_SET, SEEK_CUR, SEEK_END}; //!< platform convert table for \b fseek() relative position modes + + + + + +/*! \brief This function find the next file in a directory + * + * @param[in] *dh - Directory handler to an open DIR + * @param[out] CurrentEntry - entry for the file found in Directory (pre allocated) + * + * \return true - upon successful operation.\n + * + */ +PAL_PRIVATE bool pal_plat_findNextFile(DIR *dh, struct dirent ** CurrentEntry); + +/*! \brief This function translate the platform errors opcode to pal error codes + * + * @param[in] errorOpCode - platform opcode to be translated + * + * \return PAL_SUCCESS upon successful operation.\n + */ +PAL_PRIVATE palStatus_t pal_plat_errorTranslation (int errorOpCode); + + +/*! \brief This function build the full path name by adding the filename to the working path given in pathName arg + * + * @param[in] *pathName - pointer to the null-terminated string that specifies the directory name. + * @param[in] *fileName - pointer to the file name + * @param[out] *fullPath - pointer to the full path including the filename (pre allocated) + * + * \return PAL_SUCCESS upon successful operation.\n + * PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t + * + */ +PAL_PRIVATE palStatus_t pal_plat_addFileNameToPath(const char *pathName, const char * fileName, char * fullPath); + +/*! \brief This function copy one file from source folder to destination folder +* +* @param[in] pathNameSrc - Pointer to a null-terminated string that specifies the source dir. +* @param[in] pathNameDest - Pointer to a null-terminated string that specifies the destination dir +* @param[in] fileName - pointer the the file name +* +* \return PAL_SUCCESS upon successful operation.\n +* PAL_FILE_SYSTEM_ERROR - see error code description \c palError_t +* +* \note File should not be open.\n +* If the Destination file exist then it shall be truncated +* +*/ +PAL_PRIVATE palStatus_t pal_plat_fsCpFile(const char *pathNameSrc, char *pathNameDest, char * fileName); + +palStatus_t pal_plat_fsMkdir(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + if(mkdir(pathName, 0600)) + { + ret = pal_plat_errorTranslation(errno); + } + return ret; +} + + +palStatus_t pal_plat_fsRmdir(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + + if (ret == PAL_SUCCESS) + { + if (remove(pathName)) + { + if(errno == EACCES) + { + ret = PAL_ERR_FS_DIR_NOT_EMPTY; + } + else if(errno == ENOENT) + { + ret = PAL_ERR_FS_NO_PATH; + } + else + { + ret = pal_plat_errorTranslation(errno); + } + } + } + return ret; +} + + +palStatus_t pal_plat_fsFopen(const char *pathName, pal_fsFileMode_t mode, palFileDescriptor_t *fd) +{ + palStatus_t ret = PAL_SUCCESS; + + if (mode == PAL_FS_FLAG_READWRITEEXCLUSIVE) + { + *fd = (palFileDescriptor_t)fopen(pathName, "r"); + if (*fd) + { + ret = PAL_ERR_FS_NAME_ALREADY_EXIST; + fclose((FILE *)*fd); + } + } + + if(ret == PAL_SUCCESS) + { + *fd = (palFileDescriptor_t)fopen(pathName, g_platOpenModeConvert[mode]); + if (!(*fd)) + { + ret = pal_plat_errorTranslation(errno); + } + } + return ret; +} + + +palStatus_t pal_plat_fsFclose(palFileDescriptor_t *fd) +{ + palStatus_t ret = PAL_SUCCESS; + if (fclose((FILE *)*fd)) + { + ret = pal_plat_errorTranslation(errno); + } + return ret; +} + + +palStatus_t pal_plat_fsFread(palFileDescriptor_t *fd, void * buffer, size_t numOfBytes, size_t *numberOfBytesRead) +{ + palStatus_t ret = PAL_SUCCESS; + clearerr((FILE *)*fd); + *numberOfBytesRead = fread(buffer, 1, numOfBytes, (FILE *)*fd); + if (*numberOfBytesRead != numOfBytes) + { + if (ferror((FILE *)*fd)) + { + ret = PAL_ERR_FS_ERROR; + } + clearerr((FILE *)*fd); + } + return ret; +} + + +palStatus_t pal_plat_fsFwrite(palFileDescriptor_t *fd, const void *buffer, size_t numOfBytes, size_t *numberOfBytesWritten) +{ + palStatus_t ret = PAL_SUCCESS; + errno = 0; + *numberOfBytesWritten = fwrite(buffer, 1, numOfBytes, (FILE *)*fd); + if (*numberOfBytesWritten != numOfBytes) + { + if(errno == EBADF) + { + ret = PAL_ERR_FS_ACCESS_DENIED; + } + else + { + ret = pal_plat_errorTranslation(errno); + } + } + return ret; +} + + +palStatus_t pal_plat_fsFseek(palFileDescriptor_t *fd, int32_t offset, pal_fsOffset_t whence) +{ + palStatus_t ret = PAL_SUCCESS; + if (fseek((FILE *)*fd, offset, g_platSeekWhenceConvert[whence])) + { + ret = pal_plat_errorTranslation(errno); + } + return ret; +} + + +palStatus_t pal_plat_fsFtell(palFileDescriptor_t *fd, int32_t * pos) +{ + palStatus_t ret = PAL_SUCCESS; + long retPos = 0; + *pos = 0; + retPos = ftell((FILE *)*fd); + if (retPos < 0) + { + ret = pal_plat_errorTranslation(errno); + } + else + { + *pos = retPos; + } + return ret; +} + + +palStatus_t pal_plat_fsUnlink(const char *pathName) +{ + palStatus_t ret = PAL_SUCCESS; + if (remove(pathName)) + { + ret = pal_plat_errorTranslation(errno); + } + return ret; +} + + +palStatus_t pal_plat_fsRmFiles(const char *pathName) +{ + DIR *dh = NULL; //Directory handler + palStatus_t ret = PAL_SUCCESS; + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; //Buffer for coping the name and folder + struct dirent * currentEntry = NULL; //file Entry + + dh = opendir(pathName); + if (dh) + { + while(true) + { + if (!pal_plat_findNextFile(dh, ¤tEntry)) + { + ret = PAL_ERR_FS_ERROR_IN_SEARCHING; + break; + } + + if (currentEntry) + { + pal_plat_addFileNameToPath(pathName, currentEntry->d_name, buffer); + if (currentEntry->d_type == DT_DIR) + { + pal_plat_fsRmFiles(buffer); + } + if (remove(buffer)) + { + ret = pal_plat_errorTranslation(errno); + break; + } + } + else + {//End of directory reached without errors break, close directory and exit + break; + } + }//while() + } + else//if (dh) + { + ret = PAL_ERR_FS_NO_PATH; + } + + if (dh) + { + closedir(dh); //Close DIR handler + } + return ret; +} + + +palStatus_t pal_plat_fsCpFolder(const char *pathNameSrc, char *pathNameDest) +{ + DIR *src_dh = NULL; //Directory for the source Directory handler + palStatus_t ret = PAL_SUCCESS; + struct dirent * currentEntry = NULL; //file Entry + + src_dh = opendir(pathNameSrc); + if (src_dh == NULL) + { + ret = PAL_ERR_FS_NO_PATH; + } + + if (ret == PAL_SUCCESS) + { + while(true) + { + if (!pal_plat_findNextFile(src_dh, ¤tEntry)) + { + ret = PAL_ERR_FS_ERROR_IN_SEARCHING; + break; + } + + if (currentEntry) + { + if (currentEntry->d_type == DT_DIR) + { + continue; + } + //copy the file to the destination + ret = pal_plat_fsCpFile(pathNameSrc, pathNameDest, currentEntry->d_name); + if (ret != PAL_SUCCESS) + { + break; + } + } + else + {//End of directory reached without errors break and close directory and exit + break; + } + }//while() + } + + if (src_dh) + { + closedir(src_dh); + } + return ret; +} + + +PAL_PRIVATE palStatus_t pal_plat_fsCpFile(const char *pathNameSrc, char *pathNameDest, char * fileName) +{ + palStatus_t ret = PAL_SUCCESS; + palFileDescriptor_t src_fd = 0; + palFileDescriptor_t dst_fd = 0; + char buffer_name[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; //Buffer for coping the name and folder + char * buffer = NULL; + size_t bytesCount = 0; + + //Add file name to path + pal_plat_addFileNameToPath(pathNameSrc, fileName, buffer_name); + src_fd = (palFileDescriptor_t)fopen(buffer_name, g_platOpenModeConvert[PAL_FS_FLAG_READONLY]); + if (src_fd == 0) + { + ret = pal_plat_errorTranslation(errno); + } + else + { + //Add file name to path + pal_plat_addFileNameToPath(pathNameDest, fileName, buffer_name); + dst_fd = (palFileDescriptor_t)fopen(buffer_name, g_platOpenModeConvert[PAL_FS_FLAG_READWRITETRUNC]); + if (dst_fd == 0) + { + ret = pal_plat_errorTranslation(errno); + } + else + { + buffer = (char*)malloc(PAL_FS_COPY_BUFFER_SIZE); + if (!buffer) + { + ret = PAL_ERR_RTOS_RESOURCE; + } + } + } + + if (ret == PAL_SUCCESS) + { + while (1) + { + ret = pal_fsFread(&src_fd, buffer, PAL_FS_COPY_BUFFER_SIZE, &bytesCount); + if (ret != PAL_SUCCESS) + { + break; + } + + //Check if end of file reached + if (bytesCount == 0) + { + break; + } + + ret = pal_fsFwrite(&dst_fd, buffer, bytesCount, &bytesCount); + if (ret != PAL_SUCCESS) + { + break; + } + } + } + + if (src_fd != 0) + { + pal_fsFclose(&src_fd); + } + if (dst_fd != 0) + { + pal_fsFclose(&dst_fd); + } + if (buffer) + { + free(buffer); + } + return ret; +} + + +const char* pal_plat_fsGetDefaultRootFolder(pal_fsStorageID_t dataID) +{ + const char* returnedRoot = NULL; + if (PAL_FS_PARTITION_PRIMARY == dataID) + { + returnedRoot = PAL_FS_MOUNT_POINT_PRIMARY; + } + else if (PAL_FS_PARTITION_SECONDARY == dataID) + { + returnedRoot = PAL_FS_MOUNT_POINT_SECONDARY; + } + + return returnedRoot; +} + + +PAL_PRIVATE bool pal_plat_findNextFile(DIR *dh, struct dirent ** CurrentEntry) +{ + bool ret = true; + bool skip = false; + bool foundFile = false; + + do + { + errno = 0; + *CurrentEntry = readdir(dh); + if (*CurrentEntry) + { + /* Skip the names "." and ".." as we don't want to remove them. also make sure that the current entry point to REGULER file*/ + skip = (!strcmp((*CurrentEntry)->d_name, ".")) || (!strcmp((*CurrentEntry)->d_name, "..")); + if (skip) + { + continue; + } + else + { + foundFile = true; + } + } + else + {//Check if EOF reached + if (errno) + {//NOT!!! EOF other error + ret = false; + } + break; //Break from while + } + } + while((!foundFile) && (ret)); //While file has been found or ret is set to false + + return ret; +} + +PAL_PRIVATE palStatus_t pal_plat_addFileNameToPath(const char *pathName, const char * fileName, char * fullPath) +{ + palStatus_t ret = PAL_SUCCESS; + + if ((strlen(pathName) >= PAL_MAX_FOLDER_DEPTH_CHAR) || (strlen(fileName) >= PAL_MAX_FULL_FILE_NAME)) + { + ret = PAL_ERR_FS_FILENAME_LENGTH; + } + else if (fullPath) + { + strcpy(fullPath, pathName); + strcat(fullPath, "/"); + strcat(fullPath, fileName); + } + else + { + ret = PAL_ERR_RTOS_RESOURCE; + } + return ret; +} + + + + +PAL_PRIVATE palStatus_t pal_plat_errorTranslation (int errorOpCode) +{ + palStatus_t ret = PAL_SUCCESS; + + switch(errorOpCode) + { + case 0: + break; + case EACCES: + case EFAULT: + case EROFS: + ret = PAL_ERR_FS_ACCESS_DENIED; + break; + + case EBUSY : + ret = PAL_ERR_FS_BUSY; + break; + + case EEXIST: + ret = PAL_ERR_FS_NAME_ALREADY_EXIST; + break; + + case ENAMETOOLONG: + ret = PAL_ERR_FS_FILENAME_LENGTH; + break; + + case EBADF: + ret = PAL_ERR_FS_BAD_FD; + break; + + case EINVAL: + ret = PAL_ERR_FS_INVALID_ARGUMENT; + break; + + case EISDIR: + ret = PAL_ERR_FS_FILE_IS_DIR; + break; + + case ENOTEMPTY: + ret = PAL_ERR_FS_DIR_NOT_EMPTY; + break; + + case ENOENT: + ret = PAL_ERR_FS_NO_FILE; + break; + + default: + ret = PAL_ERR_FS_ERROR; + break; + } + return ret; +} + + +size_t pal_plat_fsSizeCheck(const char *stringToChk) +{ + size_t length = 0; + length = strlen(stringToChk); + return length; +} + + + + + +palStatus_t pal_plat_fsFormat(pal_fsStorageID_t dataID) +{ + const char* partitionTranslationArray[] = + { + PAL_FS_MOUNT_POINT_PRIMARY, + PAL_FS_MOUNT_POINT_SECONDARY + };// "/sd\0" + FileSystem *myFs; + int err = 0; + palStatus_t status = PAL_SUCCESS; + FilePath myPath(partitionTranslationArray[dataID]); + myFs = (FileSystem*)myPath.fileSystem(); + if (NULL != myFs) + { + err = myFs->reformat(NULL); + if (err < 0) + { + status = PAL_ERR_FS_ERROR; + } + } + else //This should not happen + { + status = PAL_ERR_FS_ERROR; + } + return status; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/Storage/Flash/pal_plat_internalFlash.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/Storage/Flash/pal_plat_internalFlash.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,132 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "mbed.h" +#include "flash_api.h" +#include "pal.h" +#include "pal_plat_internalFlash.h" + + +////////////////////////////PRIVATE/////////////////////////////////// +PAL_PRIVATE FlashIAP flash; +PAL_PRIVATE palStatus_t pal_platFlashErrorTranslation(int32_t status); +PAL_PRIVATE bool pal_isAlignedToSector(uint32_t address, size_t size); +////////////////////////////END PRIVATE//////////////////////////////// + +palStatus_t pal_plat_internalFlashInit(void) +{ + uint32_t status = 0; + palStatus_t ret = PAL_SUCCESS; + status = flash.init(); + if (status != 0) + { + ret = pal_platFlashErrorTranslation(status); + } + return ret; +} + + +palStatus_t pal_plat_internalFlashDeInit(void) +{ + uint32_t status = 0; + palStatus_t ret = PAL_SUCCESS; + status = flash.deinit(); + if (status != 0) + { + ret = pal_platFlashErrorTranslation(status); + } + return ret; +} + + +palStatus_t pal_plat_internalFlashWrite(const size_t size, const uint32_t address, const uint32_t * buffer) +{ + uint32_t status = 0; + palStatus_t ret = PAL_SUCCESS; + + status = flash.program(buffer, address, size); + if (status != 0) + { + ret = pal_platFlashErrorTranslation(status); + } + return ret; +} + + +palStatus_t pal_plat_internalFlashRead(const size_t size, const uint32_t address, uint32_t * buffer) +{ + uint32_t status = 0; + palStatus_t ret = PAL_SUCCESS; + status = flash.read(buffer, address, size); + if (status != 0) + { + ret = pal_platFlashErrorTranslation(status); + } + return ret; +} + + +palStatus_t pal_plat_internalFlashErase(uint32_t address, size_t size) +{ + uint32_t status = 0; + palStatus_t ret = PAL_SUCCESS; + if(!pal_isAlignedToSector(address,size)) + { + return PAL_ERR_INTERNAL_FLASH_SECTOR_NOT_ALIGNED; //not aligned to sector + } + + status = flash.erase(address, size); + if (status != 0) + { + ret = pal_platFlashErrorTranslation(status); + } + return ret; +} + + +size_t pal_plat_internalFlashGetPageSize(void) +{ + size_t ret = flash.get_page_size(); + return ret; +} + + +size_t pal_plat_internalFlashGetSectorSize(uint32_t address) +{ + size_t ret = flash.get_sector_size(address); + return ret; +} + + +PAL_PRIVATE bool pal_isAlignedToSector(uint32_t address, size_t size) +{ + uint32_t currentSectorSize = pal_plat_internalFlashGetSectorSize(address); + if ((size % currentSectorSize) || (address % currentSectorSize)) + { + return false; + } + else + { + return true; + } +} + + +PAL_PRIVATE palStatus_t pal_platFlashErrorTranslation(int32_t status) +{ + return PAL_ERR_INTERNAL_FLASH_GENERIC_FAILURE;//ALL mbedOS error are -1 +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/Update/pal_plat_update.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Source/Port/Reference-Impl/OS_Specific/mbedOS/Update/pal_plat_update.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,132 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <mbed.h> +#include <pal.h> +#include <pal_plat_update.h> + + +#ifndef PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET +#ifdef MBED_CONF_MBED_CLIENT_PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET +#define PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET MBED_CONF_MBED_CLIENT_PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET +#else // MBED_CONF_MBED_CLIENT_PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET +#define PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET 0 +#endif // MBED_CONF_MBED_CLIENT_PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET +#endif // PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET + +palStatus_t pal_plat_imageInitAPI(palImageSignalEvent_t CBfunction) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageDeInit(void) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageGetMaxNumberOfImages(uint8_t *imageNumber) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageSetVersion(palImageId_t imageId, const palConstBuffer_t* version) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageGetDirectMemAccess(palImageId_t imageId, void** imagePtr, size_t *imageSizeInBytes) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageActivate(palImageId_t imageId) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageGetActiveHash(palBuffer_t *hash) +{ + palStatus_t ret = PAL_ERR_UPDATE_ERROR; + uint32_t read_offset = PAL_UPDATE_ACTIVE_METADATA_HEADER_OFFSET + + offsetof(FirmwareHeader_t, firmwareSHA256); + + FlashIAP flash; + int rc = -1; + + rc = flash.init(); + if (rc != 0) + { + DEBUG_PRINT("flash init failed\r\n"); + goto exit; + } + + + rc = flash.read(hash->buffer, read_offset, SIZEOF_SHA256); + if (rc != 0) + { + DEBUG_PRINT("flash read failed\r\n"); + goto exit; + } + + hash->bufferLength = SIZEOF_SHA256; + + rc = flash.deinit(); + if (rc != 0) + { + DEBUG_PRINT("flash deinit failed\r\n"); + goto exit; + } + + ret = PAL_SUCCESS; + +exit: + return ret; +} + +palStatus_t pal_plat_imageGetActiveVersion (palBuffer_t* version) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageWriteHashToMemory(const palConstBuffer_t* const hashValue) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageSetHeader(palImageId_t imageId, palImageHeaderDeails_t *details) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageReserveSpace(palImageId_t imageId, size_t imageSize) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageWrite(palImageId_t imageId, size_t offset, palConstBuffer_t *chunk) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageReadToBuffer(palImageId_t imageId, size_t offset, palBuffer_t *chunk) +{ + return PAL_ERR_NOT_IMPLEMENTED; +} + +palStatus_t pal_plat_imageFlush(palImageId_t package_id) +{ + return PAL_ERR_NOT_IMPLEMENTED; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/CMakeLists.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,124 @@ +include_directories(../Source/PAL-Impl/Services-API) +include_directories(../Source/Port/Platform-API) +option(SPLIT_BINARIES "Choose whether to split the tests into 2 binaries or not" OFF) + +if (${OS_BRAND} MATCHES FreeRTOS) + add_definitions(-DUNITY_OUTPUT_CHAR=unity_output_char) +endif() + +#on Linux, we might find different names for the network interface +#so we have to find it, and pass to the code. +if (${OS_BRAND} MATCHES Linux) + add_definitions(-DPAL_NO_FATFS_SD_TEST=1) + if (NOT USE_ETH_INTERFACE) + execute_process(COMMAND ip -o -4 route show to default + COMMAND awk "{print $5}" + COMMAND head -1 + OUTPUT_STRIP_TRAILING_WHITESPACE + OUTPUT_VARIABLE ETHNAME) + set(TMPD \"${ETHNAME}\") + add_definitions(-DPAL_LINUX_ETH=${TMPD}) + message( "ETHNAME = ${ETHNAME}") + else() + add_definitions(-DPAL_LINUX_ETH=${USE_ETH_INTERFACE}) + message("Using ${USE_ETH_INTERFACE} for network") + endif() +endif() + +if (CMAKE_BUILD_TYPE MATCHES Debug) + add_definitions(-DDEBUG) +endif() + +include_directories(Unitest) +include_directories(Common) +#include_directories(Unitest/Networking) +include_directories(Unity/src) +include_directories(Unity/extras/fixture/src) + + +set (PAL_TESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Unitest/) +set (PAL_UNITY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Unity/src/) +set (PAL_UNITY_FIXTURE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Unity/extras/fixture/src) +set (PAL_TEST_BSP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../Examples/PlatformBSP) +set (PAL_UTILS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../Utils/memoryProfiler/Other) + +set(PAL_TEST_RTOS_SRCS + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/RTOS/pal_rtos_test_runner.c + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/RTOS/pal_rtos_test.c + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/RTOS/pal_rtos_test_utils.c +) + +set(PAL_TEST_NETWORK_SRCS + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/Networking/pal_socket_test_runner.c + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/Networking/pal_socket_test.c +) + +set(PAL_TEST_FS_SRCS + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/FileSystem/pal_fileSystem_test_runner.c + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/FileSystem/pal_fileSystem_test.c +) + +set(PAL_TEST_TLS_SRCS + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/TLS/pal_tls_test_runner.c + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/TLS/pal_tls_test.c +) + +set(PAL_TEST_CRYPTO_SRCS + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/Crypto/pal_crypto_test_runner.c + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/Crypto/pal_crypto_test.c +) + +set(PAL_TEST_UPDATE_SRCS + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/Update/pal_update_test_runner.c + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/Update/pal_update_test.c +) + +set(PAL_TEST_FLASH_SRCS + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/Storage/pal_internalFlash_test_runner.c + ${PAL_TESTS_SOURCE_DIR}/PAL_Modules/Storage/pal_internalFlash_test.c +) + +set(PAL_TEST_COMMON_SRCS + ${PAL_TESTS_SOURCE_DIR}/TestRunner/test_Runner.c + ${PAL_TESTS_SOURCE_DIR}/pal_test_main.c + ${PAL_UNITY_SOURCE_DIR}unity.c + ${PAL_UNITY_FIXTURE_DIR}/unity_fixture.c + ${PAL_TESTS_SOURCE_DIR}/TestRunner/pal_test${OS_BRAND}.c +) + +set(PAL_TEST_BSP_SRCS + ${PAL_TEST_BSP_DIR}/${PAL_TARGET_DEVICE}_${OS_BRAND}/BoardInit.c + ${PAL_TEST_BSP_DIR}/${PAL_TARGET_DEVICE}_${OS_BRAND}/FileSystemInit.c + ${PAL_TEST_BSP_DIR}/${PAL_TARGET_DEVICE}_${OS_BRAND}/NetworkInit.c + ${PAL_TEST_BSP_DIR}/pal_insecure_ROT.c +) + +set(PAL_TEST_FAKE_ROT_SRCS + ${PAL_TEST_BSP_DIR}/pal_insecure_ROT.c +) + + +if (PAL_MEMORY_STATISTICS) #currently working only in gcc based compilers + list (APPEND PAL_TEST_BSP_SRCS ${PAL_UTILS_DIR}/pal_memory.c) + add_definitions(-DPAL_MEMORY_STATISTICS=1) +endif() + +include_directories(${PAL_TEST_BSP_DIR}/Include/) +include_directories(${PAL_TESTS_SOURCE_DIR}/Includes/) + +set(test_src ${PAL_TEST_BSP_SRCS}; ${PAL_TEST_COMMON_SRCS}; ${PAL_TEST_NETWORK_SRCS}; ${PAL_TEST_TLS_SRCS}; ${PAL_TEST_CRYPTO_SRCS}; ${PAL_TEST_RTOS_SRCS}; ${PAL_TEST_FLASH_SRCS}; ${PAL_TEST_FS_SRCS}; ${PAL_TEST_UPDATE_SRCS}; ${PAL_TEST_FAKE_ROT_SRCS} ) +set (PAL_TEST_FLAGS + -DPAL_TEST_RTOS + -DPAL_TEST_FS + -DPAL_TEST_UPDATE + -DPAL_TEST_NETWORK + -DPAL_TEST_TLS + -DPAL_TEST_CRYPTO + -DPAL_TEST_FLASH +) + +CREATE_TEST_LIBRARY(palTests "${test_src}" "${PAL_TEST_FLAGS}") + + +CREATE_LIBRARY(palBringup "${PAL_TEST_BSP_SRCS}" "") +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +TestRunner/pal_testFreeRTOS.c +TestRunner/pal_testLinux.c \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/Includes/pal_test_main.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/Includes/pal_test_main.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,114 @@ +#ifndef MBED_CLIENT_PAL_TEST_MAINTEST_H_ +#define MBED_CLIENT_PAL_TEST_MAINTEST_H_ +#include "pal.h" +#include "pal_rtos.h" + + + +#ifndef PAL_TEST_RTOS +#define PAL_TEST_RTOS 0 +#endif // PAL_TEST_RTOS + +#ifndef PAL_TEST_NETWORK +#define PAL_TEST_NETWORK 0 +#endif // PAL_TEST_NETWORK + +#ifndef PAL_TEST_TLS +#define PAL_TEST_TLS 0 +#endif // PAL_TEST_TLS + +#ifndef PAL_TEST_CRYPTO +#define PAL_TEST_CRYPTO 0 +#endif // PAL_TEST_CRYPTO + +#ifndef PAL_TEST_FS +#define PAL_TEST_FS 0 +#endif // PAL_TEST_FS + +#ifndef PAL_TEST_UPDATE +#define PAL_TEST_UPDATE 0 +#endif // PAL_TEST_UPDATE + +#ifndef PAL_TEST_FLASH +#define PAL_TEST_FLASH 1 +#endif // PAL_TEST_FLASH + +#define TEST_PRINTF(ARGS...) PAL_PRINTF(ARGS) + +#ifdef PAL_LINUX +#define PAL_TEST_THREAD_STACK_SIZE 16*1024*sizeof(uint32_t) +#else +#define PAL_TEST_THREAD_STACK_SIZE 512*sizeof(uint32_t) +#endif + + +typedef struct { + int argc; + char **argv; +} pal_args_t; + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef void (*testMain_t)(pal_args_t *); +void palTestMain(pal_args_t * args); + +/*! \brief This function initialized the platform (BSP , file system ....) +* +* @param None +* +* \return void +* +*/ +bool initPlatform(void); + + +/*! \brief This function is called from the main function +* and calls the startup sequence for the board tests +* +* @param[in] mainTestFunc - callback function for the main test runner +* @param[in] args - structure the contains argv and argc received from the main function +* +* \return void +* +*/ +bool runProgram(testMain_t mainTestFunc, pal_args_t * args); + + +#if 1 + void TEST_pal_rtos_GROUP_RUNNER(void); +#endif + +#if PAL_TEST_NETWORK + void TEST_pal_socket_GROUP_RUNNER(void); +#endif + +#if PAL_TEST_TLS + void TEST_pal_tls_GROUP_RUNNER(void); +#endif + +#if PAL_TEST_CRYPTO + void TEST_pal_crypto_GROUP_RUNNER(void); +#endif + +#if PAL_TEST_FS + void TEST_pal_fileSystem_GROUP_RUNNER(void); +#endif + +#if PAL_TEST_UPDATE + void TEST_pal_update_GROUP_RUNNER(void); +#endif + +#if PAL_TEST_FLASH + void TEST_pal_internalFlash_GROUP_RUNNER(void); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* MBED_CLIENT_PAL_TEST_MAINTEST_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Crypto/pal_crypto_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Crypto/pal_crypto_test.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1048 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "pal_Crypto.h" +#include "unity.h" +#include "unity_fixture.h" +#include "pal_crypto_test_data.h" +#include "string.h" +#include "time.h" + + +TEST_GROUP(pal_crypto); + +TEST_SETUP(pal_crypto) +{ + pal_init(); +} + +TEST_TEAR_DOWN(pal_crypto) +{ + pal_destroy(); +} + +/** + * @brief Testing AES encryption and decryption of buffers in CTR mode. + * + * The test encrypts a buffer, compares it against a desired result and then decrypts it back and compares with the original buffer. + * + * Uses CtrVector. + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize an AES context. | PAL_SUCCESS | + * | 2 | Set an AES 128bit key for encryption. | PAL_SUCCESS | + * | 3 | Perform AES CTR encryption on an input vector and check that the result is as expected. | PAL_SUCCESS | + * | 4 | Release AES context. | PAL_SUCCESS | + * | 5 | Initialize an AES context. | PAL_SUCCESS | + * | 6 | Set an AES 128bit key for encryption (used for decryption, see AES CTR docs) | PAL_SUCCESS | + * | 7 | Perform AES CTR decryption on an input vector and check that the result is as expected. | PAL_SUCCESS | + * | 8 | Release AES context. | PAL_SUCCESS | + */ +TEST(pal_crypto, AES_CTR) +{ + palStatus_t result; + palAesHandle_t ctx_enc = NULLPTR, ctx_dec = NULLPTR; + unsigned char out[16] = {0}; + unsigned char iv[16] = {0}; + + memcpy(iv, CtrVector.nonce, sizeof(CtrVector.nonce)); + + /*#1*/ + result = pal_initAes(&ctx_enc); + TEST_ASSERT_NOT_EQUAL(ctx_enc, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#2*/ + result = pal_setAesKey(ctx_enc, CtrVector.key, 128, PAL_KEY_TARGET_ENCRYPTION); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#3*/ + result = pal_aesCTR(ctx_enc, CtrVector.input, out, sizeof(CtrVector.input), iv); + TEST_ASSERT_EQUAL_MEMORY(CtrVector.output, out, sizeof(CtrVector.output)); + + /*#4*/ + result = pal_freeAes(&ctx_enc); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + memcpy(iv, CtrVector.nonce, sizeof(CtrVector.nonce)); + memset(out, 0, sizeof(out)); + + /*#5*/ + result = pal_initAes(&ctx_dec); + TEST_ASSERT_NOT_EQUAL(ctx_dec, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#6*/ + result = pal_setAesKey(ctx_dec, CtrVector.key, 128, PAL_KEY_TARGET_ENCRYPTION); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#7*/ + result = pal_aesCTR(ctx_dec, CtrVector.output, out, sizeof(CtrVector.output), iv); + TEST_ASSERT_EQUAL_MEMORY(CtrVector.input, out, sizeof(CtrVector.output)); + + /*#8*/ + result = pal_freeAes(&ctx_dec); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); +} + +/** + * @brief Testing AES encryption and decryption of buffers in CTR mode. + * + * The test encrypts a buffer, compares it against the desired result and then decrypts it back and compares with the original buffer. + * + * Uses CtrVector. + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize an AES context. | PAL_SUCCESS | + * | 2 | Set an AES 128bit key for encryption. | PAL_SUCCESS | + * | 3 | Perform AES CTR encryption on input vector and check the encryption output. | PAL_SUCCESS | + * | 4 | Release AES context. | PAL_SUCCESS | + * | 5 | Initialize an AES context. | PAL_SUCCESS | + * | 6 | Set an AES 128bit key for encryption (used for decryption, see AES CTR docs). | PAL_SUCCESS | + * | 7 | Perform AES CTR decryption on an input vector and check that the result is as expected.| PAL_SUCCESS | + * | 8 | Release AES context. | PAL_SUCCESS | + */ +TEST(pal_crypto, AES_CTR_ZeroOffset) +{ + palStatus_t result; + palAesHandle_t ctx_enc = NULLPTR, ctx_dec = NULLPTR; + unsigned char out[16] = {0}; + unsigned char iv[16] = {0}; + + memcpy(iv, CtrVector.nonce, sizeof(CtrVector.nonce)); + + /*#1*/ + result = pal_initAes(&ctx_enc); + TEST_ASSERT_NOT_EQUAL(ctx_enc, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#2*/ + result = pal_setAesKey(ctx_enc, CtrVector.key, 128, PAL_KEY_TARGET_ENCRYPTION); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#3*/ + result = pal_aesCTRWithZeroOffset(ctx_enc, CtrVector.input, out, sizeof(CtrVector.input), iv); + TEST_ASSERT_EQUAL_MEMORY(CtrVector.output, out, sizeof(CtrVector.output)); + + /*#4*/ + result = pal_freeAes(&ctx_enc); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + memcpy(iv, CtrVector.nonce, sizeof(CtrVector.nonce)); + memset(out, 0, sizeof(out)); + + /*#5*/ + result = pal_initAes(&ctx_dec); + TEST_ASSERT_NOT_EQUAL(ctx_dec, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#6*/ + result = pal_setAesKey(ctx_dec, CtrVector.key, 128, PAL_KEY_TARGET_ENCRYPTION); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#7*/ + result = pal_aesCTRWithZeroOffset(ctx_dec, CtrVector.output, out, sizeof(CtrVector.output), iv); + TEST_ASSERT_EQUAL_MEMORY(CtrVector.input, out, sizeof(CtrVector.output)); + + /*#8*/ + result = pal_freeAes(&ctx_dec); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); +} + + +/** + * @brief Testing AES encryption and decryption of buffers in ECB mode. + * + * The test encrypts a buffer, compares it against the desired result and then decrypts it back and compares with the original buffer. + * + * Uses EcbVector. + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize an AES context. | PAL_SUCCESS | + * | 2 | Set an AES 128bit key for encryption. | PAL_SUCCESS | + * | 3 | Perform AES ECB encryption on input vector and check the encryption output. | PAL_SUCCESS | + * | 4 | Release AES context. | PAL_SUCCESS | + * | 5 | Initialize an AES context. | PAL_SUCCESS | + * | 6 | Set an AES 128bit key for decryption. | PAL_SUCCESS | + * | 7 | Perform AES ECB decryption on an input vector and check that the result is as expected.| PAL_SUCCESS | + * | 8 | Release AES context. | PAL_SUCCESS | + */ +TEST(pal_crypto, AES_ECB) +{ + palStatus_t result; + palAesHandle_t ctx_enc = NULLPTR, ctx_dec = NULLPTR; + unsigned char out[16] = {0}; + unsigned char iv[16] = {0}; + + memcpy(iv, EcbVector.nonce, sizeof(EcbVector.nonce)); + + /*#1*/ + result = pal_initAes(&ctx_enc); + TEST_ASSERT_NOT_EQUAL(ctx_enc, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#2*/ + result = pal_setAesKey(ctx_enc, EcbVector.key, 128, PAL_KEY_TARGET_ENCRYPTION); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#3*/ + result = pal_aesECB(ctx_enc, EcbVector.input, out, PAL_AES_ENCRYPT); + TEST_ASSERT_EQUAL_MEMORY(EcbVector.output, out, sizeof(EcbVector.output)); + + /*#4*/ + result = pal_freeAes(&ctx_enc); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + memcpy(iv, EcbVector.nonce, sizeof(EcbVector.nonce)); + memset(out, 0, sizeof(out)); + + /*#5*/ + result = pal_initAes(&ctx_dec); + TEST_ASSERT_NOT_EQUAL(ctx_dec, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#6*/ + result = pal_setAesKey(ctx_dec, EcbVector.key, 128, PAL_KEY_TARGET_DECRYPTION); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#7*/ + result = pal_aesECB(ctx_dec, EcbVector.output, out, PAL_AES_DECRYPT); + TEST_ASSERT_EQUAL_MEMORY(EcbVector.input, out, sizeof(EcbVector.output)); + + /*#8*/ + result = pal_freeAes(&ctx_dec); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); +} + + +/** + * @brief Testing AES encryption and decryption of buffers in CCM mode. + * + * The test encrypts a buffer, compares it against the desired result and then decrypts it back and compares with the original buffer. + * + * Uses aesCcmVectors. + * + * For each vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize an AES CCM context. | PAL_SUCCESS | + * | 2 | Set an AES 128bit key for this particular vector. | PAL_SUCCESS | + * | 3 | Perform AES CCM encryption on input vector and check the encryption output. | PAL_SUCCESS | + * | 4 | Perform AES CCM decryption on an input vector and check that the result is as expected.| PAL_SUCCESS | + * | 5 | Release AES CCM context. | PAL_SUCCESS | + */ +TEST(pal_crypto, AES_CCM) +{ + palStatus_t result; + palCCMHandle_t ctx = NULLPTR; + + unsigned char iv[16] = {0}; + unsigned char encryptBuffer[32] = {0}; + unsigned char decryptBuffer[32] = {0}; + + + for (size_t i = 0; i < sizeof(aesCcmVectors) / sizeof(palAesCcmVector_t); ++i) + { + memset(encryptBuffer, 0, sizeof(encryptBuffer)); + memset(decryptBuffer, 0, sizeof(decryptBuffer)); + memset(iv, 0, sizeof(iv)); + memcpy(iv, aesCcmVectors[i].iv, aesCcmVectors[i].ivLen); + + /*#1*/ + result = pal_CCMInit(&ctx); + TEST_ASSERT_NOT_EQUAL(ctx, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#2*/ + result = pal_CCMSetKey(ctx, aesCcmVectors[i].key, 128, PAL_CIPHER_ID_AES); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#3*/ + result = pal_CCMEncrypt(ctx, (unsigned char*)aesCcmVectors[i].in, aesCcmVectors[i].inLen, + iv, aesCcmVectors[i].ivLen, (unsigned char*)aesCcmVectors[i].ad, aesCcmVectors[i].adLen, + encryptBuffer, encryptBuffer + aesCcmVectors[i].inLen, aesCcmVectors[i].tagLen); + + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_MEMORY(aesCcmVectors[i].out, encryptBuffer, aesCcmVectors[i].inLen + aesCcmVectors[i].tagLen); + + /*#4*/ + result = pal_CCMDecrypt(ctx, encryptBuffer, aesCcmVectors[i].inLen, + iv, aesCcmVectors[i].ivLen, (unsigned char*)aesCcmVectors[i].ad, aesCcmVectors[i].adLen, + encryptBuffer + aesCcmVectors[i].inLen, aesCcmVectors[i].tagLen, decryptBuffer); + + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_MEMORY(aesCcmVectors[i].in, decryptBuffer, aesCcmVectors[i].inLen); + + /*#5*/ + result = pal_CCMFree(&ctx); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } +} + + +/** + * @brief Testing SHA256 hash algorithm. + * + * The test hashes a few buffers and compares them with a well known result using SHA256. + * + * Uses sha256Vectors. + * + * For each vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Perform SHA256 hash on the input vector and check the resulting digest Small input Buffers. | PAL_SUCCESS | + * | 2 | Perform SHA256 hash on the input vector and check the resulting digest BIG input buffer. | PAL_SUCCESS | + */ +TEST(pal_crypto, SHA256) +{ + palStatus_t result; + unsigned char output[32]; + + for (size_t i = 0; i < sizeof(sha256Vectors) / sizeof(palSha256Vector_t); ++i) + { + memset(output, 0x0, sizeof(output)); + /*#1*/ + result = pal_sha256(sha256Vectors[i].input, sha256Vectors[i].inLenInBytes, output); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + TEST_ASSERT_EQUAL_MEMORY(sha256Vectors[i].output, output, sizeof(sha256Vectors[i].output)); + } + + memset(output, 0x0, sizeof(output)); + /*#2*/ + result = pal_sha256(sha256Vectors_2nd.input, sha256Vectors_2nd.inLenInBytes, output); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_MEMORY(sha256Vectors_2nd.output, output, sizeof(sha256Vectors_2nd.output)); + +} + + +/** + * @brief Testing message digest using SHA256 hash algorithm. + * + * The test calculates a message digest of the buffers and compares them against the expected results. + * + * Uses sha256Vectors. + * + * For each vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize a message digest context. | PAL_SUCCESS | + * | 2 | Perform `pal_mdUpdate` on vector input data and check the status. | PAL_SUCCESS | + * | 3 | Get the output size using `pal_mdGetOutputSize` and check the result. | PAL_SUCCESS | + * | 4 | Get the digest result using `pal_mdFinal` and check its value. | PAL_SUCCESS | + * | 5 | Release message digest context. | PAL_SUCCESS | + * | 6 | Initialize a message digest context. with Big input buffer | PAL_SUCCESS | + * | 7 | Perform `pal_mdUpdate` on vector input data and check the status. with Big input buffer | PAL_SUCCESS | + * | 8 | Get the output size using `pal_mdGetOutputSize` and check the result. with Big input buffer| PAL_SUCCESS | + * | 9 | Get the digest result using `pal_mdFinal` and check its value. with Big input buffer | PAL_SUCCESS | + * | 10 | Release message digest context. with Big input buffer | PAL_SUCCESS | + */ +TEST(pal_crypto, md) +{ + palStatus_t result; + palMDHandle_t handle = NULLPTR; + size_t bufferSize = 0; + uint8_t output[32] = {0}; + + for (size_t i = 0; i < sizeof(sha256Vectors) / sizeof(palSha256Vector_t); ++i) + { + memset(output, 0x0, sizeof(output)); + /*#1*/ + result = pal_mdInit(&handle, PAL_SHA256); + TEST_ASSERT_NOT_EQUAL(handle, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#2*/ + result = pal_mdUpdate(handle, sha256Vectors[i].input, sha256Vectors[i].inLenInBytes); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#3*/ + result = pal_mdGetOutputSize(handle, &bufferSize); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(sha256Vectors[i].outLenInBytes, bufferSize); + + /*#4*/ + result = pal_mdFinal(handle, output); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_MEMORY(sha256Vectors[i].output, output, sizeof(sha256Vectors[i].output)); + + /*#5*/ + result = pal_mdFree(&handle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + + memset(output, 0x0, sizeof(output)); + /*#6*/ + result = pal_mdInit(&handle, PAL_SHA256); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#7*/ + result = pal_mdUpdate(handle, sha256Vectors_2nd.input, sha256Vectors_2nd.inLenInBytes); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#8*/ + result = pal_mdGetOutputSize(handle, &bufferSize); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(sha256Vectors_2nd.outLenInBytes, bufferSize); + + /*#9*/ + result = pal_mdFinal(handle, output); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_MEMORY(sha256Vectors_2nd.output, output, sizeof(sha256Vectors_2nd.output)); + + /*#10*/ + result = pal_mdFree(&handle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); +} + + +/** + * @brief Testing random number generation using deterministic random bit generators. + * + * The test generates a 128 bit number for 100 times and checks that there are no similar keys. + * + * Uses `ctr_drbg_buf` and `ctr_drbg_nonce_pers`. + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize a CTR DRBG context. | PAL_SUCCESS | + * | 2 | Generate 100 128bit random values using `pal_CtrDRBGGenerate`. | PAL_SUCCESS | + * | 3 | Release message CTR DRBG context. | PAL_SUCCESS | + * | 4 | Check that all generated numbers are different. | PAL_SUCCESS | + */ +TEST(pal_crypto, CTR_DRBG) +{ + palStatus_t result; + palCtrDrbgCtxHandle_t ctx = NULLPTR; + + memset(ctr_drbg_buf, 0x0, sizeof(ctr_drbg_buf)); + + /*#1*/ + result = pal_CtrDRBGInit(&ctx,ctr_drbg_nonce_pers, sizeof(ctr_drbg_nonce_pers)); + TEST_ASSERT_NOT_EQUAL(ctx, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#2*/ + for (int i = 0; i < 100; ++i) { + result = pal_CtrDRBGGenerate(ctx, ctr_drbg_buf[i], sizeof(ctr_drbg_buf[i])); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + + /*#3*/ + result = pal_CtrDRBGFree(&ctx); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#4*/ + for (int i = 0; i < 99; ++i) { + for (int j = i + 1; j < 100; ++j) { + TEST_ASSERT_NOT_EQUAL(0, memcmp(ctr_drbg_buf[i], ctr_drbg_buf[j], sizeof(ctr_drbg_buf[i]))); + } + } +} + + +/** + * @brief Testing CMAC operation on a buffer with one operation. + * + * The test signs a buffer using CMAC and compares with the expected result buffer. + * + * Uses cmacSingleUseVector. + * + * For each vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Perform CMAC using `pal_cipherCMAC` and check the result. | PAL_SUCCESS | + * | 2 | Check the CMAC output against the test vector. | PAL_SUCCESS | + */ +TEST(pal_crypto, CMAC_one_shot) +{ + palStatus_t result; + unsigned char output[16] = {0}; + + for (size_t i = 0; i < sizeof(cmacSingleUseVector) / sizeof(palAesCMACVector_t); ++i){ + memset(output, 0x0, sizeof(output)); + /*#1*/ + result = pal_cipherCMAC(cmacSingleUseVector[i].key, 128, cmacSingleUseVector[i].in, cmacSingleUseVector[i].inLen, output); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#2*/ + TEST_ASSERT_EQUAL_MEMORY(cmacSingleUseVector[i].out, output, sizeof(cmacSingleUseVector[i].out)); + } +} + +/** + * @brief Testing CMAC operation on a buffer with multiple operations and blocks. + * + * The test signs a buffer using CMAC multiple times and compares with the expected result buffer. + * + * Uses cmacIterativeUseVector. + * + * For each vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize CMAC context using `pal_CMACStart`. | PAL_SUCCESS | + * | 2 | Add a block of data from test vector for CMAC processing using `pal_CMACFinish`. | PAL_SUCCESS | + * | 3 | Add a block of data from test vector for CMAC processing using `pal_CMACFinish`. | PAL_SUCCESS | + * | 4 | Add a block of data from test vector for CMAC processing using `pal_CMACFinish`. | PAL_SUCCESS | + * | 5 | Add a block of data from test vector for CMAC processing using `pal_CMACFinish`. | PAL_SUCCESS | + * | 6 | Get CMAC output using `pal_CMACFinish` and check the result. | PAL_SUCCESS | + */ +TEST(pal_crypto, CMAC_Iterative) +{ + palStatus_t result; + palCMACHandle_t ctx = NULLPTR; + unsigned char output[64] = {0}; + size_t resultLen = 0; + + for (size_t i = 0; i < sizeof(cmacIterativeUseVector) / sizeof(palCMACMultipleBlockVector_t); ++i) + { + memset(output, 0x0, sizeof(output)); + /*#1*/ + result = pal_CMACStart(&ctx,cmacIterativeUseVector[i].key_string, cmacIterativeUseVector[i].keybits, cmacIterativeUseVector[i].cipher_type); + TEST_ASSERT_NOT_EQUAL(ctx, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#2*/ + if (cmacIterativeUseVector[i].block1_len >= 0) { + result = pal_CMACUpdate(ctx, cmacIterativeUseVector[i].block1_string, cmacIterativeUseVector[i].block1_len); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + /*#3*/ + if (cmacIterativeUseVector[i].block2_len >= 0) { + result = pal_CMACUpdate(ctx, cmacIterativeUseVector[i].block2_string, cmacIterativeUseVector[i].block2_len); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + /*#4*/ + if (cmacIterativeUseVector[i].block3_len >= 0) { + result = pal_CMACUpdate(ctx, cmacIterativeUseVector[i].block3_string, cmacIterativeUseVector[i].block3_len); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + /*#5*/ + if (cmacIterativeUseVector[i].block4_len >= 0) { + result = pal_CMACUpdate(ctx, cmacIterativeUseVector[i].block4_string, cmacIterativeUseVector[i].block4_len); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + /*#6*/ + result = pal_CMACFinish(&ctx, output, &resultLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(cmacIterativeUseVector[i].block_size, resultLen); + TEST_ASSERT_EQUAL_MEMORY(cmacIterativeUseVector[i].expected_result_string, output, cmacIterativeUseVector[i].block_size); + } // for ends +} + +/** + * @brief Testing HMAC operation on a buffer with one operation. + * + * The test signs a buffer using HMAC and compares with the expected result buffer. + * + * Uses mdHMACVector. + * + * For each vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Perform one shot SHA256 HMAC on input vector using `pal_mdHmacSha256` and check the result. | PAL_SUCCESS | + */ +TEST(pal_crypto, HMAC_SHA256_one_shot) +{ + palStatus_t result; + unsigned char output[32] = {0}; + + for (size_t i = 0; i < sizeof(mdHMACVector) / sizeof(palMdHMACTestVector_t); ++i){ + memset(output, 0x0, sizeof(output)); + /*#1*/ + result = pal_mdHmacSha256(mdHMACVector[i].key, mdHMACVector[i].keyLen, mdHMACVector[i].input, mdHMACVector[i].inputLen, output, NULL); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_MEMORY(mdHMACVector[i].output, output, mdHMACVector[i].outputLen); + } +} + +/** + * @brief Searching for ASN1 patterns in a DER certificate. + * + * The test extracts ASN1 tags from an existing DER format certificate and validates their types. + * + * Uses ASN1TestVector for coordinates and `asn1_data` as the dummy certificate buffer. + * + * For each vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Get data for an ASN tag using `pal_ASN1GetTag`. | PAL_SUCCESS | + * | 2 | Check if the result is success and the size tag size is correct. | PAL_SUCCESS | + */ +TEST(pal_crypto, ASN1) +{ + palStatus_t result; + size_t s = 0; + unsigned char* start = NULL; + const unsigned char* end = NULL; + + for (size_t i = 0; i < sizeof(ASN1TestVector) / sizeof(palASN1TestVector_t); ++i) { + start = (unsigned char*)(asn1_data + ASN1TestVector[i].start); + end = asn1_data + ASN1TestVector[i].end; + /*#1*/ + result = pal_ASN1GetTag(&start, end, &s, ASN1TestVector[i].type); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#2*/ + TEST_ASSERT_EQUAL(ASN1TestVector[i].dataLen, s); + } +} + +/** + * @brief Test the parsing of a dummy X509 certificate. + * + * uses x509_cert + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize the X509 ceritifcate context using `pal_x509Initiate`. | PAL_SUCCESS | + * | 2 | Parse a valid x509 certificate using `pal_x509CertParse`. | PAL_SUCCESS | + * | 3 | Parse an invalid x509 certificate using `pal_x509CertParse`. | PAL_ERR_CERT_PARSING_FAILED | + * | 4 | Parse an invalid x509 certificate using `pal_x509CertParse`. | PAL_ERR_INVALID_MD_TYPE | + * | 5 | Parse an invalid x509 certificate using `pal_x509CertParse`. | PAL_ERR_NOT_SUPPORTED_CURVE | + * | 6 | Release x509 certificate context. | PAL_SUCCESS | + */ +TEST(pal_crypto, X509_Parse) +{ + palStatus_t result; + palX509Handle_t ctx = NULLPTR; + /*#1*/ + result = pal_x509Initiate(&ctx); + TEST_ASSERT_NOT_EQUAL(ctx, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#2*/ + result = pal_x509CertParse(ctx, x509_TI, sizeof(x509_TI)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#3*/ + result = pal_x509CertParse(ctx, x509_TI_PEM, sizeof(x509_TI_PEM)); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_CERT_PARSING_FAILED, result); + /*#4*/ + result = pal_x509CertParse(ctx, (unsigned char*)testdata_x509_Sha512, sizeof(testdata_x509_Sha512)); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_MD_TYPE, result); + /*#5*/ + result = pal_x509CertParse(ctx, (unsigned char*)testdata_x509_Curve512r1, sizeof(testdata_x509_Curve512r1)); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_NOT_SUPPORTED_CURVE, result); + /*#6*/ + result = pal_x509Free(&ctx); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); +} + +/** + * @brief Test the reading of specific attributes in an X509 certificate. + * + * The test parses a X509 certificate and extracts specific attributes and compare them against the expected result. + * + * Uses `x509_cert` and `cert_not_self_signed`. + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize the X509 ceritifcate context using `pal_x509Initiate`. | PAL_SUCCESS | + * | 2 | Parse a valid x509 certificate using `pal_x509CertParse`. | PAL_SUCCESS | + * | 3 | Get the certificate attribute value using `pal_x509CertGetAttribute` and check it. | PAL_SUCCESS | + * | 4 | Get the certificate attribute value using `pal_x509CertGetAttribute` and check it. | PAL_SUCCESS | + * | 5 | Get the certificate attribute value using `pal_x509CertGetAttribute` and check it. | PAL_SUCCESS | + * | 6 | Get the certificate attribute value using `pal_x509CertGetAttribute` and check it. | PAL_SUCCESS | + * | 7 | Get the certificate attribute value using `pal_x509CertGetAttribute` and check it. | PAL_SUCCESS | + * | 8 | Release x509 certificate context using `pal_x509Free`. | PAL_SUCCESS | + * | 9 | Initialize X509 ceritifcate context using `pal_x509Initiate`. | PAL_SUCCESS | + * | 10 | Parse a valid x509 certificate using `pal_x509CertParse`. | PAL_SUCCESS | + * | 11 | Get the certificate attribute value using `pal_x509CertGetAttribute` and check it. | PAL_SUCCESS | + * | 12 | Get the certificate attribute value using `pal_x509CertGetAttribute` and check it. | PAL_SUCCESS | + * | 13 | Get the certificate attribute value using `pal_x509CertGetAttribute `and check it. | PAL_SUCCESS | + * | 14 | Get the certificate attribute value using `pal_x509CertGetAttribute` and check it. | PAL_SUCCESS | + * | 15 | Get the certificate attribute value using `pal_x509CertGetAttribute` and check it. | PAL_SUCCESS | + * | 16 | Get the certificate attribute value with a too small buffer. | PAL_ERR_BUFFER_TOO_SMALL | + * | 17 | Release x509 certificate context using `pal_x509Free`. | PAL_SUCCESS | + + */ +TEST(pal_crypto, X509_ReadAttributes) +{ + palStatus_t result; + palX509Handle_t ctx = NULLPTR; + char buffer1[512] = {0}; + char validationBuf[12] = {0}; + time_t validFrom = 0; + time_t validTo = 0; + time_t tmpTime; + size_t actualOutLen = 0; + + /*#1*/ + result = pal_x509Initiate(&ctx); + TEST_ASSERT_NOT_EQUAL(ctx, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#2*/ + result = pal_x509CertParse(ctx, x509_TI, sizeof(x509_TI)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#3*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_ISSUER_ATTR, buffer1, sizeof(buffer1), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + memset(buffer1, 0, sizeof(buffer1)); + /*#4*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_SUBJECT_ATTR, buffer1, sizeof(buffer1), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + memset(buffer1, 0, sizeof(buffer1)); + /*#5*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_VALID_FROM, validationBuf, sizeof(validationBuf), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + memcpy(&tmpTime, validationBuf, sizeof(tmpTime)); + memset(validationBuf, 0, sizeof(validationBuf)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#6*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_CN_ATTR, buffer1, sizeof(buffer1), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_STRING("IOT_PAL", buffer1); + memset(buffer1, 0, sizeof(buffer1)); + /*#7*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_OU_ATTR, buffer1, sizeof(buffer1), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_STRING("IOTBU", buffer1); + memset(buffer1, 0, sizeof(buffer1)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#8*/ + result = pal_x509Free(&ctx); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#9*/ + result = pal_x509Initiate(&ctx); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#10*/ + result = pal_x509CertParse(ctx, cert_not_self_signed, sizeof(cert_not_self_signed)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#11*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_ISSUER_ATTR, buffer1, sizeof(buffer1), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + memset(buffer1, 0, sizeof(buffer1)); + /*#12*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_SUBJECT_ATTR, buffer1, sizeof(buffer1), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + memset(buffer1, 0, sizeof(buffer1)); + /*#13*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_CN_ATTR, buffer1, sizeof(buffer1), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_STRING("IOT_TEST", buffer1); + memset(buffer1, 0, sizeof(buffer1)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#14*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_VALID_FROM, validationBuf, sizeof(validationBuf), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + memcpy(&validFrom, validationBuf, sizeof(tmpTime)); + memset(validationBuf, 0, sizeof(validationBuf)); + /*#15*/ + result = pal_x509CertGetAttribute(ctx, PAL_X509_VALID_TO, validationBuf, sizeof(validationBuf), &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + memcpy(&validTo, validationBuf, sizeof(tmpTime)); + memset(validationBuf, 0, sizeof(validationBuf)); + + //Check exact time period + TEST_ASSERT_EQUAL_HEX(0x05a39a7f, validTo - validFrom); + /*#16*/ + //! sending small buffer size to check error value scenario + result = pal_x509CertGetAttribute(ctx, PAL_X509_VALID_TO, validationBuf, 1, &actualOutLen); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_BUFFER_TOO_SMALL, result); + TEST_ASSERT_EQUAL(sizeof(uint64_t), actualOutLen); + /*#17*/ + result = pal_x509Free(&ctx); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); +} + +/** + * @brief Test the validity of a X509 certificate. + * + * Reads a X509 certificate, specific attributes such as `PAL_X509_VALID_FROM` and `PAL_X509_VALID_TO` + * and validates with `pal_x509CertVerify`. + * + * Uses `x509_verify_data`. + * + For each test vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | If the CA cert is part of vector, initialize X509 certificate context using `pal_x509Initiate`. | PAL_SUCCESS | + * | 2 | If the CA cert is part of vector, parse a valid x509 certificate using `pal_x509CertParse`. | PAL_SUCCESS | + * | 3 | Initialize X509 certificate context using `pal_x509Initiate`. | PAL_SUCCESS | + * | 4 | Parse a valid x509 certificate using `pal_x509CertParse`. | PAL_SUCCESS | + * | 5 | Verify the certificate using `pal_x509CertVerify`. | PAL_SUCCESS | + * | 6 | Release X509 certificate context. | PAL_SUCCESS | + * | 7 | If the CA cert is part of vector, release X509 certificate context. | PAL_SUCCESS | + */ +TEST(pal_crypto, X509_Verify) +{ + palStatus_t result = PAL_SUCCESS; + palX509Handle_t cert = NULLPTR; + palX509Handle_t caCert = NULLPTR; + + for (size_t i = 0; i < sizeof(x509_verify_data) / sizeof(palX509VertifyTestVector_t); ++i) + { + if (x509_verify_data[i].ca != NULL) + { + /*#1*/ + result = pal_x509Initiate(&caCert); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_NOT_EQUAL(caCert, NULLPTR); + /*#2*/ + result = pal_x509CertParse(caCert, x509_verify_data[i].ca, x509_verify_data[i].ca_size); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + + /*#3*/ + result = pal_x509Initiate(&cert); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#4*/ + result = pal_x509CertParse(cert, x509_verify_data[i].crt, x509_verify_data[i].crt_size); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#5*/ + result = pal_x509CertVerify(cert, caCert); + TEST_ASSERT_EQUAL_HEX(x509_verify_data[i].result, result); + /*#6*/ + result = pal_x509Free(&cert); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + if (x509_verify_data[i].ca != NULL) + { + /*#7*/ + result = pal_x509Free(&caCert); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + } +} + +/** + * @brief Test the parsing of elliptic-curves keys (public and private). + * + * Uses `parse_ec_key_data`. + * + * For each test vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize a new ECC key using `pal_ECKeyNew`. | PAL_SUCCESS | + * | 2 | If private key, parse using `pal_parseECPrivateKeyFromDER`, otherwise parse using `pal_parseECPublicKeyFromDER`. | PAL_SUCCESS | + * | 3 | Check the parsing status according to the test vector. | PAL_SUCCESS | + * | 4 | Release the ECC key using `pal_ECKeyFree`. | PAL_SUCCESS | + */ +TEST(pal_crypto, ECKey_parseKey) +{ + palStatus_t result; + palECKeyHandle_t handle = NULLPTR; + + for (uint32_t i = 0; i < sizeof(parse_ec_key_data) / sizeof(palParseECKeyTestVector_t) ; ++i) { + /*#1*/ + result = pal_ECKeyNew(&handle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#2*/ + switch (parse_ec_key_data[i].type) { + case PAL_CHECK_PRIVATE_KEY: + result = pal_parseECPrivateKeyFromDER(parse_ec_key_data[i].key, parse_ec_key_data[i].len, handle); + break; + case PAL_CHECK_PUBLIC_KEY: + result = pal_parseECPublicKeyFromDER(parse_ec_key_data[i].key, parse_ec_key_data[i].len, handle); + break; + default: + TEST_FAIL(); + } + /*#3*/ + if (parse_ec_key_data[i].shouldSucceed) + { + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + else + { + TEST_ASSERT_NOT_EQUAL(PAL_SUCCESS, result); + } + /*#4*/ + result = pal_ECKeyFree(&handle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } +} + +/** + * @brief Test the validity of elliptic-curves keys (public and private). + * + * Uses `check_ec_key_data`. + * + * For each test vector: + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize and load EC curve using `pal_ECGroupInitAndLoad`. | PAL_SUCCESS | + * | 2 | Initialize a new ECC key using `pal_ECKeyNew`. | PAL_SUCCESS | + * | 3 | If private key, parse using `pal_parseECPrivateKeyFromDER` and check the parsing status according to the test vector.| PAL_SUCCESS | + * | 4 | If successfully parsed, check the key using `pal_ECCheckKey`. | PAL_SUCCESS | + * | 5 | Release the ECC key using `pal_ECKeyFree`. | PAL_SUCCESS | + * | 6 | Initialize a new ECC key using `pal_ECKeyNew`. | PAL_SUCCESS | + * | 7 | If public key, parse using `pal_parseECPublicKeyFromDER` and check the parsing status according to test the vector. | PAL_SUCCESS | + * | 8 | If successfully parsed, check the key using `pal_ECCheckKey`. | PAL_SUCCESS | + * | 9 | Release the ECC key using `pal_ECKeyFree`. | PAL_SUCCESS | + * | 10 | Release the EC curve using `pal_ECGroupFree`. | PAL_SUCCESS | + */ +TEST(pal_crypto, ECKey_checkKey) +{ + palStatus_t result; + palCurveHandle_t grp = NULLPTR; + bool verified = false; + palECKeyHandle_t key = NULLPTR; + + for (uint32_t i = 0; i < sizeof(check_ec_key_data) / sizeof(palCheckEcKeyTestVector_t); ++i) + { + /*#1*/ + result = pal_ECGroupInitAndLoad(&grp, check_ec_key_data[i].index); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#2*/ + result = pal_ECKeyNew(&key); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#3*/ + result = pal_parseECPrivateKeyFromDER(check_ec_key_data[i].key, check_ec_key_data[i].keyLen, key); + TEST_ASSERT_EQUAL_HEX(check_ec_key_data[i].parsePrvRes, result); + if (PAL_SUCCESS == result) + { + /*#4*/ + result = pal_ECCheckKey(grp, key, PAL_CHECK_PRIVATE_KEY, &verified); + TEST_ASSERT_EQUAL(check_ec_key_data[i].checkPrvRes, result); + TEST_ASSERT_EQUAL(check_ec_key_data[i].verifed, verified); + } + + /*#5*/ + result = pal_ECKeyFree(&key); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#6*/ + result = pal_ECKeyNew(&key); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#7*/ + result = pal_parseECPublicKeyFromDER(check_ec_key_data[i].key, check_ec_key_data[i].keyLen, key); + TEST_ASSERT_EQUAL_HEX(check_ec_key_data[i].parsePubRes, result); + if (PAL_SUCCESS == result) + { + /*#8*/ + result = pal_ECCheckKey(grp, key, PAL_CHECK_PUBLIC_KEY, &verified); + TEST_ASSERT_EQUAL(check_ec_key_data[i].checkPubRes, result); + TEST_ASSERT_EQUAL(check_ec_key_data[i].verifed, verified); + } + /*#9*/ + result = pal_ECKeyFree(&key); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#10*/ + result = pal_ECGroupFree(&grp); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } +} + +/** + * @brief Create a CSR from an elliptic-curve key and assure its validity. + * + * Uses CsrTests. + * + * For each test vector (steps 1A-1O are run for each tect vector): + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Initialize and load the EC curve using `pal_ECGroupInitAndLoad`. | PAL_SUCCESS | + * | 1A | Initialize a new ECC key using `pal_ECKeyNew`. | PAL_SUCCESS | + * | 1B | Parse using `pal_parseECPrivateKeyFromDER` and check the parsing status according to the test vector. | PAL_SUCCESS | + * | 1C | Check the key using `pal_ECCheckKey`. | PAL_SUCCESS | + * | 1D | Initialize a new ECC key using `pal_ECKeyNew`. | PAL_SUCCESS | + * | 1E | Parse using `pal_parseECPublicKeyFromDER` and check the parsing status according to the test vector. | PAL_SUCCESS | + * | 1F | Check the key using `pal_ECCheckKey`. | PAL_SUCCESS | + * | 1G | Initialize the x509 certificate context using `pal_x509CSRInit`. | PAL_SUCCESS | + * | 1H | Set the cert subject using `pal_x509CSRSetSubject`. | PAL_SUCCESS | + * | 1I | Set the cert MD using `pal_x509CSRSetMD`. | PAL_SUCCESS | + * | 1J | Set the cert keys using `pal_x509CSRSetKey`. | PAL_SUCCESS | + * | 1K | Set the cert key usage using `pal_x509CSRSetKey`. | PAL_SUCCESS | + * | 1L | Write the certificate to DER file using `pal_x509CSRWriteDER`. | PAL_SUCCESS | + * | 1M | Release the x509 ceritifcate context using `pal_x509CSRFree`. | PAL_SUCCESS | + * | 1N | Release the ECC key using `pal_ECKeyFree`. | PAL_SUCCESS | + * | 1O | Release the ECC key using `pal_ECKeyFree`. | PAL_SUCCESS | + * | 2 | Release the EC curve using `pal_ECGroupFree`. | PAL_SUCCESS | + */ +TEST(pal_crypto, CSR) +{ + palStatus_t result; + palECKeyHandle_t prvKeyHandle = NULLPTR, pubKeyHandle = NULLPTR; + unsigned char outDer[1000] = {0}; + size_t reqLen; + palx509CSRHandle_t CSRHandle = NULLPTR; + + bool goodKey = false; + palCurveHandle_t grp = NULLPTR; + palGroupIndex_t index = PAL_ECP_DP_SECP256R1; + /*#1*/ + result = pal_ECGroupInitAndLoad(&grp, index); + TEST_ASSERT_NOT_EQUAL(grp, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + for (uint32_t i = 0; i < sizeof(CsrTests) / sizeof(palX509CSRTestVector_t); ++i) + { + memset(outDer,0, sizeof(outDer)); + + goodKey = false; + /*#1A*/ + result = pal_ECKeyNew(&prvKeyHandle); + TEST_ASSERT_NOT_EQUAL(prvKeyHandle, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1B*/ + result = pal_parseECPrivateKeyFromDER(CsrTests[i].prvkey, CsrTests[i].prvkeyLen, prvKeyHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1C*/ + result = pal_ECCheckKey(grp, prvKeyHandle, PAL_CHECK_PRIVATE_KEY, &goodKey); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL(true, goodKey); + + goodKey = false; + /*#1D*/ + result = pal_ECKeyNew(&pubKeyHandle); + TEST_ASSERT_NOT_EQUAL(pubKeyHandle, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1E*/ + result = pal_parseECPublicKeyFromDER(CsrTests[i].pubkey, CsrTests[i].pubkeyLen, pubKeyHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1F*/ + result = pal_ECCheckKey(grp, pubKeyHandle, PAL_CHECK_PUBLIC_KEY, &goodKey); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL(true, goodKey); + /*#1G*/ + result = pal_x509CSRInit(&CSRHandle); + TEST_ASSERT_NOT_EQUAL(CSRHandle, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1H*/ + result = pal_x509CSRSetSubject(CSRHandle, CsrTests[i].subject_name); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1I*/ + result = pal_x509CSRSetMD(CSRHandle, CsrTests[i].mdType); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1J*/ + result = pal_x509CSRSetKey(CSRHandle, pubKeyHandle, prvKeyHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1K*/ + result = pal_x509CSRSetKeyUsage(CSRHandle, CsrTests[i].keyUsage); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1L*/ + //pal_x509CSRSetExtension - need input from provisioning + reqLen = 0; + result = pal_x509CSRWriteDER(CSRHandle, outDer, sizeof(outDer), &reqLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + TEST_ASSERT_EQUAL(CsrTests[i].derOutLen, reqLen); + TEST_ASSERT_EQUAL_MEMORY(CsrTests[i].derOut, outDer, reqLen); + /*#1M*/ + result = pal_x509CSRFree(&CSRHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1N*/ + result = pal_ECKeyFree(&prvKeyHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#1O*/ + result = pal_ECKeyFree(&pubKeyHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + /*#2*/ + result = pal_ECGroupFree(&grp); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Crypto/pal_crypto_test_data.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Crypto/pal_crypto_test_data.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1251 @@ +typedef struct palAesTestVector{ + unsigned char key[16]; + unsigned char nonce[16]; + unsigned char input[16]; + unsigned char output[16]; +} palAesTestVector_t; + +const palAesTestVector_t CtrVector = +{ + { + 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E + }, + { + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }, + { + 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 + }, + { + 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79, + 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 + } +}; + +const palAesTestVector_t EcbVector = +{ + { + 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E + }, + { + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }, + { + 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 + }, + { + 0x61, 0x5f, 0x09, 0xfb, 0x35, 0x3f, 0x61, 0x3b, + 0xa2, 0x8f, 0xf3, 0xa3, 0x0c, 0x64, 0x75, 0x2d + } +}; + + + +typedef struct palSha256Vector_2nd{ + size_t inLenInBytes; + size_t outLenInBytes; + unsigned char output[32]; + unsigned char input[1000]; +} palSha256Vector_2nd_t; + +palSha256Vector_2nd_t sha256Vectors_2nd ={ + 955, + 32, + { + 0x41, 0x09, 0xcd, 0xbe, 0xc3, 0x24, 0x0a, 0xd7, 0x4c, 0xc6,0xc3, 0x7f, 0x39, 0x30, 0x0f, 0x70, + 0xfe, 0xde, 0x16, 0xe2, 0x1e, 0xfc, 0x77, 0xf7, 0x86, 0x59,0x98, 0x71, 0x4a, 0xad, 0x0b, 0x5e + }, + { + 0x83, 0x90, 0xcf, 0x0b, 0xe0, 0x76, 0x61, 0xcc, 0x76, 0x69, 0xaa, 0xc5, 0x4c, 0xe0, 0x9a, 0x37, + 0x73, 0x3a, 0x62, 0x9d, 0x45, 0xf5, 0xd9, 0x83, 0xef, 0x20, 0x1f, 0x9b, 0x2d, 0x13, 0x80, 0x0e, + 0x55, 0x5d, 0x9b, 0x10, 0x97, 0xfe, 0xc3, 0xb7, 0x83, 0xd7, 0xa5, 0x0d, 0xcb, 0x5e, 0x2b, 0x64, + 0x4b, 0x96, 0xa1, 0xe9, 0x46, 0x3f, 0x17, 0x7c, 0xf3, 0x49, 0x06, 0xbf, 0x38, 0x8f, 0x36, 0x6d, + 0xb5, 0xc2, 0xde, 0xee, 0x04, 0xa3, 0x0e, 0x28, 0x3f, 0x76, 0x4a, 0x97, 0xc3, 0xb3, 0x77, 0xa0, + 0x34, 0xfe, 0xfc, 0x22, 0xc2, 0x59, 0x21, 0x4f, 0xaa, 0x99, 0xba, 0xba, 0xff, 0x16, 0x0a, 0xb0, + 0xaa, 0xa7, 0xe2, 0xcc, 0xb0, 0xce, 0x09, 0xc6, 0xb3, 0x2f, 0xe0, 0x8c, 0xbc, 0x47, 0x46, 0x94, + 0x37, 0x5a, 0xba, 0x70, 0x3f, 0xad, 0xbf, 0xa3, 0x1c, 0xf6, 0x85, 0xb3, 0x0a, 0x11, 0xc5, 0x7f, + 0x3c, 0xf4, 0xed, 0xd3, 0x21, 0xe5, 0x7d, 0x3a, 0xe6, 0xeb, 0xb1, 0x13, 0x3c, 0x82, 0x60, 0xe7, + 0x5b, 0x92, 0x24, 0xfa, 0x47, 0xa2, 0xbb, 0x20, 0x52, 0x49, 0xad, 0xd2, 0xe2, 0xe6, 0x2f, 0x81, + 0x74, 0x91, 0x48, 0x2a, 0xe1, 0x52, 0x32, 0x2b, 0xe0, 0x90, 0x03, 0x55, 0xcd, 0xcc, 0x8d, 0x42, + 0xa9, 0x8f, 0x82, 0xe9, 0x61, 0xa0, 0xdc, 0x6f, 0x53, 0x7b, 0x7b, 0x41, 0x0e, 0xff, 0x10, 0x5f, + 0x59, 0x67, 0x3b, 0xfb, 0x78, 0x7b, 0xf0, 0x42, 0xaa, 0x07, 0x1f, 0x7a, 0xf6, 0x8d, 0x94, 0x4d, + 0x27, 0x37, 0x1c, 0x64, 0x16, 0x0f, 0xe9, 0x38, 0x27, 0x72, 0x37, 0x25, 0x16, 0xc2, 0x30, 0xc1, + 0xf4, 0x5c, 0x0d, 0x6b, 0x6c, 0xca, 0x7f, 0x27, 0x4b, 0x39, 0x4d, 0xa9, 0x40, 0x2d, 0x3e, 0xaf, + 0xdf, 0x73, 0x39, 0x94, 0xec, 0x58, 0xab, 0x22, 0xd7, 0x18, 0x29, 0xa9, 0x83, 0x99, 0x57, 0x4d, + 0x4b, 0x59, 0x08, 0xa4, 0x47, 0xa5, 0xa6, 0x81, 0xcb, 0x0d, 0xd5, 0x0a, 0x31, 0x14, 0x53, 0x11, + 0xd9, 0x2c, 0x22, 0xa1, 0x6d, 0xe1, 0xea, 0xd6, 0x6a, 0x54, 0x99, 0xf2, 0xdc, 0xeb, 0x4c, 0xae, + 0x69, 0x47, 0x72, 0xce, 0x90, 0x76, 0x2e, 0xf8, 0x33, 0x6a, 0xfe, 0xc6, 0x53, 0xaa, 0x9b, 0x1a, + 0x1c, 0x48, 0x20, 0xb2, 0x21, 0x13, 0x6d, 0xfc, 0xe8, 0x0d, 0xce, 0x2b, 0xa9, 0x20, 0xd8, 0x8a, + 0x53, 0x0c, 0x94, 0x10, 0xd0, 0xa4, 0xe0, 0x35, 0x8a, 0x3a, 0x11, 0x05, 0x2e, 0x58, 0xdd, 0x73, + 0xb0, 0xb1, 0x79, 0xef, 0x8f, 0x56, 0xfe, 0x3b, 0x5a, 0x2d, 0x11, 0x7a, 0x73, 0xa0, 0xc3, 0x8a, + 0x13, 0x92, 0xb6, 0x93, 0x8e, 0x97, 0x82, 0xe0, 0xd8, 0x64, 0x56, 0xee, 0x48, 0x84, 0xe3, 0xc3, + 0x9d, 0x4d, 0x75, 0x81, 0x3f, 0x13, 0x63, 0x3b, 0xc7, 0x9b, 0xaa, 0x07, 0xc0, 0xd2, 0xd5, 0x55, + 0xaf, 0xbf, 0x20, 0x7f, 0x52, 0xb7, 0xdc, 0xa1, 0x26, 0xd0, 0x15, 0xaa, 0x2b, 0x98, 0x73, 0xb3, + 0xeb, 0x06, 0x5e, 0x90, 0xb9, 0xb0, 0x65, 0xa5, 0x37, 0x3f, 0xe1, 0xfb, 0x1b, 0x20, 0xd5, 0x94, + 0x32, 0x7d, 0x19, 0xfb, 0xa5, 0x6c, 0xb8, 0x1e, 0x7b, 0x66, 0x96, 0x60, 0x5f, 0xfa, 0x56, 0xeb, + 0xa3, 0xc2, 0x7a, 0x43, 0x86, 0x97, 0xcc, 0x21, 0xb2, 0x01, 0xfd, 0x7e, 0x09, 0xf1, 0x8d, 0xee, + 0xa1, 0xb3, 0xea, 0x2f, 0x0d, 0x1e, 0xdc, 0x02, 0xdf, 0x0e, 0x20, 0x39, 0x6a, 0x14, 0x54, 0x12, + 0xcd, 0x6b, 0x13, 0xc3, 0x2d, 0x2e, 0x60, 0x56, 0x41, 0xc9, 0x48, 0xb7, 0x14, 0xae, 0xc3, 0x0c, + 0x06, 0x49, 0xdc, 0x44, 0x14, 0x35, 0x11, 0xf3, 0x5a, 0xb0, 0xfd, 0x5d, 0xd6, 0x4c, 0x34, 0xd0, + 0x6f, 0xe8, 0x6f, 0x38, 0x36, 0xdf, 0xe9, 0xed, 0xeb, 0x7f, 0x08, 0xcf, 0xc3, 0xbd, 0x40, 0x95, + 0x68, 0x26, 0x35, 0x62, 0x42, 0x19, 0x1f, 0x99, 0xf5, 0x34, 0x73, 0xf3, 0x2b, 0x0c, 0xc0, 0xcf, + 0x93, 0x21, 0xd6, 0xc9, 0x2a, 0x11, 0x2e, 0x8d, 0xb9, 0x0b, 0x86, 0xee, 0x9e, 0x87, 0xcc, 0x32, + 0xd0, 0x34, 0x3d, 0xb0, 0x1e, 0x32, 0xce, 0x9e, 0xb7, 0x82, 0xcb, 0x24, 0xef, 0xbb, 0xbe, 0xb4, + 0x40, 0xfe, 0x92, 0x9e, 0x8f, 0x2b, 0xf8, 0xdf, 0xb1, 0x55, 0x0a, 0x3a, 0x2e, 0x74, 0x2e, 0x8b, + 0x45, 0x5a, 0x3e, 0x57, 0x30, 0xe9, 0xe6, 0xa7, 0xa9, 0x82, 0x4d, 0x17, 0xac, 0xc0, 0xf7, 0x2a, + 0x7f, 0x67, 0xea, 0xe0, 0xf0, 0x97, 0x0f, 0x8b, 0xde, 0x46, 0xdc, 0xde, 0xfa, 0xed, 0x30, 0x47, + 0xcf, 0x80, 0x7e, 0x7f, 0x00, 0xa4, 0x2e, 0x5f, 0xd1, 0x1d, 0x40, 0xf5, 0xe9, 0x85, 0x33, 0xd7, + 0x57, 0x44, 0x25, 0xb7, 0xd2, 0xbc, 0x3b, 0x38, 0x45, 0xc4, 0x43, 0x00, 0x8b, 0x58, 0x98, 0x0e, + 0x76, 0x8e, 0x46, 0x4e, 0x17, 0xcc, 0x6f, 0x6b, 0x39, 0x39, 0xee, 0xe5, 0x2f, 0x71, 0x39, 0x63, + 0xd0, 0x7d, 0x8c, 0x4a, 0xbf, 0x02, 0x44, 0x8e, 0xf0, 0xb8, 0x89, 0xc9, 0x67, 0x1e, 0x2f, 0x8a, + 0x43, 0x6d, 0xde, 0xef, 0xfc, 0xca, 0x71, 0x76, 0xe9, 0xbf, 0x9d, 0x10, 0x05, 0xec, 0xd3, 0x77, + 0xf2, 0xfa, 0x67, 0xc2, 0x3e, 0xd1, 0xf1, 0x37, 0xe6, 0x0b, 0xf4, 0x60, 0x18, 0xa8, 0xbd, 0x61, + 0x3d, 0x03, 0x8e, 0x88, 0x37, 0x04, 0xfc, 0x26, 0xe7, 0x98, 0x96, 0x9d, 0xf3, 0x5e, 0xc7, 0xbb, + 0xc6, 0xa4, 0xfe, 0x46, 0xd8, 0x91, 0x0b, 0xd8, 0x2f, 0xa3, 0xcd, 0xed, 0x26, 0x5d, 0x0a, 0x3b, + 0x6d, 0x39, 0x9e, 0x42, 0x51, 0xe4, 0xd8, 0x23, 0x3d, 0xaa, 0x21, 0xb5, 0x81, 0x2f, 0xde, 0xd6, + 0x53, 0x61, 0x98, 0xff, 0x13, 0xaa, 0x5a, 0x1c, 0xd4, 0x6a, 0x5b, 0x9a, 0x17, 0xa4, 0xdd, 0xc1, + 0xd9, 0xf8, 0x55, 0x44, 0xd1, 0xd1, 0xcc, 0x16, 0xf3, 0xdf, 0x85, 0x80, 0x38, 0xc8, 0xe0, 0x71, + 0xa1, 0x1a, 0x7e, 0x15, 0x7a, 0x85, 0xa6, 0xa8, 0xdc, 0x47, 0xe8, 0x8d, 0x75, 0xe7, 0x00, 0x9a, + 0x8b, 0x26, 0xfd, 0xb7, 0x3f, 0x33, 0xa2, 0xa7, 0x0f, 0x1e, 0x0c, 0x25, 0x9f, 0x8f, 0x95, 0x33, + 0xb9, 0xb8, 0xf9, 0xaf, 0x92, 0x88, 0xb7, 0x27, 0x4f, 0x21, 0xba, 0xee, 0xc7, 0x8d, 0x39, 0x6f, + 0x8b, 0xac, 0xdc, 0xc2, 0x24, 0x71, 0x20, 0x7d, 0x9b, 0x4e, 0xfc, 0xcd, 0x3f, 0xed, 0xc5, 0xc5, + 0xa2, 0x21, 0x4f, 0xf5, 0xe5, 0x1c, 0x55, 0x3f, 0x35, 0xe2, 0x1a, 0xe6, 0x96, 0xfe, 0x51, 0xe8, + 0xdf, 0x73, 0x3a, 0x8e, 0x06, 0xf5, 0x0f, 0x41, 0x9e, 0x59, 0x9e, 0x9f, 0x9e, 0x4b, 0x37, 0xce, + 0x64, 0x3f, 0xc8, 0x10, 0xfa, 0xaa, 0x47, 0x98, 0x97, 0x71, 0x50, 0x9d, 0x69, 0xa1, 0x10, 0xac, + 0x91, 0x62, 0x61, 0x42, 0x70, 0x26, 0x36, 0x9a, 0x21, 0x26, 0x3a, 0xc4, 0x46, 0x0f, 0xb4, 0xf7, + 0x08, 0xf8, 0xae, 0x28, 0x59, 0x98, 0x56, 0xdb, 0x7c, 0xb6, 0xa4, 0x3a, 0xc8, 0xe0, 0x3d, 0x64, + 0xa9, 0x60, 0x98, 0x07, 0xe7, 0x6c, 0x5f, 0x31, 0x2b, 0x9d, 0x18, 0x63, 0xbf, 0xa3, 0x04, 0xe8, + 0x95, 0x36, 0x47, 0x64, 0x8b, 0x4f, 0x4a, 0xb0, 0xed, 0x99, 0x5e + } +}; + +typedef struct palSha256Vector{ + size_t inLenInBytes; + size_t outLenInBytes; + unsigned char output[32]; + unsigned char input[5]; +} palSha256Vector_t; + +palSha256Vector_t sha256Vectors[6] = +{ + { + 0, + 32, + { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 + }, + {0x00} + }, + { + 1, + 32, + { + 0x68, 0x32, 0x57, 0x20, 0xaa, 0xbd, 0x7c, 0x82, 0xf3, 0x0f, 0x55, 0x4b, 0x31, 0x3d, 0x05, 0x70, + 0xc9, 0x5a, 0xcc, 0xbb, 0x7d, 0xc4, 0xb5, 0xaa, 0xe1, 0x12, 0x04, 0xc0, 0x8f, 0xfe, 0x73, 0x2b + }, + {0xbd} + }, + { + 2, + 32, + { + 0x7c, 0x4f, 0xbf, 0x48, 0x44, 0x98, 0xd2, 0x1b, 0x48, 0x7b, 0x9d, 0x61, 0xde, 0x89,0x14, 0xb2, + 0xea, 0xda, 0xf2, 0x69, 0x87, 0x12, 0x93, 0x6d, 0x47, 0xc3, 0xad, 0xa2, 0x55, 0x8f,0x67, 0x88 + }, + {0x5f, 0xd4} + }, + { + 3, + 32, + { + 0x40, 0x96, 0x80, 0x42, 0x21, 0x09, 0x3d, 0xdc, 0xcf, 0xbf, 0x46, 0x83, 0x14, 0x90, 0xea, 0x63, + 0xe9, 0xe9, 0x94, 0x14, 0x85, 0x8f, 0x8d, 0x75, 0xff, 0x7f, 0x64, 0x2c, 0x7c, 0xa6, 0x18, 0x03 + }, + {0xb0, 0xbd, 0x69} + }, + { + 4, + 32, + { + 0x7a, 0xbc, 0x22, 0xc0, 0xae, 0x5a, 0xf2, 0x6c, 0xe9, 0x3d, 0xbb, 0x94, 0x43, 0x3a, 0x0e, 0x0b, + 0x2e, 0x11, 0x9d, 0x01, 0x4f, 0x8e, 0x7f, 0x65, 0xbd, 0x56, 0xc6, 0x1c,0xcc, 0xcd, 0x95, 0x04 + }, + {0xc9, 0x8c, 0x8e, 0x55 } + }, + { + 5, + 32, + { + 0x75, 0x16, 0xfb, 0x8b, 0xb1, 0x13, 0x50, 0xdf, 0x2b, 0xf3, 0x86, 0xbc, 0x3c, 0x33, 0xbd, 0x0f, + 0x52, 0xcb, 0x4c, 0x67, 0xc6, 0xe4, 0x74, 0x5e, 0x04, 0x88, 0xe6, 0x2c, 0x2a, 0xea, 0x26, 0x05 + }, + {0x81, 0xa7, 0x23, 0xd9, 0x66} + } +}; + +typedef struct palAesCcmVector{ + const unsigned char key[16]; + const unsigned char iv[16]; + const unsigned char ad[20]; + const unsigned char in[24]; + const unsigned char out[32]; + size_t ivLen; + size_t adLen; + size_t inLen; + size_t tagLen; + // size_t outLen; + +}palAesCcmVector_t; + +static const palAesCcmVector_t aesCcmVectors[3] = +{ + { + { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }, + { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, + { 0x20, 0x21, 0x22, 0x23 }, + { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, + 7, 8, 4, 4 + }, + { + { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }, + { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }, + { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f + }, + { + 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, + 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, + 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd + }, + 8, 16, 16, 6 + }, + { + { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f + }, + { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b + }, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 + }, + { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + }, + { + 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, + 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, + 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, + 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 + }, + 12, 20, 24, 8 + } +}; + +static const unsigned char ctr_drbg_nonce_pers[16] = +{ + 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5, + 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f +}; + +unsigned char ctr_drbg_buf[100][16]; + +typedef struct palAesCMACVector{ + const unsigned char key[16]; + const unsigned char in[64]; + const unsigned char out[16]; + size_t inLen; +}palAesCMACVector_t; + +static const palAesCMACVector_t cmacSingleUseVector[4] = +{ + { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x00 + }, + { + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + }, + 0 + }, + { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }, + { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, + 16 + }, + { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57 + }, + { + 0x7d, 0x85, 0x44, 0x9e, 0xa6, 0xea, 0x19, 0xc8, + 0x23, 0xa7, 0xbf, 0x78, 0x83, 0x7d, 0xfa, 0xde + }, + 20 + }, + { + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }, + { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + }, + 64 + } +}; + +typedef struct palCMACMultipleBlockVector{ + palCipherID_t cipher_type; + unsigned char key_string[64]; + unsigned char block1_string[64]; + unsigned char block2_string[64]; + unsigned char block3_string[64]; + unsigned char block4_string[64]; + unsigned char expected_result_string[64]; + uint32_t keybits; + uint32_t block_size; + int32_t block1_len; + int32_t block2_len; + int32_t block3_len; + int32_t block4_len; +}palCMACMultipleBlockVector_t; + +static const palCMACMultipleBlockVector_t cmacIterativeUseVector[] = +{ + { + PAL_CIPHER_ID_AES, + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { 0x00 }, + { 0x00 }, + { 0x00 }, + { 0x00 }, + { + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + }, 128, 16, -1, -1, -1, -1 + }, + { + PAL_CIPHER_ID_AES, + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }, + { 0x00 }, + { 0x00 }, + { 0x00 }, + { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, 128, 16, 16, -1, -1, -1 + }, + { + PAL_CIPHER_ID_AES, + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }, + { 0x00 }, + { 0x00 }, + { 0x00 }, + { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + }, 128, 16, 64, -1, -1, -1 + }, + { + PAL_CIPHER_ID_AES, + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96 + }, + { + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }, + { 0x00 }, + { 0x00 }, + { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, 128, 16, 8, 8, -1, -1 + }, + { + PAL_CIPHER_ID_AES, + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }, + { + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 + }, + { + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef + }, + { + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }, + { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + }, 128, 16, 16, 16, 16, 16 + }, + { + PAL_CIPHER_ID_AES, + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96 + }, + { + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c + }, + { + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef + }, + { + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 + }, + { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + },128, 16, 8, 16, 24, 16 + }, + { + PAL_CIPHER_ID_AES, + { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + }, + { 0x00 }, + { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96 + }, + { 0x00 }, + { + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a + }, + { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, 128, 16, 0, 8, 0, 8 + } +}; + +typedef struct palASN1TestVector{ + size_t start; + size_t end; + size_t dataLen; + uint8_t type; +}palASN1TestVector_t; + +static const palASN1TestVector_t ASN1TestVector[11] = { + { 0, 879, 875, PAL_ASN1_SEQUENCE | PAL_ASN1_CONSTRUCTED }, + { 10, 13, 1, PAL_ASN1_INTEGER }, + { 26, 37, 9, PAL_ASN1_OID }, + { 37, 39, 0, PAL_ASN1_NULL }, + { 41, 54, 11, PAL_ASN1_SET | PAL_ASN1_CONSTRUCTED }, + { 50, 54, 2, PAL_ASN1_PRINTABLE_STRING }, + { 63, 75, 10, PAL_ASN1_UTF8_STRING }, + { 119, 134, 13, PAL_ASN1_UTC_TIME }, + { 532, 556, 22, PAL_ASN1_OCTET_STRING }, + { 600, 603, 1, PAL_ASN1_BOOLEAN }, + { 618, 879, 257, PAL_ASN1_BIT_STRING } +}; + + +static const unsigned char asn1_data[879] = +{ + 0x30, 0x82, 0x03, 0x6B, 0x30, 0x82, 0x02, 0x53, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, + 0xAA, 0xF6, 0x26, 0x55, 0x10, 0xA4, 0x58, 0x1E, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x4C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x49, 0x4C, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, + 0x0A, 0x53, 0x6F, 0x6D, 0x65, 0x2D, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x0C, 0x30, 0x0A, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x0C, 0x03, 0x4E, 0x65, 0x74, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, + 0x04, 0x0A, 0x0C, 0x03, 0x41, 0x52, 0x4D, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x0B, + 0x0C, 0x03, 0x50, 0x41, 0x4C, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x36, 0x31, 0x31, 0x32, 0x33, 0x31, + 0x33, 0x35, 0x30, 0x31, 0x39, 0x5A, 0x17, 0x0D, 0x31, 0x37, 0x31, 0x31, 0x32, 0x33, 0x31, 0x33, + 0x35, 0x30, 0x31, 0x39, 0x5A, 0x30, 0x4C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x49, 0x4C, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x53, + 0x6F, 0x6D, 0x65, 0x2D, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0C, 0x03, 0x4E, 0x65, 0x74, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x0A, + 0x0C, 0x03, 0x41, 0x52, 0x4D, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x03, + 0x50, 0x41, 0x4C, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xCE, 0xD5, 0x2F, 0x89, 0x97, 0xD5, 0xC1, 0xDF, 0x2D, 0xDB, 0x1B, 0xF5, + 0x4B, 0x0F, 0xAF, 0xD0, 0xF1, 0xC5, 0xD4, 0x45, 0xD4, 0x6D, 0x55, 0x73, 0x73, 0xD5, 0xBB, 0x7D, + 0x2E, 0x56, 0x8E, 0xF4, 0xCB, 0xAC, 0x0A, 0x78, 0x91, 0x9E, 0x6C, 0x72, 0xA6, 0x0F, 0x65, 0xFE, + 0x86, 0x91, 0x2D, 0x96, 0xE0, 0x40, 0xF4, 0x3A, 0xBB, 0x82, 0x29, 0x69, 0x23, 0x92, 0x93, 0xC8, + 0x20, 0x83, 0xD3, 0x7A, 0xFF, 0x71, 0xB4, 0x11, 0x43, 0xF0, 0x30, 0xE8, 0x32, 0xF8, 0x4C, 0xCB, + 0xE6, 0xF1, 0xE2, 0xBC, 0x01, 0xE6, 0xB8, 0x17, 0xBF, 0x82, 0xA2, 0xBF, 0x75, 0xFF, 0x88, 0x44, + 0x15, 0x86, 0x88, 0x4A, 0xDF, 0xEF, 0x48, 0x46, 0xD8, 0xFA, 0x81, 0xBB, 0xAA, 0xED, 0x16, 0xC7, + 0x7C, 0xE8, 0xCE, 0x1E, 0x79, 0x6C, 0x2D, 0x66, 0x88, 0x4C, 0xB7, 0x88, 0xA5, 0x35, 0xD7, 0x4A, + 0xE8, 0x6D, 0x89, 0xD1, 0x84, 0xBF, 0x23, 0x9B, 0xA2, 0xF4, 0xF3, 0x0D, 0x3E, 0xB8, 0x12, 0x48, + 0x38, 0xC6, 0x76, 0xD3, 0xEF, 0xAE, 0xA1, 0xD9, 0xC9, 0xA8, 0x32, 0xE7, 0x5E, 0xD5, 0x7C, 0x2A, + 0x26, 0xAD, 0x94, 0x60, 0xF6, 0x73, 0x73, 0xD1, 0x8B, 0xA3, 0x2A, 0x42, 0xA6, 0x86, 0x47, 0x0F, + 0x61, 0x59, 0xCD, 0x13, 0x87, 0xFB, 0x14, 0x16, 0x0E, 0x22, 0xBA, 0x7E, 0xC4, 0xF9, 0xC5, 0x59, + 0x31, 0xDF, 0xDA, 0x6A, 0xBB, 0x3F, 0x8B, 0xE7, 0xF7, 0x22, 0x7E, 0x35, 0xF2, 0xE3, 0x8A, 0xAC, + 0xFA, 0xCF, 0x49, 0xE0, 0x64, 0xC0, 0xC8, 0x24, 0x96, 0x69, 0x23, 0x3A, 0xC7, 0x04, 0x0A, 0x99, + 0xA7, 0x21, 0x87, 0x87, 0x9A, 0x01, 0x7B, 0x50, 0xCF, 0xE1, 0x7B, 0x0E, 0x8A, 0x4A, 0x25, 0xCF, + 0x88, 0xE4, 0x47, 0xAD, 0x85, 0x47, 0x8A, 0xE7, 0x35, 0xD9, 0x6B, 0x13, 0xA4, 0x77, 0x3F, 0x58, + 0x8F, 0x55, 0x65, 0xFF, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x50, 0x30, 0x4E, 0x30, 0x1D, 0x06, + 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x53, 0x43, 0x7D, 0x59, 0x2A, 0xF5, 0x93, 0xA5, + 0xA5, 0x02, 0x43, 0xD9, 0x7B, 0xC4, 0x2C, 0xCA, 0xBD, 0xDE, 0x96, 0x0D, 0x30, 0x1F, 0x06, 0x03, + 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x53, 0x43, 0x7D, 0x59, 0x2A, 0xF5, 0x93, + 0xA5, 0xA5, 0x02, 0x43, 0xD9, 0x7B, 0xC4, 0x2C, 0xCA, 0xBD, 0xDE, 0x96, 0x0D, 0x30, 0x0C, 0x06, + 0x03, 0x55, 0x1D, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09, 0x2A, + 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x15, + 0x9A, 0xFC, 0xBF, 0x26, 0x7A, 0x6A, 0xF9, 0x3F, 0xD4, 0x88, 0xF9, 0x83, 0x6C, 0xF6, 0x68, 0xC6, + 0x99, 0xDD, 0x55, 0x62, 0x89, 0xFB, 0x80, 0x74, 0x5B, 0x14, 0x1A, 0x82, 0x4F, 0xFF, 0x5E, 0xCC, + 0x20, 0x97, 0x68, 0x8C, 0x7B, 0x85, 0x02, 0xDE, 0x5A, 0x02, 0x4C, 0x72, 0x57, 0xE8, 0x01, 0x0A, + 0x08, 0x0F, 0xA2, 0xAB, 0xA4, 0x57, 0xC8, 0x4C, 0x8A, 0x3D, 0xCF, 0x23, 0xA6, 0xE4, 0x8D, 0xE3, + 0x1E, 0x9F, 0x50, 0xB3, 0x2C, 0xDD, 0xC6, 0x11, 0x98, 0xAA, 0x71, 0xA9, 0xF3, 0x02, 0x5C, 0x16, + 0xDB, 0xC2, 0x28, 0xA3, 0x9E, 0x51, 0xB1, 0xE7, 0xEC, 0x60, 0xE4, 0x59, 0x62, 0x1B, 0xC0, 0x4F, + 0xE4, 0xF3, 0xD7, 0x10, 0x12, 0x38, 0x6D, 0x2A, 0xF8, 0x96, 0x4E, 0x25, 0xE5, 0x05, 0xE1, 0x77, + 0x1F, 0xC7, 0xAB, 0x54, 0xDA, 0x0D, 0x09, 0xE5, 0xC3, 0xB0, 0x61, 0x50, 0x11, 0xC8, 0x5C, 0x7B, + 0x6B, 0x96, 0x71, 0x2E, 0xC9, 0x7C, 0x8E, 0x34, 0xA9, 0xB9, 0x25, 0x0A, 0x35, 0x0F, 0xA1, 0x77, + 0x6C, 0xC3, 0x30, 0x96, 0x7C, 0x40, 0x12, 0x9D, 0xBB, 0x62, 0xA7, 0xD6, 0xE6, 0x07, 0xCB, 0xAB, + 0xC6, 0xD7, 0xD1, 0x3C, 0x4D, 0x7F, 0xAE, 0x62, 0x22, 0xBD, 0x88, 0x33, 0x43, 0x15, 0xFF, 0x63, + 0x80, 0x95, 0x29, 0xCD, 0x00, 0x76, 0x53, 0xF6, 0xA6, 0xA1, 0xD0, 0x07, 0xE4, 0xF0, 0xC2, 0x03, + 0xBA, 0x7B, 0x25, 0x9B, 0x75, 0xA1, 0xB6, 0xA8, 0x4C, 0x44, 0x72, 0x14, 0x48, 0x29, 0x75, 0x76, + 0x66, 0xB1, 0xBB, 0x5A, 0x2D, 0x7C, 0x21, 0xBB, 0xEA, 0x70, 0x45, 0x8E, 0x6E, 0xFA, 0xCE, 0xCE, + 0x26, 0xDE, 0xF7, 0x36, 0xB7, 0x52, 0xBC, 0x9F, 0x21, 0x35, 0x2F, 0x5B, 0xAF, 0x0A, 0xAE, 0xD8, + 0xE1, 0x0C, 0x69, 0x27, 0x30, 0xFF, 0xCF, 0x13, 0xE8, 0x57, 0x1F, 0x5B, 0x38, 0x13, 0x02 +}; + + +typedef struct palCheckEcKeyTestVector +{ + const unsigned char key[200]; + size_t keyLen; + palGroupIndex_t index; + uint32_t keyType; + palStatus_t parsePrvRes; + palStatus_t checkPrvRes; + bool verifed; + palStatus_t parsePubRes; + palStatus_t checkPubRes; +}palCheckEcKeyTestVector_t; + + + +static const palCheckEcKeyTestVector_t check_ec_key_data[3] = +{ + { + { 0x00 }, 0, PAL_ECP_DP_SECP256R1, PAL_CHECK_PRIVATE_KEY, PAL_ERR_PK_KEY_INVALID_FORMAT, PAL_ERR_PARSING_PRIVATE_KEY, false, PAL_ERR_PARSING_PUBLIC_KEY, PAL_ERR_PARSING_PUBLIC_KEY + }, + { + { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x07, 0xED, 0xF8, 0x74, 0xA2, 0x0A, 0x3D, 0xA2, 0xC5, + 0x89, 0x99, 0x8A, 0x28, 0xC5, 0x00, 0x8C, 0x12, 0xD8, 0x9B, 0xC9, 0x74, 0x2F, 0x94, 0x53, 0x40, + 0x82, 0x36, 0x96, 0x04, 0x15, 0x2A, 0xB6, 0xA0, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x03, 0x01, 0x07, 0xA1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xE5, 0xD8, 0x40, 0xEF, 0xE8, 0x3B, 0x0D, + 0xC5, 0x7E, 0x72, 0x21, 0x65, 0xF6, 0x96, 0xF0, 0xC8, 0x16, 0xCC, 0xC5, 0x9D, 0x88, 0x24, 0x41, + 0xF3, 0xB3, 0x39, 0x34, 0xD2, 0xA1, 0x5B, 0xF9, 0xC7, 0xAF, 0xF6, 0x8F, 0x4E, 0x78, 0x01, 0xDB, + 0xB2, 0xAA, 0x7E, 0x7E, 0xC7, 0x41, 0x31, 0xF4, 0x8D, 0xD4, 0x8E, 0x98, 0x7B, 0x16, 0x4E, 0x96, + 0x26, 0x71, 0x9D, 0x1F, 0x84, 0xEC, 0x68, 0x9A, 0x31 + }, 121, PAL_ECP_DP_SECP256R1, PAL_CHECK_PRIVATE_KEY, PAL_SUCCESS, PAL_SUCCESS, true, PAL_ERR_PARSING_PUBLIC_KEY, PAL_ERR_PARSING_PUBLIC_KEY + }, + { + { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, + 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xE5, 0xD8, 0x40, 0xEF, 0xE8, + 0x3B, 0x0D, 0xC5, 0x7E, 0x72, 0x21, 0x65, 0xF6, 0x96, 0xF0, 0xC8, 0x16, 0xCC, 0xC5, 0x9D, 0x88, + 0x24, 0x41, 0xF3, 0xB3, 0x39, 0x34, 0xD2, 0xA1, 0x5B, 0xF9, 0xC7, 0xAF, 0xF6, 0x8F, 0x4E, 0x78, + 0x01, 0xDB, 0xB2, 0xAA, 0x7E, 0x7E, 0xC7, 0x41, 0x31, 0xF4, 0x8D, 0xD4, 0x8E, 0x98, 0x7B, 0x16, + 0x4E, 0x96, 0x26, 0x71, 0x9D, 0x1F, 0x84, 0xEC, 0x68, 0x9A, 0x31 + }, 91, PAL_ECP_DP_SECP256R1, PAL_CHECK_PUBLIC_KEY, PAL_ERR_PK_KEY_INVALID_FORMAT, PAL_ERR_PARSING_PRIVATE_KEY, true, PAL_SUCCESS, PAL_SUCCESS + } +}; + +typedef struct palParseECKeyTestVector{ + const unsigned char key[250]; + size_t len; + uint32_t type; + bool isDER; + bool shouldSucceed; + +}palParseECKeyTestVector_t; + +static const palParseECKeyTestVector_t parse_ec_key_data[8] = +{ + { + {0x00, 0x00}, 0, PAL_CHECK_PRIVATE_KEY, true, false + }, + { + {0x00, 0x00}, 0, PAL_CHECK_PUBLIC_KEY, true, false + }, + { + { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0xBD, 0x42, 0xD6, 0x36, 0x31, 0x2D, 0xF3, 0x2B, 0x31, + 0xEB, 0xE6, 0xE3, 0xC8, 0x63, 0x61, 0xA8, 0x45, 0x92, 0x2C, 0x70, 0xAB, 0x02, 0xC7, 0x45, 0xA7, + 0xBA, 0x7F, 0x39, 0xD3, 0xFD, 0xF0, 0x07, 0xA0, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x03, 0x01, 0x07, 0xA1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x7A, 0xDC, 0x03, 0xFE, 0xEF, 0x2B, 0x2B, + 0xF4, 0xE4, 0x6B, 0xAB, 0xA4, 0xD8, 0xEE, 0x2D, 0xAE, 0xA5, 0xD2, 0x28, 0xC5, 0xC1, 0xB2, 0x3C, + 0x7A, 0xAA, 0x5D, 0xE7, 0x81, 0x09, 0x1F, 0xE5, 0x9D, 0x80, 0xD4, 0xE9, 0xC5, 0x99, 0xF8, 0xBB, + 0xB1, 0x7B, 0xCB, 0x9A, 0x48, 0x2E, 0xF9, 0xEB, 0x01, 0xA3, 0xA4, 0x81, 0x70, 0x29, 0x34, 0xDB, + 0xE0, 0x65, 0x68, 0x48, 0x62, 0x99, 0x6D, 0xEC, 0x2E + },121, PAL_CHECK_PRIVATE_KEY, true, true + }, + { + { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, + 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x7A, 0xDC, 0x03, 0xFE, 0xEF, + 0x2B, 0x2B, 0xF4, 0xE4, 0x6B, 0xAB, 0xA4, 0xD8, 0xEE, 0x2D, 0xAE, 0xA5, 0xD2, 0x28, 0xC5, 0xC1, + 0xB2, 0x3C, 0x7A, 0xAA, 0x5D, 0xE7, 0x81, 0x09, 0x1F, 0xE5, 0x9D, 0x80, 0xD4, 0xE9, 0xC5, 0x99, + 0xF8, 0xBB, 0xB1, 0x7B, 0xCB, 0x9A, 0x48, 0x2E, 0xF9, 0xEB, 0x01, 0xA3, 0xA4, 0x81, 0x70, 0x29, + 0x34, 0xDB, 0xE0, 0x65, 0x68, 0x48, 0x62, 0x99, 0x6D, 0xEC, 0x2E + }, 91, PAL_CHECK_PUBLIC_KEY, true, true + }, + { + { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0xBD, 0x42, 0xD6, 0x36, 0x31, 0x2D, 0xF3, 0x2B, 0x31, + 0xEB, 0xE6, 0xE3, 0xC8, 0x63, 0x61, 0xA8, 0x45, 0x92, 0x2C, 0x70, 0xAB, 0x02, 0xC7, 0x45, 0xA7, + 0xBA, 0x7F, 0x39, 0xD3, 0xFD, 0xF0, 0x07, 0xA0, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x03, 0x01, 0x07, 0xA1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x7A, 0xDC, 0x03, 0xFE, 0xEF, 0x2B, 0x2B, + 0xF4, 0xE4, 0x6B, 0xAB, 0xA4, 0xD8, 0xEE, 0x2D, 0xAE, 0xA5, 0xD2, 0x28, 0xC5, 0xC1, 0xB2, 0x3C, + 0x7A, 0xAA, 0x5D, 0xE7, 0x81, 0x09, 0x1F, 0xE5, 0x9D, 0x80, 0xD4, 0xE9, 0xC5, 0x99, 0xF8, 0xBB, + 0xB1, 0x7B, 0xCB, 0x9A, 0x48, 0x2E, 0xF9, 0xEB, 0x01, 0xA3, 0xA4, 0x81, 0x70, 0x29, 0x34, 0xDB, + 0xE0, 0x65, 0x68, 0x48, 0x62, 0x99, 0x6D, 0xEC, 0x2E + }, 121, PAL_CHECK_PUBLIC_KEY, true, false + }, + { + { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, + 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x7A, 0xDC, 0x03, 0xFE, 0xEF, + 0x2B, 0x2B, 0xF4, 0xE4, 0x6B, 0xAB, 0xA4, 0xD8, 0xEE, 0x2D, 0xAE, 0xA5, 0xD2, 0x28, 0xC5, 0xC1, + 0xB2, 0x3C, 0x7A, 0xAA, 0x5D, 0xE7, 0x81, 0x09, 0x1F, 0xE5, 0x9D, 0x80, 0xD4, 0xE9, 0xC5, 0x99, + 0xF8, 0xBB, 0xB1, 0x7B, 0xCB, 0x9A, 0x48, 0x2E, 0xF9, 0xEB, 0x01, 0xA3, 0xA4, 0x81, 0x70, 0x29, + 0x34, 0xDB, 0xE0, 0x65, 0x68, 0x48, 0x62, 0x99, 0x6D, 0xEC, 0x2E + },91, PAL_CHECK_PRIVATE_KEY, true, false + }, + { + "-----BEGIN EC PRIVATE KEY-----\r\n" + "MHcCAQEEIBnI7FMl8SVLh8u3jUyGtJRxtyzf8WhZ6zVlR+uezRi/oAoGCCqGSM49\r\n" + "AwEHoUQDQgAE7XbxNHg17rUMJ8nwTSTwSRrskUVWVkrnB7HARGN8eX4vL6v75D/3\r\n" + "WsseEnEVMAhsbPs7rDx7xaKStJQKKSX84w==\r\n" + "-----END EC PRIVATE KEY-----\r\n", + 236, PAL_CHECK_PRIVATE_KEY, false, false + }, + { + "-----BEGIN PUBLIC KEY-----\r\n" + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7XbxNHg17rUMJ8nwTSTwSRrskUVW\r\n" + "VkrnB7HARGN8eX4vL6v75D/3WsseEnEVMAhsbPs7rDx7xaKStJQKKSX84w==\r\n" + "-----END PUBLIC KEY-----\r\n", + 185, PAL_CHECK_PUBLIC_KEY, false, false + } +}; + + +typedef struct palX509CSRTestVector{ + unsigned char prvkey[300]; + size_t prvkeyLen; + unsigned char pubkey[300]; + size_t pubkeyLen; + palMDType_t mdType; + const char subject_name[50]; + uint32_t keyUsage; + unsigned char derOut[300]; + size_t derOutLen; +}palX509CSRTestVector_t; + +static const palX509CSRTestVector_t CsrTests[2] = +{ + { + { + 0x30, 0x78, 0x02, 0x01, 0x01, 0x04, 0x21, 0x00, 0xAE, 0xD9, 0xBE, 0xEA, 0x76, 0x78, 0xF2, 0xD9, + 0xEC, 0x11, 0xC5, 0x49, 0x00, 0xDC, 0xB7, 0xB1, 0x06, 0xBD, 0xA5, 0xF6, 0xF7, 0x06, 0xBB, 0xC2, + 0x8A, 0x8D, 0x46, 0xCB, 0xCF, 0xAE, 0x1F, 0x22, 0xA0, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, + 0x3D, 0x03, 0x01, 0x07, 0xA1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xC9, 0xEB, 0xAC, 0x6F, 0x9C, 0x39, + 0x1D, 0xFC, 0xFE, 0xBD, 0x25, 0x69, 0x51, 0x56, 0x80, 0xAC, 0xBF, 0x1A, 0x6F, 0xD4, 0xD7, 0x2E, + 0x02, 0x07, 0xBF, 0xF8, 0x4C, 0xEF, 0xEC, 0x60, 0x41, 0xAC, 0xDC, 0x7D, 0xD6, 0xDE, 0xD9, 0xF4, + 0xAA, 0xB8, 0x81, 0x0F, 0x96, 0xB6, 0xB3, 0x4A, 0x47, 0xD3, 0x98, 0x3F, 0x52, 0x87, 0x62, 0x0D, + 0xC7, 0xA0, 0x40, 0xCD, 0x23, 0x03, 0xBD, 0x17, 0x1E, 0xDE + },122, + { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, + 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xC9, 0xEB, 0xAC, 0x6F, 0x9C, + 0x39, 0x1D, 0xFC, 0xFE, 0xBD, 0x25, 0x69, 0x51, 0x56, 0x80, 0xAC, 0xBF, 0x1A, 0x6F, 0xD4, 0xD7, + 0x2E, 0x02, 0x07, 0xBF, 0xF8, 0x4C, 0xEF, 0xEC, 0x60, 0x41, 0xAC, 0xDC, 0x7D, 0xD6, 0xDE, 0xD9, + 0xF4, 0xAA, 0xB8, 0x81, 0x0F, 0x96, 0xB6, 0xB3, 0x4A, 0x47, 0xD3, 0x98, 0x3F, 0x52, 0x87, 0x62, + 0x0D, 0xC7, 0xA0, 0x40, 0xCD, 0x23, 0x03, 0xBD, 0x17, 0x1E, 0xDE + }, 91, PAL_SHA256, "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", PAL_X509_KU_DIGITAL_SIGNATURE, + { + 0x30, 0x82, 0x01, 0x20, 0x30, 0x81, 0xC5, 0x02, 0x01, 0x00, 0x30, 0x45, 0x31, 0x0B, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x13, 0x0A, 0x53, 0x6F, 0x6D, 0x65, 0x2D, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, + 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x18, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, + 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4C, 0x74, + 0x64, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xC9, 0xEB, 0xAC, 0x6F, + 0x9C, 0x39, 0x1D, 0xFC, 0xFE, 0xBD, 0x25, 0x69, 0x51, 0x56, 0x80, 0xAC, 0xBF, 0x1A, 0x6F, 0xD4, + 0xD7, 0x2E, 0x02, 0x07, 0xBF, 0xF8, 0x4C, 0xEF, 0xEC, 0x60, 0x41, 0xAC, 0xDC, 0x7D, 0xD6, 0xDE, + 0xD9, 0xF4, 0xAA, 0xB8, 0x81, 0x0F, 0x96, 0xB6, 0xB3, 0x4A, 0x47, 0xD3, 0x98, 0x3F, 0x52, 0x87, + 0x62, 0x0D, 0xC7, 0xA0, 0x40, 0xCD, 0x23, 0x03, 0xBD, 0x17, 0x1E, 0xDE, 0xA0, 0x1E, 0x30, 0x1C, + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x0E, 0x31, 0x0F, 0x30, 0x0D, 0x30, + 0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04, 0x04, 0x03, 0x02, 0x01, 0x80, 0x30, 0x0C, 0x06, 0x08, + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x05, 0x00, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, + 0x21, 0x00, 0xEF, 0xA5, 0x91, 0xE8, 0x43, 0x2C, 0x95, 0x54, 0x51, 0xFA, 0x75, 0xAE, 0xF3, 0xE5, + 0x5B, 0xAE, 0x37, 0x28, 0x43, 0x12, 0xBE, 0xCB, 0x54, 0x67, 0x1C, 0xF8, 0x5F, 0x28, 0xD8, 0x87, + 0x23, 0x35, 0x02, 0x20, 0x32, 0xB7, 0x86, 0x38, 0xEF, 0x9F, 0x96, 0x25, 0x4B, 0xB5, 0xCD, 0x11, + 0xBB, 0x23, 0x3F, 0x93, 0x44, 0x31, 0x73, 0xF1, 0x0A, 0xBA, 0x2F, 0x43, 0x21, 0xFB, 0xBD, 0x4B, + 0xE5, 0xD4, 0xF0, 0x42 + }, 292 + }, + { + { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x12, 0x02, 0xAF, 0xCF, 0x14, 0xEC, 0xDB, 0x72, 0xDF, + 0x1C, 0x0C, 0xF1, 0xE3, 0x23, 0x97, 0x83, 0x62, 0x31, 0x71, 0x4C, 0xE6, 0x5B, 0x88, 0x9B, 0xF1, + 0x19, 0x40, 0xE4, 0xBE, 0xE9, 0x34, 0x76, 0xA0, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x03, 0x01, 0x07, 0xA1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x6D, 0xE7, 0x22, 0xF3, 0xCB, 0x5F, 0x84, + 0x83, 0xEE, 0x27, 0xE2, 0xA1, 0x24, 0xFF, 0xAC, 0x19, 0xF7, 0x2D, 0xDD, 0xFA, 0x69, 0x20, 0xBE, + 0x06, 0x7E, 0x8A, 0x20, 0x40, 0x26, 0x90, 0xE9, 0xFB, 0xBA, 0x86, 0x0A, 0xE0, 0x9A, 0x39, 0x1B, + 0x0F, 0xB8, 0x53, 0xD5, 0xFC, 0xE1, 0x5E, 0x94, 0xBC, 0x1E, 0x97, 0x9C, 0xC2, 0x7B, 0x4E, 0xF7, + 0x17, 0x36, 0xCA, 0x59, 0xD5, 0x01, 0xBB, 0x56, 0x74 + }, 121, + { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, + 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x6D, 0xE7, 0x22, 0xF3, 0xCB, + 0x5F, 0x84, 0x83, 0xEE, 0x27, 0xE2, 0xA1, 0x24, 0xFF, 0xAC, 0x19, 0xF7, 0x2D, 0xDD, 0xFA, 0x69, + 0x20, 0xBE, 0x06, 0x7E, 0x8A, 0x20, 0x40, 0x26, 0x90, 0xE9, 0xFB, 0xBA, 0x86, 0x0A, 0xE0, 0x9A, + 0x39, 0x1B, 0x0F, 0xB8, 0x53, 0xD5, 0xFC, 0xE1, 0x5E, 0x94, 0xBC, 0x1E, 0x97, 0x9C, 0xC2, 0x7B, + 0x4E, 0xF7, 0x17, 0x36, 0xCA, 0x59, 0xD5, 0x01, 0xBB, 0x56, 0x74 + }, 91, PAL_SHA256, "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", PAL_X509_KU_NON_REPUDIATION, + { + 0x30, 0x82, 0x01, 0x20, 0x30, 0x81, 0xC5, 0x02, 0x01, 0x00, 0x30, 0x45, 0x31, 0x0B, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x13, 0x0A, 0x53, 0x6F, 0x6D, 0x65, 0x2D, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, + 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x18, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, + 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4C, 0x74, + 0x64, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x6D, 0xE7, 0x22, 0xF3, + 0xCB, 0x5F, 0x84, 0x83, 0xEE, 0x27, 0xE2, 0xA1, 0x24, 0xFF, 0xAC, 0x19, 0xF7, 0x2D, 0xDD, 0xFA, + 0x69, 0x20, 0xBE, 0x06, 0x7E, 0x8A, 0x20, 0x40, 0x26, 0x90, 0xE9, 0xFB, 0xBA, 0x86, 0x0A, 0xE0, + 0x9A, 0x39, 0x1B, 0x0F, 0xB8, 0x53, 0xD5, 0xFC, 0xE1, 0x5E, 0x94, 0xBC, 0x1E, 0x97, 0x9C, 0xC2, + 0x7B, 0x4E, 0xF7, 0x17, 0x36, 0xCA, 0x59, 0xD5, 0x01, 0xBB, 0x56, 0x74, 0xA0, 0x1E, 0x30, 0x1C, + 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x0E, 0x31, 0x0F, 0x30, 0x0D, 0x30, + 0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04, 0x04, 0x03, 0x02, 0x01, 0x40, 0x30, 0x0C, 0x06, 0x08, + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x05, 0x00, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, + 0x21, 0x00, 0xEC, 0xA1, 0xDE, 0x83, 0x89, 0x1A, 0x05, 0xA6, 0x38, 0x7B, 0xC1, 0xDB, 0x0D, 0x67, + 0xEC, 0x9E, 0x98, 0x3C, 0x92, 0xB3, 0x58, 0x06, 0x34, 0x87, 0x19, 0xAB, 0x57, 0x2B, 0x70, 0x29, + 0x4C, 0x3D, 0x02, 0x20, 0x6A, 0x9D, 0x7D, 0xFF, 0x8B, 0x00, 0x74, 0x24, 0xA1, 0xD6, 0xD6, 0xEF, + 0xF7, 0x70, 0x86, 0x8D, 0x2D, 0x52, 0x68, 0x55, 0x18, 0x7C, 0x45, 0xFB, 0xEE, 0x49, 0x50, 0x62, + 0x9E, 0x6C, 0x1C, 0xCA + }, 292 + } +}; + +const unsigned char cert_not_self_signed[] = +{ + 0x30, 0x82, 0x01, 0xc4, 0x30, 0x82, 0x01, 0x69, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, + 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x30, 0x3d, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x07, 0x49, 0x4f, 0x54, 0x5f, 0x50, + 0x41, 0x4c, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x03, 0x50, 0x41, 0x4c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31, 0x0e, 0x30, + 0x0c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x05, 0x49, 0x4f, 0x54, 0x42, 0x55, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x33, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, + 0x31, 0x35, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x42, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x08, 0x49, 0x4f, 0x54, 0x5f, 0x54, 0x45, + 0x53, 0x54, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x04, 0x50, 0x41, 0x41, + 0x4c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x08, 0x49, 0x4f, 0x54, 0x42, 0x55, 0x5f, 0x49, + 0x4c, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x18, 0xf7, 0x26, 0xc6, + 0x86, 0x30, 0xec, 0xed, 0xd6, 0xb4, 0x3a, 0xd3, 0x86, 0x7a, 0x49, 0xbb, 0xb3, 0x93, 0xee, 0x43, + 0x56, 0x18, 0x71, 0x2a, 0x40, 0xda, 0xc8, 0x2c, 0x4a, 0xc6, 0x3d, 0x09, 0xfc, 0xe0, 0x84, 0x2f, + 0x0d, 0xce, 0xf8, 0x17, 0xcf, 0x28, 0x8f, 0x4f, 0xb4, 0xea, 0xde, 0xf9, 0xe4, 0x9a, 0x16, 0xeb, + 0x8c, 0x67, 0x02, 0xfd, 0x64, 0x7b, 0x62, 0x0e, 0x9b, 0x29, 0x05, 0x22, 0xa3, 0x53, 0x30, 0x51, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, + 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x13, 0xde, 0xa2, 0x8b, + 0x8d, 0x40, 0x1e, 0xd6, 0x62, 0xfd, 0x7e, 0x27, 0x53, 0xb8, 0x8f, 0x17, 0x18, 0x76, 0x33, 0x20, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x13, 0xde, 0xa2, + 0x8b, 0x8d, 0x40, 0x1e, 0xd6, 0x62, 0xfd, 0x7e, 0x27, 0x53, 0xb8, 0x8f, 0x17, 0x18, 0x76, 0x33, + 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x03, + 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x47, 0xb7, 0xf8, 0x12, 0xb0, 0xe7, 0x7b, 0x33, 0x7f, 0x31, + 0x5e, 0x2f, 0x54, 0x40, 0x8f, 0xff, 0xe1, 0x05, 0x1b, 0xe5, 0xf1, 0xd5, 0xa7, 0x6a, 0xb8, 0x2a, + 0x6f, 0x22, 0x5a, 0xce, 0x31, 0x84, 0x02, 0x20, 0x51, 0x5d, 0x68, 0x41, 0x7f, 0x26, 0xb2, 0x6b, + 0x71, 0x1e, 0xd2, 0xa2, 0x2d, 0xd9, 0x43, 0x69, 0xbf, 0xf0, 0x73, 0xf6, 0x01, 0x7f, 0xf7, 0xac, + 0x0e, 0x5c, 0xb4, 0x4e, 0x56, 0x73, 0x63, 0x3c +}; + +//Certificate based on unsupported hash â sha512 +const uint8_t testdata_x509_Sha512[506] = + { + 0x30, 0x82, 0x01, 0xf6, 0x30, 0x82, 0x01, 0x9c, 0x02, 0x09, 0x00, 0xb4, 0x60, 0xcc, 0x6f, 0xa2, + 0x55, 0x52, 0xfe, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04, 0x30, + 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x4b, 0x66, 0x61, 0x72, 0x2d, 0x6e, + 0x65, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x4e, + 0x65, 0x74, 0x61, 0x6e, 0x69, 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x03, 0x41, 0x52, 0x4d, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03, 0x49, + 0x4f, 0x54, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x09, 0x01, 0x16, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x30, 0x31, 0x40, 0x61, 0x72, 0x6d, + 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x39, 0x31, 0x30, 0x31, 0x34, + 0x30, 0x33, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x33, 0x30, 0x33, 0x31, 0x34, 0x30, + 0x33, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x4b, + 0x66, 0x61, 0x72, 0x2d, 0x6e, 0x65, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x07, 0x4e, 0x65, 0x74, 0x61, 0x6e, 0x69, 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x03, 0x41, 0x52, 0x4d, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x03, 0x49, 0x4f, 0x54, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x30, + 0x31, 0x40, 0x61, 0x72, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, + 0x03, 0x42, 0x00, 0x04, 0x41, 0xdf, 0x03, 0x36, 0x9c, 0xb3, 0xb2, 0x9e, 0x42, 0xbc, 0x48, 0x37, + 0x3c, 0x21, 0xc2, 0x99, 0xb1, 0x47, 0x1d, 0x96, 0x84, 0x28, 0xdb, 0x07, 0x30, 0xad, 0x69, 0x86, + 0x39, 0x10, 0x10, 0x52, 0xe9, 0x3a, 0xe5, 0x4e, 0xd3, 0x3f, 0xd3, 0x0d, 0xfd, 0x9f, 0xd9, 0x4b, + 0xcb, 0xa1, 0x81, 0xbe, 0x3f, 0xbe, 0x24, 0x68, 0xc3, 0xe9, 0x73, 0xbf, 0x34, 0xb7, 0xa0, 0x61, + 0x56, 0x96, 0xb5, 0x74, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04, + 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xa0, 0xa6, 0x46, 0xaa, 0xef, 0x18, 0xa6, 0xa3, + 0x7b, 0x81, 0xdb, 0x36, 0xf7, 0x2c, 0xbc, 0xb4, 0x29, 0x7f, 0x3c, 0x35, 0xbd, 0x88, 0xba, 0xa6, + 0x98, 0x8f, 0x5f, 0x67, 0x35, 0xf8, 0xf2, 0x18, 0x02, 0x20, 0x65, 0x88, 0x9e, 0x5d, 0x5a, 0x84, + 0xb7, 0x42, 0x96, 0xe4, 0xb7, 0x7d, 0x9b, 0x5c, 0x01, 0xc3, 0x5a, 0x40, 0x11, 0x0d, 0xf5, 0xfe, + 0x44, 0x9c, 0xbb, 0xd2, 0x2f, 0x37, 0x38, 0xbe, 0x03, 0x56}; + +//Certificate based on unsupported curve â secp521r1 +const uint8_t testdata_x509_Curve512r1[641] = + { + 0x30, 0x82, 0x02, 0x7d, 0x30, 0x82, 0x01, 0xdf, 0x02, 0x09, 0x00, 0xe2, 0x16, 0x36, 0x0a, 0x28, + 0x52, 0x3e, 0x81, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, + 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x4b, 0x66, 0x61, 0x72, 0x2d, 0x6e, + 0x65, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x4e, + 0x65, 0x74, 0x61, 0x6e, 0x69, 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x03, 0x41, 0x52, 0x4d, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03, 0x49, + 0x4f, 0x54, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x09, 0x01, 0x16, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x30, 0x31, 0x40, 0x61, 0x72, 0x6d, + 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x30, 0x30, 0x31, 0x30, 0x38, + 0x35, 0x36, 0x35, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x33, 0x32, 0x34, 0x30, 0x38, 0x35, + 0x36, 0x35, 0x31, 0x5a, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x4b, + 0x66, 0x61, 0x72, 0x2d, 0x6e, 0x65, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x07, 0x4e, 0x65, 0x74, 0x61, 0x6e, 0x69, 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x03, 0x41, 0x52, 0x4d, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x03, 0x49, 0x4f, 0x54, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x30, + 0x31, 0x40, 0x61, 0x72, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, + 0x86, 0x00, 0x04, 0x00, 0xf6, 0x6f, 0x0f, 0xbe, 0x33, 0x95, 0xa3, 0xd1, 0x00, 0x47, 0x27, 0xcf, + 0xd6, 0x3d, 0x0b, 0x69, 0x77, 0x40, 0xba, 0xaa, 0x82, 0xf4, 0xc3, 0x81, 0x41, 0x2b, 0xbd, 0x7b, + 0x2a, 0xf5, 0xd3, 0xf2, 0x09, 0x5a, 0x61, 0xb4, 0x5d, 0x6e, 0x32, 0x10, 0x61, 0xfd, 0x6e, 0x5a, + 0x74, 0x89, 0xad, 0xba, 0x23, 0x92, 0x33, 0x37, 0xa0, 0x4f, 0x98, 0x30, 0x4d, 0x8b, 0xae, 0xbf, + 0x5f, 0x49, 0x56, 0x17, 0x69, 0x00, 0x37, 0x1b, 0xde, 0xa0, 0x11, 0x38, 0x17, 0xb5, 0x15, 0x61, + 0xbd, 0xa1, 0xd8, 0x8d, 0x71, 0x48, 0x27, 0x4d, 0xbe, 0x60, 0x74, 0x3a, 0xd1, 0xe1, 0xff, 0xea, + 0x0a, 0xa2, 0x3d, 0xaa, 0x28, 0x39, 0x28, 0x32, 0xa7, 0x0c, 0x9d, 0xfa, 0x52, 0xc1, 0x2c, 0xba, + 0xac, 0x0f, 0x42, 0xa2, 0xcc, 0x78, 0x01, 0x45, 0x11, 0x62, 0xcf, 0x4f, 0x87, 0xcb, 0xf1, 0xff, + 0x2a, 0x1a, 0x30, 0xe9, 0x3d, 0x31, 0x59, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x04, 0x03, 0x02, 0x03, 0x81, 0x8b, 0x00, 0x30, 0x81, 0x87, 0x02, 0x41, 0x31, 0x73, 0x8d, 0x4a, + 0x28, 0x86, 0xa9, 0x06, 0xbd, 0x7f, 0xe8, 0x58, 0x43, 0xc2, 0xce, 0xd9, 0xdb, 0x75, 0xae, 0x42, + 0x83, 0x98, 0x29, 0x28, 0x61, 0x02, 0xfc, 0x23, 0x54, 0xe3, 0xcd, 0x07, 0x6f, 0xdc, 0xa0, 0x2e, + 0xdd, 0xd3, 0xc6, 0x2e, 0x11, 0xcc, 0xd9, 0x3c, 0xdf, 0x26, 0xd4, 0x66, 0xdb, 0x03, 0x9e, 0x79, + 0x9a, 0x60, 0x8f, 0x1d, 0x52, 0x6e, 0x3d, 0x16, 0x2f, 0x7d, 0x86, 0x43, 0x98, 0x02, 0x42, 0x01, + 0xaa, 0xf2, 0x7f, 0xad, 0xad, 0xaa, 0x16, 0x35, 0x66, 0xe7, 0x52, 0xcc, 0x60, 0xdd, 0x09, 0xae, + 0x1b, 0x44, 0x33, 0xa1, 0x57, 0x3a, 0xa0, 0xc5, 0xe3, 0x08, 0x84, 0xa7, 0xe3, 0x59, 0xf3, 0x79, + 0x9a, 0xbf, 0xcb, 0x26, 0x36, 0x45, 0x64, 0x4b, 0x92, 0xb8, 0xc7, 0x51, 0x14, 0x57, 0x94, 0x4c, + 0x96, 0x59, 0x2a, 0x5f, 0xb1, 0x38, 0x84, 0xc3, 0x26, 0x51, 0x57, 0x64, 0x4e, 0x54, 0x30, 0x3e, + 0x00}; + +const unsigned char x509_TI[] = +{ + 0x30, 0x82, 0x01, 0xc1, 0x30, 0x82, 0x01, 0x64, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, + 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x30, 0x3d, + 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x07, 0x49, 0x4f, 0x54, 0x5f, 0x50, + 0x41, 0x4c, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x03, 0x50, 0x41, 0x4c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31, 0x0e, 0x30, + 0x0c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x05, 0x49, 0x4f, 0x54, 0x42, 0x55, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x33, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, + 0x31, 0x35, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x3d, 0x31, + 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x07, 0x49, 0x4f, 0x54, 0x5f, 0x50, 0x41, + 0x4c, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x03, 0x50, 0x41, 0x4c, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31, 0x0e, 0x30, 0x0c, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x05, 0x49, 0x4f, 0x54, 0x42, 0x55, 0x30, 0x59, 0x30, 0x13, + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x18, 0xf7, 0x26, 0xc6, 0x86, 0x30, 0xec, 0xed, 0xd6, + 0xb4, 0x3a, 0xd3, 0x86, 0x7a, 0x49, 0xbb, 0xb3, 0x93, 0xee, 0x43, 0x56, 0x18, 0x71, 0x2a, 0x40, + 0xda, 0xc8, 0x2c, 0x4a, 0xc6, 0x3d, 0x09, 0xfc, 0xe0, 0x84, 0x2f, 0x0d, 0xce, 0xf8, 0x17, 0xcf, + 0x28, 0x8f, 0x4f, 0xb4, 0xea, 0xde, 0xf9, 0xe4, 0x9a, 0x16, 0xeb, 0x8c, 0x67, 0x02, 0xfd, 0x64, + 0x7b, 0x62, 0x0e, 0x9b, 0x29, 0x05, 0x22, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x13, 0xde, 0xa2, 0x8b, 0x8d, 0x40, 0x1e, 0xd6, 0x62, + 0xfd, 0x7e, 0x27, 0x53, 0xb8, 0x8f, 0x17, 0x18, 0x76, 0x33, 0x20, 0x30, 0x1f, 0x06, 0x03, 0x55, + 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x13, 0xde, 0xa2, 0x8b, 0x8d, 0x40, 0x1e, 0xd6, + 0x62, 0xfd, 0x7e, 0x27, 0x53, 0xb8, 0x8f, 0x17, 0x18, 0x76, 0x33, 0x20, 0x30, 0x0c, 0x06, 0x08, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, + 0x21, 0x00, 0xb7, 0xbb, 0x7b, 0x05, 0x17, 0x5f, 0x74, 0x0a, 0x91, 0xd7, 0x95, 0x30, 0xa8, 0xb4, + 0x47, 0x26, 0x2d, 0xc4, 0xbf, 0xb4, 0xba, 0x00, 0x54, 0x92, 0xcd, 0xb8, 0xb4, 0x42, 0x4b, 0x05, + 0x95, 0xe6, 0x02, 0x21, 0x00, 0xdb, 0x61, 0x24, 0x78, 0xed, 0x54, 0xcd, 0x8e, 0xfa, 0x31, 0x21, + 0x8b, 0xe7, 0x11, 0x7e, 0x6e, 0xe2, 0x17, 0x63, 0xbe, 0x31, 0x90, 0x2b, 0xf8, 0xd2, 0x11, 0x5d, + 0x9d, 0x8d, 0x5a, 0xaa, 0xdd +}; + +const unsigned char x509_TI_PEM[] = "-----BEGIN CERTIFICATE-----\r\n" + "MIIFIzCCBAugAwIBAgIQVYyM7bV85U+m+zUfuEsiLzANBgkqhkiG9w0BAQUFADCB\r\n" + "tDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\r\n" + "ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2Ug\r\n" + "YXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykxMDEuMCwGA1UEAxMl\r\n" + "VmVyaVNpZ24gQ2xhc3MgMyBDb2RlIFNpZ25pbmcgMjAxMCBDQTAeFw0xNDA0MTUw\r\n" + "MDAwMDBaFw0xNTA0MTYyMzU5NTlaMHQxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIEwVU\r\n" + "ZXhhczEPMA0GA1UEBxMGRGFsbGFzMRowGAYDVQQKFBFUZXhhcyBJbnN0cnVtZW50\r\n" + "czEMMAoGA1UECxQDV0NTMRowGAYDVQQDFBFUZXhhcyBJbnN0cnVtZW50czCCASIw\r\n" + "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMuAIvJOnebITQe2qli+t6Juwoy7\r\n" + "I9qenavTt7D2cYsEBO+Oj/SLWjkieGPKek1Q+DIo66h3ZAYB9mDhxIAxY8bMmO61\r\n" + "SOwxtcjA7nLgoqacMi61ly5OmjDuTholKjCyFCYmun7YPiI4b0BRNwFIMxOjfKdc\r\n" + "9Jj1UCl7TH0DFsn1ly583NOlJey7AV5v4sijU5AWSR+JeaV/yFw1MPbY58ekjnS8\r\n" + "tv5K8r5k5D770jDOZ/nuLpVZ3oNvhP9uMb6abEcUcVnxHkPu8ovFa43T1FwAKYSF\r\n" + "4FAPpe4P9EQVUBJAupMt91J6iPWeiSjKYMYbd3dgNHNabsoT1gACAhCWwJkCAwEA\r\n" + "AaOCAW4wggFqMAkGA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG\r\n" + "CCsGAQUFBwMDMGYGA1UdIARfMF0wWwYLYIZIAYb4RQEHFwMwTDAjBggrBgEFBQcC\r\n" + "ARYXaHR0cHM6Ly9kLnN5bWNiLmNvbS9jcHMwJQYIKwYBBQUHAgIwGRoXaHR0cHM6\r\n" + "Ly9kLnN5bWNiLmNvbS9ycGEwHwYDVR0jBBgwFoAUz5mp6nsm9EvJjo/X8AUm7+PS\r\n" + "p50wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3NmLnN5bWNiLmNvbS9zZi5jcmww\r\n" + "VwYIKwYBBQUHAQEESzBJMB8GCCsGAQUFBzABhhNodHRwOi8vc2Yuc3ltY2QuY29t\r\n" + "MCYGCCsGAQUFBzAChhpodHRwOi8vc2Yuc3ltY2IuY29tL3NmLmNydDARBglghkgB\r\n" + "hvhCAQEEBAMCBBAwFgYKKwYBBAGCNwIBGwQIMAYBAQABAf8wDQYJKoZIhvcNAQEF\r\n" + "BQADggEBACKIttb6LKlpjDHUFo9BHdYw6qxbF3Ham5GPjAn+ofYqpv3KoF7L2Rc9\r\n" + "jhYDIA5IHmYAjDdHLUBx+DdzMP80cXcRIdBGgOFFw++rRboUi0yOpg47yD0AipNT\r\n" + "Q00rBdoeEzs3ERiPir20402OmFUBkCcwM85XaXh1hvOKDZaCEj/6vlK/Y6++y1QC\r\n" + "tQGm08HAAuEz4VsnE/mcVeuaVM8DqFInrp9mpCNiCCwdiG3TEC1UgACjxFmFk0UH\r\n" + "mrUNww35tofUjAoXIkcegm2d/ld8bZxludWG2sJRydVTAQe1jJJDg+N7IdyH/gv7\r\n" + "y8i1xf5goGEvMqLiYY5njLCSSpCeNqE=\r\n" + "-----END CERTIFICATE-----\r\n"; + +const unsigned char x509_selfsign[] = +{ + 0x30, 0x82, 0x01, 0x9a, 0x30, 0x82, 0x01, 0x3e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, + 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x30, 0x2d, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x02, 0x43, 0x41, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x6d, 0x62, 0x65, 0x64, 0x20, 0x54, 0x4c, 0x53, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x30, 0x1e, 0x17, + 0x0d, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, + 0x33, 0x30, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x2d, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x02, 0x43, 0x41, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x6d, 0x62, 0x65, 0x64, 0x20, 0x54, 0x4c, 0x53, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x30, 0x59, 0x30, 0x13, + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xf7, 0xc6, 0x63, 0x68, 0x8d, 0x48, 0x3a, 0xcc, 0xeb, + 0xc1, 0x01, 0xcb, 0xd5, 0xc9, 0xa9, 0xc8, 0x42, 0x62, 0x2e, 0xd0, 0xb2, 0x34, 0x6a, 0x9f, 0xc9, + 0xce, 0xe0, 0x1c, 0x57, 0xc7, 0x0a, 0x62, 0x6e, 0x8e, 0x2e, 0xc5, 0x9f, 0xef, 0x8e, 0x04, 0x44, + 0x7e, 0xf3, 0xd0, 0xe6, 0x92, 0xc9, 0x0a, 0x49, 0x72, 0x98, 0x7f, 0x73, 0x3e, 0xf6, 0x97, 0x70, + 0x74, 0xb7, 0x9f, 0xe1, 0xb5, 0xef, 0xce, 0xa3, 0x4d, 0x30, 0x4b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x0f, 0xc6, 0x27, 0x51, 0xce, 0x06, 0x0b, 0x3b, 0xbd, 0xf1, 0xd1, 0x8e, 0x25, 0x6d, 0xcd, + 0x12, 0x64, 0x8f, 0x73, 0x4d, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0x0f, 0xc6, 0x27, 0x51, 0xce, 0x06, 0x0b, 0x3b, 0xbd, 0xf1, 0xd1, 0x8e, 0x25, 0x6d, + 0xcd, 0x12, 0x64, 0x8f, 0x73, 0x4d, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, + 0x03, 0x02, 0x05, 0x00, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xf1, 0x6a, 0x24, 0x08, + 0x99, 0xf1, 0xe0, 0x55, 0x4f, 0x0a, 0x52, 0x72, 0x68, 0x63, 0x6e, 0xec, 0x2f, 0x9d, 0x54, 0x61, + 0x9d, 0x7f, 0xa3, 0x5d, 0xa5, 0x79, 0x69, 0xc2, 0xab, 0xcf, 0x0f, 0x48, 0x02, 0x20, 0x51, 0x41, + 0x26, 0x4b, 0xdf, 0x1b, 0x5e, 0xda, 0xa4, 0x53, 0x8d, 0xe5, 0x92, 0xa6, 0x1b, 0x8a, 0x0d, 0x58, + 0x59, 0x9e, 0x77, 0x99, 0xd6, 0x81, 0xf1, 0x5d, 0xcd, 0x28, 0xcc, 0x03, 0x75, 0x96 +}; + +const unsigned char x509_verify_ca[] = +{ + 0x30, 0x82, 0x01, 0xf6, 0x30, 0x82, 0x01, 0x9c, 0x02, 0x09, 0x00, 0xe3, 0x22, 0x71, 0x24, 0xb8, + 0xa6, 0x9b, 0xce, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, + 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x4b, 0x66, 0x61, 0x72, 0x2d, 0x6e, + 0x65, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x4e, + 0x65, 0x74, 0x61, 0x6e, 0x69, 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x03, 0x41, 0x52, 0x4d, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03, 0x49, + 0x4f, 0x54, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x09, 0x01, 0x16, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x30, 0x31, 0x40, 0x61, 0x72, 0x6d, + 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x33, 0x30, 0x31, 0x31, 0x37, + 0x34, 0x33, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x38, 0x32, 0x32, 0x31, 0x37, 0x34, + 0x33, 0x35, 0x33, 0x5a, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x4b, + 0x66, 0x61, 0x72, 0x2d, 0x6e, 0x65, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x07, 0x4e, 0x65, 0x74, 0x61, 0x6e, 0x69, 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x03, 0x41, 0x52, 0x4d, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x03, 0x49, 0x4f, 0x54, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x30, + 0x31, 0x40, 0x61, 0x72, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, + 0x03, 0x42, 0x00, 0x04, 0x24, 0xb5, 0x1b, 0xaf, 0x82, 0xd6, 0xc6, 0xc4, 0x66, 0xba, 0xe7, 0xdf, + 0x41, 0xd2, 0x03, 0xdb, 0xbf, 0x49, 0xf0, 0x99, 0x66, 0xf1, 0xe1, 0x15, 0x37, 0x94, 0x66, 0x2b, + 0x22, 0x4c, 0x8e, 0xc6, 0xd4, 0x5e, 0x6f, 0x1a, 0xdb, 0x44, 0xe5, 0x06, 0xd8, 0x34, 0xad, 0xf2, + 0x1e, 0x92, 0x23, 0xd8, 0xd4, 0xd2, 0x01, 0x6a, 0x6e, 0x3c, 0x09, 0x7b, 0x5b, 0xff, 0x0e, 0x6f, + 0xb4, 0x28, 0xe6, 0x28, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, + 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xae, 0xaf, 0x9e, 0xfb, 0xea, 0x53, 0xe7, 0xe3, + 0xd5, 0xe0, 0x90, 0x87, 0x15, 0xaf, 0x48, 0x9f, 0x50, 0x2c, 0x44, 0x4d, 0x2a, 0x68, 0x38, 0xa0, + 0x3c, 0x09, 0xbc, 0x32, 0xb8, 0x78, 0xcf, 0xfa, 0x02, 0x20, 0x0c, 0x0d, 0xc8, 0xda, 0xcd, 0x09, + 0x7a, 0xa9, 0x6d, 0x18, 0x6c, 0xc1, 0x58, 0x1a, 0xec, 0x9a, 0x8b, 0x0d, 0x8a, 0xc4, 0xea, 0x9d, + 0x49, 0x5f, 0xa1, 0x9e, 0xcc, 0xcf, 0xbe, 0xb5, 0x25, 0xfd +}; + +const unsigned char x509_verify_cert[] = +{ + 0x30, 0x82, 0x01, 0xf2, 0x30, 0x82, 0x01, 0x98, 0x02, 0x01, 0x03, 0x30, 0x0a, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0a, 0x4b, 0x66, 0x61, 0x72, 0x2d, 0x6e, 0x65, 0x74, 0x65, 0x72, 0x31, 0x10, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x4e, 0x65, 0x74, 0x61, 0x6e, 0x69, 0x61, 0x31, 0x0c, + 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x03, 0x41, 0x52, 0x4d, 0x31, 0x0c, 0x30, 0x0a, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03, 0x49, 0x4f, 0x54, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x30, 0x31, 0x40, 0x61, 0x72, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x37, 0x30, 0x33, 0x30, 0x31, 0x31, 0x37, 0x34, 0x33, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x31, + 0x37, 0x30, 0x33, 0x33, 0x31, 0x31, 0x37, 0x34, 0x33, 0x35, 0x33, 0x5a, 0x30, 0x81, 0x86, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x4b, 0x66, 0x61, 0x72, 0x2d, 0x6e, 0x65, 0x74, 0x65, + 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x4e, 0x65, 0x74, 0x61, + 0x6e, 0x69, 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x03, 0x41, 0x52, + 0x4d, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03, 0x49, 0x4f, 0x54, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x09, 0x01, 0x16, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x30, 0x31, 0x40, 0x61, 0x72, + 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, + 0x6b, 0x28, 0x07, 0xf4, 0x9a, 0xf7, 0x19, 0x2b, 0x3f, 0x6a, 0xf4, 0xa1, 0xcb, 0x5f, 0x21, 0x18, + 0x46, 0xef, 0xcf, 0x9c, 0xbd, 0x31, 0x89, 0xac, 0x9c, 0xb6, 0xe4, 0x2c, 0xb9, 0x81, 0xae, 0x6d, + 0xb6, 0x57, 0x88, 0x18, 0xde, 0x06, 0x12, 0xe4, 0xfe, 0x63, 0xea, 0x13, 0x8b, 0xf7, 0x76, 0xe3, + 0x97, 0xc9, 0xbd, 0x47, 0xbf, 0x50, 0x92, 0xba, 0x1e, 0x3e, 0x3b, 0x8d, 0x6e, 0x8f, 0x86, 0xfd, + 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, + 0x45, 0x02, 0x20, 0x30, 0xc2, 0xd4, 0xbd, 0xa9, 0x5d, 0xe1, 0xd0, 0xc5, 0xcb, 0xb5, 0xb3, 0x31, + 0x8a, 0xad, 0x7a, 0xab, 0xc7, 0x85, 0xf2, 0x1a, 0x0a, 0x4f, 0xd1, 0x63, 0x33, 0x05, 0x20, 0x1f, + 0xb4, 0xd6, 0x6e, 0x02, 0x21, 0x00, 0x8c, 0xcd, 0x36, 0x73, 0x9c, 0xb7, 0xc2, 0xee, 0xf3, 0x0a, + 0xbf, 0x4f, 0xd3, 0x95, 0x08, 0xa6, 0xcd, 0xdd, 0x5b, 0x78, 0x8f, 0x83, 0x90, 0xef, 0x2a, 0x8a, + 0x27, 0x0d, 0x73, 0x0b, 0xa0, 0xfa +}; + +typedef struct palX509VertifyTestVector +{ + const unsigned char* ca; + size_t ca_size; + const unsigned char* crt; + size_t crt_size; + palStatus_t result; +}palX509VertifyTestVector_t; + +#ifdef PAL_CERT_TIME_VERIFY +#define PAL_CRYPTO_TEST_CERT_TIME_OFFSET 10000 + +static const palX509VertifyTestVector_t x509_verify_data[4] = +{ + { x509_selfsign, sizeof(x509_selfsign), x509_selfsign, sizeof(x509_selfsign), 0 }, + { NULL, 0, x509_selfsign, sizeof(x509_selfsign), PAL_ERR_X509_BADCERT_NOT_TRUSTED }, + { x509_verify_ca, sizeof(x509_verify_ca), x509_verify_cert, sizeof(x509_verify_cert), PAL_ERR_X509_BADCERT_FUTURE }, + { x509_verify_cert, sizeof(x509_verify_cert), x509_verify_ca, sizeof(x509_verify_ca), PAL_ERR_X509_BADCERT_EXPIRED }, +}; + +#else + +static const palX509VertifyTestVector_t x509_verify_data[4] = +{ + { x509_selfsign, sizeof(x509_selfsign), x509_selfsign, sizeof(x509_selfsign), 0 }, + { NULL, 0, x509_selfsign, sizeof(x509_selfsign), PAL_ERR_X509_BADCERT_NOT_TRUSTED }, + { x509_verify_ca, sizeof(x509_verify_ca), x509_verify_cert, sizeof(x509_verify_cert), 0 }, + { x509_verify_cert, sizeof(x509_verify_cert), x509_verify_ca, sizeof(x509_verify_ca), PAL_ERR_X509_BADCERT_NOT_TRUSTED } +}; + + +#endif //PAL_CERT_TIME_VERIFY + +typedef struct palMdHMACTestVector +{ + const unsigned char key[131]; + const unsigned char input[152]; + unsigned char output[32]; + size_t keyLen; + size_t inputLen; + size_t outputLen; +} palMdHMACTestVector_t; + +const palMdHMACTestVector_t mdHMACVector[7] = +{ + { + { + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b + }, + { + 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 + }, + { + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, + 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7 + }, 20, 8, 32 + }, + { + { + 0x4a, 0x65, 0x66, 0x65 + }, + { + 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x3f + }, + { + 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, + 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 + }, 4, 28, 32 + }, + { + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa + }, + { + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd + }, + { + 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, + 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe + }, 20, 50, 32 + }, + { + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 + }, + { + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd + }, + { + 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, + 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b + }, 25, 50, 32 + }, + { + { + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c + }, + { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x57, 0x69, 0x74, 0x68, 0x20, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e + }, + { + 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0, 0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b + }, 20, 20, 16 + }, + { + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa + }, + + { + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 + }, + + { + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, + 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54 + }, 131, 54, 32 + }, + { + { + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa + }, + { + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e + }, + { + 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, + 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2 + }, 131, 152, 32 + } +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Crypto/pal_crypto_test_runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Crypto/pal_crypto_test_runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "unity.h" +#include "unity_fixture.h" + + +// PAL Socket API tests +TEST_GROUP_RUNNER(pal_crypto) +{ + // AES cryptography + RUN_TEST_CASE(pal_crypto, AES_CTR); + RUN_TEST_CASE(pal_crypto, AES_ECB); + RUN_TEST_CASE(pal_crypto, AES_CCM); + + //Hashing using SHA256 + RUN_TEST_CASE(pal_crypto, SHA256); + RUN_TEST_CASE(pal_crypto, md); + + //Random Number Generation + RUN_TEST_CASE(pal_crypto, CTR_DRBG); + + //CMAC + RUN_TEST_CASE(pal_crypto, CMAC_one_shot); + RUN_TEST_CASE(pal_crypto, CMAC_Iterative); + + //MD HMAC SHA256 + RUN_TEST_CASE(pal_crypto, HMAC_SHA256_one_shot); + + //Certificate + RUN_TEST_CASE(pal_crypto, ASN1); + RUN_TEST_CASE(pal_crypto, X509_Parse); + RUN_TEST_CASE(pal_crypto, X509_ReadAttributes); + RUN_TEST_CASE(pal_crypto, X509_Verify); + + //Elliptic Curves + RUN_TEST_CASE(pal_crypto, ECKey_checkKey); + RUN_TEST_CASE(pal_crypto, ECKey_parseKey); +#if 0 + //Not required for R1.2 + RUN_TEST_CASE(pal_crypto, CSR); +#endif //0 +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/FileSystem/pal_fileSystem_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/FileSystem/pal_fileSystem_test.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1273 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "unity.h" +#include "unity_fixture.h" + + +#define TEST_DIR "dir1" +#define TEST_DIR2 "dir2" +#define TEST_WORKING_DIR "work1" +#define TEST_DIR_FILE "dir1/test.txt" +#define TEST_NUMBER_OF_FILE_TO_CREATE 20 +#define TEST_BUFFER_SIZE 100 +#define TEST_BUFFER_SMALL_SIZE 17 +//#define TEST_BYTES_TO_WRITE 300*4 +#define TEST_BYTES_TO_WRITE 100 +#define TEST_FILE_NAME "%s/test_f%d" +#define BUFFER_TEST_SIZE 1123 + +#if (false == PAL_PRIMARY_PARTITION_PRIVATE) + #define PAL_TEST_PRIMARY_PATH "/pri" +#else + #define PAL_TEST_PRIMARY_PATH "" +#endif + +#if (false == PAL_SECONDARY_PARTITION_PRIVATE) + #define PAL_TEST_SECONDARY_PATH "/sec" +#else + #define PAL_TEST_SECONDARY_PATH "" +#endif + +//out should in length be PAL_MAX_FILE_AND_FOLDER_LENGTH +static char* addRootToPath(const char* in, char* out,pal_fsStorageID_t id) +{ + char root[PAL_MAX_FILE_AND_FOLDER_LENGTH] = { 0 }; + size_t len = 0; + palStatus_t status; + + memset(out,0,PAL_MAX_FILE_AND_FOLDER_LENGTH); + status = pal_fsGetMountPoint(id, PAL_MAX_FILE_AND_FOLDER_LENGTH, root); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + strncat(out, root, PAL_MAX_FILE_AND_FOLDER_LENGTH-1); //-1 for null terminator space + len = strlen(out); + if (PAL_FS_PARTITION_PRIMARY == id) + { + strncat(out, PAL_TEST_PRIMARY_PATH, PAL_MAX_FILE_AND_FOLDER_LENGTH - len); + } + else + { + strncat(out, PAL_TEST_SECONDARY_PATH, PAL_MAX_FILE_AND_FOLDER_LENGTH - len); + } + len = strlen(out); + if (*in != '\0') + { + strncat(out,"/",PAL_MAX_FILE_AND_FOLDER_LENGTH - len); + strncat(out,in,PAL_MAX_FILE_AND_FOLDER_LENGTH -len -1); + } + return(out); +} + + + +PAL_PRIVATE uint8_t *bufferTest = NULL; +PAL_PRIVATE uint8_t *bufferTest2 = NULL; + +PAL_PRIVATE palFileDescriptor_t g_fd1 = 0; +PAL_PRIVATE palFileDescriptor_t g_fd2 = 0; + +PAL_PRIVATE palStatus_t pal_fsClearAndInitialyze(pal_fsStorageID_t id) +{ + palStatus_t status = PAL_SUCCESS; + + if (pal_fsIsPrivatePartition(id)) + { + status = pal_fsFormat(id); + } + else + { + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + status = pal_fsRmFiles(addRootToPath("",buffer,id)); + } + return(status); +} + +/*! \brief This function compare two files +* +* @param[in] *pathCmp1 - pointer to the null-terminated string that specifies the first filename to be compare +* @param[in] *pathCmp2 - pointer to the null-terminated string that specifies the second filename to be compare +* +* \return PAL_SUCCESS upon successful operation.\n +* +*/ +PAL_PRIVATE palStatus_t fileSystemCompareUtil(const char * pathCmp1, const char * pathCmp2) +{ + palStatus_t status = PAL_SUCCESS; + + char bufferCmp1[TEST_BUFFER_SIZE]; + char bufferCmp2[TEST_BUFFER_SIZE]; + size_t numOfBytesCmp1 = 0; + size_t numOfBytesCmp2 = 0; + palFileDescriptor_t fdCmp1 = 0; + palFileDescriptor_t fdCmp2 = 0; + + status = pal_fsFopen(pathCmp1, PAL_FS_FLAG_READONLY, &fdCmp1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + status = pal_fsFopen(pathCmp2, PAL_FS_FLAG_READONLY, &fdCmp2); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + while(true) + { + + status = pal_fsFread(&fdCmp1, bufferCmp1, TEST_BUFFER_SIZE, &numOfBytesCmp1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + status = pal_fsFread(&fdCmp2, bufferCmp2, TEST_BUFFER_SIZE, &numOfBytesCmp2); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + if ((numOfBytesCmp2 == 0) && (numOfBytesCmp1 == 0)) + {//End of file reached + break; + } + + TEST_ASSERT_EQUAL(numOfBytesCmp1, numOfBytesCmp2); + TEST_ASSERT_EQUAL_MEMORY(bufferCmp1, bufferCmp2, numOfBytesCmp1); + } + + status = pal_fsFclose(&fdCmp1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + status = pal_fsFclose(&fdCmp2); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + return status; +} + +TEST_GROUP(pal_fileSystem); + +TEST_SETUP(pal_fileSystem) +{ + + pal_init(); + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + + pal_fsRmFiles(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_PRIMARY));//Remove all files in the testing DIRECTORY + pal_fsRmDir(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_PRIMARY)); //Delete Directory if exist + pal_fsRmFiles(addRootToPath(TEST_WORKING_DIR,buffer,PAL_FS_PARTITION_PRIMARY));//Remove all files in the testing DIRECTORY + pal_fsRmDir(addRootToPath(TEST_WORKING_DIR,buffer,PAL_FS_PARTITION_PRIMARY)); //Delete Directory if exist + pal_fsRmFiles(addRootToPath(TEST_DIR2,buffer,PAL_FS_PARTITION_PRIMARY));//Remove all files in the testing DIRECTORY + pal_fsRmDir(addRootToPath(TEST_DIR2,buffer,PAL_FS_PARTITION_PRIMARY)); //Delete Directory if exist + + + pal_fsRmFiles(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_SECONDARY));//Remove all files in the testing DIRECTORY + pal_fsRmDir(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_SECONDARY)); //Delete Directory if exist + pal_fsRmFiles(addRootToPath(TEST_WORKING_DIR,buffer,PAL_FS_PARTITION_SECONDARY));//Remove all files in the testing DIRECTORY + pal_fsRmDir(addRootToPath(TEST_WORKING_DIR,buffer,PAL_FS_PARTITION_SECONDARY)); //Delete Directory if exist + pal_fsRmFiles(addRootToPath(TEST_DIR2,buffer,PAL_FS_PARTITION_SECONDARY));//Remove all files in the testing DIRECTORY + pal_fsRmDir(addRootToPath(TEST_DIR2,buffer,PAL_FS_PARTITION_SECONDARY)); //Delete Directory if exist + + g_fd1 = 0; + g_fd2 = 0; + bufferTest = NULL; + bufferTest2 = NULL; + if(!pal_fsIsPrivatePartition(PAL_FS_PARTITION_PRIMARY)) + { + + addRootToPath("",buffer,PAL_FS_PARTITION_PRIMARY); + pal_fsMkDir(buffer); + } + if(!pal_fsIsPrivatePartition(PAL_FS_PARTITION_SECONDARY)) + { + addRootToPath("",buffer,PAL_FS_PARTITION_SECONDARY); + pal_fsMkDir(buffer); + } +} + +TEST_TEAR_DOWN(pal_fileSystem) +{ + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + pal_fsFclose(&g_fd1); + pal_fsFclose(&g_fd2); + g_fd1 = 0; + g_fd2 = 0; + + if (bufferTest != NULL) + { + free(bufferTest); + bufferTest = NULL; + } + if (bufferTest2 != NULL) + { + free(bufferTest2); + bufferTest2 = NULL; + } + + pal_fsClearAndInitialyze(PAL_FS_PARTITION_PRIMARY); + pal_fsClearAndInitialyze(PAL_FS_PARTITION_SECONDARY); + + if(!pal_fsIsPrivatePartition(PAL_FS_PARTITION_PRIMARY)) + { + + addRootToPath("",buffer,PAL_FS_PARTITION_PRIMARY); + pal_fsRmDir(buffer); + } + if(!pal_fsIsPrivatePartition(PAL_FS_PARTITION_SECONDARY)) + { + addRootToPath("",buffer,PAL_FS_PARTITION_SECONDARY); + pal_fsRmDir(buffer); + } + pal_destroy(); + +} + +/*! \brief /b SDFormat function tests formatting an SD card. +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | create TEST_DIR with pal_fsMkDir | PAL_SUCCESS | +* | 2 | create TEST_DIR_FILE file with pal_fsOpen | PAL_SUCCESS | +* | 3 | close file TEST_DIR_FILE with pal_fsClose | PAL_SUCCESS | +* | 4 | Format SD card with pal_FormatSDPartition | PAL_SUCCESS | +* | 5 | TEST_DIR_FILE should not exist after format | PAL_ERR_FS_NO_FILE | +* | 6 | create TEST_DIR with pal_fsMkDir | PAL_SUCCESS | +*/ +void SDFormat_1Partition() +{ + palStatus_t status = PAL_SUCCESS; + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + + /*#1*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_PRIMARY)); //Create Directory + if (PAL_SUCCESS == status) + { + /*#2*/ + status = pal_fsFopen(addRootToPath(TEST_DIR_FILE,buffer,PAL_FS_PARTITION_PRIMARY), PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + + + /*#4*/ + status = pal_fsClearAndInitialyze(PAL_FS_PARTITION_PRIMARY); //Format SD + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + /*#5*/ + status = pal_fsFopen(addRootToPath(TEST_DIR_FILE,buffer,PAL_FS_PARTITION_PRIMARY), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL(PAL_ERR_FS_NO_FILE, status); //Failed all files where deleted in previous step + + status = pal_fsClearAndInitialyze(PAL_FS_PARTITION_SECONDARY); //Format SD + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + + /*#6*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_PRIMARY)); //Create Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +} + +/*! \brief /b SDFormat function tests formatting an SD card. +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | create TEST_DIR with pal_fsMkDir primary partition | PAL_SUCCESS | +* | 2 | create TEST_DIR_FILE file with pal_fsOpen primary partition | PAL_SUCCESS | +* | 3 | close file TEST_DIR_FILE with pal_fsClose | PAL_SUCCESS | +* | 4 | create TEST_DIR with pal_fsMkDir secondary partition | PAL_SUCCESS | +* | 5 | create TEST_DIR_FILE file with pal_fsOpen secondary partition | PAL_SUCCESS | +* | 6 | close file TEST_DIR_FILE with pal_fsClose | PAL_SUCCESS | +* | 7 | Format SD card primary partition with pal_FormatSDPartition | PAL_SUCCESS | +* | 8 | TEST_DIR_FILE in primary should not exist after format | PAL_ERR_FS_NO_FILE | +* | 9 | TEST_DIR_FILE in secondary should exist after format | PAL_SUCCESS | +* | 10| Format SD card secondary partition with pal_FormatSDPartition | PAL_SUCCESS | +* | 11| TEST_DIR_FILE in secondary should not exist after format | PAL_ERR_FS_NO_FILE | +* | 12| create TEST_DIR with pal_fsMkDir in primary partition | PAL_SUCCESS | +* | 13| create TEST_DIR with pal_fsMkDir in secondary partition | PAL_SUCCESS | +*/ +void SDFormat_2Partition() +{ + palStatus_t status = PAL_SUCCESS; + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + + /*#1*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_PRIMARY)); //Create Directory + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_fsFopen(addRootToPath(TEST_DIR_FILE,buffer,PAL_FS_PARTITION_PRIMARY), PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#4*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_SECONDARY)); //Create Directory + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#5*/ + status = pal_fsFopen(addRootToPath(TEST_DIR_FILE,buffer,PAL_FS_PARTITION_SECONDARY), PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#6*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + + /*#7*/ + status = pal_fsClearAndInitialyze(PAL_FS_PARTITION_PRIMARY); //Format SD + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#8*/ + status = pal_fsFopen(addRootToPath(TEST_DIR_FILE,buffer,PAL_FS_PARTITION_PRIMARY), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_FS_NO_FILE, status); //Failed all files where deleted in previous step + + /*#9*/ + status = pal_fsFopen(addRootToPath(TEST_DIR_FILE,buffer,PAL_FS_PARTITION_SECONDARY), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); //the file still exists in secondary + + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#10*/ + status = pal_fsClearAndInitialyze(PAL_FS_PARTITION_SECONDARY); //Format SD + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#11*/ + status = pal_fsFopen(addRootToPath(TEST_DIR_FILE,buffer,PAL_FS_PARTITION_SECONDARY), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_FS_NO_FILE, status); //Failed all files where deleted in previous step + + /*#12*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_PRIMARY)); //Create Directory + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#13*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,PAL_FS_PARTITION_SECONDARY)); //Create Directory + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + + + +TEST(pal_fileSystem, SDFormat) +{ + SDFormat_2Partition(); + SDFormat_1Partition(); +} + + +/*! \brief /b directoryTests function Tests root Directory commands +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | get root directory with pal_fsGetMountPoint | PAL_SUCCESS | +* | 2 | create TEST_WORKING_DIR with pal_fsMkDir | PAL_SUCCESS | +* | 3 | Change Root Directory to TEST_WORKING_DIR with pal_fsSetMountPoint | PAL_SUCCESS | +* | 4 | create TEST_WORKING_DIR with pal_fsMkDir | PAL_ERR_FS_NAME_ALREADY_EXIST | +* | 5 | get root directory with pal_fsGetMountPoint | PAL_SUCCESS | +*/ +void rootDirectoryTests(pal_fsStorageID_t storageId) +{ + palStatus_t status = PAL_SUCCESS; + char getRootPath[TEST_BUFFER_SIZE] = { 0 }; + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; +/*#1*/ + status = pal_fsGetMountPoint(storageId, TEST_BUFFER_SIZE, getRootPath); //Setting New working Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#2*/ + status = pal_fsMkDir(addRootToPath(TEST_WORKING_DIR,buffer,storageId)); //Create Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#3*/ + status = pal_fsSetMountPoint(storageId, addRootToPath(TEST_WORKING_DIR,buffer,storageId)); //Setting New working Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#4*/ + status = pal_fsMkDir(getRootPath); //should fail because already exits and path is absolute + TEST_ASSERT_EQUAL(PAL_ERR_FS_NAME_ALREADY_EXIST, status); + +/*#5*/ + status = pal_fsGetMountPoint(storageId, TEST_BUFFER_SIZE, getRootPath); //Setting New working Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +} + + +TEST(pal_fileSystem, rootDirectoryTests) +{ + + rootDirectoryTests(PAL_FS_PARTITION_PRIMARY); + +} + + +/*! \brief /b directoryTests function Tests Directory commands +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | create TEST_DIR with pal_fsMkDir | PAL_SUCCESS | +* | 2 | create TEST_DIR with pal_fsMkDir | PAL_ERR_FS_NAME_ALREADY_EXIST | +* | 3 | Create File TEST_DIR_FILE With PAL_ERR_FS_READWRITEEXCLUSIVE with pal_fsFopen | PAL_SUCCESS | +* | 4 | Create File TEST_DIR_FILE With PAL_ERR_FS_READWRITEEXCLUSIVE with pal_fsFopen | PAL_ERR_FS_NAME_ALREADY_EXIST | +* | 5 | Close file with uninitialized file descriptor | PAL_ERR_FS_BAD_FD | +* | 6 | Close file with initialized file descriptor | PAL_SUCCESS | +* | 7 | Delete directory with pal_fsRmDir (directory not empty) | PAL_ERR_FS_ERROR | +* | 8 | Delete file TEST_DIR_FILE with pal_fsUnlink | PAL_SUCCESS | +* | 9 | Delete file TEST_DIR_FILE with pal_fsUnlink | PAL_SUCCESS | +* | 10 | Delete a folder which not exists with pal_fsUnlink | PAL_ERR_FS_NO_PATH | +* +*/ +void directoryTests(pal_fsStorageID_t storageId) +{ + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + char *pathToFile = NULL; + palStatus_t status = PAL_SUCCESS; + +/*#1*/ + pathToFile = addRootToPath(TEST_DIR,buffer,storageId); + status = pal_fsMkDir(pathToFile); //Create Directory + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + +/*#2*/ + pathToFile = addRootToPath(TEST_DIR,buffer,storageId); + status = pal_fsMkDir(pathToFile); //Create same Directory Shall failed + TEST_ASSERT_EQUAL_HEX(PAL_ERR_FS_NAME_ALREADY_EXIST, status); + +/*#3*/ + pathToFile = addRootToPath(TEST_DIR_FILE,buffer,storageId); + status = pal_fsFopen(pathToFile, PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + +/*#4*/ + pathToFile = addRootToPath(TEST_DIR_FILE,buffer,storageId); + status = pal_fsFopen(pathToFile, PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd2); // Failed open Exclusively and file already created + TEST_ASSERT_EQUAL_HEX(PAL_ERR_FS_NAME_ALREADY_EXIST, status); + +/*#5*/ + pal_fsFclose(&g_fd2);//Failed fd1 was not a valid File descriptor + //TEST_ASSERT_EQUAL(PAL_ERR_FS_BAD_FD, status); //TODO Pass on mbedOS + +/*#6*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + +/*#7*/ + pathToFile = addRootToPath(TEST_DIR,buffer,storageId); + status = pal_fsRmDir(pathToFile); //Delete Directory Failed Directory not empty + TEST_ASSERT_EQUAL_HEX(PAL_ERR_FS_DIR_NOT_EMPTY, status); + +/*#8*/ + pathToFile = addRootToPath(TEST_DIR_FILE,buffer,storageId); + status = pal_fsUnlink(pathToFile); //Delete the file in a directory + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + +/*#9*/ + pathToFile = addRootToPath(TEST_DIR,buffer,storageId); + status = pal_fsRmDir(pathToFile); //Delete Directory success + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + +/*#10*/ + pathToFile = addRootToPath(TEST_DIR,buffer,storageId); + status = pal_fsRmDir(pathToFile); //Delete not existing Directory + TEST_ASSERT_EQUAL_HEX(PAL_ERR_FS_NO_PATH, status); +} + +TEST(pal_fileSystem, directoryTests) +{ + directoryTests(PAL_FS_PARTITION_PRIMARY); + directoryTests(PAL_FS_PARTITION_SECONDARY); +} + +/*! \brief /b FilesTests function Tests files commands +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Init Test | | +* | 2 | create TEST_DIR with pal_fsMkDir | PAL_SUCCESS | +* | 3 | create TEST_DIR2 with pal_fsMkDir | PAL_SUCCESS | +* | 4 | Start Loop i from [0 - TEST_NUMBER_OF_FILE_TO_CREATE] | | +* | 5 | Create File in DIR_FILE named f_i (i - index of loop)with PAL_ERR_FS_READWRITEEXCLUSIVE mode using pal_fsFopen | PAL_SUCCESS | +* | 6 | Write random buffer[TEST_BYTES_TO_WRITE] to file with pal_fsFwrite | PAL_SUCCESS | +* | 7 | close file handler with pal_fsFclose | PAL_SUCCESS | +* | 8 | End Loop | | +* | 9 | Copy TEST_DIR folder to TEST_DIR2 with pal_fsCpFolder | PAL_SUCCESS | +* | 10 | Compare Folders | | +* | 11 | remove all files from TEST_DIR2 | PAL_SUCCESS | +* | 12 | remove all files from TEST_DIR | PAL_SUCCESS | +* | 13 | Start Loop i from [0 - TEST_NUMBER_OF_FILE_TO_CREATE] | | +* | 14 | open Files in DIR_FILE named f_i (i - index of loop) with PAL_ERR_FS_READONLY mode using pal_fsFopen | PAL_ERR_FS_NO_FILE | +* | 15 | open Files in DIR_FILE named f_i (i - index of loop) with PAL_ERR_FS_READWRITE mode using pal_fsFopen | PAL_ERR_FS_NO_FILE | +* | 16 | open Files in DIR_FILE2 named f_i (i - index of loop) with PAL_ERR_FS_READONLY mode using pal_fsFopen | PAL_ERR_FS_NO_FILE | +* | 17 | open Files in DIR_FILE2 named f_i (i - index of loop) with PAL_ERR_FS_READWRITE mode using pal_fsFopen | PAL_ERR_FS_NO_FILE | +* | 18 | remove TEST_DIR with pal_fsRmDir | PAL_SUCCESS | +* | 19 | remove TEST_DIR2 with pal_fsRmDir | PAL_SUCCESS | +* | 20 | try to remove a file that does not exist | PAL_ERR_FS_NO_FILE | +* | 21 | try to remove a a variety of files that does not exist | PAL_ERR_FS_NO_PATH | +* | 22 | try to copy a non existing folder | PAL_ERR_FS_NO_PATH | +* +*/ +void FilesTests(pal_fsStorageID_t storageId) +{ + palStatus_t status = PAL_SUCCESS; + char rootPathBuffer1[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + char rootPathBuffer2[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + char buffer1[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + char buffer2[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + int i = 0; + size_t numOfBytes; +/*#1*/ + //---------------- INIT TESTS----------------------------// + memset(rootPathBuffer1, '1', PAL_MAX_FILE_AND_FOLDER_LENGTH); + memset(rootPathBuffer2, '1', PAL_MAX_FILE_AND_FOLDER_LENGTH); + //----------------END INIT TESTS-------------------------// + +/*#2*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,rootPathBuffer1,storageId)); //Create Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#3*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR2,rootPathBuffer2,storageId)); //Create Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#4*/ + for(i = 0; i < TEST_NUMBER_OF_FILE_TO_CREATE; i++) + { +/*#5*/ + snprintf(rootPathBuffer1, PAL_MAX_FILE_AND_FOLDER_LENGTH, TEST_FILE_NAME, TEST_DIR, i); + status = pal_fsFopen(addRootToPath(rootPathBuffer1,buffer1,storageId), PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#6*/ + status = pal_fsFwrite(&g_fd1, (void *)rootPathBuffer1, TEST_BYTES_TO_WRITE, &numOfBytes); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#7*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); +/*#8*/ + } + +/*#9*/ + status = pal_fsCpFolder(addRootToPath(TEST_DIR,rootPathBuffer1,storageId), addRootToPath(TEST_DIR2,rootPathBuffer2,storageId));//Copy all files from TEST_DIR to TEST_DIR2 + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); +/*#10*/ + for(i = 0; i < TEST_NUMBER_OF_FILE_TO_CREATE; i++) + { + snprintf(rootPathBuffer1, PAL_MAX_FILE_AND_FOLDER_LENGTH, TEST_FILE_NAME, TEST_DIR, i); + snprintf(rootPathBuffer2, PAL_MAX_FILE_AND_FOLDER_LENGTH, TEST_FILE_NAME, TEST_DIR2, i); + + fileSystemCompareUtil(addRootToPath(rootPathBuffer1,buffer1,storageId), addRootToPath(rootPathBuffer2,buffer2,storageId)); + } + +/*#11*/ + status = pal_fsRmFiles(addRootToPath(TEST_DIR2,rootPathBuffer2,storageId));//Remove all files in the testing DIRECTORY + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#12*/ + status = pal_fsRmFiles(addRootToPath(TEST_DIR,rootPathBuffer1,storageId));//Remove all files in the testing DIRECTORY + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#13*/ + for(i = 0; i < TEST_NUMBER_OF_FILE_TO_CREATE; i++) + { +/*#14*/ + snprintf(buffer1, PAL_MAX_FILE_AND_FOLDER_LENGTH, TEST_FILE_NAME, TEST_DIR, i); + status = pal_fsFopen(addRootToPath(buffer1,rootPathBuffer1,storageId), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL(PAL_ERR_FS_NO_FILE, status); //Failed all files where deleted in previous step + +/*#15*/ + status = pal_fsFopen(addRootToPath(buffer1,rootPathBuffer1,storageId), PAL_FS_FLAG_READWRITE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_ERR_FS_NO_FILE, status); //Failed all files where deleted in previous step + +/*#16*/ + snprintf(buffer2, PAL_MAX_FILE_AND_FOLDER_LENGTH, TEST_FILE_NAME, TEST_DIR2, i); + status = pal_fsFopen(addRootToPath(buffer2,rootPathBuffer2,storageId), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL(PAL_ERR_FS_NO_FILE, status); //Failed all files where deleted in previous step + +/*#17*/ + status = pal_fsFopen(addRootToPath(buffer1,rootPathBuffer1,storageId), PAL_FS_FLAG_READWRITE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_ERR_FS_NO_FILE, status); //Failed all files where deleted in previous step + + } + +/*#18*/ + status = pal_fsRmDir(addRootToPath(TEST_DIR,buffer1,storageId)); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#19*/ + status = pal_fsRmDir(addRootToPath(TEST_DIR2,buffer2,storageId)); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#20*/ + status = pal_fsUnlink(addRootToPath("aaaa.t",rootPathBuffer1, storageId));//not existing file + TEST_ASSERT_EQUAL(PAL_ERR_FS_NO_FILE, status); + +/*#21*/ + status = pal_fsRmFiles(addRootToPath("aaaaa",rootPathBuffer1, storageId));//Remove all file in not existing directory + TEST_ASSERT_EQUAL(PAL_ERR_FS_NO_PATH, status); + +/*#22*/ + + status = pal_fsCpFolder(addRootToPath("aaaaa", rootPathBuffer1, storageId), addRootToPath("bbbb" ,rootPathBuffer2,storageId)); //copy from not existing dir + TEST_ASSERT_EQUAL(PAL_ERR_FS_NO_PATH, status); +} + +TEST(pal_fileSystem, FilesTests) +{ + FilesTests(PAL_FS_PARTITION_PRIMARY); + FilesTests(PAL_FS_PARTITION_SECONDARY); +} + +/*! \brief /b FilesTestsSeek function Tests \b fseek() , \b fteel() & \b fread() function +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | create TEST_DIR with pal_fsMkDir | PAL_SUCCESS | +* | 2 | Create File TEST_DIR_FILE With PAL_ERR_FS_READWRITETRUNC with pal_fsFopen | PAL_SUCCESS | +* | 3 | Create buffer[TEST_BUFFER_SIZE] with incremental data, Buffer size TEST_BUFFER_SIZE | PAL_SUCCESS | +* | 4 | Write buffer to file with pal_fsFwrite | PAL_SUCCESS | +* | 5 | Start Loop i from [0 - TEST_BUFFER_SIZE] | | +* | 6 | run pal_fsFseek with PAL_FS_OFFSET_SEEKSET option and incremental offset i | PAL_SUCCESS | +* | 7 | run pal_fsFtell and compare offset to i | PAL_SUCCESS | +* | 8 | run pal_fsFread, read one byte and compare it to the buffer[i] | PAL_SUCCESS | +* | 9 | End Loop | | +* | 10 | Start Loop i from [0 - TEST_BUFFER_SIZE] | | +* | 11 | run pal_fsFseek with PAL_FS_OFFSET_SEEKEND option and incremental offset (-1)*i | PAL_SUCCESS | +* | 12 | run pal_fsFtell and compare offset to TEST_BUFFER_SIZE - i | PAL_SUCCESS | +* | 13 | End Loop | | +* | 14 | run pal_fsFseek with PAL_FS_OFFSET_SEEKSET option offset TEST_BUFFER_SIZE/2 | PAL_SUCCESS | +* | 15 | Start Loop i from [0 - TEST_BUFFER_SIZE/10] | | +* | 16 | run pal_fsFseek with PAL_FS_OFFSET_SEEKEND option and incremental offset i | PAL_SUCCESS | +* | 17 | run pal_fsFtell and compare offset to i | PAL_SUCCESS | +* | 18 | End Loop | | +* | 19 | Cleanup | PAL_SUCCESS | +* +*/ +void FilesTestsSeek(pal_fsStorageID_t storageId) +{ + palStatus_t status = PAL_SUCCESS; + char buffer[TEST_BUFFER_SIZE]; + int i = 0; + size_t numOfBytes; + int32_t pos = 0; + char read_buf = 1; + size_t prePos = 0; +/*#1*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,storageId)); //Create Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#2*/ + status = pal_fsFopen(addRootToPath(TEST_DIR_FILE,buffer,storageId), PAL_FS_FLAG_READWRITETRUNC, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#3*/ + for(i = 0; i < TEST_BUFFER_SIZE; i++) + { + buffer[i] = i; + } + +/*#4*/ + status = pal_fsFwrite(&g_fd1, (void *)buffer, TEST_BUFFER_SIZE, &numOfBytes); //Write incremental buffer for seek testing + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BUFFER_SIZE, numOfBytes); + +/*#5*/ + //Test Seek "PAL_FS_OFFSET_SEEKSET" + for(i = 0; i < TEST_BUFFER_SIZE; i++) + { + +/*#6*/ + status = pal_fsFseek(&g_fd1, i, PAL_FS_OFFSET_SEEKSET); //Set position to start of the stream + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#7*/ + status = pal_fsFtell(&g_fd1, &pos); //Check if position is in the start of the stream + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(i, pos); + +/*#8*/ + status = pal_fsFread(&g_fd1, &read_buf, 1, &numOfBytes); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(1, numOfBytes); + TEST_ASSERT_EQUAL(buffer[i], read_buf); + +/*#9*/ + } + +/*#10*/ + //Test Seek "PAL_FS_OFFSET_SEEKEND" + for(i = 0; i < TEST_BUFFER_SIZE; i++) + { +/*#11*/ + status = pal_fsFseek(&g_fd1, (-1)*i, PAL_FS_OFFSET_SEEKEND); //Set position to end of the stream + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#12*/ + status = pal_fsFtell(&g_fd1, &pos); //Get position + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BUFFER_SIZE - i, pos); + +/*#13*/ + } + +/*#14*/ + //Test Seek "PAL_ERR_FS_SEEKCUR" + status = pal_fsFseek(&g_fd1, TEST_BUFFER_SIZE/2, PAL_FS_OFFSET_SEEKSET); //Set position to middle of the stream + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + prePos = TEST_BUFFER_SIZE/2; + +/*#15*/ + for(i = 0; i < TEST_BUFFER_SIZE/10 ; i++) + { + +/*#16*/ + status = pal_fsFseek(&g_fd1, i, PAL_FS_OFFSET_SEEKCUR); //Set position to start of the stream + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*17*/ + status = pal_fsFtell(&g_fd1, &pos); //Get position + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(prePos + i, pos); + prePos = pos; + +/*#18*/ + } + +/*#19*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); +} + + +TEST(pal_fileSystem, FilesTestsSeek) +{ + FilesTestsSeek(PAL_FS_PARTITION_PRIMARY); +#if (PAL_NUMBER_OF_PARTITIONS == 2) + FilesTestsSeek(PAL_FS_PARTITION_SECONDARY); +#endif +} + +/*! \brief /b FilesPermission function Tests \b fopen() with r +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Init Test | Success | +* | 2 | create TEST_DIR with pal_fsMkDir | PAL_SUCCESS | +* | 3 | create new file using fopen with PAL_FS_FLAG_READWRITEEXCLUSIVE | PAL_SUCCESS | +* | 4 | write buffer to file | PAL_SUCCESS | +* | 5 | close file | PAL_SUCCESS | +* | 6 | open file using fopen() with PAL_FS_FLAG_READONLY | PAL_SUCCESS | +* | 7 | write buffer to file with fwrite() | failed | +* | 8 | read buffer from file with fread() | PAL_SUCCESS | +* | 9 | close file | PAL_SUCCESS | +* | 10 | remove all files in folder | PAL_SUCCESS | +* | 11 | remove folder | PAL_SUCCESS | +*/ +void FilesPermission_read_only(pal_fsStorageID_t storageId) +{ + palStatus_t status = PAL_SUCCESS; + char readBuffer[TEST_BUFFER_SIZE]; + char readBuffer2[TEST_BUFFER_SIZE]; + char filename[TEST_BUFFER_SIZE]; + size_t numOfBytes = 0; + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + +/*#1*/ + //---------------- INIT TESTS----------------------------// + memset(readBuffer, '1', TEST_BUFFER_SIZE); + //----------------END INIT TESTS-------------------------// + +/*#2*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,storageId)); //Create Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + snprintf(filename, TEST_BUFFER_SIZE, TEST_FILE_NAME, TEST_DIR, 1); +/*#3*/ + status = pal_fsFopen(addRootToPath(filename,buffer,storageId), PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#4*/ + status = pal_fsFwrite(&g_fd1, (void *)readBuffer, TEST_BYTES_TO_WRITE, &numOfBytes); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BYTES_TO_WRITE, numOfBytes); + +/*#5*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#6*/ + status = pal_fsFopen(addRootToPath(filename,buffer,storageId), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#7*/ + pal_fsFwrite(&g_fd1, (void *)readBuffer, TEST_BYTES_TO_WRITE, &numOfBytes); + TEST_ASSERT_EQUAL(0, numOfBytes); + +/*#8*/ + status = pal_fsFread(&g_fd1, readBuffer2, TEST_BUFFER_SIZE, &numOfBytes); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BUFFER_SIZE, numOfBytes); + TEST_ASSERT_EQUAL_MEMORY(readBuffer, readBuffer2, TEST_BUFFER_SIZE); + +/*#9*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#10*/ + status = pal_fsRmFiles(addRootToPath(TEST_DIR,buffer,storageId));//Remove all files in the testing DIRECTORY + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#11*/ + status = pal_fsRmDir(addRootToPath(TEST_DIR,buffer,storageId)); //Delete Directory if exist + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); +} + +TEST(pal_fileSystem, FilesPermission_read_only) +{ + FilesPermission_read_only(PAL_FS_PARTITION_PRIMARY); + FilesPermission_read_only(PAL_FS_PARTITION_SECONDARY); +} + + +/*! \brief /b FilesPermission function Tests \b fopen() with r+ +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Init Test | Success | +* | 2 | create TEST_DIR with pal_fsMkDir | PAL_SUCCESS | +* | 3 | create new file using fopen with PAL_FS_FLAG_READWRITEEXCLUSIVE | PAL_SUCCESS | +* | 4 | write buffer to file | PAL_SUCCESS | +* | 5 | close file | PAL_SUCCESS | +* | 6 | open file using fopen() with PAL_FS_FLAG_READONLY | PAL_SUCCESS | +* | 7 | write buffer to file with fwrite() | PAL_SUCCESS | +* | 8 | seek to the begining of the file | PAL_SUCCESS | +* | 9 | read buffer from file with fread() | PAL_SUCCESS | +* | 10 | close file | PAL_SUCCESS | +* | 11 | remove all files in folder | PAL_SUCCESS | +* | 12 | remove folder | PAL_SUCCESS | +*/ +void FilesPermission_read_write(pal_fsStorageID_t storageId) +{ + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + palStatus_t status = PAL_SUCCESS; + char readBuffer[TEST_BUFFER_SIZE]; + char readBuffer2[TEST_BUFFER_SIZE]; + char filename[TEST_BUFFER_SIZE]; + size_t numOfBytes = 0; + +/*#1*/ + //---------------- INIT TESTS----------------------------// + memset(readBuffer, '1', TEST_BUFFER_SIZE); + //----------------END INIT TESTS-------------------------// + +/*#2*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,storageId)); //Create Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + snprintf(filename, TEST_BUFFER_SIZE, TEST_FILE_NAME, TEST_DIR, 1); +/*#3*/ + status = pal_fsFopen(addRootToPath(filename,buffer,storageId), PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#4*/ + status = pal_fsFwrite(&g_fd1, (void *)readBuffer, TEST_BYTES_TO_WRITE, &numOfBytes); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BYTES_TO_WRITE, numOfBytes); + +/*#5*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#6*/ + status = pal_fsFopen(addRootToPath(filename,buffer,storageId), PAL_FS_FLAG_READWRITE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#7*/ + status = pal_fsFwrite(&g_fd1, (void *)readBuffer, TEST_BYTES_TO_WRITE, &numOfBytes); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BYTES_TO_WRITE, numOfBytes); + +/*#8*/ + status = pal_fsFseek(&g_fd1, 0, PAL_FS_OFFSET_SEEKSET); //Set position to start of the stream + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#9*/ + status = pal_fsFread(&g_fd1, readBuffer2, TEST_BUFFER_SIZE, &numOfBytes); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BYTES_TO_WRITE, numOfBytes); + TEST_ASSERT_EQUAL_MEMORY(readBuffer, readBuffer2, TEST_BUFFER_SIZE); + +/*#10*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#11*/ + status = pal_fsRmFiles(addRootToPath(TEST_DIR,buffer,storageId));//Remove all files in the testing DIRECTORY + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#12*/ + status = pal_fsRmDir(addRootToPath(TEST_DIR,buffer,storageId)); //Delete Directory if exist + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); +} + + +TEST(pal_fileSystem, FilesPermission_read_write) +{ + FilesPermission_read_write(PAL_FS_PARTITION_PRIMARY); + FilesPermission_read_write(PAL_FS_PARTITION_SECONDARY); +} + + +/*! \brief /b FilesPermission function Tests \b fopen() with w+x +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Init Test | Success | +* | 2 | create TEST_DIR with pal_fsMkDir | PAL_SUCCESS | +* | 3 | create new file using fopen with PAL_FS_FLAG_READWRITEEXCLUSIVE | PAL_SUCCESS | +* | 4 | write buffer to file | PAL_SUCCESS | +* | 5 | close file | PAL_SUCCESS | +* | 6 | open file using fopen() withPAL_FS_FLAG_READWRITETRUNC | PAL_SUCCESS | +* | 7 | read buffer from file with fread() | PAL_SUCCESS with read length 0 | +* | 8 | close file | PAL_SUCCESS | +* | 9 | remove all files in folder | PAL_SUCCESS | +* | 10 | remove folder | PAL_SUCCESS | +*/ +void FilesPermission_read_write_trunc(pal_fsStorageID_t storageId) +{ + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + palStatus_t status = PAL_SUCCESS; + char readBuffer[TEST_BUFFER_SIZE]; + char filename[TEST_BUFFER_SIZE]; + size_t numOfBytes = 0; + +/*#1*/ + //---------------- INIT TESTS----------------------------// + memset(readBuffer, '1', TEST_BUFFER_SIZE); + //----------------END INIT TESTS-------------------------// + +/*#2*/ + status = pal_fsMkDir(addRootToPath(TEST_DIR,buffer,storageId)); //Create Directory + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + + snprintf(filename, TEST_BUFFER_SIZE, TEST_FILE_NAME, TEST_DIR, 1); +/*#3*/ + status = pal_fsFopen(addRootToPath(filename,buffer,storageId), PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#4*/ + status = pal_fsFwrite(&g_fd1, (void *)readBuffer, TEST_BYTES_TO_WRITE, &numOfBytes); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(TEST_BYTES_TO_WRITE, numOfBytes); + +/*#5*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#6*/ + status = pal_fsFopen(addRootToPath(filename,buffer,storageId), PAL_FS_FLAG_READWRITETRUNC, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#7*/ + status = pal_fsFread(&g_fd1, readBuffer, TEST_BUFFER_SIZE, &numOfBytes); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(0, numOfBytes); //nothing to read empty file + +/*#8*/ + status = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#9*/ + status = pal_fsRmFiles(addRootToPath(TEST_DIR,buffer,storageId));//Remove all files in the testing DIRECTORY + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); + +/*#10*/ + status = pal_fsRmDir(addRootToPath(TEST_DIR,buffer,storageId)); //Delete Directory if exist + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); +} + + +TEST(pal_fileSystem, FilesPermission_read_write_trunc) +{ + FilesPermission_read_write_trunc(PAL_FS_PARTITION_PRIMARY); + FilesPermission_read_write_trunc(PAL_FS_PARTITION_SECONDARY); +} + + +void create_write_and_read_pal_file(pal_fsStorageID_t storageId) +{ + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + char fileName[] = "fileName"; + palStatus_t res = PAL_SUCCESS; + size_t num_bytes_write = 0; + size_t num_bytes_read = 0; + + uint32_t i = 0; + + bufferTest = malloc(BUFFER_TEST_SIZE); + TEST_ASSERT_NOT_EQUAL(bufferTest, NULL); + bufferTest2 = malloc(BUFFER_TEST_SIZE); + TEST_ASSERT_NOT_EQUAL(bufferTest2, NULL); + memset(bufferTest, 0, BUFFER_TEST_SIZE); + memset(bufferTest2, 0, BUFFER_TEST_SIZE); + + for (i = 0; i < BUFFER_TEST_SIZE; i++){ + bufferTest[i] = (uint8_t)(i % 256); + } + + pal_fsUnlink(addRootToPath(fileName,buffer,storageId)); + + res = pal_fsFopen(addRootToPath(fileName,buffer,storageId), PAL_FS_FLAG_READWRITEEXCLUSIVE, &(g_fd1)); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFwrite(&(g_fd1), bufferTest, BUFFER_TEST_SIZE, &num_bytes_write); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(BUFFER_TEST_SIZE, num_bytes_write); + + res = pal_fsFclose(&(g_fd1)); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFopen(addRootToPath(fileName,buffer,storageId), PAL_FS_FLAG_READONLY, &(g_fd1)); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFread(&(g_fd1), bufferTest2, 223, &num_bytes_read); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(223, num_bytes_read); + + // split the reads + res = pal_fsFread(&(g_fd1), bufferTest2, 900, &num_bytes_read); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(900, num_bytes_read); + + + // Compare the buffers � here we have a mismatch in location buffer2[288] + TEST_ASSERT_EQUAL_INT8_ARRAY(&(bufferTest[223]), bufferTest2, 900); + + res = pal_fsFclose(&(g_fd1)); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsUnlink(addRootToPath(fileName,buffer,storageId)); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + free(bufferTest); + bufferTest = NULL; + free(bufferTest2); + bufferTest2 = NULL; + +} + + +TEST(pal_fileSystem, create_write_and_read_pal_file) +{ + create_write_and_read_pal_file(PAL_FS_PARTITION_PRIMARY); + create_write_and_read_pal_file(PAL_FS_PARTITION_SECONDARY); +} + +void WriteInTheMiddle(pal_fsStorageID_t storageId) +{ + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + char fileName[] = "fileName"; + const uint32_t inputSizeSmall = (TEST_BUFFER_SIZE * 6) + 1; + const uint32_t inputSizeBig = BUFFER_TEST_SIZE; + palStatus_t res = PAL_SUCCESS; + size_t num_bytes_write = 0; + size_t num_bytes_read = 0; + unsigned char *smallBuffer = NULL; + const size_t offset = 200; + uint32_t residue = inputSizeBig - (offset + inputSizeSmall); + + bufferTest = malloc(inputSizeBig); + TEST_ASSERT_NOT_EQUAL(bufferTest, NULL); + bufferTest2 = malloc(inputSizeBig); + TEST_ASSERT_NOT_EQUAL(bufferTest2, NULL); + smallBuffer = malloc(inputSizeSmall); + TEST_ASSERT_NOT_EQUAL(smallBuffer, NULL); + memset(bufferTest, 0, inputSizeBig); + memset(bufferTest2, 0, inputSizeBig); + memset(smallBuffer, 0, inputSizeSmall); + + // create 1123 bytes buffer filled with the numbers 0..255 + for (uint32_t i = 0; i < inputSizeBig; i++) + { + bufferTest[i] = (uint8_t)(i % 256); + } + + // create 601 bytes buffer filled with only 0xCC + for (uint32_t i = 0; i < inputSizeSmall; i++) + { + smallBuffer[i] = 0xCC; + } + + pal_fsUnlink(addRootToPath(fileName,buffer,storageId)); + TEST_ASSERT((PAL_SUCCESS == res) || (PAL_ERR_FS_NO_FILE == res)); + + /* 1. Write bufferTest data to file, read it and compare read content to bufferTest */ + res = pal_fsFopen(addRootToPath(fileName,buffer,storageId), PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFwrite(&g_fd1, bufferTest, inputSizeBig, &num_bytes_write); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(inputSizeBig, num_bytes_write); + + res = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFopen(addRootToPath(fileName,buffer,storageId), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFread(&g_fd1, bufferTest2, inputSizeBig, &num_bytes_read); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(inputSizeBig, num_bytes_read); + TEST_ASSERT_EQUAL_HEX8_ARRAY(bufferTest, bufferTest2, inputSizeBig); + + res = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + /* + 2. Write smallBuffer data to offset 201 of the file and then compare each fragment: + - offset 0..200 equal to bufferTest[0..200] + - offset 201..801 equal to smallBuffer + - offset 802..1122 equal to bufferTest[802..1122] + */ + res = pal_fsFopen(addRootToPath(fileName,buffer,storageId), PAL_FS_FLAG_READWRITE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFseek(&g_fd1, offset, PAL_FS_OFFSET_SEEKSET); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFwrite(&g_fd1, smallBuffer, inputSizeSmall, &num_bytes_write); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(inputSizeSmall, num_bytes_write); + + res = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFopen(addRootToPath(fileName,buffer,storageId), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + // offset 0..200 equal to bufferTest[0..200] + res = pal_fsFread(&g_fd1, bufferTest2, offset, &num_bytes_read); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(offset, num_bytes_read); + TEST_ASSERT_EQUAL_HEX8_ARRAY(bufferTest, bufferTest2, offset); + + // offset 201..801 equal to smallBuffer + res = pal_fsFread(&g_fd1, bufferTest2, inputSizeSmall, &num_bytes_read); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(inputSizeSmall, num_bytes_read); + TEST_ASSERT_EQUAL_HEX8_ARRAY(smallBuffer, bufferTest2, inputSizeSmall); + + // offset 802..1122 equal to bufferTest[802..1122] + res = pal_fsFread(&g_fd1, bufferTest2, residue, &num_bytes_read); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(residue, num_bytes_read); + TEST_ASSERT_EQUAL_HEX8_ARRAY(bufferTest + offset + inputSizeSmall, bufferTest2, residue); + + res = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsUnlink(addRootToPath(fileName,buffer,storageId)); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + free(bufferTest); + bufferTest = NULL; + free(bufferTest2); + bufferTest2 = NULL; + free(smallBuffer); + smallBuffer = NULL; +} + +TEST(pal_fileSystem, WriteInTheMiddle) +{ + WriteInTheMiddle(PAL_FS_PARTITION_PRIMARY); + WriteInTheMiddle(PAL_FS_PARTITION_SECONDARY); +} + + + + +void SequentialWriteAndRead(pal_fsStorageID_t storageId) +{ + char buffer[PAL_MAX_FILE_AND_FOLDER_LENGTH] = {0}; + char fileName[] = "fileName"; + palStatus_t res = PAL_SUCCESS; + size_t num_bytes_write = 0; + size_t num_bytes_read = 0; + unsigned char small_write_buffer[TEST_BUFFER_SMALL_SIZE] = { + 0x2D, 0x6B, 0xAC, 0xCC, 0x08, 0x6B, 0x14, 0x82, + 0xF3, 0x0C, 0xF5, 0x67, 0x17, 0x23, 0x50, 0xB4, + 0xFF + }; + unsigned char small_read_buffer[TEST_BUFFER_SMALL_SIZE] = { 0 }; + bufferTest = malloc(BUFFER_TEST_SIZE); + TEST_ASSERT_NOT_EQUAL(bufferTest, NULL); + bufferTest2 = malloc(BUFFER_TEST_SIZE); + TEST_ASSERT_NOT_EQUAL(bufferTest2, NULL); + memset(bufferTest, 0, BUFFER_TEST_SIZE); + memset(bufferTest2, 0, BUFFER_TEST_SIZE); + + // create 1123 bytes buffer filled with the numbers 0..255 + for (uint32_t i = 0; i < BUFFER_TEST_SIZE; i++) + { + bufferTest[i] = (uint8_t)(i % 256); + } + res = pal_fsUnlink(addRootToPath(fileName,buffer,storageId)); + TEST_ASSERT((PAL_SUCCESS == res) || (PAL_ERR_FS_NO_FILE == res)); + + res = pal_fsFopen(addRootToPath(fileName,buffer,storageId), PAL_FS_FLAG_READWRITEEXCLUSIVE, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + // split the writes + res = pal_fsFwrite(&g_fd1, small_write_buffer, TEST_BUFFER_SMALL_SIZE, &num_bytes_write); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(TEST_BUFFER_SMALL_SIZE, num_bytes_write); + + res = pal_fsFwrite(&g_fd1, bufferTest, BUFFER_TEST_SIZE, &num_bytes_write); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(BUFFER_TEST_SIZE, num_bytes_write); + + res = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsFopen(addRootToPath(fileName,buffer,storageId), PAL_FS_FLAG_READONLY, &g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + // split the reads + res = pal_fsFread(&g_fd1, small_read_buffer, TEST_BUFFER_SMALL_SIZE, &num_bytes_read); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(TEST_BUFFER_SMALL_SIZE, num_bytes_read); + + res = pal_fsFread(&g_fd1, bufferTest2, BUFFER_TEST_SIZE, &num_bytes_read); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + TEST_ASSERT_EQUAL(BUFFER_TEST_SIZE, num_bytes_read); + + TEST_ASSERT_EQUAL_INT8_ARRAY(bufferTest, bufferTest2, BUFFER_TEST_SIZE); + + res = pal_fsFclose(&g_fd1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + res = pal_fsUnlink(addRootToPath(fileName,buffer,storageId)); + TEST_ASSERT_EQUAL(PAL_SUCCESS, res); + + free(bufferTest); + bufferTest = NULL; + free(bufferTest2); + bufferTest2 = NULL; +} + +TEST(pal_fileSystem, SequentialWriteAndRead) +{ + SequentialWriteAndRead(PAL_FS_PARTITION_PRIMARY); + SequentialWriteAndRead(PAL_FS_PARTITION_SECONDARY); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/FileSystem/pal_fileSystem_test_runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/FileSystem/pal_fileSystem_test_runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP_RUNNER(pal_fileSystem) +{ + RUN_TEST_CASE(pal_fileSystem, SDFormat); +// RUN_TEST_CASE(pal_fileSystem, rootDirectoryTests); + RUN_TEST_CASE(pal_fileSystem, directoryTests); + RUN_TEST_CASE(pal_fileSystem, FilesTests); + RUN_TEST_CASE(pal_fileSystem, FilesTestsSeek); + RUN_TEST_CASE(pal_fileSystem, FilesPermission_read_only); + RUN_TEST_CASE(pal_fileSystem, FilesPermission_read_write); + RUN_TEST_CASE(pal_fileSystem, FilesPermission_read_write_trunc); + RUN_TEST_CASE(pal_fileSystem, create_write_and_read_pal_file); + RUN_TEST_CASE(pal_fileSystem, WriteInTheMiddle); + RUN_TEST_CASE(pal_fileSystem, SequentialWriteAndRead); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Networking/pal_socket_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Networking/pal_socket_test.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1587 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "pal_network.h" +#include "unity.h" +#include "unity_fixture.h" +#include "PlatIncludes.h" +#include "pal_test_main.h" +#include "string.h" +#ifdef __LINUX__ +#include <netdb.h> +#define test_getAddressInfo getAddressInfoIPv4 +#else +#define test_getAddressInfo pal_getAddressInfo +#endif + +TEST_GROUP(pal_socket); + +//Sometimes you may want to get local data in a module, +//for example if you need to pass a reference. +//However, you should usually avoid this. +//extern int Counter; + +#define PAL_NET_SUPPORT_LWIP 1 +#define PAL_NET_TEST_SERVER_NAME "www.arm.com" +#define PAL_NET_TEST_SERVER_NAME_UDP "8.8.8.8" + + +#define PAL_NET_TEST_SERVER_HTTP_PORT 80 +#define PAL_NET_TEST_SERVER_UDP_PORT 53 +#define PAL_NET_TEST_INCOMING_PORT 8002 +#define PAL_NET_TEST_INCOMING_PORT2 8989 + +#define PAL_NET_TEST_LOCAL_LOOPBACK_IF_INDEX 0 +PAL_PRIVATE void * g_networkInterface = NULL; +PAL_PRIVATE uint32_t g_interfaceCTXIndex = 0; +PAL_PRIVATE uint32_t s_callbackcounter = 0; + +#define PAL_NET_TEST_SOCKETS 4 +PAL_PRIVATE palSocket_t g_testSockets[PAL_NET_TEST_SOCKETS] = {0,0,0,0}; + +#define PAL_NET_TEST_GOOGLE_CDN_HOST "ajax.googleapis.com" /*! CDN host server */ +#define PAL_NET_TEST_GOOGLE_CDN_HOST_PORT 80 /*! CDN host port */ +#define PAL_NET_TEST_GOOGLE_CDN_REQUEST "GET /ajax/libs/jquery/3.2.1/jquery.js HTTP/1.0\r\nHost:" PAL_NET_TEST_GOOGLE_CDN_HOST "\r\n\r\n" /*! HTTP get request */ +#define PAL_NET_TEST_BUFFERED_TCP_BUF_SIZE_SMALL 4 +#define PAL_NET_TEST_BUFFERED_TCP_BUF_SIZE_LARGE 1024 +#define PAL_NET_TEST_BUFFERED_UDP_BUF_SIZE_SMALL 64 +#define PAL_NET_TEST_BUFFERED_UDP_BUF_SIZE_LARGE 512 +#define PAL_NET_TEST_BUFFERED_UDP_PORT 2606 +#define PAL_NET_TEST_BUFFERED_UDP_MESSAGE_SIZE (1024 * 256) +PAL_PRIVATE uint8_t *g_testRecvBuffer = NULLPTR; +PAL_PRIVATE uint8_t *g_testSendBuffer = NULLPTR; + +typedef struct pal_udp_test_data /*! structure used to hold state in UDP buffered tests */ +{ + const size_t messageSize; + const size_t bufferSize; + const uint8_t startValue; + palNetInterfaceInfo_t interfaceInfo; + uint8_t currentValue; + size_t totalSize; + size_t chunkSize; +} pal_udp_test_data_t; + +TEST_SETUP(pal_socket) +{ + uint32_t i = 0; + palStatus_t status = PAL_SUCCESS; + //This is run before *each test* + pal_init(); + if (g_networkInterface == NULL) + { + g_networkInterface = palTestGetNetWorkInterfaceContext(); + status = pal_registerNetworkInterface(g_networkInterface , &g_interfaceCTXIndex); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + + for (i = 0; i < PAL_NET_TEST_SOCKETS; i++) + { + g_testSockets[i] = 0; + } +} + +TEST_TEAR_DOWN(pal_socket) +{ + uint32_t i = 0; + for (i = 0; i < PAL_NET_TEST_SOCKETS; i++) + { + if (g_testSockets[i] != 0) + { + pal_close(&(g_testSockets[i])); + } + } + + if (g_testRecvBuffer != NULLPTR) + { + free(g_testRecvBuffer); + g_testRecvBuffer = NULLPTR; + } + if (g_testSendBuffer != NULLPTR) + { + free(g_testSendBuffer); + g_testSendBuffer = NULLPTR; + } + + pal_destroy(); +} + +#define PAL_TEST_BUFFER_SIZE 50 +PAL_PRIVATE void socketCallback1( void * arg) +{ + s_callbackcounter++; +} + +/*! \brief Test socket creation, destruction and modification, as well as getting address infromation and checking the blocking status of sockets. +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Register a net interface using `pal_registerNetworkInterface`. | PAL_SUCCESS | +* | 2 | Register a net interface using `pal_registerNetworkInterface`, and check that the ID is the same as the previous step. | PAL_SUCCESS | +* | 3 | Get the interface address using `pal_getNetInterfaceInfo`. | PAL_SUCCESS | +* | 4 | Create a blocking UDP socket using `pal_socket`. | PAL_SUCCESS | +* | 5 | Create a blocking UDP socket using `pal_socket`. | PAL_SUCCESS | +* | 6 | Create a non-blocking UDP socket using `pal_socket`. | PAL_SUCCESS | +* | 7 | Create a blocking asynchronous TCP socket with `socketCallback1` as callback. | PAL_SUCCESS | +* | 8 | Check the number of net interfaces registered using `pal_getNetInterfaceInfo`. | PAL_SUCCESS | +* | 9 | Set the socket receive timeout using `pal_setSocketOptions`. | PAL_SUCCESS | +* | 10 | Check that the sockets return the correct blocking status using `pal_isNonBlocking`. | PAL_SUCCESS | +* | 11 | Check the `pal_getAddressInfo` function with an invalid address. | PAL_ERR_SOCKET_DNS_ERROR | +* | 12 | Close all sockets. | PAL_SUCCESS | +*/ +TEST(pal_socket, socketUDPCreationOptionsTest) +{ + palStatus_t result = PAL_SUCCESS; + uint32_t numInterface = 0; + palNetInterfaceInfo_t interfaceInfo; + uint32_t interfaceIndex = 0; + uint32_t interfaceIndex2 = 0; + uint32_t sockOptVal = 5000; + uint32_t sockOptLen = sizeof(sockOptVal); + palSocketAddress_t address = { 0 }; + palSocketLength_t addrlen = 0; + bool isNonBlocking = false; + + memset(&interfaceInfo,0,sizeof(interfaceInfo)); + // Check that re-adding the network interface returns the same index + /*#1*/ + result = pal_registerNetworkInterface(g_networkInterface, &interfaceIndex); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#2*/ + result = pal_registerNetworkInterface(g_networkInterface, &interfaceIndex2); + TEST_ASSERT_EQUAL_HEX(interfaceIndex, interfaceIndex2); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#3*/ + result = pal_getNetInterfaceInfo(interfaceIndex, &interfaceInfo); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_PRINTF("Default interface address: %u %u %u %u \r\n", + (unsigned char)interfaceInfo.address.addressData[2], + (unsigned char)interfaceInfo.address.addressData[3], + (unsigned char)interfaceInfo.address.addressData[4], + (unsigned char)interfaceInfo.address.addressData[5]);; + + + //Blocking + /*#4*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_DGRAM, false, interfaceIndex, &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + /*#5*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_DGRAM, false, interfaceIndex, &g_testSockets[1]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + //Non-blocking + /*#6*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_DGRAM, true, interfaceIndex, &g_testSockets[3]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + /*#7*/ + result = pal_asynchronousSocket(PAL_AF_INET, PAL_SOCK_STREAM, false, interfaceIndex, socketCallback1, &g_testSockets[2]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); +#endif // PAL_NET_ASYNCHRONOUS_SOCKET_API + + /*#8*/ + result = pal_getNumberOfNetInterfaces(&numInterface); + TEST_ASSERT_NOT_EQUAL(numInterface, 0); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#9*/ + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_RCVTIMEO, &sockOptVal, sockOptLen); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#10*/ + result = pal_isNonBlocking(g_testSockets[0],&isNonBlocking); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(isNonBlocking, false); + + result = pal_isNonBlocking(g_testSockets[3], &isNonBlocking); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(isNonBlocking, true); + + /*#11*/ + result = pal_getAddressInfo("0.0.0.0", &address, &addrlen); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_SOCKET_DNS_ERROR, result); + + /*#12*/ +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + result = pal_close(&g_testSockets[2]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + +#endif // PAL_NET_ASYNCHRONOUS_SOCKET_API + + result = pal_close(&g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + result = pal_close(&g_testSockets[1]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + result = pal_close(&g_testSockets[3]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + result = pal_close(&g_testSockets[3]); //double close - should succeed + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); +} + + +/*! \brief Test TCP socket creation, connection, send and receive with a test server. +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a blocking TCP socket using `pal_socket`. | PAL_SUCCESS | +* | 2 | Look up the IP address of the test server using `pal_getAddressInfo`. | PAL_SUCCESS | +* | 3 | Set the port to a test port in the address structure using `pal_setSockAddrPort` and set timeout. | PAL_SUCCESS | +* | 4 | Connect the socket to the test server using `pal_connect`. | PAL_SUCCESS | +* | 5 | Send a test message (short HTTP request) to the test server using `pal_send`. | PAL_SUCCESS | +* | 6 | Receive (blocking) the server's response using `pal_recv` and check it is HTTP. | PAL_SUCCESS | +* | 7 | Close the socket. | PAL_SUCCESS | +*/ +TEST(pal_socket, basicTCPclientSendRecieve) +{ + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t address = { 0 }; + const char message[] = "GET / HTTP/1.0\r\n\r\n"; + size_t sent = 0; + char buffer[100] = { 0 }; + size_t read = 0; + palSocketLength_t addrlen = 0; + int timeout = 1000; + + /*#1*/ + + result = pal_socket(PAL_AF_INET, PAL_SOCK_STREAM, false, 0, &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#2*/ + result = pal_getAddressInfo(PAL_NET_TEST_SERVER_NAME, &address, &addrlen); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#3*/ + result = pal_setSockAddrPort(&address, PAL_NET_TEST_SERVER_HTTP_PORT); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_SNDTIMEO, &timeout, sizeof(timeout)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_RCVTIMEO, &timeout, sizeof(timeout)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + + /*#4*/ + result = pal_connect(g_testSockets[0], &address, 16); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#5*/ + result = pal_send(g_testSockets[0], message, sizeof(message) - 1, &sent); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#6*/ + result = pal_recv(g_testSockets[0], buffer, 99, &read); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + TEST_ASSERT(read >= 4); + TEST_ASSERT(buffer[0] == 'H' && buffer[1] == 'T'&& buffer[2] == 'T' && buffer[3] == 'P'); + + /*#7*/ + pal_close(&g_testSockets[0]); + +} + +/*! \brief Test UDP socket creation, connection, send and recieve with a test server. +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a blocking UDP socket using `pal_socket`. | PAL_SUCCESS | +* | 2 | Look up the IP address of the test server using `pal_getAddressInfo`. | PAL_SUCCESS | +* | 3 | Set the port to a test port in the address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | 4 | Connect the socket to the test server using `pal_connect`. | PAL_SUCCESS | +* | 5 | Send a test message (short DNS request) to the test server using `pal_send`. | PAL_SUCCESS | +* | 6 | Receive (blocking) the server's response using `pal_recv`. | PAL_SUCCESS | +* | 7 | Close the socket. | PAL_SUCCESS | +*/ +TEST(pal_socket, basicUDPclientSendRecieve) +{ + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t address = { 0 }; + palSocketAddress_t address2 = { 0 }; + uint8_t buffer[33] = { 0x8e, 0xde, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x61, 0x72, 0x73, 0x74, 0x65, 0x63, 0x68, 0x6e, 0x69, 0x63, 0x61, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 }; + uint8_t buffer_in[10]; + size_t sent = 0; + size_t read = 0; + size_t socket_timeout_ms = 5000; + palSocketLength_t addrlen = 0; + + /*#1*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_DGRAM, false, 0, &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#2*/ + result = pal_getAddressInfo(PAL_NET_TEST_SERVER_NAME_UDP, &address, &addrlen); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#3*/ + result = pal_setSockAddrPort(&address, PAL_NET_TEST_SERVER_UDP_PORT); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#4*/ + //We set a timeout for receiving so we won't get stuck in the test + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_RCVTIMEO, &socket_timeout_ms, sizeof(socket_timeout_ms)); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#5*/ + result = pal_sendTo(g_testSockets[0], buffer, sizeof(buffer), &address, 16, &sent); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + TEST_ASSERT_EQUAL(sent, sizeof(buffer)); + + /*#6*/ + result = pal_receiveFrom(g_testSockets[0], buffer_in, 10, &address2, &addrlen, &read); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + TEST_ASSERT_EQUAL(read, 10); + + /*#7*/ + pal_close(&g_testSockets[0]); +} + + + + +// This is an example showing how to check for a socket that has been closed remotely. +#if 0 +PAL_PRIVATE void basicSocketScenario3Callback(void * arg) +{ + char buffer[400]; + size_t read = 0; + palStatus_t result; + + + s_callbackcounter++; + result = pal_recv(g_testSockets[0], buffer, 999, &read); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + // If 0 bytes are read it means that the peer has performed an orderly shutdown so we must close the socket + // to avoid ppoll from checking it. Checking a socket whose other end has been shut down causes ppoll to immediately return + // with events == 0x1. + if(read == 0) + { + pal_close(&g_testSockets[0]); + } + else + { + buffer[read] = '\0'; + if(s_callbackcounter == 0) + { + TEST_ASSERT(read >= 4); + TEST_ASSERT(buffer[0] == 'H' && buffer[1] == 'T'&& buffer[2] == 'T' && buffer[3] == 'P'); + } + } + +} +#endif +palSemaphoreID_t s_semaphoreID = NULLPTR; + +PAL_PRIVATE void socketCallback2(void * arg) +{ + palStatus_t result; + if(s_callbackcounter == 0) + { + result = pal_osSemaphoreRelease(s_semaphoreID); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + } + s_callbackcounter++; + +} + +static int s_secondCallbackCounter = 0; +PAL_PRIVATE void socketCallbackErr(void * arg) +{ + s_secondCallbackCounter++; +} + +/*! \brief Test asynchronous socket callbacks. +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Look up the IP address of the test server using `pal_getAddressInfo`. | PAL_SUCCESS | +* | 2 | Create a blocking asynchronous TCP socket with `socketCallback2` as callback. | PAL_SUCCESS | +* | 3 | Set port to a test port in the address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | 4 | Connect the socket to the test server using `pal_connect`. | PAL_SUCCESS | +* | 5 | Send a test message (short HTTP request) to the test server using `pal_send`. | PAL_SUCCESS | +* | 6 | Wait for a callback to release the semaphore when the response arrives. | PAL_SUCCESS | +* | 7 | Receive (blocking) the server's response using `pal_recv` and check that the response is HTTP.| PAL_SUCCESS | +* | 8 | Close the socket. | PAL_SUCCESS | +*/ +TEST(pal_socket, basicSocketScenario3) +{ + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t address = { 0 }; + const char* message = "GET / HTTP/1.0\r\nHost:10.45.48.68:8000\r\n\r\n"; + size_t sent = 0; + char buffer[100] = { 0 }; + size_t read = 0; + s_callbackcounter = 0; + palSocketLength_t addrlen = 0; + int32_t countersAvailable; + + result = pal_osSemaphoreCreate(1, &s_semaphoreID); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + result = pal_osSemaphoreWait(s_semaphoreID, 40000, &countersAvailable); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#1*/ + result = pal_getAddressInfo(PAL_NET_TEST_SERVER_NAME, &address, &addrlen); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + /*#2*/ + result = pal_asynchronousSocketWithArgument(PAL_AF_INET, PAL_SOCK_STREAM, false, 0, socketCallback2, "socketCallback2Arg", &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + s_secondCallbackCounter = 0; + result = pal_asynchronousSocketWithArgument(PAL_AF_INET, PAL_SOCK_STREAM, false, 0, socketCallbackErr, "socketCallback2Arg", &g_testSockets[1]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + TEST_ASSERT_EQUAL_HEX(0, s_secondCallbackCounter); + /*#3*/ + result = pal_setSockAddrPort(&address, PAL_NET_TEST_SERVER_HTTP_PORT); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#4*/ + result = pal_connect(g_testSockets[0], &address, 16); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + TEST_ASSERT_EQUAL_HEX(0, s_secondCallbackCounter); + /*#5*/ + result = pal_send(g_testSockets[0], message, strlen(message), &sent); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + TEST_ASSERT_EQUAL_HEX(0, s_secondCallbackCounter); + // Give a chance for the callback to be called. + /*#6*/ + result=pal_osSemaphoreWait(s_semaphoreID, 40000, &countersAvailable); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + result=pal_osSemaphoreDelete(&s_semaphoreID); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#7*/ + result = pal_recv(g_testSockets[0], buffer, 99, &read); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + TEST_ASSERT(read >= 4); + TEST_ASSERT(buffer[0] == 'H' && buffer[1] == 'T'&& buffer[2] == 'T' && buffer[3] == 'P'); + TEST_ASSERT(s_callbackcounter > 0); + + + TEST_ASSERT_EQUAL_HEX(0, s_secondCallbackCounter); + /*#8*/ + pal_close(&g_testSockets[0]); +#endif // PAL_NET_ASYNCHRONOUS_SOCKET_API +} + + +/*! \brief Tests two main secenarios: +* 1. Use `pal_socketMiniSelect` to detect incoming traffic. +* 2. Use `pal_socketMiniSelect` to check if a non-blocking socket has finished connecting. +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a blocking TCP socket using `pal_socket`. | PAL_SUCCESS | +* | 2 | Create a blocking UDP socket using `pal_socket`. | PAL_SUCCESS | +* | 3 | Look up the IP address of the `www.arm.com` server using `pal_getAddressInfo`. | PAL_SUCCESS | +* | 4 | Set a port to the test port in the address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | 5 | Connect a socket to the test server using `pal_connect`. | PAL_SUCCESS | +* | 6 | Send a test message (short HTTP request) to the test server using `pal_send`. | PAL_SUCCESS | +* | 7 | Call `socketMiniSelect` with a timeout of 5 seconds, and check for correct socket state. Check `select` again when the data arrives.| PAL_SUCCESS | +* | 8 | Receive (blocking) the server's response using `pal_recv` and check that the response is HTTP. | PAL_SUCCESS | +* | 9 | Close the socket. | PAL_SUCCESS | +* | 10 | Call `socketMiniSelect` with a timeout of 1 second and check for the correct socket state.| PAL_SUCCESS | +* | 11 | Close the socket. | PAL_SUCCESS | +* | 12 | Create a non-blocking TCP socket using `pal_socket`. | PAL_SUCCESS | +* | 13 | Look up the IP address `192.0.2.0` (invalid IP address) using `pal_getAddressInfo`. | PAL_SUCCESS | +* | 14 | Set the port to the test port in the address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | 15 | Connect to an invalid address and call `select`; check that the socket is not writable. | PAL_SUCCESS | +* | 16 | Close the socket. | PAL_SUCCESS | +* | 17 | Create a non-blocking TCP socket using `pal_socket`. | PAL_SUCCESS | +* | 18 | Look up the IP address of the `www.arm.com` server using `pal_getAddressInfo`. | PAL_SUCCESS | +* | 19 | Set the port to the test port in the address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | 20 | Connect and call `select` with a timeout of 2 seconds, and check that the socket is writable. | PAL_SUCCESS | +* | 21 | Close the socket. | PAL_SUCCESS | +*/ +TEST(pal_socket, basicSocketScenario4) +{ + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t address = { 0 }; + const char* message = "GET / HTTP/1.0\r\n\r\n"; + size_t sent = 0; + char buffer[100] = { 0 }; + size_t read = 0; + palSocketLength_t addlen = 0; + uint32_t numSockets = 0; + palSocket_t socketsToCheck[2] = { 0 }; + pal_timeVal_t tv = {0}; + uint8_t palSocketStatus[2] = { 0 }; + + /*#1*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_STREAM, false, 0, &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#2*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_DGRAM, false, 0, &g_testSockets[1]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#3*/ + result = pal_getAddressInfo("www.arm.com", &address, &addlen); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#4*/ + result = pal_setSockAddrPort(&address, 80); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#5*/ + result = pal_connect(g_testSockets[0], &address, 16); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#6*/ + result = pal_send(g_testSockets[0], message, strlen(message), &sent); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#7*/ + socketsToCheck[0] = g_testSockets[0]; + socketsToCheck[1] = g_testSockets[1]; + tv.pal_tv_sec = 5; + result = pal_socketMiniSelect(socketsToCheck, 2, &tv, palSocketStatus, &numSockets); // Data is expected to arrive during select + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + if (numSockets == 0) // Clean up to prevent resource leak. + { + pal_close(&g_testSockets[0]); + pal_close(&g_testSockets[1]); + } + TEST_ASSERT( 0 < numSockets); + TEST_ASSERT(0< palSocketStatus[0] ); + TEST_ASSERT(PAL_NET_SELECT_IS_TX(palSocketStatus, 0) || PAL_NET_SELECT_IS_RX(palSocketStatus, 0) || PAL_NET_SELECT_IS_ERR(palSocketStatus, 0)); + TEST_ASSERT((palSocketStatus[1] & (PAL_NET_SOCKET_SELECT_RX_BIT | PAL_NET_SOCKET_SELECT_ERR_BIT)) == 0); + TEST_ASSERT_FALSE((PAL_NET_SELECT_IS_RX(palSocketStatus,1))); + TEST_ASSERT_FALSE((PAL_NET_SELECT_IS_ERR(palSocketStatus, 1))); + + + palSocketStatus[0] = 0; + palSocketStatus[1] = 0; + result = pal_socketMiniSelect(socketsToCheck, 2, &tv, palSocketStatus, &numSockets); // Check what happens when you call `select` when the data has already arrived. + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + if (numSockets == 0) // Clean up to prevent resource leak. + { + pal_close(&g_testSockets[0]); + pal_close(&g_testSockets[1]); + } + TEST_ASSERT(0 < numSockets); + TEST_ASSERT(0< palSocketStatus[0]); + TEST_ASSERT((palSocketStatus[1] & (PAL_NET_SOCKET_SELECT_RX_BIT | PAL_NET_SOCKET_SELECT_ERR_BIT)) == 0); + TEST_ASSERT_FALSE((PAL_NET_SELECT_IS_RX(palSocketStatus, 1))); + TEST_ASSERT_FALSE((PAL_NET_SELECT_IS_ERR(palSocketStatus, 1))); + + + + /*#8*/ + + result = pal_recv(g_testSockets[0], buffer, 99, &read); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + TEST_ASSERT(read >= 4); + TEST_ASSERT(buffer[0] == 'H' && buffer[1] == 'T'&& buffer[2] == 'T' && buffer[3] == 'P'); + + /*#9*/ + pal_close(&g_testSockets[0]); + + /*#10*/ + numSockets = 0; + palSocketStatus[0] =0; + palSocketStatus[1] =0; + socketsToCheck[0] = g_testSockets[1]; + socketsToCheck[1] = 0; + tv.pal_tv_sec = 1; + + result = pal_socketMiniSelect(socketsToCheck, 1, &tv, palSocketStatus, &numSockets); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + TEST_ASSERT((palSocketStatus[0] & (PAL_NET_SOCKET_SELECT_RX_BIT | PAL_NET_SOCKET_SELECT_ERR_BIT)) == 0); + TEST_ASSERT_FALSE((PAL_NET_SELECT_IS_RX(palSocketStatus, 1))); + TEST_ASSERT_FALSE((PAL_NET_SELECT_IS_ERR(palSocketStatus, 1))); + + /*#11*/ + pal_close(&g_testSockets[1]); + + // Non-responsive socket connection + /*#12*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_STREAM, true, 0, &g_testSockets[2]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + numSockets = 0; + palSocketStatus[0] =0; + palSocketStatus[1] =0; + socketsToCheck[0] = g_testSockets[2]; + socketsToCheck[1] = 0; + tv.pal_tv_sec = 1; + + /*#13*/ + result = pal_getAddressInfo("192.0.2.0", &address, &addlen); // Address intended for testing (not a real address); we don't expect a connection. + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#14*/ + result = pal_setSockAddrPort(&address, 80); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + result = pal_connect(g_testSockets[2], &address, 16); + //TEST_ASSERT_EQUAL_HEX( PAL_ERR_SOCKET_IN_PROGRES, result); // Comment back in when a non-blocking connection is enabled on mbed OS + + /*#15*/ + result = pal_socketMiniSelect(socketsToCheck, 1, &tv, palSocketStatus, &numSockets); + + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + TEST_ASSERT( 0 == numSockets); + TEST_ASSERT(0 == palSocketStatus[0] ); + + /*#16*/ + pal_close(&g_testSockets[2]); + + /*#17*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_STREAM, true, 0, &g_testSockets[2]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + numSockets = 0; + palSocketStatus[0] =0; + palSocketStatus[1] =0; + socketsToCheck[0] = g_testSockets[2]; + socketsToCheck[1] = 0; + tv.pal_tv_sec = 2; + + /*#18*/ + result = pal_getAddressInfo("www.arm.com", &address, &addlen); // Address intended for testing (not a real address); we don't expect a connection. + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#19*/ + result = pal_setSockAddrPort(&address, 80); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + result = pal_connect(g_testSockets[2], &address, 16); + //TEST_ASSERT_EQUAL_HEX( PAL_ERR_SOCKET_IN_PROGRES, result); // Comment back in when a non-blocking connection is enabled on mbed OS + + /*#20*/ + result = pal_socketMiniSelect(socketsToCheck, 1, &tv, palSocketStatus, &numSockets); + /*#21*/ + pal_close(&g_testSockets[2]); + + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + TEST_ASSERT( 1 == numSockets); + TEST_ASSERT( PAL_NET_SOCKET_SELECT_TX_BIT == (palSocketStatus[0]& ( PAL_NET_SOCKET_SELECT_TX_BIT) )); + TEST_ASSERT((PAL_NET_SELECT_IS_TX(palSocketStatus, 0))); +} + + +typedef struct palNetTestThreadData{ + palSemaphoreID_t sem1; + palSemaphoreID_t sem2; + uint16_t port; +} palNetTestThreadData_t; + +char s_rcv_buffer[20] = {0}; +char s_rcv_buffer2[50] = {0}; + +void palNetClientFunc(void const *argument) +{ + palStatus_t result = PAL_SUCCESS; + int32_t tmp = 0; + size_t sent = 0; + size_t read = 0; + palNetTestThreadData_t* dualSem = (palNetTestThreadData_t*)argument; + palSocketLength_t addrlen = 16; + //palSocketAddress_t address = { 0 }; + palNetInterfaceInfo_t interfaceInfo; + const char* message = "GET / HTTP/1.0\r\n\r\n"; + + /*#C1*/ + result = pal_osSemaphoreWait(dualSem->sem1, 500, &tmp); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#C2*/ + result = pal_getNetInterfaceInfo(PAL_NET_TEST_LOCAL_LOOPBACK_IF_INDEX, &interfaceInfo); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#C3*/ + uint16_t incoming_port = dualSem->port; + TEST_PRINTF("client port = %u", incoming_port); + result = pal_setSockAddrPort(&(interfaceInfo.address), incoming_port); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#C4*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_STREAM, false, 0, &g_testSockets[2]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#C5*/ + result = pal_connect(g_testSockets[2], &(interfaceInfo.address), addrlen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#C6*/ + result = pal_send(g_testSockets[2], message, 18, &sent); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#C7*/ + result = pal_recv(g_testSockets[2], s_rcv_buffer, 15, &read); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_PRINTF(s_rcv_buffer); + + /*#C8*/ + pal_close(&g_testSockets[2]); + + result = pal_osSemaphoreRelease(dualSem->sem2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); +} + +/*! \brief /b ServerSocketScenario tests a TCP client-server scenario using device loopback. +* +* \note The test steps are divided into those in the server main thread (S1..S13) and those in the client thread (C1..C8). +* The sequence below is an approximation of the actual order of execution. +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | S1 | Create a blocking TCP server socket using `pal_socket`. | PAL_SUCCESS | +* | S2 | Create a blocking TCP socket using `pal_socket`. | PAL_SUCCESS | +* | S3 | Look up the IP address of loopback using `pal_getAddressInfo`. | PAL_SUCCESS | +* | S4 | Set the port to test port in address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | S5 | Bind the server socket to the port and address using `pal_bind`. | PAL_SUCCESS | +* | S6 | Create synchronization sepmaphores and set count to 0. | PAL_SUCCESS | +* | S7 | Create a client thread with `BelowNormal` priority running `palNetClientFunc`. | PAL_SUCCESS | +* | C1 | Client thread blocks on client sepmaphore s1. | PAL_SUCCESS | +* | S8 | Listen to the server port using `pal_listen`. | PAL_SUCCESS | +* | S9 | Release the client sepmahore s1. | PAL_SUCCESS | +* | S10 | Call `accept` (blocking) to accept a new connection (retry in case of failure). | PAL_SUCCESS | +* | C2 | Look up the IP address of the loopback using `pal_getAddressInfo`. | PAL_SUCCESS | +* | C3 | Set the port to test port in the address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | C4 | Create a blocking TCP socket using `pal_socket`. | PAL_SUCCESS | +* | C5 | Connect to the server using `pal_connect`. | PAL_SUCCESS | +* | C6 | Send data to server. | PAL_SUCCESS | +* | S11 | Receive data from the client. | PAL_SUCCESS | +* | S12 | Send data to the client. | PAL_SUCCESS | +* | C7 | Receive data from the server. | PAL_SUCCESS | +* | C8 | Client thread cleanup - close the socket and release the semaphore. | PAL_SUCCESS | +* | S13 | Cleanup: close sockets and delete semaphores. | PAL_SUCCESS | +*/ + +TEST(pal_socket, ServerSocketScenario) +{ + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t address2 = { 0 }; + const char* messageOut = "HTTP/1.0 200 OK"; + size_t sent = 0; + size_t read = 0; + palSocketLength_t addrlen = 16; + + palSemaphoreID_t semaphoreID = NULLPTR; + palSemaphoreID_t semaphoreID2 = NULLPTR; + palNetTestThreadData_t dualSem = {0}; + palThreadID_t threadID1 = NULLPTR; + int32_t tmp = 0; + palNetInterfaceInfo_t interfaceInfo; + memset(&interfaceInfo,0,sizeof(interfaceInfo)); + + + /*#S1*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_STREAM_SERVER, false, 0, &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#S2*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_STREAM, false, 0, &g_testSockets[1]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#S3*/ + result = pal_getNetInterfaceInfo(PAL_NET_TEST_LOCAL_LOOPBACK_IF_INDEX, &interfaceInfo); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + TEST_PRINTF("interface addr: %u %u %u %u \r\n", + (unsigned char)interfaceInfo.address.addressData[2], + (unsigned char)interfaceInfo.address.addressData[3], + (unsigned char)interfaceInfo.address.addressData[4], + (unsigned char)interfaceInfo.address.addressData[5]);; + /*#S4*/ + uint32_t rand_number = 0; + uint16_t incoming_port; + + for (int i=0; i<5; i++) { + pal_osRandom32bit(&rand_number); + incoming_port = (uint16_t)(35400 + (rand_number % (40000 - 35400))); + TEST_PRINTF("server port = %u", incoming_port); + + result = pal_setSockAddrPort(&(interfaceInfo.address), incoming_port); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#S5*/ + result = pal_bind(g_testSockets[0], &(interfaceInfo.address), interfaceInfo.addressSize); + + if (PAL_SUCCESS == result) { + TEST_PRINTF("bind succeeded on port %u", incoming_port); + break; + } else { + TEST_PRINTF("bind failed on port %u", incoming_port); + } + } + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#S6*/ + + // start client thread to connect to the server. + result = pal_osSemaphoreCreate(1 ,&semaphoreID); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + result = pal_osSemaphoreWait(semaphoreID, 1000, &tmp); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + + result = pal_osSemaphoreCreate(1 ,&semaphoreID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + result = pal_osSemaphoreWait(semaphoreID2, 1000, &tmp); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + dualSem.sem1 = semaphoreID; + dualSem.sem2 = semaphoreID2; + dualSem.port = incoming_port; + + /*#S7*/ + result = pal_osThreadCreateWithAlloc(palNetClientFunc, &dualSem , PAL_osPriorityBelowNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#S8*/ + result = pal_listen(g_testSockets[0], 10); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#S9*/ + result = pal_osSemaphoreRelease(dualSem.sem1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + + TEST_PRINTF("waiting for connection:\r\n"); + /*#S10*/ + result = pal_accept(g_testSockets[0], &address2, &addrlen, &g_testSockets[1]); + TEST_PRINTF("after accept: %" PRIu32 "\r\n", result); + if (PAL_SUCCESS != result ) + { + result = pal_accept(g_testSockets[0], &address2, &addrlen, &g_testSockets[1]); + TEST_PRINTF("after accept: %" PRIu32 "\r\n",result); + } + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#S11*/ + result = pal_recv(g_testSockets[1], s_rcv_buffer2, 49, &read); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_PRINTF(s_rcv_buffer2); + + /*#S12*/ + result = pal_send(g_testSockets[1], messageOut, 15, &sent); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + +//cleanup + +/*#S13*/ + pal_close(&g_testSockets[1]); + pal_close(&g_testSockets[0]); + + result = pal_osSemaphoreWait(semaphoreID2, 5000, &tmp); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + pal_osDelay(2000); + pal_osThreadTerminate(&threadID1); + result = pal_osSemaphoreDelete(&semaphoreID); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(NULL, semaphoreID); + + result = pal_osSemaphoreDelete(&semaphoreID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(NULL, semaphoreID2); +} + + + +PAL_PRIVATE volatile uint32_t s_callbackCounterNonBlock = 0; + +PAL_PRIVATE void nonBlockCallback(void * arg) +{ + s_callbackCounterNonBlock++; +} + +#define PAL_NET_TEST_HTTP_HEADER_LEN 5 + +/*! \brief /b nonBlockingAsyncTest checks the asynchronous- nonblocking socket scenario. +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Look up the IP address of the test server using `pal_getAddressInfo`. | PAL_SUCCESS | +* | 2 | Create an asynchronous non-blocking TCP socket with `nonBlockCallback` as callback. | PAL_SUCCESS | +* | 3 | Set the port to test port in the address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | 4 | Connect the socket. | PAL_SUCCESS or PAL_ERR_SOCKET_IN_PROGRES | +* | 5 | Send a test message to the test server using `pal_send` (repeat until success). | PAL_SUCCESS or PAL_ERR_SOCKET_IN_PROGRES | +* | 6 | Wait for the callback and receive server response using `pal_recv` (repeat until success). | PAL_SUCCESS or PAL_ERR_SOCKET_WOULD_BLOCK| +* | 7 | Close the socket. | PAL_SUCCESS | +*/ +TEST(pal_socket, nonBlockingAsyncTest) +{ + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t address = { 0 }; + const char* message = "GET / HTTP/1.0\r\nHost:10.45.48.68:8000\r\n\r\n"; + size_t sent = 0; + char buffer[100] = { 0 }; + size_t read = 0; + s_callbackcounter = 0; + palSocketLength_t addrlen = 0; + int32_t waitIterations = 0; + + /*#1*/ + result = pal_getAddressInfo(PAL_NET_TEST_SERVER_NAME, &address, &addrlen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + +#if PAL_NET_ASYNCHRONOUS_SOCKET_API + /*#2*/ + result = pal_asynchronousSocketWithArgument(PAL_AF_INET, PAL_SOCK_STREAM, true, 0, nonBlockCallback, "non-blockSocketCallbackArg", &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#3*/ + result = pal_setSockAddrPort(&address, PAL_NET_TEST_SERVER_HTTP_PORT); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#4*/ + result = pal_connect(g_testSockets[0], &address, 16); + if (PAL_ERR_SOCKET_IN_PROGRES == result) + { + result = pal_connect(g_testSockets[0], &address, 16); + if ((result != PAL_SUCCESS) && (result != PAL_ERR_SOCKET_ALREADY_CONNECTED) && (result != PAL_ERR_SOCKET_IN_PROGRES) && (result != PAL_ERR_SOCKET_WOULD_BLOCK)) // check expected result codes.(connection should either be in progress or connected already) + { + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + pal_osDelay(400); + } + else + { + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + } + s_callbackCounterNonBlock = 0; + + /*#5*/ + result = pal_send(g_testSockets[0], message, strlen(message), &sent); + + while (PAL_ERR_SOCKET_IN_PROGRES == result) + { + pal_osDelay(100); + result = pal_send(g_testSockets[0], message, strlen(message), &sent); + } + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#6*/ + result = pal_recv(g_testSockets[0], buffer, PAL_NET_TEST_HTTP_HEADER_LEN, &read); // may block + while ((PAL_ERR_SOCKET_WOULD_BLOCK == result) && (10 > waitIterations )) + { + s_callbackCounterNonBlock = 0; + while (s_callbackCounterNonBlock == 0) + { + waitIterations++; + pal_osDelay(100); + } + result = pal_recv(g_testSockets[0], buffer, PAL_NET_TEST_HTTP_HEADER_LEN, &read); // shouldnt block + } + + /*#7*/ + pal_close(&g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT(read >= 4); + TEST_ASSERT(buffer[0] == 'H' && buffer[1] == 'T'&& buffer[2] == 'T' && buffer[3] == 'P'); + TEST_ASSERT(s_callbackCounterNonBlock > 0); + +#endif // PAL_NET_ASYNCHRONOUS_SOCKET_API +} + +/*! \brief /b tProvUDPTest tests UDP socket send/receive and checks that we get the correct error for receive timeout. +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a blocking UDP socket using `pal_socket`. | PAL_SUCCESS | +* | 2 | Look up the IP address of the test server using `pal_getAddressInfo`. | PAL_SUCCESS | +* | 3 | Set the port to test port in the address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | 4 | Set socket timeouts using `pal_setSocketOptions`. | PAL_SUCCESS | +* | 5 | Send a test message (short HTTP request) to test the server using `pal_send`. | PAL_SUCCESS | +* | 6 | Receive the (blocking) server response using `pal_recv`. | PAL_SUCCESS | +* | 7 | Receive the (blocking) server response again using `pal_recv` and fail. | PAL_ERR_SOCKET_WOULD_BLOCK | +* | 8 | Close the socket. | PAL_SUCCESS | +*/ +TEST(pal_socket, tProvUDPTest) +{ + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t address = { 0,{0} }; + uint8_t buffer[100] = { 0 }; + uint8_t buffer_dns[33] = { 0x8e, 0xde, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x61, 0x72, 0x73, 0x74, 0x65, 0x63, 0x68, 0x6e, 0x69, 0x63, 0x61, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 }; + size_t sent = 0; + size_t read = 0; + palSocketLength_t addrlen = 16; + int timeout = 1000; + + /*#1*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_DGRAM, false, 0, &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#2*/ + result = pal_getAddressInfo(PAL_NET_TEST_SERVER_NAME_UDP, &address, &addrlen); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#3*/ + result = pal_setSockAddrPort(&address, PAL_NET_TEST_SERVER_UDP_PORT); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#4*/ + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_SNDTIMEO, &timeout, sizeof(timeout)); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + timeout = 1000; + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_RCVTIMEO, &timeout, sizeof(timeout)); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + + /*#5*/ + result = pal_sendTo(g_testSockets[0], buffer_dns, sizeof(buffer_dns), &address, addrlen, &sent); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(sent, sizeof(buffer_dns)); + + /*#6*/ + result = pal_receiveFrom(g_testSockets[0], buffer, 16, NULL, NULL, &read); + TEST_ASSERT_EQUAL_HEX( PAL_SUCCESS, result); + TEST_ASSERT_EQUAL(read, 16); + + /*#7*/ + result = pal_receiveFrom(g_testSockets[0], buffer, 100, NULL, NULL, &read); // should get timeout + TEST_ASSERT_EQUAL_HEX(result, PAL_ERR_SOCKET_WOULD_BLOCK); + + /*#8*/ + pal_close(&g_testSockets[0]); +} + + +void socket_event_handler(void* arg) +{ + +} + + + +#define PAL_COAP_NET_TEST_SERVER_NAME "coap-integration-lab.dev.mbed.com" +#define PAL_COAP_NET_TEST_SERVER_HTTP_PORT 5684 +#define WAIT_TIME_ASYNC_SEC 0 +#define RETRY_COUNT 10 +/*! \brief /b PalTestAPPTestt tests TCP async connection to COAP server. +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a blocking UDP socket using `pal_socket`. | PAL_SUCCESS | +* | 2 | Look up the IP address of the test server using `pal_getAddressInfo`. | PAL_SUCCESS | +* | 3 | Set the port to test port in the address structure using `pal_setSockAddrPort`. | PAL_SUCCESS | +* | 4 | Get the local unit IP using `pal_getSockAddrIPV4Addr`. | PAL_SUCCESS | +* | 5 | Get the number of connected interfaces using `pal_getNumberOfNetInterfaces`. | PAL_SUCCESS | +* | 6 | Get the interface info using `pal_getNetInterfaceInfo`. | PAL_SUCCESS | +* | 7 | Set the async socket `pal_asynchronousSocket`. | PAL_SUCCESS | +* | 8| Connect to the socket. | PAL_SUCCESS Or PAL_ERR_SOCKET_IN_PROGRES| +* | 9| If step 10 failed, check if socket was connected using `pal_socketMiniSelect`. | PAL_SUCCESS | +* | 10| If mini select passes, try sending data to socket. | PAL_SUCCESS | +* | 11 | Close the socket. | PAL_SUCCESS | +*/ +TEST(pal_socket, PalMiniSelectNoBlockingTcpConnection) +{ + palStatus_t status = PAL_SUCCESS; + palSocketLength_t _socket_address_len = 0; + palSocketAddress_t _socket_address = { 0 }; + palSocket_t _socket = 0; + palIpV4Addr_t interface_address4 = {0}; + palIpV6Addr_t interface_address6 = {0}; + uint32_t interface_count; + palNetInterfaceInfo_t interface_info; + palSocketAddress_t bind_address; + pal_timeVal_t zeroTime = {WAIT_TIME_ASYNC_SEC, 0}; + uint32_t socketsSet = 0; + uint8_t socketStatus[1] = { 0 }; + int i = 0; + + /*#1*/ + memset(&interface_info,0,sizeof(interface_info)); + memset(&bind_address, 0, sizeof(palSocketAddress_t)); + + /*#2*/ + status = pal_getAddressInfo(PAL_COAP_NET_TEST_SERVER_NAME, &_socket_address, &_socket_address_len); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#3*/ + status = pal_setSockAddrPort(&_socket_address, PAL_COAP_NET_TEST_SERVER_HTTP_PORT); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + if (PAL_AF_INET == _socket_address.addressType) //if address is IPV4 extract ipv4 address. + { + status = pal_getSockAddrIPV4Addr(&_socket_address, interface_address4); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + else if (PAL_AF_INET6 == _socket_address.addressType){ // address is IPV6 - extract IPV6 address. + status = pal_getSockAddrIPV6Addr(&_socket_address, interface_address6); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + else + { + // unexpected address type ---> error + TEST_ASSERT(((PAL_AF_INET6 == _socket_address.addressType) || (PAL_AF_INET == _socket_address.addressType))); + } + + /*#5*/ + status = pal_getNumberOfNetInterfaces(&interface_count); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#6*/ + status = pal_getNetInterfaceInfo(g_interfaceCTXIndex, &interface_info); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#7*/ + status = pal_asynchronousSocket((palSocketDomain_t)_socket_address.addressType, (palSocketType_t)PAL_SOCK_STREAM, true, (uint32_t)g_interfaceCTXIndex, (palAsyncSocketCallback_t)&socket_event_handler, &_socket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#8*/ + status = pal_connect(_socket, &_socket_address, _socket_address_len); + pal_osDelay(300); + + /*#9*/ + if(status != PAL_SUCCESS) + { + for(i = 0; i < RETRY_COUNT ; i++) + { + status = pal_socketMiniSelect(&_socket, 1, &zeroTime, socketStatus, &socketsSet); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + if(socketsSet > 0) + { + TEST_ASSERT_EQUAL_HEX(socketsSet >= 1, 1); + break; + } + pal_osDelay(100); + } + } + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#10*/ + { + uint8_t message[] = { 0x16 ,0x03 ,0x01 ,0x00 ,0x79 ,0x01 ,0x00 ,0x00 ,0x75 ,0x03 ,0x03 ,0x59 ,0x11 ,0xae ,0xef ,0x4f + ,0x6f ,0x5f ,0xd7 ,0x0f ,0x50 ,0x7c ,0x05 ,0x37 ,0xe3 ,0xd9 ,0x47 ,0x82 ,0x8e ,0x64 ,0x75 ,0x3c + ,0xa4 ,0xca ,0xef ,0x45 ,0x25 ,0x4e ,0x36 ,0xdf ,0x5d ,0xbf ,0x96 ,0x00 ,0x00 ,0x04 ,0xc0 ,0xac + ,0x00 ,0xff ,0x01 ,0x00 ,0x00 ,0x48 ,0x00 ,0x0d ,0x00 ,0x16 ,0x00 ,0x14 ,0x06 ,0x03 ,0x06 ,0x01 + ,0x05 ,0x03 ,0x05 ,0x01 ,0x04 ,0x03 ,0x04 ,0x01 ,0x03 ,0x03 ,0x03 ,0x01 ,0x02 ,0x03 ,0x02 ,0x01 + ,0x00 ,0x0a ,0x00 ,0x18 ,0x00 ,0x16 ,0x00 ,0x19 ,0x00 ,0x1c ,0x00 ,0x18 ,0x00 ,0x1b ,0x00 ,0x17 + ,0x00 ,0x16 ,0x00 ,0x1a ,0x00 ,0x15 ,0x00 ,0x14 ,0x00 ,0x13 ,0x00 ,0x12 ,0x00 ,0x0b ,0x00 ,0x02 + ,0x01 ,0x00 ,0x00 ,0x16 ,0x00 ,0x00 ,0x00 ,0x17 ,0x00 ,0x00 ,0x00 ,0x23 ,0x00 ,0x00}; + + size_t sent = 0; + for(i = 0; i < RETRY_COUNT; i++) + { + status = pal_send(_socket, message, sizeof(message), &sent); + if(status == PAL_SUCCESS) + { + break; + } + pal_osDelay(100); + } + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + } + + /*#10*/ + pal_close(&_socket); +} + +PAL_PRIVATE void fillUDPTestBuffer(pal_udp_test_data_t *data, uint8_t* buffer) +{ + memset(buffer, 0, data->bufferSize); + data->chunkSize = (data->messageSize - data->totalSize > data->bufferSize) ? data->bufferSize : (data->messageSize - data->totalSize); + memset(buffer, ++(data->currentValue), data->chunkSize); + data->totalSize += data->chunkSize; +} + +// UDP test sender thread function. +PAL_PRIVATE void socketUDPBufferedTestSender(const void *arg) +{ + palStatus_t result = PAL_SUCCESS; + pal_udp_test_data_t *data = (pal_udp_test_data_t*)arg; // cast from const to non-const + size_t sent = 0, totalSent = 0; + + g_testSendBuffer = (uint8_t*)malloc(sizeof(uint8_t) * data->bufferSize); + TEST_ASSERT_NOT_EQUAL(NULLPTR, g_testSendBuffer); + + data->totalSize = 0; + data->chunkSize = 0; + data->currentValue = data->startValue; + while (totalSent != data->messageSize) + { + fillUDPTestBuffer(data, g_testSendBuffer); + result = pal_sendTo(g_testSockets[0], g_testSendBuffer, data->chunkSize, &(data->interfaceInfo.address), data->interfaceInfo.addressSize, &sent); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + totalSent += sent; + pal_osDelay(5); // allow some time for the RX bits to be set + }; + + free(g_testSendBuffer); + g_testSendBuffer = NULLPTR; +} + +/*! \brief Test UDP socket read in chunks +* +* \note The test generates data and calculates its hash, then this data is re-generated from a dedicated thread and +* received on the current thread which calculates the received data hash and compares it to the original hash +* +* @param[in] bufSize - the read buffer size +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the MD context. | PAL_SUCCESS | +* | 2 | Allocate buffer. | PAL_SUCCESS | +* | 3 | Generate data incrementally and update the MD context. | PAL_SUCCESS | +* | 4 | Get the hash output size and validate it. | PAL_SUCCESS | +* | 5 | Get the calculated hash. | PAL_SUCCESS | +* | 6 | Free the MD context resources. | PAL_SUCCESS | +* | 7 | Get the interface address. | PAL_SUCCESS | +* | 8 | Create a (blocking) UDP socket. | PAL_SUCCESS | +* | 9 | Set the socket port and set send/receive timeouts. | PAL_SUCCESS | +* | 10 | Bind the socket. | PAL_SUCCESS | +* | 11 | Initialize the MD context. | PAL_SUCCESS | +* | 12 | Launch the data sender thread. | PAL_SUCCESS | +* | 13 | Read data from the socket until there's no more data or all data has been received. | PAL_SUCCESS | +* | 14 | Update the MD context. | PAL_SUCCESS | +* | 15 | Terminate the sending thread. | PAL_SUCCESS | +* | 16 | Close the socket. | PAL_SUCCESS | +* | 17 | Get the hash output size and validate it. | PAL_SUCCESS | +* | 18 | Get the calculated hash and compare it. | PAL_SUCCESS | +* | 19 | Free the MD context resources. | PAL_SUCCESS | +* | 20 | Free allocated buffer. | PAL_SUCCESS | +*/ +PAL_PRIVATE void socketUDPBuffered(size_t bufSize) +{ + palStatus_t result = PAL_SUCCESS; + pal_udp_test_data_t data = { PAL_NET_TEST_BUFFERED_UDP_MESSAGE_SIZE, bufSize, 0 }; + uint8_t expectedHash[PAL_SHA256_SIZE] = { 0 }, actualHash[PAL_SHA256_SIZE] = { 0 }; + size_t read = 0, totalRead = 0, hashlen = 0; + int timeout = 1000; + palMDHandle_t handle = NULLPTR; + palThreadID_t thread = NULLPTR; + + /*#1*/ + result = pal_mdInit(&handle, PAL_SHA256); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_NOT_EQUAL(NULLPTR, handle); + + /*#2*/ + g_testRecvBuffer = (uint8_t*)malloc(sizeof(uint8_t) * bufSize); + TEST_ASSERT_NOT_EQUAL(NULLPTR, g_testRecvBuffer); + + /*#3*/ + data.totalSize = data.chunkSize = 0; + data.currentValue = data.startValue; + while (data.totalSize != data.messageSize) + { + fillUDPTestBuffer(&data, g_testRecvBuffer); + result = pal_mdUpdate(handle, g_testRecvBuffer, data.chunkSize); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + }; + + /*#4*/ + result = pal_mdGetOutputSize(handle, &hashlen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(PAL_SHA256_SIZE, hashlen); + + /*#5*/ + result = pal_mdFinal(handle, expectedHash); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#6*/ + result = pal_mdFree(&handle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#7*/ + memset(&(data.interfaceInfo), 0, sizeof(data.interfaceInfo)); + result = pal_getNetInterfaceInfo(0, &(data.interfaceInfo)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#8*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_DGRAM, false, 0, &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#9*/ + result = pal_setSockAddrPort(&(data.interfaceInfo.address), PAL_NET_TEST_BUFFERED_UDP_PORT); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_RCVTIMEO, &timeout, sizeof(timeout)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_SNDTIMEO, &timeout, sizeof(timeout)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#10*/ + result = pal_bind(g_testSockets[0], &(data.interfaceInfo.address), data.interfaceInfo.addressSize); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#11*/ + handle = NULLPTR; + result = pal_mdInit(&handle, PAL_SHA256); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_NOT_EQUAL(NULLPTR, handle); + + /*#12*/ + result = pal_osThreadCreateWithAlloc(socketUDPBufferedTestSender, &data, PAL_osPriorityNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &thread); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_NOT_EQUAL(NULLPTR, thread); + + /*#13*/ + do + { + read = 0; + memset(g_testRecvBuffer, 0, data.bufferSize); + result = pal_receiveFrom(g_testSockets[0], g_testRecvBuffer, data.bufferSize, &(data.interfaceInfo.address), &(data.interfaceInfo.addressSize), &read); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + /*#14*/ + result = pal_mdUpdate(handle, g_testRecvBuffer, read); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + totalRead += read; + } while (read > 0 && totalRead < data.messageSize); + + /*#15*/ + result = pal_osThreadTerminate(&thread); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#16*/ + result = pal_close(&g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#17*/ + hashlen = 0; + result = pal_mdGetOutputSize(handle, &hashlen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(PAL_SHA256_SIZE, hashlen); + + /*#18*/ + result = pal_mdFinal(handle, actualHash); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_MEMORY(expectedHash, actualHash, PAL_SHA256_SIZE); + + /*#19*/ + result = pal_mdFree(&handle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#20*/ + free(g_testRecvBuffer); + g_testRecvBuffer = NULLPTR; +} + +/*! \brief Test function UDP socket read in small chunks +* +** \test +*/ +TEST(pal_socket, socketUDPBufferedSmall) +{ + socketUDPBuffered(PAL_NET_TEST_BUFFERED_UDP_BUF_SIZE_SMALL); +} + +/*! \brief Test function UDP socket read in large chunks +* +** \test +*/ +TEST(pal_socket, socketUDPBufferedLarge) +{ + socketUDPBuffered(PAL_NET_TEST_BUFFERED_UDP_BUF_SIZE_LARGE); +} + +#ifdef __LINUX__ // Linux CI tests for socketTCPBufferedSmall & socketTCPBufferedLarge must use an ipv4 address in order to connect to the external host +PAL_PRIVATE palStatus_t getAddressInfoIPv4(char const *url, palSocketAddress_t *address, palSocketLength_t* addressLength) +{ + struct addrinfo *info = NULLPTR; + struct addrinfo hints = { 0 }; + struct sockaddr_in *sockAddress = NULLPTR; + palIpV4Addr_t ipV4Address = { 0 }; + int ret; + palStatus_t result; + + hints.ai_family = AF_INET; + ret = getaddrinfo(url, NULL, &hints, &info); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_NOT_EQUAL(NULLPTR, info); + TEST_ASSERT_EQUAL(AF_INET, info->ai_family); + + sockAddress = (struct sockaddr_in*)info->ai_addr; + memcpy(ipV4Address, &(sockAddress->sin_addr), PAL_IPV4_ADDRESS_SIZE); + freeaddrinfo(info); + + result = pal_setSockAddrIPV4Addr(address, ipV4Address); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + *addressLength = sizeof(struct sockaddr_in); + return result; +} +#endif + +/*! \brief Test TCP socket read in chunks +* +* \note The test attempts to perform an HTTP get request to a google (jquery) CDN, read the file in chunks (ignoring HTTP headers) and compare its hash to a pre-known hash using SHA256. +* +* @param[in] bufSize - the read buffer size +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a (blocking) TCP socket. | PAL_SUCCESS | +* | 2 | Look up the IP address of the CDN server. | PAL_SUCCESS | +* | 3 | Set the port to the CDN server's HTTP port and set send/receive timeouts. | PAL_SUCCESS | +* | 4 | Connect the socket to the CDN server. | PAL_SUCCESS | +* | 5 | Send an HTTP get request to the CDN server. | PAL_SUCCESS | +* | 6 | Initialize the MD context. | PAL_SUCCESS | +* | 7 | Allocate HTTP response buffer. | PAL_SUCCESS | +* | 8 | Read the server's response until there's no more data to read. | PAL_SUCCESS | +* | 9 | If we're done dealing with the HTTP headers then update the MD context. | PAL_SUCCESS | +* | 10 | Locate the end of the HTTP headers in the server's response (HTTP headers end with a double CRLF). | PAL_SUCCESS | +* | 11 | Update the MD context. | PAL_SUCCESS | +* | 12 | Close the socket. | PAL_SUCCESS | +* | 13 | Get the hash output size and validate it. | PAL_SUCCESS | +* | 14 | Get the calculated hash and compare it to the pre-known hash. | PAL_SUCCESS | +* | 15 | Free the MD context resources. | PAL_SUCCESS | +* | 16 | Free HTTP response buffer. | PAL_SUCCESS | +*/ +PAL_PRIVATE void socketTCPBuffered(size_t bufSize) +{ + palStatus_t result = PAL_SUCCESS; + palSocketAddress_t address = { 0 }; + palSocketLength_t addrlen = 0; + int timeout = 5000; + uint8_t next = '\r', state = 0; + size_t read = 0, sent = 0, hashlen = 0; + bool body = false; + palMDHandle_t handle = NULLPTR; + uint8_t actualHash[PAL_SHA256_SIZE] = { 0 }; + const uint8_t expectedHash[] = // pre-calculated jquery.js 3.2.1 SHA256 + { + 0x0d, 0x90, 0x27, 0x28, 0x9f, 0xfa, 0x5d, 0x9f, 0x6c, 0x8b, 0x4e, 0x07, 0x82, 0xbb, 0x31, 0xbb, + 0xff, 0x2c, 0xef, 0x5e, 0xe3, 0x70, 0x8c, 0xcb, 0xcb, 0x7a, 0x22, 0xdf, 0x91, 0x28, 0xbb, 0x21 + }; + + /*#1*/ + result = pal_socket(PAL_AF_INET, PAL_SOCK_STREAM, false, 0, &g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#2*/ + result = test_getAddressInfo(PAL_NET_TEST_GOOGLE_CDN_HOST, &address, &addrlen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#3*/ + result = pal_setSockAddrPort(&address, PAL_NET_TEST_GOOGLE_CDN_HOST_PORT); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_SNDTIMEO, &timeout, sizeof(timeout)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + result = pal_setSocketOptions(g_testSockets[0], PAL_SO_RCVTIMEO, &timeout, sizeof(timeout)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#4*/ + result = pal_connect(g_testSockets[0], &address, addrlen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#5*/ + result = pal_send(g_testSockets[0], PAL_NET_TEST_GOOGLE_CDN_REQUEST, sizeof(PAL_NET_TEST_GOOGLE_CDN_REQUEST) - 1, &sent); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#6*/ + result = pal_mdInit(&handle, PAL_SHA256); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_NOT_EQUAL(NULLPTR, handle); + + /*#7*/ + g_testRecvBuffer = (uint8_t*)malloc(sizeof(uint8_t) * bufSize + 1); + TEST_ASSERT_NOT_EQUAL(NULLPTR, g_testRecvBuffer); + + /*#8*/ + do + { + read = 0; + memset(g_testRecvBuffer, 0, bufSize + 1); + result = pal_recv(g_testSockets[0], g_testRecvBuffer, bufSize, &read); + TEST_ASSERT_TRUE((PAL_SUCCESS == result && read > 0) || (PAL_ERR_SOCKET_CONNECTION_CLOSED == result && read == 0)); + + /*#9*/ + if (body) + { + result = pal_mdUpdate(handle, g_testRecvBuffer, read); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + continue; + } + + /*#10*/ + for (size_t i = 0; i < bufSize; i++) // dealing with the HTTP headers - headers end on a double CRLF + { + if (g_testRecvBuffer[i] == next) + { + next = (next == '\r') ? '\n' : '\r'; + state = state | (state + 1); + if (state == 0xf) + { + /*#11*/ + body = true; + result = pal_mdUpdate(handle, (g_testRecvBuffer + i + 1), strlen(((char*)g_testRecvBuffer) + i + 1)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + break; + } + } + else if (state != 0) + { + next = '\r'; + state = 0; + } + } + } while (read > 0); + + /*#12*/ + result = pal_close(&g_testSockets[0]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#13*/ + result = pal_mdGetOutputSize(handle, &hashlen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_HEX(PAL_SHA256_SIZE, hashlen); + + /*#14*/ + result = pal_mdFinal(handle, actualHash); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + TEST_ASSERT_EQUAL_MEMORY(expectedHash, actualHash, PAL_SHA256_SIZE); + + /*#15*/ + result = pal_mdFree(&handle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, result); + + /*#16*/ + free(g_testRecvBuffer); + g_testRecvBuffer = NULLPTR; +} + +/*! \brief Test function TCP socket read in small chunks +* +** \test +*/ +TEST(pal_socket, socketTCPBufferedSmall) +{ + socketTCPBuffered(PAL_NET_TEST_BUFFERED_TCP_BUF_SIZE_SMALL); +} + +/*! \brief Test function TCP socket read in large chunks +* +** \test +*/ +TEST(pal_socket, socketTCPBufferedLarge) +{ + socketTCPBuffered(PAL_NET_TEST_BUFFERED_TCP_BUF_SIZE_LARGE); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Networking/pal_socket_test_runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Networking/pal_socket_test_runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "unity.h" +#include "unity_fixture.h" + +#define PAL_RUN_ALL_TESTS 1 + +// pal Socket API tests +TEST_GROUP_RUNNER(pal_socket) +{ + RUN_TEST_CASE(pal_socket, socketUDPCreationOptionsTest); + RUN_TEST_CASE(pal_socket, basicTCPclientSendRecieve); + RUN_TEST_CASE(pal_socket, basicUDPclientSendRecieve); + RUN_TEST_CASE(pal_socket, basicSocketScenario3); + RUN_TEST_CASE(pal_socket, basicSocketScenario4); + RUN_TEST_CASE(pal_socket, tProvUDPTest); + RUN_TEST_CASE(pal_socket, nonBlockingAsyncTest); + RUN_TEST_CASE(pal_socket, ServerSocketScenario); + RUN_TEST_CASE(pal_socket, PalMiniSelectNoBlockingTcpConnection); + RUN_TEST_CASE(pal_socket, socketTCPBufferedSmall); + RUN_TEST_CASE(pal_socket, socketTCPBufferedLarge); + RUN_TEST_CASE(pal_socket, socketUDPBufferedSmall); + RUN_TEST_CASE(pal_socket, socketUDPBufferedLarge); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/RTOS/pal_rtos_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/RTOS/pal_rtos_test.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1194 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pal.h" +#include "unity.h" +#include "unity_fixture.h" +#include "pal_rtos_test_utils.h" +#include <string.h> +#include <stdlib.h> + + + +TEST_GROUP(pal_rtos); + +//Sometimes you may want to get local data in a module, +//for example if you need to pass a reference. +//However, you should usually avoid this. +//extern int Counter; +palThreadLocalStore_t g_threadStorage = {NULL}; +threadsArgument_t g_threadsArg = {0}; +timerArgument_t g_timerArgs = {0}; +palMutexID_t mutex1 = NULLPTR; +palMutexID_t mutex2 = NULLPTR; +palSemaphoreID_t semaphore1 = NULLPTR; +palRecursiveMutexParam_t* recursiveMutexData = NULL; +#define PAL_TEST_HIGH_RES_TIMER 100 +#define PAL_TEST_HIGH_RES_TIMER2 10 +#define PAL_TEST_PERCENTAGE_LOW 95 +#define PAL_TEST_PERCENTAGE_HIGH 105 +#define PAL_TEST_PERCENTAGE_HUNDRED 100 + +//Forward declarations +void palRunThreads(void); + + +TEST_SETUP(pal_rtos) +{ + pal_init(); +} + +TEST_TEAR_DOWN(pal_rtos) +{ + if (NULL != recursiveMutexData) + { + if (recursiveMutexData->higherPriorityThread != NULLPTR) + { + pal_osThreadTerminate(&(recursiveMutexData->higherPriorityThread)); + } + if (recursiveMutexData->lowerPriorityThread != NULLPTR) + { + pal_osThreadTerminate(&(recursiveMutexData->lowerPriorityThread)); + } + if (recursiveMutexData->mtx != NULLPTR) + { + pal_osMutexDelete(&(recursiveMutexData->mtx)); + } + if (recursiveMutexData->sem != NULLPTR) + { + pal_osSemaphoreDelete(&recursiveMutexData->sem); + } + free(recursiveMutexData); + recursiveMutexData = NULL; + } + pal_destroy(); +} + +/*! \brief Sanity check of the kernel system tick API. + * Fails if system tic value is zero (**note:** this can sometimes happen on wrap-around). + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Get current tick count using `pal_osKernelSysTick` and check that it is not 0. | PAL_SUCCESS | + */ +TEST(pal_rtos, pal_osKernelSysTick_Unity) +{ + uint32_t tick1 = 0, tick2 = 0; + /*#1*/ + tick1 = pal_osKernelSysTick(); + TEST_PRINTF("%" PRIu32 " %" PRIu32 "\n", tick1, tick2); + + TEST_ASSERT_TRUE(tick2 != tick1); +} + +/*! \brief Sanity check of the kernel system tick API. + * Fails if two calls return the same `sysTick` value. + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Get current tick count using `pal_osKernelSysTick`. | PAL_SUCCESS | + * | 2 | Get current tick count using `pal_osKernelSysTick`. | PAL_SUCCESS | + * | 3 | Check that the two tick count values are not the same. | PAL_SUCCESS | + */ +TEST(pal_rtos, pal_osKernelSysTick64_Unity) +{ + uint64_t tick1 = 0, tick2 = 0; + /*#1*/ + tick1 = pal_osKernelSysTick(); + /*#2*/ + tick2 = pal_osKernelSysTick(); + /*#3*/ + TEST_ASSERT_TRUE(tick2 >= tick1); +} + +/*! \brief Check the conversion from a non-zero `sysTick` value to microseconds. + * Verify that the result is not 0. + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Convert a nubmer in `sysTicks` to microseconds using `pal_osKernelSysTickMicroSec` and check it is not 0. | PAL_SUCCESS | + */ +TEST(pal_rtos, pal_osKernelSysTickMicroSec_Unity) +{ + uint64_t tick = 0; + uint64_t microSec = 2000 * 1000; + /*#1*/ + tick = pal_osKernelSysTickMicroSec(microSec); + TEST_ASSERT_TRUE(0 != tick); +} + +/*! \brief Sanity check of non-zero values conversion between microseconds to ticks to milliseconds. + * Verify that the result is correct when converting the input (microseconds) to the test output (milliseconds). + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Convert a nubmer in `sysTicks` to mircorseconds using `pal_osKernelSysTickMicroSec` and check it is not 0. | PAL_SUCCESS | + * | 2 | Convert a nubmer in `sysTicks` to milliseconds using `pal_osKernelSysMilliSecTick` and check the returned value. | PAL_SUCCESS | + */ +TEST(pal_rtos, pal_osKernelSysMilliSecTick_Unity) +{ + uint64_t tick = 0; + uint64_t microSec = 2000 * 1000; + uint64_t milliseconds = 0; + /*#1*/ + tick = pal_osKernelSysTickMicroSec(microSec); + TEST_ASSERT_TRUE(0 != tick); + /*#2*/ + milliseconds = pal_osKernelSysMilliSecTick(tick); + TEST_ASSERT_EQUAL(microSec/1000, milliseconds); +} + +/*! \brief Verify that the tick frequency function returns a non-zero value. + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Get the kernel `sysTick` frequency and check that it is positive. | PAL_SUCCESS | + */ +TEST(pal_rtos, pal_osKernelSysTickFrequency_Unity) +{ + uint64_t frequency = 0; + /*#1*/ + frequency = pal_osKernelSysTickFrequency(); + + TEST_ASSERT_TRUE(frequency > 0); +} + +/*! \brief Sanity check for the Delay API, verifying that `sysTick` increments after delay. + * The test reads two system tick values. Between the two calls, it calls the delay function and + * verifies that the tick values are different. + * + * | # | Step | Expected | + * |---|--------------------------------|-------------| + * | 1 | Get the kernel `sysTick` value. | PAL_SUCCESS | + * | 2 | Sleep for a short period . | PAL_SUCCESS | + * | 3 | Get the kernel `sysTick` value. | PAL_SUCCESS | + * | 4 | Check that second tick value is greater than the first. | PAL_SUCCESS | + */ +TEST(pal_rtos, pal_osDelay_Unity) +{ + palStatus_t status = PAL_SUCCESS; + uint32_t tick1 , tick2; + /*#1*/ + tick1 = pal_osKernelSysTick(); + /*#2*/ + status = pal_osDelay(200); + /*#3*/ + tick2 = pal_osKernelSysTick(); + /*#4*/ + TEST_ASSERT_TRUE(tick2 > tick1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + +/*! \brief Test for basic timing scenarios based on calls for the ticks and delay +* functionality while verifying that results meet the defined deltas. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Get the kernel `sysTick` value. | PAL_SUCCESS | +* | 2 | Sleep for a very short period. | PAL_SUCCESS | +* | 3 | Get the kernel `sysTick` value. | PAL_SUCCESS | +* | 4 | Check that second tick value is greater than the first. | PAL_SUCCESS | +* | 5 | Get the kernel `sysTick` value. | PAL_SUCCESS | +* | 6 | Sleep for a longer period. | PAL_SUCCESS | +* | 7 | Get the kernel `sysTick` value. | PAL_SUCCESS | +* | 8 | Check that second tick value is greated than the first. | PAL_SUCCESS | +* | 9 | Calculate the difference between the ticks. | PAL_SUCCESS | +* | 10 | Convert last sleep period to ticks. | PAL_SUCCESS | +* | 11 | Check that the tick period is correct (same as sleep period +/-delta). | PAL_SUCCESS | +*/ +TEST(pal_rtos, BasicTimeScenario) +{ + palStatus_t status = PAL_SUCCESS; + uint64_t tick, tick1 , tick2 , tickDiff, tickDelta; + + /*#1*/ + tick1 = pal_osKernelSysTick(); + /*#2*/ + status = pal_osDelay(1); + /*#3*/ + tick2 = pal_osKernelSysTick(); + + /*#4*/ + TEST_ASSERT_TRUE(tick1 != tick2); + TEST_ASSERT_TRUE(tick2 > tick1); // To check that the tick counts are incremental - be aware of wrap-arounds + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /****************************************/ + /*#5*/ + tick1 = pal_osKernelSysTick(); + /*#6*/ + status = pal_osDelay(2000); + /*#7*/ + tick2 = pal_osKernelSysTick(); + + /*#8*/ + TEST_ASSERT_TRUE(tick1 != tick2); + TEST_ASSERT_TRUE(tick2 > tick1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#9*/ + tickDiff = tick2 - tick1; + /*#10*/ + tick = pal_osKernelSysTickMicroSec(2000 * 1000); + // 10 milliseconds delta + /*#11*/ + tickDelta = pal_osKernelSysTickMicroSec(10 * 1000); + TEST_ASSERT_TRUE((tick - tickDelta < tickDiff) && (tickDiff < tick + tickDelta)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + +/*! \brief Create two timers: periodic and one-shot. Starts both timers, +* then causes a delay to allow output from the timer functions to be printed on the console. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a one-shot timer, which calls `palTimerFunc1` when triggered, using `pal_osTimerCreate`. | PAL_SUCCESS | +* | 2 | Create a periodic timer, which calls `palTimerFunc2` when triggered, using `pal_osTimerCreate`. | PAL_SUCCESS | +* | 3 | Get the kernel `sysTick` value. | PAL_SUCCESS | +* | 4 | Start the first timer using `pal_osTimerStart`. | PAL_SUCCESS | +* | 5 | Get the kernel `sysTick` value. | PAL_SUCCESS | +* | 6 | Start the first timer using `pal_osTimerStart`. | PAL_SUCCESS | +* | 7 | Sleep for a period. | PAL_SUCCESS | +* | 8 | Stop the second timer using `pal_osTimerStop`. | PAL_SUCCESS | +* | 9 | Delete the first timer using `pal_osTimerDelete`. | PAL_SUCCESS | +* | 10 | Delete the second timer using `pal_osTimerDelete`. | PAL_SUCCESS | +* | 11 | Create a periodic timer, which calls `palTimerFunc3` when triggered, using `pal_osTimerCreate`. | PAL_SUCCESS | +* | 12 | Create a periodic timer, which calls `palTimerFunc4` when triggered, using `pal_osTimerCreate`. | PAL_ERR_NO_HIGH_RES_TIMER_LEFT | +* | 13 | Start the first timer using `pal_osTimerStart` as high res timer. | PAL_SUCCESS | +* | 14 | Start the second timer using `pal_osTimerStart` as high res timer. | PAL_ERR_NO_HIGH_RES_TIMER_LEFT | +* | 15 | Sleep for a period. | PAL_SUCCESS | +* | 16 | Stop the second timer using `pal_osTimerStop`. | PAL_SUCCESS | +* | 17 | Start the second timer using `pal_osTimerStart` as high res timer | PAL_SUCCESS | +* | 18 | Sleep for a period. | PAL_SUCCESS | +* | 19 | Delete the first timer using `pal_osTimerDelete`. | PAL_SUCCESS | +* | 20 | Delete the second timer using `pal_osTimerDelete`. | PAL_SUCCESS | +* | 21 | Create a periodic timer, which calls `palTimerFunc5` when triggered, using `pal_osTimerCreate`. | PAL_SUCCESS | +* | 22 | Sleep for a period. | PAL_SUCCESS | +* | 23 | Delete the first timer using `pal_osTimerDelete`. | PAL_SUCCESS | +* | 24 | Stop the timer using `pal_osTimerStop`. and check the number of callbacks is correct | PAL_SUCCESS | +* | 25 | Delete the timer using `pal_osTimerDelete`. | PAL_SUCCESS | +*/ +TEST(pal_rtos, TimerUnityTest) +{ + palStatus_t status = PAL_SUCCESS; + palTimerID_t timerID1 = NULLPTR; + palTimerID_t timerID2 = NULLPTR; + /*#1*/ + status = pal_osTimerCreate(palTimerFunc1, NULL, palOsTimerOnce, &timerID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_osTimerCreate(palTimerFunc2, NULL, palOsTimerPeriodic, &timerID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + g_timerArgs.ticksBeforeTimer = pal_osKernelSysTick(); + /*#4*/ + status = pal_osTimerStart(timerID1, 1000); + TEST_PRINTF("ticks before Timer: 0 - %" PRIu32 "\n", g_timerArgs.ticksBeforeTimer); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#5*/ + g_timerArgs.ticksBeforeTimer = pal_osKernelSysTick(); + /*#6*/ + status = pal_osTimerStart(timerID2, 1000); + TEST_PRINTF("ticks before Timer: 1 - %" PRIu32 "\n", g_timerArgs.ticksBeforeTimer); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#7*/ + status = pal_osDelay(1500); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#8*/ + status = pal_osTimerStop(timerID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#9*/ + status = pal_osTimerDelete(&timerID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(NULL, timerID1); + /*#10*/ + status = pal_osTimerDelete(&timerID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(NULL, timerID2); + + g_timerArgs.ticksBeforeTimer = 0; + g_timerArgs.ticksInFunc1 = 0; + g_timerArgs.ticksInFunc2 = 0; + + /*#11*/ + status = pal_osTimerCreate(palTimerFunc3, NULL, palOsTimerPeriodic, &timerID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#12*/ + status = pal_osTimerCreate(palTimerFunc4, NULL, palOsTimerPeriodic, &timerID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#13*/ + status = pal_osTimerStart(timerID1, PAL_TEST_HIGH_RES_TIMER); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#14*/ + status = pal_osTimerStart(timerID2, PAL_TEST_HIGH_RES_TIMER); + if (PAL_SUCCESS == status) // behavior is slightly different for Linux due to high res timer limitation there (only one at a time supported there) + { + status = pal_osTimerStop(timerID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + else + { + TEST_ASSERT_EQUAL_HEX(PAL_ERR_NO_HIGH_RES_TIMER_LEFT, status); + } + /*#15*/ + status = pal_osDelay(500); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#16*/ + status = pal_osTimerStop(timerID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#17*/ + status = pal_osTimerStart(timerID2, PAL_TEST_HIGH_RES_TIMER2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#18*/ + status = pal_osDelay(PAL_TIME_TO_WAIT_SHORT_MS); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osTimerStop(timerID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + TEST_ASSERT_TRUE(g_timerArgs.ticksInFunc1 >= ((PAL_TIME_TO_WAIT_SHORT_MS / PAL_TEST_HIGH_RES_TIMER2)*PAL_TEST_PERCENTAGE_LOW)/ PAL_TEST_PERCENTAGE_HUNDRED); // check there is at least more than 95% of expected timer callbacks. + + /*#19*/ + status = pal_osTimerDelete(&timerID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(NULL, timerID1); + + /*#20*/ + status = pal_osTimerDelete(&timerID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(NULL, timerID2); + + /*#21*/ + g_timerArgs.ticksBeforeTimer = 0; + g_timerArgs.ticksInFunc1 = 0; + g_timerArgs.ticksInFunc2 = 0; + + status = pal_osTimerCreate(palTimerFunc5, NULL, palOsTimerPeriodic, &timerID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#22*/ + status = pal_osTimerStart(timerID1, PAL_TEST_HIGH_RES_TIMER); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#23*/ + status = pal_osDelay(PAL_TIME_TO_WAIT_MS); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#24*/ + status = pal_osTimerStop(timerID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + TEST_ASSERT_TRUE(g_timerArgs.ticksInFunc1 >= ((PAL_TIME_TO_WAIT_MS / PAL_TEST_HIGH_RES_TIMER) * PAL_TEST_PERCENTAGE_LOW) / PAL_TEST_PERCENTAGE_HUNDRED); // check there is at least more than 95% of expected timer callbacks. + TEST_ASSERT_TRUE(g_timerArgs.ticksInFunc1 <= ((PAL_TIME_TO_WAIT_MS / PAL_TEST_HIGH_RES_TIMER) * PAL_TEST_PERCENTAGE_HIGH) / PAL_TEST_PERCENTAGE_HUNDRED); // check there is at most less than 105% of expected timer callbacks. + + /*#25*/ + status = pal_osTimerDelete(&timerID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(NULL, timerID1); +} + +/*! \brief Creates mutexes and semaphores and uses them to communicate between +* the different threads it creates (as defined in `pal_rtos_test_utils.c`). +* In this test, we check that thread communication is working as expected between the threads and in the designed order. +* In one case, we expect the thread to fail to lock a mutex â (thread1). +* Threads are created with different priorities (PAL enforces this attribute). +* For each case, the thread function prints the expected result. The test code verifies this result as well. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a mutex using `pal_osMutexCreate`. | PAL_SUCCESS | +* | 2 | Create a mutex using `pal_osMutexCreate`. | PAL_SUCCESS | +* | 3 | Create a semaphore with count 1. | PAL_SUCCESS | +* | 4 | Run the PAL test threads using the `palRunThreads` test function. | PAL_SUCCESS | +* | 5 | Delete the semaphore using `pal_osSemaphoreDelete`. | PAL_SUCCESS | +* | 6 | Delete the first mutex using `pal_osMutexDelete`. | PAL_SUCCESS | +* | 7 | Delete the second mutex using `pal_osMutexDelete`. | PAL_SUCCESS | +*/ +TEST(pal_rtos, PrimitivesUnityTest1) +{ + palStatus_t status = PAL_SUCCESS; + /*#1*/ + status = pal_osMutexCreate(&mutex1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_osMutexCreate(&mutex2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_osSemaphoreCreate(1 ,&semaphore1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + palRunThreads(); + /*#5*/ + status = pal_osSemaphoreDelete(&semaphore1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(NULL, semaphore1); + /*#6*/ + status = pal_osMutexDelete(&mutex1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(NULL, mutex1); + /*#7*/ + status = pal_osMutexDelete(&mutex2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(NULL, mutex2); + +} + +/*! \brief Verifies that several RTOS primitives APIs can handle invalid +* arguments. The test calls each API with invalid arguments and verifies the result. +* It also verifies that the semaphore wait API can accept NULL as the third parameter. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Test thread creation with invalid arguments (`pal_osThreadCreateWithAlloc`). | PAL_ERR_INVALID_ARGUMENT | +* | 2 | Test thread creation with invalid arguments (`pal_osThreadCreateWithAlloc`). | PAL_ERR_INVALID_ARGUMENT | +* | 3 | Test thread creation with invalid arguments (`pal_osThreadCreateWithAlloc`). | PAL_ERR_INVALID_ARGUMENT | +* | 4 | Test semaphore creation with invalid arguments (`pal_osSemaphoreCreate`). | PAL_ERR_INVALID_ARGUMENT | +* | 5 | Test semaphore creation with invalid arguments (`pal_osSemaphoreCreate`). | PAL_ERR_INVALID_ARGUMENT | +* | 6 | Test semaphore creation with invalid arguments (`pal_osSemaphoreCreate`). | PAL_ERR_INVALID_ARGUMENT | +* | 7 | Test semaphore creation with invalid arguments (`pal_osSemaphoreCreate`). | PAL_ERR_INVALID_ARGUMENT | +*/ +TEST(pal_rtos, PrimitivesUnityTest2) +{ + palStatus_t status = PAL_SUCCESS; + int32_t tmp = 0; + palThreadID_t threadID = NULLPTR; + + /*#1*/ + //Check thread parameter validation + status = pal_osThreadCreateWithAlloc(palThreadFunc1, NULL, PAL_osPriorityError, 1024, NULL, &threadID); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + /*#2*/ + status = pal_osThreadCreateWithAlloc(palThreadFunc1, NULL, PAL_osPriorityIdle, 0, NULL, &threadID); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + /*#3*/ + status = pal_osThreadCreateWithAlloc(palThreadFunc1, NULL, PAL_osPriorityIdle, 1024, NULL, NULL); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + + /*#4*/ + //Check semaphore parameter validation + status = pal_osSemaphoreCreate(1 ,NULL); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + /*#5*/ + status = pal_osSemaphoreDelete(NULL); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + /*#6*/ + status = pal_osSemaphoreWait(NULLPTR, 1000, &tmp); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + /*#7*/ + status = pal_osSemaphoreRelease(NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); +} + +/*! \brief Creates a semaphore with count=1 and a thread to +* test that it waits forever (the test waits 5 seconds). Then deletes the semaphore +* and terminates the thread. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a semaphore with count = 1 using `pal_osSemaphoreCreate`. | PAL_SUCCESS | +* | 2 | Wait for the semaphore using `pal_osSemaphoreWait` (should not block). | PAL_SUCCESS | +* | 3 | Create a thread running `palThreadFuncWaitForEverTestusing` and `pal_osThreadCreateWithAlloc`. | PAL_SUCCESS | +* | 4 | Set time using `pal_osSetTime`. | PAL_SUCCESS | +* | 5 | Wait for the semaphore using `pal_osSemaphoreWait` (should block; released by thread). | PAL_SUCCESS | +* | 6 | Delete the semaphore using `pal_osSemaphoreDelete`. | PAL_SUCCESS | +* | 7 | Terminate the thread using `pal_osThreadTerminate`. | PAL_SUCCESS | +*/ +TEST(pal_rtos, SemaphoreWaitForever) +{ + int32_t count = 0; + uint64_t timeElapsed = PAL_MIN_SEC_FROM_EPOCH; + uint64_t timePassedInSec; + palStatus_t status = PAL_SUCCESS; + palThreadID_t threadID1 = PAL_INVALID_THREAD; + + /*#1*/ + status = pal_osSemaphoreCreate(1 ,&semaphore1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_osSemaphoreWait(semaphore1, PAL_RTOS_WAIT_FOREVER, &count); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_osSetTime(timeElapsed); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); // More than current epoch time -> success + status = pal_osThreadCreateWithAlloc(palThreadFuncWaitForEverTest, (void *)&semaphore1, PAL_osPriorityAboveNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + status = pal_osSemaphoreWait(semaphore1, PAL_RTOS_WAIT_FOREVER, &count); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#5*/ + timePassedInSec = pal_osGetTime(); + TEST_ASSERT_EQUAL_HEX(0, (timePassedInSec - timeElapsed) >= PAL_TIME_TO_WAIT_MS/2); + /*#6*/ + status = pal_osSemaphoreDelete(&semaphore1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(0, semaphore1); + /*#7*/ + status = pal_osThreadTerminate(&threadID1); + TEST_ASSERT_EQUAL(PAL_SUCCESS, status); +} + +/*! \brief Creates a semaphore and waits on it to verify the +* available count for it. Also verifies that the semaphore release API works correctly. +* In addition, it checks the semaphore parameter validation scenarios. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a semaphore with count = 2 using `pal_osSemaphoreCreate`. | PAL_SUCCESS | +* | 2 | Wait for the semaphore using `pal_osSemaphoreWait` (should not block), and check count. | PAL_SUCCESS | +* | 3 | Increase semaphore count by ten using `pal_osSemaphoreRelease` in a loop. | PAL_SUCCESS | +* | 4 | Delete semaphore using `pal_osSemaphoreDelete`. | PAL_SUCCESS | +* | 5 | Test semaphore creation with invalid arguments (`pal_osSemaphoreCreate`). | PAL_ERR_INVALID_ARGUMENT | +* | 6 | Test semaphore deletion with invalid arguments (`pal_osSemaphoreDelete`). | PAL_ERR_INVALID_ARGUMENT | +* | 7 | Test semaphore waiting with invalid arguments (`pal_osSemaphoreWait`). | PAL_ERR_INVALID_ARGUMENT | +* | 8 | Test semaphore release with invalid arguments (`pal_osSemaphoreRelease`). | PAL_ERR_INVALID_ARGUMENT | +*/ +TEST(pal_rtos, SemaphoreBasicTest) +{ + + palStatus_t status = PAL_SUCCESS; + int counter = 0; + /*#1*/ + status = pal_osSemaphoreCreate(2 ,&semaphore1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + int32_t count = -1; + status = pal_osSemaphoreWait(semaphore1, 1000, &count); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(1, count); + + /*#3*/ + for(counter = 0; counter < 10; counter++) + { + status=pal_osSemaphoreRelease(semaphore1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + /*#4*/ + status=pal_osSemaphoreDelete(&semaphore1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(0, semaphore1); + + //Check semaphore parameter validation + int32_t tmp; + /*#5*/ + status = pal_osSemaphoreCreate(1 ,NULL); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + /*#6*/ + status = pal_osSemaphoreDelete(NULL); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + /*#7*/ + status = pal_osSemaphoreWait(NULLPTR, 1000, &tmp); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + /*#8*/ + status = pal_osSemaphoreRelease(NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); +} + +/*! \brief Creates two memory pools. +* Allocates blocks from each pool using the APIs `pal_osPoolAlloc` and `pal_osPoolCAlloc`. +* Verifies that none of the allocated blocks are NULL. +* Deallocates the blocks. +* Destroys the pools. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a memory pool using `pal_osPoolCreate`. | PAL_SUCCESS | +* | 2 | Create a memory pool using `pal_osPoolCreate`. | PAL_SUCCESS | +* | 3 | Allocate blocks from the first pool in a loop using `pal_osPoolAlloc`. | PAL_SUCCESS | +* | 4 | Allocate blocks from the second pool in a loop using `pal_osPoolAlloc`. | PAL_SUCCESS | +* | 5 | Free blocks from the first pool in a loop using `pal_osPoolAlloc`. | PAL_SUCCESS | +* | 6 | Free blocks from the second pool in a loop using `pal_osPoolAlloc`. | PAL_SUCCESS | +* | 7 | Delete first memory pool. | PAL_SUCCESS | +* | 7 | Delete second memory pool. | PAL_SUCCESS | +*/ +TEST(pal_rtos, MemoryPoolUnityTest) +{ + palStatus_t status = PAL_SUCCESS; + palMemoryPoolID_t poolID1 = NULLPTR; + palMemoryPoolID_t poolID2 = NULLPTR; + uint8_t* ptr1[MEMORY_POOL1_BLOCK_COUNT] = {0}; + uint8_t* ptr2[MEMORY_POOL2_BLOCK_COUNT] = {0}; + + /*#1*/ + status = pal_osPoolCreate(MEMORY_POOL1_BLOCK_SIZE, MEMORY_POOL1_BLOCK_COUNT, &poolID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_osPoolCreate(MEMORY_POOL2_BLOCK_SIZE, MEMORY_POOL2_BLOCK_COUNT, &poolID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + for(uint8_t block1 = 0 ; block1 < MEMORY_POOL1_BLOCK_COUNT; ++block1) + { + ptr1[block1] = pal_osPoolAlloc(poolID1); + TEST_ASSERT_NOT_EQUAL(ptr1[block1], NULL); + } + /*#4*/ + for(uint8_t block2 = 0 ; block2 < MEMORY_POOL2_BLOCK_COUNT; ++block2) + { + ptr2[block2] = pal_osPoolCAlloc(poolID2); + TEST_ASSERT_NOT_EQUAL(ptr2[block2], NULL); + } + /*#5*/ + for(uint8_t freeblock1 = 0; freeblock1 < MEMORY_POOL1_BLOCK_COUNT; ++freeblock1) + { + status = pal_osPoolFree(poolID1, ptr1[freeblock1]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + /*#6*/ + for(uint8_t freeblock2 = 0; freeblock2 < MEMORY_POOL2_BLOCK_COUNT; ++freeblock2) + { + status = pal_osPoolFree(poolID2, ptr2[freeblock2]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + /*#7*/ + status = pal_osPoolDestroy(&poolID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(poolID1, NULL); + /*#8*/ + status = pal_osPoolDestroy(&poolID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(poolID2, NULL); +} + +/*! \brief Creates a message queue. +* Puts a message in the queue, and reads the message from the queue. +* Verifies that the message has the expected value. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a MessageQueue using `pal_osMessageQueueCreate`. | PAL_SUCCESS | +* | 2 | Put a message in the queue using `pal_osMessagePut`. | PAL_SUCCESS | +* | 3 | Get a message from the queue using `pal_osMessageGet`. | PAL_SUCCESS | +* | 4 | Delete the MessageQueue using `pal_osMessageQueueDestroy`. | PAL_SUCCESS | +*/ +TEST(pal_rtos, MessageUnityTest) +{ + palStatus_t status = PAL_SUCCESS; + palMessageQID_t messageQID = NULLPTR; + uint32_t infoToSend = 3215; + uint32_t infoToGet = 0; + + /*#1*/ + status = pal_osMessageQueueCreate(10, &messageQID); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#2*/ + status = pal_osMessagePut(messageQID, infoToSend, 1500); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#3*/ + status = pal_osMessageGet(messageQID, 1500, &infoToGet); + + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL_UINT32(infoToSend, infoToGet); + + /*#4*/ + status = pal_osMessageQueueDestroy(&messageQID); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(messageQID, NULL); +} + +/*! \brief Performs a single atomic increment call +* to an integer value and verifies that the result is as expected. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Call atomic increment using `pal_osAtomicIncrement` and check that the value was incremented. | PAL_SUCCESS | +*/ +TEST(pal_rtos, AtomicIncrementUnityTest) +{ + int32_t num1 = 0; + int32_t increment = 10; + int32_t tmp = 0; + int32_t original = num1; + /*#1*/ + tmp = pal_osAtomicIncrement(&num1, increment); + + + TEST_ASSERT_EQUAL(original + increment, tmp); + +} + +struct randBuf +{ + uint8_t rand[6]; +}; + +/*! \brief Check the random APIs. For each API, the test calls the random API in a loop +* and stores the result. When the loop finishes, we verify that the count of the +* duplication in the stored values is less than the defined random margin value for each API. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Fill array with random 32bit values using `pal_osRandom32bit` in a loop. | PAL_SUCCESS | +* | 2 | Check array for matching values and make sure there are not too many. | PAL_SUCCESS | +* | 3 | Fill array with random values using `pal_osRandomUniform` in a loop. | PAL_SUCCESS | +* | 4 | Check array for matching values and make sure there are not too many. | PAL_SUCCESS | +* | 5 | Fill array with random byte sequences using `pal_osRandomBuffer` in a loop. | PAL_SUCCESS | +* | 6 | Check array for matching values and make sure there are not too many. | PAL_SUCCESS | +*/ +TEST(pal_rtos, RandomUnityTest) +{ + palStatus_t status = PAL_SUCCESS; + uint32_t randomArray[PAL_RANDOM_ARRAY_TEST_SIZE]; + struct randBuf randomBufArray[PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE]; + uint32_t randomMargin = 0; + uint32_t upperBound = PAL_MAX_UINT32; //This value need to be changed once PAL implements `pal_osRandomUniform` correctly + + memset(randomArray, 0x0, sizeof(randomArray)); + memset(randomBufArray, 0x0, sizeof(randomBufArray)); + /*#1*/ + for(int i = 0; i < PAL_RANDOM_ARRAY_TEST_SIZE ; ++i) + { + status = pal_osRandom32bit(&randomArray[i]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + /*#2*/ + for(int k = 0; k < PAL_RANDOM_ARRAY_TEST_SIZE ; ++k) + { + for (int j = k+1 ; j < PAL_RANDOM_ARRAY_TEST_SIZE ; ++j) + { + if (randomArray[k] == randomArray[j]) + { + ++randomMargin; + } + } + randomArray[k] = 0; + } + TEST_ASSERT_TRUE(20 >= randomMargin); + randomMargin = 0; + /*#3*/ + for(int i = 0; i < PAL_RANDOM_ARRAY_TEST_SIZE ; ++i) + { + status = pal_osRandomUniform(upperBound , &randomArray[i]); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + /*#4*/ + for(int k = 0; k < PAL_RANDOM_ARRAY_TEST_SIZE ; ++k) + { + if (randomArray[k] > upperBound) + { + ++randomMargin; + } + randomArray[k] = 0; + } + + TEST_ASSERT_TRUE(1 >= randomMargin); + randomMargin = 0; + /*#5*/ + for (int i = 0; i < PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE ; ++i) + { + status = pal_osRandomBuffer(randomBufArray[i].rand, sizeof(randomBufArray[i].rand)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + /*#6*/ + for(int k = 0; k < PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE ; ++k) + { + for (int j = k+1 ; j < PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE ; ++j) + { + if(0 == memcmp(randomBufArray[k].rand, randomBufArray[j].rand, sizeof(uint8_t)*6)) + { + ++randomMargin; + } + } + } + + TEST_ASSERT_TRUE(10 >= randomMargin); +} + + +/*! \brief call the random API in a PAL_RANDOM_TEST_LOOP loop. +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Call `pal_osRandomBuffer` in a PAL_RANDOM_TEST_LOOP loop . PAL_SUCCESS | +*/ +TEST(pal_rtos, loopRandomBigNumber) +{ + palStatus_t status = PAL_SUCCESS; + uint8_t loopRandomArray[PAL_RANDOM_ARRAY_TEST_SIZE]; + + for (int i = 0; i < PAL_RANDOM_TEST_LOOP; ++i) + { + status = pal_osRandomBuffer(loopRandomArray, sizeof(loopRandomArray)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } +} + +/*! \brief Verify that PAL can handle multiple calls for `pal_init()` and `pal_destroy()`. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Call `pal_init`. | PAL_SUCCESS | +* | 2 | Call `pal_init`. | PAL_SUCCESS | +* | 3 | Call `pal_init`. | PAL_SUCCESS | +* | 4 | Call `pal_destroy` in a loop untill init count == 0. | PAL_SUCCESS | +* | 5 | Call `pal_init`. | PAL_SUCCESS | +* | 6 | Call `pal_destroy`. | PAL_SUCCESS | +*/ +TEST(pal_rtos, pal_init_test) +{ + palStatus_t status = PAL_SUCCESS; + int32_t initCounter = 0; + /*#1*/ + status = pal_init(); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_init(); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_init(); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#4*/ + do + { + initCounter = pal_destroy(); + //TEST_ASSERT_EQUAL_HEX(0, initCounter); + + }while(initCounter != 0); + + /*#5*/ + status = pal_init(); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#6*/ + initCounter = pal_destroy(); + TEST_ASSERT_EQUAL_HEX(0, initCounter); +} + +/*! \brief This test does not run by default in the PAL Unity tets. +* It's called "customized" because the purpose of it is to provide a test structure +* for a developer who wants to check a specific API. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a thread that runs `palThreadFuncCustom1` using `pal_osThreadCreateWithAlloc`. | PAL_SUCCESS | +* | 2 | Create a thread that runs `palThreadFuncCustom2` using `pal_osThreadCreateWithAlloc`. | PAL_SUCCESS | +* | 3 | Sleep. | PAL_SUCCESS | +* | 4 | Terminate the first thread. | PAL_SUCCESS | +* | 5 | Terminate the second thread. | PAL_SUCCESS | +* | 6 | Create a thread that runs `palThreadFuncCustom1` using `pal_osThreadCreateWithAlloc`. | PAL_SUCCESS | +* | 7 | Create a thread that runs `palThreadFuncCustom2` using `pal_osThreadCreateWithAlloc`. | PAL_SUCCESS | +* | 8 | compare threads index | PAL_SUCCESS | +* | 9 | check threadIDs are not equal. | PAL_SUCCESS | +* | 10 | Sleep. | PAL_SUCCESS | +* | 11 | Terminate the first thread. | PAL_SUCCESS | +* | 12 | Terminate again the first thread. | PAL_SUCCESS | +* | 13 | Terminate the second thread. | PAL_SUCCESS | +* +*/ + + +TEST(pal_rtos, ThreadReCreateSamePriority) +{ + palStatus_t status = PAL_SUCCESS; + + palThreadID_t threadID1 = NULLPTR; + palThreadID_t threadID2 = NULLPTR; + palThreadID_t threadIndex = NULLPTR; + + /*#1*/ + status = pal_osThreadCreateWithAlloc(palThreadFuncCustom1, NULL, PAL_osPriorityAboveNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + threadIndex = threadID1; + /*#2*/ + status = pal_osThreadCreateWithAlloc(palThreadFuncCustom2, NULL, PAL_osPriorityHigh, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + pal_osDelay(3000); + /*#4*/ + // We deliberately dont terminate threadID1, it should end by itself + /*#5*/ + // We deliberately dont terminate threadID2, it should end by itself + /*#6*/ + status = pal_osThreadCreateWithAlloc(palThreadFuncCustom1, NULL, PAL_osPriorityAboveNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#7*/ + status = pal_osThreadCreateWithAlloc(palThreadFuncCustom2, NULL, PAL_osPriorityHigh, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#8*/ + TEST_ASSERT_EQUAL_UINT32(PAL_GET_THREAD_INDEX(threadIndex),PAL_GET_THREAD_INDEX(threadID1)); + /*#9*/ + TEST_ASSERT_NOT_EQUAL(threadIndex,threadID1); + /*#10*/ + pal_osDelay(3000); + /*#11*/ + status = pal_osThreadTerminate(&threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#12*/ + status = pal_osThreadTerminate(&threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#13*/ + status = pal_osThreadTerminate(&threadID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + pal_osDelay(500); + + mutex1 = NULLPTR; + status = pal_osMutexCreate(&mutex1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osMutexWait(mutex1, PAL_RTOS_WAIT_FOREVER); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadCreateWithAlloc(palThreadFuncCustom3, NULL, PAL_osPriorityAboveNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadCreateWithAlloc(palThreadFuncCustom4, NULL, PAL_osPriorityAboveNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID2); +#if PAL_UNIQUE_THREAD_PRIORITY + TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_PRIORITY, status); +#else + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + status = pal_osThreadTerminate(&threadID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +#endif + + status = pal_osMutexRelease(mutex1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadTerminate(&threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osMutexDelete(&mutex1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(NULL, mutex1); + +} + +/*! \brief Check derivation of keys from the platform's Root of Trust using the KDF algorithm. + * + * + * +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Start a loop to perform the following steps. | | +* | 2 | Derive a device key for encryption using `pal_osGetDeviceKey`. | PAL_SUCCESS | +* | 3 | Derive a device key for signing using `pal_osGetDeviceKey`. | PAL_SUCCESS | +* | 4 | Call `pal_osGetDeviceKey` with invalid arguments. | PAL_FAILURE | +* | 5 | Call `pal_osGetDeviceKey` with invalid arguments. | PAL_FAILURE | +* | 6 | Check that the derived signing and encryption keys are different. | PAL_SUCCESS | +* | 7 | Check that all integrations of each type of derivation return the same value. | PAL_SUCCESS | + */ +TEST(pal_rtos, GetDeviceKeyTest_CMAC) +{ + palStatus_t status = PAL_SUCCESS; + size_t keyLenBytes = 16; + uint8_t timesToDerive = 4; + unsigned char encKeyDerive[timesToDerive][keyLenBytes]; //16 bytes=128bit + unsigned char signKeyDerive[timesToDerive][keyLenBytes]; //16 bytes=128bit + /*#1*/ + for (int i=0; i < timesToDerive; i++) + { + /*#2*/ + status = pal_osGetDeviceKey(palOsStorageEncryptionKey128Bit, encKeyDerive[i], keyLenBytes); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_osGetDeviceKey(palOsStorageSignatureKey128Bit, signKeyDerive[i], keyLenBytes); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + status = pal_osGetDeviceKey(palOsStorageSignatureKey128Bit, signKeyDerive[i], keyLenBytes-1); + TEST_ASSERT_NOT_EQUAL(PAL_SUCCESS, status); + /*#5*/ + status = pal_osGetDeviceKey(palOsStorageSignatureKey128Bit, NULL, keyLenBytes); + TEST_ASSERT_NOT_EQUAL(PAL_SUCCESS, status); + /*#6*/ + status = memcmp(encKeyDerive[i], signKeyDerive[i], keyLenBytes); + TEST_ASSERT_NOT_EQUAL(status,0); //The keys MUST be different! + /*#7*/ + if (i > 0) //Make sure key derivation is persistent every time + { + TEST_ASSERT_EQUAL_MEMORY(encKeyDerive[i-1], encKeyDerive[i], keyLenBytes); + TEST_ASSERT_EQUAL_MEMORY(signKeyDerive[i-1], signKeyDerive[i], keyLenBytes); + + } //if + + } //for + +} + +/*! \brief Check derivation of keys from the platform's Root of Trust using the KDF algorithm. + * + * + * +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Start a loop to perform the following steps. | | +* | 2 | Derive a device key for encryption using `pal_osGetDeviceKey`. | PAL_SUCCESS | +* | 3 | Call `pal_osGetDeviceKey` with invalid arguments. | PAL_FAILURE | +* | 4 | Call `pal_osGetDeviceKey` with invalid arguments. | PAL_FAILURE | +* | 5 | Check that all integrations of each type of derivation return the same value. | PAL_SUCCESS | + */ +TEST(pal_rtos, GetDeviceKeyTest_HMAC_SHA256) +{ + palStatus_t status = PAL_SUCCESS; + size_t keyLenBytes = 32; + uint8_t timesToDerive = 4; + unsigned char encKeyDerive[timesToDerive][keyLenBytes]; //32 bytes=256bit + /*#1*/ + for (int i=0; i < timesToDerive; i++) + { + /*#2*/ + status = pal_osGetDeviceKey(palOsStorageHmacSha256, encKeyDerive[i], keyLenBytes); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + status = pal_osGetDeviceKey(palOsStorageHmacSha256, encKeyDerive[i], keyLenBytes-1); + TEST_ASSERT_NOT_EQUAL(PAL_SUCCESS, status); + /*#5*/ + status = pal_osGetDeviceKey(palOsStorageHmacSha256, NULL, keyLenBytes); + TEST_ASSERT_NOT_EQUAL(PAL_SUCCESS, status); + /*#7*/ + if (i > 0) //Make sure key derivation is persistent every time + { + TEST_ASSERT_EQUAL_MEMORY(encKeyDerive[i-1], encKeyDerive[i], keyLenBytes); + } //if + + } //for + +} + +/*! \brief Check the APIs `pal_osSetTime()` and `pal_osGetTime()` with different scenarios +* for valid and non-valid scenarios and epoch values. +* The test also checks that the time increases. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Get time using `pal_osGetTime`. | PAL_SUCCESS | +* | 2 | Set time to invalid value using `pal_osSetTime`. | PAL_ERR_INVALID_TIME | +* | 3 | Get time using `pal_osGetTime`. | PAL_SUCCESS | +* | 4 | Start a loop for the following steps. | PAL_SUCCESS | +* | 5 | Set time to invalid value using `pal_osSetTime`. | PAL_ERR_INVALID_TIME | +* | 6 | Get time using `pal_osGetTime`. | PAL_SUCCESS | +* | 7 | Set time to valid value using `pal_osSetTime`. | PAL_SUCCESS | +* | 8 | Sleep. | PAL_SUCCESS | +* | 9 | Get time using `pal_osGetTime` and check that it equals set time + sleep time. | PAL_SUCCESS | +*/ +TEST(pal_rtos, RealTimeClockTest1) +{ + palStatus_t status; + uint64_t curTime; + uint64_t lastTimeSeen = 0; + const uint64_t minSecSinceEpoch = PAL_MIN_SEC_FROM_EPOCH + 1; //At least 47 years passed from 1.1.1970 in seconds + + /*#1*/ + curTime = pal_osGetTime(); + TEST_ASSERT_EQUAL(0, curTime); //Time was not previously set; 0 is acceptable + /*#2*/ + status = pal_osSetTime(3); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_TIME, status); // Less than current epoch time -> error + /*#3*/ + curTime = pal_osGetTime(); + TEST_ASSERT_EQUAL(lastTimeSeen, curTime); //Time was not previously set; 0 is acceptable + + /*#4*/ + for (int i=0; i < 2; i++) + { + /*#5*/ + status = pal_osSetTime(3); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_TIME, status); // Less than current epoch time -> error + + /*#6*/ + curTime = pal_osGetTime(); + TEST_ASSERT_TRUE(lastTimeSeen <= curTime); //Time was not previously set; 0 is acceptable + /*#7*/ + status = pal_osSetTime(minSecSinceEpoch); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); // More than current epoch time -> success + /*#8*/ + int milliDelay = 1500; + pal_osDelay(milliDelay); //500 milliseconds + /*#9*/ + curTime = pal_osGetTime(); + TEST_ASSERT_TRUE(curTime > minSecSinceEpoch); + TEST_PRINTF("Current sys time in sec:%lld after delay:%lld\n", curTime, minSecSinceEpoch+(int)ceil((float)milliDelay/1000)); + TEST_ASSERT_TRUE(curTime <= minSecSinceEpoch+(int)ceil((float)milliDelay/1000)); + lastTimeSeen = curTime; + } +} + + +/*! \brief Check recursive mutex behavior. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a mutex using `pal_osMutexCreate`. | PAL_SUCCESS | +* | 2 | Create a semaphore using `pal_osSemaphoreCreate`. | PAL_SUCCESS | +* | 3 | Create a thread running `RecursiveLockThread` using `pal_osThreadCreateWithAlloc`. | PAL_SUCCESS | +* | 4 | Create a thread running `RecursiveLockThread` using `pal_osThreadCreateWithAlloc`. | PAL_SUCCESS | +* | 5 | Release the semaphore using `pal_osSemaphoreRelease`. | PAL_SUCCESS | +* | 6 | Release the semaphore using `pal_osSemaphoreRelease`. | PAL_SUCCESS | +* | 7 | Sleep for a short interval. | PAL_SUCCESS | +* | 8 | Wait for the semaphore using `pal_osSemaphoreWait`. | PAL_SUCCESS | +* | 9 | Wait for the semaphore using `pal_osSemaphoreWait`. | PAL_SUCCESS | +* | 10 | Terminate the first thread using `pal_osThreadTerminate`. | PAL_SUCCESS | +* | 11 | Terminate the second thread using `pal_osThreadTerminate`. | PAL_SUCCESS | +* | 12 | Delete the mutex using `pal_osMutexDelete`. | PAL_SUCCESS | +* | 13 | Delete the semaphore using `pal_osSemaphoreDelete`. | PAL_SUCCESS | +*/ +TEST(pal_rtos, Recursive_Mutex_Test) +{ + palStatus_t status; + int32_t val = 0; + + recursiveMutexData = malloc(sizeof(palRecursiveMutexParam_t)); + TEST_ASSERT_NOT_NULL(recursiveMutexData); + memset(recursiveMutexData, 0, sizeof(palRecursiveMutexParam_t)); + /*#1*/ + status = pal_osMutexCreate(&(recursiveMutexData->mtx)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_osSemaphoreCreate(0, &(recursiveMutexData->sem)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_osThreadCreateWithAlloc(RecursiveLockThread, (void*)recursiveMutexData, PAL_osPriorityHigh, PAL_TEST_THREAD_STACK_SIZE, NULL, &(recursiveMutexData->higherPriorityThread)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + status = pal_osThreadCreateWithAlloc(RecursiveLockThread, (void*)recursiveMutexData, PAL_osPriorityAboveNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &(recursiveMutexData->lowerPriorityThread)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#5*/ + status = pal_osSemaphoreRelease(recursiveMutexData->sem); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#6*/ + status = pal_osSemaphoreRelease(recursiveMutexData->sem); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#7*/ + pal_osDelay(1000); + /*#8*/ + status = pal_osSemaphoreWait(recursiveMutexData->sem, PAL_RTOS_WAIT_FOREVER, &val); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#9*/ + status = pal_osSemaphoreWait(recursiveMutexData->sem, PAL_RTOS_WAIT_FOREVER, &val); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_EQUAL(0, val); + TEST_ASSERT_EQUAL_HEX(NULLPTR, recursiveMutexData->activeThread); + /*#10*/ + status = pal_osThreadTerminate(&(recursiveMutexData->higherPriorityThread)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#11*/ + status = pal_osThreadTerminate(&(recursiveMutexData->lowerPriorityThread)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#12*/ + status = pal_osMutexDelete(&(recursiveMutexData->mtx)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#13*/ + status = pal_osSemaphoreDelete(&recursiveMutexData->sem); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + TEST_ASSERT_EQUAL(400, recursiveMutexData->count); + + free(recursiveMutexData); + recursiveMutexData = NULL; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/RTOS/pal_rtos_test_runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/RTOS/pal_rtos_test_runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unity.h" +#include "unity_fixture.h" + +#if 0 // MUST GO TO PLATFORM SPECIFIC FILE +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" +#include "board.h" + +#include "pin_mux.h" +#include "clock_config.h" + +#endif // MUST GO TO PLATFORM SPECIFIC FILE + +TEST_GROUP_RUNNER(pal_rtos) +{ + RUN_TEST_CASE(pal_rtos, RealTimeClockTest1); + RUN_TEST_CASE(pal_rtos, SemaphoreWaitForever); + RUN_TEST_CASE(pal_rtos, pal_osKernelSysTick_Unity); + RUN_TEST_CASE(pal_rtos, pal_osKernelSysTick64_Unity); + RUN_TEST_CASE(pal_rtos, pal_osKernelSysTickMicroSec_Unity); + RUN_TEST_CASE(pal_rtos, pal_osKernelSysMilliSecTick_Unity); + RUN_TEST_CASE(pal_rtos, pal_osKernelSysTickFrequency_Unity); + RUN_TEST_CASE(pal_rtos, pal_osDelay_Unity); + RUN_TEST_CASE(pal_rtos, BasicTimeScenario); + RUN_TEST_CASE(pal_rtos, TimerUnityTest); + RUN_TEST_CASE(pal_rtos, MemoryPoolUnityTest); + RUN_TEST_CASE(pal_rtos, MessageUnityTest); + RUN_TEST_CASE(pal_rtos, AtomicIncrementUnityTest); + RUN_TEST_CASE(pal_rtos, GetDeviceKeyTest_CMAC); + RUN_TEST_CASE(pal_rtos, GetDeviceKeyTest_HMAC_SHA256); + RUN_TEST_CASE(pal_rtos, PrimitivesUnityTest1); + RUN_TEST_CASE(pal_rtos, PrimitivesUnityTest2); + RUN_TEST_CASE(pal_rtos, ThreadReCreateSamePriority); + RUN_TEST_CASE(pal_rtos, SemaphoreBasicTest); + RUN_TEST_CASE(pal_rtos, RandomUnityTest); + RUN_TEST_CASE(pal_rtos, loopRandomBigNumber); + RUN_TEST_CASE(pal_rtos, pal_init_test); + RUN_TEST_CASE(pal_rtos, Recursive_Mutex_Test); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/RTOS/pal_rtos_test_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/RTOS/pal_rtos_test_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pal_rtos_test_utils.h" +#include "pal_rtos.h" +#include "pal_test_main.h" +#include "unity_fixture.h" + +#include "pal.h" + + +extern threadsArgument_t g_threadsArg; +extern palThreadLocalStore_t g_threadStorage; +timerArgument_t timerArgs; + +void palThreadFunc1(void const *argument) +{ + volatile palThreadID_t threadID; + palThreadLocalStore_t * threadStorage = NULL; + threadsArgument_t *tmp = (threadsArgument_t*)argument; +#ifdef MUTEX_UNITY_TEST + palStatus_t status = PAL_SUCCESS; + PAL_PRINTF("palThreadFunc1::before mutex\n"); + status = pal_osMutexWait(mutex1, 100); + PAL_PRINTF("palThreadFunc1::after mutex: 0x%08x\n", status); + PAL_PRINTF("palThreadFunc1::after mutex (expected): 0x%08x\n", PAL_ERR_RTOS_TIMEOUT); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_TIMEOUT, status); + return; // for Mutex scenario, this should end here +#endif //MUTEX_UNITY_TEST + + tmp->arg1 = 10; + threadID = pal_osThreadGetId(); + TEST_ASSERT_NOT_EQUAL(threadID, NULLPTR); + PAL_PRINTF("palThreadFunc1::Thread ID is %d\n", threadID); + + threadStorage = pal_osThreadGetLocalStore(); + if (threadStorage == &g_threadStorage) + { + PAL_PRINTF("Thread storage updated as expected\n"); + } + TEST_ASSERT_EQUAL_HEX((uintptr_t)threadStorage, (uintptr_t)(&g_threadStorage)); + +#ifdef MUTEX_UNITY_TEST + status = pal_osMutexRelease(mutex1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +#endif //MUTEX_UNITY_TEST + PAL_PRINTF("palThreadFunc1::STAAAAM\n"); +} + +void palThreadFunc2(void const *argument) +{ + volatile palThreadID_t threadID; + threadsArgument_t *tmp = (threadsArgument_t*)argument; +#ifdef MUTEX_UNITY_TEST + palStatus_t status = PAL_SUCCESS; + PAL_PRINTF("palThreadFunc2::before mutex\n"); + status = pal_osMutexWait(mutex2, 300); + PAL_PRINTF("palThreadFunc2::after mutex: 0x%08x\n", status); + PAL_PRINTF("palThreadFunc2::after mutex (expected): 0x%08x\n", PAL_SUCCESS); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +#endif //MUTEX_UNITY_TEST + + tmp->arg2 = 20; + threadID = pal_osThreadGetId(); + TEST_ASSERT_NOT_EQUAL(threadID, NULLPTR); + PAL_PRINTF("palThreadFunc2::Thread ID is %d\n", threadID); +#ifdef MUTEX_UNITY_TEST + status = pal_osMutexRelease(mutex2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +#endif //MUTEX_UNITY_TEST + PAL_PRINTF("palThreadFunc2::STAAAAM\n"); +} + +void palThreadFunc3(void const *argument) +{ + volatile palThreadID_t threadID; + threadsArgument_t *tmp = (threadsArgument_t*)argument; + +#ifdef SEMAPHORE_UNITY_TEST + palStatus_t status = PAL_SUCCESS; + uint32_t semaphoresAvailable = 10; + status = pal_osSemaphoreWait(semaphore1, 200, &semaphoresAvailable); + + if (PAL_SUCCESS == status) + { + PAL_PRINTF("palThreadFunc3::semaphoresAvailable: %d\n", semaphoresAvailable); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + else if(PAL_ERR_RTOS_TIMEOUT == status) + { + PAL_PRINTF("palThreadFunc3::semaphoresAvailable: %d\n", semaphoresAvailable); + PAL_PRINTF("palThreadFunc3::status: 0x%08x\n", status); + PAL_PRINTF("palThreadFunc3::failed to get Semaphore as expected\n", status); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_TIMEOUT, status); + return; + } + pal_osDelay(6000); +#endif //SEMAPHORE_UNITY_TEST + tmp->arg3 = 30; + threadID = pal_osThreadGetId(); + TEST_ASSERT_NOT_EQUAL(threadID, NULLPTR); + PAL_PRINTF("palThreadFunc3::Thread ID is %d\n", threadID); + +#ifdef SEMAPHORE_UNITY_TEST + status = pal_osSemaphoreRelease(semaphore1); + PAL_PRINTF("palThreadFunc3::pal_osSemaphoreRelease res: 0x%08x\n", status); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +#endif //SEMAPHORE_UNITY_TEST + PAL_PRINTF("palThreadFunc3::STAAAAM\n"); +} + +void palThreadFunc4(void const *argument) +{ + volatile palThreadID_t threadID; + threadsArgument_t *tmp = (threadsArgument_t*)argument; +#ifdef MUTEX_UNITY_TEST + palStatus_t status = PAL_SUCCESS; + PAL_PRINTF("palThreadFunc4::before mutex\n"); + status = pal_osMutexWait(mutex1, 200); + PAL_PRINTF("palThreadFunc4::after mutex: 0x%08x\n", status); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + pal_osDelay(3500); //wait 3.5 seconds to make sure that the next thread arrive to this point +#endif //MUTEX_UNITY_TEST + + tmp->arg4 = 40; + threadID = pal_osThreadGetId(); + TEST_ASSERT_NOT_EQUAL(threadID, NULLPTR); + PAL_PRINTF("Thread ID is %d\n", threadID); + +#ifdef MUTEX_UNITY_TEST + status = pal_osMutexRelease(mutex1); + PAL_PRINTF("palThreadFunc4::after release mutex: 0x%08x\n", status); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +#endif //MUTEX_UNITY_TEST + PAL_PRINTF("palThreadFunc4::STAAAAM\n"); +} + +void palThreadFunc5(void const *argument) +{ + volatile palThreadID_t threadID; + threadsArgument_t *tmp = (threadsArgument_t*)argument; +#ifdef MUTEX_UNITY_TEST + palStatus_t status = PAL_SUCCESS; + PAL_PRINTF("palThreadFunc5::before mutex\n"); + status = pal_osMutexWait(mutex1, 4500); + PAL_PRINTF("palThreadFunc5::after mutex: 0x%08x\n", status); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +#endif //MUTEX_UNITY_TEST + tmp->arg5 = 50; + threadID = pal_osThreadGetId(); + TEST_ASSERT_NOT_EQUAL(threadID, NULLPTR); + PAL_PRINTF("Thread ID is %d\n", threadID); +#ifdef MUTEX_UNITY_TEST + status = pal_osMutexRelease(mutex1); + PAL_PRINTF("palThreadFunc5::after release mutex: 0x%08x\n", status); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +#endif //MUTEX_UNITY_TEST + PAL_PRINTF("palThreadFunc5::STAAAAM\n"); +} + +void palThreadFunc6(void const *argument) +{ + volatile palThreadID_t threadID; + threadsArgument_t *tmp = (threadsArgument_t*)argument; +#ifdef SEMAPHORE_UNITY_TEST + palStatus_t status = PAL_SUCCESS; + uint32_t semaphoresAvailable = 10; + status = pal_osSemaphoreWait(123456, 200, &semaphoresAvailable); //MUST fail, since there is no semaphore with ID=3 + PAL_PRINTF("palThreadFunc6::semaphoresAvailable: %d\n", semaphoresAvailable); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_PARAMETER, status); + return; +#endif //SEMAPHORE_UNITY_TEST + tmp->arg6 = 60; + threadID = pal_osThreadGetId(); + TEST_ASSERT_NOT_EQUAL(threadID, NULLPTR); + PAL_PRINTF("Thread ID is %d\n", threadID); +#ifdef SEMAPHORE_UNITY_TEST + status = pal_osSemaphoreRelease(123456); + PAL_PRINTF("palThreadFunc6::pal_osSemaphoreRelease res: 0x%08x\n", status); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_PARAMETER, status); +#endif //SEMAPHORE_UNITY_TEST + PAL_PRINTF("palThreadFunc6::STAAAAM\n"); +} + + +void palTimerFunc1(void const *argument) +{ + g_timerArgs.ticksInFunc1 = pal_osKernelSysTick(); + PAL_PRINTF("ticks in palTimerFunc1: 0 - %" PRIu32 "\n", g_timerArgs.ticksInFunc1); + PAL_PRINTF("Once Timer function was called\n"); +} + +void palTimerFunc2(void const *argument) +{ + g_timerArgs.ticksInFunc2 = pal_osKernelSysTick(); + PAL_PRINTF("ticks in palTimerFunc2: 0 - %" PRIu32 "\n", g_timerArgs.ticksInFunc2); + PAL_PRINTF("Periodic Timer function was called\n"); +} + +void palTimerFunc3(void const *argument) +{ + static int counter =0; + counter++; +} + +void palTimerFunc4(void const *argument) +{ + static int counter =0; + counter++; + g_timerArgs.ticksInFunc1 = counter; +} + +void palTimerFunc5(void const *argument) // function to count calls + wait alternatin short and long periods for timer drift test +{ + static int counter = 0; + counter++; + g_timerArgs.ticksInFunc1 = counter; + if (counter % 2 == 0) + { + pal_osDelay(PAL_TIMER_TEST_TIME_TO_WAIT_MS_LONG); + } + else + { + pal_osDelay(PAL_TIMER_TEST_TIME_TO_WAIT_MS_SHORT); + } +} + + +void palThreadFuncCustom1(void const *argument) +{ + PAL_PRINTF("palThreadFuncCustom1 was called\n"); +} + +void palThreadFuncCustom2(void const *argument) +{ + PAL_PRINTF("palThreadFuncCustom2 was called\n"); +} + +void palThreadFuncCustom3(void const *argument) +{ + palStatus_t status = PAL_SUCCESS; + PAL_PRINTF("palThreadFuncCustom3 was called\n"); + status = pal_osMutexWait(mutex1, PAL_RTOS_WAIT_FOREVER); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osMutexRelease(mutex1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + +void palThreadFuncCustom4(void const *argument) +{ + PAL_PRINTF("palThreadFuncCustom4 was called\n"); +} + +void palThreadFuncWaitForEverTest(void const *argument) +{ + pal_osDelay(PAL_TIME_TO_WAIT_MS/2); + pal_osSemaphoreRelease(*((palSemaphoreID_t*)(argument))); +} + +void palRunThreads() +{ + palStatus_t status = PAL_SUCCESS; + palThreadID_t threadID1 = NULLPTR; + palThreadID_t threadID2 = NULLPTR; + palThreadID_t threadID3 = NULLPTR; + palThreadID_t threadID4 = NULLPTR; + palThreadID_t threadID5 = NULLPTR; + palThreadID_t threadID6 = NULLPTR; + + status = pal_osThreadCreateWithAlloc(palThreadFunc1, &g_threadsArg, PAL_osPriorityIdle, PAL_TEST_THREAD_STACK_SIZE, &g_threadStorage, &threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadCreateWithAlloc(palThreadFunc2, &g_threadsArg, PAL_osPriorityLow, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadCreateWithAlloc(palThreadFunc3, &g_threadsArg, PAL_osPriorityNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID3); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadCreateWithAlloc(palThreadFunc4, &g_threadsArg, PAL_osPriorityBelowNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID4); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osDelay(PAL_RTOS_THREAD_CLEANUP_TIMER_MILISEC * 2); // dealy to work around mbedOS timer issue (starting more than 6 timers at once will cause a hang) + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadCreateWithAlloc(palThreadFunc5, &g_threadsArg, PAL_osPriorityAboveNormal, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID5); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadCreateWithAlloc(palThreadFunc6, &g_threadsArg, PAL_osPriorityHigh, PAL_TEST_THREAD_STACK_SIZE, NULL, &threadID6); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + pal_osDelay(PAL_TIME_TO_WAIT_MS/5); + + status = pal_osThreadTerminate(&threadID1); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadTerminate(&threadID2); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadTerminate(&threadID3); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadTerminate(&threadID4); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadTerminate(&threadID5); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osThreadTerminate(&threadID6); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + +void RecursiveLockThread(void const *param) +{ + size_t i = 0; + palStatus_t status; + palRecursiveMutexParam_t *actualParams = (palRecursiveMutexParam_t*)param; + size_t countbeforeStart = 0; + volatile palThreadID_t threadID = 10; + + status = pal_osSemaphoreWait(actualParams->sem, PAL_RTOS_WAIT_FOREVER, NULL); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + for (i = 0; i < 100; ++i) + { + status = pal_osMutexWait(actualParams->mtx, PAL_RTOS_WAIT_FOREVER); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + if (i == 0) + { + countbeforeStart = actualParams->count; + TEST_ASSERT_EQUAL_HEX(NULLPTR, actualParams->activeThread); + actualParams->activeThread = pal_osThreadGetId(); + } + actualParams->count++; + threadID = pal_osThreadGetId(); + TEST_ASSERT_NOT_EQUAL(NULLPTR, threadID); + TEST_ASSERT_EQUAL(actualParams->activeThread, threadID); + pal_osDelay(1); + } + + pal_osDelay(50); + TEST_ASSERT_EQUAL(100, actualParams->count - countbeforeStart); + for (i = 0; i < 100; ++i) + { + threadID = pal_osThreadGetId(); + TEST_ASSERT_NOT_EQUAL(NULLPTR, threadID); + TEST_ASSERT_EQUAL(actualParams->activeThread, threadID); + actualParams->count++; + if (i == 99) + { + TEST_ASSERT_EQUAL(200, actualParams->count - countbeforeStart); + actualParams->activeThread = NULLPTR; + } + + status = pal_osMutexRelease(actualParams->mtx); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + pal_osDelay(1); + } + + status = pal_osSemaphoreRelease(actualParams->sem); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/RTOS/pal_rtos_test_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/RTOS/pal_rtos_test_utils.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,108 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef _PAL_RTOS_TEST_UTILS_H +#define _PAL_RTOS_TEST_UTILS_H + +#include "pal_types.h" +#include "pal_rtos.h" +#include "pal_test_main.h" +#if 0 //MUST MOVE TO PLATFORM SPECIFIC HEADER +#include "fsl_device_registers.h" +#include "fsl_debug_console.h" +#include "board.h" + +#include "pin_mux.h" +#include "clock_config.h" + + +#define MUTEX_UNITY_TEST 1 +#define SEMAPHORE_UNITY_TEST 1 +#endif // MUST MOVE TO PLATFORM SPECIFIC HEADER +#define PAL_RANDOM_TEST_LOOP 100000 +#define PAL_RANDOM_ARRAY_TEST_SIZE 100 +#define PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE 60 +#define PAL_TIME_TO_WAIT_MS 5000 //in [ms] +#define PAL_TIME_TO_WAIT_SHORT_MS 300 //in [ms] +#define PAL_TIMER_TEST_TIME_TO_WAIT_MS_SHORT 40 //in [ms] +#define PAL_TIMER_TEST_TIME_TO_WAIT_MS_LONG 130 //in [ms] + +typedef struct threadsArgument{ + uint32_t arg1; + uint32_t arg2; + uint32_t arg3; + uint32_t arg4; + uint32_t arg5; + uint32_t arg6; + uint32_t arg7; + uint8_t threadCounter; +}threadsArgument_t; + + +extern threadsArgument_t g_threadsArg; + +extern palThreadLocalStore_t g_threadStorage; + +void palThreadFunc1(void const *argument); +void palThreadFunc2(void const *argument); +void palThreadFunc3(void const *argument); +void palThreadFunc4(void const *argument); +void palThreadFunc5(void const *argument); +void palThreadFunc6(void const *argument); + + +typedef struct timerArgument{ + uint32_t ticksBeforeTimer; + uint32_t ticksInFunc1; + uint32_t ticksInFunc2; +}timerArgument_t; + +extern timerArgument_t g_timerArgs; + +void palTimerFunc1(void const *argument); +void palTimerFunc2(void const *argument); +void palTimerFunc3(void const *argument); +void palTimerFunc4(void const *argument); +void palTimerFunc5(void const *argument); + + +void palThreadFuncCustom1(void const *argument); +void palThreadFuncCustom2(void const *argument); +void palThreadFuncCustom3(void const *argument); +void palThreadFuncCustom4(void const *argument); +void palThreadFuncWaitForEverTest(void const *argument); + +void RecursiveLockThread(void const *param); +typedef struct palRecursiveMutexParam{ + palMutexID_t mtx; + palSemaphoreID_t sem; + size_t count; + palThreadID_t higherPriorityThread; + palThreadID_t lowerPriorityThread; + palThreadID_t activeThread; +} palRecursiveMutexParam_t; + +#define MEMORY_POOL1_BLOCK_SIZE 32 +#define MEMORY_POOL1_BLOCK_COUNT 5 +#define MEMORY_POOL2_BLOCK_SIZE 12 +#define MEMORY_POOL2_BLOCK_COUNT 4 + +extern palMutexID_t mutex1; +extern palMutexID_t mutex2; + +extern palSemaphoreID_t semaphore1; + +#endif //_PAL_RTOS_TEST_UTILS_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Storage/pal_internalFlash_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Storage/pal_internalFlash_test.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pal.h" +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP(pal_internalFlash); +#define LITTLE_BUFFER_SIZE 120 +#define PRIME_NUMBER_FOR_TESTING 11 //must be 4 times lower then LITTLE_BUFFER_SIZE +#define MAX_BUFFER_SIZE 0x1000 + +palSotpAreaData_t areaOneData; +palSotpAreaData_t areaTwoData; +uint32_t *ReadBuffer = NULL; +uint32_t *compareBuffer = NULL; +uint32_t biggestSectorSize = 0; + + +palStatus_t InternalFlashWriteTest(uint32_t address_offset); +palStatus_t InternalFlashReadTest(uint32_t address_offset); + +TEST_SETUP(pal_internalFlash) +{ + palStatus_t status = PAL_SUCCESS; + status = pal_internalFlashGetAreaInfo(0, &areaOneData); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + status = pal_internalFlashGetAreaInfo(1, &areaTwoData); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + biggestSectorSize = (PAL_MAX(areaTwoData.size, areaOneData.size)); + biggestSectorSize = (PAL_MIN(biggestSectorSize, MAX_BUFFER_SIZE)); //there are sector size 128KB so this limit the buffer to 4KB + ReadBuffer = (uint32_t *)malloc(biggestSectorSize); + TEST_ASSERT_NOT_NULL(ReadBuffer); + compareBuffer = (uint32_t *)malloc(biggestSectorSize); + TEST_ASSERT_NOT_NULL(compareBuffer); + pal_init(); +} + +TEST_TEAR_DOWN(pal_internalFlash) +{ + if (compareBuffer != NULL) + { + free(compareBuffer); + compareBuffer = NULL; + } + + if (ReadBuffer != NULL) + { + free(ReadBuffer); + ReadBuffer = NULL; + } + pal_destroy(); +} + +/*! \brief This function checks if the flash needed to be deleted by checking if all bytes in sector are 0xFF */ +void SectorDeleteValidity(uint32_t address, size_t size) +{ + palStatus_t status = PAL_SUCCESS; + uint32_t index = 0; + memset(ReadBuffer, 0, biggestSectorSize); + + status = pal_internalFlashRead(biggestSectorSize, address, ReadBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + for(index = 0; index < biggestSectorSize; index++) + { + if((*(uint8_t*)ReadBuffer +index) != 0xFF) + { + status = pal_internalFlashErase(address, size); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + break; + } + + } +} + +/*! \brief Basic read write & erase tests + * +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Check if Sector A and B are erased | | +* | 2 | Read sector A & B and compare them to 0xFF (erased sector) | PAL_SUCCESS | +* | 3 | Run Write tests See function for more details | PAL_SUCCESS | +* | 4 | Run Read tests See function for more details | PAL_SUCCESS | +* | 5 | fill sector B with provided Data (full sector write) | PAL_SUCCESS | +* | 6 | Read full sector and compare | PAL_SUCCESS | +* | 7 | Delete Sector one | PAL_SUCCESS | +* | 8 | Read and verify that sector two in not changed | PAL_SUCCESS | +* | 9 | Delete Sector two | PAL_SUCCESS | +* | 10 | read compare both sectors to 0xff (verify erased) | PAL_SUCCESS | +*/ +TEST(pal_internalFlash, BasicTest) +{ + palStatus_t status = PAL_SUCCESS; + /*1*/ + SectorDeleteValidity(areaOneData.address, areaOneData.size); + SectorDeleteValidity(areaTwoData.address, areaTwoData.size); + + memset(compareBuffer, 0xFF, biggestSectorSize); + memset(ReadBuffer, 0, biggestSectorSize); + + /*2*/ + DEBUG_PRINT("Read both sectors and compare to 0xFF \n\r"); + status = pal_internalFlashRead(biggestSectorSize, areaOneData.address, ReadBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + TEST_ASSERT_EQUAL_UINT8_ARRAY((uint8_t *)ReadBuffer, (uint8_t *)compareBuffer, biggestSectorSize); + + status = pal_internalFlashRead(biggestSectorSize, areaTwoData.address, ReadBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + TEST_ASSERT_EQUAL_UINT8_ARRAY((uint8_t *)ReadBuffer, (uint8_t *)compareBuffer, biggestSectorSize); + + /*3*/ + status = InternalFlashWriteTest(areaOneData.address); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + /*4*/ + status = InternalFlashReadTest(areaOneData.address + 2 * LITTLE_BUFFER_SIZE); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + + + DEBUG_PRINT("---------FULL SECTOR TEST---------r\n\r"); + for (uint32_t i = 0; i < biggestSectorSize / 4; i++) + { + compareBuffer[biggestSectorSize - i - 1] = (uint8_t)(i % 256); + } + DEBUG_PRINT("Write data to second sector\n\r"); + /*5*/ + status = pal_internalFlashWrite(biggestSectorSize, areaTwoData.address, compareBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + + /*6*/ + memset(ReadBuffer, 0, biggestSectorSize); + DEBUG_PRINT("Read and compare from second sector\n\r"); + status = pal_internalFlashRead(biggestSectorSize, areaTwoData.address, ReadBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + TEST_ASSERT_EQUAL_UINT8_ARRAY((uint8_t *)ReadBuffer, (uint8_t *)compareBuffer, biggestSectorSize); + + /*7*/ + DEBUG_PRINT("Delete sector one\n\r"); + status = pal_internalFlashErase(areaOneData.address, areaOneData.size); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + + /*8*/ + DEBUG_PRINT("Verify that sector 2 was not changed in sector one erasing\n\r"); + status = pal_internalFlashRead(biggestSectorSize, areaTwoData.address, ReadBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + TEST_ASSERT_EQUAL_UINT8_ARRAY((uint8_t *)ReadBuffer, (uint8_t *)compareBuffer, biggestSectorSize); + + /*9*/ + DEBUG_PRINT("Delete sector two\n\r"); + status = pal_internalFlashErase(areaTwoData.address, areaTwoData.size); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + + /*10*/ + memset(compareBuffer, 0xFF, biggestSectorSize); + DEBUG_PRINT("Read both sectors and compare to 0xFF (verify that erase is done)\n\r"); + status = pal_internalFlashRead(biggestSectorSize, areaOneData.address, ReadBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + TEST_ASSERT_EQUAL_UINT8_ARRAY((uint8_t *)ReadBuffer, (uint8_t *)compareBuffer, biggestSectorSize); + + status = pal_internalFlashRead(biggestSectorSize, areaTwoData.address, ReadBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + TEST_ASSERT_EQUAL_UINT8_ARRAY((uint8_t *)ReadBuffer, (uint8_t *)compareBuffer, biggestSectorSize); +} + + + +/*! \brief Write tests to internal Flash with different sizes +* +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Write Data to sector from align address and up to prime number, prime number will never divide in page size | PAL_SUCCESS | +* | 2 | Read & compare Data up to prime number | PAL_SUCCESS | +* | 3 | Write Data from next align address from the prime number up to buffer size | PAL_SUCCESS | +* | 4 | Read & compare Data from prime number and up to end of buffer | PAL_SUCCESS | +*/ + + +palStatus_t InternalFlashWriteTest(uint32_t address_offset) +{ + palStatus_t status = PAL_SUCCESS; + uint32_t alignPage = pal_internalFlashGetPageSize(); + + TEST_ASSERT_NOT_EQUAL(alignPage, 0); + + DEBUG_PRINT("---------WRITE TEST---------r\n\r"); + memset(compareBuffer, 0xFF, biggestSectorSize); + memset(ReadBuffer, 0, biggestSectorSize); + + for (uint32_t i = 0; i < PRIME_NUMBER_FOR_TESTING; i++) + { + compareBuffer[i] = (uint8_t)(i % 256); + } + /*1*/ + DEBUG_PRINT("Write data to First Sector up to PRIME_NUMBER_FOR_TESTINGr\n\r"); + status = pal_internalFlashWrite(PRIME_NUMBER_FOR_TESTING,address_offset, compareBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + + /*2*/ + DEBUG_PRINT("Read and compare from first sector\n\r"); + status = pal_internalFlashRead(PRIME_NUMBER_FOR_TESTING, address_offset, ReadBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + TEST_ASSERT_EQUAL_UINT8_ARRAY((uint8_t *)ReadBuffer, (uint8_t *)compareBuffer, PRIME_NUMBER_FOR_TESTING); + + for (uint32_t i = PRIME_NUMBER_FOR_TESTING; i < LITTLE_BUFFER_SIZE / 4 ; i++) + { + compareBuffer[i] = (uint32_t)(i % 256); + } + + /*3*/ + uint32_t offset = PRIME_NUMBER_FOR_TESTING - (PRIME_NUMBER_FOR_TESTING % alignPage) + alignPage; + DEBUG_PRINT("Write data to First Sector from PRIME_NUMBER_FOR_TESTING up to LITTLE_BUFFER_SIZE\n\r"); + status = pal_internalFlashWrite(LITTLE_BUFFER_SIZE - offset, address_offset + offset, compareBuffer + offset / 4); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + + /*4*/ + DEBUG_PRINT("Read and compare from first sector\n\r"); + status = pal_internalFlashRead(LITTLE_BUFFER_SIZE - offset, address_offset + offset, ReadBuffer + offset / 4); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + TEST_ASSERT_EQUAL_UINT8_ARRAY((uint8_t *)ReadBuffer + offset, (uint8_t *)compareBuffer + offset, LITTLE_BUFFER_SIZE - offset); + return PAL_SUCCESS; +} + + +/*! \brief read tests with different sizes + * * +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Write data to sector | PAL_SUCCESS | +* | 2 | Read data in chunks of bytes and compare | PAL_SUCCESS | +*/ + +palStatus_t InternalFlashReadTest(uint32_t address_offset) +{ + palStatus_t status = PAL_SUCCESS; + DEBUG_PRINT("---------READ TEST---------r\n\r"); + memset(compareBuffer, 0xFF, biggestSectorSize); + memset(ReadBuffer, 0, biggestSectorSize); + for (uint32_t i = 0; i < LITTLE_BUFFER_SIZE / 4; i++) + { + ReadBuffer[i] = (uint32_t)(i % 256); + } + /*1*/ + DEBUG_PRINT("Write data to Sector up to LITTLE_BUFFER_SIZE\n\r"); + status = pal_internalFlashWrite(LITTLE_BUFFER_SIZE, address_offset, ReadBuffer); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + + /*2*/ + DEBUG_PRINT("Read and compare\n\r"); + for (uint32_t i = 0; i < LITTLE_BUFFER_SIZE / 4; i++) + { + uint32_t value = 0; + status = pal_internalFlashRead(1, address_offset + i, &value); + TEST_ASSERT_EQUAL_HEX(status, PAL_SUCCESS); + TEST_ASSERT_EQUAL_HEX(*((uint8_t *)ReadBuffer + i), (uint8_t)value); + } + return PAL_SUCCESS; +} + +/*! \brief Negative tests to verify validations and errors + * +** \test +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Delete sector with unaligned address | PAL_ERR_INTERNAL_FLASH_SECTOR_NOT_ALIGNED | +* | 2 | Write data that crosses between sectors | PAL_ERR_INTERNAL_FLASH_CROSSING_SECTORS | +* | 3 | Write with null ptr has buffer | PAL_ERR_INTERNAL_FLASH_CROSSING_SECTORS | +* | 4 | write with address not align to page size | PAL_ERR_INTERNAL_FLASH_ADDRESS_NOT_ALIGNED | +* | 5 | write to unaligned buffer | PAL_ERR_INTERNAL_FLASH_BUFFER_ADDRESS_NOT_ALIGNED | +*/ + +TEST(pal_internalFlash, NegativeTest) +{ + palStatus_t status = PAL_SUCCESS; + uint8_t alignPage = pal_internalFlashGetPageSize(); + uint32_t * ReadBuffer1 = NULL; + TEST_ASSERT_NOT_EQUAL(alignPage, 0); + + /*1*/ + status = pal_internalFlashErase(areaOneData.address + 4, areaOneData.size); + TEST_ASSERT_EQUAL_HEX(status, PAL_ERR_INTERNAL_FLASH_SECTOR_NOT_ALIGNED); + + /*2*/ + status = pal_internalFlashWrite(areaOneData.size * 2, areaOneData.address, (uint32_t*)&ReadBuffer1); + TEST_ASSERT_EQUAL_HEX(status, PAL_ERR_INTERNAL_FLASH_CROSSING_SECTORS); + + /*3*/ + status = pal_internalFlashWrite(areaOneData.size * 2, areaOneData.address, ReadBuffer1); + TEST_ASSERT_EQUAL_HEX(status, PAL_ERR_INTERNAL_FLASH_NULL_PTR_RECEIVED); + + /*4*/ + if( pal_internalFlashGetPageSize() > 1) + {//This test only valid if page size is bigger then 1 + status = pal_internalFlashWrite(8, (uint32_t)4, (uint32_t*)&ReadBuffer1); + TEST_ASSERT_EQUAL_HEX(status, PAL_ERR_INTERNAL_FLASH_ADDRESS_NOT_ALIGNED); + } + + /*5*/ + status = pal_internalFlashWrite(8 , areaOneData.address + alignPage + 1, (uint32_t*)0x11); + TEST_ASSERT_EQUAL_HEX(status, PAL_ERR_INTERNAL_FLASH_BUFFER_ADDRESS_NOT_ALIGNED); + +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Storage/pal_internalFlash_test_runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Storage/pal_internalFlash_test_runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unity.h" +#include "unity_fixture.h" + + +TEST_GROUP_RUNNER(pal_internalFlash) +{ + RUN_TEST_CASE(pal_internalFlash, BasicTest); + RUN_TEST_CASE(pal_internalFlash, NegativeTest); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/TLS/pal_tls_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/TLS/pal_tls_test.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,634 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "unity.h" +#include "unity_fixture.h" +#include "pal.h" +#include "pal_tls_utils.h" +//#include "pal_socket_test_utils.h" +#include "PlatIncludes.h" +#include "pal_network.h" +#include "stdlib.h" + + +PAL_PRIVATE palSocket_t g_socket = 0; +PAL_PRIVATE void * g_interfaceCTX = NULL; +PAL_PRIVATE uint32_t g_interfaceCTXIndex = 0; + +TEST_GROUP(pal_tls); + +TEST_SETUP(pal_tls) +{ + palStatus_t status = PAL_SUCCESS; +#ifdef PAL_CERT_TIME_VERIFY + uint64_t currentTime = 1491151775; // 02/04/2017 +#endif //PAL_CERT_TIME_VERIFY + pal_init(); + + if (g_interfaceCTX == NULL) + { + g_interfaceCTX = palTestGetNetWorkInterfaceContext(); + status = pal_registerNetworkInterface(g_interfaceCTX , &g_interfaceCTXIndex); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + + g_socket = 0; + +#ifdef PAL_CERT_TIME_VERIFY + status = pal_osSetTime(currentTime); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +#endif //PAL_CERT_TIME_VERIFY +} + +TEST_TEAR_DOWN(pal_tls) +{ + if (0 != g_socket) + { + pal_close(&g_socket); + } + + pal_destroy(); +} + +/** +* @brief Test TLS cofiguration initialization and uninitialization. +* +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize TLS configuration using `pal_initTLSConfiguration`. | PAL_SUCCESS | +* | 2 | Uninitialize TLS configuration using `pal_tlsConfigurationFree`. | PAL_SUCCESS | +*/ +TEST(pal_tls, tlsConfiguration) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConfHandle_t palTLSConf = NULLPTR; + palTLSTransportMode_t transportationMode = PAL_TLS_MODE; + /*#1*/ + status = pal_initTLSConfiguration(&palTLSConf, transportationMode); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_TRUE(NULLPTR != palTLSConf); + /*#2*/ + status = pal_tlsConfigurationFree(&palTLSConf); + TEST_ASSERT_EQUAL_HEX(NULLPTR, palTLSConf); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + +int palTestEntropySource(void *data, unsigned char *output, size_t len, size_t *olen) +{ + palStatus_t status = PAL_SUCCESS; + (void)data; + + status = pal_osRandomBuffer(output, len); + if (PAL_SUCCESS == status) + { + *olen = len; + } + else + { + return -1; + } + return 0; +} + +static void handshakeUDP(bool socketNonBlocking) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConfHandle_t palTLSConf = NULLPTR; + palTLSHandle_t palTLSHandle = NULLPTR; + palTLSTransportMode_t transportationMode = PAL_DTLS_MODE; + palSocketAddress_t socketAddr = {0}; + palSocketLength_t addressLength = 0; + char serverResponse[PAL_TLS_MESSAGE_SIZE] = {0}; + uint32_t actualLen = 0; + uint32_t written = 0; + palX509_t pubKey = {(const void*)g_pubKey,sizeof(g_pubKey)}; + palPrivateKey_t prvKey = {(const void*)g_prvKey,sizeof(g_prvKey)}; + palTLSSocket_t tlsSocket = {g_socket, &socketAddr, 0, transportationMode}; + palX509_t caCert = { (const void*)pal_test_cas,sizeof(pal_test_cas) }; + uint8_t coapHelloWorldRequest[16] = { 0x50,0x01,0x57,0x3e,0xff,0x2f,0x68,0x65,0x6c,0x6c,0x6f,0x57,0x6f,0x72,0x6c,0x64 }; + + /*#1*/ + status = pal_socket(PAL_AF_INET, PAL_SOCK_DGRAM, socketNonBlocking, 0, &g_socket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_getAddressInfo(PAL_TLS_TEST_SERVER_ADDRESS, &socketAddr, &addressLength); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + tlsSocket.addressLength = addressLength; + tlsSocket.socket = g_socket; + /*#3*/ + status = pal_setSockAddrPort(&socketAddr, DTLS_SERVER_PORT); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + status = pal_initTLSConfiguration(&palTLSConf, transportationMode); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#5*/ + status = pal_initTLS(palTLSConf, &palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + //status = pal_sslDebugging(true); + //TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#6*/ + status = pal_setOwnCertAndPrivateKey(palTLSConf, &pubKey, &prvKey); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#7*/ + status = pal_setCAChain(palTLSConf, &caCert, NULL); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#8*/ + status = pal_tlsSetSocket(palTLSConf, &tlsSocket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#9*/ + + status = pal_setHandShakeTimeOut(palTLSConf, 30000); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#10*/ + + do + { + status = pal_handShake(palTLSHandle, palTLSConf); + } + while (PAL_ERR_TLS_WANT_READ == status || PAL_ERR_TLS_WANT_WRITE == status); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#11*/ + status = pal_sslGetVerifyResult(palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#12*/ + status = pal_sslWrite(palTLSHandle, coapHelloWorldRequest, sizeof(coapHelloWorldRequest), &written); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#13*/ + pal_osDelay(5000); + /*#14*/ + do status = pal_sslRead(palTLSHandle, serverResponse, PAL_TLS_MESSAGE_SIZE, &actualLen); + while (PAL_ERR_TLS_WANT_READ == status); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#15*/ + status = pal_freeTLS(&palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#16*/ + status = pal_tlsConfigurationFree(&palTLSConf); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#17*/ + status = pal_close(&g_socket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + + +static void handshakeTCP(bool socketNonBlocking) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConfHandle_t palTLSConf = NULLPTR; + palTLSHandle_t palTLSHandle = NULLPTR; + palTLSTransportMode_t transportationMode = PAL_TLS_MODE; + palSocketAddress_t socketAddr = {0}; + palSocketLength_t addressLength = 0; + char serverResponse[PAL_TLS_MESSAGE_SIZE] = {0}; + uint32_t actualLen = 0; + uint32_t written = 0; + palX509_t pubKey = {(const void*)g_pubKey,sizeof(g_pubKey)}; + palPrivateKey_t prvKey = {(const void*)g_prvKey,sizeof(g_prvKey)}; + palTLSSocket_t tlsSocket = { g_socket, &socketAddr, 0, transportationMode }; + palX509_t caCert = { (const void*)pal_test_cas,sizeof(pal_test_cas) }; + uint64_t curTimeInSec, timePassedInSec; + const uint64_t minSecSinceEpoch = PAL_MIN_SEC_FROM_EPOCH + 1; //At least 47 years passed from 1.1.1970 in seconds + + + /*#1*/ + status = pal_socket(PAL_AF_INET, PAL_SOCK_STREAM, socketNonBlocking, 0, &g_socket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_getAddressInfo(PAL_TLS_TEST_SERVER_ADDRESS, &socketAddr, &addressLength); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + tlsSocket.addressLength = addressLength; + tlsSocket.socket = g_socket; + /*#3*/ + if (true == socketNonBlocking) + { + status = pal_setSockAddrPort(&socketAddr, TLS_SERVER_PORT_NB); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + else //blocking + { + status = pal_setSockAddrPort(&socketAddr, TLS_SERVER_PORT); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + + /*#4*/ + status = pal_connect(g_socket, &socketAddr, addressLength); + if (PAL_ERR_SOCKET_IN_PROGRES == status) + { + pal_osDelay(400); + } + else + { + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + } + /*#5*/ + status = pal_initTLSConfiguration(&palTLSConf, transportationMode); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + TEST_ASSERT_NOT_EQUAL(palTLSConf, NULLPTR); + /*#6*/ + status = pal_initTLS(palTLSConf, &palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + //status = pal_sslDebugging(true); + //TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#7*/ + status = pal_setOwnCertAndPrivateKey(palTLSConf, &pubKey, &prvKey); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#8*/ + status = pal_setCAChain(palTLSConf, &caCert, NULL); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#9*/ + status = pal_tlsSetSocket(palTLSConf, &tlsSocket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#10*/ + if (true == socketNonBlocking) + { + status = pal_osSetTime(minSecSinceEpoch); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); // More than current epoch time -> success + do + { + curTimeInSec = pal_osGetTime(); + TEST_ASSERT_TRUE(curTimeInSec >= minSecSinceEpoch); + timePassedInSec = curTimeInSec - minSecSinceEpoch; + status = pal_handShake(palTLSHandle, palTLSConf); + } + while ( (PAL_ERR_TLS_WANT_READ == status || PAL_ERR_TLS_WANT_WRITE == status) && + (timePassedInSec < PAL_SECONDS_PER_MIN)); //2 minutes to wait for handshake + } + else //blocking + { + status = pal_handShake(palTLSHandle, palTLSConf); + } + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#11*/ + status = pal_sslGetVerifyResult(palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#12*/ + status = pal_sslWrite(palTLSHandle, TLS_GET_REQUEST, sizeof(TLS_GET_REQUEST), &written); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#13*/ + pal_osDelay(5000); + /*#14*/ + status = pal_sslRead(palTLSHandle, serverResponse, PAL_TLS_MESSAGE_SIZE, &actualLen); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + /*#15*/ + status = pal_freeTLS(&palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#16*/ + status = pal_tlsConfigurationFree(&palTLSConf); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#17*/ + status = pal_close(&g_socket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + +} + +/** +* @brief Test TLS initialization and uninitialization. +* +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize TLS configuration using `pal_initTLSConfiguration`. | PAL_SUCCESS | +* | 2 | Initialize TLS context using `pal_initTLS`. | PAL_SUCCESS | +* | 3 | Add a NULL entropy source using `pal_addEntropySource`. | PAL_ERR_INVALID_ARGUMENT | +* | 4 | Add a valid entropy source using `pal_addEntropySource`. | PAL_SUCCESS | +* | 5 | Uninitialize TLS context using `pal_freeTLS`. | PAL_SUCCESS | +* | 6 | Uninitialize TLS configuration using `pal_tlsConfigurationFree`. | PAL_SUCCESS | +*/ +TEST(pal_tls, tlsInitTLS) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConfHandle_t palTLSConf = NULLPTR; + palTLSHandle_t palTLSHandle = NULLPTR; + palTLSTransportMode_t transportationMode = PAL_TLS_MODE; + /*#1*/ + status = pal_initTLSConfiguration(&palTLSConf, transportationMode); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_initTLS(palTLSConf, &palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_addEntropySource(NULL); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT, status); + /*#4*/ + status = pal_addEntropySource(palTestEntropySource); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#5*/ + status = pal_freeTLS(&palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#6*/ + status = pal_tlsConfigurationFree(&palTLSConf); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + + +/** +* @brief Test TLS initialization and uninitialization with additional keys. +* +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize TLS configuration using `pal_initTLSConfiguration`. | PAL_SUCCESS | +* | 2 | Add keys to the configuration using `pal_setOwnCertAndPrivateKey`. | PAL_SUCCESS | +* | 3 | Initialize TLS context using `pal_initTLS`. | PAL_SUCCESS | +* | 4 | Uninitialize TLS context using `pal_freeTLS`. | PAL_SUCCESS | +* | 5 | Uninitialize TLS configuration using `pal_tlsConfigurationFree`. | PAL_SUCCESS | +*/ +TEST(pal_tls, tlsPrivateAndPublicKeys) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConfHandle_t palTLSConf = NULLPTR; + palTLSHandle_t palTLSHandle = NULLPTR; + palTLSTransportMode_t transportationMode = PAL_TLS_MODE; + palX509_t pubKey = { (const void*)g_pubKey,sizeof(g_pubKey) }; + palPrivateKey_t prvKey = { (const void*)g_prvKey,sizeof(g_prvKey) }; + + /*#1*/ + status = pal_initTLSConfiguration(&palTLSConf, transportationMode); + TEST_ASSERT_NOT_EQUAL(palTLSConf, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_setOwnCertAndPrivateKey(palTLSConf, &pubKey, &prvKey); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_initTLS(palTLSConf, &palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + status = pal_freeTLS(&palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#5*/ + status = pal_tlsConfigurationFree(&palTLSConf); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + + +/** +* @brief Test TLS initialization and uninitialization with additional certificate and pre-shared keys. +* +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize TLS configuration using `pal_initTLSConfiguration`. | PAL_SUCCESS | +* | 2 | Set pre-shared keys to the configuration using `pal_setPSK`. | PAL_SUCCESS | +* | 3 | Set certificate chain to the configuration using `pal_setCAChain`. | PAL_SUCCESS | +* | 4 | Initialize TLS context using `pal_initTLS`. | PAL_SUCCESS | +* | 5 | Uninitialize TLS context using `pal_freeTLS`. | PAL_SUCCESS | +* | 6 | Uninitialize TLS configuration using `pal_tlsConfigurationFree`. | PAL_SUCCESS | +*/ +TEST(pal_tls, tlsCACertandPSK) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConfHandle_t palTLSConf = NULLPTR; + palTLSHandle_t palTLSHandle = NULLPTR; + palTLSTransportMode_t transportationMode = PAL_TLS_MODE; + palX509_t caCert = { (const void*)g_ca_cert,sizeof(g_ca_cert) }; + /*#1*/ + status = pal_initTLSConfiguration(&palTLSConf, transportationMode); + TEST_ASSERT_NOT_EQUAL(palTLSConf, NULLPTR); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_setPSK(palTLSConf, g_psk_id, sizeof(g_psk_id) - 1, g_psk, sizeof(g_psk)); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#3*/ + status = pal_setCAChain(palTLSConf, &caCert, NULL); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + status = pal_initTLS(palTLSConf, &palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#5*/ + status = pal_freeTLS(&palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#6*/ + status = pal_tlsConfigurationFree(&palTLSConf); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +} + + +/** +* @brief Test TLS handshake (TCP blocking). +* +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a TCP (blocking) socket. | PAL_SUCCESS | +* | 2 | Perform a DNS lookup on the server address. | PAL_SUCCESS | +* | 3 | Set the server port. | PAL_SUCCESS | +* | 4 | Connect the TCP socket to the server. | PAL_SUCCESS | +* | 5 | Initialize the TLS configuration using `pal_initTLSConfiguration`. | PAL_SUCCESS | +* | 6 | Initialize the TLS context using `pal_initTLS`. | PAL_SUCCESS | +* | 7 | Set the certificate and keys to the configuration using `pal_setOwnCertAndPrivateKey`.| PAL_SUCCESS | +* | 8 | Set the certificate chain to the configuration using `pal_setCAChain`. | PAL_SUCCESS | +* | 9 | Set the socket chain to the configuration using `pal_tlsSetSocket`. | PAL_SUCCESS | +* | 10 | Perform a TLS handshake with the server using `pal_handShaket`. | PAL_SUCCESS | +* | 11 | Verify the handshake result using `pal_sslGetVerifyResult`. | PAL_SUCCESS | +* | 12 | Write data over open TLS connection using `pal_sslWrite`. | PAL_SUCCESS | +* | 13 | Wait for the response. | PAL_SUCCESS | +* | 14 | Read data from the open TLS connection using `pal_sslRead`. | PAL_SUCCESS | +* | 15 | Uninitialize the TLS context using `pal_freeTLS`. | PAL_SUCCESS | +* | 16 | Uninitialize the TLS configuration using `pal_tlsConfigurationFree`. | PAL_SUCCESS | +* | 17 | Close the TCP socket. | PAL_SUCCESS | +*/ +TEST(pal_tls, tlsHandshakeTCP) +{ + handshakeTCP(false); +} + +/** +* @brief Test TLS handshake (TCP non-blocking). +* +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a TCP (non-blocking) socket. | PAL_SUCCESS | +* | 2 | Perform a DNS lookup on the server address. | PAL_SUCCESS | +* | 3 | Set the server port. | PAL_SUCCESS | +* | 4 | Connect the TCP socket to the server. | PAL_SUCCESS | +* | 5 | Initialize the TLS configuration using `pal_initTLSConfiguration`. | PAL_SUCCESS | +* | 6 | Initialize the TLS context using `pal_initTLS`. | PAL_SUCCESS | +* | 7 | Set the certificate and keys to the configuration using `pal_setOwnCertAndPrivateKey`.| PAL_SUCCESS | +* | 8 | Set the certificate chain to the configuration using `pal_setCAChain`. | PAL_SUCCESS | +* | 9 | Set the socket chain to the configuration using `pal_tlsSetSocket`. | PAL_SUCCESS | +* | 10 | Perform a TLS handshake with the server using `pal_handShaket` in a loop. | PAL_SUCCESS | +* | 11 | Verify the handshake result using `pal_sslGetVerifyResult`. | PAL_SUCCESS | +* | 12 | Write data over the open TLS connection using `pal_sslWrite`. | PAL_SUCCESS | +* | 13 | Wait for the response. | PAL_SUCCESS | +* | 14 | Read data from the open TLS connection using `pal_sslRead`. | PAL_SUCCESS | +* | 15 | Uninitialize the TLS context using `pal_freeTLS`. | PAL_SUCCESS | +* | 16 | Uninitialize the TLS configuration using `pal_tlsConfigurationFree`. | PAL_SUCCESS | +* | 17 | Close the TCP socket. | PAL_SUCCESS | +*/ +TEST(pal_tls, tlsHandshakeTCP_nonBlocking) +{ + handshakeTCP(true); +} + +/** +* @brief Test (D)TLS handshake (UDP -blocking). +* +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a UDP (blocking) socket. | PAL_SUCCESS | +* | 2 | Perform a DNS lookup on the server address. | PAL_SUCCESS | +* | 3 | Set the server port. | PAL_SUCCESS | +* | 4 | Initialize the TLS configuration using `pal_initTLSConfiguration`. | PAL_SUCCESS | +* | 5 | Initialize the TLS context using `pal_initTLS`. | PAL_SUCCESS | +* | 6 | Set the certificate and keys to the configuration using `pal_setOwnCertAndPrivateKey`.| PAL_SUCCESS | +* | 7 | Set the certificate chain to the configuration using `pal_setCAChain`. | PAL_SUCCESS | +* | 8 | Set the socket chain to the configuration using `pal_tlsSetSocket`. | PAL_SUCCESS | +* | 9 | Set the timeout for the handshake using `pal_setHandShakeTimeOut`. | PAL_SUCCESS | +* | 10 | Perform a TLS handshake with the server using `pal_handShaket` in a loop. | PAL_SUCCESS | +* | 11 | Verify the handshake result using `pal_sslGetVerifyResult`. | PAL_SUCCESS | +* | 12 | Write data over the open TLS connection using `pal_sslWrite`. | PAL_SUCCESS | +* | 13 | Wait for the response. | PAL_SUCCESS | +* | 14 | Read data from the open TLS connection using `pal_sslRead`. | PAL_SUCCESS | +* | 15 | Uninitialize the TLS context using `pal_freeTLS`. | PAL_SUCCESS | +* | 16 | Uninitialize the TLS configuration using `pal_tlsConfigurationFree`. | PAL_SUCCESS | +* | 17 | Close the UDP socket. | PAL_SUCCESS | +*/ +TEST(pal_tls, tlsHandshakeUDP) +{ + handshakeUDP(false); +} + +/** +* @brief Test (D)TLS handshake (UDP -NonBlocking). +* +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a UDP (blocking) socket. | PAL_SUCCESS | +* | 2 | Perform a DNS lookup on the server address. | PAL_SUCCESS | +* | 3 | Set the server port. | PAL_SUCCESS | +* | 4 | Initialize the TLS configuration using `pal_initTLSConfiguration`. | PAL_SUCCESS | +* | 5 | Initialize the TLS context using `pal_initTLS`. | PAL_SUCCESS | +* | 6 | Set the certificate and keys to the configuration using `pal_setOwnCertAndPrivateKey`.| PAL_SUCCESS | +* | 7 | Set the certificate chain to the configuration using `pal_setCAChain`. | PAL_SUCCESS | +* | 8 | Set the socket chain to the configuration using `pal_tlsSetSocket`. | PAL_SUCCESS | +* | 9 | Set the timeout for the handshake using `pal_setHandShakeTimeOut`. | PAL_SUCCESS | +* | 10 | Perform a TLS handshake with the server using `pal_handShaket` in a loop. | PAL_SUCCESS | +* | 11 | Verify the handshake result using `pal_sslGetVerifyResult`. | PAL_SUCCESS | +* | 12 | Write data over the open TLS connection using `pal_sslWrite`. | PAL_SUCCESS | +* | 13 | Wait for the response. | PAL_SUCCESS | +* | 14 | Read data from the open TLS connection using `pal_sslRead`. | PAL_SUCCESS | +* | 15 | Uninitialize the TLS context using `pal_freeTLS`. | PAL_SUCCESS | +* | 16 | Uninitialize the TLS configuration using `pal_tlsConfigurationFree`. | PAL_SUCCESS | +* | 17 | Close the UDP socket. | PAL_SUCCESS | +*/ +TEST(pal_tls, tlsHandshakeUDP_NonBlocking) +{ + handshakeUDP(true); +} + +/** +* @brief Test (D)TLS handshake (UDP non-blocking) with a very short timeout to see if you get a timeout. +* +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Create a UDP (blocking) socket. | PAL_SUCCESS | +* | 2 | Perform a DNS lookup on server adderss. | PAL_SUCCESS | +* | 3 | Set the server port. | PAL_SUCCESS | +* | 4 | Initialize the TLS configuration using `pal_initTLSConfiguration`. | PAL_SUCCESS | +* | 5 | Initialize the TLS context using `pal_initTLS`. | PAL_SUCCESS | +* | 6 | Set the certificate and keys to the configuration using `pal_setOwnCertAndPrivateKey`.| PAL_SUCCESS | +* | 7 | Set the certificate chain to the configuration using `pal_setCAChain`. | PAL_SUCCESS | +* | 8 | Set the socket chain to the configuration using `pal_tlsSetSocket`. | PAL_SUCCESS | +* | 9 | Set a short timeout for the handshake using `pal_setHandShakeTimeOut`. | PAL_SUCCESS | +* | 10 | Perform a TLS handshake with the server using `pal_handShaket` in a loop. | PAL_ERR_TIMEOUT_EXPIRED | +* | 11 | Uninitialize the TLS context using `pal_freeTLS`. | PAL_SUCCESS | +* | 12 | Uninitialize the TLS configuration using `pal_tlsConfigurationFree`. | PAL_SUCCESS | +* | 13 | Close the UDP socket. | PAL_SUCCESS | +*/ +TEST(pal_tls, tlsHandshakeUDPTimeOut) +{ + palStatus_t status = PAL_SUCCESS; + palTLSConfHandle_t palTLSConf = NULLPTR; + palTLSHandle_t palTLSHandle = NULLPTR; + palTLSTransportMode_t transportationMode = PAL_DTLS_MODE; + palSocketAddress_t socketAddr = { 0 }; + palSocketLength_t addressLength = 0; + palX509_t pubKey = { (const void*)g_pubKey,sizeof(g_pubKey) }; + palPrivateKey_t prvKey = { (const void*)g_prvKey,sizeof(g_prvKey) }; + palTLSSocket_t tlsSocket = { g_socket, &socketAddr, 0, transportationMode }; + palX509_t caCert = { (const void*)pal_test_cas,sizeof(pal_test_cas) }; + uint64_t curTimeInSec; + const uint64_t minSecSinceEpoch = PAL_MIN_SEC_FROM_EPOCH + 1; //At least 47 years passed from 1.1.1970 in seconds + + /*#1*/ + status = pal_socket(PAL_AF_INET, PAL_SOCK_DGRAM, false, 0, &g_socket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#2*/ + status = pal_getAddressInfo(PAL_TLS_TEST_SERVER_ADDRESS, &socketAddr, &addressLength); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + tlsSocket.addressLength = addressLength; + tlsSocket.socket = g_socket; + /*#3*/ + status = pal_setSockAddrPort(&socketAddr, DTLS_SERVER_PORT_TIMEOUT); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#4*/ + status = pal_initTLSConfiguration(&palTLSConf, transportationMode); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#5*/ + status = pal_initTLS(palTLSConf, &palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + //status = pal_sslDebugging(true); + //TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#6*/ + status = pal_setOwnCertAndPrivateKey(palTLSConf, &pubKey, &prvKey); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#7*/ + status = pal_setCAChain(palTLSConf, &caCert, NULL); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#8*/ + status = pal_tlsSetSocket(palTLSConf, &tlsSocket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#9*/ + status = pal_setHandShakeTimeOut(palTLSConf, 100); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + + status = pal_osSetTime(minSecSinceEpoch); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); // More than current epoch time -> success + /*#10*/ + do + { + status = pal_handShake(palTLSHandle, palTLSConf); + } + while (PAL_ERR_TLS_WANT_READ == status || PAL_ERR_TLS_WANT_WRITE == status); + + curTimeInSec = pal_osGetTime(); + TEST_ASSERT_EQUAL_HEX(PAL_ERR_TIMEOUT_EXPIRED, status); + TEST_ASSERT_TRUE(curTimeInSec - minSecSinceEpoch <= 1); //less than one second + /*#11*/ + status = pal_freeTLS(&palTLSHandle); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#12*/ + status = pal_tlsConfigurationFree(&palTLSConf); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); + /*#13*/ + status = pal_close(&g_socket); + TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/TLS/pal_tls_test_address.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/TLS/pal_tls_test_address.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +#define PAL_TLS_TEST_SERVER_ADDRESS "192.168.8.19"
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/TLS/pal_tls_test_runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/TLS/pal_tls_test_runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP_RUNNER(pal_tls) +{ + RUN_TEST_CASE(pal_tls, tlsConfiguration); + RUN_TEST_CASE(pal_tls, tlsInitTLS); + RUN_TEST_CASE(pal_tls, tlsPrivateAndPublicKeys); + RUN_TEST_CASE(pal_tls, tlsCACertandPSK); + RUN_TEST_CASE(pal_tls, tlsHandshakeUDPTimeOut); + RUN_TEST_CASE(pal_tls, tlsHandshakeTCP_nonBlocking); + RUN_TEST_CASE(pal_tls, tlsHandshakeTCP); + RUN_TEST_CASE(pal_tls, tlsHandshakeUDP); + RUN_TEST_CASE(pal_tls, tlsHandshakeUDP_NonBlocking); +} + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/TLS/pal_tls_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/TLS/pal_tls_utils.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,200 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef TEST_TLS_PAL_TEST_UTILS_H_ +#define TEST_TLS_PAL_TEST_UTILS_H_ + +#include "pal_network.h" +#include "pal_TLS.h" + + +#ifdef DEBUG +#define TEST_PRINTF printf +#else +#define TEST_PRINTF // +#endif + +typedef struct palTLSSocketTest{ + palSocket_t socket; + palSocketAddress_t* socketAddress; + palSocketLength_t addressLength; + palTLSTransportMode_t transportationMode; +}palTLSSocketTest_t; + +#define PAL_TLS_MESSAGE_SIZE 256 +#define TLS_GET_REQUEST "GET / HTTP/1.0\r\n\r\n" +#ifndef PAL_TLS_TEST_SERVER_ADDRESS + #include "pal_tls_test_address.h" +#endif +#define TLS_SERVER_PORT 5544 +#define TLS_SERVER_PORT_NB 5544 +#define DTLS_SERVER_PORT 4422 +#define DTLS_SERVER_PORT_TIMEOUT 9 //Discard protocol +#define DTLS_TIMEOUT_TEST_SERVER_ADDRESS "8.8.8.8" + + + +const unsigned char g_psk[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +}; +const unsigned char g_psk_id[] = "Client_identity"; + +const unsigned char g_ca_cert[]= +{ + 0x30, 0x82, 0x01, 0xfc, 0x30, 0x82, 0x01, 0xa1, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x09, 0x00, 0xc9, 0x7a, 0x18, 0xbd, 0x8f, 0xf4, 0xe4, 0xe3, + 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, + 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x49, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x08, 0x6d, 0x6f, 0x68, 0x61, 0x6d, 0x6d, 0x61, 0x64, 0x31, 0x0d, + 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x04, 0x62, 0x61, 0x71, + 0x61, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x04, + 0x62, 0x61, 0x71, 0x61, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x03, 0x50, 0x41, 0x4c, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x03, 0x50, 0x41, 0x4c, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x37, 0x30, 0x36, 0x31, 0x32, 0x31, 0x35, 0x35, 0x31, 0x35, 0x36, + 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x36, 0x31, 0x32, 0x31, 0x35, 0x35, + 0x31, 0x35, 0x36, 0x5a, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x6d, 0x6f, 0x68, 0x61, 0x6d, 0x6d, + 0x61, 0x64, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, + 0x04, 0x62, 0x61, 0x71, 0x61, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x04, 0x62, 0x61, 0x71, 0x61, 0x31, 0x0c, 0x30, 0x0a, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03, 0x50, 0x41, 0x4c, 0x31, 0x0c, + 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x03, 0x50, 0x41, 0x4c, + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0x77, 0xa3, 0x82, 0x16, 0xb9, 0xef, 0x71, 0xa3, 0x1d, + 0x76, 0xb8, 0x58, 0x48, 0x29, 0xc9, 0x30, 0x88, 0xa5, 0x8b, 0xe9, 0xf0, + 0x82, 0x1c, 0x13, 0xb5, 0xc2, 0xad, 0x87, 0xc9, 0x11, 0x4c, 0x8a, 0xbe, + 0x32, 0xed, 0xf8, 0x5e, 0x19, 0xf5, 0x91, 0xcb, 0x8f, 0x7e, 0x3e, 0x0b, + 0xe5, 0x62, 0x68, 0x44, 0x80, 0x98, 0x43, 0xbc, 0x68, 0x9f, 0x5c, 0xce, + 0x01, 0x8e, 0xfa, 0x9d, 0x9e, 0x32, 0xe1, 0xa3, 0x50, 0x30, 0x4e, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x82, 0xa1, + 0xc6, 0xa7, 0x08, 0xfa, 0xf1, 0xce, 0xd3, 0x24, 0x01, 0xdc, 0xd4, 0x4c, + 0x7a, 0x12, 0x48, 0x78, 0xed, 0xe0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x82, 0xa1, 0xc6, 0xa7, 0x08, + 0xfa, 0xf1, 0xce, 0xd3, 0x24, 0x01, 0xdc, 0xd4, 0x4c, 0x7a, 0x12, 0x48, + 0x78, 0xed, 0xe0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, + 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, + 0x00, 0xa1, 0x5f, 0xa8, 0xfb, 0xbf, 0x00, 0x14, 0xff, 0x74, 0xe1, 0x0f, + 0x91, 0x85, 0xb9, 0xcb, 0xf5, 0x95, 0xcd, 0x35, 0xfc, 0x52, 0x5d, 0x33, + 0xbe, 0x86, 0xb2, 0xa2, 0x0b, 0xc3, 0x48, 0xfe, 0x56, 0x02, 0x21, 0x00, + 0xd1, 0x92, 0xeb, 0xee, 0xa4, 0xc2, 0xf0, 0xca, 0x86, 0x3f, 0x57, 0x18, + 0xa3, 0xd4, 0xc9, 0xd9, 0xd6, 0xd4, 0x7b, 0x18, 0x9c, 0xa4, 0xe9, 0xd9, + 0xfd, 0xa7, 0x94, 0xe7, 0x78, 0xc3, 0xeb, 0x59 +}; + +//ECC Key +const unsigned char g_pubKey[] = +{ + 0x30, 0x82, 0x01, 0x9a, 0x30, 0x82, 0x01, 0x3e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, + 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x30, 0x2d, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x02, 0x43, 0x41, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x6d, 0x62, 0x65, 0x64, 0x20, 0x54, 0x4c, 0x53, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x30, 0x1e, 0x17, + 0x0d, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, + 0x33, 0x30, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x2d, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x02, 0x43, 0x41, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x6d, 0x62, 0x65, 0x64, 0x20, 0x54, 0x4c, 0x53, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x4b, 0x30, 0x59, 0x30, 0x13, + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xf7, 0xc6, 0x63, 0x68, 0x8d, 0x48, 0x3a, 0xcc, 0xeb, + 0xc1, 0x01, 0xcb, 0xd5, 0xc9, 0xa9, 0xc8, 0x42, 0x62, 0x2e, 0xd0, 0xb2, 0x34, 0x6a, 0x9f, 0xc9, + 0xce, 0xe0, 0x1c, 0x57, 0xc7, 0x0a, 0x62, 0x6e, 0x8e, 0x2e, 0xc5, 0x9f, 0xef, 0x8e, 0x04, 0x44, + 0x7e, 0xf3, 0xd0, 0xe6, 0x92, 0xc9, 0x0a, 0x49, 0x72, 0x98, 0x7f, 0x73, 0x3e, 0xf6, 0x97, 0x70, + 0x74, 0xb7, 0x9f, 0xe1, 0xb5, 0xef, 0xce, 0xa3, 0x4d, 0x30, 0x4b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x0f, 0xc6, 0x27, 0x51, 0xce, 0x06, 0x0b, 0x3b, 0xbd, 0xf1, 0xd1, 0x8e, 0x25, 0x6d, 0xcd, + 0x12, 0x64, 0x8f, 0x73, 0x4d, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0x0f, 0xc6, 0x27, 0x51, 0xce, 0x06, 0x0b, 0x3b, 0xbd, 0xf1, 0xd1, 0x8e, 0x25, 0x6d, + 0xcd, 0x12, 0x64, 0x8f, 0x73, 0x4d, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, + 0x03, 0x02, 0x05, 0x00, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xf1, 0x6a, 0x24, 0x08, + 0x99, 0xf1, 0xe0, 0x55, 0x4f, 0x0a, 0x52, 0x72, 0x68, 0x63, 0x6e, 0xec, 0x2f, 0x9d, 0x54, 0x61, + 0x9d, 0x7f, 0xa3, 0x5d, 0xa5, 0x79, 0x69, 0xc2, 0xab, 0xcf, 0x0f, 0x48, 0x02, 0x20, 0x51, 0x41, + 0x26, 0x4b, 0xdf, 0x1b, 0x5e, 0xda, 0xa4, 0x53, 0x8d, 0xe5, 0x92, 0xa6, 0x1b, 0x8a, 0x0d, 0x58, + 0x59, 0x9e, 0x77, 0x99, 0xd6, 0x81, 0xf1, 0x5d, 0xcd, 0x28, 0xcc, 0x03, 0x75, 0x96 +}; + +const uint8_t g_prvKey[] = +{ + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x0d, 0x2d, 0x9e, 0x38, 0xe8, 0x2c, 0x7a, 0x44, 0x66, + 0x20, 0x4a, 0x3e, 0x8c, 0xb1, 0x83, 0x43, 0xb0, 0xc0, 0xc9, 0xd7, 0x46, 0xf6, 0x9d, 0xe4, 0xd0, + 0xb2, 0x58, 0x8e, 0x0b, 0x8d, 0x70, 0xd0, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x18, 0xf7, 0x26, 0xc6, 0x86, 0x30, 0xec, + 0xed, 0xd6, 0xb4, 0x3a, 0xd3, 0x86, 0x7a, 0x49, 0xbb, 0xb3, 0x93, 0xee, 0x43, 0x56, 0x18, 0x71, + 0x2a, 0x40, 0xda, 0xc8, 0x2c, 0x4a, 0xc6, 0x3d, 0x09, 0xfc, 0xe0, 0x84, 0x2f, 0x0d, 0xce, 0xf8, + 0x17, 0xcf, 0x28, 0x8f, 0x4f, 0xb4, 0xea, 0xde, 0xf9, 0xe4, 0x9a, 0x16, 0xeb, 0x8c, 0x67, 0x02, + 0xfd, 0x64, 0x7b, 0x62, 0x0e, 0x9b, 0x29, 0x05, 0x22 +}; + + +////////////////////////////////////////// +//Data taken from mbed TLS tests (certc.c) +////////////////////////////////////////// +const char pal_test_cas[] = +{ + 0x30, 0x82, 0x02, 0x52, 0x30, 0x82, 0x01, 0xd7, 0xa0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x09, 0x00, 0xc1, 0x43, 0xe2, 0x7e, 0x62, 0x43, 0xcc, 0xe8, 0x30, 0x0a, + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x3e, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x4e, 0x4c, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, 0x50, 0x6f, 0x6c, + 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x13, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x73, 0x73, 0x6c, 0x20, 0x54, + 0x65, 0x73, 0x74, 0x20, 0x45, 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x33, 0x30, 0x39, 0x32, 0x34, 0x31, 0x35, 0x34, 0x39, 0x34, 0x38, 0x5a, + 0x17, 0x0d, 0x32, 0x33, 0x30, 0x39, 0x32, 0x32, 0x31, 0x35, 0x34, 0x39, 0x34, + 0x38, 0x5a, 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x13, 0x08, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x1c, 0x30, + 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x50, 0x6f, 0x6c, 0x61, 0x72, + 0x73, 0x73, 0x6c, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x43, 0x20, 0x43, + 0x41, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xc3, + 0xda, 0x2b, 0x34, 0x41, 0x37, 0x58, 0x2f, 0x87, 0x56, 0xfe, 0xfc, 0x89, 0xba, + 0x29, 0x43, 0x4b, 0x4e, 0xe0, 0x6e, 0xc3, 0x0e, 0x57, 0x53, 0x33, 0x39, 0x58, + 0xd4, 0x52, 0xb4, 0x91, 0x95, 0x39, 0x0b, 0x23, 0xdf, 0x5f, 0x17, 0x24, 0x62, + 0x48, 0xfc, 0x1a, 0x95, 0x29, 0xce, 0x2c, 0x2d, 0x87, 0xc2, 0x88, 0x52, 0x80, + 0xaf, 0xd6, 0x6a, 0xab, 0x21, 0xdd, 0xb8, 0xd3, 0x1c, 0x6e, 0x58, 0xb8, 0xca, + 0xe8, 0xb2, 0x69, 0x8e, 0xf3, 0x41, 0xad, 0x29, 0xc3, 0xb4, 0x5f, 0x75, 0xa7, + 0x47, 0x6f, 0xd5, 0x19, 0x29, 0x55, 0x69, 0x9a, 0x53, 0x3b, 0x20, 0xb4, 0x66, + 0x16, 0x60, 0x33, 0x1e, 0xa3, 0x81, 0xa0, 0x30, 0x81, 0x9d, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x9d, 0x6d, 0x20, 0x24, 0x49, + 0x01, 0x3f, 0x2b, 0xcb, 0x78, 0xb5, 0x19, 0xbc, 0x7e, 0x24, 0xc9, 0xdb, 0xfb, + 0x36, 0x7c, 0x30, 0x6e, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x67, 0x30, 0x65, + 0x80, 0x14, 0x9d, 0x6d, 0x20, 0x24, 0x49, 0x01, 0x3f, 0x2b, 0xcb, 0x78, 0xb5, + 0x19, 0xbc, 0x7e, 0x24, 0xc9, 0xdb, 0xfb, 0x36, 0x7c, 0xa1, 0x42, 0xa4, 0x40, + 0x30, 0x3e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x4e, 0x4c, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x08, + 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x53, 0x53, 0x4c, 0x31, 0x1c, 0x30, 0x1a, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x73, 0x73, + 0x6c, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x43, 0x20, 0x43, 0x41, 0x82, + 0x09, 0x00, 0xc1, 0x43, 0xe2, 0x7e, 0x62, 0x43, 0xcc, 0xe8, 0x30, 0x0c, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x69, 0x00, + 0x30, 0x66, 0x02, 0x31, 0x00, 0xc3, 0xb4, 0x62, 0x73, 0x56, 0x28, 0x95, 0x00, + 0x7d, 0x78, 0x12, 0x26, 0xd2, 0x71, 0x7b, 0x19, 0xf8, 0x8a, 0x98, 0x3e, 0x92, + 0xfe, 0x33, 0x9e, 0xe4, 0x79, 0xd2, 0xfe, 0x7a, 0xb7, 0x87, 0x74, 0x3c, 0x2b, + 0xb8, 0xd7, 0x69, 0x94, 0x0b, 0xa3, 0x67, 0x77, 0xb8, 0xb3, 0xbe, 0xd1, 0x36, + 0x32, 0x02, 0x31, 0x00, 0xfd, 0x67, 0x9c, 0x94, 0x23, 0x67, 0xc0, 0x56, 0xba, + 0x4b, 0x33, 0x15, 0x00, 0xc6, 0xe3, 0xcc, 0x31, 0x08, 0x2c, 0x9c, 0x8b, 0xda, + 0xa9, 0x75, 0x23, 0x2f, 0xb8, 0x28, 0xe7, 0xf2, 0x9c, 0x14, 0x3a, 0x40, 0x01, + 0x5c, 0xaf, 0x0c, 0xb2, 0xcf, 0x74, 0x7f, 0x30, 0x9f, 0x08, 0x43, 0xad, 0x20 +}; + +#endif /* TEST_TLS_PAL_TEST_UTILS_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Update/pal_update_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Update/pal_update_test.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,664 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "unity.h" +#include "unity_fixture.h" +#include "pal_test_main.h" +#include "string.h" +#include "mbed_trace.h" + + +#define KILOBYTE 1024 + +#define FIRST_IMAGE_INDEX 0 + +TEST_GROUP(pal_update); + + +palBuffer_t g_writeBuffer = {0}; +palBuffer_t g_readBuffer = {0}; +palImageHeaderDeails_t g_imageHeader = {0}; +uint8_t g_isTestDone; + + +uint8_t numberofBlocks = 0; + +/*! \brief Sanity test the update test are running. +*/ +TEST_SETUP(pal_update) +{ + PAL_LOG(INFO, "running new test\r\n"); + +} + +typedef enum _updateTestState +{ + test_init = 1, + test_write, + test_commit, + test_read +}updateTestState; + +PAL_PRIVATE void stateAdvance(palImageEvents_t state) +{ + TEST_PRINTF("Finished event %d\r\n",state); + state++; + TEST_PRINTF("Starting event %d\r\n",state); + int rc = PAL_SUCCESS; + TEST_PRINTF("Write ptr = (%p - %p) read ptr = (%p - %p)\r\n", + g_writeBuffer.buffer,g_writeBuffer.buffer + g_writeBuffer.maxBufferLength, + g_readBuffer.buffer, g_readBuffer.buffer + g_readBuffer.maxBufferLength); + switch (state) + { + case PAL_IMAGE_EVENT_PREPARE: + rc = pal_imagePrepare(FIRST_IMAGE_INDEX, &g_imageHeader); + TEST_PRINTF("pal_imagePrepare returned %d \r\n",rc); + break; + case PAL_IMAGE_EVENT_WRITE: + rc = pal_imageWrite(FIRST_IMAGE_INDEX, 0, (palConstBuffer_t*)&g_writeBuffer); + TEST_PRINTF("pal_imageWrite returned %d \r\n",rc); + TEST_ASSERT_TRUE(rc >= 0); + break; + case PAL_IMAGE_EVENT_FINALIZE: + rc = pal_imageFinalize(FIRST_IMAGE_INDEX); + TEST_PRINTF("pal_imageFinalize returned %d \r\n",rc); + TEST_ASSERT_TRUE(rc >= 0); + break; + case PAL_IMAGE_EVENT_READTOBUFFER: + rc = pal_imageReadToBuffer(FIRST_IMAGE_INDEX,0,&g_readBuffer); + TEST_ASSERT_TRUE(rc >= 0); + TEST_PRINTF("pal_imageReadToBuffer with offset %d return %d \r\n",0,rc); + break; + case PAL_IMAGE_EVENT_ACTIVATE: + TEST_PRINTF("Checking the output\r\n"); + TEST_PRINTF("\r\ng_readBuffer bufferLength=%" PRIu32 "\r\n",g_readBuffer.maxBufferLength); + + + TEST_ASSERT_EQUAL_MEMORY(g_writeBuffer.buffer,g_readBuffer.buffer,g_readBuffer.maxBufferLength); + TEST_PRINTF("write ptr = %p read ptr = %p\r\n",g_writeBuffer.buffer,g_readBuffer.buffer); + + free(g_readBuffer.buffer); + free(g_writeBuffer.buffer); + pal_imageDeInit(); + g_isTestDone = 1; + break; + default: + TEST_PRINTF("Error - this should not happen\r\n"); + TEST_PRINTF("Write ptr = %p read ptr = %p\r\n",g_writeBuffer.buffer,g_readBuffer.buffer); + free(g_readBuffer.buffer); + free(g_writeBuffer.buffer); + pal_imageDeInit(); + g_isTestDone = 1; + } +} + + + + + + +void printBuffer(uint8_t* buffer, size_t bufSize) +{ + size_t i = 0; + TEST_PRINTF("0x"); + for (i=0;i < bufSize;i++) + { + TEST_PRINTF("%x",buffer[i]); + } + TEST_PRINTF("\r\n"); +} + + +PAL_PRIVATE void fillBuffer(uint8_t* buffer, size_t bufSize) +{ + size_t i = 0; + uint8_t value = 0; + int8_t step = -1; + TEST_PRINTF("Filling buffer size %d\r\n",bufSize); + for(i=0; i < bufSize ; i++) + { + buffer[i] = value; + if ((0 == value) || (255 == value)) + { + step*=-1; + } + value+=step; + } + TEST_PRINTF("Buffer is full\r\n"); + +} + + +TEST_TEAR_DOWN(pal_update) +{ +} + + + +void pal_update_xK(int sizeInK) +{ + + palStatus_t rc = PAL_SUCCESS; + if (!(sizeInK % KILOBYTE)) + { + TEST_PRINTF("\n-====== PAL_UPDATE_%dKb ======- \n",sizeInK / KILOBYTE); + } + else + { + TEST_PRINTF("\n-====== PAL_UPDATE_%db ======- \n",sizeInK); + } + uint8_t *writeData = (uint8_t*)malloc(sizeInK); + uint8_t *readData = (uint8_t*)malloc(sizeInK); + + TEST_ASSERT_TRUE(writeData != NULL); + TEST_ASSERT_TRUE(readData != NULL); + + uint64_t version = 11111111; + uint32_t hash = 0x22222222; + + g_isTestDone = 0; + + g_imageHeader.version = version; + + g_imageHeader.hash.buffer =(uint8_t*)&hash; + g_imageHeader.hash.bufferLength = sizeof(hash); + g_imageHeader.hash.maxBufferLength = sizeof(hash); + + g_imageHeader.imageSize = sizeInK; + + g_writeBuffer.buffer = writeData; + g_writeBuffer.bufferLength = sizeInK; + g_writeBuffer.maxBufferLength = sizeInK; + + TEST_PRINTF("write buffer length %" PRIu32 " max length %" PRIu32 "\r\n",g_writeBuffer.bufferLength,g_writeBuffer.maxBufferLength); + fillBuffer(g_writeBuffer.buffer,g_writeBuffer.bufferLength); + + g_readBuffer.buffer = readData; + g_readBuffer.maxBufferLength = sizeInK; + + + rc =pal_imageInitAPI(stateAdvance); + TEST_PRINTF("pal_imageInitAPI returned %" PRIu32 " \r\n",rc); + TEST_ASSERT_TRUE(rc >= 0); + + /*Wait until the async test finishes*/ + while (!g_isTestDone) + pal_osDelay(5); //Make the OS switch context + +} + +/*! \brief Writing a 1Kb image and verifying its value. + * \test +* This test simulates a state machine for writing and reading a 1Kb image. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `pal_imagePrepare` | PAL_SUCCESS | +* | 3 | `pal_imageWrite` | PAL_SUCCESS | +* | 4 | `pal_imageFinalize` | PAL_SUCCESS | +* | 5 | `pal_imageReadToBuffer` | PAL_SUCCESS | +* | 6 | Compare the written image with the read image. | memcmp == 0 | +*/ + +TEST(pal_update, pal_update_1k) +{ + pal_update_xK(1*KILOBYTE); +} + + +/*! \brief Writing a 2Kb image and verifying its value. + * \test +* This test simulates a state machine for writing and reading a 2Kb image. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `pal_imagePrepare` | PAL_SUCCESS | +* | 3 | `pal_imageWrite` | PAL_SUCCESS | +* | 4 | `pal_imageFinalize` | PAL_SUCCESS | +* | 5 | `pal_imageReadToBuffer` | PAL_SUCCESS | +* | 6 | Compare the written image with the read image. | memcmp == 0 | +*/ + +TEST(pal_update, pal_update_2k) +{ + pal_update_xK(2*KILOBYTE); +} + +/*! \brief Writing a 4Kb image and verifying its value. + * \test +* This test simulates a state machine for writing and reading a 4Kb image. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `pal_imagePrepare` | PAL_SUCCESS | +* | 3 | `pal_imageWrite` | PAL_SUCCESS | +* | 4 | `pal_imageFinalize` | PAL_SUCCESS | +* | 5 | `pal_imageReadToBuffer` | PAL_SUCCESS | +* | 6 | Compare the written image with the read image. | memcmp == 0 | +*/ + +TEST(pal_update, pal_update_4k) +{ + pal_update_xK(4*KILOBYTE); +} + +/*! \brief Writing an 8Kb image and verifying its value. + * \test +* This test simulates a state machine for writing and reading an 8Kb image. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `pal_imagePrepare` | PAL_SUCCESS | +* | 3 | `pal_imageWrite` | PAL_SUCCESS | +* | 4 | `pal_imageFinalize` | PAL_SUCCESS | +* | 5 | `pal_imageReadToBuffer` | PAL_SUCCESS | +* | 6 | Compare the written image with the read image. | memcmp == 0 | +*/ + +TEST(pal_update, pal_update_8k) +{ + pal_update_xK(8*KILOBYTE); +} + +/*! \brief Writing a 16Kb image and verifying its value. + * \test +* This test simulates a state machine for writing and reading a 16Kb image. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `pal_imagePrepare` | PAL_SUCCESS | +* | 3 | `pal_imageWrite` | PAL_SUCCESS | +* | 4 | `pal_imageFinalize` | PAL_SUCCESS | +* | 5 | `pal_imageReadToBuffer` | PAL_SUCCESS | +* | 6 | Compare the written image with the read image. | memcmp == 0 | +*/ + +TEST(pal_update, pal_update_16k) +{ + pal_update_xK(16*KILOBYTE); +} + + +/*! \brief Writing a small image (5b) and verifying its value. + * \test +* This test simulates a state machine for writing and reading a 5b image. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `pal_imagePrepare` | PAL_SUCCESS | +* | 3 | `pal_imageWrite` | PAL_SUCCESS | +* | 4 | `pal_imageFinalize` | PAL_SUCCESS | +* | 5 | `pal_imageReadToBuffer` | PAL_SUCCESS | +* | 6 | Compare the written image with the read image. | memcmp == 0 | +*/ + + +TEST(pal_update,pal_update_writeSmallChunk_5b) +{ + pal_update_xK(5); +} + + +/*! \brief Writing an unaligned image of 1001b and verifying its value. + * \test +* This test simulates a state machine for writing and reading a 51001b image. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `pal_imagePrepare` | PAL_SUCCESS | +* | 3 | `pal_imageWrite` | PAL_SUCCESS | +* | 4 | `pal_imageFinalize` | PAL_SUCCESS | +* | 5 | `pal_imageReadToBuffer` | PAL_SUCCESS | +* | 6 | Compare the written image with the read image. | memcmp == 0 | +*/ + + +TEST(pal_update,pal_update_writeUnaligned_1001b) +{ + //1039 is a prime number so probably never aligned. + pal_update_xK(1039); +} + + + + +PAL_PRIVATE void multiWriteMultiRead(palImageEvents_t state) +{ + int rc = PAL_SUCCESS; + static uint8_t counter = 0; + static uint8_t *writeBase = NULL; + static uint8_t *readBase = NULL; + if (NULL == writeBase) + { + writeBase = g_writeBuffer.buffer; + g_writeBuffer.maxBufferLength = g_writeBuffer.maxBufferLength/numberofBlocks; + g_writeBuffer.bufferLength = g_writeBuffer.bufferLength/numberofBlocks; + + readBase = g_readBuffer.buffer; + g_readBuffer.maxBufferLength = g_readBuffer.maxBufferLength/numberofBlocks; + } + TEST_PRINTF("Finished event %d\r\n",state); + if (PAL_IMAGE_EVENT_WRITE == state) // Just wrote data + { + counter++; + if (numberofBlocks == counter) // Wrote all needed blocks + { + state++; // Advance to next state + counter = 0; //Initialize counter + } + } + else if (PAL_IMAGE_EVENT_READTOBUFFER == state) // Just read data + { + counter++ ; + if (numberofBlocks == counter) // Read all needed blocks + { + state++; // Advance to next state + counter = 0; + } + } + else + { + state++; // Advance to next state + } + + TEST_PRINTF("Starting event %d\r\n",state); + + switch (state) + { + case PAL_IMAGE_EVENT_PREPARE: + rc = pal_imagePrepare(FIRST_IMAGE_INDEX, &g_imageHeader); + TEST_PRINTF("pal_imagePrepare returned %d \r\n",rc); + break; + case PAL_IMAGE_EVENT_WRITE: + TEST_PRINTF("Write KILOBYTE * %d = %d\r\n",counter,KILOBYTE*(counter)); + g_writeBuffer.buffer = &writeBase[KILOBYTE*(counter)];// Writing 1k every time + rc = pal_imageWrite(FIRST_IMAGE_INDEX, KILOBYTE*(counter),(palConstBuffer_t*)&g_writeBuffer); + TEST_PRINTF("pal_imageWrite returned %d \r\n",rc); + TEST_ASSERT_TRUE(rc >= 0); + break; + case PAL_IMAGE_EVENT_FINALIZE: + rc = pal_imageFinalize(FIRST_IMAGE_INDEX); + TEST_PRINTF("pal_imageFinalize returned %d \r\n",rc); + TEST_ASSERT_TRUE(rc >= 0); + break; + case PAL_IMAGE_EVENT_READTOBUFFER: + TEST_PRINTF("Read KILOBYTE * %d = %d\r\n",counter, KILOBYTE*(counter)); + g_readBuffer.buffer = &readBase[KILOBYTE*(counter)];// Writing 1k every time + g_readBuffer.bufferLength = 0; + rc = pal_imageReadToBuffer(FIRST_IMAGE_INDEX, KILOBYTE*(counter),&g_readBuffer); + TEST_PRINTF("pal_imageReadToBuffer with offset %d return %d \r\n",0,rc); + break; + case PAL_IMAGE_EVENT_ACTIVATE: + + TEST_PRINTF("Checking the output\r\n"); + + TEST_ASSERT_TRUE(rc >= 0); + TEST_ASSERT_TRUE(!memcmp(readBase,writeBase,numberofBlocks*KILOBYTE)); + free(writeBase); + free(readBase); + pal_imageDeInit(); + g_isTestDone = 1; + break; + default: + TEST_PRINTF("Error\r\n"); + free(writeBase); + free(readBase); + pal_imageDeInit(); + g_isTestDone = 1; + break; + } +} + + +/*! \brief Writing a 4Kb image and reading it with a 1Kb buffer. + * \test +* This test simulates a state machine for writing and reading a 4Kb image. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `pal_imagePrepare` | PAL_SUCCESS | +* | 3 | `pal_imageWrite` | PAL_SUCCESS | +* | 4 | `pal_imageFinalize` | PAL_SUCCESS | +* | 5 | `pal_imageReadToBuffer` | PAL_SUCCESS | +* | 6 | Compare the written image with the read image. | memcmp == 0 | +*/ + +TEST(pal_update, pal_update_4k_write_1k_4_times) +{ + palStatus_t rc = PAL_SUCCESS; + + uint8_t *writeData = (uint8_t*)malloc(4*KILOBYTE); + uint8_t *readData = (uint8_t*)malloc(4*KILOBYTE); + + + TEST_ASSERT_TRUE(writeData != NULL); + TEST_ASSERT_TRUE(readData != NULL); + + uint64_t version = 11111111; + uint32_t hash = 0x22222222; + g_isTestDone = 0; + + g_imageHeader.version = version; + + g_imageHeader.hash.buffer =(uint8_t*)&hash; + g_imageHeader.hash.bufferLength = sizeof(hash); + g_imageHeader.hash.maxBufferLength = sizeof(hash); + + g_imageHeader.imageSize = 4*KILOBYTE; + + fillBuffer(writeData,4*KILOBYTE); + + g_writeBuffer.buffer = writeData; + g_writeBuffer.bufferLength = 4*KILOBYTE; + g_writeBuffer.maxBufferLength = 4*KILOBYTE; + TEST_PRINTF("pal_update_4k"); + TEST_PRINTF("Write buffer length %" PRIu32 " max length %" PRIu32 "\r\n",g_writeBuffer.bufferLength,g_writeBuffer.maxBufferLength); + fillBuffer(g_writeBuffer.buffer,g_writeBuffer.bufferLength); + + g_readBuffer.buffer = readData; + g_readBuffer.maxBufferLength = 4*KILOBYTE; + + numberofBlocks = 4; + + rc = pal_imageInitAPI(multiWriteMultiRead); + TEST_PRINTF("pal_imageInitAPI returned %" PRIu32 " \r\n",rc); + TEST_ASSERT_TRUE(rc >= 0); + /*Wait until the async test finishes*/ + while (!g_isTestDone) + pal_osDelay(5); // Make the OS switch context + +} + +/*! \brief Writing a different image with incrementing size. + * \test +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `1kb_image` | Success | +* | 3 | `2kb_image` | Success | +* | 4 | `4kb_image` | Success | +* | 5 | `8kb_image` | Success | +* | 6 | `16kb_image` | Success | +* | 7 | `32kb_image` | Success | +*/ +TEST(pal_update, pal_update_stressTest) +{ + uint8_t it,j; + TEST_PRINTF("****************************************************\r\n"); + TEST_PRINTF("******* Testing multiple writes sequentially *******\r\n"); + TEST_PRINTF("****************************************************\r\n"); + for (j=0; j < 5; j++) + { + TEST_PRINTF("1\r\n"); + for (it = 1; it < 32; it*=2) + { + pal_update_xK(it*KILOBYTE); + + } + } +} + + + + + + +PAL_PRIVATE void readStateMachine(palImageEvents_t state) +{ + static uint8_t *readData = NULL ; + static uint32_t bytesWasRead = 0; + int rc = PAL_SUCCESS; + TEST_PRINTF("Finished event %d\r\n",state); + /*If just finished reading*/ + if (PAL_IMAGE_EVENT_READTOBUFFER == state) + { + TEST_PRINTF("g_readBuffer.bufferLength %" PRIu32 "\r\n",g_readBuffer.bufferLength); + if (0 < g_readBuffer.bufferLength) + { + TEST_PRINTF("Writing %" PRIu32 " bytes to readData[%" PRIu32 "]\r\n",g_readBuffer.bufferLength,bytesWasRead); + memcpy(&readData[bytesWasRead],g_readBuffer.buffer,g_readBuffer.bufferLength); + bytesWasRead+=g_readBuffer.bufferLength; + } + else + { + state++; + } + } + else + { + state++; + } + TEST_PRINTF("Starting event %d\r\n",state); + switch (state) + { + case PAL_IMAGE_EVENT_PREPARE: + bytesWasRead = 0; + TEST_PRINTF("Allocating %" PRIu32 " byes for test \r\n",g_writeBuffer.maxBufferLength); + readData = (uint8_t*)malloc(g_writeBuffer.maxBufferLength); + TEST_ASSERT_TRUE(readData != NULL); + rc = pal_imagePrepare(FIRST_IMAGE_INDEX,&g_imageHeader); + TEST_PRINTF("pal_imagePrepare returned %d \r\n",rc); + break; + case PAL_IMAGE_EVENT_WRITE: + rc = pal_imageWrite(FIRST_IMAGE_INDEX,0,(palConstBuffer_t*)&g_writeBuffer); + TEST_PRINTF("pal_imageWrite returned %d \r\n",rc); + TEST_ASSERT_TRUE(rc >= 0); + break; + case PAL_IMAGE_EVENT_FINALIZE: + rc = pal_imageFinalize(FIRST_IMAGE_INDEX); + TEST_PRINTF("pal_imageFinalize returned %d \r\n",rc); + TEST_ASSERT_TRUE(rc >= 0); + break; + case PAL_IMAGE_EVENT_READTOBUFFER: + g_readBuffer.bufferLength = 0; + memset(g_readBuffer.buffer,0,g_readBuffer.maxBufferLength); + rc = pal_imageReadToBuffer(FIRST_IMAGE_INDEX,bytesWasRead,&g_readBuffer); + TEST_PRINTF("pal_imageReadToBuffer with offset %" PRIu32 " return %d \r\n",bytesWasRead,rc); + //TEST_ASSERT_TRUE((rc >= 0) || (rc != -10)); + break; + case PAL_IMAGE_EVENT_ACTIVATE: + TEST_PRINTF("Checking the output\r\n"); + TEST_PRINTF("\r\ng_readBuffer bufferLength=%" PRIu32 "\r\n",g_readBuffer.maxBufferLength); + TEST_ASSERT_TRUE(!memcmp(readData,g_writeBuffer.buffer,g_writeBuffer.bufferLength)); + TEST_PRINTF("write ptr = %p read ptr = %p\r\n",g_writeBuffer.buffer,g_readBuffer.buffer); + free(g_readBuffer.buffer); + free(g_writeBuffer.buffer); + free(readData); + pal_imageDeInit(); + g_isTestDone = 1; + break; + default: + TEST_PRINTF("Error - this should not happen\r\n"); + TEST_PRINTF("write ptr = %p read ptr = %p\r\n",g_writeBuffer.buffer,g_readBuffer.buffer); + free(g_readBuffer.buffer); + free(g_writeBuffer.buffer); + free(readData); + pal_imageDeInit(); + g_isTestDone = 1; + TEST_ASSERT_TRUE(rc >= 0); + } +} + + + +/*! \brief Writing an image and verifying its value by multiple reads. + * \test +* This test simulates a state machine for writing and reading an image. +* +* | # | Step | Expected | +* |---|--------------------------------|-------------| +* | 1 | Initialize the test. | Success | +* | 2 | `pal_imagePrepare` | PAL_SUCCESS | +* | 3 | `pal_imageWrite` | PAL_SUCCESS | +* | 4 | `pal_imageFinalize` | PAL_SUCCESS | +* | 5 | `pal_imageReadToBuffer` | PAL_SUCCESS | +* | 6 | Compare the written image with the read image. | memcmp == 0 | +*/ + +TEST(pal_update, pal_update_Read) +{ + uint32_t sizeIn=1500; + palStatus_t rc = PAL_SUCCESS; + TEST_PRINTF("\n-====== PAL_UPDATE_READ TEST %" PRIu32 " b ======- \n",sizeIn); + uint8_t *writeData = (uint8_t*)malloc(sizeIn); + uint8_t *readData = (uint8_t*)malloc(sizeIn/5); + + TEST_ASSERT_TRUE(writeData != NULL); + TEST_ASSERT_TRUE(readData != NULL); + + uint64_t version = 11111111; + uint32_t hash = 0x22222222; + + g_isTestDone = 0; + + g_imageHeader.version = version; + + g_imageHeader.hash.buffer = (uint8_t*)&hash; + g_imageHeader.hash.bufferLength = sizeof(hash); + g_imageHeader.hash.maxBufferLength = sizeof(hash); + + g_imageHeader.imageSize = sizeIn; + + g_writeBuffer.buffer = writeData; + g_writeBuffer.bufferLength = sizeIn; + g_writeBuffer.maxBufferLength = sizeIn; + + TEST_PRINTF("write buffer length %" PRIu32 " max length %" PRIu32 "\r\n",g_writeBuffer.bufferLength,g_writeBuffer.maxBufferLength); + fillBuffer(g_writeBuffer.buffer,g_writeBuffer.bufferLength); + + g_readBuffer.buffer = readData; + g_readBuffer.maxBufferLength = sizeIn/5; + g_readBuffer.bufferLength = 0; + + rc =pal_imageInitAPI(readStateMachine); + TEST_PRINTF("pal_imageInitAPI returned %" PRIu32 " \r\n",rc); + TEST_ASSERT_TRUE(rc >= 0); + + /*Wait until the async test finishes*/ + while (!g_isTestDone) + pal_osDelay(5); // Make the OS switch context + +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Update/pal_update_test_runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/PAL_Modules/Update/pal_update_test_runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "unity.h" +#include "unity_fixture.h" + + + +// PAL Update API tests +TEST_GROUP_RUNNER(pal_update) +{ + RUN_TEST_CASE(pal_update, pal_update_writeSmallChunk_5b); + RUN_TEST_CASE(pal_update, pal_update_writeUnaligned_1001b); + RUN_TEST_CASE(pal_update, pal_update_1k); + RUN_TEST_CASE(pal_update, pal_update_2k); + RUN_TEST_CASE(pal_update, pal_update_4k); + RUN_TEST_CASE(pal_update, pal_update_8k); + RUN_TEST_CASE(pal_update, pal_update_16k); + RUN_TEST_CASE(pal_update, pal_update_Read); + RUN_TEST_CASE(pal_update, pal_update_stressTest); + RUN_TEST_CASE(pal_update, pal_update_4k_write_1k_4_times); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/TestRunner/pal_testFreeRTOS.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/TestRunner/pal_testFreeRTOS.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,118 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "pal.h" +#include "PlatIncludes.h" +#include "pal_test_main.h" +#include "fsl_debug_console.h" +#include "FreeRTOS.h" +#include "task.h" +#include "lwip/sys.h" + +#ifndef PAL_TEST_MAIN_THREAD_STACK_SIZE +#define PAL_TEST_MAIN_THREAD_STACK_SIZE (1024*8) +#endif + +bool runProgram(testMain_t mainTestFunc, pal_args_t * args) +{ + //Init Unit testing thread + xTaskCreate((TaskFunction_t)mainTestFunc, "unity_main", (uint16_t)PAL_TEST_THREAD_STACK_SIZE, args, tskIDLE_PRIORITY + 1, NULL); + + //Start OS + vTaskStartScheduler(); + + return true; +} + + +bool initPlatform(void) +{ + //Init Board + boardInit(); + + //Init FileSystem + xTaskCreate((TaskFunction_t)fileSystemMountDrive, "FileSystemInit", 1024*4, NULL, tskIDLE_PRIORITY + 3, NULL); + + //Init DHCP thread + sys_thread_new("networkInit", networkInit, NULL, 1024, tskIDLE_PRIORITY + 2); + + return true; +} + + +#ifndef __CC_ARM /* ARM Compiler */ +/*This is a Hardfault handler to use in debug for more info please read - + * http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html */ +/* The prototype shows it is a naked function - in effect this is just an +assembly function. */ +void HardFault_Handler( void ) __attribute__( ( naked ) ); + +/* The fault handler implementation calls a function called +prvGetRegistersFromStack(). */ +void HardFault_Handler(void) +{ + __asm volatile + ( + " tst lr, #4 \n" + " ite eq \n" + " mrseq r0, msp \n" + " mrsne r0, psp \n" + " ldr r1, [r0, #24] \n" + " ldr r2, handler2_address_const \n" + " bx r2 \n" + " handler2_address_const: .word prvGetRegistersFromStack \n" + ); +} + + +void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress ) +{ +/* These are volatile to try and prevent the compiler/linker optimising them +away as the variables never actually get used. If the debugger won't show the +values of the variables, make them global my moving their declaration outside +of this function. */ +volatile uint32_t r0; +volatile uint32_t r1; +volatile uint32_t r2; +volatile uint32_t r3; +volatile uint32_t r12; +volatile uint32_t lr; /* Link register. */ +volatile uint32_t pc; /* Program counter. */ +volatile uint32_t psr;/* Program status register. */ + + r0 = pulFaultStackAddress[ 0 ]; + r1 = pulFaultStackAddress[ 1 ]; + r2 = pulFaultStackAddress[ 2 ]; + r3 = pulFaultStackAddress[ 3 ]; + + r12 = pulFaultStackAddress[ 4 ]; + lr = pulFaultStackAddress[ 5 ]; + pc = pulFaultStackAddress[ 6 ]; + psr = pulFaultStackAddress[ 7 ]; + + /* When the following line is hit, the variables contain the register values. */ + for( ;; ); +} + +#endif +// This is used by unity for output. The make file must pass a definition of the following form +// -DUNITY_OUTPUT_CHAR=unity_output_char +void unity_output_char(int c) +{ + PUTCHAR(c); +} + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/TestRunner/pal_testLinux.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/TestRunner/pal_testLinux.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,35 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "PlatIncludes.h" +#include "pal_test_main.h" + + +bool runProgram(testMain_t func, pal_args_t * args) +{ + func(args); + return true; +} + + +bool initPlatform(void) +{ + palStatus_t status = fileSystemCreateRootFolders(); + if (PAL_SUCCESS != status) + { + return false; + } + return true; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/TestRunner/pal_testMbedOS.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/TestRunner/pal_testMbedOS.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#include "PlatIncludes.h" +#include "pal_test_main.h" + +#include "mbed.h" + +#ifndef PAL_TEST_K64F_BAUD_RATE +#define PAL_TEST_K64F_BAUD_RATE 115200 +#endif + +#ifndef PAL_TEST_MAIN_THREAD_STACK_SIZE +#define PAL_TEST_MAIN_THREAD_STACK_SIZE (1024*7) +#endif + + +extern int initSDcardAndFileSystem(void); + +Serial pc(USBTX, USBRX); + +bool runProgram(testMain_t func, pal_args_t * args) +{ + Thread thread(osPriorityNormal, PAL_TEST_MAIN_THREAD_STACK_SIZE); + thread.start(callback(func, args)); + wait(1); // to be on the safe side - sleep for 1sec + bool result = (thread.join() == osOK); + return result; +} + + +bool initPlatform(void) +{ + pc.baud (PAL_TEST_K64F_BAUD_RATE); + int err = initSDcardAndFileSystem(); + if (err < 0) + { + return false; + } + return true; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/TestRunner/test_Runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/TestRunner/test_Runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "pal.h" +#include "PlatIncludes.h" +#include "pal_test_main.h" +#include "unity_fixture.h" + +extern bool dhcp_done; +void TEST_pal_all_GROUPS_RUNNER(void); + +void palTestMain(pal_args_t *args) +{ + const char * myargv[] = {"app","-v"}; + + while (dhcp_done == 0) + { + pal_osDelay(1000); + } + UnityPrint("*****PAL_TEST_START*****"); + UNITY_PRINT_EOL(); + UnityMain(sizeof(myargv)/sizeof(myargv[0]), myargv, TEST_pal_all_GROUPS_RUNNER); + UnityPrint("*****PAL_TEST_END*****"); + UNITY_PRINT_EOL(); +} + + +void TEST_pal_all_GROUPS_RUNNER(void) +{ + PRINT_MEMORY_STATS +#if PAL_TEST_RTOS + TEST_pal_rtos_GROUP_RUNNER(); +#endif + PRINT_MEMORY_STATS +#if PAL_TEST_NETWORK + TEST_pal_socket_GROUP_RUNNER(); +#endif + PRINT_MEMORY_STATS +#if PAL_TEST_CRYPTO + TEST_pal_crypto_GROUP_RUNNER(); +#endif + +#if PAL_TEST_FS + TEST_pal_fileSystem_GROUP_RUNNER(); +#endif + +#if PAL_TEST_UPDATE + TEST_pal_update_GROUP_RUNNER(); +#endif + +#if PAL_TEST_TLS + TEST_pal_tls_GROUP_RUNNER(); +#endif + PRINT_MEMORY_STATS + +#if PAL_TEST_FLASH + TEST_pal_internalFlash_GROUP_RUNNER(); +#endif + +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/pal_test_main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unitest/pal_test_main.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,51 @@ +/* +* Copyright (c) 2016 ARM Limited. All rights reserved. +* SPDX-License-Identifier: Apache-2.0 +* Licensed under the Apache License, Version 2.0 (the License); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an AS IS BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "PlatIncludes.h" +#include "pal_test_main.h" + + +#include "mbed_trace.h" + + +pal_args_t g_args; // defiend as global so it could persist + // during task execution on FreeRTOS + + +#ifdef DEBUG +#define PAL_TESTS_LOG_LEVEL ((uint8_t)((TRACE_MASK_LEVEL & TRACE_ACTIVE_LEVEL_ALL) | (TRACE_MASK_CONFIG & TRACE_CARRIAGE_RETURN))) +#else +#define PAL_TESTS_LOG_LEVEL ((uint8_t)((TRACE_MASK_LEVEL & TRACE_ACTIVE_LEVEL_ERROR) | (TRACE_MASK_CONFIG & TRACE_CARRIAGE_RETURN))) +#endif + + +int main(int argc, char * argv[]) +{ + bool ret = false; + g_args.argc = argc; + g_args.argv = argv; + + mbed_trace_init(); + mbed_trace_config_set(PAL_TESTS_LOG_LEVEL); + + ret = initPlatform(); + if(ret == true) + { + ret = runProgram(&palTestMain, &g_args); + } + mbed_trace_free(); + return (int)ret; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/colour_prompt.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/colour_prompt.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,115 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +if RUBY_PLATFORM =~/(win|w)32$/ + begin + require 'Win32API' + rescue LoadError + puts "ERROR! \"Win32API\" library not found" + puts "\"Win32API\" is required for colour on a windows machine" + puts " try => \"gem install Win32API\" on the command line" + puts + end + # puts + # puts 'Windows Environment Detected...' + # puts 'Win32API Library Found.' + # puts +end + +class ColourCommandLine + def initialize + if RUBY_PLATFORM =~/(win|w)32$/ + get_std_handle = Win32API.new("kernel32", "GetStdHandle", ['L'], 'L') + @set_console_txt_attrb = + Win32API.new("kernel32","SetConsoleTextAttribute",['L','N'], 'I') + @hout = get_std_handle.call(-11) + end + end + + def change_to(new_colour) + if RUBY_PLATFORM =~/(win|w)32$/ + @set_console_txt_attrb.call(@hout,self.win32_colour(new_colour)) + else + "\033[30;#{posix_colour(new_colour)};22m" + end + end + + def win32_colour(colour) + case colour + when :black then 0 + when :dark_blue then 1 + when :dark_green then 2 + when :dark_cyan then 3 + when :dark_red then 4 + when :dark_purple then 5 + when :dark_yellow, :narrative then 6 + when :default_white, :default, :dark_white then 7 + when :silver then 8 + when :blue then 9 + when :green, :success then 10 + when :cyan, :output then 11 + when :red, :failure then 12 + when :purple then 13 + when :yellow then 14 + when :white then 15 + else + 0 + end + end + + def posix_colour(colour) + # ANSI Escape Codes - Foreground colors + # | Code | Color | + # | 39 | Default foreground color | + # | 30 | Black | + # | 31 | Red | + # | 32 | Green | + # | 33 | Yellow | + # | 34 | Blue | + # | 35 | Magenta | + # | 36 | Cyan | + # | 37 | Light gray | + # | 90 | Dark gray | + # | 91 | Light red | + # | 92 | Light green | + # | 93 | Light yellow | + # | 94 | Light blue | + # | 95 | Light magenta | + # | 96 | Light cyan | + # | 97 | White | + + case colour + when :black then 30 + when :red, :failure then 31 + when :green, :success then 32 + when :yellow then 33 + when :blue, :narrative then 34 + when :purple, :magenta then 35 + when :cyan, :output then 36 + when :white, :default_white then 37 + when :default then 39 + else + 39 + end + end + + def out_c(mode, colour, str) + case RUBY_PLATFORM + when /(win|w)32$/ + change_to(colour) + $stdout.puts str if mode == :puts + $stdout.print str if mode == :print + change_to(:default_white) + else + $stdout.puts("#{change_to(colour)}#{str}\033[0m") if mode == :puts + $stdout.print("#{change_to(colour)}#{str}\033[0m") if mode == :print + end + end +end # ColourCommandLine + +def colour_puts(role,str) ColourCommandLine.new.out_c(:puts, role, str) end +def colour_print(role,str) ColourCommandLine.new.out_c(:print, role, str) end +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/colour_reporter.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/colour_reporter.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,39 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require "#{File.expand_path(File.dirname(__FILE__))}/colour_prompt" + +$colour_output = true + +def report(message) + if not $colour_output + $stdout.puts(message) + else + message = message.join('\n') if (message.class == Array) + message.each_line do |line| + line.chomp! + colour = case(line) + when /(?:total\s+)?tests:?\s+(\d+)\s+(?:total\s+)?failures:?\s+\d+\s+Ignored:?/i + ($1.to_i == 0) ? :green : :red + when /PASS/ + :green + when /^OK$/ + :green + when /(?:FAIL|ERROR)/ + :red + when /IGNORE/ + :yellow + when /^(?:Creating|Compiling|Linking)/ + :white + else + :silver + end + colour_puts(colour, line) + end + end + $stdout.flush + $stderr.flush +end \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/generate_module.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/generate_module.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,202 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +# This script creates all the files with start code necessary for a new module. +# A simple module only requires a source file, header file, and test file. +# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware). + +require 'rubygems' +require 'fileutils' + +HERE = File.expand_path(File.dirname(__FILE__)) + '/' + +#help text when requested +HELP_TEXT = [ "\nGENERATE MODULE\n-------- ------", + "\nUsage: ruby generate_module [options] module_name", + " -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)", + " -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)", + " -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)", + " -p\"MCH\" sets the output pattern to MCH.", + " dh - driver hardware.", + " dih - driver interrupt hardware.", + " mch - model conductor hardware.", + " mvp - model view presenter.", + " src - just a single source module. (DEFAULT)", + " -d destroy module instead of creating it.", + " -u update subversion too (requires subversion command line)", + " -y\"my.yml\" selects a different yaml config file for module generation", + "" ].join("\n") + +#Built in patterns +PATTERNS = { 'src' => {'' => { :inc => [] } }, + 'dh' => {'Driver' => { :inc => ['%1$sHardware.h'] }, + 'Hardware' => { :inc => [] } + }, + 'dih' => {'Driver' => { :inc => ['%1$sHardware.h', '%1$sInterrupt.h'] }, + 'Interrupt'=> { :inc => ['%1$sHardware.h'] }, + 'Hardware' => { :inc => [] } + }, + 'mch' => {'Model' => { :inc => [] }, + 'Conductor'=> { :inc => ['%1$sModel.h', '%1$sHardware.h'] }, + 'Hardware' => { :inc => [] } + }, + 'mvp' => {'Model' => { :inc => [] }, + 'Presenter'=> { :inc => ['%1$sModel.h', '%1$sView.h'] }, + 'View' => { :inc => [] } + } + } + +#TEMPLATE_TST +TEMPLATE_TST = %q[#include "unity.h" +%2$s#include "%1$s.h" + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +void test_%1$s_NeedToImplement(void) +{ + TEST_IGNORE_MESSAGE("Need to Implement %1$s"); +} +] + +#TEMPLATE_SRC +TEMPLATE_SRC = %q[%2$s#include "%1$s.h" +] + +#TEMPLATE_INC +TEMPLATE_INC = %q[#ifndef _%3$s_H +#define _%3$s_H%2$s + +#endif // _%3$s_H +] + +# Parse the command line parameters. +ARGV.each do |arg| + case(arg) + when /^-d/ then @destroy = true + when /^-u/ then @update_svn = true + when /^-p(\w+)/ then @pattern = $1 + when /^-s(.+)/ then @path_src = $1 + when /^-i(.+)/ then @path_inc = $1 + when /^-t(.+)/ then @path_tst = $1 + when /^-y(.+)/ then @yaml_config = $1 + when /^(\w+)/ + raise "ERROR: You can't have more than one Module name specified!" unless @module_name.nil? + @module_name = arg + when /^-(h|-help)/ + puts HELP_TEXT + exit + else + raise "ERROR: Unknown option specified '#{arg}'" + end +end +raise "ERROR: You must have a Module name specified! (use option -h for help)" if @module_name.nil? + +#load yaml file if one was requested +if @yaml_config + require 'yaml' + cfg = YAML.load_file(HERE + @yaml_config)[:generate_module] + @path_src = cfg[:defaults][:path_src] if @path_src.nil? + @path_inc = cfg[:defaults][:path_inc] if @path_inc.nil? + @path_tst = cfg[:defaults][:path_tst] if @path_tst.nil? + @update_svn = cfg[:defaults][:update_svn] if @update_svn.nil? + @extra_inc = cfg[:includes] + @boilerplates = cfg[:boilerplates] +else + @boilerplates = {} +end + +# Create default file paths if none were provided +@path_src = HERE + "../src/" if @path_src.nil? +@path_inc = @path_src if @path_inc.nil? +@path_tst = HERE + "../test/" if @path_tst.nil? +@path_src += '/' unless (@path_src[-1] == 47) +@path_inc += '/' unless (@path_inc[-1] == 47) +@path_tst += '/' unless (@path_tst[-1] == 47) +@pattern = 'src' if @pattern.nil? +@includes = { :src => [], :inc => [], :tst => [] } +@includes.merge!(@extra_inc) unless @extra_inc.nil? + +#create triad definition +TRIAD = [ { :ext => '.c', :path => @path_src, :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @boilerplates[:src] }, + { :ext => '.h', :path => @path_inc, :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @boilerplates[:inc] }, + { :ext => '.c', :path => @path_tst+'Test', :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @boilerplates[:tst] }, + ] + +#prepare the pattern for use +@patterns = PATTERNS[@pattern.downcase] +raise "ERROR: The design pattern specified isn't one that I recognize!" if @patterns.nil? + +# Assemble the path/names of the files we need to work with. +files = [] +TRIAD.each do |triad| + @patterns.each_pair do |pattern_file, pattern_traits| + files << { + :path => "#{triad[:path]}#{@module_name}#{pattern_file}#{triad[:ext]}", + :name => "#{@module_name}#{pattern_file}", + :template => triad[:template], + :boilerplate => triad[:boilerplate], + :includes => case(triad[:inc]) + when :src then @includes[:src] | pattern_traits[:inc].map{|f| f % [@module_name]} + when :inc then @includes[:inc] + when :tst then @includes[:tst] | pattern_traits[:inc].map{|f| "Mock#{f}"% [@module_name]} + end + } + end +end + +# destroy files if that was what was requested +if @destroy + files.each do |filespec| + file = filespec[:path] + if File.exist?(file) + if @update_svn + `svn delete \"#{file}\" --force` + puts "File #{file} deleted and removed from source control" + else + FileUtils.remove(file) + puts "File #{file} deleted" + end + else + puts "File #{file} does not exist so cannot be removed." + end + end + puts "Destroy Complete" + exit +end + +#Abort if any module already exists +files.each do |file| + raise "ERROR: File #{file[:name]} already exists. Exiting." if File.exist?(file[:path]) +end + +# Create Source Modules +files.each_with_index do |file, i| + File.open(file[:path], 'w') do |f| + f.write(file[:boilerplate] % [file[:name]]) unless file[:boilerplate].nil? + f.write(file[:template] % [ file[:name], + file[:includes].map{|f| "#include \"#{f}\"\n"}.join, + file[:name].upcase ] + ) + end + if (@update_svn) + `svn add \"#{file[:path]}\"` + if $?.exitstatus == 0 + puts "File #{file[:path]} created and added to source control" + else + puts "File #{file[:path]} created but FAILED adding to source control!" + end + else + puts "File #{file[:path]} created" + end +end + +puts 'Generate Complete'
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/generate_test_runner.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/generate_test_runner.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,391 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +$QUICK_RUBY_VERSION = RUBY_VERSION.split('.').inject(0){|vv,v| vv * 100 + v.to_i } +File.expand_path(File.join(File.dirname(__FILE__),'colour_prompt')) + +class UnityTestRunnerGenerator + + def initialize(options = nil) + @options = UnityTestRunnerGenerator.default_options + case(options) + when NilClass then @options + when String then @options.merge!(UnityTestRunnerGenerator.grab_config(options)) + when Hash then @options.merge!(options) + else raise "If you specify arguments, it should be a filename or a hash of options" + end + require "#{File.expand_path(File.dirname(__FILE__))}/type_sanitizer" + end + + def self.default_options + { + :includes => [], + :plugins => [], + :framework => :unity, + :test_prefix => "test|spec|should", + :setup_name => "setUp", + :teardown_name => "tearDown", + :main_name => "main", + } + end + + def self.grab_config(config_file) + options = self.default_options + unless (config_file.nil? or config_file.empty?) + require 'yaml' + yaml_guts = YAML.load_file(config_file) + options.merge!(yaml_guts[:unity] || yaml_guts[:cmock]) + raise "No :unity or :cmock section found in #{config_file}" unless options + end + return(options) + end + + def run(input_file, output_file, options=nil) + tests = [] + testfile_includes = [] + used_mocks = [] + + @options.merge!(options) unless options.nil? + module_name = File.basename(input_file) + + #pull required data from source file + source = File.read(input_file) + source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil) if ($QUICK_RUBY_VERSION > 10900) + tests = find_tests(source) + headers = find_includes(source) + testfile_includes = (headers[:local] + headers[:system]) + used_mocks = find_mocks(testfile_includes) + testfile_includes = (testfile_includes - used_mocks) + testfile_includes.delete_if{|inc| inc =~ /(unity|cmock)/} + + #build runner file + generate(input_file, output_file, tests, used_mocks, testfile_includes) + + #determine which files were used to return them + all_files_used = [input_file, output_file] + all_files_used += testfile_includes.map {|filename| filename + '.c'} unless testfile_includes.empty? + all_files_used += @options[:includes] unless @options[:includes].empty? + return all_files_used.uniq + end + + def generate(input_file, output_file, tests, used_mocks, testfile_includes) + File.open(output_file, 'w') do |output| + create_header(output, used_mocks, testfile_includes) + create_externs(output, tests, used_mocks) + create_mock_management(output, used_mocks) + create_suite_setup_and_teardown(output) + create_reset(output, used_mocks) + create_main(output, input_file, tests, used_mocks) + end + + if (@options[:header_file] && !@options[:header_file].empty?) + File.open(@options[:header_file], 'w') do |output| + create_h_file(output, @options[:header_file], tests, testfile_includes, used_mocks) + end + end + end + + def find_tests(source) + tests_and_line_numbers = [] + + source_scrubbed = source.clone + source_scrubbed = source_scrubbed.gsub(/"[^"]*"/, '') # remove things in strings + source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '') # remove line comments + source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments + lines = source_scrubbed.split(/(^\s*\#.*$) # Treat preprocessor directives as a logical line + | (;|\{|\}) /x) # Match ;, {, and } as end of lines + + lines.each_with_index do |line, index| + #find tests + if line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/ + arguments = $1 + name = $2 + call = $3 + params = $4 + args = nil + if (@options[:use_param_tests] and !arguments.empty?) + args = [] + arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) {|a| args << a[0]} + end + tests_and_line_numbers << { :test => name, :args => args, :call => call, :params => params, :line_number => 0 } + end + end + tests_and_line_numbers.uniq! {|v| v[:test] } + + #determine line numbers and create tests to run + source_lines = source.split("\n") + source_index = 0; + tests_and_line_numbers.size.times do |i| + source_lines[source_index..-1].each_with_index do |line, index| + if (line =~ /#{tests_and_line_numbers[i][:test]}/) + source_index += index + tests_and_line_numbers[i][:line_number] = source_index + 1 + break + end + end + end + + return tests_and_line_numbers + end + + def find_includes(source) + + #remove comments (block and line, in three steps to ensure correct precedence) + source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks + source.gsub!(/\/\*.*?\*\//m, '') # remove block comments + source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain) + + #parse out includes + includes = { + :local => source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten, + :system => source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" } + } + return includes + end + + def find_mocks(includes) + mock_headers = [] + includes.each do |include_path| + include_file = File.basename(include_path) + mock_headers << include_path if (include_file =~ /^mock/i) + end + return mock_headers + end + + def create_header(output, mocks, testfile_includes=[]) + output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') + create_runtest(output, mocks) + output.puts("\n/*=======Automagically Detected Files To Include=====*/") + output.puts("#include \"#{@options[:framework].to_s}.h\"") + output.puts('#include "cmock.h"') unless (mocks.empty?) + output.puts('#include <setjmp.h>') + output.puts('#include <stdio.h>') + output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception) + if (@options[:header_file] && !@options[:header_file].empty?) + output.puts("#include \"#{File.basename(@options[:header_file])}\"") + else + @options[:includes].flatten.uniq.compact.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}") + end + testfile_includes.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}") + end + end + mocks.each do |mock| + output.puts("#include \"#{mock.gsub('.h','')}.h\"") + end + if @options[:enforce_strict_ordering] + output.puts('') + output.puts('int GlobalExpectCount;') + output.puts('int GlobalVerifyOrder;') + output.puts('char* GlobalOrderError;') + end + end + + def create_externs(output, tests, mocks) + output.puts("\n/*=======External Functions This Runner Calls=====*/") + output.puts("extern void #{@options[:setup_name]}(void);") + output.puts("extern void #{@options[:teardown_name]}(void);") + tests.each do |test| + output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});") + end + output.puts('') + end + + def create_mock_management(output, mock_headers) + unless (mock_headers.empty?) + output.puts("\n/*=======Mock Management=====*/") + output.puts("static void CMock_Init(void)") + output.puts("{") + if @options[:enforce_strict_ordering] + output.puts(" GlobalExpectCount = 0;") + output.puts(" GlobalVerifyOrder = 0;") + output.puts(" GlobalOrderError = NULL;") + end + mocks = mock_headers.map {|mock| File.basename(mock)} + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Init();") + end + output.puts("}\n") + + output.puts("static void CMock_Verify(void)") + output.puts("{") + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Verify();") + end + output.puts("}\n") + + output.puts("static void CMock_Destroy(void)") + output.puts("{") + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Destroy();") + end + output.puts("}\n") + end + end + + def create_suite_setup_and_teardown(output) + unless (@options[:suite_setup].nil?) + output.puts("\n/*=======Suite Setup=====*/") + output.puts("static int suite_setup(void)") + output.puts("{") + output.puts(@options[:suite_setup]) + output.puts("}") + end + unless (@options[:suite_teardown].nil?) + output.puts("\n/*=======Suite Teardown=====*/") + output.puts("static int suite_teardown(int num_failures)") + output.puts("{") + output.puts(@options[:suite_teardown]) + output.puts("}") + end + end + + def create_runtest(output, used_mocks) + cexception = @options[:plugins].include? :cexception + va_args1 = @options[:use_param_tests] ? ', ...' : '' + va_args2 = @options[:use_param_tests] ? '__VA_ARGS__' : '' + output.puts("\n/*=======Test Runner Used To Run Each Test Below=====*/") + output.puts("#define RUN_TEST_NO_ARGS") if @options[:use_param_tests] + output.puts("#define RUN_TEST(TestFunc, TestLineNum#{va_args1}) \\") + output.puts("{ \\") + output.puts(" Unity.CurrentTestName = #TestFunc#{va_args2.empty? ? '' : " \"(\" ##{va_args2} \")\""}; \\") + output.puts(" Unity.CurrentTestLineNumber = TestLineNum; \\") + output.puts(" Unity.NumberOfTests++; \\") + output.puts(" CMock_Init(); \\") unless (used_mocks.empty?) + output.puts(" UNITY_CLR_DETAILS(); \\") unless (used_mocks.empty?) + output.puts(" if (TEST_PROTECT()) \\") + output.puts(" { \\") + output.puts(" CEXCEPTION_T e; \\") if cexception + output.puts(" Try { \\") if cexception + output.puts(" #{@options[:setup_name]}(); \\") + output.puts(" TestFunc(#{va_args2}); \\") + output.puts(" } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, \"Unhandled Exception!\"); } \\") if cexception + output.puts(" } \\") + output.puts(" if (TEST_PROTECT() && !TEST_IS_IGNORED) \\") + output.puts(" { \\") + output.puts(" #{@options[:teardown_name]}(); \\") + output.puts(" CMock_Verify(); \\") unless (used_mocks.empty?) + output.puts(" } \\") + output.puts(" CMock_Destroy(); \\") unless (used_mocks.empty?) + output.puts(" UnityConcludeTest(); \\") + output.puts("}\n") + end + + def create_reset(output, used_mocks) + output.puts("\n/*=======Test Reset Option=====*/") + output.puts("void resetTest(void);") + output.puts("void resetTest(void)") + output.puts("{") + output.puts(" CMock_Verify();") unless (used_mocks.empty?) + output.puts(" CMock_Destroy();") unless (used_mocks.empty?) + output.puts(" #{@options[:teardown_name]}();") + output.puts(" CMock_Init();") unless (used_mocks.empty?) + output.puts(" #{@options[:setup_name]}();") + output.puts("}") + end + + def create_main(output, filename, tests, used_mocks) + output.puts("\n\n/*=======MAIN=====*/") + if (@options[:main_name] != "main") + output.puts("int #{@options[:main_name]}(void);") + end + output.puts("int #{@options[:main_name]}(void)") + output.puts("{") + output.puts(" suite_setup();") unless @options[:suite_setup].nil? + output.puts(" UnityBegin(\"#{filename.gsub(/\\/,'\\\\')}\");") + if (@options[:use_param_tests]) + tests.each do |test| + if ((test[:args].nil?) or (test[:args].empty?)) + output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, RUN_TEST_NO_ARGS);") + else + test[:args].each {|args| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});")} + end + end + else + tests.each { |test| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]});") } + end + output.puts() + output.puts(" CMock_Guts_MemFreeFinal();") unless used_mocks.empty? + output.puts(" return #{@options[:suite_teardown].nil? ? "" : "suite_teardown"}(UnityEnd());") + output.puts("}") + end + + def create_h_file(output, filename, tests, testfile_includes, used_mocks) + filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, "_").upcase + output.puts("/* AUTOGENERATED FILE. DO NOT EDIT. */") + output.puts("#ifndef _#{filename}") + output.puts("#define _#{filename}\n\n") + output.puts("#include \"#{@options[:framework].to_s}.h\"") + output.puts('#include "cmock.h"') unless (used_mocks.empty?) + @options[:includes].flatten.uniq.compact.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}") + end + testfile_includes.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}") + end + output.puts "\n" + tests.each do |test| + if ((test[:params].nil?) or (test[:params].empty?)) + output.puts("void #{test[:test]}(void);") + else + output.puts("void #{test[:test]}(#{test[:params]});") + end + end + output.puts("#endif\n\n") + end +end + +if ($0 == __FILE__) + options = { :includes => [] } + yaml_file = nil + + #parse out all the options first (these will all be removed as we go) + ARGV.reject! do |arg| + case(arg) + when '-cexception' + options[:plugins] = [:cexception]; true + when /\.*\.ya?ml/ + options = UnityTestRunnerGenerator.grab_config(arg); true + when /--(\w+)=\"?(.*)\"?/ + options[$1.to_sym] = $2; true + when /\.*\.h/ + options[:includes] << arg; true + else false + end + end + + #make sure there is at least one parameter left (the input file) + if !ARGV[0] + puts ["\nusage: ruby #{__FILE__} (files) (options) input_test_file (output)", + "\n input_test_file - this is the C file you want to create a runner for", + " output - this is the name of the runner file to generate", + " defaults to (input_test_file)_Runner", + " files:", + " *.yml / *.yaml - loads configuration from here in :unity or :cmock", + " *.h - header files are added as #includes in runner", + " options:", + " -cexception - include cexception support", + " --setup_name=\"\" - redefine setUp func name to something else", + " --teardown_name=\"\" - redefine tearDown func name to something else", + " --main_name=\"\" - redefine main func name to something else", + " --test_prefix=\"\" - redefine test prefix from default test|spec|should", + " --suite_setup=\"\" - code to execute for setup of entire suite", + " --suite_teardown=\"\" - code to execute for teardown of entire suite", + " --use_param_tests=1 - enable parameterized tests (disabled by default)", + " --header_file=\"\" - path/name of test header file to generate too" + ].join("\n") + exit 1 + end + + #create the default test runner name if not specified + ARGV[1] = ARGV[0].gsub(".c","_Runner.c") if (!ARGV[1]) + + UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1]) +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/parseOutput.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/parseOutput.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,191 @@ +#============================================================ +# Author: John Theofanopoulos +# A simple parser. Takes the output files generated during the build process and +# extracts information relating to the tests. +# +# Notes: +# To capture an output file under VS builds use the following: +# devenv [build instructions] > Output.txt & type Output.txt +# +# To capture an output file under GCC/Linux builds use the following: +# make | tee Output.txt +# +# To use this parser use the following command +# ruby parseOutput.rb [options] [file] +# options: -xml : produce a JUnit compatible XML file +# file : file to scan for results +#============================================================ + + +class ParseOutput +# The following flag is set to true when a test is found or false otherwise. + @testFlag + @xmlOut + @arrayList + @totalTests + @classIndex + +# Set the flag to indicate if there will be an XML output file or not + def setXmlOutput() + @xmlOut = true + end + +# if write our output to XML + def writeXmlOuput() + output = File.open("report.xml", "w") + output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + @arrayList.each do |item| + output << item << "\n" + end + output << "</testsuite>\n" + end + +# This function will try and determine when the suite is changed. This is +# is the name that gets added to the classname parameter. + def testSuiteVerify(testSuiteName) + if @testFlag == false + @testFlag = true; + # Split the path name + testName = testSuiteName.split("/") + # Remove the extension + baseName = testName[testName.size - 1].split(".") + @testSuite = "test." + baseName[0] + printf "New Test: %s\n", @testSuite + end + end + + +# Test was flagged as having passed so format the output + def testPassed(array) + lastItem = array.length - 1 + testName = array[lastItem - 1] + testSuiteVerify(array[@className]) + printf "%-40s PASS\n", testName + if @xmlOut == true + @arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\"/>" + end + end + +# Test was flagged as being ingored so format the output + def testIgnored(array) + lastItem = array.length - 1 + testName = array[lastItem - 2] + reason = array[lastItem].chomp + testSuiteVerify(array[@className]) + printf "%-40s IGNORED\n", testName + if @xmlOut == true + @arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">" + @arrayList.push " <skipped type=\"TEST IGNORED\"> " + reason + " </skipped>" + @arrayList.push " </testcase>" + end + end + +# Test was flagged as having failed so format the line + def testFailed(array) + lastItem = array.length - 1 + testName = array[lastItem - 2] + reason = array[lastItem].chomp + " at line: " + array[lastItem - 3] + testSuiteVerify(array[@className]) + printf "%-40s FAILED\n", testName + if @xmlOut == true + @arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">" + @arrayList.push " <failure type=\"ASSERT FAILED\"> " + reason + " </failure>" + @arrayList.push " </testcase>" + end + end + + +# Figure out what OS we are running on. For now we are assuming if it's not Windows it must +# be Unix based. + def detectOS() + myOS = RUBY_PLATFORM.split("-") + if myOS.size == 2 + if myOS[1] == "mingw32" + @className = 1 + else + @className = 0 + end + else + @className = 0 + end + + end + +# Main function used to parse the file that was captured. + def process(name) + @testFlag = false + @arrayList = Array.new + + detectOS() + + puts "Parsing file: " + name + + + testPass = 0 + testFail = 0 + testIgnore = 0 + puts "" + puts "=================== RESULTS =====================" + puts "" + File.open(name).each do |line| + # Typical test lines look like this: + # <path>/<test_file>.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0 + # <path>/<test_file>.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented + # <path>/<test_file>.c:115:test_tc5100_initCanVoidPtrs:PASS + # + # where path is different on Unix vs Windows devices (Windows leads with a drive letter) + lineArray = line.split(":") + lineSize = lineArray.size + # If we were able to split the line then we can look to see if any of our target words + # were found. Case is important. + if lineSize >= 4 + # Determine if this test passed + if line.include? ":PASS" + testPassed(lineArray) + testPass += 1 + elsif line.include? ":FAIL:" + testFailed(lineArray) + testFail += 1 + elsif line.include? ":IGNORE:" + testIgnored(lineArray) + testIgnore += 1 + # If none of the keywords are found there are no more tests for this suite so clear + # the test flag + else + @testFlag = false + end + else + @testFlag = false + end + end + puts "" + puts "=================== SUMMARY =====================" + puts "" + puts "Tests Passed : " + testPass.to_s + puts "Tests Failed : " + testFail.to_s + puts "Tests Ignored : " + testIgnore.to_s + @totalTests = testPass + testFail + testIgnore + if @xmlOut == true + heading = "<testsuite tests=\"" + @totalTests.to_s + "\" failures=\"" + testFail.to_s + "\"" + " skips=\"" + testIgnore.to_s + "\">" + @arrayList.insert(0, heading) + writeXmlOuput() + end + + # return result + end + + end + +# If the command line has no values in, used a default value of Output.txt +parseMyFile = ParseOutput.new + +if ARGV.size >= 1 + ARGV.each do |a| + if a == "-xml" + parseMyFile.setXmlOutput(); + else + parseMyFile.process(a) + break + end + end +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/stylize_as_junit.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/stylize_as_junit.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,264 @@ +#!/usr/bin/ruby +# +# unity_to_junit.rb +# +require 'fileutils' +require 'optparse' +require 'ostruct' +require 'set' + +require 'pp' + +VERSION = 1.0 + +class ArgvParser + + # + # Return a structure describing the options. + # + def self.parse(args) + # The options specified on the command line will be collected in *options*. + # We set default values here. + options = OpenStruct.new + options.results_dir = "." + options.root_path = "." + options.out_file = "results.xml" + + opts = OptionParser.new do |opts| + opts.banner = "Usage: unity_to_junit.rb [options]" + + opts.separator "" + opts.separator "Specific options:" + + opts.on("-r", "--results <dir>", "Look for Unity Results files here.") do |results| + #puts "results #{results}" + options.results_dir = results + end + + opts.on("-p", "--root_path <path>", "Prepend this path to files in results.") do |root_path| + options.root_path = root_path + end + + opts.on("-o", "--output <filename>", "XML file to generate.") do |out_file| + #puts "out_file: #{out_file}" + options.out_file = out_file + end + + opts.separator "" + opts.separator "Common options:" + + # No argument, shows at tail. This will print an options summary. + opts.on_tail("-h", "--help", "Show this message") do + puts opts + exit + end + + # Another typical switch to print the version. + opts.on_tail("--version", "Show version") do + puts "unity_to_junit.rb version #{VERSION}" + exit + end + end + + opts.parse!(args) + options + end # parse() + +end # class OptparseExample + +class UnityToJUnit + include FileUtils::Verbose + attr_reader :report, :total_tests, :failures, :ignored + + def initialize + @report = '' + @unit_name = '' + end + + def run + # Clean up result file names + results = @targets.map {|target| target.gsub(/\\/,"/")} + #puts "Output File: #{@out_file}" + f = File.new(@out_file, "w") + write_xml_header(f) + write_suites_header( f ) + results.each do |result_file| + lines = File.readlines(result_file).map { |line| line.chomp } + if lines.length == 0 + raise "Empty test result file: #{result_file}" + else + result_output = get_details(result_file, lines) + tests,failures,ignored = parse_test_summary(lines) + result_output[:counts][:total] = tests + result_output[:counts][:failed] = failures + result_output[:counts][:ignored] = ignored + result_output[:counts][:passed] = (result_output[:counts][:total] - result_output[:counts][:failed] - result_output[:counts][:ignored]) + end + #use line[0] from the test output to get the test_file path and name + test_file_str = lines[0].gsub("\\","/") + test_file_str = test_file_str.split(":") + test_file = if (test_file_str.length < 2) + result_file + else + test_file_str[0] + ':' + test_file_str[1] + end + result_output[:source][:path] = File.dirname(test_file) + result_output[:source][:file] = File.basename(test_file) + + # save result_output + @unit_name = File.basename(test_file, ".*") + + write_suite_header( result_output[:counts], f) + write_failures( result_output, f ) + write_tests( result_output, f ) + write_ignored( result_output, f ) + write_suite_footer( f ) + end + write_suites_footer( f ) + f.close + end + + def set_targets(target_array) + @targets = target_array + end + + def set_root_path(path) + @root = path + end + def set_out_file(filename) + @out_file = filename + end + def usage(err_msg=nil) + puts "\nERROR: " + puts err_msg if err_msg + puts "Usage: unity_to_junit.rb [options]" + puts "" + puts "Specific options:" + puts " -r, --results <dir> Look for Unity Results files here." + puts " -p, --root_path <path> Prepend this path to files in results." + puts " -o, --output <filename> XML file to generate." + puts "" + puts "Common options:" + puts " -h, --help Show this message" + puts " --version Show version" + + exit 1 + end + + protected + def get_details(result_file, lines) + results = get_results_structure + lines.each do |line| + line = line.gsub("\\","/") + src_file,src_line,test_name,status,msg = line.split(/:/) + line_out = ((@root and (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\") + case(status) + when 'IGNORE' then results[:ignores] << {:test => test_name, :line => src_line, :message => msg} + when 'FAIL' then results[:failures] << {:test => test_name, :line => src_line, :message => msg} + when 'PASS' then results[:successes] << {:test => test_name, :line => src_line, :message => msg} + end + end + return results + end + + def parse_test_summary(summary) + if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ } + [$1.to_i,$2.to_i,$3.to_i] + else + raise "Couldn't parse test results: #{summary}" + end + end + def here; File.expand_path(File.dirname(__FILE__)); end + + private + + def get_results_structure + return { + :source => {:path => '', :file => ''}, + :successes => [], + :failures => [], + :ignores => [], + :counts => {:total => 0, :passed => 0, :failed => 0, :ignored => 0}, + :stdout => [], + } + end + + def write_xml_header( stream ) + stream.puts "<?xml version='1.0' encoding='utf-8' ?>" + end + + def write_suites_header( stream ) + stream.puts "<testsuites>" + end + + def write_suite_header( counts, stream ) + stream.puts "\t<testsuite errors=\"0\" skipped=\"#{counts[:ignored]}\" failures=\"#{counts[:failed]}\" tests=\"#{counts[:total]}\" name=\"unity\">" + end + + def write_failures( results, stream ) + result = results[:failures] + result.each do |item| + filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*')) + stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">" + stream.puts "\t\t\t<failure message=\"#{item[:message]}\" type=\"Assertion\"/>" + stream.puts "\t\t\t<system-err>
[File] #{filename}
[Line] #{item[:line]}
</system-err>" + stream.puts "\t\t</testcase>" + end + end + + def write_tests( results, stream ) + result = results[:successes] + result.each do |item| + filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*')) + stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\" />" + end + end + + def write_ignored( results, stream ) + result = results[:ignores] + result.each do |item| + filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*')) + puts "Writing ignored tests for test harness: #{filename}" + stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">" + stream.puts "\t\t\t<skipped message=\"#{item[:message]}\" type=\"Assertion\"/>" + stream.puts "\t\t\t<system-err>
[File] #{filename}
[Line] #{item[:line]}
</system-err>" + stream.puts "\t\t</testcase>" + end + end + + def write_suite_footer( stream ) + stream.puts "\t</testsuite>" + end + + def write_suites_footer( stream ) + stream.puts "</testsuites>" + end +end #UnityToJUnit + +if __FILE__ == $0 + #parse out the command options + options = ArgvParser.parse(ARGV) + + #create an instance to work with + utj = UnityToJUnit.new + begin + #look in the specified or current directory for result files + targets = "#{options.results_dir.gsub(/\\/, '/')}**/*.test*" + + results = Dir[targets] + raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty? + utj.set_targets(results) + + #set the root path + utj.set_root_path(options.root_path) + + #set the output XML file name + #puts "Output File from options: #{options.out_file}" + utj.set_out_file(options.out_file) + + #run the summarizer + puts utj.run + rescue Exception => e + utj.usage e.message + end +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/test_file_filter.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/test_file_filter.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,23 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require'yaml' + +module RakefileHelpers + class TestFileFilter + def initialize(all_files = false) + @all_files = all_files + if not @all_files == true + if File.exist?('test_file_filter.yml') + filters = YAML.load_file( 'test_file_filter.yml' ) + @all_files, @only_files, @exclude_files = + filters[:all_files], filters[:only_files], filters[:exclude_files] + end + end + end + attr_accessor :all_files, :only_files, :exclude_files + end +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/type_sanitizer.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/type_sanitizer.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +module TypeSanitizer + + def self.sanitize_c_identifier(unsanitized) + # convert filename to valid C identifier by replacing invalid chars with '_' + return unsanitized.gsub(/[-\/\\\.\,\s]/, "_") + end + +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/unity_test_summary.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/unity_test_summary.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,135 @@ +#! python3 +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2015 Alexander Mueller / XelaRellum@web.de +# [Released under MIT License. Please refer to license.txt for details] +# Based on the ruby script by Mike Karlesky, Mark VanderVoord, Greg Williams +# ========================================== +import sys +import os +import re +from glob import glob + +class UnityTestSummary: + def __init__(self): + self.report = '' + self.total_tests = 0 + self.failures = 0 + self.ignored = 0 + + def run(self): + # Clean up result file names + results = [] + for target in self.targets: + results.append(target.replace('\\', '/')) + + # Dig through each result file, looking for details on pass/fail: + failure_output = [] + ignore_output = [] + + for result_file in results: + lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n'))) + if len(lines) == 0: + raise Exception("Empty test result file: %s" % result_file) + + details = self.get_details(result_file, lines) + failures = details['failures'] + ignores = details['ignores'] + if len(failures) > 0: failure_output.append('\n'.join(failures)) + if len(ignores) > 0: ignore_output.append('n'.join(ignores)) + tests,failures,ignored = self.parse_test_summary('\n'.join(lines)) + self.total_tests += tests + self.failures += failures + self.ignored += ignored + + if self.ignored > 0: + self.report += "\n" + self.report += "--------------------------\n" + self.report += "UNITY IGNORED TEST SUMMARY\n" + self.report += "--------------------------\n" + self.report += "\n".join(ignore_output) + + if self.failures > 0: + self.report += "\n" + self.report += "--------------------------\n" + self.report += "UNITY FAILED TEST SUMMARY\n" + self.report += "--------------------------\n" + self.report += '\n'.join(failure_output) + + self.report += "\n" + self.report += "--------------------------\n" + self.report += "OVERALL UNITY TEST SUMMARY\n" + self.report += "--------------------------\n" + self.report += "{total_tests} TOTAL TESTS {failures} TOTAL FAILURES {ignored} IGNORED\n".format(total_tests = self.total_tests, failures=self.failures, ignored=self.ignored) + self.report += "\n" + + return self.report + + def set_targets(self, target_array): + self.targets = target_array + + def set_root_path(self, path): + self.root = path + + def usage(self, err_msg=None): + print("\nERROR: ") + if err_msg: + print(err_msg) + print("\nUsage: unity_test_summary.py result_file_directory/ root_path/") + print(" result_file_directory - The location of your results files.") + print(" Defaults to current directory if not specified.") + print(" Should end in / if specified.") + print(" root_path - Helpful for producing more verbose output if using relative paths.") + sys.exit(1) + + def get_details(self, result_file, lines): + results = { 'failures': [], 'ignores': [], 'successes': [] } + for line in lines: + parts = line.split(':') + if len(parts) != 5: + continue + src_file,src_line,test_name,status,msg = parts + if len(self.root) > 0: + line_out = "%s%s" % (self.root, line) + else: + line_out = line + if status == 'IGNORE': + results['ignores'].append(line_out) + elif status == 'FAIL': + results['failures'].append(line_out) + elif status == 'PASS': + results['successes'].append(line_out) + return results + + def parse_test_summary(self, summary): + m = re.search(r"([0-9]+) Tests ([0-9]+) Failures ([0-9]+) Ignored", summary) + if not m: + raise Exception("Couldn't parse test results: %s" % summary) + + return int(m.group(1)), int(m.group(2)), int(m.group(3)) + + +if __name__ == '__main__': + uts = UnityTestSummary() + try: + #look in the specified or current directory for result files + if len(sys.argv) > 1: + targets_dir = sys.argv[1] + else: + targets_dir = './' + targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*'))) + if len(targets) == 0: + raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir) + uts.set_targets(targets) + + #set the root path + if len(sys.argv) > 2: + root_path = sys.argv[2] + else: + root_path = os.path.split(__file__)[0] + uts.set_root_path(root_path) + + #run the summarizer + print(uts.run()) + except Exception as e: + uts.usage(e)
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/unity_test_summary.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/unity_test_summary.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,148 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +#!/usr/bin/ruby +# +# unity_test_summary.rb +# +require 'fileutils' +require 'set' + +class UnityTestSummary + include FileUtils::Verbose + + attr_reader :report, :total_tests, :failures, :ignored + + def initialize(opts = {}) + @report = '' + @total_tests = 0 + @failures = 0 + @ignored = 0 + + + end + + def run + # Clean up result file names + results = @targets.map {|target| target.gsub(/\\/,'/')} + + # Dig through each result file, looking for details on pass/fail: + failure_output = [] + ignore_output = [] + + results.each do |result_file| + lines = File.readlines(result_file).map { |line| line.chomp } + if lines.length == 0 + raise "Empty test result file: #{result_file}" + else + output = get_details(result_file, lines) + failure_output << output[:failures] unless output[:failures].empty? + ignore_output << output[:ignores] unless output[:ignores].empty? + tests,failures,ignored = parse_test_summary(lines) + @total_tests += tests + @failures += failures + @ignored += ignored + end + end + + if @ignored > 0 + @report += "\n" + @report += "--------------------------\n" + @report += "UNITY IGNORED TEST SUMMARY\n" + @report += "--------------------------\n" + @report += ignore_output.flatten.join("\n") + end + + if @failures > 0 + @report += "\n" + @report += "--------------------------\n" + @report += "UNITY FAILED TEST SUMMARY\n" + @report += "--------------------------\n" + @report += failure_output.flatten.join("\n") + end + + @report += "\n" + @report += "--------------------------\n" + @report += "OVERALL UNITY TEST SUMMARY\n" + @report += "--------------------------\n" + @report += "#{@total_tests} TOTAL TESTS #{@failures} TOTAL FAILURES #{@ignored} IGNORED\n" + @report += "\n" + end + + def set_targets(target_array) + @targets = target_array + end + + def set_root_path(path) + @root = path + end + + def usage(err_msg=nil) + puts "\nERROR: " + puts err_msg if err_msg + puts "\nUsage: unity_test_summary.rb result_file_directory/ root_path/" + puts " result_file_directory - The location of your results files." + puts " Defaults to current directory if not specified." + puts " Should end in / if specified." + puts " root_path - Helpful for producing more verbose output if using relative paths." + exit 1 + end + + protected + + def get_details(result_file, lines) + results = { :failures => [], :ignores => [], :successes => [] } + lines.each do |line| + src_file,src_line,test_name,status,msg = line.split(/:/) + line_out = ((@root && (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\") + case(status) + when 'IGNORE' then results[:ignores] << line_out + when 'FAIL' then results[:failures] << line_out + when 'PASS' then results[:successes] << line_out + end + end + return results + end + + def parse_test_summary(summary) + if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ } + [$1.to_i,$2.to_i,$3.to_i] + else + raise "Couldn't parse test results: #{summary}" + end + end + + def here; File.expand_path(File.dirname(__FILE__)); end + +end + +if $0 == __FILE__ + + #parse out the command options + opts, args = ARGV.partition {|v| v =~ /^--\w+/} + opts.map! {|v| v[2..-1].to_sym } + + #create an instance to work with + uts = UnityTestSummary.new(opts) + + begin + #look in the specified or current directory for result files + args[0] ||= './' + targets = "#{ARGV[0].gsub(/\\/, '/')}**/*.test*" + results = Dir[targets] + raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty? + uts.set_targets(results) + + #set the root path + args[1] ||= Dir.pwd + '/' + uts.set_root_path(ARGV[1]) + + #run the summarizer + puts uts.run + rescue Exception => e + uts.usage e.message + end +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/unity_to_junit.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/auto/unity_to_junit.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,146 @@ +import sys +import os +from glob import glob + +from pyparsing import * +from junit_xml import TestSuite, TestCase + + +class UnityTestSummary: + def __init__(self): + self.report = '' + self.total_tests = 0 + self.failures = 0 + self.ignored = 0 + self.targets = 0 + self.root = None + self.test_suites = dict() + + def run(self): + # Clean up result file names + results = [] + for target in self.targets: + results.append(target.replace('\\', '/')) + + # Dig through each result file, looking for details on pass/fail: + for result_file in results: + lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n'))) + if len(lines) == 0: + raise Exception("Empty test result file: %s" % result_file) + + # define an expression for your file reference + entry_one = Combine( + oneOf(list(alphas)) + ':/' + + Word(alphanums + '_-./')) + + entry_two = Word(printables + ' ', excludeChars=':') + entry = entry_one | entry_two + + delimiter = Literal(':').suppress() + tc_result_line = Group(entry.setResultsName('tc_file_name') + delimiter + entry.setResultsName( + 'tc_line_nr') + delimiter + entry.setResultsName('tc_name') + delimiter + entry.setResultsName( + 'tc_status') + Optional( + delimiter + entry.setResultsName('tc_msg'))).setResultsName("tc_line") + + eol = LineEnd().suppress() + sol = LineStart().suppress() + blank_line = sol + eol + + tc_summary_line = Group(Word(nums).setResultsName("num_of_tests") + "Tests" + Word(nums).setResultsName( + "num_of_fail") + "Failures" + Word(nums).setResultsName("num_of_ignore") + "Ignored").setResultsName( + "tc_summary") + tc_end_line = Or(Literal("FAIL"), Literal('Ok')).setResultsName("tc_result") + + # run it and see... + pp1 = tc_result_line | Optional(tc_summary_line | tc_end_line) + pp1.ignore(blank_line | OneOrMore("-")) + + result = list() + for l in lines: + result.append((pp1.parseString(l)).asDict()) + # delete empty results + result = filter(None, result) + + tc_list = list() + for r in result: + if 'tc_line' in r: + tmp_tc_line = r['tc_line'] + + # get only the file name which will be used as the classname + file_name = tmp_tc_line['tc_file_name'].split('\\').pop().split('/').pop().rsplit('.', 1)[0] + tmp_tc = TestCase(name=tmp_tc_line['tc_name'], classname=file_name) + if 'tc_status' in tmp_tc_line: + if str(tmp_tc_line['tc_status']) == 'IGNORE': + if 'tc_msg' in tmp_tc_line: + tmp_tc.add_skipped_info(message=tmp_tc_line['tc_msg'], + output=r'[File]={0}, [Line]={1}'.format( + tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr'])) + else: + tmp_tc.add_skipped_info(message=" ") + elif str(tmp_tc_line['tc_status']) == 'FAIL': + if 'tc_msg' in tmp_tc_line: + tmp_tc.add_failure_info(message=tmp_tc_line['tc_msg'], + output=r'[File]={0}, [Line]={1}'.format( + tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr'])) + else: + tmp_tc.add_failure_info(message=" ") + + tc_list.append((str(result_file), tmp_tc)) + + for k, v in tc_list: + try: + self.test_suites[k].append(v) + except KeyError: + self.test_suites[k] = [v] + ts = [] + for suite_name in self.test_suites: + ts.append(TestSuite(suite_name, self.test_suites[suite_name])) + + with open('result.xml', 'w') as f: + TestSuite.to_file(f, ts, prettyprint='True', encoding='utf-8') + + return self.report + + def set_targets(self, target_array): + self.targets = target_array + + def set_root_path(self, path): + self.root = path + + @staticmethod + def usage(err_msg=None): + print("\nERROR: ") + if err_msg: + print(err_msg) + print("\nUsage: unity_test_summary.py result_file_directory/ root_path/") + print(" result_file_directory - The location of your results files.") + print(" Defaults to current directory if not specified.") + print(" Should end in / if specified.") + print(" root_path - Helpful for producing more verbose output if using relative paths.") + sys.exit(1) + + +if __name__ == '__main__': + uts = UnityTestSummary() + try: + # look in the specified or current directory for result files + if len(sys.argv) > 1: + targets_dir = sys.argv[1] + else: + targets_dir = './' + targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*'))) + if len(targets) == 0: + raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir) + uts.set_targets(targets) + + # set the root path + if len(sys.argv) > 2: + root_path = sys.argv[2] + else: + root_path = os.path.split(__file__)[0] + uts.set_root_path(root_path) + + # run the summarizer + print(uts.run()) + except Exception as e: + UnityTestSummary.usage(e)
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityAssertionsCheatSheetSuitableforPrintingandPossiblyFraming.pdf Binary file simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityAssertionsCheatSheetSuitableforPrintingandPossiblyFraming.pdf has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityAssertionsReference.pdf Binary file simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityAssertionsReference.pdf has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityConfigurationGuide.pdf Binary file simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityConfigurationGuide.pdf has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityGettingStartedGuide.pdf Binary file simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityGettingStartedGuide.pdf has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityHelperScriptsGuide.pdf Binary file simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/UnityHelperScriptsGuide.pdf has changed
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/license.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/docs/license.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) <year> 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/readme.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/readme.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,5 @@ +Example 1 +========= + +Close to the simplest possible example of Unity, using only basic features. +Run make to build & run the example tests. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/src/ProductionCode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/src/ProductionCode.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ + +#include "ProductionCode.h" + +int Counter = 0; +int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; /* some obnoxious array to search that is 1-based indexing instead of 0. */ + +/* This function is supposed to search through NumbersToFind and find a particular number. + * If it finds it, the index is returned. Otherwise 0 is returned which sorta makes sense since + * NumbersToFind is indexed from 1. Unfortunately it's broken + * (and should therefore be caught by our tests) */ +int FindFunction_WhichIsBroken(int NumberToFind) +{ + int i = 0; + while (i <= 8) /* Notice I should have been in braces */ + i++; + if (NumbersToFind[i] == NumberToFind) /* Yikes! I'm getting run after the loop finishes instead of during it! */ + return i; + return 0; +} + +int FunctionWhichReturnsLocalVariable(void) +{ + return Counter; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/src/ProductionCode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/src/ProductionCode.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ + +int FindFunction_WhichIsBroken(int NumberToFind); +int FunctionWhichReturnsLocalVariable(void);
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/src/ProductionCode2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/src/ProductionCode2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ + +#include "ProductionCode2.h" + +char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction) +{ + (void)Poor; + (void)LittleFunction; + /* Since There Are No Tests Yet, This Function Could Be Empty For All We Know. + * Which isn't terribly useful... but at least we put in a TEST_IGNORE so we won't forget */ + return (char*)0; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/src/ProductionCode2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/src/ProductionCode2.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ + +char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction);
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/test/TestProductionCode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/test/TestProductionCode.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,62 @@ + +#include "ProductionCode.h" +#include "unity.h" + +/* sometimes you may want to get at local data in a module. + * for example: If you plan to pass by reference, this could be useful + * however, it should often be avoided */ +extern int Counter; + +void setUp(void) +{ + /* This is run before EACH TEST */ + Counter = 0x5a5a; +} + +void tearDown(void) +{ +} + +void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void) +{ + /* All of these should pass */ + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(1)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1)); +} + +void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void) +{ + /* You should see this line fail in your test summary */ + TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34)); + + /* Notice the rest of these didn't get a chance to run because the line above failed. + * Unit tests abort each test function on the first sign of trouble. + * Then NEXT test function runs as normal. */ + TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888)); +} + +void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void) +{ + /* This should be true because setUp set this up for us before this test */ + TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable()); + + /* This should be true because we can still change our answer */ + Counter = 0x1234; + TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable()); +} + +void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void) +{ + /* This should be true again because setup was rerun before this test (and after we changed it to 0x1234) */ + TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable()); +} + +void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void) +{ + /* Sometimes you get the test wrong. When that happens, you get a failure too... and a quick look should tell + * you what actually happened...which in this case was a failure to setup the initial condition. */ + TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/test/TestProductionCode2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/test/TestProductionCode2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,31 @@ + +#include "ProductionCode2.h" +#include "unity.h" + +/* These should be ignored because they are commented out in various ways: +#include "whatever.h" +#include "somethingelse.h" +*/ + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +void test_IgnoredTest(void) +{ + TEST_IGNORE_MESSAGE("This Test Was Ignored On Purpose"); +} + +void test_AnotherIgnoredTest(void) +{ + TEST_IGNORE_MESSAGE("These Can Be Useful For Leaving Yourself Notes On What You Need To Do Yet"); +} + +void test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented(void) +{ + TEST_IGNORE(); /* Like This */ +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/test/test_runners/TestProductionCode2_Runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/test/test_runners/TestProductionCode2_Runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,53 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "ProductionCode2.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_IgnoredTest(void); +extern void test_AnotherIgnoredTest(void); +extern void test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented(void); + + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("test/TestProductionCode2.c"); + RUN_TEST(test_IgnoredTest, 18); + RUN_TEST(test_AnotherIgnoredTest, 23); + RUN_TEST(test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented, 28); + + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/test/test_runners/TestProductionCode_Runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_1/test/test_runners/TestProductionCode_Runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "ProductionCode.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void); +extern void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void); +extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void); +extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void); +extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void); + + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("test/TestProductionCode.c"); + RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode, 20); + RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken, 30); + RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue, 41); + RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain, 51); + RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed, 57); + + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/readme.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/readme.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,5 @@ +Example 2 +========= + +Same as the first example, but now using Unity's test fixture to group tests +together. Using the test fixture also makes writing test runners much easier. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/src/ProductionCode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/src/ProductionCode.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ + +#include "ProductionCode.h" + +int Counter = 0; +int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; //some obnoxious array to search that is 1-based indexing instead of 0. + +// This function is supposed to search through NumbersToFind and find a particular number. +// If it finds it, the index is returned. Otherwise 0 is returned which sorta makes sense since +// NumbersToFind is indexed from 1. Unfortunately it's broken +// (and should therefore be caught by our tests) +int FindFunction_WhichIsBroken(int NumberToFind) +{ + int i = 0; + while (i <= 8) //Notice I should have been in braces + i++; + if (NumbersToFind[i] == NumberToFind) //Yikes! I'm getting run after the loop finishes instead of during it! + return i; + return 0; +} + +int FunctionWhichReturnsLocalVariable(void) +{ + return Counter; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/src/ProductionCode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/src/ProductionCode.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ + +int FindFunction_WhichIsBroken(int NumberToFind); +int FunctionWhichReturnsLocalVariable(void);
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/src/ProductionCode2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/src/ProductionCode2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ + +#include "ProductionCode2.h" + +char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction) +{ + (void)Poor; + (void)LittleFunction; + //Since There Are No Tests Yet, This Function Could Be Empty For All We Know. + // Which isn't terribly useful... but at least we put in a TEST_IGNORE so we won't forget + return (char*)0; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/src/ProductionCode2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/src/ProductionCode2.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ + +char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction);
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/TestProductionCode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/TestProductionCode.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,64 @@ +#include "ProductionCode.h" +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP(ProductionCode); + +//sometimes you may want to get at local data in a module. +//for example: If you plan to pass by reference, this could be useful +//however, it should often be avoided +extern int Counter; + +TEST_SETUP(ProductionCode) +{ + //This is run before EACH TEST + Counter = 0x5a5a; +} + +TEST_TEAR_DOWN(ProductionCode) +{ +} + +TEST(ProductionCode, FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode) +{ + //All of these should pass + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(1)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1)); +} + +TEST(ProductionCode, FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken) +{ + // You should see this line fail in your test summary + TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34)); + + // Notice the rest of these didn't get a chance to run because the line above failed. + // Unit tests abort each test function on the first sign of trouble. + // Then NEXT test function runs as normal. + TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888)); +} + +TEST(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue) +{ + //This should be true because setUp set this up for us before this test + TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable()); + + //This should be true because we can still change our answer + Counter = 0x1234; + TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable()); +} + +TEST(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain) +{ + //This should be true again because setup was rerun before this test (and after we changed it to 0x1234) + TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable()); +} + +TEST(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed) +{ + //Sometimes you get the test wrong. When that happens, you get a failure too... and a quick look should tell + // you what actually happened...which in this case was a failure to setup the initial condition. + TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/TestProductionCode2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/TestProductionCode2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +#include "ProductionCode2.h" +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP(ProductionCode2); + +/* These should be ignored because they are commented out in various ways: +#include "whatever.h" +*/ +//#include "somethingelse.h" + +TEST_SETUP(ProductionCode2) +{ +} + +TEST_TEAR_DOWN(ProductionCode2) +{ +} + +TEST(ProductionCode2, IgnoredTest) +{ + TEST_IGNORE_MESSAGE("This Test Was Ignored On Purpose"); +} + +TEST(ProductionCode2, AnotherIgnoredTest) +{ + TEST_IGNORE_MESSAGE("These Can Be Useful For Leaving Yourself Notes On What You Need To Do Yet"); +} + +TEST(ProductionCode2, ThisFunctionHasNotBeenTested_NeedsToBeImplemented) +{ + TEST_IGNORE(); //Like This +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/test_runners/TestProductionCode2_Runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/test_runners/TestProductionCode2_Runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,9 @@ +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP_RUNNER(ProductionCode2) +{ + RUN_TEST_CASE(ProductionCode2, IgnoredTest); + RUN_TEST_CASE(ProductionCode2, AnotherIgnoredTest); + RUN_TEST_CASE(ProductionCode2, ThisFunctionHasNotBeenTested_NeedsToBeImplemented); +} \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/test_runners/TestProductionCode_Runner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/test_runners/TestProductionCode_Runner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ +#include "unity.h" +#include "unity_fixture.h" + +TEST_GROUP_RUNNER(ProductionCode) +{ + RUN_TEST_CASE(ProductionCode, FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode); + RUN_TEST_CASE(ProductionCode, FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken); + RUN_TEST_CASE(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue); + RUN_TEST_CASE(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain); + RUN_TEST_CASE(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed); +} \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/test_runners/all_tests.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_2/test/test_runners/all_tests.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,12 @@ +#include "unity_fixture.h" + +static void RunAllTests(void) +{ + RUN_TEST_GROUP(ProductionCode); + RUN_TEST_GROUP(ProductionCode2); +} + +int main(int argc, const char * argv[]) +{ + return UnityMain(argc, argv, RunAllTests); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/helper/UnityHelper.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/helper/UnityHelper.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,10 @@ +#include "unity.h" +#include "UnityHelper.h" +#include <stdio.h> +#include <string.h> + +void AssertEqualExampleStruct(const EXAMPLE_STRUCT_T expected, const EXAMPLE_STRUCT_T actual, const unsigned short line) +{ + UNITY_TEST_ASSERT_EQUAL_INT(expected.x, actual.x, line, "Example Struct Failed For Field x"); + UNITY_TEST_ASSERT_EQUAL_INT(expected.y, actual.y, line, "Example Struct Failed For Field y"); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/helper/UnityHelper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/helper/UnityHelper.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,12 @@ +#ifndef _TESTHELPER_H +#define _TESTHELPER_H + +#include "Types.h" + +void AssertEqualExampleStruct(const EXAMPLE_STRUCT_T expected, const EXAMPLE_STRUCT_T actual, const unsigned short line); + +#define UNITY_TEST_ASSERT_EQUAL_EXAMPLE_STRUCT_T(expected, actual, line, message) AssertEqualExampleStruct(expected, actual, line); + +#define TEST_ASSERT_EQUAL_EXAMPLE_STRUCT_T(expected, actual) UNITY_TEST_ASSERT_EQUAL_EXAMPLE_STRUCT_T(expected, actual, __LINE__, NULL); + +#endif // _TESTHELPER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/rakefile.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/rakefile.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,43 @@ +HERE = File.expand_path(File.dirname(__FILE__)) + '/' +UNITY_ROOT = File.expand_path(File.dirname(__FILE__)) + '/../..' + +require 'rake' +require 'rake/clean' +require HERE+'rakefile_helper' + +TEMP_DIRS = [ + File.join(HERE, 'build') +] + +TEMP_DIRS.each do |dir| + directory(dir) + CLOBBER.include(dir) +end + +task :prepare_for_tests => TEMP_DIRS + +include RakefileHelpers + +# Load default configuration, for now +DEFAULT_CONFIG_FILE = 'target_gcc_32.yml' +configure_toolchain(DEFAULT_CONFIG_FILE) + +task :unit => [:prepare_for_tests] do + run_tests get_unit_test_files +end + +desc "Generate test summary" +task :summary do + report_summary +end + +desc "Build and test Unity" +task :all => [:clean, :unit, :summary] +task :default => [:clobber, :all] +task :ci => [:default] +task :cruise => [:default] + +desc "Load configuration" +task :config, :config_file do |t, args| + configure_toolchain(args[:config_file]) +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/rakefile_helper.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/rakefile_helper.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,256 @@ +require 'yaml' +require 'fileutils' +require UNITY_ROOT+'/auto/unity_test_summary' +require UNITY_ROOT+'/auto/generate_test_runner' +require UNITY_ROOT+'/auto/colour_reporter' + +module RakefileHelpers + + C_EXTENSION = '.c' + + def load_configuration(config_file) + $cfg_file = config_file + $cfg = YAML.load(File.read($cfg_file)) + end + + def configure_clean + CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil? + end + + def configure_toolchain(config_file=DEFAULT_CONFIG_FILE) + config_file += '.yml' unless config_file =~ /\.yml$/ + load_configuration(config_file) + configure_clean + end + + def get_unit_test_files + path = $cfg['compiler']['unit_tests_path'] + 'Test*' + C_EXTENSION + path.gsub!(/\\/, '/') + FileList.new(path) + end + + def get_local_include_dirs + include_dirs = $cfg['compiler']['includes']['items'].dup + include_dirs.delete_if {|dir| dir.is_a?(Array)} + return include_dirs + end + + def extract_headers(filename) + includes = [] + lines = File.readlines(filename) + lines.each do |line| + m = line.match(/^\s*#include\s+\"\s*(.+\.[hH])\s*\"/) + if not m.nil? + includes << m[1] + end + end + return includes + end + + def find_source_file(header, paths) + paths.each do |dir| + src_file = dir + header.ext(C_EXTENSION) + if (File.exists?(src_file)) + return src_file + end + end + return nil + end + + def tackit(strings) + if strings.is_a?(Array) + result = "\"#{strings.join}\"" + else + result = strings + end + return result + end + + def squash(prefix, items) + result = '' + items.each { |item| result += " #{prefix}#{tackit(item)}" } + return result + end + + def build_compiler_fields + command = tackit($cfg['compiler']['path']) + if $cfg['compiler']['defines']['items'].nil? + defines = '' + else + defines = squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items']) + end + options = squash('', $cfg['compiler']['options']) + includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items']) + includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + return {:command => command, :defines => defines, :options => options, :includes => includes} + end + + def compile(file, defines=[]) + compiler = build_compiler_fields + cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " + + "#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}" + obj_file = "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}" + execute(cmd_str + obj_file) + return obj_file + end + + def build_linker_fields + command = tackit($cfg['linker']['path']) + if $cfg['linker']['options'].nil? + options = '' + else + options = squash('', $cfg['linker']['options']) + end + if ($cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?) + includes = '' + else + includes = squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items']) + end + includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + return {:command => command, :options => options, :includes => includes} + end + + def link_it(exe_name, obj_list) + linker = build_linker_fields + cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " + + (obj_list.map{|obj|"#{$cfg['linker']['object_files']['path']}#{obj} "}).join + + $cfg['linker']['bin_files']['prefix'] + ' ' + + $cfg['linker']['bin_files']['destination'] + + exe_name + $cfg['linker']['bin_files']['extension'] + execute(cmd_str) + end + + def build_simulator_fields + return nil if $cfg['simulator'].nil? + if $cfg['simulator']['path'].nil? + command = '' + else + command = (tackit($cfg['simulator']['path']) + ' ') + end + if $cfg['simulator']['pre_support'].nil? + pre_support = '' + else + pre_support = squash('', $cfg['simulator']['pre_support']) + end + if $cfg['simulator']['post_support'].nil? + post_support = '' + else + post_support = squash('', $cfg['simulator']['post_support']) + end + return {:command => command, :pre_support => pre_support, :post_support => post_support} + end + + def execute(command_string, verbose=true, raise_on_fail=true) + report command_string + output = `#{command_string}`.chomp + report(output) if (verbose && !output.nil? && (output.length > 0)) + if (($?.exitstatus != 0) and (raise_on_fail)) + raise "Command failed. (Returned #{$?.exitstatus})" + end + return output + end + + def report_summary + summary = UnityTestSummary.new + summary.set_root_path(HERE) + results_glob = "#{$cfg['compiler']['build_path']}*.test*" + results_glob.gsub!(/\\/, '/') + results = Dir[results_glob] + summary.set_targets(results) + summary.run + fail_out "FAIL: There were failures" if (summary.failures > 0) + end + + def run_tests(test_files) + + report 'Running system tests...' + + # Tack on TEST define for compiling unit tests + load_configuration($cfg_file) + test_defines = ['TEST'] + $cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil? + $cfg['compiler']['defines']['items'] << 'TEST' + + include_dirs = get_local_include_dirs + + # Build and execute each unit test + test_files.each do |test| + obj_list = [] + + # Detect dependencies and build required required modules + extract_headers(test).each do |header| + # Compile corresponding source file if it exists + src_file = find_source_file(header, include_dirs) + if !src_file.nil? + obj_list << compile(src_file, test_defines) + end + end + + # Build the test runner (generate if configured to do so) + test_base = File.basename(test, C_EXTENSION) + runner_name = test_base + '_Runner.c' + if $cfg['compiler']['runner_path'].nil? + runner_path = $cfg['compiler']['build_path'] + runner_name + test_gen = UnityTestRunnerGenerator.new($cfg_file) + test_gen.run(test, runner_path) + else + runner_path = $cfg['compiler']['runner_path'] + runner_name + end + + obj_list << compile(runner_path, test_defines) + + # Build the test module + obj_list << compile(test, test_defines) + + # Link the test executable + link_it(test_base, obj_list) + + # Execute unit test and generate results file + simulator = build_simulator_fields + executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension'] + if simulator.nil? + cmd_str = executable + else + cmd_str = "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}" + end + output = execute(cmd_str, true, false) + test_results = $cfg['compiler']['build_path'] + test_base + if output.match(/OK$/m).nil? + test_results += '.testfail' + else + test_results += '.testpass' + end + File.open(test_results, 'w') { |f| f.print output } + end + end + + def build_application(main) + + report "Building application..." + + obj_list = [] + load_configuration($cfg_file) + main_path = $cfg['compiler']['source_path'] + main + C_EXTENSION + + # Detect dependencies and build required required modules + include_dirs = get_local_include_dirs + extract_headers(main_path).each do |header| + src_file = find_source_file(header, include_dirs) + if !src_file.nil? + obj_list << compile(src_file) + end + end + + # Build the main source file + main_base = File.basename(main_path, C_EXTENSION) + obj_list << compile(main_path) + + # Create the executable + link_it(main_base, obj_list) + end + + def fail_out(msg) + puts msg + exit(-1) + end +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/readme.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/readme.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,19 @@ +Example 3 +========= + +This example project gives an example of some passing, ignored, and failing tests. +It's simple and meant for you to look over and get an idea for what all of this stuff does. + +You can build and test using the makefile if you have gcc installed (you may need to tweak +the locations of some tools in the makefile). Otherwise, the rake version will let you +test with gcc or a couple versions of IAR. You can tweak the yaml files to get those versions +running. + +Ruby is required if you're using the rake version (obviously). This version shows off most of +Unity's advanced features (automatically creating test runners, fancy summaries, etc.) + +The makefile version doesn't require anything outside of your normal build tools, but won't do the +extras for you. So that you can test right away, we've written the test runners for you and +put them in the test\no_ruby subdirectory. If you make changes to the tests or source, you might +need to update these (like when you add or remove tests). Do that for a while and you'll learn +why you really want to start using the Ruby tools. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/src/ProductionCode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/src/ProductionCode.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ + +#include "ProductionCode.h" + +int Counter = 0; +int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; //some obnoxious array to search that is 1-based indexing instead of 0. + +// This function is supposed to search through NumbersToFind and find a particular number. +// If it finds it, the index is returned. Otherwise 0 is returned which sorta makes sense since +// NumbersToFind is indexed from 1. Unfortunately it's broken +// (and should therefore be caught by our tests) +int FindFunction_WhichIsBroken(int NumberToFind) +{ + int i = 0; + while (i <= 8) //Notice I should have been in braces + i++; + if (NumbersToFind[i] == NumberToFind) //Yikes! I'm getting run after the loop finishes instead of during it! + return i; + return 0; +} + +int FunctionWhichReturnsLocalVariable(void) +{ + return Counter; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/src/ProductionCode.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/src/ProductionCode.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ + +int FindFunction_WhichIsBroken(int NumberToFind); +int FunctionWhichReturnsLocalVariable(void);
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/src/ProductionCode2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/src/ProductionCode2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,11 @@ + +#include "ProductionCode2.h" + +char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction) +{ + (void)Poor; + (void)LittleFunction; + //Since There Are No Tests Yet, This Function Could Be Empty For All We Know. + // Which isn't terribly useful... but at least we put in a TEST_IGNORE so we won't forget + return (char*)0; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/src/ProductionCode2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/src/ProductionCode2.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ + +char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction);
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/test/TestProductionCode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/test/TestProductionCode.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,62 @@ + +#include "ProductionCode.h" +#include "unity.h" + +//sometimes you may want to get at local data in a module. +//for example: If you plan to pass by reference, this could be useful +//however, it should often be avoided +extern int Counter; + +void setUp(void) +{ + //This is run before EACH TEST + Counter = 0x5a5a; +} + +void tearDown(void) +{ +} + +void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void) +{ + //All of these should pass + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(1)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999)); + TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1)); +} + +void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void) +{ + // You should see this line fail in your test summary + TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34)); + + // Notice the rest of these didn't get a chance to run because the line above failed. + // Unit tests abort each test function on the first sign of trouble. + // Then NEXT test function runs as normal. + TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888)); +} + +void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void) +{ + //This should be true because setUp set this up for us before this test + TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable()); + + //This should be true because we can still change our answer + Counter = 0x1234; + TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable()); +} + +void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void) +{ + //This should be true again because setup was rerun before this test (and after we changed it to 0x1234) + TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable()); +} + +void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void) +{ + //Sometimes you get the test wrong. When that happens, you get a failure too... and a quick look should tell + // you what actually happened...which in this case was a failure to setup the initial condition. + TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/test/TestProductionCode2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/example_3/test/TestProductionCode2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,31 @@ + +#include "ProductionCode2.h" +#include "unity.h" + +/* These should be ignored because they are commented out in various ways: +#include "whatever.h" +*/ +//#include "somethingelse.h" + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +void test_IgnoredTest(void) +{ + TEST_IGNORE_MESSAGE("This Test Was Ignored On Purpose"); +} + +void test_AnotherIgnoredTest(void) +{ + TEST_IGNORE_MESSAGE("These Can Be Useful For Leaving Yourself Notes On What You Need To Do Yet"); +} + +void test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented(void) +{ + TEST_IGNORE(); //Like This +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/unity_config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/examples/unity_config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,257 @@ +/* Unity Configuration + * As of May 11th, 2016 at ThrowTheSwitch/Unity commit 837c529 + * See Also: Unity/docs/UnityConfigurationGuide.pdf + * + * Unity is designed to run on almost anything that is targeted by a C compiler. + * It would be awesome if this could be done with zero configuration. While + * there are some targets that come close to this dream, it is sadly not + * universal. It is likely that you are going to need at least a couple of the + * configuration options described in this document. + * + * All of Unity's configuration options are `#defines`. Most of these are simple + * definitions. A couple are macros with arguments. They live inside the + * unity_internals.h header file. We don't necessarily recommend opening that + * file unless you really need to. That file is proof that a cross-platform + * library is challenging to build. From a more positive perspective, it is also + * proof that a great deal of complexity can be centralized primarily to one + * place in order to provide a more consistent and simple experience elsewhere. + * + * Using These Options + * It doesn't matter if you're using a target-specific compiler and a simulator + * or a native compiler. In either case, you've got a couple choices for + * configuring these options: + * + * 1. Because these options are specified via C defines, you can pass most of + * these options to your compiler through command line compiler flags. Even + * if you're using an embedded target that forces you to use their + * overbearing IDE for all configuration, there will be a place somewhere in + * your project to configure defines for your compiler. + * 2. You can create a custom `unity_config.h` configuration file (present in + * your toolchain's search paths). In this file, you will list definitions + * and macros specific to your target. All you must do is define + * `UNITY_INCLUDE_CONFIG_H` and Unity will rely on `unity_config.h` for any + * further definitions it may need. + */ + +#ifndef UNITY_CONFIG_H +#define UNITY_CONFIG_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ************************* AUTOMATIC INTEGER TYPES *************************** + * C's concept of an integer varies from target to target. The C Standard has + * rules about the `int` matching the register size of the target + * microprocessor. It has rules about the `int` and how its size relates to + * other integer types. An `int` on one target might be 16 bits while on another + * target it might be 64. There are more specific types in compilers compliant + * with C99 or later, but that's certainly not every compiler you are likely to + * encounter. Therefore, Unity has a number of features for helping to adjust + * itself to match your required integer sizes. It starts off by trying to do it + * automatically. + **************************************************************************** */ + +/* The first thing that Unity does to guess your types is check `stdint.h`. This + * file includes defines like `UINT_MAX` that Unity can make use of to learn a + * lot about your system. It's possible you don't want it to do this or it's + * possible that your system doesn't support `stdint.h`. If that's the case, + * you're going to want to define this. That way, Unity will know to skip the + * inclusion of this file and you won't be left with a compiler error. + */ +/* #define UNITY_EXCLUDE_STDINT_H */ + +/* The second attempt to guess your types is to check `limits.h`. Some compilers + * that don't support `stdint.h` could include `limits.h` instead. If you don't + * want Unity to check this file either, define this to make it skip the + * inclusion. + */ +/* #define UNITY_EXCLUDE_LIMITS_H */ + +/* The third and final attempt to guess your types is to use the `sizeof()` + * operator. Even if the first two options don't work, this one covers most + * cases. There _is_ a rare compiler or two out there that doesn't support + * `sizeof()` in the preprocessing stage, though. For these, you have the + * ability to disable this feature as well. + */ +/* #define UNITY_EXCLUDE_SIZEOF */ + + +/* ********************** MANUAL INTEGER TYPE DEFINITION *********************** + * If you've disabled all of the automatic options above, you're going to have + * to do the configuration yourself. There are just a handful of defines that + * you are going to specify if you don't like the defaults. + **************************************************************************** */ + + /* Define this to be the number of bits an `int` takes up on your system. The + * default, if not auto-detected, is 32 bits. + * + * Example: + */ +/* #define UNITY_INT_WIDTH 16 */ + +/* Define this to be the number of bits a `long` takes up on your system. The + * default, if not autodetected, is 32 bits. This is used to figure out what + * kind of 64-bit support your system can handle. Does it need to specify a + * `long` or a `long long` to get a 64-bit value. On 16-bit systems, this option + * is going to be ignored. + * + * Example: + */ +/* #define UNITY_LONG_WIDTH 16 */ + +/* Define this to be the number of bits a pointer takes up on your system. The + * default, if not autodetected, is 32-bits. If you're getting ugly compiler + * warnings about casting from pointers, this is the one to look at. + * + * Example: + */ +/* #define UNITY_POINTER_WIDTH 64 */ + +/* Unity will automatically include 64-bit support if it auto-detects it, or if + * your `int`, `long`, or pointer widths are greater than 32-bits. Define this + * to enable 64-bit support if none of the other options already did it for you. + * There can be a significant size and speed impact to enabling 64-bit support + * on small targets, so don't define it if you don't need it. + */ +/* #define UNITY_INCLUDE_64 */ + + +/* *************************** FLOATING POINT TYPES **************************** + * In the embedded world, it's not uncommon for targets to have no support for + * floating point operations at all or to have support that is limited to only + * single precision. We are able to guess integer sizes on the fly because + * integers are always available in at least one size. Floating point, on the + * other hand, is sometimes not available at all. Trying to include `float.h` on + * these platforms would result in an error. This leaves manual configuration as + * the only option. + **************************************************************************** */ + + /* By default, Unity guesses that you will want single precision floating point + * support, but not double precision. It's easy to change either of these using + * the include and exclude options here. You may include neither, either, or + * both, as suits your needs. + */ +/* #define UNITY_INCLUDE_FLOAT */ +/* #define UNITY_EXCLUDE_FLOAT */ +/* #define UNITY_INCLUDE_DOUBLE */ +/* #define UNITY_EXCLUDE_DOUBLE */ + +/* For features that are enabled, the following floating point options also + * become available. + */ + +/* Unity aims for as small of a footprint as possible and avoids most standard + * library calls (some embedded platforms don't have a standard library!). + * Because of this, its routines for printing integer values are minimalist and + * hand-coded. To keep Unity universal, though, we chose to _not_ develop our + * own floating point print routines. Instead, the display of floating point + * values during a failure are optional. By default, Unity will not print the + * actual results of floating point assertion failure. So a failed assertion + * will produce a message like `"Values Not Within Delta"`. If you would like + * verbose failure messages for floating point assertions, use these options to + * give more explicit failure messages (e.g. `"Expected 4.56 Was 4.68"`). Note + * that this feature requires the use of `sprintf` so might not be desirable in + * all cases. + */ +/* #define UNITY_FLOAT_VERBOSE */ +/* #define UNITY_DOUBLE_VERBOSE */ + +/* If enabled, Unity assumes you want your `FLOAT` asserts to compare standard C + * floats. If your compiler supports a specialty floating point type, you can + * always override this behavior by using this definition. + * + * Example: + */ +/* #define UNITY_FLOAT_TYPE float16_t */ + +/* If enabled, Unity assumes you want your `DOUBLE` asserts to compare standard + * C doubles. If you would like to change this, you can specify something else + * by using this option. For example, defining `UNITY_DOUBLE_TYPE` to `long + * double` could enable gargantuan floating point types on your 64-bit processor + * instead of the standard `double`. + * + * Example: + */ +/* #define UNITY_DOUBLE_TYPE long double */ + +/* If you look up `UNITY_ASSERT_EQUAL_FLOAT` and `UNITY_ASSERT_EQUAL_DOUBLE` as + * documented in the Unity Assertion Guide, you will learn that they are not + * really asserting that two values are equal but rather that two values are + * "close enough" to equal. "Close enough" is controlled by these precision + * configuration options. If you are working with 32-bit floats and/or 64-bit + * doubles (the normal on most processors), you should have no need to change + * these options. They are both set to give you approximately 1 significant bit + * in either direction. The float precision is 0.00001 while the double is + * 10^-12. For further details on how this works, see the appendix of the Unity + * Assertion Guide. + * + * Example: + */ +/* #define UNITY_FLOAT_PRECISION 0.001f */ +/* #define UNITY_DOUBLE_PRECISION 0.001f */ + + +/* *************************** TOOLSET CUSTOMIZATION *************************** + * In addition to the options listed above, there are a number of other options + * which will come in handy to customize Unity's behavior for your specific + * toolchain. It is possible that you may not need to touch any of these but + * certain platforms, particularly those running in simulators, may need to jump + * through extra hoops to operate properly. These macros will help in those + * situations. + **************************************************************************** */ + +/* By default, Unity prints its results to `stdout` as it runs. This works + * perfectly fine in most situations where you are using a native compiler for + * testing. It works on some simulators as well so long as they have `stdout` + * routed back to the command line. There are times, however, where the + * simulator will lack support for dumping results or you will want to route + * results elsewhere for other reasons. In these cases, you should define the + * `UNITY_OUTPUT_CHAR` macro. This macro accepts a single character at a time + * (as an `int`, since this is the parameter type of the standard C `putchar` + * function most commonly used). You may replace this with whatever function + * call you like. + * + * Example: + * Say you are forced to run your test suite on an embedded processor with no + * `stdout` option. You decide to route your test result output to a custom + * serial `RS232_putc()` function you wrote like thus: + */ +/* #define UNITY_OUTPUT_CHAR(a) RS232_putc(a) */ +/* #define UNITY_OUTPUT_FLUSH() RS232_config(115200,1,8,0) */ +/* #define UNITY_OUTPUT_START() RS232_flush() */ +/* #define UNITY_OUTPUT_COMPLETE() RS232_close() */ + +/* For some targets, Unity can make the otherwise required `setUp()` and + * `tearDown()` functions optional. This is a nice convenience for test writers + * since `setUp` and `tearDown` don't often actually _do_ anything. If you're + * using gcc or clang, this option is automatically defined for you. Other + * compilers can also support this behavior, if they support a C feature called + * weak functions. A weak function is a function that is compiled into your + * executable _unless_ a non-weak version of the same function is defined + * elsewhere. If a non-weak version is found, the weak version is ignored as if + * it never existed. If your compiler supports this feature, you can let Unity + * know by defining `UNITY_SUPPORT_WEAK` as the function attributes that would + * need to be applied to identify a function as weak. If your compiler lacks + * support for weak functions, you will always need to define `setUp` and + * `tearDown` functions (though they can be and often will be just empty). The + * most common options for this feature are: + */ +/* #define UNITY_SUPPORT_WEAK weak */ +/* #define UNITY_SUPPORT_WEAK __attribute__((weak)) */ + +/* Some compilers require a custom attribute to be assigned to pointers, like + * `near` or `far`. In these cases, you can give Unity a safe default for these + * by defining this option with the attribute you would like. + * + * Example: + */ +/* #define UNITY_PTR_ATTRIBUTE __attribute__((far)) */ +/* #define UNITY_PTR_ATTRIBUTE near */ + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif /* UNITY_CONFIG_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/eclipse/error_parsers.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/eclipse/error_parsers.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,26 @@ +Eclipse error parsers +===================== + +These are a godsend for extracting & quickly navigating to +warnings & error messages from console output. Unforunately +I don't know how to write an Eclipse plugin so you'll have +to add them manually. + +To add a console parser to Eclipse, go to Window --> Preferences +--> C/C++ --> Build --> Settings. Click on the 'Error Parsers' +tab and then click the 'Add...' button. See the table below for +the parser fields to add. + +Eclipse will only parse the console output during a build, so +running your unit tests must be part of your build process. +Either add this to your make/rakefile, or add it as a post- +build step in your Eclipse project settings. + + +Unity unit test error parsers +----------------------------- +Severity Pattern File Line Description +------------------------------------------------------------------------------- +Error (\.+)(.*?):(\d+):(.*?):FAIL: (.*) $2 $3 $5 +Warning (\.+)(.*?):(\d+):(.*?):IGNORE: (.*) $2 $3 $5 +Warning (\.+)(.*?):(\d+):(.*?):IGNORE\s*$ $2 $3 Ignored test
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/rakefile.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/rakefile.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,48 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +HERE = File.expand_path(File.dirname(__FILE__)) + '/' + +require 'rake' +require 'rake/clean' +require 'rake/testtask' +require HERE + 'rakefile_helper' + +TEMP_DIRS = [ + File.join(HERE, 'build') +] + +TEMP_DIRS.each do |dir| + directory(dir) + CLOBBER.include(dir) +end + +task :prepare_for_tests => TEMP_DIRS + +include RakefileHelpers + +# Load default configuration, for now +DEFAULT_CONFIG_FILE = 'gcc_auto_stdint.yml' +configure_toolchain(DEFAULT_CONFIG_FILE) + +task :unit => [:prepare_for_tests] do + run_tests +end + +desc "Build and test Unity Framework" +task :all => [:clean, :unit] +task :default => [:clobber, :all] +task :ci => [:no_color, :default] +task :cruise => [:no_color, :default] + +desc "Load configuration" +task :config, :config_file do |t, args| + configure_toolchain(args[:config_file]) +end + +task :no_color do + $colour_output = false +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/rakefile_helper.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/rakefile_helper.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,179 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require 'yaml' +require 'fileutils' +require HERE+'../../auto/unity_test_summary' +require HERE+'../../auto/generate_test_runner' +require HERE+'../../auto/colour_reporter' + +module RakefileHelpers + + C_EXTENSION = '.c' + + def load_configuration(config_file) + unless ($configured) + $cfg_file = HERE+"../../test/targets/#{config_file}" unless (config_file =~ /[\\|\/]/) + $cfg = YAML.load(File.read($cfg_file)) + $colour_output = false unless $cfg['colour'] + $configured = true if (config_file != DEFAULT_CONFIG_FILE) + end + end + + def configure_clean + CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil? + end + + def configure_toolchain(config_file=DEFAULT_CONFIG_FILE) + config_file += '.yml' unless config_file =~ /\.yml$/ + config_file = config_file unless config_file =~ /[\\|\/]/ + load_configuration(config_file) + configure_clean + end + + def tackit(strings) + if strings.is_a?(Array) + result = "\"#{strings.join}\"" + else + result = strings + end + return result + end + + def squash(prefix, items) + result = '' + items.each { |item| result += " #{prefix}#{tackit(item)}" } + return result + end + + def build_compiler_fields + command = tackit($cfg['compiler']['path']) + if $cfg['compiler']['defines']['items'].nil? + defines = '' + else + defines = squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar']) + end + options = squash('', $cfg['compiler']['options']) + includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items']) + includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + return {:command => command, :defines => defines, :options => options, :includes => includes} + end + + def compile(file, defines=[]) + compiler = build_compiler_fields + unity_include = $cfg['compiler']['includes']['prefix']+'../../src' + cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{unity_include} #{file} " + + "#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}" + + "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}" + execute(cmd_str) + end + + def build_linker_fields + command = tackit($cfg['linker']['path']) + if $cfg['linker']['options'].nil? + options = '' + else + options = squash('', $cfg['linker']['options']) + end + if ($cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?) + includes = '' + else + includes = squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items']) + end + includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + return {:command => command, :options => options, :includes => includes} + end + + def link_it(exe_name, obj_list) + linker = build_linker_fields + cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " + + (obj_list.map{|obj|"#{$cfg['linker']['object_files']['path']}#{obj} "}).join + + $cfg['linker']['bin_files']['prefix'] + ' ' + + $cfg['linker']['bin_files']['destination'] + + exe_name + $cfg['linker']['bin_files']['extension'] + execute(cmd_str) + end + + def build_simulator_fields + return nil if $cfg['simulator'].nil? + if $cfg['simulator']['path'].nil? + command = '' + else + command = (tackit($cfg['simulator']['path']) + ' ') + end + if $cfg['simulator']['pre_support'].nil? + pre_support = '' + else + pre_support = squash('', $cfg['simulator']['pre_support']) + end + if $cfg['simulator']['post_support'].nil? + post_support = '' + else + post_support = squash('', $cfg['simulator']['post_support']) + end + return {:command => command, :pre_support => pre_support, :post_support => post_support} + end + + def execute(command_string, verbose=true) + report command_string + output = `#{command_string}`.chomp + report(output) if (verbose && !output.nil? && (output.length > 0)) + if ($?.exitstatus != 0) + raise "Command failed. (Returned #{$?.exitstatus})" + end + return output + end + + def report_summary + summary = UnityTestSummary.new + summary.set_root_path(HERE) + results_glob = "#{$cfg['compiler']['build_path']}*.test*" + results_glob.gsub!(/\\/, '/') + results = Dir[results_glob] + summary.set_targets(results) + summary.run + end + + def run_tests + report 'Running Unity system tests...' + + # Tack on TEST define for compiling unit tests + load_configuration($cfg_file) + test_defines = ['TEST'] + $cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil? + + # Get a list of all source files needed + src_files = Dir[HERE+'src/*.c'] + src_files += Dir[HERE+'test/*.c'] + src_files += Dir[HERE+'test/main/*.c'] + src_files << '../../src/unity.c' + + # Build object files + src_files.each { |f| compile(f, test_defines) } + obj_list = src_files.map {|f| File.basename(f.ext($cfg['compiler']['object_files']['extension'])) } + + # Link the test executable + test_base = "framework_test" + link_it(test_base, obj_list) + + # Execute unit test and generate results file + simulator = build_simulator_fields + executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension'] + if simulator.nil? + cmd_str = executable + " -v -r" + else + cmd_str = "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}" + end + output = execute(cmd_str) + test_results = $cfg['compiler']['build_path'] + test_base + if output.match(/OK$/m).nil? + test_results += '.testfail' + else + test_results += '.testpass' + end + File.open(test_results, 'w') { |f| f.print output } + end +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/readme.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/readme.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,9 @@ +Copyright (c) 2010 James Grenning and Contributed to Unity Project + +Unity Project - A Test Framework for C +Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +[Released under MIT License. Please refer to license.txt for details] + +This Framework is an optional add-on to Unity. By including unity_framework.h in place of unity.h, +you may now work with Unity in a manner similar to CppUTest. This framework adds the concepts of +test groups and gives finer control of your tests over the command line. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/src/unity_fixture.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/src/unity_fixture.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,456 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include <string.h> +#include "unity_fixture.h" +#include "unity_internals.h" + +#define UNITY_RESULTS_TAGS_TEST_START "<***UnityTest***>" +#define UNITY_RESULTS_TAGS_TEST_END "</***UnityTest***>" + +#define UNITY_RESULTS_TAGS_RESULT_START "<***UnityResult***>" +#define UNITY_RESULTS_TAGS_RESULT_END "</***UnityResult***>" + +#define UNITY_RESULTS_TAGS_IGNORE_START "<***UnityIgnoredTest***>" +#define UNITY_RESULTS_TAGS_IGNORE_END "</***UnityIgnoredTest***>" + +struct _UnityFixture UnityFixture; + +//If you decide to use the function pointer approach. +//Build with -D UNITY_OUTPUT_CHAR=outputChar and include <stdio.h> +//int (*outputChar)(int) = putchar; + +#if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA) +void setUp(void) { /*does nothing*/ } +void tearDown(void) { /*does nothing*/ } +#endif + +static void announceTestRun(unsigned int runNumber) +{ + UnityPrint("Unity test run "); + UnityPrintNumberUnsigned(runNumber+1); + UnityPrint(" of "); + UnityPrintNumberUnsigned(UnityFixture.RepeatCount); + UNITY_PRINT_EOL(); +} + +int UnityMain(int argc, const char* argv[], void (*runAllTests)(void)) +{ + int result = UnityGetCommandLineOptions(argc, argv); + unsigned int r; + if (result != 0) + return result; + + for (r = 0; r < UnityFixture.RepeatCount; r++) + { + UnityBegin(argv[0]); + announceTestRun(r); + runAllTests(); + UNITY_PRINT_EOL(); + UnityEnd(); + } + + return (int)Unity.TestFailures; +} + +static int selected(const char* filter, const char* name) +{ + if (filter == 0) + return 1; + return strstr(name, filter) ? 1 : 0; +} + +static int testSelected(const char* test) +{ + return selected(UnityFixture.NameFilter, test); +} + +static int groupSelected(const char* group) +{ + return selected(UnityFixture.GroupFilter, group); +} + +void UnityTestRunner(unityfunction* setup, + unityfunction* testBody, + unityfunction* teardown, + const char* printableName, + const char* group, + const char* name, + const char* file, unsigned int line) +{ + if (testSelected(name) && groupSelected(group)) + { + Unity.TestFile = file; + Unity.CurrentTestName = printableName; + Unity.CurrentTestLineNumber = line; + if (!UnityFixture.Verbose) + UNITY_OUTPUT_CHAR('.'); + else + { + /* SA_PATCH: Output results using easy to parse tags. */ + UnityPrint(UNITY_RESULTS_TAGS_TEST_START); + UnityPrint(printableName); + /* SA_PATCH: Output results using easy to parse tags. */ + UnityPrint(UNITY_RESULTS_TAGS_TEST_END); + //UnityPrint(printableName); + } + + Unity.NumberOfTests++; + UnityMalloc_StartTest(); + UnityPointer_Init(); + + if (TEST_PROTECT()) + { + setup(); + testBody(); + } + if (TEST_PROTECT()) + { + teardown(); + } + if (TEST_PROTECT()) + { + UnityPointer_UndoAllSets(); + if (!Unity.CurrentTestFailed) + UnityMalloc_EndTest(); + } + UnityConcludeFixtureTest(); + } +} + +void UnityIgnoreTest(const char* printableName, const char* group, const char* name) +{ + if (testSelected(name) && groupSelected(group)) + { + Unity.NumberOfTests++; + Unity.TestIgnores++; + if (!UnityFixture.Verbose) + UNITY_OUTPUT_CHAR('!'); + else + { + /* SA_PATCH: Output results using easy to parse tags. */ + UnityPrint(UNITY_RESULTS_TAGS_IGNORE_START); + UnityPrint(printableName); + /* SA_PATCH: Output results using easy to parse tags. */ + UnityPrint(UNITY_RESULTS_TAGS_IGNORE_END); + //UnityPrint(printableName); + //UNITY_PRINT_EOL(); + } + } +} + + +//------------------------------------------------- +//Malloc and free stuff +// +#define MALLOC_DONT_FAIL -1 +static int malloc_count; +static int malloc_fail_countdown = MALLOC_DONT_FAIL; + +void UnityMalloc_StartTest(void) +{ + malloc_count = 0; + malloc_fail_countdown = MALLOC_DONT_FAIL; +} + +void UnityMalloc_EndTest(void) +{ + malloc_fail_countdown = MALLOC_DONT_FAIL; + if (malloc_count != 0) + { + UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "This test leaks!"); + } +} + +void UnityMalloc_MakeMallocFailAfterCount(int countdown) +{ + malloc_fail_countdown = countdown; +} + +// These definitions are always included from unity_fixture_malloc_overrides.h +// We undef to use them or avoid conflict with <stdlib.h> per the C standard +#undef malloc +#undef free +#undef calloc +#undef realloc + +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC +static unsigned char unity_heap[UNITY_INTERNAL_HEAP_SIZE_BYTES]; +static size_t heap_index; +#else +#include <stdlib.h> +#endif + +typedef struct GuardBytes +{ + size_t size; + size_t guard_space; +} Guard; + + +static const char end[] = "END"; + +void* unity_malloc(size_t size) +{ + char* mem; + Guard* guard; + size_t total_size = size + sizeof(Guard) + sizeof(end); + + if (malloc_fail_countdown != MALLOC_DONT_FAIL) + { + if (malloc_fail_countdown == 0) + return NULL; + malloc_fail_countdown--; + } + + if (size == 0) return NULL; +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + if (heap_index + total_size > UNITY_INTERNAL_HEAP_SIZE_BYTES) + { + guard = NULL; + } + else + { + guard = (Guard*) &unity_heap[heap_index]; + heap_index += total_size; + } +#else + guard = (Guard*)UNITY_FIXTURE_MALLOC(total_size); +#endif + if (guard == NULL) return NULL; + malloc_count++; + guard->size = size; + guard->guard_space = 0; + mem = (char*)&(guard[1]); + memcpy(&mem[size], end, sizeof(end)); + + return (void*)mem; +} + +static int isOverrun(void* mem) +{ + Guard* guard = (Guard*)mem; + char* memAsChar = (char*)mem; + guard--; + + return guard->guard_space != 0 || strcmp(&memAsChar[guard->size], end) != 0; +} + +static void release_memory(void* mem) +{ + Guard* guard = (Guard*)mem; + guard--; + + malloc_count--; +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + if (mem == unity_heap + heap_index - guard->size - sizeof(end)) + { + heap_index -= (guard->size + sizeof(Guard) + sizeof(end)); + } +#else + UNITY_FIXTURE_FREE(guard); +#endif +} + +void unity_free(void* mem) +{ + int overrun; + + if (mem == NULL) + { + return; + } + + overrun = isOverrun(mem); + release_memory(mem); + if (overrun) + { + UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during free()"); + } +} + +void* unity_calloc(size_t num, size_t size) +{ + void* mem = unity_malloc(num * size); + if (mem == NULL) return NULL; + memset(mem, 0, num * size); + return mem; +} + +void* unity_realloc(void* oldMem, size_t size) +{ + Guard* guard = (Guard*)oldMem; + void* newMem; + + if (oldMem == NULL) return unity_malloc(size); + + guard--; + if (isOverrun(oldMem)) + { + release_memory(oldMem); + UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during realloc()"); + } + + if (size == 0) + { + release_memory(oldMem); + return NULL; + } + + if (guard->size >= size) return oldMem; + +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC // Optimization if memory is expandable + if (oldMem == unity_heap + heap_index - guard->size - sizeof(end) && + heap_index + size - guard->size <= UNITY_INTERNAL_HEAP_SIZE_BYTES) + { + release_memory(oldMem); // Not thread-safe, like unity_heap generally + return unity_malloc(size); // No memcpy since data is in place + } +#endif + newMem = unity_malloc(size); + if (newMem == NULL) return NULL; // Do not release old memory + memcpy(newMem, oldMem, guard->size); + release_memory(oldMem); + return newMem; +} + + +//-------------------------------------------------------- +//Automatic pointer restoration functions +struct PointerPair +{ + void** pointer; + void* old_value; +}; + +enum { MAX_POINTERS = 50 }; +static struct PointerPair pointer_store[MAX_POINTERS]; +static int pointer_index = 0; + +void UnityPointer_Init(void) +{ + pointer_index = 0; +} + +void UnityPointer_Set(void** pointer, void* newValue, UNITY_LINE_TYPE line) +{ + if (pointer_index >= MAX_POINTERS) + { + UNITY_TEST_FAIL(line, "Too many pointers set"); + } + else + { + pointer_store[pointer_index].pointer = pointer; + pointer_store[pointer_index].old_value = *pointer; + *pointer = newValue; + pointer_index++; + } +} + +void UnityPointer_UndoAllSets(void) +{ + while (pointer_index > 0) + { + pointer_index--; + *(pointer_store[pointer_index].pointer) = + pointer_store[pointer_index].old_value; + } +} + +int UnityGetCommandLineOptions(int argc, const char* argv[]) +{ + int i; + UnityFixture.Verbose = 0; + UnityFixture.GroupFilter = 0; + UnityFixture.NameFilter = 0; + UnityFixture.RepeatCount = 1; + + if (argc == 1) + return 0; + + for (i = 1; i < argc; ) + { + if (strcmp(argv[i], "-v") == 0) + { + UnityFixture.Verbose = 1; + i++; + } + else if (strcmp(argv[i], "-g") == 0) + { + i++; + if (i >= argc) + return 1; + UnityFixture.GroupFilter = argv[i]; + i++; + } + else if (strcmp(argv[i], "-n") == 0) + { + i++; + if (i >= argc) + return 1; + UnityFixture.NameFilter = argv[i]; + i++; + } + else if (strcmp(argv[i], "-r") == 0) + { + UnityFixture.RepeatCount = 2; + i++; + if (i < argc) + { + if (*(argv[i]) >= '0' && *(argv[i]) <= '9') + { + unsigned int digit = 0; + UnityFixture.RepeatCount = 0; + while (argv[i][digit] >= '0' && argv[i][digit] <= '9') + { + UnityFixture.RepeatCount *= 10; + UnityFixture.RepeatCount += (unsigned int)argv[i][digit++] - '0'; + } + i++; + } + } + } else { + // ignore unknown parameter + i++; + } + } + return 0; +} + +void UnityConcludeFixtureTest(void) +{ + if (Unity.CurrentTestIgnored) + { + Unity.TestIgnores++; + UNITY_PRINT_EOL(); + } + else if (!Unity.CurrentTestFailed) + { + if (UnityFixture.Verbose) + { + UnityPrint(" "); + /* SA_PATCH: Output results using easy to parse tags. */ + UnityPrint(UNITY_RESULTS_TAGS_RESULT_START); + UnityPrint("PASS"); + /* SA_PATCH: Output results using easy to parse tags. */ + UnityPrint(UNITY_RESULTS_TAGS_RESULT_END); + UNITY_OUTPUT_CHAR('\n'); + } +// { +// UnityPrint(" PASS"); +// UNITY_PRINT_EOL(); +// } + } + else // Unity.CurrentTestFailed + { + Unity.TestFailures++; + UNITY_PRINT_EOL(); + } + + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/src/unity_fixture.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/src/unity_fixture.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,78 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FIXTURE_H_ +#define UNITY_FIXTURE_H_ + +#include "unity.h" +#include "unity_internals.h" +#include "unity_fixture_malloc_overrides.h" +#include "unity_fixture_internals.h" + +int UnityMain(int argc, const char* argv[], void (*runAllTests)(void)); + + +#define TEST_GROUP(group)\ + static const char* TEST_GROUP_##group = #group + +#define TEST_SETUP(group) void TEST_##group##_SETUP(void);\ + void TEST_##group##_SETUP(void) + +#define TEST_TEAR_DOWN(group) void TEST_##group##_TEAR_DOWN(void);\ + void TEST_##group##_TEAR_DOWN(void) + + +#define TEST(group, name) \ + void TEST_##group##_##name##_(void);\ + void TEST_##group##_##name##_run(void);\ + void TEST_##group##_##name##_run(void)\ + {\ + UnityTestRunner(TEST_##group##_SETUP,\ + TEST_##group##_##name##_,\ + TEST_##group##_TEAR_DOWN,\ + "TEST(" #group ", " #name ")",\ + TEST_GROUP_##group, #name,\ + __FILE__, __LINE__);\ + }\ + void TEST_##group##_##name##_(void) + +#define IGNORE_TEST(group, name) \ + void TEST_##group##_##name##_(void);\ + void TEST_##group##_##name##_run(void);\ + void TEST_##group##_##name##_run(void)\ + {\ + UnityIgnoreTest("IGNORE_TEST(" #group ", " #name ")", TEST_GROUP_##group, #name);\ + }\ + void TEST_##group##_##name##_(void) + +#define RUN_TEST_CASE(group, name) \ + { void TEST_##group##_##name##_run(void);\ + TEST_##group##_##name##_run(); } + +//This goes at the bottom of each test file or in a separate c file +#define TEST_GROUP_RUNNER(group)\ + void TEST_##group##_GROUP_RUNNER(void);\ + void TEST_##group##_GROUP_RUNNER(void) + +//Call this from main +#define RUN_TEST_GROUP(group)\ + { void TEST_##group##_GROUP_RUNNER(void);\ + TEST_##group##_GROUP_RUNNER(); } + +//CppUTest Compatibility Macros +#define UT_PTR_SET(ptr, newPointerValue) UnityPointer_Set((void**)&(ptr), (void*)(newPointerValue), __LINE__) +#define TEST_ASSERT_POINTERS_EQUAL(expected, actual) TEST_ASSERT_EQUAL_PTR((expected), (actual)) +#define TEST_ASSERT_BYTES_EQUAL(expected, actual) TEST_ASSERT_EQUAL_HEX8(0xff & (expected), 0xff & (actual)) +#define FAIL(message) TEST_FAIL_MESSAGE((message)) +#define CHECK(condition) TEST_ASSERT_TRUE((condition)) +#define LONGS_EQUAL(expected, actual) TEST_ASSERT_EQUAL_INT((expected), (actual)) +#define STRCMP_EQUAL(expected, actual) TEST_ASSERT_EQUAL_STRING((expected), (actual)) +#define DOUBLES_EQUAL(expected, actual, delta) TEST_ASSERT_FLOAT_WITHIN(((expected), (actual), (delta)) + +void UnityMalloc_MakeMallocFailAfterCount(int count); + +#endif /* UNITY_FIXTURE_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/src/unity_fixture_internals.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/src/unity_fixture_internals.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,39 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FIXTURE_INTERNALS_H_ +#define UNITY_FIXTURE_INTERNALS_H_ + +struct _UnityFixture +{ + int Verbose; + unsigned int RepeatCount; + const char* NameFilter; + const char* GroupFilter; +}; +extern struct _UnityFixture UnityFixture; + +typedef void unityfunction(void); +void UnityTestRunner(unityfunction* setup, + unityfunction* body, + unityfunction* teardown, + const char* printableName, + const char* group, + const char* name, + const char* file, unsigned int line); + +void UnityIgnoreTest(const char* printableName, const char* group, const char* name); +void UnityMalloc_StartTest(void); +void UnityMalloc_EndTest(void); +int UnityGetCommandLineOptions(int argc, const char* argv[]); +void UnityConcludeFixtureTest(void); + +void UnityPointer_Set(void** ptr, void* newValue, UNITY_LINE_TYPE line); +void UnityPointer_UndoAllSets(void); +void UnityPointer_Init(void); + +#endif /* UNITY_FIXTURE_INTERNALS_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/src/unity_fixture_malloc_overrides.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/src/unity_fixture_malloc_overrides.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,46 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FIXTURE_MALLOC_OVERRIDES_H_ +#define UNITY_FIXTURE_MALLOC_OVERRIDES_H_ + +#include <stddef.h> + +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC +// Define this macro to remove the use of stdlib.h, malloc, and free. +// Many embedded systems do not have a heap or malloc/free by default. +// This internal unity_malloc() provides allocated memory deterministically from +// the end of an array only, unity_free() only releases from end-of-array, +// blocks are not coalesced, and memory not freed in LIFO order is stranded. + #ifndef UNITY_INTERNAL_HEAP_SIZE_BYTES + #define UNITY_INTERNAL_HEAP_SIZE_BYTES 256 + #endif +#endif + +// These functions are used by the Unity Fixture to allocate and release memory +// on the heap and can be overridden with platform-specific implementations. +// For example, when using FreeRTOS UNITY_FIXTURE_MALLOC becomes pvPortMalloc() +// and UNITY_FIXTURE_FREE becomes vPortFree(). +#if !defined(UNITY_FIXTURE_MALLOC) || !defined(UNITY_FIXTURE_FREE) + #define UNITY_FIXTURE_MALLOC(size) malloc(size) + #define UNITY_FIXTURE_FREE(ptr) free(ptr) +#else + extern void* UNITY_FIXTURE_MALLOC(size_t size); + extern void UNITY_FIXTURE_FREE(void* ptr); +#endif + +#define malloc unity_malloc +#define calloc unity_calloc +#define realloc unity_realloc +#define free unity_free + +void* unity_malloc(size_t size); +void* unity_calloc(size_t num, size_t size); +void* unity_realloc(void * oldMem, size_t size); +void unity_free(void * mem); + +#endif /* UNITY_FIXTURE_MALLOC_OVERRIDES_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/main/AllTests.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/main/AllTests.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,22 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include "unity_fixture.h" + +static void runAllTests(void) +{ + RUN_TEST_GROUP(UnityFixture); + RUN_TEST_GROUP(UnityCommandOptions); + RUN_TEST_GROUP(LeakDetection); + RUN_TEST_GROUP(InternalMalloc); +} + +int main(int argc, const char* argv[]) +{ + return UnityMain(argc, argv, runAllTests); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/template_fixture_tests.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/template_fixture_tests.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,39 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include "unity_fixture.h" + +static int data = -1; + +TEST_GROUP(mygroup); + +TEST_SETUP(mygroup) +{ + data = 0; +} + +TEST_TEAR_DOWN(mygroup) +{ + data = -1; +} + +TEST(mygroup, test1) +{ + TEST_ASSERT_EQUAL_INT(0, data); +} + +TEST(mygroup, test2) +{ + TEST_ASSERT_EQUAL_INT(0, data); + data = 5; +} + +TEST(mygroup, test3) +{ + data = 7; + TEST_ASSERT_EQUAL_INT(7, data); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/unity_fixture_Test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/unity_fixture_Test.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,533 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include "unity_fixture.h" +#include "unity_output_Spy.h" +#include <stdlib.h> +#include <string.h> + +TEST_GROUP(UnityFixture); + +TEST_SETUP(UnityFixture) +{ +} + +TEST_TEAR_DOWN(UnityFixture) +{ +} + +static int* pointer1 = 0; +static int* pointer2 = (int*)2; +static int* pointer3 = (int*)3; +static int int1; +static int int2; +static int int3; +static int int4; + +TEST(UnityFixture, PointerSetting) +{ + TEST_ASSERT_POINTERS_EQUAL(pointer1, 0); + UT_PTR_SET(pointer1, &int1); + UT_PTR_SET(pointer2, &int2); + UT_PTR_SET(pointer3, &int3); + TEST_ASSERT_POINTERS_EQUAL(pointer1, &int1); + TEST_ASSERT_POINTERS_EQUAL(pointer2, &int2); + TEST_ASSERT_POINTERS_EQUAL(pointer3, &int3); + UT_PTR_SET(pointer1, &int4); + UnityPointer_UndoAllSets(); + TEST_ASSERT_POINTERS_EQUAL(pointer1, 0); + TEST_ASSERT_POINTERS_EQUAL(pointer2, (int*)2); + TEST_ASSERT_POINTERS_EQUAL(pointer3, (int*)3); +} + +TEST(UnityFixture, ForceMallocFail) +{ + void* m; + void* mfails; + UnityMalloc_MakeMallocFailAfterCount(1); + m = malloc(10); + CHECK(m); + mfails = malloc(10); + TEST_ASSERT_POINTERS_EQUAL(0, mfails); + free(m); +} + +TEST(UnityFixture, ReallocSmallerIsUnchanged) +{ + void* m1 = malloc(10); + void* m2 = realloc(m1, 5); + TEST_ASSERT_POINTERS_EQUAL(m1, m2); + free(m2); +} + +TEST(UnityFixture, ReallocSameIsUnchanged) +{ + void* m1 = malloc(10); + void* m2 = realloc(m1, 10); + TEST_ASSERT_POINTERS_EQUAL(m1, m2); + free(m2); +} + +TEST(UnityFixture, ReallocLargerNeeded) +{ + void* m1 = malloc(10); + void* m2; + CHECK(m1); + strcpy((char*)m1, "123456789"); + m2 = realloc(m1, 15); + // CHECK(m1 != m2); //Depends on implementation + STRCMP_EQUAL("123456789", m2); + free(m2); +} + +TEST(UnityFixture, ReallocNullPointerIsLikeMalloc) +{ + void* m = realloc(0, 15); + CHECK(m != 0); + free(m); +} + +TEST(UnityFixture, ReallocSizeZeroFreesMemAndReturnsNullPointer) +{ + void* m1 = malloc(10); + void* m2 = realloc(m1, 0); + TEST_ASSERT_POINTERS_EQUAL(0, m2); +} + +TEST(UnityFixture, CallocFillsWithZero) +{ + void* m = calloc(3, sizeof(char)); + char* s = (char*)m; + CHECK(m); + TEST_ASSERT_BYTES_EQUAL(0, s[0]); + TEST_ASSERT_BYTES_EQUAL(0, s[1]); + TEST_ASSERT_BYTES_EQUAL(0, s[2]); + free(m); +} + +static char *p1; +static char *p2; + +TEST(UnityFixture, PointerSet) +{ + char c1; + char c2; + char newC1; + char newC2; + p1 = &c1; + p2 = &c2; + + UnityPointer_Init(); + UT_PTR_SET(p1, &newC1); + UT_PTR_SET(p2, &newC2); + TEST_ASSERT_POINTERS_EQUAL(&newC1, p1); + TEST_ASSERT_POINTERS_EQUAL(&newC2, p2); + UnityPointer_UndoAllSets(); + TEST_ASSERT_POINTERS_EQUAL(&c1, p1); + TEST_ASSERT_POINTERS_EQUAL(&c2, p2); +} + +TEST(UnityFixture, FreeNULLSafety) +{ + free(NULL); +} + +TEST(UnityFixture, ConcludeTestIncrementsFailCount) +{ + _U_UINT savedFails = Unity.TestFailures; + _U_UINT savedIgnores = Unity.TestIgnores; + UnityOutputCharSpy_Enable(1); + Unity.CurrentTestFailed = 1; + UnityConcludeFixtureTest(); // Resets TestFailed for this test to pass + Unity.CurrentTestIgnored = 1; + UnityConcludeFixtureTest(); // Resets TestIgnored + UnityOutputCharSpy_Enable(0); + TEST_ASSERT_EQUAL(savedFails + 1, Unity.TestFailures); + TEST_ASSERT_EQUAL(savedIgnores + 1, Unity.TestIgnores); + Unity.TestFailures = savedFails; + Unity.TestIgnores = savedIgnores; +} + +//------------------------------------------------------------ + +TEST_GROUP(UnityCommandOptions); + +static int savedVerbose; +static unsigned int savedRepeat; +static const char* savedName; +static const char* savedGroup; + +TEST_SETUP(UnityCommandOptions) +{ + savedVerbose = UnityFixture.Verbose; + savedRepeat = UnityFixture.RepeatCount; + savedName = UnityFixture.NameFilter; + savedGroup = UnityFixture.GroupFilter; +} + +TEST_TEAR_DOWN(UnityCommandOptions) +{ + UnityFixture.Verbose = savedVerbose; + UnityFixture.RepeatCount= savedRepeat; + UnityFixture.NameFilter = savedName; + UnityFixture.GroupFilter = savedGroup; +} + + +static const char* noOptions[] = { + "testrunner.exe" +}; + +TEST(UnityCommandOptions, DefaultOptions) +{ + UnityGetCommandLineOptions(1, noOptions); + TEST_ASSERT_EQUAL(0, UnityFixture.Verbose); + TEST_ASSERT_POINTERS_EQUAL(0, UnityFixture.GroupFilter); + TEST_ASSERT_POINTERS_EQUAL(0, UnityFixture.NameFilter); + TEST_ASSERT_EQUAL(1, UnityFixture.RepeatCount); +} + +static const char* verbose[] = { + "testrunner.exe", + "-v" +}; + +TEST(UnityCommandOptions, OptionVerbose) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(2, verbose)); + TEST_ASSERT_EQUAL(1, UnityFixture.Verbose); +} + +static const char* group[] = { + "testrunner.exe", + "-g", "groupname" +}; + +TEST(UnityCommandOptions, OptionSelectTestByGroup) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(3, group)); + STRCMP_EQUAL("groupname", UnityFixture.GroupFilter); +} + +static const char* name[] = { + "testrunner.exe", + "-n", "testname" +}; + +TEST(UnityCommandOptions, OptionSelectTestByName) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(3, name)); + STRCMP_EQUAL("testname", UnityFixture.NameFilter); +} + +static const char* repeat[] = { + "testrunner.exe", + "-r", "99" +}; + +TEST(UnityCommandOptions, OptionSelectRepeatTestsDefaultCount) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(2, repeat)); + TEST_ASSERT_EQUAL(2, UnityFixture.RepeatCount); +} + +TEST(UnityCommandOptions, OptionSelectRepeatTestsSpecificCount) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(3, repeat)); + TEST_ASSERT_EQUAL(99, UnityFixture.RepeatCount); +} + +static const char* multiple[] = { + "testrunner.exe", + "-v", + "-g", "groupname", + "-n", "testname", + "-r", "98" +}; + +TEST(UnityCommandOptions, MultipleOptions) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(8, multiple)); + TEST_ASSERT_EQUAL(1, UnityFixture.Verbose); + STRCMP_EQUAL("groupname", UnityFixture.GroupFilter); + STRCMP_EQUAL("testname", UnityFixture.NameFilter); + TEST_ASSERT_EQUAL(98, UnityFixture.RepeatCount); +} + +static const char* dashRNotLast[] = { + "testrunner.exe", + "-v", + "-g", "gggg", + "-r", + "-n", "tttt", +}; + +TEST(UnityCommandOptions, MultipleOptionsDashRNotLastAndNoValueSpecified) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(7, dashRNotLast)); + TEST_ASSERT_EQUAL(1, UnityFixture.Verbose); + STRCMP_EQUAL("gggg", UnityFixture.GroupFilter); + STRCMP_EQUAL("tttt", UnityFixture.NameFilter); + TEST_ASSERT_EQUAL(2, UnityFixture.RepeatCount); +} + +static const char* unknownCommand[] = { + "testrunner.exe", + "-v", + "-g", "groupname", + "-n", "testname", + "-r", "98", + "-z" +}; +TEST(UnityCommandOptions, UnknownCommandIsIgnored) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(9, unknownCommand)); + TEST_ASSERT_EQUAL(1, UnityFixture.Verbose); + STRCMP_EQUAL("groupname", UnityFixture.GroupFilter); + STRCMP_EQUAL("testname", UnityFixture.NameFilter); + TEST_ASSERT_EQUAL(98, UnityFixture.RepeatCount); +} + +TEST(UnityCommandOptions, GroupOrNameFilterWithoutStringFails) +{ + TEST_ASSERT_EQUAL(1, UnityGetCommandLineOptions(3, unknownCommand)); + TEST_ASSERT_EQUAL(1, UnityGetCommandLineOptions(5, unknownCommand)); + TEST_ASSERT_EQUAL(1, UnityMain(3, unknownCommand, NULL)); +} + +TEST(UnityCommandOptions, GroupFilterReallyFilters) +{ + _U_UINT saved = Unity.NumberOfTests; + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(4, unknownCommand)); + UnityIgnoreTest(NULL, "non-matching", NULL); + TEST_ASSERT_EQUAL(saved, Unity.NumberOfTests); +} + +IGNORE_TEST(UnityCommandOptions, TestShouldBeIgnored) +{ + TEST_FAIL_MESSAGE("This test should not run!"); +} + +//------------------------------------------------------------ + +TEST_GROUP(LeakDetection); + +TEST_SETUP(LeakDetection) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + UnityOutputCharSpy_Create(200); +#else + UnityOutputCharSpy_Create(1000); +#endif +} + +TEST_TEAR_DOWN(LeakDetection) +{ + UnityOutputCharSpy_Destroy(); +} + +#define EXPECT_ABORT_BEGIN \ + { \ + jmp_buf TestAbortFrame; \ + memcpy(TestAbortFrame, Unity.AbortFrame, sizeof(jmp_buf)); \ + if (TEST_PROTECT()) \ + { + +#define EXPECT_ABORT_END \ + } \ + memcpy(Unity.AbortFrame, TestAbortFrame, sizeof(jmp_buf)); \ + } + +// This tricky set of defines lets us see if we are using the Spy, returns 1 if true +#ifdef __STDC_VERSION__ + +#if __STDC_VERSION__ >= 199901L +#define USING_SPY_AS(a) EXPAND_AND_USE_2ND(ASSIGN_VALUE(a), 0) +#define ASSIGN_VALUE(a) VAL_##a +#define VAL_UnityOutputCharSpy_OutputChar 0, 1 +#define EXPAND_AND_USE_2ND(a, b) SECOND_PARAM(a, b, throwaway) +#define SECOND_PARAM(a, b, ...) b +#if USING_SPY_AS(UNITY_OUTPUT_CHAR) + #define USING_OUTPUT_SPY // UNITY_OUTPUT_CHAR = UnityOutputCharSpy_OutputChar +#endif +#endif // >= 199901 + +#else // __STDC_VERSION__ else +#define UnityOutputCharSpy_OutputChar 42 +#if UNITY_OUTPUT_CHAR == UnityOutputCharSpy_OutputChar // Works if no -Wundef -Werror + #define USING_OUTPUT_SPY +#endif +#undef UnityOutputCharSpy_OutputChar +#endif // __STDC_VERSION__ + +TEST(LeakDetection, DetectsLeak) +{ +#ifndef USING_OUTPUT_SPY + TEST_IGNORE_MESSAGE("Build with '-D UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar' to enable tests"); +#else + void* m = malloc(10); + TEST_ASSERT_NOT_NULL(m); + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + UnityMalloc_EndTest(); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + CHECK(strstr(UnityOutputCharSpy_Get(), "This test leaks!")); + free(m); +#endif +} + +TEST(LeakDetection, BufferOverrunFoundDuringFree) +{ +#ifndef USING_OUTPUT_SPY + TEST_IGNORE(); +#else + void* m = malloc(10); + char* s = (char*)m; + TEST_ASSERT_NOT_NULL(m); + s[10] = (char)0xFF; + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + free(m); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during free()")); +#endif +} + +TEST(LeakDetection, BufferOverrunFoundDuringRealloc) +{ +#ifndef USING_OUTPUT_SPY + TEST_IGNORE(); +#else + void* m = malloc(10); + char* s = (char*)m; + TEST_ASSERT_NOT_NULL(m); + s[10] = (char)0xFF; + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + m = realloc(m, 100); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during realloc()")); +#endif +} + +TEST(LeakDetection, BufferGuardWriteFoundDuringFree) +{ +#ifndef USING_OUTPUT_SPY + TEST_IGNORE(); +#else + void* m = malloc(10); + char* s = (char*)m; + TEST_ASSERT_NOT_NULL(m); + s[-1] = (char)0x00; // Will not detect 0 + s[-2] = (char)0x01; + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + free(m); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during free()")); +#endif +} + +TEST(LeakDetection, BufferGuardWriteFoundDuringRealloc) +{ +#ifndef USING_OUTPUT_SPY + TEST_IGNORE(); +#else + void* m = malloc(10); + char* s = (char*)m; + TEST_ASSERT_NOT_NULL(m); + s[-1] = (char)0x0A; + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + m = realloc(m, 100); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during realloc()")); +#endif +} + +TEST(LeakDetection, PointerSettingMax) +{ +#ifndef USING_OUTPUT_SPY + TEST_IGNORE(); +#else + int i; + for (i = 0; i < 50; i++) UT_PTR_SET(pointer1, &int1); + UnityOutputCharSpy_Enable(1); + EXPECT_ABORT_BEGIN + UT_PTR_SET(pointer1, &int1); + EXPECT_ABORT_END + UnityOutputCharSpy_Enable(0); + Unity.CurrentTestFailed = 0; + CHECK(strstr(UnityOutputCharSpy_Get(), "Too many pointers set")); +#endif +} + +//------------------------------------------------------------ + +TEST_GROUP(InternalMalloc); + +TEST_SETUP(InternalMalloc) { } +TEST_TEAR_DOWN(InternalMalloc) { } + +TEST(InternalMalloc, MallocPastBufferFails) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + void* n = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2); + TEST_ASSERT_NOT_NULL(m); + TEST_ASSERT_NULL(n); + free(m); +#endif +} + +TEST(InternalMalloc, CallocPastBufferFails) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = calloc(1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + void* n = calloc(1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2); + TEST_ASSERT_NOT_NULL(m); + TEST_ASSERT_NULL(n); + free(m); +#endif +} + +TEST(InternalMalloc, MallocThenReallocGrowsMemoryInPlace) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + void* n = realloc(m, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 9); + TEST_ASSERT_NOT_NULL(m); + TEST_ASSERT_EQUAL(m, n); + free(n); +#endif +} + +TEST(InternalMalloc, ReallocFailDoesNotFreeMem) +{ +#ifdef UNITY_EXCLUDE_STDLIB_MALLOC + void* m = malloc(UNITY_INTERNAL_HEAP_SIZE_BYTES/2); + void* n1 = malloc(10); + void* out_of_mem = realloc(n1, UNITY_INTERNAL_HEAP_SIZE_BYTES/2 + 1); + void* n2 = malloc(10); + TEST_ASSERT_NOT_NULL(m); + TEST_ASSERT_NULL(out_of_mem); + TEST_ASSERT_NOT_EQUAL(n2, n1); + free(n2); + free(n1); + free(m); +#endif +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/unity_fixture_TestRunner.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/unity_fixture_TestRunner.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include "unity_fixture.h" + +TEST_GROUP_RUNNER(UnityFixture) +{ + RUN_TEST_CASE(UnityFixture, PointerSetting); + RUN_TEST_CASE(UnityFixture, ForceMallocFail); + RUN_TEST_CASE(UnityFixture, ReallocSmallerIsUnchanged); + RUN_TEST_CASE(UnityFixture, ReallocSameIsUnchanged); + RUN_TEST_CASE(UnityFixture, ReallocLargerNeeded); + RUN_TEST_CASE(UnityFixture, ReallocNullPointerIsLikeMalloc); + RUN_TEST_CASE(UnityFixture, ReallocSizeZeroFreesMemAndReturnsNullPointer); + RUN_TEST_CASE(UnityFixture, CallocFillsWithZero); + RUN_TEST_CASE(UnityFixture, PointerSet); + RUN_TEST_CASE(UnityFixture, FreeNULLSafety); + RUN_TEST_CASE(UnityFixture, ConcludeTestIncrementsFailCount); +} + +TEST_GROUP_RUNNER(UnityCommandOptions) +{ + RUN_TEST_CASE(UnityCommandOptions, DefaultOptions); + RUN_TEST_CASE(UnityCommandOptions, OptionVerbose); + RUN_TEST_CASE(UnityCommandOptions, OptionSelectTestByGroup); + RUN_TEST_CASE(UnityCommandOptions, OptionSelectTestByName); + RUN_TEST_CASE(UnityCommandOptions, OptionSelectRepeatTestsDefaultCount); + RUN_TEST_CASE(UnityCommandOptions, OptionSelectRepeatTestsSpecificCount); + RUN_TEST_CASE(UnityCommandOptions, MultipleOptions); + RUN_TEST_CASE(UnityCommandOptions, MultipleOptionsDashRNotLastAndNoValueSpecified); + RUN_TEST_CASE(UnityCommandOptions, UnknownCommandIsIgnored); + RUN_TEST_CASE(UnityCommandOptions, GroupOrNameFilterWithoutStringFails); + RUN_TEST_CASE(UnityCommandOptions, GroupFilterReallyFilters); + RUN_TEST_CASE(UnityCommandOptions, TestShouldBeIgnored); +} + +TEST_GROUP_RUNNER(LeakDetection) +{ + RUN_TEST_CASE(LeakDetection, DetectsLeak); + RUN_TEST_CASE(LeakDetection, BufferOverrunFoundDuringFree); + RUN_TEST_CASE(LeakDetection, BufferOverrunFoundDuringRealloc); + RUN_TEST_CASE(LeakDetection, BufferGuardWriteFoundDuringFree); + RUN_TEST_CASE(LeakDetection, BufferGuardWriteFoundDuringRealloc); + RUN_TEST_CASE(LeakDetection, PointerSettingMax); +} + +TEST_GROUP_RUNNER(InternalMalloc) +{ + RUN_TEST_CASE(InternalMalloc, MallocPastBufferFails); + RUN_TEST_CASE(InternalMalloc, CallocPastBufferFails); + RUN_TEST_CASE(InternalMalloc, MallocThenReallocGrowsMemoryInPlace); + RUN_TEST_CASE(InternalMalloc, ReallocFailDoesNotFreeMem); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/unity_output_Spy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/unity_output_Spy.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + + +#include "unity_output_Spy.h" +#include "unity_fixture.h" + +#include <stdio.h> +#include <string.h> + +static int size; +static int count; +static char* buffer; +static int spy_enable; + +void UnityOutputCharSpy_Create(int s) +{ + size = (s > 0) ? s : 0; + count = 0; + spy_enable = 0; + buffer = malloc((size_t)size); + TEST_ASSERT_NOT_NULL_MESSAGE(buffer, "Internal malloc failed in Spy Create():" __FILE__); + memset(buffer, 0, (size_t)size); +} + +void UnityOutputCharSpy_Destroy(void) +{ + size = 0; + free(buffer); +} + +void UnityOutputCharSpy_OutputChar(int c) +{ + if (spy_enable) + { + if (count < (size-1)) + buffer[count++] = (char)c; + } + else + { + putchar(c); + } +} + +const char * UnityOutputCharSpy_Get(void) +{ + return buffer; +} + +void UnityOutputCharSpy_Enable(int enable) +{ + spy_enable = enable; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/unity_output_Spy.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/extras/fixture/test/unity_output_Spy.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,17 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef D_unity_output_Spy_H +#define D_unity_output_Spy_H + +void UnityOutputCharSpy_Create(int s); +void UnityOutputCharSpy_Destroy(void); +void UnityOutputCharSpy_OutputChar(int c); +const char * UnityOutputCharSpy_Get(void); +void UnityOutputCharSpy_Enable(int enable); + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/release/build.info --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/release/build.info Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +119 +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/release/version.info --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/release/version.info Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +2.3.2 +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/src/unity.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/src/unity.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1320 @@ +/* ========================================================================= + Unity Project - A Test Framework for C + Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +============================================================================ */ + +#include "unity.h" +#include <stddef.h> + +/* If omitted from header, declare overrideable prototypes here so they're ready for use */ +#ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION +void UNITY_OUTPUT_CHAR(int); +#endif + +/* Helpful macros for us to use here */ +#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; longjmp(Unity.AbortFrame, 1); } +#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; longjmp(Unity.AbortFrame, 1); } + +/* return prematurely if we are already in failure or ignore state */ +#define UNITY_SKIP_EXECUTION { if ((Unity.CurrentTestFailed != 0) || (Unity.CurrentTestIgnored != 0)) {return;} } + +struct _Unity Unity; + +static const char UnityStrOk[] = "OK"; +static const char UnityStrPass[] = "PASS"; +static const char UnityStrFail[] = "FAIL"; +static const char UnityStrIgnore[] = "IGNORE"; +static const char UnityStrNull[] = "NULL"; +static const char UnityStrSpacer[] = ". "; +static const char UnityStrExpected[] = " Expected "; +static const char UnityStrWas[] = " Was "; +static const char UnityStrElement[] = " Element "; +static const char UnityStrByte[] = " Byte "; +static const char UnityStrMemory[] = " Memory Mismatch."; +static const char UnityStrDelta[] = " Values Not Within Delta "; +static const char UnityStrPointless[] = " You Asked Me To Compare Nothing, Which Was Pointless."; +static const char UnityStrNullPointerForExpected[] = " Expected pointer to be NULL"; +static const char UnityStrNullPointerForActual[] = " Actual pointer was NULL"; +static const char UnityStrNot[] = "Not "; +static const char UnityStrInf[] = "Infinity"; +static const char UnityStrNegInf[] = "Negative Infinity"; +static const char UnityStrNaN[] = "NaN"; +static const char UnityStrDet[] = "Determinate"; +static const char UnityStrInvalidFloatTrait[] = "Invalid Float Trait"; +const char UnityStrErrFloat[] = "Unity Floating Point Disabled"; +const char UnityStrErrDouble[] = "Unity Double Precision Disabled"; +const char UnityStrErr64[] = "Unity 64-bit Support Disabled"; +static const char UnityStrBreaker[] = "-----------------------"; +static const char UnityStrResultsTests[] = " Tests "; +static const char UnityStrResultsFailures[] = " Failures "; +static const char UnityStrResultsIgnored[] = " Ignored "; +static const char UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " "; +static const char UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " "; + +#ifdef UNITY_FLOAT_NEEDS_ZERO +/* Dividing by these constants produces +/- infinity. + * The rationale is given in UnityAssertFloatIsInf's body. */ +static const _UF f_zero = 0.0f; +#endif + +/* compiler-generic print formatting masks */ +static const _U_UINT UnitySizeMask[] = +{ + 255u, /* 0xFF */ + 65535u, /* 0xFFFF */ + 65535u, + 4294967295u, /* 0xFFFFFFFF */ + 4294967295u, + 4294967295u, + 4294967295u +#ifdef UNITY_SUPPORT_64 + ,0xFFFFFFFFFFFFFFFF +#endif +}; + +/*----------------------------------------------- + * Pretty Printers & Test Result Output Handlers + *-----------------------------------------------*/ + +void UnityPrint(const char* string) +{ + const char* pch = string; + + if (pch != NULL) + { + while (*pch) + { + /* printable characters plus CR & LF are printed */ + if ((*pch <= 126) && (*pch >= 32)) + { + UNITY_OUTPUT_CHAR(*pch); + } + /* write escaped carriage returns */ + else if (*pch == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (*pch == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UnityPrintNumberHex((_U_UINT)*pch, 2); + } + pch++; + } + } +} + +void UnityPrintLen(const char* string, const _UU32 length); +void UnityPrintLen(const char* string, const _UU32 length) +{ + const char* pch = string; + + if (pch != NULL) + { + while (*pch && (_UU32)(pch - string) < length) + { + /* printable characters plus CR & LF are printed */ + if ((*pch <= 126) && (*pch >= 32)) + { + UNITY_OUTPUT_CHAR(*pch); + } + /* write escaped carriage returns */ + else if (*pch == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (*pch == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UnityPrintNumberHex((_U_UINT)*pch, 2); + } + pch++; + } + } +} + +/*-----------------------------------------------*/ +void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style) +{ + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + UnityPrintNumber(number); + } + else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT) + { + UnityPrintNumberUnsigned( (_U_UINT)number & UnitySizeMask[((_U_UINT)style & (_U_UINT)0x0F) - 1] ); + } + else + { + UnityPrintNumberHex((_U_UINT)number, (char)((style & 0x000F) << 1)); + } +} + +/*-----------------------------------------------*/ +void UnityPrintNumber(const _U_SINT number_to_print) +{ + _U_UINT number = (_U_UINT)number_to_print; + + if (number_to_print < 0) + { + /* A negative number, including MIN negative */ + UNITY_OUTPUT_CHAR('-'); + number = (_U_UINT)(-number_to_print); + } + UnityPrintNumberUnsigned(number); +} + +/*----------------------------------------------- + * basically do an itoa using as little ram as possible */ +void UnityPrintNumberUnsigned(const _U_UINT number) +{ + _U_UINT divisor = 1; + + /* figure out initial divisor */ + while (number / divisor > 9) + { + divisor *= 10; + } + + /* now mod and print, then divide divisor */ + do + { + UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10))); + divisor /= 10; + } + while (divisor > 0); +} + +/*-----------------------------------------------*/ +void UnityPrintNumberHex(const _U_UINT number, const char nibbles_to_print) +{ + _U_UINT nibble; + char nibbles = nibbles_to_print; + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + + while (nibbles > 0) + { + nibble = (number >> (--nibbles << 2)) & 0x0000000F; + if (nibble <= 9) + { + UNITY_OUTPUT_CHAR((char)('0' + nibble)); + } + else + { + UNITY_OUTPUT_CHAR((char)('A' - 10 + nibble)); + } + } +} + +/*-----------------------------------------------*/ +void UnityPrintMask(const _U_UINT mask, const _U_UINT number) +{ + _U_UINT current_bit = (_U_UINT)1 << (UNITY_INT_WIDTH - 1); + _US32 i; + + for (i = 0; i < UNITY_INT_WIDTH; i++) + { + if (current_bit & mask) + { + if (current_bit & number) + { + UNITY_OUTPUT_CHAR('1'); + } + else + { + UNITY_OUTPUT_CHAR('0'); + } + } + else + { + UNITY_OUTPUT_CHAR('X'); + } + current_bit = current_bit >> 1; + } +} + +/*-----------------------------------------------*/ +#ifdef UNITY_FLOAT_VERBOSE +#include <stdio.h> + +#ifndef UNITY_VERBOSE_NUMBER_MAX_LENGTH +# ifdef UNITY_DOUBLE_VERBOSE +# define UNITY_VERBOSE_NUMBER_MAX_LENGTH 317 +# else +# define UNITY_VERBOSE_NUMBER_MAX_LENGTH 47 +# endif +#endif + +void UnityPrintFloat(_UF number) +{ + char TempBuffer[UNITY_VERBOSE_NUMBER_MAX_LENGTH + 1]; + snprintf(TempBuffer, sizeof(TempBuffer), "%.6f", number); + UnityPrint(TempBuffer); +} +#endif + +/*-----------------------------------------------*/ + +void UnityPrintFail(void); +void UnityPrintFail(void) +{ + UnityPrint(UnityStrFail); +} + +void UnityPrintOk(void); +void UnityPrintOk(void) +{ + UnityPrint(UnityStrOk); +} + +/*-----------------------------------------------*/ +static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line); +static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line) +{ +#ifndef UNITY_FIXTURES + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((_U_SINT)line); + UNITY_OUTPUT_CHAR(':'); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#else + UNITY_UNUSED(file); + UNITY_UNUSED(line); +#endif +} + +/* SA_PATCH: Make failures more noticable. */ +static void UnityPrintVisibleFailure(void); +static void UnityPrintVisibleFailure(void) +{ + UNITY_OUTPUT_CHAR('\n'); + UnityPrint("===!!!===> "); + /* SA_PATCH: Output results using easy to parse tags. */ + UnityPrint(UNITY_RESULTS_TAGS_RESULT_START); + UnityPrint(UnityStrFail); + /* SA_PATCH: Output results using easy to parse tags. */ + UnityPrint(UNITY_RESULTS_TAGS_RESULT_END); + UnityPrint(" <===!!!==="); +} +/*-----------------------------------------------*/ +static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line); +static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line) +{ +#ifndef UNITY_FIXTURES + UnityTestResultsBegin(Unity.TestFile, line); +#else + UNITY_UNUSED(line); +#endif + /* SA_PATCH: Make failures more noticable. */ + UnityPrintVisibleFailure(); + //UnityPrint(UnityStrFail); + UNITY_OUTPUT_CHAR(':'); +} + +/*-----------------------------------------------*/ +void UnityConcludeTest(void) +{ + if (Unity.CurrentTestIgnored) + { + Unity.TestIgnores++; + } + else if (!Unity.CurrentTestFailed) + { + UnityTestResultsBegin(Unity.TestFile, Unity.CurrentTestLineNumber); + UnityPrint(UnityStrPass); + } + else + { + Unity.TestFailures++; + } + + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; + UNITY_PRINT_EOL(); + UNITY_FLUSH_CALL(); +} + +/*-----------------------------------------------*/ +static void UnityAddMsgIfSpecified(const char* msg); +static void UnityAddMsgIfSpecified(const char* msg) +{ + if (msg) + { + UnityPrint(UnityStrSpacer); +#ifndef UNITY_EXCLUDE_DETAILS + if (Unity.CurrentDetail1) + { + UnityPrint(UnityStrDetail1Name); + UnityPrint(Unity.CurrentDetail1); + if (Unity.CurrentDetail2) + { + UnityPrint(UnityStrDetail2Name); + UnityPrint(Unity.CurrentDetail2); + } + UnityPrint(UnityStrSpacer); + } +#endif + UnityPrint(msg); + } +} + +/*-----------------------------------------------*/ +static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual); +static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual) +{ + UnityPrint(UnityStrExpected); + if (expected != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrint(expected); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } + UnityPrint(UnityStrWas); + if (actual != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrint(actual); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } +} + +/*-----------------------------------------------*/ +static void UnityPrintExpectedAndActualStringsLen(const char* expected, const char* actual, const _UU32 length) +{ + UnityPrint(UnityStrExpected); + if (expected != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrintLen(expected, length); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } + UnityPrint(UnityStrWas); + if (actual != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrintLen(actual, length); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } +} + + + +/*----------------------------------------------- + * Assertion & Control Helpers + *-----------------------------------------------*/ + +static int UnityCheckArraysForNull(UNITY_INTERNAL_PTR expected, UNITY_INTERNAL_PTR actual, const UNITY_LINE_TYPE lineNumber, const char* msg) +{ + /* return true if they are both NULL */ + if ((expected == NULL) && (actual == NULL)) + return 1; + + /* throw error if just expected is NULL */ + if (expected == NULL) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrNullPointerForExpected); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + + /* throw error if just actual is NULL */ + if (actual == NULL) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrNullPointerForActual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + + /* return false if neither is NULL */ + return 0; +} + +/*----------------------------------------------- + * Assertion Functions + *-----------------------------------------------*/ + +void UnityAssertBits(const _U_SINT mask, + const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + UNITY_SKIP_EXECUTION; + + if ((mask & expected) != (mask & actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintMask((_U_UINT)mask, (_U_UINT)expected); + UnityPrint(UnityStrWas); + UnityPrintMask((_U_UINT)mask, (_U_UINT)actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualNumber(const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + UNITY_SKIP_EXECUTION; + + if (expected != actual) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expected, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +#define UnityPrintPointlessAndBail() \ +{ \ + UnityTestResultsFailBegin(lineNumber); \ + UnityPrint(UnityStrPointless); \ + UnityAddMsgIfSpecified(msg); \ + UNITY_FAIL_AND_BAIL; } + +/*-----------------------------------------------*/ +void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + _UU32 elements = num_elements; + UNITY_INTERNAL_PTR ptr_exp = (UNITY_INTERNAL_PTR)expected; + UNITY_INTERNAL_PTR ptr_act = (UNITY_INTERNAL_PTR)actual; + + UNITY_SKIP_EXECUTION; + + if (elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) + return; + + /* If style is UNITY_DISPLAY_STYLE_INT, we'll fall into the default case rather than the INT16 or INT32 (etc) case + * as UNITY_DISPLAY_STYLE_INT includes a flag for UNITY_DISPLAY_RANGE_AUTO, which the width-specific + * variants do not. Therefore remove this flag. */ + switch(style & (UNITY_DISPLAY_STYLE_T)(~UNITY_DISPLAY_RANGE_AUTO)) + { + case UNITY_DISPLAY_STYLE_HEX8: + case UNITY_DISPLAY_STYLE_INT8: + case UNITY_DISPLAY_STYLE_UINT8: + while (elements--) + { + if (*(UNITY_PTR_ATTRIBUTE const _US8*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US8*)ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US8*)ptr_exp, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US8*)ptr_act, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 1); + ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 1); + } + break; + case UNITY_DISPLAY_STYLE_HEX16: + case UNITY_DISPLAY_STYLE_INT16: + case UNITY_DISPLAY_STYLE_UINT16: + while (elements--) + { + if (*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US16*)ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_exp, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_act, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 2); + ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 2); + } + break; +#ifdef UNITY_SUPPORT_64 + case UNITY_DISPLAY_STYLE_HEX64: + case UNITY_DISPLAY_STYLE_INT64: + case UNITY_DISPLAY_STYLE_UINT64: + while (elements--) + { + if (*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US64*)ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_exp, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_act, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 8); + ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 8); + } + break; +#endif + default: + while (elements--) + { + if (*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US32*)ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_exp, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_act, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 4); + ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 4); + } + break; + } +} + +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_FLOAT +void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const _UF* expected, + UNITY_PTR_ATTRIBUTE const _UF* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UU32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const _UF* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const _UF* ptr_actual = actual; + _UF diff, tol; + + UNITY_SKIP_EXECUTION; + + if (elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) + return; + + while (elements--) + { + diff = *ptr_expected - *ptr_actual; + if (diff < 0.0f) + diff = 0.0f - diff; + tol = UNITY_FLOAT_PRECISION * *ptr_expected; + if (tol < 0.0f) + tol = 0.0f - tol; + + /* This first part of this condition will catch any NaN or Infinite values */ + if (isnan(diff) || isinf(diff) || (diff > tol)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); +#ifdef UNITY_FLOAT_VERBOSE + UnityPrint(UnityStrExpected); + UnityPrintFloat(*ptr_expected); + UnityPrint(UnityStrWas); + UnityPrintFloat(*ptr_actual); +#else + UnityPrint(UnityStrDelta); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_expected++; + ptr_actual++; + } +} + +/*-----------------------------------------------*/ +void UnityAssertFloatsWithin(const _UF delta, + const _UF expected, + const _UF actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UF diff = actual - expected; + _UF pos_delta = delta; + + UNITY_SKIP_EXECUTION; + + if (diff < 0.0f) + { + diff = 0.0f - diff; + } + if (pos_delta < 0.0f) + { + pos_delta = 0.0f - pos_delta; + } + + /* This first part of this condition will catch any NaN or Infinite values */ + if (isnan(diff) || isinf(diff) || (pos_delta < diff)) + { + UnityTestResultsFailBegin(lineNumber); +#ifdef UNITY_FLOAT_VERBOSE + UnityPrint(UnityStrExpected); + UnityPrintFloat(expected); + UnityPrint(UnityStrWas); + UnityPrintFloat(actual); +#else + UnityPrint(UnityStrDelta); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertFloatSpecial(const _UF actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = { UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet }; + _U_SINT should_be_trait = ((_U_SINT)style & 1); + _U_SINT is_trait = !should_be_trait; + _U_SINT trait_index = (_U_SINT)(style >> 1); + + UNITY_SKIP_EXECUTION; + + switch(style) + { + /* To determine Inf / Neg Inf, we compare to an Inf / Neg Inf value we create on the fly + * We are using a variable to hold the zero value because some compilers complain about dividing by zero otherwise */ + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = isinf(actual) & ispos(actual); + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = isinf(actual) & isneg(actual); + break; + + /* NaN is the only floating point value that does NOT equal itself. Therefore if Actual == Actual, then it is NOT NaN. */ + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = isnan(actual); + break; + + /* A determinate number is non infinite and not NaN. (therefore the opposite of the two above) */ + case UNITY_FLOAT_IS_DET: + case UNITY_FLOAT_IS_NOT_DET: + if (isinf(actual) | isnan(actual)) + is_trait = 0; + else + is_trait = 1; + break; + + default: + trait_index = 0; + trait_names[0] = UnityStrInvalidFloatTrait; + break; + } + + if (is_trait != should_be_trait) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + if (!should_be_trait) + UnityPrint(UnityStrNot); + UnityPrint(trait_names[trait_index]); + UnityPrint(UnityStrWas); +#ifdef UNITY_FLOAT_VERBOSE + UnityPrintFloat(actual); +#else + if (should_be_trait) + UnityPrint(UnityStrNot); + UnityPrint(trait_names[trait_index]); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +#endif /* not UNITY_EXCLUDE_FLOAT */ + +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_DOUBLE +void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const _UD* expected, + UNITY_PTR_ATTRIBUTE const _UD* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UU32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const _UD* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const _UD* ptr_actual = actual; + _UD diff, tol; + + UNITY_SKIP_EXECUTION; + + if (elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) + return; + + while (elements--) + { + diff = *ptr_expected - *ptr_actual; + if (diff < 0.0) + diff = 0.0 - diff; + tol = UNITY_DOUBLE_PRECISION * *ptr_expected; + if (tol < 0.0) + tol = 0.0 - tol; + + /* This first part of this condition will catch any NaN or Infinite values */ + if (isnan(diff) || isinf(diff) || (diff > tol)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); +#ifdef UNITY_DOUBLE_VERBOSE + UnityPrint(UnityStrExpected); + UnityPrintFloat((float)(*ptr_expected)); + UnityPrint(UnityStrWas); + UnityPrintFloat((float)(*ptr_actual)); +#else + UnityPrint(UnityStrDelta); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_expected++; + ptr_actual++; + } +} + +/*-----------------------------------------------*/ +void UnityAssertDoublesWithin(const _UD delta, + const _UD expected, + const _UD actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UD diff = actual - expected; + _UD pos_delta = delta; + + UNITY_SKIP_EXECUTION; + + if (diff < 0.0) + { + diff = 0.0 - diff; + } + if (pos_delta < 0.0) + { + pos_delta = 0.0 - pos_delta; + } + + /* This first part of this condition will catch any NaN or Infinite values */ + if (isnan(diff) || isinf(diff) || (pos_delta < diff)) + { + UnityTestResultsFailBegin(lineNumber); +#ifdef UNITY_DOUBLE_VERBOSE + UnityPrint(UnityStrExpected); + UnityPrintFloat((float)expected); + UnityPrint(UnityStrWas); + UnityPrintFloat((float)actual); +#else + UnityPrint(UnityStrDelta); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ + +void UnityAssertDoubleSpecial(const _UD actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = { UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet }; + _U_SINT should_be_trait = ((_U_SINT)style & 1); + _U_SINT is_trait = !should_be_trait; + _U_SINT trait_index = (_U_SINT)(style >> 1); + + UNITY_SKIP_EXECUTION; + + switch(style) + { + /* To determine Inf / Neg Inf, we compare to an Inf / Neg Inf value we create on the fly + * We are using a variable to hold the zero value because some compilers complain about dividing by zero otherwise */ + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = isinf(actual) & ispos(actual); + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = isinf(actual) & isneg(actual); + break; + + /* NaN is the only floating point value that does NOT equal itself. Therefore if Actual == Actual, then it is NOT NaN. */ + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = isnan(actual); + break; + + /* A determinate number is non infinite and not NaN. (therefore the opposite of the two above) */ + case UNITY_FLOAT_IS_DET: + case UNITY_FLOAT_IS_NOT_DET: + if (isinf(actual) | isnan(actual)) + is_trait = 0; + else + is_trait = 1; + break; + + default: + trait_index = 0; + trait_names[0] = UnityStrInvalidFloatTrait; + break; + } + + if (is_trait != should_be_trait) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + if (!should_be_trait) + UnityPrint(UnityStrNot); + UnityPrint(trait_names[trait_index]); + UnityPrint(UnityStrWas); +#ifdef UNITY_DOUBLE_VERBOSE + UnityPrintFloat(actual); +#else + if (should_be_trait) + UnityPrint(UnityStrNot); + UnityPrint(trait_names[trait_index]); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + + +#endif /* not UNITY_EXCLUDE_DOUBLE */ + +/*-----------------------------------------------*/ +void UnityAssertNumbersWithin( const _U_UINT delta, + const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + UNITY_SKIP_EXECUTION; + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (actual > expected) + Unity.CurrentTestFailed = ((_U_UINT)(actual - expected) > delta); + else + Unity.CurrentTestFailed = ((_U_UINT)(expected - actual) > delta); + } + else + { + if ((_U_UINT)actual > (_U_UINT)expected) + Unity.CurrentTestFailed = ((_U_UINT)(actual - expected) > delta); + else + Unity.CurrentTestFailed = ((_U_UINT)(expected - actual) > delta); + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrDelta); + UnityPrintNumberByStyle((_U_SINT)delta, style); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expected, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualString(const char* expected, + const char* actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UU32 i; + + UNITY_SKIP_EXECUTION; + + /* if both pointers not null compare the strings */ + if (expected && actual) + { + for (i = 0; expected[i] || actual[i]; i++) + { + if (expected[i] != actual[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* handle case of one pointers being null (if both null, test should pass) */ + if (expected != actual) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrintExpectedAndActualStrings(expected, actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualStringLen(const char* expected, + const char* actual, + const _UU32 length, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UU32 i; + + UNITY_SKIP_EXECUTION; + + /* if both pointers not null compare the strings */ + if (expected && actual) + { + for (i = 0; (expected[i] || actual[i]) && i < length; i++) + { + if (expected[i] != actual[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* handle case of one pointers being null (if both null, test should pass) */ + if (expected != actual) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrintExpectedAndActualStringsLen(expected, actual, length); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + + +/*-----------------------------------------------*/ +void UnityAssertEqualStringArray( const char** expected, + const char** actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UU32 i, j = 0; + + UNITY_SKIP_EXECUTION; + + /* if no elements, it's an error */ + if (num_elements == 0) + { + UnityPrintPointlessAndBail(); + } + + if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) + return; + + do + { + /* if both pointers not null compare the strings */ + if (expected[j] && actual[j]) + { + for (i = 0; expected[j][i] || actual[j][i]; i++) + { + if (expected[j][i] != actual[j][i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* handle case of one pointers being null (if both null, test should pass) */ + if (expected[j] != actual[j]) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + if (num_elements > 1) + { + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(j); + } + UnityPrintExpectedAndActualStrings((const char*)(expected[j]), (const char*)(actual[j])); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + } while (++j < num_elements); +} + +/*-----------------------------------------------*/ +void UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const _UU32 length, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + UNITY_PTR_ATTRIBUTE const unsigned char* ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected; + UNITY_PTR_ATTRIBUTE const unsigned char* ptr_act = (UNITY_PTR_ATTRIBUTE const unsigned char*)actual; + _UU32 elements = num_elements; + _UU32 bytes; + + UNITY_SKIP_EXECUTION; + + if ((elements == 0) || (length == 0)) + { + UnityPrintPointlessAndBail(); + } + + if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1) + return; + + while (elements--) + { + /* /////////////////////////////////// */ + bytes = length; + while (bytes--) + { + if (*ptr_exp != *ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrMemory); + if (num_elements > 1) + { + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + } + UnityPrint(UnityStrByte); + UnityPrintNumberUnsigned(length - bytes - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*ptr_exp, UNITY_DISPLAY_STYLE_HEX8); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*ptr_act, UNITY_DISPLAY_STYLE_HEX8); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 1); + ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 1); + } + /* /////////////////////////////////// */ + + } +} + +/*----------------------------------------------- + * Control Functions + *-----------------------------------------------*/ + +void UnityFail(const char* msg, const UNITY_LINE_TYPE line) +{ + UNITY_SKIP_EXECUTION; + + UnityTestResultsBegin(Unity.TestFile, line); + /* SA_PATCH: Make failures more noticable. */ + UnityPrintVisibleFailure(); + //UnityPrintFail(); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + +#ifndef UNITY_EXCLUDE_DETAILS + if (Unity.CurrentDetail1) + { + UnityPrint(UnityStrDetail1Name); + UnityPrint(Unity.CurrentDetail1); + if (Unity.CurrentDetail2) + { + UnityPrint(UnityStrDetail2Name); + UnityPrint(Unity.CurrentDetail2); + } + UnityPrint(UnityStrSpacer); + } +#endif + if (msg[0] != ' ') + { + UNITY_OUTPUT_CHAR(' '); + } + UnityPrint(msg); + } + + UNITY_FAIL_AND_BAIL; +} + +/*-----------------------------------------------*/ +void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) +{ + UNITY_SKIP_EXECUTION; + + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrIgnore); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(msg); + } + UNITY_IGNORE_AND_BAIL; +} + +/*-----------------------------------------------*/ +#if defined(UNITY_WEAK_ATTRIBUTE) + UNITY_WEAK_ATTRIBUTE void setUp(void) { } + UNITY_WEAK_ATTRIBUTE void tearDown(void) { } +#elif defined(UNITY_WEAK_PRAGMA) +# pragma weak setUp + void setUp(void) { } +# pragma weak tearDown + void tearDown(void) { } +#endif +/*-----------------------------------------------*/ +void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) +{ + Unity.CurrentTestName = FuncName; + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum; + Unity.NumberOfTests++; + UNITY_CLR_DETAILS(); + if (TEST_PROTECT()) + { + setUp(); + Func(); + } + if (TEST_PROTECT() && !(Unity.CurrentTestIgnored)) + { + tearDown(); + } + UnityConcludeTest(); +} + +/*-----------------------------------------------*/ +void UnityBegin(const char* filename) +{ + Unity.TestFile = filename; + Unity.CurrentTestName = NULL; + Unity.CurrentTestLineNumber = 0; + Unity.NumberOfTests = 0; + Unity.TestFailures = 0; + Unity.TestIgnores = 0; + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; + + UNITY_CLR_DETAILS(); + UNITY_OUTPUT_START(); +} + +/*-----------------------------------------------*/ +int UnityEnd(void) +{ + UNITY_PRINT_EOL(); + UnityPrint(UnityStrBreaker); + UNITY_PRINT_EOL(); + UnityPrintNumber((_U_SINT)(Unity.NumberOfTests)); + UnityPrint(UnityStrResultsTests); + UnityPrintNumber((_U_SINT)(Unity.TestFailures)); + UnityPrint(UnityStrResultsFailures); + UnityPrintNumber((_U_SINT)(Unity.TestIgnores)); + UnityPrint(UnityStrResultsIgnored); + UNITY_PRINT_EOL(); + if (Unity.TestFailures == 0U) + { + UnityPrintOk(); + } + else + { + UnityPrintFail(); +#ifdef UNITY_DIFFERENTIATE_FINAL_FAIL + UNITY_OUTPUT_CHAR('E'); UNITY_OUTPUT_CHAR('D'); +#endif + } + UNITY_PRINT_EOL(); + UNITY_FLUSH_CALL(); + UNITY_OUTPUT_COMPLETE(); + return (int)(Unity.TestFailures); +} + +/*-----------------------------------------------*/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/src/unity.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/src/unity.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,291 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FRAMEWORK_H +#define UNITY_FRAMEWORK_H +#define UNITY + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "unity_internals.h" + +void setUp(void); +void tearDown(void); + +/*------------------------------------------------------- + * Configuration Options + *------------------------------------------------------- + * All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above. + + * Integers/longs/pointers + * - Unity attempts to automatically discover your integer sizes + * - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in <stdint.h> + * - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in <limits.h> + * - define UNITY_EXCLUDE_SIZEOF to stop attempting to use sizeof in macros + * - If you cannot use the automatic methods above, you can force Unity by using these options: + * - define UNITY_SUPPORT_64 + * - define UNITY_INT_WIDTH + * - UNITY_LONG_WIDTH + * - UNITY_POINTER_WIDTH + + * Floats + * - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons + * - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT + * - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats + * - define UNITY_FLOAT_VERBOSE to print floating point values in errors (uses sprintf) + * - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons + * - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default) + * - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE + * - define UNITY_DOUBLE_TYPE to specify something other than double + * - define UNITY_DOUBLE_VERBOSE to print floating point values in errors (uses sprintf) + * - define UNITY_VERBOSE_NUMBER_MAX_LENGTH to change maximum length of printed numbers (used by sprintf) + + * Output + * - by default, Unity prints to standard out with putchar. define UNITY_OUTPUT_CHAR(a) with a different function if desired + * - define UNITY_DIFFERENTIATE_FINAL_FAIL to print FAILED (vs. FAIL) at test end summary - for automated search for failure + + * Optimization + * - by default, line numbers are stored in unsigned shorts. Define UNITY_LINE_TYPE with a different type if your files are huge + * - by default, test and failure counters are unsigned shorts. Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests. + + * Test Cases + * - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script + + * Parameterized Tests + * - you'll want to create a define of TEST_CASE(...) which basically evaluates to nothing + + *------------------------------------------------------- + * Basic Fail and Ignore + *-------------------------------------------------------*/ + +#define TEST_FAIL_MESSAGE(message) UNITY_TEST_FAIL(__LINE__, (message)) +#define TEST_FAIL() UNITY_TEST_FAIL(__LINE__, NULL) +#define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, (message)) +#define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL) +#define TEST_ONLY() + +/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails. + * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */ +#define TEST_PASS() longjmp(Unity.AbortFrame, 1) + +/*------------------------------------------------------- + * Test Asserts (simple) + *-------------------------------------------------------*/ + +/* Boolean */ +#define TEST_ASSERT(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expression Evaluated To FALSE") +#define TEST_ASSERT_TRUE(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expected TRUE Was FALSE") +#define TEST_ASSERT_UNLESS(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expression Evaluated To TRUE") +#define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE") +#define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL") +#define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL") + +/* Integers (of all sizes) */ +#define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#define TEST_ASSERT_EQUAL_UINT(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX8(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX16(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX32(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(0), (actual), __LINE__, NULL) + +/* Integer Ranges (of all sizes) */ +#define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL) + +/* Structs and Strings */ +#define TEST_ASSERT_EQUAL_PTR(expected, actual) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING(expected, actual) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, NULL) + +/* Arrays */ +#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL) + +/* Floating Point (If Enabled) */ +#define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_FLOAT(expected, actual) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, NULL) + +/* Double (If Enabled) */ +#define TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_DOUBLE(expected, actual) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL) + +/*------------------------------------------------------- + * Test Asserts (with additional messages) + *-------------------------------------------------------*/ + +/* Boolean */ +#define TEST_ASSERT_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) +#define TEST_ASSERT_TRUE_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) +#define TEST_ASSERT_UNLESS_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) +#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) +#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message)) +#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message)) + +/* Integers (of all sizes) */ +#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, (message)) +#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(-1), (actual), __LINE__, (message)) +#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(0), (actual), __LINE__, (message)) + +/* Integer Ranges (of all sizes) */ +#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message)) + +/* Structs and Strings */ +#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, (message)) + +/* Arrays */ +#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, (message)) + +/* Floating Point (If Enabled) */ +#define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_FLOAT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_FLOAT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, (message)) + +/* Double (If Enabled) */ +#define TEST_ASSERT_DOUBLE_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_DOUBLE_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message)) + +/* end of UNITY_FRAMEWORK_H */ +#ifdef __cplusplus +} +#endif +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/src/unity_internals.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/src/unity_internals.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,794 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_INTERNALS_H +#define UNITY_INTERNALS_H + +#ifdef UNITY_INCLUDE_CONFIG_H +//#include "unity_config.h" +#endif + +#include <setjmp.h> + +/* Unity Attempts to Auto-Detect Integer Types + * Attempt 1: UINT_MAX, ULONG_MAX, etc in <stdint.h> + * Attempt 2: UINT_MAX, ULONG_MAX, etc in <limits.h> + * Attempt 3: Deduced from sizeof() macros */ +#ifndef UNITY_EXCLUDE_STDINT_H +#include <stdint.h> +#endif + +#ifndef UNITY_EXCLUDE_LIMITS_H +#include <limits.h> +#endif + +#ifndef UNITY_EXCLUDE_SIZEOF +#ifndef UINT_MAX +#define UINT_MAX (sizeof(unsigned int) * 256 - 1) +#endif +#ifndef ULONG_MAX +#define ULONG_MAX (sizeof(unsigned long) * 256 - 1) +#endif +#ifndef UINTPTR_MAX +/* apparently this is not a constant expression: (sizeof(unsigned int *) * 256 - 1) so we have to just let this fall through */ +#endif +#endif + +#ifndef UNITY_EXCLUDE_MATH_H +#include <math.h> +#endif + +/*------------------------------------------------------- + * Guess Widths If Not Specified + *-------------------------------------------------------*/ + +/* Determine the size of an int, if not already specificied. + * We cannot use sizeof(int), because it is not yet defined + * at this stage in the trnslation of the C program. + * Therefore, infer it from UINT_MAX if possible. */ +#ifndef UNITY_INT_WIDTH + #ifdef UINT_MAX + #if (UINT_MAX == 0xFFFF) + #define UNITY_INT_WIDTH (16) + #elif (UINT_MAX == 0xFFFFFFFF) + #define UNITY_INT_WIDTH (32) + #elif (UINT_MAX == 0xFFFFFFFFFFFFFFFF) + #define UNITY_INT_WIDTH (64) + #endif + #endif +#endif +#ifndef UNITY_INT_WIDTH + #define UNITY_INT_WIDTH (32) +#endif + +/* Determine the size of a long, if not already specified, + * by following the process used above to define + * UNITY_INT_WIDTH. */ +#ifndef UNITY_LONG_WIDTH + #ifdef ULONG_MAX + #if (ULONG_MAX == 0xFFFF) + #define UNITY_LONG_WIDTH (16) + #elif (ULONG_MAX == 0xFFFFFFFF) + #define UNITY_LONG_WIDTH (32) + #elif (ULONG_MAX == 0xFFFFFFFFFFFFFFFF) + #define UNITY_LONG_WIDTH (64) + #endif + #endif +#endif +#ifndef UNITY_LONG_WIDTH + #define UNITY_LONG_WIDTH (32) +#endif + +/* Determine the size of a pointer, if not already specified, + * by following the process used above to define + * UNITY_INT_WIDTH. */ +#ifndef UNITY_POINTER_WIDTH + #ifdef UINTPTR_MAX + #if (UINTPTR_MAX+0 <= 0xFFFF) + #define UNITY_POINTER_WIDTH (16) + #elif (UINTPTR_MAX+0 <= 0xFFFFFFFF) + #define UNITY_POINTER_WIDTH (32) + #elif (UINTPTR_MAX+0 <= 0xFFFFFFFFFFFFFFFF) + #define UNITY_POINTER_WIDTH (64) + #endif + #endif +#endif +#ifndef UNITY_POINTER_WIDTH + #ifdef INTPTR_MAX + #if (INTPTR_MAX+0 <= 0x7FFF) + #define UNITY_POINTER_WIDTH (16) + #elif (INTPTR_MAX+0 <= 0x7FFFFFFF) + #define UNITY_POINTER_WIDTH (32) + #elif (INTPTR_MAX+0 <= 0x7FFFFFFFFFFFFFFF) + #define UNITY_POINTER_WIDTH (64) + #endif + #endif +#endif +#ifndef UNITY_POINTER_WIDTH + #define UNITY_POINTER_WIDTH UNITY_LONG_WIDTH +#endif + +/*------------------------------------------------------- + * Int Support (Define types based on detected sizes) + *-------------------------------------------------------*/ + +#if (UNITY_INT_WIDTH == 32) + typedef unsigned char _UU8; + typedef unsigned short _UU16; + typedef unsigned int _UU32; + typedef signed char _US8; + typedef signed short _US16; + typedef signed int _US32; +#elif (UNITY_INT_WIDTH == 16) + typedef unsigned char _UU8; + typedef unsigned int _UU16; + typedef unsigned long _UU32; + typedef signed char _US8; + typedef signed int _US16; + typedef signed long _US32; +#else + #error Invalid UNITY_INT_WIDTH specified! (16 or 32 are supported) +#endif + +/*------------------------------------------------------- + * 64-bit Support + *-------------------------------------------------------*/ + +#ifndef UNITY_SUPPORT_64 +#if UNITY_LONG_WIDTH > 32 +#define UNITY_SUPPORT_64 +#endif +#endif +#ifndef UNITY_SUPPORT_64 +#if UNITY_POINTER_WIDTH > 32 +#define UNITY_SUPPORT_64 +#endif +#endif + +#ifndef UNITY_SUPPORT_64 + +/* No 64-bit Support */ +typedef _UU32 _U_UINT; +typedef _US32 _U_SINT; + +#else + +/* 64-bit Support */ +#if (UNITY_LONG_WIDTH == 32) + typedef unsigned long long _UU64; + typedef signed long long _US64; +#elif (UNITY_LONG_WIDTH == 64) + typedef unsigned long _UU64; + typedef signed long _US64; +#else + #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported) +#endif +typedef _UU64 _U_UINT; +typedef _US64 _U_SINT; + +#endif + +/*------------------------------------------------------- + * Pointer Support + *-------------------------------------------------------*/ + +#if (UNITY_POINTER_WIDTH == 32) + typedef _UU32 _UP; +#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 +#elif (UNITY_POINTER_WIDTH == 64) + typedef _UU64 _UP; +#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 +#elif (UNITY_POINTER_WIDTH == 16) + typedef _UU16 _UP; +#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 +#else + #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) +#endif + +#ifndef UNITY_PTR_ATTRIBUTE +#define UNITY_PTR_ATTRIBUTE +#endif + +#ifndef UNITY_INTERNAL_PTR +#define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void* +/* #define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const _UU8* */ +#endif + +/*------------------------------------------------------- + * Float Support + *-------------------------------------------------------*/ + +#ifdef UNITY_EXCLUDE_FLOAT + +/* No Floating Point Support */ +#undef UNITY_INCLUDE_FLOAT +#undef UNITY_FLOAT_PRECISION +#undef UNITY_FLOAT_TYPE +#undef UNITY_FLOAT_VERBOSE + +#else + +#ifndef UNITY_INCLUDE_FLOAT +#define UNITY_INCLUDE_FLOAT +#endif + +/* Floating Point Support */ +#ifndef UNITY_FLOAT_PRECISION +#define UNITY_FLOAT_PRECISION (0.00001f) +#endif +#ifndef UNITY_FLOAT_TYPE +#define UNITY_FLOAT_TYPE float +#endif +typedef UNITY_FLOAT_TYPE _UF; + +#ifndef isinf +#define isinf(n) (((1.0f / f_zero) == n) ? 1 : 0) || (((-1.0f / f_zero) == n) ? 1 : 0) +#define UNITY_FLOAT_NEEDS_ZERO +#endif + +#ifndef isnan +#define isnan(n) ((n != n) ? 1 : 0) +#endif + +#ifndef isneg +#define isneg(n) ((n < 0.0f) ? 1 : 0) +#endif + +#ifndef ispos +#define ispos(n) ((n > 0.0f) ? 1 : 0) +#endif + +#endif + +/*------------------------------------------------------- + * Double Float Support + *-------------------------------------------------------*/ + +/* unlike FLOAT, we DON'T include by default */ +#ifndef UNITY_EXCLUDE_DOUBLE +#ifndef UNITY_INCLUDE_DOUBLE +#define UNITY_EXCLUDE_DOUBLE +#endif +#endif + +#ifdef UNITY_EXCLUDE_DOUBLE + +/* No Floating Point Support */ +#undef UNITY_DOUBLE_PRECISION +#undef UNITY_DOUBLE_TYPE +#undef UNITY_DOUBLE_VERBOSE + +#ifdef UNITY_INCLUDE_DOUBLE +#undef UNITY_INCLUDE_DOUBLE +#endif + +#else + +/* Double Floating Point Support */ +#ifndef UNITY_DOUBLE_PRECISION +#define UNITY_DOUBLE_PRECISION (1e-12f) +#endif +#ifndef UNITY_DOUBLE_TYPE +#define UNITY_DOUBLE_TYPE double +#endif +typedef UNITY_DOUBLE_TYPE _UD; + +#endif + +#ifdef UNITY_DOUBLE_VERBOSE +#ifndef UNITY_FLOAT_VERBOSE +#define UNITY_FLOAT_VERBOSE +#endif +#endif + +/*------------------------------------------------------- + * Output Method: stdout (DEFAULT) + *-------------------------------------------------------*/ +#ifndef UNITY_OUTPUT_CHAR +/* Default to using putchar, which is defined in stdio.h */ +#include <stdio.h> +#define UNITY_OUTPUT_CHAR(a) (void)putchar(a) +#else + /* If defined as something else, make sure we declare it here so it's ready for use */ + #ifndef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION +extern void UNITY_OUTPUT_CHAR(int); + #endif +#endif + +#ifndef UNITY_OUTPUT_FLUSH +/* Default to using fflush, which is defined in stdio.h */ +#include <stdio.h> +#define UNITY_OUTPUT_FLUSH (void)fflush(stdout) +#else + /* If defined as something else, make sure we declare it here so it's ready for use */ + #ifndef UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION +extern void UNITY_OUTPUT_FLUSH(void); + #endif +#endif + +#ifndef UNITY_OUTPUT_FLUSH +#define UNITY_FLUSH_CALL() +#else +#define UNITY_FLUSH_CALL() UNITY_OUTPUT_FLUSH +#endif + +#ifndef UNITY_PRINT_EOL +#define UNITY_PRINT_EOL() UNITY_OUTPUT_CHAR('\n') +#endif + +#ifndef UNITY_OUTPUT_START +#define UNITY_OUTPUT_START() +#endif + +#ifndef UNITY_OUTPUT_COMPLETE +#define UNITY_OUTPUT_COMPLETE() +#endif + +/*------------------------------------------------------- + * Footprint + *-------------------------------------------------------*/ + +#ifndef UNITY_LINE_TYPE +#define UNITY_LINE_TYPE _U_UINT +#endif + +#ifndef UNITY_COUNTER_TYPE +#define UNITY_COUNTER_TYPE _U_UINT +#endif + +/*------------------------------------------------------- + * Language Features Available + *-------------------------------------------------------*/ +#if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA) +# ifdef __GNUC__ /* includes clang */ +# if !(defined(__WIN32__) && defined(__clang__)) +# define UNITY_WEAK_ATTRIBUTE __attribute__((weak)) +# endif +# endif +#endif + +#ifdef UNITY_NO_WEAK +# undef UNITY_WEAK_ATTRIBUTE +# undef UNITY_WEAK_PRAGMA +#endif + + +/*------------------------------------------------------- + * Internal Structs Needed + *-------------------------------------------------------*/ + +typedef void (*UnityTestFunction)(void); + +#define UNITY_DISPLAY_RANGE_INT (0x10) +#define UNITY_DISPLAY_RANGE_UINT (0x20) +#define UNITY_DISPLAY_RANGE_HEX (0x40) +#define UNITY_DISPLAY_RANGE_AUTO (0x80) + +typedef enum +{ +#if (UNITY_INT_WIDTH == 16) + UNITY_DISPLAY_STYLE_INT = 2 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, +#elif (UNITY_INT_WIDTH == 32) + UNITY_DISPLAY_STYLE_INT = 4 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, +#elif (UNITY_INT_WIDTH == 64) + UNITY_DISPLAY_STYLE_INT = 8 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, +#endif + UNITY_DISPLAY_STYLE_INT8 = 1 + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT16 = 2 + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT32 = 4 + UNITY_DISPLAY_RANGE_INT, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_INT64 = 8 + UNITY_DISPLAY_RANGE_INT, +#endif + +#if (UNITY_INT_WIDTH == 16) + UNITY_DISPLAY_STYLE_UINT = 2 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, +#elif (UNITY_INT_WIDTH == 32) + UNITY_DISPLAY_STYLE_UINT = 4 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, +#elif (UNITY_INT_WIDTH == 64) + UNITY_DISPLAY_STYLE_UINT = 8 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, +#endif + UNITY_DISPLAY_STYLE_UINT8 = 1 + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT16 = 2 + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT32 = 4 + UNITY_DISPLAY_RANGE_UINT, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_UINT64 = 8 + UNITY_DISPLAY_RANGE_UINT, +#endif + UNITY_DISPLAY_STYLE_HEX8 = 1 + UNITY_DISPLAY_RANGE_HEX, + UNITY_DISPLAY_STYLE_HEX16 = 2 + UNITY_DISPLAY_RANGE_HEX, + UNITY_DISPLAY_STYLE_HEX32 = 4 + UNITY_DISPLAY_RANGE_HEX, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_HEX64 = 8 + UNITY_DISPLAY_RANGE_HEX, +#endif + UNITY_DISPLAY_STYLE_UNKNOWN +} UNITY_DISPLAY_STYLE_T; + +#ifndef UNITY_EXCLUDE_FLOAT +typedef enum _UNITY_FLOAT_TRAIT_T +{ + UNITY_FLOAT_IS_NOT_INF = 0, + UNITY_FLOAT_IS_INF, + UNITY_FLOAT_IS_NOT_NEG_INF, + UNITY_FLOAT_IS_NEG_INF, + UNITY_FLOAT_IS_NOT_NAN, + UNITY_FLOAT_IS_NAN, + UNITY_FLOAT_IS_NOT_DET, + UNITY_FLOAT_IS_DET, + UNITY_FLOAT_INVALID_TRAIT +} UNITY_FLOAT_TRAIT_T; +#endif + +struct _Unity +{ + const char* TestFile; + const char* CurrentTestName; +#ifndef UNITY_EXCLUDE_DETAILS + const char* CurrentDetail1; + const char* CurrentDetail2; +#endif + UNITY_LINE_TYPE CurrentTestLineNumber; + UNITY_COUNTER_TYPE NumberOfTests; + UNITY_COUNTER_TYPE TestFailures; + UNITY_COUNTER_TYPE TestIgnores; + UNITY_COUNTER_TYPE CurrentTestFailed; + UNITY_COUNTER_TYPE CurrentTestIgnored; + jmp_buf AbortFrame; +}; + +extern struct _Unity Unity; + +/*------------------------------------------------------- + * Test Suite Management + *-------------------------------------------------------*/ + +void UnityBegin(const char* filename); +int UnityEnd(void); +void UnityConcludeTest(void); +void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum); + +/*------------------------------------------------------- + * Details Support + *-------------------------------------------------------*/ + +#ifdef UNITY_EXCLUDE_DETAILS +#define UNITY_CLR_DETAILS() +#define UNITY_SET_DETAIL(d1) +#define UNITY_SET_DETAILS(d1,d2) +#else +#define UNITY_CLR_DETAILS() { Unity.CurrentDetail1 = 0; Unity.CurrentDetail2 = 0; } +#define UNITY_SET_DETAIL(d1) { Unity.CurrentDetail1 = d1; Unity.CurrentDetail2 = 0; } +#define UNITY_SET_DETAILS(d1,d2) { Unity.CurrentDetail1 = d1; Unity.CurrentDetail2 = d2; } + +#ifndef UNITY_DETAIL1_NAME +#define UNITY_DETAIL1_NAME "Function" +#endif + +#ifndef UNITY_DETAIL2_NAME +#define UNITY_DETAIL2_NAME "Argument" +#endif +#endif + +/*------------------------------------------------------- + * Test Output + *-------------------------------------------------------*/ + +void UnityPrint(const char* string); +void UnityPrintMask(const _U_UINT mask, const _U_UINT number); +void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style); +void UnityPrintNumber(const _U_SINT number); +void UnityPrintNumberUnsigned(const _U_UINT number); +void UnityPrintNumberHex(const _U_UINT number, const char nibbles); + +#ifdef UNITY_FLOAT_VERBOSE +void UnityPrintFloat(const _UF number); +#endif + +/*------------------------------------------------------- + * Test Assertion Fuctions + *------------------------------------------------------- + * Use the macros below this section instead of calling + * these directly. The macros have a consistent naming + * convention and will pull in file and line information + * for you. */ + +void UnityAssertEqualNumber(const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertBits(const _U_SINT mask, + const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualString(const char* expected, + const char* actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualStringLen(const char* expected, + const char* actual, + const _UU32 length, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualStringArray( const char** expected, + const char** actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const _UU32 length, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertNumbersWithin(const _U_UINT delta, + const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityFail(const char* message, const UNITY_LINE_TYPE line); + +void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); + +#ifndef UNITY_EXCLUDE_FLOAT +void UnityAssertFloatsWithin(const _UF delta, + const _UF expected, + const _UF actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const _UF* expected, + UNITY_PTR_ATTRIBUTE const _UF* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertFloatSpecial(const _UF actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); +#endif + +#ifndef UNITY_EXCLUDE_DOUBLE +void UnityAssertDoublesWithin(const _UD delta, + const _UD expected, + const _UD actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const _UD* expected, + UNITY_PTR_ATTRIBUTE const _UD* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertDoubleSpecial(const _UD actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); +#endif + +/*------------------------------------------------------- + * Error Strings We Might Need + *-------------------------------------------------------*/ + +extern const char UnityStrErrFloat[]; +extern const char UnityStrErrDouble[]; +extern const char UnityStrErr64[]; + +/*------------------------------------------------------- + * Test Running Macros + *-------------------------------------------------------*/ + +#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) + +#define TEST_ABORT() {longjmp(Unity.AbortFrame, 1);} + +/* This tricky series of macros gives us an optional line argument to treat it as RUN_TEST(func, num=__LINE__) */ +#ifndef RUN_TEST +#ifdef __STDC_VERSION__ +#if __STDC_VERSION__ >= 199901L +#define RUN_TEST(...) UnityDefaultTestRun(RUN_TEST_FIRST(__VA_ARGS__), RUN_TEST_SECOND(__VA_ARGS__)) +#define RUN_TEST_FIRST(...) RUN_TEST_FIRST_HELPER(__VA_ARGS__, throwaway) +#define RUN_TEST_FIRST_HELPER(first, ...) (first), #first +#define RUN_TEST_SECOND(...) RUN_TEST_SECOND_HELPER(__VA_ARGS__, __LINE__, throwaway) +#define RUN_TEST_SECOND_HELPER(first, second, ...) (second) +#endif +#endif +#endif + +/* If we can't do the tricky version, we'll just have to require them to always include the line number */ +#ifndef RUN_TEST +#ifdef CMOCK +#define RUN_TEST(func, num) UnityDefaultTestRun(func, #func, num) +#else +#define RUN_TEST(func) UnityDefaultTestRun(func, #func, __LINE__) +#endif +#endif + +#define TEST_LINE_NUM (Unity.CurrentTestLineNumber) +#define TEST_IS_IGNORED (Unity.CurrentTestIgnored) +#define UNITY_NEW_TEST(a) \ + Unity.CurrentTestName = (a); \ + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)(__LINE__); \ + Unity.NumberOfTests++; + +#ifndef UNITY_BEGIN +#define UNITY_BEGIN() UnityBegin(__FILE__) +#endif + +#ifndef UNITY_END +#define UNITY_END() UnityEnd() +#endif + +#define UNITY_UNUSED(x) (void)(sizeof(x)) + +/*------------------------------------------------------- + * Basic Fail and Ignore + *-------------------------------------------------------*/ + +#define UNITY_TEST_FAIL(line, message) UnityFail( (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)(line)) + +/*------------------------------------------------------- + * Test Asserts + *-------------------------------------------------------*/ + +#define UNITY_TEST_ASSERT(condition, line, message) if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));} +#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)(line), (message)) + +#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UU8 )(expected), (_U_SINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UU16)(expected), (_U_SINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UU32)(expected), (_U_SINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((_U_SINT)(mask), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line)) + +#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU8 )(delta), (_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU16)(delta), (_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU32)(delta), (_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU8 )(delta), (_U_SINT)(_U_UINT)(_UU8 )(expected), (_U_SINT)(_U_UINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU16)(delta), (_U_SINT)(_U_UINT)(_UU16)(expected), (_U_SINT)(_U_UINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU32)(delta), (_U_SINT)(_U_UINT)(_UU32)(expected), (_U_SINT)(_U_UINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU8 )(delta), (_U_SINT)(_U_UINT)(_UU8 )(expected), (_U_SINT)(_U_UINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU16)(delta), (_U_SINT)(_U_UINT)(_UU16)(expected), (_U_SINT)(_U_UINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_UU32)(delta), (_U_SINT)(_U_UINT)(_UU32)(expected), (_U_SINT)(_U_UINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) + +#define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UP)(expected), (_U_SINT)(_UP)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER) +#define UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, line, message) UnityAssertEqualString((const char*)(expected), (const char*)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len, line, message) UnityAssertEqualStringLen((const char*)(expected), (const char*)(actual), (_UU32)(len), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(len), 1, (message), (UNITY_LINE_TYPE)(line)) + +#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(_UP*)(expected), (UNITY_INTERNAL_PTR)(_UP*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER) +#define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualStringArray((const char**)(expected), (const char**)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(len), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line)) + +#ifdef UNITY_SUPPORT_64 +#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#else +#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#endif + +#ifdef UNITY_EXCLUDE_FLOAT +#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#else +#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UnityAssertFloatsWithin((_UF)(delta), (_UF)(expected), (_UF)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((_UF)(expected) * (_UF)UNITY_FLOAT_PRECISION, (_UF)(expected), (_UF)(actual), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualFloatArray((_UF*)(expected), (_UF*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) +#endif + +#ifdef UNITY_EXCLUDE_DOUBLE +#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#else +#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UnityAssertDoublesWithin((_UD)(delta), (_UD)(expected), (_UD)(actual), (message), (UNITY_LINE_TYPE)line) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((_UD)(expected) * (_UD)UNITY_DOUBLE_PRECISION, (_UD)expected, (_UD)actual, (UNITY_LINE_TYPE)(line), message) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray((_UD*)(expected), (_UD*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) +#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) +#endif + +/* + * SA_PATCH: Output results using easy to parse tags. + * These tags are used when sending out verbose Unity output ("-v"). + * They wrap each of the important data pieces, and allow parsing of the results by an + * external tool. + * The tags are always printed - this isn't configurable. + */ +#define UNITY_RESULTS_TAGS_TEST_START "<***UnityTest***>" +#define UNITY_RESULTS_TAGS_TEST_END "</***UnityTest***>" + +#define UNITY_RESULTS_TAGS_RESULT_START "<***UnityResult***>" +#define UNITY_RESULTS_TAGS_RESULT_END "</***UnityResult***>" + +#define UNITY_RESULTS_TAGS_IGNORE_START "<***UnityIgnoredTest***>" +#define UNITY_RESULTS_TAGS_IGNORE_END "</***UnityIgnoredTest***>" + +/* End of UNITY_INTERNALS_H */ +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_cmd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_cmd.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,61 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + CEXCEPTION_T e; \ + Try { \ + setUp(); \ + TestFunc(); \ + } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "CException.h" +#include "funky.h" +#include "stanky.h" +#include <setjmp.h> + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); +extern void test_TheThirdThingToTest(void); +extern void test_TheFourthThingToTest(void); + + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/testsample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + RUN_TEST(test_TheThirdThingToTest, 53); + RUN_TEST(test_TheFourthThingToTest, 58); + + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_def.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_def.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "funky.h" +#include "stanky.h" +#include <setjmp.h> + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); +extern void test_TheThirdThingToTest(void); +extern void test_TheFourthThingToTest(void); + + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/testsample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + RUN_TEST(test_TheThirdThingToTest, 53); + RUN_TEST(test_TheFourthThingToTest, 58); + + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_head1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_head1.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,55 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "testsample_head1.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); +extern void test_TheThirdThingToTest(void); +extern void test_TheFourthThingToTest(void); + + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/testsample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + RUN_TEST(test_TheThirdThingToTest, 53); + RUN_TEST(test_TheFourthThingToTest, 58); + + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_head1.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_head1.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,15 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ +#ifndef _TESTSAMPLE_HEAD1_H +#define _TESTSAMPLE_HEAD1_H + +#include "unity.h" +#include "funky.h" +#include "stanky.h" +#include <setjmp.h> + +void test_TheFirstThingToTest(void); +void test_TheSecondThingToTest(void); +void test_TheThirdThingToTest(void); +void test_TheFourthThingToTest(void); +#endif +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_cmd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_cmd.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,80 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + CMock_Init(); \ + UNITY_CLR_DETAILS(); \ + if (TEST_PROTECT()) \ + { \ + CEXCEPTION_T e; \ + Try { \ + setUp(); \ + TestFunc(); \ + } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + CMock_Verify(); \ + } \ + CMock_Destroy(); \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include "cmock.h" +#include <setjmp.h> +#include <stdio.h> +#include "CException.h" +#include "funky.h" +#include <setjmp.h> +#include "Mockstanky.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); + + +/*=======Mock Management=====*/ +static void CMock_Init(void) +{ + Mockstanky_Init(); +} +static void CMock_Verify(void) +{ + Mockstanky_Verify(); +} +static void CMock_Destroy(void) +{ + Mockstanky_Destroy(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + CMock_Verify(); + CMock_Destroy(); + tearDown(); + CMock_Init(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/mocksample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + + CMock_Guts_MemFreeFinal(); + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_def.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_def.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,76 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + CMock_Init(); \ + UNITY_CLR_DETAILS(); \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + CMock_Verify(); \ + } \ + CMock_Destroy(); \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include "cmock.h" +#include <setjmp.h> +#include <stdio.h> +#include "funky.h" +#include <setjmp.h> +#include "Mockstanky.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); + + +/*=======Mock Management=====*/ +static void CMock_Init(void) +{ + Mockstanky_Init(); +} +static void CMock_Verify(void) +{ + Mockstanky_Verify(); +} +static void CMock_Destroy(void) +{ + Mockstanky_Destroy(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + CMock_Verify(); + CMock_Destroy(); + tearDown(); + CMock_Init(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/mocksample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + + CMock_Guts_MemFreeFinal(); + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_head1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_head1.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,75 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + CMock_Init(); \ + UNITY_CLR_DETAILS(); \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + CMock_Verify(); \ + } \ + CMock_Destroy(); \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include "cmock.h" +#include <setjmp.h> +#include <stdio.h> +#include "testsample_mock_head1.h" +#include "Mockstanky.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); + + +/*=======Mock Management=====*/ +static void CMock_Init(void) +{ + Mockstanky_Init(); +} +static void CMock_Verify(void) +{ + Mockstanky_Verify(); +} +static void CMock_Destroy(void) +{ + Mockstanky_Destroy(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + CMock_Verify(); + CMock_Destroy(); + tearDown(); + CMock_Init(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/mocksample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + + CMock_Guts_MemFreeFinal(); + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_head1.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_head1.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,13 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ +#ifndef _TESTSAMPLE_MOCK_HEAD1_H +#define _TESTSAMPLE_MOCK_HEAD1_H + +#include "unity.h" +#include "cmock.h" +#include "funky.h" +#include <setjmp.h> + +void test_TheFirstThingToTest(void); +void test_TheSecondThingToTest(void); +#endif +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_new1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_new1.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,89 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + CMock_Init(); \ + UNITY_CLR_DETAILS(); \ + if (TEST_PROTECT()) \ + { \ + CEXCEPTION_T e; \ + Try { \ + setUp(); \ + TestFunc(); \ + } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + CMock_Verify(); \ + } \ + CMock_Destroy(); \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include "cmock.h" +#include <setjmp.h> +#include <stdio.h> +#include "CException.h" +#include "one.h" +#include "two.h" +#include "funky.h" +#include <setjmp.h> +#include "Mockstanky.h" + +int GlobalExpectCount; +int GlobalVerifyOrder; +char* GlobalOrderError; + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); + + +/*=======Mock Management=====*/ +static void CMock_Init(void) +{ + GlobalExpectCount = 0; + GlobalVerifyOrder = 0; + GlobalOrderError = NULL; + Mockstanky_Init(); +} +static void CMock_Verify(void) +{ + Mockstanky_Verify(); +} +static void CMock_Destroy(void) +{ + Mockstanky_Destroy(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + CMock_Verify(); + CMock_Destroy(); + tearDown(); + CMock_Init(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/mocksample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + + CMock_Guts_MemFreeFinal(); + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_new2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_new2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,89 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + CMock_Init(); \ + UNITY_CLR_DETAILS(); \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + CMock_Verify(); \ + } \ + CMock_Destroy(); \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include "cmock.h" +#include <setjmp.h> +#include <stdio.h> +#include "funky.h" +#include <setjmp.h> +#include "Mockstanky.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); + + +/*=======Mock Management=====*/ +static void CMock_Init(void) +{ + Mockstanky_Init(); +} +static void CMock_Verify(void) +{ + Mockstanky_Verify(); +} +static void CMock_Destroy(void) +{ + Mockstanky_Destroy(); +} + +/*=======Suite Setup=====*/ +static int suite_setup(void) +{ +a_custom_setup(); +} + +/*=======Suite Teardown=====*/ +static int suite_teardown(int num_failures) +{ +a_custom_teardown(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + CMock_Verify(); + CMock_Destroy(); + tearDown(); + CMock_Init(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + suite_setup(); + UnityBegin("testdata/mocksample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + + CMock_Guts_MemFreeFinal(); + return suite_teardown(UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_param.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_param.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,77 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST_NO_ARGS +#define RUN_TEST(TestFunc, TestLineNum, ...) \ +{ \ + Unity.CurrentTestName = #TestFunc "(" #__VA_ARGS__ ")"; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + CMock_Init(); \ + UNITY_CLR_DETAILS(); \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(__VA_ARGS__); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + CMock_Verify(); \ + } \ + CMock_Destroy(); \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include "cmock.h" +#include <setjmp.h> +#include <stdio.h> +#include "funky.h" +#include <setjmp.h> +#include "Mockstanky.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); + + +/*=======Mock Management=====*/ +static void CMock_Init(void) +{ + Mockstanky_Init(); +} +static void CMock_Verify(void) +{ + Mockstanky_Verify(); +} +static void CMock_Destroy(void) +{ + Mockstanky_Destroy(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + CMock_Verify(); + CMock_Destroy(); + tearDown(); + CMock_Init(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/mocksample.c"); + RUN_TEST(test_TheFirstThingToTest, 21, RUN_TEST_NO_ARGS); + RUN_TEST(test_TheSecondThingToTest, 43, RUN_TEST_NO_ARGS); + + CMock_Guts_MemFreeFinal(); + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_run1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_run1.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,89 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + CMock_Init(); \ + UNITY_CLR_DETAILS(); \ + if (TEST_PROTECT()) \ + { \ + CEXCEPTION_T e; \ + Try { \ + setUp(); \ + TestFunc(); \ + } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + CMock_Verify(); \ + } \ + CMock_Destroy(); \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include "cmock.h" +#include <setjmp.h> +#include <stdio.h> +#include "CException.h" +#include "one.h" +#include "two.h" +#include "funky.h" +#include <setjmp.h> +#include "Mockstanky.h" + +int GlobalExpectCount; +int GlobalVerifyOrder; +char* GlobalOrderError; + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); + + +/*=======Mock Management=====*/ +static void CMock_Init(void) +{ + GlobalExpectCount = 0; + GlobalVerifyOrder = 0; + GlobalOrderError = NULL; + Mockstanky_Init(); +} +static void CMock_Verify(void) +{ + Mockstanky_Verify(); +} +static void CMock_Destroy(void) +{ + Mockstanky_Destroy(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + CMock_Verify(); + CMock_Destroy(); + tearDown(); + CMock_Init(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/mocksample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + + CMock_Guts_MemFreeFinal(); + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_run2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_run2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,89 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + CMock_Init(); \ + UNITY_CLR_DETAILS(); \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + CMock_Verify(); \ + } \ + CMock_Destroy(); \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include "cmock.h" +#include <setjmp.h> +#include <stdio.h> +#include "funky.h" +#include <setjmp.h> +#include "Mockstanky.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); + + +/*=======Mock Management=====*/ +static void CMock_Init(void) +{ + Mockstanky_Init(); +} +static void CMock_Verify(void) +{ + Mockstanky_Verify(); +} +static void CMock_Destroy(void) +{ + Mockstanky_Destroy(); +} + +/*=======Suite Setup=====*/ +static int suite_setup(void) +{ +a_custom_setup(); +} + +/*=======Suite Teardown=====*/ +static int suite_teardown(int num_failures) +{ +a_custom_teardown(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + CMock_Verify(); + CMock_Destroy(); + tearDown(); + CMock_Init(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + suite_setup(); + UnityBegin("testdata/mocksample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + + CMock_Guts_MemFreeFinal(); + return suite_teardown(UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_yaml.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_mock_yaml.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,90 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + CMock_Init(); \ + UNITY_CLR_DETAILS(); \ + if (TEST_PROTECT()) \ + { \ + CEXCEPTION_T e; \ + Try { \ + setUp(); \ + TestFunc(); \ + } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + CMock_Verify(); \ + } \ + CMock_Destroy(); \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include "cmock.h" +#include <setjmp.h> +#include <stdio.h> +#include "CException.h" +#include "two.h" +#include "three.h" +#include <four.h> +#include "funky.h" +#include <setjmp.h> +#include "Mockstanky.h" + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); + + +/*=======Mock Management=====*/ +static void CMock_Init(void) +{ + Mockstanky_Init(); +} +static void CMock_Verify(void) +{ + Mockstanky_Verify(); +} +static void CMock_Destroy(void) +{ + Mockstanky_Destroy(); +} + +/*=======Suite Setup=====*/ +static int suite_setup(void) +{ +a_yaml_setup(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + CMock_Verify(); + CMock_Destroy(); + tearDown(); + CMock_Init(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + suite_setup(); + UnityBegin("testdata/mocksample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + + CMock_Guts_MemFreeFinal(); + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_new1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_new1.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,67 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + CEXCEPTION_T e; \ + Try { \ + setUp(); \ + TestFunc(); \ + } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "CException.h" +#include "one.h" +#include "two.h" +#include "funky.h" +#include "stanky.h" +#include <setjmp.h> + +int GlobalExpectCount; +int GlobalVerifyOrder; +char* GlobalOrderError; + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); +extern void test_TheThirdThingToTest(void); +extern void test_TheFourthThingToTest(void); + + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/testsample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + RUN_TEST(test_TheThirdThingToTest, 53); + RUN_TEST(test_TheFourthThingToTest, 58); + + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_new2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_new2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,70 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "funky.h" +#include "stanky.h" +#include <setjmp.h> + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); +extern void test_TheThirdThingToTest(void); +extern void test_TheFourthThingToTest(void); + + +/*=======Suite Setup=====*/ +static int suite_setup(void) +{ +a_custom_setup(); +} + +/*=======Suite Teardown=====*/ +static int suite_teardown(int num_failures) +{ +a_custom_teardown(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + suite_setup(); + UnityBegin("testdata/testsample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + RUN_TEST(test_TheThirdThingToTest, 53); + RUN_TEST(test_TheFourthThingToTest, 58); + + return suite_teardown(UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_param.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_param.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,58 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST_NO_ARGS +#define RUN_TEST(TestFunc, TestLineNum, ...) \ +{ \ + Unity.CurrentTestName = #TestFunc "(" #__VA_ARGS__ ")"; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(__VA_ARGS__); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "funky.h" +#include "stanky.h" +#include <setjmp.h> + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); +extern void test_TheThirdThingToTest(void); +extern void test_TheFourthThingToTest(void); + + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/testsample.c"); + RUN_TEST(test_TheFirstThingToTest, 21, RUN_TEST_NO_ARGS); + RUN_TEST(test_TheSecondThingToTest, 43, RUN_TEST_NO_ARGS); + RUN_TEST(test_TheThirdThingToTest, 53, RUN_TEST_NO_ARGS); + RUN_TEST(test_TheFourthThingToTest, 58, RUN_TEST_NO_ARGS); + + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_run1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_run1.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,67 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + CEXCEPTION_T e; \ + Try { \ + setUp(); \ + TestFunc(); \ + } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "CException.h" +#include "one.h" +#include "two.h" +#include "funky.h" +#include "stanky.h" +#include <setjmp.h> + +int GlobalExpectCount; +int GlobalVerifyOrder; +char* GlobalOrderError; + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); +extern void test_TheThirdThingToTest(void); +extern void test_TheFourthThingToTest(void); + + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + UnityBegin("testdata/testsample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + RUN_TEST(test_TheThirdThingToTest, 53); + RUN_TEST(test_TheFourthThingToTest, 58); + + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_run2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_run2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,70 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + setUp(); \ + TestFunc(); \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "funky.h" +#include "stanky.h" +#include <setjmp.h> + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); +extern void test_TheThirdThingToTest(void); +extern void test_TheFourthThingToTest(void); + + +/*=======Suite Setup=====*/ +static int suite_setup(void) +{ +a_custom_setup(); +} + +/*=======Suite Teardown=====*/ +static int suite_teardown(int num_failures) +{ +a_custom_teardown(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + suite_setup(); + UnityBegin("testdata/testsample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + RUN_TEST(test_TheThirdThingToTest, 53); + RUN_TEST(test_TheFourthThingToTest, 58); + + return suite_teardown(UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_yaml.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/expectdata/testsample_yaml.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,71 @@ +/* AUTOGENERATED FILE. DO NOT EDIT. */ + +/*=======Test Runner Used To Run Each Test Below=====*/ +#define RUN_TEST(TestFunc, TestLineNum) \ +{ \ + Unity.CurrentTestName = #TestFunc; \ + Unity.CurrentTestLineNumber = TestLineNum; \ + Unity.NumberOfTests++; \ + if (TEST_PROTECT()) \ + { \ + CEXCEPTION_T e; \ + Try { \ + setUp(); \ + TestFunc(); \ + } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); } \ + } \ + if (TEST_PROTECT() && !TEST_IS_IGNORED) \ + { \ + tearDown(); \ + } \ + UnityConcludeTest(); \ +} + +/*=======Automagically Detected Files To Include=====*/ +#include "unity.h" +#include <setjmp.h> +#include <stdio.h> +#include "CException.h" +#include "two.h" +#include "three.h" +#include <four.h> +#include "funky.h" +#include "stanky.h" +#include <setjmp.h> + +/*=======External Functions This Runner Calls=====*/ +extern void setUp(void); +extern void tearDown(void); +extern void test_TheFirstThingToTest(void); +extern void test_TheSecondThingToTest(void); +extern void test_TheThirdThingToTest(void); +extern void test_TheFourthThingToTest(void); + + +/*=======Suite Setup=====*/ +static int suite_setup(void) +{ +a_yaml_setup(); +} + +/*=======Test Reset Option=====*/ +void resetTest(void); +void resetTest(void) +{ + tearDown(); + setUp(); +} + + +/*=======MAIN=====*/ +int main(void) +{ + suite_setup(); + UnityBegin("testdata/testsample.c"); + RUN_TEST(test_TheFirstThingToTest, 21); + RUN_TEST(test_TheSecondThingToTest, 43); + RUN_TEST(test_TheThirdThingToTest, 53); + RUN_TEST(test_TheFourthThingToTest, 58); + + return (UnityEnd()); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/rakefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/rakefile Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,60 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +UNITY_ROOT = File.expand_path(File.dirname(__FILE__)) + '/' + +require 'rake' +require 'rake/clean' +require UNITY_ROOT + 'rakefile_helper' + +TEMP_DIRS = [ + File.join(UNITY_ROOT, 'build') +] + +TEMP_DIRS.each do |dir| + directory(dir) + CLOBBER.include(dir) +end + +task :prepare_for_tests => TEMP_DIRS + +include RakefileHelpers + +# Load proper GCC as defult configuration +DEFAULT_CONFIG_FILE = 'gcc_auto_stdint.yml' +configure_toolchain(DEFAULT_CONFIG_FILE) + +desc "Test unity with its own unit tests" +task :unit => [:prepare_for_tests] do + run_tests get_unit_test_files +end + +desc "Test unity's helper scripts" +task :scripts => [:prepare_for_tests] do + Dir['tests/test_*.rb'].each do |scriptfile| + require "./"+scriptfile + end +end + +desc "Generate test summary" +task :summary do + report_summary +end + +desc "Build and test Unity" +task :all => [:clean, :prepare_for_tests, :scripts, :unit, :summary] +task :default => [:clobber, :all] +task :ci => [:no_color, :default] +task :cruise => [:no_color, :default] + +desc "Load configuration" +task :config, :config_file do |t, args| + configure_toolchain(args[:config_file]) +end + +task :no_color do + $colour_output = false +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/rakefile_helper.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/rakefile_helper.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,255 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require 'yaml' +require 'fileutils' +require UNITY_ROOT + '../auto/unity_test_summary' +require UNITY_ROOT + '../auto/generate_test_runner' +require UNITY_ROOT + '../auto/colour_reporter' + +module RakefileHelpers + + C_EXTENSION = '.c' + + def load_configuration(config_file) + unless ($configured) + $cfg_file = "targets/#{config_file}" unless (config_file =~ /[\\|\/]/) + $cfg = YAML.load(File.read($cfg_file)) + $colour_output = false unless $cfg['colour'] + $configured = true if (config_file != DEFAULT_CONFIG_FILE) + end + end + + def configure_clean + CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil? + end + + def configure_toolchain(config_file=DEFAULT_CONFIG_FILE) + config_file += '.yml' unless config_file =~ /\.yml$/ + config_file = config_file unless config_file =~ /[\\|\/]/ + load_configuration(config_file) + configure_clean + end + + def get_unit_test_files + path = $cfg['compiler']['unit_tests_path'] + 'test*' + C_EXTENSION + path.gsub!(/\\/, '/') + FileList.new(path) + end + + def get_local_include_dirs + include_dirs = $cfg['compiler']['includes']['items'].dup + include_dirs.delete_if {|dir| dir.is_a?(Array)} + return include_dirs + end + + def extract_headers(filename) + includes = [] + lines = File.readlines(filename) + lines.each do |line| + m = line.match(/^\s*#include\s+\"\s*(.+\.[hH])\s*\"/) + if not m.nil? + includes << m[1] + end + end + return includes + end + + def find_source_file(header, paths) + paths.each do |dir| + src_file = dir + header.ext(C_EXTENSION) + if (File.exists?(src_file)) + return src_file + end + end + return nil + end + + def tackit(strings) + if strings.is_a?(Array) + result = "\"#{strings.join}\"" + else + result = strings + end + return result + end + + def squash(prefix, items) + result = '' + items.each { |item| result += " #{prefix}#{tackit(item)}" } + return result + end + + def should(behave, &block) + if block + puts "Should " + behave + yield block + else + puts "UNIMPLEMENTED CASE: Should #{behave}" + end + end + + def build_compiler_fields + command = tackit($cfg['compiler']['path']) + if $cfg['compiler']['defines']['items'].nil? + defines = '' + else + defines = squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=putcharSpy']) + end + options = squash('', $cfg['compiler']['options']) + includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items']) + includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + return {:command => command, :defines => defines, :options => options, :includes => includes} + end + + def compile(file, defines=[]) + compiler = build_compiler_fields + cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " + + "#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}" + obj_file = "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}" + execute(cmd_str + obj_file) + return obj_file + end + + def build_linker_fields + command = tackit($cfg['linker']['path']) + if $cfg['linker']['options'].nil? + options = '' + else + options = squash('', $cfg['linker']['options']) + end + if ($cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?) + includes = '' + else + includes = squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items']) + end + includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR) + return {:command => command, :options => options, :includes => includes} + end + + def link_it(exe_name, obj_list) + linker = build_linker_fields + cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " + + (obj_list.map{|obj|"#{$cfg['linker']['object_files']['path']}#{obj} "}).join + + $cfg['linker']['bin_files']['prefix'] + ' ' + + $cfg['linker']['bin_files']['destination'] + + exe_name + $cfg['linker']['bin_files']['extension'] + execute(cmd_str) + end + + def build_simulator_fields + return nil if $cfg['simulator'].nil? + if $cfg['simulator']['path'].nil? + command = '' + else + command = (tackit($cfg['simulator']['path']) + ' ') + end + if $cfg['simulator']['pre_support'].nil? + pre_support = '' + else + pre_support = squash('', $cfg['simulator']['pre_support']) + end + if $cfg['simulator']['post_support'].nil? + post_support = '' + else + post_support = squash('', $cfg['simulator']['post_support']) + end + return {:command => command, :pre_support => pre_support, :post_support => post_support} + end + + def execute(command_string, verbose=true) + report command_string + output = `#{command_string}`.chomp + report(output) if (verbose && !output.nil? && (output.length > 0)) + if $?.exitstatus != 0 + raise "Command failed. (Returned #{$?.exitstatus})" + end + return output + end + + def report_summary + summary = UnityTestSummary.new + summary.set_root_path(UNITY_ROOT) + results_glob = "#{$cfg['compiler']['build_path']}*.test*" + results_glob.gsub!(/\\/, '/') + results = Dir[results_glob] + summary.set_targets(results) + report summary.run + end + + def run_tests(test_files) + report 'Running Unity system tests...' + + # Tack on TEST define for compiling unit tests + load_configuration($cfg_file) + test_defines = ['TEST'] + $cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil? + $cfg['compiler']['defines']['items'] << 'TEST' + + include_dirs = get_local_include_dirs + + # Build and execute each unit test + test_files.each do |test| + obj_list = [] + + if !$cfg['compiler']['aux_sources'].nil? + $cfg['compiler']['aux_sources'].each do |aux| + obj_list << compile(aux, test_defines) + end + end + + # Detect dependencies and build required modules + extract_headers(test).each do |header| + # Compile corresponding source file if it exists + src_file = find_source_file(header, include_dirs) + if !src_file.nil? + obj_list << compile(src_file, test_defines) + end + end + + # Build the test runner (generate if configured to do so) + test_base = File.basename(test, C_EXTENSION) + + runner_name = test_base + '_Runner.c' + runner_path = '' + + if $cfg['compiler']['runner_path'].nil? + runner_path = $cfg['compiler']['build_path'] + runner_name + else + runner_path = $cfg['compiler']['runner_path'] + runner_name + end + + options = $cfg[:unity] + options[:use_param_tests] = (test =~ /parameterized/) ? true : false + UnityTestRunnerGenerator.new(options).run(test, runner_path) + obj_list << compile(runner_path, test_defines) + + # Build the test module + obj_list << compile(test, test_defines) + + # Link the test executable + link_it(test_base, obj_list) + + # Execute unit test and generate results file + simulator = build_simulator_fields + executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension'] + if simulator.nil? + cmd_str = executable + else + cmd_str = "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}" + end + output = execute(cmd_str) + test_results = $cfg['compiler']['build_path'] + test_base + if output.match(/OK$/m).nil? + test_results += '.testfail' + else + test_results += '.testpass' + end + File.open(test_results, 'w') { |f| f.print output } + + end + end +end
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/testdata/mocksample.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/testdata/mocksample.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,51 @@ +// This is just a sample test file to be used to test the generator script +#ifndef TEST_SAMPLE_H +#define TEST_SAMPLE_H + +#include <setjmp.h> +#include "unity.h" +#include "funky.h" +#include "Mockstanky.h" + +void setUp(void) +{ + CustomSetupStuff(); +} + +void tearDown(void) +{ + CustomTeardownStuff +} + +//Yup, nice comment +void test_TheFirstThingToTest(void) +{ + TEST_ASSERT(1); + + TEST_ASSERT_TRUE(1); +} + +/* +void test_ShouldBeIgnored(void) +{ + DoesStuff(); +} +*/ + +//void test_ShouldAlsoNotBeTested(void) +//{ +// Call_An_Expect(); +// +// CallAFunction(); +// test_CallAFunctionThatLooksLikeATest(); +//} + +void test_TheSecondThingToTest(void) +{ + Call_An_Expect(); + + CallAFunction(); + test_CallAFunctionThatLooksLikeATest(); +} + +#endif //TEST_SAMPLE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/testdata/testsample.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/testdata/testsample.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,68 @@ +// This is just a sample test file to be used to test the generator script +#ifndef TEST_SAMPLE_H +#define TEST_SAMPLE_H + +#include <setjmp.h> +#include "unity.h" +#include "funky.h" +#include "stanky.h" + +void setUp(void) +{ + CustomSetupStuff(); +} + +void tearDown(void) +{ + CustomTeardownStuff +} + +//Yup, nice comment +void test_TheFirstThingToTest(void) +{ + TEST_ASSERT(1); + + TEST_ASSERT_TRUE(1); +} + +/* +void test_ShouldBeIgnored(void) +{ + DoesStuff(); +} +*/ + +//void test_ShouldAlsoNotBeTested(void) +//{ +// Call_An_Expect(); +// +// CallAFunction(); +// test_CallAFunctionThatLooksLikeATest(); +//} + +void test_TheSecondThingToTest(void) +{ + uint8_t* crazyString = "GET / HTTP/1.1\r\nHost: 127.0.0.1:8081\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36\r\nPostman-Token: 768c7149-c3fb-f704-71a2-63918d9195b2\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-GB,en-US;q=0.8,en;q=0.6\r\n\r\n"; + + Call_An_Expect(); + + CallAFunction(); + test_CallAFunctionThatLooksLikeATest(); +} + +void test_TheThirdThingToTest(void) +{ + CallAFunction(); +} + +void test_TheFourthThingToTest(void) +{ + uint8_t* anotherString = "GET / HTTP/1.1\r\nHost: 127.0.0.1:8081\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36\r\nPostman-Token: 768c7149-c3fb-f704-71a2-63918d9195b2\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate, sdch\r\nAccept-Language: en-GB,en-US;q=0.8,en;q=0.6\r\n\r\n"; + + Call_An_Expect(); + + CallAFunction(); + test_CallAFunctionThatLooksLikeATest(); +} + +#endif //TEST_SAMPLE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/tests/test_generate_test_runner.rb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/tests/test_generate_test_runner.rb Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,102 @@ +# ========================================== +# CMock Project - Automatic Mock Generation for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require '../auto/generate_test_runner.rb' + +TEST_FILE = 'testdata/testsample.c' +TEST_MOCK = 'testdata/mocksample.c' +OUT_FILE = 'build/testsample_' +EXP_FILE = 'expectdata/testsample_' + +$generate_test_runner_failures = 0 + +def verify_output_equal(subtest) + expected = File.read(EXP_FILE + subtest + '.c').gsub(/\r\n/,"\n") + actual = File.read(OUT_FILE + subtest + '.c').gsub(/\r\n/,"\n") + if (expected != actual) + report(" #{subtest}:FAIL") + $generate_test_runner_failures += 1 + else + report(" #{subtest}:PASS") + end +end + +should "GenerateARunnerByCreatingRunnerWithOptions" do + sets = { 'def' => nil, + 'new1' => { :plugins => [:cexception], :includes => ['one.h', 'two.h'], :enforce_strict_ordering => true }, + 'new2' => { :plugins => [:ignore], :suite_setup => "a_custom_setup();", :suite_teardown => "a_custom_teardown();" } + } + + sets.each_pair do |subtest, options| + UnityTestRunnerGenerator.new(options).run(TEST_FILE, OUT_FILE + subtest + '.c') + verify_output_equal(subtest) + UnityTestRunnerGenerator.new(options).run(TEST_MOCK, OUT_FILE + 'mock_' + subtest + '.c') + verify_output_equal('mock_' + subtest) + end +end + +should "GenerateARunnerAlongWithAHeaderIfSpecified" do + sets = { 'head1' => { :header_file => "#{OUT_FILE}head1.h" } } + sets.each_pair do |subtest, options| + UnityTestRunnerGenerator.new(options).run(TEST_FILE, OUT_FILE + subtest + '.c') + verify_output_equal(subtest) + end + + sets = { 'head1' => { :header_file => "#{OUT_FILE}mock_head1.h" } } + sets.each_pair do |subtest, options| + UnityTestRunnerGenerator.new(options).run(TEST_MOCK, OUT_FILE + 'mock_' + subtest + '.c') + verify_output_equal('mock_' + subtest) + end +end + +should "GenerateARunnerByRunningRunnerWithOptions" do + sets = { 'run1' => { :plugins => [:cexception], :includes => ['one.h', 'two.h'], :enforce_strict_ordering => true }, + 'run2' => { :plugins => [:ignore], :suite_setup => "a_custom_setup();", :suite_teardown => "a_custom_teardown();" } + } + + sets.each_pair do |subtest, options| + UnityTestRunnerGenerator.new.run(TEST_FILE, OUT_FILE + subtest + '.c', options) + verify_output_equal(subtest) + UnityTestRunnerGenerator.new.run(TEST_MOCK, OUT_FILE + 'mock_' + subtest + '.c', options) + verify_output_equal('mock_' + subtest) + end +end + +should "GenerateARunnerByPullingYamlOptions" do + subtest = 'yaml' + cmdstr = "ruby ../auto/generate_test_runner.rb testdata/sample.yml \"#{TEST_FILE}\" \"#{OUT_FILE + subtest + '.c'}\"" + `#{cmdstr}` + verify_output_equal(subtest) + + cmdstr = "ruby ../auto/generate_test_runner.rb testdata/sample.yml \"#{TEST_MOCK}\" \"#{OUT_FILE + 'mock_' + subtest + '.c'}\"" + `#{cmdstr}` + verify_output_equal('mock_' + subtest) +end + +should "GenerateARunnerByPullingCommandlineOptions" do + subtest = 'cmd' + cmdstr = "ruby ../auto/generate_test_runner.rb -cexception \"#{TEST_FILE}\" \"#{OUT_FILE + subtest + '.c'}\"" + `#{cmdstr}` + verify_output_equal(subtest) + + cmdstr = "ruby ../auto/generate_test_runner.rb -cexception \"#{TEST_MOCK}\" \"#{OUT_FILE + 'mock_' + subtest + '.c'}\"" + `#{cmdstr}` + verify_output_equal('mock_' + subtest) +end + +should "GenerateARunnerThatUsesParameterizedTests" do + sets = { 'param' => { :plugins => [:ignore], :use_param_tests => true } + } + + sets.each_pair do |subtest, options| + UnityTestRunnerGenerator.new(options).run(TEST_FILE, OUT_FILE + subtest + '.c') + verify_output_equal(subtest) + UnityTestRunnerGenerator.new(options).run(TEST_MOCK, OUT_FILE + 'mock_' + subtest + '.c') + verify_output_equal('mock_' + subtest) + end +end + +raise "There were #{$generate_test_runner_failures.to_s} failures while testing generate_test_runner.rb" if ($generate_test_runner_failures > 0)
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/tests/testparameterized.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/tests/testparameterized.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,104 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include <setjmp.h> +#include <stdio.h> +#include "unity.h" + +void putcharSpy(int c) { (void)putchar(c);} // include passthrough for linking tests + +#define TEST_CASE(...) + +#define EXPECT_ABORT_BEGIN \ + if (TEST_PROTECT()) \ + { + +#define VERIFY_FAILS_END \ + } \ + Unity.CurrentTestFailed = (Unity.CurrentTestFailed == 1) ? 0 : 1; \ + if (Unity.CurrentTestFailed == 1) { \ + SetToOneMeanWeAlreadyCheckedThisGuy = 1; \ + UnityPrint("[[[[ Previous Test Should Have Failed But Did Not ]]]]"); \ + UNITY_OUTPUT_CHAR('\n'); \ + } + +#define VERIFY_IGNORES_END \ + } \ + Unity.CurrentTestFailed = (Unity.CurrentTestIgnored == 1) ? 0 : 1; \ + Unity.CurrentTestIgnored = 0; \ + if (Unity.CurrentTestFailed == 1) { \ + SetToOneMeanWeAlreadyCheckedThisGuy = 1; \ + UnityPrint("[[[[ Previous Test Should Have Ignored But Did Not ]]]]"); \ + UNITY_OUTPUT_CHAR('\n'); \ + } + +int SetToOneToFailInTearDown; +int SetToOneMeanWeAlreadyCheckedThisGuy; + +void setUp(void) +{ + SetToOneToFailInTearDown = 0; + SetToOneMeanWeAlreadyCheckedThisGuy = 0; +} + +void tearDown(void) +{ + if (SetToOneToFailInTearDown == 1) + TEST_FAIL_MESSAGE("<= Failed in tearDown"); + if ((SetToOneMeanWeAlreadyCheckedThisGuy == 0) && (Unity.CurrentTestFailed > 0)) + { + UnityPrint("[[[[ Previous Test Should Have Passed But Did Not ]]]]"); + UNITY_OUTPUT_CHAR('\n'); + } +} + +TEST_CASE(0) +TEST_CASE(44) +TEST_CASE((90)+9) +void test_TheseShouldAllPass(int Num) +{ + TEST_ASSERT_TRUE(Num < 100); +} + +TEST_CASE(3) +TEST_CASE(77) +TEST_CASE( (99) + 1 - (1)) +void test_TheseShouldAllFail(int Num) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_TRUE(Num > 100); + VERIFY_FAILS_END +} + +TEST_CASE(1) +TEST_CASE(44) +TEST_CASE(99) +TEST_CASE(98) +void test_TheseAreEveryOther(int Num) +{ + if (Num & 1) + { + EXPECT_ABORT_BEGIN + TEST_ASSERT_TRUE(Num > 100); + VERIFY_FAILS_END + } + else + { + TEST_ASSERT_TRUE(Num < 100); + } +} + +void test_NormalPassesStillWork(void) +{ + TEST_ASSERT_TRUE(1); +} + +void test_NormalFailsStillWork(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_TRUE(0); + VERIFY_FAILS_END +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/tests/testunity.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/Unity/test/tests/testunity.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3804 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include <setjmp.h> +#include "unity.h" +#include <string.h> + +// Dividing by these constants produces +/- infinity. +// The rationale is given in UnityAssertFloatIsInf's body. +#ifndef UNITY_EXCLUDE_FLOAT +static const _UF f_zero = 0.0f; +#endif + +#ifndef UNITY_EXCLUDE_DOUBLE +static const _UD d_zero = 0.0; +#endif + +#define EXPECT_ABORT_BEGIN \ + if (TEST_PROTECT()) \ + { + +#define VERIFY_FAILS_END \ + } \ + Unity.CurrentTestFailed = (Unity.CurrentTestFailed == 1) ? 0 : 1; \ + if (Unity.CurrentTestFailed == 1) { \ + SetToOneMeanWeAlreadyCheckedThisGuy = 1; \ + UnityPrintNumberUnsigned(Unity.CurrentTestLineNumber); \ + UNITY_OUTPUT_CHAR(':'); \ + UnityPrint(Unity.CurrentTestName); \ + UnityPrint("[[[[ Previous Test Should Have Failed But Did Not ]]]]"); \ + UNITY_OUTPUT_CHAR('\n'); \ + } + +#define VERIFY_IGNORES_END \ + } \ + Unity.CurrentTestFailed = (Unity.CurrentTestIgnored == 1) ? 0 : 1; \ + Unity.CurrentTestIgnored = 0; \ + if (Unity.CurrentTestFailed == 1) { \ + SetToOneMeanWeAlreadyCheckedThisGuy = 1; \ + UnityPrint("[[[[ Previous Test Should Have Ignored But Did Not ]]]]"); \ + UNITY_OUTPUT_CHAR('\n'); \ + } + +static int SetToOneToFailInTearDown; +static int SetToOneMeanWeAlreadyCheckedThisGuy; + +void setUp(void) +{ + SetToOneToFailInTearDown = 0; + SetToOneMeanWeAlreadyCheckedThisGuy = 0; +} + +void tearDown(void) +{ + if (SetToOneToFailInTearDown == 1) + TEST_FAIL_MESSAGE("<= Failed in tearDown"); + if ((SetToOneMeanWeAlreadyCheckedThisGuy == 0) && (Unity.CurrentTestFailed > 0)) + { + UnityPrint("[[[[ Previous Test Should Have Passed But Did Not ]]]]"); + UNITY_OUTPUT_CHAR('\n'); + } +} + +void testUnitySizeInitializationReminder(void) +{ + /* This test ensures that sizeof(struct _Unity) doesn't change. If this + * test breaks, go look at the initialization of the Unity global variable + * in unity.c and make sure we're filling in the proper fields. */ + const char* message = "Unexpected size for _Unity struct. Please check that " + "the initialization of the Unity symbol in unity.c is " + "still correct."; + + /* Define a structure with all the same fields as `struct _Unity`. */ +#ifdef UNITY_EXCLUDE_DETAILS + struct { + const char* TestFile; + const char* CurrentTestName; + UNITY_LINE_TYPE CurrentTestLineNumber; + UNITY_COUNTER_TYPE NumberOfTests; + UNITY_COUNTER_TYPE TestFailures; + UNITY_COUNTER_TYPE TestIgnores; + UNITY_COUNTER_TYPE CurrentTestFailed; + UNITY_COUNTER_TYPE CurrentTestIgnored; + jmp_buf AbortFrame; + } _Expected_Unity; +#else + struct { + const char* TestFile; + const char* CurrentTestName; + const char* CurrentDetails1; + const char* CurrentDetails2; + UNITY_LINE_TYPE CurrentTestLineNumber; + UNITY_COUNTER_TYPE NumberOfTests; + UNITY_COUNTER_TYPE TestFailures; + UNITY_COUNTER_TYPE TestIgnores; + UNITY_COUNTER_TYPE CurrentTestFailed; + UNITY_COUNTER_TYPE CurrentTestIgnored; + jmp_buf AbortFrame; + } _Expected_Unity; +#endif + + /* Compare our fake structure's size to the actual structure's size. They + * should be the same. + * + * This accounts for alignment, padding, and packing issues that might come + * up between different architectures. */ + TEST_ASSERT_EQUAL_MESSAGE(sizeof(_Expected_Unity), sizeof(Unity), message); +} + +void testPassShouldEndImmediatelyWithPass(void) +{ + TEST_PASS(); + TEST_FAIL_MESSAGE("We should have passed already and finished this test"); +} + +void testTrue(void) +{ + TEST_ASSERT(1); + + TEST_ASSERT_TRUE(1); +} + +void testFalse(void) +{ + TEST_ASSERT_FALSE(0); + + TEST_ASSERT_UNLESS(0); +} + +void testPreviousPass(void) +{ + TEST_ASSERT_EQUAL_INT(0U, Unity.TestFailures); +} + +void testNotVanilla(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT(0); + VERIFY_FAILS_END +} + +void testNotTrue(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_TRUE(0); + VERIFY_FAILS_END +} + +void testNotFalse(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_FALSE(1); + VERIFY_FAILS_END +} + +void testNotUnless(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UNLESS(1); + VERIFY_FAILS_END +} + +void testNotNotEqual(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_NOT_EQUAL(10, 10); + VERIFY_FAILS_END +} + +void testFail(void) +{ + EXPECT_ABORT_BEGIN + TEST_FAIL_MESSAGE("Expected for testing"); + VERIFY_FAILS_END +} + +void testIsNull(void) +{ + char* ptr1 = NULL; + const char* ptr2 = "hello"; + + TEST_ASSERT_NULL(ptr1); + TEST_ASSERT_NOT_NULL(ptr2); +} + +void testIsNullShouldFailIfNot(void) +{ + const char* ptr1 = "hello"; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_NULL(ptr1); + VERIFY_FAILS_END +} + +void testNotNullShouldFailIfNULL(void) +{ + char* ptr1 = NULL; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_NOT_NULL(ptr1); + VERIFY_FAILS_END +} + +void testIgnore(void) +{ + EXPECT_ABORT_BEGIN + TEST_IGNORE(); + TEST_FAIL_MESSAGE("This should not be reached"); + VERIFY_IGNORES_END +} + +void testIgnoreMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_IGNORE_MESSAGE("This is an expected TEST_IGNORE_MESSAGE string!"); + TEST_FAIL_MESSAGE("This should not be reached"); + VERIFY_IGNORES_END +} + +void testNotEqualInts(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT(3982, 3983); + VERIFY_FAILS_END +} + +void testNotEqualInt8s(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT8(-127, -126); + VERIFY_FAILS_END +} + +void testNotEqualInt16s(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT16(-16383, -16382); + VERIFY_FAILS_END +} + +void testNotEqualInt32s(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT32(-2147483647, -2147483648); //use largest 32 bit negative to test printability + VERIFY_FAILS_END +} + +void testNotEqualBits(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_BITS(0xFF00, 0x5555, 0x5A55); + VERIFY_FAILS_END +} + +void testNotEqualUInts(void) +{ + _UU16 v0, v1; + + v0 = 9000; + v1 = 9001; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT(v0, v1); + VERIFY_FAILS_END +} + +void testNotEqualUInt8s(void) +{ + _UU8 v0, v1; + + v0 = 254; + v1 = 255; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT8(v0, v1); + VERIFY_FAILS_END +} + +void testNotEqualUInt16s(void) +{ + _UU16 v0, v1; + + v0 = 65535; + v1 = 65534; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT16(v0, v1); + VERIFY_FAILS_END +} + +void testNotEqualUInt32s(void) +{ + _UU32 v0, v1; + + v0 = 4294967295; + v1 = 4294967294; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT32(v0, v1); + VERIFY_FAILS_END +} + +void testNotEqualHex8s(void) +{ + _UU8 v0, v1; + + v0 = 0x23; + v1 = 0x22; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX8(v0, v1); + VERIFY_FAILS_END +} + +void testNotEqualHex8sIfSigned(void) +{ + _US8 v0, v1; + + v0 = -2; + v1 = 2; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX8(v0, v1); + VERIFY_FAILS_END +} + +void testNotEqualHex16s(void) +{ + _UU16 v0, v1; + + v0 = 0x1234; + v1 = 0x1235; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX16(v0, v1); + VERIFY_FAILS_END +} + +void testNotEqualHex16sIfSigned(void) +{ + _US16 v0, v1; + + v0 = -1024; + v1 = -1028; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX16(v0, v1); + VERIFY_FAILS_END +} + +void testNotEqualHex32s(void) +{ + _UU32 v0, v1; + + v0 = 900000; + v1 = 900001; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX32(v0, v1); + VERIFY_FAILS_END +} + +void testNotEqualHex32sIfSigned(void) +{ + _US32 v0, v1; + + v0 = -900000; + v1 = 900001; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX32(v0, v1); + VERIFY_FAILS_END +} + +void testEqualInts(void) +{ + int v0, v1; + int *p0, *p1; + + v0 = 19467; + v1 = 19467; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT(1837, 1837); + TEST_ASSERT_EQUAL_INT(-27365, -27365); + TEST_ASSERT_EQUAL_INT(v0, v1); + TEST_ASSERT_EQUAL_INT(19467, v1); + TEST_ASSERT_EQUAL_INT(v0, 19467); + TEST_ASSERT_EQUAL_INT(*p0, v1); + TEST_ASSERT_EQUAL_INT(*p0, *p1); + TEST_ASSERT_EQUAL_INT(*p0, 19467); +} + +void testEqualInt8s(void) +{ + _US8 v0, v1; + _US8 *p0, *p1; + + v0 = 0x22; + v1 = 0x22; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT8(0x22, 0x22); + TEST_ASSERT_EQUAL_INT8(v0, v1); + TEST_ASSERT_EQUAL_INT8(0x22, v1); + TEST_ASSERT_EQUAL_INT8(v0, 0x22); + TEST_ASSERT_EQUAL_INT8(*p0, v1); + TEST_ASSERT_EQUAL_INT8(*p0, *p1); + TEST_ASSERT_EQUAL_INT8(*p0, 0x22); +} + +void testEqualInt8sWhenThereAreDifferencesOutside8Bits(void) +{ + TEST_ASSERT_EQUAL_INT8(0x321,0x421); + TEST_ASSERT_EQUAL_INT8(0xFF21,0x0021); +} + +void testEqualInt16s(void) +{ + _US16 v0, v1; + _US16 *p0, *p1; + + v0 = 0x7876; + v1 = 0x7876; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT16(0x7876, 0x7876); + TEST_ASSERT_EQUAL_INT16(v0, v1); + TEST_ASSERT_EQUAL_INT16(0x7876, v1); + TEST_ASSERT_EQUAL_INT16(v0, 0x7876); + TEST_ASSERT_EQUAL_INT16(*p0, v1); + TEST_ASSERT_EQUAL_INT16(*p0, *p1); + TEST_ASSERT_EQUAL_INT16(*p0, 0x7876); +} + +void testEqualInt16sNegatives(void) +{ + _US16 v0, v1; + _US16 *p0, *p1; + + v0 = -7876; + v1 = -7876; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT16(-7876, -7876); + TEST_ASSERT_EQUAL_INT16(v0, v1); + TEST_ASSERT_EQUAL_INT16(-7876, v1); + TEST_ASSERT_EQUAL_INT16(v0, -7876); + TEST_ASSERT_EQUAL_INT16(*p0, v1); + TEST_ASSERT_EQUAL_INT16(*p0, *p1); + TEST_ASSERT_EQUAL_INT16(*p0, -7876); +} + +void testEqualInt16sWhenThereAreDifferencesOutside16Bits(void) +{ + TEST_ASSERT_EQUAL_INT16(0x54321,0x64321); + TEST_ASSERT_EQUAL_INT16(0xFFFF4321,0x00004321); +} + +void testEqualInt32s(void) +{ + _US32 v0, v1; + _US32 *p0, *p1; + + v0 = 0x78760000; + v1 = 0x78760000; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT32(0x78760000, 0x78760000); + TEST_ASSERT_EQUAL_INT32(v0, v1); + TEST_ASSERT_EQUAL_INT32(0x78760000, v1); + TEST_ASSERT_EQUAL_INT32(v0, 0x78760000); + TEST_ASSERT_EQUAL_INT32(*p0, v1); + TEST_ASSERT_EQUAL_INT32(*p0, *p1); + TEST_ASSERT_EQUAL_INT32(*p0, 0x78760000); +} + +void testEqualInt32sNegatives(void) +{ + _US32 v0, v1; + _US32 *p0, *p1; + + v0 = -123456789; + v1 = -123456789; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT32(-123456789, -123456789); + TEST_ASSERT_EQUAL_INT32(v0, v1); + TEST_ASSERT_EQUAL_INT32(-123456789, v1); + TEST_ASSERT_EQUAL_INT32(v0, -123456789); + TEST_ASSERT_EQUAL_INT32(*p0, v1); + TEST_ASSERT_EQUAL_INT32(*p0, *p1); + TEST_ASSERT_EQUAL_INT32(*p0, -123456789); +} + + +void testEqualUints(void) +{ + unsigned int v0, v1; + unsigned int *p0, *p1; + + v0 = 19467; + v1 = 19467; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_UINT(1837, 1837); + TEST_ASSERT_EQUAL_UINT(v0, v1); + TEST_ASSERT_EQUAL_UINT(19467, v1); + TEST_ASSERT_EQUAL_UINT(v0, 19467); + TEST_ASSERT_EQUAL_UINT(*p0, v1); + TEST_ASSERT_EQUAL_UINT(*p0, *p1); + TEST_ASSERT_EQUAL_UINT(*p0, 19467); + TEST_ASSERT_EQUAL_UINT(60872u, 60872u); +} + + +void testEqualUint8s(void) +{ + _UU8 v0, v1; + _UU8 *p0, *p1; + + v0 = 0x22; + v1 = 0x22; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_UINT8(0x22, 0x22); + TEST_ASSERT_EQUAL_UINT8(v0, v1); + TEST_ASSERT_EQUAL_UINT8(0x22, v1); + TEST_ASSERT_EQUAL_UINT8(v0, 0x22); + TEST_ASSERT_EQUAL_UINT8(*p0, v1); + TEST_ASSERT_EQUAL_UINT8(*p0, *p1); + TEST_ASSERT_EQUAL_UINT8(*p0, 0x22); +} + +void testEqualUint8sWhenThereAreDifferencesOutside8Bits(void) +{ + TEST_ASSERT_EQUAL_UINT8(0x321,0x421); + TEST_ASSERT_EQUAL_UINT8(0xFF21,0x0021); +} + +void testEqualUint16s(void) +{ + _UU16 v0, v1; + _UU16 *p0, *p1; + + v0 = 0x9876; + v1 = 0x9876; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_UINT16(0x9876, 0x9876); + TEST_ASSERT_EQUAL_UINT16(v0, v1); + TEST_ASSERT_EQUAL_UINT16(0x9876, v1); + TEST_ASSERT_EQUAL_UINT16(v0, 0x9876); + TEST_ASSERT_EQUAL_UINT16(*p0, v1); + TEST_ASSERT_EQUAL_UINT16(*p0, *p1); + TEST_ASSERT_EQUAL_UINT16(*p0, 0x9876); +} + +void testEqualUint16sWhenThereAreDifferencesOutside16Bits(void) +{ + TEST_ASSERT_EQUAL_UINT16(0x54321,0x64321); + TEST_ASSERT_EQUAL_UINT16(0xFFFF4321,0x00004321); +} + +void testEqualUint32s(void) +{ + _UU32 v0, v1; + _UU32 *p0, *p1; + + v0 = 0x98760000; + v1 = 0x98760000; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_UINT32(0x98760000, 0x98760000); + TEST_ASSERT_EQUAL_UINT32(v0, v1); + TEST_ASSERT_EQUAL_UINT32(0x98760000, v1); + TEST_ASSERT_EQUAL_UINT32(v0, 0x98760000); + TEST_ASSERT_EQUAL_UINT32(*p0, v1); + TEST_ASSERT_EQUAL_UINT32(*p0, *p1); + TEST_ASSERT_EQUAL_UINT32(*p0, 0x98760000); +} + +void testNotEqual(void) +{ + TEST_ASSERT_NOT_EQUAL(0, 1); + TEST_ASSERT_NOT_EQUAL(1, 0); + TEST_ASSERT_NOT_EQUAL(100, 101); + TEST_ASSERT_NOT_EQUAL(0, -1); + TEST_ASSERT_NOT_EQUAL(65535, -65535); + TEST_ASSERT_NOT_EQUAL(75, 900); + TEST_ASSERT_NOT_EQUAL(-100, -101); +} + +void testEqualHex8s(void) +{ + _UU8 v0, v1; + _UU8 *p0, *p1; + + v0 = 0x22; + v1 = 0x22; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_HEX8(0x22, 0x22); + TEST_ASSERT_EQUAL_HEX8(v0, v1); + TEST_ASSERT_EQUAL_HEX8(0x22, v1); + TEST_ASSERT_EQUAL_HEX8(v0, 0x22); + TEST_ASSERT_EQUAL_HEX8(*p0, v1); + TEST_ASSERT_EQUAL_HEX8(*p0, *p1); + TEST_ASSERT_EQUAL_HEX8(*p0, 0x22); +} + +void testEqualHex8sWhenThereAreDifferencesOutside8Bits(void) +{ + TEST_ASSERT_EQUAL_HEX8(0x321,0x421); + TEST_ASSERT_EQUAL_HEX8(0xFF21,0x0021); +} + +void testEqualHex8sNegatives(void) +{ + _UU8 v0, v1; + _UU8 *p0, *p1; + + v0 = 0xDD; + v1 = 0xDD; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_HEX8(0xDD, 0xDD); + TEST_ASSERT_EQUAL_HEX8(v0, v1); + TEST_ASSERT_EQUAL_HEX8(0xDD, v1); + TEST_ASSERT_EQUAL_HEX8(v0, 0xDD); + TEST_ASSERT_EQUAL_HEX8(*p0, v1); + TEST_ASSERT_EQUAL_HEX8(*p0, *p1); + TEST_ASSERT_EQUAL_HEX8(*p0, 0xDD); +} + +void testEqualHex16s(void) +{ + _UU16 v0, v1; + _UU16 *p0, *p1; + + v0 = 0x9876; + v1 = 0x9876; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_HEX16(0x9876, 0x9876); + TEST_ASSERT_EQUAL_HEX16(v0, v1); + TEST_ASSERT_EQUAL_HEX16(0x9876, v1); + TEST_ASSERT_EQUAL_HEX16(v0, 0x9876); + TEST_ASSERT_EQUAL_HEX16(*p0, v1); + TEST_ASSERT_EQUAL_HEX16(*p0, *p1); + TEST_ASSERT_EQUAL_HEX16(*p0, 0x9876); +} + +void testEqualHex16sWhenThereAreDifferencesOutside16Bits(void) +{ + TEST_ASSERT_EQUAL_HEX16(0x54321,0x64321); + TEST_ASSERT_EQUAL_HEX16(0xFFFF4321,0x00004321); +} + +void testEqualHex32s(void) +{ + _UU32 v0, v1; + _UU32 *p0, *p1; + + v0 = 0x98765432ul; + v1 = 0x98765432ul; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_HEX32(0x98765432ul, 0x98765432ul); + TEST_ASSERT_EQUAL_HEX32(v0, v1); + TEST_ASSERT_EQUAL_HEX32(0x98765432ul, v1); + TEST_ASSERT_EQUAL_HEX32(v0, 0x98765432ul); + TEST_ASSERT_EQUAL_HEX32(*p0, v1); + TEST_ASSERT_EQUAL_HEX32(*p0, *p1); + TEST_ASSERT_EQUAL_HEX32(*p0, 0x98765432ul); +} + +void testEqualBits(void) +{ + _UU32 v0 = 0xFF55AA00; + _UU32 v1 = 0x55550000; + + TEST_ASSERT_BITS(v1, v0, 0x55550000); + TEST_ASSERT_BITS(v1, v0, 0xFF55CC00); + TEST_ASSERT_BITS(0xFFFFFFFF, v0, 0xFF55AA00); + TEST_ASSERT_BITS(0xFFFFFFFF, v0, v0); + TEST_ASSERT_BITS(0xF0F0F0F0, v0, 0xFC5DAE0F); + TEST_ASSERT_BITS_HIGH(v1, v0); + TEST_ASSERT_BITS_LOW(0x000055FF, v0); + TEST_ASSERT_BIT_HIGH(30, v0); + TEST_ASSERT_BIT_LOW(5, v0); +} + +void testNotEqualBitHigh(void) +{ + _UU32 v0 = 0x7F55AA00; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_BIT_HIGH(31, v0); + VERIFY_FAILS_END +} + +void testNotEqualBitLow(void) +{ + _UU32 v0 = 0xFF55AA00; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_BIT_LOW(30, v0); + VERIFY_FAILS_END +} + +void testNotEqualBitsHigh(void) +{ + _UU32 v0 = 0xFF55AA00; + _UU32 v1 = 0x55550000; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_BITS_HIGH(v0, v1); + VERIFY_FAILS_END + +} + +void testNotEqualBitsLow(void) +{ + _UU32 v0 = 0xFF55AA00; + _UU32 v1 = 0x55550000; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_BITS_LOW(v0, v1); + VERIFY_FAILS_END + +} +void testEqualShorts(void) +{ + short v0, v1; + short *p0, *p1; + + v0 = 19467; + v1 = 19467; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT(1837, 1837); + TEST_ASSERT_EQUAL_INT(-2987, -2987); + TEST_ASSERT_EQUAL_INT(v0, v1); + TEST_ASSERT_EQUAL_INT(19467, v1); + TEST_ASSERT_EQUAL_INT(v0, 19467); + TEST_ASSERT_EQUAL_INT(*p0, v1); + TEST_ASSERT_EQUAL_INT(*p0, *p1); + TEST_ASSERT_EQUAL_INT(*p0, 19467); +} + +void testEqualUShorts(void) +{ + unsigned short v0, v1; + unsigned short *p0, *p1; + + v0 = 19467; + v1 = 19467; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_UINT(1837, 1837); + TEST_ASSERT_EQUAL_UINT(2987, 2987); + TEST_ASSERT_EQUAL_UINT(v0, v1); + TEST_ASSERT_EQUAL_UINT(19467, v1); + TEST_ASSERT_EQUAL_UINT(v0, 19467); + TEST_ASSERT_EQUAL_UINT(*p0, v1); + TEST_ASSERT_EQUAL_UINT(*p0, *p1); + TEST_ASSERT_EQUAL_UINT(*p0, 19467); +} + +void testEqualChars(void) +{ + signed char v0, v1; + signed char *p0, *p1; + + v0 = 109; + v1 = 109; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT(42, 42); + TEST_ASSERT_EQUAL_INT(-116, -116); + TEST_ASSERT_EQUAL_INT(v0, v1); + TEST_ASSERT_EQUAL_INT(109, v1); + TEST_ASSERT_EQUAL_INT(v0, 109); + TEST_ASSERT_EQUAL_INT(*p0, v1); + TEST_ASSERT_EQUAL_INT(*p0, *p1); + TEST_ASSERT_EQUAL_INT(*p0, 109); +} + +void testEqualUChars(void) +{ + unsigned char v0, v1; + unsigned char *p0, *p1; + + v0 = 251; + v1 = 251; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT(42, 42); + TEST_ASSERT_EQUAL_INT(v0, v1); + TEST_ASSERT_EQUAL_INT(251, v1); + TEST_ASSERT_EQUAL_INT(v0, 251); + TEST_ASSERT_EQUAL_INT(*p0, v1); + TEST_ASSERT_EQUAL_INT(*p0, *p1); + TEST_ASSERT_EQUAL_INT(*p0, 251); +} + +void testEqualPointers(void) +{ + int v0, v1; + int *p0, *p1, *p2; + + v0 = 19467; + v1 = 18271; + p0 = &v0; + p1 = &v1; + p2 = &v1; + + TEST_ASSERT_EQUAL_PTR(p0, &v0); + TEST_ASSERT_EQUAL_PTR(&v1, p1); + TEST_ASSERT_EQUAL_PTR(p2, p1); + TEST_ASSERT_EQUAL_PTR(&v0, &v0); +} + +void testNotEqualPointers(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_PTR(0x12345678, 0x12345677); + VERIFY_FAILS_END +} + +void testIntsWithinDelta(void) +{ + TEST_ASSERT_INT_WITHIN(1, 5000, 5001); + TEST_ASSERT_INT_WITHIN(5, 5000, 4996); + TEST_ASSERT_INT_WITHIN(5, 5000, 5005); + TEST_ASSERT_INT_WITHIN(500, 50, -440); + + TEST_ASSERT_INT_WITHIN(2, -1, -1); + TEST_ASSERT_INT_WITHIN(5, 1, -1); + TEST_ASSERT_INT_WITHIN(5, -1, 1); +} + +void testIntsWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_INT_WITHIN_MESSAGE(1, 5000, 5001, "Custom Message."); + TEST_ASSERT_INT_WITHIN_MESSAGE(5, 5000, 4996, "Custom Message."); + TEST_ASSERT_INT_WITHIN_MESSAGE(5, 5000, 5005, "Custom Message."); + TEST_ASSERT_INT_WITHIN_MESSAGE(500, 50, -440, "Custom Message."); + + TEST_ASSERT_INT_WITHIN_MESSAGE(2, -1, -1, "Custom Message."); + TEST_ASSERT_INT_WITHIN_MESSAGE(5, 1, -1, "Custom Message."); + TEST_ASSERT_INT_WITHIN_MESSAGE(5, -1, 1, "Custom Message."); +} + +void testIntsNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT_WITHIN(5, 5000, 5006); + VERIFY_FAILS_END +} + +void testIntsNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT_WITHIN_MESSAGE(5, 5000, 5006, "Custom Message."); + VERIFY_FAILS_END +} + +void testUIntsWithinDelta(void) +{ + TEST_ASSERT_UINT_WITHIN(1, 5000, 5001); + TEST_ASSERT_UINT_WITHIN(5, 5000, 4996); + TEST_ASSERT_UINT_WITHIN(5, 5000, 5005); +} + +void testUIntsWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_UINT_WITHIN_MESSAGE(1, 5000, 5001, "Custom Message."); + TEST_ASSERT_UINT_WITHIN_MESSAGE(5, 5000, 4996, "Custom Message."); + TEST_ASSERT_UINT_WITHIN_MESSAGE(5, 5000, 5005, "Custom Message."); +} + +void testUIntsNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT_WITHIN(1, 2147483647u, 2147483649u); + VERIFY_FAILS_END +} + +void testUIntsNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT_WITHIN_MESSAGE(1, 2147483647u, 2147483649u, "Custom Message."); + VERIFY_FAILS_END +} + +void testUIntsNotWithinDeltaEvenThoughASignedIntWouldPassSmallFirst(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT_WITHIN(5, 1, -1); + VERIFY_FAILS_END +} + +void testUIntsNotWithinDeltaEvenThoughASignedIntWouldPassSmallFirstAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT_WITHIN_MESSAGE(5, 1, -1, "Custom Message."); + VERIFY_FAILS_END +} + +void testUIntsNotWithinDeltaEvenThoughASignedIntWouldPassBigFirst(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT_WITHIN(5, -1, 1); + VERIFY_FAILS_END +} + +void testUIntsNotWithinDeltaEvenThoughASignedIntWouldPassBigFirstAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT_WITHIN_MESSAGE(5, -1, 1, "Custom Message."); + VERIFY_FAILS_END +} + +void testHEX32sWithinDelta(void) +{ + TEST_ASSERT_HEX32_WITHIN(1, 5000, 5001); + TEST_ASSERT_HEX32_WITHIN(5, 5000, 4996); + TEST_ASSERT_HEX32_WITHIN(5, 5000, 5005); +} + +void testHEX32sWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_HEX32_WITHIN_MESSAGE(1, 5000, 5001, "Custom Message."); + TEST_ASSERT_HEX32_WITHIN_MESSAGE(5, 5000, 4996, "Custom Message."); + TEST_ASSERT_HEX32_WITHIN_MESSAGE(5, 5000, 5005, "Custom Message."); +} + +void testHEX32sNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX32_WITHIN(1, 2147483647u, 2147483649u); + VERIFY_FAILS_END +} + +void testHEX32sNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX32_WITHIN_MESSAGE(1, 2147483647u, 2147483649u, "Custom Message."); + VERIFY_FAILS_END +} + +void testHEX32sNotWithinDeltaEvenThoughASignedIntWouldPass(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX32_WITHIN(5, 1, -1); + VERIFY_FAILS_END +} + +void testHEX32sNotWithinDeltaEvenThoughASignedIntWouldPassAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX32_WITHIN_MESSAGE(5, 1, -1, "Custom Message."); + VERIFY_FAILS_END +} + +void testHEX16sWithinDelta(void) +{ + TEST_ASSERT_HEX16_WITHIN(1, 5000, 5001); + TEST_ASSERT_HEX16_WITHIN(5, 5000, 4996); + TEST_ASSERT_HEX16_WITHIN(5, 5000, 5005); +} + +void testHEX16sWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_HEX16_WITHIN_MESSAGE(1, 5000, 5001, "Custom Message."); + TEST_ASSERT_HEX16_WITHIN_MESSAGE(5, 5000, 4996, "Custom Message."); + TEST_ASSERT_HEX16_WITHIN_MESSAGE(5, 5000, 5005, "Custom Message."); +} + +void testHEX16sWithinDeltaWhenThereAreDifferenceOutsideOf16Bits(void) +{ + TEST_ASSERT_HEX16_WITHIN(5, 0x54321, 0x44321); +} + +void testHEX16sWithinDeltaWhenThereAreDifferenceOutsideOf16BitsAndCustomMessage(void) +{ + TEST_ASSERT_HEX16_WITHIN_MESSAGE(5, 0x54321, 0x44321, "Custom Message."); +} + +void testHEX16sNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX16_WITHIN(2, 65535, 0); + VERIFY_FAILS_END +} + +void testHEX16sNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX16_WITHIN_MESSAGE(2, 65535, 0, "Custom Message."); + VERIFY_FAILS_END +} + +void testHEX8sWithinDelta(void) +{ + TEST_ASSERT_HEX8_WITHIN(1, 254, 255); + TEST_ASSERT_HEX8_WITHIN(5, 251, 255); + TEST_ASSERT_HEX8_WITHIN(5, 1, 4); +} + +void testHEX8sWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_HEX8_WITHIN_MESSAGE(1, 254, 255, "Custom Message."); + TEST_ASSERT_HEX8_WITHIN_MESSAGE(5, 251, 255, "Custom Message."); + TEST_ASSERT_HEX8_WITHIN_MESSAGE(5, 1, 4, "Custom Message."); +} + +void testHEX8sWithinDeltaWhenThereAreDifferenceOutsideOf8Bits(void) +{ + TEST_ASSERT_HEX8_WITHIN(5, 0x123, 0xF23); +} + +void testHEX8sWithinDeltaWhenThereAreDifferenceOutsideOf8BitsAndCustomMessage(void) +{ + TEST_ASSERT_HEX8_WITHIN_MESSAGE(5, 0x123, 0xF23, "Custom Message."); +} + +void testHEX8sNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX8_WITHIN(2, 255, 0); + VERIFY_FAILS_END +} + +void testHEX8sNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX8_WITHIN_MESSAGE(2, 255, 0, "Custom Message."); + VERIFY_FAILS_END +} + +//----------------- + +void testUINT32sWithinDelta(void) +{ + TEST_ASSERT_UINT32_WITHIN(1, 5000, 5001); + TEST_ASSERT_UINT32_WITHIN(5, 5000, 4996); + TEST_ASSERT_UINT32_WITHIN(5, 5000, 5005); +} + +void testUINT32sWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_UINT32_WITHIN_MESSAGE(1, 5000, 5001, "Custom Message."); + TEST_ASSERT_UINT32_WITHIN_MESSAGE(5, 5000, 4996, "Custom Message."); + TEST_ASSERT_UINT32_WITHIN_MESSAGE(5, 5000, 5005, "Custom Message."); +} + +void testUINT32sNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT32_WITHIN(1, 2147483647u, 2147483649u); + VERIFY_FAILS_END +} + +void testUINT32sNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT32_WITHIN_MESSAGE(1, 2147483647u, 2147483649u, "Custom Message."); + VERIFY_FAILS_END +} + +void testUINT32sNotWithinDeltaEvenThoughASignedIntWouldPass(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT32_WITHIN(5, 1, -1); + VERIFY_FAILS_END +} + +void testUINT32sNotWithinDeltaEvenThoughASignedIntWouldPassAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT32_WITHIN_MESSAGE(5, 1, -1, "Custom Message."); + VERIFY_FAILS_END +} + +void testUINT16sWithinDelta(void) +{ + TEST_ASSERT_UINT16_WITHIN(1, 5000, 5001); + TEST_ASSERT_UINT16_WITHIN(5, 5000, 4996); + TEST_ASSERT_UINT16_WITHIN(5, 5000, 5005); +} + +void testUINT16sWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_UINT16_WITHIN_MESSAGE(1, 5000, 5001, "Custom Message."); + TEST_ASSERT_UINT16_WITHIN_MESSAGE(5, 5000, 4996, "Custom Message."); + TEST_ASSERT_UINT16_WITHIN_MESSAGE(5, 5000, 5005, "Custom Message."); +} + +void testUINT16sWithinDeltaWhenThereAreDifferenceOutsideOf16Bits(void) +{ + TEST_ASSERT_UINT16_WITHIN(5, 0x54321, 0x44321); +} + +void testUINT16sWithinDeltaWhenThereAreDifferenceOutsideOf16BitsAndCustomMessage(void) +{ + TEST_ASSERT_UINT16_WITHIN_MESSAGE(5, 0x54321, 0x44321, "Custom Message."); +} + +void testUINT16sNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT16_WITHIN(2, 65535, 0); + VERIFY_FAILS_END +} + +void testUINT16sNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT16_WITHIN_MESSAGE(2, 65535, 0, "Custom Message."); + VERIFY_FAILS_END +} + +void testUINT8sWithinDelta(void) +{ + TEST_ASSERT_UINT8_WITHIN(1, 254, 255); + TEST_ASSERT_UINT8_WITHIN(5, 251, 255); + TEST_ASSERT_UINT8_WITHIN(5, 1, 4); +} + +void testUINT8sWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_UINT8_WITHIN_MESSAGE(1, 254, 255, "Custom Message."); + TEST_ASSERT_UINT8_WITHIN_MESSAGE(5, 251, 255, "Custom Message."); + TEST_ASSERT_UINT8_WITHIN_MESSAGE(5, 1, 4, "Custom Message."); +} + +void testUINT8sWithinDeltaWhenThereAreDifferenceOutsideOf8Bits(void) +{ + TEST_ASSERT_UINT8_WITHIN(5, 0x123, 0xF23); +} + +void testUINT8sWithinDeltaWhenThereAreDifferenceOutsideOf8BitsAndCustomMessage(void) +{ + TEST_ASSERT_UINT8_WITHIN_MESSAGE(5, 0x123, 0xF23, "Custom Message."); +} + +void testUINT8sNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT8_WITHIN(2, 255, 0); + VERIFY_FAILS_END +} + +void testUINT8sNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT8_WITHIN_MESSAGE(2, 255, 0, "Custom Message."); + VERIFY_FAILS_END +} + +void testINT32sWithinDelta(void) +{ + TEST_ASSERT_INT32_WITHIN(1, 5000, 5001); + TEST_ASSERT_INT32_WITHIN(5, 1, -2); + TEST_ASSERT_INT32_WITHIN(5, -2, 1); +} + +void testINT32sWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_INT32_WITHIN_MESSAGE(1, 5000, 5001, "Custom Message."); +} + +void testINT32sNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT32_WITHIN(1, -3, 1); + VERIFY_FAILS_END +} + +void testINT32sNotWithinDeltaAndDifferenceOverflows(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT32_WITHIN(1, -1, 0x7FFFFFFF); + VERIFY_FAILS_END +} +void testINT32sNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT32_WITHIN_MESSAGE(1, -2, 1, "Custom Message."); + VERIFY_FAILS_END +} + +void testINT16sWithinDelta(void) +{ + TEST_ASSERT_INT16_WITHIN(1, 5000, 5001); + TEST_ASSERT_INT16_WITHIN(5, 2, -2); + TEST_ASSERT_INT16_WITHIN(5, -2, 2); +} + +void testINT16sWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_INT16_WITHIN_MESSAGE(1, 5000, 5001, "Custom Message."); +} + +void testINT16sWithinDeltaWhenThereAreDifferenceOutsideOf16Bits(void) +{ + TEST_ASSERT_INT16_WITHIN(5, 0x54321, 0x44321); +} + +void testINT16sWithinDeltaWhenThereAreDifferenceOutsideOf16BitsAndCustomMessage(void) +{ + TEST_ASSERT_INT16_WITHIN_MESSAGE(5, 0x54321, 0x44321, "Custom Message."); +} + +void testINT16sNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT16_WITHIN(2, 4, -2); + VERIFY_FAILS_END +} + +void testINT16sNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT16_WITHIN_MESSAGE(2, 3, 0, "Custom Message."); + VERIFY_FAILS_END +} + +void testINT8sWithinDelta(void) +{ + TEST_ASSERT_INT8_WITHIN(1, 127, 126); + TEST_ASSERT_INT8_WITHIN(5, -2, 2); + TEST_ASSERT_INT8_WITHIN(5, 2, -2); +} + +void testINT8sWithinDeltaAndCustomMessage(void) +{ + TEST_ASSERT_INT8_WITHIN_MESSAGE(5, 1, 4, "Custom Message."); +} + +void testINT8sWithinDeltaWhenThereAreDifferenceOutsideOf8Bits(void) +{ + TEST_ASSERT_INT8_WITHIN(5, 0x123, 0xF23); +} + +void testINT8sWithinDeltaWhenThereAreDifferenceOutsideOf8BitsAndCustomMessage(void) +{ + TEST_ASSERT_INT8_WITHIN_MESSAGE(5, 0x123, 0xF23, "Custom Message."); +} + +void testINT8sNotWithinDelta(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT8_WITHIN(2, -3, 0); + VERIFY_FAILS_END +} + +void testINT8sNotWithinDeltaAndCustomMessage(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT8_WITHIN_MESSAGE(2, -4, 0, "Custom Message."); + VERIFY_FAILS_END +} + +void testEqualStrings(void) +{ + const char *testString = "foo"; + + TEST_ASSERT_EQUAL_STRING(testString, testString); + TEST_ASSERT_EQUAL_STRING_MESSAGE("foo", "foo", "foo isn't foo"); + TEST_ASSERT_EQUAL_STRING("foo", testString); + TEST_ASSERT_EQUAL_STRING(testString, "foo"); + TEST_ASSERT_EQUAL_STRING("", ""); +} + +void testEqualStringsLen(void) +{ + const char *testString = "foobar"; + TEST_ASSERT_EQUAL_STRING_LEN(testString, testString, strlen(testString)); + TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE("foobar", "foobaz", 5, "fooba isn't fooba"); + TEST_ASSERT_EQUAL_STRING_LEN("foo", testString, 3); + TEST_ASSERT_EQUAL_STRING_LEN(testString, "foo", 3); + TEST_ASSERT_EQUAL_STRING_LEN("", "", 3); +} + +void testEqualStringsWithCarriageReturnsAndLineFeeds(void) +{ + const char *testString = "foo\r\nbar"; + + TEST_ASSERT_EQUAL_STRING(testString, testString); + TEST_ASSERT_EQUAL_STRING("foo\r\nbar", "foo\r\nbar"); + TEST_ASSERT_EQUAL_STRING("foo\r\nbar", testString); + TEST_ASSERT_EQUAL_STRING(testString, "foo\r\nbar"); + TEST_ASSERT_EQUAL_STRING("", ""); +} + +void testNotEqualString1(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING("foo", "bar"); + VERIFY_FAILS_END +} + +void testNotEqualStringLen1(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_LEN("foobar", "foobaz", 6); + VERIFY_FAILS_END +} + +void testNotEqualString2(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING("foo", ""); + VERIFY_FAILS_END +} + +void testNotEqualStringLen2(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_LEN("foo", "", 3); + VERIFY_FAILS_END +} + +void testNotEqualString3(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING("", "bar"); + VERIFY_FAILS_END +} + +void testNotEqualStringLen3(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_LEN("", "bar", 3); + VERIFY_FAILS_END +} + +void testNotEqualString4(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING("bar\r", "bar\n"); + VERIFY_FAILS_END +} + +void testNotEqualStringLen4(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_LEN("\r\x16", "bar\n", 4); + VERIFY_FAILS_END +} + +void testNotEqualString5(void) +{ + const char str1[] = { 0x41, 0x42, 0x03, 0x00 }; + const char str2[] = { 0x41, 0x42, 0x04, 0x00 }; + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING(str1, str2); + VERIFY_FAILS_END +} + +void testNotEqualString_ExpectedStringIsNull(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING(NULL, "bar"); + VERIFY_FAILS_END +} + +void testNotEqualStringLen_ExpectedStringIsNull(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_LEN(NULL, "bar", 1); + VERIFY_FAILS_END +} + +void testNotEqualString_ActualStringIsNull(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING("foo", NULL); + VERIFY_FAILS_END +} + +void testNotEqualStringLen_ActualStringIsNull(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_LEN("foo", NULL, 1); + VERIFY_FAILS_END +} + +void testEqualStringArrays(void) +{ + const char *testStrings[] = { "foo", "boo", "woo", "moo" }; + const char *expStrings[] = { "foo", "boo", "woo", "zoo" }; + + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, expStrings, 3); + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 3); + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 2); + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 1); +} + +void testNotEqualStringArray1(void) +{ + const char *testStrings[] = { "foo", "boo", "woo", "moo" }; + const char *expStrings[] = { "foo", "boo", "woo", "zoo" }; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 4); + VERIFY_FAILS_END +} + +void testNotEqualStringArray2(void) +{ + const char *testStrings[] = { "zoo", "boo", "woo", "moo" }; + const char *expStrings[] = { "foo", "boo", "woo", "moo" }; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 4); + VERIFY_FAILS_END +} + +void testNotEqualStringArray3(void) +{ + const char *testStrings[] = { "foo", "boo", "woo", NULL }; + const char *expStrings[] = { "foo", "boo", "woo", "zoo" }; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 4); + VERIFY_FAILS_END +} + +void testNotEqualStringArray4(void) +{ + const char *testStrings[] = { "foo", "boo", "woo", "moo" }; + const char *expStrings[] = { "foo", NULL, "woo", "moo" }; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 4); + VERIFY_FAILS_END +} + +void testNotEqualStringArray5(void) +{ + const char **testStrings = NULL; + const char *expStrings[] = { "foo", "boo", "woo", "zoo" }; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 4); + VERIFY_FAILS_END +} + +void testNotEqualStringArray6(void) +{ + const char *testStrings[] = { "foo", "boo", "woo", "zoo" }; + const char **expStrings = NULL; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 4); + VERIFY_FAILS_END +} + +void testEqualStringArrayIfBothNulls(void) +{ + const char **testStrings = NULL; + const char **expStrings = NULL; + + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 4); +} + +void testNotEqualStringArrayLengthZero(void) +{ + const char *testStrings[] = {NULL}; + const char **expStrings = NULL; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_ARRAY(expStrings, testStrings, 0); + VERIFY_FAILS_END +} + +void testEqualMemory(void) +{ + const char *testString = "whatever"; + + TEST_ASSERT_EQUAL_MEMORY(testString, testString, 8); + TEST_ASSERT_EQUAL_MEMORY("whatever", "whatever", 8); + TEST_ASSERT_EQUAL_MEMORY("whatever", testString, 8); + TEST_ASSERT_EQUAL_MEMORY(testString, "whatever", 8); + TEST_ASSERT_EQUAL_MEMORY(testString, "whatever", 2); + TEST_ASSERT_EQUAL_MEMORY(NULL, NULL, 1); +} + +void testNotEqualMemory1(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY("foo", "bar", 3); + VERIFY_FAILS_END +} + +void testNotEqualMemory2(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY("fool", "food", 4); + VERIFY_FAILS_END +} + +void testNotEqualMemory3(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY(NULL, "food", 4); + VERIFY_FAILS_END +} + +void testNotEqualMemory4(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY("fool", NULL, 4); + VERIFY_FAILS_END +} + +void testNotEqualMemoryLengthZero(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY(NULL, NULL, 0); + VERIFY_FAILS_END +} + +void testEqualIntArrays(void) +{ + int p0[] = {1, 8, 987, -2}; + int p1[] = {1, 8, 987, -2}; + int p2[] = {1, 8, 987, 2}; + int p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p3, 1); + TEST_ASSERT_EQUAL_INT_ARRAY(NULL, NULL, 1); +} + +void testNotEqualIntArraysNullExpected(void) +{ + int* p0 = NULL; + int p1[] = {1, 8, 987, 2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualIntArraysNullActual(void) +{ + int* p1 = NULL; + int p0[] = {1, 8, 987, 2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualIntArrays1(void) +{ + int p0[] = {1, 8, 987, -2}; + int p1[] = {1, 8, 987, 2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualIntArrays2(void) +{ + int p0[] = {1, 8, 987, -2}; + int p1[] = {2, 8, 987, -2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualIntArrays3(void) +{ + int p0[] = {1, 8, 987, -2}; + int p1[] = {1, 8, 986, -2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualIntArraysLengthZero(void) +{ + _UU32 p0[1] = {1}; + _UU32 p1[1] = {1}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT_ARRAY(p0, p1, 0); + VERIFY_FAILS_END +} + +void testEqualPtrArrays(void) +{ + char A = 1; + char B = 2; + char C = 3; + char* p0[] = {&A, &B, &C}; + char* p1[] = {&A, &B, &C, &A}; + char* p2[] = {&A, &B}; + char* p3[] = {&A}; + + TEST_ASSERT_EQUAL_PTR_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_PTR_ARRAY(p0, p0, 3); + TEST_ASSERT_EQUAL_PTR_ARRAY(p0, p1, 3); + TEST_ASSERT_EQUAL_PTR_ARRAY(p1, p2, 2); + TEST_ASSERT_EQUAL_PTR_ARRAY(p3, p0, 1); +} + +void testNotEqualPtrArraysNullExpected(void) +{ + char A = 1; + char B = 2; + char** p0 = NULL; + char* p1[] = {&A, &B}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_PTR_ARRAY(p0, p1, 2); + VERIFY_FAILS_END +} + +void testNotEqualPtrArraysNullActual(void) +{ + char A = 1; + char B = 2; + char** p0 = NULL; + char* p1[] = {&A, &B}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_PTR_ARRAY(p1, p0, 2); + VERIFY_FAILS_END +} + +void testNotEqualPtrArrays1(void) +{ + char A = 1; + char B = 2; + char C = 3; + char* p0[] = {&A, &B, &C, &B}; + char* p1[] = {&A, &B, &C, &A}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_PTR_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualPtrArrays2(void) +{ + char A = 1; + char B = 2; + char C = 3; + char* p0[] = {&B, &B, &C, &A}; + char* p1[] = {&A, &B, &C, &A}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_PTR_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualPtrArrays3(void) +{ + char A = 1; + char B = 2; + char C = 3; + char* p0[] = {&A, &B, &B, &A}; + char* p1[] = {&A, &B, &C, &A}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_PTR_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualInt8Arrays(void) +{ + _US8 p0[] = {1, 8, 117, -2}; + _US8 p1[] = {1, 8, 117, -2}; + _US8 p2[] = {1, 8, 117, 2}; + _US8 p3[] = {1, 50, 60, 70}; + + TEST_ASSERT_EQUAL_INT8_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_INT8_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_INT8_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_INT8_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_INT8_ARRAY(p0, p3, 1); +} + +void testNotEqualInt8Arrays(void) +{ + _US8 p0[] = {1, 8, 36, -2}; + _US8 p1[] = {1, 8, 36, 2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT8_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualUIntArrays(void) +{ + unsigned int p0[] = {1, 8, 987, 65132u}; + unsigned int p1[] = {1, 8, 987, 65132u}; + unsigned int p2[] = {1, 8, 987, 2}; + unsigned int p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_UINT_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_UINT_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_UINT_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_UINT_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_UINT_ARRAY(p0, p3, 1); +} + +void testNotEqualUIntArrays1(void) +{ + unsigned int p0[] = {1, 8, 987, 65132u}; + unsigned int p1[] = {1, 8, 987, 65131u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualUIntArrays2(void) +{ + unsigned int p0[] = {1, 8, 987, 65132u}; + unsigned int p1[] = {2, 8, 987, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualUIntArrays3(void) +{ + unsigned int p0[] = {1, 8, 987, 65132u}; + unsigned int p1[] = {1, 8, 986, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualInt16Arrays(void) +{ + _US16 p0[] = {1, 8, 117, 3}; + _US16 p1[] = {1, 8, 117, 3}; + _US16 p2[] = {1, 8, 117, 2}; + _US16 p3[] = {1, 50, 60, 70}; + + TEST_ASSERT_EQUAL_INT16_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_INT16_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_INT16_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_INT16_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_INT16_ARRAY(p0, p3, 1); +} + +void testNotEqualInt16Arrays(void) +{ + _US16 p0[] = {1, 8, 127, 3}; + _US16 p1[] = {1, 8, 127, 2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT16_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualInt32Arrays(void) +{ + _US32 p0[] = {1, 8, 117, 3}; + _US32 p1[] = {1, 8, 117, 3}; + _US32 p2[] = {1, 8, 117, 2}; + _US32 p3[] = {1, 50, 60, 70}; + + TEST_ASSERT_EQUAL_INT32_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_INT32_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_INT32_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_INT32_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_INT32_ARRAY(p0, p3, 1); +} + +void testNotEqualInt32Arrays(void) +{ + _US32 p0[] = {1, 8, 127, 3}; + _US32 p1[] = {1, 8, 127, 2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT32_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualUINT8Arrays(void) +{ + _UU8 p0[] = {1, 8, 100, 127}; + _UU8 p1[] = {1, 8, 100, 127}; + _UU8 p2[] = {1, 8, 100, 2}; + _UU8 p3[] = {1, 50, 60, 70}; + + TEST_ASSERT_EQUAL_UINT8_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_UINT8_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_UINT8_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_UINT8_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_UINT8_ARRAY(p0, p3, 1); +} + +void testNotEqualUINT8Arrays1(void) +{ + unsigned char p0[] = {1, 8, 100, 127u}; + unsigned char p1[] = {1, 8, 100, 255u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT8_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualUINT8Arrays2(void) +{ + unsigned char p0[] = {1, 8, 100, 127u}; + unsigned char p1[] = {1, 8, 100, 255u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT8_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualUINT8Arrays3(void) +{ + unsigned char p0[] = {1, 8, 100, 127u}; + unsigned char p1[] = {1, 8, 100, 255u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT8_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + + +void testEqualUINT16Arrays(void) +{ + unsigned short p0[] = {1, 8, 987, 65132u}; + unsigned short p1[] = {1, 8, 987, 65132u}; + unsigned short p2[] = {1, 8, 987, 2}; + unsigned short p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_UINT16_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_UINT16_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_UINT16_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_UINT16_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_UINT16_ARRAY(p0, p3, 1); +} + +void testNotEqualUINT16Arrays1(void) +{ + unsigned short p0[] = {1, 8, 987, 65132u}; + unsigned short p1[] = {1, 8, 987, 65131u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT16_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualUINT16Arrays2(void) +{ + unsigned short p0[] = {1, 8, 987, 65132u}; + unsigned short p1[] = {2, 8, 987, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT16_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualUINT16Arrays3(void) +{ + unsigned short p0[] = {1, 8, 987, 65132u}; + unsigned short p1[] = {1, 8, 986, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT16_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualUINT32Arrays(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {1, 8, 987, 65132u}; + _UU32 p2[] = {1, 8, 987, 2}; + _UU32 p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_UINT32_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_UINT32_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_UINT32_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_UINT32_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_UINT32_ARRAY(p0, p3, 1); +} + +void testNotEqualUINT32Arrays1(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {1, 8, 987, 65131u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT32_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualUINT32Arrays2(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {2, 8, 987, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT32_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualUINT32Arrays3(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {1, 8, 986, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT32_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualHEXArrays(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {1, 8, 987, 65132u}; + _UU32 p2[] = {1, 8, 987, 2}; + _UU32 p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_HEX_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_HEX_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_HEX_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p3, 1); +} + +void testNotEqualHEXArrays1(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {1, 8, 987, 65131u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualHEXArrays2(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {2, 8, 987, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualHEXArrays3(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {1, 8, 986, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualHEX32Arrays(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {1, 8, 987, 65132u}; + _UU32 p2[] = {1, 8, 987, 2}; + _UU32 p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p3, 1); +} + +void testNotEqualHEX32Arrays1(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {1, 8, 987, 65131u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualHEX32Arrays2(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {2, 8, 987, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualHEX32Arrays3(void) +{ + _UU32 p0[] = {1, 8, 987, 65132u}; + _UU32 p1[] = {1, 8, 986, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX32_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualHEX16Arrays(void) +{ + unsigned short p0[] = {1, 8, 987, 65132u}; + unsigned short p1[] = {1, 8, 987, 65132u}; + unsigned short p2[] = {1, 8, 987, 2}; + unsigned short p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_HEX16_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_HEX16_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_HEX16_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_HEX16_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_HEX16_ARRAY(p0, p3, 1); +} + +void testNotEqualHEX16Arrays1(void) +{ + unsigned short p0[] = {1, 8, 987, 65132u}; + unsigned short p1[] = {1, 8, 987, 65131u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX16_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualHEX16Arrays2(void) +{ + unsigned short p0[] = {1, 8, 987, 65132u}; + unsigned short p1[] = {2, 8, 987, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX16_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualHEX16Arrays3(void) +{ + unsigned short p0[] = {1, 8, 987, 65132u}; + unsigned short p1[] = {1, 8, 986, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX16_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualHEX8Arrays(void) +{ + unsigned short p0[] = {1, 8, 254u, 123}; + unsigned short p1[] = {1, 8, 254u, 123}; + unsigned short p2[] = {1, 8, 254u, 2}; + unsigned short p3[] = {1, 23, 25, 26}; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p3, 1); +} + +void testNotEqualHEX8Arrays1(void) +{ + unsigned char p0[] = {1, 8, 254u, 253u}; + unsigned char p1[] = {1, 8, 254u, 252u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualHEX8Arrays2(void) +{ + unsigned char p0[] = {1, 8, 254u, 253u}; + unsigned char p1[] = {2, 8, 254u, 253u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testNotEqualHEX8Arrays3(void) +{ + unsigned char p0[] = {1, 8, 254u, 253u}; + unsigned char p1[] = {1, 8, 255u, 253u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX8_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +} + +void testEqualMemoryArrays(void) +{ + int p0[] = {1, 8, 987, -2}; + int p1[] = {1, 8, 987, -2}; + int p2[] = {1, 8, 987, 2}; + int p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p0, sizeof(int), 1); + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p0, sizeof(int), 4); + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p1, sizeof(int), 4); + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p2, sizeof(int), 3); + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p3, sizeof(int), 1); +} + +void testNotEqualMemoryArraysExpectedNull(void) +{ + int* p0 = NULL; + int p1[] = {1, 8, 987, 2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p1, sizeof(int), 4); + VERIFY_FAILS_END +} + +void testNotEqualMemoryArraysActualNull(void) +{ + int p0[] = {1, 8, 987, -2}; + int* p1 = NULL; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p1, sizeof(int), 4); + VERIFY_FAILS_END +} + +void testNotEqualMemoryArrays1(void) +{ + int p0[] = {1, 8, 987, -2}; + int p1[] = {1, 8, 987, 2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p1, sizeof(int), 4); + VERIFY_FAILS_END +} + +void testNotEqualMemoryArrays2(void) +{ + int p0[] = {1, 8, 987, -2}; + int p1[] = {2, 8, 987, -2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p1, sizeof(int), 4); + VERIFY_FAILS_END +} + +void testNotEqualMemoryArrays3(void) +{ + int p0[] = {1, 8, 987, -2}; + int p1[] = {1, 8, 986, -2}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_MEMORY_ARRAY(p0, p1, sizeof(int), 4); + VERIFY_FAILS_END +} + +void testProtection(void) +{ + volatile int mask = 0; + + if (TEST_PROTECT()) + { + mask |= 1; + TEST_ABORT(); + } + else + { + Unity.CurrentTestFailed = 0; + mask |= 2; + } + + TEST_ASSERT_EQUAL(3, mask); +} + +void testIgnoredAndThenFailInTearDown(void) +{ + SetToOneToFailInTearDown = 1; + TEST_IGNORE(); +} + +// Tricky series of macros to set USING_OUTPUT_SPY +#define USING_SPY_AS(a) EXPAND_AND_USE_2ND(ASSIGN_VALUE(a), 0) +#define ASSIGN_VALUE(a) VAL_##a +#define VAL_putcharSpy 0, 1 +#define EXPAND_AND_USE_2ND(a, b) SECOND_PARAM(a, b, throwaway) +#define SECOND_PARAM(a, b, ...) b +#if USING_SPY_AS(UNITY_OUTPUT_CHAR) + #define USING_OUTPUT_SPY // true only if UNITY_OUTPUT_CHAR = putcharSpy +#endif + +#ifdef USING_OUTPUT_SPY +#include <stdio.h> +#define SPY_BUFFER_MAX 40 +static char putcharSpyBuffer[SPY_BUFFER_MAX]; +#endif +static int indexSpyBuffer; +static int putcharSpyEnabled; + +void startPutcharSpy(void) {indexSpyBuffer = 0; putcharSpyEnabled = 1;} + +void endPutcharSpy(void) {putcharSpyEnabled = 0;} + +char* getBufferPutcharSpy(void) +{ +#ifdef USING_OUTPUT_SPY + putcharSpyBuffer[indexSpyBuffer] = '\0'; + return putcharSpyBuffer; +#else + return NULL; +#endif +} + +void putcharSpy(int c) +{ +#ifdef USING_OUTPUT_SPY + if (putcharSpyEnabled) + { + if (indexSpyBuffer < SPY_BUFFER_MAX - 1) + putcharSpyBuffer[indexSpyBuffer++] = (char)c; + } else + c = putchar(c); +#endif +} + +void testFailureCountIncrementsAndIsReturnedAtEnd(void) +{ + Unity.CurrentTestFailed = 1; + startPutcharSpy(); // Suppress output + UnityConcludeTest(); + TEST_ASSERT_EQUAL(1, Unity.TestFailures); + + int failures = UnityEnd(); + Unity.TestFailures--; + endPutcharSpy(); + TEST_ASSERT_EQUAL(1, failures); +} + +#define TEST_ASSERT_EQUAL_PRINT_NUMBERS(expected, actual) { \ + startPutcharSpy(); UnityPrintNumber((actual)); endPutcharSpy(); \ + TEST_ASSERT_EQUAL_STRING((expected), getBufferPutcharSpy()); \ + } + +#define TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS(expected, actual) { \ + startPutcharSpy(); UnityPrintNumberUnsigned((actual)); endPutcharSpy(); \ + TEST_ASSERT_EQUAL_STRING((expected), getBufferPutcharSpy()); \ + } + +void testPrintNumbers32(void) +{ +#ifndef USING_OUTPUT_SPY + TEST_IGNORE_MESSAGE("Compile with '-D UNITY_OUTPUT_CHAR=putcharSpy' to enable print testing"); +#else + TEST_ASSERT_EQUAL_PRINT_NUMBERS("0", 0); + TEST_ASSERT_EQUAL_PRINT_NUMBERS("1", 1); + TEST_ASSERT_EQUAL_PRINT_NUMBERS("-1", -1); + TEST_ASSERT_EQUAL_PRINT_NUMBERS("2000000000", 2000000000); + TEST_ASSERT_EQUAL_PRINT_NUMBERS("-2147483648", (_US32)0x80000000); + TEST_ASSERT_EQUAL_PRINT_NUMBERS("-1", (_US32)0xFFFFFFFF); +#endif +} + +void testPrintNumbersUnsigned32(void) +{ +#ifndef USING_OUTPUT_SPY + TEST_IGNORE(); +#else + TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS("0", 0); + TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS("1", 1); + TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS("1500000000", 1500000000); + TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS("2147483648", (_UU32)0x80000000); + TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS("4294967295", (_UU32)0xFFFFFFFF); +#endif +} + +// ===================== THESE TEST WILL RUN IF YOUR CONFIG INCLUDES 64 BIT SUPPORT ================== + +void testPrintNumbersInt64(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + #ifndef USING_OUTPUT_SPY + TEST_IGNORE(); + #else + TEST_ASSERT_EQUAL_PRINT_NUMBERS("0", 0); + TEST_ASSERT_EQUAL_PRINT_NUMBERS("10000000000", 10000000000); + TEST_ASSERT_EQUAL_PRINT_NUMBERS("-9223372036854775808", (_U_SINT)0x8000000000000000); + TEST_ASSERT_EQUAL_PRINT_NUMBERS("-1", (_U_SINT)0xFFFFFFFFFFFFFFFF); + #endif +#endif +} + +void testPrintNumbersUInt64(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + #ifndef USING_OUTPUT_SPY + TEST_IGNORE(); + #else + TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS("0", 0); + TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS("70000000000", 70000000000); + TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS("9223372036854775808", (_U_UINT)0x8000000000000000); + TEST_ASSERT_EQUAL_PRINT_UNSIGNED_NUMBERS("18446744073709551615", (_U_UINT)0xFFFFFFFFFFFFFFFF); + #endif +#endif +} + +void testEqualHex64s(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _UU64 v0, v1; + _UU64 *p0, *p1; + + v0 = 0x9876543201234567; + v1 = 0x9876543201234567; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_HEX64(0x9876543201234567, 0x9876543201234567); + TEST_ASSERT_EQUAL_HEX64(v0, v1); + TEST_ASSERT_EQUAL_HEX64(0x9876543201234567, v1); + TEST_ASSERT_EQUAL_HEX64(v0, 0x9876543201234567); + TEST_ASSERT_EQUAL_HEX64(*p0, v1); + TEST_ASSERT_EQUAL_HEX64(*p0, *p1); + TEST_ASSERT_EQUAL_HEX64(*p0, 0x9876543201234567); +#endif +} + +void testEqualUint64s(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _UU64 v0, v1; + _UU64 *p0, *p1; + + v0 = 0x9876543201234567; + v1 = 0x9876543201234567; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_UINT64(0x9876543201234567, 0x9876543201234567); + TEST_ASSERT_EQUAL_UINT64(v0, v1); + TEST_ASSERT_EQUAL_UINT64(0x9876543201234567, v1); + TEST_ASSERT_EQUAL_UINT64(v0, 0x9876543201234567); + TEST_ASSERT_EQUAL_UINT64(*p0, v1); + TEST_ASSERT_EQUAL_UINT64(*p0, *p1); + TEST_ASSERT_EQUAL_UINT64(*p0, 0x9876543201234567); +#endif +} + +void testEqualInt64s(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _US64 v0, v1; + _US64 *p0, *p1; + + v0 = (_US64)0x9876543201234567; + v1 = (_US64)0x9876543201234567; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_EQUAL_INT64(0x9876543201234567, 0x9876543201234567); + TEST_ASSERT_EQUAL_INT64(v0, v1); + TEST_ASSERT_EQUAL_INT64(0x9876543201234567, v1); + TEST_ASSERT_EQUAL_INT64(v0, 0x9876543201234567); + TEST_ASSERT_EQUAL_INT64(*p0, v1); + TEST_ASSERT_EQUAL_INT64(*p0, *p1); + TEST_ASSERT_EQUAL_INT64(*p0, 0x9876543201234567); +#endif +} + + +void testNotEqualHex64s(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _UU64 v0, v1; + + v0 = 9000000000; + v1 = 9100000000; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX64(v0, v1); + VERIFY_FAILS_END +#endif +} + +void testNotEqualUint64s(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _UU64 v0, v1; + + v0 = 9000000000; + v1 = 9100000000; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT64(v0, v1); + VERIFY_FAILS_END +#endif +} + +void testNotEqualInt64s(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _US64 v0, v1; + + v0 = -9000000000; + v1 = 9100000000; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT64(v0, v1); + VERIFY_FAILS_END +#endif +} + +void testNotEqualHex64sIfSigned(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _US64 v0, v1; + + v0 = -9000000000; + v1 = 9000000000; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX64(v0, v1); + VERIFY_FAILS_END +#endif +} + +void testHEX64sWithinDelta(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + TEST_ASSERT_HEX64_WITHIN(1, 0x7FFFFFFFFFFFFFFF,0x7FFFFFFFFFFFFFFE); + TEST_ASSERT_HEX64_WITHIN(5, 5000, 4996); + TEST_ASSERT_HEX64_WITHIN(5, 5000, 5005); +#endif +} + +void testHEX64sNotWithinDelta(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX64_WITHIN(1, 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFC); + VERIFY_FAILS_END +#endif +} + +void testHEX64sNotWithinDeltaEvenThoughASignedIntWouldPass(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_HEX64_WITHIN(5, 1, -1); + VERIFY_FAILS_END +#endif +} + +void testUINT64sWithinDelta(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + TEST_ASSERT_UINT64_WITHIN(1, 0x7FFFFFFFFFFFFFFF,0x7FFFFFFFFFFFFFFE); + TEST_ASSERT_UINT64_WITHIN(5, 5000, 4996); + TEST_ASSERT_UINT64_WITHIN(5, 5000, 5005); +#endif +} + +void testUINT64sNotWithinDelta(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT64_WITHIN(1, 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFC); + VERIFY_FAILS_END +#endif +} + +void testUINT64sNotWithinDeltaEvenThoughASignedIntWouldPass(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_UINT64_WITHIN(5, 1, -1); + VERIFY_FAILS_END +#endif +} + +void testINT64sWithinDelta(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + TEST_ASSERT_INT64_WITHIN(1, 0x7FFFFFFFFFFFFFFF,0x7FFFFFFFFFFFFFFE); + TEST_ASSERT_INT64_WITHIN(5, 5000, 4996); + TEST_ASSERT_INT64_WITHIN(5, 5000, 5005); +#endif +} + +void testINT64sNotWithinDelta(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT64_WITHIN(1, 0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFC); + VERIFY_FAILS_END +#endif +} + +void testINT64sNotWithinDeltaAndDifferenceOverflows(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_INT64_WITHIN(1, 0x8000000000000000, 0x7FFFFFFFFFFFFFFF); + VERIFY_FAILS_END +#endif +} + +void testEqualHEX64Arrays(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _UU64 p0[] = {1, 8, 987, 65132u}; + _UU64 p1[] = {1, 8, 987, 65132u}; + _UU64 p2[] = {1, 8, 987, 2}; + _UU64 p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_HEX64_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_HEX64_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_HEX64_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_HEX64_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_HEX64_ARRAY(p0, p3, 1); +#endif +} + +void testEqualUint64Arrays(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _UU64 p0[] = {1, 8, 987, 65132u}; + _UU64 p1[] = {1, 8, 987, 65132u}; + _UU64 p2[] = {1, 8, 987, 2}; + _UU64 p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_UINT64_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_UINT64_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_UINT64_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_UINT64_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_UINT64_ARRAY(p0, p3, 1); +#endif +} + +void testEqualInt64Arrays(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _US64 p0[] = {1, 8, 987, -65132}; + _US64 p1[] = {1, 8, 987, -65132}; + _US64 p2[] = {1, 8, 987, -2}; + _US64 p3[] = {1, 500, 600, 700}; + + TEST_ASSERT_EQUAL_INT64_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_INT64_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_INT64_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_INT64_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_INT64_ARRAY(p0, p3, 1); +#endif +} + + +void testNotEqualHEX64Arrays1(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _UU64 p0[] = {1, 8, 987, 65132u}; + _UU64 p1[] = {1, 8, 987, 65131u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX64_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualHEX64Arrays2(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _UU64 p0[] = {1, 8, 987, 65132u}; + _UU64 p1[] = {2, 8, 987, 65132u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX64_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualUint64Arrays(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _UU64 p0[] = {1, 8, 987, 65132u}; + _UU64 p1[] = {1, 8, 987, 65131u}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_UINT64_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualInt64Arrays(void) +{ +#ifndef UNITY_SUPPORT_64 + TEST_IGNORE(); +#else + _US64 p0[] = {1, 8, 987, -65132}; + _US64 p1[] = {1, 8, 987, -65131}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT64_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} +// ===================== THESE TEST WILL RUN IF YOUR CONFIG INCLUDES FLOAT SUPPORT ================== + +void testFloatsWithinDelta(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + TEST_ASSERT_FLOAT_WITHIN(0.00003f, 187245.03485f, 187245.03488f); + TEST_ASSERT_FLOAT_WITHIN(1.0f, 187245.0f, 187246.0f); + TEST_ASSERT_FLOAT_WITHIN(0.05f, 9273.2549f, 9273.2049f); + TEST_ASSERT_FLOAT_WITHIN(0.007f, -726.93724f, -726.94424f); +#endif +} + +void testFloatsNotWithinDelta(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_WITHIN(0.05f, 9273.2649f, 9273.2049f); + VERIFY_FAILS_END +#endif +} + +void testFloatsEqual(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + TEST_ASSERT_EQUAL_FLOAT(187245.0f, 187246.0f); + TEST_ASSERT_EQUAL_FLOAT(18724.5f, 18724.6f); + TEST_ASSERT_EQUAL_FLOAT(9273.2549f, 9273.2599f); + TEST_ASSERT_EQUAL_FLOAT(-726.93724f, -726.9374f); +#endif +} + +void testFloatsNotEqual(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(9273.9649f, 9273.0049f); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualNegative1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(-9273.9649f, -9273.0049f); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualNegative2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(-9273.0049f, -9273.9649f); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualActualNaN(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(85.963f, 0.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualExpectedNaN(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(0.0f / f_zero, 85.963f); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualBothNaN(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(0.0f / f_zero, 0.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualInfNaN(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(1.0f / f_zero, 0.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualNaNInf(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(0.0f / f_zero, 1.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualActualInf(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(321.642f, 1.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualExpectedInf(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(1.0f / f_zero, 321.642f); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualBothInf(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(1.0f / f_zero, 1.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatsNotEqualPlusMinusInf(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT(1.0f / f_zero, -1.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatIsPosInf1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + TEST_ASSERT_FLOAT_IS_INF(2.0f / f_zero); +#endif +} + +void testFloatIsPosInf2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_NOT_INF(2.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatIsNegInf1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + TEST_ASSERT_FLOAT_IS_NEG_INF(-3.0f / f_zero); +#endif +} + +void testFloatIsNegInf2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(-3.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatIsNotPosInf1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_INF(2.0f); + VERIFY_FAILS_END +#endif +} + +void testFloatIsNotPosInf2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + TEST_ASSERT_FLOAT_IS_NOT_INF(2.0f); +#endif +} + +void testFloatIsNotNegInf(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_NEG_INF(-999.876f); + VERIFY_FAILS_END +#endif +} + +void testFloatIsNan1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + TEST_ASSERT_FLOAT_IS_NAN(0.0f / f_zero); +#endif +} + +void testFloatIsNan2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_NOT_NAN(0.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatIsNotNan1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_NAN(234.9f); + VERIFY_FAILS_END +#endif +} + +void testFloatIsNotNan2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + TEST_ASSERT_FLOAT_IS_NOT_NAN(234.9f); +#endif +} + +void testFloatInfIsNotNan(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_NAN(1.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatNanIsNotInf(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_INF(0.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatIsDeterminate1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + TEST_ASSERT_FLOAT_IS_DETERMINATE(0.0f); + TEST_ASSERT_FLOAT_IS_DETERMINATE(123.3f); + TEST_ASSERT_FLOAT_IS_DETERMINATE(-88.3f); +#endif +} + +void testFloatIsDeterminate2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(-88.3f); + VERIFY_FAILS_END +#endif +} + +void testFloatIsNotDeterminate1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(1.0f / f_zero); + TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(-1.0f / f_zero); + TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(0.0f / f_zero); +#endif +} + +void testFloatIsNotDeterminate2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_FLOAT_IS_DETERMINATE(-1.0f / f_zero); + VERIFY_FAILS_END +#endif +} + +void testFloatTraitFailsOnInvalidTrait(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + UnityAssertFloatSpecial(1.0f, NULL, __LINE__, UNITY_FLOAT_INVALID_TRAIT); + VERIFY_FAILS_END +#endif +} + + +void testEqualFloatArrays(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {1.0f, -8.0f, 25.4f, -0.123f}; + float p1[] = {1.0f, -8.0f, 25.4f, -0.123f}; + float p2[] = {1.0f, -8.0f, 25.4f, -0.2f}; + float p3[] = {1.0f, -23.0f, 25.0f, -0.26f}; + + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p3, 1); + TEST_ASSERT_EQUAL_FLOAT_ARRAY(NULL, NULL, 1); +#endif +} + +void testNotEqualFloatArraysExpectedNull(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float* p0 = NULL; + float p1[] = {1.0f, 8.0f, 25.4f, 0.252f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArraysActualNull(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {1.0f, 8.0f, 25.4f, 0.253f}; + float* p1 = NULL; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArrays1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {1.0f, 8.0f, 25.4f, 0.253f}; + float p1[] = {1.0f, 8.0f, 25.4f, 0.252f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArrays2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {1.0f, 8.0f, 25.4f, 0.253f}; + float p1[] = {2.0f, 8.0f, 25.4f, 0.253f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArrays3(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {1.0f, 8.0f, 25.4f, 0.253f}; + float p1[] = {1.0f, 8.0f, 25.5f, 0.253f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArraysNegative1(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {-1.0f, -8.0f, -25.4f, -0.253f}; + float p1[] = {-1.0f, -8.0f, -25.4f, -0.252f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArraysNegative2(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {-1.0f, -8.0f, -25.4f, -0.253f}; + float p1[] = {-2.0f, -8.0f, -25.4f, -0.253f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArraysNegative3(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {-1.0f, -8.0f, -25.4f, -0.253f}; + float p1[] = {-1.0f, -8.0f, -25.5f, -0.253f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArraysNaN(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {1.0f, 0.0f / f_zero, 25.4f, 0.253f}; + float p1[] = {1.0f, 0.0f / f_zero, 25.4f, 0.253f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArraysInf(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[] = {1.0f, 1.0f / f_zero, 25.4f, 0.253f}; + float p1[] = {1.0f, 1.0f / f_zero, 25.4f, 0.253f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualFloatArraysLengthZero(void) +{ +#ifdef UNITY_EXCLUDE_FLOAT + TEST_IGNORE(); +#else + float p0[1] = {0.0f}; + float p1[1] = {0.0f}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_FLOAT_ARRAY(p0, p1, 0); + VERIFY_FAILS_END +#endif +} + +// ===================== THESE TEST WILL RUN IF YOUR CONFIG INCLUDES DOUBLE SUPPORT ================== + +void testDoublesWithinDelta(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + TEST_ASSERT_DOUBLE_WITHIN(0.00003, 187245.03485, 187245.03488); + TEST_ASSERT_DOUBLE_WITHIN(1.0, 187245.0, 187246.0); + TEST_ASSERT_DOUBLE_WITHIN(0.05, 9273.2549, 9273.2049); + TEST_ASSERT_DOUBLE_WITHIN(0.007, -726.93725, -726.94424); +#endif +} + +void testDoublesNotWithinDelta(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_WITHIN(0.05, 9273.2649, 9273.2049); + VERIFY_FAILS_END +#endif +} + + +void testDoublesEqual(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + TEST_ASSERT_EQUAL_DOUBLE(187245123456.0, 187245123456.0); + TEST_ASSERT_EQUAL_DOUBLE(187241234567.5, 187241234567.6); + TEST_ASSERT_EQUAL_DOUBLE(9273.2512345649, 9273.25123455699); + TEST_ASSERT_EQUAL_DOUBLE(-726.12345693724, -726.1234569374); +#endif +} + +void testDoublesNotEqual(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(9273.9649, 9273.0049); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualNegative1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(-9273.9649, -9273.0049); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualNegative2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(-9273.0049, -9273.9649); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualActualNaN(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(85.963, 0.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualExpectedNaN(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(0.0 / d_zero, 85.963); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualBothNaN(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(0.0 / d_zero, 0.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualInfNaN(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(1.0 / d_zero, 0.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualNaNInf(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(0.0 / d_zero, 1.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualActualInf(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(321.642, 1.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualExpectedInf(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(1.0 / d_zero, 321.642); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualBothInf(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(1.0 / d_zero, 1.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoublesNotEqualPlusMinusInf(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE(1.0 / d_zero, -1.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoubleIsPosInf1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + TEST_ASSERT_DOUBLE_IS_INF(2.0 / d_zero); +#endif +} + +void testDoubleIsPosInf2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_NOT_INF(2.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoubleIsNegInf1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + TEST_ASSERT_DOUBLE_IS_NEG_INF(-3.0 / d_zero); +#endif +} + +void testDoubleIsNegInf2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(-3.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoubleIsNotPosInf1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_INF(2.0); + VERIFY_FAILS_END +#endif +} + +void testDoubleIsNotPosInf2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + TEST_ASSERT_DOUBLE_IS_NOT_INF(2.0); +#endif +} + +void testDoubleIsNotNegInf(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_NEG_INF(-999.876); + VERIFY_FAILS_END +#endif +} + +void testDoubleIsNan1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + TEST_ASSERT_DOUBLE_IS_NAN(0.0 / d_zero); +#endif +} + +void testDoubleIsNan2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_NOT_NAN(0.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoubleIsNotNan1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_NAN(234.9); + VERIFY_FAILS_END +#endif +} + +void testDoubleIsNotNan2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + TEST_ASSERT_DOUBLE_IS_NOT_NAN(234.9); +#endif +} + +void testDoubleInfIsNotNan(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_NAN(1.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoubleNanIsNotInf(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_INF(0.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoubleIsDeterminate1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + TEST_ASSERT_DOUBLE_IS_DETERMINATE(0.0); + TEST_ASSERT_DOUBLE_IS_DETERMINATE(123.3); + TEST_ASSERT_DOUBLE_IS_DETERMINATE(-88.3); +#endif +} + +void testDoubleIsDeterminate2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(-88.3); + VERIFY_FAILS_END +#endif +} + +void testDoubleIsNotDeterminate1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(1.0 / d_zero); + TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(-1.0 / d_zero); + TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(0.0 / d_zero); +#endif +} + +void testDoubleIsNotDeterminate2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + TEST_ASSERT_DOUBLE_IS_DETERMINATE(-1.0 / d_zero); + VERIFY_FAILS_END +#endif +} + +void testDoubleTraitFailsOnInvalidTrait(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + EXPECT_ABORT_BEGIN + UnityAssertDoubleSpecial(1.0, NULL, __LINE__, UNITY_FLOAT_INVALID_TRAIT); + VERIFY_FAILS_END +#endif +} + +void testEqualDoubleArrays(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {1.0, -8.0, 25.4, -0.123}; + double p1[] = {1.0, -8.0, 25.4, -0.123}; + double p2[] = {1.0, -8.0, 25.4, -0.2}; + double p3[] = {1.0, -23.0, 25.0, -0.26}; + + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p0, 1); + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p0, 4); + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p2, 3); + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p3, 1); + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(NULL, NULL, 1); +#endif +} + +void testNotEqualDoubleArraysExpectedNull(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double* p0 = NULL; + double p1[] = {1.0, 8.0, 25.4, 0.252}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArraysActualNull(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {1.0, 8.0, 25.4, 0.253}; + double* p1 = NULL; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArrays1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {1.0, 8.0, 25.4, 0.25666666667}; + double p1[] = {1.0, 8.0, 25.4, 0.25666666666}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArrays2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {1.0, 8.0, 25.4, 0.253}; + double p1[] = {2.0, 8.0, 25.4, 0.253}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArrays3(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {1.0, 8.0, 25.4, 0.253}; + double p1[] = {1.0, 8.0, 25.5, 0.253}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArraysNegative1(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {-1.0, -8.0, -25.4, -0.2566666667}; + double p1[] = {-1.0, -8.0, -25.4, -0.2566666666}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArraysNegative2(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {-1.0, -8.0, -25.4, -0.253}; + double p1[] = {-2.0, -8.0, -25.4, -0.253}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArraysNegative3(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {-1.0, -8.0, -25.4, -0.253}; + double p1[] = {-1.0, -8.0, -25.5, -0.253}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArraysNaN(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {1.0, 0.0 / d_zero, 25.4, 0.253}; + double p1[] = {1.0, 0.0 / d_zero, 25.4, 0.253}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArraysInf(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[] = {1.0, 1.0 / d_zero, 25.4, 0.253}; + double p1[] = {1.0, 1.0 / d_zero, 25.4, 0.253}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 4); + VERIFY_FAILS_END +#endif +} + +void testNotEqualDoubleArraysLengthZero(void) +{ +#ifdef UNITY_EXCLUDE_DOUBLE + TEST_IGNORE(); +#else + double p0[1] = {0.0}; + double p1[1] = {0.0}; + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_DOUBLE_ARRAY(p0, p1, 0); + VERIFY_FAILS_END +#endif +} + +// ===================== THESE TEST WILL RUN IF YOUR CONFIG INCLUDES DETAIL SUPPORT ================== + +void testThatDetailsCanBeHandleOneDetail(void) +{ +#ifdef UNITY_EXCLUDE_DETAILS + TEST_IGNORE(); +#else + UNITY_SET_DETAIL("Detail1"); + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_INT_MESSAGE(5, 6, "Should Fail And Say Detail1"); + VERIFY_FAILS_END +#endif +} + +void testThatDetailsCanHandleTestFail(void) +{ +#ifdef UNITY_EXCLUDE_DETAILS + TEST_IGNORE(); +#else + UNITY_SET_DETAILS("Detail1","Detail2"); + + EXPECT_ABORT_BEGIN + TEST_FAIL_MESSAGE("Should Fail And Say Detail1 and Detail2"); + VERIFY_FAILS_END +#endif +} + +void testThatDetailsCanBeHandleTwoDetails(void) +{ +#ifdef UNITY_EXCLUDE_DETAILS + TEST_IGNORE(); +#else + UNITY_SET_DETAILS("Detail1","Detail2"); + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_HEX8_MESSAGE(7, 8, "Should Fail And Say Detail1 and Detail2"); + VERIFY_FAILS_END +#endif +} + +void testThatDetailsCanBeHandleSingleDetailClearingTwoDetails(void) +{ +#ifdef UNITY_EXCLUDE_DETAILS + TEST_IGNORE(); +#else + UNITY_SET_DETAILS("Detail1","Detail2"); + UNITY_SET_DETAIL("DetailNew"); + + EXPECT_ABORT_BEGIN + TEST_ASSERT_EQUAL_STRING_MESSAGE("MEH", "GUH", "Should Fail And Say DetailNew"); + VERIFY_FAILS_END +#endif +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/mbed_app.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/mbed_app.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,53 @@ +{ + "config": { + "run_pal_crypto_tests": { + "macro_name": "PAL_TEST_CRYPTO", + "value": true + }, + "run_pal_filesystem_tests": { + "macro_name": "PAL_TEST_FS", + "value": true + }, + "run_pal_networking_tests": { + "macro_name": "PAL_TEST_NETWORK", + "value": true + }, + "run_pal_rtos_tests": { + "macro_name": "PAL_TEST_RTOS", + "value": true + }, + "run_pal_tls_tests": { + "macro_name": "PAL_TEST_TLS", + "value": true + }, + "run_pal_update_tests": { + "macro_name": "PAL_TEST_UPDATE", + "value": true + } + }, + "macros": [ + "LWIP_NETIF_LOOPBACK=1", + "MBEDTLS_USER_CONFIG_FILE=\"Configs/mbedTLS/mbedTLSConfig_mbedOS.h\"" + ], + "target_overrides": { + "*": { + "target.features_add": [ + "NANOSTACK", + "LOWPAN_ROUTER", + "COMMON_PAL" + ], + "platform.stdio-baud-rate": 115200, + "platform.stdio-convert-newlines": true, + "mbed-trace.enable": true + }, + "UBLOX_EVK_ODIN_W2": { + "target.device_has_remove": [ + "EMAC" + ] + }, + "NUCLEO_F429ZI": { + "app.run_pal_filesystem_tests": false, + "app.run_pal_update_tests": false + } + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/pal_make.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Test/pal_make.py Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,19 @@ +import sys +import subprocess +import re + +pal_warn = re.compile("Warning.*pal") +pal_dont_treat_as_warn = re.compile("Warning.*PAL_INSECURE") + +proc = subprocess.Popen(sys.argv[1].split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + +for line in proc.stdout: + print line + if len(pal_warn.findall(line)) > 0: + if not len(pal_dont_treat_as_warn.findall(line)) > 0: + raise Exception("No Warnings Allowed in Pal") +proc.wait() +print "mbed compile returned {}".format(proc.returncode) +if not proc.returncode == 0: + raise Exception("mbed compile failed") +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Utils/memoryProfiler/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Utils/memoryProfiler/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +Other/* \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Utils/memoryProfiler/Other/pal_memory.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Utils/memoryProfiler/Other/pal_memory.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,142 @@ +/* + * pal_memory.c + * + * Created on: Jun 26, 2017 + * Author: pal + */ +#ifdef PAL_MEMORY_STATISTICS +#include "stdio.h" +#include "mbed-trace/mbed_trace.h" + + +#define TRACE_GROUP "PAL_MEMORY" + +#define SMALL_BUCKET 32 +#define LARGE_BUCKET 4096 + +typedef enum _memoryBucketSizes +{ + PAL_BUCKET_SIZE_32, + PAL_BUCKET_SIZE_64, + PAL_BUCKET_SIZE_128, + PAL_BUCKET_SIZE_256, + PAL_BUCKET_SIZE_512, + PAL_BUCKET_SIZE_1024, + PAL_BUCKET_SIZE_2048, + PAL_BUCKET_SIZE_4096, + PAL_BUCKET_SIZE_LARGE, + PAL_BUCKET_NUMBER +}memoryBucketSizes; + +typedef struct _memoryAllocationData +{ + int32_t totalsize; + int32_t waterMark; + int32_t buckets[PAL_BUCKET_NUMBER]; + int32_t waterMarkBuckets[PAL_BUCKET_NUMBER]; +}memoryAllocationData; + +static memoryAllocationData memoryStats = {0}; + + +static inline memoryBucketSizes getBucketNumber(size_t size) +{ + if (size <= SMALL_BUCKET) + { + return PAL_BUCKET_SIZE_32; + } + if (size >= LARGE_BUCKET) + { + return PAL_BUCKET_SIZE_LARGE; + } + + uint8_t bucket = 1; + uint32_t power = 64; // Starting with 32 + while (power < size) + { + bucket++; + power*=2; + } + return bucket; +} + + +void* __wrap_malloc(size_t c) +{ + void *ptr = __real_malloc(c + sizeof(size_t) + sizeof(size_t)); + if (ptr == NULL) + { + return NULL; + } + int32_t currentTotal = pal_osAtomicIncrement((&memoryStats.totalsize),c); + if (currentTotal > memoryStats.waterMark) + { + memoryStats.waterMark = currentTotal; // need to make this thread safe + } + + *(size_t*)ptr = c; + ptr = ((size_t*)ptr+1); + *(size_t*)ptr = (size_t)getBucketNumber(c); + int32_t currentBucketTotal = pal_osAtomicIncrement(&(memoryStats.buckets[*(size_t*)ptr]),1); + if (memoryStats.waterMarkBuckets[*(size_t*)ptr] < currentBucketTotal) + { + memoryStats.waterMarkBuckets[*(size_t*)ptr] = currentBucketTotal; + } + ptr = ((size_t*)ptr + 1); + return ptr; +} + + +void __wrap_free(void* ptr) +{ + if (NULL == ptr) + { + return; + } + ptr = ((size_t*)ptr-1); + pal_osAtomicIncrement(&(memoryStats.buckets[*(size_t*)ptr]),-1); + ptr = ((size_t*)ptr-1); + pal_osAtomicIncrement((&memoryStats.totalsize),-1*(*(size_t*)ptr)); + __real_free(ptr); +} + + +void* __wrap_calloc(size_t num, size_t size) +{ + void* ptr = __wrap_malloc(num*size); + if (NULL != ptr) + { + memset(ptr,0,(num*size)); + } + return (ptr); +} + + +void printMemoryStats(void) +{ + tr_info("\n*******************************************************\r\n"); + tr_info("water mark size = %ld\r\n",memoryStats.waterMark); + tr_info("total size = %ld\r\n",memoryStats.totalsize); + tr_info("bucket 32 allocation number %ld\r\n",memoryStats.buckets[0]); + tr_info("bucket 64 allocation number %ld\r\n",memoryStats.buckets[1]); + tr_info("bucket 128 allocation number %ld\r\n",memoryStats.buckets[2]); + tr_info("bucket 258 allocation number %ld\r\n",memoryStats.buckets[3]); + tr_info("bucket 512 allocation number %ld\r\n",memoryStats.buckets[4]); + tr_info("bucket 1024 allocation number %ld\r\n",memoryStats.buckets[5]); + tr_info("bucket 2048 allocation number %ld\r\n",memoryStats.buckets[6]); + tr_info("bucket 4096 allocation number %ld\r\n",memoryStats.buckets[7]); + tr_info("bucket large allocation number %ld\r\n",memoryStats.buckets[8]); + + + tr_info("water mark bucket 32 allocation number %ld\r\n",memoryStats.waterMarkBuckets[0]); + tr_info("water mark bucket 64 allocation number %ld\r\n",memoryStats.waterMarkBuckets[1]); + tr_info("water mark bucket 128 allocation number %ld\r\n",memoryStats.waterMarkBuckets[2]); + tr_info("water mark bucket 256 allocation number %ld\r\n",memoryStats.waterMarkBuckets[3]); + tr_info("water mark bucket 512 allocation number %ld\r\n",memoryStats.waterMarkBuckets[4]); + tr_info("water mark bucket 1024 allocation number %ld\r\n",memoryStats.waterMarkBuckets[5]); + tr_info("water mark bucket 2048 allocation number %ld\r\n",memoryStats.waterMarkBuckets[6]); + tr_info("water mark bucket 4096 allocation number %ld\r\n",memoryStats.waterMarkBuckets[7]); + tr_info("water mark bucket large allocation number %ld\r\n",memoryStats.waterMarkBuckets[8]); + tr_info("*******************************************************\r\n"); +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Utils/memoryProfiler/mbed-os/pal_memory.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/Utils/memoryProfiler/mbed-os/pal_memory.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,34 @@ +/* + * pal_memory.c + * + * Created on: Jun 26, 2017 + * Author: pal + */ + +#ifdef PAL_MEMORY_STATISTICS +#include "stdio.h" +#include "mbed-trace/mbed_trace.h" +#include "mbed_stats.h" + +TRACE_GROUP "PAL_MEMORY" +void printMemoryStats(void) +{ + mbed_stats_heap_t heap_stats; + mbed_stats_heap_get(&heap_stats); + + mbed_stats_stack_t stack_stats; + mbed_stats_stack_get(&stack_stats); + tr_info("--- heap stats ---\n"); + + tr_info("heap max size: %ld\n", heap_stats.max_size); + tr_info("heap reserved size: %ld\n", heap_stats.reserved_size); + tr_info("heap alloc cnt: %ld\n", heap_stats.alloc_cnt); + tr_info("heap alloc fail cnt: %ld\n", heap_stats.alloc_fail_cnt); + + tr_info("--- stack stats ---\n"); + tr_info("stack max size: %ld\n", stack_stats.max_size); + tr_info("stack reserved size: %ld\n", stack_stats.reserved_size); + tr_info("stack stack cnt: %ld\n", stack_stats.stack_cnt); + +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,8 @@ +{ + "name": "mbed-client-pal", + "config": { + "update-active-metadata-header-offset": null + } + +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/pal_version.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/pal_version.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,6 @@ +#define PAL_VERSION_MAJOR +#define PAL_VERSION_MINOR +#define PAL_VERSION_PATCH +#define PAL_VERSION .. + +/* #undef PAL_USE_CMSIS */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/pal_version.h.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-pal/pal_version.h.in Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,6 @@ +#define PAL_VERSION_MAJOR @PAL_VERSION_MAJOR@ +#define PAL_VERSION_MINOR @PAL_VERSION_MINOR@ +#define PAL_VERSION_PATCH @PAL_VERSION_PATCH@ +#define PAL_VERSION @PAL_VERSION@ + +#cmakedefine PAL_USE_CMSIS \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +linux/* +test/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/apache-2.0.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/mbed-client-randlib/platform/arm_hal_random.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/mbed-client-randlib/platform/arm_hal_random.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ARM_HAL_RANDOM_H_ +#define ARM_HAL_RANDOM_H_ +#ifdef __cplusplus +extern "C" { +#endif +/** + * \brief This function performs Random number driver init. + */ +extern void arm_random_module_init(void); +/** + * \brief Get random library seed value. + * + * This function should return as random a value as possible, using + * hardware sources. Repeated calls should return different values if + * at all possible. + */ +extern uint32_t arm_random_seed_get(void); +#ifdef __cplusplus +} +#endif +#endif /* ARM_HAL_RANDOM_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/mbed-client-randlib/randLIB.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/mbed-client-randlib/randLIB.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file randLIB.h + * \brief Pseudo Random Library API: + * + * + * \section net-boot Network Bootstrap Control API: + * - randLIB_seed_random(), Set seed for pseudo random + * - randLIB_get_8bit(), Generate 8-bit random number + * - randLIB_get_16bit(),Generate 16-bit random number + * - randLIB_get_32bit(),Generate 32-bit random number + * - randLIB_get_n_bytes_random(), Generate n-bytes random numbers + * + */ + +#ifndef RANDLIB_H_ +#define RANDLIB_H_ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This library is made for getting random numbers for Timing needs in protocols. + * + * **not safe to use for security or cryptographic operations.** + * + */ + + +/** + * \brief Init seed for Pseudo Random. + * + * Makes call(s) to the platform's arm_random_seed_get() to seed the + * pseudo-random generator. + * + * \return None + * + */ +extern void randLIB_seed_random(void); + +/** + * \brief Update seed for pseudo-random generator + * + * Adds seed information to existing generator, to perturb the + * sequence. + * \param seed 64 bits of data to add to the seed. + */ +extern void randLIB_add_seed(uint64_t seed); + +/** + * \brief Generate 8-bit random number. + * + * \param None + * \return 8-bit random number + * + */ +extern uint8_t randLIB_get_8bit(void); + +/** + * \brief Generate 16-bit random number. + * + * \param None + * \return 16-bit random number + * + */ +extern uint16_t randLIB_get_16bit(void); + +/** + * \brief Generate 32-bit random number. + * + * \param None + * \return 32-bit random number + * + */ +extern uint32_t randLIB_get_32bit(void); + +/** + * \brief Generate 64-bit random number. + * + * \param None + * \return 64-bit random number + * + */ +extern uint64_t randLIB_get_64bit(void); + +/** + * \brief Generate n-bytes random numbers. + * + * \param data_ptr pointer where random will be stored + * \param count how many bytes need random + * + * \return data_ptr + */ +extern void *randLIB_get_n_bytes_random(void *data_ptr, uint8_t count); + +/** + * \brief Generate a random number within a range. + * + * The result is linearly distributed in the range [min..max], inclusive. + * + * \param min minimum value that can be generated + * \param max maximum value that can be generated + */ +uint16_t randLIB_get_random_in_range(uint16_t min, uint16_t max); + +/** + * \brief Randomise a base 32-bit number by a jitter factor + * + * The result is linearly distributed in the jitter range, which is expressed + * as fixed-point unsigned 1.15 values. For example, to produce a number in the + * range [0.75 * base, 1.25 * base], set min_factor to 0x6000 and max_factor to + * 0xA000. + * + * Result is clamped to 0xFFFFFFFF if it overflows. + * + * \param base The base 32-bit value + * \param min_factor The minimum value for the random factor + * \param max_factor The maximum value for the random factor + */ +uint32_t randLIB_randomise_base(uint32_t base, uint16_t min_factor, uint16_t max_factor); + +#ifdef RANDLIB_PRNG +/* \internal Reset the PRNG state to zero (invalid) */ +void randLIB_reset(void); +#endif + + +#ifdef __cplusplus +} +#endif +#endif /* RANDLIB_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/source/randLIB.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client-randlib/source/randLIB.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdint.h> +#include <limits.h> +#include "randLIB.h" +#include "platform/arm_hal_random.h" + +/** + * This library is made for getting random numbers for timing needs in + * protocols, plus to generate dynamic ports, random IDs etc. + * + * **not safe to use for security or cryptographic operations.** + * + * Base implementation is a pseudo-RNG, but may also use a system RNG. + * Replay of sequence by reseeding is not possible. + * + * Base pseudo-RNG is the xoroshiro128+ generator by Marsaglia, Blackman and + * Vigna: + * + * http://xoroshiro.di.unimi.it/ + * + * Certainly not the fastest for 32-bit or smaller platforms, but speed + * is not critical. None of the long operations in the core are actually hard, + * unlike the divisions and multiplies in the utility functions below, where we + * do try to keep the operations narrow. + */ + +/* On some platforms, read from a system RNG, rather than use our own */ +/* RANDLIB_PRNG disables this and forces use of the PRNG (useful for test only?) */ +#ifndef RANDLIB_PRNG +#ifdef __linux +#define RANDOM_DEVICE "/dev/urandom" +#endif +#endif // RANDLIB_PRNG + +/* RAM usage - 16 bytes of state (or a FILE * pointer and underlying FILE, which + * will include a buffer) */ +#ifdef RANDOM_DEVICE +#include <stdio.h> +static FILE *random_file; +#else +static uint64_t state[2]; +#endif + +#ifdef RANDLIB_PRNG +void randLIB_reset(void) +{ + state[0] = 0; + state[1] = 0; +} +#endif + +#ifndef RANDOM_DEVICE +static inline uint64_t rol(uint64_t n, int bits) +{ + return (n << bits) | (n >> (64 - bits)); +} + +/* Lower-quality generator used only for initial seeding, if platform + * isn't returning multiple seeds itself. Multiplies are rather heavy + * for lower-end platforms, but this is initialisation only. + */ +static uint64_t splitmix64(uint64_t *seed) +{ + uint64_t z = (*seed += UINT64_C(0x9E3779B97F4A7C15)); + z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9); + z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB); + return z ^ (z >> 31); +} +#endif // RANDOM_DEVICE + +void randLIB_seed_random(void) +{ +#ifdef RANDOM_DEVICE + if (!random_file) { + random_file = fopen(RANDOM_DEVICE, "rb"); + } +#else + arm_random_module_init(); + + /* We exclusive-OR with the current state, in case they make this call + * multiple times,or in case someone has called randLIB_add_seed before + * this. We don't want to potentially lose entropy. + */ + + /* Spell out expressions so we get known ordering of 4 seed calls */ + uint64_t s = (uint64_t) arm_random_seed_get() << 32; + state[0] ^= ( s | arm_random_seed_get()); + + s = (uint64_t) arm_random_seed_get() << 32; + state[1] ^= s | arm_random_seed_get(); + + /* This check serves to both to stir the state if the platform is returning + * constant seeding values, and to avoid the illegal all-zero state. + */ + if (state[0] == state[1]) { + randLIB_add_seed(state[0]); + } +#endif // RANDOM_DEVICE +} + +void randLIB_add_seed(uint64_t seed) +{ +#ifndef RANDOM_DEVICE + state[0] ^= splitmix64(&seed); + state[1] ^= splitmix64(&seed); + /* This is absolutely necessary, but I challenge you to add it to line coverage */ + if (state[1] == 0 && state[0] == 0) { + state[0] = 1; + } +#else + (void)seed; +#endif +} + +uint8_t randLIB_get_8bit(void) +{ + uint64_t r = randLIB_get_64bit(); + return (uint8_t) (r >> 56); +} + +uint16_t randLIB_get_16bit(void) +{ + uint64_t r = randLIB_get_64bit(); + return (uint16_t) (r >> 48); +} + +uint32_t randLIB_get_32bit(void) +{ + uint64_t r = randLIB_get_64bit(); + return (uint32_t) (r >> 32); +} + + +uint64_t randLIB_get_64bit(void) +{ +#ifdef RANDOM_DEVICE + if (!random_file) { + return 0; + } + uint64_t result; + if (fread(&result, sizeof result, 1, random_file) != 1) { + result = 0; + } + return result; +#else + const uint64_t s0 = state[0]; + uint64_t s1 = state[1]; + const uint64_t result = s0 + s1; + + s1 ^= s0; + state[0] = rol(s0, 55) ^ s1 ^ (s1 << 14); + state[1] = rol(s1, 36); + + return result; +#endif +} + +void *randLIB_get_n_bytes_random(void *ptr, uint8_t count) +{ + uint8_t *data_ptr = ptr; + uint64_t r = 0; + for (uint_fast8_t i = 0; i < count; i++) { + /* Take 8 bytes at a time */ + if (i % 8 == 0) { + r = randLIB_get_64bit(); + } else { + r >>= 8; + } + data_ptr[i] = (uint8_t) r; + } + return data_ptr; +} + +uint16_t randLIB_get_random_in_range(uint16_t min, uint16_t max) +{ + /* This special case is potentially common, particularly in this routine's + * first user (Trickle), so worth catching immediately */ + if (min == max) { + return min; + } + +#if UINT_MAX >= 0xFFFFFFFF + const unsigned int rand_max = 0xFFFFFFFFu; // will use rand32 +#else + const unsigned int rand_max = 0xFFFFu; // will use rand16 + + /* 16-bit arithmetic below fails in this extreme case; we can optimise it */ + if (max - min == 0xFFFF) { + return randLIB_get_16bit(); + } +#endif + + /* We get rand_max values from rand16 or 32() in the range [0..rand_max-1], and + * need to divvy them up into the number of values we need. And reroll any + * odd values off the end as we insist every value having equal chance. + * + * Using the range [0..rand_max-1] saves long division on the band + * calculation - it means rand_max ends up always being rerolled. + * + * Eg, range(1,2), rand_max = 0xFFFF: + * We have 2 bands of size 0x7FFF (0xFFFF/2). + * + * We roll: 0x0000..0x7FFE -> 1 + * 0x7FFF..0xFFFD -> 2 + * 0xFFFE..0xFFFF -> reroll + * (calculating band size as 0x10000/2 would have avoided the reroll cases) + * + * Eg, range(1,3), rand_max = 0xFFFFFFFF: + * We have 3 bands of size 0x55555555 (0xFFFFFFFF/3). + * + * We roll: 0x00000000..0x555555554 -> 1 + * 0x55555555..0xAAAAAAAA9 -> 2 + * 0xAAAAAAAA..0xFFFFFFFFE -> 3 + * 0xFFFFFFFF -> reroll + * + * (Bias problem clearly pretty insignificant there, but gets worse as + * range increases). + */ + const unsigned int values_needed = max + 1 - min; + /* Avoid the need for long division, at the expense of fractionally + * increasing reroll chance. */ + const unsigned int band_size = rand_max / values_needed; + const unsigned int top_of_bands = band_size * values_needed; + unsigned int result; + do { +#if UINT_MAX > 0xFFFF + result = randLIB_get_32bit(); +#else + result = randLIB_get_16bit(); +#endif + } while (result >= top_of_bands); + + return min + (uint16_t)(result / band_size); +} + +uint32_t randLIB_randomise_base(uint32_t base, uint16_t min_factor, uint16_t max_factor) +{ + uint16_t random_factor = randLIB_get_random_in_range(min_factor, max_factor); + + /* 32x16-bit long multiplication, to get 48-bit result */ + uint32_t hi = (base >> 16) * random_factor; + uint32_t lo = (base & 0xFFFF) * random_factor; + /* Add halves, and take top 32 bits of 48-bit result */ + uint32_t res = hi + (lo >> 16); + + /* Randomisation factor is *2^15, so need to shift up 1 more bit, avoiding overflow */ + if (res & 0x80000000) { + res = 0xFFFFFFFF; + } else { + res = (res << 1) | ((lo >> 15) & 1); + } + + return res; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,9 @@ +config/* +docs/* +doxygen/* +test/* +yotta_modules/* +yotta_targets/* +build/* +test_modules/* +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/DOXYGEN_FRONTPAGE.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/DOXYGEN_FRONTPAGE.md Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,13 @@ +mbed Client API +================ + +This is the Doxygen generated API documentation of mbed Client. See the [Files](files.html) section to find the documentation about specific API. It should be used together with the [mbed Client Guide](https://docs.mbed.com/docs/mbed-client-guide/en/latest/) +hosted in http://docs.mbed.com. + +The mbed Client high-level APIs allow mbed OS developers to create applications with LwM2M features as described in the [Lightweight Machine to Machine Technical Specification](http://technical.openmobilealliance.org/Technical/technical-information/release-program/current-releases/oma-lightweightm2m-v1-0): + +- Manage devices on mbed Device Server. +- Securely communicate with internet services over the industry standard TLS/DTLS. +- Fully control the endpoint and application logic. + +The API is written in C++ to allow quick application development.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,202 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/doxygen/mbedclient_doxy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/doxygen/mbedclient_doxy Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1850 @@ +# Doxyfile 1.8.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = mbed-client + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "mbed Client C++ library" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 16 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = YES + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 18 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../mbed-client + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */config/* +EXCLUDE_PATTERNS += */docs/* +EXCLUDE_PATTERNS += */doxygen/* +EXCLUDE_PATTERNS += */source/* +EXCLUDE_PATTERNS += */test/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 44 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +test/* +unittest/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/README.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,5 @@ +The mbed Device C Client Library provides a simple and efficient way to create mbed Device Client in +C. + +Applications not using mbed-coap via mbedOS should add mbed-coap library either via mbed-coap.lib or via other +applicable means.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/apache-2.0.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/doxygen/client-c_doxy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/doxygen/client-c_doxy Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1846 @@ +# Doxyfile 1.8.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = client-c + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "mbed Client C library" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 16 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = YES + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 18 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../nsdl-c + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 44 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/nsdl-c/sn_client_config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/nsdl-c/sn_client_config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SN_CLIENT_CONFIG_H +#define SN_CLIENT_CONFIG_H + +#ifdef __DOXYGEN__ + +/** +* \brief Configuration options (set of defines and values) +* +* This lists set of compile-time options that needs to be used to enable +* or disable features selectively, and set the values for the mandatory +* parameters. +*/ + +/** + * \def DISABLE_RESOURCE_TYPE + * \brief For Disabling Resource type + * + */ +#define DISABLE_RESOURCE_TYPE + +/** + * \def DISABLE_INTERFACE_DESCRIPTION + * \brief For Disabling Resource type + * + */ +#define DISABLE_INTERFACE_DESCRIPTION + +/** + * \def MBED_CLIENT_PRINT_COAP_PAYLOAD + * \brief If enabled this will print out the CoAP package payload. + */ +#define MBED_CLIENT_PRINT_COAP_PAYLOAD +#endif + +#ifdef MBED_CLIENT_USER_CONFIG_FILE +#include MBED_CLIENT_USER_CONFIG_FILE +#endif + +#endif // SN_CONFIG_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/nsdl-c/sn_nsdl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/nsdl-c/sn_nsdl.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** +* \file sn_nsdl.h +* +* \brief libNsdl generic header file +* +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SN_NSDL_H_ +#define SN_NSDL_H_ + +#define SN_NSDL_SUCCESS 0 +#define SN_NSDL_FAILURE (-1) +#define SN_NSDL_RESEND_QUEUE_FULL (-2) + +#include "sn_coap_header.h" + +#endif /* SN_NSDL_H_ */ + +#ifdef __cplusplus +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/nsdl-c/sn_nsdl_lib.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/nsdl-c/sn_nsdl_lib.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,779 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** +* \file sn_nsdl_lib.h +* +* \brief NanoService Devices Library header file +* +* +*/ + +#ifndef SN_NSDL_LIB_H_ +#define SN_NSDL_LIB_H_ + +#include "ns_list.h" +#include "sn_client_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SN_NSDL_ENDPOINT_NOT_REGISTERED 0 +#define SN_NSDL_ENDPOINT_IS_REGISTERED 1 + +#define MAX_TOKEN_SIZE 8 + +#ifdef YOTTA_CFG_DISABLE_INTERFACE_DESCRIPTION +#define DISABLE_INTERFACE_DESCRIPTION YOTTA_CFG_DISABLE_INTERFACE_DESCRIPTION +#elif defined MBED_CONF_MBED_CLIENT_DISABLE_INTERFACE_DESCRIPTION +#define DISABLE_INTERFACE_DESCRIPTION MBED_CONF_MBED_CLIENT_DISABLE_INTERFACE_DESCRIPTION +#endif + +#ifdef YOTTA_CFG_DISABLE_RESOURCE_TYPE +#define DISABLE_RESOURCE_TYPE YOTTA_CFG_DISABLE_RESOURCE_TYPE +#elif defined MBED_CONF_MBED_CLIENT_DISABLE_RESOURCE_TYPE +#define DISABLE_RESOURCE_TYPE MBED_CONF_MBED_CLIENT_DISABLE_RESOURCE_TYPE +#endif + +/* Handle structure */ +struct nsdl_s; + +/** + * \brief Received device server security + */ +typedef enum omalw_server_security_ { + SEC_NOT_SET = -1, + PSK = 0, + RPK = 1, + CERTIFICATE = 2, + NO_SEC = 3 +} omalw_server_security_t; + +/** + * \brief Endpoint binding and mode + */ +typedef enum sn_nsdl_oma_binding_and_mode_ { + BINDING_MODE_NOT_SET = 0, + BINDING_MODE_U = 0x01, + BINDING_MODE_Q = 0x02, + BINDING_MODE_S = 0x04 +} sn_nsdl_oma_binding_and_mode_t; + +//#define RESOURCE_ATTRIBUTES_LIST +#ifdef RESOURCE_ATTRIBUTES_LIST +/* + * \brief Resource attributes types + */ +typedef enum sn_nsdl_resource_attribute_ { + ATTR_RESOURCE_TYPE, + ATTR_INTERFACE_DESCRIPTION, + ATTR_ENDPOINT_NAME, + ATTR_QUEUE_MODE, + ATTR_LIFETIME, + ATTR_NOP, + ATTR_END +} sn_nsdl_resource_attribute_t; + +typedef struct sn_nsdl_attribute_item_ { + sn_nsdl_resource_attribute_t attribute_name; + char *value; +} sn_nsdl_attribute_item_s; + +#endif + +/** + * \brief Endpoint registration mode. + * If REGISTER_WITH_RESOURCES, endpoint sends list of all resources during registration. + * If REGISTER_WITH_TEMPLATE, endpoint sends registration without resource list. Device server must have + * correctly configured template. + */ +typedef enum sn_nsdl_registration_mode_ { + REGISTER_WITH_RESOURCES = 0, + REGISTER_WITH_TEMPLATE +} sn_nsdl_registration_mode_t; + +/** + * \brief Endpoint registration parameters + */ +typedef struct sn_nsdl_ep_parameters_ { + uint8_t endpoint_name_len; + uint8_t domain_name_len; + uint8_t type_len; + uint8_t lifetime_len; + uint8_t location_len; + + sn_nsdl_registration_mode_t ds_register_mode; /**< Defines registration mode */ + sn_nsdl_oma_binding_and_mode_t binding_and_mode; /**< Defines endpoints binding and mode */ + + uint8_t *endpoint_name_ptr; /**< Endpoint name */ + uint8_t *domain_name_ptr; /**< Domain to register. If null, NSP uses default domain */ + uint8_t *type_ptr; /**< Endpoint type */ + uint8_t *lifetime_ptr; /**< Endpoint lifetime in seconds. eg. "1200" = 1200 seconds */ + uint8_t *location_ptr; /**< Endpoint location in server, optional parameter,default is NULL */ +} sn_nsdl_ep_parameters_s; + +/** + * \brief For internal use + */ +typedef struct sn_nsdl_sent_messages_ { + uint8_t message_type; + uint16_t msg_id_number; + ns_list_link_t link; +} sn_nsdl_sent_messages_s; + +/** + * \brief Includes resource path + */ +typedef struct sn_grs_resource_ { + char *path; +} sn_grs_resource_s; + +/** + * \brief Table of created resources + */ +typedef struct sn_grs_resource_list_ { + uint8_t res_count; /**< Number of resources */ + sn_grs_resource_s *res; +} sn_grs_resource_list_s; + +/** + * \brief Resource access rights + */ +typedef enum sn_grs_resource_acl_ { + SN_GRS_GET_ALLOWED = 0x01 , + SN_GRS_PUT_ALLOWED = 0x02, + SN_GRS_POST_ALLOWED = 0x04, + SN_GRS_DELETE_ALLOWED = 0x08 +} sn_grs_resource_acl_e; + +/** + * \brief Defines the resource mode + */ +typedef enum sn_nsdl_resource_mode_ { + SN_GRS_STATIC = 0, /**< Static resources have some value that doesn't change */ + SN_GRS_DYNAMIC, /**< Dynamic resources are handled in application. Therefore one must give function callback pointer to them */ + SN_GRS_DIRECTORY /**< Directory resources are unused and unsupported */ +} sn_nsdl_resource_mode_e; + +/** + * Enum defining an status codes that can happen when + * sending notification +*/ +typedef enum { + NOTIFICATION_STATUS_INIT = 0, // Initial state. + NOTIFICATION_STATUS_BUILD_ERROR, // CoAP message building fails. + NOTIFICATION_STATUS_RESEND_QUEUE_FULL, // CoAP resend queue full. + NOTIFICATION_STATUS_SENT, // Notification sent to the server but ACK not yet received. + NOTIFICATION_STATUS_DELIVERED, // Received ACK from server. + NOTIFICATION_STATUS_SEND_FAILED, // Message sending failed (retransmission completed). + NOTIFICATION_STATUS_SUBSCRIBED, // Server has started the observation + NOTIFICATION_STATUS_UNSUBSCRIBED // Server has stopped the observation (RESET message or GET with observe 1) +} NoticationDeliveryStatus; + + +/** + * \brief Defines static parameters for the resource. + */ +typedef struct sn_nsdl_static_resource_parameters_ { +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + char *resource_type_ptr; /**< Type of the resource */ +#endif +#ifndef DISABLE_INTERFACE_DESCRIPTION + char *interface_description_ptr; /**< Interface description */ +#endif +#else + sn_nsdl_attribute_item_s *attributes_ptr; +#endif + char *path; /**< Resource path */ + bool external_memory_block:1; /**< 0 means block messages are handled inside this library, + otherwise block messages are passed to application */ + unsigned mode:2; /**< STATIC etc.. */ + bool free_on_delete:1; /**< 1 if struct is dynamic allocted --> to be freed */ +} sn_nsdl_static_resource_parameters_s; + +/** + * \brief Defines dynamic parameters for the resource. + */ +typedef struct sn_nsdl_resource_parameters_ { + uint8_t (*sn_grs_dyn_res_callback)(struct nsdl_s *, + sn_coap_hdr_s *, + sn_nsdl_addr_s *, + sn_nsdl_capab_e); +#ifdef MEMORY_OPTIMIZED_API + const sn_nsdl_static_resource_parameters_s *static_resource_parameters; +#else + sn_nsdl_static_resource_parameters_s *static_resource_parameters; +#endif + uint8_t *resource; /**< NULL if dynamic resource */ + ns_list_link_t link; + uint16_t resourcelen; /**< 0 if dynamic resource, resource information in static resource */ + uint16_t coap_content_type; /**< CoAP content type */ + uint16_t msg_id; /**< Notification message id. */ + unsigned access:4; /**< Allowed operation mode, GET, PUT, etc, + TODO! This should be in static struct but current + mbed-client implementation requires this to be changed at runtime */ + unsigned registered:2; /**< Is resource registered or not */ + bool publish_uri:1; /**< 1 if resource to be published to server */ + bool free_on_delete:1; /**< 1 if struct is dynamic allocted --> to be freed */ + bool observable:1; /**< Is resource observable or not */ + bool auto_observable:1; /**< Is resource auto observable or not */ + NoticationDeliveryStatus notification_status:3; /**< Notification delivery status */ +} sn_nsdl_dynamic_resource_parameters_s; + +/** + * \brief Defines OMAlw server information + */ +typedef struct sn_nsdl_oma_server_info_ { + sn_nsdl_addr_s *omalw_address_ptr; + omalw_server_security_t omalw_server_security; + +} sn_nsdl_oma_server_info_t; + +/** + * \brief Defines endpoint parameters to OMA bootstrap. + */ +typedef struct sn_nsdl_bs_ep_info_ { + void (*oma_bs_status_cb)(sn_nsdl_oma_server_info_t *); /**< Callback for OMA bootstrap status */ + + void (*oma_bs_status_cb_handle)(sn_nsdl_oma_server_info_t *, + struct nsdl_s *); /**< Callback for OMA bootstrap status with nsdl handle */ +} sn_nsdl_bs_ep_info_t; + +/** + * \fn struct nsdl_s *sn_nsdl_init (uint8_t (*sn_nsdl_tx_cb)(sn_nsdl_capab_e , uint8_t *, uint16_t, sn_nsdl_addr_s *), + * uint8_t (*sn_nsdl_rx_cb)(sn_coap_hdr_s *, sn_nsdl_addr_s *), + * sn_nsdl_mem_s *sn_memory) + * + * \brief Initialization function for NSDL library. Initializes NSDL, GRS, HTTP and CoAP. + * + * \param *sn_nsdl_tx_callback A callback function for sending messages. + * + * \param *sn_nsdl_rx_callback A callback function for parsed messages. If received message is not CoAP protocol message (eg. ACK), message for GRS (GET, PUT, POST, DELETE) or + * reply for some DS messages (register message etc.), rx callback will be called. + * + * \param *sn_memory Memory structure which includes function pointers to the allocation and free functions. + * + * \return pointer to created handle structure. NULL if failed + */ +struct nsdl_s *sn_nsdl_init(uint8_t (*sn_nsdl_tx_cb)(struct nsdl_s *, sn_nsdl_capab_e , uint8_t *, uint16_t, sn_nsdl_addr_s *), + uint8_t (*sn_nsdl_rx_cb)(struct nsdl_s *, sn_coap_hdr_s *, sn_nsdl_addr_s *), + void *(*sn_nsdl_alloc)(uint16_t), void (*sn_nsdl_free)(void *), + uint8_t (*sn_nsdl_auto_obs_token_cb)(struct nsdl_s *, const char *, uint8_t *)); + +/** + * \fn extern uint16_t sn_nsdl_register_endpoint(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *endpoint_info_ptr); + * + * \brief Registers endpoint to mbed Device Server. + * \param *handle Pointer to nsdl-library handle + * \param *endpoint_info_ptr Contains endpoint information. + * \param *uri_query_parameters List of uri query parameters. + * \param *query_param_count Count of uri query parameters. + * + * \return registration message ID, 0 if failed + */ +extern uint16_t sn_nsdl_register_endpoint(struct nsdl_s *handle, + sn_nsdl_ep_parameters_s *endpoint_info_ptr, + char *uri_query_parameters[], + uint32_t query_param_count); + +/** + * \fn extern int32_t sn_nsdl_unregister_endpoint(struct nsdl_s *handle) + * + * \brief Sends unregister-message to mbed Device Server. + * + * \param *handle Pointer to nsdl-library handle + * + * \return unregistration message ID, 0 if failed + */ +extern int32_t sn_nsdl_unregister_endpoint(struct nsdl_s *handle); + +/** + * \fn extern int32_t sn_nsdl_update_registration(struct nsdl_s *handle, uint8_t *lt_ptr, uint8_t lt_len); + * + * \brief Update the registration with mbed Device Server. + * + * \param *handle Pointer to nsdl-library handle + * \param *lt_ptr Pointer to lifetime value string in ascii form, eg. "1200" + * \param lt_len Length of the lifetime string + * + * \return registration update message ID, <0 if failed + */ +extern int32_t sn_nsdl_update_registration(struct nsdl_s *handle, uint8_t *lt_ptr, uint8_t lt_len); + +/** + * \fn extern int8_t sn_nsdl_set_endpoint_location(struct nsdl_s *handle, uint8_t *location_ptr, uint8_t location_len); + * + * \brief Sets the location receievd from Device Server. + * + * \param *handle Pointer to nsdl-library handle + * \param *lt_ptr Pointer to location value string , eg. "s322j4k" + * \param lt_len Length of the location string + * + * \return success, <0 if failed + */ +extern int8_t sn_nsdl_set_endpoint_location(struct nsdl_s *handle, uint8_t *location_ptr, uint8_t location_len); + +/** + * \fn extern int8_t sn_nsdl_is_ep_registered(struct nsdl_s *handle) + * + * \brief Checks if endpoint is registered. + * + * \param *handle Pointer to nsdl-library handle + * + * \return 1 Endpoint registration is done successfully + * \return 0 Endpoint is not registered + */ +extern int8_t sn_nsdl_is_ep_registered(struct nsdl_s *handle); + +/** + * \fn extern void sn_nsdl_nsp_lost(struct nsdl_s *handle); + * + * \brief A function to inform mbed Device C client library if application detects a fault in mbed Device Server registration. + * + * \param *handle Pointer to nsdl-library handle + * + * After calling this function sn_nsdl_is_ep_registered() will return "not registered". + */ +extern void sn_nsdl_nsp_lost(struct nsdl_s *handle); + +/** + * \fn extern uint16_t sn_nsdl_send_observation_notification(struct nsdl_s *handle, uint8_t *token_ptr, uint8_t token_len, + * uint8_t *payload_ptr, uint16_t payload_len, + * sn_coap_observe_e observe, + * sn_coap_msg_type_e message_type, sn_coap_content_format_e content_format) + * + * + * \brief Sends observation message to mbed Device Server + * + * \param *handle Pointer to nsdl-library handle + * \param *token_ptr Pointer to token to be used + * \param token_len Token length + * \param *payload_ptr Pointer to payload to be sent + * \param payload_len Payload length + * \param observe Observe option value to be sent + * \param message_type Observation message type (confirmable or non-confirmable) + * \param content_format Observation message payload content format + * \param message_id -1 means stored value to be used otherwise new one is generated + * + * \return >0 Success, observation messages message ID + * \return <=0 Failure + */ +extern int32_t sn_nsdl_send_observation_notification(struct nsdl_s *handle, uint8_t *token_ptr, uint8_t token_len, + uint8_t *payload_ptr, uint16_t payload_len, + sn_coap_observe_e observe, + sn_coap_msg_type_e message_type, + sn_coap_content_format_e content_format, + const int32_t message_id); + +/** + * \fn extern uint32_t sn_nsdl_get_version(void) + * + * \brief Version query function. + * + * Used to retrieve the version information from the mbed Device C Client library. + * + * \return Pointer to library version string +*/ +extern char *sn_nsdl_get_version(void); + +/** + * \fn extern int8_t sn_nsdl_process_coap(struct nsdl_s *handle, uint8_t *packet, uint16_t packet_len, sn_nsdl_addr_s *src) + * + * \brief To push CoAP packet to mbed Device C Client library + * + * Used to push an CoAP packet to mbed Device C Client library for processing. + * + * \param *handle Pointer to nsdl-library handle + * + * \param *packet Pointer to a uint8_t array containing the packet (including the CoAP headers). + * After successful execution this array may contain the response packet. + * + * \param *packet_len Pointer to length of the packet. After successful execution this array may contain the length + * of the response packet. + * + * \param *src Pointer to packet source address information. After successful execution this array may contain + * the destination address of the response packet. + * + * \return 0 Success + * \return -1 Failure + */ +extern int8_t sn_nsdl_process_coap(struct nsdl_s *handle, uint8_t *packet, uint16_t packet_len, sn_nsdl_addr_s *src); + +/** + * \fn extern int8_t sn_nsdl_exec(struct nsdl_s *handle, uint32_t time); + * + * \brief CoAP retransmission function. + * + * Used to give execution time for the mbed Device C Client library for retransmissions. + * + * \param *handle Pointer to nsdl-library handle + * + * \param time Time in seconds. + * + * \return 0 Success + * \return -1 Failure + */ +extern int8_t sn_nsdl_exec(struct nsdl_s *handle, uint32_t time); + +/** + * \fn extern int8_t sn_nsdl_put_resource(struct nsdl_s *handle, const sn_nsdl_dynamic_resource_parameters_s *res); + * + * \brief Resource putting function. + * + * Used to put a static or dynamic CoAP resource without creating copy of it. + * NOTE: Remember that only resource will be owned, not data that it contains + * NOTE: The resource may be removed from list by sn_nsdl_pop_resource(). + * + * \param *res Pointer to a structure of type sn_nsdl_dynamic_resource_parameters_s that contains the information + * about the resource. + * + * \return 0 Success + * \return -1 Failure + * \return -2 Resource already exists + * \return -3 Invalid path + * \return -4 List adding failure + */ +extern int8_t sn_nsdl_put_resource(struct nsdl_s *handle, sn_nsdl_dynamic_resource_parameters_s *res); + +/** + * \fn extern int8_t sn_nsdl_pop_resource(struct nsdl_s *handle, const sn_nsdl_dynamic_resource_parameters_s *res); + * + * \brief Resource popping function. + * + * Used to remove a static or dynamic CoAP resource from lists without deleting it. + * NOTE: This function is a counterpart of sn_nsdl_put_resource(). + * + * \param *res Pointer to a structure of type sn_nsdl_dynamic_resource_parameters_s that contains the information + * about the resource. + * + * \return 0 Success + * \return -1 Failure + * \return -3 Invalid path + */ +extern int8_t sn_nsdl_pop_resource(struct nsdl_s *handle, sn_nsdl_dynamic_resource_parameters_s *res); + +/** + * \fn extern int8_t sn_nsdl_delete_resource(struct nsdl_s *handle, char *path) + * + * \brief Resource delete function. + * + * Used to delete a resource. If resource has a subresources, these all must also be removed. + * + * \param *handle Pointer to nsdl-library handle + * \param *path_ptr A pointer to an array containing the path. + * + * \return 0 Success + * \return -1 Failure (No such resource) + */ +extern int8_t sn_nsdl_delete_resource(struct nsdl_s *handle, const char *path); + +/** + * \fn extern sn_nsdl_dynamic_resource_parameters_s *sn_nsdl_get_resource(struct nsdl_s *handle, char *path) + * + * \brief Resource get function. + * + * Used to get a resource. + * + * \param *handle Pointer to nsdl-library handle + * \param *path A pointer to an array containing the path. + * + * \return !NULL Success, pointer to a sn_nsdl_dynamic_resource_parameters_s that contains the resource information\n + * \return NULL Failure + */ +extern sn_nsdl_dynamic_resource_parameters_s *sn_nsdl_get_resource(struct nsdl_s *handle, const char *path); + +/** + * \fn extern sn_grs_resource_list_s *sn_nsdl_list_resource(struct nsdl_s *handle, char *path) + * + * \brief Resource list function. + * + * \param *handle Pointer to nsdl-library handle + * \param *path A pointer to an array containing the path or a NULL pointer. + * + * \return !NULL A pointer to a sn_grs_resource_list_s structure containing the resource listing. + * \return NULL Failure with an unspecified error + */ +sn_grs_resource_list_s *sn_nsdl_list_resource(struct nsdl_s *handle, const char *path); + +/** + * \fn extern void sn_nsdl_free_resource_list(struct nsdl_s *handle, sn_grs_resource_list_s *list) + * + * \brief Free a resource list obtained from sn_nsdl_list_resource() + * + * \param list The list to free, or NULL. + */ +void sn_nsdl_free_resource_list(struct nsdl_s *handle, sn_grs_resource_list_s *list); + +/** + * \fn extern int8_t sn_nsdl_send_coap_message(struct nsdl_s *handle, sn_nsdl_addr_s *address_ptr, sn_coap_hdr_s *coap_hdr_ptr); + * + * \brief Send an outgoing CoAP request. + * + * \param *handle Pointer to nsdl-library handle + * \param *address_ptr Pointer to source address struct + * \param *coap_hdr_ptr Pointer to CoAP message to be sent + * + * \return 0 Success + * \return -1 Failure + */ +extern int8_t sn_nsdl_send_coap_message(struct nsdl_s *handle, sn_nsdl_addr_s *address_ptr, sn_coap_hdr_s *coap_hdr_ptr); + +/** + * \fn extern int32_t sn_nsdl_send_get_data_request(struct nsdl_s *handle); + * + * \brief Send an outgoing CoAP GET request. + * + * \param *handle Pointer to nsdl-library handle + * \param *uri_path Path to the data + * \param *token Message token + * + * \return 0 Success + * \return -1 Failure + */ +extern int32_t sn_nsdl_send_get_data_request(struct nsdl_s *handle, + const char *uri_path, + const uint32_t token, + const size_t offset); + +/** + * \fn extern int8_t set_NSP_address(struct nsdl_s *handle, uint8_t *NSP_address, uint8_t address_length, uint16_t port, sn_nsdl_addr_type_e address_type); + * + * \brief This function is used to set the mbed Device Server address given by an application. + * + * \param *handle Pointer to nsdl-library handle + * \return 0 Success + * \return -1 Failed to indicate that internal address pointer is not allocated (call nsdl_init() first). + */ +extern int8_t set_NSP_address(struct nsdl_s *handle, uint8_t *NSP_address, uint8_t address_length, uint16_t port, sn_nsdl_addr_type_e address_type); + +/** + * \fn extern int8_t sn_nsdl_destroy(struct nsdl_s *handle); + * + * \param *handle Pointer to nsdl-library handle + * \brief This function releases all allocated memory in mbed Device C Client library. + */ +extern int8_t sn_nsdl_destroy(struct nsdl_s *handle); + +/** + * \fn extern uint16_t sn_nsdl_oma_bootstrap(struct nsdl_s *handle, sn_nsdl_addr_s *bootstrap_address_ptr, sn_nsdl_ep_parameters_s *endpoint_info_ptr, sn_nsdl_bs_ep_info_t *bootstrap_endpoint_info_ptr); + * + * \brief Starts OMA bootstrap process + * + * \param *handle Pointer to nsdl-library handle + * + * \return bootstrap message ID, 0 if failed + */ +extern uint16_t sn_nsdl_oma_bootstrap(struct nsdl_s *handle, + sn_nsdl_addr_s *bootstrap_address_ptr, + sn_nsdl_ep_parameters_s *endpoint_info_ptr, + sn_nsdl_bs_ep_info_t *bootstrap_endpoint_info_ptr, + char *uri_query_parameters[], + uint32_t query_param_count); + +/** + * \fn sn_coap_hdr_s *sn_nsdl_build_response(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code) + * + * \brief Prepares generic response packet from a request packet. This function allocates memory for the resulting sn_coap_hdr_s + * + * \param *handle Pointer to library handle + * \param *coap_packet_ptr The request packet pointer + * \param msg_code response messages code + * + * \return *coap_packet_ptr The allocated and pre-filled response packet pointer + * NULL Error in parsing the request + * + */ +extern sn_coap_hdr_s *sn_nsdl_build_response(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code); + +/** + * \brief Allocates and initializes options list structure + * + * \param *handle Pointer to library handle + * \param *coap_msg_ptr is pointer to CoAP message that will contain the options + * + * If the message already has a pointer to an option structure, that pointer + * is returned, rather than a new structure being allocated. + * + * \return Return value is pointer to the CoAP options structure.\n + * In following failure cases NULL is returned:\n + * -Failure in given pointer (= NULL)\n + * -Failure in memory allocation (malloc() returns NULL) + */ +extern sn_coap_options_list_s *sn_nsdl_alloc_options_list(struct nsdl_s *handle, sn_coap_hdr_s *coap_msg_ptr); + +/** + * \fn void sn_nsdl_release_allocated_coap_msg_mem(struct nsdl_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr) + * + * \brief Releases memory of given CoAP message + * + * Note!!! Does not release Payload part + * + * \param *handle Pointer to library handle + * + * \param *freed_coap_msg_ptr is pointer to released CoAP message + */ +extern void sn_nsdl_release_allocated_coap_msg_mem(struct nsdl_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr); + +/** + * \fn int8_t sn_nsdl_set_retransmission_parameters(struct nsdl_s *handle, uint8_t resending_count, uint8_t resending_intervall) + * + * \brief If re-transmissions are enabled, this function changes resending count and interval. + * + * \param *handle Pointer to library handle + * \param uint8_t resending_count max number of resendings for message + * \param uint8_t resending_intervall message resending intervall in seconds + * \return 0 = success, -1 = failure + */ +extern int8_t sn_nsdl_set_retransmission_parameters(struct nsdl_s *handle, uint8_t resending_count, uint8_t resending_interval); + +/** + * \fn int8_t sn_nsdl_set_retransmission_buffer(struct nsdl_s *handle, uint8_t buffer_size_messages, uint16_t buffer_size_bytes) + * + * \brief If re-transmissions are enabled, this function changes message retransmission queue size. + * Set size to '0' to disable feature. If both are set to '0', then re-sendings are disabled. + * + * \param *handle Pointer to library handle + * \param uint8_t buffer_size_messages queue size - maximum number of messages to be saved to queue + * \param uint8_t buffer_size_bytes queue size - maximum size of messages saved to queue + * \return 0 = success, -1 = failure + */ +extern int8_t sn_nsdl_set_retransmission_buffer(struct nsdl_s *handle, + uint8_t buffer_size_messages, uint16_t buffer_size_bytes); + +/** + * \fn int8_t sn_nsdl_set_block_size(struct nsdl_s *handle, uint16_t block_size) + * + * \brief If block transfer is enabled, this function changes the block size. + * + * \param *handle Pointer to library handle + * \param uint16_t block_size maximum size of CoAP payload. Valid sizes are 16, 32, 64, 128, 256, 512 and 1024 bytes + * \return 0 = success, -1 = failure + */ +extern int8_t sn_nsdl_set_block_size(struct nsdl_s *handle, uint16_t block_size); + +/** + * \fn int8_t sn_nsdl_set_duplicate_buffer_size(struct nsdl_s *handle,uint8_t message_count) + * + * \brief If dublicate message detection is enabled, this function changes buffer size. + * + * \param *handle Pointer to library handle + * \param uint8_t message_count max number of messages saved for duplicate control + * \return 0 = success, -1 = failure + */ +extern int8_t sn_nsdl_set_duplicate_buffer_size(struct nsdl_s *handle, uint8_t message_count); + +/** + * \fn void *sn_nsdl_set_context(const struct nsdl_s *handle, void *context) + * + * \brief Set the application defined context parameter for given handle. + * This is useful for example when interfacing with c++ objects where a + * pointer to object is set as the context, and in the callback functions + * the context pointer can be used to call methods for the correct instance + * of the c++ object. + * + * \param *handle Pointer to library handle + * \param *context Pointer to the application defined context + * \return 0 = success, -1 = failure + */ +extern int8_t sn_nsdl_set_context(struct nsdl_s * const handle, void * const context); + +/** + * \fn void *sn_nsdl_get_context(const struct nsdl_s *handle) + * + * \brief Get the application defined context parameter for given handle. + * This is useful for example when interfacing with c++ objects where a + * pointer to object is set as the context, and in the callback functions + * the context pointer can be used to call methods for the correct instance + * of the c++ object. + * + * \param *handle Pointer to library handle + * \return Pointer to the application defined context + */ +extern void *sn_nsdl_get_context(const struct nsdl_s * const handle); + +/** + * \fn int8_t sn_nsdl_clear_coap_resending_queue(struct nsdl_s *handle) + * + * \brief Clean confirmable message list. + * + * \param *handle Pointer to library handle + * \return 0 = success, -1 = failure + */ +extern int8_t sn_nsdl_clear_coap_resending_queue(struct nsdl_s *handle); + + +/** + * \fn int8_t sn_nsdl_handle_block2_response_internally(struct nsdl_s *handle, uint8_t handle_response) + * + * \brief This function change the state whether CoAP library sends the block 2 response automatically or not. + * + * \param *handle Pointer to NSDL library handle + * \param handle_response 1 if CoAP library handles the response sending otherwise 0. + * + * \return 0 = success, -1 = failure + */ +extern int8_t sn_nsdl_handle_block2_response_internally(struct nsdl_s *handle, uint8_t handle_response); + +#ifdef RESOURCE_ATTRIBUTES_LIST +/** + * \fn int8_t sn_nsdl_free_resource_attributes_list(struct nsdl_s *handle, sn_nsdl_static_resource_parameters_s *params) + * + * \brief Free resource attributes list if free_on_delete is true for params. This will also free all attributes values + * if they are pointer types. + * + * \param *params Pointer to resource static parameters + */ +extern void sn_nsdl_free_resource_attributes_list(sn_nsdl_static_resource_parameters_s *params); + +/* + * \fn bool sn_nsdl_set_resource_attribute(sn_nsdl_static_resource_parameters_s *params, sn_nsdl_attribute_item_s attribute) + * + * \brief Set resource link-format attribute value, create if it doesn't exist yet. + * + * \param *params Pointer to resource static parameters + * \param attribute sn_nsdl_attribute_item_s structure containing attribute to set + * \return True if successful, false on error + */ +extern bool sn_nsdl_set_resource_attribute(sn_nsdl_static_resource_parameters_s *params, const sn_nsdl_attribute_item_s *attribute); + +/* + * \fn bool sn_nsdl_get_resource_attribute(sn_nsdl_static_resource_parameters_s *params, sn_nsdl_resource_attribute_t attribute) + * + * \brief Get resource link-format attribute value + * + * \param *params Pointer to resource static parameters + * \param attribute sn_nsdl_resource_attribute_t enum value for attribute to get + * \return Pointer to value or null if attribute did not exist or had no value + */ +extern const char* sn_nsdl_get_resource_attribute(const sn_nsdl_static_resource_parameters_s *params, sn_nsdl_resource_attribute_t attribute); + +/* + * \fn bool sn_nsdl_remove_resource_attribute(sn_nsdl_static_resource_parameters_s *params, sn_nsdl_resource_attribute_t attribute) + * + * \brief Remove resource link-format attribute value + * + * \param *params Pointer to resource static parameters + * \param attribute sn_nsdl_resource_attribute_t enum value for attribute to remove + */ +extern bool sn_nsdl_remove_resource_attribute(sn_nsdl_static_resource_parameters_s *params, sn_nsdl_resource_attribute_t attribute); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* SN_NSDL_LIB_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/source/include/sn_grs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/source/include/sn_grs.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef GRS_H_ +#define GRS_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SN_GRS_RESOURCE_ALREADY_EXISTS -2 +#define SN_GRS_INVALID_PATH -3 +#define SN_GRS_LIST_ADDING_FAILURE -4 +#define SN_GRS_RESOURCE_UPDATED -5 + +#define ACCESS_DENIED -6 + +#define SN_GRS_DELETE_METHOD 0 +#define SN_GRS_SEARCH_METHOD 1 + +#define SN_GRS_DEFAULT_ACCESS 0x0F + +#define SN_NDSL_RESOURCE_NOT_REGISTERED 0 +#define SN_NDSL_RESOURCE_REGISTERING 1 +#define SN_NDSL_RESOURCE_REGISTERED 2 + +/***** Structs *****/ + +typedef struct sn_grs_version_ { + uint8_t major_version; + uint8_t minor_version; + uint8_t build; +} sn_grs_version_s; + +typedef NS_LIST_HEAD(sn_nsdl_dynamic_resource_parameters_s, link) resource_list_t; + +struct grs_s { + struct coap_s *coap; + + void *(*sn_grs_alloc)(uint16_t); + void (*sn_grs_free)(void *); + uint8_t (*sn_grs_tx_callback)(struct nsdl_s *, sn_nsdl_capab_e , uint8_t *, uint16_t, sn_nsdl_addr_s *); + int8_t (*sn_grs_rx_callback)(struct nsdl_s *, sn_coap_hdr_s *, sn_nsdl_addr_s *); + + uint16_t resource_root_count; + resource_list_t resource_root_list; +}; + + +struct nsdl_s { + uint16_t update_register_msg_id; + uint16_t register_msg_len; + uint16_t update_register_msg_len; + + uint16_t register_msg_id; + uint16_t unregister_msg_id; + + uint16_t bootstrap_msg_id; + uint16_t oma_bs_port; /* Bootstrap port */ + uint8_t oma_bs_address_len; /* Bootstrap address length */ + unsigned int sn_nsdl_endpoint_registered:1; + + struct grs_s *grs; + uint8_t *oma_bs_address_ptr; /* Bootstrap address pointer. If null, no bootstrap in use */ + sn_nsdl_ep_parameters_s *ep_information_ptr; // Endpoint parameters, Name, Domain etc.. + sn_nsdl_oma_server_info_t *nsp_address_ptr; // NSP server address information + /* Application definable context. This is useful for example when interfacing with c++ objects where a pointer to object is set as the + * context, and in the callback functions the context pointer can be used to call methods for the correct instance of the c++ object. */ + void *context; + + void (*sn_nsdl_oma_bs_done_cb)(sn_nsdl_oma_server_info_t *server_info_ptr); /* Callback to inform application when bootstrap is done */ + void *(*sn_nsdl_alloc)(uint16_t); + void (*sn_nsdl_free)(void *); + uint8_t (*sn_nsdl_tx_callback)(struct nsdl_s *, sn_nsdl_capab_e , uint8_t *, uint16_t, sn_nsdl_addr_s *); + uint8_t (*sn_nsdl_rx_callback)(struct nsdl_s *, sn_coap_hdr_s *, sn_nsdl_addr_s *); + void (*sn_nsdl_oma_bs_done_cb_handle)(sn_nsdl_oma_server_info_t *server_info_ptr, + struct nsdl_s *handle); /* Callback to inform application when bootstrap is done with nsdl handle */ + uint8_t (*sn_nsdl_auto_obs_token_callback)(struct nsdl_s *, const char*, uint8_t*); +}; + +/***** Function prototypes *****/ +/** + * \fn extern grs_s *sn_grs_init (uint8_t (*sn_grs_tx_callback_ptr)(sn_nsdl_capab_e , uint8_t *, uint16_t, + * sn_nsdl_addr_s *), uint8_t (*sn_grs_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *), + * sn_grs_mem_s *sn_memory) + * + * \brief GRS library initialize function. + * + * This function initializes GRS and CoAP. + * + * \param sn_grs_tx_callback A function pointer to a transmit callback function. Should return 1 when succeed, 0 when failed + * \param *sn_grs_rx_callback_ptr A function pointer to a receiving callback function. If received packet is not for GRS, it will be passed to + * upper level (NSDL) to be proceed. + * \param sn_memory A pointer to a structure containing the platform specific functions for memory allocation and free. + * + * \return success pointer to handle, failure = NULL + * +*/ +extern struct grs_s *sn_grs_init(uint8_t (*sn_grs_tx_callback_ptr)(struct nsdl_s *, sn_nsdl_capab_e , uint8_t *, uint16_t, + sn_nsdl_addr_s *), + int8_t (*sn_grs_rx_callback_ptr)(struct nsdl_s *, sn_coap_hdr_s *, sn_nsdl_addr_s *), + void *(*sn_grs_alloc)(uint16_t), + void (*sn_grs_free)(void *)); + +extern sn_nsdl_dynamic_resource_parameters_s *sn_grs_get_first_resource(struct grs_s *handle); +extern sn_nsdl_dynamic_resource_parameters_s *sn_grs_get_next_resource(struct grs_s *handle, + const sn_nsdl_dynamic_resource_parameters_s *sn_grs_current_resource); +extern int8_t sn_grs_process_coap(struct nsdl_s *handle, + sn_coap_hdr_s *coap_packet_ptr, + sn_nsdl_addr_s *src); +extern sn_nsdl_dynamic_resource_parameters_s *sn_grs_search_resource(struct grs_s *handle, + const char *path, + uint8_t search_method); +extern int8_t sn_grs_destroy(struct grs_s *handle); +extern sn_grs_resource_list_s *sn_grs_list_resource(struct grs_s *handle, const char *path); +extern void sn_grs_free_resource_list(struct grs_s *handle, sn_grs_resource_list_s *list); +extern int8_t sn_grs_send_coap_message(struct nsdl_s *handle, + sn_nsdl_addr_s *address_ptr, + sn_coap_hdr_s *coap_hdr_ptr); +extern int8_t sn_grs_put_resource(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *res); +extern int8_t sn_grs_pop_resource(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *res); +extern int8_t sn_grs_delete_resource(struct grs_s *handle, const char *path); +extern void sn_grs_mark_resources_as_registered(struct nsdl_s *handle); + +#ifdef __cplusplus +} +#endif + + + + +#endif /* GRS_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/source/sn_grs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/source/sn_grs.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,819 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * \file sn_grs.c + * + * \brief General resource server. + * + */ +#include <string.h> +#include <stdlib.h> +#include "ns_list.h" +#include "ns_types.h" +#include "sn_nsdl.h" +#include "sn_coap_header.h" +#include "sn_coap_protocol.h" +#include "source/include/sn_coap_protocol_internal.h" +#include "sn_nsdl_lib.h" +#include "sn_grs.h" + +/* Defines */ +#define WELLKNOWN_PATH_LEN 16 +#define WELLKNOWN_PATH (".well-known/core") + +/* Local static function prototypes */ +static int8_t sn_grs_resource_info_free(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *resource_ptr); +static char *sn_grs_convert_uri(uint16_t *uri_len, const char *uri_ptr); +static int8_t sn_grs_core_request(struct nsdl_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *coap_packet_ptr); +static uint8_t coap_tx_callback(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *); +static int8_t coap_rx_callback(sn_coap_hdr_s *coap_ptr, sn_nsdl_addr_s *address_ptr, void *param); + +/* Extern function prototypes */ +extern int8_t sn_nsdl_build_registration_body(struct nsdl_s *handle, sn_coap_hdr_s *message_ptr, uint8_t updating_registeration); + +/** + * \fn int8_t sn_grs_destroy(void) + * \brief This function may be used to flush GRS related stuff when a program exits. + * @return always 0. + */ +extern int8_t sn_grs_destroy(struct grs_s *handle) +{ + if( handle == NULL ){ + return 0; + } + ns_list_foreach_safe(sn_nsdl_dynamic_resource_parameters_s, tmp, &handle->resource_root_list) { + ns_list_remove(&handle->resource_root_list, tmp); + --handle->resource_root_count; + sn_grs_resource_info_free(handle, tmp); + } + handle->sn_grs_free(handle); + + return 0; +} + +static uint8_t coap_tx_callback(uint8_t *data_ptr, uint16_t data_len, sn_nsdl_addr_s *address_ptr, void *param) +{ + struct nsdl_s *handle = (struct nsdl_s *)param; + + if (handle == NULL) { + return 0; + } + + return handle->grs->sn_grs_tx_callback(handle, SN_NSDL_PROTOCOL_COAP, data_ptr, data_len, address_ptr); +} + +static int8_t coap_rx_callback(sn_coap_hdr_s *coap_ptr, sn_nsdl_addr_s *address_ptr, void *param) +{ + struct nsdl_s *handle = (struct nsdl_s *)param; + + if (handle == NULL) { + return 0; + } + + return handle->sn_nsdl_rx_callback(handle, coap_ptr, address_ptr); +} + +/** + * \fn int8_t sn_grs_init (uint8_t (*sn_grs_tx_callback_ptr)(sn_nsdl_capab_e , uint8_t *, uint16_t, + * sn_nsdl_addr_s *), int8_t (*sn_grs_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *), sn_nsdl_mem_s *sn_memory) + * + * \brief GRS library initialize function. + * + * This function initializes GRS and CoAP libraries. + * + * \param sn_grs_tx_callback A function pointer to a transmit callback function. + * \param *sn_grs_rx_callback_ptr A function pointer to a receiving callback function. If received packet is not for GRS, it will be passed to + * upper level (NSDL) to be proceed. + * \param sn_memory A pointer to a structure containing the platform specific functions for memory allocation and free. + * + * \return success = 0, failure = -1 + * +*/ +extern struct grs_s *sn_grs_init(uint8_t (*sn_grs_tx_callback_ptr)(struct nsdl_s *, sn_nsdl_capab_e , uint8_t *, uint16_t, + sn_nsdl_addr_s *), int8_t (*sn_grs_rx_callback_ptr)(struct nsdl_s *, sn_coap_hdr_s *, sn_nsdl_addr_s *), + void *(*sn_grs_alloc)(uint16_t), void (*sn_grs_free)(void *)) +{ + + struct grs_s *handle_ptr = NULL; + + /* Check parameters */ + if (sn_grs_alloc == NULL || sn_grs_free == NULL || + sn_grs_tx_callback_ptr == NULL || sn_grs_rx_callback_ptr == NULL) { + return NULL; + } + + handle_ptr = sn_grs_alloc(sizeof(struct grs_s)); + + if (handle_ptr == NULL) { + return NULL; + } + + memset(handle_ptr, 0, sizeof(struct grs_s)); + + /* Allocation and free - function pointers */ + handle_ptr->sn_grs_alloc = sn_grs_alloc; + handle_ptr->sn_grs_free = sn_grs_free; + + /* TX callback function pointer */ + handle_ptr->sn_grs_tx_callback = sn_grs_tx_callback_ptr; + handle_ptr->sn_grs_rx_callback = sn_grs_rx_callback_ptr; + + /* Initialize CoAP protocol library */ + handle_ptr->coap = sn_coap_protocol_init(sn_grs_alloc, sn_grs_free, coap_tx_callback, coap_rx_callback); + + return handle_ptr; +} + +extern sn_grs_resource_list_s *sn_grs_list_resource(struct grs_s *handle, const char *path) +{ + (void) (path); + sn_grs_resource_list_s *grs_resource_list_ptr = NULL; + + if(handle == NULL){ + return NULL; + } + + /* Allocate memory for the resource list to be filled */ + grs_resource_list_ptr = handle->sn_grs_alloc(sizeof(sn_grs_resource_list_s)); + if (!grs_resource_list_ptr) { + goto fail; + } + + /* Count resources to the resource list struct */ + grs_resource_list_ptr->res_count = handle->resource_root_count; + grs_resource_list_ptr->res = NULL; + + /**************************************/ + /* Fill resource structs to the table */ + /**************************************/ + + /* If resources in list */ + if (grs_resource_list_ptr->res_count) { + int i; + + /* Allocate memory for resources */ + grs_resource_list_ptr->res = handle->sn_grs_alloc(grs_resource_list_ptr->res_count * sizeof(sn_grs_resource_s)); + if (!grs_resource_list_ptr->res) { + goto fail; + } + + /* Initialise the pointers to NULL to permit easy cleanup */ + for (i = 0; i < grs_resource_list_ptr->res_count; i++) { + grs_resource_list_ptr->res[i].path = NULL; + } + + i = 0; + size_t len = 0; + ns_list_foreach(sn_nsdl_dynamic_resource_parameters_s, grs_resource_ptr, &handle->resource_root_list) { + /* Copy pathlen to resource list */ + len = strlen(grs_resource_ptr->static_resource_parameters->path); + + /* Allocate memory for path string */ + grs_resource_list_ptr->res[i].path = handle->sn_grs_alloc(len); + if (!grs_resource_list_ptr->res[i].path) { + goto fail; + } + + /* Copy pathstring to resource list */ + memcpy(grs_resource_list_ptr->res[i].path, + grs_resource_ptr->static_resource_parameters->path, + len); + + i++; + } + } + return grs_resource_list_ptr; + +fail: + sn_grs_free_resource_list(handle, grs_resource_list_ptr); + return NULL; +} + +extern void sn_grs_free_resource_list(struct grs_s *handle, sn_grs_resource_list_s *list) +{ + if (!list || !handle) { + return; + } + + if (list->res) { + for (int i = 0; i < list->res_count; i++) { + if (list->res[i].path) { + handle->sn_grs_free(list->res[i].path); + list->res[i].path = NULL; + } + } + handle->sn_grs_free(list->res); + list->res = NULL; + } + + handle->sn_grs_free(list); +} + +extern sn_nsdl_dynamic_resource_parameters_s *sn_grs_get_first_resource(struct grs_s *handle) +{ + if( !handle ){ + return NULL; + } + return ns_list_get_first(&handle->resource_root_list); +} + +extern sn_nsdl_dynamic_resource_parameters_s *sn_grs_get_next_resource(struct grs_s *handle, + const sn_nsdl_dynamic_resource_parameters_s *sn_grs_current_resource) +{ + if( !handle || !sn_grs_current_resource ){ + return NULL; + } + return ns_list_get_next(&handle->resource_root_list, sn_grs_current_resource); +} + +extern int8_t sn_grs_delete_resource(struct grs_s *handle, const char *path) +{ + /* Local variables */ + sn_nsdl_dynamic_resource_parameters_s *resource_temp = NULL; + + /* Search if resource found */ + resource_temp = sn_grs_search_resource(handle, path, SN_GRS_SEARCH_METHOD); + + /* If not found */ + if (resource_temp == NULL) { + return SN_NSDL_FAILURE; + } + + /* If found, delete it and delete also subresources, if there is any */ + do { + /* Remove from list */ + ns_list_remove(&handle->resource_root_list, resource_temp); + --handle->resource_root_count; + + /* Free */ + sn_grs_resource_info_free(handle, resource_temp); + + /* Search for subresources */ + resource_temp = sn_grs_search_resource(handle, path, SN_GRS_DELETE_METHOD); + } while (resource_temp != NULL); + + return SN_NSDL_SUCCESS; +} + +int8_t sn_grs_put_resource(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) +{ + if (!res || !handle) { + return SN_NSDL_FAILURE; + } + + /* Check path validity */ + if (!res->static_resource_parameters->path || res->static_resource_parameters->path[0] == '\0') { + return SN_GRS_INVALID_PATH; + } + + /* Check if resource already exists */ + if (sn_grs_search_resource(handle, + res->static_resource_parameters->path, SN_GRS_SEARCH_METHOD) != (sn_nsdl_dynamic_resource_parameters_s *)NULL) { + return SN_GRS_RESOURCE_ALREADY_EXISTS; + } + + res->registered = SN_NDSL_RESOURCE_NOT_REGISTERED; + + ns_list_add_to_start(&handle->resource_root_list, res); + ++handle->resource_root_count; + + return SN_NSDL_SUCCESS; +} + +int8_t sn_grs_pop_resource(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) +{ + if (!res || !handle) { + return SN_NSDL_FAILURE; + } + + /* Check path validity */ + if (!res->static_resource_parameters->path || res->static_resource_parameters->path[0] == '\0') { + return SN_GRS_INVALID_PATH; + } + + /* Check if resource exists on list. */ + if (sn_grs_search_resource(handle, + res->static_resource_parameters->path, SN_GRS_SEARCH_METHOD) == (sn_nsdl_dynamic_resource_parameters_s *)NULL) { + return SN_NSDL_FAILURE; + } + + ns_list_remove(&handle->resource_root_list, res); + --handle->resource_root_count; + + return SN_NSDL_SUCCESS; +} + +/** + * \fn extern int8_t sn_grs_process_coap(uint8_t *packet, uint16_t *packet_len, sn_nsdl_addr_s *src) + * + * \brief To push CoAP packet to GRS library + * + * Used to push an CoAP packet to GRS library for processing. + * + * \param *packet Pointer to a uint8_t array containing the packet (including the CoAP headers). + * After successful execution this array may contain the response packet. + * + * \param *packet_len Pointer to length of the packet. After successful execution this array may contain the length + * of the response packet. + * + * \param *src Pointer to packet source address information. After successful execution this array may contain + * the destination address of the response packet. + * + * \return 0 = success, -1 = failure +*/ +extern int8_t sn_grs_process_coap(struct nsdl_s *nsdl_handle, sn_coap_hdr_s *coap_packet_ptr, sn_nsdl_addr_s *src_addr_ptr) +{ + if( !coap_packet_ptr || !nsdl_handle){ + return SN_NSDL_FAILURE; + } + + sn_nsdl_dynamic_resource_parameters_s *resource_temp_ptr = NULL; + sn_coap_msg_code_e status = COAP_MSG_CODE_EMPTY; + sn_coap_hdr_s *response_message_hdr_ptr = NULL; + struct grs_s *handle = nsdl_handle->grs; + bool static_get_request = false; + + if (coap_packet_ptr->msg_code <= COAP_MSG_CODE_REQUEST_DELETE) { + /* Check if .well-known/core */ + if (coap_packet_ptr->uri_path_len == WELLKNOWN_PATH_LEN && memcmp(coap_packet_ptr->uri_path_ptr, WELLKNOWN_PATH, WELLKNOWN_PATH_LEN) == 0) { + return sn_grs_core_request(nsdl_handle, src_addr_ptr, coap_packet_ptr); + } + + /* Get resource */ + char* path = nsdl_handle->grs->sn_grs_alloc(coap_packet_ptr->uri_path_len + 1); + if (!path) { + return SN_NSDL_FAILURE; + } + + memcpy(path, + coap_packet_ptr->uri_path_ptr, + coap_packet_ptr->uri_path_len); + path[coap_packet_ptr->uri_path_len] = '\0'; + + resource_temp_ptr = sn_grs_search_resource(handle, path, SN_GRS_SEARCH_METHOD); + nsdl_handle->grs->sn_grs_free(path); + + /* * * * * * * * * * * */ + /* If resource exists */ + /* * * * * * * * * * * */ + if (resource_temp_ptr) { + /* If dynamic resource, go to callback */ + if (resource_temp_ptr->static_resource_parameters->mode == SN_GRS_DYNAMIC) { + /* Check accesses */ + if (((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET) && !(resource_temp_ptr->access & SN_GRS_GET_ALLOWED)) || + ((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_POST) && !(resource_temp_ptr->access & SN_GRS_POST_ALLOWED)) || + ((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT) && !(resource_temp_ptr->access & SN_GRS_PUT_ALLOWED)) || + ((coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_DELETE) && !(resource_temp_ptr->access & SN_GRS_DELETE_ALLOWED))) { + status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } else { + /* Do not call null pointer.. */ + if (resource_temp_ptr->sn_grs_dyn_res_callback != NULL) { + resource_temp_ptr->sn_grs_dyn_res_callback(nsdl_handle, coap_packet_ptr, src_addr_ptr, SN_NSDL_PROTOCOL_COAP); + } + + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { + handle->sn_grs_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); + return SN_NSDL_SUCCESS; + } + } else { + /* Static resource handling */ + switch (coap_packet_ptr->msg_code) { + case COAP_MSG_CODE_REQUEST_GET: + if (resource_temp_ptr->access & SN_GRS_GET_ALLOWED) { + status = COAP_MSG_CODE_RESPONSE_CONTENT; + static_get_request = true; + } else { + status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + break; + + case COAP_MSG_CODE_REQUEST_POST: + case COAP_MSG_CODE_REQUEST_PUT: + case COAP_MSG_CODE_REQUEST_DELETE: + status = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + break; + + default: + status = COAP_MSG_CODE_RESPONSE_FORBIDDEN; + break; + } + } + } + + /* * * * * * * * * * * * * * */ + /* If resource was not found */ + /* * * * * * * * * * * * * * */ + + else { + if (coap_packet_ptr->msg_code == COAP_MSG_CODE_REQUEST_POST) { + handle->sn_grs_rx_callback(nsdl_handle, coap_packet_ptr, src_addr_ptr); + + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { + handle->sn_grs_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = 0; + } + + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); + return SN_NSDL_SUCCESS; + } else { + status = COAP_MSG_CODE_RESPONSE_NOT_FOUND; + } + } + } + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + /* If received packed was other than reset, create response */ + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + if (coap_packet_ptr->msg_type != COAP_MSG_TYPE_RESET && coap_packet_ptr->msg_type != COAP_MSG_TYPE_ACKNOWLEDGEMENT) { + + /* Allocate resopnse message */ + response_message_hdr_ptr = sn_coap_parser_alloc_message(handle->coap); + if (!response_message_hdr_ptr) { + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { + handle->sn_grs_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); + return SN_NSDL_FAILURE; + } + + /* If status has not been defined, response internal server error */ + if (status == COAP_MSG_CODE_EMPTY) { + status = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR; + } + + /* Fill header */ + response_message_hdr_ptr->msg_code = status; + + if (coap_packet_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { + response_message_hdr_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; + } else { + response_message_hdr_ptr->msg_type = COAP_MSG_TYPE_NON_CONFIRMABLE; + } + + response_message_hdr_ptr->msg_id = coap_packet_ptr->msg_id; + + if (coap_packet_ptr->token_ptr) { + response_message_hdr_ptr->token_len = coap_packet_ptr->token_len; + response_message_hdr_ptr->token_ptr = handle->sn_grs_alloc(response_message_hdr_ptr->token_len); + if (!response_message_hdr_ptr->token_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response_message_hdr_ptr); + + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { + handle->sn_grs_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = 0; + } + + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); + return SN_NSDL_FAILURE; + } + memcpy(response_message_hdr_ptr->token_ptr, coap_packet_ptr->token_ptr, response_message_hdr_ptr->token_len); + } + + if (status == COAP_MSG_CODE_RESPONSE_CONTENT) { + /* Add content type if other than default */ + if (resource_temp_ptr->static_resource_parameters) { + response_message_hdr_ptr->content_format = + (sn_coap_content_format_e) resource_temp_ptr->coap_content_type; + } + + /* Add payload */ + if (resource_temp_ptr->resourcelen != 0) { + response_message_hdr_ptr->payload_len = resource_temp_ptr->resourcelen; + response_message_hdr_ptr->payload_ptr = handle->sn_grs_alloc(response_message_hdr_ptr->payload_len); + + if (!response_message_hdr_ptr->payload_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response_message_hdr_ptr); + + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { + handle->sn_grs_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = 0; + } + + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); + return SN_NSDL_FAILURE; + } + + memcpy(response_message_hdr_ptr->payload_ptr, + resource_temp_ptr->resource, + response_message_hdr_ptr->payload_len); + } + // Add max-age attribute for static resources. + // Not a mandatory parameter, no need to return in case of memory allocation fails. + if (static_get_request) { + if (sn_coap_parser_alloc_options(handle->coap, response_message_hdr_ptr)) { + response_message_hdr_ptr->options_list_ptr->max_age = 0; + } + } + } + sn_grs_send_coap_message(nsdl_handle, src_addr_ptr, response_message_hdr_ptr); + + if (response_message_hdr_ptr->payload_ptr) { + handle->sn_grs_free(response_message_hdr_ptr->payload_ptr); + response_message_hdr_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, response_message_hdr_ptr); + } + + /* Free parsed CoAP message */ + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { + handle->sn_grs_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->coap, coap_packet_ptr); + + return SN_NSDL_SUCCESS; +} + +extern int8_t sn_grs_send_coap_message(struct nsdl_s *handle, sn_nsdl_addr_s *address_ptr, sn_coap_hdr_s *coap_hdr_ptr) +{ + uint8_t *message_ptr = NULL; + uint16_t message_len = 0; + int16_t ret_val = 0; + + if( !handle ){ + return SN_NSDL_FAILURE; + } + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ + ret_val = prepare_blockwise_message(handle->grs->coap, coap_hdr_ptr); + if( 0 != ret_val ) { + return SN_NSDL_FAILURE; + } +#endif + + /* Calculate message length */ + message_len = sn_coap_builder_calc_needed_packet_data_size_2(coap_hdr_ptr, handle->grs->coap->sn_coap_block_data_size); + + /* Allocate memory for message and check was allocating successfully */ + message_ptr = handle->grs->sn_grs_alloc(message_len); + if (message_ptr == NULL) { + return SN_NSDL_FAILURE; + } + + /* Build CoAP message */ + ret_val = sn_coap_protocol_build(handle->grs->coap, address_ptr, message_ptr, coap_hdr_ptr, (void *)handle); + if (ret_val < 0) { + handle->grs->sn_grs_free(message_ptr); + message_ptr = 0; + if (ret_val == -4) { + return SN_NSDL_RESEND_QUEUE_FULL; + } else { + return SN_NSDL_FAILURE; + } + } + + /* Call tx callback function to send message */ + ret_val = handle->grs->sn_grs_tx_callback(handle, SN_NSDL_PROTOCOL_COAP, message_ptr, message_len, address_ptr); + + /* Free allocated memory */ + handle->grs->sn_grs_free(message_ptr); + message_ptr = 0; + + if (ret_val == 0) { + return SN_NSDL_FAILURE; + } else { + return SN_NSDL_SUCCESS; + } +} + +static int8_t sn_grs_core_request(struct nsdl_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *coap_packet_ptr) +{ + sn_coap_hdr_s *response_message_hdr_ptr = NULL; + sn_coap_content_format_e wellknown_content_format = COAP_CT_LINK_FORMAT; + + /* Allocate response message */ + response_message_hdr_ptr = sn_coap_parser_alloc_message(handle->grs->coap); + if (response_message_hdr_ptr == NULL) { + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { + handle->grs->sn_grs_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_FAILURE; + } + + /* Build response */ + response_message_hdr_ptr->msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + response_message_hdr_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; + response_message_hdr_ptr->msg_id = coap_packet_ptr->msg_id; + response_message_hdr_ptr->content_format = wellknown_content_format; + + sn_nsdl_build_registration_body(handle, response_message_hdr_ptr, 0); + + /* Send and free */ + sn_grs_send_coap_message(handle, src_addr_ptr, response_message_hdr_ptr); + + if (response_message_hdr_ptr->payload_ptr) { + handle->grs->sn_grs_free(response_message_hdr_ptr->payload_ptr); + response_message_hdr_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, response_message_hdr_ptr); + + /* Free parsed CoAP message */ + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && coap_packet_ptr->payload_ptr) { + handle->grs->sn_grs_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + + return SN_NSDL_SUCCESS; +} + +/** + * \fn static sn_grs_resource_info_s *sn_grs_search_resource(struct grs_s *handle, const char *path, uint8_t search_method) + * + * \brief Searches given resource from linked list + * + * Search either precise path, or subresources, eg. dr/x -> returns dr/x/1, dr/x/2 etc... + * + * \param pathlen Length of the path to be search + * + * \param *path Pointer to the path string to be search + * + * \param search_method Search method, SEARCH or DELETE + * + * \return Pointer to the resource. If resource not found, return value is NULL + * +*/ + +sn_nsdl_dynamic_resource_parameters_s *sn_grs_search_resource(struct grs_s *handle, const char *path, uint8_t search_method) +{ + /* Local variables */ + char *path_temp_ptr = NULL; + /* Check parameters */ + if (!handle || !path) { + return NULL; + } + uint16_t pathlen = strlen(path); + /* Remove '/' - marks from the end and beginning */ + path_temp_ptr = sn_grs_convert_uri(&pathlen, path); + + /* Searchs exact path */ + if (search_method == SN_GRS_SEARCH_METHOD) { + /* Scan all nodes on list */ + ns_list_foreach(sn_nsdl_dynamic_resource_parameters_s, resource_search_temp, &handle->resource_root_list) { + /* If length equals.. */ + size_t len = 0; + if(resource_search_temp && + resource_search_temp->static_resource_parameters && + resource_search_temp->static_resource_parameters->path) { + len = strlen(resource_search_temp->static_resource_parameters->path); + } + + if (len == pathlen) { + /* Compare paths, If same return node pointer*/ + if (0 == memcmp(resource_search_temp->static_resource_parameters->path, + path_temp_ptr, + pathlen)) { + return resource_search_temp; + } + } + } + } + /* Search also subresources, eg. dr/x -> returns dr/x/1, dr/x/2 etc... */ + else if (search_method == SN_GRS_DELETE_METHOD) { + /* Scan all nodes on list */ + ns_list_foreach(sn_nsdl_dynamic_resource_parameters_s, resource_search_temp, &handle->resource_root_list) { + char *temp_path = resource_search_temp->static_resource_parameters->path; + if (strlen(resource_search_temp->static_resource_parameters->path) > pathlen && + (*(temp_path + (uint8_t)pathlen) == '/') && + 0 == memcmp(resource_search_temp->static_resource_parameters->path, + path_temp_ptr, + pathlen)) { + return resource_search_temp; + } + } + } + + /* If there was not nodes we wanted, return NULL */ + return NULL; +} + +/** + * \fn static uint8_t *sn_grs_convert_uri(uint16_t *uri_len, uint8_t *uri_ptr) + * + * \brief Removes '/' from the beginning and from the end of uri string + * + * \param *uri_len Pointer to the length of the path string + * + * \param *uri_ptr Pointer to the path string + * + * \return start pointer of the uri + * +*/ + +static char *sn_grs_convert_uri(uint16_t *uri_len, const char *uri_ptr) +{ + /* Local variables */ + char *uri_start_ptr = (char *) uri_ptr; + + /* If '/' in the beginning, update uri start pointer and uri len */ + if (*uri_ptr == '/') { + uri_start_ptr = (char *) uri_ptr + 1; + *uri_len = *uri_len - 1; + } + + /* If '/' at the end, update uri len */ + if (*(uri_start_ptr + *uri_len - 1) == '/') { + *uri_len = *uri_len - 1; + } + + /* Return start pointer */ + return uri_start_ptr; +} + +/** + * \fn static int8_t sn_grs_resource_info_free(sn_grs_resource_info_s *resource_ptr) + * + * \brief Frees resource info structure + * + * \param *resource_ptr Pointer to the resource + * + * \return 0 if success, -1 if failed + * +*/ +static int8_t sn_grs_resource_info_free(struct grs_s *handle, sn_nsdl_dynamic_resource_parameters_s *resource_ptr) +{ + if (resource_ptr) { +#ifdef MEMORY_OPTIMIZED_API + if (resource_ptr->free_on_delete) { + handle->sn_grs_free(resource_ptr); + } + return SN_NSDL_FAILURE; +#else + if (resource_ptr->static_resource_parameters && + resource_ptr->static_resource_parameters->free_on_delete) { +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_INTERFACE_DESCRIPTION + if (resource_ptr->static_resource_parameters->interface_description_ptr) { + handle->sn_grs_free(resource_ptr->static_resource_parameters->interface_description_ptr); + resource_ptr->static_resource_parameters->interface_description_ptr = 0; + } +#endif +#ifndef DISABLE_RESOURCE_TYPE + if (resource_ptr->static_resource_parameters->resource_type_ptr) { + handle->sn_grs_free(resource_ptr->static_resource_parameters->resource_type_ptr); + resource_ptr->static_resource_parameters->resource_type_ptr = 0; + } +#endif +#else + sn_nsdl_free_resource_attributes_list(resource_ptr->static_resource_parameters); +#endif + if (resource_ptr->static_resource_parameters->path) { + handle->sn_grs_free(resource_ptr->static_resource_parameters->path); + resource_ptr->static_resource_parameters->path = 0; + } + + if (resource_ptr->resource) { + handle->sn_grs_free(resource_ptr->resource); + resource_ptr->resource = 0; + } + + handle->sn_grs_free(resource_ptr->static_resource_parameters); + resource_ptr->static_resource_parameters = 0; + } + if (resource_ptr->free_on_delete) { + handle->sn_grs_free(resource_ptr); + } + return SN_NSDL_SUCCESS; +#endif + } + return SN_NSDL_FAILURE; //Dead code? +} + +void sn_grs_mark_resources_as_registered(struct nsdl_s *handle) +{ + if( !handle ){ + return; + } + + sn_nsdl_dynamic_resource_parameters_s *temp_resource; + + temp_resource = sn_grs_get_first_resource(handle->grs); + + while (temp_resource) { + if (temp_resource->registered == SN_NDSL_RESOURCE_REGISTERING) { + temp_resource->registered = SN_NDSL_RESOURCE_REGISTERED; + } + temp_resource = sn_grs_get_next_resource(handle->grs, temp_resource); + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/source/sn_nsdl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-c/source/sn_nsdl.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2465 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * \file sn_nsdl.c + * + * \brief Nano service device library + * + */ + +// Needed for PRIu64 on FreeRTOS +#include <stdio.h> +// Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include <string.h> + +#include "ns_types.h" +#include "sn_nsdl.h" +#include "sn_coap_header.h" +#include "sn_coap_protocol.h" +#include "source/include/sn_coap_protocol_internal.h" +#include "sn_nsdl_lib.h" +#include "sn_grs.h" +#include "mbed-trace/mbed_trace.h" +#include "common_functions.h" +#include <stdlib.h> + +/* Defines */ +#define TRACE_GROUP "mClt" +#define RESOURCE_DIR_LEN 2 +#define EP_NAME_PARAMETERS_LEN 3 +#define ET_PARAMETER_LEN 3 +#define LT_PARAMETER_LEN 3 +#define DOMAIN_PARAMETER_LEN 2 +#define RT_PARAMETER_LEN 3 +#define IF_PARAMETER_LEN 3 +#define NAME_PARAMETER_LEN 5 +#define OBS_PARAMETER_LEN 3 +#define AOBS_PARAMETER_LEN 5 +#define COAP_CON_PARAMETER_LEN 3 +#define BS_EP_PARAMETER_LEN 3 +#define BS_QUEUE_MODE_PARAMATER_LEN 2 + +#define SN_NSDL_EP_REGISTER_MESSAGE 1 +#define SN_NSDL_EP_UPDATE_MESSAGE 2 + +#define SN_NSDL_MSG_UNDEFINED 0 +#define SN_NSDL_MSG_REGISTER 1 +#define SN_NSDL_MSG_UNREGISTER 2 +#define SN_NSDL_MSG_UPDATE 3 +#define SN_NSDL_MSG_BOOTSTRAP 4 + +#ifdef YOTTA_CFG_DISABLE_OBS_FEATURE +#define COAP_DISABLE_OBS_FEATURE YOTTA_CFG_DISABLE_OBS_FEATURE +#elif defined MBED_CONF_MBED_CLIENT_COAP_DISABLE_OBS_FEATURE +#define COAP_DISABLE_OBS_FEATURE MBED_CONF_MBED_CLIENT_COAP_DISABLE_OBS_FEATURE +#endif + +#ifdef YOTTA_CFG_DISABLE_BOOTSTRAP_FEATURE +#define MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE YOTTA_CFG_DISABLE_BOOTSTRAP_FEATURE +#elif defined MBED_CONF_MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +#define MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE MBED_CONF_MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +#endif + +/* Constants */ +static uint8_t ep_name_parameter_string[] = {'e', 'p', '='}; /* Endpoint name. A unique name for the registering node in a domain. */ +static uint8_t resource_path_ptr[] = {'r', 'd'}; /* For resource directory */ +static uint8_t resource_type_parameter[] = {'r', 't', '='}; /* Resource type. Only once for registration */ +#ifndef COAP_DISABLE_OBS_FEATURE +static uint8_t obs_parameter[] = {'o', 'b', 's'}; /* Observable */ +static uint8_t aobs_parameter[] = {'a', 'o', 'b', 's', '='}; /* Auto observable */ +#endif +static uint8_t if_description_parameter[] = {'i', 'f', '='}; /* Interface description. Only once */ +static uint8_t ep_lifetime_parameter[] = {'l', 't', '='}; /* Lifetime. Number of seconds that this registration will be valid for. Must be updated within this time, or will be removed. */ +static uint8_t ep_domain_parameter[] = {'d', '='}; /* Domain name. If this parameter is missing, a default domain is assumed. */ +static uint8_t coap_con_type_parameter[] = {'c', 't', '='}; /* CoAP content type */ + +#ifdef RESOURCE_ATTRIBUTES_LIST +static uint8_t name_parameter[] = {'n', 'a', 'm', 'e', '='}; +#endif + +/* * OMA BS parameters * */ +static uint8_t bs_uri[] = {'b', 's'}; +static uint8_t bs_ep_name[] = {'e', 'p', '='}; +static uint8_t et_parameter[] = {'e', 't', '='}; /* Endpoint type */ +static uint8_t bs_queue_mode[] = {'b', '='}; + +/* Function prototypes */ +static int32_t sn_nsdl_internal_coap_send(struct nsdl_s *handle, sn_coap_hdr_s *coap_header_ptr, sn_nsdl_addr_s *dst_addr_ptr, uint8_t message_description); +static void sn_nsdl_resolve_nsp_address(struct nsdl_s *handle); +int8_t sn_nsdl_build_registration_body(struct nsdl_s *handle, sn_coap_hdr_s *message_ptr, uint8_t updating_registeration); +static uint16_t sn_nsdl_calculate_registration_body_size(struct nsdl_s *handle, uint8_t updating_registeration, int8_t *error); +static uint8_t sn_nsdl_calculate_uri_query_option_len(sn_nsdl_ep_parameters_s *endpoint_info_ptr, uint8_t msg_type); +static int8_t sn_nsdl_fill_uri_query_options(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *parameter_ptr, sn_coap_hdr_s *source_msg_ptr, uint8_t msg_type, char *uri_queries[], uint32_t query_count); +static int8_t sn_nsdl_local_rx_function(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, sn_nsdl_addr_s *address_ptr); +static int8_t sn_nsdl_resolve_ep_information(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr); +static uint8_t sn_nsdl_itoa_len(uint32_t value); +static uint8_t *sn_nsdl_itoa(uint8_t *ptr, uint32_t value); +static int8_t set_endpoint_info(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *endpoint_info_ptr); +static bool validateParameters(sn_nsdl_ep_parameters_s *parameter_ptr); +static bool validate(uint8_t* ptr, uint32_t len, char illegalChar); +static bool sn_nsdl_check_uint_overflow(uint16_t resource_size, uint16_t param_a, uint16_t param_b); +static void remove_previous_block_data(struct nsdl_s *handle, sn_nsdl_addr_s *src_ptr, const uint32_t block_number); +static bool update_last_block_data(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, bool block1); +static void sn_nsdl_print_coap_data(sn_coap_hdr_s *coap_header_ptr, bool outgoing); +#if defined(FEA_TRACE_SUPPORT) || MBED_CONF_MBED_TRACE_ENABLE || YOTTA_CFG_MBED_TRACE || (defined(YOTTA_CFG) && !defined(NDEBUG)) +static const char* sn_nsdl_coap_status_description(sn_coap_status_e status); +static const char* sn_nsdl_coap_message_code_desc(int msg_code); +static const char* sn_nsdl_coap_message_type_desc(int msg_type); +#endif + +int8_t sn_nsdl_destroy(struct nsdl_s *handle) +{ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + if (handle->ep_information_ptr) { + handle->sn_nsdl_free(handle->ep_information_ptr->endpoint_name_ptr); + handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); + handle->sn_nsdl_free(handle->ep_information_ptr->location_ptr); + handle->sn_nsdl_free(handle->ep_information_ptr->type_ptr); + handle->sn_nsdl_free(handle->ep_information_ptr->lifetime_ptr); + handle->sn_nsdl_free(handle->ep_information_ptr); + } + + if (handle->nsp_address_ptr) { + if (handle->nsp_address_ptr->omalw_address_ptr) { + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr); + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr); + } + + handle->sn_nsdl_free(handle->nsp_address_ptr); + } + + handle->sn_nsdl_free(handle->oma_bs_address_ptr); + + /* Destroy also libCoap and grs part of libNsdl */ + sn_coap_protocol_destroy(handle->grs->coap); + sn_grs_destroy(handle->grs); + handle->sn_nsdl_free(handle); + + return SN_NSDL_SUCCESS; +} + +struct nsdl_s *sn_nsdl_init(uint8_t (*sn_nsdl_tx_cb)(struct nsdl_s *, sn_nsdl_capab_e , uint8_t *, uint16_t, sn_nsdl_addr_s *), + uint8_t (*sn_nsdl_rx_cb)(struct nsdl_s *, sn_coap_hdr_s *, sn_nsdl_addr_s *), + void *(*sn_nsdl_alloc)(uint16_t), void (*sn_nsdl_free)(void *), + uint8_t (*sn_nsdl_auto_obs_token_cb)(struct nsdl_s *, const char *, uint8_t *)) +{ + /* Check pointers and define function pointers */ + if (!sn_nsdl_alloc || !sn_nsdl_free || !sn_nsdl_tx_cb || !sn_nsdl_rx_cb) { + return NULL; + } + + struct nsdl_s *handle = NULL; + + handle = sn_nsdl_alloc(sizeof(struct nsdl_s)); + + if (handle == NULL) { + return NULL; + } + + memset(handle, 0, sizeof(struct nsdl_s)); + + /* Define function pointers */ + handle->sn_nsdl_alloc = sn_nsdl_alloc; + handle->sn_nsdl_free = sn_nsdl_free; + + handle->sn_nsdl_tx_callback = sn_nsdl_tx_cb; + handle->sn_nsdl_rx_callback = sn_nsdl_rx_cb; + handle->sn_nsdl_auto_obs_token_callback = sn_nsdl_auto_obs_token_cb; + + /* Initialize ep parameters struct */ + if (!handle->ep_information_ptr) { + handle->ep_information_ptr = handle->sn_nsdl_alloc(sizeof(sn_nsdl_ep_parameters_s)); + if (!handle->ep_information_ptr) { + sn_nsdl_free(handle); + return NULL; + } + memset(handle->ep_information_ptr, 0, sizeof(sn_nsdl_ep_parameters_s)); + } + + handle->grs = sn_grs_init(sn_nsdl_tx_cb, &sn_nsdl_local_rx_function, sn_nsdl_alloc, sn_nsdl_free); + + /* Initialize GRS */ + if (handle->grs == NULL) { + handle->sn_nsdl_free(handle->ep_information_ptr); + handle->ep_information_ptr = 0; + sn_nsdl_free(handle); + return NULL; + } + + sn_nsdl_resolve_nsp_address(handle); + + handle->sn_nsdl_endpoint_registered = SN_NSDL_ENDPOINT_NOT_REGISTERED; + handle->context = NULL; + + return handle; +} + +uint16_t sn_nsdl_register_endpoint(struct nsdl_s *handle, + sn_nsdl_ep_parameters_s *endpoint_info_ptr, + char *uri_query_parameters[], + uint32_t query_param_count) +{ + /* Local variables */ + sn_coap_hdr_s *register_message_ptr; + uint16_t message_id = 0; + + if (endpoint_info_ptr == NULL || handle == NULL) { + return 0; + } + + /*** Build endpoint register message ***/ + + /* Allocate memory for header struct */ + register_message_ptr = sn_coap_parser_alloc_message(handle->grs->coap); + if (register_message_ptr == NULL) { + return 0; + } + + /* Fill message fields -> confirmable post to specified NSP path */ + register_message_ptr->msg_type = COAP_MSG_TYPE_CONFIRMABLE; + register_message_ptr->msg_code = COAP_MSG_CODE_REQUEST_POST; + + /* Allocate memory for the extended options list */ + if (sn_coap_parser_alloc_options(handle->grs->coap, register_message_ptr) == NULL) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + register_message_ptr = 0; + return 0; + } + + register_message_ptr->uri_path_len = sizeof(resource_path_ptr); + register_message_ptr->uri_path_ptr = resource_path_ptr; + + /* Fill Uri-query options */ + if( SN_NSDL_FAILURE == sn_nsdl_fill_uri_query_options(handle, endpoint_info_ptr, + register_message_ptr, SN_NSDL_EP_REGISTER_MESSAGE, + uri_query_parameters, query_param_count) ){ + register_message_ptr->uri_path_ptr = NULL; + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + return 0; + } + + if (endpoint_info_ptr->ds_register_mode == REGISTER_WITH_RESOURCES) { + /* Built body for message */ + if (sn_nsdl_build_registration_body(handle, register_message_ptr, 0) == SN_NSDL_FAILURE) { + register_message_ptr->uri_path_ptr = NULL; + register_message_ptr->options_list_ptr->uri_host_ptr = NULL; + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + return 0; + } + } + + /* Clean (possible) existing and save new endpoint info to handle */ + if (set_endpoint_info(handle, endpoint_info_ptr) == -1) { + + handle->sn_nsdl_free(register_message_ptr->payload_ptr); + register_message_ptr->payload_ptr = NULL; + + register_message_ptr->uri_path_ptr = NULL; + register_message_ptr->options_list_ptr->uri_host_ptr = NULL; + + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + + return 0; + } + + /* Build and send coap message to NSP */ + message_id = sn_nsdl_internal_coap_send(handle, register_message_ptr, handle->nsp_address_ptr->omalw_address_ptr, SN_NSDL_MSG_REGISTER); + + handle->sn_nsdl_free(register_message_ptr->payload_ptr); + register_message_ptr->payload_ptr = NULL; + + register_message_ptr->uri_path_ptr = NULL; + register_message_ptr->options_list_ptr->uri_host_ptr = NULL; + + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + + return message_id; +} + +int32_t sn_nsdl_unregister_endpoint(struct nsdl_s *handle) +{ + /* Local variables */ + sn_coap_hdr_s *unregister_message_ptr; + uint8_t *temp_ptr = 0; + int32_t message_id = 0; + + /* Check parameters */ + if (handle == NULL) { + return 0; + } + + /* Check that EP have been registered */ + if (sn_nsdl_is_ep_registered(handle)) { + + /* Memory allocation for unregister message */ + unregister_message_ptr = sn_coap_parser_alloc_message(handle->grs->coap); + if (!unregister_message_ptr) { + return 0; + } + + /* Fill unregister message */ + unregister_message_ptr->msg_type = COAP_MSG_TYPE_CONFIRMABLE; + unregister_message_ptr->msg_code = COAP_MSG_CODE_REQUEST_DELETE; + + if(handle->ep_information_ptr->location_ptr) { + unregister_message_ptr->uri_path_len = handle->ep_information_ptr->location_len; + unregister_message_ptr->uri_path_ptr = handle->sn_nsdl_alloc(unregister_message_ptr->uri_path_len); + if (!unregister_message_ptr->uri_path_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, unregister_message_ptr); + return 0; + } + + temp_ptr = unregister_message_ptr->uri_path_ptr; + + memcpy(temp_ptr , handle->ep_information_ptr->location_ptr, handle->ep_information_ptr->location_len); + } else { + unregister_message_ptr->uri_path_len = (RESOURCE_DIR_LEN + 1 + handle->ep_information_ptr->domain_name_len + 1 + handle->ep_information_ptr->endpoint_name_len); + unregister_message_ptr->uri_path_ptr = handle->sn_nsdl_alloc(unregister_message_ptr->uri_path_len); + if (!unregister_message_ptr->uri_path_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, unregister_message_ptr); + return 0; + } + + temp_ptr = unregister_message_ptr->uri_path_ptr; + + memcpy(temp_ptr, resource_path_ptr, RESOURCE_DIR_LEN); + temp_ptr += RESOURCE_DIR_LEN; + + *temp_ptr++ = '/'; + + memcpy(temp_ptr , handle->ep_information_ptr->domain_name_ptr, handle->ep_information_ptr->domain_name_len); + temp_ptr += handle->ep_information_ptr->domain_name_len; + + *temp_ptr++ = '/'; + + memcpy(temp_ptr , handle->ep_information_ptr->endpoint_name_ptr, handle->ep_information_ptr->endpoint_name_len); + } + + /* Send message */ + message_id = sn_nsdl_internal_coap_send(handle, unregister_message_ptr, handle->nsp_address_ptr->omalw_address_ptr, SN_NSDL_MSG_UNREGISTER); + + /* Free memory */ + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, unregister_message_ptr); + + } + + return message_id; +} + +int32_t sn_nsdl_update_registration(struct nsdl_s *handle, uint8_t *lt_ptr, uint8_t lt_len) +{ + /* Local variables */ + sn_coap_hdr_s *register_message_ptr; + uint8_t *temp_ptr; + sn_nsdl_ep_parameters_s temp_parameters; + int32_t message_id = 0; + + /* Check parameters */ + if (handle == NULL) { + return 0; + } + + if (!sn_nsdl_is_ep_registered(handle)){ + return 0; + } + + memset(&temp_parameters, 0, sizeof(sn_nsdl_ep_parameters_s)); + + temp_parameters.lifetime_len = lt_len; + temp_parameters.lifetime_ptr = lt_ptr; + + /*** Build endpoint register update message ***/ + + /* Allocate memory for header struct */ + register_message_ptr = sn_coap_parser_alloc_message(handle->grs->coap); + if (register_message_ptr == NULL) { + return 0; + } + + /* Fill message fields -> confirmable post to specified NSP path */ + register_message_ptr->msg_type = COAP_MSG_TYPE_CONFIRMABLE; + register_message_ptr->msg_code = COAP_MSG_CODE_REQUEST_POST; + + if(handle->ep_information_ptr->location_ptr) { + register_message_ptr->uri_path_len = handle->ep_information_ptr->location_len; /* = Only location set by Device Server*/ + + register_message_ptr->uri_path_ptr = handle->sn_nsdl_alloc(register_message_ptr->uri_path_len); + if (!register_message_ptr->uri_path_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + return 0; + } + + temp_ptr = register_message_ptr->uri_path_ptr; + + /* location */ + memcpy(temp_ptr, handle->ep_information_ptr->location_ptr, handle->ep_information_ptr->location_len); + } else { + register_message_ptr->uri_path_len = sizeof(resource_path_ptr) + handle->ep_information_ptr->domain_name_len + handle->ep_information_ptr->endpoint_name_len + 2; /* = rd/domain/endpoint */ + + register_message_ptr->uri_path_ptr = handle->sn_nsdl_alloc(register_message_ptr->uri_path_len); + if (!register_message_ptr->uri_path_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + return 0; + } + + temp_ptr = register_message_ptr->uri_path_ptr; + + /* rd/ */ + memcpy(temp_ptr, resource_path_ptr, sizeof(resource_path_ptr)); + temp_ptr += sizeof(resource_path_ptr); + *temp_ptr++ = '/'; + + /* rd/DOMAIN/ */ + memcpy(temp_ptr, handle->ep_information_ptr->domain_name_ptr, handle->ep_information_ptr->domain_name_len); + temp_ptr += handle->ep_information_ptr->domain_name_len; + *temp_ptr++ = '/'; + + /* rd/domain/ENDPOINT */ + memcpy(temp_ptr, handle->ep_information_ptr->endpoint_name_ptr, handle->ep_information_ptr->endpoint_name_len); + } + + /* Allocate memory for the extended options list */ + if (sn_coap_parser_alloc_options(handle->grs->coap, register_message_ptr) == NULL) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + return 0; + } + + /* Fill Uri-query options */ + sn_nsdl_fill_uri_query_options(handle, &temp_parameters, register_message_ptr, SN_NSDL_EP_UPDATE_MESSAGE, NULL, 0); + + /* Build payload */ + if (handle->ep_information_ptr->ds_register_mode == REGISTER_WITH_RESOURCES) { + + if (sn_nsdl_build_registration_body(handle, register_message_ptr, 1) == SN_NSDL_FAILURE) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + return 0; + } + } + + /* Build and send coap message to NSP */ + message_id = sn_nsdl_internal_coap_send(handle, register_message_ptr, handle->nsp_address_ptr->omalw_address_ptr, SN_NSDL_MSG_UPDATE); + + handle->sn_nsdl_free(register_message_ptr->payload_ptr); + + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, register_message_ptr); + + return message_id; +} + +int8_t sn_nsdl_set_endpoint_location(struct nsdl_s *handle, uint8_t *location_ptr, uint8_t location_len) +{ + if(!handle || !location_ptr || (location_len == 0)) { + return -1; + } + + handle->sn_nsdl_free(handle->ep_information_ptr->location_ptr); + handle->ep_information_ptr->location_ptr = handle->sn_nsdl_alloc(location_len); + memcpy(handle->ep_information_ptr->location_ptr, location_ptr, location_len); + handle->ep_information_ptr->location_len = location_len; + + return 0; +} + +void sn_nsdl_nsp_lost(struct nsdl_s *handle) +{ + /* Check parameters */ + if (handle == NULL) { + return; + } + + handle->sn_nsdl_endpoint_registered = SN_NSDL_ENDPOINT_NOT_REGISTERED; +} + +int8_t sn_nsdl_is_ep_registered(struct nsdl_s *handle) +{ + /* Check parameters */ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + return handle->sn_nsdl_endpoint_registered; +} + +int32_t sn_nsdl_send_observation_notification(struct nsdl_s *handle, uint8_t *token_ptr, uint8_t token_len, + uint8_t *payload_ptr, uint16_t payload_len, sn_coap_observe_e observe, sn_coap_msg_type_e message_type, + sn_coap_content_format_e content_format, + const int32_t message_id) +{ + sn_coap_hdr_s *notification_message_ptr; + int32_t return_msg_id = 0; + + /* Check parameters */ + if (handle == NULL || handle->grs == NULL) { + return 0; + } + + /* Allocate and initialize memory for header struct */ + notification_message_ptr = sn_coap_parser_alloc_message(handle->grs->coap); + if (notification_message_ptr == NULL) { + return 0; + } + + if (sn_coap_parser_alloc_options(handle->grs->coap, notification_message_ptr) == NULL) { + handle->sn_nsdl_free(notification_message_ptr); + return 0; + } + + /* Fill header */ + notification_message_ptr->msg_type = message_type; + notification_message_ptr->msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + + /* Fill token */ + notification_message_ptr->token_len = token_len; + notification_message_ptr->token_ptr = token_ptr; + + /* Fill payload */ + notification_message_ptr->payload_len = payload_len; + notification_message_ptr->payload_ptr = payload_ptr; + + /* Fill observe */ + notification_message_ptr->options_list_ptr->observe = observe; + + /* Fill content format */ + notification_message_ptr->content_format = content_format; + + if (message_id != -1) { + notification_message_ptr->msg_id = message_id; + } + + /* Send message */ + return_msg_id = sn_nsdl_send_coap_message(handle, handle->nsp_address_ptr->omalw_address_ptr, notification_message_ptr); + if (return_msg_id >= SN_NSDL_SUCCESS) { + return_msg_id = notification_message_ptr->msg_id; + } + + /* Free memory */ + notification_message_ptr->payload_ptr = NULL; + notification_message_ptr->token_ptr = NULL; + + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, notification_message_ptr); + + return return_msg_id; +} + +/* * * * * * * * * * */ +/* ~ OMA functions ~ */ +/* * * * * * * * * * */ + +uint16_t sn_nsdl_oma_bootstrap(struct nsdl_s *handle, sn_nsdl_addr_s *bootstrap_address_ptr, + sn_nsdl_ep_parameters_s *endpoint_info_ptr, + sn_nsdl_bs_ep_info_t *bootstrap_endpoint_info_ptr, + char *uri_query_parameters[], + uint32_t query_param_count) +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + /* Local variables */ + sn_coap_hdr_s bootstrap_coap_header; + uint8_t *uri_query_tmp_ptr; + uint16_t message_id = 0; + + /* Check parameters */ + if (!bootstrap_address_ptr || !bootstrap_endpoint_info_ptr || !endpoint_info_ptr || !handle) { + return 0; + } + + handle->sn_nsdl_oma_bs_done_cb = bootstrap_endpoint_info_ptr->oma_bs_status_cb; + handle->sn_nsdl_oma_bs_done_cb_handle = bootstrap_endpoint_info_ptr->oma_bs_status_cb_handle; + + /* XXX FIX -- Init CoAP header struct */ + sn_coap_parser_init_message(&bootstrap_coap_header); + + if (!sn_coap_parser_alloc_options(handle->grs->coap, &bootstrap_coap_header)) { + return 0; + } + + /* Build bootstrap start message */ + bootstrap_coap_header.msg_code = COAP_MSG_CODE_REQUEST_POST; + bootstrap_coap_header.msg_type = COAP_MSG_TYPE_CONFIRMABLE; + + bootstrap_coap_header.uri_path_ptr = bs_uri; + bootstrap_coap_header.uri_path_len = sizeof(bs_uri); + + size_t query_len = endpoint_info_ptr->endpoint_name_len + BS_EP_PARAMETER_LEN; + bool optional_params = false; + if (query_param_count && uri_query_parameters) { + optional_params = true; + for (uint32_t i = 0; i < query_param_count; i++) { + query_len += strlen(uri_query_parameters[i]); + } + query_len += query_param_count; // Reserve space for '&' + } + + uri_query_tmp_ptr = handle->sn_nsdl_alloc(query_len); + if (!uri_query_tmp_ptr) { + handle->sn_nsdl_free(bootstrap_coap_header.options_list_ptr); + return 0; + } + + memcpy(uri_query_tmp_ptr, bs_ep_name, BS_EP_PARAMETER_LEN); + memcpy((uri_query_tmp_ptr + BS_EP_PARAMETER_LEN), + endpoint_info_ptr->endpoint_name_ptr, + endpoint_info_ptr->endpoint_name_len); + + // Add optional parameters, parsed from the server URL. + if (optional_params) { + uint8_t *temp_ptr = uri_query_tmp_ptr; + temp_ptr += endpoint_info_ptr->endpoint_name_len + BS_EP_PARAMETER_LEN; + for (uint32_t i = 0; i < query_param_count; i++) { + tr_info("sn_nsdl_oma_bootstrap - query: %s", uri_query_parameters[i]); + memcpy(temp_ptr, "&", 1); + temp_ptr++; + memcpy(temp_ptr, uri_query_parameters[i], strlen(uri_query_parameters[i])); + temp_ptr += strlen(uri_query_parameters[i]); + } + } + + bootstrap_coap_header.options_list_ptr->uri_query_len = query_len; + bootstrap_coap_header.options_list_ptr->uri_query_ptr = uri_query_tmp_ptr; + + /* Save bootstrap server address */ + handle->oma_bs_address_len = bootstrap_address_ptr->addr_len; /* Length.. */ + handle->oma_bs_address_ptr = handle->sn_nsdl_alloc(handle->oma_bs_address_len); /* Address.. */ + if (!handle->oma_bs_address_ptr) { + handle->sn_nsdl_free(bootstrap_coap_header.options_list_ptr); + handle->sn_nsdl_free(uri_query_tmp_ptr); + return 0; + } + memcpy(handle->oma_bs_address_ptr, bootstrap_address_ptr->addr_ptr, handle->oma_bs_address_len); + handle->oma_bs_port = bootstrap_address_ptr->port; /* And port */ + + /* Send message */ + message_id = sn_nsdl_internal_coap_send(handle, &bootstrap_coap_header, bootstrap_address_ptr, SN_NSDL_MSG_BOOTSTRAP); + + /* Free allocated memory */ + handle->sn_nsdl_free(uri_query_tmp_ptr); + handle->sn_nsdl_free(bootstrap_coap_header.options_list_ptr); + + return message_id; +#else + return 0; +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + +} + +char *sn_nsdl_get_version(void) +{ +#if defined(YOTTA_MBED_CLIENT_C_VERSION_STRING) + return YOTTA_MBED_CLIENT_C_VERSION_STRING; +#elif defined(VERSION) + return VERSION; +#else + return "0.0.0"; +#endif +} + +int8_t sn_nsdl_process_coap(struct nsdl_s *handle, uint8_t *packet_ptr, uint16_t packet_len, sn_nsdl_addr_s *src_ptr) +{ + sn_coap_hdr_s *coap_packet_ptr = NULL; + sn_coap_hdr_s *coap_response_ptr = NULL; + sn_nsdl_dynamic_resource_parameters_s *resource = NULL; + /* Check parameters */ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + /* Parse CoAP packet */ + coap_packet_ptr = sn_coap_protocol_parse(handle->grs->coap, src_ptr, packet_len, packet_ptr, (void *)handle); + + /* Check if parsing was successfull */ + if (coap_packet_ptr == (sn_coap_hdr_s *)NULL) { + return SN_NSDL_FAILURE; + } + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + // Pass block to application if external_memory_block is set + if((coap_packet_ptr->options_list_ptr && + coap_packet_ptr->options_list_ptr->block1 != -1) && + (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING || + coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED)) { + // Block 1 handling + /* Get resource */ + char* path = handle->sn_nsdl_alloc(coap_packet_ptr->uri_path_len + 1); + if (!path) { + return SN_NSDL_FAILURE; + } + + memcpy(path, + coap_packet_ptr->uri_path_ptr, + coap_packet_ptr->uri_path_len); + path[coap_packet_ptr->uri_path_len] = '\0'; + + + resource = sn_nsdl_get_resource(handle, path); + handle->sn_nsdl_free(path); + + if (coap_packet_ptr->options_list_ptr) { + if(resource && + resource->static_resource_parameters->external_memory_block && + coap_packet_ptr->options_list_ptr->block1) { + + uint32_t block_number = coap_packet_ptr->options_list_ptr->block1 >> 4; + if (block_number) { + remove_previous_block_data(handle, src_ptr, block_number); + } + + // Whole message received --> pass only the last block data to application + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { + // Get the block size + uint8_t temp = (coap_packet_ptr->options_list_ptr->block1 & 0x07); + uint16_t block_size = 1u << (temp + 4); + + uint32_t new_payload_len = coap_packet_ptr->payload_len - block_size; + uint8_t *temp_ptr = handle->grs->coap->sn_coap_protocol_malloc(new_payload_len); + if (temp_ptr) { + // Skip the second last block data since it's still stored in mbed-coap list! + memcpy(temp_ptr, coap_packet_ptr->payload_ptr + block_size, new_payload_len); + handle->grs->coap->sn_coap_protocol_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = NULL; + + coap_packet_ptr->payload_ptr = handle->grs->coap->sn_coap_protocol_malloc(new_payload_len); + if (coap_packet_ptr->payload_ptr) { + memcpy(coap_packet_ptr->payload_ptr, temp_ptr, new_payload_len); + coap_packet_ptr->payload_len = new_payload_len; + } + + handle->grs->coap->sn_coap_protocol_free(temp_ptr); + } + } + } else { + resource = NULL; + } + } else { + resource = NULL; + } + } +#endif + + sn_nsdl_print_coap_data(coap_packet_ptr, false); + + // Handling of GET responses + if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_CONTENT) { + bool data_updated = false; + if (coap_packet_ptr->options_list_ptr && coap_packet_ptr->options_list_ptr->block2 != -1) { + uint32_t block_number = coap_packet_ptr->options_list_ptr->block2 >> 4; + if (block_number) { + remove_previous_block_data(handle, src_ptr, block_number); + } + + // Modify payload to have only last received block data + data_updated = update_last_block_data(handle, coap_packet_ptr, false); + } + + handle->sn_nsdl_rx_callback(handle, coap_packet_ptr, src_ptr); + if (data_updated) { + handle->grs->coap->sn_coap_protocol_free(coap_packet_ptr->payload_ptr); + } + + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_SUCCESS; + } + + /* Check, if coap itself sends response, or block receiving is ongoing... */ + if (coap_packet_ptr->coap_status != COAP_STATUS_OK && + coap_packet_ptr->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && + coap_packet_ptr && + !resource) { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_SUCCESS; + } + + /* If proxy options added, return not supported */ + if (coap_packet_ptr->options_list_ptr) { + if (coap_packet_ptr->options_list_ptr->proxy_uri_len) { + coap_response_ptr = sn_coap_build_response(handle->grs->coap, coap_packet_ptr, COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED); + if (coap_response_ptr) { + sn_nsdl_send_coap_message(handle, src_ptr, coap_response_ptr); + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_response_ptr); + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_SUCCESS; + } else { + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_FAILURE; + } + } + } + + /* * * * * * * * * * * * * * * * * * * * * * * * * * */ + /* If message is response message, call RX callback */ + /* * * * * * * * * * * * * * * * * * * * * * * * * * */ + + if (((coap_packet_ptr->msg_code > COAP_MSG_CODE_REQUEST_DELETE) || + (coap_packet_ptr->msg_type >= COAP_MSG_TYPE_ACKNOWLEDGEMENT))) { + int8_t retval = sn_nsdl_local_rx_function(handle, coap_packet_ptr, src_ptr); + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED && + coap_packet_ptr->payload_ptr) { + handle->sn_nsdl_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return retval; + } +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + /* * If OMA bootstrap message... * */ + bool bootstrap_msg = src_ptr && (handle->oma_bs_address_len == src_ptr->addr_len) && + (handle->oma_bs_port == src_ptr->port) && + !memcmp(handle->oma_bs_address_ptr, src_ptr->addr_ptr, handle->oma_bs_address_len); + + // Pass bootstrap data to application + if (bootstrap_msg) { + handle->sn_nsdl_rx_callback(handle, coap_packet_ptr,src_ptr); + if (coap_packet_ptr && + coap_packet_ptr->options_list_ptr && + coap_packet_ptr->coap_status != COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED && + coap_packet_ptr->options_list_ptr->block1 != -1) { + handle->sn_nsdl_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = NULL; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, coap_packet_ptr); + return SN_NSDL_SUCCESS; + } +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + + /* * * * * * * * * * * * * * * */ + /* Other messages are for GRS */ + /* * * * * * * * * * * * * * * */ + return sn_grs_process_coap(handle, coap_packet_ptr, src_ptr); +} + +int8_t sn_nsdl_exec(struct nsdl_s *handle, uint32_t time) +{ + if(!handle || !handle->grs){ + return SN_NSDL_FAILURE; + } + /* Call CoAP execution function */ + return sn_coap_protocol_exec(handle->grs->coap, time); +} + +sn_nsdl_dynamic_resource_parameters_s *sn_nsdl_get_resource(struct nsdl_s *handle, const char *path_ptr) +{ + /* Check parameters */ + if (handle == NULL) { + return NULL; + } + + return sn_grs_search_resource(handle->grs, path_ptr, SN_GRS_SEARCH_METHOD); +} + + +/** + * \fn static int32_t sn_nsdl_internal_coap_send(struct nsdl_s *handle, sn_coap_hdr_s *coap_header_ptr, sn_nsdl_addr_s *dst_addr_ptr, uint8_t message_description) + * + * + * \brief To send NSDL messages. Stores message id?s and message description to catch response from NSP server + * \param *handle Pointer to nsdl-library handle + * \param *coap_header_ptr Pointer to the CoAP message header to be sent + * \param *dst_addr_ptr Pointer to the address structure that contains destination address information + * \param message_description Message description to be stored to list for waiting response + * + * \return message id, <=0 if failed + */ +static int32_t sn_nsdl_internal_coap_send(struct nsdl_s *handle, sn_coap_hdr_s *coap_header_ptr, sn_nsdl_addr_s *dst_addr_ptr, uint8_t message_description) +{ + + tr_debug("sn_nsdl_internal_coap_send"); + uint8_t *coap_message_ptr = NULL; + int32_t coap_message_len = 0; + uint16_t coap_header_len = 0; + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ + int8_t ret_val = prepare_blockwise_message(handle->grs->coap, coap_header_ptr); + if( 0 != ret_val ) { + return 0; + } +#endif + + coap_message_len = sn_coap_builder_calc_needed_packet_data_size_2(coap_header_ptr, handle->grs->coap->sn_coap_block_data_size); + tr_debug("sn_nsdl_internal_coap_send - msg len after calc: %" PRId32 "", coap_message_len); + if (coap_message_len == 0) { + return 0; + } + + coap_message_ptr = handle->sn_nsdl_alloc(coap_message_len); + if (!coap_message_ptr) { + return 0; + } + + coap_header_len = coap_header_ptr->payload_len; + + /* Build message */ + int16_t ret = sn_coap_protocol_build(handle->grs->coap, dst_addr_ptr, coap_message_ptr, coap_header_ptr, (void *)handle); + if (ret < 0) { + handle->sn_nsdl_free(coap_message_ptr); + return ret; + } + + /* If message type is confirmable, save it to list to wait for reply */ + if (coap_header_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { + if (message_description == SN_NSDL_MSG_REGISTER) { + handle->register_msg_id = coap_header_ptr->msg_id; + handle->register_msg_len = coap_header_len; + } + else if (message_description == SN_NSDL_MSG_UNREGISTER) { + handle->unregister_msg_id = coap_header_ptr->msg_id; + } + else if (message_description == SN_NSDL_MSG_UPDATE) { + handle->update_register_msg_id = coap_header_ptr->msg_id; + handle->update_register_msg_len = coap_header_len; + } + else if (message_description == SN_NSDL_MSG_BOOTSTRAP) { + handle->bootstrap_msg_id = coap_header_ptr->msg_id; + } + } + sn_nsdl_print_coap_data(coap_header_ptr, true); + handle->sn_nsdl_tx_callback(handle, SN_NSDL_PROTOCOL_COAP, coap_message_ptr, coap_message_len, dst_addr_ptr); + handle->sn_nsdl_free(coap_message_ptr); + + return coap_header_ptr->msg_id; +} + +/** + * \fn static void sn_nsdl_resolve_nsp_address(struct nsdl_s *handle) + * + * \brief Resolves NSP server address. + * + * \param *handle Pointer to nsdl-library handle + * \note Application must set NSP address with set_nsp_address + */ +static void sn_nsdl_resolve_nsp_address(struct nsdl_s *handle) +{ + /* Local variables */ + if (!handle->nsp_address_ptr) { + //allocate only if previously not allocated + handle->nsp_address_ptr = handle->sn_nsdl_alloc(sizeof(sn_nsdl_oma_server_info_t)); + } + + if (handle->nsp_address_ptr) { + handle->nsp_address_ptr->omalw_server_security = SEC_NOT_SET; + handle->nsp_address_ptr->omalw_address_ptr = handle->sn_nsdl_alloc(sizeof(sn_nsdl_addr_s)); + if (handle->nsp_address_ptr->omalw_address_ptr) { + memset(handle->nsp_address_ptr->omalw_address_ptr, 0, sizeof(sn_nsdl_addr_s)); + handle->nsp_address_ptr->omalw_address_ptr->type = SN_NSDL_ADDRESS_TYPE_NONE; + } + } +} + +#ifdef RESOURCE_ATTRIBUTES_LIST +static char *sn_nsdl_build_resource_attribute_str(char *dst, const sn_nsdl_attribute_item_s *attribute, const char *name, const size_t name_len) +{ + if (attribute != NULL && name != NULL && name_len > 0 && attribute->value) { + size_t attribute_len = strlen(attribute->value); + *dst++ = ';'; + memcpy(dst, name, name_len); + dst += name_len; + *dst++ = '"'; + memcpy(dst, + attribute->value, + attribute_len); + dst += attribute_len; + *dst++ = '"'; + } + return dst; +} +#endif + +/** + * \fn int8_t sn_nsdl_build_registration_body(struct nsdl_s *handle, sn_coap_hdr_s *message_ptr, uint8_t updating_registeration) + * + * \brief To build GRS resources to registration message payload + * \param *handle Pointer to nsdl-library handle + * \param *message_ptr Pointer to CoAP message header + * + * \return SN_NSDL_SUCCESS = 0, Failed = -1 + */ +int8_t sn_nsdl_build_registration_body(struct nsdl_s *handle, sn_coap_hdr_s *message_ptr, uint8_t updating_registeration) +{ + tr_debug("sn_nsdl_build_registration_body"); + /* Local variables */ + uint8_t *temp_ptr; + sn_nsdl_dynamic_resource_parameters_s *resource_temp_ptr; + + /* Calculate needed memory and allocate */ + int8_t error = 0; + uint16_t msg_len = sn_nsdl_calculate_registration_body_size(handle, updating_registeration, &error); + if (SN_NSDL_FAILURE == error) { + return error; + } + + if (!msg_len) { + return SN_NSDL_SUCCESS; + } else { + message_ptr->payload_len = msg_len; + } + tr_debug("sn_nsdl_build_registration_body - body size: [%d]", message_ptr->payload_len); + message_ptr->payload_ptr = handle->sn_nsdl_alloc(message_ptr->payload_len); + if (!message_ptr->payload_ptr) { + return SN_NSDL_FAILURE; + } + + /* Build message */ + temp_ptr = message_ptr->payload_ptr; + + resource_temp_ptr = sn_grs_get_first_resource(handle->grs); + + /* Loop trough all resources */ + while (resource_temp_ptr) { + /* if resource needs to be registered */ + if (resource_temp_ptr->publish_uri) { + if (updating_registeration && resource_temp_ptr->registered == SN_NDSL_RESOURCE_REGISTERED) { + resource_temp_ptr = sn_grs_get_next_resource(handle->grs, resource_temp_ptr); + continue; + } else { + resource_temp_ptr->registered = SN_NDSL_RESOURCE_REGISTERED; + } + + /* If not first resource, add '.' to separator */ + if (temp_ptr != message_ptr->payload_ptr) { + *temp_ptr++ = ','; + } + + *temp_ptr++ = '<'; + *temp_ptr++ = '/'; + size_t path_len = 0; + if (resource_temp_ptr->static_resource_parameters->path) { + path_len = strlen(resource_temp_ptr->static_resource_parameters->path); + } + memcpy(temp_ptr, + resource_temp_ptr->static_resource_parameters->path, + path_len); + temp_ptr += path_len; + *temp_ptr++ = '>'; + + /* Resource attributes */ +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + size_t resource_type_len = 0; + if (resource_temp_ptr->static_resource_parameters->resource_type_ptr) { + resource_type_len = strlen(resource_temp_ptr->static_resource_parameters->resource_type_ptr); + } + if (resource_type_len) { + *temp_ptr++ = ';'; + memcpy(temp_ptr, resource_type_parameter, RT_PARAMETER_LEN); + temp_ptr += RT_PARAMETER_LEN; + *temp_ptr++ = '"'; + memcpy(temp_ptr, + resource_temp_ptr->static_resource_parameters->resource_type_ptr, + resource_type_len); + temp_ptr += resource_type_len; + *temp_ptr++ = '"'; + } +#endif +#ifndef DISABLE_INTERFACE_DESCRIPTION + size_t interface_description_len = 0; + if (resource_temp_ptr->static_resource_parameters->interface_description_ptr) { + interface_description_len = strlen(resource_temp_ptr->static_resource_parameters->interface_description_ptr); + } + + if (interface_description_len) { + *temp_ptr++ = ';'; + memcpy(temp_ptr, if_description_parameter, IF_PARAMETER_LEN); + temp_ptr += IF_PARAMETER_LEN; + *temp_ptr++ = '"'; + memcpy(temp_ptr, + resource_temp_ptr->static_resource_parameters->interface_description_ptr, + interface_description_len); + temp_ptr += interface_description_len; + *temp_ptr++ = '"'; + } +#endif +#else + size_t attribute_len = 0; + if (resource_temp_ptr->static_resource_parameters->attributes_ptr) { + sn_nsdl_attribute_item_s *attribute = resource_temp_ptr->static_resource_parameters->attributes_ptr; + while (attribute->attribute_name != ATTR_END) { + switch (attribute->attribute_name) { + case ATTR_RESOURCE_TYPE: + temp_ptr = sn_nsdl_build_resource_attribute_str(temp_ptr, attribute, resource_type_parameter, RT_PARAMETER_LEN); + break; + case ATTR_INTERFACE_DESCRIPTION: + temp_ptr = sn_nsdl_build_resource_attribute_str(temp_ptr, attribute, if_description_parameter, IF_PARAMETER_LEN); + break; + case ATTR_ENDPOINT_NAME: + temp_ptr = sn_nsdl_build_resource_attribute_str(temp_ptr, attribute, name_parameter, NAME_PARAMETER_LEN); + break; + default: + break; + } + attribute++; + } + } +#endif + if (resource_temp_ptr->coap_content_type != 0) { + *temp_ptr++ = ';'; + memcpy(temp_ptr, coap_con_type_parameter, COAP_CON_PARAMETER_LEN); + temp_ptr += COAP_CON_PARAMETER_LEN; + *temp_ptr++ = '"'; + temp_ptr = sn_nsdl_itoa(temp_ptr, + resource_temp_ptr->coap_content_type); + *temp_ptr++ = '"'; + } + + /* ;aobs / ;obs */ + // This needs to be re-visited and may be need an API for maganging obs value for different server implementation +#ifndef COAP_DISABLE_OBS_FEATURE + if (resource_temp_ptr->auto_observable) { + uint8_t token[MAX_TOKEN_SIZE] = {0}; + uint8_t len = handle->sn_nsdl_auto_obs_token_callback(handle, + resource_temp_ptr->static_resource_parameters->path, + (uint8_t*)token); + if (len > 0) { + *temp_ptr++ = ';'; + memcpy(temp_ptr, aobs_parameter, AOBS_PARAMETER_LEN); + temp_ptr += AOBS_PARAMETER_LEN; + *temp_ptr++ = '"'; + uint16_t temp = common_read_16_bit((uint8_t*)token); + temp_ptr = sn_nsdl_itoa(temp_ptr, temp); + *temp_ptr++ = '"'; + } else { + return SN_NSDL_FAILURE; + } + } + else if (resource_temp_ptr->observable) { + *temp_ptr++ = ';'; + memcpy(temp_ptr, obs_parameter, OBS_PARAMETER_LEN); + temp_ptr += OBS_PARAMETER_LEN; + } +#endif + } + resource_temp_ptr = sn_grs_get_next_resource(handle->grs, resource_temp_ptr); + + } + return SN_NSDL_SUCCESS; +} + +/** + * \fn static uint16_t sn_nsdl_calculate_registration_body_size(struct nsdl_s *handle, uint8_t updating_registeration, int8_t *error) + * + * + * \brief Calculates registration message payload size + * \param *handle Pointer to nsdl-library handle + * \param *updating_registeration Pointer to list of GRS resources + * \param *error Error code, SN_NSDL_SUCCESS or SN_NSDL_FAILURE + * + * \return Needed payload size + */ +static uint16_t sn_nsdl_calculate_registration_body_size(struct nsdl_s *handle, uint8_t updating_registeration, int8_t *error) +{ + tr_debug("sn_nsdl_calculate_registration_body_size"); + /* Local variables */ + uint16_t return_value = 0; + *error = SN_NSDL_SUCCESS; + const sn_nsdl_dynamic_resource_parameters_s *resource_temp_ptr; + + /* check pointer */ + resource_temp_ptr = sn_grs_get_first_resource(handle->grs); + + while (resource_temp_ptr) { + if (resource_temp_ptr->publish_uri) { + if (updating_registeration && resource_temp_ptr->registered == SN_NDSL_RESOURCE_REGISTERED) { + resource_temp_ptr = sn_grs_get_next_resource(handle->grs, resource_temp_ptr); + continue; + } + /* If not first resource, then '.' will be added */ + if (return_value) { + if (sn_nsdl_check_uint_overflow(return_value, 1, 0)) { + return_value++; + } else { + *error = SN_NSDL_FAILURE; + break; + } + } + + /* Count length for the resource path </path> */ + size_t path_len = 0; + if (resource_temp_ptr->static_resource_parameters->path) { + path_len = strlen(resource_temp_ptr->static_resource_parameters->path); + } + + if (sn_nsdl_check_uint_overflow(return_value, 3, path_len)) { + return_value += (3 + path_len); + } else { + *error = SN_NSDL_FAILURE; + break; + } + + /* Count lengths of the attributes */ +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + /* Resource type parameter */ + size_t resource_type_len = 0; + if (resource_temp_ptr->static_resource_parameters->resource_type_ptr) { + resource_type_len = strlen(resource_temp_ptr->static_resource_parameters->resource_type_ptr); + } + + if (resource_type_len) { + /* ;rt="restype" */ + if (sn_nsdl_check_uint_overflow(return_value, + 6, + resource_type_len)) { + return_value += (6 + resource_type_len); + } else { + *error = SN_NSDL_FAILURE; + break; + } + } +#endif + +#ifndef DISABLE_INTERFACE_DESCRIPTION + /* Interface description parameter */ + size_t interface_description_len = 0; + if (resource_temp_ptr->static_resource_parameters->interface_description_ptr) { + interface_description_len = strlen(resource_temp_ptr->static_resource_parameters->interface_description_ptr); + } + if (interface_description_len) { + /* ;if="iftype" */ + if (sn_nsdl_check_uint_overflow(return_value, + 6, + interface_description_len)) { + return_value += (6 + interface_description_len); + } else { + *error = SN_NSDL_FAILURE; + break; + } + } +#endif +#else + /* All attributes */ + if (resource_temp_ptr->static_resource_parameters->attributes_ptr) { + size_t attribute_len = 0; + size_t attribute_desc_len = 0; + uint8_t success = 1; + sn_nsdl_attribute_item_s *item = resource_temp_ptr->static_resource_parameters->attributes_ptr; + while (item->attribute_name != ATTR_END) { + switch(item->attribute_name) { + case ATTR_RESOURCE_TYPE: + /* ;rt="restype" */ + attribute_desc_len = 6; + attribute_len = strlen(item->value); + break; + case ATTR_INTERFACE_DESCRIPTION: + /* ;if="iftype" */ + attribute_desc_len = 6; + attribute_len = strlen(item->value); + break; + case ATTR_ENDPOINT_NAME: + /* ;name="name" */ + attribute_desc_len = 8; + attribute_len = strlen(item->value); + break; + default: + break; + } + if (sn_nsdl_check_uint_overflow(return_value, + attribute_desc_len, + attribute_len)) { + return_value += (attribute_desc_len + attribute_len); + } else { + success = 0; + break; + } + item++; + } + if (!success) { + *error = SN_NSDL_FAILURE; + break; + } + } +#endif + if (resource_temp_ptr->coap_content_type != 0) { + /* ;if="content" */ + uint8_t len = sn_nsdl_itoa_len(resource_temp_ptr->coap_content_type); + if (sn_nsdl_check_uint_overflow(return_value, 6, len)) { + return_value += (6 + len); + } else { + *error = SN_NSDL_FAILURE; + break; + } + } +#ifndef COAP_DISABLE_OBS_FEATURE + // Auto obs will take higher priority + // This needs to be re-visited and may be need an API for maganging obs value for different server implementation + if (resource_temp_ptr->auto_observable) { + /* ;aobs="" */ + uint8_t token[MAX_TOKEN_SIZE] = {0}; + uint8_t len = handle->sn_nsdl_auto_obs_token_callback(handle, + resource_temp_ptr->static_resource_parameters->path, + (uint8_t*)token); + + if (len > 0) { + uint16_t temp = common_read_16_bit((uint8_t*)token); + uint8_t token_len = sn_nsdl_itoa_len(temp); + if (sn_nsdl_check_uint_overflow(return_value, 8, token_len)) { + return_value += (8 + token_len); + } else { + *error = SN_NSDL_FAILURE; + break; + } + } else { + *error = SN_NSDL_FAILURE; + break; + } + } + else if (resource_temp_ptr->observable) { + if (sn_nsdl_check_uint_overflow(return_value, 4, 0)) { + return_value += 4; + } else { + *error = SN_NSDL_FAILURE; + break; + } + } +#endif + } + resource_temp_ptr = sn_grs_get_next_resource(handle->grs, resource_temp_ptr); + } + return return_value; +} + +/** + * \fn static uint8_t sn_nsdl_calculate_uri_query_option_len(sn_nsdl_ep_parameters_s *endpoint_info_ptr, uint8_t msg_type) + * + * + * \brief Calculates needed uri query option length + * + * \param *endpoint_info_ptr Pointer to endpoint info structure + * \param msg_type Message type + * + * \return number of parameters in uri query + */ +static uint8_t sn_nsdl_calculate_uri_query_option_len(sn_nsdl_ep_parameters_s *endpoint_info_ptr, uint8_t msg_type) +{ + uint8_t return_value = 0; + uint8_t number_of_parameters = 0; + + + if ((endpoint_info_ptr->endpoint_name_len != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE) && endpoint_info_ptr->endpoint_name_ptr != 0) { + return_value += endpoint_info_ptr->endpoint_name_len; + return_value += EP_NAME_PARAMETERS_LEN; //ep= + number_of_parameters++; + } + + if ((endpoint_info_ptr->type_len != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE) && (endpoint_info_ptr->type_ptr != 0)) { + return_value += endpoint_info_ptr->type_len; + return_value += ET_PARAMETER_LEN; //et= + number_of_parameters++; + } + + if ((endpoint_info_ptr->lifetime_len != 0) && (endpoint_info_ptr->lifetime_ptr != 0)) { + return_value += endpoint_info_ptr->lifetime_len; + return_value += LT_PARAMETER_LEN; //lt= + number_of_parameters++; + } + + if ((endpoint_info_ptr->domain_name_len != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE) && (endpoint_info_ptr->domain_name_ptr != 0)) { + return_value += endpoint_info_ptr->domain_name_len; + return_value += DOMAIN_PARAMETER_LEN; //d= + number_of_parameters++; + } + + if (((endpoint_info_ptr->binding_and_mode & 0x04) || (endpoint_info_ptr->binding_and_mode & 0x01)) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE)) { + return_value += BS_QUEUE_MODE_PARAMATER_LEN; + + if (endpoint_info_ptr->binding_and_mode & 0x01) { + return_value++; + } + if (endpoint_info_ptr->binding_and_mode & 0x04) { + return_value++; + } + if ((endpoint_info_ptr->binding_and_mode & 0x02) && ((endpoint_info_ptr->binding_and_mode & 0x04) || (endpoint_info_ptr->binding_and_mode & 0x01))) { + return_value++; + } + + number_of_parameters++; + } + + if (number_of_parameters != 0) { + return_value += (number_of_parameters - 1); + } + + return return_value; +} + +/** + * \fn static int8_t sn_nsdl_fill_uri_query_options(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *parameter_ptr, sn_coap_hdr_s *source_msg_ptr, uint8_t msg_type) + * + * + * \brief Fills uri-query options to message header struct + * \param *handle Pointer to nsdl-library handle + * \param *parameter_ptr Pointer to endpoint parameters struct + * \param *source_msg_ptr Pointer to CoAP header struct + * \param msg_type Message type + * + * \return SN_NSDL_SUCCESS = 0, Failed = -1 + */ +static int8_t sn_nsdl_fill_uri_query_options(struct nsdl_s *handle, + sn_nsdl_ep_parameters_s *parameter_ptr, + sn_coap_hdr_s *source_msg_ptr, + uint8_t msg_type, + char *uri_queries[], + uint32_t query_count) +{ + uint8_t *temp_ptr = NULL; + if( !validateParameters(parameter_ptr) ){ + return SN_NSDL_FAILURE; + } + + size_t query_len = sn_nsdl_calculate_uri_query_option_len(parameter_ptr, msg_type); + if (query_len == 0) { + return 0; + } + + bool optional_params = false; + if (query_count && uri_queries) { + optional_params = true; + for (uint32_t i = 0; i < query_count; i++) { + query_len += strlen(uri_queries[i]); + } + query_len += query_count; // Reserve space for '&' + } + + source_msg_ptr->options_list_ptr->uri_query_len = query_len; + source_msg_ptr->options_list_ptr->uri_query_ptr = handle->sn_nsdl_alloc(query_len); + + if (source_msg_ptr->options_list_ptr->uri_query_ptr == NULL) { + return SN_NSDL_FAILURE; + } + memset(source_msg_ptr->options_list_ptr->uri_query_ptr,0,source_msg_ptr->options_list_ptr->uri_query_len); + + temp_ptr = source_msg_ptr->options_list_ptr->uri_query_ptr; + + /******************************************************/ + /* If endpoint name is configured, fill needed fields */ + /******************************************************/ + + if ((parameter_ptr->endpoint_name_len != 0) && (parameter_ptr->endpoint_name_ptr != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE)) { + /* fill endpoint name, first ?ep=, then endpoint name */ + memcpy(temp_ptr, ep_name_parameter_string, sizeof(ep_name_parameter_string)); + temp_ptr += EP_NAME_PARAMETERS_LEN; + memcpy(temp_ptr, parameter_ptr->endpoint_name_ptr, parameter_ptr->endpoint_name_len); + temp_ptr += parameter_ptr->endpoint_name_len; + } + + /******************************************************/ + /* If endpoint type is configured, fill needed fields */ + /******************************************************/ + + if ((parameter_ptr->type_len != 0) && (parameter_ptr->type_ptr != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE)) { + if (temp_ptr != source_msg_ptr->options_list_ptr->uri_query_ptr) { + *temp_ptr++ = '&'; + } + + memcpy(temp_ptr, et_parameter, sizeof(et_parameter)); + temp_ptr += ET_PARAMETER_LEN; + memcpy(temp_ptr, parameter_ptr->type_ptr, parameter_ptr->type_len); + temp_ptr += parameter_ptr->type_len; + } + + + /******************************************************/ + /* If lifetime is configured, fill needed fields */ + /******************************************************/ + + if ((parameter_ptr->lifetime_len != 0) && (parameter_ptr->lifetime_ptr != 0)) { + if (temp_ptr != source_msg_ptr->options_list_ptr->uri_query_ptr) { + *temp_ptr++ = '&'; + } + + memcpy(temp_ptr, ep_lifetime_parameter, sizeof(ep_lifetime_parameter)); + temp_ptr += LT_PARAMETER_LEN; + memcpy(temp_ptr, parameter_ptr->lifetime_ptr, parameter_ptr->lifetime_len); + temp_ptr += parameter_ptr->lifetime_len; + } + + /******************************************************/ + /* If domain is configured, fill needed fields */ + /******************************************************/ + + if ((parameter_ptr->domain_name_len != 0) && (parameter_ptr->domain_name_ptr != 0) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE)) { + if (temp_ptr != source_msg_ptr->options_list_ptr->uri_query_ptr) { + *temp_ptr++ = '&'; + } + + memcpy(temp_ptr, ep_domain_parameter, sizeof(ep_domain_parameter)); + temp_ptr += DOMAIN_PARAMETER_LEN; + memcpy(temp_ptr, parameter_ptr->domain_name_ptr, parameter_ptr->domain_name_len); + temp_ptr += parameter_ptr->domain_name_len; + } + + /******************************************************/ + /* If queue-mode is configured, fill needed fields */ + /******************************************************/ + + if (((parameter_ptr->binding_and_mode & 0x01) || (parameter_ptr->binding_and_mode & 0x04)) && (msg_type == SN_NSDL_EP_REGISTER_MESSAGE)) { + if (temp_ptr != source_msg_ptr->options_list_ptr->uri_query_ptr) { + *temp_ptr++ = '&'; + } + + memcpy(temp_ptr, bs_queue_mode, sizeof(bs_queue_mode)); + temp_ptr += BS_QUEUE_MODE_PARAMATER_LEN; + + if (parameter_ptr->binding_and_mode & 0x01) { + *temp_ptr++ = 'U'; + if (parameter_ptr->binding_and_mode & 0x02) { + *temp_ptr++ = 'Q'; + } + } + + if (parameter_ptr->binding_and_mode & 0x04) { + *temp_ptr++ = 'S'; + if ((parameter_ptr->binding_and_mode & 0x02) && !(parameter_ptr->binding_and_mode & 0x01)) { + *temp_ptr++ = 'Q'; + } + } + } + + // Add optional parameters, parsed from the server URL. + if (optional_params) { + for (uint32_t i = 0; i < query_count; i++) { + tr_info("sn_nsdl_fill_uri_query_options - query: %s", uri_queries[i]); + memcpy(temp_ptr, "&", 1); + temp_ptr++; + memcpy(temp_ptr, uri_queries[i], strlen(uri_queries[i])); + temp_ptr += strlen(uri_queries[i]); + } + } + + return SN_NSDL_SUCCESS; +} + +static bool validateParameters(sn_nsdl_ep_parameters_s *parameter_ptr) +{ + if( !validate( parameter_ptr->domain_name_ptr, parameter_ptr->domain_name_len, '&' ) ){ + return false; + } + + if( !validate( parameter_ptr->endpoint_name_ptr, parameter_ptr->endpoint_name_len, '&' ) ){ + return false; + } + + if( !validate( parameter_ptr->lifetime_ptr, parameter_ptr->lifetime_len, '&' ) ){ + return false; + } + + if( !validate( parameter_ptr->type_ptr, parameter_ptr->type_len, '&' ) ){ + return false; + } + return true; +} + +static bool validate(uint8_t* ptr, uint32_t len, char illegalChar) +{ + if( ptr ){ + for( uint32_t i=0; i < len; i++ ){ + if( ptr[i] == illegalChar ){ + return false; + } + } + } + return true; +} + +/** + * \fn static int8_t sn_nsdl_local_rx_function(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, sn_nsdl_addr_s *address_ptr) + * + * \brief If received message is reply for the message that NSDL has been sent, it is processed here. Else, packet will be sent to application. + * \param *handle Pointer to nsdl-library handle + * \param *coap_packet_ptr Pointer to received CoAP packet + * \param *address_ptr Pointer to source address struct + * + * \return SN_NSDL_SUCCESS = 0, Failed = -1 + */ +static int8_t sn_nsdl_local_rx_function(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, sn_nsdl_addr_s *address_ptr) +{ + if ((coap_packet_ptr == 0) || (address_ptr == 0)) { + return -1; + } + + bool is_reg_msg = false; + bool is_update_reg_msg = false; + bool is_unreg_msg = false; + if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_CREATED) { + if (handle->grs->coap->sn_coap_block_data_size > 0) { + handle->register_msg_id += handle->register_msg_len / handle->grs->coap->sn_coap_block_data_size; + } + if (coap_packet_ptr->msg_id == handle->register_msg_id) { + handle->sn_nsdl_endpoint_registered = SN_NSDL_ENDPOINT_IS_REGISTERED; + is_reg_msg = true; + sn_grs_mark_resources_as_registered(handle); + if (sn_nsdl_resolve_ep_information(handle, coap_packet_ptr) != SN_NSDL_SUCCESS) { + return SN_NSDL_FAILURE; + } + } + } + + else if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_CHANGED) { + if (handle->grs->coap->sn_coap_block_data_size > 0) { + handle->update_register_msg_id += handle->update_register_msg_len / handle->grs->coap->sn_coap_block_data_size; + } + if (coap_packet_ptr->msg_id == handle->update_register_msg_id) { + is_update_reg_msg = true; + } + } + + if (coap_packet_ptr->msg_id == handle->unregister_msg_id) { + is_unreg_msg = true; + if (coap_packet_ptr->msg_code == COAP_MSG_CODE_RESPONSE_DELETED) { + + handle->sn_nsdl_free(handle->ep_information_ptr->endpoint_name_ptr); + handle->ep_information_ptr->endpoint_name_ptr = 0; + handle->ep_information_ptr->endpoint_name_len = 0; + + handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); + handle->ep_information_ptr->domain_name_ptr = 0; + handle->ep_information_ptr->domain_name_len = 0; + } + } + + /* No messages to wait for, or message was not response to our request */ + int ret = handle->sn_nsdl_rx_callback(handle, coap_packet_ptr, address_ptr); + if (is_reg_msg) { + handle->register_msg_id = 0; + handle->register_msg_len = 0; + } + else if (is_unreg_msg) { + handle->unregister_msg_id = 0; + } + else if (is_update_reg_msg) { + handle->update_register_msg_id = 0; + handle->update_register_msg_len = 0; + } + else if (coap_packet_ptr->msg_id == handle->bootstrap_msg_id) { + handle->bootstrap_msg_id = 0; + } + return ret; +} + +/** + * \fn static int8_t sn_nsdl_resolve_ep_information(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr) + * + * + * \brief Resolves endpoint information from received CoAP message + * \param *handle Pointer to nsdl-library handle + * \param *coap_packet_ptr Pointer to received CoAP message + * + * \return SN_NSDL_SUCCESS = 0, Failed = -1 + */ +static int8_t sn_nsdl_resolve_ep_information(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr) +{ + uint8_t *temp_ptr; + uint8_t parameter_count = 0; + uint16_t parameter_len = 0; + + if (!coap_packet_ptr || !coap_packet_ptr->options_list_ptr || + !coap_packet_ptr->options_list_ptr->location_path_ptr) { + return SN_NSDL_FAILURE; + } + + temp_ptr = coap_packet_ptr->options_list_ptr->location_path_ptr; + + while (temp_ptr <= (coap_packet_ptr->options_list_ptr->location_path_ptr + coap_packet_ptr->options_list_ptr->location_path_len)) { + + if ((temp_ptr == (coap_packet_ptr->options_list_ptr->location_path_ptr + coap_packet_ptr->options_list_ptr->location_path_len)) || (*temp_ptr == '/')) { + + parameter_count++; + if (parameter_count == 2) { + if (!handle->ep_information_ptr->domain_name_ptr) { + handle->ep_information_ptr->domain_name_len = parameter_len - 1; + handle->ep_information_ptr->domain_name_ptr = handle->sn_nsdl_alloc(handle->ep_information_ptr->domain_name_len); + if (!handle->ep_information_ptr->domain_name_ptr) { + return SN_NSDL_FAILURE; + } + memcpy(handle->ep_information_ptr->domain_name_ptr, temp_ptr - handle->ep_information_ptr->domain_name_len, handle->ep_information_ptr->domain_name_len); + } + + } + if (parameter_count == 3) { + if (!handle->ep_information_ptr->endpoint_name_ptr) { + handle->ep_information_ptr->endpoint_name_len = parameter_len - 1; + handle->ep_information_ptr->endpoint_name_ptr = handle->sn_nsdl_alloc(handle->ep_information_ptr->endpoint_name_len); + if (!handle->ep_information_ptr->endpoint_name_ptr) { + if (handle->ep_information_ptr->domain_name_ptr) { + handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); + handle->ep_information_ptr->domain_name_ptr = NULL; + handle->ep_information_ptr->domain_name_len = 0; + } + + return SN_NSDL_FAILURE; + + } + memcpy(handle->ep_information_ptr->endpoint_name_ptr, temp_ptr - handle->ep_information_ptr->endpoint_name_len, handle->ep_information_ptr->endpoint_name_len); + } + } + parameter_len = 0; + } + parameter_len++; + temp_ptr++; + } + + + return SN_NSDL_SUCCESS; +} + +extern int8_t set_NSP_address(struct nsdl_s *handle, uint8_t *NSP_address, uint8_t address_length, uint16_t port, sn_nsdl_addr_type_e address_type) +{ + /* Check parameters and source pointers */ + if (!handle || !handle->nsp_address_ptr || !handle->nsp_address_ptr->omalw_address_ptr || !NSP_address) { + return SN_NSDL_FAILURE; + } + + handle->nsp_address_ptr->omalw_address_ptr->type = address_type; + handle->nsp_address_ptr->omalw_server_security = SEC_NOT_SET; + + handle->sn_nsdl_free(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr); + + handle->nsp_address_ptr->omalw_address_ptr->addr_len = address_length; + + handle->nsp_address_ptr->omalw_address_ptr->addr_ptr = handle->sn_nsdl_alloc(handle->nsp_address_ptr->omalw_address_ptr->addr_len); + if (!handle->nsp_address_ptr->omalw_address_ptr->addr_ptr) { + return SN_NSDL_FAILURE; + } + + memcpy(handle->nsp_address_ptr->omalw_address_ptr->addr_ptr, NSP_address, handle->nsp_address_ptr->omalw_address_ptr->addr_len); + handle->nsp_address_ptr->omalw_address_ptr->port = port; + + return SN_NSDL_SUCCESS; +} + + +static uint8_t sn_nsdl_itoa_len(uint32_t value) +{ + uint8_t i = 0; + + do { + i++; + } while ((value /= 10) > 0); + + return i; +} + +static uint8_t *sn_nsdl_itoa(uint8_t *ptr, uint32_t value) +{ + + uint8_t start = 0; + uint8_t end = 0; + uint8_t i; + + i = 0; + + /* ITOA */ + do { + ptr[i++] = (value % 10) + '0'; + } while ((value /= 10) > 0); + + end = i - 1; + + /* reverse (part of ITOA) */ + while (start < end) { + uint8_t chr; + + chr = ptr[start]; + ptr[start] = ptr[end]; + ptr[end] = chr; + + start++; + end--; + + } + return (ptr + i); +} + +static int8_t set_endpoint_info(struct nsdl_s *handle, sn_nsdl_ep_parameters_s *endpoint_info_ptr) +{ + handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); + handle->ep_information_ptr->domain_name_ptr = 0; + handle->ep_information_ptr->domain_name_len = 0; + + handle->sn_nsdl_free(handle->ep_information_ptr->endpoint_name_ptr); + handle->ep_information_ptr->endpoint_name_ptr = 0; + handle->ep_information_ptr->endpoint_name_len = 0; + + if (endpoint_info_ptr->domain_name_ptr && endpoint_info_ptr->domain_name_len) { + handle->ep_information_ptr->domain_name_ptr = handle->sn_nsdl_alloc(endpoint_info_ptr->domain_name_len); + + if (!handle->ep_information_ptr->domain_name_ptr) { + return -1; + } + + memcpy(handle->ep_information_ptr->domain_name_ptr, endpoint_info_ptr->domain_name_ptr, endpoint_info_ptr->domain_name_len); + handle->ep_information_ptr->domain_name_len = endpoint_info_ptr->domain_name_len; + } + + if (endpoint_info_ptr->endpoint_name_ptr && endpoint_info_ptr->endpoint_name_len) { + handle->ep_information_ptr->endpoint_name_ptr = handle->sn_nsdl_alloc(endpoint_info_ptr->endpoint_name_len); + + if (!handle->ep_information_ptr->endpoint_name_ptr) { + handle->sn_nsdl_free(handle->ep_information_ptr->domain_name_ptr); + handle->ep_information_ptr->domain_name_ptr = 0; + handle->ep_information_ptr->domain_name_len = 0; + return -1; + } + + memcpy(handle->ep_information_ptr->endpoint_name_ptr, endpoint_info_ptr->endpoint_name_ptr, endpoint_info_ptr->endpoint_name_len); + handle->ep_information_ptr->endpoint_name_len = endpoint_info_ptr->endpoint_name_len; + } + + handle->ep_information_ptr->binding_and_mode = endpoint_info_ptr->binding_and_mode; + handle->ep_information_ptr->ds_register_mode = endpoint_info_ptr->ds_register_mode; + + return 0; +} + +/* Wrapper */ +sn_grs_resource_list_s *sn_nsdl_list_resource(struct nsdl_s *handle, const char *path) +{ + /* Check parameters */ + if (handle == NULL) { + return NULL; + } + + return sn_grs_list_resource(handle->grs, path); +} + +void sn_nsdl_free_resource_list(struct nsdl_s *handle, sn_grs_resource_list_s *list) +{ + /* Check parameters */ + if (handle == NULL) { + return; + } + + sn_grs_free_resource_list(handle->grs, list); +} + +extern int8_t sn_nsdl_send_coap_message(struct nsdl_s *handle, sn_nsdl_addr_s *address_ptr, sn_coap_hdr_s *coap_hdr_ptr) +{ + /* Check parameters */ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + int8_t ret = sn_grs_send_coap_message(handle, address_ptr, coap_hdr_ptr); + + sn_nsdl_print_coap_data(coap_hdr_ptr, true); + + return ret; +} + +extern int8_t sn_nsdl_handle_block2_response_internally(struct nsdl_s *handle, uint8_t build_response) +{ + /* Check parameters */ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + return sn_coap_protocol_handle_block2_response_internally(handle->grs->coap, build_response); +} + +extern int32_t sn_nsdl_send_get_data_request(struct nsdl_s *handle, + const char *uri_path, + const uint32_t token, + const size_t offset) +{ + sn_coap_hdr_s req_message; + int32_t message_id; + + if (handle == NULL || uri_path == NULL || handle->grs->coap->sn_coap_block_data_size == 0) { + return 0; + } + + memset(&req_message, 0, sizeof(sn_coap_hdr_s)); + + // Fill message fields + req_message.msg_type = COAP_MSG_TYPE_CONFIRMABLE; + req_message.msg_code = COAP_MSG_CODE_REQUEST_GET; + req_message.uri_path_len = (uint16_t)strlen(uri_path); + req_message.uri_path_ptr = (uint8_t*)uri_path; + req_message.token_ptr = (uint8_t*)&token; + req_message.token_len = sizeof(token); + +// Skip block options if feature is not enabled +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + if (sn_coap_parser_alloc_options(handle->grs->coap, &req_message) == NULL) { + handle->grs->coap->sn_coap_protocol_free(req_message.options_list_ptr); + return 0; + } + + // Add block number + req_message.options_list_ptr->block2 = 0; + if (offset > 0) { + req_message.options_list_ptr->block2 = ((offset / handle->grs->coap->sn_coap_block_data_size) << 4); + } + // Add block size + req_message.options_list_ptr->block2 |= sn_coap_convert_block_size(handle->grs->coap->sn_coap_block_data_size); +#endif + + // Build and send coap message + message_id = sn_nsdl_internal_coap_send(handle, &req_message, handle->nsp_address_ptr->omalw_address_ptr, SN_NSDL_MSG_UNDEFINED); + handle->grs->coap->sn_coap_protocol_free(req_message.options_list_ptr); + + return message_id; +} + +extern int8_t sn_nsdl_put_resource(struct nsdl_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) +{ + if (!handle) { + return SN_NSDL_FAILURE; + } + + return sn_grs_put_resource(handle->grs, res); +} + +extern int8_t sn_nsdl_pop_resource(struct nsdl_s *handle, sn_nsdl_dynamic_resource_parameters_s *res) +{ + if (!handle) { + return SN_NSDL_FAILURE; + } + + return sn_grs_pop_resource(handle->grs, res); +} + +extern int8_t sn_nsdl_delete_resource(struct nsdl_s *handle, const char *path) +{ + /* Check parameters */ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + + return sn_grs_delete_resource(handle->grs, path); +} +extern const sn_nsdl_dynamic_resource_parameters_s *sn_nsdl_get_first_resource(struct nsdl_s *handle) +{ + /* Check parameters */ + if (handle == NULL) { + return NULL; + } + + return sn_grs_get_first_resource(handle->grs); +} +extern const sn_nsdl_dynamic_resource_parameters_s *sn_nsdl_get_next_resource(struct nsdl_s *handle, const sn_nsdl_dynamic_resource_parameters_s *resource) +{ + /* Check parameters */ + if (handle == NULL) { + return NULL; + } + + return sn_grs_get_next_resource(handle->grs, resource); +} + +extern sn_coap_hdr_s *sn_nsdl_build_response(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code) +{ + if (handle == NULL) { + return NULL; + } + + return sn_coap_build_response(handle->grs->coap, coap_packet_ptr, msg_code); +} + +extern sn_coap_options_list_s *sn_nsdl_alloc_options_list(struct nsdl_s *handle, sn_coap_hdr_s *coap_msg_ptr) +{ + if (handle == NULL || coap_msg_ptr == NULL) { + return NULL; + } + return sn_coap_parser_alloc_options(handle->grs->coap, coap_msg_ptr); +} + +extern void sn_nsdl_release_allocated_coap_msg_mem(struct nsdl_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr) +{ + if (handle == NULL) { + return; + } + + sn_coap_parser_release_allocated_coap_msg_mem(handle->grs->coap, freed_coap_msg_ptr); +} + +extern int8_t sn_nsdl_set_retransmission_parameters(struct nsdl_s *handle, + uint8_t resending_count, uint8_t resending_interval) +{ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + return sn_coap_protocol_set_retransmission_parameters(handle->grs->coap, + resending_count,resending_interval); +} + +extern int8_t sn_nsdl_set_retransmission_buffer(struct nsdl_s *handle, + uint8_t buffer_size_messages, uint16_t buffer_size_bytes) +{ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + return sn_coap_protocol_set_retransmission_buffer(handle->grs->coap, + buffer_size_messages, buffer_size_bytes); +} + +extern int8_t sn_nsdl_set_block_size(struct nsdl_s *handle, uint16_t block_size) +{ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + return sn_coap_protocol_set_block_size(handle->grs->coap, block_size); +} + +extern int8_t sn_nsdl_set_duplicate_buffer_size(struct nsdl_s *handle, uint8_t message_count) +{ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + return sn_coap_protocol_set_duplicate_buffer_size(handle->grs->coap, message_count); +} + +bool sn_nsdl_check_uint_overflow(uint16_t resource_size, uint16_t param_a, uint16_t param_b) +{ + uint16_t first_check = param_a + param_b; + if (first_check < param_b) { + return false; + } else { + uint16_t total = resource_size + first_check; + if (total < first_check) { + return false; + } else { + return true; + } + } +} + +extern int8_t sn_nsdl_set_context(struct nsdl_s * const handle, void * const context) +{ + if (handle == NULL) { + return SN_NSDL_FAILURE; + } + handle->context = context; + return SN_NSDL_SUCCESS; +} + +extern void *sn_nsdl_get_context(const struct nsdl_s * const handle) +{ + if (handle == NULL) { + return NULL; + } + return handle->context; +} + + +int8_t sn_nsdl_clear_coap_resending_queue(struct nsdl_s *handle) +{ + if (handle == NULL || handle->grs == NULL) { + tr_err("sn_nsdl_clear_coap_resending_queue failed."); + return SN_NSDL_FAILURE; + } + sn_coap_protocol_clear_retransmission_buffer(handle->grs->coap); + return SN_NSDL_SUCCESS; +} + +#ifdef RESOURCE_ATTRIBUTES_LIST +static void sn_nsdl_free_attribute_value(sn_nsdl_attribute_item_s *attribute) +{ + switch (attribute->attribute_name) { + case ATTR_RESOURCE_TYPE: + case ATTR_INTERFACE_DESCRIPTION: + case ATTR_ENDPOINT_NAME: + free(attribute->value); + attribute->value = NULL; + break; + case ATTR_NOP: + case ATTR_END: + default: + break; + } +} + +void sn_nsdl_free_resource_attributes_list(sn_nsdl_static_resource_parameters_s *params) +{ + if (params == NULL || params->free_on_delete == false) { + return; + } + sn_nsdl_attribute_item_s *item = params->attributes_ptr; + if (item) { + while (item->attribute_name != ATTR_END) { + sn_nsdl_free_attribute_value(item); + item++; + } + free(params->attributes_ptr); + params->attributes_ptr = NULL; + } +} + +bool sn_nsdl_set_resource_attribute(sn_nsdl_static_resource_parameters_s *params, const sn_nsdl_attribute_item_s *attribute) +{ + if (params == NULL || params->free_on_delete == false) { + return false; + } + unsigned int item_count = 0; + sn_nsdl_attribute_item_s *item = params->attributes_ptr; + // Count the number of attributes for reallocation, update in place though + // if the attribute already existed + while (item != NULL) { + item_count++; + if (item->attribute_name == ATTR_END) { + break; + } + // Check if attribute already exists or if there is NOP we can overwrite + if (item->attribute_name == attribute->attribute_name || item->attribute_name == ATTR_NOP) { + // Found attribute or NOP, overwrite it + sn_nsdl_free_attribute_value(item); + item->attribute_name = attribute->attribute_name; + item->value = attribute->value; + return true; + } + item++; + } + // Attribute did not yet exist (ptr was null or ATTR_END was first one) + if (item_count > 0) { + // List already had some attributes, so reallocate + size_t new_size = (item_count + 1) * sizeof(sn_nsdl_attribute_item_s); + item = params->attributes_ptr; + params->attributes_ptr = realloc(item, new_size); + if (params->attributes_ptr == NULL) { + // realloc failed, put back original pointer and return false + params->attributes_ptr = item; + return false; + } + // And move item ptr to ATTR_END to update that and last attribute + item = &(params->attributes_ptr[item_count - 1]); + } + else { + // No attributes, so allocate first time (1 struct for attribute and 1 struct for ATTR_END) + params->attributes_ptr = (char*)malloc(2 * sizeof(sn_nsdl_attribute_item_s)); + if (params->attributes_ptr == NULL) { + return false; + } + item = params->attributes_ptr; + } + item->attribute_name = attribute->attribute_name; + item->value = attribute->value; + item++; + item->attribute_name = ATTR_END; + item->value = NULL; + return true; +} + +const char *sn_nsdl_get_resource_attribute(const sn_nsdl_static_resource_parameters_s *params, sn_nsdl_resource_attribute_t attribute_name) +{ + char *value = NULL; + if (params != NULL) { + sn_nsdl_attribute_item_s *item = params->attributes_ptr; + while (item != NULL && item->attribute_name != ATTR_END) { + if (item->attribute_name == attribute_name) { + value = item->value; + break; + } + item++; + } + } + return value; +} + +bool sn_nsdl_remove_resource_attribute(sn_nsdl_static_resource_parameters_s *params, sn_nsdl_resource_attribute_t attribute_name) +{ + if (params == NULL || params->free_on_delete == false) { + return false; + } + + bool found = false; + sn_nsdl_attribute_item_s *item = params->attributes_ptr; + while (item != NULL) { + if (item->attribute_name == ATTR_END) { + break; + } + // Remove if attribute name matches + if (item->attribute_name == attribute_name) { + // Currently only pointer values, need to free and set as NOP + sn_nsdl_free_attribute_value(item); + item->attribute_name = ATTR_NOP; + found = true; + break; + } + item++; + } + + return found; + +} + +#endif + + +void sn_nsdl_print_coap_data(sn_coap_hdr_s *coap_header_ptr, bool outgoing) +{ +#if defined(FEA_TRACE_SUPPORT) || MBED_CONF_MBED_TRACE_ENABLE || YOTTA_CFG_MBED_TRACE || (defined(YOTTA_CFG) && !defined(NDEBUG)) + if (!coap_header_ptr) { + return; + } + + if (outgoing) { + tr_info("======== Outgoing CoAP package ========"); + } else { + tr_info("======== Incoming CoAP package ========"); + } + + if (coap_header_ptr->uri_path_len > 0 && coap_header_ptr->uri_path_ptr) { + tr_info("Uri-Path:\t\t%.*s", coap_header_ptr->uri_path_len, coap_header_ptr->uri_path_ptr); + } + tr_info("Status:\t\t%s", sn_nsdl_coap_status_description(coap_header_ptr->coap_status)); + tr_info("Code:\t\t%s", sn_nsdl_coap_message_code_desc(coap_header_ptr->msg_code)); + tr_info("Type:\t\t%s", sn_nsdl_coap_message_type_desc(coap_header_ptr->msg_type)); + tr_info("Id:\t\t%d", coap_header_ptr->msg_id); + if (coap_header_ptr->token_ptr && coap_header_ptr->token_len > 0) { + tr_info("Token:\t\t%s", tr_array(coap_header_ptr->token_ptr, coap_header_ptr->token_len)); + } + if (coap_header_ptr->content_format != -1) { + tr_info("Content-type:\t%d", coap_header_ptr->content_format); + } + tr_info("Payload len:\t%d", coap_header_ptr->payload_len); +#ifdef MBED_CLIENT_PRINT_COAP_PAYLOAD + if (coap_header_ptr->payload_ptr && coap_header_ptr->payload_len > 0) { + int i = 0; + int row_len = 40; + int max_length = 2048; + while (i < coap_header_ptr->payload_len && i < max_length) { + if (i + row_len > coap_header_ptr->payload_len) { + row_len = coap_header_ptr->payload_len - i; + } + tr_info("Payload:\t\t%s", tr_array( coap_header_ptr->payload_ptr + i, row_len)); + i += row_len; + } + if (i >= max_length) + tr_info("Payload:\t\t....."); + } +#endif + + if (coap_header_ptr->options_list_ptr) { + if (coap_header_ptr->options_list_ptr->etag_ptr && coap_header_ptr->options_list_ptr->etag_len > 0) { + tr_info("E-tag:\t%.*s", coap_header_ptr->options_list_ptr->etag_len, coap_header_ptr->options_list_ptr->etag_ptr); + } + if (coap_header_ptr->options_list_ptr->proxy_uri_ptr && coap_header_ptr->options_list_ptr->proxy_uri_len > 0) { + tr_info("Proxy uri:\t%.*s", coap_header_ptr->options_list_ptr->proxy_uri_len, coap_header_ptr->options_list_ptr->proxy_uri_ptr); + } + + if (coap_header_ptr->options_list_ptr->uri_host_ptr && coap_header_ptr->options_list_ptr->uri_host_len > 0) { + tr_info("Uri host:\t%.*s", coap_header_ptr->options_list_ptr->uri_host_len, coap_header_ptr->options_list_ptr->uri_host_ptr); + } + + if (coap_header_ptr->options_list_ptr->location_path_ptr && coap_header_ptr->options_list_ptr->location_path_len > 0) { + tr_info("Location path:\t%.*s", coap_header_ptr->options_list_ptr->location_path_len, coap_header_ptr->options_list_ptr->location_path_ptr); + } + + if (coap_header_ptr->options_list_ptr->location_query_ptr && coap_header_ptr->options_list_ptr->location_query_len > 0) { + tr_info("Location query:\t%.*s", coap_header_ptr->options_list_ptr->location_query_len, coap_header_ptr->options_list_ptr->location_query_ptr); + } + + if (coap_header_ptr->options_list_ptr->uri_query_ptr && coap_header_ptr->options_list_ptr->uri_query_len > 0) { + tr_info("Uri query:\t%.*s", coap_header_ptr->options_list_ptr->uri_query_len, coap_header_ptr->options_list_ptr->uri_query_ptr); + } + + tr_info("Max-age:\t\t%" PRIu32"", coap_header_ptr->options_list_ptr->max_age); + if (coap_header_ptr->options_list_ptr->use_size1) { + tr_info("Size 1:\t\t%" PRIu32"", coap_header_ptr->options_list_ptr->size1); + } + if (coap_header_ptr->options_list_ptr->use_size2) { + tr_info("Size 2:\t\t%" PRIu32"", coap_header_ptr->options_list_ptr->size2); + } + if (coap_header_ptr->options_list_ptr->accept != -1) { + tr_info("Accept:\t\t%d", coap_header_ptr->options_list_ptr->accept); + } + if (coap_header_ptr->options_list_ptr->uri_port != -1) { + tr_info("Uri port:\t%" PRId32"", coap_header_ptr->options_list_ptr->uri_port); + } + if (coap_header_ptr->options_list_ptr->observe != -1) { + tr_info("Observe:\t\t%" PRId32"", coap_header_ptr->options_list_ptr->observe); + } + if (coap_header_ptr->options_list_ptr->block1 != -1) { + tr_info("Block1 number:\t%" PRId32"", coap_header_ptr->options_list_ptr->block1 >> 4); + uint8_t temp = (coap_header_ptr->options_list_ptr->block1 & 0x07); + uint16_t block_size = 1u << (temp + 4); + tr_info("Block1 size:\t%d", block_size); + tr_info("Block1 more:\t%d", (coap_header_ptr->options_list_ptr->block1) & 0x08 ? true : false); + } + if (coap_header_ptr->options_list_ptr->block2 != -1) { + tr_info("Block2 number:\t%" PRId32"", coap_header_ptr->options_list_ptr->block2 >> 4); + uint8_t temp = (coap_header_ptr->options_list_ptr->block2 & 0x07); + uint16_t block_size = 1u << (temp + 4); + tr_info("Block2 size:\t%d", block_size); + tr_info("Block2 more:\t%d", (coap_header_ptr->options_list_ptr->block2) & 0x08 ? true : false); + } + } + tr_info("======== End of CoAP package ========"); +#else + (void) coap_header_ptr; + (void) outgoing; +#endif +} + +#if defined(FEA_TRACE_SUPPORT) || MBED_CONF_MBED_TRACE_ENABLE || YOTTA_CFG_MBED_TRACE || (defined(YOTTA_CFG) && !defined(NDEBUG)) +const char *sn_nsdl_coap_status_description(sn_coap_status_e status) +{ + switch(status) { + case COAP_STATUS_OK: + return "COAP_STATUS_OK"; + case COAP_STATUS_PARSER_ERROR_IN_HEADER: + return "COAP_STATUS_PARSER_ERROR_IN_HEADER"; + case COAP_STATUS_PARSER_DUPLICATED_MSG: + return "COAP_STATUS_PARSER_DUPLICATED_MSG"; + case COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING: + return "COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING"; + case COAP_STATUS_PARSER_BLOCKWISE_ACK: + return "COAP_STATUS_PARSER_BLOCKWISE_ACK"; + case COAP_STATUS_PARSER_BLOCKWISE_MSG_REJECTED: + return "COAP_STATUS_PARSER_BLOCKWISE_MSG_REJECTED"; + case COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED: + return "COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED"; + case COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED: + return "COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED"; + default: + return ""; + } +} + +const char *sn_nsdl_coap_message_code_desc(int msg_code) +{ + switch(msg_code) { + case COAP_MSG_CODE_EMPTY: + return "COAP_MSG_CODE_EMPTY"; + case COAP_MSG_CODE_REQUEST_GET: + return "COAP_MSG_CODE_REQUEST_GET"; + case COAP_MSG_CODE_REQUEST_POST: + return "COAP_MSG_CODE_REQUEST_POST"; + case COAP_MSG_CODE_REQUEST_PUT: + return "COAP_MSG_CODE_REQUEST_PUT"; + case COAP_MSG_CODE_REQUEST_DELETE: + return "COAP_MSG_CODE_REQUEST_DELETE"; + case COAP_MSG_CODE_RESPONSE_CREATED: + return "COAP_MSG_CODE_RESPONSE_CREATED"; + case COAP_MSG_CODE_RESPONSE_DELETED: + return "COAP_MSG_CODE_RESPONSE_DELETED"; + case COAP_MSG_CODE_RESPONSE_VALID: + return "COAP_MSG_CODE_RESPONSE_VALID"; + case COAP_MSG_CODE_RESPONSE_CHANGED: + return "COAP_MSG_CODE_RESPONSE_CHANGED"; + case COAP_MSG_CODE_RESPONSE_CONTENT: + return "COAP_MSG_CODE_RESPONSE_CONTENT"; + case COAP_MSG_CODE_RESPONSE_CONTINUE: + return "COAP_MSG_CODE_RESPONSE_CONTINUE"; + case COAP_MSG_CODE_RESPONSE_BAD_REQUEST: + return "COAP_MSG_CODE_RESPONSE_BAD_REQUEST"; + case COAP_MSG_CODE_RESPONSE_UNAUTHORIZED: + return "COAP_MSG_CODE_RESPONSE_UNAUTHORIZED"; + case COAP_MSG_CODE_RESPONSE_BAD_OPTION: + return "COAP_MSG_CODE_RESPONSE_BAD_OPTION"; + case COAP_MSG_CODE_RESPONSE_FORBIDDEN: + return "COAP_MSG_CODE_RESPONSE_FORBIDDEN"; + case COAP_MSG_CODE_RESPONSE_NOT_FOUND: + return "COAP_MSG_CODE_RESPONSE_NOT_FOUND"; + case COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED: + return "COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"; + case COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE: + return "COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE"; + case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE: + return "COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE"; + case COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED: + return "COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED"; + case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE: + return "COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE"; + case COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT: + return "COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT"; + case COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR: + return "COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR"; + case COAP_MSG_CODE_RESPONSE_NOT_IMPLEMENTED: + return "COAP_MSG_CODE_RESPONSE_NOT_IMPLEMENTED"; + case COAP_MSG_CODE_RESPONSE_BAD_GATEWAY: + return "COAP_MSG_CODE_RESPONSE_BAD_GATEWAY"; + case COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE: + return "COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE"; + case COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT: + return "COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT"; + case COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED: + return "COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED"; + default: + return ""; + } +} + +const char *sn_nsdl_coap_message_type_desc(int msg_type) +{ + switch(msg_type) { + case COAP_MSG_TYPE_CONFIRMABLE: + return "COAP_MSG_TYPE_CONFIRMABLE"; + case COAP_MSG_TYPE_NON_CONFIRMABLE: + return "COAP_MSG_TYPE_NON_CONFIRMABLE"; + case COAP_MSG_TYPE_ACKNOWLEDGEMENT: + return "COAP_MSG_TYPE_ACKNOWLEDGEMENT"; + case COAP_MSG_TYPE_RESET: + return "COAP_MSG_TYPE_RESET"; + default: + return ""; + } +} +#endif + +void remove_previous_block_data(struct nsdl_s *handle, sn_nsdl_addr_s *src_ptr, const uint32_t block_number) +{ +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + ns_list_foreach(coap_blockwise_payload_s, stored_payload_info_ptr, &handle->grs->coap->linked_list_blockwise_received_payloads) { + uint32_t stored_number = stored_payload_info_ptr->block_number; + // Remove the previous block data + if (block_number - 1 == stored_number) { + sn_coap_protocol_block_remove(handle->grs->coap, + src_ptr, + stored_payload_info_ptr->payload_len, + stored_payload_info_ptr->payload_ptr); + break; + } + } +#endif +} + +bool update_last_block_data(struct nsdl_s *handle, sn_coap_hdr_s *coap_packet_ptr, bool block1) +{ + bool data_updated = false; + // Whole message received --> pass only the last block data to application + if (coap_packet_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { + // Get the block size + uint8_t temp = 0; + if (block1) { + temp = (coap_packet_ptr->options_list_ptr->block1 & 0x07); + } else { + temp = (coap_packet_ptr->options_list_ptr->block2 & 0x07); + } + uint16_t block_size = 1u << (temp + 4); + + uint32_t new_payload_len = coap_packet_ptr->payload_len - block_size; + uint8_t *temp_ptr = handle->grs->coap->sn_coap_protocol_malloc(new_payload_len); + if (temp_ptr) { + // Skip the second last block data since it's still stored in mbed-coap list! + memcpy(temp_ptr, coap_packet_ptr->payload_ptr + block_size, new_payload_len); + handle->grs->coap->sn_coap_protocol_free(coap_packet_ptr->payload_ptr); + coap_packet_ptr->payload_ptr = temp_ptr; + coap_packet_ptr->payload_len = new_payload_len; + data_updated = true; + } + } + + return data_updated; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +test/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/mbed-client-classic/m2mconnectionhandlerpimpl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/mbed-client-classic/m2mconnectionhandlerpimpl.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_CONNECTION_HANDLER_PIMPL_H__ +#define M2M_CONNECTION_HANDLER_PIMPL_H__ + +#include "ns_types.h" +#include "ns_list.h" +#include "eventOS_event.h" +#include "mbed-client/m2mconfig.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2minterface.h" +#include "mbed-client/m2mconnectionobserver.h" +#include "mbed-client/m2mconnectionsecurity.h" +#include "nsdl-c/sn_nsdl.h" +#include "pal.h" + + +class M2MConnectionSecurity; +class M2MConnectionHandler; +class M2MSecurity; + +/** + * @brief M2MConnectionHandlerPimpl. + * This class handles the socket connection for LWM2M Client + */ + + +class M2MConnectionHandlerPimpl { +public: + + enum SocketEvent { + ESocketIdle = 0x00, + ESocketCallback = 0x02, + ESocketConnect = 0x04, + ESocketSend = 0x08, + ESocketDnsResolved = 0x10, + ESocketDnsError = 0x20, + ESocketClose = 0x40 + }; + + /** + * @brief Constructor + */ + M2MConnectionHandlerPimpl(M2MConnectionHandler* base, M2MConnectionObserver &observer, + M2MConnectionSecurity* sec, + M2MInterface::BindingMode mode, + M2MInterface::NetworkStack /*stack*/); + + /** + * @brief Destructor + */ + ~M2MConnectionHandlerPimpl(); + + void start_timer(void); + + /** + * @brief This binds the socket connection. + * @param listen_port Port to listen for incoming connection. + * @return true if successful else false. + */ + bool bind_connection(const uint16_t listen_port); + + /** + * @brief This resolves the server address. Output is + * returned through callback + * @param String server address. + * @param uint16_t Server port. + * @param ServerType, Server Type to be resolved. + * @return true if address is valid else false. + */ + bool resolve_server_address(const String& server_address, + const uint16_t server_port, + M2MConnectionObserver::ServerType server_type, + const M2MSecurity* security); + + /** + * @brief Sends data, to the connected sent to server. + * @param data, Data to be sent. + */ + bool send_data(uint8_t *data_ptr, + uint16_t data_len, + sn_nsdl_addr_s *address_ptr); + + /** + * @brief Listens for incoming data from remote server + * @return true if successful else false. + */ + bool start_listening_for_data(); + + /** + * @brief Stops listening for incoming data + */ + void stop_listening(); + + /** + * @brief Error handling for DTLS connectivity. + * @param error, Error code from TLS library + */ + void handle_connection_error(int error); + + /** + * \brief Sets the network interface handler that is used by client to connect + * to a network over IP.. + * \param handler A network interface handler that is used by client to connect. + * This API is optional but provides a mechanism for different platforms to + * manage usage of underlying network interface by client. + */ + void set_platform_network_handler(void *handler = NULL); + + /** + * \brief Claims mutex to prevent thread clashes + * in multithreaded environment. + */ + void claim_mutex(); + + /** + * \brief Releases mutex to prevent thread clashes + * in multithreaded environment. + */ + void release_mutex(); + + /** + * @brief Callback handler for receiving data over socket. + */ + void receive_handler(); + + /** + * @brief Returns true if DTLS handshake is still ongoing. + */ + bool is_handshake_ongoing() const; + + /** + * @brief Sends data to socket through event loop. + */ + void send_socket_data(); + + /** + * @brief This function is used for generating socket events. + */ + void send_socket_event(SocketEvent event_type); + + /** + * @brief Does DNS resolving, called by dns_thread. + */ + void address_resolver(void); + + /** + * @brief handler for eventloop events. Note, this needs to be public as it is called + * from C wrapper. + */ + void event_handler(arm_event_s *event); + +private: + + /** + * @brief Terminate the DNS thread, if any is used. The #ifdef magic is inside this + * method, so it can be used without ifdef guards. + */ + void terminate_dns_thread(); + + /** + * @brief Handles socket initialization and connect phase. + */ + void socket_connect_handler(); + + /** + * @brief Callback handler for receiving data for secured connection. + */ + void receive_handshake_handler(); + + /** + * @brief Callback handler for socket events. + */ + void socket_event(); + + /** + * @brief Handles the result set by address_resolver. + */ + void handle_dns_result(bool success); + + + /** + * @brief Initialize socket + */ + bool init_socket(); + + /** + * @brief Check socket type + * @return True if TCP connection otherwise false + */ + bool is_tcp_connection() const; + + /** + * @brief Close and delete socket + */ + void close_socket(); + + /** + * @brief Enables keepalive for TCP connections. + */ + void enable_keepalive(); + + /** + * @brief Internal helper for sending an event. + */ + bool send_event(SocketEvent event_type); + + typedef struct send_data_queue { + uint8_t *data; + uint16_t offset; + uint16_t data_len; + ns_list_link_t link; + } send_data_queue_s; + + /** + * @brief Get first item from the queue list. + */ + send_data_queue_s* get_item_from_list(); + + /** + * @brief Add queue data back to list. + */ + void add_item_to_list(send_data_queue_s* data); + +private: + enum SocketState { + + /* NOTE: Order of these values does matter, do not make unplanned changes to it. */ + + /** Socket has not been initialized/connected yet. */ + ESocketStateDisconnected, + + /** pal_close() is in progress. */ + ESocketStateCloseBeingCalled, + + /** DNS resolving in progress. */ + ESocketStateDNSResolving, + + /** DNS resolving done, connection needs to be initialized. */ + EsocketStateInitializeConnection, + + /** pal_connect() is in progress. */ + ESocketStateConnectBeingCalled, + + /** pal_connect() has been called and we are waiting for asynchronous response. */ + ESocketStateConnecting, + + /** pal_connect is complete and the (D)TLS handshake is to be done if in secure mode. */ + ESocketStateConnected, + + /** (D)TLS Handshaking in progress */ + ESocketStateHandshaking, + + /** Unsecure Connection to the server has been established */ + ESocketStateUnsecureConnection, + + /** Secure Connection to the server has been established */ + ESocketStateSecureConnection + }; + + typedef NS_LIST_HEAD(send_data_queue_s, link) send_data_list_t; + + M2MConnectionHandler *_base; + M2MConnectionObserver &_observer; + M2MConnectionSecurity *_security_impl; //owned + const M2MSecurity *_security; //non-owned + M2MInterface::BindingMode _binding_mode; + M2MConnectionObserver::SocketAddress _address; + + // _address._address will point to one of these two + palIpV4Addr_t _ipV4Addr; + palIpV6Addr_t _ipV6Addr; + + palSocket_t _socket; + M2MConnectionObserver::ServerType _server_type; + uint16_t _server_port; + uint16_t _listen_port; + uint32_t _net_iface; + volatile palSocketAddress_t _socket_address; + static int8_t _tasklet_id; + String _server_address; + +#ifdef MBED_CONF_MBED_CLIENT_DNS_USE_THREAD + palThreadID_t _dns_thread_id; +#endif + + // A state variable for the socket itself, which is needed to handle the + // asynchronous events and callbacks. Note: the state may be accessed from + // event sender and receiver threads. + SocketState _socket_state; + uint8_t _handshake_retry; + + /** + * This is a flag which is set before sending a socket callback event + * and cleared when the event handler side is started. It is meant to get rid of + * event storm which happens whenever one socket transfers data and spurious + * events are sent to all the other sockets. + */ + volatile bool _suppressable_event_in_flight; + + send_data_list_t _linked_list_send_data; + + bool _secure_connection; + +friend class Test_M2MConnectionHandlerPimpl; +friend class Test_M2MConnectionHandlerPimpl_mbed; +friend class Test_M2MConnectionHandlerPimpl_classic; +friend class M2MConnection_TestObserver; +}; + +#endif //M2M_CONNECTION_HANDLER_PIMPL_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/mbed-client-classic/m2mtimerpimpl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/mbed-client-classic/m2mtimerpimpl.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef M2M_TIMER_PIMPL_H__ +#define M2M_TIMER_PIMPL_H__ + +#include "ns_types.h" +#include "mbed-client/m2mtimerobserver.h" + +class M2MTimerPimpl { +private: + + // Prevents the use of assignment operator + M2MTimerPimpl& operator=(const M2MTimerPimpl& other); + + // Prevents the use of copy constructor + M2MTimerPimpl(const M2MTimerPimpl& other); +public: + + /** + * Constructor. + */ + M2MTimerPimpl(M2MTimerObserver& _observer); + + /** + * Destructor. + */ + virtual ~M2MTimerPimpl(); + + /** + * Starts timer + * @param interval Timer's interval in milliseconds + * @param single_shot defines if timer is ticked + * once or is it restarted everytime timer is expired. + */ + void start_timer(uint64_t interval, M2MTimerObserver::Type type, bool single_shot = true); + + /** + * @brief Starts timer in DTLS manner + * @param intermediate_interval Intermediate interval to use, must be smaller than tiotal (usually 1/4 of total) + * @param total_interval Total interval to use; This is the timeout value of a DTLS packet + * @param type Type of the timer + */ + void start_dtls_timer(uint64_t intermediate_interval, uint64_t total_interval, M2MTimerObserver::Type type); + + /** + * Stops timer. + * This cancels the ongoing timer. + */ + void stop_timer(); + + /** + * Callback function for timer completion. + */ + void timer_expired(); + + /** + * @brief Checks if the intermediate interval has passed + * @return true if interval has passed, false otherwise + */ + bool is_intermediate_interval_passed(); + + /** + * @brief Checks if the total interval has passed + * @return true if interval has passed, false otherwise + */ + bool is_total_interval_passed(); + + /** + * @brief Start long period timer + */ + void start_still_left_timer(); + + /** + * @brief Get timer id + * @return Timer id + */ + inline int8_t get_timer_id() const; + + /** + * @brief Get still left time + * @return Time left in milliseconds + */ + uint64_t get_still_left_time() const; + +private: + + void start(); + void cancel(); + +private: + M2MTimerObserver& _observer; + bool _single_shot; + uint64_t _interval; + M2MTimerObserver::Type _type; + + uint64_t _intermediate_interval; + uint64_t _total_interval; + uint64_t _still_left; + uint8_t _status; + bool _dtls_type; + + // this is the timer-id of this object, used to map the + // timer event callback to the correct object. + int8_t _timer_id; + + static int8_t _tasklet_id; + static int8_t _next_timer_id; + + friend class M2MTimer; + friend class Test_M2MTimerPimpl_classic; +}; + +inline int8_t M2MTimerPimpl::get_timer_id() const +{ + return _timer_id; +} + +#endif //M2M_TIMER_PIMPL_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/source/m2mconnectionhandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/source/m2mconnectionhandler.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed-client-classic/m2mconnectionhandlerpimpl.h" +#include "mbed-client/m2mconnectionobserver.h" +#include "mbed-client/m2mconnectionhandler.h" +#include "mbed-client/m2mconstants.h" + +M2MConnectionHandler::M2MConnectionHandler(M2MConnectionObserver &observer, + M2MConnectionSecurity* sec, + M2MInterface::BindingMode mode, + M2MInterface::NetworkStack stack) +:_observer(observer) +{ + _private_impl = new M2MConnectionHandlerPimpl(this, observer, sec, mode, stack); +} + +M2MConnectionHandler::~M2MConnectionHandler() +{ + delete _private_impl; +} + +bool M2MConnectionHandler::bind_connection(const uint16_t listen_port) +{ + + return _private_impl->bind_connection(listen_port); +} + +bool M2MConnectionHandler::resolve_server_address(const String& server_address, + const uint16_t server_port, + M2MConnectionObserver::ServerType server_type, + const M2MSecurity* security) +{ + return _private_impl->resolve_server_address(server_address, server_port, + server_type, security); +} + +bool M2MConnectionHandler::start_listening_for_data() +{ + return _private_impl->start_listening_for_data(); +} + +void M2MConnectionHandler::stop_listening() +{ + _private_impl->stop_listening(); +} + +bool M2MConnectionHandler::send_data(uint8_t *data, + uint16_t data_len, + sn_nsdl_addr_s *address) +{ + return _private_impl->send_data(data, data_len, address); +} + +void M2MConnectionHandler::handle_connection_error(int error) +{ + _private_impl->handle_connection_error(error); +} + +void M2MConnectionHandler::set_platform_network_handler(void *handler) +{ + _private_impl->set_platform_network_handler(handler); +} + +void M2MConnectionHandler::claim_mutex() +{ + _private_impl->claim_mutex(); +} + +void M2MConnectionHandler::release_mutex() +{ + _private_impl->release_mutex(); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,968 @@ +/* + * Copyright (c) 2015 - 2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// fixup the compilation on ARMCC for PRIu32 +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include "mbed-client-classic/m2mconnectionhandlerpimpl.h" +#include "mbed-client/m2mconnectionobserver.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2msecurity.h" +#include "mbed-client/m2mconnectionhandler.h" + +#include "pal.h" + +#include "eventOS_scheduler.h" + +#include "eventOS_event_timer.h" + +#include "mbed-trace/mbed_trace.h" + +#include <stdlib.h> // free() and malloc() + +#define TRACE_GROUP "mClt" + +#ifndef MBED_CONF_MBED_CLIENT_TLS_MAX_RETRY +#define MBED_CONF_MBED_CLIENT_TLS_MAX_RETRY 60 +#endif + +// TODO: remove this also, as it is platform specific and this default will not work on Linux at all. +#ifndef MBED_CONF_MBED_CLIENT_DNS_THREAD_STACK_SIZE +#define MBED_CONF_MBED_CLIENT_DNS_THREAD_STACK_SIZE 2048 +#endif + + +int8_t M2MConnectionHandlerPimpl::_tasklet_id = -1; + +static M2MConnectionHandlerPimpl *connection_handler = NULL; + +// This is called from event loop, but as it is static C function, this is just a wrapper +// which calls C++ on the instance. +extern "C" void eventloop_event_handler(arm_event_s *event) +{ + if (!connection_handler) { + return; + } + connection_handler->event_handler(event); +} + +// event handler that forwards the event according to its type and/or connection state +void M2MConnectionHandlerPimpl::event_handler(arm_event_s *event) +{ + switch (event->event_type) { + + // Event from socket callback method + case M2MConnectionHandlerPimpl::ESocketCallback: + + // this will enable sending more events during this event processing, but that is less evil than missing one + _suppressable_event_in_flight = false; + + if (_socket_state == M2MConnectionHandlerPimpl::ESocketStateHandshaking) { + receive_handshake_handler(); + } else if ((_socket_state == M2MConnectionHandlerPimpl::ESocketStateUnsecureConnection) || + (_socket_state == M2MConnectionHandlerPimpl::ESocketStateSecureConnection)) { + // the connection is established + receive_handler(); + } else { + socket_connect_handler(); + } + + // Receive processing could have changed state, so recheck + if ((_socket_state == M2MConnectionHandlerPimpl::ESocketStateUnsecureConnection) || + (_socket_state == M2MConnectionHandlerPimpl::ESocketStateSecureConnection)) { + // the connection is established + send_socket_data(); + } + break; + + // Data send request from client side + case M2MConnectionHandlerPimpl::ESocketSend: + send_socket_data(); + break; + + // DNS resolved successfully + case M2MConnectionHandlerPimpl::ESocketDnsResolved: + handle_dns_result(true); + break; + + // DNS resolving failed + case M2MConnectionHandlerPimpl::ESocketDnsError: + handle_dns_result(false); + break; + + // Establish the connection by connecting the socket + case M2MConnectionHandlerPimpl::ESocketConnect: + socket_connect_handler(); + break; + + case M2MConnectionHandlerPimpl::ESocketClose: + close_socket(); + break; + + default: + tr_debug("M2MConnectionHandlerPimpl::connection_event_handler: default type: %d", (int)event->event_type); + break; + } +} + +// This callback is used from PAL sockets, it is called with object instance as argument. +// This is received from "some" socket event from "some" socket and the C++ side is responsible +// of forwarding it or ignoring the event completely. +extern "C" void socket_event_handler(void* arg) +{ + M2MConnectionHandlerPimpl* instance = (M2MConnectionHandlerPimpl*)arg; + + if (!instance) { + tr_error("Invalid callback argument"); + return; + } + + instance->send_socket_event(M2MConnectionHandlerPimpl::ESocketCallback); +} + +void M2MConnectionHandlerPimpl::send_socket_event(SocketEvent event_type) +{ + // the socket callback events can safely be suppressed, the receiving end must tolerate that + if (event_type == ESocketCallback) { + // only the socket connected state supports retries somehow + if (_suppressable_event_in_flight == false) { + _suppressable_event_in_flight = true; + } else { + // XXX: DO NOT ADD FOLLOWING LINE TO OFFICIAL GIT, THIS WILL KILL SOME NETWORK STACKS + // IF EVENT IS SENT FROM A INTERRUPT CONTEXT + // tr_debug("** SKIPPING event"); + return; + } + } + + if (!send_event(event_type)) { + // TODO: give a proper error based on state instead of this + _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true); + } +} + +M2MConnectionHandlerPimpl::M2MConnectionHandlerPimpl(M2MConnectionHandler* base, M2MConnectionObserver &observer, + M2MConnectionSecurity* sec, + M2MInterface::BindingMode mode, + M2MInterface::NetworkStack stack) +:_base(base), + _observer(observer), + _security_impl(sec), + _security(NULL), + _binding_mode(mode), + _socket(0), + _server_type(M2MConnectionObserver::LWM2MServer), + _server_port(0), + _listen_port(0), + _net_iface(0), +#ifdef MBED_CONF_MBED_CLIENT_DNS_USE_THREAD + _dns_thread_id(0), +#endif + _socket_state(ESocketStateDisconnected), + _handshake_retry(0), + _suppressable_event_in_flight(false), + _secure_connection(false) +{ +#ifndef PAL_NET_TCP_AND_TLS_SUPPORT + if (is_tcp_connection()) { + tr_error("ConnectionHandler: TCP support not available."); + return; + } +#endif + + if (PAL_SUCCESS != pal_init()) { + tr_error("PAL init failed."); + } + + memset(&_address, 0, sizeof _address); + memset((void*)&_socket_address, 0, sizeof _socket_address); + memset(&_ipV4Addr, 0, sizeof(palIpV4Addr_t)); + memset(&_ipV6Addr, 0, sizeof(palIpV6Addr_t)); + ns_list_init(&_linked_list_send_data); + + connection_handler = this; + eventOS_scheduler_mutex_wait(); + if (M2MConnectionHandlerPimpl::_tasklet_id == -1) { + M2MConnectionHandlerPimpl::_tasklet_id = eventOS_event_handler_create(&eventloop_event_handler, ESocketIdle); + } + eventOS_scheduler_mutex_release(); +} + +M2MConnectionHandlerPimpl::~M2MConnectionHandlerPimpl() +{ + tr_debug("~M2MConnectionHandlerPimpl()"); + + // terminate the DNS thread, if any is used + terminate_dns_thread(); + + close_socket(); + delete _security_impl; + _security_impl = NULL; + pal_destroy(); + tr_debug("~M2MConnectionHandlerPimpl() - OUT"); +} + +void M2MConnectionHandlerPimpl::terminate_dns_thread() +{ +#ifdef MBED_CONF_MBED_CLIENT_DNS_USE_THREAD + if (_dns_thread_id) { + pal_osThreadTerminate(&_dns_thread_id); + _dns_thread_id = 0; + } +#endif +} + + +bool M2MConnectionHandlerPimpl::bind_connection(const uint16_t listen_port) +{ + _listen_port = listen_port; + return true; +} + +bool M2MConnectionHandlerPimpl::send_event(SocketEvent event_type) +{ + arm_event_s event = {0}; + + event.receiver = M2MConnectionHandlerPimpl::_tasklet_id; + event.sender = 0; + event.event_type = event_type; + event.data_ptr = NULL; + event.event_data = 0; + event.priority = ARM_LIB_HIGH_PRIORITY_EVENT; + return !eventOS_event_send(&event); +} + +extern "C" void dns_thread(void const *connection_handler) +{ + ((M2MConnectionHandlerPimpl*)connection_handler)->address_resolver(); + + // Sleep until terminated. + for (;;) { + // This trace line is causing unexpected behaviour in Linux.To be investigated! + //tr_debug("M2MConnectionHandlerPimpl::dns_thread() going to sleep.."); + pal_osDelay(0xFFFFFFFF); + } +} + +void M2MConnectionHandlerPimpl::address_resolver(void) +{ + palStatus_t status; + palSocketLength_t socket_address_len; + + status = pal_getAddressInfo(_server_address.c_str(), (palSocketAddress_t*)&_socket_address, &socket_address_len); + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::getAddressInfo failed with %d", (int)status); + if (!send_event(ESocketDnsError)) { + tr_error("M2MConnectionHandlerPimpl::address_resolver, error event alloc fail."); + } + } else { + if (!send_event(ESocketDnsResolved)) { + tr_error("M2MConnectionHandlerPimpl::address_resolver, resolved event alloc fail."); + } + } +} + +void M2MConnectionHandlerPimpl::handle_dns_result(bool success) +{ + + if (_socket_state != ESocketStateDNSResolving) { + tr_warn("M2MConnectionHandlerPimpl::handle_dns_result() called, not in ESocketStateDNSResolving state!"); + return; + } + + // DNS thread no-longer needed. + terminate_dns_thread(); + + if (success) { + _socket_state = EsocketStateInitializeConnection; + socket_connect_handler(); + + } else { + _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR); + } +} + +bool M2MConnectionHandlerPimpl::resolve_server_address(const String& server_address, + const uint16_t server_port, + M2MConnectionObserver::ServerType server_type, + const M2MSecurity* security) +{ + _socket_state = ESocketStateDNSResolving; + _security = security; + + int32_t security_instance_id = _security->get_security_instance_id(M2MSecurity::M2MServer); + if (server_type == M2MConnectionObserver::Bootstrap) { + security_instance_id = _security->get_security_instance_id(M2MSecurity::Bootstrap); + } + + if (_security && + security_instance_id >= 0 && + (_security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id) == M2MSecurity::Certificate || + _security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id) == M2MSecurity::Psk)) { + _secure_connection = true; + } + + _server_port = server_port; + _server_type = server_type; + _server_address = server_address; + +#ifdef MBED_CONF_MBED_CLIENT_DNS_USE_THREAD + + tr_debug("M2MConnectionHandlerPimpl::resolve_server_address: starting DNS thread"); + + // terminate previous thread if it was still there + terminate_dns_thread(); + + // Try to create the DNS thread. If it fails, give an error. + if (PAL_SUCCESS != pal_osThreadCreateWithAlloc(dns_thread, this, PAL_osPriorityAboveNormal, MBED_CONF_MBED_CLIENT_DNS_THREAD_STACK_SIZE, NULL, &_dns_thread_id)) { + tr_error("M2MConnectionHandlerPimpl::dns_thread create failed."); + _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR); + return false; + } +#else + + tr_debug("M2MConnectionHandlerPimpl::resolve_server_address: synchronous DNS"); + + address_resolver(); + +#endif + return true; +} + +void M2MConnectionHandlerPimpl::socket_connect_handler() +{ + palStatus_t status; + int32_t security_instance_id = _security->get_security_instance_id(M2MSecurity::M2MServer); + if (_server_type == M2MConnectionObserver::Bootstrap) { + security_instance_id = _security->get_security_instance_id(M2MSecurity::Bootstrap); + } + + tr_debug("M2MConnectionHandlerPimpl::socket_connect_handler - _socket_state = %d", _socket_state); + + switch (_socket_state) { + case ESocketStateCloseBeingCalled: + case ESocketStateDNSResolving: + case ESocketStateDisconnected: + case ESocketStateHandshaking: + case ESocketStateUnsecureConnection: + case ESocketStateSecureConnection: + // Ignore these events + break; + + case EsocketStateInitializeConnection: + + // Initialize the socket to stable state + close_socket(); + + status = pal_setSockAddrPort((palSocketAddress_t*)&_socket_address, _server_port); + + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - setSockAddrPort err: %d", (int)status); + } else { + tr_debug("address family: %d", (int)_socket_address.addressType); + } + + if (_socket_address.addressType == PAL_AF_INET) { + status = pal_getSockAddrIPV4Addr((palSocketAddress_t*)&_socket_address,_ipV4Addr); + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - sockAddr4, err: %d", (int)status); + _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR); + return; + } + + tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - IPv4 Address %d.%d.%d.%d", + _ipV4Addr[0], _ipV4Addr[1], _ipV4Addr[2], _ipV4Addr[3]); + + _address._address = (void*)_ipV4Addr; + _address._length = PAL_IPV4_ADDRESS_SIZE; + _address._port = _server_port; + } else if (_socket_address.addressType == PAL_AF_INET6) { + status = pal_getSockAddrIPV6Addr((palSocketAddress_t*)&_socket_address,_ipV6Addr); + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - sockAddr6, err: %d", (int)status); + _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR); + return; + } + + tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - IPv6 Address: %s", mbed_trace_ipv6(_ipV6Addr)); + + _address._address = (void*)_ipV6Addr; + _address._length = PAL_IPV6_ADDRESS_SIZE; + _address._port = _server_port; + } else { + tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - socket config error, stack: %d", (int)_socket_address.addressType); + _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); + return; + } + + if (!init_socket()) { + tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - socket init error"); + // The init_socket() calls the socket_error() -callback directly, so it must not be + // done here too. + return; + } + + // This state was used to ignore the spurious events _during_ the call of non-blocking pal_connect(). + // Now that we just retry connect when it is not yet succeeded anyway this state might be removed completely. + _socket_state = ESocketStateConnectBeingCalled; + + // fall through is intentional + case ESocketStateConnectBeingCalled: + case ESocketStateConnecting: + if (is_tcp_connection()) { +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - Using TCP"); + + status = pal_connect(_socket, (palSocketAddress_t*)&_socket_address, sizeof(_socket_address)); + + if ((status == PAL_ERR_SOCKET_IN_PROGRES) || (status == PAL_ERR_SOCKET_WOULD_BLOCK)) { + // In this case the connect is done asynchronously, and the pal_socketMiniSelect() + // will be used to detect the end of connect. + tr_debug("M2MConnectionHandlerPimpl::socket_connect_handler - pal_connect(): %d, async connect started", (int)status); + // we need to wait for the event + _socket_state = ESocketStateConnecting; + break; + + } else if (status == PAL_SUCCESS || status == PAL_ERR_SOCKET_ALREADY_CONNECTED) { + + tr_debug("M2MConnectionHandlerPimpl::socket_connect_handler - pal_connect(): success"); + _socket_state = ESocketStateConnected; + + } else { + tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - pal_connect(): failed: %d", (int)status); + close_socket(); + _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); + return; + } +#else + tr_error("socket_connect_handler() - TCP not configured" +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + } else { + tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - Using UDP"); + _socket_state = ESocketStateConnected; + } + + // fall through is a normal flow in case the UDP was used or pal_connect() happened to return immediately with PAL_SUCCESS + case ESocketStateConnected: + if (_security && security_instance_id >= 0) { + if (_secure_connection) { + if ( _security_impl != NULL ) { + _security_impl->reset(); + + if (_security_impl->init(_security, security_instance_id) == 0) { + // Initiate handshake. Perhaps there could be a separate event type for this? + _socket_state = ESocketStateHandshaking; + send_socket_event(ESocketCallback); + } else { + tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - init failed"); + close_socket(); + _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, true); + return; + } + } else { + tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - sec is null"); + close_socket(); + _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, true); + return; + } + } + } + if (_socket_state != ESocketStateHandshaking) { + _socket_state = ESocketStateUnsecureConnection; + enable_keepalive(); + _observer.address_ready(_address, + _server_type, + _address._port); + } + break; + + } +} + +bool M2MConnectionHandlerPimpl::send_data(uint8_t *data, + uint16_t data_len, + sn_nsdl_addr_s *address) +{ + arm_event_s event = {0}; + + if (address == NULL || data == NULL || !data_len || _socket_state < ESocketStateUnsecureConnection) { + tr_warn("M2MConnectionHandlerPimpl::send_data() - too early"); + return false; + } + + send_data_queue_s* out_data = (send_data_queue_s*)malloc(sizeof(send_data_queue_s)); + if (!out_data) { + return false; + } + + memset(out_data, 0, sizeof(send_data_queue_s)); + + uint8_t offset = 0; +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + if (is_tcp_connection() && !_secure_connection ) { + offset = 4; + } +#endif + + out_data->data = (uint8_t*)malloc(data_len + offset); + if (!out_data->data) { + free(out_data); + return false; + } + + // TCP non-secure + // We need to "shim" the length in front +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + if (is_tcp_connection() && !_secure_connection ) { + out_data->data[0] = 0; + out_data->data[1] = 0; + out_data->data[2] = (data_len >> 8 ) & 0xff; + out_data->data[3] = data_len & 0xff; + } +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + + memcpy(out_data->data + offset, data, data_len); + out_data->data_len = data_len + offset; + + event.receiver = M2MConnectionHandlerPimpl::_tasklet_id; + event.sender = 0; + event.event_type = ESocketSend; + event.priority = ARM_LIB_HIGH_PRIORITY_EVENT; + + claim_mutex(); + ns_list_add_to_end(&_linked_list_send_data, out_data); + release_mutex(); + + if (eventOS_event_send(&event) != 0) { + // Event push failed, free the buffer + claim_mutex(); + ns_list_remove(&_linked_list_send_data, out_data); + release_mutex(); + free(out_data->data); + free(out_data); + return false; + } + + return true; +} + +void M2MConnectionHandlerPimpl::send_socket_data() +{ + tr_debug("M2MConnectionHandlerPimpl::send_socket_data()"); + int bytes_sent = 0; + bool success = true; + + send_data_queue_s* out_data = get_item_from_list(); + if (!out_data) { + return; + } + + if (!out_data->data || !out_data->data_len || _socket_state < ESocketStateUnsecureConnection) { + tr_warn("M2MConnectionHandlerPimpl::send_socket_data() - too early"); + add_item_to_list(out_data); + return; + } + + // Loop until all the data is sent + for (; out_data->offset < out_data->data_len; out_data->offset += bytes_sent) { + // Secure send + if (_socket_state == ESocketStateSecureConnection) { + // TODO! Change the send_message API to take bytes_sent as a out param like the pal send API's. + while ((bytes_sent = _security_impl->send_message(out_data->data + out_data->offset, + out_data->data_len - out_data->offset)) <= 0) { + if (bytes_sent == M2MConnectionHandler::CONNECTION_ERROR_WANTS_WRITE) { + // Return and wait the next event + add_item_to_list(out_data); + return; + } + + if (bytes_sent != M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ) { + tr_error("M2MConnectionHandlerPimpl::send_socket_data() - secure, failed %d", bytes_sent); + success = false; + break; + } + } + if (!success) { + break; + } + } + // Unsecure send + else { + bytes_sent = 0; + palStatus_t ret; + if (is_tcp_connection()) { +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + ret = pal_send(_socket, + out_data->data + out_data->offset, + out_data->data_len - out_data->offset, + (size_t*)&bytes_sent); +#endif + } else { + ret = pal_sendTo(_socket, + out_data->data + out_data->offset, + out_data->data_len - out_data->offset, + (palSocketAddress_t*)&_socket_address, + sizeof(_socket_address), + (size_t*)&bytes_sent); + } + if (ret == PAL_ERR_SOCKET_WOULD_BLOCK) { + // Return and wait next event + add_item_to_list(out_data); + return; + } + if (ret < 0) { + tr_error("M2MConnectionHandlerPimpl::send_socket_data() - unsecure failed %d", (int)ret); + success = false; + break; + } + } + } + + free(out_data->data); + free(out_data); + + if (!success) { + if (bytes_sent == M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY) { + _observer.socket_error(M2MConnectionHandler::SSL_PEER_CLOSED, true); + } else { + tr_error("M2MConnectionHandlerPimpl::send_socket_data() - SOCKET_SEND_ERROR"); + _observer.socket_error(M2MConnectionHandler::SOCKET_SEND_ERROR, true); + } + close_socket(); + } else { + _observer.data_sent(); + } +} + +bool M2MConnectionHandlerPimpl::start_listening_for_data() +{ + return true; +} + +void M2MConnectionHandlerPimpl::stop_listening() +{ + // Do not call close_socket() directly here. + // This can be called from multiple locations. + send_socket_event(ESocketClose); +} + +void M2MConnectionHandlerPimpl::handle_connection_error(int error) +{ + tr_error("M2MConnectionHandlerPimpl::handle_connection_error - error %d", error); + _observer.socket_error(error); +} + +void M2MConnectionHandlerPimpl::set_platform_network_handler(void *handler) +{ + tr_debug("M2MConnectionHandlerPimpl::set_platform_network_handler"); + if (PAL_SUCCESS != pal_registerNetworkInterface(handler, &_net_iface)) { + tr_error("M2MConnectionHandlerPimpl::set_platform_network_handler - Interface registration failed."); + } +} + +void M2MConnectionHandlerPimpl::receive_handshake_handler() +{ + int return_value; + tr_debug("M2MConnectionHandlerPimpl::receive_handshake_handler()"); + + // assert(_socket_state == ESocketStateHandshaking); + + return_value = _security_impl->connect(_base); + + if (!return_value) { + + _handshake_retry = 0; + _socket_state = ESocketStateSecureConnection; + enable_keepalive(); + _observer.address_ready(_address, + _server_type, + _server_port); + + } else if (return_value == M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY) { + _handshake_retry = 0; + _observer.socket_error(M2MConnectionHandler::SSL_PEER_CLOSED, true); + close_socket(); + + } else if (return_value != M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ) { + + tr_error("M2MConnectionHandlerPimpl::receive_handshake_handler() - SSL_HANDSHAKE_ERROR"); + _handshake_retry = 0; + _observer.socket_error(M2MConnectionHandler::SSL_HANDSHAKE_ERROR, true); + close_socket(); + + } else { + + if (_handshake_retry++ > MBED_CONF_MBED_CLIENT_TLS_MAX_RETRY) { + + tr_error("M2MConnectionHandlerPimpl::receive_handshake_handler() - Max TLS retry fail"); + _handshake_retry = 0; + _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT, true); + close_socket(); + + } + eventOS_event_timer_cancel(ESocketCallback, M2MConnectionHandlerPimpl::_tasklet_id); + eventOS_event_timer_request(ESocketCallback, ESocketCallback, M2MConnectionHandlerPimpl::_tasklet_id, 1000); + + } +} + +bool M2MConnectionHandlerPimpl::is_handshake_ongoing() const +{ + return (_socket_state == ESocketStateHandshaking); +} + +void M2MConnectionHandlerPimpl::receive_handler() +{ + // assert(_socket_state > ESocketStateHandshaking); + + if (_socket_state == ESocketStateSecureConnection) { + + int rcv_size; + unsigned char recv_buffer[BUFFER_LENGTH]; + + // we need to read as much as there is data available as the events may or may not be suppressed + do { + tr_debug("M2MConnectionHandlerPimpl::receive_handler().."); + rcv_size = _security_impl->read(recv_buffer, sizeof(recv_buffer)); + tr_debug("M2MConnectionHandlerPimpl::receive_handler() res: %d", rcv_size); + if (rcv_size > 0) { + _observer.data_available((uint8_t*)recv_buffer, + rcv_size, _address); + + } else if (M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY == rcv_size) { + _observer.socket_error(M2MConnectionHandler::SSL_PEER_CLOSED, true); + return; + } else if (M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ != rcv_size && rcv_size < 0) { + tr_error("M2MConnectionHandlerPimpl::receive_handler() - secure SOCKET_READ_ERROR"); + _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true); + close_socket(); + return; + } + } while (rcv_size > 0); + + } else { + size_t recv; + palStatus_t status; + unsigned char recv_buffer[BUFFER_LENGTH]; + do { + if (is_tcp_connection()) { +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + status = pal_recv(_socket, recv_buffer, sizeof(recv_buffer), &recv); +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + } else { + status = pal_receiveFrom(_socket, recv_buffer, sizeof(recv_buffer), NULL, NULL, &recv); + } + + if (status == PAL_ERR_SOCKET_WOULD_BLOCK) { + return; + } else if (status != PAL_SUCCESS) { + tr_error("M2MConnectionHandlerPimpl::receive_handler() - SOCKET_READ_ERROR (%d)", (int)status); + _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true); + close_socket(); + return; + } + + tr_debug("M2MConnectionHandlerPimpl::receive_handler() - data received, len: %zu", recv); + + if (!is_tcp_connection()) { // Observer for UDP plain mode + _observer.data_available((uint8_t*)recv_buffer, recv, _address); + } else { +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + if ( recv < 4 ) { + tr_error("M2MConnectionHandlerPimpl::receive_handler() - TCP SOCKET_READ_ERROR"); + _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true); + close_socket(); + return; + } + + //We need to "shim" out the length from the front + uint32_t len = (recv_buffer[0] << 24 & 0xFF000000) + (recv_buffer[1] << 16 & 0xFF0000); + len += (recv_buffer[2] << 8 & 0xFF00) + (recv_buffer[3] & 0xFF); + if (len > 0 && len <= recv - 4) { + // Observer for TCP plain mode + _observer.data_available(recv_buffer + 4, len, _address); + } +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + } + } while (recv > 0); + } +} + +void M2MConnectionHandlerPimpl::claim_mutex() +{ + eventOS_scheduler_mutex_wait(); +} + +void M2MConnectionHandlerPimpl::release_mutex() +{ + eventOS_scheduler_mutex_release(); +} + + +bool M2MConnectionHandlerPimpl::init_socket() +{ + palSocketType_t socket_type = PAL_SOCK_DGRAM; + palStatus_t status; + palSocketAddress_t bind_address; + + palNetInterfaceInfo_t interface_info; + palIpV4Addr_t interface_address4; + palIpV6Addr_t interface_address6; + + memset(&bind_address, 0, sizeof(palSocketAddress_t)); + memset(&interface_address4, 0, sizeof(interface_address4)); + memset(&interface_address6, 0, sizeof(interface_address6)); + + if (is_tcp_connection()) { +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + socket_type = PAL_SOCK_STREAM; +#else + // Somebody has built code without TCP support but tries to use it. + // Perhaps a "assert(false)" would be sufficient. + tr_error("M2MConnectionHandlerPimpl::init_socket() - TCP config error"); + _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); + return; +#endif //PAL_NET_TCP_AND_TLS_SUPPORT + } + + uint32_t interface_count; + pal_getNumberOfNetInterfaces(&interface_count); + pal_getNetInterfaceInfo(_net_iface, &interface_info); + + status = pal_asynchronousSocketWithArgument((palSocketDomain_t)_socket_address.addressType, + socket_type, true, _net_iface, &socket_event_handler, + this, &_socket); + + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::init_socket() - socket create error : %d", (int)status); + _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); + return false; + } + + if (_socket_address.addressType == PAL_AF_INET) { + status = pal_setSockAddrIPV4Addr(&bind_address, interface_address4); + } else if (_socket_address.addressType == PAL_AF_INET6) { + status = pal_setSockAddrIPV6Addr(&bind_address, interface_address6); + } else { + tr_warn("M2MConnectionHandlerPimpl::init_socket() - stack type: %d", (int)_socket_address.addressType); + } + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::init_socket - setSockAddrIPV err: %d", (int)status); + return false; + } + status = pal_setSockAddrPort(&bind_address, _listen_port); + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::init_socket - setSockAddrPort err: %d", (int)status); + return false; + } + pal_bind(_socket, &bind_address, sizeof(bind_address)); + + _security_impl->set_socket(_socket, (palSocketAddress_t*)&_socket_address); + + return true; +} + +bool M2MConnectionHandlerPimpl::is_tcp_connection() const +{ + return ( _binding_mode == M2MInterface::TCP || + _binding_mode == M2MInterface::TCP_QUEUE ); +} + +void M2MConnectionHandlerPimpl::close_socket() +{ + _suppressable_event_in_flight = false; + + terminate_dns_thread(); + + if (_socket) { + // At least on mbed-os the pal_close() will perform callbacks even during it + // is called, which we will ignore when this state is set. + _socket_state = ESocketStateCloseBeingCalled; + pal_close(&_socket); + _socket = 0; + } + + // make sure the socket connection statemachine is reset too. + _socket_state = ESocketStateDisconnected; + + if (_security_impl) { + _security_impl->reset(); + } + + claim_mutex(); + /*ns_list_foreach_safe(M2MConnectionHandlerPimpl::send_data_queue_s, tmp, &_linked_list_send_data) { + ns_list_remove(&_linked_list_send_data, tmp); + free(tmp->data); + free(tmp); + }*/ + // Workaround for IAR compilation issue. ns_list_foreach does not compile with IAR. + // Error[Pe144]: a value of type "void *" cannot be used to initialize an entity of type "M2MConnectionHandlerPimpl::send_data_queue *" + while (!ns_list_is_empty(&_linked_list_send_data)) { + send_data_queue_s* data = (send_data_queue_s*)ns_list_get_first(&_linked_list_send_data); + ns_list_remove(&_linked_list_send_data, data); + free(data->data); + free(data); + } + release_mutex(); +} + +void M2MConnectionHandlerPimpl::enable_keepalive() +{ +#if MBED_CLIENT_TCP_KEEPALIVE_TIME +#ifdef PAL_NET_TCP_AND_TLS_SUPPORT + palStatus_t status; + if (is_tcp_connection()) { + int enable = 1; + status = pal_setSocketOptions(_socket, PAL_SO_KEEPALIVE, &enable, sizeof(enable)); + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::enable_keepalive - PAL_SO_KEEPALIVE err: %d", (int)status); + } + + int idle_period = MBED_CLIENT_TCP_KEEPALIVE_TIME; + tr_info("M2MConnectionHandlerPimpl::enable_keepalive - PAL_SO_KEEPIDLE %d", idle_period); + status = pal_setSocketOptions(_socket, PAL_SO_KEEPIDLE, &idle_period, sizeof(idle_period)); + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::enable_keepalive - PAL_SO_KEEPIDLE err: %d", (int)status); + } + + int intvl = MBED_CLIENT_TCP_KEEPALIVE_INTERVAL; + status = pal_setSocketOptions(_socket, PAL_SO_KEEPINTVL, &intvl, sizeof(intvl)); + if (PAL_SUCCESS != status) { + tr_error("M2MConnectionHandlerPimpl::enable_keepalive - PAL_SO_KEEPINTVL err: %d", (int)status); + } + } +#endif +#endif +} + +M2MConnectionHandlerPimpl::send_data_queue_s* M2MConnectionHandlerPimpl::get_item_from_list() +{ + claim_mutex(); + send_data_queue_s* out_data = (send_data_queue_s*)ns_list_get_first(&_linked_list_send_data); + if (out_data) { + ns_list_remove(&_linked_list_send_data, out_data); + } + release_mutex(); + return out_data; +} + +void M2MConnectionHandlerPimpl::add_item_to_list(M2MConnectionHandlerPimpl::send_data_queue_s *data) +{ + claim_mutex(); + ns_list_add_to_start(&_linked_list_send_data, data); + release_mutex(); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/source/m2mtimer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/source/m2mtimer.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed-client/m2mtimer.h" +#include "mbed-client/m2mtimerobserver.h" +#include "mbed-client-classic/m2mtimerpimpl.h" + + +M2MTimer::M2MTimer(M2MTimerObserver& observer) +: _observer(observer) +{ + _private_impl = new M2MTimerPimpl(observer); +} + +M2MTimer::~M2MTimer() +{ + delete _private_impl; + //_private_impl = NULL; +} + +void M2MTimer::start_timer( uint64_t interval, + M2MTimerObserver::Type type, + bool single_shot) +{ + _private_impl->start_timer(interval, + type, + single_shot); +} + +void M2MTimer::start_dtls_timer(uint64_t intermediate_interval, uint64_t total_interval, M2MTimerObserver::Type type){ + _private_impl->start_dtls_timer(intermediate_interval, total_interval, type); +} + +void M2MTimer::stop_timer() +{ + _private_impl->stop_timer(); +} + +bool M2MTimer::is_intermediate_interval_passed(){ + return _private_impl->is_intermediate_interval_passed(); +} + +bool M2MTimer::is_total_interval_passed(){ + return _private_impl->is_total_interval_passed(); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/source/m2mtimerpimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-classic/source/m2mtimerpimpl.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2015-2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <assert.h> +#include <time.h> + +#include "mbed-client-classic/m2mtimerpimpl.h" +#include "mbed-client/m2mtimerobserver.h" +#include "mbed-client/m2mvector.h" + +#include "eventOS_event.h" +#include "eventOS_event_timer.h" +#include "eventOS_scheduler.h" +#include "ns_hal_init.h" + +#define MBED_CLIENT_TIMER_TASKLET_INIT_EVENT 0 // Tasklet init occurs always when generating a tasklet +#define MBED_CLIENT_TIMER_EVENT 10 + +#ifdef MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE +#define MBED_CLIENT_EVENT_LOOP_SIZE MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE +#else +#define MBED_CLIENT_EVENT_LOOP_SIZE 1024 +#endif + +int8_t M2MTimerPimpl::_tasklet_id = -1; + +int8_t M2MTimerPimpl::_next_timer_id = 1; + +static m2m::Vector<M2MTimerPimpl*> timer_impl_list; + +extern "C" void tasklet_func(arm_event_s *event) +{ + // skip the init event as there will be a timer event after + if (event->event_type == MBED_CLIENT_TIMER_EVENT) { + bool timer_found = false; + eventOS_scheduler_mutex_wait(); + int timer_count = timer_impl_list.size(); + for (int index = 0; index < timer_count; index++) { + M2MTimerPimpl* timer = timer_impl_list[index]; + if (timer->get_timer_id() == event->event_id) { + eventOS_scheduler_mutex_release(); + timer_found = true; + if (timer->get_still_left_time() > 0) { + timer->start_still_left_timer(); + }else { + timer->timer_expired(); + } + break; + } + } + if(!timer_found) { + eventOS_scheduler_mutex_release(); + } + } +} + +M2MTimerPimpl::M2MTimerPimpl(M2MTimerObserver& observer) +: _observer(observer), + _single_shot(true), + _interval(0), + _type(M2MTimerObserver::Notdefined), + _intermediate_interval(0), + _total_interval(0), + _still_left(0), + _status(0), + _dtls_type(false) +{ + ns_hal_init(NULL, MBED_CLIENT_EVENT_LOOP_SIZE, NULL, NULL); + eventOS_scheduler_mutex_wait(); + if (_tasklet_id < 0) { + _tasklet_id = eventOS_event_handler_create(tasklet_func, MBED_CLIENT_TIMER_TASKLET_INIT_EVENT); + assert(_tasklet_id >= 0); + } + + // XXX: this wraps over quite soon + _timer_id = M2MTimerPimpl::_next_timer_id++; + timer_impl_list.push_back(this); + eventOS_scheduler_mutex_release(); +} + +M2MTimerPimpl::~M2MTimerPimpl() +{ + // cancel the timer request, if any is pending + cancel(); + + // there is no turning back, event os does not have eventOS_event_handler_delete() or similar, + // so the tasklet is lost forever. Same goes with timer_impl_list, which leaks now memory. + + // remove the timer from object list + eventOS_scheduler_mutex_wait(); + int timer_count = timer_impl_list.size(); + for (int index = 0; index < timer_count; index++) { + const M2MTimerPimpl* timer = timer_impl_list[index]; + if (timer->get_timer_id() == _timer_id) { + timer_impl_list.erase(index); + break; + } + } + eventOS_scheduler_mutex_release(); +} + +void M2MTimerPimpl::start_timer( uint64_t interval, + M2MTimerObserver::Type type, + bool single_shot) +{ + _dtls_type = false; + _intermediate_interval = 0; + _total_interval = 0; + _status = 0; + _single_shot = single_shot; + _interval = interval; + _type = type; + _still_left = 0; + start(); +} + +void M2MTimerPimpl::start_dtls_timer(uint64_t intermediate_interval, uint64_t total_interval, M2MTimerObserver::Type type) +{ + _dtls_type = true; + _intermediate_interval = intermediate_interval; + _total_interval = total_interval; + _interval = _intermediate_interval; + _status = 0; + _single_shot = false; + _type = type; + start(); +} + +void M2MTimerPimpl::start() +{ + int status; + if(_interval > INT32_MAX) { + _still_left = _interval - INT32_MAX; + status = eventOS_event_timer_request(_timer_id, MBED_CLIENT_TIMER_EVENT, + M2MTimerPimpl::_tasklet_id, + INT32_MAX); + } + else { + status = eventOS_event_timer_request(_timer_id, MBED_CLIENT_TIMER_EVENT, + M2MTimerPimpl::_tasklet_id, + _interval); + } + assert(status == 0); +} + +void M2MTimerPimpl::cancel() +{ + eventOS_event_timer_cancel(_timer_id, M2MTimerPimpl::_tasklet_id); +} + +void M2MTimerPimpl::stop_timer() +{ + _interval = 0; + _single_shot = true; + _still_left = 0; + cancel(); +} + +void M2MTimerPimpl::timer_expired() +{ + _status++; + _observer.timer_expired(_type); + + if ((!_dtls_type) && (!_single_shot)) { + // start next round of periodic timer + start(); + } else if ((_dtls_type) && (!is_total_interval_passed())) { + // if only the intermediate time has passed, we need still wait up to total time + _interval = _total_interval - _intermediate_interval; + start(); + } +} + +bool M2MTimerPimpl::is_intermediate_interval_passed() +{ + if (_status > 0) { + return true; + } + return false; +} + +bool M2MTimerPimpl::is_total_interval_passed() +{ + if (_status > 1) { + return true; + } + return false; +} + +uint64_t M2MTimerPimpl::get_still_left_time() const +{ + return _still_left; +} + +void M2MTimerPimpl::start_still_left_timer() +{ + if (_still_left > 0) { + int status; + if( _still_left > INT32_MAX) { + _still_left = _still_left - INT32_MAX; + status = eventOS_event_timer_request(_timer_id, MBED_CLIENT_TIMER_EVENT, + M2MTimerPimpl::_tasklet_id, + INT32_MAX); + } + else { + status = eventOS_event_timer_request(_timer_id, MBED_CLIENT_TIMER_EVENT, + M2MTimerPimpl::_tasklet_id, + _still_left); + _still_left = 0; + } + assert(status == 0); + } else { + _observer.timer_expired(_type); + if(!_single_shot) { + start_timer(_interval, _type, _single_shot); + } + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +test/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/apache-2.0.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/mbed-client-mbedtls/m2mconnectionsecuritypimpl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/mbed-client-mbedtls/m2mconnectionsecuritypimpl.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2015 - 2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __M2M_CONNECTION_SECURITY_PIMPL_H__ +#define __M2M_CONNECTION_SECURITY_PIMPL_H__ + +#include "mbed-client/m2mconnectionsecurity.h" +#include "mbed-client/m2mtimerobserver.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2msecurity.h" +#include "mbed-client/m2mconfig.h" + +#include "pal.h" + +#include <time.h> + +/** + * @brief The M2MConnectionSecurityPimpl class + */ +class M2MConnectionSecurityPimpl{ + +private: + + enum{ + INIT_NOT_STARTED = 0, + INIT_CONFIGURING, + INIT_DONE + }; + + // Prevents the use of assignment operator by accident. + M2MConnectionSecurityPimpl& operator=( const M2MConnectionSecurityPimpl& /*other*/ ); + // Prevents the use of copy constructor by accident + M2MConnectionSecurityPimpl( const M2MConnectionSecurityPimpl& /*other*/ ); + +public: + + /** + * @brief Constructor + */ + M2MConnectionSecurityPimpl(M2MConnectionSecurity::SecurityMode mode); + + /** + * @brief Destructor + */ + virtual ~M2MConnectionSecurityPimpl(); + + /** + * \brief Resets the socket connection states. + */ + void reset(); + + /** + * \brief Initiatlizes the socket connection states. + */ + int init(const M2MSecurity *security, uint16_t security_instance_id); + + /** + * \brief Connects the client to the server. + * \param connHandler The ConnectionHandler object that maintains the socket. + * \return Returns the state of the connection. Successful or not. + * If 2MConnectionHandler::CONNECTION_ERROR_WANTS_READ is returned + * this function must be called again later to continue the handshake. + */ + int connect(M2MConnectionHandler* connHandler); + + /** + * \brief Sends data to the server. + * \param message The data to be sent. + * \param len The length of the data. + * @return Indicates whether the data is sent successfully or not. + */ + int send_message(unsigned char *message, int len); + + /** + * \brief Reads the data received from the server. + * \param message The data to be read. + * \param len The length of the data. + * \return Indicates whether the data is read successfully or not. + */ + int read(unsigned char* buffer, uint16_t len); + + /** + * This function is no longer used. + */ + void set_random_number_callback(random_number_cb callback); + + /** + * \brief Sets the function callback that will be called by mbed-client for + * providing entropy source from application for ensuring strong entropy. + * \param entropy_callback A function pointer that will be called by mbed-client + * while performing secure handshake. + * Function signature , if using mbed-client-mbedtls should be + * int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, + * size_t len, size_t *olen); + * + * NOTE: This function is only used if MBED_CLOUD_CLIENT_CUSTOM_MBEDTLS_ENTROPY is defined + * and mbed TLS is used. + */ + void set_entropy_callback(entropy_cb callback); + + /** + * \brief Set socket information for this secure connection. + * \param socket Socket used with this TLS session. + * \param address Pointer to the address of the server. + * \return Indicates whether the data is read successfully or not. + */ + void set_socket(palSocket_t socket, palSocketAddress_t *address); + +private: + + int start_handshake(); + + /** + * \brief Returns certificate expiration time in epoch format. + * \param certificate, The certificate to be extracted. + * \param cert_len, Length of the certificate. + * \return epoch time or 0 if failure. + */ + uint32_t certificate_expiration_time(const unsigned char *certificate, const uint32_t cert_len); + + /** + * \brief Returns certificate validFrom time in epoch format. + * \param certificate, The certificate to be extracted. + * \param cert_len, Length of the certificate. + * \return epoch time or 0 if failure. + */ + uint32_t certificate_validfrom_time(const unsigned char *certificate, const uint32_t cert_len); + + /** + * \brief A utility function to check if provided certificate is valid with given time + * \return True if certificate is valid, false if not + */ + bool check_certificate_validity(const uint8_t *cert, const uint32_t cert_len, const int64_t device_time); + + /** + * \brief Returns certificate validFrom and validTo times in epoch format. + * \param certificate, The certificate to be extracted. + * \param valid_from ValidFrom time will be written to this parameter on success. + * \param valid_to ValidTo time will be written to this parameter on success. + * \return true on success or false on failure. + */ + bool certificate_parse_valid_time(const char *certificate, uint32_t certificate_len, uint64_t *valid_from, uint64_t *valid_to); + + /** + * \brief A utility function to check if provided security object + * has client and server certificates that are valid with current time set + * in device object + * \param security, M2MSecurity object to validate + * \param security_instance_id, Object instance id of security instance to validate + * \return True if certificates are valid, false if M2MSecurity or M2MDevice + * objects are missing, or if current time is not within the validity periods + */ + bool check_security_object_validity(const M2MSecurity *security, uint16_t security_instance_id); + +private: + + uint8_t _init_done; + palTLSConfHandle_t _conf; + palTLSHandle_t _ssl; + M2MConnectionSecurity::SecurityMode _sec_mode; + palTLSSocket_t _tls_socket; + entropy_cb _entropy; + + friend class Test_M2MConnectionSecurityPimpl; +}; + +#endif //__M2M_CONNECTION_SECURITY_PIMPL_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/source/m2mconnectionsecurity.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/source/m2mconnectionsecurity.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> +#include "mbed-client/m2mconnectionhandler.h" +#include "mbed-client/m2mconnectionsecurity.h" +#include "mbed-client-mbedtls/m2mconnectionsecuritypimpl.h" + +M2MConnectionSecurity::M2MConnectionSecurity(SecurityMode mode) +{ + _private_impl = new M2MConnectionSecurityPimpl(mode); +} + +M2MConnectionSecurity::~M2MConnectionSecurity(){ + delete _private_impl; +} + +void M2MConnectionSecurity::reset(){ + _private_impl->reset(); +} + +int M2MConnectionSecurity::init(const M2MSecurity *security, uint16_t security_instance_id){ + return _private_impl->init(security, security_instance_id); +} + +int M2MConnectionSecurity::connect(M2MConnectionHandler* connHandler){ + return _private_impl->connect(connHandler); +} + +int M2MConnectionSecurity::send_message(unsigned char *message, int len){ + return _private_impl->send_message(message, len); +} + +int M2MConnectionSecurity::read(unsigned char* buffer, uint16_t len){ + return _private_impl->read(buffer, len); +} + +void M2MConnectionSecurity::set_random_number_callback(random_number_cb callback) +{ + _private_impl->set_random_number_callback(callback); +} + +void M2MConnectionSecurity::set_entropy_callback(entropy_cb callback) +{ + _private_impl->set_entropy_callback(callback); +} + +void M2MConnectionSecurity::set_socket(void *socket, void *address) +{ + _private_impl->set_socket((palSocket_t) socket, (palSocketAddress_t*) address); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/source/m2mconnectionsecuritypimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client-mbed-tls/source/m2mconnectionsecuritypimpl.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2015 - 2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Needed for PRIu64 on FreeRTOS +#include <stdio.h> +// Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include "mbed-client/m2mconnectionhandler.h" +#include "mbed-client-mbedtls/m2mconnectionsecuritypimpl.h" +#include "mbed-client/m2msecurity.h" +#include "mbed-trace/mbed_trace.h" +#include "pal.h" +#include "m2mdevice.h" +#include "m2minterfacefactory.h" +#include <string.h> + +#define TRACE_GROUP "mClt" + +M2MConnectionSecurityPimpl::M2MConnectionSecurityPimpl(M2MConnectionSecurity::SecurityMode mode) + :_init_done(M2MConnectionSecurityPimpl::INIT_NOT_STARTED), + _conf(0), + _ssl(0), + _sec_mode(mode) +{ + memset(&_entropy, 0, sizeof(entropy_cb)); + memset(&_tls_socket, 0, sizeof(palTLSSocket_t)); +} + +M2MConnectionSecurityPimpl::~M2MConnectionSecurityPimpl() +{ + pal_freeTLS(&_ssl); + pal_tlsConfigurationFree(&_conf); +} + +void M2MConnectionSecurityPimpl::reset() +{ + pal_freeTLS(&_ssl); + pal_tlsConfigurationFree(&_conf); + _init_done = M2MConnectionSecurityPimpl::INIT_NOT_STARTED; +} + +int M2MConnectionSecurityPimpl::init(const M2MSecurity *security, uint16_t security_instance_id) +{ + tr_debug("M2MConnectionSecurityPimpl::init"); + + if(!security){ + tr_error("M2MConnectionSecurityPimpl Security NULL."); + return -1; + } + + if(_entropy.entropy_source_ptr) { + if(PAL_SUCCESS != pal_addEntropySource(_entropy.entropy_source_ptr)){ + return -1; + } + } + + palTLSTransportMode_t mode = PAL_DTLS_MODE; + if(_sec_mode == M2MConnectionSecurity::TLS){ + mode = PAL_TLS_MODE; + } + + if(PAL_SUCCESS != pal_initTLSConfiguration(&_conf, mode)){ + tr_error("pal_initTLSConfiguration failed"); + return -1; + } + + _init_done = M2MConnectionSecurityPimpl::INIT_CONFIGURING; + + + if(_sec_mode == M2MConnectionSecurity::DTLS){ + // PAL divides the defined MAX_TIMEOUT by 2 + pal_setHandShakeTimeOut(_conf, MBED_CLIENT_DTLS_PEER_MAX_TIMEOUT*2); + } + + M2MSecurity::SecurityModeType cert_mode = + (M2MSecurity::SecurityModeType)security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id); + + if( cert_mode == M2MSecurity::Certificate ){ + + palX509_t owncert; + palPrivateKey_t privateKey; + palX509_t caChain; + + // Check if we are connecting to M2MServer and check if server and device certificates are valid, no need to do this + // for Bootstrap or direct LWM2M server case + if ((security->server_type(security_instance_id) == M2MSecurity::M2MServer) && + (security->get_security_instance_id(M2MSecurity::Bootstrap) >= 0) && + !check_security_object_validity(security, security_instance_id)) { + tr_error("M2MConnectionSecurityPimpl::init - M2MServer certificate invalid or device certificate expired!"); + return -1; + } + + owncert.size = 1 + security->resource_value_buffer(M2MSecurity::PublicKey, (const uint8_t*&)owncert.buffer, security_instance_id); + privateKey.size = 1 + security->resource_value_buffer(M2MSecurity::Secretkey, (const uint8_t*&)privateKey.buffer, security_instance_id); + caChain.size = 1 + security->resource_value_buffer(M2MSecurity::ServerPublicKey, (const uint8_t*&)caChain.buffer, security_instance_id); + + if(PAL_SUCCESS != pal_setOwnCertAndPrivateKey(_conf, &owncert, &privateKey)){ + tr_error("pal_setOwnCertAndPrivateKey failed"); + return -1; + } + if(PAL_SUCCESS != pal_setCAChain(_conf, &caChain, NULL)){ + tr_error("pal_setCAChain failed"); + return -1; + } + + }else if(cert_mode == M2MSecurity::Psk){ + + uint8_t *identity = NULL; + uint32_t identity_len; + uint8_t *psk = NULL; + uint32_t psk_len; + + identity_len = security->resource_value_buffer(M2MSecurity::PublicKey, identity, security_instance_id); + psk_len = security->resource_value_buffer(M2MSecurity::Secretkey, psk, security_instance_id); + palStatus_t ret = pal_setPSK(_conf, identity, identity_len, psk, psk_len); + free(identity); + free(psk); + + if(PAL_SUCCESS != ret){ + tr_error("pal_setPSK failed"); + return -1; + } + + }else{ + tr_error("Security mode not set"); + return -1; + + } + + if(PAL_SUCCESS != pal_initTLS(_conf, &_ssl)){ + tr_error("pal_initTLS failed"); + return -1; + } + + if(PAL_SUCCESS != pal_tlsSetSocket(_conf, &_tls_socket)){ + tr_error("pal_tlsSetSocket failed"); + return -1; + } + + _init_done = M2MConnectionSecurityPimpl::INIT_DONE; + +#ifdef MBED_CONF_MBED_TRACE_ENABLE + // Note: This call is not enough, one also needs the MBEDTLS_DEBUG_C to be defined globally + // on build and if using default mbedtls configuration file, the + // "#undef MBEDTLS_DEBUG_C" -line needs to be removed from mbedtls_mbed_client_config.h + pal_sslDebugging(1); +#endif + + tr_debug("M2MConnectionSecurityPimpl::init - out"); + return 0; +} + +int M2MConnectionSecurityPimpl::start_handshake() +{ + tr_debug("M2MConnectionSecurityPimpl::start_handshake"); + + palStatus_t ret; + + ret = pal_handShake(_ssl, _conf); + + if(ret == PAL_ERR_TLS_WANT_READ || ret == PAL_ERR_TLS_WANT_WRITE || ret == PAL_ERR_TIMEOUT_EXPIRED){ + return M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; + } + else if(ret == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { + return M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; + } + + if(ret != PAL_SUCCESS){ //We loose the original error here! + tr_debug("M2MConnectionSecurityPimpl::start_handshake pal_handShake() error %" PRId32, ret); + return -1; + } + + ret = pal_sslGetVerifyResult(_ssl); + if(PAL_SUCCESS != ret){ + tr_debug("M2MConnectionSecurityPimpl::start_handshake pal_sslGetVerifyResult() error %" PRId32, ret); + return -1; + } + + return ret; +} + +int M2MConnectionSecurityPimpl::connect(M2MConnectionHandler* connHandler) +{ + tr_debug("M2MConnectionSecurityPimpl::connect"); + int ret = -1; + + if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ + return ret; + } + + ret = start_handshake(); + tr_debug("M2MConnectionSecurityPimpl::connect - handshake ret: %d", ret); + return ret; +} + + +int M2MConnectionSecurityPimpl::send_message(unsigned char *message, int len) +{ + tr_debug("M2MConnectionSecurityPimpl::send_message"); + int ret = -1; + palStatus_t return_value; + uint32_t len_write; + + if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ + return ret; + } + + + if(PAL_SUCCESS == (return_value = pal_sslWrite(_ssl, message, len, &len_write))){ + ret = (int)len_write; + } + else if(return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TIMEOUT_EXPIRED){ + ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; + } + else if(return_value == PAL_ERR_TLS_WANT_WRITE) { + ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_WRITE; + } + else if(return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { + ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; + } + + tr_debug("M2MConnectionSecurityPimpl::send_message - ret: %d", ret); + return ret; //bytes written +} + +int M2MConnectionSecurityPimpl::read(unsigned char* buffer, uint16_t len) +{ + int ret = -1; + palStatus_t return_value; + uint32_t len_read; + + if(M2MConnectionSecurityPimpl::INIT_DONE != _init_done){ + tr_error("M2MConnectionSecurityPimpl::read - init not done!"); + return ret; + } + + if(PAL_SUCCESS == (return_value = pal_sslRead(_ssl, buffer, len, &len_read))){ + ret = (int)len_read; + } + + else if(return_value == PAL_ERR_TLS_WANT_READ || return_value == PAL_ERR_TLS_WANT_WRITE || return_value == PAL_ERR_TIMEOUT_EXPIRED){ + ret = M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; + } + + else if(return_value == PAL_ERR_TLS_PEER_CLOSE_NOTIFY) { + ret = M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY; + } + + return ret; +} + +void M2MConnectionSecurityPimpl::set_random_number_callback(random_number_cb callback) +{ + (void)callback; +} + +void M2MConnectionSecurityPimpl::set_entropy_callback(entropy_cb callback) +{ + + _entropy = callback; + +} + +void M2MConnectionSecurityPimpl::set_socket(palSocket_t socket, palSocketAddress_t *address) +{ + _tls_socket.socket = socket; + _tls_socket.socketAddress = address; + _tls_socket.addressLength = sizeof(palSocketAddress_t); + + if(_sec_mode == M2MConnectionSecurity::TLS){ + _tls_socket.transportationMode = PAL_TLS_MODE; + } + else{ + _tls_socket.transportationMode = PAL_DTLS_MODE; + } +} + +bool M2MConnectionSecurityPimpl::certificate_parse_valid_time(const char *certificate, uint32_t certificate_len, uint64_t *valid_from, uint64_t *valid_to) +{ + palX509Handle_t cert = 0; + size_t len; + palStatus_t ret; + + tr_debug("certificate_validfrom_time"); + + if(PAL_SUCCESS != (ret = pal_x509Initiate(&cert))) { + tr_error("certificate_validfrom_time - cert init failed: %u", (int)ret); + pal_x509Free(&cert); + return false; + } + if(PAL_SUCCESS != (ret = pal_x509CertParse(cert, (const unsigned char*)certificate, certificate_len))) { + tr_error("certificate_validfrom_time - cert parse failed: %u", (int)ret); + pal_x509Free(&cert); + return false; + } + if(PAL_SUCCESS != (ret = pal_x509CertGetAttribute(cert, PAL_X509_VALID_FROM, valid_from, sizeof(uint64_t), &len))) { + tr_error("certificate_validfrom_time - cert attr get failed: %u", (int)ret); + pal_x509Free(&cert); + return false; + } + if(PAL_SUCCESS != (ret = pal_x509CertGetAttribute(cert, PAL_X509_VALID_TO, valid_to, sizeof(uint64_t), &len))) { + tr_error("certificate_validto_time - cert attr get failed: %u", (int)ret); + pal_x509Free(&cert); + return false; + } + + pal_x509Free(&cert); + return true; +} + +bool M2MConnectionSecurityPimpl::check_security_object_validity(const M2MSecurity *security, uint16_t security_instance_id) { + // Get time from device object + M2MDevice *device = M2MInterfaceFactory::create_device(); + const uint8_t *certificate = NULL; + int64_t device_time = 0; + uint32_t cert_len = 0; + + if (device == NULL || security == NULL) { + tr_error("No time from device object or security object available, fail connector registration %p, %p\n", device, security); + return false; + } + + // Get time from device object, returns -1 if resource not found + device_time = device->resource_value_int(M2MDevice::CurrentTime, 0); + + tr_debug("Checking client certificate validity"); + + // Get client certificate + cert_len = security->resource_value_buffer(M2MSecurity::PublicKey, certificate, security_instance_id); + if (cert_len == 0 || certificate == NULL) { + tr_error("No certificate to check, return fail"); + return false; + } + + if (device_time == -1 || !check_certificate_validity(certificate, cert_len, device_time)) { + tr_error("Client certificate not valid!"); + return false; + } + return true; +} + +bool M2MConnectionSecurityPimpl::check_certificate_validity(const uint8_t *cert, const uint32_t cert_len, const int64_t device_time) +{ + + // Get the validFrom and validTo fields from certificate + uint64_t server_validfrom = 0; + uint64_t server_validto = 0; + if(!certificate_parse_valid_time((const char*)cert, cert_len, &server_validfrom, &server_validto)) { + tr_error("Certificate time parsing failed"); + return false; + } + + tr_debug("M2MConnectionSecurityPimpl::check_certificate_validity - valid from: %" PRIu64, server_validfrom); + tr_debug("M2MConnectionSecurityPimpl::check_certificate_validity - valid to: %" PRIu64, server_validto); + // Cast to uint32_t since all platforms does not support PRId64 macro + tr_debug("M2MConnectionSecurityPimpl::check_certificate_validity - device time: %" PRIu32, (uint32_t)device_time); + + if (device_time < (uint32_t)server_validfrom || device_time > (uint32_t)server_validto) { + tr_error("Invalid certificate validity or device time outside of certificate validity period!"); + return false; + } + + return true; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/functionpointer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/functionpointer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef FUNCTIONPOINTER_H +#define FUNCTIONPOINTER_H + +#include <string.h> +#include <stdint.h> + +/*! \file functionpointer.h +* \brief A class for storing and calling a pointer to a static or member void function. + */ + +template <typename R> +class FP0{ +public: + /** Create a function pointer, attaching a static function. + * + * \param function The void static function to attach (default is none). + */ + FP0(R (*function)(void) = 0) { + memset(_member,0,sizeof(_member)); + attach(function); + } + + /** Create a function pointer, attaching a member function. + * + * \param object The object pointer to invoke the member function on (the "this" pointer). + * \param function The address of the void member function to attach. + */ + template<typename T> + FP0(T *object, R (T::*member)(void)) { + attach(object, member); + } + + /** Attach a static function. + * + * \param function The void static function to attach (default is none). + */ + void attach(R (*function)(void)) { + _p.function = function; + _membercaller = 0; + } + + /** Attach a member function. + * + * \param object The object pointer to invoke the member function on (the "this" pointer). + * \param function The address of the void member function to attach. + */ + template<typename T> + void attach(T *object, R (T::*member)(void)) { + _p.object = static_cast<void*>(object); + *reinterpret_cast<R (T::**)(void)>(_member) = member; + _membercaller = &FP0::membercaller<T>; + } + + /** Call the attached static or member function. + */ + R call(){ + if (_membercaller == 0 && _p.function) { + return _p.function(); + } else if (_membercaller && _p.object) { + return _membercaller(_p.object, _member); + } + return (R)0; + } + + typedef R (*static_fp)(); + static_fp get_function() const { + return (R(*)())_p.function; + } + + R operator ()(void) { + return call(); + } + operator bool(void) { + void *q = &_p.function; + return (_membercaller != NULL) && _p.object != NULL && (*static_cast<void **>(q) != NULL); + } + +private: + template<typename T> + static void membercaller(void *object, uintptr_t *member) { + T* o = static_cast<T*>(object); + R (T::**m)(void) = reinterpret_cast<R (T::**)(void)>(member); + (o->**m)(); + } + + union { + R (*function)(void); // static function pointer - 0 if none attached + void *object; // object this pointer - 0 if none attached + } _p; + uintptr_t _member[2]; // aligned raw member function pointer storage - converted back by registered _membercaller + R (*_membercaller)(void*, uintptr_t*); // registered membercaller function to convert back and call _m.member on _object +}; + +/* If we had variadic templates, this wouldn't be a problem, but until C++11 is enabled, we are stuck with multiple classes... */ + +/** A class for storing and calling a pointer to a static or member void function + */ +template <typename R, typename A1> +class FP1{ +public: + /** Create a function pointer, attaching a static function. + * + * \param function The void static function to attach (default is none). + */ + FP1(R (*function)(A1) = 0) { + memset(_member,0,sizeof(_member)); + attach(function); + } + + /** Create a function pointeer, attaching a member function. + * + * \param object The object pointer to invoke the member function on (the "this" pointer). + * \param function The address of the void member function to attach. + */ + template<typename T> + FP1(T *object, R (T::*member)(A1)) { + attach(object, member); + } + + /** Attach a static function. + * + * \param function The void static function to attach (default is none). + */ + void attach(R (*function)(A1)) { + _p.function = function; + _membercaller = 0; + } + + /** Attach a member function. + * + * \param object The object pointer to invoke the member function on (the "this" pointer). + * \param function The address of the void member function to attach. + */ + template<typename T> + void attach(T *object, R (T::*member)(A1)) { + _p.object = static_cast<void*>(object); + *reinterpret_cast<R (T::**)(A1)>(_member) = member; + _membercaller = &FP1::membercaller<T>; + } + + /** Call the attached static or member function. + */ + R call(A1 a){ + if (_membercaller == 0 && _p.function) { + return _p.function(a); + } else if (_membercaller && _p.object) { + return _membercaller(_p.object, _member, a); + } + return (R)0; + } + + typedef R (*static_fp)(); + static_fp get_function() const { + return (R(*)())_p.function; + } + + R operator ()(A1 a) { + return call(a); + } + operator bool(void) + { + void *q = &_p.function; + return (_membercaller != NULL) && _p.object != NULL && (*static_cast<void **>(q) != NULL); + } +private: + template<typename T> + static void membercaller(void *object, uintptr_t *member, A1 a) { + T* o = static_cast<T*>(object); + R (T::**m)(A1) = reinterpret_cast<R (T::**)(A1)>(member); + (o->**m)(a); + } + + union { + R (*function)(A1); // static function pointer - 0 if none attached + void *object; // object this pointer - 0 if none attached + } _p; + uintptr_t _member[2]; // aligned raw member function pointer storage - converted back by registered _membercaller + R (*_membercaller)(void*, uintptr_t*, A1); // registered membercaller function to convert back and call _m.member on _object +}; + +/** A class for storing and calling a pointer to a static or member void function. + */ +template <typename R, typename A1, typename A2> +class FP2{ +public: + /** Create a function pointer, attaching a static function. + * + * \param function The void static function to attach (default is none). + */ + FP2(R (*function)(A1, A2) = 0) { + memset(_member,0,sizeof(_member)); + attach(function); + } + + /** Create a function pointer, attaching a member function. + * + * \param object The object pointer to invoke the member function on (the "this" pointer). + * \param function The address of the void member function to attach. + */ + template<typename T> + FP2(T *object, R (T::*member)(A1, A2)) { + attach(object, member); + } + + /** Attach a static function. + * + * \param function The void static function to attach (default is none). + */ + void attach(R (*function)(A1, A2)) { + _p.function = function; + _membercaller = 0; + } + + /** Attach a member function + * + * \param object The object pointer to invoke the member function on (the "this" pointer). + * \param function The address of the void member function to attach. + */ + template<typename T> + void attach(T *object, R (T::*member)(A1, A2)) { + _p.object = static_cast<void*>(object); + *reinterpret_cast<R (T::**)(A1, A2)>(_member) = member; + _membercaller = &FP2::membercaller<T>; + } + + /** Call the attached static or member function. + */ + R call(A1 a1, A2 a2){ + if (_membercaller == 0 && _p.function) { + return _p.function(a1, a2); + } else if (_membercaller && _p.object) { + return _membercaller(_p.object, _member, a1, a2); + } + return (R)0; + } + + typedef R (*static_fp)(); + static_fp get_function() const { + return (R(*)())_p.function; + } + + R operator ()(A1 a1, A2 a2) { + return call(a1, a2); + } + operator bool(void) + { + void *q = &_p.function; + return (_membercaller != NULL) && _p.object != NULL && (*static_cast<void **>(q) != NULL); + } +private: + template<typename T> + static void membercaller(void *object, uintptr_t *member, A1 a1, A2 a2) { + T* o = static_cast<T*>(object); + R (T::**m)(A1, A2) = reinterpret_cast<R (T::**)(A1, A2)>(member); + (o->**m)(a1, a2); + } + + union { + R (*function)(A1, A2); // static function pointer - 0 if none attached + void *object; // object this pointer - 0 if none attached + } _p; + uintptr_t _member[2]; // aligned raw member function pointer storage - converted back by registered _membercaller + R (*_membercaller)(void*, uintptr_t*, A1, A2); // registered membercaller function to convert back and call _m.member on _object +}; + +/** A class for storing and calling a pointer to a static or member void function. + */ +template <typename R, typename A1, typename A2, typename A3> +class FP3{ +public: + /** Create a function pointer, attaching a static function. + * + * \param function The void static function to attach (default is none). + */ + FP3(R (*function)(A1, A2, A3) = 0) { + memset(_member,0,sizeof(_member)); + attach(function); + } + + /** Create a function pointer, attaching a member function. + * + * \param object The object pointer to invoke the member function on (the "this" pointer). + * \param function The address of the void member function to attach. + */ + template<typename T> + FP3(T *object, R (T::*member)(A1, A2, A3)) { + attach(object, member); + } + + /** Attach a static function. + * + * \param function The void static function to attach (default is none). + */ + void attach(R (*function)(A1, A2, A3)) { + _p.function = function; + _membercaller = 0; + } + + /** Attach a member function. + * + * \param object The object pointer to invoke the member function on (the "this" pointer). + * \param function The address of the void member function to attach. + */ + template<typename T> + void attach(T *object, R (T::*member)(A1, A2, A3)) { + _p.object = static_cast<void*>(object); + *reinterpret_cast<R (T::**)(A1, A2, A3)>(_member) = member; + _membercaller = &FP3::membercaller<T>; + } + + /** Call the attached static or member function. + */ + R call(A1 a1, A2 a2, A3 a3){ + if (_membercaller == 0 && _p.function) { + return _p.function(a1, a2, a3); + } else if (_membercaller && _p.object) { + return _membercaller(_p.object, _member, a1, a2, a3); + } + return (R)0; + } + + typedef R (*static_fp)(); + static_fp get_function() const { + return (R(*)())_p.function; + } + + R operator ()(A1 a1, A2 a2, A3 a3) { + return call(a1, a2, a3); + } + operator bool(void) + { + void *q = &_p.function; + return (_membercaller != NULL) && _p.object != NULL && (*static_cast<void **>(q) != NULL); + } +private: + template<typename T> + static void membercaller(void *object, uintptr_t *member, A1 a1, A2 a2, A3 a3) { + T* o = static_cast<T*>(object); + R (T::**m)(A1, A2, A3) = reinterpret_cast<R (T::**)(A1, A2, A3)>(member); + (o->**m)(a1, a2, a3); + } + + union { + R (*function)(A1, A2, A3); // static function pointer - 0 if none attached + void *object; // object this pointer - 0 if none attached + } _p; + uintptr_t _member[2]; // aligned raw member function pointer storage - converted back by registered _membercaller + R (*_membercaller)(void*, uintptr_t*, A1, A2, A3); // registered membercaller function to convert back and call _m.member on _object +}; + +typedef FP0<void> FP; + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mbase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mbase.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,654 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_BASE_H +#define M2M_BASE_H + +// Support for std args +#include <stdint.h> +#include "mbed-client/m2mconfig.h" +#include "mbed-client/m2mreportobserver.h" +#include "mbed-client/functionpointer.h" +#include "mbed-client/m2mstringbuffer.h" +#include "nsdl-c/sn_nsdl.h" +#include "sn_coap_header.h" +#include "nsdl-c/sn_nsdl_lib.h" + +//FORWARD DECLARATION +struct sn_coap_hdr_; +typedef sn_coap_hdr_ sn_coap_hdr_s; +struct nsdl_s; +struct sn_nsdl_addr_; +typedef sn_nsdl_addr_ sn_nsdl_addr_s; + +typedef FP1<void, const char*> value_updated_callback; +typedef void(*value_updated_callback2) (const char* object_name); +class M2MObservationHandler; +class M2MReportHandler; + +class M2MObjectInstance; +class M2MObject; +class M2MResource; + + +/*! \file m2mbase.h + * \brief M2MBase. + * This class is the base class based on which all LWM2M object models + * can be created. This serves base class for Object, ObjectInstances and Resources. + */ +class M2MBase : public M2MReportObserver { + +public: + + /** + * Enum to define the type of object. + */ + typedef enum { + Object = 0x0, + Resource = 0x1, + ObjectInstance = 0x2, + ResourceInstance = 0x3 + } BaseType; + + /** + * Enum to define observation level. + */ + typedef enum { + None = 0x0, + R_Attribute = 0x01, + OI_Attribute = 0x02, + OIR_Attribute = 0x03, + O_Attribute = 0x04, + OR_Attribute = 0x05, + OOI_Attribute = 0x06, + OOIR_Attribute = 0x07 + } Observation; + + + /** + * \brief Enum defining a resource type. + */ + typedef enum { + Static, + Dynamic, + Directory + }Mode; + + /** + * \brief Enum defining a resource data type. + */ + typedef enum { + STRING, + INTEGER, + FLOAT, + BOOLEAN, + OPAQUE, + TIME, + OBJLINK + }DataType; + + /** + * Enum defining an operation that can be + * supported by a given resource. + */ + typedef enum { + NOT_ALLOWED = 0x00, + GET_ALLOWED = 0x01, + PUT_ALLOWED = 0x02, + GET_PUT_ALLOWED = 0x03, + POST_ALLOWED = 0x04, + GET_POST_ALLOWED = 0x05, + PUT_POST_ALLOWED = 0x06, + GET_PUT_POST_ALLOWED = 0x07, + DELETE_ALLOWED = 0x08, + GET_DELETE_ALLOWED = 0x09, + PUT_DELETE_ALLOWED = 0x0A, + GET_PUT_DELETE_ALLOWED = 0x0B, + POST_DELETE_ALLOWED = 0x0C, + GET_POST_DELETE_ALLOWED = 0x0D, + PUT_POST_DELETE_ALLOWED = 0x0E, + GET_PUT_POST_DELETE_ALLOWED = 0x0F + }Operation; + + enum MaxPathSize { + MAX_NAME_SIZE = 64, + MAX_INSTANCE_SIZE = 5, + + MAX_PATH_SIZE = ((MAX_NAME_SIZE * 2) + (MAX_INSTANCE_SIZE * 2) + 3 + 1), + MAX_PATH_SIZE_2 = ((MAX_NAME_SIZE * 2) + MAX_INSTANCE_SIZE + 2 + 1), + MAX_PATH_SIZE_3 = (MAX_NAME_SIZE + (MAX_INSTANCE_SIZE * 2) + 2 + 1), + MAX_PATH_SIZE_4 = (MAX_NAME_SIZE + MAX_INSTANCE_SIZE + 1 + 1) + }; + + typedef void(*notification_delivery_status_cb) (const M2MBase& base, + const NoticationDeliveryStatus status, + void *client_args); + + typedef struct lwm2m_parameters { + //add multiple_instances + uint32_t max_age; // todo: add flag + union { + char* name; //for backwards compatibility + uint16_t instance_id; // XXX: this is not properly aligned now, need to reorder these after the elimination is done + } identifier; + sn_nsdl_dynamic_resource_parameters_s *dynamic_resource_params; + BaseType base_type : 2; + M2MBase::DataType data_type : 3; + bool multiple_instance; + bool free_on_delete; /**< true if struct is dynamically allocated and it + and its members (name) are to be freed on destructor. + Note: the sn_nsdl_dynamic_resource_parameters_s has + its own similar, independent flag. + Note: this also serves as a read-only flag. */ + bool identifier_int_type; + } lwm2m_parameters_s; + +protected: + + // Prevents the use of default constructor. + M2MBase(); + + // Prevents the use of assignment operator. + M2MBase& operator=( const M2MBase& /*other*/ ); + + // Prevents the use of copy constructor + M2MBase( const M2MBase& /*other*/ ); + + /** + * \brief Constructor + * \param name Name of the object created. + * \param mode Type of the resource. + * \param resource_type Textual information of resource. + * \param path Path of the object like 3/0/1 + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + */ + M2MBase(const String &name, + M2MBase::Mode mode, +#ifndef DISABLE_RESOURCE_TYPE + const String &resource_type, +#endif + char *path, + bool external_blockwise_store, + bool multiple_instance, + M2MBase::DataType type = M2MBase::OBJLINK); + + M2MBase(const lwm2m_parameters_s* s); + +public: + + /** + * Destructor + */ + virtual ~M2MBase(); + + /** + * \brief Sets the operation type for an object. + * \param operation The operation to be set. + */ + void set_operation(M2MBase::Operation operation); + +#if !defined(MEMORY_OPTIMIZED_API) || defined(RESOURCE_ATTRIBUTES_LIST) + /** + * \brief Sets the interface description of the object. + * \param description The description to be set. + */ +#if !defined(DISABLE_INTERFACE_DESCRIPTION) || defined(RESOURCE_ATTRIBUTES_LIST) + void set_interface_description(const String &description); + + /** + * \brief Sets the interface description of the object. + * \param description The description to be set. + */ + void set_interface_description(const char *description); + + /** + * \brief Returns the interface description of the object. + * \return The interface description of the object. + */ + const char* interface_description() const; +#endif +#if !defined(DISABLE_RESOURCE_TYPE) || defined(RESOURCE_ATTRIBUTES_LIST) + /** + * \brief Sets the resource type of the object. + * \param resource_type The resource type to be set. + */ + virtual void set_resource_type(const String &resource_type); + + /** + * \brief Sets the resource type of the object. + * \param resource_type The resource type to be set. + */ + virtual void set_resource_type(const char *resource_type); + + /** + * \brief Returns the resource type of the object. + * \return The resource type of the object. + */ + const char* resource_type() const; +#endif +#endif + + /** + * \brief Sets the CoAP content type of the object. + * \param content_type The content type to be set based on + * CoAP specifications. + */ + void set_coap_content_type(const uint16_t content_type); + + /** + * \brief Sets the observable mode for the object. + * \param observable A value for the observation. + */ + void set_observable(bool observable); + + /** + * \brief Sets the object to be auto-observable. + * + * \note This is not a standard CoAP or LWM2M feature and it only works in mbed Cloud. + * \note This must be called before registration process, since this info must be in a registration message. + * \note Auto-observable will take higher precedence if both observable methods are set. + * + * \param auto_observable Is auto-obs feature enabled or not. + */ + void set_auto_observable(bool auto_observable); + + /** + * \brief Adds the observation level for the object. + * \param observation_level The level of observation. + */ + virtual void add_observation_level(M2MBase::Observation observation_level); + + /** + * \brief Removes the observation level for the object. + * \param observation_level The level of observation. + */ + virtual void remove_observation_level(M2MBase::Observation observation_level); + + /** + * \brief Sets the object under observation. + * \param observed The value for observation. When true, starts observing. When false, the ongoing observation is cancelled. + * \param handler A handler object for sending + * observation callbacks. + */ + void set_under_observation(bool observed, + M2MObservationHandler *handler); + /** + * \brief Returns the Observation Handler object. + * \return M2MObservationHandler object. + */ + virtual M2MObservationHandler* observation_handler() const = 0; + + /** + * \brief Sets the observation handler + * \param handler Observation handler + */ + virtual void set_observation_handler(M2MObservationHandler *handler) = 0; + + /** + * \brief Sets the instance ID of the object. + * \param instance_id The instance ID of the object. + */ + void set_instance_id(const uint16_t instance_id); + + /** + * \brief Sets the max age for the resource value to be cached. + * \param max_age The max age in seconds. + */ + void set_max_age(const uint32_t max_age); + + /** + * \brief Returns the object type. + * \return The base type of the object. + */ + M2MBase::BaseType base_type() const; + + /** + * \brief Returns the operation type of the object. + * \return The supported operation on the object. + */ + M2MBase::Operation operation() const; + + /** + * \brief Returns the object name. + * \return The name of the object. + */ + const char* name() const; + + /** + * \brief Returns the object name in integer. + * \return The name of the object in integer. + */ + int32_t name_id() const; + + /** + * \brief Returns the object's instance ID. + * \returns The instance ID of the object. + */ + uint16_t instance_id() const; + + /** + * \brief Returns the path of the object. + * \return The path of the object (eg. 3/0/1). + */ + const char* uri_path() const; + + /** + * \brief Returns the CoAP content type of the object. + * \return The CoAP content type of the object. + */ + uint16_t coap_content_type() const; + + /** + * \brief Returns the observation status of the object. + * \return True if observable, else false. + */ + bool is_observable() const; + + /** + * \brief Returns the observation level of the object. + * \return The observation level of the object. + */ + M2MBase::Observation observation_level() const; + + /** + * \brief Returns the mode of the resource. + * \return The mode of the resource. + */ + Mode mode() const; + + /** + * \brief Returns the observation number. + * \return The observation number of the object. + */ + uint16_t observation_number() const; + + /** + * \brief Returns the max age for the resource value to be cached. + * \return The maax age in seconds. + */ + uint32_t max_age() const; + + /** + * \brief Parses the received query for the notification + * attribute. + * \param query The query that needs to be parsed. + * \return True if required attributes are present, else false. + */ + virtual bool handle_observation_attribute(const char *query); + + /** + * \brief Handles GET request for the registered objects. + * \param nsdl An NSDL handler for the CoAP library. + * \param received_coap_header The received CoAP message from the server. + * \param observation_handler A handler object for sending + * observation callbacks. + * \return sn_coap_hdr_s The message that needs to be sent to server. + */ + virtual sn_coap_hdr_s* handle_get_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler = NULL); + /** + * \brief Handles PUT request for the registered objects. + * \param nsdl An NSDL handler for the CoAP library. + * \param received_coap_header The received CoAP message from the server. + * \param observation_handler A handler object for sending + * observation callbacks. + * \param execute_value_updated True executes the "value_updated" callback. + * \return sn_coap_hdr_s The message that needs to be sent to server. + */ + virtual sn_coap_hdr_s* handle_put_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated); + + /** + * \brief Handles GET request for the registered objects. + * \param nsdl An NSDL handler for the CoAP library. + * \param received_coap_header The received CoAP message from the server. + * \param observation_handler A handler object for sending + * observation callbacks. + * \param execute_value_updated True executes the "value_updated" callback. + * \return sn_coap_hdr_s The message that needs to be sent to server. + */ + virtual sn_coap_hdr_s* handle_post_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated, + sn_nsdl_addr_s *address = NULL); + + /** + * \brief Executes the function that is set in "set_notification_delivery_status_cb". + */ + void send_notification_delivery_status(const M2MBase& object, const NoticationDeliveryStatus status); + + /** + * \brief Sets whether this resource is published to server or not. + * \param register_uri True sets the resource as part of registration message. + */ + void set_register_uri(bool register_uri); + + /** + * \brief Returns whether this resource is published to server or not. + * \return True if the resource is a part of the registration message, else false. + */ + bool register_uri(); + + /** + * @brief Returns whether this resource is under observation or not. + * @return True if the resource is under observation, else false, + */ + bool is_under_observation() const; + + /** + * @brief Sets the function that is executed when this + * object receives a PUT or POST command. + * @param callback The function pointer that is called. + * @return True, if callback could be set, false otherwise. + */ + bool set_value_updated_function(value_updated_callback callback); + + /** + * @brief Sets the function that is executed when this + * object receives a PUT or POST command. + * @param callback The function pointer that is called. + * @return True, if callback could be set, false otherwise. + */ + bool set_value_updated_function(value_updated_callback2 callback); + + /** + * @brief Returns whether a callback function is set or not. + * @return True if the callback function is set, else false. + */ + bool is_value_updated_function_set() const; + + /** + * @brief Calls the function that is set in the "set_value_updated_function". + * @param name The name of the object. + */ + void execute_value_updated(const String& name); + + /** + * @brief Returns length of the object name. + * @return Length of the object name. + */ + size_t resource_name_length() const; + + /** + * @brief Returns the resource information. + * @return Resource information. + */ + sn_nsdl_dynamic_resource_parameters_s* get_nsdl_resource() const; + + /** + * @brief Returns the resource structure. + * @return Resource structure. + */ + M2MBase::lwm2m_parameters_s* get_lwm2m_parameters() const; + + /** + * @brief Returns the notification message id. + * @return Message id. + */ + uint16_t get_notification_msgid() const; + + /** + * @brief Sets the notification message id. + * This is used to map RESET and EMPTY ACK messages. + * @param msgid The message id. + */ + void set_notification_msgid(uint16_t msgid); + + /** + * @brief Sets the function that is executed when notification message state changes. + * @param callback The function pointer that is called. + * @param client_args The argument which is passed to the callback function. + */ + bool set_notification_delivery_status_cb(notification_delivery_status_cb callback, void *client_args); + + static char* create_path(const M2MObject &parent, const char *name); + static char* create_path(const M2MObject &parent, uint16_t object_instance); + static char* create_path(const M2MResource &parent, uint16_t resource_instance); + static char* create_path(const M2MResource &parent, const char *name); + static char* create_path(const M2MObjectInstance &parent, const char *name); + +protected : // from M2MReportObserver + + virtual void observation_to_be_sent(const m2m::Vector<uint16_t> &changed_instance_ids, + uint16_t obs_number, + bool send_object = false); + +protected: + + /** + * \brief Sets the base type for an object. + * \param type The base type of the object. + */ + void set_base_type(M2MBase::BaseType type); + + /** + * \brief Memory allocation required for libCoap. + * \param size The size of memory to be reserved. + */ + static void* memory_alloc(uint32_t size); + + /** + * \brief Memory free functions required for libCoap. + * \param ptr The object whose memory needs to be freed. + */ + static void memory_free(void *ptr); + + /** + * \brief Allocate and make a copy of given zero terminated string. This + * is functionally equivalent with strdup(). + * \param source The source string to copy, may not be NULL. + */ + static char* alloc_string_copy(const char* source); + + /** + * \brief Allocate (size + 1) amount of memory, copy size bytes into + * it and add zero termination. + * \param source The source string to copy, may not be NULL. + * \param size The size of memory to be reserved. + */ + static uint8_t* alloc_string_copy(const uint8_t* source, uint32_t size); + + /** + * \brief Allocate (size) amount of memory, copy size bytes into it. + * \param source The source buffer to copy, may not be NULL. + * \param size The size of memory to be reserved. + */ + static uint8_t* alloc_copy(const uint8_t* source, uint32_t size); + + // validate string length to be [min_length..max_length] + static bool validate_string_length(const String &string, size_t min_length, size_t max_length); + static bool validate_string_length(const char* string, size_t min_length, size_t max_length); + + /** + * \brief Create Report Handler object. + * \return M2MReportHandler object. + */ + M2MReportHandler* create_report_handler(); + + /** + * \brief Returns the Report Handler object. + * \return M2MReportHandler object. + */ + M2MReportHandler* report_handler() const; + + static bool build_path(StringBuffer<MAX_PATH_SIZE> &buffer, const char *s1, uint16_t i1, const char *s2, uint16_t i2); + + static bool build_path(StringBuffer<MAX_PATH_SIZE_2> &buffer, const char *s1, uint16_t i1, const char *s2); + + static bool build_path(StringBuffer<MAX_PATH_SIZE_3> &buffer, const char *s1, uint16_t i1, uint16_t i2); + + static bool build_path(StringBuffer<MAX_PATH_SIZE_4> &buffer, const char *s1, uint16_t i1); + + static char* stringdup(const char* s); + + /** + * \brief Delete the resource structures owned by this object. Note: this needs + * to be called separately from each subclass' destructor as this method uses a + * virtual method and the call needs to be done at same class which has the + * implementation of the pure virtual method. + */ + void free_resources(); + + /** + * \brief Returns notification send status. + * \return Notification status. + */ + NoticationDeliveryStatus get_notification_delivery_status() const; + + /** + * \brief Clears the notification send status to initial state. + */ + void clear_notification_delivery_status(); + + /** + * \brief Provides the observation token of the object. + * \param value[OUT] A pointer to the value of the token. + * \param value_length[OUT] The length of the token pointer. + */ + void get_observation_token(uint8_t *token, uint8_t &token_length) const; + + /** + * \brief Sets the observation token value. + * \param token A pointer to the token of the resource. + * \param length The length of the token pointer. + */ + void set_observation_token(const uint8_t *token, + const uint8_t length); + +private: + + static bool is_integer(const String &value); + + static bool is_integer(const char *value); + + static char* create_path_base(const M2MBase &parent, const char *name); + +private: + lwm2m_parameters_s *_sn_resource; + M2MReportHandler *_report_handler; // TODO: can be broken down to smaller classes with inheritance. + +friend class Test_M2MBase; +friend class Test_M2MObject; +friend class M2MNsdlInterface; +friend class M2MInterfaceFactory; +}; + +#endif // M2M_BASE_H +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mblockmessage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mblockmessage.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2MBLOCKMESSAGE_H +#define M2MBLOCKMESSAGE_H + +#include "ns_types.h" +#include "sn_coap_header.h" + +/*! \file m2mblockmessage.h + * \brief M2MBlockMessage. + * This class contains the data of an incoming block message. + */ +class M2MBlockMessage { + +public: + + /** + * \brief An enum defining different kinds of errors + * that can occur during the block-wise operation. + */ + typedef enum { + ErrorNone = 0, + EntityTooLarge + }Error; + + /** + * Constructor. + */ + M2MBlockMessage(); + + /** + * Destructor. + */ + virtual ~M2MBlockMessage(); + + /** + * \brief Store the data from a CoAP message. + * \param coap_header The message to parse. + */ + void set_message_info(sn_coap_hdr_s *coap_header); + + /** + * \brief Clear values. + */ + void clear_values(); + + /** + * \brief Check if the message is a block message. + * \param coap_header The message to check. + * \return True if block message, else false. + */ + bool is_block_message() const; + + /** + * \brief Returns the number of an incoming block. + * \return Block number, starting from 0. + */ + uint16_t block_number() const; + + /** + * \brief Returns the total size of the message. + * \return The total size in bytes. + */ + uint32_t total_message_size() const; + + /** + * \brief Check if last block. + * \return True if last block, else false. + */ + bool is_last_block() const; + + /** + * \brief Returns the payload of the message. + * \return The message payload. + */ + uint8_t* block_data() const; + + /** + * \brief Returns the length of the payload. + * \return The payload length. + */ + uint32_t block_data_len() const; + + /** + * \brief Returns an error code. + * \return Error code. + */ + Error error_code() const; + +private: + uint8_t *_block_data_ptr; + uint32_t _total_message_size; + uint16_t _block_data_len; + uint16_t _block_number; + Error _error_code; + bool _is_last_block; + bool _is_block_message; +}; + +#endif // M2MBLOCKMESSAGE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconfig.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconfig.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2MCONFIG_H +#define M2MCONFIG_H + +/*! \file m2mconfig.h +* \brief File defining all system build time configuration used by mbed-client. +*/ + +#include "mbed-client/m2mstring.h" + +#include <stddef.h> + +using namespace m2m; + +/** + * \def MBED_CLIENT_RECONNECTION_COUNT + * + * \brief Sets Reconnection count for mbed Client + * to attempt a reconnection re-tries until + * reaches the defined value either by the application + * or the default value set in Client. + * By default, the value is 3. + */ +#undef MBED_CLIENT_RECONNECTION_COUNT /* 3 */ + +/** + * \def MBED_CLIENT_RECONNECTION_INTERVAL + * + * \brief Sets Reconnection interval (in seconds) for + * mbed Client to attempt a reconnection re-tries. + * By default, the value is 5 seconds. + */ +#undef MBED_CLIENT_RECONNECTION_INTERVAL /* 5 */ + +/** + * \def MBED_CLIENT_TCP_KEEPALIVE_TIME + * + * \brief Keep alive time (in seconds) to send pings + * in case mbed Client is connected through TCP. + * By default, the value is 600 seconds. + */ +#undef MBED_CLIENT_TCP_KEEPALIVE_TIME /* 600 */ + +/** + * \def MBED_CLIENT_TCP_KEEPALIVE_INTERVAL + * + * \brief The number of seconds between TCP keep-alive probes. + * By default, the value is 75 seconds. + */ +#undef MBED_CLIENT_TCP_KEEPALIVE_INTERVAL /* 75 */ + +/** + * \def MBED_CLIENT_EVENT_LOOP_SIZE + * + * \brief Defines the size of memory allocated for + * event loop (in bytes) for timer and network event + * handling of mbed Client. + * By default, this value is 1024 bytes.This memory is + * allocated from heap + */ +#undef MBED_CLIENT_EVENT_LOOP_SIZE /* 1024 */ + +#ifdef YOTTA_CFG_RECONNECTION_COUNT +#define MBED_CLIENT_RECONNECTION_COUNT YOTTA_CFG_RECONNECTION_COUNT +#elif defined MBED_CONF_MBED_CLIENT_RECONNECTION_COUNT +#define MBED_CLIENT_RECONNECTION_COUNT MBED_CONF_MBED_CLIENT_RECONNECTION_COUNT +#endif + +#ifdef YOTTA_CFG_RECONNECTION_INTERVAL +#define MBED_CLIENT_RECONNECTION_INTERVAL YOTTA_CFG_RECONNECTION_INTERVAL +#elif defined MBED_CONF_MBED_CLIENT_RECONNECTION_INTERVAL +#define MBED_CLIENT_RECONNECTION_INTERVAL MBED_CONF_MBED_CLIENT_RECONNECTION_INTERVAL +#endif + +#ifdef YOTTA_CFG_TCP_KEEPALIVE_TIME +#define MBED_CLIENT_TCP_KEEPALIVE_TIME YOTTA_CFG_TCP_KEEPALIVE_TIME +#elif defined MBED_CONF_MBED_CLIENT_TCP_KEEPALIVE_TIME +#define MBED_CLIENT_TCP_KEEPALIVE_TIME MBED_CONF_MBED_CLIENT_TCP_KEEPALIVE_TIME +#endif + +#ifdef YOTTA_CFG_TCP_KEEPALIVE_INTERVAL +#define MBED_CLIENT_TCP_KEEPALIVE_INTERVAL YOTTA_CFG_TCP_KEEPALIVE_INTERVAL +#elif defined MBED_CONF_MBED_CLIENT_TCP_KEEPALIVE_INTERVAL +#define MBED_CLIENT_TCP_KEEPALIVE_INTERVAL MBED_CONF_MBED_CLIENT_TCP_KEEPALIVE_INTERVAL +#endif + +#ifdef YOTTA_CFG_DISABLE_BOOTSTRAP_FEATURE +#define MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE YOTTA_CFG_DISABLE_BOOTSTRAP_FEATURE +#elif defined MBED_CONF_MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +#define MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE MBED_CONF_MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +#endif + +#ifdef YOTTA_CFG_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE +#define SN_COAP_MAX_INCOMING_MESSAGE_SIZE YOTTA_CFG_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE +#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_MAX_INCOMING_MESSAGE_SIZE +#define SN_COAP_MAX_INCOMING_MESSAGE_SIZE MBED_CONF_MBED_CLIENT_SN_COAP_MAX_INCOMING_MESSAGE_SIZE +#endif + +#ifdef MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE +#define MBED_CLIENT_EVENT_LOOP_SIZE MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE +#endif + +#ifdef YOTTA_CFG_DISABLE_INTERFACE_DESCRIPTION +#define DISABLE_INTERFACE_DESCRIPTION YOTTA_CFG_DISABLE_INTERFACE_DESCRIPTION +#elif defined MBED_CONF_MBED_CLIENT_DISABLE_INTERFACE_DESCRIPTION +#define DISABLE_INTERFACE_DESCRIPTION MBED_CONF_MBED_CLIENT_DISABLE_INTERFACE_DESCRIPTION +#endif + +#ifdef YOTTA_CFG_DISABLE_RESOURCE_TYPE +#define DISABLE_RESOURCE_TYPE YOTTA_CFG_DISABLE_RESOURCE_TYPE +#elif defined MBED_CONF_MBED_CLIENT_DISABLE_RESOURCE_TYPE +#define DISABLE_RESOURCE_TYPE MBED_CONF_MBED_CLIENT_DISABLE_RESOURCE_TYPE +#endif + +#ifdef YOTTA_CFG_DISABLE_DELAYED_RESPONSE +#define DISABLE_DELAYED_RESPONSE YOTTA_CFG_DISABLE_DELAYED_RESPONSE +#elif defined MBED_CONF_MBED_CLIENT_DISABLE_DELAYED_RESPONSE +#define DISABLE_DELAYED_RESPONSE MBED_CONF_MBED_CLIENT_DISABLE_DELAYED_RESPONSE +#endif + +#ifdef YOTTA_CFG_DISABLE_BLOCK_MESSAGE +#define DISABLE_BLOCK_MESSAGE YOTTA_CFG_DISABLE_BLOCK_MESSAGE +#elif defined MBED_CONF_MBED_CLIENT_DISABLE_BLOCK_MESSAGE +#define DISABLE_BLOCK_MESSAGE MBED_CONF_MBED_CLIENT_DISABLE_BLOCK_MESSAGE +#endif + +#ifdef MBED_CONF_MBED_CLIENT_DTLS_PEER_MAX_TIMEOUT +#define MBED_CLIENT_DTLS_PEER_MAX_TIMEOUT MBED_CONF_MBED_CLIENT_DTLS_PEER_MAX_TIMEOUT +#endif + + +#if defined (__ICCARM__) +#define m2m_deprecated +#else +#define m2m_deprecated __attribute__ ((deprecated)) +#endif + +// This is valid for mbed-client-mbedtls +// For other SSL implementation there +// can be other + +/* +*\brief A callback function for a random number +* required by the mbed-client-mbedtls module. +*/ +typedef uint32_t (*random_number_cb)(void) ; + +/* +*\brief An entropy structure for an mbedtls entropy source. +* \param entropy_source_ptr The entropy function. +* \param p_source The function data. +* \param threshold A minimum required from the source before entropy is released +* (with mbedtls_entropy_func()) (in bytes). +* \param strong MBEDTLS_ENTROPY_SOURCE_STRONG = 1 or +* MBEDTSL_ENTROPY_SOURCE_WEAK = 0. +* At least one strong source needs to be added. +* Weaker sources (such as the cycle counter) can be used as +* a complement. +*/ +typedef struct mbedtls_entropy { + int (*entropy_source_ptr)(void *, unsigned char *,size_t , size_t *); + void *p_source; + size_t threshold; + int strong; +}entropy_cb; + +#ifdef MBED_CLIENT_USER_CONFIG_FILE +#include MBED_CLIENT_USER_CONFIG_FILE +#endif + +#ifndef MBED_CLIENT_RECONNECTION_COUNT +#define MBED_CLIENT_RECONNECTION_COUNT 3 +#endif + +#ifndef MBED_CLIENT_RECONNECTION_INTERVAL +#define MBED_CLIENT_RECONNECTION_INTERVAL 5 +#endif + +#ifndef MBED_CLIENT_TCP_KEEPALIVE_TIME +#define MBED_CLIENT_TCP_KEEPALIVE_TIME 600 +#endif + +#ifndef MBED_CLIENT_TCP_KEEPALIVE_INTERVAL +#define MBED_CLIENT_TCP_KEEPALIVE_INTERVAL 75 +#endif + +#ifndef MBED_CLIENT_EVENT_LOOP_SIZE +#define MBED_CLIENT_EVENT_LOOP_SIZE 1024 +#endif + +#ifndef SN_COAP_MAX_INCOMING_MESSAGE_SIZE +#define SN_COAP_MAX_INCOMING_MESSAGE_SIZE UINT16_MAX +#endif + +#ifndef MBED_CLIENT_DTLS_PEER_MAX_TIMEOUT +#define MBED_CLIENT_DTLS_PEER_MAX_TIMEOUT 80000 +#endif + +#endif // M2MCONFIG_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconnectionhandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconnectionhandler.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_CONNECTION_HANDLER_H__ +#define M2M_CONNECTION_HANDLER_H__ + +#include "mbed-client/m2mconnectionobserver.h" +#include "mbed-client/m2mconfig.h" +#include "mbed-client/m2minterface.h" +#include "nsdl-c/sn_nsdl.h" + +class M2MConnectionSecurity; +class M2MConnectionHandlerPimpl; + +/*! \file m2mconnectionhandler.h + * \brief M2MConnectionHandler. + * This class handles the socket connection for the LWM2M Client. + */ + +class M2MConnectionHandler { +public: + + /** + * @enum ConnectionError + * This enum defines an error that can come from the + * socket read and write operation. + */ + typedef enum { + CONNECTION_ERROR_WANTS_READ = -1000, + CONNECTION_ERROR_WANTS_WRITE = -1001, + SSL_PEER_CLOSE_NOTIFY = -1002, + ERROR_NONE = 0, + SSL_CONNECTION_ERROR, + SOCKET_READ_ERROR, + SOCKET_SEND_ERROR, + SOCKET_ABORT, + DNS_RESOLVING_ERROR, + SSL_HANDSHAKE_ERROR, + SSL_PEER_CLOSED + }ConnectionError; + + +public: + + /** + * \brief Constructor + */ + M2MConnectionHandler(M2MConnectionObserver &observer, + M2MConnectionSecurity* sec, + M2MInterface::BindingMode mode, + M2MInterface::NetworkStack stack); + + /** + * \brief Destructor + */ + ~M2MConnectionHandler(); + + /** + * \brief This binds the socket connection. + * \param listen_port The port to be listened to for an incoming connection. + * \return True if successful, else false. + */ + bool bind_connection(const uint16_t listen_port); + + /** + * \brief This resolves the server address. The output is + * returned through a callback. + * \param String The server address. + * \param uint16_t The server port. + * \param ServerType The server type to be resolved. + * \param security The M2MSecurity object that determines which + * type of secure connection is used by the socket. + * \return True if the address is valid, else false. + */ + bool resolve_server_address(const String& server_address, + const uint16_t server_port, + M2MConnectionObserver::ServerType server_type, + const M2MSecurity* security); + + /** + * \brief Sends data to the connected server. + * \param data_ptr The data to be sent. + * \param data_len The length of data to be sent. + * \param address_ptr The address structure to which the data needs to be sent. + * \return True if data is sent successfully, else false. + */ + bool send_data(uint8_t *data_ptr, + uint16_t data_len, + sn_nsdl_addr_s *address_ptr); + + /** + * \brief Listens to the incoming data from a remote server. + * \return True if successful, else false. + */ + bool start_listening_for_data(); + + /** + * \brief Stops listening to the incoming data. + */ + void stop_listening(); + + /** + * \brief Closes the open connection. + */ + void close_connection(); + + /** + * \brief Error handling for DTLS connectivity. + * \param error An error code from the TLS library. + */ + void handle_connection_error(int error); + + /** + * \brief Sets the network interface handler that is used by the client to connect + * to a network over IP. + * \param handler A network interface handler that is used by the client to connect. + * This API is optional but it provides a mechanism for different platforms to + * manage the usage of underlying network interface by client. + */ + void set_platform_network_handler(void *handler = NULL); + + /** + * \brief Claims mutex to prevent thread clashes + * in multithreaded environment. + */ + void claim_mutex(); + + /** + * \brief Releases mutex to prevent thread clashes + * in multithreaded environment. + */ + void release_mutex(); + +private: + + M2MConnectionObserver &_observer; + M2MConnectionHandlerPimpl *_private_impl; + +friend class Test_M2MConnectionHandler; +friend class Test_M2MConnectionHandler_mbed; +friend class Test_M2MConnectionHandler_linux; +friend class M2MConnection_TestObserver; +}; + +#endif //M2M_CONNECTION_HANDLER_H__ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconnectionobserver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconnectionobserver.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_CONNECTION_OBSERVER_H__ +#define M2M_CONNECTION_OBSERVER_H__ + +#include "mbed-client/m2minterface.h" + +/*! \file m2mconnectionobserver.h + * \brief M2MConnectionObserver. + * The observer class for passing the socket activity to the state machine. + */ + +class M2MConnectionObserver +{ + +public : + + /** + * \enum ServerType, Defines the type of the + * server that the client wants to use. + */ + typedef enum { + Bootstrap, + LWM2MServer + }ServerType; + + /** + * \brief The M2MSocketAddress struct. + * A unified container for holding socket address data + * across different platforms. + */ + struct SocketAddress{ + M2MInterface::NetworkStack _stack; + void *_address; + uint8_t _length; + uint16_t _port; + }; + + /** + * \brief Indicates that data is available from socket. + * \param data The data read from the socket. + * \param data_size The length of the data read from the socket. + * \param address The address of the server where the data is coming from. + */ + virtual void data_available(uint8_t* data, + uint16_t data_size, + const M2MConnectionObserver::SocketAddress &address) = 0; + + /** + * \brief Indicates an error occured in socket. + * \param error_code The error code from socket, it cannot be used any further. + * \param retry Indicates whether to re-establish the connection. + */ + virtual void socket_error(uint8_t error_code, bool retry = true) = 0; + + /** + * \brief Indicates that the server address resolving is ready. + * \param address The resolved socket address. + * \param server_type The type of the server. + * \param server_port The port of the resolved server address. + */ + virtual void address_ready(const M2MConnectionObserver::SocketAddress &address, + M2MConnectionObserver::ServerType server_type, + const uint16_t server_port) = 0; + + /** + * \brief Indicates that data has been sent successfully. + */ + virtual void data_sent() = 0; +}; + +#endif // M2M_CONNECTION_OBSERVER_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconnectionsecurity.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconnectionsecurity.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __M2M_CONNECTION_SECURITY_H__ +#define __M2M_CONNECTION_SECURITY_H__ + +#include "mbed-client/m2mconfig.h" + +#include <stdint.h> + +class M2MConnectionHandler; +class M2MSecurity; +class M2MConnectionSecurityPimpl; +class M2MConnectionHandler; + +/*! \file m2mconnectionsecurity.h + * \brief M2MConnectionSecurity. + * This class provides a method to create a secure socket connection + * to handle connectivity for the mbed Client. It handles sending, receiving + * and establishing a secure connection for mbed Client on top of the + * normal socket connection. + */ + +class M2MConnectionSecurity { +public: + typedef enum { + NO_SECURITY = 0, + TLS, + DTLS + } SecurityMode; + +private: + // Prevents the use of assignment operator by accident. + M2MConnectionSecurity& operator=( const M2MConnectionSecurity& /*other*/ ); + // Prevents the use of copy constructor by accident. + M2MConnectionSecurity( const M2MConnectionSecurity& /*other*/ ); + +public: + /** + * \brief Default Constructor. + */ + M2MConnectionSecurity(SecurityMode mode); + + /** + * \brief Default Destructor. + */ + ~M2MConnectionSecurity(); + + /** + * \brief Resets the socket connection states. + */ + void reset(); + + /** + * \brief Initiatlizes the socket connection states. + */ + int init(const M2MSecurity *security, uint16_t security_instance_id); + + /** + * \brief Starts the connection in non-blocking mode. + * \param connHandler The ConnectionHandler object that maintains the socket. + * \return Returns the state of the connection. Successful or not. + */ + int start_connecting_non_blocking(M2MConnectionHandler* connHandler); + + /** + * \brief Continues connectivity logic for a secure connection. + * \return Returns an error code if any while continuing the connection sequence. + */ + int continue_connecting(); + + /** + * \brief Connects the client to the server. + * \param connHandler The ConnectionHandler object that maintains the socket. + * \return Returns the state of the connection. Successful or not. + */ + int connect(M2MConnectionHandler* connHandler); + + /** + * \brief Sends data to the server. + * \param message The data to be sent. + * \param len The length of the data. + * \return Indicates whether the data is sent successfully or not. + */ + int send_message(unsigned char *message, int len); + + /** + * \brief Reads the data received from the server. + * \param message The data to be read. + * \param len The length of the data. + * \return Indicates whether the data is read successfully or not. + */ + int read(unsigned char* buffer, uint16_t len); + + /** + * \brief Sets the function callback that is called by mbed Client to + * fetch a random number from an application to ensure strong entropy. + * \param random_callback A function pointer that is called by mbed Client + * while performing a secure handshake. + * The function signature should be uint32_t (*random_number_callback)(void); + */ + void set_random_number_callback(random_number_cb callback); + + /** + * \brief Sets the function callback that is called by mbed Client to + * provide an entropy source from an application to ensure strong entropy. + * \param entropy_callback A function pointer that is called by mbed-client + * while performing a secure handshake. + * Function signature, if using mbed-client-mbedtls, should be + * int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, + * size_t len, size_t *olen); + */ + void set_entropy_callback(entropy_cb callback); + + /** + * \brief Set socket information for this secure connection. + * \param socket Socket used with this TLS session. + * \param address Pointer to the address of the server. + * \return Indicates whether the data is read successfully or not. + */ + void set_socket(void *socket, void *address); + +private: + + M2MConnectionSecurityPimpl* _private_impl; + + friend class Test_M2MConnectionSecurity; + //friend class Test_M2MConnectionSecurityImpl; +}; + +#endif //__M2M_CONNECTION_SECURITY_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconstants.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mconstants.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2MCONSTANTS_H +#define M2MCONSTANTS_H + +/*! \file m2mconstants.h +* \brief File defining all the constants used across mbed-client. +*/ + +#include <stdint.h> +#include "m2mconfig.h" + +const int MAX_VALUE_LENGTH = 256; +const int BUFFER_LENGTH = 1152; + +const uint8_t MINIMUM_REGISTRATION_TIME = 60; //in seconds +const uint8_t ONE_SECOND_TIMER = 1; +const uint8_t MAX_ALLOWED_STRING_LENGTH = 64; +const uint8_t MAX_ALLOWED_ERROR_STRING_LENGTH = 64; +const uint16_t OPTIMUM_LIFETIME = 3600; +const uint16_t REDUCE_LIFETIME = 900; +const float REDUCTION_FACTOR = 0.75f; + +// XXX: +// <name></><inst-id></><res-name> +//#define MAX_OBJECT_INSTANCE_NAME (255 + 1 + 5 + 1 + 255 + 1 + 5) +// <name></><inst-id></><inst-id><zero-terminator> +#define MAX_OBJECT_PATH_NAME (255 + 1 + 5 + 1 + 5 + 1) + +// values per: draft-ietf-core-observe-16 +// OMA LWM2M CR ref. +#define START_OBSERVATION 0 +#define STOP_OBSERVATION 1 + +#define COAP "coap://" +#define COAPS "coaps://" +#define BOOTSTRAP_URI "bs" +// PUT attributes to be checked from server +#define EQUAL "=" +#define AMP "&" +#define PMIN "pmin" +#define PMAX "pmax" +#define GT "gt" +#define LT "lt" +#define ST_SIZE "st" +#define STP "stp" +#define CANCEL "cancel" + +// just a helper for "String default_value = "";" pattern +extern const String EMPTY; + +//LWM2MOBJECT NAME/ID +#define M2M_SECURITY_ID "0" +#define M2M_SERVER_ID "1" +#define M2M_ACCESS_CONTROL_ID "2" +#define M2M_DEVICE_ID "3" +#define M2M_CONNECTIVITY_MONITOR_ID "4" +#define M2M_FIRMWARE_ID "5" +#define M2M_LOCATION_ID "6" +#define M2M_CONNECTIVITY_STATISTICS_ID "7" +#define RESERVED_ID "8" + +//OMA RESOURCE TYPE +#define OMA_RESOURCE_TYPE "" //oma.lwm2m + +//DEVICE RESOURCES +#define DEVICE_MANUFACTURER "0" +#define DEVICE_DEVICE_TYPE "17" +#define DEVICE_MODEL_NUMBER "1" +#define DEVICE_SERIAL_NUMBER "2" +#define DEVICE_HARDWARE_VERSION "18" +#define DEVICE_FIRMWARE_VERSION "3" +#define DEVICE_SOFTWARE_VERSION "19" +#define DEVICE_REBOOT "4" +#define DEVICE_FACTORY_RESET "5" +#define DEVICE_AVAILABLE_POWER_SOURCES "6" +#define DEVICE_POWER_SOURCE_VOLTAGE "7" +#define DEVICE_POWER_SOURCE_CURRENT "8" +#define DEVICE_BATTERY_LEVEL "9" +#define DEVICE_BATTERY_STATUS "20" +#define DEVICE_MEMORY_FREE "10" +#define DEVICE_MEMORY_TOTAL "21" +#define DEVICE_ERROR_CODE "11" +#define DEVICE_RESET_ERROR_CODE "12" +#define DEVICE_CURRENT_TIME "13" +#define DEVICE_UTC_OFFSET "14" +#define DEVICE_TIMEZONE "15" +#define DEVICE_SUPPORTED_BINDING_MODE "16" +#define BINDING_MODE_UDP "U" +#define BINDING_MODE_UDP_QUEUE "UQ" +#define BINDING_MODE_SMS "S" +#define BINDING_MODE_SMS_QUEUE "SQ" +#define ERROR_CODE_VALUE "0" + +//SECURITY RESOURCES +#define SECURITY_M2M_SERVER_URI "0" +#define SECURITY_BOOTSTRAP_SERVER "1" +#define SECURITY_SECURITY_MODE "2" +#define SECURITY_PUBLIC_KEY "3" +#define SECURITY_SERVER_PUBLIC_KEY "4" +#define SECURITY_SECRET_KEY "5" +#define SECURITY_SMS_SECURITY_MODE "6" +#define SECURITY_SMS_BINDING_KEY "7" +#define SECURITY_SMS_BINDING_SECRET_KEY "8" +#define SECURITY_M2M_SERVER_SMS_NUMBER "9" +#define SECURITY_SHORT_SERVER_ID "10" +#define SECURITY_CLIENT_HOLD_OFF_TIME "11" + +//SERVER RESOURCES +#define SERVER_PATH_PREFIX "1/0/" +#define SERVER_SHORT_SERVER_ID "0" +#define SERVER_LIFETIME "1" +#define SERVER_DEFAULT_MIN_PERIOD "2" +#define SERVER_DEFAULT_MAX_PERIOD "3" +#define SERVER_DISABLE "4" +#define SERVER_DISABLE_TIMEOUT "5" +#define SERVER_NOTIFICATION_STORAGE "6" +#define SERVER_BINDING "7" +#define SERVER_REGISTRATION_UPDATE "8" +#define SERVER_LIFETIME_PATH SERVER_PATH_PREFIX SERVER_LIFETIME + +//FIRMWARE RESOURCES +#define FIRMWARE_PATH_PREFIX "5/0/" +#define FIRMWARE_PACKAGE "0" +#define FIRMWARE_PACKAGE_URI "1" +#define FIRMWARE_UPDATE "2" +#define FIRMWARE_STATE "3" +#define FIRMWARE_UPDATE_SUPPORTED_OBJECTS "4" +#define FIRMWARE_UPDATE_RESULT "5" +#define FIRMWARE_PACKAGE_NAME "6" +#define FIRMWARE_PACKAGE_VERSION "7" +#define FIRMAWARE_PACKAGE_URI_PATH FIRMWARE_PATH_PREFIX FIRMWARE_PACKAGE_URI + +// Error Strings + +#define ERROR_REASON_1 "No security object found for Bootstrap" +#define ERROR_REASON_2 "Bootstrap not allowed for now, try later" +#define ERROR_REASON_3 "Bootstrap feature is disabled" +#define ERROR_REASON_4 "No security object found for Registration" +#define ERROR_REASON_5 "Registration not allowed for now, try later" +#define ERROR_REASON_6 "Unregistration not allowed for now, try later" +#define ERROR_REASON_7 "Client is not connected, cannot send data now" +#define ERROR_REASON_8 "LWM2M server rejected client registration" +#define ERROR_REASON_9 "Client in reconnection mode %s" +#define ERROR_REASON_10 "Client cannot connect anymore %s" +#define ERROR_REASON_11 "Bootstrap server URL is not correctly formed" +#define ERROR_REASON_12 "Bootstrap resource is not correctly formed" +#define ERROR_REASON_13 "LWM2M server URL is not correctly formed" +#define ERROR_REASON_14 "LWM2M server address is not set correctly in client" +#define ERROR_REASON_15 "Failed to do full registration because of missing parameters in registration" +#define ERROR_REASON_16 "Cannot unregister as client is not registered" +#define ERROR_REASON_17 "Incoming CoAP message parsing failed" +#define ERROR_REASON_18 "Sending reg-update failed as lifetime is less than 60 sec" +#define ERROR_REASON_19 "LWM2M server URL is not correctly formed" +#define ERROR_REASON_20 "BS PUT fails :%s" +#define ERROR_REASON_21 "BS DEL fails :%s" +#define ERROR_REASON_22 "BS FIN fails :%s" +#define ERROR_REASON_23 "Bootstrap SecureConnection failed" +#define ERROR_REASON_24 "LWM2M server rejected client unregistration (not-found)" +#define ERROR_REASON_25 "Failed to allocate registration message" + +#define COAP_ERROR_REASON_1 "bad-request" +#define COAP_ERROR_REASON_2 "bad-option" +#define COAP_ERROR_REASON_3 "request-entity-incomplete" +#define COAP_ERROR_REASON_4 "precondition-failed" +#define COAP_ERROR_REASON_5 "request-entity-too-large" +#define COAP_ERROR_REASON_6 "unsupported-content-format" +#define COAP_ERROR_REASON_7 "response-unauthorized" +#define COAP_ERROR_REASON_8 "response-forbidden" +#define COAP_ERROR_REASON_9 "not-acceptable" +#define COAP_ERROR_REASON_10 "not-found" +#define COAP_ERROR_REASON_11 "method-not-allowed" +#define COAP_ERROR_REASON_12 "message-sending-failed" +#define COAP_ERROR_REASON_13 "service-unavailable" +#define COAP_ERROR_REASON_14 "internal-server-error" +#define COAP_ERROR_REASON_15 "bad-gateway" +#define COAP_ERROR_REASON_16 "gateway-timeout" +#define COAP_ERROR_REASON_17 "proxying-not-supported" +#define COAP_NO_ERROR "no-error" + +#define ERROR_SECURE_CONNECTION "SecureConnectionFailed" +#define ERROR_DNS "DnsResolvingFailed" +#define ERROR_NETWORK "NetworkError" +#define ERROR_NO "No error" + +#define MAX_RECONNECT_TIMEOUT 604800 +#define RECONNECT_INCREMENT_FACTOR 2 + +#define AUTO_OBS_TOKEN_MIN 1 +#define AUTO_OBS_TOKEN_MAX 1023 + +// TLV serializer / deserializer +const uint8_t TYPE_RESOURCE = 0xC0; +const uint8_t TYPE_MULTIPLE_RESOURCE = 0x80; +const uint8_t TYPE_RESOURCE_INSTANCE = 0x40; +const uint8_t TYPE_OBJECT_INSTANCE = 0x0; + +const uint8_t ID8 = 0x0; +const uint8_t ID16 = 0x20; + +const uint8_t LENGTH8 = 0x08; +const uint8_t LENGTH16 = 0x10; +const uint8_t LENGTH24 = 0x18; + +const uint8_t COAP_CONTENT_OMA_PLAIN_TEXT_TYPE = 0; +const uint8_t COAP_CONTENT_OMA_TLV_TYPE_OLD = 99; +const uint16_t COAP_CONTENT_OMA_TLV_TYPE = 11542; +const uint16_t COAP_CONTENT_OMA_JSON_TYPE = 11543; +const uint8_t COAP_CONTENT_OMA_OPAQUE_TYPE = 42; + +const uint16_t MAX_UNINT_16_COUNT = 65535; + +#endif // M2MCONSTANTS_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mdevice.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mdevice.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_DEVICE_H +#define M2M_DEVICE_H + +#include "mbed-client/m2mobject.h" + +// FORWARD DECLARATION +class M2MResource; +class M2MResourceInstance; + +/*! \file m2mdevice.h + * \brief M2MDevice. + * This class represents the Device Object model of the LWM2M framework. + * It provides an interface for handling the device object + * and all its corresponding resources. There can be only one instance + * of a Device Object. + */ +class M2MDevice : public M2MObject { + +friend class M2MInterfaceFactory; + +public: + + /** + * \brief An enum defining all the resources associated with the + * Device Object in the LWM2M framework. + */ + typedef enum { + Manufacturer, + DeviceType, + ModelNumber, + SerialNumber, + HardwareVersion, + FirmwareVersion, + SoftwareVersion, + Reboot, + FactoryReset, + AvailablePowerSources, + PowerSourceVoltage, + PowerSourceCurrent, + BatteryLevel, + BatteryStatus, + MemoryFree, + MemoryTotal, + ErrorCode, + ResetErrorCode, + CurrentTime, + UTCOffset, + Timezone, + SupportedBindingMode + }DeviceResource; + +private: + + /** + * Constructor + */ + M2MDevice(char *path); + + // Prevents the use of assignment operator. + M2MDevice& operator=( const M2MDevice& /*other*/ ); + + // Prevents the use of copy constructor + M2MDevice( const M2MDevice& /*other*/ ); + + /** + * Destructor + */ + virtual ~M2MDevice(); + + static M2MDevice* get_instance(); + +public: + + /** + * \brief Deletes an M2MDevice instance. + */ + static void delete_instance(); + + /** + * \brief Creates a new resource for the given resource enum. + * \param resource With this function, the following resources can be created: + * 'Manufacturer', 'DeviceType','ModelNumber','SerialNumber', + * 'HardwareVersion', 'FirmwareVersion', 'SoftwareVersion', + * 'UTCOffset', 'Timezone', 'SupportedBindingMode'. + * \param value The value to be set on the resource, in string format. + * \return M2MResource if created successfully, else NULL. + */ + M2MResource* create_resource(DeviceResource resource, const String &value); + + /** + * \brief Creates a new resource for given resource enum. + * \param resource With this function, the following resources can be created: + * 'AvailablePowerSources','PowerSourceVoltage','PowerSourceCurrent', + * 'BatteryLevel', 'BatteryStatus', 'MemoryFree', 'MemoryTotal', + * 'ErrorCode', 'CurrentTime'. For 'CurrentTime', pass the time value in EPOCH format, for example + * 1438944683. + * \param value The value to be set on the resource, in integer format. + * \return M2MResource if created successfully, else NULL. + */ + M2MResource* create_resource(DeviceResource resource, int64_t value); + + /** + * \brief Creates a new resource instance for given resource enum. + * \param resource With this function, the following resources can be created: + * 'AvailablePowerSources','PowerSourceVoltage','PowerSourceCurrent', + * 'ErrorCode'. + * \param value The value to be set on the resource, in integer format. + * \return M2MResourceInstance if created successfully, else NULL. + */ + M2MResourceInstance* create_resource_instance(DeviceResource resource, int64_t value, + uint16_t instance_id); + + /** + * \brief Creates a new resource for given resource name. + * \param resource With this function, the following resources can be created: + * 'ResetErrorCode','FactoryReset'. + * \return M2MResource if created successfully, else NULL. + */ + M2MResource* create_resource(DeviceResource resource); + + /** + * \brief Deletes the resource with the given resource enum. + * Mandatory resources cannot be deleted. + * \param resource The name of the resource to be deleted. + * \return True if deleted, else false. + */ + bool delete_resource(DeviceResource resource); + + /** + * \brief Deletes the resource with the given resource enum. + * Mandatory resources cannot be deleted. + * \param resource The name of the resource to be deleted. + * \param instance_id The instance ID of the resource. + * \return True if deleted, else false. + */ + bool delete_resource_instance(DeviceResource resource, + uint16_t instance_id); + + /** + * \brief Sets the value of the given resource enum. + * \param resource With this function, a value can be set for the following resources: + * 'Manufacturer', 'DeviceType','ModelNumber','SerialNumber', + * 'HardwareVersion', 'FirmwareVersion', 'SoftwareVersion', + * 'UTCOffset', 'Timezone', 'SupportedBindingMode'. + * \param value The value to be set on the resource, in string format. + * \param instance_id The instance ID of the resource, default is 0. + * \return True if successfully set, else false. + */ + bool set_resource_value(DeviceResource resource, + const String &value, + uint16_t instance_id = 0); + + /** + * \brief Sets the value of the given resource enum. + * \param resource With this function, a value can be set for the following resources: + * 'AvailablePowerSources','PowerSourceVoltage','PowerSourceCurrent', + * 'BatteryLevel', 'BatteryStatus', 'MemoryFree', 'MemoryTotal', + * 'ErrorCode', 'CurrentTime'. + * \param value The value to be set on the resource, in integer format. + * \param instance_id The instance ID of the resource, default is 0. + * \return True if successfully set, else false. + */ + bool set_resource_value(DeviceResource resource, + int64_t value, + uint16_t instance_id = 0); + + /** + * \brief Returns the value of the given resource enum, in string format. + * \param resource With this function, the following resources can return a value: + * 'Manufacturer', 'DeviceType','ModelNumber','SerialNumber', + * 'HardwareVersion', 'FirmwareVersion', 'SoftwareVersion', + * 'UTCOffset', 'Timezone', 'SupportedBindingMode'. + * \param instance_id The instance ID of the resource, default is 0. + * \return The value associated with that resource. If the resource is not valid NULL is returned. + */ + String resource_value_string(DeviceResource resource, + uint16_t instance_id = 0) const; + + /** + * \brief Returns the value of the given resource key name, in integer format. + * \param resource With this function, the following resources can return a value: + * 'AvailablePowerSources','PowerSourceVoltage','PowerSourceCurrent', + * 'BatteryLevel', 'BatteryStatus', 'MemoryFree', 'MemoryTotal', + * 'ErrorCode', 'CurrentTime'. + * \param instance_id The instance ID of the resource, default is 0 + * \return The value associated with that resource. If the resource is not valid -1 is returned. + */ + int64_t resource_value_int(DeviceResource resource, + uint16_t instance_id = 0) const; + + /** + * \brief Indicates whether the resource instance with the given resource enum exists or not. + * \param resource The resource enum. + * \return True if at least one instance exists, else false. + */ + bool is_resource_present(DeviceResource resource)const; + + /** + * \brief Returns the number of resources for the whole device object. + * \return Total number of resources belonging to the device object. + */ + uint16_t total_resource_count()const; + + /** + * \brief Returns the number of resources for a given resource enum. + * \param resource The resource enum. + * \return The number of resources for a given resource enum. Returns 1 for the + * mandatory resources. Can be 0 as well if no instances exist for an + * optional resource. + */ + uint16_t per_resource_count(DeviceResource resource)const; + +private: + + M2MResourceBase* get_resource_instance(DeviceResource dev_res, + uint16_t instance_id) const; + + static const char* resource_name(DeviceResource resource); + + static bool check_value_range(DeviceResource resource, const int64_t value); + +private : + + M2MObjectInstance* _device_instance; //Not owned + +protected: + + static M2MDevice* _instance; + + friend class Test_M2MDevice; + friend class Test_M2MInterfaceFactory; +}; + +#endif // M2M_DEVICE_H +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mfirmware.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mfirmware.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2MFIRMWARE_H +#define M2MFIRMWARE_H + +#include "mbed-client/m2mobject.h" + +// FORWARD DECLARATION +class M2MResource; +class M2MResourceInstance; + +/*! \file m2mfirmware.h + * \brief M2MFirmware. + * This class represents the Firmware Object model of the LWM2M framework. + * It provides an interface for handling the Firmware Object + * and all its corresponding resources. There can be only one instance + * of a Firmware Object. + */ +class M2MFirmware : public M2MObject { + +friend class M2MInterfaceFactory; + +public: + + /** + * \brief An enum defining all the resources associated with a + * Firmware Object in the LWM2M framework. + */ + typedef enum { + Package, + PackageUri, + Update, + State, + UpdateSupportedObjects, + UpdateResult, + PackageName, + PackageVersion + } FirmwareResource; + + /** + * \brief An enum defining the state of the firmware update. + */ + typedef enum { + Idle = 0, + Downloading, + Downloaded, + Updating + } UpdateState; + + /** + * \brief An enum defining the result of the firmware update. + */ + typedef enum { + Default = 0, + SuccessfullyUpdated, + NotEnoughSpace, + OutOfMemory, + ConnectionLost, + CRCCheckFailure, + UnsupportedPackageType, + InvalidURI + } ResultOfUpdate; + +private: + + /** + * Constructor + */ + M2MFirmware(); + + // Prevents the use of assignment operator. + M2MFirmware& operator=( const M2MFirmware& /*other*/ ); + + // Prevents the use of copy constructor. + M2MFirmware( const M2MFirmware& /*other*/ ); + + /** + * Destructor + */ + virtual ~M2MFirmware(); + + static M2MFirmware* get_instance(); + +public: + + /** + * \brief Deletes a M2MFirmware instance. + */ + static void delete_instance(); + + /** + * \brief Creates a new resource for a given resource enum. + * \param resource With this function, the following resources can be created: + * 'PackageUri', 'PackageName','PackageVersion'. + * \param value The value to be set on the resource, in string format. + * \return M2MResource if created successfully, else NULL. + */ + M2MResource* create_resource(FirmwareResource resource, const String &value); + + /** + * \brief Creates a new resource for a given resource enum. + * \param resource With this function, the following resources can be created: + * 'State','UpdateSupportedObjects','UpdateResult'. + * \param value The value to be set on the resource, in integer format. + * \return M2MResource if created successfully, else NULL. + */ + M2MResource* create_resource(FirmwareResource resource, int64_t value); + + /** + * \brief Deletes a resource with a given resource enum. + * Mandatory resources cannot be deleted. + * \param resource The name of the resource to be deleted. + * \return True if deleted, else false. + */ + bool delete_resource(FirmwareResource resource); + + /** + * \brief Sets a value of a given resource enum. + * \param resource With this function, a value can be set on the following resources: + * 'Package', 'PackageUri', 'PackageName','PackageVersion'. + * \param value The value to be set on the resource, in string format. + * \return True if successfully set, else false. + */ + bool set_resource_value(FirmwareResource resource, + const String &value); + + /** + * \brief Sets a value of a given resource enum. + * \param resource With this function, a value can be set for the following resources: + * 'State','UpdateSupportedObjects','UpdateResult'. + * \param value The value to be set on the resource, in integer format. + * \return True if successfully set, else false. + */ + bool set_resource_value(FirmwareResource resource, + int64_t value); + + /** + * \brief Sets a value of a given resource enum. + * \param resource With this function, a value can be set for the following resources: + * 'Package'. + * \param value The value to be set on the resource, in uint8_t format. + * \param size The size of the buffer value to be set on the resource. + * \return True if successfully set, else false. + */ + bool set_resource_value(FirmwareResource resource, + const uint8_t *value, + const uint32_t length); + + /** + * \brief Returns a value of a given resource enum, in string format. + * \param resource With this function, the following resources can return a value: + * 'PackageUri', 'PackageName','PackageVersion'. + * \return The value associated with that resource, if the key is not valid it returns NULL. + */ + String resource_value_string(FirmwareResource resource) const; + + /** + * \brief Returns a value of a given resource key name, in integer format. + * \param resource With this function, the following resources can return a value: + * 'State','UpdateSupportedObjects','UpdateResult'. + * \return The value associated with that resource. If the resource is not valid -1 is returned. + */ + int64_t resource_value_int(FirmwareResource resource) const; + + /** + * \brief Populates the data buffer and returns the size of the buffer. + * \param resource With this function, the following resources can return a value: + * 'Package'. + * \param [OUT]data The data buffer containing the value. + * Tha value of the pointer MUST be set as NULL before calling this function unless it has been + * allocated using malloc. In that case the data is freed when calling this function. + * The buffer is allocated using malloc when this function is called and MUST be passed to function free after use. + * \return The size of the buffer populated. + */ + uint32_t resource_value_buffer(FirmwareResource resource, + uint8_t *&data) const; + + /** + * \brief Returns whether a resource instance with a given resource enum exists or not. + * \param resource The resource enum. + * \return True if at least one instance exists, else false. + */ + bool is_resource_present(FirmwareResource resource) const; + + /** + * \brief Returns the number of resources for a whole firmware object. + * \return Total number of resources belonging to the firmware object. + */ + uint16_t total_resource_count() const; + + /** + * \brief Returns the number of resources for a given resource enum. + * \param resource The resource enum. + * \return The number of resources for a given resource enum. Returns 1 for the + * mandatory resources. Can be 0 as well if no instances exist for an + * optional resource. + */ + uint16_t per_resource_count(FirmwareResource resource) const; + + /** + * \brief Set update resource execute callback function. This is called when update resource + * receives POST command + * \param callback The function pointer that is called. + * \return True if successfully set, else false. + */ + bool set_update_execute_callback(execute_callback callback); + + /** + * \brief Set resource value update callback function. This is called when resource value + * is updated. + * \param resource The resource enum. + * \param callback The function pointer that is called. + * \return True if successfully set, else false. + */ + bool set_resource_value_update_callback(FirmwareResource resource, + value_updated_callback callback); + + /** + * \brief Sets the callback function that is executed when this object receives + * response(Empty ACK) for notification message + * \param resource The resource enum. + * \param callback The function pointer that is called. + * \return True if successfully set, else false. + * \deprecated + */ + bool set_resource_notification_sent_callback(FirmwareResource resource, + notification_sent_callback_2 callback) m2m_deprecated; + + + /** + * \brief Sets the callback function that is executed when notification message state changes. + * \param resource The resource enum. + * \param callback The function pointer that is called. + * \return True if successfully set, else false. + */ + bool set_resource_notification_sent_callback(FirmwareResource resource, + notification_delivery_status_cb callback); + +#ifndef DISABLE_BLOCK_MESSAGE + /** + * \brief Set incoming_block_message_callback for the package resource. + * The callback will be called when a block of the package has been received. + * \param callback The function pointer to be called. + * \return true if successfully set, else false. + */ + bool set_package_block_message_callback(incoming_block_message_callback callback); +#endif + +private: + + M2MResource* get_resource(FirmwareResource resource) const; + + static const char* resource_name(FirmwareResource resource); + + void create_mandatory_resources(); + + bool check_value_range(FirmwareResource resource, const int64_t value) const; + +private : + + M2MObjectInstance* _firmware_instance; //Not owned + +protected: + + static M2MFirmware* _instance; + + friend class Test_M2MFirmware; + friend class Test_M2MInterfaceFactory; +}; + + +#endif // M2MFIRMWARE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2minterface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2minterface.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_INTERFACE_H +#define M2M_INTERFACE_H + +#include <stdint.h> +#include "mbed-client/m2mvector.h" +#include "mbed-client/m2mconfig.h" +#include "mbed-client/functionpointer.h" + +//FORWARD DECLARATION +class M2MSecurity; +class M2MObject; +class M2MInterfaceObserver; + +typedef Vector<M2MObject *> M2MObjectList; +typedef FP callback_handler; + +// TODO! Add more errors +typedef enum get_data_req_error_e { + FAILED_TO_SEND_MSG = 0 +} get_data_req_error_t; + +/*! + * @brief A callback function to receive data from GET request. + * Transfer is completed once total size equals to received size. + * Caller needs to take care of counting how many bytes it has received. + * @param buffer Buffer containing the payload. + * @param buffer_size Size of the payload. + * @param total_size Total size of the package. This information is available only in first package. + * Caller must store this information to detect when the download has completed. + * @param context Application context +*/ +typedef void (*get_data_cb)(const uint8_t *buffer, + size_t buffer_size, + size_t total_size, + void *context); + +/*! + * @brief A callback function to receive errors from GET transfer. + * @param error_code + * @param context Application context +*/ +typedef void (*get_data_error_cb)(get_data_req_error_t error_code, void *context); + +/*! \file m2minterface.h + * \brief M2MInterface. + * This class provides an interface for handling all mbed Client interface operations + * defined in the OMA LWM2M specifications. + * This includes Bootstrapping, Client Registration, Device Management & + * Service Enablement and Information Reporting. + */ + +class M2MInterface { + +public: + + /** + * \brief An enum defining different kinds of errors + * that can occur during various client operations. + */ + typedef enum { + ErrorNone = 0, + AlreadyExists, + BootstrapFailed, + InvalidParameters, + NotRegistered, + Timeout, + NetworkError, + ResponseParseFailed, + UnknownError, + MemoryFail, + NotAllowed, + SecureConnectionFailed, + DnsResolvingFailed, + UnregistrationFailed + }Error; + + /** + * \brief An enum defining different kinds of binding + * modes handled for client operations. + */ + typedef enum { + NOT_SET = 0, + UDP = 0x01, + UDP_QUEUE = 0x03, + SMS = 0x04, + SMS_QUEUE =0x06, + UDP_SMS_QUEUE = 0x07, + TCP = 0x09, //not real value, spec does not have one! + //this has nsdl binding mode bit UDP set + TCP_QUEUE = 0x0b //not real value, spec does not have one! + //this has nsdl binding mode bits, UDP and UDP_QUEUE set + }BindingMode; + + /** + * \brief An enum defining different kinds of network + * stacks that can be used by mbed Client. + */ + typedef enum { + Uninitialized = 0, + LwIP_IPv4, + LwIP_IPv6, + Reserved, + Nanostack_IPv6, + ATWINC_IPv4, + Unknown + }NetworkStack; + +public: + + virtual ~M2MInterface(){} + + /** + * \brief Initiates bootstrapping of the client with the provided Bootstrap + * Server information. + * NOTE: This API is not supported for developers!! + * \param security_object A security object that contains information + * required for successful bootstrapping of the client. + */ + virtual void bootstrap(M2MSecurity *security_object) = 0; + + /** + * \brief Cancels an ongoing bootstrapping operation of the client. If the client has + * already successfully bootstrapped, this function deletes the existing + * bootstrap information from the client. + * NOTE: This API is not supported for developers!! + */ + virtual void cancel_bootstrap() = 0; + + /** + * \brief Initiates the registration of a provided security object to the + * corresponding LWM2M server. + * \param security_object The security object that contains information + * required for registering to the LWM2M server. + * If the client wants to register to multiple LWM2M servers, it must call + * this function once for each of the LWM2M server objects separately. + * \param object_list Objects that contain information about the + * client attempting to register to the LWM2M server. + */ + virtual void register_object(M2MSecurity *security_object, const M2MObjectList &object_list) = 0; + + /** + * \brief Updates or refreshes the client's registration on the LWM2M + * server. + * \param security_object A security object from which the device object + * needs to update the registration. If there is only one LWM2M server registered, + * this parameter can be NULL. + * \param lifetime The lifetime of the endpoint client in seconds. If the same value + * has to be passed, set the default value to 0. + */ + virtual void update_registration(M2MSecurity *security_object, const uint32_t lifetime = 0) = 0; + + /** + * \brief Updates or refreshes the client's registration on the LWM2M + * server. Use this function to publish new objects to LWM2M server. + * \param security_object The security object from which the device object + * needs to update the registration. If there is only one LWM2M server registered, + * this parameter can be NULL. + * \param object_list Objects that contain information about the + * client attempting to register to the LWM2M server. + * \param lifetime The lifetime of the endpoint client in seconds. If the same value + * has to be passed, set the default value to 0. + */ + virtual void update_registration(M2MSecurity *security_object, const M2MObjectList &object_list, + const uint32_t lifetime = 0) = 0; + + /** + * \brief Unregisters the registered object from the LWM2M server. + * \param security_object The security object from which the device object + * needs to be unregistered. If there is only one LWM2M server registered, + * this parameter can be NULL. + */ + virtual void unregister_object(M2MSecurity* security_object = NULL) = 0; + + /** + * \brief Sets the function that is called for indicating that the client + * is going to sleep when the binding mode is selected with queue mode. + * \param callback A function pointer that is called when the client + * goes to sleep. + */ + virtual void set_queue_sleep_handler(callback_handler handler) = 0; + + /** + * \brief Sets the function callback that is called by mbed Client to + * fetch a random number from an application to ensure strong entropy. + * \param random_callback A function pointer that is called by mbed Client + * while performing a secure handshake. + * The function signature should be uint32_t (*random_number_callback)(void); + */ + virtual void set_random_number_callback(random_number_cb callback) = 0; + + /** + * \brief Sets the function callback that is called by mbed Client to + * provide an entropy source from an application to ensure strong entropy. + * \param entropy_callback A function pointer that is called by mbed Client + * while performing a secure handshake. + * Function signature, if using mbed-client-mbedtls, should be + * int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, + * size_t len, size_t *olen); + */ + virtual void set_entropy_callback(entropy_cb callback) = 0; + + /** + * \brief Sets the network interface handler that is used by mbed Client to connect + * to a network over IP. + * \param handler A network interface handler that is used by mbed Client to connect. + * This API is optional but it provides a mechanism for different platforms to + * manage the usage of underlying network interface by the client. + */ + virtual void set_platform_network_handler(void *handler = NULL) = 0; + + /** + * @brief Updates the endpoint name. + * @param name New endpoint name + */ + virtual void update_endpoint(String &name) = 0; + + /** + * @brief Updates the domain name. + * @param domain New domain name + */ + virtual void update_domain(String &domain) = 0; + + + /** + * @brief Return internal endpoint name + * @return internal endpoint name + */ + virtual const String internal_endpoint_name() const = 0; + + /** + * @brief Return error description for the latest error code + * @return Error description string + */ + virtual const char *error_description() const = 0; + + /** + * @brief Sends the CoAP GET request to the server. + * @uri Uri path to the data. + * @offset Data offset. + * @async In async mode application must call this API again with the updated offset. + * If set to false then client will automatically download the whole package. + * @get_data_cb Callback which is triggered once there is data available. + * @get_data_error_cb Callback which is trigged in case of any error. + */ + virtual void get_data_request(const char *uri, + const size_t offset, + const bool async, + get_data_cb, + get_data_error_cb, + void *context) = 0; +}; + +#endif // M2M_INTERFACE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2minterfacefactory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2minterfacefactory.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_INTERFACE_FACTORY_H +#define M2M_INTERFACE_FACTORY_H + +#include <stdlib.h> +#include "mbed-client/m2msecurity.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2minterfaceobserver.h" + +//FORWARD DECLARATION +class M2MDevice; +class M2MServer; +class M2MInterfaceImpl; +class M2MFirmware; + +/*! \file m2minterfacefactory.h + * \brief M2MInterfaceFactory. + * This is a factory class that provides an interface for creating an mbed Client Interface + * object for an application to utilize the LWM2M features provided by the client. + */ + +class M2MInterfaceFactory { +private: + // Prevents the use of an assignment operator by accident. + M2MInterfaceFactory& operator=( const M2MInterfaceFactory& /*other*/ ); + + // Prevents the use of a copy constructor by accident. + M2MInterfaceFactory( const M2MInterfaceFactory& /*other*/ ); + +public: + + /** + * \brief Creates an interface object for the mbed Client Inteface. With this, the + * client can handle client operations like Bootstrapping, Client + * Registration, Device Management and Information Reporting. + * \param endpoint_name The endpoint name of mbed Client. + * \param endpoint_type The endpoint type of mbed Client, default is empty. + * \param life_time The lifetime of the endpoint in seconds, + * if -1 it is optional. + * \param listen_port The listening port for the endpoint, default is 5683. + * \param domain The domain of the endpoint, default is empty. + * \param mode The binding mode of the endpoint, default is NOT_SET. + * \param stack The underlying network stack to be used for the connection, + * default is LwIP_IPv4. + * \param context_address The context address for M2M-HTTP, not used currently. + * \return M2MInterfaceImpl An object for managing other client operations. + */ + static M2MInterface *create_interface(M2MInterfaceObserver &observer, + const String &endpoint_name, + const String &endpoint_type = "", + const int32_t life_time = -1, + const uint16_t listen_port = 5683, + const String &domain = "", + M2MInterface::BindingMode mode = M2MInterface::NOT_SET, + M2MInterface::NetworkStack stack = M2MInterface::LwIP_IPv4, + const String &context_address = ""); + + /** + * \brief Creates a security object for the mbed Client Inteface. With this, the + * client can manage Bootstrapping and Client Registration. + * \param ServerType The type of the Security Object, bootstrap or LWM2M server. + * \return M2MSecurity An object for managing other client operations. + */ + static M2MSecurity *create_security(M2MSecurity::ServerType server_type); + + /** + * \brief Creates a server object for the mbed Client Inteface. With this, the + * client can manage the server resources used for client operations + * such as Client Registration, server lifetime. + * \return M2MServer An object for managing server client operations. + */ + static M2MServer *create_server(); + + /** + * \brief Creates a device object for the mbed Client Inteface. With this, the + * client can manage the device resources used for client operations + * such as Client Registration, Device Management and Information Reporting. + * \param name The name of the device object. + * \return M2MDevice An object for managing other client operations. + */ + static M2MDevice *create_device(); + + /** + * \brief Creates a firmware object for the mbed Client Inteface. With this, the + * client can manage the firmware resources used for the client operations + * such as Client Registration, Device Management and Information Reporting. + * \return M2MFirmware An object for managing other client operations. + */ + static M2MFirmware *create_firmware(); + + /** + * \brief Creates a generic object for the mbed Client Inteface. With this, the + * client can manage its own customized resources used for registering + * Device Management and Information Reporting for those resources. + * \param name The name of the object. + * \param id A unique ID for the object. It should be other than the reserved + * LWM2M object IDs. + * \return M2MObject An object for managing other mbed Client operations. + */ + static M2MObject *create_object(const String &name); + + + friend class Test_M2MInterfaceFactory; +}; + +#endif // M2M_INTERFACE_FACTORY_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2minterfaceobserver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2minterfaceobserver.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_INTERFACE_OBSERVER_H +#define M2M_INTERFACE_OBSERVER_H + +#include "mbed-client/m2mbase.h" +#include "mbed-client/m2minterface.h" + +//FORWARD DECLARATION +class M2MServer; + +/*! \file m2minterfaceobserver.h + * \brief M2MInterfaceObserver + * This is an observer class that updates the calling application about + * various events associated with various Interface operations. + * Also, it informs about various errors that can occur during any of the above + * operations. + */ +class M2MInterfaceObserver { + +public: + + /** + * \brief A callback indicating that the bootstap has been performed successfully. + * \param server_object The server object that contains information fetched + * about the LWM2M server from the bootstrap server. This object can be used + * to register to the LWM2M server. The object ownership is passed. + */ + virtual void bootstrap_done(M2MSecurity *server_object) = 0; + + /** + * \brief A callback indicating that the device object has been registered + * successfully to the LWM2M server. + * \param security_object The server object on which the device object is + * registered. The object ownership is passed. + * \param server_object An object containing information about the LWM2M server. + * The client maintains the object. + */ + virtual void object_registered(M2MSecurity *security_object, const M2MServer &server_object) = 0; + + /** + * \brief A callback indicating that the device object has been successfully unregistered + * from the LWM2M server. + * \param server_object The server object from which the device object is + * unregistered. The object ownership is passed. + */ + virtual void object_unregistered(M2MSecurity *server_object) = 0; + + /** + * \brief A callback indicating that the device object registration has been successfully + * updated on the LWM2M server. + * \param security_object The server object on which the device object registration + * updated. The object ownership is passed. + * \param server_object An object containing information about the LWM2M server. + * The client maintains the object. + */ + virtual void registration_updated(M2MSecurity *security_object, const M2MServer & server_object) = 0; + + /** + * \brief A callback indicating that there was an error during the operation. + * \param error An error code for the occurred error. + */ + virtual void error(M2MInterface::Error error) = 0; + + /** + * \brief A callback indicating that the value of the resource object is updated by the server. + * \param base The object whose value is updated. + * \param type The type of the object. + */ + virtual void value_updated(M2MBase *base, M2MBase::BaseType type) = 0; +}; + +#endif // M2M_INTERFACE_OBSERVER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mobject.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mobject.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_OBJECT_H +#define M2M_OBJECT_H + +#include "mbed-client/m2mvector.h" +#include "mbed-client/m2mbase.h" +#include "mbed-client/m2mobjectinstance.h" + +//FORWARD DECLARATION +typedef Vector<M2MObjectInstance *> M2MObjectInstanceList; + +/*! \file m2mobject.h + * \brief M2MObject. + * This class is the base class for the mbed Client Objects. All defined + * LWM2M object models can be created based on it. This class also holds all object + * instances associated with the given object. + */ + +class M2MObject : public M2MBase +{ + +friend class M2MInterfaceFactory; + +protected : + + /** + * \brief Constructor + * \param name The name of the object. + * \param path Path of the object like 3/0/1 + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + */ + M2MObject(const String &object_name, + char *path, + bool external_blockwise_store = false); + + // Prevents the use of default constructor. + M2MObject(); + + // Prevents the use of assignment operator. + M2MObject& operator=( const M2MObject& /*other*/ ); + + // Prevents the use of copy constructor. + M2MObject( const M2MObject& /*other*/ ); + + /** + * \brief Constructor + * \param name The name of the object. + */ + M2MObject(const M2MBase::lwm2m_parameters_s* static_res); + +public: + + /** + * \brief Destructor + */ + virtual ~M2MObject(); + + /** + * \brief Creates a new object instance for a given mbed Client Interface object. With this, + * the client can respond to server's GET methods with the provided value. + * \return M2MObjectInstance. An object instance for managing other client operations. + */ + M2MObjectInstance* create_object_instance(uint16_t instance_id = 0); + + /** + * TODO!! + */ + M2MObjectInstance* create_object_instance(const lwm2m_parameters_s* s); + + /** + * \brief Removes the object instance resource with the given instance id. + * \param instance_id The instance ID of the object instance to be removed, default is 0. + * \return True if removed, else false. + */ + bool remove_object_instance(uint16_t instance_id = 0); + + /** + * \brief Returns the object instance with the the given instance ID. + * \param instance_id The instance ID of the requested object instance ID, default is 0. + * \return Object instance reference if found, else NULL. + */ + M2MObjectInstance* object_instance(uint16_t instance_id = 0) const; + + /** + * \brief Returns a list of object instances. + * \return A list of object instances. + */ + const M2MObjectInstanceList& instances() const; + + /** + * \brief Returns the total number of object instances- + * \return The total number of the object instances. + */ + uint16_t instance_count() const; + + /** + * \brief Returns the Observation Handler object. + * \return M2MObservationHandler object. + */ + virtual M2MObservationHandler* observation_handler() const; + + /** + * \brief Sets the observation handler + * \param handler Observation handler + */ + virtual void set_observation_handler(M2MObservationHandler *handler); + + /** + * \brief Adds the observation level for the object. + * \param observation_level The level of observation. + */ + virtual void add_observation_level(M2MBase::Observation observation_level); + + /** + * \brief Removes the observation level from the object. + * \param observation_level The level of observation. + */ + virtual void remove_observation_level(M2MBase::Observation observation_level); + + /** + * \brief Handles GET request for the registered objects. + * \param nsdl The NSDL handler for the CoAP library. + * \param received_coap_header The CoAP message received from the server. + * \param observation_handler The handler object for sending + * observation callbacks. + * \return sn_coap_hdr_s The message that needs to be sent to server. + */ + virtual sn_coap_hdr_s* handle_get_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler = NULL); + + /** + * \brief Handles PUT request for the registered objects. + * \param nsdl The NSDL handler for the CoAP library. + * \param received_coap_header The received CoAP message from the server. + * \param observation_handler The handler object for sending + * observation callbacks. + * \param execute_value_updated True will execute the "value_updated" callback. + * \return sn_coap_hdr_s The message that needs to be sent to server. + */ + virtual sn_coap_hdr_s* handle_put_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated); + + /** + * \brief Handles GET request for the registered objects. + * \param nsdl The NSDL handler for the CoAP library. + * \param received_coap_header The received CoAP message from the server. + * \param observation_handler The handler object for sending + * observation callbacks. + * \param execute_value_updated True will execute the "value_updated" callback. + * \return sn_coap_hdr_s The message that needs to be sent to server. + */ + virtual sn_coap_hdr_s* handle_post_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated, + sn_nsdl_addr_s *address = NULL); + + void notification_update(uint16_t obj_instance_id); + +protected : + + +private: + + M2MObjectInstanceList _instance_list; // owned + + M2MObservationHandler *_observation_handler; // Not owned + +friend class Test_M2MObject; +friend class Test_M2MInterfaceImpl; +friend class Test_M2MNsdlInterface; +friend class Test_M2MTLVSerializer; +friend class Test_M2MTLVDeserializer; +friend class Test_M2MDevice; +friend class Test_M2MFirmware; +friend class Test_M2MBase; +friend class Test_M2MObjectInstance; +friend class Test_M2MResource; +friend class Test_M2MSecurity; +friend class Test_M2MServer; +friend class Test_M2MResourceInstance; +}; + +#endif // M2M_OBJECT_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mobjectinstance.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mobjectinstance.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_OBJECT_INSTANCE_H +#define M2M_OBJECT_INSTANCE_H + +#include "mbed-client/m2mvector.h" +#include "mbed-client/m2mresource.h" + +//FORWARD DECLARATION +typedef Vector<M2MResource *> M2MResourceList; +typedef Vector<M2MResourceInstance *> M2MResourceInstanceList; + + +class M2MObject; + +/*! \file m2mobjectinstance.h + * \brief M2MObjectInstance. + * This class is the instance class for mbed Client Objects. All defined + * LWM2M object models can be created based on it. This class also holds all resource + * instances associated with the given object. + */ + +class M2MObjectInstance : public M2MBase +{ + +friend class M2MObject; + +private: // Constructor and destructor are private which means + // that these objects can be created or + // deleted only through function provided by M2MObject. + + /** + * \brief Constructor + * \param name Name of the object + */ + M2MObjectInstance(M2MObject& parent, + const String &resource_type, + char *path, + bool external_blockwise_store = false); + + M2MObjectInstance(M2MObject& parent, const lwm2m_parameters_s* static_res); + + // Prevents the use of default constructor. + M2MObjectInstance(); + + // Prevents the use of assignment operator. + M2MObjectInstance& operator=( const M2MObjectInstance& /*other*/ ); + + // Prevents the use of copy constructor. + M2MObjectInstance( const M2MObjectInstance& /*other*/ ); + + /** + * Destructor + */ + virtual ~M2MObjectInstance(); + +public: + + /** + * \brief TODO! + * \return M2MResource The resource for managing other client operations. + */ + M2MResource* create_static_resource(const lwm2m_parameters_s* static_res, + M2MResourceInstance::ResourceType type); + + /** + * \brief Creates a static resource for a given mbed Client Inteface object. With this, the + * client can respond to server's GET methods with the provided value. + * \param resource_name The name of the resource. + * \param resource_type The type of the resource. + * \param value A pointer to the value of the resource. + * \param value_length The length of the value in the pointer. + * \param multiple_instance A resource can have + * multiple instances, default is false. + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + * \return M2MResource The resource for managing other client operations. + */ + M2MResource* create_static_resource(const String &resource_name, + const String &resource_type, + M2MResourceInstance::ResourceType type, + const uint8_t *value, + const uint8_t value_length, + bool multiple_instance = false, + bool external_blockwise_store = false); + + /** + * \brief Creates a dynamic resource for a given mbed Client Inteface object. With this, + * the client can respond to different queries from the server (GET,PUT etc). + * This type of resource is also observable and carries callbacks. + * \param resource_name The name of the resource. + * \param resource_type The type of the resource. + * \param observable Indicates whether the resource is observable or not. + * \param multiple_instance The resource can have + * multiple instances, default is false. + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + * \return M2MResource The resource for managing other client operations. + */ + M2MResource* create_dynamic_resource(const String &resource_name, + const String &resource_type, + M2MResourceInstance::ResourceType type, + bool observable, + bool multiple_instance = false, + bool external_blockwise_store = false); + + /** + * \brief TODO! + * \return M2MResource The resource for managing other client operations. + */ + M2MResource* create_dynamic_resource(const lwm2m_parameters_s* static_res, + M2MResourceInstance::ResourceType type, + bool observable); + + /** + * \brief Creates a static resource instance for a given mbed Client Inteface object. With this, + * the client can respond to server's GET methods with the provided value. + * \param resource_name The name of the resource. + * \param resource_type The type of the resource. + * \param value A pointer to the value of the resource. + * \param value_length The length of the value in pointer. + * \param instance_id The instance ID of the resource. + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + * \return M2MResourceInstance The resource instance for managing other client operations. + */ + M2MResourceInstance* create_static_resource_instance(const String &resource_name, + const String &resource_type, + M2MResourceInstance::ResourceType type, + const uint8_t *value, + const uint8_t value_length, + uint16_t instance_id, + bool external_blockwise_store = false); + + /** + * \brief Creates a dynamic resource instance for a given mbed Client Inteface object. With this, + * the client can respond to different queries from the server (GET,PUT etc). + * This type of resource is also observable and carries callbacks. + * \param resource_name The name of the resource. + * \param resource_type The type of the resource. + * \param observable Indicates whether the resource is observable or not. + * \param instance_id The instance ID of the resource. + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + * \return M2MResourceInstance The resource instance for managing other client operations. + */ + M2MResourceInstance* create_dynamic_resource_instance(const String &resource_name, + const String &resource_type, + M2MResourceInstance::ResourceType type, + bool observable, + uint16_t instance_id, + bool external_blockwise_store = false); + + /** + * \brief Removes the resource with the given name. + * \param name The name of the resource to be removed. + * Note: this will be removed in next version, please use the + * remove_resource(const char*) version instead. + * \return True if removed, else false. + */ + bool remove_resource(const String &name); + + /** + * \brief Removes the resource with the given name. + * \param name The name of the resource to be removed. + * \return True if removed, else false. + */ + bool remove_resource(const char *name); + + /** + * \brief Removes the resource instance with the given name. + * \param resource_name The name of the resource instance to be removed. + * \param instance_id The instance ID of the instance. + * \return True if removed, else false. + */ + bool remove_resource_instance(const String &resource_name, + uint16_t instance_id); + + /** + * \brief Returns the resource with the given name. + * \param name The name of the requested resource. + * \return Resource reference if found, else NULL. + */ + M2MResource* resource(const String &name) const; + + M2MResource* resource(const char *resource) const; + + /** + * \brief Returns a list of M2MResourceBase objects. + * \return A list of M2MResourceBase objects. + */ + const M2MResourceList& resources() const; + + /** + * \brief Returns the total number of resources with the object. + * \return Total number of the resources. + */ + uint16_t resource_count() const; + + /** + * \brief Returns the total number of single resource instances. + * Note: this will be removed in next version, please use the + * resource_count(const char*) version instead. + * \param resource The name of the resource. + * \return Total number of the resources. + */ + uint16_t resource_count(const String& resource) const; + + /** + * \brief Returns the total number of single resource instances. + * \param resource The name of the resource. + * \return Total number of the resources. + */ + uint16_t resource_count(const char *resource) const; + + /** + * \brief Adds the observation level for the object. + * \param observation_level The level of observation. + */ + virtual void add_observation_level(M2MBase::Observation observation_level); + + /** + * \brief Removes the observation level from the object. + * \param observation_level The level of observation. + */ + virtual void remove_observation_level(M2MBase::Observation observation_level); + + /** + * \brief Returns the Observation Handler object. + * \return M2MObservationHandler object. + */ + virtual M2MObservationHandler* observation_handler() const; + + /** + * \brief Sets the observation handler + * \param handler Observation handler + */ + virtual void set_observation_handler(M2MObservationHandler *handler); + + /** + * \brief Handles GET request for the registered objects. + * \param nsdl The NSDL handler for the CoAP library. + * \param received_coap_header The CoAP message received from the server. + * \param observation_handler The handler object for sending + * observation callbacks. + * return sn_coap_hdr_s The message that needs to be sent to the server. + */ + virtual sn_coap_hdr_s* handle_get_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler = NULL); + /** + * \brief Handles PUT request for the registered objects. + * \param nsdl The NSDL handler for the CoAP library. + * \param received_coap_header The CoAP message received from the server. + * \param observation_handler The handler object for sending + * observation callbacks. + * \param execute_value_updated True will execute the "value_updated" callback. + * \return sn_coap_hdr_s The message that needs to be sent to server. + */ + virtual sn_coap_hdr_s* handle_put_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated); + + /** + * \brief Handles POST request for the registered objects. + * \param nsdl The NSDL handler for the CoAP library. + * \param received_coap_header The CoAP message received from the server. + * \param observation_handler The handler object for sending + * observation callbacks. + * \param execute_value_updated True will execute the "value_updated" callback. + * \return sn_coap_hdr_s The message that needs to be sent to server. + */ + virtual sn_coap_hdr_s* handle_post_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated, + sn_nsdl_addr_s *address = NULL); + + inline M2MObject& get_parent_object() const; + + // callback used from M2MResource/M2MResourceInstance + void notification_update(M2MBase::Observation observation_level); + +private: + + /** + * \brief Utility function to map M2MResourceInstance ResourceType + * to M2MBase::DataType. + * \param resource_type M2MResourceInstance::ResourceType. + * \return M2MBase::DataType. + */ + M2MBase::DataType convert_resource_type(M2MResourceInstance::ResourceType); + +private: + + M2MObject &_parent; + + M2MResourceList _resource_list; // owned + + friend class Test_M2MObjectInstance; + friend class Test_M2MObject; + friend class Test_M2MDevice; + friend class Test_M2MSecurity; + friend class Test_M2MServer; + friend class Test_M2MNsdlInterface; + friend class Test_M2MFirmware; + friend class Test_M2MTLVSerializer; + friend class Test_M2MTLVDeserializer; + friend class Test_M2MBase; + friend class Test_M2MResource; + friend class Test_M2MResourceInstance; +}; + +inline M2MObject& M2MObjectInstance::get_parent_object() const +{ + return _parent; +} + +#endif // M2M_OBJECT_INSTANCE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mobservationhandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mobservationhandler.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_OBSERVATION_HANDLER_H +#define M2M_OBSERVATION_HANDLER_H + +//FORWARD DECLARATION +class M2MBase; +class M2MResourceInstance; + +/*! \file m2mobservationhandler.h + * \brief M2MObservationHandler. + * An interface for handling observation + * callbacks from different objects. + * + */ +class M2MObservationHandler +{ + public: + + /** + * \brief The observation callback to be sent to the + * server due to a change in a parameter under observation. + * \param object The observed object whose information needs to be sent. + * \param obs_number The observation number. + * \param changed_instance_ids A list of changed object instance IDs. + * \param send_object Indicates whether the whole object will be sent or not. + */ + virtual void observation_to_be_sent(M2MBase *object, + uint16_t obs_number, + const m2m::Vector<uint16_t> &changed_instance_ids, + bool send_object = false) = 0; + + /** + * \brief A callback for removing an NSDL resource from the data structures. + * \param The M2MBase derived observed object whose information + * needs to be removed. + */ + virtual void resource_to_be_deleted(M2MBase *base) = 0; + + /** + * \brief A callback indicating that the value of the resource object is updated by server. + * \param base The object whose value is updated. + * \param object_name The name of the updated resource, default is empty. + */ + virtual void value_updated(M2MBase *base) = 0; + + /** + * \brief A callback for removing an object from the list. + * \param object The M2MObject to be removed. + */ + virtual void remove_object(M2MBase *object) = 0; + +#ifndef DISABLE_DELAYED_RESPONSE + /** + * \brief A delayed response callback to be sent to the + * server due to a changed response. + * \param base The resource sending the response. + */ + virtual void send_delayed_response(M2MBase *base) = 0; +#endif +}; + + +#endif // M2M_OBSERVATION_HANDLER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mreportobserver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mreportobserver.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2MREPORTOBSERVER_H +#define M2MREPORTOBSERVER_H + +#include <inttypes.h> +#include <mbed-client/m2mvector.h> + +/*! \file m2mreportobserver.h + * \brief M2MReportObserver. + * An interface for inviting the base class + * to send a report to the server. + * + */ +class M2MReportObserver +{ + public: + + /** + * \brief An observation callback to be sent to the + * server due to a change in the observed parameter. + * \param changed_instance_ids A list of changed object instance IDs. + * \param obs_number The observation number. + * \param send_object Indicates whether the whole object will be sent or not. + */ + virtual void observation_to_be_sent(const m2m::Vector<uint16_t> &changed_instance_ids, + uint16_t obs_number, + bool send_object = false) = 0; + +}; + +#endif // M2MREPORTOBSERVER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mresource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mresource.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_RESOURCE_H +#define M2M_RESOURCE_H + +#include "mbed-client/m2mvector.h" +#include "mbed-client/m2mresourcebase.h" +#include "mbed-client/m2mresourceinstance.h" + +//FORWARD DECLARATION +class M2MObjectInstance; +typedef Vector<M2MResourceInstance *> M2MResourceInstanceList; + +/*! \file m2mresource.h + * \brief M2MResource. + * This class is the base class for mbed Client Resources. All defined + * LWM2M object models can be created using it. This class will also hold all resources + * instances associated with the given object. + */ + +class M2MResource : public M2MResourceBase { + + friend class M2MObjectInstance; + +public: + class M2MExecuteParameter; + +private: // Constructor and destructor are private, + // which means that these objects can be created or + // deleted only through a function provided by the M2MObjectInstance. + + M2MResource(M2MObjectInstance &_parent, + const lwm2m_parameters_s* s, + M2MBase::DataType type); + /** + * \brief Constructor + * \param resource_name The resource name of the object. + * \param resource_type The resource type of the object. + * \param type The resource data type of the object. + * \param value The value pointer of the object. + * \param value_length The length of the value pointer. + * \param path Full path of the resource, eg. 1/2/3. Ownership of the memory is transferred. + * \param object_name The name of the object where the resource exists. + * \param multiple_instance True if the resource supports instances. + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + */ + M2MResource(M2MObjectInstance &_parent, + const String &resource_name, + M2MBase::Mode mode, + const String &resource_type, + M2MBase::DataType type, + const uint8_t *value, + const uint8_t value_length, + char *path, + bool multiple_instance = false, + bool external_blockwise_store = false); + + /** + * \brief Constructor + * \param resource_name The resource name of the object. + * \param resource_type The resource type of the object. + * \param type The resource data type of the object. + * \param observable Indicates whether the resource is observable or not. + * \param path Full path of the resource, eg. 1/2/3. Ownership of the memory is transferred. + * \param object_name The name of the object where the resource exists. + * \param multiple_instance True if the resource supports instances. + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + */ + M2MResource(M2MObjectInstance &_parent, + const String &resource_name, + M2MBase::Mode mode, + const String &resource_type, + M2MBase::DataType type, + bool observable, + char *path, + bool multiple_instance = false, + bool external_blockwise_store = false); + + // Prevents the use of a default constructor. + M2MResource(); + + // Prevents the use of an assignment operator. + M2MResource& operator=( const M2MResource& /*other*/ ); + + // Prevents the use of a copy constructor + M2MResource( const M2MResource& /*other*/ ); + + /** + * Destructor + */ + virtual ~M2MResource(); + +public: + + /** + * \brief Adds resource instances to a M2MResource. + * \param resource_instance The resource instance to be added. + */ + void add_resource_instance(M2MResourceInstance *resource_instance); + + /** + * \brief Returns whether the resource has multiple + * resource instances or not. + * \return True if the resource base has multiple instances, + * else false. + */ + bool supports_multiple_instances() const; + +#ifndef DISABLE_DELAYED_RESPONSE + /** + * \brief Sets whether the resource should send a delayed response for a POST request. + * \param delayed_response A boolean value to set the delayed response. + */ + void set_delayed_response(bool delayed_response); + + /** + * \brief A trigger to send the delayed response for the POST request. + * The delayed_response flag must be set before receiving the POST request + * and the value of the resource must be updated before calling this function. + * \return True if a response is sent, else false. + */ + bool send_delayed_post_response(); + + /** + * \brief Provides the value of the given token. + * \param value[OUT] A pointer to the token value. + * \param value_length[OUT] The length of the token pointer. + */ + void get_delayed_token(uint8_t *&token, uint8_t &token_length); +#endif + + /** + * \brief Removes a resource with a given name. + * \param name The name of the resource to be removed. + * \param instance_id The instance ID of the resource to be removed, default is 0. + * \return True if removed, else false. + */ + bool remove_resource_instance(uint16_t instance_id = 0); + + /** + * \brief Returns a resource instance with a given name. + * \param instance_id The instance ID of the requested resource, default is 0 + * \return M2MResourceInstance object if found, else NULL. + */ + M2MResourceInstance* resource_instance(uint16_t instance_id = 0) const; + + /** + * \brief Returns a list of resources. + * \return A list of resources. + */ + const M2MResourceInstanceList& resource_instances() const; + + /** + * \brief Returns the total number of resources. + * \return The total number of resources. + */ + uint16_t resource_instance_count() const; + + /** + * \brief Returns the value set for delayed response. + * \return The value for delayed response. + */ + bool delayed_response() const; + + /** + * \brief Returns the Observation Handler object. + * \return M2MObservationHandler object. + */ + virtual M2MObservationHandler* observation_handler() const; + + /** + * \brief Sets the observation handler + * \param handler Observation handler + */ + virtual void set_observation_handler(M2MObservationHandler *handler); + + /** + * \brief Parses the received query for a notification + * attribute. + * \return True if required attributes are present, else false. + */ + virtual bool handle_observation_attribute(const char *query); + + /** + * \brief Adds the observation level for the object. + * \param observation_level The level of observation. + */ + virtual void add_observation_level(M2MBase::Observation observation_level); + + /** + * \brief Removes the observation level from an object. + * \param observation_level The level of observation. + */ + virtual void remove_observation_level(M2MBase::Observation observation_level); + + /** + * \brief Handles the GET request for registered objects. + * \param nsdl An NSDL handler for the CoAP library. + * \param received_coap_header The CoAP message received from the server. + * \param observation_handler A handler object for sending + * observation callbacks. + * \return sn_coap_hdr_s The message that needs to be sent to the server. + */ + virtual sn_coap_hdr_s* handle_get_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler = NULL); + /** + * \brief Handles the PUT request for registered objects. + * \param nsdl An NSDL handler for the CoAP library. + * \param received_coap_header The CoAP message received from the server. + * \param observation_handler A handler object for sending + * observation callbacks. + * \param execute_value_updated True executes the "value_updated" callback. + * \return sn_coap_hdr_s The message that needs to be sent to the server. + */ + virtual sn_coap_hdr_s* handle_put_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated); + /** + * \brief Handles the POST request for registered objects. + * \param nsdl An NSDL handler for the CoAP library. + * \param received_coap_header The CoAP message received from the server. + * \param observation_handler A handler object for sending + * observation callbacks. + * \param execute_value_updated True executes the "value_updated" callback. + * \return sn_coap_hdr_s The message that needs to be sent to the server. + */ + virtual sn_coap_hdr_s* handle_post_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated, + sn_nsdl_addr_s *address = NULL); + + M2MObjectInstance& get_parent_object_instance() const; + + /** + * \brief Returns the instance ID of the object where the resource exists. + * \return Object instance ID. + */ + virtual uint16_t object_instance_id() const; + + /** + * \brief Returns the name of the object where the resource exists. + * \return Object name. + */ + virtual const char* object_name() const; + + virtual M2MResource& get_parent_resource() const; +private: + M2MObjectInstance &_parent; + + M2MResourceInstanceList _resource_instance_list; // owned +#ifndef DISABLE_DELAYED_RESPONSE + uint8_t *_delayed_token; + uint8_t _delayed_token_len; + bool _delayed_response; +#endif + +friend class Test_M2MResource; +friend class Test_M2MObjectInstance; +friend class Test_M2MObject; +friend class Test_M2MDevice; +friend class Test_M2MSecurity; +friend class Test_M2MServer; +friend class Test_M2MNsdlInterface; +friend class Test_M2MFirmware; +friend class Test_M2MTLVSerializer; +friend class Test_M2MTLVDeserializer; +friend class Test_M2MBase; +friend class Test_M2MResourceInstance; +}; + +/** + * \brief M2MResource::M2MExecuteParameter. + * This class handles the "Execute" operation arguments. + */ +class M2MResource::M2MExecuteParameter { + +private: + + /** + * \brief Constructor, since there is no implementation, it prevents invalid use of it + */ + M2MExecuteParameter(); + +#ifdef MEMORY_OPTIMIZED_API + M2MExecuteParameter(const char *object_name, const char *resource_name, uint16_t object_instance_id); +#else + // This is a deprecated constructor, to be removed on next release. + M2MExecuteParameter(const String &object_name, const String &resource_name, uint16_t object_instance_id); +#endif + +public: + + /** + * \brief Returns the value of an argument. + * \return uint8_t * The argument value. + */ + const uint8_t *get_argument_value() const; + + /** + * \brief Returns the length of the value argument. + * \return uint8_t The argument value length. + */ + uint16_t get_argument_value_length() const; + + /** + * \brief Returns the name of the object where the resource exists. + * \return Object name. + */ +#ifdef MEMORY_OPTIMIZED_API + const char* get_argument_object_name() const; +#else + const String& get_argument_object_name() const; +#endif + + /** + * \brief Returns the resource name. + * \return Resource name. + */ +#ifdef MEMORY_OPTIMIZED_API + const char* get_argument_resource_name() const; +#else + const String& get_argument_resource_name() const; +#endif + + /** + * \brief Returns the instance ID of the object where the resource exists. + * \return Object instance ID. + */ + uint16_t get_argument_object_instance_id() const; + +private: + // pointers to const data, not owned by this instance + +#ifdef MEMORY_OPTIMIZED_API + const char *_object_name; + const char *_resource_name; +#else + const String &_object_name; + const String &_resource_name; +#endif + + const uint8_t *_value; + uint16_t _value_length; + uint16_t _object_instance_id; + +friend class Test_M2MResource; +friend class M2MResource; +}; + +#endif // M2M_RESOURCE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mresourcebase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mresourcebase.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_RESOURCE_BASE_H +#define M2M_RESOURCE_BASE_H + +#include "mbed-client/m2mbase.h" +#include "mbed-client/functionpointer.h" + + +/*! \file m2mresourceinstance.h + * \brief M2MResourceInstance. + * This class is the base class for mbed Client Resources. All defined + * LWM2M resource models can be created based on it. + */ +class M2MBlockMessage; + +typedef FP1<void,void*> execute_callback; +typedef void(*execute_callback_2) (void *arguments); + +typedef FP0<void> notification_sent_callback; +typedef void(*notification_sent_callback_2) (void); + +#ifndef DISABLE_BLOCK_MESSAGE +typedef FP1<void, M2MBlockMessage *> incoming_block_message_callback; +typedef FP3<void, const String &, uint8_t *&, uint32_t &> outgoing_block_message_callback; +#endif + +class M2MResource; + +class M2MResourceBase : public M2MBase { + +friend class M2MObjectInstance; +friend class M2MResource; +friend class M2MResourceInstance; + +public: + + typedef enum { + INIT = 0, // Initial state. + SENT, // Notification created/sent but not received ACK yet. + DELIVERED // Received ACK from server. + } NoticationStatus; + + typedef FP2<void, const uint16_t, const M2MResourceBase::NoticationStatus> notification_status_callback; + + typedef void(*notification_status_callback_2) (const uint16_t msg_id, + const M2MResourceBase::NoticationStatus status); + + /** + * An enum defining a resource type that can be + * supported by a given resource. + */ + typedef enum { + STRING, + INTEGER, + FLOAT, + BOOLEAN, + OPAQUE, + TIME, + OBJLINK + }ResourceType; + +protected: // Constructor and destructor are private + // which means that these objects can be created or + // deleted only through a function provided by the M2MObjectInstance. + + M2MResourceBase( + const lwm2m_parameters_s* s, + M2MBase::DataType type); + /** + * \brief A constructor for creating a resource. + * \param resource_name The name of the resource. + * \param resource_type The type of the resource. + * \param type The resource data type of the object. + * \param object_name Object name where resource exists. + * \param path Path of the object like 3/0/1 + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + */ + M2MResourceBase( + const String &resource_name, + M2MBase::Mode mode, + const String &resource_type, + M2MBase::DataType type, + char* path, + bool external_blockwise_store, + bool multiple_instance); + + /** + * \brief A Constructor for creating a resource. + * \param resource_name The name of the resource. + * \param resource_type The type of the resource. + * \param type The resource data type of the object. + * \param value The value pointer of the object. + * \param value_length The length of the value pointer. + * \param value_length The length of the value pointer. + * \param object_name Object name where resource exists. + * \param path Path of the object like 3/0/1 + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + */ + M2MResourceBase( + const String &resource_name, + M2MBase::Mode mode, + const String &resource_type, + M2MBase::DataType type, + const uint8_t *value, + const uint8_t value_length, + char* path, + bool external_blockwise_store, + bool multiple_instance); + + // Prevents the use of default constructor. + M2MResourceBase(); + + // Prevents the use of assignment operator. + M2MResourceBase& operator=( const M2MResourceBase& /*other*/ ); + + // Prevents the use of copy constructor + M2MResourceBase( const M2MResourceBase& /*other*/ ); + + /** + * Destructor + */ + virtual ~M2MResourceBase(); + +public: + + /** + * \brief Returns the resource data type. + * \return ResourceType. + */ + M2MResourceBase::ResourceType resource_instance_type() const; + + /** + * \brief Sets the function that should be executed when this + * resource receives a POST command. + * \param callback The function pointer that needs to be executed. + * \return True, if callback could be set, false otherwise. + */ + bool set_execute_function(execute_callback callback); + + /** + * \brief Sets the function that should be executed when this + * resource receives a POST command. + * \param callback The function pointer that needs to be executed. + * \return True, if callback could be set, false otherwise. + */ + bool set_execute_function(execute_callback_2 callback); + + /** + * \brief Sets a value of a given resource. + * \param value A pointer to the value to be set on the resource. + * \param value_length The length of the value pointer. + * \return True if successfully set, else false. + * \note If resource is observable, calling this API rapidly (< 1s) can fill up the CoAP resending queue + * and notification sending fails. CoAP resending queue size can be modified through: + * "sn-coap-resending-queue-size-msgs" and "sn-coap-resending-queue-size-bytes" parameters. + * Increasing these parameters will increase the memory consumption. + */ + bool set_value(const uint8_t *value, const uint32_t value_length); + + /** + * \brief Sets a value of a given resource. + * \param value A pointer to the value to be set on the resource, ownerhip transfered. + * \param value_length The length of the value pointer. + * \return True if successfully set, else false. + * \note If resource is observable, calling this API rapidly (< 1s) can fill up the CoAP resending queue + * and notification sending fails. CoAP resending queue size can be modified through: + * "sn-coap-resending-queue-size-msgs" and "sn-coap-resending-queue-size-bytes" parameters. + * Increasing these parameters will increase the memory consumption. + */ + bool set_value_raw(uint8_t *value, const uint32_t value_length); + + /** + * \brief Sets a value of a given resource. + * \param value, A new value formatted as a string + * and set on the resource. + * \return True if successfully set, else false. + * \note If resource is observable, calling this API rapidly (< 1s) can fill up the CoAP resending queue + * and notification sending fails. CoAP resending queue size can be modified through: + * "sn-coap-resending-queue-size-msgs" and "sn-coap-resending-queue-size-bytes" parameters. + * Increasing these parameters will increase the memory consumption. + */ + bool set_value(int64_t value); + + /** + * \brief Clears the value of a given resource. + */ + void clear_value(); + + /** + * \brief Executes the function that is set in "set_execute_function". + * \param arguments The arguments that are passed to be executed. + */ + void execute(void *arguments); + + /** + * \brief Provides the value of the given resource. + * \param value[OUT] A pointer to the resource value. + * \param value_length[OUT] The length of the value pointer. + */ + void get_value(uint8_t *&value, uint32_t &value_length); + + /** + * \brief Converts a value to integer and returns it. Note: Conversion + * errors are not detected. + */ + int64_t get_value_int() const; + + /** + * Get the value as a string object. No encoding/charset conversions + * are done for the value, just a raw copy. + */ + String get_value_string() const; + + /** + * \brief Returns the value pointer of the object. + * \return The value pointer of the object. + */ + uint8_t* value() const; + + /** + * \brief Returns the length of the value pointer. + * \return The length of the value pointer. + */ + uint32_t value_length() const; + + + /** + * \brief Handles the GET request for the registered objects. + * \param nsdl An NSDL handler for the CoAP library. + * \param received_coap_header The CoAP message received from the server. + * \param observation_handler A handler object for sending + * observation callbacks. + * \return sn_coap_hdr_s The message that needs to be sent to the server. + */ + virtual sn_coap_hdr_s* handle_get_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler = NULL); + /** + * \brief Handles the PUT request for the registered objects. + * \param nsdl An NSDL handler for the CoAP library. + * \param received_coap_header The CoAP message received from the server. + * \param observation_handler A handler object for sending + * observation callbacks. + * \param execute_value_updated True will execute the "value_updated" callback. + * \return sn_coap_hdr_s The message that needs to be sent to the server. + */ + virtual sn_coap_hdr_s* handle_put_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated); + + /** + * \brief Returns the instance ID of the object where the resource exists. + * \return Object instance ID. + */ + virtual uint16_t object_instance_id() const = 0; + + /** + * \brief Returns the name of the object where the resource exists. + * \return Object name. + */ + virtual const char* object_name() const = 0; + + virtual M2MResource& get_parent_resource() const = 0; + +#ifndef DISABLE_BLOCK_MESSAGE + /** + * @brief Sets the function that is executed when this + * object receives a block-wise message. + * @param callback The function pointer that is called. + */ + bool set_incoming_block_message_callback(incoming_block_message_callback callback); + + /** + * @brief Sets the function that is executed when this + * object receives a GET request. + * This is called if resource values are stored on the application side. + * NOTE! Due to a limitation in the mbed-client-c library, a GET request can only contain data size up to 65KB. + * @param callback The function pointer that is called. + */ + bool set_outgoing_block_message_callback(outgoing_block_message_callback callback); + + /** + * \brief Returns the block message object. + * \return Block message. + */ + M2MBlockMessage* block_message() const; + +#endif + + /** + * @brief Sets the function that is executed when this object receives + * response(Empty ACK) for notification message. + * @param callback The function pointer that is called. + */ + bool set_notification_sent_callback(notification_sent_callback callback) m2m_deprecated; + + /** + * @brief Sets the function that is executed when this object receives + * response(Empty ACK) for notification message. + * @param callback The function pointer that is called. + */ + bool set_notification_sent_callback(notification_sent_callback_2 callback) m2m_deprecated; + + /** + * @brief Sets the function that is executed when this object receives + * response(Empty ACK) for notification message. + * @param callback The function pointer that is called. + */ + bool set_notification_status_callback(notification_status_callback callback) m2m_deprecated; + + /** + * @brief Sets the function that is executed when this object receives + * response(Empty ACK) for notification message. + * @param callback The function pointer that is called. + */ + bool set_notification_status_callback(notification_status_callback_2 callback); + + /** + * \brief Executes the function that is set in "set_notification_sent_callback". + */ + void notification_sent(); + + /** + * \brief Executes the function that is set in "set_notification_status_callback". + */ + void notification_status(const uint16_t msg_id, NoticationStatus status); + + /** + * \brief Returns notification send status. + * \return Notification status. + */ + M2MResourceBase::NoticationStatus notification_status() const; + + /** + * \brief Clears the notification send status to initial state. + */ + void clear_notification_status(); + +private: + + void report(); + + void report_value_change(); + + bool has_value_changed(const uint8_t* value, const uint32_t value_len); + + M2MResourceBase::ResourceType convert_data_type(M2MBase::DataType type) const; + +private: + +#ifndef DISABLE_BLOCK_MESSAGE + M2MBlockMessage *_block_message_data; +#endif + + NoticationStatus _notification_status : 2; + + friend class Test_M2MResourceInstance; + friend class Test_M2MResource; + friend class Test_M2MObjectInstance; + friend class Test_M2MObject; + friend class Test_M2MDevice; + friend class Test_M2MSecurity; + friend class Test_M2MServer; + friend class Test_M2MNsdlInterface; + friend class Test_M2MFirmware; + friend class Test_M2MTLVSerializer; + friend class Test_M2MTLVDeserializer; +}; + +#endif // M2M_RESOURCE_BASE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mresourceinstance.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mresourceinstance.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_RESOURCE_INSTANCE_H +#define M2M_RESOURCE_INSTANCE_H + +#include "mbed-client/m2mresourcebase.h" + + +/*! \file m2mresourceinstance.h + * \brief M2MResourceInstance. + * This class is the base class for mbed Client Resources. All defined + * LWM2M resource models can be created based on it. + */ +class M2MBlockMessage; + + +class M2MResource; + +class M2MResourceInstance : public M2MResourceBase { + +friend class M2MObjectInstance; +friend class M2MResource; + +private: // Constructor and destructor are private + // which means that these objects can be created or + // deleted only through a function provided by the M2MObjectInstance. + + M2MResourceInstance(M2MResource &parent, + const lwm2m_parameters_s* s, + M2MBase::DataType type); + /** + * \brief A constructor for creating a resource. + * \param resource_name The name of the resource. + * \param resource_type The type of the resource. + * \param type The resource data type of the object. + * \param object_name Object name where resource exists. + * \param path Path of the object like 3/0/1 + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + */ + M2MResourceInstance(M2MResource &parent, + const String &resource_name, + M2MBase::Mode mode, + const String &resource_type, + M2MBase::DataType type, + char* path, + bool external_blockwise_store, + bool multiple_instance); + + /** + * \brief A Constructor for creating a resource. + * \param resource_name The name of the resource. + * \param resource_type The type of the resource. + * \param type The resource data type of the object. + * \param value The value pointer of the object. + * \param value_length The length of the value pointer. + * \param value_length The length of the value pointer. + * \param object_name Object name where resource exists. + * \param path Path of the object like 3/0/1 + * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks + * otherwise handled in mbed-client-c. + */ + M2MResourceInstance(M2MResource &parent, + const String &resource_name, + M2MBase::Mode mode, + const String &resource_type, + M2MBase::DataType type, + const uint8_t *value, + const uint8_t value_length, + char* path, + bool external_blockwise_store, + bool multiple_instance); + + // Prevents the use of default constructor. + M2MResourceInstance(); + + // Prevents the use of assignment operator. + M2MResourceInstance& operator=( const M2MResourceInstance& /*other*/ ); + + // Prevents the use of copy constructor + M2MResourceInstance( const M2MResourceInstance& /*other*/ ); + + /** + * Destructor + */ + virtual ~M2MResourceInstance(); + +public: + + /** + * \brief Returns the Observation Handler object. + * \return M2MObservationHandler object. + */ + virtual M2MObservationHandler* observation_handler() const; + + /** + * \brief Sets the observation handler + * \param handler Observation handler + */ + virtual void set_observation_handler(M2MObservationHandler *handler); + + /** + * \brief Parses the received query for a notification + * attribute. + * \return True if required attributes are present, else false. + */ + virtual bool handle_observation_attribute(const char *query); + + + /** + * \brief Returns the instance ID of the object where the resource exists. + * \return Object instance ID. + */ + virtual uint16_t object_instance_id() const; + + /** + * \brief Returns the name of the object where the resource exists. + * \return Object name. + */ + virtual const char* object_name() const; + + /** + * \brief Get reference to the resource owning this resource instance. + * \return parent resource + */ + virtual M2MResource& get_parent_resource() const; + +private: + + // Parent resource which owns this resource instance + M2MResource &_parent_resource; + + friend class Test_M2MResourceInstance; + friend class Test_M2MResource; + friend class Test_M2MObjectInstance; + friend class Test_M2MObject; + friend class Test_M2MDevice; + friend class Test_M2MSecurity; + friend class Test_M2MServer; + friend class Test_M2MNsdlInterface; + friend class Test_M2MFirmware; + friend class Test_M2MTLVSerializer; + friend class Test_M2MTLVDeserializer; +}; + +#endif // M2M_RESOURCE_INSTANCE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2msecurity.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2msecurity.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_SECURITY_H +#define M2M_SECURITY_H + +#include "mbed-client/m2mobject.h" + +// FORWARD DECLARATION +class M2MResource; + +/*! \file m2msecurity.h + * \brief M2MSecurity. + * This class represents an interface for the Security Object model of the LWM2M framework. + * It handles the security object instances and all corresponding + * resources. + */ + +class M2MSecurity : public M2MObject { + +friend class M2MInterfaceFactory; +friend class M2MNsdlInterface; + +public: + + /** + * \brief An enum defining all resources associated with a + * Security Object in the LWM2M framework. + */ + typedef enum { + M2MServerUri, + BootstrapServer, + SecurityMode, + PublicKey, + ServerPublicKey, + Secretkey, + SMSSecurityMode, + SMSBindingKey, + SMSBindingSecretKey, + M2MServerSMSNumber, + ShortServerID, + ClientHoldOffTime + }SecurityResource; + + /** + * \brief An enum defining the type of the security attribute + * used by the Security Object. + */ + typedef enum { + SecurityNotSet = -1, + Psk = 0, + Certificate = 2, + NoSecurity = 3 + } SecurityModeType; + + /** + * \brief An enum defining an interface operation that can be + * handled by the Security Object. + */ + typedef enum { + M2MServer = 0x0, + Bootstrap = 0x1 + } ServerType; + +private: + + /** + * \brief Constructor + * \param server_type The type of the security object created. Either bootstrap or LWM2M server. + */ + M2MSecurity(ServerType server_type); + + + /** + * \brief Destructor + */ + virtual ~M2MSecurity(); + + // Prevents the use of default constructor. + M2MSecurity(); + + // Prevents the use of assignment operator. + M2MSecurity& operator=( const M2MSecurity& /*other*/ ); + + // Prevents the use of copy constructor + M2MSecurity( const M2MSecurity& /*other*/ ); + +public: + + /** + * \brief Get the singleton instance of M2MSecurity + */ + static M2MSecurity* get_instance(); + + /** + * \brief Delete the singleton instance of M2MSecurity + */ + static void delete_instance(); + + /** + * \brief Creates a new object instance. + * \param server_type Server type for new object instance. + * \return M2MObjectInstance if created successfully, else NULL. + */ + M2MObjectInstance* create_object_instance(ServerType server_type); + + /** + * \brief Remove all security object instances. + */ + void remove_security_instances(); + + /** + * \brief Creates a new resource for a given resource enum. + * \param rescource With this function, the following resources can be created: + * ' BootstrapServer', 'SecurityMode', 'SMSSecurityMode', + * 'M2MServerSMSNumber', 'ShortServerID', 'ClientHoldOffTime'. + * \param value The value to be set on the resource, in integer format. + * \param instance_id Instance id of the security instance where resource should be created. + * \return M2MResource if created successfully, else NULL. + */ + M2MResource* create_resource(SecurityResource rescource, uint32_t value, uint16_t instance_id); + + /** + * \brief Deletes a resource with a given resource enum. + * Mandatory resources cannot be deleted. + * \param resource The resource to be deleted. + * \param instance_id Instance id of the security instance where resource should be deleted. + * \return True if deleted, else false. + */ + bool delete_resource(SecurityResource rescource, uint16_t instance_id); + + /** + * \brief Sets the value of a given resource enum. + * \param resource With this function, a value can be set for the following resources: + * 'M2MServerUri', 'SMSBindingKey', 'SMSBindingSecretKey'. + * \param value The value to be set on the resource, in string format. + * \param instance_id Instance id of the security instance where resource value should be set. + * \return True if successfully set, else false. + */ + bool set_resource_value(SecurityResource resource, + const String &value, + uint16_t instance_id); + + /** + * \brief Sets the value of a given resource enum. + * \param resource With this function, a value can be set for the following resourecs: + * 'BootstrapServer', 'SecurityMode', 'SMSSecurityMode', + * 'M2MServerSMSNumber', 'ShortServerID', 'ClientHoldOffTime'. + * \param value The value to be set on the resource, in integer format. + * \param instance_id Instance id of the security instance where resource value should be set. + * \return True if successfully set, else false. + */ + bool set_resource_value(SecurityResource resource, + uint32_t value, + uint16_t instance_id); + + /** + * \brief Sets the value of a given resource enum. + * \param resource With this function, a value can be set for the follwing resources: + * 'PublicKey', 'ServerPublicKey', 'Secretkey'. + * \param value The value to be set on the resource, in uint8_t format. + * \param length The size of the buffer value to be set on the resource. + * \param instance_id Instance id of the security instance where resource value should be set. + * \return True if successfully set, else false. + */ + bool set_resource_value(SecurityResource resource, + const uint8_t *value, + const uint16_t length, + uint16_t instance_id); + + /** + * \brief Returns the value of a given resource enum, in string format. + * \param resource With this function, the following resources can return a value: + * 'M2MServerUri','SMSBindingKey', 'SMSBindingSecretKey'. + * \param instance_id Instance id of the security instance where resource value should be retrieved. + * \return The value associated with the resource. If the resource is not valid an empty string is returned. + */ + String resource_value_string(SecurityResource resource, uint16_t instance_id) const; + + /** + * \brief Populates the data buffer and returns the size of the buffer. + * \param resource With this function, the following resources can return a value: + * 'PublicKey', 'ServerPublicKey', 'Secretkey'. + * \param [OUT]data A copy of the data buffer that contains the value. The caller + * is responsible for freeing this buffer. + * \param instance_id Instance id of the security instance where resource value should be retrieve. + * \return The size of the populated buffer. + */ + uint32_t resource_value_buffer(SecurityResource resource, + uint8_t *&data, + uint16_t instance_id) const; + + /** + * \brief Returns a pointer to the value and size of the buffer. + * \param resource With this function, the following resources can return a value: + * 'PublicKey', 'ServerPublicKey', 'Secretkey'. + * \param [OUT]data A pointer to the data buffer that contains the value. + * \param instance_id Instance id of the security instance where resource value should be retrieved. + * \return The size of the populated buffer. + */ + uint32_t resource_value_buffer(SecurityResource resource, + const uint8_t *&data, + uint16_t instance_id) const; + + /** + * \brief Returns the value of a given resource name, in integer format. + * \param resource With this function, the following resources can return a value: + * 'BootstrapServer', 'SecurityMode', 'SMSSecurityMode', + * 'M2MServerSMSNumber', 'ShortServerID', 'ClientHoldOffTime'. + * \param instance_id Instance id of the security instance where resource should be created. + * \return The value associated with the resource. If the resource is not valid 0 is returned. + */ + uint32_t resource_value_int(SecurityResource resource, + uint16_t instance_id) const; + + /** + * \brief Returns whether a resource instance with a given resource enum exists or not + * \param resource Resource enum. + * \param instance_id Instance id of the security instance where resource should be checked. + * \return True if at least one instance exists, else false. + */ + bool is_resource_present(SecurityResource resource, + uint16_t instance_id) const; + + /** + * \brief Returns the total number of resources for a security object. + * \param instance_id Instance id of the security instance where resources should be counted. + * \return The total number of resources. + */ + uint16_t total_resource_count(uint16_t instance_id) const; + + /** + * \brief Returns the type of the Security Object. It can be either + * Bootstrap or M2MServer. + * \param instance_id Instance id of the security instance where resource should be created. + * \return ServerType The type of the Security Object. + */ + ServerType server_type(uint16_t instance_id) const; + + /** + * \brief Returns first bootstrap or lwm2m server security object instance id. + * \param server_type Which server type security instance to return. + * \return Object instance id, or -1 if no such instance exists. + */ + int32_t get_security_instance_id(ServerType server_type) const; + +private: + + M2MResource* get_resource(SecurityResource resource, uint16_t instance_id = 0) const; + void clear_resources(uint16_t instance_id = 0); + +protected: + static M2MSecurity* _instance; + + friend class Test_M2MSecurity; + friend class Test_M2MInterfaceImpl; + friend class Test_M2MConnectionSecurityImpl; + friend class Test_M2MConnectionHandlerPimpl_linux; + friend class Test_M2MConnectionHandlerPimpl_mbed; + friend class Test_M2MConnectionSecurityPimpl; + friend class Test_M2MNsdlInterface; + friend class Test_M2MConnectionHandlerPimpl_classic; +}; + +#endif // M2M_SECURITY_H + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mserver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mserver.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_SERVER_H +#define M2M_SERVER_H + +#include "mbed-client/m2mobject.h" + +// FORWARD DECLARATION +class M2MResource; + +/*! \file m2mserver.h + * \brief M2MServer. + * This class represents an interface for the Server Object model of the LWM2M framework. + * It handles the server object and all its corresponding + * resources. + */ + +class M2MServer : public M2MObject +{ + +friend class M2MInterfaceFactory; +friend class M2MNsdlInterface; + +public: + + /** + * \brief Am enum defining all resources associated with + * a Server Object in the LWM2M framework. + */ + typedef enum { + ShortServerID, + Lifetime, + DefaultMinPeriod, + DefaultMaxPeriod, + Disable, + DisableTimeout, + NotificationStorage, + Binding, + RegistrationUpdate + }ServerResource; + +private: + + /** + * \brief Constructor + */ + M2MServer(); + + + // Prevents the use of assignment operator. + M2MServer& operator=( const M2MServer& /*other*/ ); + + // Prevents the use of copy constructor + M2MServer( const M2MServer& /*other*/ ); + +public: + + /** + * \brief Destructor + */ + virtual ~M2MServer(); + + /** + * \brief Creates a new resource for a given resource enum. + * \param resource With this function, a value can be set to the following resources: + * 'ShortServerID','Lifetime','DefaultMinPeriod','DefaultMaxPeriod','DisableTimeout', + * 'NotificationStorage'. + * \param value The value to be set on the resource, in integer format. + * \return M2MResource if created successfully, else NULL. + */ + M2MResource* create_resource(ServerResource resource, uint32_t value); + + /** + * \brief Creates a new resource for a given resource enum. + * \param resource With this function, the following resources can be created: + * 'Disable', 'RegistrationUpdate' + * \return M2MResource if created successfully, else NULL. + */ + M2MResource* create_resource(ServerResource resource); + + /** + * \brief Deletes the resource with the given resource enum. + * Mandatory resources cannot be deleted. + * \param resource The name of the resource to be deleted. + * \return True if deleted, else false. + */ + bool delete_resource(ServerResource rescource); + + /** + * \brief Sets the value of a given resource enum. + * \param resource With this function, a value can be set on the following resources: + * 'Binding'. + * \param value The value to be set on the resource, in string format. + * \return True if successfully set, else false. + */ + bool set_resource_value(ServerResource resource, + const String &value); + + /** + * \brief Sets the value of a given resource enum. + * \param resource With this function, a value can be set to the following resources: + * 'ShortServerID','Lifetime','DefaultMinPeriod','DefaultMaxPeriod','DisableTimeout', + * 'NotificationStorage'. + * \param value The value to be set on the resource, in integer format. + * \return True if successfully set, else false. + */ + bool set_resource_value(ServerResource resource, + uint32_t value); + /** + * \brief Returns the value of the given resource enum, in string format. + * \param resource With this function, the following resources can return a value: + * 'Binding'. + * \return The value associated with the resource. If the resource is not valid an empty string is returned. + */ + String resource_value_string(ServerResource resource) const; + + /** + * \brief Returns the value of a given resource name, in integer format. + * \param resource With this function, the following resources can return a value: + * 'ShortServerID','Lifetime','DefaultMinPeriod','DefaultMaxPeriod','DisableTimeout', + * 'NotificationStorage' + * \return The value associated with the resource. If the resource is not valid -1 is returned. + */ + uint32_t resource_value_int(ServerResource resource) const; + + /** + * \brief Returns whether the resource instance with the given resource enum exists or not. + * \param resource Resource enum. + * \return True if at least one instance exists, else false. + */ + bool is_resource_present(ServerResource resource)const; + + /** + * \brief Returns the total number of resources for the server object. + * \return The total number of resources. + */ + uint16_t total_resource_count()const; + +private: + + M2MResource* get_resource(ServerResource res) const; + + +private: + + M2MObjectInstance* _server_instance; + + friend class Test_M2MServer; + friend class Test_M2MNsdlInterface; +}; + +#endif // M2M_SERVER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mstring.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mstring.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_STRING_H +#define M2M_STRING_H + +#include <stddef.h> // size_t +#include <stdint.h> + +class Test_M2MString; + +namespace m2m +{ + +/*! \file m2mstring.h +* \brief A simple C++ string class, used as replacement for std::string. + */ + class String + { + char* p; ///< The data. + size_t allocated_; ///< The allocated memory size (including trailing NULL). + size_t size_; ///< The currently used memory size (excluding trailing NULL). + + public: + typedef size_t size_type; + static const size_type npos; + + String(); + ~String(); + String(const String&); + String(const char*); + String(const char*, size_t); + + String& operator=(const char*); + String& operator=(const String&); + + String& operator+=(const String&); + String& operator+=(const char*); + String& operator+=(char); + void push_back(char); + + bool operator==(const char*) const; + bool operator==(const String&) const; + + void clear(); // Set the string to empty (memory remains reserved). + + size_type size() const { return size_; } ///< size without terminating NULL + size_type length() const { return size_; } ///< as size() + + size_type capacity() const { return allocated_-1; } + + bool empty() const { return size_ == 0; } + + const char* c_str() const { return p; } ///< raw data + + /** Reserve internal string memory so that n characters can be put into the + string (plus 1 for the NULL char). If there is already enough memory, + nothing happens, if not, the memory is realloated to exactly this + amount. + */ + void reserve( size_type n); + + /** Resize string. If n is less than the current size, the string is truncated. + If n is larger, the memory is reallocated to exactly this amount, and + the additional characters are NULL characters. + */ + void resize( size_type n); + + /** Resize string. If n is less than the current size, the string is truncated. + If n is larger, the memory is reallocated to exactly this amount, and + the additional characters are c characters. + */ + void resize( size_type n, char c); + + /// swap contents + void swap( String& ); + + String substr(const size_type pos, size_type length) const; + + // unchecked access: + char& operator[](const size_type i) { return p[i]; } + char operator[](const size_type i) const { return p[i]; } + // checked access: + char at(const size_type i) const; + + /// erase len characters at position pos + String& erase(size_type pos, size_type len); + /// Append n characters of a string + String& append(const char* str, size_type n); + + // Append n characters of a non-zero-terminated string + // (in contrast with other append(), which performs strlen() for the given string). + String& append_raw(const char*, size_type); + + // convert int to ascii and append it to end of string + void append_int(int); + + int compare( size_type pos, size_type len, const String& str ) const; + int compare( size_type pos, size_type len, const char* str ) const; + + int find_last_of(char c) const; + + static uint8_t* convert_integer_to_array(int64_t value, uint8_t &size, const uint8_t *array = NULL, const uint32_t array_size = 0); + static int64_t convert_array_to_integer(const uint8_t *value, const uint32_t size); + + private: + // reallocate the internal memory + void new_realloc( size_type n); + char* strdup(const char* other); + + friend class ::Test_M2MString; + + }; + // class + + bool operator<(const String&, const String&); + + void reverse(char s[], uint32_t length); + + uint32_t itoa_c (int64_t n, char s[]); +} // namespace + + +#endif // M2M_STRING_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mstringbuffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mstringbuffer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __STRING_BUFFER_H__ +#define __STRING_BUFFER_H__ + +#include "mbed-client/m2mstringbufferbase.h" + +#include <assert.h> +#include <stddef.h> + +template <int SIZE> +class StringBuffer : private StringBufferBase +{ +public: + /** + * Initialize a empty buffer with zero length and zero content. + */ + inline StringBuffer(); + + // + // This is not implemented on purpose, as the given string may conflict with + // templated size. Otoh, if we used compile time assert, the overflow + // could be prevented at compile time. + // + // inline StringBuffer(const char *initial_string); + + /** + * Verify, if the buffer has still room for given amount of bytes. + * Note: the given size value must include the zero terminator as it is not + * implicitly taken into account for. + */ + bool ensure_space(size_t required_size) const; + + /** + * Append given char to end of string. + * Return false if the buffer would overflow, true otherwise. + */ + bool append(char data); + + /** + * Append given zero terminated string to end of buffer. + * + * Return false if the buffer would overflow, true otherwise. + * + * Note: the whole string, including the zero terminator must fit + * to buffer or the append operation is not done and false is returned. + */ + bool append(const char *data); + + /** + * Append given block of chars to end of buffer. + * + * Return false if the buffer would overflow, true otherwise. + * + * Note: the whole string, including the zero terminator must fit + * to buffer or the append operation is not done and false is returned. + */ + bool append(const char *data, size_t data_len); + + /** + * Convert given uint16_t into string representation and add it to the + * end of buffer. + * + * Note: the whole string, including the zero terminator must fit + * to buffer or the append operation is not done and false is returned. + */ + bool append_int(uint16_t data); + + /** + * Get the amount of bytes added to the buffer. + * + * Note: the size does not include the terminating zero, so this is + * functionally equal to strlen(). + */ + inline size_t get_size() const; + + // API functionality copied from m2mstring: + + // find the index of last occurance of given char in string, or negative if not found + int find_last_of(char search_char) const; + + /** + * Get a read only pointer to the data. + */ + inline const char* c_str() const; + + // Add this only if needed + //inline char* c_str(); +private: + char _buff[SIZE]; +}; + +template <int SIZE> +inline StringBuffer<SIZE>::StringBuffer() +{ + // actually a assert_compile() would be better as this is completely a code problem + assert(SIZE > 0); + + _buff[0] = '\0'; +} + +template <int SIZE> +bool StringBuffer<SIZE>::ensure_space(size_t required_size) const +{ + return StringBufferBase::ensure_space(SIZE, required_size); +} + +template <int SIZE> +bool StringBuffer<SIZE>::append(const char *data) +{ + return StringBufferBase::append(_buff, SIZE, data); +} + +template <int SIZE> +bool StringBuffer<SIZE>::append(const char *data, size_t data_len) +{ + return StringBufferBase::append(_buff, SIZE, data, data_len); +} + +template <int SIZE> +inline bool StringBuffer<SIZE>::append(char data) +{ + return StringBufferBase::append(_buff, SIZE, data); +} + +template <int SIZE> +bool StringBuffer<SIZE>::append_int(uint16_t data) +{ + return StringBufferBase::append_int(_buff, SIZE, data); +} + +template <int SIZE> +int StringBuffer<SIZE>::find_last_of(char search_char) const +{ + return StringBufferBase::find_last_of(_buff, search_char); +} + +template <int SIZE> +inline const char* StringBuffer<SIZE>::c_str() const +{ + return _buff; +} + +template <int SIZE> +inline size_t StringBuffer<SIZE>::get_size() const +{ + return _curr_size; +} + +#endif // !__STRING_BUFFER_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mstringbufferbase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mstringbufferbase.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __STRING_BUFFER_BASE_H__ +#define __STRING_BUFFER_BASE_H__ + +#include <stdint.h> +#include <stddef.h> + +class StringBufferBase +{ +protected: + + // inline version of this produces smaller code + inline StringBufferBase(); + + // all the docs are at template level, as it is the only public API + + bool ensure_space(size_t max_size, size_t required_size) const; + + bool append(char *buff, size_t max_size, char data); + + bool append(char *buff, size_t max_size, const char *data); + + bool append(char *buff, size_t max_size, const char *data, size_t data_len); + + bool append_int(char *buff, size_t max_size, uint16_t data); + + int find_last_of(const char *buff, char search_char) const; + +protected: + //const size_t _max_size; + size_t _curr_size; +}; + +inline StringBufferBase::StringBufferBase() : _curr_size(0) +{ +} + +#endif // !__STRING_BUFFER_BASE_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mtimer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mtimer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_TIMER_H +#define M2M_TIMER_H + +#include <stdint.h> +#include "mbed-client/m2mtimerobserver.h" + +class M2MTimerPimpl; + +/*! \file m2mtimer.h +* \brief M2MTimer. +* Timer class for mbed client. +*/ +class M2MTimer +{ +private: + // Prevents the use of assignment operator + M2MTimer& operator=(const M2MTimer& other); + + // Prevents the use of copy constructor + M2MTimer(const M2MTimer& other); + +public: + + /** + * Constructor. + */ + M2MTimer(M2MTimerObserver& observer); + + /** + * Destructor. + */ + ~M2MTimer(); + + /** + * \brief Starts the timer. + * \param interval The timer interval in milliseconds. + * \param single_shot Defines whether the timer is ticked once or restarted every time at expiry. + */ + void start_timer(uint64_t interval, M2MTimerObserver::Type type, bool single_shot = true); + + /** + * \brief Starts the timer in DTLS manner. + * \param intermediate_interval The intermediate interval to use, must be smaller than total (usually 1/4 of total). + * \param total_interval The total interval to use; This is the timeout value of a DTLS packet. + * \param type The type of the timer. + */ + void start_dtls_timer(uint64_t intermediate_interval, uint64_t total_interval, M2MTimerObserver::Type type = M2MTimerObserver::Dtls); + + /** + * \brief Stops the timer. + * This cancels the ongoing timer. + */ + void stop_timer(); + + /** + * \brief Checks if the intermediate interval has passed. + * \return True if the interval has passed, else false. + */ + bool is_intermediate_interval_passed(); + + /** + * \brief Checks if the total interval has passed. + * \return True if the interval has passed, else false. + */ + bool is_total_interval_passed(); + +private: + + M2MTimerObserver& _observer; + M2MTimerPimpl *_private_impl; + friend class Test_M2MTimerImpl_linux; +}; + +#endif // M2M_TIMER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mtimerobserver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mtimerobserver.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_TIMER_OBSERVER_H +#define M2M_TIMER_OBSERVER_H + +/*! \file m2mtimerobserver.h + * \brief M2MTimerObserver. + * Observer class for indicating the timer expiry to the parent class. + */ +class M2MTimerObserver +{ +public: + /** + * \enum Defines the types of timer + * that can be created for mbed Client. + */ + typedef enum { + Notdefined, + Registration, + NsdlExecution, + PMinTimer, + PMaxTimer, + Dtls, + QueueSleep, + RetryTimer, + BootstrapFlowTimer, + RegistrationFlowTimer + }Type; + + /** + * \brief Indicates that the timer has expired. + * \param type The type of the timer that has expired. + */ + virtual void timer_expired(M2MTimerObserver::Type type = + M2MTimerObserver::Notdefined) = 0; +}; + +#endif // M2M_TIMER_OBSERVER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mvector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed-client/m2mvector.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2015-2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef M2M_VECTOR_H +#define M2M_VECTOR_H + +/*! \file m2mvector.h +* \brief A simple C++ Vector class, used as replacement for std::vector. +*/ + + +namespace m2m +{ + +template <typename ObjectTemplate> + +class Vector +{ + public: + explicit Vector( int init_size = MIN_CAPACITY) + : _size(0), + _capacity((init_size >= MIN_CAPACITY) ? init_size : MIN_CAPACITY) { + _object_template = new ObjectTemplate[ _capacity ]; + } + + Vector(const Vector & rhs ): _object_template(0) { + operator=(rhs); + } + + ~Vector() { + delete [] _object_template; + } + + const Vector & operator=(const Vector & rhs) { + if(this != &rhs) { + delete[] _object_template; + _size = rhs.size(); + _capacity = rhs._capacity; + + _object_template = new ObjectTemplate[capacity()]; + for(int k = 0; k < size(); k++) { + _object_template[k] = rhs._object_template[k]; + } + } + return *this; + } + + void resize(int new_size) { + if(new_size > _capacity) { + reserve(new_size * 2 + 1); + } + _size = new_size; + } + + void reserve(int new_capacity) { + if(new_capacity < _size) { + return; + } + ObjectTemplate *old_array = _object_template; + + _object_template = new ObjectTemplate[new_capacity]; + for(int k = 0; k < _size; k++) { + _object_template[k] = old_array[k]; + } + _capacity = new_capacity; + delete [] old_array; + } + + ObjectTemplate & operator[](int idx) { + return _object_template[idx]; + } + + const ObjectTemplate& operator[](int idx) const { + return _object_template[idx]; + } + + bool empty() const{ + return size() == 0; + } + + int size() const { + return _size; + } + + int capacity() const { + return _capacity; + } + + void push_back(const ObjectTemplate& x) { + if(_size == _capacity) { + reserve(2 * _capacity + 1); + } + _object_template[_size] = x; + _size++; + } + + void pop_back() { + _size--; + } + + void clear() { + _size = 0; + } + + const ObjectTemplate& back() const { + return _object_template[_size - 1]; + } + + typedef ObjectTemplate* iterator; + typedef const ObjectTemplate* const_iterator; + + iterator begin() { + return &_object_template[0]; + } + + const_iterator begin() const { + return &_object_template[0]; + } + + iterator end() { + return &_object_template[_size]; + } + + const_iterator end() const { + return &_object_template[_size]; + } + + void erase(int position) { + if(position < _size) { + for(int k = position; k + 1 < _size; k++) { + _object_template[k] = _object_template[k + 1]; + } + _size--; + } + } + + enum { + MIN_CAPACITY = 1 + }; + + private: + int _size; + int _capacity; + ObjectTemplate* _object_template; +}; + +} // namespace + +#endif // M2M_VECTOR_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,29 @@ +{ + "name": "mbed-client", + "config": { + "event-loop-size": 1024, + "reconnection-count": 3, + "reconnection-interval": 5, + "tcp-keepalive-time": null, + "tcp-keepalive-interval": null, + "disable-bootstrap-feature": null, + "coap-disable-obs-feature":null, + "reconnection-loop": 1, + "dns-use-thread": null, + "dns-thread-stack-size": 3072, + "dtls_peer_max_timeout": null, + "sn-coap-max-blockwise-payload-size" : null, + "sn-coap-duplication-max-msgs-count": null, + "sn-coap-max-incoming-message-size": null, + "sn-coap-resending-queue-size-msgs": null, + "sn-coap-resending-queue-size-bytes": null, + "sn-coap-blockwise-max-time-data-stored": null, + "disable-interface-description": null, + "disable-resource-type": null, + "disable-delayed-response": null, + "disable-block-message": null + }, + "macros" : [ + "MBED_CLIENT_C_NEW_API" + ] +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/eventdata.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/eventdata.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EVENT_DATA_H +#define EVENT_DATA_H + +#include "mbed-client/m2mvector.h" + +//FORWARD DECLARATION +class M2MObject; + + +typedef Vector<M2MObject *> M2MObjectList; + +class M2MSecurity; + +class EventData +{ +public: + virtual ~EventData() {} +}; + +class M2MSecurityData : public EventData +{ +public: + M2MSecurityData() + :_object(NULL){} + virtual ~M2MSecurityData() {} + M2MSecurity *_object; +}; + +class ResolvedAddressData : public EventData +{ +public: + ResolvedAddressData() + :_address(NULL), + _port(0){} + virtual ~ResolvedAddressData() {} + const M2MConnectionObserver::SocketAddress *_address; + uint16_t _port; +}; + +class ReceivedData : public EventData +{ +public: + ReceivedData() + :_data(NULL), + _size(0), + _port(0), + _address(NULL){} + virtual ~ReceivedData() {} + uint8_t *_data; + uint16_t _size; + uint16_t _port; + const M2MConnectionObserver::SocketAddress *_address; +}; + +class M2MRegisterData : public EventData +{ +public: + M2MRegisterData() + :_object(NULL){} + virtual ~M2MRegisterData() {} + M2MSecurity *_object; + M2MObjectList _object_list; +}; + +class M2MUpdateRegisterData : public EventData +{ +public: + M2MUpdateRegisterData() + :_object(NULL), + _lifetime(0){} + virtual ~M2MUpdateRegisterData() {} + M2MSecurity *_object; + uint32_t _lifetime; + M2MObjectList _object_list; +}; + + +#endif //EVENT_DATA_H +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mcallbackstorage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mcallbackstorage.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __M2M_CALLBACK_STORAGE_H__ +#define __M2M_CALLBACK_STORAGE_H__ + +#include "mbed-client/m2mvector.h" + +class M2MBase; +class M2MCallbackAssociation; +class M2MCallbackStorage; + +typedef m2m::Vector<M2MCallbackAssociation> M2MCallbackAssociationList; + +// XXX: this should not be visible for client code +class M2MCallbackAssociation +{ +public: + + // Types of callbacks stored as "void*" in the _callback variable. + // Note: the FPn<> -types are actually stored as pointers to object instances, + // which needs to be handled externally when fetching and deleting the callbacks. + enum M2MCallbackType { + // typedef FP1<void, const char*> value_updated_callback; + M2MBaseValueUpdatedCallback, + + // typedef void(*value_updated_callback2) (const char* object_name); + M2MBaseValueUpdatedCallback2, + + // typedef FP1<void,void*> execute_callback; + M2MResourceInstanceExecuteCallback, + + //typedef void(*execute_callback_2) (void *arguments); + M2MResourceInstanceExecuteCallback2, + + // typedef FP1<void, M2MBlockMessage *> incoming_block_message_callback; + M2MResourceInstanceIncomingBlockMessageCallback, + + // typedef FP3<void, const String &, uint8_t *&, uint32_t &> outgoing_block_message_callback; + M2MResourceInstanceOutgoingBlockMessageCallback, + + // class M2MResourceCallback + M2MResourceInstanceM2MResourceCallback, + + // typedef FP0<void> notification_sent_callback; + M2MResourceInstanceNotificationSentCallback, + + // typedef void(*notification_sent_callback_2) (void); + M2MResourceInstanceNotificationSentCallback2, + + // typedef FP2<void, const uint16_t, const M2MResourceBase::NoticationStatus> notification_status_callback; + M2MResourceInstanceNotificationStatusCallback, + + // typedef void(*notification_status_callback_2) (const uint16_t msg_id, const M2MResourceBase::NoticationStatus status); + M2MResourceInstanceNotificationStatusCallback2, + + // typedef void(*notification_delivery_status_cb) (const M2MBase& base, + // const M2MBase::NoticationDeliveryStatus status, void *client_args); + M2MBaseNotificationDeliveryStatusCallback + + }; + + /** + * Dummy constructor which does not initialize any predictable value to members, + * needed for array instantiation. Please use the parameterized constructor for real work. + */ + M2MCallbackAssociation(); + + M2MCallbackAssociation(const M2MBase *object, void *callback, M2MCallbackType type, void *client_args); + +public: + /** Object, where the callback is associated to. This is used as key on searches, must not be null. */ + const M2MBase *_object; + + /** + * Callback pointer, actual data type of the is dependent of _type. + * + * We could also use eg. a union with specific pointer types to avoid ugly casts, but that would + * then require a type-specific get_callback_<type>() to avoid casts on caller side too - unless + * the get_callback() would return this object and the caller would access the union._callback_<type> + * variable according to the _type. + */ + void *_callback; + + /** Type of the data _callback points to and needed for interpreting the data in it. */ + M2MCallbackType _type; + + void *_client_args; +}; + + +class M2MCallbackStorage +{ +public: + + ~M2MCallbackStorage(); + + // get the shared instance of the storage. + // TODO: tie this' instance to the nsdlinterface or similar class instead, as it would help + // to manage the lifecycle of the object. This would also remove the need for these static methods. + static M2MCallbackStorage *get_instance(); + + // utility for deleting the singleton instance, used on unit test and on application exit + static void delete_instance(); + + static bool add_callback(const M2MBase &object, + void *callback, + M2MCallbackAssociation::M2MCallbackType type, + void *client_args = 0); + + // remove all callbacks attached for given object + static void remove_callbacks(const M2MBase &object); + + // remove callback if one exists, return old value of it + static void* remove_callback(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type); + + // XXX: needed for protecting the vector during iteration, but that would add a dependency on PAL here + // void lock(); + // void release(); + + // XXX: const_iterator would be nicer + //int get_callback(const M2MBase &object, void &*callback, M2MCallbackType type); + + static bool does_callback_exist(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type); + + static void* get_callback(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type); + + static M2MCallbackAssociation* get_association_item(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type); + // XXX: this is actually not needed unless the client has multiple callbacks per object and type. + inline const M2MCallbackAssociationList& get_callbacks() const; + +private: + bool does_callback_exist(const M2MBase &object, void *callback, M2MCallbackAssociation::M2MCallbackType type) const; + void do_remove_callbacks(const M2MBase &object); + void* do_remove_callback(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type); + bool do_add_callback(const M2MBase &object, void *callback, M2MCallbackAssociation::M2MCallbackType type, void *client_args); + void* do_get_callback(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type) const; + + M2MCallbackAssociation* do_get_association_item(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type) const; + +private: + + /** + * Currently there is only one storage object, which is shared between all the interfaces and + * M2M objects. + */ + static M2MCallbackStorage *_static_instance; + + /** + * Callback objects stored. There combination of <object>+<type> is used on searches and + * the code does not fully support for adding multiple callbacks for <object>+<type> -pair. + * But that should not be too hard if the feature was added to M2M object API too, it just + * requires the M2M objects to iterate through the callbacks associated to it, not just call + * the get_callback(<object>,<type>) and call the first one. + */ + M2MCallbackAssociationList _callbacks; +}; + +inline const M2MCallbackAssociationList& M2MCallbackStorage::get_callbacks() const +{ + return _callbacks; +} + +#endif // !__M2M_CALLBACK_STORAGE_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2minterfaceimpl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2minterfaceimpl.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_INTERFACE_IMPL_H +#define M2M_INTERFACE_IMPL_H + +#include "mbed-client/m2minterface.h" +#include "mbed-client/m2mserver.h" +#include "mbed-client/m2mconnectionobserver.h" +#include "mbed-client/m2mconnectionsecurity.h" +#include "include/m2mnsdlobserver.h" +#include "include/m2mnsdlinterface.h" +#include "mbed-client/m2mtimerobserver.h" +#include "mbed-client/m2mtimer.h" +#include "mbed-client/m2mconnectionhandler.h" +#include "mbed-client/m2mconstants.h" + +//FORWARD DECLARATION +class M2MConnectionSecurity; +class EventData; +class M2MUpdateRegisterData; +/** + * @brief M2MInterfaceImpl. + * This class implements handling of all mbed Client Interface operations + * defined in OMA LWM2M specifications. + * This includes Bootstrapping, Client Registration, Device Management & + * Service Enablement and Information Reporting. + */ + +class M2MInterfaceImpl : public M2MInterface, + public M2MNsdlObserver, + public M2MConnectionObserver, + public M2MTimerObserver +{ +private: + // Prevents the use of assignment operator by accident. + M2MInterfaceImpl& operator=( const M2MInterfaceImpl& /*other*/ ); + + // Prevents the use of copy constructor by accident + M2MInterfaceImpl( const M2MInterfaceImpl& /*other*/ ); + +friend class M2MInterfaceFactory; + +private: + + /** + * @brief Constructor + * @param observer, Observer to pass the event callbacks for various + * interface operations. + * @param endpoint_name Endpoint name of the client. + * @param endpoint_type Endpoint type of the client. + * @param life_time Life time of the client in seconds + * @param listen_port Listening port for the endpoint, default is 8000. + * @param domain Domain of the client. + * @param mode Binding mode of the client, default is UDP + * @param stack Network stack to be used for connection, default is LwIP_IPv4. + * @param context_address Context address, default is empty. + */ + M2MInterfaceImpl(M2MInterfaceObserver& observer, + const String &endpoint_name, + const String &endpoint_type, + const int32_t life_time, + const uint16_t listen_port, + const String &domain = "", + BindingMode mode = M2MInterface::NOT_SET, + M2MInterface::NetworkStack stack = M2MInterface::LwIP_IPv4, + const String &context_address = ""); + +public: + + /** + * @brief Destructor + */ + virtual ~M2MInterfaceImpl(); + + /** + * @brief Initiates bootstrapping of the client with the provided Bootstrap + * server information. + * @param security_object Security object which contains information + * required for successful bootstrapping of the client. + */ + virtual void bootstrap(M2MSecurity *security); + + /** + * @brief Cancels on going bootstrapping operation of the client. If the client has + * already successfully bootstrapped then this function deletes existing + * bootstrap information from the client. + */ + virtual void cancel_bootstrap(); + + /** + * @brief Initiates registration of the provided Security object to the + * corresponding LWM2M server. + * @param security_object Security object which contains information + * required for registering to the LWM2M server. + * If client wants to register to multiple LWM2M servers then it has call + * this function once for each of LWM2M server object separately. + * @param object_list Objects which contains information + * which the client want to register to the LWM2M server. + */ + virtual void register_object(M2MSecurity *security_object, const M2MObjectList &object_list); + + /** + * @brief Updates or refreshes the client's registration on the LWM2M + * server. + * @param security_object Security object from which the device object + * needs to update registration, if there is only one LWM2M server registered + * then this parameter can be NULL. + * @param lifetime Lifetime for the endpoint client in seconds. + */ + virtual void update_registration(M2MSecurity *security_object, const uint32_t lifetime = 0); + + /** + * @brief Updates or refreshes the client's registration on the LWM2M + * server. Use this function to publish new objects to LWM2M server. + * @param security_object The security object from which the device object + * needs to update the registration. If there is only one LWM2M server registered, + * this parameter can be NULL. + * @param object_list Objects that contain information about the + * client attempting to register to the LWM2M server. + * @param lifetime The lifetime of the endpoint client in seconds. If the same value + * has to be passed, set the default value to 0. + */ + virtual void update_registration(M2MSecurity *security_object, const M2MObjectList &object_list, + const uint32_t lifetime = 0); + + /** + * @brief Unregisters the registered object from the LWM2M server + * @param security_object Security object from which the device object + * needs to be unregistered. If there is only one LWM2M server registered + * this parameter can be NULL. + */ + virtual void unregister_object(M2MSecurity* security = NULL); + + /** + * @brief Sets the function which will be called indicating client + * is going to sleep when the Binding mode is selected with Queue mode. + * @param callback A function pointer that will be called when client + * goes to sleep. + */ + virtual void set_queue_sleep_handler(callback_handler handler); + + /** + * @brief Sets the network interface handler that is used by client to connect + * to a network over IP. + * @param handler A network interface handler that is used by client to connect. + * This API is optional but provides a mechanism for different platforms to + * manage usage of underlying network interface by client. + */ + virtual void set_platform_network_handler(void *handler = NULL); + + /** + * \brief Sets the function callback that will be called by mbed-client for + * fetching random number from application for ensuring strong entropy. + * \param random_callback A function pointer that will be called by mbed-client + * while performing secure handshake. + * Function signature should be uint32_t (*random_number_callback)(void); + */ + virtual void set_random_number_callback(random_number_cb callback); + + /** + * \brief Sets the function callback that will be called by mbed-client for + * providing entropy source from application for ensuring strong entropy. + * \param entropy_callback A function pointer that will be called by mbed-client + * while performing secure handshake. + * Function signature , if using mbed-client-mbedtls should be + * int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, + * size_t len, size_t *olen); + */ + virtual void set_entropy_callback(entropy_cb callback); + + /** + * @brief Updates the endpoint name. + * @param name New endpoint name + */ + virtual void update_endpoint(String &name); + + /** + * @brief Updates the domain name. + * @param domain New domain name + */ + virtual void update_domain(String &domain); + + /** + * @brief Return internal endpoint name + * @return internal endpoint name + */ + virtual const String internal_endpoint_name() const; + + /** + * @brief Return error description for the latest error code + * @return Error description string + */ + virtual const char *error_description() const; + + /** + * @brief Sends the CoAP GET request to the server. + * @uri Uri path to the data. + * @offset Data offset. + * @async In async mode application must call this API again with the updated offset. + * If set to false then client will automatically download the whole package. + * @get_data_cb Callback which is triggered once there is data available. + * @get_data_error_cb Callback which is trigged in case of any error. + */ + virtual void get_data_request(const char *uri, + const size_t offset, + const bool async, + get_data_cb data_cb, + get_data_error_cb error_cb, + void *context); + +protected: // From M2MNsdlObserver + + virtual void coap_message_ready(uint8_t *data_ptr, + uint16_t data_len, + sn_nsdl_addr_s *address_ptr); + + virtual void client_registered(M2MServer *server_object); + + virtual void registration_updated(const M2MServer &server_object); + + virtual void registration_error(uint8_t error_code, bool retry = false); + + virtual void client_unregistered(); + + virtual void bootstrap_done(); + + virtual void bootstrap_wait(); + + virtual void bootstrap_error_wait(const char *reason); + + virtual void bootstrap_error(const char *reason); + + virtual void coap_data_processed(); + + virtual void value_updated(M2MBase *base); + +protected: // From M2MConnectionObserver + + virtual void data_available(uint8_t* data, + uint16_t data_size, + const M2MConnectionObserver::SocketAddress &address); + + virtual void socket_error(uint8_t error_code, bool retry = true); + + virtual void address_ready(const M2MConnectionObserver::SocketAddress &address, + M2MConnectionObserver::ServerType server_type, + const uint16_t server_port); + + virtual void data_sent(); + +protected: // from M2MTimerObserver + + virtual void timer_expired(M2MTimerObserver::Type type); + + +private: // state machine state functions + + /** + * When the state is Idle. + */ + void state_idle(EventData* data); + + /** + * When the client starts bootstrap. + */ + void state_bootstrap( EventData *data); + + /** + * When the bootstrap server address is resolved. + */ + void state_bootstrap_address_resolved( EventData *data); + + /** + * When the bootstrap resource is created. + */ + void state_bootstrap_resource_created( EventData *data); + + /** + * When the server has sent response and bootstrapping is done. + */ + void state_bootstrapped( EventData *data); + + /** + * When the client starts register. + */ + void state_register( EventData *data); + + /** + * When the server address for register is resolved. + */ + void state_register_address_resolved( EventData *data); + + /** + * When the client is registered. + */ + void state_registered( EventData *data); + + /** + * When the client is updating registration. + */ + void state_update_registration( EventData *data); + + /** + * When the client starts unregister. + */ + void state_unregister( EventData *data); + + /** + * When the client has been unregistered. + */ + void state_unregistered( EventData *data); + + /** + * When the coap data is been sent through socket. + */ + void state_sending_coap_data( EventData *data); + + /** + * When the coap data is sent successfully. + */ + void state_coap_data_sent( EventData *data); + + /** + * When the socket is receiving coap data. + */ + void state_receiving_coap_data( EventData *data); + + /** + * When the socket has received coap data. + */ + void state_coap_data_received( EventData *data); + + /** + * When the coap message is being processed. + */ + void state_processing_coap_data( EventData *data); + + /** + * When the coap message has been processed. + */ + void state_coap_data_processed( EventData *data); + + /** + * When the client is waiting to receive or send data. + */ + void state_waiting( EventData *data); + + /** + * Start registration update. + */ + void start_register_update(M2MUpdateRegisterData *data); + + /** + * State enumeration order must match the order of state + * method entries in the state map + */ + enum E_States { + STATE_IDLE = 0, + STATE_BOOTSTRAP, + STATE_BOOTSTRAP_ADDRESS_RESOLVED, + STATE_BOOTSTRAP_RESOURCE_CREATED, + STATE_BOOTSTRAP_WAIT, + STATE_BOOTSTRAP_ERROR_WAIT, // 5 + STATE_BOOTSTRAPPED, + STATE_REGISTER, + STATE_REGISTER_ADDRESS_RESOLVED, + STATE_REGISTERED, + STATE_UPDATE_REGISTRATION, // 10 + STATE_UNREGISTER, + STATE_UNREGISTERED, + STATE_SENDING_COAP_DATA, + STATE_COAP_DATA_SENT, + STATE_COAP_DATA_RECEIVED, // 15 + STATE_PROCESSING_COAP_DATA, + STATE_COAP_DATA_PROCESSED, + STATE_WAITING, + STATE_MAX_STATES + }; + + /** + * @brief Redirects the state machine to right function. + * @param current_state Current state to be set. + * @param data Data to be passed to the state function. + */ + void state_function( uint8_t current_state, EventData* data ); + + /** + * @brief State Engine maintaining state machine logic. + */ + void state_engine(void); + + /** + * External event which can trigger the state machine. + * @param New The state to which the state machine should go. + * @param data The data to be passed to the state machine. + */ + void external_event(uint8_t, EventData* = NULL); + + /** + * Internal event generated by state machine. + * @param New State which the state machine should go to. + * @param data The data to be passed to the state machine. + */ + void internal_event(uint8_t, EventData* = NULL); + + /** + * Queue mode enabled or not. + * @return True if queue mode otherwise false. + */ + bool queue_mode() const; + + enum + { + EVENT_IGNORED = 0xFE, + CANNOT_HAPPEN + }; + + /** + * Helper method for extracting the IP address part and port from the + * given server address. + * @param server_address Source URL (without "coap" or "coaps" prefix). + * @param ip_address The extracted IP. + * @param port The extracted port. + */ + static void process_address(const String& server_address, String& ip_address, uint16_t& port); + + /** + * Helper method for storing the error description to _error_description if the feature + * has not been turned off. + * @param error description + */ + void set_error_description(const char *description); + + enum ReconnectionState{ + None, + WithUpdate, + FullRegistration, + Unregistration + }; + +private: + + EventData *_event_data; + M2MTimer *_registration_flow_timer; + uint16_t _server_port; + uint16_t _listen_port; + int32_t _life_time; + String _server_ip_address; + M2MSecurity *_register_server; //TODO: to be the list not owned + M2MTimer _queue_sleep_timer; + M2MTimer _retry_timer; + callback_handler _callback_handler; + const uint8_t _max_states; + bool _event_ignored; + bool _event_generated; + bool _reconnecting; + bool _retry_timer_expired; + bool _bootstrapped; + bool _queue_mode_timer_ongoing; + uint8_t _current_state; + BindingMode _binding_mode; + ReconnectionState _reconnection_state; + M2MInterfaceObserver &_observer; + M2MConnectionSecurity *_security_connection; // Doesn't own + M2MConnectionHandler _connection_handler; + M2MNsdlInterface _nsdl_interface; + M2MSecurity *_security; + +#ifndef DISABLE_ERROR_DESCRIPTION + // The DISABLE_ERROR_DESCRIPTION macro will reduce the flash usage by ~1800 bytes. + char _error_description[MAX_ALLOWED_ERROR_STRING_LENGTH]; +#endif + + uint8_t _initial_reconnection_time; + uint64_t _reconnection_time; + + friend class Test_M2MInterfaceImpl; + +}; + +#define BEGIN_TRANSITION_MAP \ + static const uint8_t TRANSITIONS[] = {\ + +#define TRANSITION_MAP_ENTRY(entry)\ + entry, + +#define END_TRANSITION_MAP(data) \ + 0 };\ + external_event(TRANSITIONS[_current_state], data); + +#endif //M2M_INTERFACE_IMPL_H + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mnsdlinterface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mnsdlinterface.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2MNSDLINTERFACE_H +#define M2MNSDLINTERFACE_H + +#include "ns_list.h" +#include "mbed-client/m2mvector.h" +#include "mbed-client/m2mconfig.h" +#include "mbed-client/m2minterface.h" +#include "mbed-client/m2mtimerobserver.h" +#include "mbed-client/m2mobservationhandler.h" +#include "mbed-client/m2mtimer.h" +#include "mbed-client/m2mbase.h" +#include "mbed-client/m2mserver.h" +#include "include/nsdllinker.h" + +//FORWARD DECLARARTION +class M2MSecurity; +class M2MObject; +class M2MObjectInstance; +class M2MResource; +class M2MResourceInstance; +class M2MNsdlObserver; +class M2MServer; +class M2MConnectionHandler; + +typedef Vector<M2MObject *> M2MObjectList; + +/** + * @brief M2MNsdlInterface + * Class which interacts between mbed Client C++ Library and mbed-client-c library. + */ +class M2MNsdlInterface : public M2MTimerObserver, + public M2MObservationHandler +{ +private: + // Prevents the use of assignment operator by accident. + M2MNsdlInterface& operator=( const M2MNsdlInterface& /*other*/ ); + + // Prevents the use of copy constructor by accident + M2MNsdlInterface( const M2MNsdlInterface& /*other*/ ); + +public: + + struct get_data_request_s { + get_data_cb on_get_data_cb; + get_data_error_cb on_get_data_error_cb; + size_t received_size; + uint32_t msg_token; + char *uri_path; + void *context; + bool async_req; + ns_list_link_t link; + }; + + typedef NS_LIST_HEAD(get_data_request_s, link) get_data_request_list_t; + + /** + * @brief Constructor + * @param observer, Observer to pass the event callbacks from nsdl library. + */ + M2MNsdlInterface(M2MNsdlObserver &observer, M2MConnectionHandler &connection_handler); + + /** + * @brief Destructor + */ + virtual ~M2MNsdlInterface(); + + /** + * @brief Creates endpoint object for the nsdl stack. + * @param endpoint_name, Endpoint name of the client. + * @param endpoint_type, Endpoint type of the client. + * @param life_time, Life time of the client in seconds + * @param domain, Domain of the client. + * @param mode, Binding mode of the client, default is UDP + * @param context_address, Context address default is empty. + */ + void create_endpoint(const String &endpoint_name, + const String &endpoint_type, + const int32_t life_time, + const String &domain, + const uint8_t mode, + const String &context_address); + + /** + * @brief Deletes the endpoint. + */ + void delete_endpoint(); + + /** + * @brief Updates endpoint name. + */ + void update_endpoint(const String &name); + + /** + * @brief Updates domain. + */ + void update_domain(const String &domain); + + /** + * @brief Creates the NSDL structure for the registered objectlist. + * @param object_list, List of objects to be registered. + * @return true if structure created successfully else false. + */ + bool create_nsdl_list_structure(const M2MObjectList &object_list); + + /** + * @brief Removed the NSDL resource for the given resource. + * @param base, Resource to be removed. + * @return true if removed successfully else false. + */ + bool remove_nsdl_resource(M2MBase *base); + + /** + * @brief Creates the bootstrap object. + * @param address Bootstrap address. + * @return true if created and sent successfully else false. + */ + bool create_bootstrap_resource(sn_nsdl_addr_s *address); + + /** + * @brief Sets the register message to the server. + * @param address M2MServer address. + * @param address_length M2MServer address length. + * @param port M2MServer port. + * @param address_type IP Address type. + */ + void set_server_address(uint8_t* address, + uint8_t address_length, + const uint16_t port, + sn_nsdl_addr_type_e address_type); + /** + * @brief Sends the register message to the server. + * @return true if register sent successfully else false. + */ + bool send_register_message(); + + /** + * @brief Sends the CoAP GET request to the server. + * @uri Uri path to the data. + * @offset Data offset. + * @async In async mode application must call this API again with the updated offset. + * If set to false then client will automatically download the whole package. + * @get_data_cb Callback which is triggered once there is data available. + * @get_data_error_cb Callback which is trigged in case of any error. + * @context Application context. + */ + bool send_get_data_request(const char *uri, + const size_t offset, + const bool async, + get_data_cb data_cb, + get_data_error_cb error_cb, + void *context); + + /** + * @brief Sends the update registration message to the server. + * @param lifetime, Updated lifetime value in seconds. + * @param clear_queue, Empties resending queue, by default it doesn't empties queue. + * @return true if sent successfully else false. + * + */ + bool send_update_registration(const uint32_t lifetime = 0, bool clear_queue = false); + + /** + * @brief Sends unregister message to the server. + * @return true if unregister sent successfully else false. + */ + bool send_unregister_message(); + + /** + * @brief Memory Allocation required for libCoap. + * @param size, Size of memory to be reserved. + */ + static void* memory_alloc(uint32_t size); + + /** + * @brief Memory free functions required for libCoap + * @param ptr, Object whose memory needs to be freed. + */ + static void memory_free(void *ptr); + + /** + * @brief Callback from nsdl library to inform the data is ready + * to be sent to server. + * @param nsdl_handle, Handler for the nsdl structure for this endpoint + * @param protocol, Protocol format of the data + * @param data, Data to be sent. + * @param data_len, Size of the data to be sent + * @param address, server address where data has to be sent. + * @return 1 if successful else 0. + */ + uint8_t send_to_server_callback(struct nsdl_s * nsdl_handle, + sn_nsdl_capab_e protocol, + uint8_t *data, + uint16_t data_len, + sn_nsdl_addr_s *address); + + /** + * @brief Callback from nsdl library to inform the data which is + * received from server for the client has been converted to coap message. + * @param nsdl_handle, Handler for the nsdl structure for this endpoint + * @param coap_header, Coap message formed from data. + * @param address, Server address from where the data is received. + * @return 1 if successful else 0. + */ + uint8_t received_from_server_callback(struct nsdl_s * nsdl_handle, + sn_coap_hdr_s *coap_header, + sn_nsdl_addr_s *address); + + /** + * @brief Callback from nsdl library to inform the data which is + * received from server for the resources has been converted to coap message. + * @param nsdl_handle, Handler for the nsdl resource structure for this endpoint.. + * @param coap_header, Coap message formed from data. + * @param address, Server address from where the data is received. + * @param nsdl_capab, Protocol for the message, currently only coap is supported. + * @return 1 if successful else 0. + */ + uint8_t resource_callback(struct nsdl_s *nsdl_handle, sn_coap_hdr_s *coap, + sn_nsdl_addr_s *address, + sn_nsdl_capab_e nsdl_capab); + + /** + * @brief Callback when there is data received from server and needs to be processed. + * @param data, data received from server. + * @param data_size, data size received from server. + * @param addres, address structure of the server. + * @return true if successfully processed else false. + */ + bool process_received_data(uint8_t *data, + uint16_t data_size, + sn_nsdl_addr_s *address); + + /** + * @brief Stops all the timers in case there is any errors. + */ + void stop_timers(); + + /** + * @brief Returns nsdl handle. + * @return ndsl handle + */ + nsdl_s* get_nsdl_handle() const; + + /** + * @brief Get endpoint name + * @return endpoint name + */ + const String& endpoint_name() const; + + /** + * @brief Get internal endpoint name + * @return internal endpoint name + */ + const String internal_endpoint_name() const; + + /** + * @brief Set server address + * @param server_address, Bootstrap or M2M server address. + */ + void set_server_address(const char *server_address); + + /** + * @brief Get NSDL timer. + * @return NSDL execution timer. + */ + M2MTimer &get_nsdl_execution_timer(); + + /** + * @brief Get unregister state. + * @return Is unregistration ongoing. + */ + bool get_unregister_ongoing() const; + + /** + * @brief Starts the NSDL execution timer. + */ + void start_nsdl_execution_timer(); + + /** + * @brief Returns security object. + * @return M2MSecurity object, contains lwm2m server information. + */ + M2MSecurity* get_security_object(); + + /** + * @brief Returns auto-observation token. + * @param path, Resource path, used for searching the right object. + * @param token[OUT], Token data. + * @return Length of the token if found otherwise 0. + */ + uint8_t find_auto_obs_token(const char *path, uint8_t *token) const; + +protected: // from M2MTimerObserver + + virtual void timer_expired(M2MTimerObserver::Type type); + +protected: // from M2MObservationHandler + + virtual void observation_to_be_sent(M2MBase *object, + uint16_t obs_number, + const m2m::Vector<uint16_t> &changed_instance_ids, + bool send_object = false); + + virtual void resource_to_be_deleted(M2MBase* base); + + virtual void value_updated(M2MBase *base); + + virtual void remove_object(M2MBase *object); +#ifndef DISABLE_DELAYED_RESPONSE + virtual void send_delayed_response(M2MBase *base); +#endif + +private: + + /** + * Enum defining an LWM2M object type. + */ + typedef enum { + SECURITY = 0x00, + SERVER = 0x01, + DEVICE = 0x02 + }ObjectType; + + /** + * @brief Initializes all the nsdl library component to be usable. + * @return true if initialization is successful else false. + */ + bool initialize(); + + bool add_object_to_list(M2MObject *object); + + bool create_nsdl_object_structure(M2MObject *object); + + bool create_nsdl_object_instance_structure(M2MObjectInstance *object_instance); + + bool create_nsdl_resource_structure(M2MResource *resource, + bool multiple_instances = false); + + bool create_nsdl_resource(M2MBase *base); + + static String coap_to_string(const uint8_t *coap_data_ptr, + int coap_data_ptr_length); + + void execute_nsdl_process_loop(); + + uint64_t registration_time() const; + + M2MBase* find_resource(const String &object, + const uint16_t msg_id) const; + + M2MBase* find_resource(const M2MObject *object, + const String &object_instance, + const uint16_t msg_id) const; + + M2MBase* find_resource(const M2MObjectInstance *object_instance, + const String &resource_instance, + const uint16_t msg_id) const; + + M2MBase* find_resource(const M2MResource *resource, + const String &object_name, + const String &resource_instance) const; + + bool object_present(M2MObject * object) const; + + static M2MInterface::Error interface_error(const sn_coap_hdr_s &coap_header); + + void send_object_observation(M2MObject *object, + uint16_t obs_number, + const m2m::Vector<uint16_t> &changed_instance_ids, + bool send_object, bool resend); + + void send_object_instance_observation(M2MObjectInstance *object_instance, + uint16_t obs_number, bool resend); + + void send_resource_observation(M2MResource *resource, uint16_t obs_number, bool resend); + + /** + * @brief Allocate (size + 1) amount of memory, copy size bytes into + * it and add zero termination. + * @param source Source string to copy, may not be NULL. + * @param size The size of memory to be reserved. + */ + static uint8_t* alloc_string_copy(const uint8_t* source, uint16_t size); + + /** + * @brief Utility method to convert given lifetime int to ascii + * and allocate a buffer for it and set it to _endpoint->lifetime_ptr. + * @param lifetime A new value for lifetime. + */ + void set_endpoint_lifetime_buffer(int lifetime); + + /** + * @brief Handle incoming bootstrap PUT message. + * @param coap_header, Received CoAP message + * @param address, Server address + */ + void handle_bootstrap_put_message(sn_coap_hdr_s *coap_header, sn_nsdl_addr_s *address); + + /** + * @brief Handle bootstrap finished message. + * @param coap_header, Received CoAP message + * @param address, Server address + */ + void handle_bootstrap_finished(sn_coap_hdr_s *coap_header,sn_nsdl_addr_s *address); + + /** + * @brief Handle bootstrap delete message. + * @param coap_header, Received CoAP message + * @param address, Server address + */ + void handle_bootstrap_delete(sn_coap_hdr_s *coap_header,sn_nsdl_addr_s *address); + + /** + * @brief Parse bootstrap TLV message. + * @param coap_header, Received CoAP message + * @return True if parsing was succesful else false + */ + bool parse_bootstrap_message(sn_coap_hdr_s *coap_header, M2MNsdlInterface::ObjectType lwm2m_object_type); + + /** + * @brief Parse bootstrap TLV message. + * @param coap_header, Received CoAP message + * @return True if parsing was succesful else false + */ + bool validate_security_object(); + + /** + * @brief Handle bootstrap errors. + * @param reason, Reason for Bootstrap failure. + * @param wait, True if need to wait that ACK has been sent. + * False if reconnection can start immediately. + */ + void handle_bootstrap_error(const char *reason, bool wait); + + /** + * @brief Handle different coap errors. + * @param coap_header, CoAP structure. + * @return Error reason. + */ + static const char *coap_error(const sn_coap_hdr_s &coap_header); + + /** + * @brief Claim + */ + void claim_mutex(); + + /** + * @brief Release + */ + void release_mutex(); + + /** + * @brief Change operation mode of every resource. + * @param object, Object to be updated. + * @return operation, New operation mode. + */ + void change_operation_mode(M2MObject *object, M2MBase::Operation operation); + + /** + * @brief Parse URI query parameters and pass those to nsdl-c. + * @return True if parsing success otherwise False + */ + bool parse_and_send_uri_query_parameters(); + + /** + * @brief Handle pending notifications. + * @param clear, If set clears the flag to initial state otherwise sends the notification. + */ + void handle_pending_notifications(bool clear); + + /** + * @brief Callback function that triggers the registration update call. + * @param argument, Arguments part of the POST request. + */ + void update_trigger_callback(void *argument); + + bool lifetime_value_changed() const; + + static void execute_notification_delivery_status_cb(M2MBase* object, int32_t msgid); + + bool is_response_to_get_req(const sn_coap_hdr_s *coap_header, get_data_request_s &get_data); + + void free_get_request_list(const sn_coap_hdr_s *coap_header = NULL); + +private: + + M2MNsdlObserver &_observer; + M2MObjectList _object_list; + sn_nsdl_ep_parameters_s *_endpoint; + nsdl_s *_nsdl_handle; + M2MSecurity *_security; // Not owned + M2MServer *_server; + M2MTimer _nsdl_exceution_timer; + M2MTimer _registration_timer; + M2MConnectionHandler &_connection_handler; + sn_nsdl_addr_s _sn_nsdl_address; + String _endpoint_name; + uint32_t _counter_for_nsdl; + uint16_t _bootstrap_id; + char *_server_address; // BS or M2M address + bool _unregister_ongoing; + bool _identity_accepted; + bool _nsdl_exceution_timer_running; + uint8_t _binding_mode; + uint16_t _auto_obs_token; + get_data_request_list_t _get_request_list; + + +friend class Test_M2MNsdlInterface; + +}; + +#endif // M2MNSDLINTERFACE_H +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mnsdlobserver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mnsdlobserver.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2M_NSDL_OBSERVER_H +#define M2M_NSDL_OBSERVER_H + +#include "include/nsdllinker.h" + +//FORWARD DECLARATION +class M2MSecurity; +class M2MServer; + +/** + * @brief Observer class for informing NSDL callback to the state machine + */ + +class M2MNsdlObserver +{ + +public : + + /** + * @brief Informs that coap message is ready. + * @param data_ptr, Data object of coap message. + * @param data_len, Length of the data object. + * @param address_ptr, Address structure of the server. + */ + virtual void coap_message_ready(uint8_t *data_ptr, + uint16_t data_len, + sn_nsdl_addr_s *address_ptr) = 0; + + /** + * @brief Informs that client is registered successfully. + * @param server_object, Server object associated with + * registered server. + */ + virtual void client_registered(M2MServer *server_object) = 0; + + /** + * @brief Informs that client registration is updated successfully. + * @param server_object, Server object associated with + * registered server. + */ + virtual void registration_updated(const M2MServer &server_object) = 0; + + /** + * @brief Informs that some error occured during + * registration. + * @param error_code, Error code for registration error + * @param retry, Indicates state machine to re-establish connection + */ + virtual void registration_error(uint8_t error_code, bool retry = false) = 0; + + /** + * @brief Informs that client is unregistered successfully. + */ + virtual void client_unregistered() = 0; + + /** + * @brief Informs that client bootstrapping is done. + * @param security_object, M2MSecurity Object which contains information about + * LWM2M server fetched from bootstrap server. + */ + virtual void bootstrap_done() = 0; + + /** + * @brief Informs that client bootstrapping is waiting for message to be sent. + * @param security_object, M2MSecurity Object which contains information about + * LWM2M server fetched from bootstrap server. + */ + virtual void bootstrap_wait() = 0; + + /** + * @brief Informs that client bootstrapping is waiting for error message to be sent. + * @param reason, Error description. + */ + virtual void bootstrap_error_wait(const char *reason) = 0; + + /** + * @brief Informs that some error occured during + * bootstrapping. + * @param reason, Error string explaining the failure reason + */ + virtual void bootstrap_error(const char *reason) = 0; + + /** + * @brief Informs that received data has been processed. + */ + virtual void coap_data_processed() = 0; + + /** + * @brief Callback informing that the value of the resource object is updated by server. + * @param base Object whose value is updated. + */ + virtual void value_updated(M2MBase *base) = 0; +}; +#endif // M2M_NSDL_OBSERVER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mreporthandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mreporthandler.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef M2MREPORTHANDLER_H +#define M2MREPORTHANDLER_H + +// Support for std args +#include <stdint.h> +#include "mbed-client/m2mconfig.h" +#include "mbed-client/m2mbase.h" +#include "mbed-client/m2mtimerobserver.h" +#include "mbed-client/m2mresourceinstance.h" +#include "mbed-client/m2mvector.h" +#include "mbed-client/m2mtimer.h" + +//FORWARD DECLARATION +class M2MReportObserver; +class M2MTimer; +class M2MResourceInstance; + +/** + * @brief M2MReportHandler. + * This class is handles all the observation related operations. + */ +class M2MReportHandler: public M2MTimerObserver +{ +private: + // Prevents the use of assignment operator by accident. + M2MReportHandler& operator=( const M2MReportHandler& /*other*/ ); + +public: + + M2MReportHandler(M2MReportObserver &observer); + +public: + + /** + * Enum defining which write attributes are set. + */ + enum { + Cancel = 1, + Pmin = 2, + Pmax = 4, + Lt = 8, + Gt = 16, + St = 32 + }; + + /** + * Destructor + */ + virtual ~M2MReportHandler(); + + /** + * @brief Sets that object is under observation. + * @param Value for the observation. + * @param handler, Handler object for sending + * observation callbacks. + */ + void set_under_observation(bool observed); + + /** + * @brief Sets the value of the given resource. + * @param value, Value of the observed resource. + */ + void set_value(float value); + + /** + * @brief Sets notification trigger. + * @param obj_instance_id, Object instance id that has changed + */ + void set_notification_trigger(uint16_t obj_instance_id = 0); + + /** + * @brief Parses the received query for notification + * attribute. + * @param query Query to be parsed for attributes. + * @param type Type of the Base Object. + * @param resource_type Type of the Resource. + * @return true if required attributes are present else false. + */ + bool parse_notification_attribute(const char *query, + M2MBase::BaseType type, + M2MResourceInstance::ResourceType resource_type = M2MResourceInstance::OPAQUE); + + /** + * @brief Set back to default values. + */ + void set_default_values(); + + /** + * @brief Return write attribute flags. + */ + uint8_t attribute_flags() const; + + /** + * \brief Sets the observation token value. + * \param token A pointer to the token of the resource. + * \param length The length of the token pointer. + */ + void set_observation_token(const uint8_t *token, const uint8_t length); + + /** + * \brief Provides a copy of the observation token of the object. + * \param value[OUT] A pointer to the value of the token. + * \param value_length[OUT] The length of the token pointer. + */ + void get_observation_token(uint8_t *token, uint8_t &token_length) const; + + /** + * \brief Returns the observation number. + * \return The observation number of the object. + */ + uint16_t observation_number() const; + + /** + * \brief Adds the observation level for the object. + * \param observation_level The level of observation. + */ + void add_observation_level(M2MBase::Observation obs_level); + + /** + * \brief Removes the observation level for the object. + * \param observation_level The level of observation. + */ + void remove_observation_level(M2MBase::Observation obs_level); + + /** + * \brief Returns the observation level of the object. + * \return The observation level of the object. + */ + M2MBase::Observation observation_level() const; + + /** + * @brief Returns whether this resource is under observation or not. + * @return True if the resource is under observation, else false, + */ + bool is_under_observation() const; + +protected : // from M2MTimerObserver + + virtual void timer_expired(M2MTimerObserver::Type type = + M2MTimerObserver::Notdefined); + +private: + + + + bool set_notification_attribute(const char* option, + M2MBase::BaseType type, + M2MResourceInstance::ResourceType resource_type); + + /** + * @brief Schedule a report, if the pmin is exceeded + * then report immediately else store the state to be + * reported once the time fires. + */ + void schedule_report(); + + /** + * @brief Reports a sample that satisfies the reporting criteria. + */ + void report(); + + /** + * @brief Manage timers for pmin and pmax. + */ + void handle_timers(); + + /** + * @brief Check whether notification params can be accepted. + */ + bool check_attribute_validity() const; + + /** + * @brief Stop pmin & pmax timers. + */ + void stop_timers(); + + /** + * @brief Check if current value match threshold values. + * @return True if notify can be send otherwise false. + */ + bool check_threshold_values() const; + + /** + * @brief Check whether current value matches with GT & LT. + * @return True if current value match with GT or LT values. + */ + bool check_gt_lt_params() const; + + /** + * \brief Allocate (size + 1) amount of memory, copy size bytes into + * it and add zero termination. + * \param source The source string to copy, may not be NULL. + * \param size The size of memory to be reserved. + */ + static uint8_t* alloc_string_copy(const uint8_t* source, uint32_t size); + +private: + M2MReportObserver &_observer; + bool _is_under_observation : 1; + M2MBase::Observation _observation_level : 4; + uint8_t _attribute_state; + unsigned _token_length : 8; + bool _notify; + bool _pmin_exceeded; + bool _pmax_exceeded; + unsigned _observation_number : 24; + M2MTimer _pmin_timer; + M2MTimer _pmax_timer; + uint8_t *_token; + int32_t _pmax; + int32_t _pmin; + float _current_value; + float _gt; + float _lt; + float _st; + float _high_step; + float _low_step; + float _last_value; + m2m::Vector<uint16_t> _changed_instance_ids; + +friend class Test_M2MReportHandler; + +}; + +#endif // M2MREPORTHANDLER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mtlvdeserializer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mtlvdeserializer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed-client/m2mvector.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mresource.h" + +/** + * @brief M2MTLVDeserializer + * TLV Deserialiser get the object instances and resources as binary data and + * builds the <code>lwm2m</code> representation from it. See OMA-LWM2M + * specification, chapter 6.1 for the resource model and chapter 6.3.3 for + * the OMA-TLV specification. + */ +class M2MTLVDeserializer { + +public : + + typedef enum { + None, + NotFound, + NotAllowed, + NotValid, + OutOfMemory + } Error; + + typedef enum { + Put, + Post + } Operation; + + + /** + * This method checks whether the given binary encodes an object instance + * or something else. It returns <code>true</code> if bits 7-6 of the first + * byte is "00". + * @param tlv Binary to be checked as LWM2M object instance + * @return <code>true</code> or <code>false</code>. + */ + static bool is_object_instance(const uint8_t *tlv); + + /** + * This method checks whether the given binary encodes a resource or + * something else. It returns <code>true</code> if bits 7-6 of the first + * byte is "11". + * @param tlv Binary to be checked as LWM2M resource. + * @return <code>true</code> or <code>false</code>. + */ + static bool is_resource(const uint8_t *tlv); + + /** + * This method checks whether the given binary encodes a multiple resource + * or something else. It returns <code>true</code> if bits 7-6 of the first + * byte is "10". + * @param tlv Binary to be checked as LWM2M multiple resource. + * @return <code>true</code> or <code>false</code>. + */ + static bool is_multiple_resource(const uint8_t *tlv); + + /** + * This method checks whether the given binary encodes a resource instance + * or something else. It returns <code>true</code> if bits 7-6 of the first + * byte is "01". + * @param tlv Binary to be checked as LWM2M resource instance. + * @return <code>true</code> or <code>false</code>. + */ + static bool is_resource_instance(const uint8_t *tlv); + + /** + * Deserialises the given binary that must encode object instances. Binary + * array can be checked before invoking this method with + */ + static M2MTLVDeserializer::Error deserialise_object_instances(const uint8_t* tlv, + uint32_t tlv_size, + M2MObject &object, + M2MTLVDeserializer::Operation operation); + + /** + * Deserialises the given binary that must encode resources. Binary array + * can be checked before invoking this method. + */ + static M2MTLVDeserializer::Error deserialize_resources(const uint8_t *tlv, + uint32_t tlv_size, + M2MObjectInstance &object_instance, + M2MTLVDeserializer::Operation operation); + + /** + * Deserialises the given binary that must encode resource instances. Binary array + * can be checked before invoking this method. + */ + static M2MTLVDeserializer::Error deserialize_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + M2MResource &resource, + M2MTLVDeserializer::Operation operation); + /** + * This method return object instance id or resource id. + * @param tlv Binary to be checked + * @return Object instance id or resource id. + */ + static uint16_t instance_id(const uint8_t *tlv); + +private: + + static M2MTLVDeserializer::Error deserialize_object_instances(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MObject &object, + M2MTLVDeserializer::Operation operation, + bool update_value); + + static M2MTLVDeserializer::Error deserialize_resources(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MObjectInstance &object_instance, + M2MTLVDeserializer::Operation operation, + bool update_value); + + static M2MTLVDeserializer::Error deserialize_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MResource &resource, + M2MObjectInstance &object_instance, + M2MTLVDeserializer::Operation operation, + bool update_value); + + static M2MTLVDeserializer::Error deserialize_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MResource &resource, + M2MTLVDeserializer::Operation operation, + bool update_value); + + static bool is_object_instance(const uint8_t *tlv, uint32_t offset); + + static bool is_resource(const uint8_t *tlv, uint32_t offset); + + static bool is_multiple_resource(const uint8_t *tlv, uint32_t offset); + + static bool is_resource_instance(const uint8_t *tlv, uint32_t offset); + + static bool set_resource_instance_value(M2MResourceBase *res, const uint8_t *tlv, const uint32_t size); + + static void remove_resources(const uint8_t *tlv, + uint32_t tlv_size, + M2MObjectInstance &object_instance, + uint32_t offset_size); + + static void remove_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + M2MResource &resource, + uint32_t offset_size); +}; + +class TypeIdLength { + +public: + TypeIdLength(const uint8_t *tlv, uint32_t offset); + + void deserialize(); + + void deserialiseID(uint32_t idLength); + + void deserialiseLength(uint32_t lengthType); + + const uint8_t *_tlv; + uint32_t _offset; + uint32_t _type; + uint16_t _id; + uint32_t _length; + + friend class Test_M2MTLVDeserializer; +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mtlvserializer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/m2mtlvserializer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed-client/m2mvector.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mresource.h" + +class M2MResourceBase; + +/** + * @brief M2MTLVSerializer + * TLV Serialiser constructs the binary representation of object instances, + * resources and resource instances (see OMA-LWM2M specification, chapter 6.1 + * for resource model) as OMA-TLV according described in chapter 6.3.3. + * + */ +class M2MTLVSerializer { + +public: + + /** + * Serialises given objects instances that contain resources or multiple + * resources. Object instance IDs are also encoded. This method must be + * used when an operation targets an object with (potential) multiple + * instances like "GET /1". In that case the generated TLV will contain the + * following data: + * <ul> + * <li> ./0 + * <li> ./0/0 + * <li> ./0/1 + * <li> ... + * <li> ./1 + * <li> ./1/0 + * <li> ./1/1 + * <li> ... + * </ul> + * + * @param objects List of object instances. + * @return Object instances encoded binary as OMA-TLV + * @see #serializeObjectInstances(List) + */ + static uint8_t* serialize(const M2MObjectInstanceList &object_instance_list, uint32_t &size); + + /** + * Serialises given resources with no information about the parent object + * instance. This method must be used when an operation targets an object + * instance like "GET /1/0" or a single-instance object like "GET /3//". + * Resources may have single or multiple instances. The generated TLV will + * contain the following data as response to "GET /3//": + * <ul> + * <li> ./0 + * <li> ./1 + * <li> ./2 + * <li> ./6/0 (1st instance of a multiple resource) + * <li> ./6/1 (2nd instance of a multiple resource) + * <li> ... + * </ul> + * @param resources Array of resources and resource instances. + * @return Resources encoded binary as OMA-TLV + * @see #serializeResources(List) + */ + static uint8_t* serialize(const M2MResourceList &resource_list, uint32_t &size); + + static uint8_t* serialize(const M2MResource *resource, uint32_t &size); + +private : + + static uint8_t* serialize_object_instances(const M2MObjectInstanceList &object_instance_list, uint32_t &size); + + static uint8_t* serialize_resources(const M2MResourceList &resource_list, uint32_t &size, bool &valid); + + static bool serialize(uint16_t id, const M2MObjectInstance *object_instance, uint8_t *&data, uint32_t &size); + + static bool serialize(const M2MResource *resource, uint8_t *&data, uint32_t &size); + + static bool serialize_resource(const M2MResource *resource, uint8_t *&data, uint32_t &size); + + static bool serialize_multiple_resource(const M2MResource *resource, uint8_t *&data, uint32_t &size); + + static bool serialize_resource_instance(uint16_t id, const M2MResourceInstance *resource, uint8_t *&data, uint32_t &size); + + static bool serialize_TILV (uint8_t type, uint16_t id, uint8_t *value, uint32_t value_length, uint8_t *&data, uint32_t &size); + + static void serialize_id(uint16_t id, uint32_t &size, uint8_t *id_ptr); + + static void serialize_length(uint32_t length, uint32_t &size, uint8_t *length_ptr); + + static bool serialize_TLV_binary_int(const M2MResourceBase *resource, uint8_t type, uint16_t id, uint8_t *&data, uint32_t &size); +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/nsdlaccesshelper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/nsdlaccesshelper.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef NSDL_ACCESS_HELPER_H +#define NSDL_ACCESS_HELPER_H +#include "mbed-client/m2mconnectionhandler.h" +#include "include/m2mnsdlinterface.h" + +typedef Vector<M2MNsdlInterface *> M2MNsdlInterfaceList; + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t __nsdl_c_callback(struct nsdl_s * nsdl_handle, + sn_coap_hdr_s *received_coap_ptr, + sn_nsdl_addr_s *address, + sn_nsdl_capab_e nsdl_capab); + +void *__nsdl_c_memory_alloc(uint16_t size); + +void __nsdl_c_memory_free(void *ptr); + +uint8_t __nsdl_c_send_to_server(struct nsdl_s * nsdl_handle, + sn_nsdl_capab_e protocol, + uint8_t *data_ptr, + uint16_t data_len, + sn_nsdl_addr_s *address_ptr); + +uint8_t __nsdl_c_received_from_server(struct nsdl_s * nsdl_handle, + sn_coap_hdr_s *coap_header, + sn_nsdl_addr_s *address_ptr); + +uint8_t __nsdl_c_auto_obs_token(struct nsdl_s *nsdl_handle, const char *path, uint8_t *token); + +void *__socket_malloc( void * context, size_t size); + +void __socket_free(void * context, void * ptr); + +M2MNsdlInterface* get_interface(struct nsdl_s* nsdl_handle); + +#ifdef __cplusplus +} +#endif + +#endif // NSDL_ACCESS_HELPER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/nsdllinker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/nsdllinker.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef NSDL_LINKER_H +#define NSDL_LINKER_H + +#include <stdint.h> +#include "nsdl-c/sn_nsdl.h" +#include "sn_coap_header.h" +#include "sn_coap_protocol.h" +#include "nsdl-c/sn_nsdl_lib.h" +#include "ns_list.h" + +#endif // NSDL_LINKER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/smartpointer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/smartpointer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SMART_POINTER_H +#define SMART_POINTER_H + +class ReferenceCount +{ +private: + + int _count; // Reference count + +public: + +void add_ref() +{ + // Increment the reference count + _count++; +} + +int release() +{ + // Decrement the reference count and + // return the reference count. + return --_count; +} +}; + +template < typename T > class SmartPointer +{ +private: + + T *_data; // Generic pointer to be stored + ReferenceCount *_reference; // Reference count + + +public: + +SmartPointer() +: _data(0), _reference(0) +{ + // Create a new reference + _reference = new ReferenceCount(); + // Increment the reference count + _reference->add_ref(); +} + +SmartPointer(T* value) +: _data(value), _reference(0) +{ + // Create a new reference + _reference = new ReferenceCount(); + // Increment the reference count + _reference->add_ref(); +} + +SmartPointer(const SmartPointer<T>& smart_pointer) +: _data(smart_pointer._data), reference(smart_pointer._reference) +{ + // Copy constructor + // Copy the data and reference pointer + // and increment the reference count + _reference->add_ref(); +} + +~SmartPointer() +{ + if(_reference->release() == 0) { + delete _data; + delete _reference; + } +} + +T& operator* () +{ + return *_data; +} + +T* operator-> () +{ + return _data; +} + +SmartPointer<T>& operator = (const SmartPointer<T>& smart_pointer) +{ + // Assignment operator + if (this != &SmartPointer) { // Avoid self assignment + // Decrement the old reference count + // if reference become zero delete the old data + if(_reference->release() == 0) { + delete _data; + delete _reference; + } + + // Copy the data and reference pointer + // and increment the reference count + _data = SmartPointer._data; + _reference = SmartPointer._reference; + _reference->add_ref(); + } + return *this; +} + +}; + +#endif // SMART_POINTER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/uriqueryparser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/include/uriqueryparser.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,55 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef URIQUERYPARSER_H +#define URIQUERYPARSER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ns_types.h" + +/** + * \brief Returns string containing query parameters. + * \param uri URL + * \return Query parameters or NULL if there is no parameters. + */ +char *query_string(char *uri); + +/** + * \brief Return count of query parameters. + * \param query Query string + * \return Count of query parameters + */ +int8_t query_param_count(char *query); + +/** + * \brief Extract queries from the query string. + * \param query Query string + * \param uri_query_parameters [OUT] List of queries + * \param index Starting index + * \return True if parsing success otherwise False. + */ +bool uri_query_parameters(char* query, char *uri_query_parameters[], int index); + +#ifdef __cplusplus +} +#endif + +#endif // URIQUERYPARSER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mbase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mbase.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,882 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed-client/m2mbase.h" +#include "mbed-client/m2mobservationhandler.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mtimer.h" + +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mresource.h" + +#include "include/m2mreporthandler.h" +#include "include/nsdlaccesshelper.h" +#include "include/m2mcallbackstorage.h" +#include "mbed-trace/mbed_trace.h" + +#include "sn_nsdl_lib.h" +#include <assert.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include "common_functions.h" + +#define TRACE_GROUP "mClt" + +M2MBase::M2MBase(const String& resource_name, + M2MBase::Mode mode, +#ifndef DISABLE_RESOURCE_TYPE + const String &resource_type, +#endif + char *path, + bool external_blockwise_store, + bool multiple_instance, + M2MBase::DataType type) +: + _sn_resource(NULL), + _report_handler(NULL) +{ + // Checking the name length properly, i.e returning error is impossible from constructor without exceptions + assert(resource_name.length() <= MAX_ALLOWED_STRING_LENGTH); + + _sn_resource = (lwm2m_parameters_s*)memory_alloc(sizeof(lwm2m_parameters_s)); + if(_sn_resource) { + memset(_sn_resource, 0, sizeof(lwm2m_parameters_s)); + _sn_resource->free_on_delete = true; + _sn_resource->multiple_instance = multiple_instance; + _sn_resource->data_type = type; + _sn_resource->dynamic_resource_params = + (sn_nsdl_dynamic_resource_parameters_s*)memory_alloc(sizeof(sn_nsdl_dynamic_resource_parameters_s)); + if(_sn_resource->dynamic_resource_params) { + memset(_sn_resource->dynamic_resource_params, + 0, sizeof(sn_nsdl_dynamic_resource_parameters_s)); + _sn_resource->dynamic_resource_params->static_resource_parameters = + (sn_nsdl_static_resource_parameters_s*)memory_alloc(sizeof(sn_nsdl_static_resource_parameters_s)); + + // Set callback function in case of both dynamic and static resource + _sn_resource->dynamic_resource_params->sn_grs_dyn_res_callback = __nsdl_c_callback; + + if(_sn_resource->dynamic_resource_params->static_resource_parameters) { + // Cast const away to able to compile using MEMORY_OPTIMIZED_API flag + sn_nsdl_static_resource_parameters_s *params = + const_cast<sn_nsdl_static_resource_parameters_s *>(_sn_resource->dynamic_resource_params->static_resource_parameters); + memset(params, 0, sizeof(sn_nsdl_static_resource_parameters_s)); + const size_t len = strlen(resource_type.c_str()); + if (len > 0) { +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + params->resource_type_ptr = (char*)alloc_string_copy((uint8_t*) resource_type.c_str(), len); +#endif +#else + sn_nsdl_attribute_item_s item; + item.attribute_name = ATTR_RESOURCE_TYPE; + item.value = (char*)alloc_string_copy((uint8_t*) resource_type.c_str(), len); + sn_nsdl_set_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, &item); +#endif + } + params->path = path; + params->mode = (unsigned)mode; + params->free_on_delete = true; + params->external_memory_block = external_blockwise_store; + _sn_resource->dynamic_resource_params->static_resource_parameters = params; + } + } + + if((!resource_name.empty())) { + _sn_resource->identifier_int_type = false; + _sn_resource->identifier.name = stringdup((char*)resource_name.c_str()); + } else { + tr_debug("M2MBase::M2Mbase resource name is EMPTY ==========="); + _sn_resource->identifier_int_type = true; + _sn_resource->identifier.instance_id = 0; + } + _sn_resource->dynamic_resource_params->publish_uri = true; + _sn_resource->dynamic_resource_params->free_on_delete = true; + _sn_resource->dynamic_resource_params->notification_status = NOTIFICATION_STATUS_INIT; + _sn_resource->dynamic_resource_params->auto_observable = false; + } +} + +M2MBase::M2MBase(const lwm2m_parameters_s *s): + _sn_resource((lwm2m_parameters_s*) s), + _report_handler(NULL) +{ + tr_debug("M2MBase::M2MBase(const lwm2m_parameters_s *s)"); + // Set callback function in case of both dynamic and static resource + _sn_resource->dynamic_resource_params->sn_grs_dyn_res_callback = __nsdl_c_callback; +} + +M2MBase::~M2MBase() +{ + tr_debug("M2MBase::~M2MBase()"); + delete _report_handler; + + value_updated_callback* callback = (value_updated_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback); + delete callback; + + M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2); + M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback); +} + +char* M2MBase::create_path_base(const M2MBase &parent, const char *name) +{ + char * result = NULL; + // Expectation is that every element can be MAX_NAME_SZE, + 4 /'s + \0 + StringBuffer<(MAX_NAME_SIZE * 4 + (4 + 1))> path; + path.append(parent.uri_path()); + path.append('/'); + path.append(name); + result = stringdup(path.c_str()); + + return result; +} + +char* M2MBase::create_path(const M2MObject &parent, uint16_t object_instance) +{ + StringBuffer<6> obj_inst_id; + obj_inst_id.append_int(object_instance); + + return create_path_base(parent, obj_inst_id.c_str()); +} + +char* M2MBase::create_path(const M2MObject &parent, const char *name) +{ + return create_path_base(parent, name); +} + +char* M2MBase::create_path(const M2MResource &parent, uint16_t resource_instance) +{ + StringBuffer<6> res_inst; + res_inst.append_int(resource_instance); + + return create_path_base(parent, res_inst.c_str()); +} + +char* M2MBase::create_path(const M2MResource &parent, const char *name) +{ + return create_path_base(parent, name); +} + +char* M2MBase::create_path(const M2MObjectInstance &parent, const char *name) +{ + return create_path_base(parent, name); +} + +void M2MBase::set_operation(M2MBase::Operation opr) +{ + // If the mode is Static, there is only GET_ALLOWED supported. + if(M2MBase::Static == mode()) { + _sn_resource->dynamic_resource_params->access = M2MBase::GET_ALLOWED; + } else { + _sn_resource->dynamic_resource_params->access = opr; + } +} + +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef MEMORY_OPTIMIZED_API +#ifndef DISABLE_INTERFACE_DESCRIPTION +void M2MBase::set_interface_description(const char *desc) +{ + assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); + free(_sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr); + _sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr = NULL; + const size_t len = strlen(desc); + if (len > 0 ) { + _sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr = + (char*)alloc_string_copy((uint8_t*) desc, len); + } +} + +void M2MBase::set_interface_description(const String &desc) +{ + assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); + set_interface_description(desc.c_str()); +} +#endif // DISABLE_INTERFACE_DESCRIPTION + +#ifndef DISABLE_RESOURCE_TYPE +void M2MBase::set_resource_type(const String &res_type) +{ + assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); + set_resource_type(res_type.c_str()); +} + +void M2MBase::set_resource_type(const char *res_type) +{ + assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); + free(_sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr); + _sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr = NULL; + const size_t len = strlen(res_type); + if (len > 0) { + _sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr = (char*) + alloc_string_copy((uint8_t*) res_type, len); + } +} +#endif // DISABLE_RESOURCE_TYPE +#endif //MEMORY_OPTIMIZED_API +#else // RESOURCE_ATTRIBUTES_LIST +void M2MBase::set_interface_description(const char *desc) +{ + assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); + const size_t len = strlen(desc); + if (len > 0 ) { + sn_nsdl_attribute_item_s item; + item.attribute_name = ATTR_INTERFACE_DESCRIPTION; + item.value = (char*)alloc_string_copy((uint8_t*) desc, len); + sn_nsdl_set_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, &item); + } +} + +void M2MBase::set_interface_description(const String &desc) +{ + assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); + set_interface_description(desc.c_str()); +} + +void M2MBase::set_resource_type(const String &res_type) +{ + assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); + set_resource_type(res_type.c_str()); +} + +void M2MBase::set_resource_type(const char *res_type) +{ + assert(_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete); + const size_t len = strlen(res_type); + if (len > 0) { + sn_nsdl_attribute_item_s item; + item.attribute_name = ATTR_RESOURCE_TYPE; + item.value = (char*)alloc_string_copy((uint8_t*) res_type, len); + sn_nsdl_set_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, &item); + } +} +#endif // RESOURCE_ATTRIBUTES_LIST + +void M2MBase::set_coap_content_type(const uint16_t con_type) +{ + _sn_resource->dynamic_resource_params->coap_content_type = con_type; +} + +void M2MBase::set_observable(bool observable) +{ + _sn_resource->dynamic_resource_params->observable = observable; +} + +void M2MBase::set_auto_observable(bool auto_observable) +{ + _sn_resource->dynamic_resource_params->auto_observable = auto_observable; +} + +void M2MBase::add_observation_level(M2MBase::Observation obs_level) +{ + if(_report_handler) { + _report_handler->add_observation_level(obs_level); + } +} + +void M2MBase::remove_observation_level(M2MBase::Observation obs_level) +{ + if(_report_handler) { + _report_handler->remove_observation_level(obs_level); + } +} + + +void M2MBase::set_under_observation(bool observed, + M2MObservationHandler *handler) +{ + tr_debug("M2MBase::set_under_observation - observed: %d", observed); + tr_debug("M2MBase::set_under_observation - base_type: %d", base_type()); + if(_report_handler) { + _report_handler->set_under_observation(observed); + } + + set_observation_handler(handler); + + if (handler) { + if (base_type() != M2MBase::ResourceInstance) { + // Create report handler only if it does not exist and one wants observation + // This saves 76 bytes of memory on most usual case. + if (observed) { + if(!_report_handler) { + _report_handler = new M2MReportHandler(*this); + } + } + if (_report_handler) { + _report_handler->set_under_observation(observed); + } + } + } else { + delete _report_handler; + _report_handler = NULL; + } +} + +void M2MBase::set_observation_token(const uint8_t *token, const uint8_t length) +{ + if (_report_handler) { + _report_handler->set_observation_token(token, length); + } +} + +void M2MBase::set_instance_id(const uint16_t inst_id) +{ + _sn_resource->identifier_int_type = true; + _sn_resource->identifier.instance_id = inst_id; +} + +void M2MBase::set_max_age(const uint32_t max_age) +{ + _sn_resource->max_age = max_age; +} + +M2MBase::BaseType M2MBase::base_type() const +{ + return (M2MBase::BaseType)_sn_resource->base_type; +} + +M2MBase::Operation M2MBase::operation() const +{ + return (M2MBase::Operation)_sn_resource->dynamic_resource_params->access; +} + +const char* M2MBase::name() const +{ + assert(_sn_resource->identifier_int_type == false); + return _sn_resource->identifier.name; +} + +int32_t M2MBase::name_id() const +{ + int32_t name_id = -1; + assert(_sn_resource->identifier_int_type == false); + if(is_integer(_sn_resource->identifier.name) && strlen(_sn_resource->identifier.name) <= MAX_ALLOWED_STRING_LENGTH) { + name_id = strtoul(_sn_resource->identifier.name, NULL, 10); + if(name_id > 65535){ + name_id = -1; + } + } + return name_id; +} + +uint16_t M2MBase::instance_id() const +{ + assert(_sn_resource->identifier_int_type == true); + return _sn_resource->identifier.instance_id; +} + +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_INTERFACE_DESCRIPTION +const char* M2MBase::interface_description() const +{ + return (reinterpret_cast<char*>( + _sn_resource->dynamic_resource_params->static_resource_parameters->interface_description_ptr)); +} +#endif + +#ifndef DISABLE_RESOURCE_TYPE +const char* M2MBase::resource_type() const +{ + return (reinterpret_cast<char*>( + _sn_resource->dynamic_resource_params->static_resource_parameters->resource_type_ptr)); +} +#endif +#else // RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_INTERFACE_DESCRIPTION +const char* M2MBase::interface_description() const +{ + return sn_nsdl_get_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, ATTR_INTERFACE_DESCRIPTION); +} +#endif + +#ifndef DISABLE_RESOURCE_TYPE +const char* M2MBase::resource_type() const +{ + return sn_nsdl_get_resource_attribute(_sn_resource->dynamic_resource_params->static_resource_parameters, ATTR_RESOURCE_TYPE); +} +#endif +#endif // RESOURCE_ATTRIBUTES_LIST +const char* M2MBase::uri_path() const +{ + return (reinterpret_cast<char*>( + _sn_resource->dynamic_resource_params->static_resource_parameters->path)); +} + +uint16_t M2MBase::coap_content_type() const +{ + return _sn_resource->dynamic_resource_params->coap_content_type; +} + +bool M2MBase::is_observable() const +{ + if (_sn_resource->dynamic_resource_params->auto_observable) { + return true; + } else { + return _sn_resource->dynamic_resource_params->observable; + } +} + +M2MBase::Observation M2MBase::observation_level() const +{ + M2MBase::Observation obs_level = M2MBase::None; + if(_report_handler) { + obs_level = _report_handler->observation_level(); + } + return obs_level; +} + +void M2MBase::get_observation_token(uint8_t *token, uint8_t &token_length) const +{ + if(_report_handler) { + _report_handler->get_observation_token(token, token_length); + } +} + +M2MBase::Mode M2MBase::mode() const +{ + return (M2MBase::Mode)_sn_resource->dynamic_resource_params->static_resource_parameters->mode; +} + +uint16_t M2MBase::observation_number() const +{ + uint16_t obs_number = 0; + if(_report_handler) { + obs_number = _report_handler->observation_number(); + } + return obs_number; +} + +uint32_t M2MBase::max_age() const +{ + return _sn_resource->max_age; +} + +bool M2MBase::handle_observation_attribute(const char *query) +{ + tr_debug("M2MBase::handle_observation_attribute - under observation(%d)", is_under_observation()); + bool success = false; + // Create handler if not already exists. Client must able to parse write attributes even when + // observation is not yet set + if (!_report_handler) { + _report_handler = new M2MReportHandler(*this); + } + + success = _report_handler->parse_notification_attribute(query,base_type()); + if (success) { + if (is_under_observation()) { + _report_handler->set_under_observation(true); + } + } else { + _report_handler->set_default_values(); + } + return success; +} + +void M2MBase::observation_to_be_sent(const m2m::Vector<uint16_t> &changed_instance_ids, + uint16_t obs_number, + bool send_object) +{ + //TODO: Move this to M2MResourceInstance + M2MObservationHandler *obs_handler = observation_handler(); + if (obs_handler) { + obs_handler->observation_to_be_sent(this, + obs_number, + changed_instance_ids, + send_object); + } +} + +void M2MBase::set_base_type(M2MBase::BaseType type) +{ + assert(_sn_resource->free_on_delete); + _sn_resource->base_type = type; +} + +sn_coap_hdr_s* M2MBase::handle_get_request(nsdl_s */*nsdl*/, + sn_coap_hdr_s */*received_coap_header*/, + M2MObservationHandler */*observation_handler*/) +{ + //Handled in M2MResource, M2MObjectInstance and M2MObject classes + return NULL; +} + +sn_coap_hdr_s* M2MBase::handle_put_request(nsdl_s */*nsdl*/, + sn_coap_hdr_s */*received_coap_header*/, + M2MObservationHandler */*observation_handler*/, + bool &) +{ + //Handled in M2MResource, M2MObjectInstance and M2MObject classes + return NULL; +} + +sn_coap_hdr_s* M2MBase::handle_post_request(nsdl_s */*nsdl*/, + sn_coap_hdr_s */*received_coap_header*/, + M2MObservationHandler */*observation_handler*/, + bool &, + sn_nsdl_addr_s *) +{ + //Handled in M2MResource, M2MObjectInstance and M2MObject classes + return NULL; +} + +void *M2MBase::memory_alloc(uint32_t size) +{ + if(size) + return malloc(size); + else + return 0; +} + +void M2MBase::memory_free(void *ptr) +{ + free(ptr); +} + +char* M2MBase::alloc_string_copy(const char* source) +{ + assert(source != NULL); + + // Note: the armcc's libc does not have strdup, so we need to implement it here + const size_t len = strlen(source); + + return (char*)alloc_string_copy((uint8_t*)source, len); +} + +uint8_t* M2MBase::alloc_string_copy(const uint8_t* source, uint32_t size) +{ + assert(source != NULL); + + uint8_t* result = (uint8_t*)memory_alloc(size + 1); + if (result) { + memcpy(result, source, size); + result[size] = '\0'; + } + return result; +} + +uint8_t* M2MBase::alloc_copy(const uint8_t* source, uint32_t size) +{ + assert(source != NULL); + + uint8_t* result = (uint8_t*)memory_alloc(size); + if (result) { + memcpy(result, source, size); + } + return result; +} + +bool M2MBase::validate_string_length(const String &string, size_t min_length, size_t max_length) +{ + bool valid = false; + + const size_t len = string.length(); + if ((len >= min_length) && (len <= max_length)) { + valid = true; + } + + return valid; +} + +bool M2MBase::validate_string_length(const char* string, size_t min_length, size_t max_length) +{ + bool valid = false; + + if (string != NULL) { + const size_t len = strlen(string); + if ((len >= min_length) && (len <= max_length)) { + valid = true; + } + } + return valid; +} + +M2MReportHandler* M2MBase::create_report_handler() +{ + if (!_report_handler) { + _report_handler = new M2MReportHandler(*this); + } + return _report_handler; +} + +M2MReportHandler* M2MBase::report_handler() const +{ + return _report_handler; +} + +void M2MBase::set_register_uri(bool register_uri) +{ + _sn_resource->dynamic_resource_params->publish_uri = register_uri; +} + +bool M2MBase::register_uri() +{ + return _sn_resource->dynamic_resource_params->publish_uri; +} + +bool M2MBase::is_integer(const String &value) +{ + const char *s = value.c_str(); + if(value.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) { + return false; + } + char * p; + strtol(value.c_str(), &p, 10); + return (*p == 0); +} + +bool M2MBase::is_integer(const char *value) +{ + assert(value != NULL); + + if((strlen(value) < 1) || ((!isdigit(value[0])) && (value[0] != '-') && (value[0] != '+'))) { + return false; + } + char * p; + strtol(value, &p, 10); + return (*p == 0); +} + +bool M2MBase::is_under_observation() const +{ + bool under_observation = false; + if(_report_handler) { + under_observation = _report_handler->is_under_observation(); + } + return under_observation; +} + +bool M2MBase::set_value_updated_function(value_updated_callback callback) +{ + value_updated_callback* old_callback = (value_updated_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback); + delete old_callback; + // XXX: create a copy of the copy of callback object. Perhaps it would better to + // give a reference as parameter and just store that, as it would save some memory. + value_updated_callback* new_callback = new value_updated_callback(callback); + + return M2MCallbackStorage::add_callback(*this, new_callback, M2MCallbackAssociation::M2MBaseValueUpdatedCallback); +} + +bool M2MBase::set_value_updated_function(value_updated_callback2 callback) +{ + M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2); + + return M2MCallbackStorage::add_callback(*this, (void*)callback, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2); +} + +bool M2MBase::is_value_updated_function_set() const +{ + bool func_set = false; + if ((M2MCallbackStorage::does_callback_exist(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback) == true) || + (M2MCallbackStorage::does_callback_exist(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2) == true)) { + + func_set = true; + } + return func_set; +} + +void M2MBase::execute_value_updated(const String& name) +{ + // Q: is there a point to call both callback types? Or should we call just one of them? + + value_updated_callback* callback = (value_updated_callback*)M2MCallbackStorage::get_callback(*this, + M2MCallbackAssociation::M2MBaseValueUpdatedCallback); + if (callback) { + (*callback)(name.c_str()); + } + + value_updated_callback2 callback2 = (value_updated_callback2)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MBaseValueUpdatedCallback2); + if (callback2) { + (*callback2)(name.c_str()); + } +} + +bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE> &buffer, const char *s1, uint16_t i1, const char *s2, uint16_t i2) +{ + + if(!buffer.ensure_space(strlen(s1) + strlen(s2) + (MAX_INSTANCE_SIZE * 2) + 3 + 1)){ + return false; + } + + buffer.append(s1); + buffer.append('/'); + buffer.append_int(i1); + buffer.append('/'); + buffer.append(s2); + buffer.append('/'); + buffer.append_int(i2); + + return true; + +} + +bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE_2> &buffer, const char *s1, uint16_t i1, const char *s2) +{ + if(!buffer.ensure_space(strlen(s1) + strlen(s2) + MAX_INSTANCE_SIZE + 2 + 1)){ + return false; + } + + buffer.append(s1); + buffer.append('/'); + buffer.append_int(i1); + buffer.append('/'); + buffer.append(s2); + + return true; +} + +bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE_3> &buffer, const char *s1, uint16_t i1, uint16_t i2) +{ + if(!buffer.ensure_space(strlen(s1) + (MAX_INSTANCE_SIZE * 2) + 2 + 1)){ + return false; + } + + buffer.append(s1); + buffer.append('/'); + buffer.append_int(i1); + buffer.append('/'); + buffer.append_int(i2); + + return true; +} + +bool M2MBase::build_path(StringBuffer<MAX_PATH_SIZE_4> &buffer, const char *s1, uint16_t i1) +{ + if(!buffer.ensure_space(strlen(s1) + MAX_INSTANCE_SIZE + 1 + 1)){ + return false; + } + + buffer.append(s1); + buffer.append('/'); + buffer.append_int(i1); + + return true; +} + +char* M2MBase::stringdup(const char* src) +{ + assert(src != NULL); + + const size_t len = strlen(src) + 1; + + char *dest = (char*)malloc(len); + + if (dest) { + memcpy(dest, src, len); + } + return dest; +} + +void M2MBase::free_resources() +{ + // remove the nsdl structures from the nsdlinterface's lists. + M2MObservationHandler *obs_handler = observation_handler(); + if (obs_handler) { + tr_debug("M2MBase::free_resources()"); + obs_handler->resource_to_be_deleted(this); + } + + if (_sn_resource->dynamic_resource_params->static_resource_parameters->free_on_delete) { + sn_nsdl_static_resource_parameters_s *params = + const_cast<sn_nsdl_static_resource_parameters_s *>(_sn_resource->dynamic_resource_params->static_resource_parameters); + + free(params->path); + //free(params->resource); +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + free(params->resource_type_ptr); +#endif +#ifndef DISABLE_INTERFACE_DESCRIPTION + free(params->interface_description_ptr); +#endif +#else + sn_nsdl_free_resource_attributes_list(_sn_resource->dynamic_resource_params->static_resource_parameters); +#endif + free(params); + } + if (_sn_resource->dynamic_resource_params->free_on_delete) { + free(_sn_resource->dynamic_resource_params->resource); + free(_sn_resource->dynamic_resource_params); + } + + if(_sn_resource->free_on_delete && _sn_resource->identifier_int_type == false) { + tr_debug("M2MBase::free_resources()"); + free(_sn_resource->identifier.name); + } + if(_sn_resource->free_on_delete) { + free(_sn_resource); + } +} + +size_t M2MBase::resource_name_length() const +{ + assert(_sn_resource->identifier_int_type == false); + return strlen(_sn_resource->identifier.name); +} + +sn_nsdl_dynamic_resource_parameters_s* M2MBase::get_nsdl_resource() const +{ + return _sn_resource->dynamic_resource_params; +} + +M2MBase::lwm2m_parameters_s* M2MBase::get_lwm2m_parameters() const +{ + return _sn_resource; +} + +uint16_t M2MBase::get_notification_msgid() const +{ + return _sn_resource->dynamic_resource_params->msg_id; +} + +void M2MBase::set_notification_msgid(uint16_t msgid) +{ + _sn_resource->dynamic_resource_params->msg_id = msgid; +} + +bool M2MBase::set_notification_delivery_status_cb(notification_delivery_status_cb callback, void *client_args) +{ + M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback); + + return M2MCallbackStorage::add_callback(*this, + (void*)callback, + M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback, + client_args); +} + +void M2MBase::send_notification_delivery_status(const M2MBase& object, const NoticationDeliveryStatus status) +{ + _sn_resource->dynamic_resource_params->notification_status = status; + M2MCallbackAssociation* item = M2MCallbackStorage::get_association_item(object, + M2MCallbackAssociation::M2MBaseNotificationDeliveryStatusCallback); + if (item) { + notification_delivery_status_cb callback = (notification_delivery_status_cb)item->_callback; + if (callback) { + (*callback)(object, status, item->_client_args); + } + } +} + +NoticationDeliveryStatus M2MBase::get_notification_delivery_status() const +{ + return _sn_resource->dynamic_resource_params->notification_status; +} + +void M2MBase::clear_notification_delivery_status() +{ + _sn_resource->dynamic_resource_params->notification_status = NOTIFICATION_STATUS_INIT; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mblockmessage.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mblockmessage.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed-client/m2mblockmessage.h" +#include "mbed-client/m2mconfig.h" +#include <stdlib.h> +#include <string.h> + +M2MBlockMessage::M2MBlockMessage() : + _block_data_ptr(NULL), + _total_message_size(0), + _block_data_len(0), + _block_number(0), + _error_code(M2MBlockMessage::ErrorNone), + _is_last_block(false), + _is_block_message(false) +{ +} + +M2MBlockMessage::~M2MBlockMessage() +{ + free(_block_data_ptr); + _block_data_ptr = NULL; +} + +void M2MBlockMessage::set_message_info(sn_coap_hdr_s *coap_header) +{ + _is_block_message = (coap_header && + coap_header->options_list_ptr && + coap_header->options_list_ptr->block1 != -1) ? true : false; + + if (coap_header && coap_header->options_list_ptr) { + // Check total size + if (coap_header->options_list_ptr->use_size1) { + _total_message_size = coap_header->options_list_ptr->size1; + } + + // Default value in coap library is 65kb + uint32_t max_size = SN_COAP_MAX_INCOMING_MESSAGE_SIZE; + if (_total_message_size > max_size) { + _error_code = M2MBlockMessage::EntityTooLarge; + } else { + _error_code = M2MBlockMessage::ErrorNone; + } + if (M2MBlockMessage::ErrorNone == _error_code) { + // Is last block + if (coap_header->options_list_ptr->block1 != -1) { +// if (!(*(coap_header->options_list_ptr->block1_ptr + (coap_header->options_list_ptr->block1_len - 1)) & 0x08)) { + if (!((coap_header->options_list_ptr->block1) & 0x08)) { + _is_last_block = true; + } else { + _is_last_block = false; + } + } + + _block_number = coap_header->options_list_ptr->block1 >> 4; + // Block number +// if (coap_header->options_list_ptr->block1_len == 3) { +// _block_number = *(coap_header->options_list_ptr->block1_ptr) << 12; +// _block_number |= *(coap_header->options_list_ptr->block1_ptr + 1) << 4; +// _block_number |= (*(coap_header->options_list_ptr->block1_ptr + 2)) >> 4; +// } + +// else if (coap_header->options_list_ptr->block1_len == 2) { +// _block_number = *(coap_header->options_list_ptr->block1_ptr) << 4; +// _block_number |= (*(coap_header->options_list_ptr->block1_ptr + 1)) >> 4; +// } +// else if (coap_header->options_list_ptr->block1_len == 1) { +// _block_number = (*coap_header->options_list_ptr->block1_ptr) >> 4; +// } +// else { +// _block_number = 0; +// } + + // Payload + free(_block_data_ptr); + _block_data_ptr = NULL; + _block_data_len = coap_header->payload_len; + if(_block_data_len > 0) { + _block_data_ptr = (uint8_t *)malloc(_block_data_len); + if (_block_data_ptr) { + memcpy(_block_data_ptr, coap_header->payload_ptr, _block_data_len); + } + } + } + } +} + +void M2MBlockMessage::clear_values() +{ + free(_block_data_ptr); + _block_data_ptr = NULL; + _block_data_len = 0; + _block_number = 0; + _total_message_size = 0; + _is_last_block = false; + _error_code = M2MBlockMessage::ErrorNone; +} + +bool M2MBlockMessage::is_block_message() const +{ + return _is_block_message; +} + +uint16_t M2MBlockMessage::block_number() const +{ + return _block_number; +} + +uint32_t M2MBlockMessage::total_message_size() const +{ + return _total_message_size; +} + +bool M2MBlockMessage::is_last_block() const +{ + return _is_last_block; +} + +uint8_t* M2MBlockMessage::block_data() const +{ + return _block_data_ptr; +} + +uint32_t M2MBlockMessage::block_data_len() const +{ + return _block_data_len; +} + +M2MBlockMessage::Error M2MBlockMessage::error_code() const +{ + return _error_code; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mcallbackstorage.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mcallbackstorage.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/m2mcallbackstorage.h" + +#include <cstddef> + +// Dummy constructor, which does not init any value to something meaningful but needed for array construction. +// It is better to leave values unintialized, so the Valgrind will point out if the Vector is used without +// setting real values in there. +M2MCallbackAssociation::M2MCallbackAssociation() +{ +} + +M2MCallbackAssociation::M2MCallbackAssociation(const M2MBase *object, void *callback, M2MCallbackType type, void *client_args) +: _object(object), _callback(callback), _type(type), _client_args(client_args) +{ +} + +M2MCallbackStorage* M2MCallbackStorage::_static_instance = NULL; + +M2MCallbackStorage *M2MCallbackStorage::get_instance() +{ + if (M2MCallbackStorage::_static_instance == NULL) { + M2MCallbackStorage::_static_instance = new M2MCallbackStorage(); + } + return M2MCallbackStorage::_static_instance; +} + +void M2MCallbackStorage::delete_instance() +{ + delete M2MCallbackStorage::_static_instance; + M2MCallbackStorage::_static_instance = NULL; +} + +M2MCallbackStorage::~M2MCallbackStorage() +{ + // TODO: go through the list and delete all the FP<n> objects if there are any. + // On the other hand, if the system is done properly, each m2mobject should actually + // remove its callbacks from its destructor so there is nothing here to do +} + +bool M2MCallbackStorage::add_callback(const M2MBase &object, + void *callback, + M2MCallbackAssociation::M2MCallbackType type, + void *client_args) +{ + bool add_success = false; + M2MCallbackStorage* instance = get_instance(); + if (instance) { + + add_success = instance->do_add_callback(object, callback, type, client_args); + } + return add_success; +} + +bool M2MCallbackStorage::do_add_callback(const M2MBase &object, void *callback, M2MCallbackAssociation::M2MCallbackType type, void *client_args) +{ + bool add_success = false; + + // verify that the same callback is not re-added. + if (does_callback_exist(object, callback, type) == false) { + + const M2MCallbackAssociation association(&object, callback, type, client_args); + _callbacks.push_back(association); + add_success = true; + } + + return add_success; +} + +#if 0 // Functions not used currently +void M2MCallbackStorage::remove_callbacks(const M2MBase &object) +{ + // do not use the get_instance() here as it might create the instance + M2MCallbackStorage* instance = M2MCallbackStorage::_static_instance; + if (instance) { + + instance->do_remove_callbacks(object); + } +} + +void M2MCallbackStorage::do_remove_callbacks(const M2MBase &object) +{ + // find any association to given object and delete them from the vector + for (int index = 0; index < _callbacks.size();) { + if (_callbacks[index]._object == &object) { + _callbacks.erase(index); + } else { + index++; + } + } +} +#endif + +void* M2MCallbackStorage::remove_callback(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type) +{ + void* callback = NULL; + + // do not use the get_instance() here as it might create the instance + M2MCallbackStorage* instance = M2MCallbackStorage::_static_instance; + if (instance) { + + callback = instance->do_remove_callback(object, type); + } + return callback; +} + +void* M2MCallbackStorage::do_remove_callback(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type) +{ + void* callback = NULL; + for (int index = 0; index < _callbacks.size(); index++) { + + if ((_callbacks[index]._object == &object) && (_callbacks[index]._type == type)) { + callback = _callbacks[index]._callback; + _callbacks.erase(index); + break; + } + } + return callback; +} + +void* M2MCallbackStorage::get_callback(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type) +{ + void* callback = NULL; + const M2MCallbackStorage* instance = get_instance(); + if (instance) { + + callback = instance->do_get_callback(object, type); + } + return callback; +} + +void* M2MCallbackStorage::do_get_callback(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type) const +{ + void* callback = NULL; + if (!_callbacks.empty()) { + M2MCallbackAssociationList::const_iterator it = _callbacks.begin(); + + for ( ; it != _callbacks.end(); it++ ) { + + if ((it->_object == &object) && (it->_type == type)) { + callback = it->_callback; + break; + } + } + } + return callback; +} + +M2MCallbackAssociation* M2MCallbackStorage::get_association_item(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type) +{ + M2MCallbackAssociation* callback_association = NULL; + const M2MCallbackStorage* instance = get_instance(); + if (instance) { + + callback_association = instance->do_get_association_item(object, type); + } + return callback_association; +} + +M2MCallbackAssociation* M2MCallbackStorage::do_get_association_item(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type) const +{ + M2MCallbackAssociation* callback_association = NULL; + if (!_callbacks.empty()) { + M2MCallbackAssociationList::const_iterator it = _callbacks.begin(); + + for ( ; it != _callbacks.end(); it++ ) { + + if ((it->_object == &object) && (it->_type == type)) { + callback_association = (M2MCallbackAssociation*)it; + break; + } + } + } + return callback_association; +} + +bool M2MCallbackStorage::does_callback_exist(const M2MBase &object, M2MCallbackAssociation::M2MCallbackType type) +{ + bool found = false; + if (get_callback(object, type) != NULL) { + found = true; + } + return found; +} + +bool M2MCallbackStorage::does_callback_exist(const M2MBase &object, void *callback, M2MCallbackAssociation::M2MCallbackType type) const +{ + bool match_found = false; + + if (!_callbacks.empty()) { + M2MCallbackAssociationList::const_iterator it = _callbacks.begin(); + + for ( ; it != _callbacks.end(); it++ ) { + + if ((it->_object == &object) && (it->_callback == callback) && (it->_type == type)) { + match_found = true; + break; + } + } + } + + return match_found; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mdevice.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mdevice.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed-client/m2mdevice.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mresource.h" +#include "mbed-trace/mbed_trace.h" + +#define BUFFER_SIZE 21 +#define TRACE_GROUP "mClt" + +M2MDevice* M2MDevice::_instance = NULL; + +M2MDevice* M2MDevice::get_instance() +{ + if(_instance == NULL) { + // ownership of this path is transferred to M2MBase. + // Since this object is a singleton, we could use the C-structs to avoid heap + // allocation on a lot of M2MDevice -objects data. + char *path = stringdup(M2M_DEVICE_ID); + if (path) { + _instance = new M2MDevice(path); + } + } + return _instance; +} + +void M2MDevice::delete_instance() +{ + delete _instance; + _instance = NULL; +} + +M2MDevice::M2MDevice(char *path) +: M2MObject(M2M_DEVICE_ID, path) +{ + M2MBase::set_register_uri(false); + M2MBase::set_operation(M2MBase::GET_ALLOWED); + + _device_instance = M2MObject::create_object_instance(); + if(_device_instance) { + _device_instance->set_operation(M2MBase::GET_ALLOWED); + _device_instance->set_register_uri(true); + _device_instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE); + M2MResource* res = _device_instance->create_dynamic_resource(DEVICE_REBOOT, + OMA_RESOURCE_TYPE, + M2MResourceInstance::OPAQUE, + false); + if(res) { + res->set_operation(M2MBase::POST_ALLOWED); + res->set_register_uri(false); + } + + M2MResourceInstance* instance = _device_instance->create_dynamic_resource_instance(DEVICE_ERROR_CODE, + OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + true,0); + if(instance) { + M2MResource * dev_res = _device_instance->resource(DEVICE_ERROR_CODE); + if(dev_res) { + dev_res->set_register_uri(false); + } + instance->set_operation(M2MBase::GET_ALLOWED); + + instance->set_value(0); + + instance->set_register_uri(false); + } + res = _device_instance->create_dynamic_resource(DEVICE_SUPPORTED_BINDING_MODE, + OMA_RESOURCE_TYPE, + M2MResourceInstance::STRING, + true); + if(res) { + res->set_operation(M2MBase::GET_ALLOWED); + res->set_value((const uint8_t*)BINDING_MODE_UDP,sizeof(BINDING_MODE_UDP)-1); + res->set_register_uri(false); + } + } +} + +M2MDevice::~M2MDevice() +{ +} + +M2MResource* M2MDevice::create_resource(DeviceResource resource, const String &value) +{ + M2MResource* res = NULL; + const char* device_id_ptr = ""; + M2MBase::Operation operation = M2MBase::GET_ALLOWED; + if(!is_resource_present(resource) && value.size() <= MAX_ALLOWED_STRING_LENGTH) { + switch(resource) { + case Manufacturer: + device_id_ptr = DEVICE_MANUFACTURER; + break; + case DeviceType: + device_id_ptr = DEVICE_DEVICE_TYPE; + break; + case ModelNumber: + device_id_ptr = DEVICE_MODEL_NUMBER; + break; + case SerialNumber: + device_id_ptr = DEVICE_SERIAL_NUMBER; + break; + case HardwareVersion: + device_id_ptr = DEVICE_HARDWARE_VERSION; + break; + case FirmwareVersion: + device_id_ptr = DEVICE_FIRMWARE_VERSION; + break; + case SoftwareVersion: + device_id_ptr = DEVICE_SOFTWARE_VERSION; + break; + case UTCOffset: + device_id_ptr = DEVICE_UTC_OFFSET; + operation = M2MBase::GET_PUT_ALLOWED; + break; + case Timezone: + device_id_ptr = DEVICE_TIMEZONE; + operation = M2MBase::GET_PUT_ALLOWED; + break; + default: + break; + } + } + const String device_id(device_id_ptr); + + if(!device_id.empty()) { + if(_device_instance) { + res = _device_instance->create_dynamic_resource(device_id, + OMA_RESOURCE_TYPE, + M2MResourceInstance::STRING, + true); + + if(res ) { + res->set_operation(operation); + if (value.empty()) { + res->clear_value(); + } else { + res->set_value((const uint8_t*)value.c_str(), + (uint32_t)value.length()); + } + res->set_register_uri(false); + } + } + } + return res; +} + +M2MResource* M2MDevice::create_resource(DeviceResource resource, int64_t value) +{ + M2MResource* res = NULL; + const char* device_id_ptr = ""; + M2MBase::Operation operation = M2MBase::GET_ALLOWED; + if(!is_resource_present(resource)) { + switch(resource) { + case BatteryLevel: + if(check_value_range(resource, value)) { + device_id_ptr = DEVICE_BATTERY_LEVEL; + } + break; + case BatteryStatus: + if(check_value_range(resource, value)) { + device_id_ptr = DEVICE_BATTERY_STATUS; + } + break; + case MemoryFree: + device_id_ptr = DEVICE_MEMORY_FREE; + break; + case MemoryTotal: + device_id_ptr = DEVICE_MEMORY_TOTAL; + break; + case CurrentTime: + device_id_ptr = DEVICE_CURRENT_TIME; + operation = M2MBase::GET_PUT_ALLOWED; + break; + default: + break; + } + } + + const String device_id(device_id_ptr); + + if(!device_id.empty()) { + if(_device_instance) { + res = _device_instance->create_dynamic_resource(device_id, + OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + true); + + if(res) { + + + res->set_operation(operation); + res->set_value(value); + + res->set_register_uri(false); + } + } + } + return res; +} + +M2MResourceInstance* M2MDevice::create_resource_instance(DeviceResource resource, int64_t value, + uint16_t instance_id) +{ + M2MResourceInstance* res_instance = NULL; + const char* device_id_ptr = ""; + // For these resources multiple instance can exist + if(AvailablePowerSources == resource) { + if(check_value_range(resource, value)) { + device_id_ptr = DEVICE_AVAILABLE_POWER_SOURCES; + } + } else if(PowerSourceVoltage == resource) { + device_id_ptr = DEVICE_POWER_SOURCE_VOLTAGE; + } else if(PowerSourceCurrent == resource) { + device_id_ptr = DEVICE_POWER_SOURCE_CURRENT; + } else if(ErrorCode == resource) { + if(check_value_range(resource, value)) { + device_id_ptr = DEVICE_ERROR_CODE; + } + } + + const String device_id(device_id_ptr); + + if(!device_id.empty()) { + if(_device_instance) { + res_instance = _device_instance->create_dynamic_resource_instance(device_id,OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + true, instance_id); + + M2MResource *res = _device_instance->resource(device_id); + if(res) { + res->set_register_uri(false); + } + if(res_instance) { + res_instance->set_value(value); + // Only read operation is allowed for above resources + res_instance->set_operation(M2MBase::GET_ALLOWED); + + res_instance->set_register_uri(false); + } + } + } + return res_instance; +} +M2MResource* M2MDevice::create_resource(DeviceResource resource) +{ + M2MResource* res = NULL; + if(!is_resource_present(resource)) { + const char* device_Id_ptr = ""; + if(FactoryReset == resource) { + device_Id_ptr = DEVICE_FACTORY_RESET; + } else if(ResetErrorCode == resource) { + device_Id_ptr = DEVICE_RESET_ERROR_CODE; + } + const String device_Id(device_Id_ptr); + + if(_device_instance && !device_Id.empty()) { + res = _device_instance->create_dynamic_resource(device_Id, + OMA_RESOURCE_TYPE, + M2MResourceInstance::OPAQUE, + true); + if(res) { + res->set_operation(M2MBase::POST_ALLOWED); + res->set_register_uri(false); + } + } + } + return res; +} + +bool M2MDevice::delete_resource(DeviceResource resource) +{ + bool success = false; + if(M2MDevice::Reboot != resource && + M2MDevice::ErrorCode != resource && + M2MDevice::SupportedBindingMode != resource) { + if(_device_instance) { + success = _device_instance->remove_resource(resource_name(resource)); + } + } + return success; +} + +bool M2MDevice::delete_resource_instance(DeviceResource resource, + uint16_t instance_id) +{ + bool success = false; + if(M2MDevice::Reboot != resource && + M2MDevice::ErrorCode != resource && + M2MDevice::SupportedBindingMode != resource) { + if(_device_instance) { + success = _device_instance->remove_resource_instance(resource_name(resource),instance_id); + } + } + return success; +} + +bool M2MDevice::set_resource_value(DeviceResource resource, + const String &value, + uint16_t instance_id) +{ + bool success = false; + M2MResourceBase* res = get_resource_instance(resource, instance_id); + if(res && value.size() <= MAX_ALLOWED_STRING_LENGTH) { + if(M2MDevice::Manufacturer == resource || + M2MDevice::ModelNumber == resource || + M2MDevice::DeviceType == resource || + M2MDevice::SerialNumber == resource || + M2MDevice::HardwareVersion == resource || + M2MDevice::FirmwareVersion == resource || + M2MDevice::SoftwareVersion == resource || + M2MDevice::UTCOffset == resource || + M2MDevice::Timezone == resource || + M2MDevice::SupportedBindingMode == resource) { + if (value.empty()) { + res->clear_value(); + success = true; + } else { + success = res->set_value((const uint8_t*)value.c_str(),(uint32_t)value.length()); + } + } + } + return success; +} + +bool M2MDevice::set_resource_value(DeviceResource resource, + int64_t value, + uint16_t instance_id) +{ + bool success = false; + M2MResourceBase* res = get_resource_instance(resource, instance_id); + if(res) { + if(M2MDevice::BatteryLevel == resource || + M2MDevice::BatteryStatus == resource || + M2MDevice::MemoryFree == resource || + M2MDevice::MemoryTotal == resource || + M2MDevice::ErrorCode == resource || + M2MDevice::CurrentTime == resource || + M2MDevice::AvailablePowerSources == resource || + M2MDevice::PowerSourceVoltage == resource || + M2MDevice::PowerSourceCurrent == resource) { + // If it is any of the above resource + // set the value of the resource. + if (check_value_range(resource, value)) { + + success = res->set_value(value); + } + } + } + return success; +} + +String M2MDevice::resource_value_string(DeviceResource resource, + uint16_t instance_id) const +{ + String value = ""; + const M2MResourceBase* res = get_resource_instance(resource, instance_id); + if(res) { + if(M2MDevice::Manufacturer == resource || + M2MDevice::ModelNumber == resource || + M2MDevice::DeviceType == resource || + M2MDevice::SerialNumber == resource || + M2MDevice::HardwareVersion == resource || + M2MDevice::FirmwareVersion == resource || + M2MDevice::SoftwareVersion == resource || + M2MDevice::UTCOffset == resource || + M2MDevice::Timezone == resource || + M2MDevice::SupportedBindingMode == resource) { + + + value = res->get_value_string(); + } + } + return value; +} + +int64_t M2MDevice::resource_value_int(DeviceResource resource, + uint16_t instance_id) const +{ + int64_t value = -1; + M2MResourceBase* res = get_resource_instance(resource, instance_id); + if(res) { + if(M2MDevice::BatteryLevel == resource || + M2MDevice::BatteryStatus == resource || + M2MDevice::MemoryFree == resource || + M2MDevice::MemoryTotal == resource || + M2MDevice::ErrorCode == resource || + M2MDevice::CurrentTime == resource || + M2MDevice::AvailablePowerSources == resource || + M2MDevice::PowerSourceVoltage == resource || + M2MDevice::PowerSourceCurrent == resource) { + + // note: the value may be 32bit int on 32b archs. + value = res->get_value_int(); + } + } + return value; +} + +bool M2MDevice::is_resource_present(DeviceResource resource) const +{ + bool success = false; + const M2MResourceBase* res = get_resource_instance(resource,0); + if(res) { + success = true; + } + return success; +} + +uint16_t M2MDevice::per_resource_count(DeviceResource res) const +{ + uint16_t count = 0; + if(_device_instance) { + count = _device_instance->resource_count(resource_name(res)); + } + return count; +} + +uint16_t M2MDevice::total_resource_count() const +{ + uint16_t count = 0; + if(_device_instance) { + count = _device_instance->resources().size(); + } + return count; +} + +M2MResourceBase* M2MDevice::get_resource_instance(DeviceResource dev_res, + uint16_t instance_id) const +{ + M2MResource* res = NULL; + M2MResourceBase* inst = NULL; + if(_device_instance) { + res = _device_instance->resource(resource_name(dev_res)); + if(res) { + if(res->supports_multiple_instances()) { + inst = res->resource_instance(instance_id); + } else { + inst = res; + } + } + } + return inst; +} + +const char* M2MDevice::resource_name(DeviceResource resource) +{ + const char* res_name = ""; + switch(resource) { + case Manufacturer: + res_name = DEVICE_MANUFACTURER; + break; + case DeviceType: + res_name = DEVICE_DEVICE_TYPE; + break; + case ModelNumber: + res_name = DEVICE_MODEL_NUMBER; + break; + case SerialNumber: + res_name = DEVICE_SERIAL_NUMBER; + break; + case HardwareVersion: + res_name = DEVICE_HARDWARE_VERSION; + break; + case FirmwareVersion: + res_name = DEVICE_FIRMWARE_VERSION; + break; + case SoftwareVersion: + res_name = DEVICE_SOFTWARE_VERSION; + break; + case Reboot: + res_name = DEVICE_REBOOT; + break; + case FactoryReset: + res_name = DEVICE_FACTORY_RESET; + break; + case AvailablePowerSources: + res_name = DEVICE_AVAILABLE_POWER_SOURCES; + break; + case PowerSourceVoltage: + res_name = DEVICE_POWER_SOURCE_VOLTAGE; + break; + case PowerSourceCurrent: + res_name = DEVICE_POWER_SOURCE_CURRENT; + break; + case BatteryLevel: + res_name = DEVICE_BATTERY_LEVEL; + break; + case BatteryStatus: + res_name = DEVICE_BATTERY_STATUS; + break; + case MemoryFree: + res_name = DEVICE_MEMORY_FREE; + break; + case MemoryTotal: + res_name = DEVICE_MEMORY_TOTAL; + break; + case ErrorCode: + res_name = DEVICE_ERROR_CODE; + break; + case ResetErrorCode: + res_name = DEVICE_RESET_ERROR_CODE; + break; + case CurrentTime: + res_name = DEVICE_CURRENT_TIME; + break; + case UTCOffset: + res_name = DEVICE_UTC_OFFSET; + break; + case Timezone: + res_name = DEVICE_TIMEZONE; + break; + case SupportedBindingMode: + res_name = DEVICE_SUPPORTED_BINDING_MODE; + break; + } + return res_name; +} + +bool M2MDevice::check_value_range(DeviceResource resource, int64_t value) +{ + bool success = false; + switch (resource) { + case AvailablePowerSources: + if(value >= 0 && value <= 7) { + success = true; + } + break; + case BatteryLevel: + if (value >= 0 && value <= 100) { + success = true; + } + break; + case BatteryStatus: + if (value >= 0 && value <= 6) { + success = true; + } + break; + case ErrorCode: + if (value >= 0 && value <= 8) { + success = true; + } + break; + default: + success = true; + break; + } + return success; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mfirmware.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mfirmware.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,756 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed-client/m2mfirmware.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mresource.h" +#include "include/nsdlaccesshelper.h" + +#define BUFFER_SIZE 21 +#define TRACE_GROUP "mClt" + +M2MFirmware* M2MFirmware::_instance = NULL; + +M2MFirmware* M2MFirmware::get_instance() +{ + if(_instance == NULL) { + _instance = new M2MFirmware(); + } + return _instance; +} + +void M2MFirmware::delete_instance() +{ + delete _instance; + _instance = NULL; +} + +M2MFirmware::M2MFirmware() +: M2MObject(M2M_FIRMWARE_ID, stringdup(M2M_FIRMWARE_ID)) +{ + M2MBase::set_register_uri(false); + M2MBase::set_operation(M2MBase::GET_PUT_ALLOWED); + _firmware_instance = M2MObject::create_object_instance(); + if(_firmware_instance) { + _firmware_instance->set_operation(M2MBase::GET_PUT_ALLOWED); + create_mandatory_resources(); + } +} + +M2MFirmware::~M2MFirmware() +{ +} + +// Conditionally put the static part of parameter struct into flash. +// Unfortunately this can't be done yet by default as there is old API which +// may be used to modify the values in sn_nsdl_static_resource_parameters_s. +#ifdef MEMORY_OPTIMIZED_API +#define STATIC_PARAM_TYPE const +#else +#define STATIC_PARAM_TYPE +#endif + +#define PACKAGE_PATH FIRMWARE_PATH_PREFIX FIRMWARE_PACKAGE + +#ifdef RESOURCE_ATTRIBUTES_LIST +sn_nsdl_attribute_item_s default_attributes[2] = { + {ATTR_RESOURCE_TYPE, OMA_RESOURCE_TYPE}, + {ATTR_END, 0} +}; +#endif + +STATIC_PARAM_TYPE +static sn_nsdl_static_resource_parameters_s firmware_package_params_static = { +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + (char*)OMA_RESOURCE_TYPE, // resource_type_ptr +#endif +#ifndef DISABLE_INTERFACE_DESCRIPTION + (char*)"", // interface_description_ptr +#endif +#else + default_attributes, +#endif + (char*)PACKAGE_PATH, // path +// (uint8_t*)"", // resource +// 0, // resourcelen + false, // external_memory_block + SN_GRS_DYNAMIC, // mode + false // free_on_delete +}; + +#define PACKAGE_URI_PATH FIRMWARE_PATH_PREFIX FIRMWARE_PACKAGE_URI + +STATIC_PARAM_TYPE +static sn_nsdl_static_resource_parameters_s firmware_package_uri_params_static = { +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + (char*)OMA_RESOURCE_TYPE, // resource_type_ptr +#endif +#ifndef DISABLE_INTERFACE_DESCRIPTION + (char*)"", // interface_description_ptr +#endif +#else + default_attributes, +#endif + (char*)PACKAGE_URI_PATH, // path +// (uint8_t*)"", // resource +// 0, // resourcelen + false, // external_memory_block + SN_GRS_DYNAMIC, // mode + false // free_on_delete +}; + +#define UPDATE_PATH FIRMWARE_PATH_PREFIX FIRMWARE_UPDATE + +STATIC_PARAM_TYPE +static sn_nsdl_static_resource_parameters_s firmware_update_params_static = { +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + (char*)OMA_RESOURCE_TYPE, // resource_type_ptr +#endif +#ifndef DISABLE_INTERFACE_DESCRIPTION + (char*)"", // interface_description_ptr +#endif +#else + default_attributes, +#endif + (char*)UPDATE_PATH, // path +// (uint8_t*)"", // resource +// 0, // resourcelen + false, // external_memory_block + SN_GRS_DYNAMIC, // mode + false // free_on_delete +}; + +#define STATE_URI_PATH FIRMWARE_PATH_PREFIX FIRMWARE_STATE + +STATIC_PARAM_TYPE +static sn_nsdl_static_resource_parameters_s firmware_state_params_static = { +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + (char*)OMA_RESOURCE_TYPE, // resource_type_ptr +#endif +#ifndef DISABLE_INTERFACE_DESCRIPTION + (char*)"", // interface_description_ptr +#endif +#else + default_attributes, +#endif + (char*)STATE_URI_PATH, // path + false, // external_memory_block + SN_GRS_DYNAMIC, // mode + false // free_on_delete +}; + +#define UPDATE_RESULT_PATH FIRMWARE_PATH_PREFIX FIRMWARE_UPDATE_RESULT + +STATIC_PARAM_TYPE +static sn_nsdl_static_resource_parameters_s firmware_update_result_params_static = { +#ifndef RESOURCE_ATTRIBUTES_LIST +#ifndef DISABLE_RESOURCE_TYPE + (char*)OMA_RESOURCE_TYPE, // resource_type_ptr +#endif +#ifndef DISABLE_INTERFACE_DESCRIPTION + (char*)"", // interface_description_ptr +#endif +#else + default_attributes, +#endif + (char*)UPDATE_RESULT_PATH, // path + false, // external_memory_block + SN_GRS_DYNAMIC, // mode + false // free_on_delete +}; + +static sn_nsdl_dynamic_resource_parameters_s firmware_package_params_dynamic = { + __nsdl_c_callback, + &firmware_package_params_static, + NULL, + {NULL, NULL}, // link + 0, + COAP_CONTENT_OMA_PLAIN_TEXT_TYPE, // coap_content_type + 0, // msg_id + M2MBase::PUT_ALLOWED, // access + 0, // registered + false, // publish_uri + false, // free_on_delete + true, // observable + false, // auto-observable + NOTIFICATION_STATUS_INIT +}; + +static sn_nsdl_dynamic_resource_parameters_s firmware_package_uri_params_dynamic = { + __nsdl_c_callback, + &firmware_package_uri_params_static, + NULL, + {NULL, NULL}, // link + 0, + COAP_CONTENT_OMA_PLAIN_TEXT_TYPE, // coap_content_type + 0, // msg_id + M2MBase::PUT_ALLOWED, // access + 0, // registered + false, // publish_uri + false, // free_on_delete + true, // observable + false, // auto-observable + NOTIFICATION_STATUS_INIT +}; + +static sn_nsdl_dynamic_resource_parameters_s firmware_update_params_dynamic = { + __nsdl_c_callback, + &firmware_update_params_static, + NULL, + {NULL, NULL}, // link + 0, + COAP_CONTENT_OMA_PLAIN_TEXT_TYPE, // coap_content_type + 0, // msg_id + M2MBase::NOT_ALLOWED, // access + 0, // registered + false, // publish_uri + false, // free_on_delete + true, // observable + false, // auto-observable + NOTIFICATION_STATUS_INIT +}; + +static sn_nsdl_dynamic_resource_parameters_s firmware_state_params_dynamic = { + __nsdl_c_callback, + &firmware_state_params_static, + NULL, // resource + {NULL, NULL}, // link + 0, // resourcelen + COAP_CONTENT_OMA_PLAIN_TEXT_TYPE, // coap_content_type + 0, // msg_id + M2MBase::GET_ALLOWED, // access + 0, // registered + false, // publish_uri + false, // free_on_delete + true, // observable + false, // auto-observable + NOTIFICATION_STATUS_INIT +}; + +static sn_nsdl_dynamic_resource_parameters_s firmware_update_result_params_dynamic = { + __nsdl_c_callback, + &firmware_update_result_params_static, + NULL, // resource + {NULL, NULL}, // link + 0, // resourcelen + COAP_CONTENT_OMA_PLAIN_TEXT_TYPE, // coap_content_type + 0, // msg_id + M2MBase::GET_ALLOWED, // access + 0, // registered + false, // publish_uri + false, // free_on_delete + true, // observable + false, // auto-observable + NOTIFICATION_STATUS_INIT +}; + +const static M2MBase::lwm2m_parameters firmware_package_params = { + 0, // max_age + (char*)FIRMWARE_PACKAGE, + &firmware_package_params_dynamic, + M2MBase::Resource, // base_type + M2MBase::OPAQUE, + false, + false, // free_on_delete + false // identifier_int_type +}; + +const static M2MBase::lwm2m_parameters firmware_package_uri_params = { + 0, // max_age + (char*)FIRMWARE_PACKAGE_URI, + &firmware_package_uri_params_dynamic, + M2MBase::Resource, // base_type + M2MBase::STRING, + false, + false, // free_on_delete + false // identifier_int_type +}; + +const static M2MBase::lwm2m_parameters firmware_update_params = { + 0, // max_age + (char*)FIRMWARE_UPDATE, + &firmware_update_params_dynamic, + M2MBase::Resource, // base_type + M2MBase::OPAQUE, + false, + false, // free_on_delete + false // identifier_int_type +}; + +const static M2MBase::lwm2m_parameters firmware_state_params = { + 0, // max_age + (char*)FIRMWARE_STATE, + &firmware_state_params_dynamic, + M2MBase::Resource, // base_type + M2MBase::INTEGER, + false, + false, // free_on_delete + false // identifier_int_type +}; + +const static M2MBase::lwm2m_parameters firmware_update_result_params = { + 0, // max_age + (char*)FIRMWARE_UPDATE_RESULT, + &firmware_update_result_params_dynamic, + M2MBase::Resource, // base_type + M2MBase::INTEGER, + false, + false, // free_on_delete + false // identifier_int_type +}; + +void M2MFirmware::create_mandatory_resources() +{ + _firmware_instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE); + + M2MResource* res; + + // todo: + // perhaps we should have a API for batch creation of objects by using a array + // of lwm2m_parameters. + res = _firmware_instance->create_dynamic_resource(&firmware_package_params, + M2MResourceInstance::OPAQUE, + false); + + res = _firmware_instance->create_dynamic_resource(&firmware_package_uri_params, + M2MResourceInstance::STRING, + false); + + res = _firmware_instance->create_dynamic_resource(&firmware_update_params, + M2MResourceInstance::OPAQUE, + false); + + res = _firmware_instance->create_dynamic_resource(&firmware_state_params, + M2MResourceInstance::INTEGER, + true); + + // XXX: some of the tests expect to have some value available here + if (res) { + res->set_value(0); + } + + res = _firmware_instance->create_dynamic_resource(&firmware_update_result_params, + M2MResourceInstance::INTEGER, + true); + + // XXX: some of the tests expect to have some value available here + if (res) { + res->set_value(0); + } +} + +M2MResource* M2MFirmware::create_resource(FirmwareResource resource, const String &value) +{ + M2MResource* res = NULL; + const char* firmware_id_ptr = ""; + M2MBase::Operation operation = M2MBase::GET_ALLOWED; + if(!is_resource_present(resource)) { + switch(resource) { + case PackageName: + firmware_id_ptr = FIRMWARE_PACKAGE_NAME; + break; + case PackageVersion: + firmware_id_ptr = FIRMWARE_PACKAGE_VERSION; + break; + default: + break; + } + } + String firmware_id(firmware_id_ptr); + + if(!firmware_id.empty() && value.size() < 256) { + if(_firmware_instance) { + res = _firmware_instance->create_dynamic_resource(firmware_id, + OMA_RESOURCE_TYPE, + M2MResourceInstance::STRING, + false); + + if(res) { + res->set_register_uri(false); + res->set_operation(operation); + if(value.empty()) { + res->clear_value(); + } else { + res->set_value((const uint8_t*)value.c_str(), + (uint32_t)value.length()); + } + } + } + } + return res; +} + +M2MResource* M2MFirmware::create_resource(FirmwareResource resource, int64_t value) +{ + M2MResource* res = NULL; + const char* firmware_id_ptr = ""; + M2MBase::Operation operation = M2MBase::GET_ALLOWED; + if(!is_resource_present(resource)) { + switch(resource) { + case UpdateSupportedObjects: + if(check_value_range(resource, value)) { + firmware_id_ptr = FIRMWARE_UPDATE_SUPPORTED_OBJECTS; + operation = M2MBase::GET_PUT_ALLOWED; + } + break; + default: + break; + } + } + + const String firmware_id(firmware_id_ptr); + + if(!firmware_id.empty()) { + if(_firmware_instance) { + res = _firmware_instance->create_dynamic_resource(firmware_id, + OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + false); + + if(res) { + res->set_register_uri(false); + + res->set_operation(operation); + res->set_value(value); + } + } + } + return res; +} + +bool M2MFirmware::set_resource_value(FirmwareResource resource, + const String &value) +{ + bool success = false; + M2MResource* res = get_resource(resource); + if(res) { + if(M2MFirmware::PackageUri == resource || + M2MFirmware::PackageName == resource || + M2MFirmware::PackageVersion == resource) { + if (value.size() < 256) { + if(value.empty()) { + res->clear_value(); + success = true; + } else { + success = res->set_value((const uint8_t*)value.c_str(),(uint32_t)value.length()); + } + } + } + } + return success; +} + +bool M2MFirmware::set_resource_value(FirmwareResource resource, + int64_t value) +{ + bool success = false; + M2MResource* res = get_resource(resource); + if(res) { + if(M2MFirmware::State == resource || + M2MFirmware::UpdateSupportedObjects == resource || + M2MFirmware::UpdateResult == resource) { + // If it is any of the above resource + // set the value of the resource. + if (check_value_range(resource, value)) { + + success = res->set_value(value); + } + } + } + return success; +} + +bool M2MFirmware::set_resource_value(FirmwareResource resource, + const uint8_t *value, + const uint32_t length) +{ + bool success = false; + M2MResource* res = get_resource(resource); + if(res) { + if(M2MFirmware::Package == resource) { + success = res->set_value(value,length); + } + } + return success; +} + +bool M2MFirmware::is_resource_present(FirmwareResource resource) const +{ + bool success = false; + M2MResource* res = get_resource(resource); + if(res) { + success = true; + } + return success; +} + +const char* M2MFirmware::resource_name(FirmwareResource resource) +{ + const char* res_name = ""; + switch(resource) { + case Package: + res_name = FIRMWARE_PACKAGE; + break; + case PackageUri: + res_name = FIRMWARE_PACKAGE_URI; + break; + case Update: + res_name = FIRMWARE_UPDATE; + break; + case State: + res_name = FIRMWARE_STATE; + break; + case UpdateSupportedObjects: + res_name = FIRMWARE_UPDATE_SUPPORTED_OBJECTS; + break; + case UpdateResult: + res_name = FIRMWARE_UPDATE_RESULT; + break; + case PackageName: + res_name = FIRMWARE_PACKAGE_NAME; + break; + case PackageVersion: + res_name = FIRMWARE_PACKAGE_VERSION; + break; + } + return res_name; +} + +uint16_t M2MFirmware::per_resource_count(FirmwareResource res) const +{ + uint16_t count = 0; + if(_firmware_instance) { + count = _firmware_instance->resource_count(resource_name(res)); + } + return count; +} + +uint16_t M2MFirmware::total_resource_count() const +{ + uint16_t count = 0; + if(_firmware_instance) { + count = _firmware_instance->resources().size(); + } + return count; +} + +uint32_t M2MFirmware::resource_value_buffer(FirmwareResource resource, + uint8_t *&data) const +{ + uint32_t size = 0; + M2MResource* res = get_resource(resource); + if(res) { + if(M2MFirmware::Package == resource) { + res->get_value(data,size); + } + } + return size; +} + +M2MResource* M2MFirmware::get_resource(FirmwareResource res) const +{ + M2MResource* res_object = NULL; + if(_firmware_instance) { + const char* res_name_ptr = ""; + switch(res) { + case Package: + res_name_ptr = FIRMWARE_PACKAGE; + break; + case PackageUri: + res_name_ptr = FIRMWARE_PACKAGE_URI; + break; + case Update: + res_name_ptr = FIRMWARE_UPDATE; + break; + case State: + res_name_ptr = FIRMWARE_STATE; + break; + case UpdateSupportedObjects: + res_name_ptr = FIRMWARE_UPDATE_SUPPORTED_OBJECTS; + break; + case UpdateResult: + res_name_ptr = FIRMWARE_UPDATE_RESULT; + break; + case PackageName: + res_name_ptr = FIRMWARE_PACKAGE_NAME; + break; + case PackageVersion: + res_name_ptr = FIRMWARE_PACKAGE_VERSION; + break; + } + + res_object = _firmware_instance->resource(res_name_ptr); + } + return res_object; +} + +bool M2MFirmware::delete_resource(FirmwareResource resource) +{ + bool success = false; + if(M2MFirmware::UpdateSupportedObjects == resource || + M2MFirmware::PackageName == resource || + M2MFirmware::PackageVersion == resource) { + if(_firmware_instance) { + success = _firmware_instance->remove_resource(resource_name(resource)); + } + } + return success; +} + +int64_t M2MFirmware::resource_value_int(FirmwareResource resource) const +{ + int64_t value = -1; + M2MResource* res = get_resource(resource); + if(res) { + if(M2MFirmware::State == resource || + M2MFirmware::UpdateSupportedObjects == resource || + M2MFirmware::UpdateResult == resource) { + + value = res->get_value_int(); + } + } + return value; +} + +String M2MFirmware::resource_value_string(FirmwareResource resource) const +{ + String value = ""; + M2MResource* res = get_resource(resource); + if(res) { + if(M2MFirmware::PackageUri == resource || + M2MFirmware::PackageName == resource || + M2MFirmware::PackageVersion == resource) { + + value = res->get_value_string(); + } + } + return value; +} + +bool M2MFirmware::check_value_range(FirmwareResource resource, int64_t value) const +{ + bool success = false; + switch (resource) { + case UpdateSupportedObjects: + if(value == 0 || value == 1) { + success = true; + } + break; + case State: + if (value >= 0 && value <= 3) { + success = true; + M2MResource* updateRes = get_resource(M2MFirmware::Update); + if (updateRes){ + if (value == M2MFirmware::Downloaded) { + updateRes->set_operation(M2MBase::POST_ALLOWED); + } + else { + updateRes->set_operation(M2MBase::NOT_ALLOWED); + } + } + } + break; + case UpdateResult: + if (value >= 0 && value <= 7) { + success = true; + } + break; + default: + break; + } + return success; +} + +bool M2MFirmware::set_update_execute_callback(execute_callback callback) +{ + M2MResource* m2mresource; + + m2mresource = get_resource(Update); + + if(m2mresource) { + m2mresource->set_execute_function(callback); + return true; + } + + return false; +} + +bool M2MFirmware::set_resource_value_update_callback(FirmwareResource resource, + value_updated_callback callback) +{ + M2MResource* m2mresource; + + m2mresource = get_resource(resource); + + if(m2mresource) { + m2mresource->set_value_updated_function(callback); + return true; + } + + return false; +} + +bool M2MFirmware::set_resource_notification_sent_callback(FirmwareResource resource, + notification_sent_callback_2 callback) +{ + M2MResource* m2mresource; + + m2mresource = get_resource(resource); + + if(m2mresource) { + m2mresource->set_notification_sent_callback(callback); + return true; + } + + return false; +} + +bool M2MFirmware::set_resource_notification_sent_callback(FirmwareResource resource, + notification_delivery_status_cb callback) +{ + M2MResource* m2mresource; + + m2mresource = get_resource(resource); + + if(m2mresource) { + m2mresource->set_notification_delivery_status_cb(callback, 0); + return true; + } + + return false; +} + +#ifndef DISABLE_BLOCK_MESSAGE +bool M2MFirmware::set_package_block_message_callback(incoming_block_message_callback callback) +{ + M2MResource* m2mresource; + + m2mresource = get_resource(Package); + + if(m2mresource) { + m2mresource->set_incoming_block_message_callback(callback); + return true; + } + + return false; +} +#endif // DISABLE_BLOCK_MESSAGE
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2minterfacefactory.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2minterfacefactory.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include "mbed-client/m2minterfacefactory.h" +#include "mbed-client/m2mserver.h" +#include "mbed-client/m2mdevice.h" +#include "mbed-client/m2mfirmware.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mconfig.h" +#include "include/m2minterfaceimpl.h" +#include "mbed-trace/mbed_trace.h" + +#include <inttypes.h> + +#define TRACE_GROUP "mClt" + +M2MInterface* M2MInterfaceFactory::create_interface(M2MInterfaceObserver &observer, + const String &endpoint_name, + const String &endpoint_type, + const int32_t life_time, + const uint16_t listen_port, + const String &domain, + M2MInterface::BindingMode mode, + M2MInterface::NetworkStack stack, + const String &context_address) +{ + tr_debug("M2MInterfaceFactory::create_interface - IN"); + tr_info("M2MInterfaceFactory::create_interface - parameters endpoint name : %s",endpoint_name.c_str()); + tr_info("M2MInterfaceFactory::create_interface - parameters endpoint type : %s",endpoint_type.c_str()); + tr_info("M2MInterfaceFactory::create_interface - parameters life time(in secs): %" PRId32,life_time); + tr_info("M2MInterfaceFactory::create_interface - parameters Listen Port : %d",listen_port); + tr_info("M2MInterfaceFactory::create_interface - parameters Binding Mode : %d",(int)mode); + tr_info("M2MInterfaceFactory::create_interface - parameters NetworkStack : %d",(int)stack); + M2MInterfaceImpl *interface = NULL; + + + bool endpoint_type_valid = true; + if(!endpoint_type.empty()) { + if(endpoint_type.size() > MAX_ALLOWED_STRING_LENGTH){ + endpoint_type_valid = false; + } + } + + bool domain_valid = true; + if(!domain.empty()) { + if(domain.size() > MAX_ALLOWED_STRING_LENGTH){ + domain_valid = false; + } + } + + if(((life_time == -1) || (life_time >= MINIMUM_REGISTRATION_TIME)) && + !endpoint_name.empty() && (endpoint_name.size() <= MAX_ALLOWED_STRING_LENGTH) && + endpoint_type_valid && domain_valid) { + tr_debug("M2MInterfaceFactory::create_interface - Creating M2MInterfaceImpl"); + interface = new M2MInterfaceImpl(observer, endpoint_name, + endpoint_type, life_time, + listen_port, domain, mode, + stack, context_address); + + } + tr_debug("M2MInterfaceFactory::create_interface - OUT"); + return interface; +} + +M2MSecurity* M2MInterfaceFactory::create_security(M2MSecurity::ServerType server_type) +{ + tr_debug("M2MInterfaceFactory::create_security"); + M2MSecurity *security = M2MSecurity::get_instance(); + return security; +} + +M2MServer* M2MInterfaceFactory::create_server() +{ + tr_debug("M2MInterfaceFactory::create_server"); + M2MServer *server = new M2MServer(); + return server; +} + +M2MDevice* M2MInterfaceFactory::create_device() +{ + tr_debug("M2MInterfaceFactory::create_device"); + M2MDevice* device = M2MDevice::get_instance(); + return device; +} + +M2MFirmware* M2MInterfaceFactory::create_firmware() +{ + tr_debug("M2MInterfaceFactory::create_firmware"); + M2MFirmware* firmware = M2MFirmware::get_instance(); + return firmware; +} + +M2MObject* M2MInterfaceFactory::create_object(const String &name) +{ + tr_debug("M2MInterfaceFactory::create_object : Name : %s", name.c_str()); + if(name.size() > MAX_ALLOWED_STRING_LENGTH || name.empty()){ + return NULL; + } + + M2MObject *object = NULL; + char *name_copy = M2MBase::stringdup(name.c_str()); + if (name_copy) { + object = new M2MObject(name, name_copy); + } + return object; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2minterfaceimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2minterfaceimpl.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1259 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Needed for PRIu64 on FreeRTOS +#include <stdio.h> +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include <inttypes.h> + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include "include/m2minterfaceimpl.h" +#include "include/eventdata.h" +#include "mbed-client/m2minterfaceobserver.h" +#include "mbed-client/m2mconnectionhandler.h" +#include "mbed-client/m2mconnectionsecurity.h" +#include "include/m2mnsdlinterface.h" +#include "mbed-client/m2msecurity.h" +#include "mbed-client/m2mtimer.h" +#include "mbed-trace/mbed_trace.h" +#include "randLIB.h" + +#include <stdlib.h> + +#define TRACE_GROUP "mClt" + +#define RESOLVE_SEC_MODE(mode) ((mode == M2MInterface::TCP || mode == M2MInterface::TCP_QUEUE) ? M2MConnectionSecurity::TLS : M2MConnectionSecurity::DTLS) + +M2MInterfaceImpl::M2MInterfaceImpl(M2MInterfaceObserver& observer, + const String &ep_name, + const String &ep_type, + const int32_t l_time, + const uint16_t listen_port, + const String &dmn, + M2MInterface::BindingMode mode, + M2MInterface::NetworkStack stack, + const String &con_addr) +: _event_data(NULL), + _registration_flow_timer(NULL), + _server_port(0), + _listen_port(listen_port), + _life_time(l_time), + _register_server(NULL), + _queue_sleep_timer(*this), + _retry_timer(*this), + _callback_handler(NULL), + _max_states( STATE_MAX_STATES ), + _event_ignored(false), + _event_generated(false), + _reconnecting(false), + _retry_timer_expired(false), + _bootstrapped(true), // True as default to get it working with connector only configuration + _queue_mode_timer_ongoing(false), + _current_state(0), + _binding_mode(mode), + _reconnection_state(M2MInterfaceImpl::None), + _observer(observer), + _security_connection( new M2MConnectionSecurity( RESOLVE_SEC_MODE(mode) )), + _connection_handler(*this, _security_connection, mode, stack), + _nsdl_interface(*this, _connection_handler), + _security(NULL) +{ + tr_debug("M2MInterfaceImpl::M2MInterfaceImpl() -IN"); + //TODO:Increase the range from 1 to 100 seconds + randLIB_seed_random(); + // Range is from 2 to 10 + _initial_reconnection_time = randLIB_get_random_in_range(2, 10); + + tr_info("M2MInterfaceImpl::M2MInterfaceImpl() initial random time %d\n", _initial_reconnection_time); + _reconnection_time = _initial_reconnection_time; + +#ifndef DISABLE_ERROR_DESCRIPTION + memset(_error_description, 0, sizeof(_error_description)); +#endif + + _nsdl_interface.create_endpoint(ep_name, + ep_type, + _life_time, + dmn, + (uint8_t)_binding_mode, + con_addr); + + //Here we must use TCP still + _connection_handler.bind_connection(_listen_port); + + // We need this timer only in case of TCP + if (_binding_mode == M2MInterface::TCP || + _binding_mode == M2MInterface::TCP_QUEUE ) { + _registration_flow_timer = new M2MTimer(*this); + } + tr_debug("M2MInterfaceImpl::M2MInterfaceImpl() -OUT"); +} + + +M2MInterfaceImpl::~M2MInterfaceImpl() +{ + tr_debug("M2MInterfaceImpl::~M2MInterfaceImpl() - IN"); + delete _registration_flow_timer; + _security_connection = NULL; + tr_debug("M2MInterfaceImpl::~M2MInterfaceImpl() - OUT"); +} + +void M2MInterfaceImpl::bootstrap(M2MSecurity *security) +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_debug("M2MInterfaceImpl::bootstrap(M2MSecurity *security) - IN"); + _retry_timer.stop_timer(); + _security = NULL; + if(!security) { + set_error_description(ERROR_REASON_1); + _observer.error(M2MInterface::InvalidParameters); + return; + } + // Transition to a new state based upon + // the current state of the state machine + M2MSecurityData data; + data._object = security; + BEGIN_TRANSITION_MAP // - Current State - + TRANSITION_MAP_ENTRY (STATE_BOOTSTRAP) // state_idle + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state__bootstrap_address_resolved + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_resource_created + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_wait + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_error_wait + TRANSITION_MAP_ENTRY (STATE_BOOTSTRAP) // state_bootstrapped + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register_address_resolved + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_registered + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_update_registration + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregister + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregistered + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_sending_coap_data + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_sent + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_received + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_processing_coap_data + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_processed + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_waiting + END_TRANSITION_MAP(&data) + if(_event_ignored) { + _event_ignored = false; + set_error_description(ERROR_REASON_2); + _observer.error(M2MInterface::NotAllowed); + } + tr_debug("M2MInterfaceImpl::bootstrap(M2MSecurity *security) - OUT"); +#else + set_error_description(ERROR_REASON_3); + _observer.error(M2MInterface::NotAllowed); +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::cancel_bootstrap() +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +//TODO: Do we need this ? +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::register_object(M2MSecurity *security, const M2MObjectList &object_list) +{ + tr_debug("M2MInterfaceImpl::register_object - IN"); + if(!security) { + set_error_description(ERROR_REASON_4); + _observer.error(M2MInterface::InvalidParameters); + return; + } + // Transition to a new state based upon + // the current state of the state machine + //TODO: manage register object in a list. + _connection_handler.claim_mutex(); + _register_server = security; + M2MRegisterData data; + data._object = security; + data._object_list = object_list; + BEGIN_TRANSITION_MAP // - Current State - + TRANSITION_MAP_ENTRY (STATE_REGISTER) // state_idle + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state__bootstrap_address_resolved + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_resource_created + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_wait + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_error_wait + TRANSITION_MAP_ENTRY (STATE_REGISTER) // state_bootstrapped + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register_address_resolved + TRANSITION_MAP_ENTRY (STATE_REGISTER) // state_registered + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_update_registration + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregister + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregistered + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_sending_coap_data + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_sent + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_received + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_processing_coap_data + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_processed + TRANSITION_MAP_ENTRY (STATE_REGISTER) // state_waiting + END_TRANSITION_MAP(&data) + if(_event_ignored) { + _event_ignored = false; + set_error_description(ERROR_REASON_5); + _observer.error(M2MInterface::NotAllowed); + } + _connection_handler.release_mutex(); + tr_debug("M2MInterfaceImpl::register_object - OUT"); +} + +void M2MInterfaceImpl::update_registration(M2MSecurity *security_object, const uint32_t lifetime) +{ + tr_debug("M2MInterfaceImpl::update_registration()"); + _connection_handler.claim_mutex(); + M2MUpdateRegisterData data; + data._object = security_object; + data._lifetime = lifetime; + start_register_update(&data); + _connection_handler.release_mutex(); +} + +void M2MInterfaceImpl::update_registration(M2MSecurity *security_object, + const M2MObjectList &object_list, + const uint32_t lifetime) +{ + tr_debug("M2MInterfaceImpl::update_registration - with object list"); + _connection_handler.claim_mutex(); + M2MUpdateRegisterData data; + data._object = security_object; + data._lifetime = lifetime; + data._object_list = object_list; + start_register_update(&data); + _connection_handler.release_mutex(); +} + +void M2MInterfaceImpl::unregister_object(M2MSecurity* /*security*/) +{ + tr_debug("M2MInterfaceImpl::unregister_object - current state %d", _current_state); + _connection_handler.claim_mutex(); + // Transition to a new state based upon + // the current state of the state machine + BEGIN_TRANSITION_MAP // - Current State - + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_idle + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state__bootstrap_address_resolved + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_resource_created + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_wait + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_error_wait + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrapped + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register_address_resolved + TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_registered + TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_update_registration + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregister + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregistered + TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_sending_coap_data + TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_coap_data_sent + TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_coap_data_received + TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_processing_coap_data + TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_coap_data_processed + TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_waiting + END_TRANSITION_MAP(NULL) + if(_event_ignored) { + _event_ignored = false; + set_error_description(ERROR_REASON_6); + _observer.error(M2MInterface::NotAllowed); + } + _connection_handler.release_mutex(); + tr_debug("M2MInterfaceImpl::unregister_object - OUT"); +} + +void M2MInterfaceImpl::set_queue_sleep_handler(callback_handler handler) +{ + _callback_handler = handler; +} + +void M2MInterfaceImpl::set_random_number_callback(random_number_cb callback) +{ + if(_security_connection) { + _security_connection->set_random_number_callback(callback); + } +} + +void M2MInterfaceImpl::set_entropy_callback(entropy_cb callback) +{ + if(_security_connection) { + _security_connection->set_entropy_callback(callback); + } +} + +void M2MInterfaceImpl::set_platform_network_handler(void *handler) +{ + _connection_handler.set_platform_network_handler(handler); +} + +void M2MInterfaceImpl::coap_message_ready(uint8_t *data_ptr, + uint16_t data_len, + sn_nsdl_addr_s *address_ptr) +{ + tr_debug("M2MInterfaceImpl::coap_message_ready"); + if (_current_state != STATE_IDLE) { + internal_event(STATE_SENDING_COAP_DATA); + if(!_connection_handler.send_data(data_ptr,data_len,address_ptr)) { + internal_event( STATE_IDLE); + tr_error("M2MInterfaceImpl::coap_message_ready() - M2MInterface::NetworkError"); + if (!_reconnecting) { + _queue_mode_timer_ongoing = false; + socket_error(M2MConnectionHandler::SOCKET_SEND_ERROR, true); + } else { + socket_error(M2MConnectionHandler::SOCKET_ABORT); + } + } + } +} + +void M2MInterfaceImpl::client_registered(M2MServer *server_object) +{ + tr_info("M2MInterfaceImpl::client_registered"); + internal_event(STATE_REGISTERED); + //Inform client is registered. + //TODO: manage register object in a list. + _observer.object_registered(_register_server,*server_object); +} + +void M2MInterfaceImpl::registration_updated(const M2MServer &server_object) +{ + tr_info("M2MInterfaceImpl::registration_updated"); + internal_event(STATE_REGISTERED); + _observer.registration_updated(_register_server,server_object); +} + +void M2MInterfaceImpl::registration_error(uint8_t error_code, bool retry) +{ + tr_error("M2MInterfaceImpl::registration_error code [%d]", error_code); + // Try to register again + if (retry) { + _queue_mode_timer_ongoing = false; + if (error_code == M2MInterface::UnregistrationFailed) { + _reconnection_state = M2MInterfaceImpl::Unregistration; + } + socket_error(M2MConnectionHandler::SOCKET_SEND_ERROR); + } else { + _security = NULL; + internal_event(STATE_IDLE); + if (error_code == M2MInterface::UnregistrationFailed) { + set_error_description(ERROR_REASON_24); + } else { + set_error_description(ERROR_REASON_8); + } + _observer.error((M2MInterface::Error)error_code); + } +} + +void M2MInterfaceImpl::client_unregistered() +{ + tr_info("M2MInterfaceImpl::client_unregistered()"); + internal_event(STATE_UNREGISTERED); + //TODO: manage register object in a list. + _observer.object_unregistered(_register_server); +} + +void M2MInterfaceImpl::bootstrap_done() +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_info("M2MInterfaceImpl::bootstrap_done"); + _reconnection_time = _initial_reconnection_time; + _reconnecting = false; + _reconnection_state = M2MInterfaceImpl::None; + _bootstrapped = true; + if (_registration_flow_timer) { + _registration_flow_timer->stop_timer(); + } + internal_event(STATE_BOOTSTRAPPED); + _observer.bootstrap_done(_nsdl_interface.get_security_object()); +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::bootstrap_wait() +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_info("M2MInterfaceImpl::bootstrap_wait"); + internal_event(STATE_BOOTSTRAP_WAIT); +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::bootstrap_error_wait(const char *reason) +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_error("M2MInterfaceImpl::bootstrap_error_wait"); + set_error_description(reason); + internal_event(STATE_BOOTSTRAP_ERROR_WAIT); +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::bootstrap_error(const char *reason) +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_error("M2MInterfaceImpl::bootstrap_error(%s)", reason); + _bootstrapped = false; + if (_registration_flow_timer) { + _registration_flow_timer->stop_timer(); + } + + _reconnection_state = M2MInterfaceImpl::None; + + set_error_description(reason); + + _observer.error(M2MInterface::BootstrapFailed); + + internal_event(STATE_IDLE); + _reconnecting = true; + _connection_handler.stop_listening(); + + _retry_timer_expired = false; + _retry_timer.start_timer(_reconnection_time * 1000, + M2MTimerObserver::RetryTimer); + tr_info("M2MInterfaceImpl::bootstrap_error - reconnecting in %" PRIu64 "(s)", _reconnection_time); + _reconnection_time = _reconnection_time * RECONNECT_INCREMENT_FACTOR; + if(_reconnection_time >= MAX_RECONNECT_TIMEOUT) { + _reconnection_time = MAX_RECONNECT_TIMEOUT; + } +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::coap_data_processed() +{ + tr_debug("M2MInterfaceImpl::coap_data_processed()"); + internal_event(STATE_COAP_DATA_PROCESSED); +} + +void M2MInterfaceImpl::value_updated(M2MBase *base) +{ + tr_debug("M2MInterfaceImpl::value_updated"); + if(base) { + M2MBase::BaseType type = base->base_type(); + _observer.value_updated(base, type); + } +} + +void M2MInterfaceImpl::data_available(uint8_t* data, + uint16_t data_size, + const M2MConnectionObserver::SocketAddress &address) +{ + tr_debug("M2MInterfaceImpl::data_available"); + ReceivedData event; + event._data = data; + event._size = data_size; + event._address = &address; + internal_event(STATE_COAP_DATA_RECEIVED, &event); +} + +void M2MInterfaceImpl::socket_error(uint8_t error_code, bool retry) +{ + // Bootstrap completed once PEER CLOSE notify received from the server. + if (_current_state == STATE_BOOTSTRAP_WAIT && + error_code == M2MConnectionHandler::SSL_PEER_CLOSED) { + _security = NULL; + bootstrap_done(); + return; + } + + tr_error("M2MInterfaceImpl::socket_error: (%d), retry (%d), reconnecting (%d), reconnection_state (%d)", + error_code, retry, _reconnecting, (int)_reconnection_state); + + // Ignore errors while client is sleeping + if(queue_mode()) { + if(_callback_handler && _queue_mode_timer_ongoing) { + tr_info("M2MInterfaceImpl::socket_error - Queue Mode - don't try to reconnect while in QueueMode"); + return; + } + } + _queue_sleep_timer.stop_timer(); + + if (_registration_flow_timer) { + _registration_flow_timer->stop_timer(); + } + + _queue_sleep_timer.stop_timer(); + + // Don't change flag state if unregistration has failed. + // This info is needed for continuing unregistration process after client is registered again. + if (_reconnection_state != M2MInterfaceImpl::Unregistration && _reconnection_state != M2MInterfaceImpl::FullRegistration) { + _reconnection_state = M2MInterfaceImpl::WithUpdate; + } + + const char *error_code_des; + M2MInterface::Error error = M2MInterface::ErrorNone; + switch (error_code) { + case M2MConnectionHandler::SSL_CONNECTION_ERROR: + error = M2MInterface::SecureConnectionFailed; + error_code_des = ERROR_SECURE_CONNECTION; + break; + case M2MConnectionHandler::DNS_RESOLVING_ERROR: + error = M2MInterface::DnsResolvingFailed; + error_code_des = ERROR_DNS; + break; + case M2MConnectionHandler::SOCKET_READ_ERROR: + error = M2MInterface::NetworkError; + error_code_des = ERROR_NETWORK; + break; + case M2MConnectionHandler::SOCKET_SEND_ERROR: + error = M2MInterface::NetworkError; + error_code_des = ERROR_NETWORK; + break; + case M2MConnectionHandler::SSL_HANDSHAKE_ERROR: + error = M2MInterface::SecureConnectionFailed; + error_code_des = ERROR_SECURE_CONNECTION; + break; + case M2MConnectionHandler::SOCKET_ABORT: + error = M2MInterface::NetworkError; + error_code_des = ERROR_NETWORK; + break; + default: + error_code_des = ERROR_NO; + break; + } + + internal_event(STATE_IDLE); + // Try to do reconnecting + if (retry) { + _reconnecting = true; + _connection_handler.stop_listening(); + _retry_timer_expired = false; + _retry_timer.start_timer(_reconnection_time * 1000, + M2MTimerObserver::RetryTimer); + tr_info("M2MInterfaceImpl::socket_error - reconnecting in %" PRIu64 "(s)", _reconnection_time); + _reconnection_time = _reconnection_time * RECONNECT_INCREMENT_FACTOR; + if(_reconnection_time >= MAX_RECONNECT_TIMEOUT) { + _reconnection_time = MAX_RECONNECT_TIMEOUT; + } +#ifndef DISABLE_ERROR_DESCRIPTION + snprintf(_error_description, sizeof(_error_description), ERROR_REASON_9, error_code_des); +#endif + } + // Inform application + if (!retry && M2MInterface::ErrorNone != error) { + tr_info("M2MInterfaceImpl::socket_error - send error to application"); + _connection_handler.stop_listening(); + _retry_timer.stop_timer(); + _security = NULL; + _reconnecting = false; + _reconnection_time = _initial_reconnection_time; + _reconnection_state = M2MInterfaceImpl::None; +#ifndef DISABLE_ERROR_DESCRIPTION + snprintf(_error_description, sizeof(_error_description), ERROR_REASON_10, error_code_des); +#endif + } + if(M2MInterface::ErrorNone != error) { + _observer.error(error); + } +} + +void M2MInterfaceImpl::address_ready(const M2MConnectionObserver::SocketAddress &address, + M2MConnectionObserver::ServerType server_type, + const uint16_t server_port) +{ + tr_debug("M2MInterfaceImpl::address_ready"); + ResolvedAddressData data; + data._address = &address; + data._port = server_port; + if( M2MConnectionObserver::Bootstrap == server_type) { + tr_info("M2MInterfaceImpl::address_ready() Server Type Bootstrap"); + internal_event(STATE_BOOTSTRAP_ADDRESS_RESOLVED, &data); + } else { + tr_info("M2MInterfaceImpl::address_ready() Server Type LWM2M"); + internal_event(STATE_REGISTER_ADDRESS_RESOLVED, &data); + } +} + +void M2MInterfaceImpl::data_sent() +{ + tr_debug("M2MInterfaceImpl::data_sent()"); + if(queue_mode()) { + if(_callback_handler && (_nsdl_interface.get_unregister_ongoing() == false)) { + _queue_sleep_timer.stop_timer(); + // Multiply by two to get enough time for coap retransmissions. + _queue_sleep_timer.start_timer(MBED_CLIENT_RECONNECTION_COUNT*MBED_CLIENT_RECONNECTION_INTERVAL*1000*2, + M2MTimerObserver::QueueSleep); + } + } + + if (_current_state == STATE_BOOTSTRAP_ERROR_WAIT) { + // bootstrap_error to be called only after we have sent the last ACK. + // Otherwise client will goto reconnection mode before ACK has sent. + bootstrap_error(_error_description); + } else if (_current_state != STATE_BOOTSTRAP_WAIT) { + internal_event(STATE_COAP_DATA_SENT); + } +} + +void M2MInterfaceImpl::timer_expired(M2MTimerObserver::Type type) +{ + if(M2MTimerObserver::QueueSleep == type) { + tr_debug("M2MInterfaceImpl::timer_expired() - sleep"); + M2MTimer &timer = _nsdl_interface.get_nsdl_execution_timer(); + timer.stop_timer(); + _queue_mode_timer_ongoing = true; + if(_callback_handler) { + _callback_handler(); + } + } + else if (M2MTimerObserver::RetryTimer == type) { + tr_debug("M2MInterfaceImpl::timer_expired() - retry"); + _retry_timer_expired = true; + if (_bootstrapped) { + internal_event(STATE_REGISTER); + } else { + internal_event(STATE_BOOTSTRAP); + } + } + else if (M2MTimerObserver::BootstrapFlowTimer == type) { +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_debug("M2MInterfaceImpl::timer_expired() - bootstrap"); + _bootstrapped = false; + if (_registration_flow_timer) { + _registration_flow_timer->stop_timer(); + } + bootstrap_error(ERROR_REASON_23); +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + } + else if (M2MTimerObserver::RegistrationFlowTimer == type) { + tr_debug("M2MInterfaceImpl::timer_expired() - register"); + registration_error(M2MInterface::Timeout, true); + } +} + +// state machine sits here. +void M2MInterfaceImpl::state_idle(EventData* /*data*/) +{ + tr_debug("M2MInterfaceImpl::state_idle"); + _nsdl_interface.stop_timers(); + _queue_sleep_timer.stop_timer(); +} + +void M2MInterfaceImpl::state_bootstrap(EventData *data) +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_debug("M2MInterfaceImpl::state_bootstrap"); + // Start with bootstrapping preparation + _bootstrapped = false; + M2MSecurityData *event = static_cast<M2MSecurityData *> (data); + if(!_security) { + M2MInterface::Error error = M2MInterface::InvalidParameters; + if (event) { + _security = event->_object; + if(_security) { + int32_t bs_id = _security->get_security_instance_id(M2MSecurity::Bootstrap); + tr_info("M2MInterfaceImpl::state_bootstrap - bs_id = %d", bs_id); + if(bs_id >= 0) { + String server_address = _security->resource_value_string(M2MSecurity::M2MServerUri, bs_id); + _nsdl_interface.set_server_address(server_address.c_str()); + tr_info("M2MInterfaceImpl::state_bootstrap - server_address %s", server_address.c_str()); + String coap; + if(server_address.compare(0,sizeof(COAP)-1,COAP) == 0) { + coap = COAP; + } + else if(server_address.compare(0,sizeof(COAPS)-1,COAPS) == 0) { + _security->resource_value_int(M2MSecurity::SecurityMode, bs_id) != M2MSecurity::NoSecurity ? coap = COAPS: coap = ""; + } + if(!coap.empty()) { + server_address = server_address.substr(coap.size(), + server_address.size()-coap.size()); + + process_address(server_address, _server_ip_address, _server_port); + + tr_info("M2MInterfaceImpl::state_bootstrap - IP address %s, Port %d", _server_ip_address.c_str(), _server_port); + // If bind and resolving server address succeed then proceed else + // return error to the application and go to Idle state. + if(!_server_ip_address.empty()) { + error = M2MInterface::ErrorNone; + if (_registration_flow_timer) { + _registration_flow_timer->stop_timer(); + _registration_flow_timer->start_timer(MBED_CLIENT_RECONNECTION_COUNT * MBED_CLIENT_RECONNECTION_INTERVAL * 8 * 1000, + M2MTimerObserver::BootstrapFlowTimer); + } + _connection_handler.resolve_server_address(_server_ip_address, + _server_port, + M2MConnectionObserver::Bootstrap, + _security); + } + } + } + } + } + if (error != M2MInterface::ErrorNone) { + tr_error("M2MInterfaceImpl::state_bootstrap - set error as M2MInterface::InvalidParameters"); + internal_event(STATE_IDLE); + set_error_description(ERROR_REASON_11); + _observer.error(error); + } + } else { + _listen_port = 0; + _connection_handler.bind_connection(_listen_port); + if (_registration_flow_timer) { + _registration_flow_timer->stop_timer(); + _registration_flow_timer->start_timer(MBED_CLIENT_RECONNECTION_COUNT * MBED_CLIENT_RECONNECTION_INTERVAL * 8 * 1000, + M2MTimerObserver::BootstrapFlowTimer); + } + tr_info("M2MInterfaceImpl::state_bootstrap (reconnect) - IP address %s, Port %d", _server_ip_address.c_str(), _server_port); + _connection_handler.resolve_server_address(_server_ip_address, + _server_port, + M2MConnectionObserver::Bootstrap, + _security); + } +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::state_bootstrap_address_resolved( EventData *data) +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_debug("M2MInterfaceImpl::state_bootstrap_address_resolved"); + if (data) { + ResolvedAddressData *event = static_cast<ResolvedAddressData *> (data); + sn_nsdl_addr_s address; + + M2MInterface::NetworkStack stack = event->_address->_stack; + + if(M2MInterface::LwIP_IPv4 == stack) { + tr_info("M2MInterfaceImpl::state_bootstrap_address_resolved : IPv4 address"); + address.type = SN_NSDL_ADDRESS_TYPE_IPV4; + } else if((M2MInterface::LwIP_IPv6 == stack) || + (M2MInterface::Nanostack_IPv6 == stack)) { + tr_info("M2MInterfaceImpl::state_bootstrap_address_resolved : IPv6 address"); + address.type = SN_NSDL_ADDRESS_TYPE_IPV6; + } + address.port = event->_port; + address.addr_ptr = (uint8_t*)event->_address->_address; + address.addr_len = event->_address->_length; + _connection_handler.start_listening_for_data(); + + if(_nsdl_interface.create_bootstrap_resource(&address)) { + internal_event(STATE_BOOTSTRAP_RESOURCE_CREATED); + } else{ + // If resource creation fails then inform error to application + tr_error("M2MInterfaceImpl::state_bootstrap_address_resolved : M2MInterface::InvalidParameters"); + internal_event(STATE_IDLE); + set_error_description(ERROR_REASON_12); + _observer.error(M2MInterface::InvalidParameters); + } + } +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::state_bootstrap_resource_created( EventData */*data*/) +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_debug("M2MInterfaceImpl::state_bootstrap_resource_created"); +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::state_bootstrapped( EventData */*data*/) +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_debug("M2MInterfaceImpl::state_bootstrapped"); +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MInterfaceImpl::state_register(EventData *data) +{ + tr_debug("M2MInterfaceImpl::state_register"); + M2MRegisterData *event = static_cast<M2MRegisterData *> (data); + if (!_security) { + M2MInterface::Error error = M2MInterface::InvalidParameters; + // Start with registration preparation + if(event) { + _security = event->_object; + if(_security) { + int32_t m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer); + if(m2m_id >= 0) { + if(_nsdl_interface.create_nsdl_list_structure(event->_object_list)) { + // If the nsdl resource structure is created successfully + String server_address = _security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id); + _nsdl_interface.set_server_address(server_address.c_str()); + tr_info("M2MInterfaceImpl::state_register - server_address %s", server_address.c_str()); + String coap; + if(server_address.compare(0,sizeof(COAP)-1,COAP) == 0) { + coap = COAP; + } + else if(server_address.compare(0,sizeof(COAPS)-1,COAPS) == 0) { + _security->resource_value_int(M2MSecurity::SecurityMode, m2m_id) != M2MSecurity::NoSecurity ? coap = COAPS: coap = ""; + } + if(!coap.empty()) { + server_address = server_address.substr(coap.size(), + server_address.size() - coap.size()); + process_address(server_address, _server_ip_address, _server_port); + + tr_info("M2MInterfaceImpl::state_register - IP address %s, Port %d", _server_ip_address.c_str(), _server_port); + if(!_server_ip_address.empty()) { + // Connection related errors are coming through callback + if (_registration_flow_timer) { + _registration_flow_timer->stop_timer(); + _registration_flow_timer->start_timer(MBED_CLIENT_RECONNECTION_COUNT * MBED_CLIENT_RECONNECTION_INTERVAL * 8 * 1000, + M2MTimerObserver::RegistrationFlowTimer); + } + _reconnection_state = M2MInterfaceImpl::FullRegistration; + error = M2MInterface::ErrorNone; + _connection_handler.resolve_server_address(_server_ip_address,_server_port, + M2MConnectionObserver::LWM2MServer, + _security); + } + } + } else { + tr_error("M2MInterfaceImpl::state_register - fail to create nsdl list structure!"); + } + } + } + } + if (error != M2MInterface::ErrorNone) { + tr_error("M2MInterfaceImpl::state_register - set error as M2MInterface::InvalidParameters"); + internal_event(STATE_IDLE); + set_error_description(ERROR_REASON_13); + _observer.error(error); + } + } else { + _listen_port = 0; + if (event) { + _nsdl_interface.create_nsdl_list_structure(event->_object_list); + } + _connection_handler.bind_connection(_listen_port); + if (_registration_flow_timer) { + _registration_flow_timer->stop_timer(); + _registration_flow_timer->start_timer(MBED_CLIENT_RECONNECTION_COUNT * MBED_CLIENT_RECONNECTION_INTERVAL * 8 * 1000, + M2MTimerObserver::RegistrationFlowTimer); + } + _reconnection_state = M2MInterfaceImpl::FullRegistration; + tr_info("M2MInterfaceImpl::state_register (reconnect) - IP address %s, Port %d", _server_ip_address.c_str(), _server_port); + _connection_handler.resolve_server_address(_server_ip_address,_server_port, + M2MConnectionObserver::LWM2MServer, + _security); + } +} + +void M2MInterfaceImpl::process_address(const String& server_address, String& ip_address, uint16_t& port) { + + int colonFound = server_address.find_last_of(':'); //10 + if(colonFound != -1) { + ip_address = server_address.substr(0,colonFound); + port = atoi(server_address.substr(colonFound+1, + server_address.size()-ip_address.size()).c_str()); + colonFound = ip_address.find_last_of(']'); + if(ip_address.compare(0,1,"[") == 0) { + if(colonFound == -1) { + ip_address.clear(); + } else { + ip_address = ip_address.substr(1,colonFound-1); + } + } else if(colonFound != -1) { + ip_address.clear(); + } + } +} + +void M2MInterfaceImpl::state_register_address_resolved( EventData *data) +{ + tr_debug("M2MInterfaceImpl::state_register_address_resolved"); + if(data) { + ResolvedAddressData *event = static_cast<ResolvedAddressData *> (data); + + sn_nsdl_addr_type_e address_type = SN_NSDL_ADDRESS_TYPE_IPV6; + + M2MInterface::NetworkStack stack = event->_address->_stack; + + if(M2MInterface::LwIP_IPv4 == stack) { + tr_info("M2MInterfaceImpl::state_register_address_resolved : IPv4 address"); + address_type = SN_NSDL_ADDRESS_TYPE_IPV4; + } else if((M2MInterface::LwIP_IPv6 == stack) || + (M2MInterface::Nanostack_IPv6 == stack)) { + tr_info("M2MInterfaceImpl::state_register_address_resolved : IPv6 address"); + address_type = SN_NSDL_ADDRESS_TYPE_IPV6; + } + _connection_handler.start_listening_for_data(); + _nsdl_interface.set_server_address((uint8_t*)event->_address->_address,event->_address->_length, + event->_port, address_type); + switch (_reconnection_state) { + case M2MInterfaceImpl::None: + case M2MInterfaceImpl::FullRegistration: + if(!_nsdl_interface.send_register_message()) { + // If resource creation fails then inform error to application + tr_error("M2MInterfaceImpl::state_register_address_resolved : M2MInterface::MemoryFail"); + internal_event(STATE_IDLE); + set_error_description(ERROR_REASON_25); + _observer.error(M2MInterface::MemoryFail); + } + break; + case M2MInterfaceImpl::Unregistration: + case M2MInterfaceImpl::WithUpdate: + // Start registration update in case it is reconnection logic because of network issue. + internal_event(STATE_UPDATE_REGISTRATION); + break; + } + } +} + +void M2MInterfaceImpl::state_registered( EventData */*data*/) +{ + tr_info("M2MInterfaceImpl::state_registered"); + if (_registration_flow_timer) { + _registration_flow_timer->stop_timer(); + } + _reconnection_time = _initial_reconnection_time; + _reconnecting = false; + + // Continue with the unregistration process if it has failed due to connection lost + if (_reconnection_state == M2MInterfaceImpl::Unregistration) { + internal_event(STATE_UNREGISTER); + } + + _reconnection_state = M2MInterfaceImpl::None; +} + +void M2MInterfaceImpl::state_update_registration(EventData *data) +{ + tr_debug("M2MInterfaceImpl::state_update_registration"); + uint32_t lifetime = 0; + bool clear_queue = false; + // Set to false to allow reconnection to work. + _queue_mode_timer_ongoing = false; + + if(data) { + M2MUpdateRegisterData *event = static_cast<M2MUpdateRegisterData *> (data); + // Create new resources if any + if (!event->_object_list.empty()) { + _nsdl_interface.create_nsdl_list_structure(event->_object_list); + } + lifetime = event->_lifetime; + } else { + clear_queue = true; + } + + bool success = _nsdl_interface.send_update_registration(lifetime, clear_queue); + if(!success) { + if(_reconnection_state == M2MInterfaceImpl::WithUpdate) { + if (_reconnection_state != M2MInterfaceImpl::Unregistration) { + _reconnection_state = M2MInterfaceImpl::FullRegistration; + if(!_nsdl_interface.send_register_message()) { + tr_error("M2MInterfaceImpl::state_update_registration : M2MInterface::MemoryFail"); + internal_event(STATE_IDLE); + set_error_description(ERROR_REASON_25); + _observer.error(M2MInterface::MemoryFail); + } + } + } + } +} + +void M2MInterfaceImpl::state_unregister(EventData */*data*/) +{ + tr_debug("M2MInterfaceImpl::state_unregister"); + internal_event(STATE_SENDING_COAP_DATA); + if(!_nsdl_interface.send_unregister_message()) { + tr_error("M2MInterfaceImpl::state_unregister : M2MInterface::NotRegistered"); + internal_event(STATE_IDLE); + set_error_description(ERROR_REASON_16); + _observer.error(M2MInterface::NotRegistered); + } +} + +void M2MInterfaceImpl::state_unregistered( EventData */*data*/) +{ + tr_info("M2MInterfaceImpl::state_unregistered"); + _reconnection_time = _initial_reconnection_time; + _connection_handler.stop_listening(); + internal_event(STATE_IDLE); +} + +void M2MInterfaceImpl::state_sending_coap_data( EventData */*data*/) +{ + tr_debug("M2MInterfaceImpl::state_sending_coap_data"); + _nsdl_interface.start_nsdl_execution_timer(); + internal_event(STATE_WAITING); +} + +void M2MInterfaceImpl::state_coap_data_sent( EventData */*data*/) +{ + tr_debug("M2MInterfaceImpl::state_coap_data_sent"); + internal_event(STATE_WAITING); +} + +void M2MInterfaceImpl::state_coap_data_received( EventData *data) +{ + tr_debug("M2MInterfaceImpl::state_coap_data_received"); + if(data) { + ReceivedData *event = static_cast<ReceivedData*> (data); + sn_nsdl_addr_s address; + + M2MInterface::NetworkStack stack = event->_address->_stack; + + if(M2MInterface::LwIP_IPv4 == stack) { + address.type = SN_NSDL_ADDRESS_TYPE_IPV4; + address.addr_len = 4; + } else if((M2MInterface::LwIP_IPv6 == stack) || + (M2MInterface::Nanostack_IPv6 == stack)) { + address.type = SN_NSDL_ADDRESS_TYPE_IPV6; + address.addr_len = 16; + } + address.port = event->_address->_port; + address.addr_ptr = (uint8_t*)event->_address->_address; + address.addr_len = event->_address->_length; + + // Process received data + internal_event(STATE_PROCESSING_COAP_DATA); + if(!_nsdl_interface.process_received_data(event->_data, + event->_size, + &address)) { + tr_error("M2MInterfaceImpl::state_coap_data_received : M2MInterface::ResponseParseFailed"); + set_error_description(ERROR_REASON_17); + _observer.error(M2MInterface::ResponseParseFailed); + } + } +} + +void M2MInterfaceImpl::state_processing_coap_data( EventData */*data*/) +{ + tr_debug("M2MInterfaceImpl::state_processing_coap_data"); + internal_event(STATE_WAITING); +} + +void M2MInterfaceImpl::state_coap_data_processed( EventData */*data*/) +{ + tr_debug("M2MInterfaceImpl::state_coap_data_processed"); + internal_event(STATE_WAITING); +} + +void M2MInterfaceImpl::state_waiting( EventData */*data*/) +{ + tr_debug("M2MInterfaceImpl::state_waiting"); +} + +// generates an external event. called once per external event +// to start the state machine executing +void M2MInterfaceImpl::external_event(uint8_t new_state, + EventData* p_data) +{ + tr_debug("M2MInterfaceImpl::external_event : new state %d", new_state); + // if we are supposed to ignore this event + if (new_state == EVENT_IGNORED) { + tr_debug("M2MInterfaceImpl::external_event : new state is EVENT_IGNORED"); + _event_ignored = true; + } + else { + tr_debug("M2MInterfaceImpl::external_event : handle new state"); + // generate the event and execute the state engine + internal_event(new_state, p_data); + } +} + +// generates an internal event. called from within a state +// function to transition to a new state +void M2MInterfaceImpl::internal_event(uint8_t new_state, + EventData* p_data) +{ + tr_debug("M2MInterfaceImpl::internal_event : new state %d", new_state); + _event_data = p_data; + _event_generated = true; + _current_state = new_state; + state_engine(); +} + +// the state engine executes the state machine states +void M2MInterfaceImpl::state_engine (void) +{ + tr_debug("M2MInterfaceImpl::state_engine"); + EventData* p_data_temp = NULL; + + // while events are being generated keep executing states + while (_event_generated) { + p_data_temp = _event_data; // copy of event data pointer + _event_data = NULL; // event data used up, reset ptr + _event_generated = false; // event used up, reset flag + + assert(_current_state < _max_states); + + state_function( _current_state, p_data_temp ); + } +} + +void M2MInterfaceImpl::state_function( uint8_t current_state, EventData* data ) +{ + switch( current_state ) { + case STATE_IDLE: + M2MInterfaceImpl::state_idle(data); + break; + case STATE_BOOTSTRAP: + #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + M2MInterfaceImpl::state_bootstrap(data); + #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + break; + case STATE_BOOTSTRAP_ADDRESS_RESOLVED: + #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + M2MInterfaceImpl::state_bootstrap_address_resolved(data); + #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + break; + case STATE_BOOTSTRAP_RESOURCE_CREATED: + #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + M2MInterfaceImpl::state_bootstrap_resource_created(data); + #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + break; + case STATE_BOOTSTRAP_WAIT: + case STATE_BOOTSTRAP_ERROR_WAIT: + #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + // Do nothing, we're just waiting for data_sent callback + #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + break; + case STATE_BOOTSTRAPPED: + #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + M2MInterfaceImpl::state_bootstrapped(data); + #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + break; + case STATE_REGISTER: + M2MInterfaceImpl::state_register(data); + break; + case STATE_REGISTER_ADDRESS_RESOLVED: + M2MInterfaceImpl::state_register_address_resolved(data); + break; + case STATE_REGISTERED: + M2MInterfaceImpl::state_registered(data); + break; + case STATE_UPDATE_REGISTRATION: + M2MInterfaceImpl::state_update_registration(data); + break; + case STATE_UNREGISTER: + M2MInterfaceImpl::state_unregister(data); + break; + case STATE_UNREGISTERED: + M2MInterfaceImpl::state_unregistered(data); + break; + case STATE_SENDING_COAP_DATA: + M2MInterfaceImpl::state_sending_coap_data(data); + break; + case STATE_COAP_DATA_SENT: + M2MInterfaceImpl::state_coap_data_sent(data); + break; + case STATE_COAP_DATA_RECEIVED: + M2MInterfaceImpl::state_coap_data_received(data); + break; + case STATE_PROCESSING_COAP_DATA: + M2MInterfaceImpl::state_processing_coap_data(data); + break; + case STATE_COAP_DATA_PROCESSED: + M2MInterfaceImpl::state_coap_data_processed(data); + break; + case STATE_WAITING: + M2MInterfaceImpl::state_waiting(data); + break; + } +} + +void M2MInterfaceImpl::start_register_update(M2MUpdateRegisterData *data) { + tr_debug("M2MInterfaceImpl::start_register_update()"); + if(!data || (data->_lifetime != 0 && (data->_lifetime < MINIMUM_REGISTRATION_TIME))) { + set_error_description(ERROR_REASON_18); + _observer.error(M2MInterface::InvalidParameters); + } + + if (_reconnecting) { + //If client is in reconnection mode, ignore this call, state machine will reconnect on its own. + return; + } + + _reconnection_state = M2MInterfaceImpl::WithUpdate; + BEGIN_TRANSITION_MAP // - Current State - + TRANSITION_MAP_ENTRY (STATE_REGISTER) // state_idle + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state__bootstrap_address_resolved + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_resource_created + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_wait + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_error_wait + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrapped + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register_address_resolved + TRANSITION_MAP_ENTRY (STATE_UPDATE_REGISTRATION) // state_registered + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_update_registration + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregister + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregistered + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_sending_coap_data + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_sent + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_received + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_processing_coap_data + TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_processed + TRANSITION_MAP_ENTRY (STATE_UPDATE_REGISTRATION) // state_waiting + END_TRANSITION_MAP(data) + if(_event_ignored) { + _event_ignored = false; + if (!_reconnecting) { + set_error_description(ERROR_REASON_19); + _observer.error(M2MInterface::NotAllowed); + } + } +} + +void M2MInterfaceImpl::update_endpoint(String &name) { + _nsdl_interface.update_endpoint(name); +} + +void M2MInterfaceImpl::update_domain(String &domain) +{ + _nsdl_interface.update_domain(domain); +} + +const String M2MInterfaceImpl::internal_endpoint_name() const +{ + return _nsdl_interface.internal_endpoint_name(); +} + +const char *M2MInterfaceImpl::error_description() const +{ +#ifndef DISABLE_ERROR_DESCRIPTION + return _error_description; +#else + return ""; +#endif +} + +void M2MInterfaceImpl::set_error_description(const char *description) +{ +#ifndef DISABLE_ERROR_DESCRIPTION + if (strncmp(_error_description, description, sizeof(_error_description)) != 0) { + strncpy(_error_description, description, MAX_ALLOWED_ERROR_STRING_LENGTH - 1); + } +#endif +} + +bool M2MInterfaceImpl::queue_mode() const +{ + return (_binding_mode == M2MInterface::UDP_QUEUE || + _binding_mode == M2MInterface::TCP_QUEUE || + _binding_mode == M2MInterface::SMS_QUEUE || + _binding_mode == M2MInterface::UDP_SMS_QUEUE); +} + +void M2MInterfaceImpl::get_data_request(const char *uri, + const size_t offset, + const bool async, + get_data_cb data_cb, + get_data_error_cb error_cb, + void *context) +{ + get_data_req_error_e error = FAILED_TO_SEND_MSG; + if(_current_state != STATE_IDLE && uri) { + if (!_nsdl_interface.send_get_data_request(uri, offset, async, data_cb, error_cb, context)) { + error_cb(error, context); + } + } + else { + error_cb(error, context); + } +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mnsdlinterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mnsdlinterface.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2298 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Needed for PRIu64 on FreeRTOS +#include <stdio.h> +// Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include <assert.h> +#include <inttypes.h> +#include <stdlib.h> +#include "include/nsdlaccesshelper.h" +#include "include/m2mnsdlobserver.h" +#include "include/m2mtlvdeserializer.h" +#include "include/m2mtlvserializer.h" +#include "include/m2mnsdlinterface.h" +#include "include/uriqueryparser.h" +#include "include/m2mreporthandler.h" +#include "mbed-client/m2mstring.h" +#include "mbed-client/m2msecurity.h" +#include "mbed-client/m2mserver.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mblockmessage.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-trace/mbed_trace.h" +#include "sn_grs.h" +#include "mbed-client/m2minterfacefactory.h" +#include "mbed-client/m2mdevice.h" +#include "randLIB.h" +#include "common_functions.h" +#include "sn_nsdl_lib.h" + +#define BUFFER_SIZE 21 +#define TRACE_GROUP "mClt" +#define MAX_QUERY_COUNT 10 + +const char *MCC_VERSION = "mccv=1.2.6"; + +M2MNsdlInterface::M2MNsdlInterface(M2MNsdlObserver &observer, M2MConnectionHandler &connection_handler) +: _observer(observer), + _endpoint(NULL), + _nsdl_handle(NULL), + _security(NULL), + _server(NULL), + _nsdl_exceution_timer(*this), + _registration_timer(*this), + _connection_handler(connection_handler), + _counter_for_nsdl(0), + _bootstrap_id(0), + _server_address(NULL), + _unregister_ongoing(false), + _identity_accepted(false), + _nsdl_exceution_timer_running(false), + _binding_mode(M2MInterface::NOT_SET) +{ + tr_debug("M2MNsdlInterface::M2MNsdlInterface()"); + _sn_nsdl_address.addr_len = 0; + _sn_nsdl_address.addr_ptr = NULL; + _sn_nsdl_address.port = 0; + _sn_nsdl_address.type = SN_NSDL_ADDRESS_TYPE_NONE; + _server = new M2MServer(); + // This initializes libCoap and libNsdl + // Parameters are function pointers to used memory allocation + // and free functions in structure and used functions for sending + // and receiving purposes. + _nsdl_handle = sn_nsdl_init(&(__nsdl_c_send_to_server), &(__nsdl_c_received_from_server), + &(__nsdl_c_memory_alloc), &(__nsdl_c_memory_free), &(__nsdl_c_auto_obs_token)); + sn_nsdl_set_context(_nsdl_handle, this); + + // Randomize the initial auto obs token. Range is in 1 - 1023 + _auto_obs_token = randLIB_get_random_in_range(AUTO_OBS_TOKEN_MIN, AUTO_OBS_TOKEN_MAX); + + initialize(); +} + +M2MNsdlInterface::~M2MNsdlInterface() +{ + tr_debug("M2MNsdlInterface::~M2MNsdlInterface() - IN"); + if(_endpoint) { + memory_free(_endpoint->endpoint_name_ptr); + memory_free(_endpoint->domain_name_ptr); + memory_free(_endpoint->type_ptr); + memory_free(_endpoint->lifetime_ptr); + memory_free(_endpoint); + } + _object_list.clear(); + _security = NULL; + delete _server; + sn_nsdl_destroy(_nsdl_handle); + _nsdl_handle = NULL; + free(_server_address); + free_get_request_list(); + tr_debug("M2MNsdlInterface::~M2MNsdlInterface() - OUT"); +} + +bool M2MNsdlInterface::initialize() +{ + tr_debug("M2MNsdlInterface::initialize()"); + bool success = false; + + // Sets the packet retransmission attempts and time interval + sn_nsdl_set_retransmission_parameters(_nsdl_handle, + MBED_CLIENT_RECONNECTION_COUNT, + MBED_CLIENT_RECONNECTION_INTERVAL); + + sn_nsdl_handle_block2_response_internally(_nsdl_handle, false); + + // Allocate the memory for endpoint + _endpoint = (sn_nsdl_ep_parameters_s*)memory_alloc(sizeof(sn_nsdl_ep_parameters_s)); + if(_endpoint) { + memset(_endpoint, 0, sizeof(sn_nsdl_ep_parameters_s)); + success = true; + } + + M2MResource* update_trigger = _server->get_resource(M2MServer::RegistrationUpdate); + if (update_trigger) { + update_trigger->set_execute_function(execute_callback(this, + &M2MNsdlInterface::update_trigger_callback)); + } + + add_object_to_list(_server); + create_nsdl_object_structure(_server); + ns_list_init(&_get_request_list); + + return success; +} + +void M2MNsdlInterface::create_endpoint(const String &name, + const String &type, + const int32_t life_time, + const String &domain, + const uint8_t mode, + const String &/*context_address*/) +{ + tr_info("M2MNsdlInterface::create_endpoint( name %s type %s lifetime %" PRId32 ", domain %s, mode %d)", + name.c_str(), type.c_str(), life_time, domain.c_str(), mode); + _endpoint_name = name; + _binding_mode = mode; + if(_endpoint){ + memset(_endpoint, 0, sizeof(sn_nsdl_ep_parameters_s)); + if(!_endpoint_name.empty()) { + memory_free(_endpoint->endpoint_name_ptr); + _endpoint->endpoint_name_ptr = alloc_string_copy((uint8_t*)_endpoint_name.c_str(), _endpoint_name.length()); + _endpoint->endpoint_name_len = _endpoint_name.length(); + } + if(!type.empty()) { + _endpoint->type_ptr = alloc_string_copy((uint8_t*)type.c_str(), type.length()); + _endpoint->type_len = type.length(); + } + if(!domain.empty()) { + _endpoint->domain_name_ptr = alloc_string_copy((uint8_t*)domain.c_str(), domain.length()); + _endpoint->domain_name_len = domain.length(); + } + + // nsdl binding mode is only 3 least significant bits + _endpoint->binding_and_mode = (sn_nsdl_oma_binding_and_mode_t)((uint8_t)mode & 0x07); + + // If lifetime is less than zero then leave the field empty + if( life_time > 0) { + set_endpoint_lifetime_buffer(life_time); + } + } +} + +void M2MNsdlInterface::update_endpoint(const String &name) +{ + _endpoint_name = name; + if(_endpoint){ + if(!_endpoint_name.empty()) { + memory_free(_endpoint->endpoint_name_ptr); + _endpoint->endpoint_name_ptr = alloc_string_copy((uint8_t*)_endpoint_name.c_str(), _endpoint_name.length()); + _endpoint->endpoint_name_len = _endpoint_name.length(); + } + } +} + +void M2MNsdlInterface::update_domain(const String &domain) +{ + if(_endpoint){ + memory_free(_endpoint->domain_name_ptr); + _endpoint->domain_name_len = 0; + if(!domain.empty()) { + _endpoint->domain_name_ptr = alloc_string_copy((uint8_t*)domain.c_str(), domain.length()); + _endpoint->domain_name_len = domain.length(); + } + } +} + +void M2MNsdlInterface::set_endpoint_lifetime_buffer(int lifetime) +{ + tr_debug("M2MNsdlInterface::set_endpoint_lifetime_buffer - %d", lifetime); + if (lifetime < 60) { + return; + } + + _server->set_resource_value(M2MServer::Lifetime, lifetime); + + if (_endpoint && _endpoint->lifetime_ptr) { + memory_free(_endpoint->lifetime_ptr); + _endpoint->lifetime_ptr = NULL; + _endpoint->lifetime_len = 0; + } + + char buffer[20+1]; + uint32_t size = m2m::itoa_c(lifetime, buffer); + if (_endpoint && size <= sizeof(buffer)) { + _endpoint->lifetime_len = 0; + _endpoint->lifetime_ptr = alloc_string_copy((uint8_t*)buffer, size); + if (_endpoint->lifetime_ptr) { + _endpoint->lifetime_len = size; + } + } +} + + +void M2MNsdlInterface::delete_endpoint() +{ + tr_debug("M2MNsdlInterface::delete_endpoint()"); + if(_endpoint) { + free(_endpoint->lifetime_ptr); + memory_free(_endpoint); + _endpoint = NULL; + } +} + +bool M2MNsdlInterface::create_nsdl_list_structure(const M2MObjectList &object_list) +{ + tr_debug("M2MNsdlInterface::create_nsdl_list_structure()"); + bool success = false; + if(!object_list.empty()) { + M2MObjectList::const_iterator it; + it = object_list.begin(); + for ( ; it != object_list.end(); it++ ) { + // Create NSDL structure for all Objects inside + success = create_nsdl_object_structure(*it); + add_object_to_list(*it); + } + } + if (!success) { + tr_error("M2MNsdlInterface::create_nsdl_list_structure - fail!"); + } + return success; +} + +bool M2MNsdlInterface::remove_nsdl_resource(M2MBase *base) +{ + sn_nsdl_dynamic_resource_parameters_s* resource = base->get_nsdl_resource(); + return sn_nsdl_pop_resource(_nsdl_handle, resource); +} + +bool M2MNsdlInterface::create_bootstrap_resource(sn_nsdl_addr_s *address) +{ +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_debug("M2MNsdlInterface::create_bootstrap_resource()"); + _identity_accepted = false; + bool success = false; + sn_nsdl_bs_ep_info_t bootstrap_endpoint; + tr_debug("M2MNsdlInterface::create_bootstrap_resource() - endpoint name: %.*s", _endpoint->endpoint_name_len, + _endpoint->endpoint_name_ptr); + + if(_bootstrap_id == 0) { + // Take copy of the address, uri_query_parameters() will modify the source buffer + bool msg_sent = false; + if (_server_address) { + char *address_copy = M2MBase::alloc_string_copy(_server_address); + if (address_copy) { + char* query = query_string(_server_address); + if (query != NULL) { + int param_count = query_param_count(query); + if (param_count) { + char* uri_query_params[MAX_QUERY_COUNT] = {}; + if (uri_query_parameters(query, uri_query_params,0)) { + + + uri_query_parameters((char*)MCC_VERSION, uri_query_params, param_count); + param_count += query_param_count((char*)MCC_VERSION); + + + msg_sent = true; + sn_nsdl_clear_coap_resending_queue(_nsdl_handle); + _bootstrap_id = sn_nsdl_oma_bootstrap(_nsdl_handle, + address, + _endpoint, + &bootstrap_endpoint, + uri_query_params, + param_count); + } + free(_server_address); + _server_address = M2MBase::alloc_string_copy(address_copy); + } + } + free(address_copy); + } + } + if (!msg_sent) { + sn_nsdl_clear_coap_resending_queue(_nsdl_handle); + _bootstrap_id = sn_nsdl_oma_bootstrap(_nsdl_handle, + address, + _endpoint, + &bootstrap_endpoint, + NULL, + 0); + } + + success = _bootstrap_id != 0; + tr_debug("M2MNsdlInterface::create_bootstrap_resource - _bootstrap_id %d", _bootstrap_id); + } + return success; +#else + (void)address; + (void)bootstrap_endpoint_name; + return false; +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE +} + +void M2MNsdlInterface::set_server_address(uint8_t* address, + uint8_t address_length, + const uint16_t port, + sn_nsdl_addr_type_e address_type) +{ + tr_debug("M2MNsdlInterface::set_server_address()"); + set_NSP_address(_nsdl_handle, address, address_length, port, address_type); +} + +bool M2MNsdlInterface::send_register_message() +{ + tr_info("M2MNsdlInterface::send_register_message()"); + handle_pending_notifications(true); + + bool success = false; + if (_server_address) { + success = parse_and_send_uri_query_parameters(); + } + // If URI parsing fails or there is no parameters, try again without parameters + if (!success) { + sn_nsdl_clear_coap_resending_queue(_nsdl_handle); + success = sn_nsdl_register_endpoint(_nsdl_handle,_endpoint, NULL, 0) != 0; + } + return success; +} + +bool M2MNsdlInterface::send_get_data_request(const char *uri, + const size_t offset, + const bool async, + get_data_cb data_cb, + get_data_error_cb error_cb, + void *context) +{ + int32_t message_id = 0; + uint32_t token = 0; + get_data_request_s *data_request = (get_data_request_s*)memory_alloc(sizeof(get_data_request_s)); + if (data_request == NULL) { + return false; + } + data_request->context = context; + data_request->async_req = async; + data_request->received_size = offset; + data_request->uri_path = (char*)alloc_string_copy((uint8_t*)uri, strlen(uri)); + if (data_request->uri_path == NULL) { + memory_free(data_request); + return false; + } + + data_request->on_get_data_cb = data_cb; + data_request->on_get_data_error_cb = error_cb; + + randLIB_get_n_bytes_random(&token, sizeof(token)); + + if (!token) { + token++; + } + + data_request->msg_token = token; + + message_id = sn_nsdl_send_get_data_request(_nsdl_handle, uri, token, offset); + if (message_id == 0) { + memory_free(data_request->uri_path); + memory_free(data_request); + return false; + } + + ns_list_add_to_end(&_get_request_list, data_request); + + return true; +} + +bool M2MNsdlInterface::send_update_registration(const uint32_t lifetime, bool clear_queue) +{ + tr_info("M2MNsdlInterface::send_update_registration( lifetime %" PRIu32 ")", lifetime); + bool success = false; + int32_t ret = 0; + create_nsdl_list_structure(_object_list); + + _registration_timer.stop_timer(); + bool lifetime_changed = true; + + // Check if resource(1/0/1) value has been updated and update it into _endpoint struct + if (lifetime == 0) { + lifetime_changed = lifetime_value_changed(); + if (lifetime_changed) { + set_endpoint_lifetime_buffer(_server->resource_value_int(M2MServer::Lifetime)); + } + } else { + set_endpoint_lifetime_buffer(lifetime); + } + + if(_nsdl_handle) { + if(clear_queue) { + sn_nsdl_clear_coap_resending_queue(_nsdl_handle); + } + if (!lifetime_changed) { + tr_debug("M2MNsdlInterface::send_update_registration - regular update"); + ret = sn_nsdl_update_registration(_nsdl_handle, NULL, 0); + } else { + if (_endpoint && _endpoint->lifetime_ptr) { + tr_debug("M2MNsdlInterface::send_update_registration - new lifetime value"); + ret = sn_nsdl_update_registration(_nsdl_handle, + _endpoint->lifetime_ptr, + _endpoint->lifetime_len); + } + } + if (ret == -4) { + tr_warn("Failed to send registration update. Clearing queue and retrying."); + sn_nsdl_clear_coap_resending_queue(_nsdl_handle); + if (!lifetime_changed) { + tr_debug("M2MNsdlInterface::send_update_registration - regular update - retry"); + ret = sn_nsdl_update_registration(_nsdl_handle, NULL, 0); + } else { + tr_debug("M2MNsdlInterface::send_update_registration - new lifetime value - retry"); + ret = sn_nsdl_update_registration(_nsdl_handle, + _endpoint->lifetime_ptr, + _endpoint->lifetime_len); + } + } + } + if (ret >= 0) { + success = true; + } + + _registration_timer.start_timer(registration_time() * 1000, + M2MTimerObserver::Registration, + false); + + return success; +} + +bool M2MNsdlInterface::send_unregister_message() +{ + tr_info("M2MNsdlInterface::send_unregister_message"); + if (_unregister_ongoing) { + tr_debug("M2MNsdlInterface::send_unregister_message - unregistration already in progress"); + return true; + } + + bool success = false; + int32_t ret = 0; + + _unregister_ongoing = true; + ret = sn_nsdl_unregister_endpoint(_nsdl_handle); + if (ret == -4) { + tr_warn("Failed to send registration update. Clearing queue and retrying."); + sn_nsdl_clear_coap_resending_queue(_nsdl_handle); + ret = sn_nsdl_unregister_endpoint(_nsdl_handle); + } + if (ret >= 0) { + success = true; + } + return success; +} + +// XXX: move these to common place, no need to copy these wrappers to multiple places: +void *M2MNsdlInterface::memory_alloc(uint32_t size) +{ + if(size) + return malloc(size); + else + return 0; +} + +void M2MNsdlInterface::memory_free(void *ptr) +{ + if(ptr) + free(ptr); +} + +uint8_t* M2MNsdlInterface::alloc_string_copy(const uint8_t* source, uint16_t size) +{ + assert(source != NULL); + + uint8_t* result = (uint8_t*)memory_alloc(size + 1); + if (result) { + memcpy(result, source, size); + result[size] = '\0'; + } + return result; +} + +uint8_t M2MNsdlInterface::send_to_server_callback(struct nsdl_s * /*nsdl_handle*/, + sn_nsdl_capab_e /*protocol*/, + uint8_t *data_ptr, + uint16_t data_len, + sn_nsdl_addr_s *address) +{ + tr_debug("M2MNsdlInterface::send_to_server_callback(data size %d)", data_len); + _observer.coap_message_ready(data_ptr,data_len,address); + return 1; +} + +uint8_t M2MNsdlInterface::received_from_server_callback(struct nsdl_s *nsdl_handle, + sn_coap_hdr_s *coap_header, + sn_nsdl_addr_s *address) +{ + tr_debug("M2MNsdlInterface::received_from_server_callback"); + _observer.coap_data_processed(); + uint8_t value = 0; + get_data_request_s get_data_req; + if(nsdl_handle && coap_header) { + bool is_bootstrap_msg = address && (nsdl_handle->oma_bs_address_len == address->addr_len) && + (nsdl_handle->oma_bs_port == address->port) && + !memcmp(nsdl_handle->oma_bs_address_ptr, address->addr_ptr, nsdl_handle->oma_bs_address_len); + + if(coap_header->msg_id == nsdl_handle->register_msg_id) { + if(coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CREATED) { + tr_info("M2MNsdlInterface::received_from_server_callback - registered"); + // If lifetime is less than zero then leave the field empty + if(coap_header->options_list_ptr) { + uint32_t max_time = coap_header->options_list_ptr->max_age; + + // If a sufficiently-large Max-Age option is present, we interpret it as registration lifetime; + // mbed server (mDS) reports lifetime this way as a non-standard extension. Other servers + // would likely not include an explicit Max-Age option, in which case we'd see the default 60 seconds. + if( max_time >= MINIMUM_REGISTRATION_TIME) { + set_endpoint_lifetime_buffer(max_time); + } + if(coap_header->options_list_ptr->location_path_ptr) { + sn_nsdl_set_endpoint_location(_nsdl_handle, + coap_header->options_list_ptr->location_path_ptr, + coap_header->options_list_ptr->location_path_len); + } + + } + if (_endpoint->lifetime_ptr) { + _registration_timer.stop_timer(); + _registration_timer.start_timer(registration_time() * 1000, + M2MTimerObserver::Registration, + false); + } + _observer.client_registered(_server); + } else { + tr_error("M2MNsdlInterface::received_from_server_callback - registration error %d", coap_header->msg_code); + if(coap_header->coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED) { + tr_error("M2MNsdlInterface::received_from_server_callback - message sending failed !!!!"); + } + // Try to do clean register again + if(COAP_MSG_CODE_RESPONSE_BAD_REQUEST == coap_header->msg_code || + COAP_MSG_CODE_RESPONSE_FORBIDDEN == coap_header->msg_code) { + _observer.registration_error(M2MInterface::InvalidParameters, false); + } else { + _observer.registration_error(M2MInterface::NetworkError, true); + } + + } + } else if(coap_header->msg_id == nsdl_handle->unregister_msg_id) { + _unregister_ongoing = false; + tr_info("M2MNsdlInterface::received_from_server_callback - unregistered"); + if(coap_header->msg_code == COAP_MSG_CODE_RESPONSE_DELETED) { + _registration_timer.stop_timer(); + _observer.client_unregistered(); + } else { + tr_error("M2MNsdlInterface::received_from_server_callback - unregistration error %d", coap_header->msg_code); + M2MInterface::Error error = M2MInterface::UnregistrationFailed; + if (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_NOT_FOUND) { + _observer.registration_error(error, false); + } else { + _observer.registration_error(error, true); + } + } + } else if(coap_header->msg_id == nsdl_handle->update_register_msg_id) { + if(coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CHANGED) { + tr_info("M2MNsdlInterface::received_from_server_callback - registration_updated"); + _observer.registration_updated(*_server); + handle_pending_notifications(false); + } else { + tr_error("M2MNsdlInterface::received_from_server_callback - registration_updated failed %d, %d", coap_header->msg_code, coap_header->coap_status); + + _registration_timer.stop_timer(); + if ((_binding_mode == M2MInterface::UDP || + _binding_mode == M2MInterface::UDP_QUEUE || + _binding_mode == M2MInterface::UDP_SMS_QUEUE) && + coap_header->msg_code != COAP_MSG_CODE_RESPONSE_NOT_FOUND) { + _observer.registration_error(M2MInterface::NetworkError, true); + } else { + bool msg_sent = false; + if (_server_address) { + msg_sent = parse_and_send_uri_query_parameters(); + } + if (!msg_sent) { + sn_nsdl_clear_coap_resending_queue(_nsdl_handle); + sn_nsdl_register_endpoint(_nsdl_handle,_endpoint, NULL, 0); + } + } + } + } + // Response for GET request + else if (coap_header->token_ptr && is_response_to_get_req(coap_header, get_data_req)) { + tr_info("M2MNsdlInterface::received_from_server_callback - GET response"); + size_t total_size = 0; + + if (coap_header->options_list_ptr) { + if (coap_header->options_list_ptr->use_size2) { + total_size = coap_header->options_list_ptr->size2; + } + } else { + total_size = coap_header->payload_len; + } + + if (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CONTENT) { + get_data_req.received_size += coap_header->payload_len; + get_data_req.on_get_data_cb(coap_header->payload_ptr, + coap_header->payload_len, + total_size, + get_data_req.context); + + // In sync mode, call next GET automatically until all blocks have been received + if (!get_data_req.async_req) { + if (coap_header->options_list_ptr && coap_header->options_list_ptr->block2 & 0x08) { + send_get_data_request(get_data_req.uri_path, + get_data_req.received_size, + get_data_req.async_req, + get_data_req.on_get_data_cb, + get_data_req.on_get_data_error_cb, + get_data_req.context); + } else { + tr_info("M2MNsdlInterface::received_from_server_callback - GET response, all blocks received"); + } + } + } else { + // TODO! Convert coap error code + get_data_req_error_e error = FAILED_TO_SEND_MSG; + get_data_req.on_get_data_error_cb(error, get_data_req.context); + } + + free_get_request_list(coap_header); + } +#ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + else if(coap_header->msg_id == nsdl_handle->bootstrap_msg_id) { + tr_info("M2MNsdlInterface::received_from_server_callback - bootstrap message"); + _bootstrap_id = 0; + M2MInterface::Error error = interface_error(*coap_header); + if(error != M2MInterface::ErrorNone) { + char buffer[MAX_ALLOWED_ERROR_STRING_LENGTH]; + memset(buffer,0,MAX_ALLOWED_ERROR_STRING_LENGTH); + + const char* error= coap_error(*coap_header); + memcpy(buffer,error,strlen(error)); + if(coap_header->payload_ptr) { + strncat(buffer,":",1); + strncat(buffer,(char*)coap_header->payload_ptr,coap_header->payload_len); + } + + handle_bootstrap_error(buffer, false); + } else { + _identity_accepted = true; + } + } +#endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE + else { + + sn_coap_hdr_s *coap_response = NULL; + bool execute_value_updated = false; + M2MObjectInstance *obj_instance = NULL; + String resource_name; + + if(COAP_MSG_CODE_REQUEST_PUT == coap_header->msg_code) { + if (is_bootstrap_msg) { + handle_bootstrap_put_message(coap_header, address); + } + else{ + tr_debug("M2MNsdlInterface::received_from_server_callback - Method not allowed (PUT)."); + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED); + } + } + else if(COAP_MSG_CODE_REQUEST_DELETE == coap_header->msg_code) { + if (is_bootstrap_msg) { + handle_bootstrap_delete(coap_header, address); + } + else{ + tr_debug("M2MNsdlInterface::received_from_server_callback - Method not allowed (DELETE)."); + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED); + } + } + else if(COAP_MSG_CODE_REQUEST_POST == coap_header->msg_code) { + if(is_bootstrap_msg) { + handle_bootstrap_finished(coap_header, address); + } + else if(coap_header->uri_path_ptr) { + + resource_name = coap_to_string(coap_header->uri_path_ptr, + coap_header->uri_path_len); + + String object_name; + int slash_found = resource_name.find_last_of('/'); + //The POST operation here is only allowed for non-existing object instances + if(slash_found != -1) { + object_name = resource_name.substr(0,slash_found); + if( object_name.find_last_of('/') != -1){ + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + COAP_MSG_CODE_RESPONSE_NOT_FOUND); + } else { + int32_t instance_id = atoi(resource_name.substr(slash_found+1, + resource_name.size()-object_name.size()).c_str()); + M2MBase* base = find_resource(object_name, 0); + if(base) { + if((instance_id >= 0) && (instance_id < UINT16_MAX)) { + if(coap_header->payload_ptr) { + M2MObject* object = static_cast<M2MObject*> (base); + obj_instance = object->create_object_instance(instance_id); + if(obj_instance) { + obj_instance->set_operation(M2MBase::GET_PUT_POST_ALLOWED); + coap_response = obj_instance->handle_post_request(_nsdl_handle, + coap_header, + this, + execute_value_updated); + } + if(coap_response && coap_response->msg_code != COAP_MSG_CODE_RESPONSE_CREATED) { + //Invalid request so remove created ObjectInstance + object->remove_object_instance(instance_id); + } else { + tr_debug("M2MNsdlInterface::received_from_server_callback - Send Update registration for Create"); + if (lifetime_value_changed()) { + send_update_registration(_server->resource_value_int(M2MServer::Lifetime)); + } else { + send_update_registration(); + } + } + } else { + tr_error("M2MNsdlInterface::received_from_server_callback - Missing Payload - Cannot create"); + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + COAP_MSG_CODE_RESPONSE_BAD_REQUEST); + } + } else { // instance id out of range + tr_error("M2MNsdlInterface::received_from_server_callback - instance id out of range - Cannot create"); + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + COAP_MSG_CODE_RESPONSE_BAD_REQUEST); + } + } else { // if(base) + tr_error("M2MNsdlInterface::received_from_server_callback - Missing BASE - Cannot create"); + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + COAP_MSG_CODE_RESPONSE_NOT_FOUND); + } + } + } else{ // if(slash_found != -1) + tr_error("M2MNsdlInterface::received_from_server_callback - slash_found - Cannot create"); + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + COAP_MSG_CODE_RESPONSE_NOT_FOUND); + } + + } + } + else if(COAP_MSG_CODE_EMPTY == coap_header->msg_code) { + // Cancel ongoing observation + if (COAP_MSG_TYPE_RESET == coap_header->msg_type) { + M2MBase *base = find_resource("", coap_header->msg_id); + if (base) { + M2MBase::BaseType type = base->base_type(); + switch (type) { + case M2MBase::Object: + base->remove_observation_level(M2MBase::O_Attribute); + break; + case M2MBase::Resource: + base->remove_observation_level(M2MBase::R_Attribute); + break; + case M2MBase::ObjectInstance: + base->remove_observation_level(M2MBase::OI_Attribute); + break; + default: + break; + } + base->set_under_observation(false, this); + base->send_notification_delivery_status(*base, NOTIFICATION_STATUS_UNSUBSCRIBED); + } + // Notification delivered + } else { + M2MBase *base = find_resource("", coap_header->msg_id); + if (base) { + base->send_notification_delivery_status(*base, + NOTIFICATION_STATUS_DELIVERED); + // Supported only in Resource level + // TODO! remove below code once old API is removed + if (M2MBase::Resource == base->base_type()) { + M2MResource *resource = static_cast<M2MResource *> (base); + resource->notification_sent(); + } + } + } + // Retransmission done + } else if (COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED == coap_header->coap_status) { + tr_info("M2MNsdlInterface::received_from_server_callback - message sending failed, id %d", coap_header->msg_id); + + // Report notification status back to application + M2MBase *base = find_resource("", coap_header->msg_id); + if (base) { + base->send_notification_delivery_status(*base, NOTIFICATION_STATUS_SEND_FAILED); + } + // Handle Server-side expections during registration flow + // Client might receive error from server due to temporary connection/operability reasons, + // server might not recover the flow in this case, so it is better for Client to restart registration. + } else if (nsdl_handle->register_msg_id && + ((coap_header->msg_code == COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR) || + (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_BAD_GATEWAY) || + (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE) || + (coap_header->msg_code == COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT))) { + tr_error("M2MNsdlInterface::received_from_server_callback - registration error %d", coap_header->msg_code); + tr_error("M2MNsdlInterface::received_from_server_callback - unexpected error received from server"); + // Try to do clean register again + _observer.registration_error(M2MInterface::NetworkError, true); + } else { + // Add warn for any message that gets this far. We might be missing some handling in above. + tr_warn("M2MNsdlInterface::received_from_server_callback - msg was ignored %d", coap_header->msg_code); + } + + // Send response to server + if(coap_response) { + tr_debug("M2MNsdlInterface::received_from_server_callback - send CoAP response"); + (sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response) == 0) ? value = 0 : value = 1; + sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); + } + + // Tell to application that value has been updated + if (execute_value_updated) { + value_updated(obj_instance); + } + + } + } + return value; +} + +uint8_t M2MNsdlInterface::resource_callback(struct nsdl_s */*nsdl_handle*/, + sn_coap_hdr_s *received_coap_header, + sn_nsdl_addr_s *address, + sn_nsdl_capab_e /*nsdl_capab*/) +{ + tr_debug("M2MNsdlInterface::resource_callback()"); + _observer.coap_data_processed(); + uint8_t result = 1; + uint8_t *payload = NULL; + bool free_payload = true; + sn_coap_hdr_s *coap_response = NULL; + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 4.00 + String resource_name = coap_to_string(received_coap_header->uri_path_ptr, + received_coap_header->uri_path_len); + + bool execute_value_updated = false; + M2MBase* base = find_resource(resource_name, 0); + if (base) { + if (COAP_MSG_CODE_REQUEST_GET == received_coap_header->msg_code) { + coap_response = base->handle_get_request(_nsdl_handle, received_coap_header,this); + } else if (COAP_MSG_CODE_REQUEST_PUT == received_coap_header->msg_code) { + coap_response = base->handle_put_request(_nsdl_handle, received_coap_header, this, execute_value_updated); + } else if (COAP_MSG_CODE_REQUEST_POST == received_coap_header->msg_code) { + if (base->base_type() == M2MBase::ResourceInstance) { + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } else { + coap_response = base->handle_post_request(_nsdl_handle, + received_coap_header, + this, + execute_value_updated, + address); + } + } else if (COAP_MSG_CODE_REQUEST_DELETE == received_coap_header->msg_code) { + // Delete the object instance + M2MBase::BaseType type = base->base_type(); + if(M2MBase::ObjectInstance == type) { + M2MBase* base_object = find_resource(base->uri_path(), 0); + if(base_object) { + M2MObject &object = ((M2MObjectInstance*)base_object)->get_parent_object(); + int slash_found = resource_name.find_last_of('/'); + // Object instance validty checks done in upper level, no need for error handling + if (slash_found != -1) { + String object_name; + object_name = resource_name.substr(slash_found + 1, resource_name.length()); + if (object.remove_object_instance(strtoul( + object_name.c_str(), + NULL, + 10))) { + msg_code = COAP_MSG_CODE_RESPONSE_DELETED; + } + } + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 + } + } + } else { + tr_error("M2MNsdlInterface::resource_callback() - Resource NOT FOUND"); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 + } + + if (!coap_response) { + coap_response = sn_nsdl_build_response(_nsdl_handle, + received_coap_header, + msg_code); + } + + // This copy will be passed to resource instance + payload = (uint8_t*)memory_alloc(received_coap_header->payload_len + 1); + if (payload) { + memcpy(payload, received_coap_header->payload_ptr, received_coap_header->payload_len); + payload[received_coap_header->payload_len] = '\0'; + } + else { + if (coap_response) { + coap_response->msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; + } + } + + if (coap_response && + coap_response->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING && + coap_response->msg_code != COAP_MSG_CODE_EMPTY) { + (sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response) == 0) ? result = 0 : result = 1; + if(coap_response->payload_ptr) { + free(coap_response->payload_ptr); + coap_response->payload_ptr = NULL; + } + } + + // If the external blockwise storing is enabled call value updated once all the blocks have been received + if (execute_value_updated && + coap_response && + coap_response->coap_status != COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING && + coap_response->msg_code < COAP_MSG_CODE_RESPONSE_BAD_REQUEST) { + if ((COAP_MSG_CODE_REQUEST_PUT == received_coap_header->msg_code) && + (base->base_type() == M2MBase::Resource || + base->base_type() == M2MBase::ResourceInstance)) { + M2MResourceBase* res = (M2MResourceBase*)base; + bool external_block_store = false; + + if (res->block_message() && res->block_message()->is_block_message()) { + external_block_store = true; + } + if (!external_block_store) { + // Ownership of payload moved to resource, skip the freeing. + free_payload = false; + res->set_value_raw(payload, received_coap_header->payload_len); + } + } + + if (coap_response->msg_code != COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE) { + value_updated(base); + } + } + + if (free_payload) { + free(payload); + } + + sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); + return result; +} + +bool M2MNsdlInterface::process_received_data(uint8_t *data, + uint16_t data_size, + sn_nsdl_addr_s *address) +{ + tr_debug("M2MNsdlInterface::process_received_data(data size %d)", data_size); + return (0 == sn_nsdl_process_coap(_nsdl_handle, + data, + data_size, + address)) ? true : false; +} + +void M2MNsdlInterface::stop_timers() +{ + tr_debug("M2MNsdlInterface::stop_timers()"); + _registration_timer.stop_timer(); + _nsdl_exceution_timer.stop_timer(); + _nsdl_exceution_timer_running = false; + _bootstrap_id = 0; + _unregister_ongoing = false; +} + +void M2MNsdlInterface::timer_expired(M2MTimerObserver::Type type) +{ + if(M2MTimerObserver::NsdlExecution == type) { + sn_nsdl_exec(_nsdl_handle, _counter_for_nsdl); + _counter_for_nsdl++; + } else if((M2MTimerObserver::Registration) == type && (_unregister_ongoing==false)) { + tr_debug("M2MNsdlInterface::timer_expired - Send update registration"); + if (lifetime_value_changed()) { + send_update_registration(_server->resource_value_int(M2MServer::Lifetime)); + } else { + send_update_registration(); + } + } +} + +void M2MNsdlInterface::observation_to_be_sent(M2MBase *object, + uint16_t obs_number, + const m2m::Vector<uint16_t> &changed_instance_ids, + bool send_object) +{ + claim_mutex(); + if(object) { + tr_debug("M2MNsdlInterface::observation_to_be_sent()"); + M2MBase::BaseType type = object->base_type(); + if(type == M2MBase::Object) { + send_object_observation(static_cast<M2MObject*> (object), + obs_number, + changed_instance_ids, + send_object, false); + } else if(type == M2MBase::ObjectInstance) { + send_object_instance_observation(static_cast<M2MObjectInstance*> (object), obs_number, false); + } else if(type == M2MBase::Resource) { + send_resource_observation(static_cast<M2MResource*> (object), obs_number, false); + } + } + release_mutex(); +} + +#ifndef DISABLE_DELAYED_RESPONSE +void M2MNsdlInterface::send_delayed_response(M2MBase *base) +{ + claim_mutex(); + tr_debug("M2MNsdlInterface::send_delayed_response()"); + M2MResource *resource = NULL; + if(base) { + if(M2MBase::Resource == base->base_type()) { + resource = static_cast<M2MResource *> (base); + } + if(resource) { + sn_coap_hdr_s coap_response; + + memset(&coap_response,0,sizeof(sn_coap_hdr_s)); + + coap_response.msg_type = COAP_MSG_TYPE_CONFIRMABLE; + coap_response.msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + resource->get_delayed_token(coap_response.token_ptr,coap_response.token_len); + + uint32_t length = 0; + resource->get_value(coap_response.payload_ptr, length); + coap_response.payload_len = length; + + sn_nsdl_send_coap_message(_nsdl_handle, _nsdl_handle->nsp_address_ptr->omalw_address_ptr, &coap_response); + + free(coap_response.payload_ptr); + free(coap_response.token_ptr); + } + } + release_mutex(); +} +#endif + +void M2MNsdlInterface::resource_to_be_deleted(M2MBase *base) +{ + tr_debug("M2MNsdlInterface::resource_to_be_deleted()"); + claim_mutex(); + remove_nsdl_resource(base); + + // Since the M2MObject's are stored in _object_list, they need to be removed from there also. + if (base && base->base_type() == M2MBase::Object) { + remove_object(base); + } + + release_mutex(); +} + +void M2MNsdlInterface::value_updated(M2MBase *base) +{ + tr_debug("M2MNsdlInterface::value_updated()"); + String name; + if(base) { + switch(base->base_type()) { + case M2MBase::Object: + create_nsdl_object_structure(static_cast<M2MObject*> (base)); + name = base->name(); + break; + case M2MBase::ObjectInstance: + create_nsdl_object_instance_structure(static_cast<M2MObjectInstance*> (base)); + name = static_cast<M2MObjectInstance*> (base)->get_parent_object().name(); + + break; + case M2MBase::Resource: { + M2MResource* resource = static_cast<M2MResource*> (base); + create_nsdl_resource_structure(resource, + resource->supports_multiple_instances()); + name = base->name(); + } + break; + case M2MBase::ResourceInstance: { + M2MResourceInstance* instance = static_cast<M2MResourceInstance*> (base); + create_nsdl_resource(instance); + name = static_cast<M2MResourceInstance*> (base)->get_parent_resource().name(); + } + break; + } + } + + if (base && base->is_value_updated_function_set()) { + base->execute_value_updated(name); + } + else { + _observer.value_updated(base); + } +} + +void M2MNsdlInterface::remove_object(M2MBase *object) +{ + claim_mutex(); + tr_debug("M2MNsdlInterface::remove_object()"); + M2MObject* rem_object = static_cast<M2MObject*> (object); + if(rem_object && !_object_list.empty()) { + M2MObjectList::const_iterator it; + it = _object_list.begin(); + int index = 0; + for ( ; it != _object_list.end(); it++, index++ ) { + if((*it) == rem_object) { + _object_list.erase(index); + break; + } + } + } + if(_object_list.empty()) { + _object_list.clear(); + } + release_mutex(); +} + +bool M2MNsdlInterface::create_nsdl_object_structure(M2MObject *object) +{ + bool success = false; + if(object) { + const M2MObjectInstanceList &instance_list = object->instances(); + if(!instance_list.empty()) { + M2MObjectInstanceList::const_iterator it; + it = instance_list.begin(); + for ( ; it != instance_list.end(); it++ ) { + // Create NSDL structure for all object instances inside + success = create_nsdl_object_instance_structure(*it); + } + } + } + if(object && object->operation() != M2MBase::NOT_ALLOWED) { + success = create_nsdl_resource(object); + } + + return success; +} + +bool M2MNsdlInterface::create_nsdl_object_instance_structure(M2MObjectInstance *object_instance) +{ + bool success = false; + if( object_instance) { + const M2MResourceList &res_list = object_instance->resources(); + if(!res_list.empty()) { + M2MResourceList::const_iterator it; + it = res_list.begin(); + for ( ; it != res_list.end(); it++ ) { + // Create NSDL structure for all resources inside + success = create_nsdl_resource_structure(*it, + (*it)->supports_multiple_instances()); + } + } + if(object_instance->operation() != M2MBase::NOT_ALLOWED) { + success = create_nsdl_resource(object_instance); + } + } + return success; +} + +bool M2MNsdlInterface::create_nsdl_resource_structure(M2MResource *res, + bool multiple_instances) +{ + bool success = false; + if(res) { + // if there are multiple instances supported + if(multiple_instances) { + const M2MResourceInstanceList &res_list = res->resource_instances(); + if(!res_list.empty()) { + M2MResourceInstanceList::const_iterator it; + it = res_list.begin(); + for ( ; it != res_list.end(); it++ ) { + success = create_nsdl_resource((*it)); + if(!success) { + tr_error("M2MNsdlInterface::create_nsdl_resource_structure - instance creation failed"); + return false; + } + } + // Register the main Resource as well along with ResourceInstances + success = create_nsdl_resource(res); + } + } else { + success = create_nsdl_resource(res); + } + } + return success; +} + +bool M2MNsdlInterface::create_nsdl_resource(M2MBase *base) +{ + claim_mutex(); + bool success = false; + if(base) { + int8_t result = 0; + sn_nsdl_dynamic_resource_parameters_s* nsdl_resource = base->get_nsdl_resource(); + + // needed on deletion + if (base->observation_handler() == NULL) { + base->set_observation_handler(this); + } + + result = sn_nsdl_put_resource(_nsdl_handle, nsdl_resource); + + // Put under observation if auto-obs feature is set. + // TODO! What if the observation is set in multiple levels? + if (nsdl_resource && nsdl_resource->auto_observable && result != SN_GRS_RESOURCE_ALREADY_EXISTS) { + base->set_under_observation(true, base->observation_handler()); + + // Increment auto-obs token to be unique in every object + _auto_obs_token++; + if (_auto_obs_token > AUTO_OBS_TOKEN_MAX) { + _auto_obs_token = 1; + } + + // Store token in big-endian byte order + uint8_t token[sizeof(uint16_t)]; + common_write_16_bit(_auto_obs_token, token); + base->set_observation_token(token, sizeof(uint16_t)); + + switch (base->base_type()) { + case M2MBase::Object: + base->add_observation_level(M2MBase::O_Attribute); + break; + + case M2MBase::ObjectInstance: + base->add_observation_level(M2MBase::OI_Attribute); + break; + + case M2MBase::Resource: + case M2MBase::ResourceInstance: + base->add_observation_level(M2MBase::R_Attribute); + break; + } + } + + // Either the resource is created or it already + // exists , then result is success. + if (result == 0 || + result == SN_GRS_RESOURCE_ALREADY_EXISTS){ + success = true; + } + } + release_mutex(); + return success; +} + +// convenience method to get the URI from its buffer field... +String M2MNsdlInterface::coap_to_string(const uint8_t *coap_data, int coap_data_length) +{ + String value = ""; + if (coap_data != NULL && coap_data_length > 0) { + value.append_raw((char *)coap_data,coap_data_length); + } + return value; +} + +uint64_t M2MNsdlInterface::registration_time() const +{ + uint64_t value = 0; + if(_endpoint) { + value = _server->resource_value_int(M2MServer::Lifetime); + } + + if(value >= OPTIMUM_LIFETIME) { + value = value - REDUCE_LIFETIME; + } else { + value = REDUCTION_FACTOR * value; + } + tr_debug("M2MNsdlInterface::registration_time - value (in seconds) %" PRIu64, value); + return value; +} + +M2MBase* M2MNsdlInterface::find_resource(const String &object_name, + const uint16_t msg_id) const +{ + M2MBase *object = NULL; + if(!_object_list.empty()) { + M2MObjectList::const_iterator it; + it = _object_list.begin(); + for ( ; it != _object_list.end(); it++ ) { + if (!msg_id) { + if (strcmp((char*)(*it)->uri_path(), object_name.c_str()) == 0) { + object = (*it); + tr_debug("M2MNsdlInterface::find_resource(%s) found", object_name.c_str()); + break; + } + } else { + uint16_t stored_msg_id = (*it)->get_notification_msgid(); + if (stored_msg_id == msg_id) { + object = (*it); + tr_debug("M2MNsdlInterface::find_resource - msg id found"); + break; + } + } + object = find_resource((*it), object_name, msg_id); + if(object != NULL) { + break; + } + } + } + return object; +} + +M2MBase* M2MNsdlInterface::find_resource(const M2MObject *object, + const String &object_instance, + const uint16_t msg_id) const +{ + M2MBase *instance = NULL; + if(object) { + const M2MObjectInstanceList &list = object->instances(); + if(!list.empty()) { + M2MObjectInstanceList::const_iterator it; + it = list.begin(); + for ( ; it != list.end(); it++ ) { + if (!msg_id) { + if(!strcmp((char*)(*it)->uri_path(), object_instance.c_str())){ + instance = (*it); + tr_debug("M2MNsdlInterface::find_resource(object instance level) - found (%s)", + (char*)(*it)->uri_path()); + break; + } + } else { + uint16_t stored_msg_id = (*it)->get_notification_msgid(); + if (stored_msg_id == msg_id) { + instance = (*it); + tr_debug("M2MNsdlInterface::find_resource(object instance level) - found msgid (%d)", stored_msg_id); + break; + } + } + instance = find_resource((*it),object_instance, msg_id); + if(instance != NULL){ + break; + } + } + } + } + return instance; +} + +M2MBase* M2MNsdlInterface::find_resource(const M2MObjectInstance *object_instance, + const String &resource_instance, + const uint16_t msg_id) const +{ + M2MBase *instance = NULL; + if(object_instance) { + const M2MResourceList &list = object_instance->resources(); + if(!list.empty()) { + M2MResourceList::const_iterator it; + it = list.begin(); + for ( ; it != list.end(); it++ ) { + if (!msg_id) { + if(!strcmp((char*)(*it)->uri_path(), resource_instance.c_str())) { + instance = *it; + break; + } + else if((*it)->supports_multiple_instances()) { + instance = find_resource((*it), (*it)->uri_path(), + resource_instance); + if(instance != NULL){ + break; + } + } + } else { + uint16_t stored_msg_id = (*it)->get_notification_msgid(); + if (stored_msg_id == msg_id) { + instance = *it; + tr_debug("M2MNsdlInterface::find_resource(resource level) - found msgid (%d)", stored_msg_id); + break; + } + } + } + } + } + return instance; +} + +M2MBase* M2MNsdlInterface::find_resource(const M2MResource *resource, + const String &object_name, + const String &resource_instance) const +{ + M2MBase *res = NULL; + if(resource) { + if(resource->supports_multiple_instances()) { + const M2MResourceInstanceList &list = resource->resource_instances(); + if(!list.empty()) { + M2MResourceInstanceList::const_iterator it; + it = list.begin(); + for ( ; it != list.end(); it++ ) { + if(!strcmp((char*)(*it)->uri_path(), resource_instance.c_str())){ + res = (*it); + break; + } + } + } + } + } + return res; +} + +bool M2MNsdlInterface::object_present(M2MObject* object) const +{ + bool success = false; + if(object && !_object_list.empty()) { + M2MObjectList::const_iterator it; + it = _object_list.begin(); + for ( ; it != _object_list.end(); it++ ) { + if((*it) == object) { + success = true; + break; + } + } + } + return success; +} + +bool M2MNsdlInterface::add_object_to_list(M2MObject* object) +{ + bool success = false; + if(object && !object_present(object)) { + _object_list.push_back(object); + success = true; + } + return success; +} + +M2MInterface::Error M2MNsdlInterface::interface_error(const sn_coap_hdr_s &coap_header) +{ + M2MInterface::Error error; + switch(coap_header.msg_code) { + case COAP_MSG_CODE_RESPONSE_BAD_REQUEST: + case COAP_MSG_CODE_RESPONSE_BAD_OPTION: + case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE: + case COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED: + case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE: + case COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT: + error = M2MInterface::InvalidParameters; + break; + case COAP_MSG_CODE_RESPONSE_UNAUTHORIZED: + case COAP_MSG_CODE_RESPONSE_FORBIDDEN: + case COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE: + case COAP_MSG_CODE_RESPONSE_NOT_FOUND: + case COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED: + error = M2MInterface::NotAllowed; + break; + case COAP_MSG_CODE_RESPONSE_CREATED: + case COAP_MSG_CODE_RESPONSE_DELETED: + case COAP_MSG_CODE_RESPONSE_VALID: + case COAP_MSG_CODE_RESPONSE_CHANGED: + case COAP_MSG_CODE_RESPONSE_CONTENT: + error = M2MInterface::ErrorNone; + break; + default: + error = M2MInterface::UnknownError; + break; + } + if(coap_header.coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED) { + error = M2MInterface::NetworkError; + } + return error; +} + +const char *M2MNsdlInterface::coap_error(const sn_coap_hdr_s &coap_header) +{ + + if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_BAD_REQUEST) { + return COAP_ERROR_REASON_1; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_BAD_OPTION) { + return COAP_ERROR_REASON_2; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE) { + return COAP_ERROR_REASON_3; + }else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED) { + return COAP_ERROR_REASON_4; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE) { + return COAP_ERROR_REASON_5; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT) { + return COAP_ERROR_REASON_6; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_UNAUTHORIZED) { + return COAP_ERROR_REASON_7; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_FORBIDDEN) { + return COAP_ERROR_REASON_8; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE) { + return COAP_ERROR_REASON_9; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_NOT_FOUND) { + return COAP_ERROR_REASON_10; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED) { + return COAP_ERROR_REASON_11; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE) { + return COAP_ERROR_REASON_13; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR) { + return COAP_ERROR_REASON_14; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_BAD_GATEWAY) { + return COAP_ERROR_REASON_15; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT) { + return COAP_ERROR_REASON_16; + } else if(coap_header.msg_code == COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED) { + return COAP_ERROR_REASON_17; + } else if(coap_header.coap_status == COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED) { + return COAP_ERROR_REASON_12; + } + return COAP_NO_ERROR; +} + +void M2MNsdlInterface::send_object_observation(M2MObject *object, + uint16_t obs_number, + const m2m::Vector<uint16_t> &changed_instance_ids, + bool send_object, + bool resend) +{ + tr_info("M2MNsdlInterface::send_object_observation"); + if(object) { + uint8_t *value = 0; + uint32_t length = 0; + uint8_t token[MAX_TOKEN_SIZE]; + uint8_t token_length = 0; + + // Send whole object structure + if (send_object) { + value = M2MTLVSerializer::serialize(object->instances(), length); + } + // Send only changed object instances + else { + M2MObjectInstanceList list; + Vector<uint16_t>::const_iterator it; + it = changed_instance_ids.begin(); + for (; it != changed_instance_ids.end(); it++){ + M2MObjectInstance* obj_instance = object->object_instance(*it); + if (obj_instance){ + list.push_back(obj_instance); + } + } + if (!list.empty()) { + value = M2MTLVSerializer::serialize(list, length); + list.clear(); + } + } + + object->get_observation_token((uint8_t*)&token,token_length); + if (resend) { + sn_nsdl_send_observation_notification(_nsdl_handle, token, token_length, value, length, + sn_coap_observe_e(obs_number), COAP_MSG_TYPE_CONFIRMABLE, + sn_coap_content_format_e(object->coap_content_type()), + object->get_notification_msgid()); + } else { + int32_t msgid = sn_nsdl_send_observation_notification(_nsdl_handle, token, token_length, value, length, + sn_coap_observe_e(obs_number), COAP_MSG_TYPE_CONFIRMABLE, + sn_coap_content_format_e(object->coap_content_type()), -1); + execute_notification_delivery_status_cb(object, msgid); + } + + memory_free(value); + } +} + +void M2MNsdlInterface::send_object_instance_observation(M2MObjectInstance *object_instance, + uint16_t obs_number, + bool resend) +{ + tr_info("M2MNsdlInterface::send_object_instance_observation"); + if(object_instance) { + uint8_t *value = 0; + uint32_t length = 0; + uint8_t token[MAX_TOKEN_SIZE]; + uint8_t token_length = 0; + + value = M2MTLVSerializer::serialize(object_instance->resources(), length); + + object_instance->get_observation_token((uint8_t*)&token,token_length); + + if (resend) { + sn_nsdl_send_observation_notification(_nsdl_handle, token, token_length, value, length, + sn_coap_observe_e(obs_number), COAP_MSG_TYPE_CONFIRMABLE, + sn_coap_content_format_e(object_instance->coap_content_type()), + object_instance->get_notification_msgid()); + } else { + int32_t msgid = sn_nsdl_send_observation_notification(_nsdl_handle, token, token_length, value, length, + sn_coap_observe_e(obs_number), COAP_MSG_TYPE_CONFIRMABLE, + sn_coap_content_format_e(object_instance->coap_content_type()), -1); + execute_notification_delivery_status_cb(object_instance, msgid); + } + + memory_free(value); + } +} + +void M2MNsdlInterface::send_resource_observation(M2MResource *resource, + uint16_t obs_number, + bool resend) +{ + if(resource) { + tr_info("M2MNsdlInterface::send_resource_observation - uri %s", resource->uri_path()); + uint8_t *value = 0; + uint32_t length = 0; + uint8_t token[MAX_TOKEN_SIZE]; + uint8_t token_length = 0; + + resource->get_observation_token((uint8_t*)token,token_length); + uint16_t content_type = 0; + if(M2MResourceBase::OPAQUE == resource->resource_instance_type()) { + content_type = COAP_CONTENT_OMA_OPAQUE_TYPE; + } + if (resource->resource_instance_count() > 0) { + content_type = resource->coap_content_type(); + value = M2MTLVSerializer::serialize(resource, length); + } else { + resource->get_value(value,length); + } + + if (resend) { + sn_nsdl_send_observation_notification(_nsdl_handle, token, token_length, value, length, + sn_coap_observe_e(obs_number), + COAP_MSG_TYPE_CONFIRMABLE, + sn_coap_content_format_e(content_type), + resource->get_notification_msgid()); + } else { + int32_t msgid = sn_nsdl_send_observation_notification(_nsdl_handle, token, token_length, value, length, + sn_coap_observe_e(obs_number), + COAP_MSG_TYPE_CONFIRMABLE, + sn_coap_content_format_e(content_type), -1); + execute_notification_delivery_status_cb(resource, msgid); + } + + memory_free(value); + } +} +nsdl_s * M2MNsdlInterface::get_nsdl_handle() const +{ + return _nsdl_handle; +} + +void M2MNsdlInterface::handle_bootstrap_put_message(sn_coap_hdr_s *coap_header, + sn_nsdl_addr_s *address) { +#ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_info("M2MNsdlInterface::handle_bootstrap_put_message"); + uint8_t response_code = COAP_MSG_CODE_RESPONSE_CHANGED; + sn_coap_hdr_s *coap_response = NULL; + bool success = false; + uint16_t content_type = 0; + char buffer[MAX_ALLOWED_ERROR_STRING_LENGTH] = {0}; + M2MNsdlInterface::ObjectType object_type = M2MNsdlInterface::SECURITY; + + if (!_security) { + _security = M2MSecurity::get_instance(); + } + + String resource_name = coap_to_string(coap_header->uri_path_ptr, + coap_header->uri_path_len); + tr_debug("M2MNsdlInterface::handle_bootstrap_put_message - object path %s", resource_name.c_str()); + + // Security object + if (resource_name.compare(0,1,"0") == 0) { + object_type = M2MNsdlInterface::SECURITY; + success = true; + } + // Server object + else if (resource_name.compare(0,1,"1") == 0) { + object_type = M2MNsdlInterface::SERVER; + success = true; + } + // Device object + else if (resource_name.compare(0,1,"3") == 0) { + M2MDevice* dev = M2MInterfaceFactory::create_device(); + // Not mandatory resource, that's why it must be created first + dev->create_resource(M2MDevice::CurrentTime, 0); + object_type = M2MNsdlInterface::DEVICE; + success = true; + } + + if (success) { + if(coap_header->content_format != COAP_CT_NONE) { + content_type = coap_header->content_format; + } + + if (content_type != COAP_CONTENT_OMA_TLV_TYPE && + content_type != COAP_CONTENT_OMA_TLV_TYPE_OLD) { + tr_error("M2MNsdlInterface::handle_bootstrap_put_message - content_type %d", content_type); + success = false; + } + // Parse TLV message and check is the object valid + if (success) { + change_operation_mode(_security, M2MBase::PUT_ALLOWED); + success = parse_bootstrap_message(coap_header, object_type); + if (success && object_type == M2MNsdlInterface::SECURITY) { + success = validate_security_object(); + if (!success) { + snprintf(buffer,sizeof(buffer), ERROR_REASON_22, "Invalid security object"); + response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + } + // Set operation back to default ones + if (_security) { + change_operation_mode(_security, M2MBase::NOT_ALLOWED); + } + } + } + + if (!success) { + response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + response_code); + + if (coap_response) { + sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response); + sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); + } + + if (!success) { + // Do not overwrite ERROR_REASON_22 + if (strlen(buffer) == 0) { + snprintf(buffer,sizeof(buffer), ERROR_REASON_20,resource_name.c_str()); + } + handle_bootstrap_error(buffer, true); + } +#else + (void) coap_header; + (void) address; +#endif +} + +bool M2MNsdlInterface::parse_bootstrap_message(sn_coap_hdr_s *coap_header, + M2MNsdlInterface::ObjectType lwm2m_object_type) +{ +#ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE + tr_info("M2MNsdlInterface::parse_bootstrap_message"); + bool ret = false; + bool is_obj_instance = false; + uint16_t instance_id = 0; + if (_security) { + ret = is_obj_instance = M2MTLVDeserializer::is_object_instance(coap_header->payload_ptr); + if (!is_obj_instance) { + ret = M2MTLVDeserializer::is_resource(coap_header->payload_ptr); + } + if (ret) { + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + if (is_obj_instance) { + M2MObject* dev_object = static_cast<M2MObject*> (M2MInterfaceFactory::create_device()); + switch (lwm2m_object_type) { + case M2MNsdlInterface::SECURITY: + instance_id = M2MTLVDeserializer::instance_id(coap_header->payload_ptr); + if (_security->object_instance(instance_id) == NULL) { + _security->create_object_instance(M2MSecurity::M2MServer); + change_operation_mode(_security, M2MBase::PUT_ALLOWED); + } + error = M2MTLVDeserializer::deserialise_object_instances(coap_header->payload_ptr, + coap_header->payload_len, + *_security, + M2MTLVDeserializer::Put); + break; + case M2MNsdlInterface::SERVER: + error = M2MTLVDeserializer::deserialise_object_instances(coap_header->payload_ptr, + coap_header->payload_len, + *_server, + M2MTLVDeserializer::Put); + break; + case M2MNsdlInterface::DEVICE: + error = M2MTLVDeserializer::deserialise_object_instances(coap_header->payload_ptr, + coap_header->payload_len, + *dev_object, + M2MTLVDeserializer::Put); + break; + default: + break; + } + } + else { + instance_id = M2MTLVDeserializer::instance_id(coap_header->payload_ptr); + M2MObjectInstance* instance = NULL; + switch (lwm2m_object_type) { + case M2MNsdlInterface::SECURITY: + instance = _security->object_instance(instance_id); + if (instance) { + error = M2MTLVDeserializer::deserialize_resources(coap_header->payload_ptr, + coap_header->payload_len, + *instance, + M2MTLVDeserializer::Put); + } else { + error = M2MTLVDeserializer::NotValid; + } + + break; + case M2MNsdlInterface::SERVER: + instance = _server->object_instance(instance_id); + if (instance) { + error = M2MTLVDeserializer::deserialize_resources(coap_header->payload_ptr, + coap_header->payload_len, + *instance, + M2MTLVDeserializer::Post); + } else { + error = M2MTLVDeserializer::NotValid; + } + + break; + case M2MNsdlInterface::DEVICE: + default: + break; + } + } + + if (error != M2MTLVDeserializer::None) { + tr_error("M2MNsdlInterface::parse_bootstrap_message - error %d", error); + ret = false; + } + } + } else { + tr_error("M2MNsdlInterface::parse_bootstrap_message -- no security object!"); + } + return ret; +#else + (void) coap_header; + (void) is_security_object; + return false; +#endif +} + +void M2MNsdlInterface::handle_bootstrap_finished(sn_coap_hdr_s *coap_header,sn_nsdl_addr_s *address) +{ +#ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE + char buffer[MAX_ALLOWED_ERROR_STRING_LENGTH]; + + String object_name = coap_to_string(coap_header->uri_path_ptr, + coap_header->uri_path_len); + tr_info("M2MNsdlInterface::handle_bootstrap_finished - path: %s", object_name.c_str()); + sn_coap_hdr_s *coap_response = NULL; + uint8_t msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; + + // Accept only '/bs' path and check that needed data is in security object + if (object_name.size() != 2 || + object_name.compare(0,2,BOOTSTRAP_URI) != 0) { + snprintf(buffer,sizeof(buffer), ERROR_REASON_22, object_name.c_str()); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + else { + // Add short server id to server object + int32_t m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer); + if (m2m_id == -1) { + snprintf(buffer,sizeof(buffer), ERROR_REASON_4); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + else { + _server->set_resource_value(M2MServer::ShortServerID, + _security->resource_value_int(M2MSecurity::ShortServerID, m2m_id)); + } + } + + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + msg_code); + if(coap_response) { + sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response); + sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); + } + + if (COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) { + // Switch back to original ep name + if (_endpoint->endpoint_name_ptr) { + memory_free(_endpoint->endpoint_name_ptr); + } + _endpoint->endpoint_name_ptr = alloc_string_copy((uint8_t*)_endpoint_name.c_str(), _endpoint_name.length()); + _endpoint->endpoint_name_len = _endpoint_name.length(); + // Inform observer that bootstrap is finished but it should wait until nsdl has sent data. + // The final bootstrap_done callback is called in the observers data_sent callback. + _observer.bootstrap_wait(); + } else { + handle_bootstrap_error(buffer, true); + } +#else + (void) coap_header; + (void) address; +#endif +} + +void M2MNsdlInterface::handle_bootstrap_delete(sn_coap_hdr_s *coap_header,sn_nsdl_addr_s *address) +{ + +#ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE + char buffer[MAX_ALLOWED_ERROR_STRING_LENGTH]; + memset(buffer,0,sizeof(buffer)); + sn_coap_hdr_s *coap_response = NULL; + uint8_t msg_code = COAP_MSG_CODE_RESPONSE_DELETED; + String object_name = coap_to_string(coap_header->uri_path_ptr, + coap_header->uri_path_len); + tr_info("M2MNsdlInterface::handle_bootstrap_delete - obj %s", object_name.c_str()); + if(!_identity_accepted) { + snprintf(buffer,sizeof(buffer), ERROR_REASON_21,"/bs un-init"); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + // Only following paths are accepted, 0, 0/0 + else if (object_name.size() == 2 || object_name.size() > 3) { + snprintf(buffer,sizeof(buffer), ERROR_REASON_21,object_name.c_str()); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + else if ((object_name.size() == 1 && object_name.compare(0,1,"0") != 0) || + (object_name.size() == 3 && object_name.compare(0,3,"0/0") != 0)) { + snprintf(buffer,sizeof(buffer), ERROR_REASON_21,object_name.c_str()); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + + coap_response = sn_nsdl_build_response(_nsdl_handle, + coap_header, + msg_code); + + if(coap_response) { + sn_nsdl_send_coap_message(_nsdl_handle, address, coap_response); + sn_nsdl_release_allocated_coap_msg_mem(_nsdl_handle, coap_response); + if(_security) { + _security->clear_resources(); + } + } + if (!coap_response || COAP_MSG_CODE_RESPONSE_DELETED != msg_code) { + handle_bootstrap_error(buffer, true); + } +#else + (void) coap_header; + (void) address; +#endif +} + +bool M2MNsdlInterface::validate_security_object() +{ + bool valid = false; +#ifndef M2M_CLIENT_DISABLE_BOOTSTRAP_FEATURE + M2MObjectInstanceList instances = _security->instances(); + M2MObjectInstanceList::const_iterator it; + it = instances.begin(); + uint16_t instance_id = 0; + for ( ; it != instances.end(); it++ ) { + valid = true; + instance_id = (*it)->instance_id(); + tr_debug("M2MNsdlInterface::validate_security_object - instance %d", instance_id); + String address = _security->resource_value_string(M2MSecurity::M2MServerUri, instance_id); + uint32_t sec_mode = _security->resource_value_int(M2MSecurity::SecurityMode, instance_id); + uint32_t is_bs_server = _security->resource_value_int(M2MSecurity::BootstrapServer, instance_id); + uint32_t public_key_size = 0; + uint32_t server_key_size = 0; + uint32_t pkey_size = 0; + + M2MResource* resource = _security->get_resource(M2MSecurity::PublicKey, instance_id); + if (resource) { + public_key_size = resource->value_length(); + } + resource = _security->get_resource(M2MSecurity::ServerPublicKey, instance_id); + if (resource) { + server_key_size = resource->value_length(); + } + resource = _security->get_resource(M2MSecurity::Secretkey, instance_id); + if (resource) { + pkey_size = resource->value_length(); + } + + tr_info("M2MNsdlInterface::validate_security_object - Server URI /0/0: %s", address.c_str()); + tr_info("M2MNsdlInterface::validate_security_object - is bs server /0/1: %" PRIu32, is_bs_server); + tr_info("M2MNsdlInterface::validate_security_object - Security Mode /0/2: %" PRIu32, sec_mode); + tr_info("M2MNsdlInterface::validate_security_object - Public key size /0/3: %" PRIu32, public_key_size); + tr_info("M2MNsdlInterface::validate_security_object - Server Public key size /0/4: %" PRIu32, server_key_size); + tr_info("M2MNsdlInterface::validate_security_object - Secret key size /0/5: %" PRIu32, pkey_size); + if (address.empty()) { + return false; + } + // Only NoSec and Certificate modes are supported + if (M2MSecurity::Certificate == sec_mode) { + if (!public_key_size || !server_key_size || !pkey_size) { + return false; + } + } else if (M2MSecurity::NoSecurity != sec_mode){ + return false; + } + } +#endif + return valid; +} + + +void M2MNsdlInterface::handle_bootstrap_error(const char *reason, bool wait) +{ + tr_error("M2MNsdlInterface::handle_bootstrap_error(%s)",reason); + _identity_accepted = false; + if (_security) { + int32_t m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer); + if (m2m_id >= 0) { + _security->remove_object_instance(m2m_id); + } + } + + if (wait) { + _observer.bootstrap_error_wait(reason); + } else { + _observer.bootstrap_error(reason); + } +} + +const String& M2MNsdlInterface::endpoint_name() const +{ + return _endpoint_name; +} + +const String M2MNsdlInterface::internal_endpoint_name() const +{ + String iep(""); + if (_nsdl_handle->ep_information_ptr->location_ptr) { + String temp((const char*)_nsdl_handle->ep_information_ptr->location_ptr, + _nsdl_handle->ep_information_ptr->location_len); + // Get last part of the location path. + // In mbed Cloud environment full path is /rd/accountid/internal_endpoint + int location = temp.find_last_of('/') + 1; + iep.append_raw((const char*)_nsdl_handle->ep_information_ptr->location_ptr + location, + _nsdl_handle->ep_information_ptr->location_len - location); + } + return iep; +} + +void M2MNsdlInterface::change_operation_mode(M2MObject *object, M2MBase::Operation operation) +{ + M2MObjectInstanceList instances = object->instances(); + M2MObjectInstanceList::const_iterator inst = instances.begin(); + for (; inst != instances.end(); inst++ ) { + (*inst)->set_operation(operation); + M2MResourceList list = (*inst)->resources(); + if(!list.empty()) { + M2MResourceList::const_iterator it; + it = list.begin(); + for ( ; it != list.end(); it++ ) { + (*it)->set_operation(operation); + } + } + } +} + +void M2MNsdlInterface::set_server_address(const char* server_address) +{ + free(_server_address); + _server_address = M2MBase::alloc_string_copy(server_address); +} + +M2MTimer &M2MNsdlInterface::get_nsdl_execution_timer() +{ + return _nsdl_exceution_timer; +} + +bool M2MNsdlInterface::get_unregister_ongoing() const +{ + return _unregister_ongoing; +} + +bool M2MNsdlInterface::parse_and_send_uri_query_parameters() +{ + bool msg_sent = false; + char *address_copy = M2MBase::alloc_string_copy(_server_address); + if (address_copy) { + char* query = query_string(_server_address); + if (query != NULL) { + int param_count = query_param_count(query); + if (param_count) { + char* uri_query_params[MAX_QUERY_COUNT] = {}; + if (uri_query_parameters(query, uri_query_params, 0)) { + uri_query_parameters((char*)MCC_VERSION, uri_query_params, param_count); + param_count += query_param_count((char*)MCC_VERSION); + + sn_nsdl_clear_coap_resending_queue(_nsdl_handle); + msg_sent = sn_nsdl_register_endpoint(_nsdl_handle,_endpoint,uri_query_params, param_count) != 0; + } + free(_server_address); + _server_address = M2MBase::alloc_string_copy(address_copy); + } + } + free(address_copy); + } + return msg_sent; +} + +void M2MNsdlInterface::claim_mutex() +{ + _connection_handler.claim_mutex(); +} + +void M2MNsdlInterface::release_mutex() +{ + _connection_handler.release_mutex(); +} + +void M2MNsdlInterface::start_nsdl_execution_timer() +{ + tr_debug("M2MNsdlInterface::start_nsdl_execution_timer"); + _nsdl_exceution_timer_running = true; + _nsdl_exceution_timer.stop_timer(); + _nsdl_exceution_timer.start_timer(ONE_SECOND_TIMER * 1000, + M2MTimerObserver::NsdlExecution, + false); +} + +void M2MNsdlInterface::handle_pending_notifications(bool clear) +{ + // TODO! This logic does not work if there are multiple pending notifications. + // CoAP resend queue will fill up and message sending will fail. + // Need to have a better queuing system. + if(!_object_list.empty()) { + M2MObjectList::const_iterator object_iterator; + object_iterator = _object_list.begin(); + // Object level + for ( ; object_iterator != _object_list.end(); object_iterator++ ) { + const M2MObjectInstanceList &object_instance_list = (*object_iterator)->instances(); + // Clears all the pending notifications + if (clear) { + (*object_iterator)->clear_notification_delivery_status(); + // Send all the pending notifications + } else { + M2MReportHandler* reporter = (*object_iterator)->report_handler(); + if (((*object_iterator)->get_notification_delivery_status() == NOTIFICATION_STATUS_SENT || + (*object_iterator)->get_notification_delivery_status() == NOTIFICATION_STATUS_SEND_FAILED) && + reporter && + reporter->is_under_observation()) { + // Send the whole object in case of resend + m2m::Vector<uint16_t> changed_instance_ids; + send_object_observation((*object_iterator), + reporter->observation_number(), + changed_instance_ids, true, true); + } + } + + if(!object_instance_list.empty()) { + M2MObjectInstanceList::const_iterator object_instance_iterator; + object_instance_iterator = object_instance_list.begin(); + // Object instance level + for ( ; object_instance_iterator != object_instance_list.end(); object_instance_iterator++ ) { + // Clears all the pending notifications + if (clear) { + (*object_instance_iterator)->clear_notification_delivery_status(); + // Send all the pending notifications + } else { + M2MReportHandler* reporter = (*object_instance_iterator)->report_handler(); + if (((*object_instance_iterator)->get_notification_delivery_status() == NOTIFICATION_STATUS_SENT || + (*object_instance_iterator)->get_notification_delivery_status() == NOTIFICATION_STATUS_SEND_FAILED) && + reporter && + reporter->is_under_observation()) { + send_object_instance_observation((*object_instance_iterator), reporter->observation_number(), true); + } + } + const M2MResourceList &resource_list = (*object_instance_iterator)->resources(); + if(!resource_list.empty()) { + M2MResourceList::const_iterator resource_iterator; + resource_iterator = resource_list.begin(); + // Resource level + for ( ; resource_iterator != resource_list.end(); resource_iterator++) { + // Clears all the pending notifications + if (clear) { + (*resource_iterator)->clear_notification_delivery_status(); + // Send all the pending notifications + } else { + M2MReportHandler* reporter = (*resource_iterator)->report_handler(); + if (((*resource_iterator)->get_notification_delivery_status() == NOTIFICATION_STATUS_SENT || + (*resource_iterator)->get_notification_delivery_status() == NOTIFICATION_STATUS_SEND_FAILED) && + reporter && + reporter->is_under_observation()) { + send_resource_observation( (*resource_iterator), reporter->observation_number(), true); + } + } + } + } + } + } + } + } +} + +M2MSecurity* M2MNsdlInterface::get_security_object() +{ + return _security; +} + +void M2MNsdlInterface::update_trigger_callback(void */*argument*/) +{ + if (lifetime_value_changed()) { + send_update_registration(_server->resource_value_int(M2MServer::Lifetime)); + } else { + send_update_registration(); + } +} + +bool M2MNsdlInterface::lifetime_value_changed() const +{ + uint64_t value = 0; + if (_endpoint && _endpoint->lifetime_ptr) { + value = atol((const char*)_endpoint->lifetime_ptr); + } + if (_server->resource_value_int(M2MServer::Lifetime) != value) { + return true; + } + return false; +} + +void M2MNsdlInterface::execute_notification_delivery_status_cb(M2MBase* object, int32_t msgid) +{ + if (msgid > 0) { + object->send_notification_delivery_status(*object, NOTIFICATION_STATUS_SENT); + object->set_notification_msgid(msgid); + } else if (msgid == SN_NSDL_RESEND_QUEUE_FULL) { + object->send_notification_delivery_status(*object, NOTIFICATION_STATUS_RESEND_QUEUE_FULL); + } else { + object->send_notification_delivery_status(*object, NOTIFICATION_STATUS_BUILD_ERROR); + } +} + +uint8_t M2MNsdlInterface::find_auto_obs_token(const char *path, uint8_t *token) const +{ + uint8_t token_len = 0; + const String name(path); + M2MBase *object = find_resource(name, 0); + if (object) { + object->get_observation_token(token, token_len); + } + return token_len; +} + +bool M2MNsdlInterface::is_response_to_get_req(const sn_coap_hdr_s *coap_header, get_data_request_s &get_data) +{ + // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. + get_data_request_s *data = (get_data_request_s *)ns_list_get_first(&_get_request_list); + while (data) { + if (memcmp(coap_header->token_ptr, &data->msg_token, sizeof(data->msg_token)) == 0) { + get_data = *data; + return true; + } + data = (get_data_request_s *)ns_list_get_next(&_get_request_list, data); + } + + return false; +} + +void M2MNsdlInterface::free_get_request_list(const sn_coap_hdr_s *coap_header) +{ + // Clean up whole list + if (coap_header == NULL) { + // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. + while (!ns_list_is_empty(&_get_request_list)) { + get_data_request_s* data = (get_data_request_s*)ns_list_get_first(&_get_request_list); + ns_list_remove(&_get_request_list, data); + memory_free(data->uri_path); + memory_free(data); + } + + // Clean just one item from the list + } else { + // ns_list_foreach() replacement since it does not compile with IAR 7.x versions. + get_data_request_s *data = (get_data_request_s *)ns_list_get_first(&_get_request_list); + while (data) { + if (memcmp(coap_header->token_ptr, &data->msg_token, sizeof(data->msg_token)) == 0) { + ns_list_remove(&_get_request_list, data); + memory_free(data->uri_path); + memory_free(data); + return; + } + data = (get_data_request_s *)ns_list_get_next(&_get_request_list, data); + } + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mobject.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mobject.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include <inttypes.h> + +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mconstants.h" +#include "include/m2mtlvserializer.h" +#include "include/m2mtlvdeserializer.h" +#include "include/m2mreporthandler.h" +#include "mbed-trace/mbed_trace.h" +#include "mbed-client/m2mstringbuffer.h" +#include "include/m2mcallbackstorage.h" + +#include <stdlib.h> + +#define BUFFER_SIZE 10 +#define TRACE_GROUP "mClt" + +M2MObject::M2MObject(const String &object_name, char *path, bool external_blockwise_store) +: M2MBase(object_name, + M2MBase::Dynamic, +#ifndef DISABLE_RESOURCE_TYPE + "", +#endif + path, + external_blockwise_store, + false), + _observation_handler(NULL) +{ + M2MBase::set_base_type(M2MBase::Object); + M2MBase::set_operation(M2MBase::GET_ALLOWED); + if(M2MBase::name_id() != -1) { + M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + } +} + +M2MObject::M2MObject(const M2MBase::lwm2m_parameters_s* static_res) +: M2MBase(static_res), +_observation_handler(NULL) +{ + M2MBase::set_operation(M2MBase::GET_ALLOWED); + if(M2MBase::name_id() != -1) { + M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + } +} + +M2MObject::~M2MObject() +{ + if(!_instance_list.empty()) { + + M2MObjectInstanceList::const_iterator it; + it = _instance_list.begin(); + M2MObjectInstance* obj = NULL; + uint16_t index = 0; + for (; it!=_instance_list.end(); it++, index++ ) { + //Free allocated memory for object instances. + obj = *it; + delete obj; + } + + _instance_list.clear(); + } + + free_resources(); +} + +M2MObjectInstance* M2MObject::create_object_instance(uint16_t instance_id) +{ + tr_debug("M2MObject::create_object_instance - id: %d", instance_id); + M2MObjectInstance *instance = NULL; + if(!object_instance(instance_id)) { + char* path = create_path(*this, instance_id); + if (path) { + // Note: the object instance's name contains actually object's name. + instance = new M2MObjectInstance(*this, "", path); + if(instance) { + instance->add_observation_level(observation_level()); + instance->set_instance_id(instance_id); + if(M2MBase::name_id() != -1) { + instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + } + _instance_list.push_back(instance); + } + } + } + return instance; +} + + +M2MObjectInstance* M2MObject::create_object_instance(const lwm2m_parameters_s* s) +{ + tr_debug("M2MObject::create_object_instance - id: %d", s->identifier.instance_id); + M2MObjectInstance *instance = NULL; + if(!object_instance(s->identifier.instance_id)) { + + instance = new M2MObjectInstance(*this, s); + if(instance) { + instance->add_observation_level(observation_level()); + //instance->set_instance_id(instance_id); + //if(M2MBase::name_id() != -1) { + // instance->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + //} + _instance_list.push_back(instance); + } + } + return instance; +} + +bool M2MObject::remove_object_instance(uint16_t inst_id) +{ + tr_debug("M2MObject::remove_object_instance(inst_id %d)", inst_id); + bool success = false; + if(!_instance_list.empty()) { + M2MObjectInstance* obj = NULL; + M2MObjectInstanceList::const_iterator it; + it = _instance_list.begin(); + int pos = 0; + for ( ; it != _instance_list.end(); it++, pos++ ) { + if((*it)->instance_id() == inst_id) { + // Instance found and deleted. + obj = *it; + + _instance_list.erase(pos); + delete obj; + success = true; + break; + } + } + } + return success; +} + +M2MObjectInstance* M2MObject::object_instance(uint16_t inst_id) const +{ + tr_debug("M2MObject::object_instance(inst_id %d)", inst_id); + M2MObjectInstance *obj = NULL; + if(!_instance_list.empty()) { + M2MObjectInstanceList::const_iterator it; + it = _instance_list.begin(); + for ( ; it != _instance_list.end(); it++ ) { + if((*it)->instance_id() == inst_id) { + // Instance found. + obj = *it; + break; + } + } + } + return obj; +} + +const M2MObjectInstanceList& M2MObject::instances() const +{ + return _instance_list; +} + +uint16_t M2MObject::instance_count() const +{ + return (uint16_t)_instance_list.size(); +} + +M2MObservationHandler* M2MObject::observation_handler() const +{ + // XXX: need to check the flag too + return _observation_handler; +} + +void M2MObject::set_observation_handler(M2MObservationHandler *handler) +{ + tr_debug("M2MObject::set_observation_handler - handler: 0x%p", (void*)handler); + _observation_handler = handler; +} + +void M2MObject::add_observation_level(M2MBase::Observation observation_level) +{ + M2MBase::add_observation_level(observation_level); + if(!_instance_list.empty()) { + M2MObjectInstanceList::const_iterator it; + it = _instance_list.begin(); + for ( ; it != _instance_list.end(); it++ ) { + (*it)->add_observation_level(observation_level); + } + } +} + +void M2MObject::remove_observation_level(M2MBase::Observation observation_level) +{ + M2MBase::remove_observation_level(observation_level); + if(!_instance_list.empty()) { + M2MObjectInstanceList::const_iterator it; + it = _instance_list.begin(); + for ( ; it != _instance_list.end(); it++ ) { + (*it)->remove_observation_level(observation_level); + } + } +} + +sn_coap_hdr_s* M2MObject::handle_get_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler) +{ + tr_info("M2MObject::handle_get_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + uint8_t *data = NULL; + uint32_t data_length = 0; + if(received_coap_header) { + // process the GET if we have registered a callback for it + if ((operation() & SN_GRS_GET_ALLOWED) != 0) { + if(coap_response) { + bool content_type_present = false; + bool is_content_type_supported = true; + + if (received_coap_header->options_list_ptr && + received_coap_header->options_list_ptr->accept != COAP_CT_NONE) { + content_type_present = true; + coap_response->content_format = received_coap_header->options_list_ptr->accept; + + } + + // Check if preferred content type is supported + if (content_type_present) { + if (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD && + coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) { + is_content_type_supported = false; + } + } + + if (is_content_type_supported) { + if(!content_type_present && + (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || + M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { + coap_response->content_format = sn_coap_content_format_e(M2MBase::coap_content_type()); + } + + // fill in the CoAP response payload + if(COAP_CONTENT_OMA_TLV_TYPE == coap_response->content_format || + COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_response->content_format) { + set_coap_content_type(coap_response->content_format); + data = M2MTLVSerializer::serialize(_instance_list, data_length); + } + + coap_response->payload_len = data_length; + coap_response->payload_ptr = data; + if(data){ + coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); + if(coap_response->options_list_ptr){ + coap_response->options_list_ptr->max_age = max_age(); + } + if(received_coap_header->options_list_ptr) { + if(received_coap_header->options_list_ptr->observe != -1) { + if (is_observable()) { + uint32_t number = 0; + uint8_t observe_option = 0; + observe_option = received_coap_header->options_list_ptr->observe; + + if(START_OBSERVATION == observe_option) { + // If the observe length is 0 means register for observation. + if(received_coap_header->options_list_ptr->observe != -1) { + number = received_coap_header->options_list_ptr->observe; + } + + // If the observe value is 0 means register for observation. + if(number == 0) { + tr_info("M2MObject::handle_get_request - put resource under observation"); + set_under_observation(true,observation_handler); + add_observation_level(M2MBase::O_Attribute); + send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED); + if(coap_response->options_list_ptr){ + coap_response->options_list_ptr->observe = observation_number(); + } + } + + if(received_coap_header->token_ptr) { + set_observation_token(received_coap_header->token_ptr, + received_coap_header->token_len); + } + } else if (STOP_OBSERVATION == observe_option) { + tr_info("M2MObject::handle_get_request - stops observation"); + // If the observe options_list_ptr->observe value is 1 means de-register from observation. + set_under_observation(false,NULL); + remove_observation_level(M2MBase::O_Attribute); + send_notification_delivery_status(*this, NOTIFICATION_STATUS_UNSUBSCRIBED); + } + msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + } + else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; // Content format not supported + } + } else { + tr_error("M2MObject::handle_get_request() - Content-Type %d not supported", coap_response->content_format); + msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; + } + } + }else { + tr_error("M2MResource::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + // Operation is not allowed. + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + return coap_response; +} + +sn_coap_hdr_s* M2MObject::handle_put_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler */*observation_handler*/, + bool &/*execute_value_updated*/) +{ + tr_info("M2MObject::handle_put_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 + sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + if(received_coap_header) { + if(received_coap_header->content_format != COAP_CT_NONE) { + set_coap_content_type(received_coap_header->content_format); + } + if(received_coap_header->options_list_ptr && + received_coap_header->options_list_ptr->uri_query_ptr) { + char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, + received_coap_header->options_list_ptr->uri_query_len); + + if (query){ + tr_info("M2MObject::handle_put_request() - query %s", query); + // if anything was updated, re-initialize the stored notification attributes + if (!handle_observation_attribute(query)){ + tr_debug("M2MObject::handle_put_request() - Invalid query"); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 + } + free(query); + } + } else { + tr_error("M2MObject::handle_put_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Empty URI_QUERY"); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + return coap_response; +} + + +sn_coap_hdr_s* M2MObject::handle_post_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated, + sn_nsdl_addr_s *) +{ + tr_info("M2MObject::handle_post_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 + // process the POST if we have registered a callback for it + sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + + if(received_coap_header) { + if ((operation() & SN_GRS_POST_ALLOWED) != 0) { + if(received_coap_header->content_format != COAP_CT_NONE) { + set_coap_content_type(received_coap_header->content_format); + } + if(received_coap_header->payload_ptr) { + tr_debug("M2MObject::handle_post_request() - Update Object with new values"); + uint16_t coap_content_type = 0; + bool content_type_present = false; + if(received_coap_header->content_format != COAP_CT_NONE) { + content_type_present = true; + if(coap_response) { + coap_content_type = received_coap_header->content_format; + } + } // if(received_coap_header->content_format) + if(!content_type_present && + (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || + M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { + coap_content_type = M2MBase::coap_content_type(); + } + + tr_debug("M2MObject::handle_post_request() - Request Content-type: %d", coap_content_type); + + if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type || + COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type) { + set_coap_content_type(coap_content_type); + uint32_t instance_id = 0; + // Check next free instance id + for(instance_id = 0; instance_id <= MAX_UNINT_16_COUNT; instance_id++) { + if(NULL == object_instance(instance_id)) { + break; + } + if(instance_id == MAX_UNINT_16_COUNT) { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + break; + } + } + if(COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) { + bool is_obj_instance = false; + bool obj_instance_exists = false; + is_obj_instance = M2MTLVDeserializer::is_object_instance(received_coap_header->payload_ptr); + if (is_obj_instance) { + instance_id = M2MTLVDeserializer::instance_id(received_coap_header->payload_ptr); + tr_debug("M2MObject::handle_post_request() - instance id in TLV: %" PRIu32, instance_id); + // Check if instance id already exists + if (object_instance(instance_id)){ + obj_instance_exists = true; + } + } + if (!obj_instance_exists && coap_response) { + M2MObjectInstance *obj_instance = create_object_instance(instance_id); + if(obj_instance) { + obj_instance->set_operation(M2MBase::GET_PUT_ALLOWED); + } + + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + if(is_obj_instance) { + tr_debug("M2MObject::handle_post_request() - TLV data contains ObjectInstance"); + error = M2MTLVDeserializer::deserialise_object_instances(received_coap_header->payload_ptr, + received_coap_header->payload_len, + *this, + M2MTLVDeserializer::Post); + } else if(obj_instance && + (M2MTLVDeserializer::is_resource(received_coap_header->payload_ptr) || + M2MTLVDeserializer::is_multiple_resource(received_coap_header->payload_ptr))) { + tr_debug("M2MObject::handle_post_request() - TLV data contains Resources"); + error = M2MTLVDeserializer::deserialize_resources(received_coap_header->payload_ptr, + received_coap_header->payload_len, + *obj_instance, + M2MTLVDeserializer::Post); + } else { + error = M2MTLVDeserializer::NotValid; + } + switch(error) { + case M2MTLVDeserializer::None: + if(observation_handler) { + execute_value_updated = true; + } + coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); + + if (coap_response->options_list_ptr) { + + StringBuffer<MAX_OBJECT_PATH_NAME> obj_name; + + if (obj_name.ensure_space(M2MBase::resource_name_length() + (1 + 5 + 1))) { + obj_name.append(M2MBase::name()); + obj_name.append('/'); + obj_name.append_int(instance_id); + + coap_response->options_list_ptr->location_path_len = obj_name.get_size(); + coap_response->options_list_ptr->location_path_ptr = + alloc_copy((uint8_t*)obj_name.c_str(), obj_name.get_size()); + // todo: else return error + } + } + // todo: else return error + msg_code = COAP_MSG_CODE_RESPONSE_CREATED; + break; + case M2MTLVDeserializer::NotAllowed: + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + break; + case M2MTLVDeserializer::NotValid: + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + break; + case M2MTLVDeserializer::NotFound: + msg_code = COAP_MSG_CODE_RESPONSE_NOT_FOUND; + break; + case M2MTLVDeserializer::OutOfMemory: + msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; + break; + } + + } else { + tr_error("M2MObject::handle_post_request() - COAP_MSG_CODE_RESPONSE_BAD_REQUEST"); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + } + } else { + msg_code =COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; + } // if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) + } else { + tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_BAD_REQUEST - Missing Payload"); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // + } + } else { // if ((object->operation() & SN_GRS_POST_ALLOWED) != 0) + tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 + } + } else { //if(received_coap_header) + tr_error("M2MObject::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 + } + + if(coap_response) { + coap_response->msg_code = msg_code; + } + return coap_response; +} + +void M2MObject::notification_update(uint16_t obj_instance_id) +{ + tr_debug("M2MObject::notification_update - id: %d", obj_instance_id); + M2MReportHandler *report_handler = M2MBase::report_handler(); + if(report_handler && is_under_observation()) { + report_handler->set_notification_trigger(obj_instance_id); + } +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mobjectinstance.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mobjectinstance.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,783 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mobservationhandler.h" +#include "mbed-client/m2mstring.h" +#include "mbed-client/m2mstringbuffer.h" +#include "include/m2mtlvserializer.h" +#include "include/m2mtlvdeserializer.h" +#include "include/m2mreporthandler.h" +#include "mbed-trace/mbed_trace.h" +#include "include/m2mcallbackstorage.h" +#include <stdlib.h> + +#define BUFFER_SIZE 10 +#define TRACE_GROUP "mClt" + +M2MObjectInstance::M2MObjectInstance(M2MObject& parent, + const String &resource_type, + char *path, + bool external_blockwise_store) +: M2MBase("", + M2MBase::Dynamic, +#ifndef DISABLE_RESOURCE_TYPE + resource_type, +#endif + path, + external_blockwise_store, + false), + _parent(parent) +{ + M2MBase::set_base_type(M2MBase::ObjectInstance); + M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + M2MBase::set_operation(M2MBase::GET_ALLOWED); +} + +M2MObjectInstance::M2MObjectInstance(M2MObject& parent, const lwm2m_parameters_s* static_res) +: M2MBase(static_res), _parent(parent) +{ + M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + M2MBase::set_operation(M2MBase::GET_ALLOWED); +} + +M2MObjectInstance::~M2MObjectInstance() +{ + if(!_resource_list.empty()) { + M2MResource* res = NULL; + M2MResourceList::const_iterator it; + it = _resource_list.begin(); + for (; it!=_resource_list.end(); it++ ) { + //Free allocated memory for resources. + res = *it; + delete res; + } + _resource_list.clear(); + } + + free_resources(); +} + +// TBD, ResourceType to the base class struct?? TODO! +M2MResource* M2MObjectInstance::create_static_resource(const lwm2m_parameters_s* static_res, + M2MResourceInstance::ResourceType type) +{ + tr_debug("M2MObjectInstance::create_static_resource(lwm2m_parameters_s resource_name %s)", static_res->identifier.name); + M2MResource *res = NULL; + if (validate_string_length(static_res->identifier.name, 1, MAX_ALLOWED_STRING_LENGTH) == false) { + return res; + } + if(!resource(static_res->identifier.name)) { + res = new M2MResource(*this, static_res, convert_resource_type(type)); + if(res) { + res->add_observation_level(observation_level()); + //if (multiple_instance) { + //res->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + //} + _resource_list.push_back(res); + } + } + return res; +} + +M2MResource* M2MObjectInstance::create_static_resource(const String &resource_name, + const String &resource_type, + M2MResourceInstance::ResourceType type, + const uint8_t *value, + const uint8_t value_length, + bool multiple_instance, + bool external_blockwise_store) +{ + tr_debug("M2MObjectInstance::create_static_resource(resource_name %s)",resource_name.c_str()); + M2MResource *res = NULL; + if (validate_string_length(resource_name, 1, MAX_ALLOWED_STRING_LENGTH) == false) { + return res; + } + if(!resource(resource_name)) { + char *path = create_path(*this, resource_name.c_str()); + + if (path) { + res = new M2MResource(*this, resource_name, M2MBase::Static, resource_type, convert_resource_type(type), + value, value_length, path, + multiple_instance, external_blockwise_store); + if(res) { + res->add_observation_level(observation_level()); + if (multiple_instance) { + res->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + } + _resource_list.push_back(res); + } + } + } + return res; +} + +M2MResource* M2MObjectInstance::create_dynamic_resource(const lwm2m_parameters_s* static_res, + M2MResourceInstance::ResourceType type, + bool observable) +{ + tr_debug("M2MObjectInstance::create_dynamic_resource(resource_name %s)", static_res->identifier.name); + M2MResource *res = NULL; + + if (validate_string_length(static_res->identifier.name, 1, MAX_ALLOWED_STRING_LENGTH) == false) { + return res; + } + if(!resource(static_res->identifier.name)) { + res = new M2MResource(*this, static_res, convert_resource_type(type)); + if(res) { + //if (multiple_instance) { // TODO! + // res->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE); + //} + res->add_observation_level(observation_level()); + _resource_list.push_back(res); + } + } + return res; +} + +M2MResource* M2MObjectInstance::create_dynamic_resource(const String &resource_name, + const String &resource_type, + M2MResourceInstance::ResourceType type, + bool observable, + bool multiple_instance, + bool external_blockwise_store) +{ + tr_debug("M2MObjectInstance::create_dynamic_resource(resource_name %s)",resource_name.c_str()); + M2MResource *res = NULL; + if (validate_string_length(resource_name, 1, MAX_ALLOWED_STRING_LENGTH) == false) { + return res; + } + if(!resource(resource_name)) { + char *path = create_path(*this, resource_name.c_str()); + if (path) { + res = new M2MResource(*this, resource_name, M2MBase::Dynamic, resource_type, convert_resource_type(type), + observable, path, + multiple_instance, external_blockwise_store); + if(res) { + if (multiple_instance) { + res->set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + } + res->add_observation_level(observation_level()); + _resource_list.push_back(res); + } + } + } + return res; +} + +M2MResourceInstance* M2MObjectInstance::create_static_resource_instance(const String &resource_name, + const String &resource_type, + M2MResourceInstance::ResourceType type, + const uint8_t *value, + const uint8_t value_length, + uint16_t instance_id, + bool external_blockwise_store) +{ + tr_debug("M2MObjectInstance::create_static_resource_instance(resource_name %s)",resource_name.c_str()); + M2MResourceInstance *instance = NULL; + if (validate_string_length(resource_name, 1, MAX_ALLOWED_STRING_LENGTH) == false) { + + return instance; + } + M2MResource *res = resource(resource_name); + if(!res) { + char *path = create_path(*this, resource_name.c_str()); + if (path) { + res = new M2MResource(*this, resource_name, M2MBase::Static, resource_type, convert_resource_type(type), + value, value_length, path, + true, external_blockwise_store); + _resource_list.push_back(res); + res->set_operation(M2MBase::GET_ALLOWED); + res->set_observable(false); + res->set_register_uri(false); + } + } + if(res && res->supports_multiple_instances()&& (res->resource_instance(instance_id) == NULL)) { + char *path = M2MBase::create_path(*res, instance_id); + if (path) { + instance = new M2MResourceInstance(*res, "", M2MBase::Static, resource_type, convert_resource_type(type), + value, value_length, + path, external_blockwise_store,true); + if(instance) { + instance->set_operation(M2MBase::GET_ALLOWED); + instance->set_instance_id(instance_id); + res->add_resource_instance(instance); + } + } + } + return instance; +} + +M2MResourceInstance* M2MObjectInstance::create_dynamic_resource_instance(const String &resource_name, + const String &resource_type, + M2MResourceInstance::ResourceType type, + bool observable, + uint16_t instance_id, + bool external_blockwise_store) +{ + tr_debug("M2MObjectInstance::create_dynamic_resource_instance(resource_name %s)",resource_name.c_str()); + M2MResourceInstance *instance = NULL; + if (validate_string_length(resource_name, 1, MAX_ALLOWED_STRING_LENGTH) == false) { + return instance; + } + M2MResource *res = resource(resource_name); + if(!res) { + char *path = create_path(*this, resource_name.c_str()); + if (path) { + res = new M2MResource(*this, resource_name, M2MBase::Dynamic, resource_type, convert_resource_type(type), + false, path, true, external_blockwise_store); + _resource_list.push_back(res); + res->set_register_uri(false); + res->set_operation(M2MBase::GET_ALLOWED); + } + } + if (res && res->supports_multiple_instances() && (res->resource_instance(instance_id) == NULL)) { + char *path = create_path(*res, instance_id); + if (path) { + instance = new M2MResourceInstance(*res, "", M2MBase::Dynamic, resource_type, convert_resource_type(type), + path, external_blockwise_store,true); + if(instance) { + instance->set_operation(M2MBase::GET_ALLOWED); + instance->set_observable(observable); + instance->set_instance_id(instance_id); + res->add_resource_instance(instance); + } + } + } + return instance; +} + +bool M2MObjectInstance::remove_resource(const String &resource_name) +{ + return remove_resource(resource_name.c_str()); +} + +bool M2MObjectInstance::remove_resource(const char *resource_name) +{ + tr_debug("M2MObjectInstance::remove_resource(resource_name %s)", resource_name); + + bool success = false; + if(!_resource_list.empty()) { + M2MResource* res = NULL; + M2MResourceList::const_iterator it; + it = _resource_list.begin(); + int pos = 0; + for ( ; it != _resource_list.end(); it++, pos++ ) { + if(strcmp((*it)->name(), resource_name) == 0) { + // Resource found and deleted. + res = *it; + delete res; + _resource_list.erase(pos); + success = true; + break; + } + } + } + return success; +} + +bool M2MObjectInstance::remove_resource_instance(const String &resource_name, + uint16_t inst_id) +{ + tr_debug("M2MObjectInstance::remove_resource_instance(resource_name %s inst_id %d)", + resource_name.c_str(), inst_id); + bool success = false; + M2MResource *res = resource(resource_name); + if(res) { + M2MResourceInstanceList list = res->resource_instances(); + M2MResourceInstanceList::const_iterator it; + it = list.begin(); + for ( ; it != list.end(); it++) { + if((*it)->instance_id() == inst_id) { + success = res->remove_resource_instance(inst_id); + if(res->resource_instance_count() == 0) { + M2MResourceList::const_iterator itr; + itr = _resource_list.begin(); + int pos = 0; + for ( ; itr != _resource_list.end(); itr++, pos++ ) { + if(strcmp((*itr)->name(),resource_name.c_str()) == 0) { + delete res; + _resource_list.erase(pos); + break; + } + } + } + break; + } + } + } + return success; +} + +M2MResource* M2MObjectInstance::resource(const String &resource_name) const +{ + return resource(resource_name.c_str()); +} + +M2MResource* M2MObjectInstance::resource(const char *resource_name) const +{ + M2MResource *res = NULL; + if(!_resource_list.empty()) { + M2MResourceList::const_iterator it; + it = _resource_list.begin(); + for (; it!=_resource_list.end(); it++ ) { + if(strcmp((*it)->name(), resource_name) == 0) { + res = *it; + break; + } + } + } + return res; +} + +const M2MResourceList& M2MObjectInstance::resources() const +{ + return _resource_list; +} + +uint16_t M2MObjectInstance::resource_count() const +{ + uint16_t count = 0; + if(!_resource_list.empty()) { + M2MResourceList::const_iterator it; + it = _resource_list.begin(); + for ( ; it != _resource_list.end(); it++ ) { + if((*it)->supports_multiple_instances()) { + count += (*it)->resource_instance_count(); + } else { + count++; + } + } + } + return count; +} + +uint16_t M2MObjectInstance::resource_count(const String& resource) const +{ + + return resource_count(resource.c_str()); +} + +uint16_t M2MObjectInstance::resource_count(const char *resource) const +{ + uint16_t count = 0; + if(!_resource_list.empty()) { + M2MResourceList::const_iterator it; + it = _resource_list.begin(); + for ( ; it != _resource_list.end(); it++ ) { + if(strcmp((*it)->name(), resource) == 0) { + if((*it)->supports_multiple_instances()) { + count += (*it)->resource_instance_count(); + } else { + count++; + } + } + } + } + return count; +} + +M2MObservationHandler* M2MObjectInstance::observation_handler() const +{ + // XXX: need to check the flag too + return _parent.observation_handler(); +} + +void M2MObjectInstance::set_observation_handler(M2MObservationHandler *handler) +{ + // XXX: need to set the flag too + _parent.set_observation_handler(handler); +} + +void M2MObjectInstance::add_observation_level(M2MBase::Observation observation_level) +{ + M2MBase::add_observation_level(observation_level); + if(!_resource_list.empty()) { + M2MResourceList::const_iterator it; + it = _resource_list.begin(); + for ( ; it != _resource_list.end(); it++ ) { + (*it)->add_observation_level(observation_level); + } + } +} + +void M2MObjectInstance::remove_observation_level(M2MBase::Observation observation_level) +{ + M2MBase::remove_observation_level(observation_level); + if(!_resource_list.empty()) { + M2MResourceList::const_iterator it; + it = _resource_list.begin(); + for ( ; it != _resource_list.end(); it++ ) { + (*it)->remove_observation_level(observation_level); + } + } +} + +sn_coap_hdr_s* M2MObjectInstance::handle_get_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler) +{ + tr_info("M2MObjectInstance::handle_get_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + uint8_t * data = NULL; + uint32_t data_length = 0; + + if (received_coap_header) { + // process the GET if we have registered a callback for it + if ((operation() & SN_GRS_GET_ALLOWED) != 0) { + if (coap_response) { + bool content_type_present = false; + bool is_content_type_supported = true; + + if (received_coap_header->options_list_ptr && + received_coap_header->options_list_ptr->accept != COAP_CT_NONE) { + content_type_present = true; + coap_response->content_format = received_coap_header->options_list_ptr->accept; + + } + + // Check if preferred content type is supported + if (content_type_present) { + if (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD && + coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) { + is_content_type_supported = false; + } + } + + if (is_content_type_supported) { + if (!content_type_present && + (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || + M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { + coap_response->content_format = sn_coap_content_format_e(M2MBase::coap_content_type()); + } + + // fill in the CoAP response payload + if (COAP_CONTENT_OMA_TLV_TYPE == coap_response->content_format || + COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_response->content_format) { + set_coap_content_type(coap_response->content_format); + data = M2MTLVSerializer::serialize(_resource_list, data_length); + } + + coap_response->payload_len = data_length; + coap_response->payload_ptr = data; + + if (data) { + coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); + if (coap_response->options_list_ptr) { + coap_response->options_list_ptr->max_age = max_age(); + } + + if (received_coap_header->options_list_ptr) { + if (received_coap_header->options_list_ptr->observe != -1) { + if (is_observable()) { + uint32_t number = 0; + uint8_t observe_option = 0; + observe_option = received_coap_header->options_list_ptr->observe; + if (START_OBSERVATION == observe_option) { + // If the observe length is 0 means register for observation. + if (received_coap_header->options_list_ptr->observe != -1) { + number = received_coap_header->options_list_ptr->observe; + } + + // If the observe value is 0 means register for observation. + if (number == 0) { + tr_info("M2MObjectInstance::handle_get_request - put resource under observation"); + set_under_observation(true,observation_handler); + add_observation_level(M2MBase::OI_Attribute); + send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED); + if (coap_response->options_list_ptr) { + coap_response->options_list_ptr->observe = observation_number(); + } + } + + if (received_coap_header->token_ptr) { + set_observation_token(received_coap_header->token_ptr, + received_coap_header->token_len); + } + + } else if (STOP_OBSERVATION == observe_option) { + tr_info("M2MObjectInstance::handle_get_request - stops observation"); + set_under_observation(false,NULL); + remove_observation_level(M2MBase::OI_Attribute); + send_notification_delivery_status(*this, NOTIFICATION_STATUS_UNSUBSCRIBED); + } + msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + } + else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; // Content format not supported + } + } else { + tr_error("M2MObjectInstance::handle_get_request() - Content-type: %d not supported", coap_response->content_format); + msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; + } + } + } else { + tr_error("M2MObjectInstance::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + // Operation is not allowed. + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + return coap_response; +} + +sn_coap_hdr_s* M2MObjectInstance::handle_put_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &/*execute_value_updated*/) +{ + tr_info("M2MObjectInstance::handle_put_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 + sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code);; + if(received_coap_header) { + uint16_t coap_content_type = 0; + bool content_type_present = false; + + if(received_coap_header->content_format != COAP_CT_NONE) { + content_type_present = true; + set_coap_content_type(received_coap_header->content_format); + if(coap_response) { + coap_content_type = received_coap_header->content_format; + } + } + if(received_coap_header->options_list_ptr && + received_coap_header->options_list_ptr->uri_query_ptr) { + char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, + received_coap_header->options_list_ptr->uri_query_len); + if (query){ + tr_info("M2MObjectInstance::handle_put_request() - query %s", query); + // if anything was updated, re-initialize the stored notification attributes + if (!handle_observation_attribute(query)){ + tr_debug("M2MObjectInstance::handle_put_request() - Invalid query"); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 + } else { + msg_code =COAP_MSG_CODE_RESPONSE_CHANGED; + } + free(query); + } + } else if ((operation() & SN_GRS_PUT_ALLOWED) != 0) { + if(!content_type_present && + (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || + M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { + coap_content_type = M2MBase::coap_content_type(); + } + + tr_debug("M2MObjectInstance::handle_put_request() - Request Content-type: %d", coap_content_type); + + if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type || + COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type ) { + set_coap_content_type(coap_content_type); + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + if(received_coap_header->payload_ptr) { + error = M2MTLVDeserializer::deserialize_resources( + received_coap_header->payload_ptr, + received_coap_header->payload_len, *this, + M2MTLVDeserializer::Put); + switch(error) { + case M2MTLVDeserializer::None: + if(observation_handler) { + observation_handler->value_updated(this); + } + msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; + break; + case M2MTLVDeserializer::NotFound: + msg_code = COAP_MSG_CODE_RESPONSE_NOT_FOUND; + break; + case M2MTLVDeserializer::NotAllowed: + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + break; + case M2MTLVDeserializer::NotValid: + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + break; + case M2MTLVDeserializer::OutOfMemory: + msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; + break; + } + } + } else { + msg_code =COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; + } // if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) + } else { + // Operation is not allowed. + tr_error("M2MObjectInstance::handle_put_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + return coap_response; +} + +sn_coap_hdr_s* M2MObjectInstance::handle_post_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated, + sn_nsdl_addr_s *) +{ + tr_info("M2MObjectInstance::handle_post_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 + sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + if(received_coap_header) { + if ((operation() & SN_GRS_POST_ALLOWED) != 0) { + uint16_t coap_content_type = 0; + bool content_type_present = false; + if(received_coap_header->content_format != COAP_CT_NONE) { + set_coap_content_type(received_coap_header->content_format); + content_type_present = true; + if(coap_response) { + coap_content_type = received_coap_header->content_format; + } + } + if(!content_type_present && + (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || + M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { + coap_content_type = M2MBase::coap_content_type(); + } + + tr_debug("M2MObjectInstance::handle_post_request() - Request Content-type: %d", coap_content_type); + + if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type || + COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type) { + set_coap_content_type(coap_content_type); + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + error = M2MTLVDeserializer::deserialize_resources( + received_coap_header->payload_ptr, + received_coap_header->payload_len, *this, + M2MTLVDeserializer::Post); + + uint16_t instance_id = M2MTLVDeserializer::instance_id(received_coap_header->payload_ptr); + switch(error) { + case M2MTLVDeserializer::None: + if(observation_handler) { + execute_value_updated = true; + } + coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); + + if (coap_response->options_list_ptr) { + + StringBuffer<MAX_PATH_SIZE_3> obj_name; + if(!build_path(obj_name, _parent.name(), M2MBase::instance_id(), instance_id)) { + msg_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR; + break; + } + + coap_response->options_list_ptr->location_path_len = obj_name.get_size(); + coap_response->options_list_ptr->location_path_ptr = + alloc_string_copy((uint8_t*)obj_name.c_str(), + coap_response->options_list_ptr->location_path_len); + // todo: handle allocation error + } + msg_code = COAP_MSG_CODE_RESPONSE_CREATED; + break; + case M2MTLVDeserializer::NotAllowed: + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + break; + case M2MTLVDeserializer::NotValid: + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + break; + case M2MTLVDeserializer::NotFound: + msg_code = COAP_MSG_CODE_RESPONSE_NOT_FOUND; + break; + case M2MTLVDeserializer::OutOfMemory: + msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; + break; + default: + break; + } + } else { + msg_code =COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; + } // if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) + } else { + // Operation is not allowed. + tr_error("M2MObjectInstance::handle_post_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + return coap_response; +} + +void M2MObjectInstance::notification_update(M2MBase::Observation observation_level) +{ + tr_debug("M2MObjectInstance::notification_update() - level(%d)", observation_level); + if((M2MBase::O_Attribute & observation_level) == M2MBase::O_Attribute) { + tr_debug("M2MObjectInstance::notification_update() - object callback"); + _parent.notification_update(instance_id()); + } + if((M2MBase::OI_Attribute & observation_level) == M2MBase::OI_Attribute) { + tr_debug("M2MObjectInstance::notification_update() - object instance callback"); + M2MReportHandler *report_handler = M2MBase::report_handler(); + if(report_handler && is_under_observation()) { + report_handler->set_notification_trigger(); + } + + } +} + +M2MBase::DataType M2MObjectInstance::convert_resource_type(M2MResourceInstance::ResourceType type) +{ + M2MBase::DataType data_type = M2MBase::OBJLINK; + switch(type) { + case M2MResourceInstance::STRING: + data_type = M2MBase::STRING; + break; + case M2MResourceInstance::INTEGER: + data_type = M2MBase::INTEGER; + break; + case M2MResourceInstance::FLOAT: + data_type = M2MBase::FLOAT; + break; + case M2MResourceInstance::OPAQUE: + data_type = M2MBase::OPAQUE; + break; + case M2MResourceInstance::BOOLEAN: + data_type = M2MBase::BOOLEAN; + break; + case M2MResourceInstance::TIME: + data_type = M2MBase::TIME; + break; + case M2MResourceInstance::OBJLINK: + data_type = M2MBase::OBJLINK; + break; + } + return data_type; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mreporthandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mreporthandler.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// fixup the compilation on ARMCC for PRId32 +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include "mbed-client/m2mreportobserver.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mtimer.h" +#include "include/m2mreporthandler.h" +#include "mbed-trace/mbed_trace.h" +#include <string.h> +#include <stdlib.h> + +#define TRACE_GROUP "mClt" + +M2MReportHandler::M2MReportHandler(M2MReportObserver &observer) +: _observer(observer), + _is_under_observation(false), + _observation_level(M2MBase::None), + _attribute_state(0), + _token_length(0), + _notify(false), + _pmin_exceeded(false), + _pmax_exceeded(false), + _observation_number(0), + _pmin_timer(*this), + _pmax_timer(*this), + _token(NULL), + _pmax(-1.0f), + _pmin(1.0f), + _current_value(0.0f), + _gt(0.0f), + _lt(0.0f), + _st(0.0f), + _high_step(0.0f), + _low_step(0.0f), + _last_value(-1.0f) +{ + tr_debug("M2MReportHandler::M2MReportHandler()"); +} + +M2MReportHandler::~M2MReportHandler() +{ + tr_debug("M2MReportHandler::~M2MReportHandler()"); + free(_token); +} + +void M2MReportHandler::set_under_observation(bool observed) +{ + tr_debug("M2MReportHandler::set_under_observation(observed %d)", (int)observed); + + _is_under_observation = observed; + + stop_timers(); + if(observed) { + handle_timers(); + } + else { + set_default_values(); + } +} + +void M2MReportHandler::set_value(float value) +{ + tr_debug("M2MReportHandler::set_value() - current %f, last %f", value, _last_value); + _current_value = value; + if(_current_value != _last_value) { + tr_debug("M2MReportHandler::set_value() - UNDER OBSERVATION"); + if (check_threshold_values()) { + schedule_report(); + } + else { + tr_debug("M2MReportHandler::set_value - value not in range"); + _notify = false; + _last_value = _current_value; + if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt || + (_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt || + (_attribute_state & M2MReportHandler::St) == M2MReportHandler::St) { + tr_debug("M2MReportHandler::set_value - stop pmin timer"); + _pmin_timer.stop_timer(); + _pmin_exceeded = true; + } + } + _high_step = _current_value + _st; + _low_step = _current_value - _st; + } +} + +void M2MReportHandler::set_notification_trigger(uint16_t obj_instance_id) +{ + tr_debug("M2MReportHandler::set_notification_trigger(): %d", obj_instance_id); + // Add to array if not there yet + m2m::Vector<uint16_t>::const_iterator it; + it = _changed_instance_ids.begin(); + bool found = false; + for ( ; it != _changed_instance_ids.end(); it++) { + if ((*it) == obj_instance_id) { + found = true; + break; + } + } + if (!found) { + _changed_instance_ids.push_back(obj_instance_id); + } + + _current_value = 0.0f; + _last_value = 1.0f; + schedule_report(); +} + +bool M2MReportHandler::parse_notification_attribute(const char *query, + M2MBase::BaseType type, + M2MResourceInstance::ResourceType resource_type) +{ + tr_debug("M2MReportHandler::parse_notification_attribute(Query %s, Base type %d)", query, (int)type); + bool success = false; + const char* sep_pos = strchr(query, '&'); + const char* rest = query; + if( sep_pos != NULL ){ + char query_options[5][20]; + float pmin = _pmin; + float pmax = _pmax; + float lt = _lt; + float gt = _gt; + float st = _st; + float high = _high_step; + float low = _low_step; + uint8_t attr = _attribute_state; + + memset(query_options, 0, sizeof(query_options[0][0]) * 5 * 20); + uint8_t num_options = 0; + while( sep_pos != NULL && num_options < 5){ + size_t len = (size_t)(sep_pos-rest); + if( len > 19 ){ + len = 19; + } + memcpy(query_options[num_options], rest, len); + sep_pos++; + rest = sep_pos; + sep_pos = strchr(rest, '&'); + num_options++; + } + if( num_options < 5 && strlen(rest) > 0){ + size_t len = (size_t)strlen(rest); + if( len > 19 ){ + len = 19; + } + memcpy(query_options[num_options++], rest, len); + } + + for (int option = 0; option < num_options; option++) { + success = set_notification_attribute(query_options[option],type, resource_type); + if (!success) { + tr_debug("M2MReportHandler::parse_notification_attribute - break"); + break; + } + } + + if(success) { + success = check_attribute_validity(); + } + else { + tr_debug("M2MReportHandler::parse_notification_attribute - not valid query"); + _pmin = pmin; + _pmax = pmax; + _st = st; + _lt = lt; + _gt = gt; + _high_step = high; + _low_step = low; + _attribute_state = attr; + } + } + else { + if(set_notification_attribute(query, type, resource_type)) { + success = check_attribute_validity(); + } + } + + return success; +} + +void M2MReportHandler::timer_expired(M2MTimerObserver::Type type) +{ + switch(type) { + case M2MTimerObserver::PMinTimer: { + tr_debug("M2MReportHandler::timer_expired - PMIN"); + _pmin_exceeded = true; + if (_notify || + (_pmin > 0 && + (_attribute_state & M2MReportHandler::Pmax) != M2MReportHandler::Pmax)){ + report(); + } + } + break; + case M2MTimerObserver::PMaxTimer: { + tr_debug("M2MReportHandler::timer_expired - PMAX"); + _pmax_exceeded = true; + if (_pmin_exceeded || + (_attribute_state & M2MReportHandler::Pmin) != M2MReportHandler::Pmin ) { + report(); + } + } + break; + default: + break; + } +} + +bool M2MReportHandler::set_notification_attribute(const char* option, + M2MBase::BaseType type, + M2MResourceInstance::ResourceType resource_type) +{ + tr_debug("M2MReportHandler::set_notification_attribute()"); + bool success = false; + char attribute[20]; + char value[20]; + memset(&attribute, 0, 20); + memset(&value, 0, 20); + + const char* pos = strstr(option, EQUAL); + if( pos != NULL ){ + memcpy(attribute, option, (size_t)(pos-option)); + pos++; + memcpy(value, pos, strlen(pos)); + }else{ + memcpy(attribute, option, (size_t)strlen(option) + 1); + } + + if (strlen(value)) { + if (strcmp(attribute, PMIN) == 0) { + _pmin = atoi(value); + success = true; + _attribute_state |= M2MReportHandler::Pmin; + tr_info("M2MReportHandler::set_notification_attribute %s to %" PRId32, attribute, _pmin); + } + else if(strcmp(attribute, PMAX) == 0) { + _pmax = atoi(value); + success = true; + _attribute_state |= M2MReportHandler::Pmax; + tr_info("M2MReportHandler::set_notification_attribute %s to %" PRId32, attribute, _pmax); + } + else if(strcmp(attribute, GT) == 0 && + (M2MBase::Resource == type)){ + _gt = atof(value); + success = true; + _attribute_state |= M2MReportHandler::Gt; + tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _gt); + } + else if(strcmp(attribute, LT) == 0 && + (M2MBase::Resource == type)){ + _lt = atof(value); + success = true; + _attribute_state |= M2MReportHandler::Lt; + tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _lt); + } + else if((strcmp(attribute, ST_SIZE) == 0 || (strcmp(attribute, STP) == 0)) + && (M2MBase::Resource == type)){ + _st = atof(value); + success = true; + _high_step = _current_value + _st; + _low_step = _current_value - _st; + _attribute_state |= M2MReportHandler::St; + tr_info("M2MReportHandler::set_notification_attribute %s to %f", attribute, _st); + } + // Return false if try to set gt,lt or st when the resource type is something else than numerical + if ((resource_type != M2MResourceInstance::INTEGER && + resource_type != M2MResourceInstance::FLOAT) && + ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt || + (_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt || + (_attribute_state & M2MReportHandler::St) == M2MReportHandler::St)) { + tr_debug("M2MReportHandler::set_notification_attribute - not numerical resource"); + success = false; + } + } + return success; +} + +void M2MReportHandler::schedule_report() +{ + tr_debug("M2MReportHandler::schedule_report()"); + _notify = true; + if ((_attribute_state & M2MReportHandler::Pmin) != M2MReportHandler::Pmin || + _pmin_exceeded) { + report(); + } +} + +void M2MReportHandler::report() +{ + tr_debug("M2MReportHandler::report()"); + if(_current_value != _last_value && _notify) { + if (_pmin_exceeded) { + tr_debug("M2MReportHandler::report()- send with PMIN expiration"); + } else { + tr_debug("M2MReportHandler::report()- send with VALUE change"); + } + _pmin_exceeded = false; + _pmax_exceeded = false; + _notify = false; + _observation_number++; + if(_observation_number == 1) { + // Increment the observation number by 1 if it is already 1 because CoAP specification has reserved 1 for DEREGISTER notification + _observation_number++; + } + _observer.observation_to_be_sent(_changed_instance_ids, observation_number()); + _changed_instance_ids.clear(); + _pmax_timer.stop_timer(); + } + else { + if (_pmax_exceeded) { + tr_debug("M2MReportHandler::report()- send with PMAX expiration"); + _observation_number++; + if(_observation_number == 1) { + // Increment the observation number by 1 if it is already 1 because CoAP specification has reserved 1 for DEREGISTER notification + _observation_number++; + } + _observer.observation_to_be_sent(_changed_instance_ids, observation_number(),true); + _changed_instance_ids.clear(); + } + else { + tr_debug("M2MReportHandler::report()- no need to send"); + } + } + handle_timers(); + _last_value = _current_value; +} + +void M2MReportHandler::handle_timers() +{ + tr_debug("M2MReportHandler::handle_timers()"); + uint64_t time_interval = 0; + if ((_attribute_state & M2MReportHandler::Pmin) == M2MReportHandler::Pmin) { + if (_pmin == _pmax) { + _pmin_exceeded = true; + } else { + _pmin_exceeded = false; + time_interval = (uint64_t) ((uint64_t)_pmin * 1000); + tr_debug("M2MReportHandler::handle_timers() - Start PMIN interval: %d", (int)time_interval); + _pmin_timer.start_timer(time_interval, + M2MTimerObserver::PMinTimer, + true); + } + } + if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax) { + if (_pmax > 0) { + time_interval = (uint64_t) ((uint64_t)_pmax * 1000); + tr_debug("M2MReportHandler::handle_timers() - Start PMAX interval: %d", (int)time_interval); + _pmax_timer.start_timer(time_interval, + M2MTimerObserver::PMaxTimer, + true); + } + } +} + +bool M2MReportHandler::check_attribute_validity() const +{ + bool success = true; + if ((_attribute_state & M2MReportHandler::Pmax) == M2MReportHandler::Pmax && + ((_pmax >= -1.0) && (_pmin > _pmax))) { + success = false; + } + float low = _lt + 2 * _st; + if ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt && + (low >= _gt)) { + success = false; + } + return success; +} + +void M2MReportHandler::stop_timers() +{ + tr_debug("M2MReportHandler::stop_timers()"); + + _pmin_exceeded = false; + _pmin_timer.stop_timer(); + + _pmax_exceeded = false; + _pmax_timer.stop_timer(); + + tr_debug("M2MReportHandler::stop_timers() - out"); +} + +void M2MReportHandler::set_default_values() +{ + tr_debug("M2MReportHandler::set_default_values"); + _pmax = -1.0; + _pmin = 1.0; + _gt = 0.0f; + _lt = 0.0f; + _st = 0.0f; + _high_step = 0.0f; + _low_step = 0.0f; + _pmin_exceeded = false; + _pmax_exceeded = false; + _last_value = -1.0f; + _attribute_state = 0; + _changed_instance_ids.clear(); +} + +bool M2MReportHandler::check_threshold_values() const +{ + tr_debug("M2MReportHandler::check_threshold_values"); + tr_debug("Current value: %f", _current_value); + tr_debug("High step: %f", _high_step); + tr_debug("Low step: %f", _low_step); + tr_debug("Less than: %f", _lt); + tr_debug("Greater than: %f", _gt); + tr_debug("Step: %f", _st); + bool can_send = false; + // Check step condition + if ((_attribute_state & M2MReportHandler::St) == M2MReportHandler::St) { + if ((_current_value >= _high_step || + _current_value <= _low_step)) { + can_send = true; + } + else { + if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt || + (_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt ) { + can_send = check_gt_lt_params(); + } + else { + can_send = false; + } + } + } + else { + can_send = check_gt_lt_params(); + } + tr_debug("M2MReportHandler::check_threshold_values - value in range = %d", (int)can_send); + return can_send; +} + +bool M2MReportHandler::check_gt_lt_params() const +{ + tr_debug("M2MReportHandler::check_gt_lt_params"); + bool can_send = false; + // GT & LT set. + if ((_attribute_state & (M2MReportHandler::Lt | M2MReportHandler::Gt)) + == (M2MReportHandler::Lt | M2MReportHandler::Gt)) { + if (_current_value > _gt || _current_value < _lt) { + can_send = true; + } + else { + can_send = false; + } + } + // Only LT + else if ((_attribute_state & M2MReportHandler::Lt) == M2MReportHandler::Lt && + (_attribute_state & M2MReportHandler::Gt) == 0 ) { + if (_current_value < _lt) { + can_send = true; + } + else { + can_send = false; + } + } + // Only GT + else if ((_attribute_state & M2MReportHandler::Gt) == M2MReportHandler::Gt && + (_attribute_state & M2MReportHandler::Lt) == 0 ) { + if (_current_value > _gt) { + can_send = true; + } + else { + can_send = false; + } + } + // GT & LT not set. + else { + can_send = true; + } + tr_debug("M2MReportHandler::check_gt_lt_params - value in range = %d", (int)can_send); + return can_send; +} + +uint8_t M2MReportHandler::attribute_flags() const +{ + return _attribute_state; +} + +void M2MReportHandler::set_observation_token(const uint8_t *token, const uint8_t length) +{ + free(_token); + _token = NULL; + _token_length = 0; + + if( token != NULL && length > 0 ) { + _token = alloc_string_copy((uint8_t *)token, length); + if(_token) { + _token_length = length; + } + } +} + +void M2MReportHandler::get_observation_token(uint8_t *token, uint8_t &token_length) const +{ + memcpy(token, _token, _token_length); + token_length = _token_length; +} + +uint16_t M2MReportHandler::observation_number() const +{ + return _observation_number; +} + +void M2MReportHandler::add_observation_level(M2MBase::Observation obs_level) +{ + _observation_level = (M2MBase::Observation)(_observation_level | obs_level); +} + +void M2MReportHandler::remove_observation_level(M2MBase::Observation obs_level) +{ + _observation_level = (M2MBase::Observation)(_observation_level & ~obs_level); +} + +M2MBase::Observation M2MReportHandler::observation_level() const +{ + return _observation_level; +} + +bool M2MReportHandler::is_under_observation() const +{ + return _is_under_observation; +} + +uint8_t* M2MReportHandler::alloc_string_copy(const uint8_t* source, uint32_t size) +{ + assert(source != NULL); + + uint8_t* result = (uint8_t*)malloc(size + 1); + if (result) { + memcpy(result, source, size); + result[size] = '\0'; + } + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mresource.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mresource.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mobservationhandler.h" +#include "include/m2mreporthandler.h" +#include "include/m2mtlvserializer.h" +#include "include/m2mtlvdeserializer.h" +#include "mbed-trace/mbed_trace.h" + +#include <stdlib.h> + +#define TRACE_GROUP "mClt" + +M2MResource::M2MResource(M2MObjectInstance &parent, + const String &resource_name, + M2MBase::Mode resource_mode, + const String &resource_type, + M2MBase::DataType type, + const uint8_t *value, + const uint8_t value_length, + char *path, + bool multiple_instance, + bool external_blockwise_store) +: M2MResourceBase(resource_name, resource_mode, resource_type, type, value, value_length, + path, external_blockwise_store, multiple_instance), + _parent(parent) +#ifndef DISABLE_DELAYED_RESPONSE + ,_delayed_token(NULL), + _delayed_token_len(0), + _delayed_response(false) +#endif +{ + M2MBase::set_base_type(M2MBase::Resource); + M2MBase::set_operation(M2MBase::GET_ALLOWED); + M2MBase::set_observable(false); + if (multiple_instance) { + M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + } + +} + +M2MResource::M2MResource(M2MObjectInstance &parent, + const lwm2m_parameters_s* s, + M2MBase::DataType type) +: M2MResourceBase(s, type), + _parent(parent) +#ifndef DISABLE_DELAYED_RESPONSE + ,_delayed_token(NULL), + _delayed_token_len(0), + _delayed_response(false) +#endif +{ + // verify, that the client has hardcoded proper type to the structure + assert(base_type() == M2MBase::Resource); +} + +M2MResource::M2MResource(M2MObjectInstance &parent, + const String &resource_name, + M2MBase::Mode resource_mode, + const String &resource_type, + M2MBase::DataType type, + bool observable, + char *path, + bool multiple_instance, + bool external_blockwise_store) +: M2MResourceBase(resource_name, resource_mode, resource_type, type, + path, + external_blockwise_store,multiple_instance), + _parent(parent) +#ifndef DISABLE_DELAYED_RESPONSE + ,_delayed_token(NULL), + _delayed_token_len(0), + _delayed_response(false) +#endif +{ + M2MBase::set_base_type(M2MBase::Resource); + M2MBase::set_operation(M2MBase::GET_PUT_ALLOWED); + M2MBase::set_observable(observable); + if (multiple_instance) { + M2MBase::set_coap_content_type(COAP_CONTENT_OMA_TLV_TYPE_OLD); + } +} + + +M2MResource::~M2MResource() +{ + if(!_resource_instance_list.empty()) { + M2MResourceInstance* res = NULL; + M2MResourceInstanceList::const_iterator it; + it = _resource_instance_list.begin(); + for (; it!=_resource_instance_list.end(); it++ ) { + //Free allocated memory for resources. + res = *it; + delete res; + } + _resource_instance_list.clear(); + } +#ifndef DISABLE_DELAYED_RESPONSE + free(_delayed_token); +#endif + + free_resources(); +} + +bool M2MResource::supports_multiple_instances() const +{ + M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); + return param->multiple_instance; +} + +#ifndef DISABLE_DELAYED_RESPONSE +void M2MResource::set_delayed_response(bool delayed_response) +{ + _delayed_response = delayed_response; +} + +bool M2MResource::send_delayed_post_response() +{ + bool success = false; + if(_delayed_response) { + success = true; + // At least on some unit tests the resource object is not fully constructed, which would + // cause issues if the observation_handler is NULL. So do the check before dereferencing pointer. + M2MObservationHandler* obs = observation_handler(); + if (obs) { + obs->send_delayed_response(this); + } + } + return success; +} + +void M2MResource::get_delayed_token(uint8_t *&token, uint8_t &token_length) +{ + token_length = 0; + if(token) { + free(token); + token = NULL; + } + if(_delayed_token && _delayed_token_len > 0) { + token = alloc_copy(_delayed_token, _delayed_token_len); + if(token) { + token_length = _delayed_token_len; + } + } +} +#endif + +bool M2MResource::remove_resource_instance(uint16_t inst_id) +{ + tr_debug("M2MResource::remove_resource(inst_id %d)", inst_id); + bool success = false; + if(!_resource_instance_list.empty()) { + M2MResourceInstance* res = NULL; + M2MResourceInstanceList::const_iterator it; + it = _resource_instance_list.begin(); + int pos = 0; + for ( ; it != _resource_instance_list.end(); it++, pos++ ) { + if(((*it)->instance_id() == inst_id)) { + // Resource found and deleted. + res = *it; + delete res; + _resource_instance_list.erase(pos); + success = true; + break; + } + } + } + return success; +} + +M2MResourceInstance* M2MResource::resource_instance(uint16_t inst_id) const +{ + tr_debug("M2MResource::resource(resource_name inst_id %d)", inst_id); + M2MResourceInstance *res = NULL; + if(!_resource_instance_list.empty()) { + M2MResourceInstanceList::const_iterator it; + it = _resource_instance_list.begin(); + for ( ; it != _resource_instance_list.end(); it++ ) { + if(((*it)->instance_id() == inst_id)) { + // Resource found. + res = *it; + break; + } + } + } + return res; +} + +const M2MResourceInstanceList& M2MResource::resource_instances() const +{ + return _resource_instance_list; +} + +uint16_t M2MResource::resource_instance_count() const +{ + return (uint16_t)_resource_instance_list.size(); +} + +#ifndef DISABLE_DELAYED_RESPONSE +bool M2MResource::delayed_response() const +{ + return _delayed_response; +} +#endif + +M2MObservationHandler* M2MResource::observation_handler() const +{ + const M2MObjectInstance& parent_object_instance = get_parent_object_instance(); + + // XXX: need to check the flag too + return parent_object_instance.observation_handler(); +} + +void M2MResource::set_observation_handler(M2MObservationHandler *handler) +{ + M2MObjectInstance& parent_object_instance = get_parent_object_instance(); + + // XXX: need to set the flag too + parent_object_instance.set_observation_handler(handler); +} + +bool M2MResource::handle_observation_attribute(const char *query) +{ + tr_debug("M2MResource::handle_observation_attribute - is_under_observation(%d)", is_under_observation()); + bool success = false; + M2MReportHandler *handler = M2MBase::report_handler(); + if (!handler) { + handler = M2MBase::create_report_handler(); + } + + if (handler) { + success = handler->parse_notification_attribute(query, + M2MBase::base_type(), resource_instance_type()); + if (success) { + if (is_under_observation()) { + handler->set_under_observation(true); + } + } + else { + handler->set_default_values(); + } + + if (success) { + if(!_resource_instance_list.empty()) { + M2MResourceInstanceList::const_iterator it; + it = _resource_instance_list.begin(); + for ( ; it != _resource_instance_list.end(); it++ ) { + M2MReportHandler *report_handler = (*it)->report_handler(); + if(report_handler && is_under_observation()) { + report_handler->set_notification_trigger(); + } + } + } + } + } + return success; +} + +void M2MResource::add_observation_level(M2MBase::Observation observation_level) +{ + M2MBase::add_observation_level(observation_level); + if(!_resource_instance_list.empty()) { + M2MResourceInstanceList::const_iterator inst; + inst = _resource_instance_list.begin(); + for ( ; inst != _resource_instance_list.end(); inst++ ) { + (*inst)->add_observation_level(observation_level); + } + } +} + +void M2MResource::remove_observation_level(M2MBase::Observation observation_level) +{ + M2MBase::remove_observation_level(observation_level); + if(!_resource_instance_list.empty()) { + M2MResourceInstanceList::const_iterator inst; + inst = _resource_instance_list.begin(); + for ( ; inst != _resource_instance_list.end(); inst++ ) { + (*inst)->remove_observation_level(observation_level); + } + } +} + +void M2MResource::add_resource_instance(M2MResourceInstance *res) +{ + tr_debug("M2MResource::add_resource_instance()"); + if(res) { + _resource_instance_list.push_back(res); + } +} + +sn_coap_hdr_s* M2MResource::handle_get_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler) +{ + tr_info("M2MResource::handle_get_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + sn_coap_hdr_s * coap_response = NULL; + if(supports_multiple_instances()) { + coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + if(received_coap_header) { + // process the GET if we have registered a callback for it + if ((operation() & SN_GRS_GET_ALLOWED) != 0) { + if(coap_response) { + bool content_type_present = false; + bool is_content_type_supported = true; + + if (received_coap_header->options_list_ptr && + received_coap_header->options_list_ptr->accept != COAP_CT_NONE) { + content_type_present = true; + coap_response->content_format = received_coap_header->options_list_ptr->accept; + } + + // Check if preferred content type is supported + if (content_type_present) { + if (coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE_OLD && + coap_response->content_format != COAP_CONTENT_OMA_TLV_TYPE) { + is_content_type_supported = false; + } + } + + if (is_content_type_supported) { + if(!content_type_present && + (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || + M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { + coap_response->content_format = sn_coap_content_format_e(M2MBase::coap_content_type()); + } + + tr_debug("M2MResource::handle_get_request() - Request Content-type: %d", coap_response->content_format); + + uint8_t *data = NULL; + uint32_t data_length = 0; + // fill in the CoAP response payload + if(COAP_CONTENT_OMA_TLV_TYPE == coap_response->content_format || + COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_response->content_format) { + set_coap_content_type(coap_response->content_format); + data = M2MTLVSerializer::serialize(this, data_length); + } + + coap_response->payload_len = data_length; + coap_response->payload_ptr = data; + + coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); + if (coap_response->options_list_ptr) { + coap_response->options_list_ptr->max_age = max_age(); + } + + if(received_coap_header->options_list_ptr) { + if(received_coap_header->options_list_ptr->observe != -1) { + if (is_observable()) { + uint32_t number = 0; + uint8_t observe_option = 0; + observe_option = received_coap_header->options_list_ptr->observe; + if(START_OBSERVATION == observe_option) { + // If the observe length is 0 means register for observation. + if(received_coap_header->options_list_ptr->observe != -1) { + number = received_coap_header->options_list_ptr->observe; + } + + // If the observe value is 0 means register for observation. + if(number == 0) { + tr_info("M2MResource::handle_get_request - put resource under observation"); + M2MResourceInstanceList::const_iterator it; + it = _resource_instance_list.begin(); + for (; it!=_resource_instance_list.end(); it++ ) { + (*it)->add_observation_level(M2MBase::R_Attribute); + } + set_under_observation(true,observation_handler); + M2MBase::add_observation_level(M2MBase::R_Attribute); + send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED); + if (coap_response->options_list_ptr) { + coap_response->options_list_ptr->observe = observation_number(); + } + } + + if(received_coap_header->token_ptr) { + set_observation_token(received_coap_header->token_ptr, + received_coap_header->token_len); + } + + } else if (STOP_OBSERVATION == observe_option) { + tr_info("M2MResource::handle_get_request - stops observation"); + set_under_observation(false,NULL); + M2MBase::remove_observation_level(M2MBase::R_Attribute); + send_notification_delivery_status(*this,NOTIFICATION_STATUS_UNSUBSCRIBED); + M2MResourceInstanceList::const_iterator it; + it = _resource_instance_list.begin(); + for (; it!=_resource_instance_list.end(); it++ ) { + (*it)->remove_observation_level(M2MBase::R_Attribute); + } + } + msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } + } + } else { + tr_error("M2MResource::handle_get_request() - Content-Type %d not supported", coap_response->content_format); + msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; + } + } + } else { + tr_error("M2MResource::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + // Operation is not allowed. + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + } else { + coap_response = M2MResourceBase::handle_get_request(nsdl, + received_coap_header, + observation_handler); + } + return coap_response; +} + +sn_coap_hdr_s* M2MResource::handle_put_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated) +{ + tr_info("M2MResource::handle_put_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 + sn_coap_hdr_s * coap_response = NULL; + if(supports_multiple_instances()) { + coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + // process the PUT if we have registered a callback for it + if(received_coap_header) { + uint16_t coap_content_type = 0; + bool content_type_present = false; + if(received_coap_header->content_format != COAP_CT_NONE && coap_response) { + content_type_present = true; + coap_content_type = received_coap_header->content_format; + } + if(received_coap_header->options_list_ptr && + received_coap_header->options_list_ptr->uri_query_ptr) { + char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, + received_coap_header->options_list_ptr->uri_query_len); + if (query){ + msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; + tr_info("M2MResource::handle_put_request() - query %s", query); + // if anything was updated, re-initialize the stored notification attributes + if (!handle_observation_attribute(query)){ + tr_debug("M2MResource::handle_put_request() - Invalid query"); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; // 4.00 + } + free(query); + } + } else if ((operation() & SN_GRS_PUT_ALLOWED) != 0) { + if(!content_type_present && + (M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE || + M2MBase::coap_content_type() == COAP_CONTENT_OMA_TLV_TYPE_OLD)) { + coap_content_type = COAP_CONTENT_OMA_TLV_TYPE; + } + + tr_debug("M2MResource::handle_put_request() - Request Content-type: %d", coap_content_type); + + if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type || + COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type) { + set_coap_content_type(coap_content_type); + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + error = M2MTLVDeserializer::deserialize_resource_instances(received_coap_header->payload_ptr, + received_coap_header->payload_len, + *this, + M2MTLVDeserializer::Put); + switch(error) { + case M2MTLVDeserializer::None: + if(observation_handler) { + String value = ""; + if (received_coap_header->uri_path_ptr != NULL && + received_coap_header->uri_path_len > 0) { + + value.append_raw((char*)received_coap_header->uri_path_ptr,received_coap_header->uri_path_len); + } + execute_value_updated = true; + } + msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; + break; + case M2MTLVDeserializer::NotFound: + msg_code = COAP_MSG_CODE_RESPONSE_NOT_FOUND; + break; + case M2MTLVDeserializer::NotAllowed: + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + break; + case M2MTLVDeserializer::NotValid: + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + break; + case M2MTLVDeserializer::OutOfMemory: + msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; + break; + } + } else { + msg_code =COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; + } // if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type) + } else { + // Operation is not allowed. + tr_error("M2MResource::handle_put_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + } else { + coap_response = M2MResourceBase::handle_put_request(nsdl, + received_coap_header, + observation_handler, + execute_value_updated); + } + return coap_response; +} + + +sn_coap_hdr_s* M2MResource::handle_post_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler */*observation_handler*/, + bool &/*execute_value_updated*/, + sn_nsdl_addr_s *address) +{ + tr_info("M2MResource::handle_post_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 + sn_coap_hdr_s * coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + + // process the POST if we have registered a callback for it + if(received_coap_header) { + if ((operation() & SN_GRS_POST_ALLOWED) != 0) { + M2MResource::M2MExecuteParameter exec_params(object_name(), name(), object_instance_id()); + + uint16_t coap_content_type = 0; + if(received_coap_header->payload_ptr) { + if(received_coap_header->content_format != COAP_CT_NONE) { + coap_content_type = received_coap_header->content_format; + } + + if(coap_content_type == COAP_CT_TEXT_PLAIN) { + exec_params._value = received_coap_header->payload_ptr; + if (exec_params._value) { + exec_params._value_length = received_coap_header->payload_len; + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; + } + } + if(COAP_MSG_CODE_RESPONSE_CHANGED == msg_code) { + tr_debug("M2MResource::handle_post_request - Execute resource function"); +#ifndef DISABLE_DELAYED_RESPONSE + if (coap_response) { + if(_delayed_response) { + msg_code = COAP_MSG_CODE_EMPTY; + coap_response->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; + coap_response->msg_code = msg_code; + coap_response->msg_id = received_coap_header->msg_id; + if(received_coap_header->token_len) { + free(_delayed_token); + _delayed_token = NULL; + _delayed_token_len = 0; + _delayed_token = alloc_copy(received_coap_header->token_ptr, received_coap_header->token_len); + if(_delayed_token) { + _delayed_token_len = received_coap_header->token_len; + } + sn_nsdl_send_coap_message(nsdl, address, coap_response); + } + } else { + #endif + uint32_t length = 0; + get_value(coap_response->payload_ptr, length); + coap_response->payload_len = length; + #ifndef DISABLE_DELAYED_RESPONSE + } + } +#endif + execute(&exec_params); + } + + } else { // if ((object->operation() & SN_GRS_POST_ALLOWED) != 0) + tr_error("M2MResource::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.05 + } + } else { //if(object && received_coap_header) + tr_error("M2MResource::handle_post_request - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; // 4.01 + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + return coap_response; +} + +M2MObjectInstance& M2MResource::get_parent_object_instance() const +{ + return _parent; +} + +uint16_t M2MResource::object_instance_id() const +{ + const M2MObjectInstance& parent_object_instance = get_parent_object_instance(); + return parent_object_instance.instance_id(); +} + +M2MResource& M2MResource::get_parent_resource() const +{ + return (M2MResource&)*this; +} + +const char* M2MResource::object_name() const +{ + const M2MObjectInstance& parent_object_instance = _parent; + const M2MObject& parent_object = parent_object_instance.get_parent_object(); + + return parent_object.name(); +} + +#ifdef MEMORY_OPTIMIZED_API +M2MResource::M2MExecuteParameter::M2MExecuteParameter(const char *object_name, const char *resource_name, + uint16_t object_instance_id) : +_object_name(object_name), +_resource_name(resource_name), +_value(NULL), +_value_length(0), +_object_instance_id(object_instance_id) +{ +} +#else +M2MResource::M2MExecuteParameter::M2MExecuteParameter(const String &object_name, const String &resource_name, + uint16_t object_instance_id) : +_object_name(object_name), +_resource_name(resource_name), +_value(NULL), +_value_length(0), +_object_instance_id(object_instance_id) +{ +} +#endif + +// These could be actually changed to be inline ones, as it would likely generate +// smaller code at application side. + +const uint8_t *M2MResource::M2MExecuteParameter::get_argument_value() const +{ + return _value; +} + +uint16_t M2MResource::M2MExecuteParameter::get_argument_value_length() const +{ + return _value_length; +} + +#ifdef MEMORY_OPTIMIZED_API +const char* M2MResource::M2MExecuteParameter::get_argument_object_name() const +{ + return _object_name; +} + +const char* M2MResource::M2MExecuteParameter::get_argument_resource_name() const +{ + return _resource_name; +} +#else +const String& M2MResource::M2MExecuteParameter::get_argument_object_name() const +{ + return _object_name; +} + +const String& M2MResource::M2MExecuteParameter::get_argument_resource_name() const +{ + return _resource_name; +} +#endif + +uint16_t M2MResource::M2MExecuteParameter::get_argument_object_instance_id() const +{ + return _object_instance_id; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mresourcebase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mresourcebase.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,783 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Needed for PRIu64 on FreeRTOS +#include <stdio.h> +// Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include <stdlib.h> +#include "mbed-client/m2mresourcebase.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mobservationhandler.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "include/m2mcallbackstorage.h" +#include "include/m2mreporthandler.h" +#include "include/nsdllinker.h" +#include "include/m2mtlvserializer.h" +#include "mbed-client/m2mblockmessage.h" +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "mClt" + +M2MResourceBase::M2MResourceBase( + const String &res_name, + M2MBase::Mode resource_mode, + const String &resource_type, + M2MBase::DataType type, + char* path, + bool external_blockwise_store, + bool multiple_instance) +: M2MBase(res_name, + resource_mode, +#ifndef DISABLE_RESOURCE_TYPE + resource_type, +#endif + path, + external_blockwise_store, + multiple_instance, + type) +#ifndef DISABLE_BLOCK_MESSAGE + ,_block_message_data(NULL), +#endif + _notification_status(M2MResourceBase::INIT) +{ +} + +M2MResourceBase::M2MResourceBase( + const String &res_name, + M2MBase::Mode resource_mode, + const String &resource_type, + M2MBase::DataType type, + const uint8_t *value, + const uint8_t value_length, + char* path, + bool external_blockwise_store, + bool multiple_instance) +: M2MBase(res_name, + resource_mode, +#ifndef DISABLE_RESOURCE_TYPE + resource_type, +#endif + path, + external_blockwise_store, + multiple_instance, + type) +#ifndef DISABLE_BLOCK_MESSAGE + ,_block_message_data(NULL), +#endif + _notification_status(M2MResourceBase::INIT) +{ + M2MBase::set_base_type(M2MBase::ResourceInstance); + if( value != NULL && value_length > 0 ) { + sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); + res->resource = alloc_string_copy(value, value_length); + res->resourcelen = value_length; + } +} + +M2MResourceBase::M2MResourceBase( + const lwm2m_parameters_s* s, + M2MBase::DataType /*type*/) +: M2MBase(s) +#ifndef DISABLE_BLOCK_MESSAGE + ,_block_message_data(NULL), +#endif + _notification_status(M2MResourceBase::INIT) +{ + // we are not there yet for this check as this is called from M2MResource(): assert(base_type() == M2MBase::ResourceInstance); +} + +M2MResourceBase::~M2MResourceBase() +{ + execute_callback* callback = (execute_callback*)M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); + delete callback; + + M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); +#ifndef DISABLE_BLOCK_MESSAGE + incoming_block_message_callback *in_callback = (incoming_block_message_callback*)M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); + delete in_callback; + + outgoing_block_message_callback *out_callback = (outgoing_block_message_callback*)M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); + delete out_callback; +#endif + + notification_sent_callback *notif_callback = (notification_sent_callback*)M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); + delete notif_callback; + + M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); + + notification_status_callback *notif_status_callback = (notification_status_callback*)M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); + delete notif_status_callback; + + M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); + +#ifndef DISABLE_BLOCK_MESSAGE + delete _block_message_data; +#endif +} + +M2MResourceBase::ResourceType M2MResourceBase::resource_instance_type() const +{ + M2MBase::lwm2m_parameters_s* param = M2MBase::get_lwm2m_parameters(); + M2MBase::DataType type = param->data_type; + return convert_data_type(type); +} + + +bool M2MResourceBase::set_execute_function(execute_callback callback) +{ + execute_callback* old_callback = (execute_callback*)M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); + delete old_callback; + // XXX: create a copy of the copy of callback object. Perhaps it would better to + // give a reference as parameter and just store that, as it would save some memory. + execute_callback* new_callback = new execute_callback(callback); + + return M2MCallbackStorage::add_callback(*this, new_callback, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); +} + +bool M2MResourceBase::set_execute_function(execute_callback_2 callback) +{ + M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); + + return M2MCallbackStorage::add_callback(*this, (void*)callback, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); +} + +void M2MResourceBase::clear_value() +{ + tr_debug("M2MResourceBase::clear_value"); + sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); + free(res->resource); + res->resource = NULL; + res->resourcelen = 0; + + report(); +} + +bool M2MResourceBase::set_value(int64_t value) +{ + bool success; + // max len of "-9223372036854775808" plus zero termination + char buffer[20+1]; + uint32_t size = m2m::itoa_c(value, buffer); + + success = set_value((const uint8_t*)buffer, size); + + return success; +} + +bool M2MResourceBase::set_value(const uint8_t *value, + const uint32_t value_length) +{ + tr_debug("M2MResourceBase::set_value()"); + bool success = false; + bool changed = has_value_changed(value,value_length); + if( value != NULL && value_length > 0 ) { + sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); + free(res->resource); + res->resource = NULL; + res->resourcelen = 0; + res->resource = alloc_string_copy(value, value_length); + if(res->resource) { + success = true; + res->resourcelen = value_length; + if (changed) { + report_value_change(); + } + } + } + return success; +} + +bool M2MResourceBase::set_value_raw(uint8_t *value, + const uint32_t value_length) + +{ + tr_debug("M2MResourceBase::set_value_raw()"); + bool success = false; + bool changed = has_value_changed(value,value_length); + if( value != NULL && value_length > 0 ) { + success = true; + sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); + free(res->resource); + res->resource = value; + res->resourcelen = value_length; + if (changed) { + report_value_change(); + } + } + return success; +} + +void M2MResourceBase::report() +{ + M2MBase::Observation observation_level = M2MBase::observation_level(); + tr_debug("M2MResourceBase::report() - level %d", observation_level); + + // We must combine the parent object/objectinstance/resource observation information + // when determining if there is observation set or not. + M2MObjectInstance& object_instance = get_parent_resource().get_parent_object_instance(); + int parent_observation_level = (int)object_instance.observation_level(); + + parent_observation_level |= (int)object_instance.get_parent_object().observation_level(); + parent_observation_level |= (int)get_parent_resource().observation_level(); + parent_observation_level |= (int)observation_level; + + tr_debug("M2MResourceBase::report() - combined level %d", parent_observation_level); + + if((M2MBase::O_Attribute & parent_observation_level) == M2MBase::O_Attribute || + (M2MBase::OI_Attribute & parent_observation_level) == M2MBase::OI_Attribute) { + tr_debug("M2MResourceBase::report() -- object/instance level"); + M2MObjectInstance& object_instance = get_parent_resource().get_parent_object_instance(); + object_instance.notification_update((M2MBase::Observation)parent_observation_level); + } + + if(M2MBase::Dynamic == mode() && + (M2MBase::R_Attribute & parent_observation_level) == M2MBase::R_Attribute) { + tr_debug("M2MResourceBase::report() - resource level"); + + if (((resource_instance_type() != M2MResourceBase::STRING) && + (resource_instance_type() != M2MResourceBase::OPAQUE)) && + (observation_level != M2MBase::None)) { + M2MReportHandler *report_handler = M2MBase::report_handler(); + if (report_handler && is_observable()) { + sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); + if(res->resource) { + report_handler->set_value(atof((const char*)res->resource)); + } else { + report_handler->set_value(0); + } + } + } + else { + if (base_type() == M2MBase::ResourceInstance) { + const M2MResource& parent_resource = get_parent_resource(); + M2MReportHandler *report_handler = parent_resource.report_handler(); + if(report_handler && parent_resource.is_observable()) { + report_handler->set_notification_trigger(parent_resource.get_parent_object_instance().instance_id()); + } + } + } + } else if(M2MBase::Static == mode()) { + M2MObservationHandler *obs_handler = observation_handler(); + if(obs_handler) { + obs_handler->value_updated(this); + } + } else { + if (is_observable()) { + tr_warn("M2MResourceBase::report() - resource %s is observable but not yet subscribed!", uri_path()); + } + tr_debug("M2MResourceBase::report() - mode = %d, is_observable = %d", mode(), is_observable()); + } +} + +bool M2MResourceBase::has_value_changed(const uint8_t* value, const uint32_t value_len) +{ + bool changed = false; + sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); + + if(value_len != res->resourcelen) { + changed = true; + } else if(value && !res->resource) { + changed = true; + } else if(res->resource && !value) { + changed = true; + } else { + if (res->resource) { + if (memcmp(value, res->resource, res->resourcelen) != 0) { + changed = true; + } + } + } + return changed; +} + +void M2MResourceBase::report_value_change() +{ + if (resource_instance_type() == M2MResourceBase::STRING || + resource_instance_type() == M2MResourceBase::OPAQUE) { + M2MReportHandler *report_handler = M2MBase::report_handler(); + if(report_handler && is_under_observation()) { + report_handler->set_notification_trigger(); + } + } + report(); +} + +void M2MResourceBase::execute(void *arguments) +{ + // XXX: this line is expected by seven testcases and until this code hits master branch + // the testcases can not be modified and we need to print the false information too. + tr_debug("M2MResourceBase::execute"); + + execute_callback* callback = (execute_callback*)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback); + + if (callback) { + (*callback)(arguments); + } + + execute_callback_2 callback2 = (execute_callback_2)M2MCallbackStorage::get_callback(*this, M2MCallbackAssociation::M2MResourceInstanceExecuteCallback2); + if (callback2) { + (*callback2)(arguments); + } +} + +void M2MResourceBase::get_value(uint8_t *&value, uint32_t &value_length) +{ + value_length = 0; + if(value) { + free(value); + value = NULL; + } + sn_nsdl_dynamic_resource_parameters_s* res = get_nsdl_resource(); + if(res->resource && res->resourcelen > 0) { + value = alloc_string_copy(res->resource, res->resourcelen); + if(value) { + value_length = res->resourcelen; + } + } +} + +int64_t M2MResourceBase::get_value_int() const +{ + int64_t value_int = 0; + + // XXX: this relies on having a zero terminated value?! + const char *value_string = (char *)value(); + if (value_string) { + value_int = atoll(value_string); + } + return value_int; +} + +String M2MResourceBase::get_value_string() const +{ + // XXX: do a better constructor to avoid pointless malloc + String value; + if (get_nsdl_resource()->resource) { + value.append_raw((char*)get_nsdl_resource()->resource, get_nsdl_resource()->resourcelen); + } + return value; +} + +uint8_t* M2MResourceBase::value() const +{ + return get_nsdl_resource()->resource; +} + +uint32_t M2MResourceBase::value_length() const +{ + return get_nsdl_resource()->resourcelen; +} + +sn_coap_hdr_s* M2MResourceBase::handle_get_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler) +{ + tr_info("M2MResourceBase::handle_get_request()"); + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + if(received_coap_header) { + // process the GET if we have registered a callback for it + if ((operation() & SN_GRS_GET_ALLOWED) != 0) { + if(coap_response) { + bool content_type_present = false; + if(received_coap_header->options_list_ptr && + received_coap_header->options_list_ptr->accept != COAP_CT_NONE) { + content_type_present = true; + coap_response->content_format = received_coap_header->options_list_ptr->accept; + } + if(!content_type_present) { + if(resource_instance_type() == M2MResourceInstance::OPAQUE) { + coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_OPAQUE_TYPE); + } else { + coap_response->content_format = sn_coap_content_format_e(COAP_CONTENT_OMA_PLAIN_TEXT_TYPE); + } + } + // fill in the CoAP response payload + coap_response->payload_ptr = NULL; + uint32_t payload_len = 0; +#ifndef DISABLE_BLOCK_MESSAGE + //If handler exists it means that resource value is stored in application side + if (block_message() && block_message()->is_block_message()) { + outgoing_block_message_callback* outgoing_block_message_cb = (outgoing_block_message_callback*)M2MCallbackStorage::get_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); + if (outgoing_block_message_cb) { + String name = ""; + if (received_coap_header->uri_path_ptr != NULL && + received_coap_header->uri_path_len > 0) { + name.append_raw((char *)received_coap_header->uri_path_ptr, + received_coap_header->uri_path_len); + } + (*outgoing_block_message_cb)(name, coap_response->payload_ptr, payload_len); + } + } else { +#endif + if (coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE || + coap_response->content_format == COAP_CONTENT_OMA_TLV_TYPE_OLD) { + set_coap_content_type(coap_response->content_format); + coap_response->payload_ptr = M2MTLVSerializer::serialize(&get_parent_resource(), payload_len); + } else { + get_value(coap_response->payload_ptr,payload_len); + } +#ifndef DISABLE_BLOCK_MESSAGE + } +#endif + tr_debug("M2MResourceBase::handle_get_request() - Request Content-type: %d", coap_response->content_format); + coap_response->payload_len = payload_len; + coap_response->options_list_ptr = sn_nsdl_alloc_options_list(nsdl, coap_response); + if (coap_response->options_list_ptr) { + coap_response->options_list_ptr->max_age = max_age(); + } + + if(received_coap_header->options_list_ptr) { + if(received_coap_header->options_list_ptr->observe != -1) { + if (is_observable()) { + uint32_t number = 0; + uint8_t observe_option = 0; + observe_option = received_coap_header->options_list_ptr->observe; + + if(START_OBSERVATION == observe_option) { + // If the observe length is 0 means register for observation. + if(received_coap_header->options_list_ptr->observe != -1) { + number = received_coap_header->options_list_ptr->observe; + } + + // If the observe value is 0 means register for observation. + if(number == 0) { + tr_info("M2MResourceBase::handle_get_request - put resource under observation"); + set_under_observation(true,observation_handler); + send_notification_delivery_status(*this, NOTIFICATION_STATUS_SUBSCRIBED); + M2MBase::add_observation_level(M2MBase::R_Attribute); + if (coap_response->options_list_ptr) { + coap_response->options_list_ptr->observe = observation_number(); + } + } + + if(received_coap_header->token_ptr) { + set_observation_token(received_coap_header->token_ptr, + received_coap_header->token_len); + } + + } else if (STOP_OBSERVATION == observe_option) { + tr_info("M2MResourceBase::handle_get_request - stops observation"); + set_under_observation(false,NULL); + M2MBase::remove_observation_level(M2MBase::R_Attribute); + send_notification_delivery_status(*this, NOTIFICATION_STATUS_UNSUBSCRIBED); + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } + } + } + }else { + tr_error("M2MResourceBase::handle_get_request - Return COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + // Operation is not allowed. + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + return coap_response; +} + +sn_coap_hdr_s* M2MResourceBase::handle_put_request(nsdl_s *nsdl, + sn_coap_hdr_s *received_coap_header, + M2MObservationHandler *observation_handler, + bool &execute_value_updated) +{ + tr_info("M2MResourceBase::handle_put_request()"); + + sn_coap_msg_code_e msg_code = COAP_MSG_CODE_RESPONSE_CHANGED; // 2.04 + sn_coap_hdr_s *coap_response = sn_nsdl_build_response(nsdl, + received_coap_header, + msg_code); + // process the PUT if we have registered a callback for it + if(received_coap_header && coap_response) { + uint16_t coap_content_type = 0; + if(received_coap_header->content_format != COAP_CT_NONE) { + coap_content_type = received_coap_header->content_format; + } + if(received_coap_header->options_list_ptr && + received_coap_header->options_list_ptr->uri_query_ptr) { + char *query = (char*)alloc_string_copy(received_coap_header->options_list_ptr->uri_query_ptr, + received_coap_header->options_list_ptr->uri_query_len); + if (query){ + tr_info("M2MResourceBase::handle_put_request() - query %s", query); + + // if anything was updated, re-initialize the stored notification attributes + if (!handle_observation_attribute(query)){ + tr_error("M2MResourceBase::handle_put_request() - Invalid query"); + msg_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; + } + free(query); + } + else { + // memory allocation for query fails + tr_error("M2MResourceBase::handle_put_request() - Out of memory !!!"); + msg_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR; // 4.00 + } + } else if ((operation() & SN_GRS_PUT_ALLOWED) != 0) { + tr_debug("M2MResourceBase::handle_put_request() - Request Content-type: %d", coap_content_type); + + if(COAP_CONTENT_OMA_TLV_TYPE == coap_content_type || + COAP_CONTENT_OMA_TLV_TYPE_OLD == coap_content_type) { + msg_code = COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT; + } else { +#ifndef DISABLE_BLOCK_MESSAGE + if (block_message()) { + block_message()->set_message_info(received_coap_header); + if (block_message()->is_block_message()) { + incoming_block_message_callback* incoming_block_message_cb = (incoming_block_message_callback*)M2MCallbackStorage::get_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); + if (incoming_block_message_cb) { + (*incoming_block_message_cb)(_block_message_data); + } + if (block_message()->is_last_block()) { + block_message()->clear_values(); + coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED; + } else { + coap_response->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING; + } + if (block_message()->error_code() != M2MBlockMessage::ErrorNone) { + block_message()->clear_values(); + } + } + } +#endif + // Firmware object uri path is limited to be max 255 bytes + if ((strcmp(uri_path(), FIRMAWARE_PACKAGE_URI_PATH) == 0) && + received_coap_header->payload_len > 255) { + msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; + } else if ((strcmp(uri_path(), SERVER_LIFETIME_PATH) == 0)) { + // Check that lifetime can't go below 60s + char *query = (char*)alloc_string_copy(received_coap_header->payload_ptr, + received_coap_header->payload_len); + + if (query) { + int32_t lifetime = atol(query); + if (lifetime < MINIMUM_REGISTRATION_TIME) { + tr_error("M2MResourceBase::handle_put_request() - lifetime value % " PRId32 " not acceptable", lifetime); + msg_code = COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE; + } + free(query); + } + else { + // memory allocation for query fails + tr_error("M2MResourceBase::handle_put_request() - Out of memory !!!"); + msg_code = COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR; + } + } + + // Do not update resource value in error case. + if ((received_coap_header->payload_ptr) && (msg_code == COAP_MSG_CODE_RESPONSE_CHANGED)) { + execute_value_updated = true; + } + } + } else { + // Operation is not allowed. + tr_error("M2MResourceBase::handle_put_request() - COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED"); + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + } else { + msg_code = COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED; + } + if(coap_response) { + coap_response->msg_code = msg_code; + } + + return coap_response; +} + + +#ifndef DISABLE_BLOCK_MESSAGE + +M2MBlockMessage* M2MResourceBase::block_message() const +{ + return _block_message_data; +} + +bool M2MResourceBase::set_incoming_block_message_callback(incoming_block_message_callback callback) +{ + incoming_block_message_callback* old_callback = (incoming_block_message_callback*)M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); + delete old_callback; + + // copy the callback object. This will change on next version to be a direct pointer to a interface class, + // this FPn<> is just too heavy for this usage. + incoming_block_message_callback* new_callback = new incoming_block_message_callback(callback); + + delete _block_message_data; + _block_message_data = NULL; + _block_message_data = new M2MBlockMessage(); + + return M2MCallbackStorage::add_callback(*this, + new_callback, + M2MCallbackAssociation::M2MResourceInstanceIncomingBlockMessageCallback); +} + +bool M2MResourceBase::set_outgoing_block_message_callback(outgoing_block_message_callback callback) +{ + outgoing_block_message_callback *old_callback = (outgoing_block_message_callback*)M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); + delete old_callback; + + outgoing_block_message_callback *new_callback = new outgoing_block_message_callback(callback); + return M2MCallbackStorage::add_callback(*this, + new_callback, + M2MCallbackAssociation::M2MResourceInstanceOutgoingBlockMessageCallback); +} +#endif + +bool M2MResourceBase::set_notification_sent_callback(notification_sent_callback callback) +{ + notification_sent_callback *old_callback = (notification_sent_callback*)M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); + delete old_callback; + + notification_sent_callback *new_callback = new notification_sent_callback(callback); + return M2MCallbackStorage::add_callback(*this, + new_callback, + M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); +} + +bool M2MResourceBase::set_notification_sent_callback(notification_sent_callback_2 callback) +{ + M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); + + return M2MCallbackStorage::add_callback(*this, + (void*)callback, + M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); +} + +bool M2MResourceBase::set_notification_status_callback(notification_status_callback callback) +{ + notification_status_callback *old_callback = (notification_status_callback*)M2MCallbackStorage::remove_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); + delete old_callback; + + notification_status_callback *new_callback = new notification_status_callback(callback); + return M2MCallbackStorage::add_callback(*this, + new_callback, + M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); +} + +bool M2MResourceBase::set_notification_status_callback(notification_status_callback_2 callback) +{ + M2MCallbackStorage::remove_callback(*this, M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); + + return M2MCallbackStorage::add_callback(*this, + (void*)callback, + M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); +} + +void M2MResourceBase::notification_sent() +{ + // Now we will call both callbacks, if they are set. This is different from original behavior. + notification_sent_callback* callback = + (notification_sent_callback*)M2MCallbackStorage::get_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback); + if (callback) { + (*callback)(); + } + + notification_sent_callback_2 callback2 = + (notification_sent_callback_2)M2MCallbackStorage::get_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceNotificationSentCallback2); + if (callback2) { + (*callback2)(); + } +} + +void M2MResourceBase::notification_status(const uint16_t msg_id, const NoticationStatus status) +{ + if (_notification_status != status) { + _notification_status = status; + // Now we will call both callbacks, if they are set. This is different from original behavior. + notification_status_callback* callback = + (notification_status_callback*)M2MCallbackStorage::get_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback); + if (callback) { + (*callback)(msg_id, status); + } + + notification_status_callback_2 callback2 = + (notification_status_callback_2)M2MCallbackStorage::get_callback(*this, + M2MCallbackAssociation::M2MResourceInstanceNotificationStatusCallback2); + if (callback2) { + (*callback2)(msg_id, status); + } + } +} + +M2MResourceBase::ResourceType M2MResourceBase::convert_data_type(M2MBase::DataType type) const +{ + M2MResourceBase::ResourceType res_type = M2MResourceBase::OBJLINK; + switch(type) { + case M2MBase::STRING: + res_type = M2MResourceBase::STRING; + break; + case M2MBase::INTEGER: + res_type = M2MResourceBase::INTEGER; + break; + case M2MBase::FLOAT: + res_type = M2MResourceBase::FLOAT; + break; + case M2MBase::OPAQUE: + res_type = M2MResourceBase::OPAQUE; + break; + case M2MBase::BOOLEAN: + res_type = M2MResourceBase::BOOLEAN; + break; + case M2MBase::TIME: + res_type = M2MResourceBase::TIME; + break; + case M2MBase::OBJLINK: + res_type = M2MResourceBase::OBJLINK; + break; + } + return res_type; +} + +M2MResourceBase::NoticationStatus M2MResourceBase::notification_status() const +{ + return _notification_status; +} + +void M2MResourceBase::clear_notification_status() +{ + _notification_status = M2MResourceBase::INIT; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mresourceinstance.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mresourceinstance.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdlib.h> +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mobservationhandler.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "include/m2mcallbackstorage.h" +#include "include/m2mreporthandler.h" +#include "mbed-client/m2mblockmessage.h" +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "mClt" + +M2MResourceInstance::M2MResourceInstance(M2MResource &parent, + const String &res_name, + M2MBase::Mode resource_mode, + const String &resource_type, + M2MBase::DataType type, + char* path, + bool external_blockwise_store, + bool multiple_instance) +: M2MResourceBase(res_name, + resource_mode, + resource_type, + type, + path, + external_blockwise_store, + multiple_instance + ), + _parent_resource(parent) +{ + set_base_type(M2MBase::ResourceInstance); +} + +M2MResourceInstance::M2MResourceInstance(M2MResource &parent, + const String &res_name, + M2MBase::Mode resource_mode, + const String &resource_type, + M2MBase::DataType type, + const uint8_t *value, + const uint8_t value_length, + char* path, + bool external_blockwise_store, + bool multiple_instance) +: M2MResourceBase(res_name, + resource_mode, + resource_type, + type, + value, + value_length, + path, + external_blockwise_store, + multiple_instance), + _parent_resource(parent) +{ + set_base_type(M2MBase::ResourceInstance); +} + +M2MResourceInstance::M2MResourceInstance(M2MResource &parent, + const lwm2m_parameters_s* s, + M2MBase::DataType type) +: M2MResourceBase(s, type), + _parent_resource(parent) +{ + + assert(base_type() == M2MBase::ResourceInstance); +} + +M2MResourceInstance::~M2MResourceInstance() +{ + free_resources(); +} + +M2MObservationHandler* M2MResourceInstance::observation_handler() const +{ + const M2MResource& parent_resource = get_parent_resource(); + + // XXX: need to check the flag too + return parent_resource.observation_handler(); +} + +void M2MResourceInstance::set_observation_handler(M2MObservationHandler *handler) +{ + M2MResource& parent_resource = get_parent_resource(); + + // XXX: need to set the flag too + parent_resource.set_observation_handler(handler); +} + +bool M2MResourceInstance::handle_observation_attribute(const char *query) +{ + tr_debug("M2MResourceInstance::handle_observation_attribute - is_under_observation(%d)", is_under_observation()); + bool success = false; + + M2MReportHandler *handler = M2MBase::report_handler(); + if (!handler) { + handler = M2MBase::create_report_handler(); + } + + if (handler) { + success = handler->parse_notification_attribute(query, + M2MBase::base_type(), resource_instance_type()); + if(success) { + if (is_under_observation()) { + handler->set_under_observation(true); + } + } else { + handler->set_default_values(); + } + } + return success; +} + +uint16_t M2MResourceInstance::object_instance_id() const +{ + const M2MObjectInstance& parent_object_instance = get_parent_resource().get_parent_object_instance(); + return parent_object_instance.instance_id(); +} + +M2MResource& M2MResourceInstance::get_parent_resource() const +{ + return _parent_resource; +} + +const char* M2MResourceInstance::object_name() const +{ + const M2MObjectInstance& parent_object_instance = _parent_resource.get_parent_object_instance(); + const M2MObject& parent_object = parent_object_instance.get_parent_object(); + + return parent_object.name(); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2msecurity.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2msecurity.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed-client/m2msecurity.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mstring.h" +#include "mbed-trace/mbed_trace.h" + +#include <stdlib.h> + +#define TRACE_GROUP "mClt" + +#define BUFFER_SIZE 21 + +// Default instance id's that server uses +#define DEFAULT_M2M_INSTANCE 0 +#define DEFAULT_BOOTSTRAP_INSTANCE 1 + +M2MSecurity* M2MSecurity::_instance = NULL; + +M2MSecurity* M2MSecurity::get_instance() +{ + if (_instance == NULL) { + _instance = new M2MSecurity(M2MServer); + } + return _instance; +} + +void M2MSecurity::delete_instance() +{ + delete _instance; + _instance = NULL; +} + + +M2MSecurity::M2MSecurity(ServerType ser_type) +: M2MObject(M2M_SECURITY_ID, stringdup(M2M_SECURITY_ID)) +{ +} + +M2MSecurity::~M2MSecurity() +{ +} + +M2MObjectInstance* M2MSecurity::create_object_instance(ServerType server_type) +{ + uint16_t instance_id = DEFAULT_M2M_INSTANCE; + if (server_type == Bootstrap) { + instance_id = DEFAULT_BOOTSTRAP_INSTANCE; + } + + M2MObjectInstance *server_instance = M2MObject::object_instance(instance_id); + if (server_instance != NULL) { + // Instance already exists, return NULL + return NULL; + } + + server_instance = M2MObject::create_object_instance(instance_id); + if (server_instance) { + M2MResource* res = server_instance->create_dynamic_resource(SECURITY_M2M_SERVER_URI, + OMA_RESOURCE_TYPE, + M2MResourceInstance::STRING, + false); + if (res) { + res->set_operation(M2MBase::NOT_ALLOWED); + } + res = server_instance->create_dynamic_resource(SECURITY_BOOTSTRAP_SERVER, + OMA_RESOURCE_TYPE, + M2MResourceInstance::BOOLEAN, + false); + if (res) { + res->set_operation(M2MBase::NOT_ALLOWED); + res->set_value((int)server_type); + } + res = server_instance->create_dynamic_resource(SECURITY_SECURITY_MODE, + OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + false); + if (res) { + res->set_operation(M2MBase::NOT_ALLOWED); + } + res = server_instance->create_dynamic_resource(SECURITY_PUBLIC_KEY, + OMA_RESOURCE_TYPE, + M2MResourceInstance::OPAQUE, + false); + if (res) { + res->set_operation(M2MBase::NOT_ALLOWED); + } + res = server_instance->create_dynamic_resource(SECURITY_SERVER_PUBLIC_KEY, + OMA_RESOURCE_TYPE, + M2MResourceInstance::OPAQUE, + false); + if (res) { + res->set_operation(M2MBase::NOT_ALLOWED); + } + res = server_instance->create_dynamic_resource(SECURITY_SECRET_KEY, + OMA_RESOURCE_TYPE, + M2MResourceInstance::OPAQUE, + false); + if (res) { + res->set_operation(M2MBase::NOT_ALLOWED); + } + if (M2MSecurity::M2MServer == server_type) { + res = server_instance->create_dynamic_resource(SECURITY_SHORT_SERVER_ID, + OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + false); + if (res) { + res->set_operation(M2MBase::NOT_ALLOWED); + } + } + } + return server_instance; +} + +void M2MSecurity::remove_security_instances() +{ + int32_t instance_id = _instance->get_security_instance_id(M2MSecurity::Bootstrap); + if (instance_id >= 0) { + _instance->remove_object_instance(instance_id); + } + instance_id = _instance->get_security_instance_id(M2MSecurity::M2MServer); + if (instance_id >= 0) { + _instance->remove_object_instance(instance_id); + } +} + +M2MResource* M2MSecurity::create_resource(SecurityResource resource, uint32_t value, uint16_t instance_id) +{ + M2MResource* res = NULL; + M2MObjectInstance *server_instance = M2MObject::object_instance(instance_id); + if (server_instance == NULL) { + return NULL; + } + + const char* security_id_ptr = ""; + if (!is_resource_present(resource, instance_id)) { + switch(resource) { + case SMSSecurityMode: + security_id_ptr = SECURITY_SMS_SECURITY_MODE; + break; + case M2MServerSMSNumber: + security_id_ptr = SECURITY_M2M_SERVER_SMS_NUMBER; + break; + case ShortServerID: + security_id_ptr = SECURITY_SHORT_SERVER_ID; + break; + case ClientHoldOffTime: + security_id_ptr = SECURITY_CLIENT_HOLD_OFF_TIME; + break; + default: + break; + } + } + + const String security_id(security_id_ptr); + + if (!security_id.empty()) { + if (server_instance) { + res = server_instance->create_dynamic_resource(security_id,OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + false); + + if (res) { + res->set_operation(M2MBase::NOT_ALLOWED); + res->set_value(value); + } + } + } + return res; +} + +bool M2MSecurity::delete_resource(SecurityResource resource, uint16_t instance_id) +{ + bool success = false; + const char* security_id_ptr; + M2MObjectInstance *server_instance = M2MObject::object_instance(instance_id); + if (server_instance == NULL) { + return NULL; + } + switch(resource) { + case SMSSecurityMode: + security_id_ptr = SECURITY_SMS_SECURITY_MODE; + break; + case M2MServerSMSNumber: + security_id_ptr = SECURITY_M2M_SERVER_SMS_NUMBER; + break; + case ShortServerID: + if (M2MSecurity::Bootstrap == server_type(instance_id)) { + security_id_ptr = SECURITY_SHORT_SERVER_ID; + } else { + security_id_ptr = NULL; + } + break; + case ClientHoldOffTime: + security_id_ptr = SECURITY_CLIENT_HOLD_OFF_TIME; + break; + default: + // Others are mandatory resources hence cannot be deleted. + security_id_ptr = NULL; + break; + } + + if (security_id_ptr) { + if (server_instance) { + success = server_instance->remove_resource(security_id_ptr); + } + } + return success; +} + +bool M2MSecurity::set_resource_value(SecurityResource resource, + const String &value, + uint16_t instance_id) +{ + bool success = false; + if (M2MSecurity::M2MServerUri == resource) { + M2MResource* res = get_resource(resource, instance_id); + if (res) { + success = res->set_value((const uint8_t*)value.c_str(),(uint32_t)value.length()); + } + } + return success; +} + +bool M2MSecurity::set_resource_value(SecurityResource resource, + uint32_t value, + uint16_t instance_id) +{ + bool success = false; + M2MResource* res = get_resource(resource, instance_id); + if (res) { + if (M2MSecurity::SecurityMode == resource || + M2MSecurity::SMSSecurityMode == resource || + M2MSecurity::M2MServerSMSNumber == resource || + M2MSecurity::ShortServerID == resource || + M2MSecurity::BootstrapServer == resource || + M2MSecurity::ClientHoldOffTime == resource) { + success = res->set_value(value); + + } + } + return success; +} + +bool M2MSecurity::set_resource_value(SecurityResource resource, + const uint8_t *value, + const uint16_t length, + uint16_t instance_id) +{ + bool success = false; + M2MResource* res = get_resource(resource, instance_id); + if (res) { + if (M2MSecurity::PublicKey == resource || + M2MSecurity::ServerPublicKey == resource || + M2MSecurity::Secretkey == resource || + M2MSecurity::M2MServerUri == resource) { + success = res->set_value(value,length); + } + } + return success; +} + +String M2MSecurity::resource_value_string(SecurityResource resource, uint16_t instance_id) const +{ + String value = ""; + M2MResource* res = get_resource(resource, instance_id); + if (res) { + if (M2MSecurity::M2MServerUri == resource) { + value = res->get_value_string(); + } + } + return value; +} + +uint32_t M2MSecurity::resource_value_buffer(SecurityResource resource, + uint8_t *&data, + uint16_t instance_id) const +{ + uint32_t size = 0; + M2MResource* res = get_resource(resource, instance_id); + if (res) { + if (M2MSecurity::PublicKey == resource || + M2MSecurity::ServerPublicKey == resource || + M2MSecurity::Secretkey == resource) { + res->get_value(data,size); + } + } + return size; +} + +uint32_t M2MSecurity::resource_value_buffer(SecurityResource resource, + const uint8_t *&data, + uint16_t instance_id) const +{ + uint32_t size = 0; + M2MResource* res = get_resource(resource, instance_id); + if (res) { + if (M2MSecurity::PublicKey == resource || + M2MSecurity::ServerPublicKey == resource || + M2MSecurity::Secretkey == resource) { + data = res->value(); + size = res->value_length(); + } + } + return size; +} + + +uint32_t M2MSecurity::resource_value_int(SecurityResource resource, uint16_t instance_id) const +{ + uint32_t value = 0; + M2MResource* res = get_resource(resource, instance_id); + if (res) { + if (M2MSecurity::SecurityMode == resource || + M2MSecurity::SMSSecurityMode == resource || + M2MSecurity::M2MServerSMSNumber == resource || + M2MSecurity::ShortServerID == resource || + M2MSecurity::BootstrapServer == resource || + M2MSecurity::ClientHoldOffTime == resource) { + // note: the value may be 32bit int on 32b archs. + value = res->get_value_int(); + } + } + return value; +} + +bool M2MSecurity::is_resource_present(SecurityResource resource, uint16_t instance_id) const +{ + bool success = false; + M2MResource *res = get_resource(resource, instance_id); + if (res) { + success = true; + } + return success; +} + +uint16_t M2MSecurity::total_resource_count(uint16_t instance_id) const +{ + uint16_t count = 0; + M2MObjectInstance *server_instance = M2MObject::object_instance(instance_id); + if (server_instance) { + count = server_instance->resources().size(); + } + return count; +} + +M2MSecurity::ServerType M2MSecurity::server_type(uint16_t instance_id) const +{ + uint32_t sec_mode = resource_value_int(M2MSecurity::BootstrapServer, instance_id); + M2MSecurity::ServerType type = M2MSecurity::M2MServer; + if (sec_mode == 1) { + type = M2MSecurity::Bootstrap; + } + return type; +} + +M2MResource* M2MSecurity::get_resource(SecurityResource res, uint16_t instance_id) const +{ + M2MResource* res_object = NULL; + M2MObjectInstance *server_instance = M2MObject::object_instance(instance_id); + if (server_instance == NULL) { + return NULL; + } + + if (server_instance) { + const char* res_name_ptr = NULL; + switch(res) { + case M2MServerUri: + res_name_ptr = SECURITY_M2M_SERVER_URI; + break; + case BootstrapServer: + res_name_ptr = SECURITY_BOOTSTRAP_SERVER; + break; + case SecurityMode: + res_name_ptr = SECURITY_SECURITY_MODE; + break; + case PublicKey: + res_name_ptr = SECURITY_PUBLIC_KEY; + break; + case ServerPublicKey: + res_name_ptr = SECURITY_SERVER_PUBLIC_KEY; + break; + case Secretkey: + res_name_ptr = SECURITY_SECRET_KEY; + break; + case SMSSecurityMode: + res_name_ptr = SECURITY_SMS_SECURITY_MODE; + break; + case SMSBindingKey: + res_name_ptr = SECURITY_SMS_BINDING_KEY; + break; + case SMSBindingSecretKey: + res_name_ptr = SECURITY_SMS_BINDING_SECRET_KEY; + break; + case M2MServerSMSNumber: + res_name_ptr = SECURITY_M2M_SERVER_SMS_NUMBER; + break; + case ShortServerID: + res_name_ptr = SECURITY_SHORT_SERVER_ID; + break; + case ClientHoldOffTime: + res_name_ptr = SECURITY_CLIENT_HOLD_OFF_TIME; + break; + } + + if (res_name_ptr) { + res_object = server_instance->resource(res_name_ptr); + } + } + return res_object; +} + +void M2MSecurity::clear_resources(uint16_t instance_id) +{ + for(int i = 0; i <= M2MSecurity::ClientHoldOffTime; i++) { + M2MResource *res = get_resource((SecurityResource) i, instance_id); + if (res) { + res->clear_value(); + } + } +} + +int32_t M2MSecurity::get_security_instance_id(ServerType ser_type) const +{ + M2MObjectInstanceList::const_iterator it; + M2MObjectInstanceList insts = instances(); + it = insts.begin(); + int32_t instance_id = -1; + for ( ; it != insts.end(); it++ ) { + uint16_t id = (*it)->instance_id(); + if (server_type(id) == ser_type) { + instance_id = id; + break; + } + } + return instance_id; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mserver.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mserver.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed-client/m2mserver.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-client/m2mobject.h" +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mstring.h" + +#define TRACE_GROUP "mClt" + +#define BUFFER_SIZE 21 + +M2MServer::M2MServer() +: M2MObject(M2M_SERVER_ID, stringdup(M2M_SERVER_ID)) +{ + M2MObject::create_object_instance(); + + _server_instance = object_instance(); + + if(_server_instance) { + + M2MResource* res = _server_instance->create_dynamic_resource(SERVER_SHORT_SERVER_ID, + OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + true); + if(res) { + res->set_operation(M2MBase::GET_PUT_ALLOWED); + } + res = _server_instance->create_dynamic_resource(SERVER_LIFETIME, + OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + true); + if(res) { + res->set_operation(M2MBase::GET_PUT_POST_ALLOWED); + } + res = _server_instance->create_dynamic_resource(SERVER_NOTIFICATION_STORAGE, + OMA_RESOURCE_TYPE, + M2MResourceInstance::BOOLEAN, + true); + if(res) { + res->set_operation(M2MBase::GET_PUT_POST_ALLOWED); + } + res = _server_instance->create_dynamic_resource(SERVER_BINDING, + OMA_RESOURCE_TYPE, + M2MResourceInstance::STRING, + true); + if(res) { + res->set_operation(M2MBase::GET_PUT_POST_ALLOWED); + } + res = _server_instance->create_dynamic_resource(SERVER_REGISTRATION_UPDATE, + OMA_RESOURCE_TYPE, + M2MResourceInstance::OPAQUE, + false); + if(res) { + res->set_operation(M2MBase::POST_ALLOWED); + } + } +} + +M2MServer::~M2MServer() +{ + +} + +M2MResource* M2MServer::create_resource(ServerResource resource, uint32_t value) +{ + M2MResource* res = NULL; + const char* server_id_ptr = ""; + if(!is_resource_present(resource)) { + switch(resource) { + case DefaultMinPeriod: + server_id_ptr = SERVER_DEFAULT_MIN_PERIOD; + break; + case DefaultMaxPeriod: + server_id_ptr = SERVER_DEFAULT_MAX_PERIOD; + break; + case DisableTimeout: + server_id_ptr = SERVER_DISABLE_TIMEOUT; + break; + default: + break; + } + } + String server_id(server_id_ptr); + + if(!server_id.empty()) { + if(_server_instance) { + res = _server_instance->create_dynamic_resource(server_id, + OMA_RESOURCE_TYPE, + M2MResourceInstance::INTEGER, + true); + if(res) { + res->set_operation(M2MBase::GET_PUT_POST_ALLOWED); + + res->set_value(value); + } + } + } + return res; +} + +M2MResource* M2MServer::create_resource(ServerResource resource) +{ + M2MResource* res = NULL; + if(!is_resource_present(resource)) { + if(M2MServer::Disable == resource) { + if(_server_instance) { + res = _server_instance->create_dynamic_resource(SERVER_DISABLE, + OMA_RESOURCE_TYPE, + M2MResourceInstance::OPAQUE, + false); + if(res) { + res->set_operation(M2MBase::POST_ALLOWED); + } + } + } + } + return res; +} + +bool M2MServer::delete_resource(ServerResource resource) +{ + bool success = false; + const char* server_id_ptr; + switch(resource) { + case DefaultMinPeriod: + server_id_ptr = SERVER_DEFAULT_MIN_PERIOD; + break; + case DefaultMaxPeriod: + server_id_ptr = SERVER_DEFAULT_MAX_PERIOD; + break; + case Disable: + server_id_ptr = SERVER_DISABLE; + break; + case DisableTimeout: + server_id_ptr = SERVER_DISABLE_TIMEOUT; + break; + default: + server_id_ptr = NULL; + break; + } + + if(server_id_ptr) { + if(_server_instance) { + success = _server_instance->remove_resource(server_id_ptr); + } + } + return success; +} + +bool M2MServer::set_resource_value(ServerResource resource, + const String &value) +{ + bool success = false; + M2MResource* res = get_resource(resource); + if(res && (M2MServer::Binding == resource)) { + success = res->set_value((const uint8_t*)value.c_str(),(uint32_t)value.length()); + } + return success; +} + +bool M2MServer::set_resource_value(ServerResource resource, + uint32_t value) +{ + bool success = false; + M2MResource* res = get_resource(resource); + if(res) { + if(M2MServer::ShortServerID == resource || + M2MServer::Lifetime == resource || + M2MServer::DefaultMinPeriod == resource || + M2MServer::DefaultMaxPeriod == resource || + M2MServer::DisableTimeout == resource || + M2MServer::NotificationStorage == resource) { + // If it is any of the above resource + // set the value of the resource. + + success = res->set_value(value); + } + } + return success; +} + +String M2MServer::resource_value_string(ServerResource resource) const +{ + String value = ""; + M2MResource* res = get_resource(resource); + if(res && (M2MServer::Binding == resource)) { + + value = res->get_value_string(); + } + return value; +} + + +uint32_t M2MServer::resource_value_int(ServerResource resource) const +{ + uint32_t value = 0; + M2MResource* res = get_resource(resource); + if(res) { + if(M2MServer::ShortServerID == resource || + M2MServer::Lifetime == resource || + M2MServer::DefaultMinPeriod == resource || + M2MServer::DefaultMaxPeriod == resource || + M2MServer::DisableTimeout == resource || + M2MServer::NotificationStorage == resource) { + + value = res->get_value_int(); + } + } + return value; +} + +bool M2MServer::is_resource_present(ServerResource resource) const +{ + bool success = false; + M2MResource *res = get_resource(resource); + if(res) { + success = true; + } + return success; +} + +uint16_t M2MServer::total_resource_count() const +{ + uint16_t total_count = 0; + if(_server_instance) { + total_count = _server_instance->resources().size(); + } + return total_count; +} + +M2MResource* M2MServer::get_resource(ServerResource res) const +{ + M2MResource* res_object = NULL; + const char* res_name_ptr = NULL; + switch(res) { + case ShortServerID: + res_name_ptr = SERVER_SHORT_SERVER_ID; + break; + case Lifetime: + res_name_ptr = SERVER_LIFETIME; + break; + case DefaultMinPeriod: + res_name_ptr = SERVER_DEFAULT_MIN_PERIOD; + break; + case DefaultMaxPeriod: + res_name_ptr = SERVER_DEFAULT_MAX_PERIOD; + break; + case Disable: + res_name_ptr = SERVER_DISABLE; + break; + case DisableTimeout: + res_name_ptr = SERVER_DISABLE_TIMEOUT; + break; + case NotificationStorage: + res_name_ptr = SERVER_NOTIFICATION_STORAGE; + break; + case Binding: + res_name_ptr = SERVER_BINDING; + break; + case RegistrationUpdate: + res_name_ptr = SERVER_REGISTRATION_UPDATE; + break; + } + + if(res_name_ptr) { + if(_server_instance) { + res_object = _server_instance->resource(res_name_ptr); + } + } + return res_object; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mstring.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mstring.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed-client/m2mstring.h" +#include <string.h> // strlen +#include <stdlib.h> // malloc, realloc +#include <assert.h> +#include <algorithm> // min + +namespace m2m { + +const String::size_type String::npos = static_cast<size_t>(-1); + +char* String::strdup(const char* s) +{ + const size_t len = strlen(s)+1; + char *p2 = static_cast<char*>(malloc(len)); + if (p2) { + memcpy(p2, s, len); + allocated_ = len; + size_ = len-1; + } + return p2; +} + +String::String() + : p( strdup("") ) +{ +} + +String::~String() +{ + free(p); + p = 0; +} + +String::String(const String& s) + : p(0) +{ + p = static_cast<char*>(malloc(s.size_ + 1)); + + allocated_ = s.size_ + 1; + size_ = s.size_; + memcpy(p, s.p, size_ + 1); +} + +String::String(const char* s) + : p(strdup(s)) +{ +} + +String::String(const char* str, size_t n) +{ + p = static_cast<char*>(malloc(n + 1)); + + allocated_ = n + 1; + size_ = n; + memcpy(p, str, n); + p[n] = 0; +} + +String& String::operator=(const char* s) +{ + if ( p != s ) { + // s could point into our own string, so we have to allocate a new string + const size_t len = strlen(s); + char* copy = (char*) malloc( len + 1); + memmove(copy, s, len+1); // trailing 0 + free( p ); + p = copy; + size_ = len; + allocated_ = len+1; + } + return *this; +} + +String& String::operator=(const String& s) +{ + return operator=(s.p); +} + +String& String::operator+=(const String& s) +{ + if (s.size_ > 0) { + this->reserve(size_ + s.size_); + memmove(p+size_, s.p, s.size_+1); // trailing 0 + size_ += s.size_; + } + return *this; +} + +// since p and s may overlap, we have to copy our own string first +String& String::operator+=(const char* s) +{ + const size_type lens = strlen(s); + if (lens > 0) { + if (size_ + lens + 1 <= allocated_) { + memmove(p+size_, s, lens+1); // trailing 0 + size_ += lens; + } else { + String s2( *this ); // copy own data + s2.reserve(size_ + lens); + memmove(s2.p+size_, s, lens+1); // trailing 0 + s2.size_ = size_ + lens; + this->swap( s2 ); + } + } + return *this; +} + +String& String::operator+=(const char c) +{ + push_back(c); + return *this; +} + +void String::push_back(const char c) { + + if (size_ == allocated_ - 1) { + size_t more = (allocated_* 3) / 2; // factor 1.5 + if ( more < 4 ) more = 4; + reserve( size_ + more ); + } + + p[size_] = c; + size_++; + p[size_] = 0; +} + +bool String::operator==(const char* s) const +{ + if( s == NULL ) { + if( p == NULL ) { + return true; + } + return false; + } + bool ret = strcmp(p, s); + return !ret; +} + +bool String::operator==(const String& s) const +{ + bool ret = strcmp(p, s.p); + return !ret; +} + +void String::clear() +{ + size_ = 0; + p[0] = 0; +} + +String String::substr(const size_type pos, size_type length) const +{ + String s; + const size_type len = size_; + + if ( pos <= len ) { + + size_type remain = len - pos; + + if ( length > remain ) + length = remain; + + s.reserve( length ); + + memcpy(s.p, p + pos, length); + s.p[length] = '\0'; + s.size_ = length; + } + return s; +} + + +// checked access, accessing the NUL at end is allowed +char String::at(const size_type i) const +{ + if ( i <= strlen(p) ) { + return p[i]; + } else { + return '\0'; + } +} + +String& String::erase(size_type pos, size_type len) +{ + if (len > 0) { + + if ( pos < size_ ) { // user must not remove trailing 0 + + size_type s2 = size_; + size_type remain = s2 - pos - len; + + if (remain > 0) { + // erase by overwriting + memmove(p + pos, p + pos + len, remain); + } + + //if ( remain < 0 ) remain = 0; + + // remove unused space + this->resize( pos+remain ); + + } + } + return *this; +} + +String& String::append( const char* str, size_type n) { + if (str && n > 0) { + size_t lens = strlen(str); + if (n > lens) + n = lens; + size_t newlen = size_ + n; + this->reserve( newlen ); + memmove(p+size_, str, n); // p and s.p MAY overlap + p[newlen] = 0; // add NUL termination + size_ = newlen; + } + return *this; +} + +String& String::append_raw( const char* str, size_type n) { + if (str && n > 0) { + size_t newlen = size_ + n; + this->reserve( newlen ); + memmove(p+size_, str, n); // p and s.p MAY overlap + p[newlen] = 0; // add NUL termination + size_ = newlen; + } + return *this; +} + +void String::append_int(int param) { + + // max len of "-9223372036854775808" plus zero termination + char conv_buff[20+1]; + + int len = itoa_c(param, conv_buff); + append_raw(conv_buff, len); +} + +int String::compare( size_type pos, size_type len, const String& str ) const { + int r = -1; + if (pos <= size_) { + if ( len > size_ - pos) + len = size_ - pos; // limit len to available length + + const size_type osize = str.size(); + const size_type len2 = std::min(len, osize); + r = strncmp( p + pos, str.p, len2); + if (r==0) // equal so far, now compare sizes + r = len < osize ? -1 : ( len == osize ? 0 : +1 ); + } + return r; +} + +int String::compare( size_type pos, size_type len, const char* str ) const { + int r = -1; + if (pos <= size_) { + + if ( len > size_ - pos) + len = size_ - pos; // limit len to available length + + const size_type osize = strlen(str); + const size_type len2 = std::min(len, osize); + r = strncmp( p + pos, str, len2); + if (r==0) // equal so far, now compare sizes + r = len < osize ? -1 : ( len == osize ? 0 : +1 ); + } + return r; +} + +int String::find_last_of(char c) const { + int r = -1; + char *v; + v = strrchr(p,c); + if (v != NULL) { + r = 0; + char* i = p; + while (v != i) { + i++; + r++; + } + } + return r; +} + +void String::new_realloc( size_type n) { + if (n > 0 ) { + char* pnew = static_cast<char*>(realloc(p, n)); // could return NULL + if (pnew) + p = pnew; + } +} + +void String::reserve( const size_type n) { + if (n >= allocated_ ) { + this->new_realloc(n + 1); + allocated_ = n + 1; + } +} + +void String::resize( const size_type n) { + this->resize( n, 0 ); +} + +void String::resize( const size_type n, const char c) { + if (n < size_ ) { + p[n] = 0; + size_ = n; + } + else if (n > size_ ) { + this->reserve( n ); + for (size_type i=size_; i < n; ++i ) + p[i] = c; + p[n] = 0; + size_ = n; + } +} + +void String::swap( String& s ) { + std::swap( allocated_, s.allocated_ ); + std::swap( size_, s.size_ ); + std::swap( p, s.p ); +} + + +// Comparison +bool operator<( const String& s1, const String& s2 ) { + return strcmp( s1.c_str(), s2.c_str() ) < 0; +} + +void reverse(char s[], uint32_t length) +{ + uint32_t i, j; + char c; + + for (i = 0, j = length-1; i<j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } +} + +uint32_t itoa_c (int64_t n, char s[]) +{ + int64_t sign; + uint32_t i; + + if ((sign = n) < 0) + n = -n; + + i = 0; + + do { + s[i++] = n % 10 + '0'; + } + while ((n /= 10) > 0); + + if (sign < 0) + s[i++] = '-'; + + s[i] = '\0'; + + m2m::reverse(s, i); + return i; +} + +uint8_t* String::convert_integer_to_array(int64_t value, uint8_t &size, const uint8_t *array, const uint32_t array_size) +{ + uint8_t* buffer = NULL; + size = 0; + if (array) { + value = String::convert_array_to_integer(array, array_size); + } + + if(value < 0xFF) { + size = 1; + } else if(value < 0xFFFF) { + size = 2; + } else if(value < 0xFFFFFF) { + size = 3; + } else if(value < 0xFFFFFFFF) { + size = 4; + } else if(value < 0xFFFFFFFFFF) { + size = 5; + } else if(value < 0xFFFFFFFFFFFF) { + size = 6; + } else if(value < 0xFFFFFFFFFFFFFF) { + size = 7; + } else { + size = 8; + } + + buffer = (uint8_t*)malloc(size); + if (buffer) { + for (int i = 0; i < size; i++) { + buffer[i] = (value >> ((size - i - 1) * 8)); + } + } else { + size = 0; + } + return buffer; +} + +int64_t String::convert_array_to_integer(const uint8_t *value, const uint32_t size) +{ + int64_t temp_64 = 0; + for (int i = size - 1; i >= 0; i--) { + temp_64 += (uint64_t)(*value++) << i * 8; + } + return temp_64; +} + +} // namespace
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mstringbufferbase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mstringbufferbase.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed-client/m2mstringbufferbase.h" + +#include "mbed-client/m2mstring.h" + +#include <assert.h> +#include <string.h> + + +bool StringBufferBase::ensure_space(size_t max_size, size_t required_size) const +{ + const size_t space_left = max_size - _curr_size; + + bool space_available = false; + + if (required_size <= space_left) { + + space_available = true; + } + return space_available; +} + +bool StringBufferBase::append(char *buff, size_t max_size, char data) +{ + bool space_available = ensure_space(max_size, 1 + 1); // there must be space for trailing zero too + if (space_available) { + buff[_curr_size++] = data; + buff[_curr_size] = '\0'; + assert(_curr_size < max_size); + } + return space_available; +} + +bool StringBufferBase::append(char *buff, size_t max_size, const char *data) +{ + + const size_t string_len = strlen(data); + bool space_available = ensure_space(max_size, string_len + 1); + if (space_available) { + memcpy(buff + _curr_size, data, string_len + 1); // copy the zero terminator too + _curr_size += string_len; + assert(_curr_size < max_size); + } + return space_available; +} + +bool StringBufferBase::append(char *buff, size_t max_size, const char *data, size_t data_len) +{ + bool space_available = true; + if (data_len > 0) { + space_available = ensure_space(max_size, data_len + 1); + if (space_available) { + memcpy(buff + _curr_size, data, data_len); + _curr_size += data_len; + // Todo: should the code actually check, if the data already contained zero or not? + buff[_curr_size] = '\0'; + assert(_curr_size < max_size); + } + } + return space_available; +} + +bool StringBufferBase::append_int(char *buff, size_t max_size, uint16_t data) +{ + // max len of "-9223372036854775808" plus zero termination + char conv_buff[20+1]; + + // re-use the String's functionality, a more optimal version would use snprintf() or int size specific converter + unsigned int len = m2m::itoa_c(data, conv_buff); + + return append(buff, max_size, conv_buff, len); +} + +int StringBufferBase::find_last_of(const char *buff, char search_char) const +{ + int last_index = -1; + // search from the end of string, return upon first found matching char + for (int index = (int)_curr_size; index >= 0; index--) { + if (buff[index] == search_char) { + last_index = index; + break; + } + } + + return last_index; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mtlvdeserializer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mtlvdeserializer.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Needed for PRIu64 on FreeRTOS +#include <stdio.h> +// Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include "include/m2mtlvdeserializer.h" +#include "mbed-client/m2mconstants.h" +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "mClt" +#define BUFFER_SIZE 10 + +bool M2MTLVDeserializer::is_object_instance(const uint8_t *tlv) +{ + return is_object_instance(tlv, 0); +} + +bool M2MTLVDeserializer::is_resource(const uint8_t *tlv) +{ + return is_resource(tlv, 0); +} + +bool M2MTLVDeserializer::is_multiple_resource(const uint8_t *tlv) +{ + return is_multiple_resource(tlv, 0); +} + +bool M2MTLVDeserializer::is_resource_instance(const uint8_t *tlv) +{ + return is_resource_instance(tlv, 0); +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialise_object_instances(const uint8_t* tlv, + uint32_t tlv_size, + M2MObject &object, + M2MTLVDeserializer::Operation operation) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + if (is_object_instance(tlv) ) { + tr_debug("M2MTLVDeserializer::deserialise_object_instances"); + error = deserialize_object_instances(tlv, tlv_size, 0, object,operation,false); + if(M2MTLVDeserializer::None == error) { + error = deserialize_object_instances(tlv, tlv_size, 0, object,operation,true); + } + } else { + tr_debug("M2MTLVDeserializer::deserialise_object_instances ::NotValid"); + error = M2MTLVDeserializer::NotValid; + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resources(const uint8_t *tlv, + uint32_t tlv_size, + M2MObjectInstance &object_instance, + M2MTLVDeserializer::Operation operation) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + if (!is_resource(tlv) && !is_multiple_resource(tlv)) { + error = M2MTLVDeserializer::NotValid; + } else { + error = deserialize_resources(tlv, tlv_size, 0, object_instance, operation,false); + if(M2MTLVDeserializer::None == error) { + if (M2MTLVDeserializer::Put == operation) { + remove_resources(tlv, tlv_size, object_instance, 0); + } + error = deserialize_resources(tlv, tlv_size, 0, object_instance, operation,true); + } + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + M2MResource &resource, + M2MTLVDeserializer::Operation operation) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + if (!is_multiple_resource(tlv)) { + error = M2MTLVDeserializer::NotValid; + } else { + tr_debug("M2MTLVDeserializer::deserialize_resource_instances()"); + uint8_t offset = 2; + + ((tlv[0] & 0x20) == 0) ? offset : offset++; + + uint8_t length = tlv[0] & 0x18; + if(length == 0x08) { + offset += 1; + } else if(length == 0x10) { + offset += 2; + } else if(length == 0x18) { + offset += 3; + } + + tr_debug("M2MTLVDeserializer::deserialize_resource_instances() Offset %d", offset); + error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation,false); + if(M2MTLVDeserializer::None == error) { + if (M2MTLVDeserializer::Put == operation) { + remove_resource_instances(tlv, tlv_size, resource, offset); + } + error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation,true); + } + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_object_instances(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MObject &object, + M2MTLVDeserializer::Operation operation, + bool update_value) +{ + tr_debug("M2MTLVDeserializer::deserialize_object_instances()"); + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + + const M2MObjectInstanceList &list = object.instances(); + M2MObjectInstanceList::const_iterator it; + it = list.begin(); + + if (TYPE_OBJECT_INSTANCE == til._type) { + for (; it!=list.end(); it++) { + if((*it)->instance_id() == til._id) { + error = deserialize_resources(tlv, tlv_size, offset, (**it),operation, update_value); + } + } + offset += til._length; + + if(offset < tlv_size) { + error = deserialize_object_instances(tlv, tlv_size, offset, object, operation, update_value); + } + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resources(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MObjectInstance &object_instance, + M2MTLVDeserializer::Operation operation, + bool update_value) +{ + tr_debug("M2MTLVDeserializer::deserialize_resources()"); + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + + const M2MResourceList &list = object_instance.resources(); + M2MResourceList::const_iterator it; + it = list.begin(); + + bool found = false; + bool multi = false; + if (TYPE_RESOURCE == til._type || TYPE_RESOURCE_INSTANCE == til._type) { + multi = false; + for (; it!=list.end(); it++) { + if((*it)->name_id() == til._id){ + tr_debug("M2MTLVDeserializer::deserialize_resources() - Resource ID %d ", til._id); + found = true; + if(update_value) { + if(til._length > 0) { + tr_debug("M2MTLVDeserializer::deserialize_resources() - Update value"); + if (!set_resource_instance_value((*it), tlv+offset, til._length)) { + error = M2MTLVDeserializer::OutOfMemory; + break; + } + } else { + tr_debug("M2MTLVDeserializer::deserialize_resources() - Clear Value"); + (*it)->clear_value(); + } + break; + } else if(0 == ((*it)->operation() & SN_GRS_PUT_ALLOWED)) { + tr_debug("M2MTLVDeserializer::deserialize_resources() - NOT_ALLOWED"); + error = M2MTLVDeserializer::NotAllowed; + break; + } + } + } + } else if (TYPE_MULTIPLE_RESOURCE == til._type) { + multi = true; + for (; it!=list.end(); it++) { + if((*it)->supports_multiple_instances() && + (*it)->name_id() == til._id) { + found = true; + error = deserialize_resource_instances(tlv, tlv_size, offset, (**it), object_instance, operation, update_value); + } + } + } else { + error = M2MTLVDeserializer::NotValid; + return error; + } + + if(!found) { + if(M2MTLVDeserializer::Post == operation) { + //Create a new Resource + String id; + id.append_int(til._id); + M2MResource *resource = object_instance.create_dynamic_resource(id,"",M2MResourceInstance::OPAQUE,true,multi); + if(resource) { + resource->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED); + } + if( TYPE_MULTIPLE_RESOURCE == til._type ) { + error = deserialize_resource_instances(tlv, tlv_size, offset, (*resource), object_instance, operation, update_value); + } + } else if(M2MTLVDeserializer::Put == operation) { + error = M2MTLVDeserializer::NotFound; + } + } + + + offset += til._length; + + if(offset < tlv_size) { + error = deserialize_resources(tlv, tlv_size, offset, object_instance, operation, update_value); + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MResource &resource, + M2MObjectInstance &object_instance, + M2MTLVDeserializer::Operation operation, + bool update_value) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + + if (TYPE_MULTIPLE_RESOURCE == til._type || TYPE_RESOURCE_INSTANCE == til._type) { + const M2MResourceInstanceList &list = resource.resource_instances(); + M2MResourceInstanceList::const_iterator it; + it = list.begin(); + bool found = false; + for (; it!=list.end(); it++) { + if((*it)->instance_id() == til._id && TYPE_RESOURCE_INSTANCE == til._type) { + found = true; + if(update_value) { + if(til._length > 0) { + if (!set_resource_instance_value((*it), tlv+offset, til._length)) { + error = M2MTLVDeserializer::OutOfMemory; + break; + } + } else { + (*it)->clear_value(); + } + break; + } else if(0 == ((*it)->operation() & SN_GRS_PUT_ALLOWED)) { + error = M2MTLVDeserializer::NotAllowed; + break; + } + } + } + + if(!found) { + if(M2MTLVDeserializer::Post == operation) { + // Create a new Resource Instance + M2MResourceInstance *res_instance = object_instance.create_dynamic_resource_instance(resource.name(),"", + resource.resource_instance_type(), + true, + til._id); + if(res_instance) { + res_instance->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED); + } + } else if(M2MTLVDeserializer::Put == operation) { + error = M2MTLVDeserializer::NotFound; + } + } + } else { + error = M2MTLVDeserializer::NotValid; + return error; + } + + offset += til._length; + + if(offset < tlv_size) { + error = deserialize_resource_instances(tlv, tlv_size, offset, resource, object_instance, operation, update_value); + } + return error; +} + +M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + uint32_t offset, + M2MResource &resource, + M2MTLVDeserializer::Operation operation, + bool update_value) +{ + M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + + if (TYPE_RESOURCE_INSTANCE == til._type) { + const M2MResourceInstanceList &list = resource.resource_instances(); + M2MResourceInstanceList::const_iterator it; + it = list.begin(); + bool found = false; + for (; it!=list.end(); it++) { + if((*it)->instance_id() == til._id) { + found = true; + if(update_value) { + if(til._length > 0) { + if (!set_resource_instance_value((*it),tlv+offset, til._length)) { + error = M2MTLVDeserializer::OutOfMemory; + break; + } + } else { + (*it)->clear_value(); + } + break; + } else if(0 == ((*it)->operation() & SN_GRS_PUT_ALLOWED)) { + error = M2MTLVDeserializer::NotAllowed; + break; + } + } + } + if(!found) { + if(M2MTLVDeserializer::Post == operation) { + error = M2MTLVDeserializer::NotAllowed; + } else if(M2MTLVDeserializer::Put == operation) { + error = M2MTLVDeserializer::NotFound; + } + } + } else { + error = M2MTLVDeserializer::NotValid; + return error; + } + + offset += til._length; + + if(offset < tlv_size) { + error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation, update_value); + } + return error; +} + +bool M2MTLVDeserializer::is_object_instance(const uint8_t *tlv, uint32_t offset) +{ + bool ret = false; + if (tlv) { + uint8_t value = tlv[offset]; + ret = (TYPE_OBJECT_INSTANCE == (value & TYPE_RESOURCE)); + } + return ret; +} + +uint16_t M2MTLVDeserializer::instance_id(const uint8_t *tlv) +{ + TypeIdLength til(tlv, 0); + til.deserialize(); + uint16_t id = til._id; + return id; +} + +bool M2MTLVDeserializer::is_resource(const uint8_t *tlv, uint32_t offset) +{ + bool ret = false; + if (tlv) { + ret = (TYPE_RESOURCE == (tlv[offset] & TYPE_RESOURCE)); + } + return ret; +} + +bool M2MTLVDeserializer::is_multiple_resource(const uint8_t *tlv, uint32_t offset) +{ + bool ret = false; + if (tlv) { + ret = (TYPE_MULTIPLE_RESOURCE == (tlv[offset] & TYPE_RESOURCE)); + } + return ret; +} + +bool M2MTLVDeserializer::is_resource_instance(const uint8_t *tlv, uint32_t offset) +{ + bool ret = false; + if (tlv) { + ret = (TYPE_RESOURCE_INSTANCE == (tlv[offset] & TYPE_RESOURCE)); + } + return ret; +} + +bool M2MTLVDeserializer::set_resource_instance_value(M2MResourceBase *res, const uint8_t *tlv, const uint32_t size) +{ + int64_t value = 0; + bool success = true; + switch (res->resource_instance_type()) { + case M2MResourceBase::INTEGER: + case M2MResourceBase::BOOLEAN: + case M2MResourceBase::TIME: + value = String::convert_array_to_integer(tlv, size); + if (!res->set_value(value)) { + success = false; + } + break; + // Todo! implement conversion for other types as well + case M2MResourceBase::STRING: + case M2MResourceBase::FLOAT: + case M2MResourceBase::OPAQUE: + case M2MResourceBase::OBJLINK: + if (!res->set_value(tlv, size)) { + success = false; + } + break; + default: + break; + } + + return success; +} + +void M2MTLVDeserializer::remove_resources(const uint8_t *tlv, + uint32_t tlv_size, + M2MObjectInstance &object_instance, + uint32_t offset_size) +{ + tr_debug("M2MTLVDeserializer::remove_resources"); + uint32_t offset = offset_size; + const M2MResourceList &list = object_instance.resources(); + M2MResourceList::const_iterator it; + + it = list.begin(); + for (; it!=list.end();) { + bool found = false; + while(offset < tlv_size) { + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + offset += til._length; + if((*it)->name_id() == til._id){ + offset = offset_size; + found = true; + break; + } + } + offset = offset_size; + + // Remove resource if not part of the TLV message + if (!found) { + tr_debug("M2MTLVDeserializer::remove_resources - remove resource %" PRId32, (*it)->name_id()); + object_instance.remove_resource((*it)->name()); + } else { + ++it; + } + } +} + +void M2MTLVDeserializer::remove_resource_instances(const uint8_t *tlv, + uint32_t tlv_size, + M2MResource &resource, + uint32_t offset_size) +{ + tr_debug("M2MTLVDeserializer::remove_resource_instances"); + uint32_t offset = offset_size; + const M2MResourceInstanceList &list = resource.resource_instances(); + M2MResourceInstanceList::const_iterator it; + it = list.begin(); + + for (; it!=list.end();) { + bool found = false; + while (offset < tlv_size) { + TypeIdLength til(tlv, offset); + til.deserialize(); + offset = til._offset; + offset += til._length; + if ((*it)->instance_id() == til._id){ + offset = offset_size; + found = true; + break; + } + } + offset = offset_size; + + // Remove resource instance if not part of the TLV message + if (!found) { + tr_debug("M2MTLVDeserializer::remove_resource_instances - remove resource instance %d", (*it)->instance_id()); + resource.remove_resource_instance((*it)->instance_id()); + } else { + ++it; + } + } +} + +TypeIdLength::TypeIdLength(const uint8_t *tlv, uint32_t offset) +: _tlv(tlv), _offset(offset), _type(tlv[offset] & 0xC0), _id(0), _length(0) +{ +} + +void TypeIdLength::deserialize() +{ + uint32_t idLength = _tlv[_offset] & ID16; + uint32_t lengthType = _tlv[_offset] & LENGTH24; + if (0 == lengthType) { + _length = _tlv[_offset] & 0x07; + } + _offset++; + + deserialiseID(idLength); + deserialiseLength(lengthType); +} + +void TypeIdLength::deserialiseID(uint32_t idLength) +{ + _id = _tlv[_offset++] & 0xFF; + if (ID16 == idLength) { + _id = (_id << 8) + (_tlv[_offset++] & 0xFF); + } +} + +void TypeIdLength::deserialiseLength(uint32_t lengthType) +{ + if (lengthType > 0) { + _length = _tlv[_offset++] & 0xFF; + } + if (lengthType > LENGTH8) { + _length = (_length << 8) + (_tlv[_offset++] & 0xFF); + } + if (lengthType > LENGTH16) { + _length = (_length << 8) + (_tlv[_offset++] & 0xFF); + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mtlvserializer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mtlvserializer.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "include/m2mtlvserializer.h" +#include "mbed-client/m2mconstants.h" + +#include <stdlib.h> +#include "common_functions.h" + +#define TRACE_GROUP "mClt" + +#define MAX_TLV_LENGTH_SIZE 3 +#define MAX_TLV_ID_SIZE 2 +#define TLV_TYPE_SIZE 1 + +uint8_t* M2MTLVSerializer::serialize(const M2MObjectInstanceList &object_instance_list, uint32_t &size) +{ + return serialize_object_instances(object_instance_list, size); +} + +uint8_t* M2MTLVSerializer::serialize(const M2MResourceList &resource_list, uint32_t &size) +{ + bool valid = true; + return serialize_resources(resource_list, size,valid); +} + +uint8_t* M2MTLVSerializer::serialize(const M2MResource *resource, uint32_t &size) +{ + uint8_t* data = NULL; + serialize(resource, data, size); + return data; +} + +uint8_t* M2MTLVSerializer::serialize_object_instances(const M2MObjectInstanceList &object_instance_list, uint32_t &size) +{ + uint8_t *data = NULL; + + if(!object_instance_list.empty()) { + M2MObjectInstanceList::const_iterator it; + it = object_instance_list.begin(); + for (; it!=object_instance_list.end(); it++) { + uint16_t id = (*it)->instance_id(); + serialize(id, *it, data, size); + } + } + return data; +} + +uint8_t* M2MTLVSerializer::serialize_resources(const M2MResourceList &resource_list, uint32_t &size, bool &valid) +{ + uint8_t *data = NULL; + + if(!resource_list.empty()) { + M2MResourceList::const_iterator it; + it = resource_list.begin(); + for (; it!=resource_list.end(); it++) { + if((*it)->name_id() == -1) { + valid = false; + break; + } + } + if(valid) { + it = resource_list.begin(); + for (; it!=resource_list.end(); it++) { + if (((*it)->operation() & M2MBase::GET_ALLOWED) == M2MBase::GET_ALLOWED) { + if(!serialize(*it, data, size)) { + /* serializing has failed */ + /* free data so far */ + free(data); + /* invalidate */ + valid = false; + /* return NULL immediately */ + return NULL; + } + } + } + } + } + return data; +} + +bool M2MTLVSerializer::serialize(uint16_t id, const M2MObjectInstance *object_instance, uint8_t *&data, uint32_t &size) +{ + uint8_t *resource_data = NULL; + uint32_t resource_size = 0; + bool success; + + bool valid = true; + resource_data = serialize_resources(object_instance->resources(),resource_size,valid); + if(valid) { + if(serialize_TILV(TYPE_OBJECT_INSTANCE, id, resource_data, resource_size, data, size)) { + success = true; + } else { + /* serializing object instance failed */ + success = false; + } + free(resource_data); + } else { + /* serializing resources failed */ + success = false; + } + return success; +} + +bool M2MTLVSerializer::serialize(const M2MResource *resource, uint8_t *&data, uint32_t &size) +{ + bool success = false; + if(resource->name_id() != -1) { + success = resource->supports_multiple_instances() ? + serialize_multiple_resource(resource, data, size) : + serialize_resource(resource, data, size); + } + return success; +} + +bool M2MTLVSerializer::serialize_resource(const M2MResource *resource, uint8_t *&data, uint32_t &size) +{ + bool success = false; + if(resource->name_id() != -1) { + if ( (resource->resource_instance_type() == M2MResourceBase::INTEGER) || + (resource->resource_instance_type() == M2MResourceBase::BOOLEAN) || + (resource->resource_instance_type() == M2MResourceBase::TIME) ) { + success = serialize_TLV_binary_int(resource, TYPE_RESOURCE, resource->name_id(), data, size); + } + else { + success = serialize_TILV(TYPE_RESOURCE, resource->name_id(), + resource->value(), resource->value_length(), data, size); + } + } + return success; +} + +bool M2MTLVSerializer::serialize_multiple_resource(const M2MResource *resource, uint8_t *&data, uint32_t &size) +{ + bool success = false; + uint8_t *nested_data = NULL; + uint32_t nested_data_size = 0; + + const M2MResourceInstanceList &instance_list = resource->resource_instances(); + if(!instance_list.empty()) { + M2MResourceInstanceList::const_iterator it; + it = instance_list.begin(); + for (; it!=instance_list.end(); it++) { + uint16_t id = (*it)->instance_id(); + if (((*it)->operation() & M2MBase::GET_ALLOWED) == M2MBase::GET_ALLOWED) { + if(!serialize_resource_instance(id, (*it), nested_data, nested_data_size)) { + /* serializing instance has failed */ + /* free data so far allocated */ + free(nested_data); + /* return fail immediately*/ + success = false; + return success; + } + } + } + } + if(resource->name_id() != -1 && + (resource->operation() & M2MBase::GET_ALLOWED) == M2MBase::GET_ALLOWED) { + success = serialize_TILV(TYPE_MULTIPLE_RESOURCE, resource->name_id(), + nested_data, nested_data_size, data, size); + } + + free(nested_data); + return success; +} + +bool M2MTLVSerializer::serialize_resource_instance(uint16_t id, const M2MResourceInstance *resource, uint8_t *&data, uint32_t &size) +{ + bool success; + + if ( (resource->resource_instance_type() == M2MResourceBase::INTEGER) || + (resource->resource_instance_type() == M2MResourceBase::BOOLEAN) || + (resource->resource_instance_type() == M2MResourceBase::TIME) ) { + success=serialize_TLV_binary_int(resource, TYPE_RESOURCE_INSTANCE, id, data, size); + } + else { + success=serialize_TILV(TYPE_RESOURCE_INSTANCE, id, resource->value(), resource->value_length(), data, size); + } + + return success; +} + +/* See, OMA-TS-LightweightM2M-V1_0-20170208-A, Appendix C, + * Data Types, Integer, Boolean and TY + * Yime, TLV Format */ +bool M2MTLVSerializer::serialize_TLV_binary_int(const M2MResourceBase *resource, uint8_t type, uint16_t id, uint8_t *&data, uint32_t &size) +{ + int64_t valueInt = resource->get_value_int(); + uint32_t buffer_size; + /* max len 8 bytes */ + uint8_t buffer[8]; + + if (resource->resource_instance_type() == M2MResourceBase::BOOLEAN) { + buffer_size = 1; + buffer[0] = valueInt; + } else { + buffer_size = 8; + common_write_64_bit(valueInt, buffer); + } + + return serialize_TILV(type, id, buffer, buffer_size, data, size); +} + + +bool M2MTLVSerializer::serialize_TILV(uint8_t type, uint16_t id, uint8_t *value, uint32_t value_length, uint8_t *&data, uint32_t &size) +{ + uint8_t *tlv = 0; + const uint32_t type_length = TLV_TYPE_SIZE; + type += id < 256 ? 0 : ID16; + type += value_length < 8 ? value_length : + value_length < 256 ? LENGTH8 : + value_length < 65536 ? LENGTH16 : LENGTH24; + uint8_t tlv_type; + tlv_type = type & 0xFF; + + uint32_t id_size; + uint8_t id_array[MAX_TLV_ID_SIZE]; + serialize_id(id, id_size, id_array); + + uint32_t length_size; + uint8_t length_array[MAX_TLV_LENGTH_SIZE]; + serialize_length(value_length, length_size, length_array); + + tlv = (uint8_t*)malloc(size + type_length + id_size + length_size + value_length); + if (!tlv) { + /* memory allocation has failed */ + /* return failure immediately */ + return false; + /* eventually NULL will be returned to serializer public method caller */ + } + if(data) { + memcpy(tlv, data, size); + free(data); + } + memcpy(tlv+size, &tlv_type, type_length); + memcpy(tlv+size+type_length, id_array, id_size); + memcpy(tlv+size+type_length+id_size, length_array, length_size); + memcpy(tlv+size+type_length+id_size+length_size, value, value_length); + + data = tlv; + size += type_length + id_size + length_size + value_length; + return true; +} + +void M2MTLVSerializer::serialize_id(uint16_t id, uint32_t &size, uint8_t *id_ptr) +{ + if(id > 255) { + size=2; + id_ptr[0] = (id & 0xFF00) >> 8; + id_ptr[1] = id & 0xFF; + } else { + size=1; + id_ptr[0] = id & 0xFF; + } +} + +void M2MTLVSerializer::serialize_length(uint32_t length, uint32_t &size, uint8_t *length_ptr) +{ + if (length > 65535) { + size = 3; + length_ptr[0] = (length & 0xFF0000) >> 16; + length_ptr[1] = (length & 0xFF00) >> 8; + length_ptr[2] = length & 0xFF; + } else if (length > 255) { + size = 2; + length_ptr[0] = (length & 0xFF00) >> 8; + length_ptr[1] = length & 0xFF; + } else if (length > 7) { + size = 1; + length_ptr[0] = length & 0xFF; + } else { + size=0; + } +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/nsdlaccesshelper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/nsdlaccesshelper.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "include/nsdlaccesshelper.h" +#include "include/m2mnsdlinterface.h" + +#include <stdlib.h> + +// callback function for NSDL library to call into +uint8_t __nsdl_c_callback(struct nsdl_s *nsdl_handle, + sn_coap_hdr_s *received_coap_ptr, + sn_nsdl_addr_s *address, + sn_nsdl_capab_e nsdl_capab) +{ + uint8_t status = 0; + M2MNsdlInterface *interface = (M2MNsdlInterface*)sn_nsdl_get_context(nsdl_handle); + if(interface) { + status = interface->resource_callback(nsdl_handle,received_coap_ptr, + address, nsdl_capab); + // Payload freeing must be done in app level if blockwise message + if (received_coap_ptr->coap_status == COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED) { + free(received_coap_ptr->payload_ptr); + received_coap_ptr->payload_ptr = NULL; + } + } + return status; +} + +void* __nsdl_c_memory_alloc(uint16_t size) +{ + if(size) + return malloc(size); + else + return 0; +} + +void __nsdl_c_memory_free(void *ptr) +{ + if(ptr) + free(ptr); +} + +uint8_t __nsdl_c_send_to_server(struct nsdl_s * nsdl_handle, + sn_nsdl_capab_e protocol, + uint8_t *data_ptr, + uint16_t data_len, + sn_nsdl_addr_s *address_ptr) +{ + uint8_t status = 0; + M2MNsdlInterface *interface = (M2MNsdlInterface*)sn_nsdl_get_context(nsdl_handle); + if(interface) { + status = interface->send_to_server_callback(nsdl_handle, + protocol, data_ptr, + data_len, address_ptr); + } + return status; +} + +uint8_t __nsdl_c_received_from_server(struct nsdl_s * nsdl_handle, + sn_coap_hdr_s *coap_header, + sn_nsdl_addr_s *address_ptr) +{ + uint8_t status = 0; + M2MNsdlInterface *interface = (M2MNsdlInterface*)sn_nsdl_get_context(nsdl_handle); + if(interface) { + status = interface->received_from_server_callback(nsdl_handle, + coap_header, + address_ptr); + } + return status; +} + +uint8_t __nsdl_c_auto_obs_token(struct nsdl_s *nsdl_handle, const char *path, uint8_t *token) +{ + M2MNsdlInterface *interface = (M2MNsdlInterface*)sn_nsdl_get_context(nsdl_handle); + if(interface) { + return interface->find_auto_obs_token(path, token); + } + return 0; +} + +void* __socket_malloc( void * context, size_t size) +{ + (void) context; + return malloc(size); +} + +void __socket_free(void * context, void * ptr) +{ + (void) context; + free(ptr); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/uriqueryparser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/uriqueryparser.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,61 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <string.h> +#include "include/uriqueryparser.h" + +char* query_string(char* uri) +{ + char* query = strchr((char*)uri, '?'); + if (query != NULL) { + query++; + if (*query == '\0') { + return NULL; + } else { + return query; + } + } else { + return NULL; + } +} + +int8_t query_param_count(char* query) +{ + int param_count = 0; + while (NULL != (query = strchr(query, '='))) { + param_count++; + ++query; + } + return param_count; +} + +bool uri_query_parameters(char* query, char *uri_query_parameters[], int index) +{ + if (query == NULL || *query == '\0' || index < 0) { + return false; + } + + uri_query_parameters[index++] = query; + while (NULL != (query = strchr(query, '&'))) { + *query = '\0'; + uri_query_parameters[index] = ++query; + index++; + } + + return true; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-cloud-client/MbedCloudClient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-cloud-client/MbedCloudClient.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,400 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + + +#ifndef __MBED_CLOUD_CLIENT_H__ +#define __MBED_CLOUD_CLIENT_H__ + +#include <map> +#include <string> +#include <vector> +#include "include/ServiceClient.h" +#include "mbed-cloud-client/MbedCloudClientConfig.h" + +using namespace std; +class SimpleM2MResourceBase; + +/** + * \brief MbedCloudClientCallback + * A callback class for informing updated object and resource value from the + * LWM2M server to the user of the MbedCloudClient class. The user MUST instantiate the + * class derived out of this and pass the object to MbedCloudClient::set_update_callback(). + */ +class MbedCloudClientCallback { + +public: + + /** + * \brief A callback indicating that the value of the resource object is updated + * by the LWM2M Cloud server. + * \param base The object whose value is updated. + * \param type The type of the object. + */ + virtual void value_updated(M2MBase *base, M2MBase::BaseType type) = 0; +}; + + + +/*! \file MbedCloudClient.h + * \brief MbedCloudClient. + * This class provides an interface for handling all the mbed Cloud Client Interface operations + * including device provisioning, identity setup, device resource management defined in the OMA + * LWM2M specifications, and update firmware. + * Device resource management includes Bootstrapping, Client Registration, Device Management & + * Service Enablement and Information Reporting. + */ + +class MbedCloudClient : public ServiceClientCallback { + +public: + + /** + * \brief An enum defining different kinds of errors + * that can occur during various client operations. + */ + typedef enum { + ConnectErrorNone = 0x0, // Range reserved for Connector Error from 0x30 - 0x3FF + ConnectAlreadyExists, + ConnectBootstrapFailed, + ConnectInvalidParameters, + ConnectNotRegistered, + ConnectTimeout, + ConnectNetworkError, + ConnectResponseParseFailed, + ConnectUnknownError, + ConnectMemoryConnectFail, + ConnectNotAllowed, + ConnectSecureConnectionFailed, + ConnectDnsResolvingFailed, + ConnectorFailedToStoreCredentials, + ConnectorFailedToReadCredentials, + ConnectorInvalidCredentials, +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + UpdateWarningNoActionRequired = UpdateClient::WarningBase, // Range reserved for Update Error from 0x0400 - 0x04FF + UpdateWarningCertificateNotFound = UpdateClient::WarningCertificateNotFound, + UpdateWarningIdentityNotFound = UpdateClient::WarningIdentityNotFound, + UpdateWarningCertificateInvalid = UpdateClient::WarningCertificateInvalid, + UpdateWarningSignatureInvalid = UpdateClient::WarningSignatureInvalid, + UpdateWarningVendorMismatch = UpdateClient::WarningVendorMismatch, + UpdateWarningClassMismatch = UpdateClient::WarningClassMismatch, + UpdateWarningDeviceMismatch = UpdateClient::WarningDeviceMismatch, + UpdateWarningURINotFound = UpdateClient::WarningURINotFound, + UpdateWarningRollbackProtection = UpdateClient::WarningRollbackProtection, + UpdateWarningUnknown = UpdateClient::WarningUnknown, + UpdateErrorUserActionRequired = UpdateClient::ErrorBase, + UpdateErrorWriteToStorage = UpdateClient::ErrorWriteToStorage, + UpdateErrorInvalidHash = UpdateClient::ErrorInvalidHash, + UpdateFatalRebootRequired +#endif + }Error; + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + /** + * \brief Enum defining authorization requests from the Update client. + */ + enum { + UpdateRequestInvalid = UpdateClient::RequestInvalid, + UpdateRequestDownload = UpdateClient::RequestDownload, + UpdateRequestInstall = UpdateClient::RequestInstall + }; +#endif + + /** + * \brief Constructor + */ + MbedCloudClient(); + + /** + * \brief Destructor + */ + virtual ~MbedCloudClient(); + + /** + * \brief Adds a list of objects that the application wants to register to the + * LWM2M server. This function MUST be called before calling the setup() + * API. Otherwise, the application gets the error ConnectInvalidParameters, when + * calling setup(). + * \param object_list Objects that contain information about the + * client attempting to register to the LWM2M server. + */ + void add_objects(const M2MObjectList& object_list); + + /** + * \brief Sets the callback function that is called when there is + * any new update on any Object/ObjectInstance/Resource from the LWM2M server, + * typically on receiving PUT commands on the registered objects. + * \param callback Passes the class object that implements the callback + * function to handle the incoming PUT request on a given object. + */ + void set_update_callback(MbedCloudClientCallback *callback); + + /** + * \brief Initiates the Cloud Client set up on the Cloud service. This + * function manages device provisioning (first time usage), bootstrapping + * (first time usage) and registering the client application to the Cloud + * service. + * \param iface A handler to the network interface on mbedOS, can be NULL on + * other platforms. + */ + bool setup(void* iface); + + /** + * \brief Sets the callback function that is called when the client is registered + * successfully to the Cloud. This is used for a statically defined function. + * \param fn A function pointer to the function that is called when the client + * is registered. + */ + void on_registered(void(*fn)(void)); + + /** + * \brief Sets the callback function that is called when the client is registered + * successfully to the Cloud. This is an overloaded function for a class function. + * \param object A function pointer to the function that is called when the client + * is registered. + */ + template<typename T> + void on_registered(T *object, void (T::*member)(void)); + + /** + * \brief Sets the callback function that is called when there is any error + * occuring in the client functionality. The error code can be mapped from the + * MbedCloudClient::Error enum. This is used for a statically defined function. + * \param fn A function pointer to the function that is called when there + * is any error in the client. + */ + void on_error(void(*fn)(int)); + + /** + * \brief Sets the callback function that is called when there is an error + * occuring in the client functionality. The error code can be mapped from + * MbedCloudClient::Error enum. This is an overloaded function for a class function. + * \param object A function pointer to the function that is called when there + * is an error in the client. + */ + template<typename T> + void on_error(T *object, void (T::*member)(int)); + + /** + * \brief Sets the callback function that is called when the client is unregistered + * successfully from the Cloud. This is used for a statically defined function. + * \param fn A function pointer to the function that is called when the client + * is unregistered. + */ + void on_unregistered(void(*fn)(void)); + + /** + * \brief Sets the callback function that is called when the client is unregistered + * successfully from the Cloud. This is an overloaded function for a class function. + * \param object A function pointer to the function that is called when the client + * is unregistered. + */ + template<typename T> + void on_unregistered(T *object, void (T::*member)(void)); + + /** + * \brief Sets the callback function that is called when the client registration + * is updated successfully to the Cloud. This is used for a statically defined function. + * \param fn A function pointer to the function that is called when the client + * registration is updated. + */ + void on_registration_updated(void(*fn)(void)); + + /** + * \brief Sets the callback function that is called when the client registration + * is updated successfully to the Cloud. This is an overloaded function for a class + * function. + * \param object A function pointer to the function that is called when the client + * registration is updated. + */ + template<typename T> + void on_registration_updated(T *object, void (T::*member)(void)); + + /** + * \brief Sends a registration update message to the Cloud when the client is registered + * successfully to the Cloud and there is no internal connection error. + * If the client is not connected and there is some other internal network + * transaction ongoing, this function triggers an error MbedCloudClient::ConnectNotAllowed. + * \deprecated + */ + void keep_alive() m2m_deprecated; + + /** + * \brief Sends a registration update message to the Cloud when the client is registered + * successfully to the Cloud and there is no internal connection error. + * If the client is not connected and there is some other internal network + * transaction ongoing, this function triggers an error MbedCloudClient::ConnectNotAllowed. + */ + void register_update(); + + /** + * \brief Closes the connection towards Cloud and unregisters the client. + * This function triggers the on_unregistered() callback if set by the application. + */ + void close(); + + /** + * \brief Returns pointer to the ConnectorClientEndpointInfo object. + * \return ConnectorClientEndpointInfo pointer. + */ + const ConnectorClientEndpointInfo *endpoint_info() const; + + /** + * \brief Sets the function that is called for indicating that the client + * is going to sleep when the binding mode is selected with queue mode. + * \param callback A function pointer that is called when the client + * goes to sleep. + */ + void set_queue_sleep_handler(callback_handler handler); + + /** + * \brief Sets the function callback that is called by client to + * fetch a random number from an application to ensure strong entropy. + * \param random_callback A function pointer that is called by client + * while performing a secure handshake. + * The function signature should be uint32_t (*random_number_callback)(void); + */ + void set_random_number_callback(random_number_cb callback); + + /** + * \brief Sets the function callback that is called by client to + * provide an entropy source from an application to ensure strong entropy. + * \param entropy_callback A function pointer that is called by mbed Client + * while performing a secure handshake. + * Function signature, if using mbed-client-mbedtls, should be + * int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, + * size_t len, size_t *olen); + */ + void set_entropy_callback(entropy_cb callback); + + /** + * \brief Set resource value in the Device Object + * + * \param resource Device enum to have value set. + * \param value String object. + * \return True if successful, false otherwise. + */ + bool set_device_resource_value(M2MDevice::DeviceResource resource, + const std::string &value); + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + /** + * \brief Registers a callback function for authorizing firmware downloads and reboots. + * \param handler Callback function. + */ + void set_update_authorize_handler(void (*handler)(int32_t request)); + + /** + * \brief Authorize request passed to authorization handler. + * \param request Request being authorized. + */ + void update_authorize(int32_t request); + + /** + * \brief Registers a callback function for monitoring download progress. + * \param handler Callback function. + */ + void set_update_progress_handler(void (*handler)(uint32_t progress, uint32_t total)); +#endif + + /** + * @brief Return error description for the latest error code + * @return Error description string + */ + const char *error_description() const; + +protected: // from ServiceClientCallback + + /** + * \brief Indicates that the setup or close operation is complete + * with success or failure. + * \param status Indicates success or failure in terms of status code. + */ + virtual void complete(ServiceClientCallbackStatus status); + + /** + * \brief Indicates an error condition from the underlying clients like + * identity, connector or update client. + * \param error Indicates an error code translated to MbedCloudClient::Error. + * \param reason, Indicates human readable text for error description. + */ + virtual void error(int error, const char *reason); + + /** + * \brief A callback indicating that the value of the resource object is updated + * by the LWM2M Cloud server. + * \param base The object whose value is updated. + * \param type The type of the object. + */ + virtual void value_updated(M2MBase *base, M2MBase::BaseType type); + +private: + + /** + * \brief Registers the update callback functions for SimpleM2MResourceBase + * objects. + * \param route The URI path of the registered resource such as "/Test/0/res/". + * \param resource Object of the SimpleM2MResourceBase. + */ + void register_update_callback(string route, SimpleM2MResourceBase* resource); + +private: + + ServiceClient _client; + MbedCloudClientCallback *_value_callback; + map<string, M2MObject*> _objects; + map<string, M2MResource*> _resources; + M2MObjectList _object_list; + map<string, SimpleM2MResourceBase*> _update_values; + FP0<void> _on_registered; + FP0<void> _on_unregistered; + FP0<void> _on_registration_updated; + FP1<void,int> _on_error; + const char *_error_description; + + +friend class SimpleM2MResourceBase; +}; + +template<typename T> +void MbedCloudClient::on_registered(T *object, void (T::*member)(void)) +{ + FP0<void> fp(object, member); + _on_registered = fp; +} + +template<typename T> +void MbedCloudClient::on_error(T *object, void (T::*member)(int)) +{ + FP1<void, int> fp(object, member); + _on_error = fp; +} + +template<typename T> +void MbedCloudClient::on_unregistered(T *object, void (T::*member)(void)) +{ + FP0<void> fp(object, member); + _on_unregistered = fp; +} + +template<typename T> +void MbedCloudClient::on_registration_updated(T *object, void (T::*member)(void)) +{ + FP0<void> fp(object, member); + _on_registration_updated = fp; +} +#endif // __MBED_CLOUD_CLIENT_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-cloud-client/MbedCloudClientConfig.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-cloud-client/MbedCloudClientConfig.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,100 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MBED_CLOUD_CLIENT_CONFIG_H +#define MBED_CLOUD_CLIENT_CONFIG_H + +#include <stdint.h> + +/*! \file MbedCloudClientConfig.h +* \brief Configuration options (set of defines and values). +* +* This lists a set of compile-time options that needs to be used to enable +* or disable features selectively, and set the values for the mandatory +* parameters. +*/ + +#if defined (__ICCARM__) +#define m2m_deprecated +#else +#define m2m_deprecated __attribute__ ((deprecated)) +#endif + +#ifdef __DOXYGEN__ + +/** +* \def MBED_CLOUD_CLIENT_ENDPOINT_TYPE +* +* \brief This is mandatory MACRO and MUST be enabled. You MUST define it like this #define MBED_CLOUD_CLIENT_ENDPOINT_TYPE "default". +*/ +#define MBED_CLOUD_CLIENT_ENDPOINT_TYPE /* "default" */ + +/** +* \def MBED_CLOUD_CLIENT_LIFETIME +* +* \brief This is mandatory MACRO and MUST be enabled. You MUST define it like this: #define MBED_CLOUD_CLIENT_LIFETIME 3600. +* This value denotes time in seconds. +*/ +#define MBED_CLOUD_CLIENT_LIFETIME /* 3600 */ + +/** +* \def MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP +* +* \brief Enable this MACRO if you want to enable UDP mode for the client. +*/ +#define MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP + +/** +* \def MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP +* +* \brief Enable this MACRO if you want to enable TCP mode for the client. +*/ +#define MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP + +/** +* \def MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE +* +* \brief Enable this MACRO if you want to enable UDP_QUEUE mode for the client. +*/ +#define MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE + +/** +* \def MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE +* +* \brief Enable this MACRO if you want to enable TCP_QUEUE mode for the client. +*/ + +#define MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE + +#endif + +/** +* \def MBED_CLOUD_CLIENT_LISTEN_PORT +* +* \brief This is mandatory MACRO and is set to 0 by default. This implies that the client picks a random port + * for listening to the incoming connection. +*/ +#define MBED_CLOUD_CLIENT_LISTEN_PORT 0 + +#ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#include MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#endif + +#include "MbedCloudClientConfigCheck.h" + +#endif // MBED_CLOUD_CLIENT_CONFIG_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-cloud-client/MbedCloudClientConfigCheck.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-cloud-client/MbedCloudClientConfigCheck.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,75 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + + +#ifndef MBED_CLOUD_CONFIG_CHECK_H +#define MBED_CLOUD_CONFIG_CHECK_H + +/*! \file MbedCloudClientConfigCheck.h +* \brief Configuration options check. +* +* This set checks and validates the compile-time options that can be made for possible client library. +* NOTE: Not to be used by developers. +*/ + +#ifndef MBED_CLOUD_CLIENT_ENDPOINT_TYPE +#error "MBED_CLOUD_CLIENT_ENDPOINT_TYPE must be defined with valid endpoint type" +#endif + +#ifndef MBED_CLOUD_CLIENT_LIFETIME +#error "MBED_CLOUD_CLIENT_LIFETIME must be defined with valid non-zero lifetime value in seconds, default is 60" +#endif + +#ifndef MBED_CLOUD_CLIENT_LISTEN_PORT +#error "MBED_CLOUD_CLIENT_LISTEN_PORT must be defined with valid non-zero port number, default is 0" +#endif + +#if !defined (SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE) || (SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE < 16) +#error "SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE must be defined with one of the values from this - 128, 256, 512 or 1024" +#endif + +#if defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE) +#error "TCP queue mode not supported!" +#endif + +#if defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP) && ( defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP) || \ +defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE) || defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE)) +#error "Only one MBED_CLOUD_CLIENT_TRANSPORT_MODE can be defined at a time" +#endif + +#if defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP) && ( defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP) || \ +defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE) || defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE)) +#error "Only one MBED_CLOUD_CLIENT_TRANSPORT_MODE can be defined at a time" +#endif + +#if defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE) && ( defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP) || \ +defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP) || defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE)) +#error "Only one MBED_CLOUD_CLIENT_TRANSPORT_MODE can be defined at a time" +#endif + +#if defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE) && ( defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP) || \ +defined (MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE) || defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP)) +#error "Only one MBED_CLOUD_CLIENT_TRANSPORT_MODE can be defined at a time" +#endif + +#if !defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP) && !defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP) \ +&& !defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE) && !defined(MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE) +#error "One MBED_CLOUD_CLIENT_TRANSPORT_MODE must be defined at a time" +#endif + +#endif // MBED_CLOUD_CONFIG_CHECK_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-cloud-client/SimpleM2MResource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-cloud-client/SimpleM2MResource.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,279 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef SIMPLE_M2M_RESOURCE_H +#define SIMPLE_M2M_RESOURCE_H + + +#include "mbed-cloud-client/MbedCloudClient.h" + +/*! \file SimpleM2MResource.h + * \brief SimpleM2MResourceBase. + * This class provides an easy wrapper base class for creating a simple M2MResource based on + * integer and string values. This class is NOT meant to be directed instantiated but is used + * by the SimpleM2MResourceInt and SimpleM2MResourceString classes to create resources. + */ + +class SimpleM2MResourceBase { + +protected: + + // Prevents the use of default constructor. + SimpleM2MResourceBase(); + + // Prevents the use of assignment operator. + SimpleM2MResourceBase& operator=( const SimpleM2MResourceBase& /*other*/ ); + + // Prevents the use of copy constructor + SimpleM2MResourceBase( const M2MBase& /*other*/ ); + + SimpleM2MResourceBase(MbedCloudClient* client, string route); + + /** + * \brief Destructor + */ + virtual ~SimpleM2MResourceBase(); + + +public: + + /** + * \brief Defines M2MResource internally and creates a necessary LWM2M + * structure like object and object instance based on the given string + * URI path and sets the right M2M operation to the resource. + * \param v The URI path for the resource "Test/0/res" in this format. + * \param opr An operation to be set for the resource. + * \param observable True if the resource is observable, else false. + * \return True if resource is created, else false. + */ + bool define_resource_internal(string v, + M2MBase::Operation opr, + bool observable); + + /** + * \brief Gets the value set in a resource in text format. + * \return The value set in the resource. + */ + string get() const; + + /** + * \brief Sets the value in a resource in text format. + * \param v The value to be set. + * \return True if set successfully, else false. + */ + bool set(string v); + + /** + * \brief Sets the value in a resource in integer format. + * \param v The value to be set. + * \return True if set successfully, else false. + */ + bool set(const int& v); + + /** + * \brief Sets the callback function to be called + * when the resource received a POST command. + * \param fn A function to be called. + * This is used for a statically defined function. + * \return True if set successfully, else false. + */ + bool set_post_function(void(*fn)(void*)); + + /** + * \brief Sets the callback function to be called + * when a resource received the POST command. + * \param fn A function to be called. + * This is an overloaded function for a class function. + * \return True if set successfully, else false. + */ + bool set_post_function(execute_callback fn); + + /** + * \brief Returns the M2MResource object of the registered object through + * the SimpleM2MResourceBase objects. + * \return The object of the M2MResource. + */ + M2MResource* get_resource(); + + /** + * \brief Calls when there is an indication that the value of the resource + * object is updated by the LWM2M Cloud server. + */ + virtual void update(){} + +private: + + /** + * \brief An internal helper function to break the URI path into a list of + * strings such as "Test/0/res" into a list of three strings. + * \param route The URI path in the format "Test/0/res". + * \return A list of strings parsed from the URI path. + */ + vector<string> parse_route(const char* route); + +private: + MbedCloudClient* _client; // Not owned + string _route; +}; + +/** + * \brief SimpleM2MResourceString. + * This class provides an easy wrapper base class for creating a simple M2MResource based on + * string values. This class provides an easy access to the M2MResource objects without the application + * requiring to create Objects and Object Instances. + */ + +class SimpleM2MResourceString : public SimpleM2MResourceBase +{ +public: + + /** + * \brief Constructor. + * \param client A handler for MbedCloudClient. + * \param route The route for the resource such as "Test/0/res". + * \param v The value of the resource. + * \param opr An operation that can be supported by the resource. + * \param observable True if the resource is observable. + * \param on_update If the resource supports the PUT operation, a function pointer + * for the callback function that is called when the client receives an + * updated value for this resource. + */ + SimpleM2MResourceString(MbedCloudClient* client, + const char* route, + string v, + M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED, + bool observable = true, + FP1<void, string> on_update = NULL); + + /** + * \brief Constructor. This is overloaded function. + * \param client A handler for MbedCloudClient. + * \param route The route for the resource such as "Test/0/res". + * \param v The value of the resource. + * \param opr An operation that can be supported by the resource. + * \param observable True if resource is observable. + * \param on_update If the resource supports the PUT operation, a function pointer + * for the callback function that is called when the client receives an + * updated value for this resource. + */ + SimpleM2MResourceString(MbedCloudClient* client, + const char* route, + string v, + M2MBase::Operation opr, + bool observable, + void(*on_update)(string)); + + + /** + * \brief Destructor + */ + virtual ~SimpleM2MResourceString(); + + /** + * \brief Overloaded operator for = operation. + */ + string operator=(const string& new_value); + + /** + * \brief Overloaded operator for string() operation. + */ + operator string() const; + + /** + * \brief Calls when there is an indication that the value of the resource + * object is updated by the LWM2M Cloud server. + */ + virtual void update(); + +private: + FP1<void, string> _on_update; +}; + +/** + * \brief SimpleM2MResourceInt. + * This class provides an easy wrapper base class for creating a simple M2MResource based on + * integer values. This class provides easy access to M2MResource objects without the application + * requiring to create Objects and Object Instances. + */ + +class SimpleM2MResourceInt : public SimpleM2MResourceBase +{ +public: + + /** + * \brief Constructor. + * \param client A handler for MbedCloudClient. + * \param route The route for the resource such as "Test/0/res". + * \param v The value of the resource. + * \param opr An operation that can be supported by the resource. + * \param observable True if the resource is observable, else false. + * \param on_update If the resource supports the PUT operation, a function pointer + * for the callback function that is called when the client receives an + * updated value for this resource. + */ + SimpleM2MResourceInt(MbedCloudClient* client, + const char* route, + int v, + M2MBase::Operation opr = M2MBase::GET_PUT_ALLOWED, + bool observable = true, + FP1<void, int> on_update = NULL); + + /** + * \brief Constructor. This is an overloaded function + * \param client A handler for MbedCloudClient. + * \param route The route for the resource such as "Test/0/res" + * \param v The value of the resource. + * \param opr An operation that can be supported by the resource. + * \param observable True if the resource is observable, else false. + * \param on_update If the resource supports the PUT operation, a function pointer + * for the callback function that is called when the client receives an + * updated value for this resource. + */ + SimpleM2MResourceInt(MbedCloudClient* client, + const char* route, + int v, + M2MBase::Operation opr, + bool observable, + void(*on_update)(int)); + + /** + * \brief Destructor + */ + virtual ~SimpleM2MResourceInt(); + + /** + * \brief Overloaded operator for = operation. + */ + int operator=(int new_value); + + /** + * \brief Overloaded operator for int() operation. + */ + operator int() const; + + /** + * \brief Calls when there is an indication that the value of the resource + * object is updated by the LWM2M Cloud server. + */ + virtual void update(); + +private: + FP1<void, int> _on_update; +}; + +#endif // SIMPLE_M2M_RESOURCE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +test/* +unittest/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/README.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +CoAP C library - Builder and Parser for CoAP messages.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/apache-2.0.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/doxygen/libcoap_doxy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/doxygen/libcoap_doxy Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1846 @@ +# Doxyfile 1.8.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = libcoap + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "CoAP C library" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 16 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = YES + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 18 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../nsdl-c + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 44 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/mbed-coap/sn_coap_header.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/mbed-coap/sn_coap_header.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file sn_coap_header.h + * + * \brief CoAP C-library User header interface header file + */ + +#ifndef SN_COAP_HEADER_H_ +#define SN_COAP_HEADER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Handle structure */ +struct coap_s; + +/* * * * * * * * * * * * * * */ +/* * * * ENUMERATIONS * * * */ +/* * * * * * * * * * * * * * */ + +/** + * \brief Enumeration for CoAP Version + */ +typedef enum coap_version_ { + COAP_VERSION_1 = 0x40, + COAP_VERSION_UNKNOWN = 0xFF +} coap_version_e; + +/** + * \brief Enumeration for CoAP Message type, used in CoAP Header + */ +typedef enum sn_coap_msg_type_ { + COAP_MSG_TYPE_CONFIRMABLE = 0x00, /**< Reliable Request messages */ + COAP_MSG_TYPE_NON_CONFIRMABLE = 0x10, /**< Non-reliable Request and Response messages */ + COAP_MSG_TYPE_ACKNOWLEDGEMENT = 0x20, /**< Response to a Confirmable Request */ + COAP_MSG_TYPE_RESET = 0x30 /**< Answer a Bad Request */ +} sn_coap_msg_type_e; + +/** + * \brief Enumeration for CoAP Message code, used in CoAP Header + */ +typedef enum sn_coap_msg_code_ { + COAP_MSG_CODE_EMPTY = 0, + COAP_MSG_CODE_REQUEST_GET = 1, + COAP_MSG_CODE_REQUEST_POST = 2, + COAP_MSG_CODE_REQUEST_PUT = 3, + COAP_MSG_CODE_REQUEST_DELETE = 4, + + COAP_MSG_CODE_RESPONSE_CREATED = 65, + COAP_MSG_CODE_RESPONSE_DELETED = 66, + COAP_MSG_CODE_RESPONSE_VALID = 67, + COAP_MSG_CODE_RESPONSE_CHANGED = 68, + COAP_MSG_CODE_RESPONSE_CONTENT = 69, + COAP_MSG_CODE_RESPONSE_CONTINUE = 95, + COAP_MSG_CODE_RESPONSE_BAD_REQUEST = 128, + COAP_MSG_CODE_RESPONSE_UNAUTHORIZED = 129, + COAP_MSG_CODE_RESPONSE_BAD_OPTION = 130, + COAP_MSG_CODE_RESPONSE_FORBIDDEN = 131, + COAP_MSG_CODE_RESPONSE_NOT_FOUND = 132, + COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED = 133, + COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE = 134, + COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE = 136, + COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED = 140, + COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE = 141, + COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT = 143, + COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR = 160, + COAP_MSG_CODE_RESPONSE_NOT_IMPLEMENTED = 161, + COAP_MSG_CODE_RESPONSE_BAD_GATEWAY = 162, + COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE = 163, + COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT = 164, + COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED = 165 +} sn_coap_msg_code_e; + +/** + * \brief Enumeration for CoAP Option number, used in CoAP Header + */ +typedef enum sn_coap_option_numbers_ { + COAP_OPTION_IF_MATCH = 1, + COAP_OPTION_URI_HOST = 3, + COAP_OPTION_ETAG = 4, + COAP_OPTION_IF_NONE_MATCH = 5, + COAP_OPTION_OBSERVE = 6, + COAP_OPTION_URI_PORT = 7, + COAP_OPTION_LOCATION_PATH = 8, + COAP_OPTION_URI_PATH = 11, + COAP_OPTION_CONTENT_FORMAT = 12, + COAP_OPTION_MAX_AGE = 14, + COAP_OPTION_URI_QUERY = 15, + COAP_OPTION_ACCEPT = 17, + COAP_OPTION_LOCATION_QUERY = 20, + COAP_OPTION_BLOCK2 = 23, + COAP_OPTION_BLOCK1 = 27, + COAP_OPTION_SIZE2 = 28, + COAP_OPTION_PROXY_URI = 35, + COAP_OPTION_PROXY_SCHEME = 39, + COAP_OPTION_SIZE1 = 60 +// 128 = (Reserved) +// 132 = (Reserved) +// 136 = (Reserved) +} sn_coap_option_numbers_e; + +/** + * \brief Enumeration for CoAP Content Format codes + */ +typedef enum sn_coap_content_format_ { + COAP_CT_NONE = -1, // internal + COAP_CT_TEXT_PLAIN = 0, + COAP_CT_LINK_FORMAT = 40, + COAP_CT_XML = 41, + COAP_CT_OCTET_STREAM = 42, + COAP_CT_EXI = 47, + COAP_CT_JSON = 50, + COAP_CT__MAX = 0xffff +} sn_coap_content_format_e; + +/** + * \brief Enumeration for CoAP Observe option values + * + * draft-ietf-core-observe-16 + */ +typedef enum sn_coap_observe_ { + COAP_OBSERVE_NONE = -1, // internal + + // Values for GET requests + COAP_OBSERVE_REGISTER = 0, + COAP_OBSERVE_DEREGISTER = 1, + + // In responses, value is a 24-bit opaque sequence number + COAP_OBSERVE__MAX = 0xffffff +} sn_coap_observe_e; + +/** + * \brief Enumeration for CoAP status, used in CoAP Header + */ +typedef enum sn_coap_status_ { + COAP_STATUS_OK = 0, /**< Default value is OK */ + COAP_STATUS_PARSER_ERROR_IN_HEADER = 1, /**< CoAP will send Reset message to invalid message sender */ + COAP_STATUS_PARSER_DUPLICATED_MSG = 2, /**< CoAP will send Acknowledgement message to duplicated message sender */ + COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING = 3, /**< User will get whole message after all message blocks received. + User must release messages with this status. */ + COAP_STATUS_PARSER_BLOCKWISE_ACK = 4, /**< Acknowledgement for sent Blockwise message received */ + COAP_STATUS_PARSER_BLOCKWISE_MSG_REJECTED = 5, /**< Blockwise message received but not supported by compiling switch */ + COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED = 6, /**< Blockwise message fully received and returned to app. + User must take care of releasing whole payload of the blockwise messages */ + COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED = 7 /**< When re-transmissions have been done and ACK not received, CoAP library calls + RX callback with this status */ +} sn_coap_status_e; + + +/* * * * * * * * * * * * * */ +/* * * * STRUCTURES * * * */ +/* * * * * * * * * * * * * */ + +/** + * \brief Structure for CoAP Options + */ +typedef struct sn_coap_options_list_ { + uint8_t etag_len; /**< 1-8 bytes. Repeatable */ + unsigned int use_size1:1; + unsigned int use_size2:1; + + uint16_t proxy_uri_len; /**< 1-1034 bytes. */ + uint16_t uri_host_len; /**< 1-255 bytes. */ + uint16_t location_path_len; /**< 0-255 bytes. Repeatable */ + uint16_t location_query_len; /**< 0-255 bytes. Repeatable */ + uint16_t uri_query_len; /**< 1-255 bytes. Repeatable */ + + sn_coap_content_format_e accept; /**< Value 0-65535. COAP_CT_NONE if not used */ + + uint32_t max_age; /**< Value in seconds (default is 60) */ + uint32_t size1; /**< 0-4 bytes. */ + uint32_t size2; /**< 0-4 bytes. */ + int32_t uri_port; /**< Value 0-65535. -1 if not used */ + int32_t observe; /**< Value 0-0xffffff. -1 if not used */ + int32_t block1; /**< Value 0-0xffffff. -1 if not used. Not for user */ + int32_t block2; /**< Value 0-0xffffff. -1 if not used. Not for user */ + + uint8_t *proxy_uri_ptr; /**< Must be set to NULL if not used */ + uint8_t *etag_ptr; /**< Must be set to NULL if not used */ + uint8_t *uri_host_ptr; /**< Must be set to NULL if not used */ + uint8_t *location_path_ptr; /**< Must be set to NULL if not used */ + uint8_t *location_query_ptr; /**< Must be set to NULL if not used */ + uint8_t *uri_query_ptr; /**< Must be set to NULL if not used */ +} sn_coap_options_list_s; + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!! Main CoAP message struct !!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +/** + * \brief Main CoAP message struct + */ +typedef struct sn_coap_hdr_ { + uint8_t token_len; /**< 1-8 bytes. */ + + sn_coap_status_e coap_status; /**< Used for telling to User special cases when parsing message */ + sn_coap_msg_code_e msg_code; /**< Empty: 0; Requests: 1-31; Responses: 64-191 */ + + sn_coap_msg_type_e msg_type; /**< Confirmable, Non-Confirmable, Acknowledgement or Reset */ + sn_coap_content_format_e content_format; /**< Set to COAP_CT_NONE if not used */ + + uint16_t msg_id; /**< Message ID. Parser sets parsed message ID, builder sets message ID of built coap message */ + uint16_t uri_path_len; /**< 0-255 bytes. Repeatable. */ + uint16_t payload_len; /**< Must be set to zero if not used */ + + uint8_t *token_ptr; /**< Must be set to NULL if not used */ + uint8_t *uri_path_ptr; /**< Must be set to NULL if not used. E.g: temp1/temp2 */ + uint8_t *payload_ptr; /**< Must be set to NULL if not used */ + + /* Here are not so often used Options */ + sn_coap_options_list_s *options_list_ptr; /**< Must be set to NULL if not used */ +} sn_coap_hdr_s; + +/* * * * * * * * * * * * * * */ +/* * * * ENUMERATIONS * * * */ +/* * * * * * * * * * * * * * */ + + +/** + * \brief Used protocol + */ +typedef enum sn_nsdl_capab_ { + SN_NSDL_PROTOCOL_HTTP = 0x01, /**< Unsupported */ + SN_NSDL_PROTOCOL_HTTPS = 0x02, /**< Unsupported */ + SN_NSDL_PROTOCOL_COAP = 0x04 /**< Supported */ +} sn_nsdl_capab_e; + +/* * * * * * * * * * * * * */ +/* * * * STRUCTURES * * * */ +/* * * * * * * * * * * * * */ + + +/** + * \brief Used for creating manually registration message with sn_coap_register() + */ +typedef struct registration_info_ { + uint8_t endpoint_len; + uint8_t endpoint_type_len; + uint16_t links_len; + + uint8_t *endpoint_ptr; /**< Endpoint name */ + uint8_t *endpoint_type_ptr; /**< Endpoint type */ + uint8_t *links_ptr; /**< Resource registration string */ +} registration_info_t; + + +/** + * \brief Address type of given address + */ +typedef enum sn_nsdl_addr_type_ { + SN_NSDL_ADDRESS_TYPE_IPV6 = 0x01, /**< Supported */ + SN_NSDL_ADDRESS_TYPE_IPV4 = 0x02, /**< Supported */ + SN_NSDL_ADDRESS_TYPE_HOSTNAME = 0x03, /**< Unsupported */ + SN_NSDL_ADDRESS_TYPE_NONE = 0xFF +} sn_nsdl_addr_type_e; + +/** + * \brief Address structure of Packet data + */ +typedef struct sn_nsdl_addr_ { + uint8_t addr_len; + sn_nsdl_addr_type_e type; + uint16_t port; + uint8_t *addr_ptr; +} sn_nsdl_addr_s; + + +/* * * * * * * * * * * * * * * * * * * * * * */ +/* * * * EXTERNAL FUNCTION PROTOTYPES * * * */ +/* * * * * * * * * * * * * * * * * * * * * * */ +/** + * \fn sn_coap_hdr_s *sn_coap_parser(struct coap_s *handle, uint16_t packet_data_len, uint8_t *packet_data_ptr, coap_version_e *coap_version_ptr) + * + * \brief Parses CoAP message from given Packet data + * + * \param *handle Pointer to CoAP library handle + * + * \param packet_data_len is length of given Packet data to be parsed to CoAP message + * + * \param *packet_data_ptr is source for Packet data to be parsed to CoAP message + * + * \param *coap_version_ptr is destination for parsed CoAP specification version + * + * \return Return value is pointer to parsed CoAP message.\n + * In following failure cases NULL is returned:\n + * -Failure in given pointer (= NULL)\n + * -Failure in memory allocation (malloc() returns NULL) + */ +extern sn_coap_hdr_s *sn_coap_parser(struct coap_s *handle, uint16_t packet_data_len, uint8_t *packet_data_ptr, coap_version_e *coap_version_ptr); + +/** + * \fn void sn_coap_parser_release_allocated_coap_msg_mem(struct coap_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr) + * + * \brief Releases memory of given CoAP message + * + * Note!!! Does not release Payload part + * + * \param *handle Pointer to CoAP library handle + * + * \param *freed_coap_msg_ptr is pointer to released CoAP message + */ +extern void sn_coap_parser_release_allocated_coap_msg_mem(struct coap_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr); + +/** + * \fn int16_t sn_coap_builder(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr) + * + * \brief Builds an outgoing message buffer from a CoAP header structure. + * + * \param *dst_packet_data_ptr is pointer to allocated destination to built CoAP packet + * + * \param *src_coap_msg_ptr is pointer to source structure for building Packet data + * + * \return Return value is byte count of built Packet data. In failure cases:\n + * -1 = Failure in given CoAP header structure\n + * -2 = Failure in given pointer (= NULL) + */ +extern int16_t sn_coap_builder(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr); + +/** + * \fn uint16_t sn_coap_builder_calc_needed_packet_data_size(sn_coap_hdr_s *src_coap_msg_ptr) + * + * \brief Calculates needed Packet data memory size for given CoAP message + * + * \param *src_coap_msg_ptr is pointer to data which needed Packet + * data length is calculated + * + * \return Return value is count of needed memory as bytes for build Packet data + * Null if failed + */ +extern uint16_t sn_coap_builder_calc_needed_packet_data_size(sn_coap_hdr_s *src_coap_msg_ptr); + +/** + * \fn int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_size) + * + * \brief Builds an outgoing message buffer from a CoAP header structure. + * + * \param *dst_packet_data_ptr is pointer to allocated destination to built CoAP packet + * + * \param *src_coap_msg_ptr is pointer to source structure for building Packet data + * + * \param blockwise_payload_size Blockwise message maximum payload size + * + * \return Return value is byte count of built Packet data. In failure cases:\n + * -1 = Failure in given CoAP header structure\n + * -2 = Failure in given pointer (= NULL) + */ +extern int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size); + +/** + * \fn uint16_t sn_coap_builder_calc_needed_packet_data_size_2(sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size) + * + * \brief Calculates needed Packet data memory size for given CoAP message + * + * \param *src_coap_msg_ptr is pointer to data which needed Packet + * data length is calculated + * \param blockwise_payload_size Blockwise message maximum payload size + * + * \return Return value is count of needed memory as bytes for build Packet data + * Null if failed + */ +extern uint16_t sn_coap_builder_calc_needed_packet_data_size_2(sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size); + +/** + * \fn sn_coap_hdr_s *sn_coap_build_response(struct coap_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code) + * + * \brief Prepares generic response packet from a request packet. This function allocates memory for the resulting sn_coap_hdr_s + * + * \param *handle Pointer to CoAP library handle + * \param *coap_packet_ptr The request packet pointer + * \param msg_code response messages code + * + * \return *coap_packet_ptr The allocated and pre-filled response packet pointer + * NULL Error in parsing the request + * + */ +extern sn_coap_hdr_s *sn_coap_build_response(struct coap_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code); + +/** + * \brief Initialise a message structure to empty + * + * \param *coap_msg_ptr is pointer to CoAP message to initialise + * + * \return Return value is pointer passed in + */ +extern sn_coap_hdr_s *sn_coap_parser_init_message(sn_coap_hdr_s *coap_msg_ptr); + +/** + * \brief Allocate an empty message structure + * + * \param *handle Pointer to CoAP library handle + * + * \return Return value is pointer to an empty CoAP message.\n + * In following failure cases NULL is returned:\n + * -Failure in given pointer (= NULL)\n + * -Failure in memory allocation (malloc() returns NULL) + */ +extern sn_coap_hdr_s *sn_coap_parser_alloc_message(struct coap_s *handle); + +/** + * \brief Allocates and initializes options list structure + * + * \param *handle Pointer to CoAP library handle + * \param *coap_msg_ptr is pointer to CoAP message that will contain the options + * + * If the message already has a pointer to an option structure, that pointer + * is returned, rather than a new structure being allocated. + * + * \return Return value is pointer to the CoAP options structure.\n + * In following failure cases NULL is returned:\n + * -Failure in given pointer (= NULL)\n + * -Failure in memory allocation (malloc() returns NULL) + */ +extern sn_coap_options_list_s *sn_coap_parser_alloc_options(struct coap_s *handle, sn_coap_hdr_s *coap_msg_ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* SN_COAP_HEADER_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/mbed-coap/sn_coap_protocol.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/mbed-coap/sn_coap_protocol.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file sn_coap_protocol.h + * + * \brief CoAP C-library User protocol interface header file + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SN_COAP_PROTOCOL_H_ +#define SN_COAP_PROTOCOL_H_ + +#include "sn_coap_header.h" + +/** + * \fn struct coap_s *sn_coap_protocol_init(void* (*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void*), + uint8_t (*used_tx_callback_ptr)(sn_nsdl_capab_e , uint8_t *, uint16_t, sn_nsdl_addr_s *), + int8_t (*used_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *) + * + * \brief Initializes CoAP Protocol part. When using libNsdl, sn_nsdl_init() calls this function. + * + * \param *used_malloc_func_ptr is function pointer for used memory allocation function. + * + * \param *used_free_func_ptr is function pointer for used memory free function. + * + * \param *used_tx_callback_ptr function callback pointer to tx function for sending coap messages + * + * \param *used_rx_callback_ptr used to return CoAP header struct with status COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED + * when re-sendings exceeded. If set to NULL, no error message is returned. + * + * \return Pointer to handle when success + * Null if failed + */ + +extern struct coap_s *sn_coap_protocol_init(void *(*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void *), + uint8_t (*used_tx_callback_ptr)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *), + int8_t (*used_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *, void *)); + +/** + * \fn int8_t sn_coap_protocol_destroy(void) + * + * \brief Frees all memory from CoAP protocol part + * + * \param *handle Pointer to CoAP library handle + * + * \return Return value is always 0 + */ +extern int8_t sn_coap_protocol_destroy(struct coap_s *handle); + +/** + * \fn int16_t sn_coap_protocol_build(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, void *param) + * + * \brief Builds Packet data from given CoAP header structure to be sent + * + * \param *dst_addr_ptr is pointer to destination address where CoAP message + * will be sent (CoAP builder needs that information for message resending purposes) + * + * \param *dst_packet_data_ptr is pointer to destination of built Packet data + * + * \param *src_coap_msg_ptr is pointer to source of built Packet data + * + * \param param void pointer that will be passed to tx/rx function callback when those are called. + * + * \return Return value is byte count of built Packet data.\n + * Note: If message is blockwised, all payload is not sent at the same time\n + * In failure cases:\n + * -1 = Failure in CoAP header structure\n + * -2 = Failure in given pointer (= NULL)\n + * -3 = Failure in Reset message\n + * -4 = Failure in Resending message store\n + * If there is not enough memory (or User given limit exceeded) for storing + * resending messages, situation is ignored. + */ +extern int16_t sn_coap_protocol_build(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, void *param); + +/** + * \fn sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t packet_data_len, uint8_t *packet_data_ptr) + * + * \brief Parses received CoAP message from given Packet data + * + * \param *src_addr_ptr is pointer to source address of received CoAP message + * (CoAP parser needs that information for Message acknowledgement) + * + * \param *handle Pointer to CoAP library handle + * + * \param packet_data_len is length of given Packet data to be parsed to CoAP message + * + * \param *packet_data_ptr is pointer to source of Packet data to be parsed to CoAP message + * + * \param param void pointer that will be passed to tx/rx function callback when those are called. + * + * \return Return value is pointer to parsed CoAP message structure. This structure includes also coap_status field.\n + * In following failure cases NULL is returned:\n + * -Given NULL pointer\n + * -Failure in parsed header of non-confirmable message\Å + * -Out of memory (malloc() returns NULL) + */ +extern sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t packet_data_len, uint8_t *packet_data_ptr, void *); + +/** + * \fn int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time) + * + * \brief Sends CoAP messages from re-sending queue, if there is any. + * Cleans also old messages from the duplication list and from block receiving list + * + * This function can be called e.g. once in a second but also more frequently. + * + * \param *handle Pointer to CoAP library handle + * + * \param current_time is System time in seconds. This time is + * used for message re-sending timing and to identify old saved data. + * + * \return 0 if success + * -1 if failed + */ + +extern int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time); + +/** + * \fn int8_t sn_coap_protocol_set_block_size(uint16_t block_size) + * + * \brief If block transfer is enabled, this function changes the block size. + * + * \param uint16_t block_size maximum size of CoAP payload. Valid sizes are 16, 32, 64, 128, 256, 512 and 1024 bytes + * \return 0 = success + * -1 = failure + */ +extern int8_t sn_coap_protocol_set_block_size(struct coap_s *handle, uint16_t block_size); + +/** + * \fn int8_t sn_coap_protocol_set_duplicate_buffer_size(uint8_t message_count) + * + * \brief If dublicate message detection is enabled, this function changes buffer size. + * + * \param uint8_t message_count max number of messages saved for duplicate control + * \return 0 = success + * -1 = failure + */ +extern int8_t sn_coap_protocol_set_duplicate_buffer_size(struct coap_s *handle, uint8_t message_count); + +/** + * \fn int8_t sn_coap_protocol_set_retransmission_parameters(uint8_t resending_count, uint8_t resending_intervall) + * + * \brief If re-transmissions are enabled, this function changes resending count and interval. + * + * \param uint8_t resending_count max number of resendings for message + * \param uint8_t resending_intervall message resending intervall in seconds + * \return 0 = success, -1 = failure + */ +extern int8_t sn_coap_protocol_set_retransmission_parameters(struct coap_s *handle, + uint8_t resending_count, uint8_t resending_interval); + +/** + * \fn int8_t sn_coap_protocol_set_retransmission_buffer(uint8_t buffer_size_messages, uint16_t buffer_size_bytes) + * + * \brief If re-transmissions are enabled, this function changes message retransmission queue size. + * Set size to '0' to disable feature. If both are set to '0', then re-sendings are disabled. + * + * \param uint8_t buffer_size_messages queue size - maximum number of messages to be saved to queue + * \param uint8_t buffer_size_bytes queue size - maximum size of messages saved to queue + * \return 0 = success, -1 = failure + */ +extern int8_t sn_coap_protocol_set_retransmission_buffer(struct coap_s *handle, + uint8_t buffer_size_messages, uint16_t buffer_size_bytes); + +/** + * \fn void sn_coap_protocol_clear_retransmission_buffer(struct coap_s *handle) + * + * \param *handle Pointer to CoAP library handle + * + * \brief If re-transmissions are enabled, this function removes all messages from the retransmission queue. + */ +extern void sn_coap_protocol_clear_retransmission_buffer(struct coap_s *handle); + +/** + * \fn sn_coap_protocol_block_remove + * + * \brief Remove saved block data. Can be used to remove the data from RAM to enable storing it to other place. + * + * \param handle Pointer to CoAP library handle + * \param source_address Addres from where the block has been received. + * \param payload_length Length of the coap payload of the block. + * \param payload Coap payload of the block. + * + */ +extern void sn_coap_protocol_block_remove(struct coap_s *handle, sn_nsdl_addr_s *source_address, uint16_t payload_length, void *payload); + +/** + * \fn void sn_coap_protocol_delete_retransmission(struct coap_s *handle) + * + * \param *handle Pointer to CoAP library handle + * \msg_id message ID to be removed + * \return returns 0 when success, -1 for invalid parameter, -2 if message was not found + * + * \brief If re-transmissions are enabled, this function removes message from retransmission buffer. + */ +extern int8_t sn_coap_protocol_delete_retransmission(struct coap_s *handle, uint16_t msg_id); + +/** + * \fn int8_t sn_coap_convert_block_size(uint16_t block_size) + * + * \brief Utility function to convert block size. + * + * \param block_size Block size to convert. + * + * \return Value of range 0 - 6 + */ +extern int8_t sn_coap_convert_block_size(uint16_t block_size); + +/** + * \fn int8_t sn_coap_protocol_handle_block2_response_internally(struct coap_s *handle, uint8_t handle_response) + * + * \brief This function change the state whether CoAP library sends the block 2 response automatically or not. + * + * \param *handle Pointer to CoAP library handle + * \param handle_response 1 if CoAP library handles the response sending otherwise 0. + * + * \return 0 = success, -1 = failure + */ +extern int8_t sn_coap_protocol_handle_block2_response_internally(struct coap_s *handle, uint8_t handle_response); + +#endif /* SN_COAP_PROTOCOL_H_ */ + +#ifdef __cplusplus +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/mbed-coap/sn_config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/mbed-coap/sn_config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SN_CONFIG_H +#define SN_CONFIG_H + +/** +* \brief Configuration options (set of defines and values) +* +* This lists set of compile-time options that needs to be used to enable +* or disable features selectively, and set the values for the mandatory +* parameters. +*/ + +/** + * \def SN_COAP_DUPLICATION_MAX_MSGS_COUNT + * \brief For Message duplication detection + * Init value for the maximum count of messages to be stored for duplication detection + * Setting of this value to 0 will disable duplication check, also reduce use of ROM memory + * Default is set to 1. + */ +#undef SN_COAP_DUPLICATION_MAX_MSGS_COUNT /* 1 */ + +/** + * \def SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + * + * \brief For Message blockwising + * Init value for the maximum payload size to be sent and received at one blockwise message + * Setting of this value to 0 will disable this feature, and also reduce use of ROM memory + * Note: This define is common for both received and sent Blockwise messages + */ +#undef SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* 0 */ // < Must be 2^x and x is at least 4. Suitable values: 0, 16, 32, 64, 128, 256, 512 and 1024 + +/** + * \def COAP_DISABLE_OBS_FEATURE + * + * \brief Disables CoAP 'obs' sending feature + * as part of registration message, this might be + * needed to be enabled for some strict LWM2M server implementation. + * By default, this feature is disabled. + */ +#undef COAP_DISABLE_OBS_FEATURE + +/** + * \def SN_COAP_RESENDING_QUEUE_SIZE_MSGS + * + * \brief Sets the number of messages stored + * in the resending queue. Default is 2 + */ +#undef SN_COAP_RESENDING_QUEUE_SIZE_MSGS /* 2 */ // < Default re-sending queue size - defines how many messages can be stored. Setting this to 0 disables feature + +/** + * \def SN_COAP_RESENDING_QUEUE_SIZE_BYTES + * + * \brief Sets the size of the re-sending buffer. + * Setting this to 0 disables this feature. + * By default, this feature is disabled. + */ +#undef SN_COAP_RESENDING_QUEUE_SIZE_BYTES /* 0 */ // Default re-sending queue size - defines size of the re-sending buffer. Setting this to 0 disables feature + +/** + * \def SN_COAP_MAX_INCOMING_MESSAGE_SIZE + * + * \brief Sets the maximum size (in bytes) that + * mbed Client will allow to be handled while + * receiving big payload in blockwise mode. + * Application can set this value based on their + * available storage capability. + * By default, maximum size is UINT16_MAX, 65535 bytes. + */ +#undef SN_COAP_MAX_INCOMING_MESSAGE_SIZE /* UINT16_MAX */ + +#ifdef MBED_CLIENT_USER_CONFIG_FILE +#include MBED_CLIENT_USER_CONFIG_FILE +#endif + +#endif // SN_CONFIG_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/include/sn_coap_header_internal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/include/sn_coap_header_internal.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file sn_coap_header_internal.h + * + * \brief Header file for CoAP Header part + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SN_COAP_HEADER_INTERNAL_H_ +#define SN_COAP_HEADER_INTERNAL_H_ + + +/* * * * * * * * * * * */ +/* * * * DEFINES * * * */ +/* * * * * * * * * * * */ + +#define COAP_VERSION COAP_VERSION_1 /* Tells which IETF CoAP specification version the CoAP message supports. */ +/* This value is written to CoAP message header part. */ + +/* CoAP Header defines */ +#define COAP_HEADER_LENGTH 4 /* Fixed Header length of CoAP message as bytes */ +#define COAP_HEADER_VERSION_MASK 0xC0 +#define COAP_HEADER_MSG_TYPE_MASK 0x30 +#define COAP_HEADER_TOKEN_LENGTH_MASK 0x0F +#define COAP_HEADER_MSG_ID_MSB_SHIFT 8 + +/* CoAP Options defines */ +#define COAP_OPTIONS_OPTION_NUMBER_SHIFT 4 + +/* * * * * * * * * * * * * * */ +/* * * * ENUMERATIONS * * * */ +/* * * * * * * * * * * * * * */ + +/* * * * * * * * * * * * * */ +/* * * * STRUCTURES * * * */ +/* * * * * * * * * * * * * */ + +/** + * \brief This structure is returned by sn_coap_exec() for sending + */ +typedef struct sn_nsdl_transmit_ { + sn_nsdl_addr_s *dst_addr_ptr; + + sn_nsdl_capab_e protocol; + + uint16_t packet_len; + uint8_t *packet_ptr; +} sn_nsdl_transmit_s; + +/* * * * * * * * * * * * * * * * * * * * * * */ +/* * * * EXTERNAL FUNCTION PROTOTYPES * * * */ +/* * * * * * * * * * * * * * * * * * * * * * */ +extern int8_t sn_coap_header_validity_check(sn_coap_hdr_s *src_coap_msg_ptr, coap_version_e coap_version); + +#endif /* SN_COAP_HEADER_INTERNAL_H_ */ + +#ifdef __cplusplus +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/include/sn_coap_protocol_internal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/include/sn_coap_protocol_internal.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file sn_coap_protocol_internal.h + * + * \brief Header file for CoAP Protocol part + * + */ + +#ifndef SN_COAP_PROTOCOL_INTERNAL_H_ +#define SN_COAP_PROTOCOL_INTERNAL_H_ + +#include "ns_list.h" +#include "sn_coap_header_internal.h" +#include "mbed-coap/sn_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct sn_coap_hdr_; + +/* * * * * * * * * * * */ +/* * * * DEFINES * * * */ +/* * * * * * * * * * * */ + +/* * For Message resending * */ +#define ENABLE_RESENDINGS 1 /**< Enable / Disable resending from library in building */ + +#define SN_COAP_RESENDING_MAX_COUNT 3 /**< Default number of re-sendings */ + +#ifdef YOTTA_CFG_COAP_RESENDING_QUEUE_SIZE_MSGS +#define SN_COAP_RESENDING_QUEUE_SIZE_MSGS YOTTA_CFG_COAP_RESENDING_QUEUE_SIZE_MSGS +#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_RESENDING_QUEUE_SIZE_MSGS +#define SN_COAP_RESENDING_QUEUE_SIZE_MSGS MBED_CONF_MBED_CLIENT_SN_COAP_RESENDING_QUEUE_SIZE_MSGS +#endif + +#ifndef SN_COAP_RESENDING_QUEUE_SIZE_MSGS +#define SN_COAP_RESENDING_QUEUE_SIZE_MSGS 2 /**< Default re-sending queue size - defines how many messages can be stored. Setting this to 0 disables feature */ +#endif + +#ifdef YOTTA_CFG_COAP_RESENDING_QUEUE_SIZE_BYTES +#define SN_COAP_RESENDING_QUEUE_SIZE_BYTES YOTTA_CFG_COAP_RESENDING_QUEUE_SIZE_BYTES +#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_RESENDING_QUEUE_SIZE_BYTES +#define SN_COAP_RESENDING_QUEUE_SIZE_BYTES MBED_CONF_MBED_CLIENT_SN_COAP_RESENDING_QUEUE_SIZE_BYTES +#endif + +#ifndef SN_COAP_RESENDING_QUEUE_SIZE_BYTES +#define SN_COAP_RESENDING_QUEUE_SIZE_BYTES 0 /**< Default re-sending queue size - defines size of the re-sending buffer. Setting this to 0 disables feature */ +#endif + +#define DEFAULT_RESPONSE_TIMEOUT 10 /**< Default re-sending timeout as seconds */ + +/* These parameters sets maximum values application can set with API */ +#define SN_COAP_MAX_ALLOWED_RESENDING_COUNT 6 /**< Maximum allowed count of re-sending */ +#define SN_COAP_MAX_ALLOWED_RESENDING_BUFF_SIZE_MSGS 6 /**< Maximum allowed number of saved re-sending messages */ +#define SN_COAP_MAX_ALLOWED_RESENDING_BUFF_SIZE_BYTES 512 /**< Maximum allowed size of re-sending buffer */ +#define SN_COAP_MAX_ALLOWED_RESPONSE_TIMEOUT 40 /**< Maximum allowed re-sending timeout */ + +#define RESPONSE_RANDOM_FACTOR 1.5 /**< Resending random factor, value is specified in IETF CoAP specification */ + +/* * For Message duplication detecting * */ + +/* Init value for the maximum count of messages to be stored for duplication detection */ +/* Setting of this value to 0 will disable duplication check, also reduce use of ROM memory */ + +// Keep the old flag to maintain backward compatibility +#ifndef SN_COAP_DUPLICATION_MAX_MSGS_COUNT +#define SN_COAP_DUPLICATION_MAX_MSGS_COUNT 0 +#endif + +#ifdef YOTTA_CFG_COAP_DUPLICATION_MAX_MSGS_COUNT +#define SN_COAP_DUPLICATION_MAX_MSGS_COUNT YOTTA_CFG_COAP_DUPLICATION_MAX_MSGS_COUNT +#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_DUPLICATION_MAX_MSGS_COUNT +#define SN_COAP_DUPLICATION_MAX_MSGS_COUNT MBED_CONF_MBED_CLIENT_SN_COAP_DUPLICATION_MAX_MSGS_COUNT +#endif + + + +/* Maximum allowed number of saved messages for duplicate searching */ +#define SN_COAP_MAX_ALLOWED_DUPLICATION_MESSAGE_COUNT 6 + +/* Maximum time in seconds of messages to be stored for duplication detection */ +#define SN_COAP_DUPLICATION_MAX_TIME_MSGS_STORED 60 /* RESPONSE_TIMEOUT * RESPONSE_RANDOM_FACTOR * (2 ^ MAX_RETRANSMIT - 1) + the expected maximum round trip time */ + +/* * For Message blockwising * */ + +/* Init value for the maximum payload size to be sent and received at one blockwise message */ +/* Setting of this value to 0 will disable this feature, and also reduce use of ROM memory */ +/* Note: This define is common for both received and sent Blockwise messages */ + +#ifdef YOTTA_CFG_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE +#define SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE YOTTA_CFG_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE +#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE +#define SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE MBED_CONF_MBED_CLIENT_SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE +#endif + +#ifndef SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE +#define SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE 0 /**< Must be 2^x and x is at least 4. Suitable values: 0, 16, 32, 64, 128, 256, 512 and 1024 */ +#endif + +#ifdef MBED_CONF_MBED_CLIENT_SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED +#define SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED MBED_CONF_MBED_CLIENT_SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED +#endif + +#ifndef SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED +#define SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED 60 /**< Maximum time in seconds of data (messages and payload) to be stored for blockwising */ +#endif + +#ifdef YOTTA_CFG_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE +#define SN_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE YOTTA_CFG_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE +#elif defined MBED_CONF_MBED_CLIENT_SN_COAP_MAX_INCOMING_MESSAGE_SIZE +#define SN_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE MBED_CONF_MBED_CLIENT_SN_COAP_MAX_INCOMING_MESSAGE_SIZE +#endif + +#ifndef SN_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE +#define SN_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE UINT16_MAX +#endif + +/* * For Option handling * */ +#define COAP_OPTION_MAX_AGE_DEFAULT 60 /**< Default value of Max-Age if option not present */ +#define COAP_OPTION_URI_PORT_NONE (-1) /**< Internal value to represent no Uri-Port option */ +#define COAP_OPTION_BLOCK_NONE (-1) /**< Internal value to represent no Block1/2 option */ + + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ +int8_t prepare_blockwise_message(struct coap_s *handle, struct sn_coap_hdr_ *coap_hdr_ptr); +#endif + +/* Structure which is stored to Linked list for message sending purposes */ +typedef struct coap_send_msg_ { + uint8_t resending_counter; /* Tells how many times message is still tried to resend */ + uint32_t resending_time; /* Tells next resending time */ + + sn_nsdl_transmit_s *send_msg_ptr; + + struct coap_s *coap; /* CoAP library handle */ + void *param; /* Extra parameter that will be passed to TX/RX callback functions */ + + ns_list_link_t link; +} coap_send_msg_s; + +typedef NS_LIST_HEAD(coap_send_msg_s, link) coap_send_msg_list_t; + +/* Structure which is stored to Linked list for message duplication detection purposes */ +typedef struct coap_duplication_info_ { + uint32_t timestamp; /* Tells when duplication information is stored to Linked list */ + uint16_t msg_id; + uint16_t packet_len; + uint8_t *packet_ptr; + struct coap_s *coap; /* CoAP library handle */ + sn_nsdl_addr_s *address; + void *param; + ns_list_link_t link; +} coap_duplication_info_s; + +typedef NS_LIST_HEAD(coap_duplication_info_s, link) coap_duplication_info_list_t; + +/* Structure which is stored to Linked list for blockwise messages sending purposes */ +typedef struct coap_blockwise_msg_ { + uint32_t timestamp; /* Tells when Blockwise message is stored to Linked list */ + + sn_coap_hdr_s *coap_msg_ptr; + struct coap_s *coap; /* CoAP library handle */ + + ns_list_link_t link; +} coap_blockwise_msg_s; + +typedef NS_LIST_HEAD(coap_blockwise_msg_s, link) coap_blockwise_msg_list_t; + +/* Structure which is stored to Linked list for blockwise messages receiving purposes */ +typedef struct coap_blockwise_payload_ { + uint32_t timestamp; /* Tells when Payload is stored to Linked list */ + + uint8_t addr_len; + uint8_t *addr_ptr; + uint16_t port; + uint32_t block_number; + + uint16_t payload_len; + uint8_t *payload_ptr; + struct coap_s *coap; /* CoAP library handle */ + + ns_list_link_t link; +} coap_blockwise_payload_s; + +typedef NS_LIST_HEAD(coap_blockwise_payload_s, link) coap_blockwise_payload_list_t; + +struct coap_s { + void *(*sn_coap_protocol_malloc)(uint16_t); + void (*sn_coap_protocol_free)(void *); + + uint8_t (*sn_coap_tx_callback)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *); + int8_t (*sn_coap_rx_callback)(sn_coap_hdr_s *, sn_nsdl_addr_s *, void *); + + #if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ + coap_send_msg_list_t linked_list_resent_msgs; /* Active resending messages are stored to this Linked list */ + uint16_t count_resent_msgs; + #endif + + #if SN_COAP_DUPLICATION_MAX_MSGS_COUNT /* If Message duplication detection is not used at all, this part of code will not be compiled */ + coap_duplication_info_list_t linked_list_duplication_msgs; /* Messages for duplicated messages detection is stored to this Linked list */ + uint16_t count_duplication_msgs; + #endif + + #if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwise is not used at all, this part of code will not be compiled */ + coap_blockwise_msg_list_t linked_list_blockwise_sent_msgs; /* Blockwise message to to be sent is stored to this Linked list */ + coap_blockwise_payload_list_t linked_list_blockwise_received_payloads; /* Blockwise payload to to be received is stored to this Linked list */ + #endif + + uint32_t system_time; /* System time seconds */ + uint16_t sn_coap_block_data_size; + uint8_t sn_coap_resending_queue_msgs; + uint32_t sn_coap_resending_queue_bytes; + uint8_t sn_coap_resending_count; + uint8_t sn_coap_resending_intervall; + uint8_t sn_coap_duplication_buffer_size; + uint8_t sn_coap_internal_block2_resp_handling; /* If this is set then coap itself sends a next GET request automatically */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* SN_COAP_PROTOCOL_INTERNAL_H_ */ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/sn_coap_builder.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/sn_coap_builder.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1089 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file sn_coap_builder.c + * + * \brief CoAP Message builder + * + * Functionality: Builds CoAP message + * + */ + +/* * * * * * * * * * * * * * */ +/* * * * INCLUDE FILES * * * */ +/* * * * * * * * * * * * * * */ + +#include <string.h> /* For memset() and memcpy() */ + +#include "ns_types.h" +#include "mbed-coap/sn_coap_header.h" +#include "sn_coap_header_internal.h" +#include "sn_coap_protocol_internal.h" +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "coap" +/* * * * LOCAL FUNCTION PROTOTYPES * * * */ +static int8_t sn_coap_builder_header_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr); +static int8_t sn_coap_builder_options_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr); +static uint16_t sn_coap_builder_options_calc_option_size(uint16_t query_len, uint8_t *query_ptr, sn_coap_option_numbers_e option); +static int16_t sn_coap_builder_options_build_add_one_option(uint8_t **dst_packet_data_pptr, uint16_t option_len, uint8_t *option_ptr, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number); +static int16_t sn_coap_builder_options_build_add_multiple_option(uint8_t **dst_packet_data_pptr, uint8_t **src_pptr, uint16_t *src_len_ptr, sn_coap_option_numbers_e option, uint16_t *previous_option_number); +static uint8_t sn_coap_builder_options_build_add_uint_option(uint8_t **dst_packet_data_pptr, uint32_t value, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number); +static uint8_t sn_coap_builder_options_get_option_part_count(uint16_t query_len, uint8_t *query_ptr, sn_coap_option_numbers_e option); +static uint16_t sn_coap_builder_options_get_option_part_length_from_whole_option_string(uint16_t query_len, uint8_t *query_ptr, uint8_t query_index, sn_coap_option_numbers_e option); +static int16_t sn_coap_builder_options_get_option_part_position(uint16_t query_len, uint8_t *query_ptr, uint8_t query_index, sn_coap_option_numbers_e option); +static void sn_coap_builder_payload_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr); +static uint8_t sn_coap_builder_options_calculate_jump_need(sn_coap_hdr_s *src_coap_msg_ptr/*, uint8_t block_option*/); + +sn_coap_hdr_s *sn_coap_build_response(struct coap_s *handle, sn_coap_hdr_s *coap_packet_ptr, uint8_t msg_code) +{ + sn_coap_hdr_s *coap_res_ptr; + + if (!coap_packet_ptr || !handle) { + return NULL; + } + + coap_res_ptr = sn_coap_parser_alloc_message(handle); + if (!coap_res_ptr) { + tr_error("sn_coap_build_response - failed to allocate message!"); + return NULL; + } + + if (msg_code == COAP_MSG_CODE_REQUEST_GET) { + // Blockwise message response is new GET + coap_res_ptr->msg_type = COAP_MSG_TYPE_CONFIRMABLE; + coap_res_ptr->msg_code = (sn_coap_msg_code_e)msg_code; + /* msg_id needs to be set by the caller in this case */ + } + else if (coap_packet_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { + coap_res_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; + coap_res_ptr->msg_code = (sn_coap_msg_code_e)msg_code; + coap_res_ptr->msg_id = coap_packet_ptr->msg_id; + } + else if (coap_packet_ptr->msg_type == COAP_MSG_TYPE_NON_CONFIRMABLE) { + coap_res_ptr->msg_type = COAP_MSG_TYPE_NON_CONFIRMABLE; + coap_res_ptr->msg_code = (sn_coap_msg_code_e)msg_code; + /* msg_id needs to be set by the caller in this case */ + } + else { + handle->sn_coap_protocol_free( coap_res_ptr ); + return NULL; + } + + if (coap_packet_ptr->token_ptr) { + coap_res_ptr->token_len = coap_packet_ptr->token_len; + coap_res_ptr->token_ptr = handle->sn_coap_protocol_malloc(coap_res_ptr->token_len); + if (!coap_res_ptr->token_ptr) { + tr_error("sn_coap_build_response - failed to allocate token!"); + handle->sn_coap_protocol_free(coap_res_ptr); + return NULL; + } + memcpy(coap_res_ptr->token_ptr, coap_packet_ptr->token_ptr, coap_res_ptr->token_len); + } + return coap_res_ptr; +} + +int16_t sn_coap_builder(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr) +{ + return sn_coap_builder_2(dst_packet_data_ptr, src_coap_msg_ptr, SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE); +} + +int16_t sn_coap_builder_2(uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size) +{ + uint8_t *base_packet_data_ptr = NULL; + + /* * * * Check given pointers * * * */ + if (dst_packet_data_ptr == NULL || src_coap_msg_ptr == NULL) { + return -2; + } + + /* Initialize given Packet data memory area with zero values */ + uint16_t dst_byte_count_to_be_built = sn_coap_builder_calc_needed_packet_data_size_2(src_coap_msg_ptr, blockwise_payload_size); + if (!dst_byte_count_to_be_built) { + tr_error("sn_coap_builder_2 - failed to allocate message!"); + return -1; + } + + memset(dst_packet_data_ptr, 0, dst_byte_count_to_be_built); + + /* * * * Store base (= original) destination Packet data pointer for later usage * * * */ + base_packet_data_ptr = dst_packet_data_ptr; + + /* * * * * * * * * * * * * * * * * * */ + /* * * * Header part building * * * */ + /* * * * * * * * * * * * * * * * * * */ + if (sn_coap_builder_header_build(&dst_packet_data_ptr, src_coap_msg_ptr) != 0) { + /* Header building failed */ + tr_error("sn_coap_builder_2 - header building failed!"); + return -1; + } + + /* If else than Reset message because Reset message must be empty */ + if (src_coap_msg_ptr->msg_type != COAP_MSG_TYPE_RESET) { + /* * * * * * * * * * * * * * * * * * */ + /* * * * Options part building * * * */ + /* * * * * * * * * * * * * * * * * * */ + sn_coap_builder_options_build(&dst_packet_data_ptr, src_coap_msg_ptr); + + /* * * * * * * * * * * * * * * * * * */ + /* * * * Payload part building * * * */ + /* * * * * * * * * * * * * * * * * * */ + sn_coap_builder_payload_build(&dst_packet_data_ptr, src_coap_msg_ptr); + } + /* * * * Return built Packet data length * * * */ + return (dst_packet_data_ptr - base_packet_data_ptr); +} +uint16_t sn_coap_builder_calc_needed_packet_data_size(sn_coap_hdr_s *src_coap_msg_ptr) +{ + return sn_coap_builder_calc_needed_packet_data_size_2(src_coap_msg_ptr, SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE); +} + +uint16_t sn_coap_builder_calc_needed_packet_data_size_2(sn_coap_hdr_s *src_coap_msg_ptr, uint16_t blockwise_payload_size) +{ + (void)blockwise_payload_size; + uint16_t returned_byte_count = 0; + + if (!src_coap_msg_ptr) { + return 0; + } + /* * * * * HEADER * * * * */ + + /* Header size is fixed */ + returned_byte_count = COAP_HEADER_LENGTH; + + /* * * * * OPTIONS * * * * */ + + /* If else than Reset message because Reset message must be empty */ + if (src_coap_msg_ptr->msg_type != COAP_MSG_TYPE_RESET) { + uint16_t repeatable_option_size = 0; + /* TOKEN - Length is 1-8 bytes */ + if (src_coap_msg_ptr->token_ptr != NULL) { + if (src_coap_msg_ptr->token_len > 8 || src_coap_msg_ptr->token_len < 1) { /* Check that option is not longer than defined */ + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - token too large!"); + return 0; + } + + returned_byte_count += src_coap_msg_ptr->token_len; + } + /* URI PATH - Repeatable option. Length of one option is 0-255 */ + if (src_coap_msg_ptr->uri_path_ptr != NULL) { + repeatable_option_size = sn_coap_builder_options_calc_option_size(src_coap_msg_ptr->uri_path_len, + src_coap_msg_ptr->uri_path_ptr, COAP_OPTION_URI_PATH); + if (repeatable_option_size) { + returned_byte_count += repeatable_option_size; + } else { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - uri path size failed!"); + return 0; + } + } + + uint16_t tempInt = 0; + /* CONTENT FORMAT - An integer option, up to 2 bytes */ + if (src_coap_msg_ptr->content_format != COAP_CT_NONE) { + if ((uint32_t) src_coap_msg_ptr->content_format > 0xffff) { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - content format too large!"); + return 0; + } + + returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->content_format, COAP_OPTION_CONTENT_FORMAT, &tempInt); + } + /* If options list pointer exists */ + if (src_coap_msg_ptr->options_list_ptr != NULL) { + /* ACCEPT - An integer option, up to 2 bytes */ + if (src_coap_msg_ptr->options_list_ptr->accept != COAP_CT_NONE) { + if ((uint32_t) src_coap_msg_ptr->options_list_ptr->accept > 0xffff) { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - accept too large!"); + return 0; + } + + returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->options_list_ptr->accept, COAP_OPTION_ACCEPT, &tempInt); + } + /* MAX AGE - An integer option, omitted for default. Up to 4 bytes */ + if (src_coap_msg_ptr->options_list_ptr->max_age != COAP_OPTION_MAX_AGE_DEFAULT) { + returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->options_list_ptr->max_age, COAP_OPTION_MAX_AGE, &tempInt); + } + /* PROXY URI - Length of this option is 1-1034 bytes */ + if (src_coap_msg_ptr->options_list_ptr->proxy_uri_ptr != NULL) { + if (src_coap_msg_ptr->options_list_ptr->proxy_uri_len >= 1 && src_coap_msg_ptr->options_list_ptr->proxy_uri_len <= 12) { /* Add option header byte(s) - depending of option length */ + returned_byte_count++; + } + + else if (src_coap_msg_ptr->options_list_ptr->proxy_uri_len >= 13 && src_coap_msg_ptr->options_list_ptr->proxy_uri_len <= 269) { + returned_byte_count += 2; + } + + else if (src_coap_msg_ptr->options_list_ptr->proxy_uri_len >= 270 && src_coap_msg_ptr->options_list_ptr->proxy_uri_len <= 1034) { + returned_byte_count += 3; + } + + else { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - proxy uri too large!"); + return 0; + } + + /* Add needed memory for Option value */ + returned_byte_count += src_coap_msg_ptr->options_list_ptr->proxy_uri_len; + } + /* ETAG - Repeatable option. Length of this option is 1-8 bytes*/ + if (src_coap_msg_ptr->options_list_ptr->etag_ptr != NULL) { + repeatable_option_size = sn_coap_builder_options_calc_option_size(src_coap_msg_ptr->options_list_ptr->etag_len, + src_coap_msg_ptr->options_list_ptr->etag_ptr, COAP_OPTION_ETAG); + if (repeatable_option_size) { + returned_byte_count += repeatable_option_size; + } else { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - etag too large!"); + return 0; + } + } + /* URI HOST - Length of this option is 1-255 bytes */ + if (src_coap_msg_ptr->options_list_ptr->uri_host_ptr != NULL) { + if (src_coap_msg_ptr->options_list_ptr->uri_host_len > 0 && src_coap_msg_ptr->options_list_ptr->uri_host_len <= 12) { + returned_byte_count++; + } + + else if (src_coap_msg_ptr->options_list_ptr->uri_host_len >= 13 && src_coap_msg_ptr->options_list_ptr->uri_host_len <= 255) { + returned_byte_count += 2; + } + + else { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - uri host too large!"); + return 0; + } + + returned_byte_count += src_coap_msg_ptr->options_list_ptr->uri_host_len; + } + /* LOCATION PATH - Repeatable option. Length of this option is 0-255 bytes*/ + if (src_coap_msg_ptr->options_list_ptr->location_path_ptr != NULL) { + repeatable_option_size = sn_coap_builder_options_calc_option_size(src_coap_msg_ptr->options_list_ptr->location_path_len, + src_coap_msg_ptr->options_list_ptr->location_path_ptr, COAP_OPTION_LOCATION_PATH); + if (repeatable_option_size) { + returned_byte_count += repeatable_option_size; + } else { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - location path too large!"); + return 0; + } + } + /* URI PORT - An integer option, up to 2 bytes */ + if (src_coap_msg_ptr->options_list_ptr->uri_port != COAP_OPTION_URI_PORT_NONE) { + if ((uint32_t) src_coap_msg_ptr->options_list_ptr->uri_port > 0xffff) { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - uri port too large!"); + return 0; + } + returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->options_list_ptr->uri_port, COAP_OPTION_URI_PORT, &tempInt); + } + /* lOCATION QUERY - Repeatable option. Length of this option is 0-255 bytes */ + if (src_coap_msg_ptr->options_list_ptr->location_query_ptr != NULL) { + repeatable_option_size = sn_coap_builder_options_calc_option_size(src_coap_msg_ptr->options_list_ptr->location_query_len, + src_coap_msg_ptr->options_list_ptr->location_query_ptr, COAP_OPTION_LOCATION_QUERY); + if (repeatable_option_size) { + returned_byte_count += repeatable_option_size; + } else { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - location query too large!"); + return 0; + } + } + /* OBSERVE - An integer option, up to 3 bytes */ + if (src_coap_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { + if ((uint32_t) src_coap_msg_ptr->options_list_ptr->observe > 0xffffff) { + return 0; + } + returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->options_list_ptr->observe, COAP_OPTION_OBSERVE, &tempInt); + } + /* URI QUERY - Repeatable option. Length of this option is 1-255 */ + if (src_coap_msg_ptr->options_list_ptr->uri_query_ptr != NULL) { + repeatable_option_size = sn_coap_builder_options_calc_option_size(src_coap_msg_ptr->options_list_ptr->uri_query_len, + src_coap_msg_ptr->options_list_ptr->uri_query_ptr, COAP_OPTION_URI_QUERY); + if (repeatable_option_size) { + returned_byte_count += repeatable_option_size; + } else { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - observe too large!"); + return 0; + } + } + + /* BLOCK 1 - An integer option, up to 3 bytes */ + if (src_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE) { + if ((uint32_t) src_coap_msg_ptr->options_list_ptr->block1 > 0xffffff) { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - block1 too large!"); + return 0; + } + returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->options_list_ptr->block1, COAP_OPTION_BLOCK1, &tempInt); + } + /* SIZE1 - Length of this option is 0-4 bytes */ + if (src_coap_msg_ptr->options_list_ptr->use_size1) { + returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->options_list_ptr->size1, COAP_OPTION_SIZE1, &tempInt); + } + /* BLOCK 2 - An integer option, up to 3 bytes */ + if (src_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE) { + if ((uint32_t) src_coap_msg_ptr->options_list_ptr->block2 > 0xffffff) { + tr_error("sn_coap_builder_calc_needed_packet_data_size_2 - block2 too large!"); + return 0; + } + returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->options_list_ptr->block2, COAP_OPTION_BLOCK2, &tempInt); + } + /* SIZE2 - Length of this option is 0-4 bytes */ + if (src_coap_msg_ptr->options_list_ptr->use_size2) { + returned_byte_count += sn_coap_builder_options_build_add_uint_option(NULL, src_coap_msg_ptr->options_list_ptr->size2, COAP_OPTION_SIZE2, &tempInt); + } + } +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + if ((src_coap_msg_ptr->payload_len > blockwise_payload_size) && (blockwise_payload_size > 0)) { + returned_byte_count += blockwise_payload_size; + } else { + returned_byte_count += src_coap_msg_ptr->payload_len; + } +#else + returned_byte_count += src_coap_msg_ptr->payload_len; +#endif + if (src_coap_msg_ptr->payload_len) { + returned_byte_count ++; /* For payload marker */ + } + returned_byte_count += sn_coap_builder_options_calculate_jump_need(src_coap_msg_ptr/*, 0*/); + } + return returned_byte_count; +} +/** + * \fn static uint8_t sn_coap_builder_options_calculate_jump_need(sn_coap_hdr_s *src_coap_msg_ptr, uint8_t block_option) + * + * \brief Checks if there is need for option jump + * + * \param *src_coap_msg_ptr is source of checked CoAP message + * + * \param block option marks if block option is to be added to message later. 0 = no block option, 1 = block1 and 2 = block2 + * + * \return Returns bytes needed for jumping + */ + +static uint8_t sn_coap_builder_options_calculate_jump_need(sn_coap_hdr_s *src_coap_msg_ptr/*, uint8_t block_option*/) +{ + uint8_t previous_option_number = 0; + uint8_t needed_space = 0; + + if (src_coap_msg_ptr->options_list_ptr != NULL) { + /* If option numbers greater than 12 is not used, then jumping is not needed */ + //TODO: Check if this is really needed! Does it enhance perf? If not -> remove + if (!src_coap_msg_ptr->options_list_ptr->uri_query_ptr && + src_coap_msg_ptr->options_list_ptr->accept == COAP_CT_NONE && + !src_coap_msg_ptr->options_list_ptr->location_query_ptr && + src_coap_msg_ptr->options_list_ptr->block2 == COAP_OPTION_BLOCK_NONE && + src_coap_msg_ptr->options_list_ptr->block1 == COAP_OPTION_BLOCK_NONE && + !src_coap_msg_ptr->options_list_ptr->proxy_uri_ptr && + src_coap_msg_ptr->options_list_ptr->max_age == COAP_OPTION_MAX_AGE_DEFAULT && + !src_coap_msg_ptr->options_list_ptr->use_size1 && + !src_coap_msg_ptr->options_list_ptr->use_size2) { + return 0; + } + + if (src_coap_msg_ptr->options_list_ptr->uri_host_ptr != NULL) { + previous_option_number = (COAP_OPTION_URI_HOST); + } + + if (src_coap_msg_ptr->options_list_ptr->etag_ptr != NULL) { + previous_option_number = (COAP_OPTION_ETAG); + } + + if (src_coap_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { + previous_option_number = (COAP_OPTION_OBSERVE); + } + + if (src_coap_msg_ptr->options_list_ptr->uri_port != COAP_OPTION_URI_PORT_NONE) { + previous_option_number = (COAP_OPTION_URI_PORT); + } + + if (src_coap_msg_ptr->options_list_ptr->location_path_ptr != NULL) { + previous_option_number = (COAP_OPTION_LOCATION_PATH); + } + + if (src_coap_msg_ptr->uri_path_ptr != NULL) { + previous_option_number = (COAP_OPTION_URI_PATH); + } + if (src_coap_msg_ptr->content_format != COAP_CT_NONE) { + previous_option_number = (COAP_OPTION_CONTENT_FORMAT); + } + if (src_coap_msg_ptr->options_list_ptr->max_age != COAP_OPTION_MAX_AGE_DEFAULT) { + if ((COAP_OPTION_MAX_AGE - previous_option_number) > 12) { + needed_space += 1; + } + previous_option_number = (COAP_OPTION_MAX_AGE); + } + + if (src_coap_msg_ptr->options_list_ptr->uri_query_ptr != NULL) { + if ((COAP_OPTION_URI_QUERY - previous_option_number) > 12) { + needed_space += 1; + } + previous_option_number = (COAP_OPTION_URI_QUERY); + } + if (src_coap_msg_ptr->options_list_ptr->accept != COAP_CT_NONE) { + if ((COAP_OPTION_ACCEPT - previous_option_number) > 12) { + needed_space += 1; + } + previous_option_number = (COAP_OPTION_ACCEPT); + } + if (src_coap_msg_ptr->options_list_ptr->location_query_ptr != NULL) { + if ((COAP_OPTION_LOCATION_QUERY - previous_option_number) > 12) { + needed_space += 1; + } + previous_option_number = (COAP_OPTION_LOCATION_QUERY); + } + if (src_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE) { + if ((COAP_OPTION_BLOCK2 - previous_option_number) > 12 ){ + needed_space += 1; + } + previous_option_number = (COAP_OPTION_BLOCK2); + } + if (src_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE) { + if ((COAP_OPTION_BLOCK1 - previous_option_number) > 12 ){ + needed_space += 1; + } + previous_option_number = (COAP_OPTION_BLOCK1); + } + if (src_coap_msg_ptr->options_list_ptr->use_size2) { + if ((COAP_OPTION_SIZE2 - previous_option_number) > 12) { + needed_space += 1; + } + previous_option_number = (COAP_OPTION_SIZE2); + } + if (src_coap_msg_ptr->options_list_ptr->proxy_uri_ptr != NULL) { + if ((COAP_OPTION_PROXY_URI - previous_option_number) > 12) { + needed_space += 1; + } + if ((COAP_OPTION_PROXY_URI - previous_option_number) > 269) { //Can not happen + needed_space += 1; + } + previous_option_number = (COAP_OPTION_PROXY_URI); + } + if (src_coap_msg_ptr->options_list_ptr->use_size1 ) { + if ((COAP_OPTION_SIZE1 - previous_option_number) > 12) { + needed_space += 1; + } + previous_option_number = (COAP_OPTION_SIZE1); + } + } + + else { + if (src_coap_msg_ptr->uri_path_ptr != 0) { + previous_option_number = (COAP_OPTION_URI_PATH); + } + + if (src_coap_msg_ptr->content_format != COAP_CT_NONE) { + previous_option_number = (COAP_OPTION_CONTENT_FORMAT); + } + } + return needed_space; +} + +/** + * \fn static int8_t sn_coap_builder_header_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) + * + * \brief Builds Header part of Packet data + * + * \param **dst_packet_data_pptr is destination for built Packet data + * + * \param *src_coap_msg_ptr is source for building Packet data + * + * \return Return value is 0 in ok case and -1 in failure case + **************************************************************************** */ +static int8_t sn_coap_builder_header_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) +{ + /* * * * Check validity of Header values * * * */ + if (sn_coap_header_validity_check(src_coap_msg_ptr, COAP_VERSION) != 0) { + tr_error("sn_coap_builder_header_build - header build failed!"); + return -1; + } + + /* * * Add CoAP Version * * */ + **dst_packet_data_pptr += COAP_VERSION; + + /* * * Add Message type * * */ + **dst_packet_data_pptr += src_coap_msg_ptr->msg_type; + + /* * * Add Token length * * */ + **dst_packet_data_pptr += (src_coap_msg_ptr->token_len); + + (*dst_packet_data_pptr) ++; + /* * * Add Message code * * */ + **dst_packet_data_pptr = src_coap_msg_ptr->msg_code; + (*dst_packet_data_pptr) ++; + + /* * * Add Message ID * * */ + **dst_packet_data_pptr = (uint8_t)(src_coap_msg_ptr->msg_id >> COAP_HEADER_MSG_ID_MSB_SHIFT); /* MSB part */ + (*dst_packet_data_pptr) ++; + **dst_packet_data_pptr = (uint8_t)src_coap_msg_ptr->msg_id; /* LSB part */ + (*dst_packet_data_pptr) ++; + + /* Success */ + return 0; +} + +/** + * \fn static int8_t sn_coap_builder_options_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) + * + * \brief Builds Options part of Packet data + * + * \param **dst_packet_data_pptr is destination for built Packet data + * + * \param *src_coap_msg_ptr is source for building Packet data + * + * \return Return value is 0 in every case + */ +static int8_t sn_coap_builder_options_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) +{ + /* * * * Check if Options are used at all * * * */ + if (src_coap_msg_ptr->uri_path_ptr == NULL && src_coap_msg_ptr->token_ptr == NULL && + src_coap_msg_ptr->content_format == COAP_CT_NONE && src_coap_msg_ptr->options_list_ptr == NULL) { + tr_error("sn_coap_builder_options_build - options not used!"); + return 0; + } + + /* * * * First add Token option * * * */ + if (src_coap_msg_ptr->token_len && src_coap_msg_ptr->token_ptr) { + memcpy(*dst_packet_data_pptr, src_coap_msg_ptr->token_ptr, src_coap_msg_ptr->token_len); + } + (*dst_packet_data_pptr) += src_coap_msg_ptr->token_len; + + /* Then build rest of the options */ + + /* * * * Initialize previous Option number for new built message * * * */ + uint16_t previous_option_number = 0; + + //missing: COAP_OPTION_IF_MATCH, COAP_OPTION_IF_NONE_MATCH, COAP_OPTION_SIZE + + /* Check if less used options are used at all */ + if (src_coap_msg_ptr->options_list_ptr != NULL) { + /* * * * Build Uri-Host option * * * */ + sn_coap_builder_options_build_add_one_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->uri_host_len, + src_coap_msg_ptr->options_list_ptr->uri_host_ptr, COAP_OPTION_URI_HOST, &previous_option_number); + + /* * * * Build ETag option * * * */ + sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, &src_coap_msg_ptr->options_list_ptr->etag_ptr, + (uint16_t *)&src_coap_msg_ptr->options_list_ptr->etag_len, COAP_OPTION_ETAG, &previous_option_number); + + /* * * * Build Observe option * * * * */ + if (src_coap_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { + sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->observe, + COAP_OPTION_OBSERVE, &previous_option_number); + } + + /* * * * Build Uri-Port option * * * */ + if (src_coap_msg_ptr->options_list_ptr->uri_port != COAP_OPTION_URI_PORT_NONE) { + sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->uri_port, + COAP_OPTION_URI_PORT, &previous_option_number); + } + + /* * * * Build Location-Path option * * * */ + sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, &src_coap_msg_ptr->options_list_ptr->location_path_ptr, + &src_coap_msg_ptr->options_list_ptr->location_path_len, COAP_OPTION_LOCATION_PATH, &previous_option_number); + } + /* * * * Build Uri-Path option * * * */ + sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, &src_coap_msg_ptr->uri_path_ptr, + &src_coap_msg_ptr->uri_path_len, COAP_OPTION_URI_PATH, &previous_option_number); + + /* * * * Build Content-Type option * * * */ + if (src_coap_msg_ptr->content_format != COAP_CT_NONE) { + sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->content_format, + COAP_OPTION_CONTENT_FORMAT, &previous_option_number); + } + + if (src_coap_msg_ptr->options_list_ptr != NULL) { + /* * * * Build Max-Age option * * * */ + if (src_coap_msg_ptr->options_list_ptr->max_age != COAP_OPTION_MAX_AGE_DEFAULT) { + sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->max_age, + COAP_OPTION_MAX_AGE, &previous_option_number); + } + + /* * * * Build Uri-Query option * * * * */ + sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, &src_coap_msg_ptr->options_list_ptr->uri_query_ptr, + &src_coap_msg_ptr->options_list_ptr->uri_query_len, COAP_OPTION_URI_QUERY, &previous_option_number); + + /* * * * Build Accept option * * * * */ + if (src_coap_msg_ptr->options_list_ptr->accept != COAP_CT_NONE) { + sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->accept, + COAP_OPTION_ACCEPT, &previous_option_number); + } + } + + if (src_coap_msg_ptr->options_list_ptr != NULL) { + /* * * * Build Location-Query option * * * */ + sn_coap_builder_options_build_add_multiple_option(dst_packet_data_pptr, &src_coap_msg_ptr->options_list_ptr->location_query_ptr, + &src_coap_msg_ptr->options_list_ptr->location_query_len, COAP_OPTION_LOCATION_QUERY, &previous_option_number); + + /* * * * Build Block2 option * * * * */ + if (src_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE) { + sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->block2, + COAP_OPTION_BLOCK2, &previous_option_number); + } + + /* * * * Build Block1 option * * * * */ + if (src_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE) { + sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->block1, + COAP_OPTION_BLOCK1, &previous_option_number); + } + + /* * * * Build Size2 option * * * */ + if (src_coap_msg_ptr->options_list_ptr->use_size2) { + sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->size2, + COAP_OPTION_SIZE2, &previous_option_number); + } + + /* * * * Build Proxy-Uri option * * * */ + sn_coap_builder_options_build_add_one_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->proxy_uri_len, + src_coap_msg_ptr->options_list_ptr->proxy_uri_ptr, COAP_OPTION_PROXY_URI, &previous_option_number); + + + /* * * * Build Size1 option * * * */ + if (src_coap_msg_ptr->options_list_ptr->use_size1) { + sn_coap_builder_options_build_add_uint_option(dst_packet_data_pptr, src_coap_msg_ptr->options_list_ptr->size1, + COAP_OPTION_SIZE1, &previous_option_number); + } + } + + /* Success */ + return 0; +} + +/** + * \fn static int16_t sn_coap_builder_options_build_add_one_option(uint8_t **dst_packet_data_pptr, uint16_t option_value_len, uint8_t *option_value_ptr, sn_coap_option_numbers_e option_number) + * + * \brief Adds Options part of Packet data + * + * \param **dst_packet_data_pptr is destination for built Packet data + * + * \param option_value_len is Option value length to be added + * + * \param *option_value_ptr is pointer to Option value data to be added + * + * \param option_number is Option number to be added + * + * \return Return value is 0 if option was not added, 1 if added + */ +static int16_t sn_coap_builder_options_build_add_one_option(uint8_t **dst_packet_data_pptr, uint16_t option_len, + uint8_t *option_ptr, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number) +{ + /* Check if there is option at all */ + if (option_ptr != NULL) { + uint16_t option_delta; + + option_delta = (option_number - *previous_option_number); + + /* * * Build option header * * */ + + /* First option length without extended part */ + if (option_len <= 12) { + **dst_packet_data_pptr = option_len; + } + + else if (option_len > 12 && option_len < 269) { + **dst_packet_data_pptr = 0x0D; + } + + else if (option_len >= 269) { + **dst_packet_data_pptr = 0x0E; + } + + /* Then option delta with extensions, and move pointer */ + if (option_delta <= 12) { + **dst_packet_data_pptr += (option_delta << 4); + *dst_packet_data_pptr += 1; + } + + else if (option_delta > 12 && option_delta < 269) { + **dst_packet_data_pptr += 0xD0; + option_delta -= 13; + + *(*dst_packet_data_pptr + 1) = (uint8_t)option_delta; + *dst_packet_data_pptr += 2; + } + //This is currently dead code (but possibly needed in future) + else if (option_delta >= 269) { + **dst_packet_data_pptr += 0xE0; + option_delta -= 269; + + *(*dst_packet_data_pptr + 2) = (uint8_t)option_delta; + *(*dst_packet_data_pptr + 1) = (option_delta >> 8); + *dst_packet_data_pptr += 3; + } + + /* Now option length extensions, if needed */ + if (option_len > 12 && option_len < 269) { + **dst_packet_data_pptr = (uint8_t)(option_len - 13); + *dst_packet_data_pptr += 1; + } + + else if (option_len >= 269) { + *(*dst_packet_data_pptr + 1) = (uint8_t)(option_len - 269); + **dst_packet_data_pptr = ((option_len - 269) >> 8); + *dst_packet_data_pptr += 2; + } + + *previous_option_number = option_number; + + /* Write Option value */ + memcpy(*dst_packet_data_pptr, option_ptr, option_len); + + /* Increase destination Packet data pointer */ + (*dst_packet_data_pptr) += option_len; + + return 1; + } + + /* Success */ + return 0; +} + +/** + * \brief Constructs a uint Options part of Packet data + * + * \param **dst_packet_data_pptr is destination for built Packet data; NULL + * to compute size only. + * + * \param option_value is Option value to be added + * + * \param option_number is Option number to be added + * + * \return Return value is total option size, or -1 in write failure case + */ +static uint8_t sn_coap_builder_options_build_add_uint_option(uint8_t **dst_packet_data_pptr, uint32_t option_value, sn_coap_option_numbers_e option_number, uint16_t *previous_option_number) +{ + uint8_t payload[4]; + uint8_t len = 0; + /* Construct the variable-length payload representing the value */ + for (uint8_t i = 0; i < 4; i++) { + if (len > 0 || (option_value & 0xff000000)) { + payload[len++] = option_value >> 24; + } + option_value <<= 8; + } + + /* If output pointer isn't NULL, write it out */ + if (dst_packet_data_pptr) { + int16_t ret = sn_coap_builder_options_build_add_one_option(dst_packet_data_pptr, len, payload, option_number, previous_option_number); + /* Allow for failure returns when writing (why even permit failure returns?) */ + if (ret < 0) { + return ret; + } + } + + /* Return the total option size */ + return 1 + len; +} + +/** + * \fn static int16_t sn_coap_builder_options_build_add_multiple_option(uint8_t **dst_packet_data_pptr, uint8_t **src_pptr, uint16_t *src_len_ptr, sn_coap_option_numbers_e option) + * + * \brief Builds Option Uri-Query from given CoAP Header structure to Packet data + * + * \param **dst_packet_data_pptr is destination for built Packet data + * + * \param uint8_t **src_pptr + * + * \param uint16_t *src_len_ptr + * + * \paramsn_coap_option_numbers_e option option to be added + * + * \return Return value is 0 always + */ +static int16_t sn_coap_builder_options_build_add_multiple_option(uint8_t **dst_packet_data_pptr, uint8_t **src_pptr, uint16_t *src_len_ptr, sn_coap_option_numbers_e option, uint16_t *previous_option_number) +{ + /* Check if there is option at all */ + if (*src_pptr != NULL) { + uint8_t *query_ptr = *src_pptr; + uint8_t query_part_count = 0; + uint16_t query_len = *src_len_ptr; + uint8_t i = 0; + uint16_t query_part_offset = 0; + + /* Get query part count */ + query_part_count = sn_coap_builder_options_get_option_part_count(query_len, query_ptr, option); + + /* * * * Options by adding all parts to option * * * */ + for (i = 0; i < query_part_count; i++) { + /* Get length of query part */ + uint16_t one_query_part_len = sn_coap_builder_options_get_option_part_length_from_whole_option_string(query_len, query_ptr, i, option); + + /* Get position of query part */ + query_part_offset = sn_coap_builder_options_get_option_part_position(query_len, query_ptr, i, option); + + /* Add Uri-query's one part to Options */ + sn_coap_builder_options_build_add_one_option(dst_packet_data_pptr, one_query_part_len, *src_pptr + query_part_offset, option, previous_option_number); + } + } + /* Success */ + return 0; +} + + +/** + * \fn static uint16_t sn_coap_builder_options_calc_option_size(uint16_t query_len, uint8_t *query_ptr, sn_coap_option_numbers_e option) + * + * \brief Calculates needed Packet data memory size for option + * + * \param path_len is length of calculated strting(s) + * + * \param *path_ptr is pointer to calculated options + * + * \return Return value is count of needed memory as bytes for Uri-query option + */ +static uint16_t sn_coap_builder_options_calc_option_size(uint16_t query_len, uint8_t *query_ptr, sn_coap_option_numbers_e option) +{ + uint8_t query_part_count = sn_coap_builder_options_get_option_part_count(query_len, query_ptr, option); + uint8_t i = 0; + uint16_t ret_value = 0; + + /* * * * * * * * * * * * * * * * * * * * * * * * */ + /* * * * Calculate Uri-query options length * * */ + /* * * * * * * * * * * * * * * * * * * * * * * * */ + for (i = 0; i < query_part_count; i++) { + /* * * Length of Option number and Option value length * * */ + + /* Get length of Query part */ + uint16_t one_query_part_len = sn_coap_builder_options_get_option_part_length_from_whole_option_string(query_len, query_ptr, i, option); + + /* Check option length */ + switch (option) { + case (COAP_OPTION_ETAG): /* Length 1-8 */ + if (one_query_part_len < 1 || one_query_part_len > 8) { + return 0; + } + break; + case (COAP_OPTION_LOCATION_PATH): /* Length 0-255 */ + case (COAP_OPTION_URI_PATH): /* Length 0-255 */ + case (COAP_OPTION_LOCATION_QUERY): /* Length 0-255 */ + if (one_query_part_len > 255) { + return 0; + } + break; + case (COAP_OPTION_URI_QUERY): /* Length 1-255 */ + if (one_query_part_len < 1 || one_query_part_len > 255) { + return 0; + } + break; +// case (COAP_OPTION_ACCEPT): /* Length 0-2 */ +// if (one_query_part_len > 2) { +// return 0; +// } +// break; + default: + break; //impossible scenario currently + } + + /* Check if 4 bits are enough for writing Option value length */ + if (one_query_part_len <= 12) { + /* 4 bits are enough for Option value length */ + ret_value++; + } else if (one_query_part_len >= 13 && one_query_part_len < 269) { + /* Extra byte for Option value length is needed */ + ret_value += 2; + } + //This can only happen if we are in default case above, currently is not happening + else if (one_query_part_len >= 270 && one_query_part_len < 1034) { + /* Extra bytes for Option value length is needed */ + ret_value += 3; + } + + + /* * * Length of Option value * * */ + + /* Increase options length */ + ret_value += one_query_part_len; + } + + /* Success */ + return ret_value; +} + + + +/** + * \fn static uint8_t sn_coap_builder_options_get_option_part_count(uint16_t query_len, uint8_t *query_ptr, sn_coap_option_numbers_e option) + * + * \brief Gets query part count from whole option string + * + * \param query_len is length of whole Path + * + * \param *query_ptr is pointer to the start of whole Path + * + * \return Return value is count of query parts + */ +static uint8_t sn_coap_builder_options_get_option_part_count(uint16_t query_len, uint8_t *query_ptr, sn_coap_option_numbers_e option) +{ + uint8_t returned_query_count = 0; + uint16_t query_len_index = 0; + uint8_t char_to_search = '&'; + + if (option == COAP_OPTION_URI_PATH || option == COAP_OPTION_LOCATION_PATH) { + char_to_search = '/'; + } + + /* Loop whole query and search '\0' characters (not first and last char) */ + for (query_len_index = 1; query_len_index < query_len - 1; query_len_index++) { + /* If new query part starts */ + if (*(query_ptr + query_len_index) == char_to_search) { /* If match */ + returned_query_count++; + } + } + + returned_query_count++; + + return returned_query_count; +} + +/** + * \fn static uint16_t sn_coap_builder_options_get_option_part_length_from_whole_option_string(uint16_t query_len, + uint8_t *query_ptr, + uint8_t query_index, sn_coap_option_numbers_e option) + * + * \brief Gets one's query part length from whole query string + * + * \param query_len is length of whole string + * + * \param *query_ptr is pointer to the start of whole string + * + * \param query_index is query part index to be found + * + * \param sn_coap_option_numbers_e option is option number of the option + * + * \return Return value is length of query part + */ +static uint16_t sn_coap_builder_options_get_option_part_length_from_whole_option_string(uint16_t query_len, uint8_t *query_ptr, + uint8_t query_index, sn_coap_option_numbers_e option) +{ + uint16_t returned_query_part_len = 0; + uint8_t temp_query_index = 0; + uint16_t query_len_index = 0; + uint8_t char_to_search = '&'; + + if (option == COAP_OPTION_URI_PATH || option == COAP_OPTION_LOCATION_PATH) { + char_to_search = '/'; + } + + /* Loop whole query and search '\0' characters */ + for (query_len_index = 0; query_len_index < query_len; query_len_index++) { + /* Store character to temp_char for helping debugging */ + uint8_t temp_char = *query_ptr; + + /* If new query part starts */ + if (temp_char == char_to_search && returned_query_part_len > 0) { /* returned_query_part_len > 0 is for querys which start with "\0" */ + /* If query part index is wanted */ + if (temp_query_index == query_index) { + /* Return length of query part */ + return returned_query_part_len; + } else { + /* Reset length of query part because wanted query part finding continues*/ + returned_query_part_len = 0; + } + + /* Next query part is looped */ + temp_query_index++; + } else if (temp_char != char_to_search) { /* Else if query part continues */ + /* Increase query part length */ + returned_query_part_len++; + } + + query_ptr++; + } + + /* Return length of query part in cases that query part does not finish to '\0' character (last query part can be like that) */ + return returned_query_part_len; +} + +/** + * \fn static uint16_t sn_coap_builder_options_get_option_part_position(uint16_t query_len, + uint8_t *query_ptr, + uint8_t query_index, sn_coap_option_numbers_e option) + * + * \brief Gets query part position in whole query + * + * \param query_len is length of whole query + * + * \param *query_ptr is pointer to the start of whole query + * + * \param query_index is query part index to be found + * + * \return Return value is position (= offset) of query part in whole query. In + * fail cases -1 is returned. + */ +static int16_t sn_coap_builder_options_get_option_part_position(uint16_t query_len, uint8_t *query_ptr, + uint8_t query_index, sn_coap_option_numbers_e option) +{ + uint16_t returned_query_part_offset = 0; + uint8_t temp_query_index = 0; + uint16_t query_len_index = 0; + uint8_t char_to_search = '&'; + + if (option == COAP_OPTION_URI_PATH || option == COAP_OPTION_LOCATION_PATH) { + char_to_search = '/'; + } + + if (query_index == 0) { + if (*query_ptr == 0 || *query_ptr == char_to_search) { + return 1; + } else { + return 0; + } + } + + /* Loop whole query and search separator characters */ + for (query_len_index = 0; query_len_index < query_len; query_len_index++) { + /* Store character to temp_char for helping debugging */ + uint8_t temp_char = *query_ptr; + + /* If new query part starts */ + if (temp_char == char_to_search && returned_query_part_offset > 0) { /* returned_query_part_offset > 0 is for querys which start with searched char */ + /* If query part index is wanted */ + if (temp_query_index == (query_index - 1)) { + /* Return offset of query part */ + return (returned_query_part_offset + 1); /* Plus one is for passing separator */ + } + + /* Next query part is looped */ + temp_query_index++; + } + + returned_query_part_offset++; + + query_ptr++; + } + + return -1; //Dead code? +} + + +/** + * \fn static void sn_coap_builder_payload_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) + * + * \brief Builds Options part of Packet data + * + * \param **dst_packet_data_pptr is destination for built Packet data + * + * \param *src_coap_msg_ptr is source for building Packet data + */ +static void sn_coap_builder_payload_build(uint8_t **dst_packet_data_pptr, sn_coap_hdr_s *src_coap_msg_ptr) +{ + /* Check if Payload is used at all */ + if (src_coap_msg_ptr->payload_len && src_coap_msg_ptr->payload_ptr != NULL) { + /* Write Payload marker */ + + **dst_packet_data_pptr = 0xff; + (*dst_packet_data_pptr)++; + + /* Write Payload */ + memcpy(*dst_packet_data_pptr, src_coap_msg_ptr->payload_ptr, src_coap_msg_ptr->payload_len); + + /* Increase destination Packet data pointer */ + (*dst_packet_data_pptr) += src_coap_msg_ptr->payload_len; + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/sn_coap_header_check.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/sn_coap_header_check.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file sn_coap_header_check.c + * + * \brief CoAP Header validity checker + * + * Functionality: Checks validity of CoAP Header + * + */ + +/* * * * INCLUDE FILES * * * */ +#include "ns_types.h" +#include "mbed-coap/sn_coap_header.h" +#include "mbed-coap/sn_coap_protocol.h" +#include "sn_coap_header_internal.h" +#include "sn_coap_protocol_internal.h" +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "coap" + +/** + * \fn int8_t sn_coap_header_validity_check(sn_coap_hdr_s *src_coap_msg_ptr, coap_version_e coap_version) + * + * \brief Checks validity of given Header + * + * \param *src_coap_msg_ptr is source for building Packet data + * \param coap_version is version of used CoAP specification + * + * \return Return value is status of validity check. In ok cases 0 and in + * failure cases -1 + */ +int8_t sn_coap_header_validity_check(sn_coap_hdr_s *src_coap_msg_ptr, coap_version_e coap_version) +{ + /* * Check validity of CoAP Version * */ + if (coap_version != COAP_VERSION_1) { + return -1; + } + + /* * Check validity of Message type * */ + switch (src_coap_msg_ptr->msg_type) { + case COAP_MSG_TYPE_CONFIRMABLE: + case COAP_MSG_TYPE_NON_CONFIRMABLE: + case COAP_MSG_TYPE_ACKNOWLEDGEMENT: + case COAP_MSG_TYPE_RESET: + break; /* Ok cases */ + default: + tr_error("sn_coap_header_validity_check - unknown message type!"); + return -1; /* Failed case */ + } + + /* * Check validity of Message code * */ + switch (src_coap_msg_ptr->msg_code) { + case COAP_MSG_CODE_EMPTY: + case COAP_MSG_CODE_REQUEST_GET: + case COAP_MSG_CODE_REQUEST_POST: + case COAP_MSG_CODE_REQUEST_PUT: + case COAP_MSG_CODE_REQUEST_DELETE: + case COAP_MSG_CODE_RESPONSE_CREATED: + case COAP_MSG_CODE_RESPONSE_DELETED: + case COAP_MSG_CODE_RESPONSE_VALID: + case COAP_MSG_CODE_RESPONSE_CHANGED: + case COAP_MSG_CODE_RESPONSE_CONTENT: + case COAP_MSG_CODE_RESPONSE_BAD_REQUEST: + case COAP_MSG_CODE_RESPONSE_UNAUTHORIZED: + case COAP_MSG_CODE_RESPONSE_BAD_OPTION: + case COAP_MSG_CODE_RESPONSE_FORBIDDEN: + case COAP_MSG_CODE_RESPONSE_NOT_FOUND: + case COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED: + case COAP_MSG_CODE_RESPONSE_NOT_ACCEPTABLE: + case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE: + case COAP_MSG_CODE_RESPONSE_PRECONDITION_FAILED: + case COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE: + case COAP_MSG_CODE_RESPONSE_UNSUPPORTED_CONTENT_FORMAT: + case COAP_MSG_CODE_RESPONSE_INTERNAL_SERVER_ERROR: + case COAP_MSG_CODE_RESPONSE_NOT_IMPLEMENTED: + case COAP_MSG_CODE_RESPONSE_BAD_GATEWAY: + case COAP_MSG_CODE_RESPONSE_SERVICE_UNAVAILABLE: + case COAP_MSG_CODE_RESPONSE_GATEWAY_TIMEOUT: + case COAP_MSG_CODE_RESPONSE_PROXYING_NOT_SUPPORTED: + case COAP_MSG_CODE_RESPONSE_CONTINUE: + break; /* Ok cases */ + default: + tr_error("sn_coap_header_validity_check - unknown message code!"); + return -1; /* Failed case */ + } + + /* Success */ + return 0; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/sn_coap_parser.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/sn_coap_parser.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,794 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + *\file sn_coap_parser.c + * + * \brief CoAP Header parser + * + * Functionality: Parses CoAP Header + * + */ + +/* * * * * * * * * * * * * * */ +/* * * * INCLUDE FILES * * * */ +/* * * * * * * * * * * * * * */ + +#include <stdio.h> +#include <string.h> /* For memset() and memcpy() */ + +#include "ns_types.h" +#include "mbed-coap/sn_coap_header.h" +#include "mbed-coap/sn_coap_protocol.h" +#include "sn_coap_header_internal.h" +#include "sn_coap_protocol_internal.h" +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "coap" +/* * * * * * * * * * * * * * * * * * * * */ +/* * * * LOCAL FUNCTION PROTOTYPES * * * */ +/* * * * * * * * * * * * * * * * * * * * */ + +static void sn_coap_parser_header_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, coap_version_e *coap_version_ptr); +static int8_t sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, uint8_t *packet_data_start_ptr, uint16_t packet_len); +static int8_t sn_coap_parser_options_parse_multiple_options(struct coap_s *handle, uint8_t **packet_data_pptr, uint16_t packet_left_len, uint8_t **dst_pptr, uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint16_t option_number_len); +static int16_t sn_coap_parser_options_count_needed_memory_multiple_option(uint8_t *packet_data_ptr, uint16_t packet_left_len, sn_coap_option_numbers_e option, uint16_t option_number_len); +static int8_t sn_coap_parser_payload_parse(uint16_t packet_data_len, uint8_t *packet_data_start_ptr, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr); + +sn_coap_hdr_s *sn_coap_parser_init_message(sn_coap_hdr_s *coap_msg_ptr) +{ + /* * * * Check given pointer * * * */ + if (coap_msg_ptr == NULL) { + tr_error("sn_coap_parser_init_message - message null!"); + return NULL; + } + + /* XXX not technically legal to memset pointers to 0 */ + memset(coap_msg_ptr, 0x00, sizeof(sn_coap_hdr_s)); + + coap_msg_ptr->content_format = COAP_CT_NONE; + + return coap_msg_ptr; +} + +sn_coap_hdr_s *sn_coap_parser_alloc_message(struct coap_s *handle) +{ + sn_coap_hdr_s *returned_coap_msg_ptr; + + /* * * * Check given pointer * * * */ + if (handle == NULL) { + return NULL; + } + + /* * * * Allocate memory for returned CoAP message and initialize allocated memory with with default values * * * */ + returned_coap_msg_ptr = handle->sn_coap_protocol_malloc(sizeof(sn_coap_hdr_s)); + + return sn_coap_parser_init_message(returned_coap_msg_ptr); +} + +sn_coap_options_list_s *sn_coap_parser_alloc_options(struct coap_s *handle, sn_coap_hdr_s *coap_msg_ptr) +{ + /* * * * Check given pointers * * * */ + if (handle == NULL || coap_msg_ptr == NULL) { + return NULL; + } + + /* * * * If the message already has options, return them * * * */ + if (coap_msg_ptr->options_list_ptr) { + return coap_msg_ptr->options_list_ptr; + } + + /* * * * Allocate memory for options and initialize allocated memory with with default values * * * */ + coap_msg_ptr->options_list_ptr = handle->sn_coap_protocol_malloc(sizeof(sn_coap_options_list_s)); + + if (coap_msg_ptr->options_list_ptr == NULL) { + tr_error("sn_coap_parser_alloc_options - failed to allocate options list!"); + return NULL; + } + + /* XXX not technically legal to memset pointers to 0 */ + memset(coap_msg_ptr->options_list_ptr, 0x00, sizeof(sn_coap_options_list_s)); + + coap_msg_ptr->options_list_ptr->max_age = COAP_OPTION_MAX_AGE_DEFAULT; + coap_msg_ptr->options_list_ptr->uri_port = COAP_OPTION_URI_PORT_NONE; + coap_msg_ptr->options_list_ptr->observe = COAP_OBSERVE_NONE; + coap_msg_ptr->options_list_ptr->accept = COAP_CT_NONE; + coap_msg_ptr->options_list_ptr->block2 = COAP_OPTION_BLOCK_NONE; + coap_msg_ptr->options_list_ptr->block1 = COAP_OPTION_BLOCK_NONE; + + return coap_msg_ptr->options_list_ptr; +} + +sn_coap_hdr_s *sn_coap_parser(struct coap_s *handle, uint16_t packet_data_len, uint8_t *packet_data_ptr, coap_version_e *coap_version_ptr) +{ + uint8_t *data_temp_ptr = packet_data_ptr; + sn_coap_hdr_s *parsed_and_returned_coap_msg_ptr = NULL; + + /* * * * Check given pointer * * * */ + if (packet_data_ptr == NULL || packet_data_len < 4 || handle == NULL) { + return NULL; + } + + /* * * * Allocate and initialize CoAP message * * * */ + parsed_and_returned_coap_msg_ptr = sn_coap_parser_alloc_message(handle); + + if (parsed_and_returned_coap_msg_ptr == NULL) { + tr_error("sn_coap_parser - failed to allocate message!"); + return NULL; + } + + /* * * * Header parsing, move pointer over the header... * * * */ + sn_coap_parser_header_parse(&data_temp_ptr, parsed_and_returned_coap_msg_ptr, coap_version_ptr); + + /* * * * Options parsing, move pointer over the options... * * * */ + if (sn_coap_parser_options_parse(handle, &data_temp_ptr, parsed_and_returned_coap_msg_ptr, packet_data_ptr, packet_data_len) != 0) { + parsed_and_returned_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_ERROR_IN_HEADER; + return parsed_and_returned_coap_msg_ptr; + } + + /* * * * Payload parsing * * * */ + if (sn_coap_parser_payload_parse(packet_data_len, packet_data_ptr, &data_temp_ptr, parsed_and_returned_coap_msg_ptr) == -1) { + parsed_and_returned_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_ERROR_IN_HEADER; + return parsed_and_returned_coap_msg_ptr; + } + + /* * * * Return parsed CoAP message * * * * */ + return parsed_and_returned_coap_msg_ptr; +} + +void sn_coap_parser_release_allocated_coap_msg_mem(struct coap_s *handle, sn_coap_hdr_s *freed_coap_msg_ptr) +{ + if (handle == NULL) { + return; + } + + if (freed_coap_msg_ptr != NULL) { + if (freed_coap_msg_ptr->uri_path_ptr != NULL) { + handle->sn_coap_protocol_free(freed_coap_msg_ptr->uri_path_ptr); + } + + if (freed_coap_msg_ptr->token_ptr != NULL) { + handle->sn_coap_protocol_free(freed_coap_msg_ptr->token_ptr); + } + + if (freed_coap_msg_ptr->options_list_ptr != NULL) { + if (freed_coap_msg_ptr->options_list_ptr->proxy_uri_ptr != NULL) { + handle->sn_coap_protocol_free(freed_coap_msg_ptr->options_list_ptr->proxy_uri_ptr); + } + + if (freed_coap_msg_ptr->options_list_ptr->etag_ptr != NULL) { + handle->sn_coap_protocol_free(freed_coap_msg_ptr->options_list_ptr->etag_ptr); + } + + if (freed_coap_msg_ptr->options_list_ptr->uri_host_ptr != NULL) { + handle->sn_coap_protocol_free(freed_coap_msg_ptr->options_list_ptr->uri_host_ptr); + } + + if (freed_coap_msg_ptr->options_list_ptr->location_path_ptr != NULL) { + handle->sn_coap_protocol_free(freed_coap_msg_ptr->options_list_ptr->location_path_ptr); + } + + if (freed_coap_msg_ptr->options_list_ptr->location_query_ptr != NULL) { + handle->sn_coap_protocol_free(freed_coap_msg_ptr->options_list_ptr->location_query_ptr); + } + + if (freed_coap_msg_ptr->options_list_ptr->uri_query_ptr != NULL) { + handle->sn_coap_protocol_free(freed_coap_msg_ptr->options_list_ptr->uri_query_ptr); + } + + handle->sn_coap_protocol_free(freed_coap_msg_ptr->options_list_ptr); + } + + handle->sn_coap_protocol_free(freed_coap_msg_ptr); + } +} + +/** + * \fn static void sn_coap_parser_header_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, coap_version_e *coap_version_ptr) + * + * \brief Parses CoAP message's Header part from given Packet data + * + * \param **packet_data_ptr is source for Packet data to be parsed to CoAP message + * + * \param *dst_coap_msg_ptr is destination for parsed CoAP message + * + * \param *coap_version_ptr is destination for parsed CoAP specification version + */ +static void sn_coap_parser_header_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, coap_version_e *coap_version_ptr) +{ + /* Parse CoAP Version and message type*/ + *coap_version_ptr = (coap_version_e)(**packet_data_pptr & COAP_HEADER_VERSION_MASK); + dst_coap_msg_ptr->msg_type = (sn_coap_msg_type_e)(**packet_data_pptr & COAP_HEADER_MSG_TYPE_MASK); + (*packet_data_pptr) += 1; + + /* Parse Message code */ + dst_coap_msg_ptr->msg_code = (sn_coap_msg_code_e) **packet_data_pptr; + (*packet_data_pptr) += 1; + + /* Parse Message ID */ + dst_coap_msg_ptr->msg_id = *(*packet_data_pptr + 1); + dst_coap_msg_ptr->msg_id += **packet_data_pptr << COAP_HEADER_MSG_ID_MSB_SHIFT; + (*packet_data_pptr) += 2; + +} + +/** + * \brief Parses a variable-length uint value from an option + * + * \param **packet_data_pptr is source of option data to be parsed + * \param option_len is length of option data (will be 0-4) + * + * \return Return value is value of uint + */ +static uint32_t sn_coap_parser_options_parse_uint(uint8_t **packet_data_pptr, uint8_t option_len) +{ + uint32_t value = 0; + while (option_len--) { + value <<= 8; + value |= *(*packet_data_pptr)++; + } + return value; +} + +/** + * \fn static uint8_t sn_coap_parser_options_parse(uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr) + * + * \brief Parses CoAP message's Options part from given Packet data + * + * \param **packet_data_pptr is source of Packet data to be parsed to CoAP message + * \param *dst_coap_msg_ptr is destination for parsed CoAP message + * + * \return Return value is 0 in ok case and -1 in failure case + */ +static int8_t sn_coap_parser_options_parse(struct coap_s *handle, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr, uint8_t *packet_data_start_ptr, uint16_t packet_len) +{ + uint8_t previous_option_number = 0; + uint8_t i = 0; + int8_t ret_status = 0; + uint16_t message_left = 0; + + /* Parse token, if exists */ + dst_coap_msg_ptr->token_len = *packet_data_start_ptr & COAP_HEADER_TOKEN_LENGTH_MASK; + + if (dst_coap_msg_ptr->token_len) { + if ((dst_coap_msg_ptr->token_len > 8) || dst_coap_msg_ptr->token_ptr) { + tr_error("sn_coap_parser_options_parse - token not valid!"); + return -1; + } + + dst_coap_msg_ptr->token_ptr = handle->sn_coap_protocol_malloc(dst_coap_msg_ptr->token_len); + + if (dst_coap_msg_ptr->token_ptr == NULL) { + tr_error("sn_coap_parser_options_parse - failed to allocate token!"); + return -1; + } + + memcpy(dst_coap_msg_ptr->token_ptr, *packet_data_pptr, dst_coap_msg_ptr->token_len); + (*packet_data_pptr) += dst_coap_msg_ptr->token_len; + } + + message_left = packet_len - ((*packet_data_pptr) - packet_data_start_ptr); + + /* Loop all Options */ + while (message_left && (**packet_data_pptr != 0xff)) { + + /* Get option length WITHOUT extensions */ + uint16_t option_len = (**packet_data_pptr & 0x0F); + + /* Resolve option delta */ + uint16_t option_number = (**packet_data_pptr >> COAP_OPTIONS_OPTION_NUMBER_SHIFT); + + if (option_number == 13) { + option_number = *(*packet_data_pptr + 1) + 13; + (*packet_data_pptr)++; + } else if (option_number == 14) { + option_number = *(*packet_data_pptr + 2); + option_number += (*(*packet_data_pptr + 1) << 8) + 269; + (*packet_data_pptr) += 2; + } + /* Option number 15 reserved for payload marker. This is handled as a error! */ + else if (option_number == 15) { + tr_error("sn_coap_parser_options_parse - invalid option number(15)!"); + return -1; + } + + /* Add previous option to option delta and get option number */ + option_number += previous_option_number; + + /* Add possible option length extension to resolve full length of the option */ + if (option_len == 13) { + option_len = *(*packet_data_pptr + 1) + 13; + (*packet_data_pptr)++; + } else if (option_len == 14) { + option_len = *(*packet_data_pptr + 2); + option_len += (*(*packet_data_pptr + 1) << 8) + 269; + (*packet_data_pptr) += 2; + } + /* Option number length 15 is reserved for the future use - ERROR */ + else if (option_len == 15) { + tr_error("sn_coap_parser_options_parse - invalid option len(15)!"); + return -1; + } + + message_left = packet_len - (*packet_data_pptr - packet_data_start_ptr); + + /* * * Parse option itself * * */ + /* Some options are handled independently in own functions */ + previous_option_number = option_number; + /* Allocate options_list_ptr if needed */ + switch (option_number) { + case COAP_OPTION_MAX_AGE: + case COAP_OPTION_PROXY_URI: + case COAP_OPTION_ETAG: + case COAP_OPTION_URI_HOST: + case COAP_OPTION_LOCATION_PATH: + case COAP_OPTION_URI_PORT: + case COAP_OPTION_LOCATION_QUERY: + case COAP_OPTION_OBSERVE: + case COAP_OPTION_URI_QUERY: + case COAP_OPTION_BLOCK2: + case COAP_OPTION_BLOCK1: + case COAP_OPTION_ACCEPT: + case COAP_OPTION_SIZE1: + case COAP_OPTION_SIZE2: + if (sn_coap_parser_alloc_options(handle, dst_coap_msg_ptr) == NULL) { + tr_error("sn_coap_parser_options_parse - failed to allocate options!"); + return -1; + } + break; + } + + /* Parse option */ + switch (option_number) { + case COAP_OPTION_CONTENT_FORMAT: + if ((option_len > 2) || (dst_coap_msg_ptr->content_format != COAP_CT_NONE)) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_CONTENT_FORMAT not valid!"); + return -1; + } + (*packet_data_pptr)++; + dst_coap_msg_ptr->content_format = (sn_coap_content_format_e) sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + break; + + case COAP_OPTION_MAX_AGE: + if (option_len > 4) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_MAX_AGE not valid!"); + return -1; + } + (*packet_data_pptr)++; + dst_coap_msg_ptr->options_list_ptr->max_age = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + break; + + case COAP_OPTION_PROXY_URI: + if ((option_len > 1034) || (option_len < 1) || dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_PROXY_URI not valid!"); + return -1; + } + dst_coap_msg_ptr->options_list_ptr->proxy_uri_len = option_len; + (*packet_data_pptr)++; + + dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr = handle->sn_coap_protocol_malloc(option_len); + + if (dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr == NULL) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_PROXY_URI allocation failed!"); + return -1; + } + + memcpy(dst_coap_msg_ptr->options_list_ptr->proxy_uri_ptr, *packet_data_pptr, option_len); + (*packet_data_pptr) += option_len; + + break; + + case COAP_OPTION_ETAG: + /* This is managed independently because User gives this option in one character table */ + + ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, + message_left, + &dst_coap_msg_ptr->options_list_ptr->etag_ptr, + (uint16_t *)&dst_coap_msg_ptr->options_list_ptr->etag_len, + COAP_OPTION_ETAG, option_len); + if (ret_status >= 0) { + i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */ + } else { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_ETAG not valid!"); + return -1; + } + break; + + case COAP_OPTION_URI_HOST: + if ((option_len > 255) || (option_len < 1) || dst_coap_msg_ptr->options_list_ptr->uri_host_ptr) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_HOST not valid!"); + return -1; + } + dst_coap_msg_ptr->options_list_ptr->uri_host_len = option_len; + (*packet_data_pptr)++; + + dst_coap_msg_ptr->options_list_ptr->uri_host_ptr = handle->sn_coap_protocol_malloc(option_len); + + if (dst_coap_msg_ptr->options_list_ptr->uri_host_ptr == NULL) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_HOST allocation failed!"); + return -1; + } + memcpy(dst_coap_msg_ptr->options_list_ptr->uri_host_ptr, *packet_data_pptr, option_len); + (*packet_data_pptr) += option_len; + + break; + + case COAP_OPTION_LOCATION_PATH: + if (dst_coap_msg_ptr->options_list_ptr->location_path_ptr) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_PATH exists!"); + return -1; + } + /* This is managed independently because User gives this option in one character table */ + ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left, + &dst_coap_msg_ptr->options_list_ptr->location_path_ptr, &dst_coap_msg_ptr->options_list_ptr->location_path_len, + COAP_OPTION_LOCATION_PATH, option_len); + if (ret_status >= 0) { + i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */ + } else { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_PATH not valid!"); + return -1; + } + + break; + + + case COAP_OPTION_URI_PORT: + if ((option_len > 2) || dst_coap_msg_ptr->options_list_ptr->uri_port != COAP_OPTION_URI_PORT_NONE) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_PORT not valid!"); + return -1; + } + (*packet_data_pptr)++; + + dst_coap_msg_ptr->options_list_ptr->uri_port = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + break; + + case COAP_OPTION_LOCATION_QUERY: + ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left, + &dst_coap_msg_ptr->options_list_ptr->location_query_ptr, &dst_coap_msg_ptr->options_list_ptr->location_query_len, + COAP_OPTION_LOCATION_QUERY, option_len); + if (ret_status >= 0) { + i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */ + } else { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_LOCATION_QUERY not valid!"); + return -1; + } + + break; + + case COAP_OPTION_URI_PATH: + ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left, + &dst_coap_msg_ptr->uri_path_ptr, &dst_coap_msg_ptr->uri_path_len, + COAP_OPTION_URI_PATH, option_len); + if (ret_status >= 0) { + i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */ + } else { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_PATH not valid!"); + return -1; + } + + break; + + case COAP_OPTION_OBSERVE: + if ((option_len > 2) || dst_coap_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_OBSERVE not valid!"); + return -1; + } + + (*packet_data_pptr)++; + + dst_coap_msg_ptr->options_list_ptr->observe = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + + break; + + case COAP_OPTION_URI_QUERY: + ret_status = sn_coap_parser_options_parse_multiple_options(handle, packet_data_pptr, message_left, + &dst_coap_msg_ptr->options_list_ptr->uri_query_ptr, &dst_coap_msg_ptr->options_list_ptr->uri_query_len, + COAP_OPTION_URI_QUERY, option_len); + if (ret_status >= 0) { + i += (ret_status - 1); /* i += is because possible several Options are handled by sn_coap_parser_options_parse_multiple_options() */ + } else { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_URI_QUERY not valid!"); + return -1; + } + + break; + + case COAP_OPTION_BLOCK2: + if ((option_len > 3) || dst_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_BLOCK2 not valid!"); + return -1; + } + (*packet_data_pptr)++; + + dst_coap_msg_ptr->options_list_ptr->block2 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + + break; + + case COAP_OPTION_BLOCK1: + if ((option_len > 3) || dst_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_BLOCK1 not valid!"); + return -1; + } + (*packet_data_pptr)++; + + dst_coap_msg_ptr->options_list_ptr->block1 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + + break; + + case COAP_OPTION_ACCEPT: + if ((option_len > 2) || (dst_coap_msg_ptr->options_list_ptr->accept != COAP_CT_NONE)) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_ACCEPT not valid!"); + return -1; + } + + (*packet_data_pptr)++; + + dst_coap_msg_ptr->options_list_ptr->accept = (sn_coap_content_format_e) sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + break; + + case COAP_OPTION_SIZE1: + if ((option_len > 4) || dst_coap_msg_ptr->options_list_ptr->use_size1) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_SIZE1 not valid!"); + return -1; + } + dst_coap_msg_ptr->options_list_ptr->use_size1 = true; + (*packet_data_pptr)++; + dst_coap_msg_ptr->options_list_ptr->size1 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + break; + + case COAP_OPTION_SIZE2: + if ((option_len > 4) || dst_coap_msg_ptr->options_list_ptr->use_size2) { + tr_error("sn_coap_parser_options_parse - COAP_OPTION_SIZE2 not valid!"); + return -1; + } + dst_coap_msg_ptr->options_list_ptr->use_size2 = true; + (*packet_data_pptr)++; + dst_coap_msg_ptr->options_list_ptr->size2 = sn_coap_parser_options_parse_uint(packet_data_pptr, option_len); + break; + + default: + tr_error("sn_coap_parser_options_parse - unknown option!"); + return -1; + } + + /* Check for overflow */ + if ((*packet_data_pptr - packet_data_start_ptr) > packet_len) { + return -1; + } + + message_left = packet_len - (*packet_data_pptr - packet_data_start_ptr); + + } + + return 0; +} + + +/** + * \fn static int8_t sn_coap_parser_options_parse_multiple_options(uint8_t **packet_data_pptr, uint8_t options_count_left, uint8_t *previous_option_number_ptr, uint8_t **dst_pptr, + * uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint16_t option_number_len) + * + * \brief Parses CoAP message's Uri-query options + * + * \param **packet_data_pptr is source for Packet data to be parsed to CoAP message + * + * \param *dst_coap_msg_ptr is destination for parsed CoAP message + * + * \param options_count_left tells how many options are unhandled in Packet data + * + * \param *previous_option_number_ptr is pointer to used and returned previous Option number + * + * \return Return value is count of Uri-query optios parsed. In failure case -1 is returned. +*/ +static int8_t sn_coap_parser_options_parse_multiple_options(struct coap_s *handle, uint8_t **packet_data_pptr, uint16_t packet_left_len, uint8_t **dst_pptr, uint16_t *dst_len_ptr, sn_coap_option_numbers_e option, uint16_t option_number_len) +{ + int16_t uri_query_needed_heap = sn_coap_parser_options_count_needed_memory_multiple_option(*packet_data_pptr, packet_left_len, option, option_number_len); + uint8_t *temp_parsed_uri_query_ptr = NULL; + uint8_t returned_option_counter = 0; + + if (uri_query_needed_heap == -1) { + return -1; + } + + if (uri_query_needed_heap) { + *dst_pptr = (uint8_t *) handle->sn_coap_protocol_malloc(uri_query_needed_heap); + + if (*dst_pptr == NULL) { + tr_error("sn_coap_parser_options_parse_multiple_options - failed to allocate options!"); + return -1; + } + } + + *dst_len_ptr = uri_query_needed_heap; + + temp_parsed_uri_query_ptr = *dst_pptr; + + /* Loop all Uri-Query options */ + while ((temp_parsed_uri_query_ptr - *dst_pptr) < uri_query_needed_heap) { + /* Check if this is first Uri-Query option */ + if (returned_option_counter > 0) { + /* Uri-Query is modified to following format: temp1'\0'temp2'\0'temp3 i.e. */ + /* Uri-Path is modified to following format: temp1\temp2\temp3 i.e. */ + if (option == COAP_OPTION_URI_QUERY || option == COAP_OPTION_LOCATION_QUERY || option == COAP_OPTION_ETAG || option == COAP_OPTION_ACCEPT) { + memset(temp_parsed_uri_query_ptr, '&', 1); + } else if (option == COAP_OPTION_URI_PATH || option == COAP_OPTION_LOCATION_PATH) { + memset(temp_parsed_uri_query_ptr, '/', 1); + } + + temp_parsed_uri_query_ptr++; + } + + returned_option_counter++; + + (*packet_data_pptr)++; + + if (((temp_parsed_uri_query_ptr - *dst_pptr) + option_number_len) > uri_query_needed_heap) { + return -1; + } + + memcpy(temp_parsed_uri_query_ptr, *packet_data_pptr, option_number_len); + + (*packet_data_pptr) += option_number_len; + temp_parsed_uri_query_ptr += option_number_len; + + if ((temp_parsed_uri_query_ptr - *dst_pptr) >= uri_query_needed_heap || ((**packet_data_pptr >> COAP_OPTIONS_OPTION_NUMBER_SHIFT) != 0)) { + return returned_option_counter; + } + + option_number_len = (**packet_data_pptr & 0x0F); + if (option_number_len == 13) { + option_number_len = *(*packet_data_pptr + 1) + 13; + (*packet_data_pptr)++; + } else if (option_number_len == 14) { + option_number_len = *(*packet_data_pptr + 2); + option_number_len += (*(*packet_data_pptr + 1) << 8) + 269; + (*packet_data_pptr) += 2; + } + } + + return returned_option_counter; +} + + + + +/** + * \fn static uint16_t sn_coap_parser_options_count_needed_memory_multiple_option(uint8_t *packet_data_ptr, uint8_t options_count_left, uint8_t previous_option_number, sn_coap_option_numbers_e option, uint16_t option_number_len) + * + * \brief Counts needed memory for uri query option + * + * \param *packet_data_ptr is start of source for Packet data to be parsed to CoAP message + * + * \param options_count_left tells how many options are unhandled in Packet data + * + * \param previous_option_number is previous Option number + * + * \param sn_coap_option_numbers_e option option number to be calculated + * + * \param uint16_t option_number_len length of the first option part + */ +static int16_t sn_coap_parser_options_count_needed_memory_multiple_option(uint8_t *packet_data_ptr, uint16_t packet_left_len, sn_coap_option_numbers_e option, uint16_t option_number_len) +{ + uint16_t ret_value = 0; + uint16_t i = 1; + + /* Loop all Uri-Query options */ + while (i <= packet_left_len) { + if (option == COAP_OPTION_LOCATION_PATH && option_number_len > 255) { + return -1; + } + if (option == COAP_OPTION_URI_PATH && option_number_len > 255) { + return -1; + } + if (option == COAP_OPTION_URI_QUERY && option_number_len > 255) { + return -1; + } + if (option == COAP_OPTION_LOCATION_QUERY && option_number_len > 255) { + return -1; + } + if (option == COAP_OPTION_ACCEPT && option_number_len > 2) { + return -1; + } + if (option == COAP_OPTION_ETAG && option_number_len > 8) { + return -1; + } + + i += option_number_len; + ret_value += option_number_len + 1; /* + 1 is for separator */ + + if( i == packet_left_len ) { + break; + } + else if( i > packet_left_len ) { + return -1; + } + + if ((*(packet_data_ptr + i) >> COAP_OPTIONS_OPTION_NUMBER_SHIFT) != 0) { + return (ret_value - 1); /* -1 because last Part path does not include separator */ + } + + option_number_len = (*(packet_data_ptr + i) & 0x0F); + + if (option_number_len == 13) { + + if(i + 1 >= packet_left_len) { + return -1; + } + + i++; + option_number_len = *(packet_data_ptr + i) + 13; + } else if (option_number_len == 14) { + + if(i + 2 >= packet_left_len) { + return -1; + } + + option_number_len = *(packet_data_ptr + i + 2); + option_number_len += (*(packet_data_ptr + i + 1) << 8) + 269; + i += 2; + } else if (option_number_len == 15) { + return -1; + } + i++; + + } + + if (ret_value != 0) { + return (ret_value - 1); /* -1 because last Part path does not include separator */ + } else { + return 0; + } +} + +/** + * \fn static void sn_coap_parser_payload_parse(uint16_t packet_data_len, uint8_t *packet_data_ptr, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr) + * + * \brief Parses CoAP message's Payload part from given Packet data + * + * \param packet_data_len is length of given Packet data to be parsed to CoAP message + * + * \param *packet_data_ptr is start of source for Packet data to be parsed to CoAP message + * + * \param **packet_data_pptr is source for Packet data to be parsed to CoAP message + * + * \param *dst_coap_msg_ptr is destination for parsed CoAP message + *****************************************************************************/ +static int8_t sn_coap_parser_payload_parse(uint16_t packet_data_len, uint8_t *packet_data_start_ptr, uint8_t **packet_data_pptr, sn_coap_hdr_s *dst_coap_msg_ptr) +{ + /* If there is payload */ + if ((*packet_data_pptr - packet_data_start_ptr) < packet_data_len) { + if (**packet_data_pptr == 0xff) { + (*packet_data_pptr)++; + /* Parse Payload length */ + dst_coap_msg_ptr->payload_len = packet_data_len - (*packet_data_pptr - packet_data_start_ptr); + + /* The presence of a marker followed by a zero-length payload MUST be processed as a message format error */ + if (dst_coap_msg_ptr->payload_len == 0) { + return -1; + } + + /* Parse Payload by setting CoAP message's payload_ptr to point Payload in Packet data */ + dst_coap_msg_ptr->payload_ptr = *packet_data_pptr; + } + /* No payload marker.. */ + else { + tr_error("sn_coap_parser_payload_parse - payload marker not found!"); + return -1; + } + } + return 0; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/sn_coap_protocol.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-coap/source/sn_coap_protocol.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2302 @@ +/* + * Copyright (c) 2011-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file sn_coap_protocol.c + * + * \brief CoAP Protocol implementation + * + * Functionality: CoAP Protocol + * + */ + + +/* * * * * * * * * * * * * * */ +/* * * * INCLUDE FILES * * * */ +/* * * * * * * * * * * * * * */ + +#include <stdio.h> +#include <stdlib.h> /* For libary malloc() */ +#include <string.h> /* For memset() and memcpy() */ +#if defined __linux__ || defined TARGET_LIKE_MBED +#include <time.h> +#endif + +#include "ns_types.h" +#include "mbed-coap/sn_coap_protocol.h" +#include "sn_coap_header_internal.h" +#include "sn_coap_protocol_internal.h" +#include "randLIB.h" +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "coap" +/* * * * * * * * * * * * * * * * * * * * */ +/* * * * LOCAL FUNCTION PROTOTYPES * * * */ +/* * * * * * * * * * * * * * * * * * * * */ + +static void sn_coap_protocol_send_rst(struct coap_s *handle, uint16_t msg_id, sn_nsdl_addr_s *addr_ptr, void *param); +#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT/* If Message duplication detection is not used at all, this part of code will not be compiled */ +static void sn_coap_protocol_linked_list_duplication_info_store(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t msg_id, void *param); +static coap_duplication_info_s *sn_coap_protocol_linked_list_duplication_info_search(struct coap_s *handle, sn_nsdl_addr_s *scr_addr_ptr, uint16_t msg_id); +static void sn_coap_protocol_linked_list_duplication_info_remove(struct coap_s *handle, uint8_t *scr_addr_ptr, uint16_t port, uint16_t msg_id); +static void sn_coap_protocol_linked_list_duplication_info_remove_old_ones(struct coap_s *handle); +#endif +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ +static void sn_coap_protocol_linked_list_blockwise_msg_remove(struct coap_s *handle, coap_blockwise_msg_s *removed_msg_ptr); +static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s *handle, sn_nsdl_addr_s *addr_ptr, uint16_t stored_payload_len, uint8_t *stored_payload_ptr, uint32_t block_number); +static uint8_t *sn_coap_protocol_linked_list_blockwise_payload_search(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t *payload_length); +static bool sn_coap_protocol_linked_list_blockwise_payload_compare_block_number(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint32_t block_number); +static void sn_coap_protocol_linked_list_blockwise_payload_remove(struct coap_s *handle, coap_blockwise_payload_s *removed_payload_ptr); +static void sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(struct coap_s *handle); +static uint32_t sn_coap_protocol_linked_list_blockwise_payloads_get_len(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr); +static void sn_coap_protocol_linked_list_blockwise_remove_old_data(struct coap_s *handle); +static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr, void *param); +static sn_coap_hdr_s *sn_coap_protocol_copy_header(struct coap_s *handle, sn_coap_hdr_s *source_header_ptr); +#endif +#if ENABLE_RESENDINGS +static uint8_t sn_coap_protocol_linked_list_send_msg_store(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint16_t send_packet_data_len, uint8_t *send_packet_data_ptr, uint32_t sending_time, void *param); +static sn_nsdl_transmit_s *sn_coap_protocol_linked_list_send_msg_search(struct coap_s *handle,sn_nsdl_addr_s *src_addr_ptr, uint16_t msg_id); +static void sn_coap_protocol_linked_list_send_msg_remove(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t msg_id); +static coap_send_msg_s *sn_coap_protocol_allocate_mem_for_msg(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint16_t packet_data_len); +static void sn_coap_protocol_release_allocated_send_msg_mem(struct coap_s *handle, coap_send_msg_s *freed_send_msg_ptr); +static uint16_t sn_coap_count_linked_list_size(const coap_send_msg_list_t *linked_list_ptr); +static uint32_t sn_coap_calculate_new_resend_time(const uint32_t current_time, const uint8_t interval, const uint8_t counter); +#endif + +/* * * * * * * * * * * * * * * * * */ +/* * * * GLOBAL DECLARATIONS * * * */ +/* * * * * * * * * * * * * * * * * */ +static uint16_t message_id; + +int8_t sn_coap_protocol_destroy(struct coap_s *handle) +{ + if (handle == NULL) { + return -1; + } +#if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ + + sn_coap_protocol_clear_retransmission_buffer(handle); + +#endif + +#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT /* If Message duplication detection is not used at all, this part of code will not be compiled */ + ns_list_foreach_safe(coap_duplication_info_s, tmp, &handle->linked_list_duplication_msgs) { + if (tmp->coap == handle) { + if (tmp->address) { + if (tmp->address->addr_ptr) { + handle->sn_coap_protocol_free(tmp->address->addr_ptr); + tmp->address->addr_ptr = 0; + } + handle->sn_coap_protocol_free(tmp->address); + tmp->address = 0; + } + if (tmp->packet_ptr) { + handle->sn_coap_protocol_free(tmp->packet_ptr); + tmp->packet_ptr = 0; + } + ns_list_remove(&handle->linked_list_duplication_msgs, tmp); + handle->count_duplication_msgs--; + handle->sn_coap_protocol_free(tmp); + tmp = 0; + } + } + +#endif + + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwise is not used at all, this part of code will not be compiled */ + ns_list_foreach_safe(coap_blockwise_msg_s, tmp, &handle->linked_list_blockwise_sent_msgs) { + if (tmp->coap == handle) { + if (tmp->coap_msg_ptr) { + if (tmp->coap_msg_ptr->payload_ptr) { + handle->sn_coap_protocol_free(tmp->coap_msg_ptr->payload_ptr); + tmp->coap_msg_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(tmp->coap, tmp->coap_msg_ptr); + } + ns_list_remove(&handle->linked_list_blockwise_sent_msgs, tmp); + handle->sn_coap_protocol_free(tmp); + tmp = 0; + } + } + ns_list_foreach_safe(coap_blockwise_payload_s, tmp, &handle->linked_list_blockwise_received_payloads) { + if (tmp->coap == handle) { + if (tmp->addr_ptr) { + handle->sn_coap_protocol_free(tmp->addr_ptr); + tmp->addr_ptr = 0; + } + if (tmp->payload_ptr) { + handle->sn_coap_protocol_free(tmp->payload_ptr); + tmp->payload_ptr = 0; + } + ns_list_remove(&handle->linked_list_blockwise_received_payloads, tmp); + handle->sn_coap_protocol_free(tmp); + tmp = 0; + } + } +#endif + + handle->sn_coap_protocol_free(handle); + handle = 0; + return 0; +} + +struct coap_s *sn_coap_protocol_init(void *(*used_malloc_func_ptr)(uint16_t), void (*used_free_func_ptr)(void *), + uint8_t (*used_tx_callback_ptr)(uint8_t *, uint16_t, sn_nsdl_addr_s *, void *), + int8_t (*used_rx_callback_ptr)(sn_coap_hdr_s *, sn_nsdl_addr_s *, void *param)) +{ + /* Check paramters */ + if ((used_malloc_func_ptr == NULL) || (used_free_func_ptr == NULL) || (used_tx_callback_ptr == NULL)) { + return NULL; + } + + struct coap_s *handle; + handle = used_malloc_func_ptr(sizeof(struct coap_s)); + if (handle == NULL) { + return NULL; + } + + memset(handle, 0, sizeof(struct coap_s)); + + /* * * Handle tx callback * * */ + handle->sn_coap_tx_callback = used_tx_callback_ptr; + + handle->sn_coap_protocol_free = used_free_func_ptr; + handle->sn_coap_protocol_malloc = used_malloc_func_ptr; + + /* * * Handle rx callback * * */ + /* If pointer = 0, then re-sending does not return error when failed */ + handle->sn_coap_rx_callback = used_rx_callback_ptr; + + // Handles internally all GET req responses + handle->sn_coap_internal_block2_resp_handling = true; + +#if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ + /* * * * Create Linked list for storing active resending messages * * * */ + ns_list_init(&handle->linked_list_resent_msgs); + handle->sn_coap_resending_queue_msgs = SN_COAP_RESENDING_QUEUE_SIZE_MSGS; + handle->sn_coap_resending_queue_bytes = SN_COAP_RESENDING_QUEUE_SIZE_BYTES; + handle->sn_coap_resending_intervall = DEFAULT_RESPONSE_TIMEOUT; + handle->sn_coap_resending_count = SN_COAP_RESENDING_MAX_COUNT; + + +#endif /* ENABLE_RESENDINGS */ + +#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT /* If Message duplication detection is not used at all, this part of code will not be compiled */ + /* * * * Create Linked list for storing Duplication info * * * */ + ns_list_init(&handle->linked_list_duplication_msgs); + handle->sn_coap_duplication_buffer_size = SN_COAP_DUPLICATION_MAX_MSGS_COUNT; +#endif + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ + + ns_list_init(&handle->linked_list_blockwise_sent_msgs); + ns_list_init(&handle->linked_list_blockwise_received_payloads); + handle->sn_coap_block_data_size = SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE; + +#endif /* ENABLE_RESENDINGS */ + + /* Randomize global message ID */ + randLIB_seed_random(); + message_id = randLIB_get_16bit(); + if (message_id == 0) { + message_id = 1; + } + + return handle; +} + +int8_t sn_coap_protocol_handle_block2_response_internally(struct coap_s *handle, uint8_t build_response) +{ + if (handle == NULL) { + return -1; + } + + handle->sn_coap_internal_block2_resp_handling = build_response; + return 0; +} + +int8_t sn_coap_protocol_set_block_size(struct coap_s *handle, uint16_t block_size) +{ + (void) handle; + (void) block_size; +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + if (handle == NULL) { + return -1; + } + switch (block_size) { + case 0: + case 16: + case 32: + case 64: + case 128: + case 256: + case 512: + case 1024: + handle->sn_coap_block_data_size = block_size; + return 0; + default: + break; + } +#endif + return -1; + +} + +int8_t sn_coap_protocol_set_duplicate_buffer_size(struct coap_s *handle, uint8_t message_count) +{ + (void) handle; + (void) message_count; +#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT + if (handle == NULL) { + return -1; + } + if (message_count <= SN_COAP_MAX_ALLOWED_DUPLICATION_MESSAGE_COUNT) { + handle->sn_coap_duplication_buffer_size = message_count; + return 0; + } +#endif + return -1; +} + +int8_t sn_coap_protocol_set_retransmission_parameters(struct coap_s *handle, + uint8_t resending_count, uint8_t resending_intervall) +{ +#if ENABLE_RESENDINGS + if (handle == NULL) { + return -1; + } + if (resending_count <= SN_COAP_MAX_ALLOWED_RESENDING_COUNT && + resending_intervall <= SN_COAP_MAX_ALLOWED_RESPONSE_TIMEOUT) { + handle->sn_coap_resending_count = resending_count; + + if (resending_intervall == 0) { + handle->sn_coap_resending_intervall = 1; + } else { + handle->sn_coap_resending_intervall = resending_intervall; + } + return 0; + } +#endif + return -1; +} + +int8_t sn_coap_protocol_set_retransmission_buffer(struct coap_s *handle, + uint8_t buffer_size_messages, uint16_t buffer_size_bytes) +{ +#if ENABLE_RESENDINGS + if (handle == NULL) { + return -1; + } + if (buffer_size_bytes <= SN_COAP_MAX_ALLOWED_RESENDING_BUFF_SIZE_BYTES && + buffer_size_messages <= SN_COAP_MAX_ALLOWED_RESENDING_BUFF_SIZE_MSGS ) { + handle->sn_coap_resending_queue_bytes = buffer_size_bytes; + handle->sn_coap_resending_queue_msgs = buffer_size_messages; + return 0; + } + +#endif + return -1; + +} + +void sn_coap_protocol_clear_retransmission_buffer(struct coap_s *handle) +{ +#if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ + if (handle == NULL) { + return; + } + ns_list_foreach_safe(coap_send_msg_s, tmp, &handle->linked_list_resent_msgs) { + ns_list_remove(&handle->linked_list_resent_msgs, tmp); + sn_coap_protocol_release_allocated_send_msg_mem(handle, tmp); + --handle->count_resent_msgs; + } +#endif +} + +int8_t sn_coap_protocol_delete_retransmission(struct coap_s *handle, uint16_t msg_id) +{ +#if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ + if (handle == NULL) { + return -1; + } + ns_list_foreach_safe(coap_send_msg_s, tmp, &handle->linked_list_resent_msgs) { + if (tmp->send_msg_ptr && tmp->send_msg_ptr->packet_ptr ) { + uint16_t temp_msg_id = (tmp->send_msg_ptr->packet_ptr[2] << 8); + temp_msg_id += (uint16_t)tmp->send_msg_ptr->packet_ptr[3]; + if(temp_msg_id == msg_id){ + ns_list_remove(&handle->linked_list_resent_msgs, tmp); + --handle->count_resent_msgs; + sn_coap_protocol_release_allocated_send_msg_mem(handle, tmp); + return 0; + } + } + } +#endif + return -2; +} + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ +int8_t prepare_blockwise_message(struct coap_s *handle, sn_coap_hdr_s *src_coap_msg_ptr) +{ + if ((src_coap_msg_ptr->payload_len > handle->sn_coap_block_data_size) && (handle->sn_coap_block_data_size > 0)) { + /* * * * Add Blockwise option to send CoAP message * * */ + + /* Allocate memory for less used options */ + if (sn_coap_parser_alloc_options(handle, src_coap_msg_ptr) == NULL) { + tr_error("prepare_blockwise_message - failed to allocate options!"); + return -2; + } + + /* Check if Request message */ + if (src_coap_msg_ptr->msg_code < COAP_MSG_CODE_RESPONSE_CREATED) { + /* Add Blockwise option, use Block1 because Request payload */ + src_coap_msg_ptr->options_list_ptr->block1 = 0x08; /* First block (BLOCK NUMBER, 4 MSB bits) + More to come (MORE, 1 bit) */ + src_coap_msg_ptr->options_list_ptr->block1 |= sn_coap_convert_block_size(handle->sn_coap_block_data_size); + + /* Add size1 parameter */ + + src_coap_msg_ptr->options_list_ptr->use_size1 = true; + src_coap_msg_ptr->options_list_ptr->use_size2 = false; + src_coap_msg_ptr->options_list_ptr->size1 = src_coap_msg_ptr->payload_len; + } else { /* Response message */ + /* Add Blockwise option, use Block2 because Response payload */ + src_coap_msg_ptr->options_list_ptr->block2 = 0x08; /* First block (BLOCK NUMBER, 4 MSB bits) + More to come (MORE, 1 bit) */ + src_coap_msg_ptr->options_list_ptr->block2 |= sn_coap_convert_block_size(handle->sn_coap_block_data_size); + + src_coap_msg_ptr->options_list_ptr->use_size1 = false; + src_coap_msg_ptr->options_list_ptr->use_size2 = true; + src_coap_msg_ptr->options_list_ptr->size2 = src_coap_msg_ptr->payload_len; + } + } + return 0; +} +#endif + +int16_t sn_coap_protocol_build(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, + uint8_t *dst_packet_data_ptr, sn_coap_hdr_s *src_coap_msg_ptr, void *param) +{ + int16_t byte_count_built = 0; +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ + uint16_t original_payload_len = 0; +#endif + /* * * * Check given pointers * * * */ + if ((dst_addr_ptr == NULL) || (dst_packet_data_ptr == NULL) || (src_coap_msg_ptr == NULL) || handle == NULL) { + return -2; + } + + if (dst_addr_ptr->addr_ptr == NULL) { + return -2; + } + + /* Check if built Message type is else than Acknowledgement or Reset i.e. message type is Confirmable or Non-confirmable */ + /* (for Acknowledgement and Reset messages is written same Message ID than was in the Request message) */ + if (src_coap_msg_ptr->msg_type != COAP_MSG_TYPE_ACKNOWLEDGEMENT && + src_coap_msg_ptr->msg_type != COAP_MSG_TYPE_RESET && + src_coap_msg_ptr->msg_id == 0) { + /* * * * Generate new Message ID and increase it by one * * * */ + src_coap_msg_ptr->msg_id = message_id; + message_id++; + if (message_id == 0) { + message_id = 1; + } + } + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ + + /* If blockwising needed */ + if ((src_coap_msg_ptr->payload_len > handle->sn_coap_block_data_size) && (handle->sn_coap_block_data_size > 0)) { + /* Store original Payload length */ + original_payload_len = src_coap_msg_ptr->payload_len; + /* Change Payload length of send message because Payload is blockwised */ + src_coap_msg_ptr->payload_len = handle->sn_coap_block_data_size; + } + +#endif + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + /* * * * Build Packet data from CoAP message by using CoAP Header builder * * * */ + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + byte_count_built = sn_coap_builder_2(dst_packet_data_ptr, src_coap_msg_ptr, handle->sn_coap_block_data_size); + + if (byte_count_built < 0) { + tr_error("sn_coap_protocol_build - failed to build message!"); + return byte_count_built; + } + +#if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ + + /* Check if built Message type was confirmable, only these messages are resent */ + if (src_coap_msg_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { + /* Store message to Linked list for resending purposes */ + uint32_t resend_time = sn_coap_calculate_new_resend_time(handle->system_time, handle->sn_coap_resending_intervall, 0); + if (sn_coap_protocol_linked_list_send_msg_store(handle, dst_addr_ptr, byte_count_built, dst_packet_data_ptr, + resend_time, + param) == 0) { + return -4; + } + } + +#endif /* ENABLE_RESENDINGS */ + +#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT + if (src_coap_msg_ptr->msg_type == COAP_MSG_TYPE_ACKNOWLEDGEMENT && + handle->sn_coap_duplication_buffer_size != 0) { + coap_duplication_info_s* info = sn_coap_protocol_linked_list_duplication_info_search(handle, + dst_addr_ptr, + src_coap_msg_ptr->msg_id); + /* Update package data to duplication info struct if it's not there yet */ + if (info && info->packet_ptr == NULL) { + info->packet_ptr = handle->sn_coap_protocol_malloc(byte_count_built); + if (info->packet_ptr) { + memcpy(info->packet_ptr, dst_packet_data_ptr, byte_count_built); + info->packet_len = byte_count_built; + } else { + tr_error("sn_coap_protocol_build - failed to allocate duplication info!"); + return -4; + } + } + } +#endif + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is not used at all, this part of code will not be compiled */ + + /* If blockwising needed */ + if ((original_payload_len > handle->sn_coap_block_data_size) && (handle->sn_coap_block_data_size > 0)) { + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + /* * * * Manage rest blockwise messages sending by storing them to Linked list * * * */ + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + coap_blockwise_msg_s *stored_blockwise_msg_ptr; + + stored_blockwise_msg_ptr = handle->sn_coap_protocol_malloc(sizeof(coap_blockwise_msg_s)); + if (!stored_blockwise_msg_ptr) { + //block paylaod save failed, only first block can be build. Perhaps we should return error. + tr_error("sn_coap_protocol_build - blockwise message allocation failed!"); + return byte_count_built; + } + memset(stored_blockwise_msg_ptr, 0, sizeof(coap_blockwise_msg_s)); + + /* Fill struct */ + stored_blockwise_msg_ptr->timestamp = handle->system_time; + + stored_blockwise_msg_ptr->coap_msg_ptr = sn_coap_protocol_copy_header(handle, src_coap_msg_ptr); + if( stored_blockwise_msg_ptr->coap_msg_ptr == NULL ){ + handle->sn_coap_protocol_free(stored_blockwise_msg_ptr); + stored_blockwise_msg_ptr = 0; + tr_error("sn_coap_protocol_build - block header copy failed!"); + return -2; + } + + stored_blockwise_msg_ptr->coap_msg_ptr->payload_len = original_payload_len; + stored_blockwise_msg_ptr->coap_msg_ptr->payload_ptr = handle->sn_coap_protocol_malloc(stored_blockwise_msg_ptr->coap_msg_ptr->payload_len); + + if (!stored_blockwise_msg_ptr->coap_msg_ptr->payload_ptr) { + //block payload save failed, only first block can be build. Perhaps we should return error. + sn_coap_parser_release_allocated_coap_msg_mem(handle, stored_blockwise_msg_ptr->coap_msg_ptr); + handle->sn_coap_protocol_free(stored_blockwise_msg_ptr); + stored_blockwise_msg_ptr = 0; + tr_error("sn_coap_protocol_build - block payload allocation failed!"); + return byte_count_built; + } + memcpy(stored_blockwise_msg_ptr->coap_msg_ptr->payload_ptr, src_coap_msg_ptr->payload_ptr, stored_blockwise_msg_ptr->coap_msg_ptr->payload_len); + + stored_blockwise_msg_ptr->coap = handle; + ns_list_add_to_end(&handle->linked_list_blockwise_sent_msgs, stored_blockwise_msg_ptr); + } + + else if (src_coap_msg_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET) { + /* Add message to linked list - response can be in blocks and we need header to build response.. */ + coap_blockwise_msg_s *stored_blockwise_msg_ptr; + + stored_blockwise_msg_ptr = handle->sn_coap_protocol_malloc(sizeof(coap_blockwise_msg_s)); + if (!stored_blockwise_msg_ptr) { + tr_error("sn_coap_protocol_build - blockwise (GET) allocation failed!"); + return byte_count_built; + } + memset(stored_blockwise_msg_ptr, 0, sizeof(coap_blockwise_msg_s)); + + /* Fill struct */ + stored_blockwise_msg_ptr->timestamp = handle->system_time; + + stored_blockwise_msg_ptr->coap_msg_ptr = sn_coap_protocol_copy_header(handle, src_coap_msg_ptr); + if( stored_blockwise_msg_ptr->coap_msg_ptr == NULL ){ + handle->sn_coap_protocol_free(stored_blockwise_msg_ptr); + stored_blockwise_msg_ptr = 0; + tr_error("sn_coap_protocol_build - blockwise (GET) copy header failed!"); + return -2; + } + + stored_blockwise_msg_ptr->coap = handle; + ns_list_add_to_end(&handle->linked_list_blockwise_sent_msgs, stored_blockwise_msg_ptr); + } + +#endif /* SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE */ + + /* * * * Return built CoAP message Packet data length * * * */ + return byte_count_built; +} + +sn_coap_hdr_s *sn_coap_protocol_parse(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t packet_data_len, uint8_t *packet_data_ptr, void *param) +{ + sn_coap_hdr_s *returned_dst_coap_msg_ptr = NULL; + coap_version_e coap_version = COAP_VERSION_UNKNOWN; + + /* * * * Check given pointer * * * */ + if (src_addr_ptr == NULL || src_addr_ptr->addr_ptr == NULL || + packet_data_ptr == NULL || handle == NULL) { + return NULL; + } + + /* * * * Parse Packet data to CoAP message by using CoAP Header parser * * * */ + returned_dst_coap_msg_ptr = sn_coap_parser(handle, packet_data_len, packet_data_ptr, &coap_version); + + /* Check status of returned pointer */ + if (returned_dst_coap_msg_ptr == NULL) { + /* Memory allocation error in parser */ + tr_error("sn_coap_protocol_parse - allocation fail in parser!"); + return NULL; + } + /* * * * Send bad request response if parsing fails * * * */ + if (returned_dst_coap_msg_ptr->coap_status == COAP_STATUS_PARSER_ERROR_IN_HEADER) { + sn_coap_protocol_send_rst(handle, returned_dst_coap_msg_ptr->msg_id, src_addr_ptr, param); + sn_coap_parser_release_allocated_coap_msg_mem(handle, returned_dst_coap_msg_ptr); + tr_error("sn_coap_protocol_parse - COAP_STATUS_PARSER_ERROR_IN_HEADER"); + return NULL; + } + + /* * * * Check validity of parsed Header values * * * */ + if (sn_coap_header_validity_check(returned_dst_coap_msg_ptr, coap_version) != 0) { + /* If message code is in a reserved class (1, 6 or 7), send reset. Message code class is 3 MSB of the message code byte */ + if (((returned_dst_coap_msg_ptr->msg_code >> 5) == 1) || // if class == 1 + ((returned_dst_coap_msg_ptr->msg_code >> 5) == 6) || // if class == 6 + ((returned_dst_coap_msg_ptr->msg_code >> 5) == 7)) { // if class == 7 + tr_error("sn_coap_protocol_parse - message code not valid!"); + sn_coap_protocol_send_rst(handle, returned_dst_coap_msg_ptr->msg_id, src_addr_ptr, param); + } + + /* Release memory of CoAP message */ + sn_coap_parser_release_allocated_coap_msg_mem(handle, returned_dst_coap_msg_ptr); + + /* Return NULL because Header validity check failed */ + return NULL; + } + + /* Check if we need to send reset message */ + /* A recipient MUST acknowledge a Confirmable message with an Acknowledgement + message or, if it lacks context to process the message properly + (including the case where the message is Empty, uses a code with a + reserved class (1, 6 or 7), or has a message format error), MUST + reject it; rejecting a Confirmable message is effected by sending a + matching Reset message and otherwise ignoring it. */ + if (returned_dst_coap_msg_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) { + /* CoAP ping */ + if (returned_dst_coap_msg_ptr->msg_code == COAP_MSG_CODE_EMPTY) { + sn_coap_protocol_send_rst(handle, returned_dst_coap_msg_ptr->msg_id, src_addr_ptr, param); + + /* Release memory of CoAP message */ + sn_coap_parser_release_allocated_coap_msg_mem(handle, returned_dst_coap_msg_ptr); + + /* Return NULL because Header validity check failed */ + return NULL; + } + } + + +#if !SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE /* If Message blockwising is used, this part of code will not be compiled */ + /* If blockwising used in received message */ + if (returned_dst_coap_msg_ptr->options_list_ptr != NULL && + (returned_dst_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE || + returned_dst_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE)) { + /* Set returned status to User */ + returned_dst_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_REJECTED; + tr_error("sn_coap_protocol_parse - COAP_STATUS_PARSER_BLOCKWISE_MSG_REJECTED!"); + //todo: send response -> not implemented + return returned_dst_coap_msg_ptr; + } +#endif /* !SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE */ + +#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT/* If Message duplication is used, this part of code will not be compiled */ + + /* * * * Manage received CoAP message duplicate detection * * * */ + + /* If no message duplication detected */ + if ((returned_dst_coap_msg_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE || + returned_dst_coap_msg_ptr->msg_type == COAP_MSG_TYPE_NON_CONFIRMABLE) && + handle->sn_coap_duplication_buffer_size != 0) { + if (sn_coap_protocol_linked_list_duplication_info_search(handle, src_addr_ptr, returned_dst_coap_msg_ptr->msg_id) == NULL) { + /* * * No Message duplication: Store received message for detecting later duplication * * */ + + /* Get count of stored duplication messages */ + uint16_t stored_duplication_msgs_count = handle->count_duplication_msgs; + + /* Check if there is no room to store message for duplication detection purposes */ + if (stored_duplication_msgs_count >= handle->sn_coap_duplication_buffer_size) { + /* Get oldest stored duplication message */ + coap_duplication_info_s *stored_duplication_info_ptr = ns_list_get_first(&handle->linked_list_duplication_msgs); + + /* Remove oldest stored duplication message for getting room for new duplication message */ + sn_coap_protocol_linked_list_duplication_info_remove(handle, + stored_duplication_info_ptr->address->addr_ptr, + stored_duplication_info_ptr->address->port, + stored_duplication_info_ptr->msg_id); + } + + /* Store Duplication info to Linked list */ + sn_coap_protocol_linked_list_duplication_info_store(handle, src_addr_ptr, returned_dst_coap_msg_ptr->msg_id, param); + } else { /* * * Message duplication detected * * */ + /* Set returned status to User */ + returned_dst_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_DUPLICATED_MSG; + coap_duplication_info_s* response = sn_coap_protocol_linked_list_duplication_info_search(handle, + src_addr_ptr, + returned_dst_coap_msg_ptr->msg_id); + /* Send ACK response */ + if (response) { + /* Check that response has been created */ + if (response->packet_ptr) { + response->coap->sn_coap_tx_callback(response->packet_ptr, + response->packet_len, response->address, response->param); + } + } + + return returned_dst_coap_msg_ptr; + } + } +#endif + + /*** And here we check if message was block message ***/ + /*** If so, we call own block handling function and ***/ + /*** return to caller. ***/ +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + + if (returned_dst_coap_msg_ptr->options_list_ptr != NULL && + (returned_dst_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE || + returned_dst_coap_msg_ptr->options_list_ptr->block2 != COAP_OPTION_BLOCK_NONE)) { + returned_dst_coap_msg_ptr = sn_coap_handle_blockwise_message(handle, src_addr_ptr, returned_dst_coap_msg_ptr, param); + } else { + /* Get ... */ + coap_blockwise_msg_s *stored_blockwise_msg_temp_ptr = NULL; + + ns_list_foreach(coap_blockwise_msg_s, msg, &handle->linked_list_blockwise_sent_msgs) { + if (returned_dst_coap_msg_ptr->msg_id == msg->coap_msg_ptr->msg_id) { + stored_blockwise_msg_temp_ptr = msg; + break; + } + } + /* Remove from the list if not an notification message. + * Initial notification message is needed for sending rest of the blocks (GET request). + */ + bool remove_from_the_list = false; + if (stored_blockwise_msg_temp_ptr) { + if (stored_blockwise_msg_temp_ptr->coap_msg_ptr && + stored_blockwise_msg_temp_ptr->coap_msg_ptr->options_list_ptr && + stored_blockwise_msg_temp_ptr->coap_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { + remove_from_the_list = false; + } else { + remove_from_the_list = true; + } + } + if (remove_from_the_list) { + ns_list_remove(&handle->linked_list_blockwise_sent_msgs, stored_blockwise_msg_temp_ptr); + if (stored_blockwise_msg_temp_ptr->coap_msg_ptr) { + if(stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr){ + handle->sn_coap_protocol_free(stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr); + stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(stored_blockwise_msg_temp_ptr->coap, stored_blockwise_msg_temp_ptr->coap_msg_ptr); + } + + handle->sn_coap_protocol_free(stored_blockwise_msg_temp_ptr); + stored_blockwise_msg_temp_ptr = 0; + } + } + + if (!returned_dst_coap_msg_ptr) { + tr_error("sn_coap_protocol_parse - returned_dst_coap_msg_ptr null!"); + return NULL; + } + +#endif + + +#if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ + + /* Check if received Message type was acknowledgement */ + if ((returned_dst_coap_msg_ptr->msg_type == COAP_MSG_TYPE_ACKNOWLEDGEMENT) || (returned_dst_coap_msg_ptr->msg_type == COAP_MSG_TYPE_RESET)) { + /* * * * Manage CoAP message resending by removing active resending message from Linked list * * */ + + /* Get node count i.e. count of active resending messages */ + uint16_t stored_resending_msgs_count = handle->count_resent_msgs; + + /* Check if there is ongoing active message resendings */ + if (stored_resending_msgs_count > 0) { + sn_nsdl_transmit_s *removed_msg_ptr = NULL; + + /* Check if received message was confirmation for some active resending message */ + removed_msg_ptr = sn_coap_protocol_linked_list_send_msg_search(handle, src_addr_ptr, returned_dst_coap_msg_ptr->msg_id); + + if (removed_msg_ptr != NULL) { + /* Remove resending message from active message resending Linked list */ + sn_coap_protocol_linked_list_send_msg_remove(handle, src_addr_ptr, returned_dst_coap_msg_ptr->msg_id); + } + } + } +#endif /* ENABLE_RESENDINGS */ + + /* * * * Return parsed CoAP message * * * */ + return returned_dst_coap_msg_ptr; +} + + +int8_t sn_coap_protocol_exec(struct coap_s *handle, uint32_t current_time) +{ + if( !handle ){ + return -1; + } + + /* * * * Store current System time * * * */ + handle->system_time = current_time; +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE + /* * * * Remove old blocwise data * * * */ + sn_coap_protocol_linked_list_blockwise_remove_old_data(handle); +#endif + + +#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT + /* * * * Remove old duplication messages * * * */ + sn_coap_protocol_linked_list_duplication_info_remove_old_ones(handle); +#endif + +#if ENABLE_RESENDINGS + /* Check if there is ongoing active message sendings */ + /* foreach_safe isn't sufficient because callback routine could cancel messages. */ +rescan: + ns_list_foreach(coap_send_msg_s, stored_msg_ptr, &handle->linked_list_resent_msgs) { + // First check that msg belongs to handle + if( stored_msg_ptr->coap == handle ){ + /* Check if it is time to send this message */ + if (current_time >= stored_msg_ptr->resending_time) { + /* * * Increase Resending counter * * */ + stored_msg_ptr->resending_counter++; + + /* Check if all re-sendings have been done */ + if (stored_msg_ptr->resending_counter > handle->sn_coap_resending_count) { + coap_version_e coap_version = COAP_VERSION_UNKNOWN; + + /* Get message ID from stored sending message */ + uint16_t temp_msg_id = (stored_msg_ptr->send_msg_ptr->packet_ptr[2] << 8); + temp_msg_id += (uint16_t)stored_msg_ptr->send_msg_ptr->packet_ptr[3]; + + /* Remove message from Linked list */ + ns_list_remove(&handle->linked_list_resent_msgs, stored_msg_ptr); + --handle->count_resent_msgs; + + /* If RX callback have been defined.. */ + if (stored_msg_ptr->coap->sn_coap_rx_callback != 0) { + sn_coap_hdr_s *tmp_coap_hdr_ptr; + /* Parse CoAP message, set status and call RX callback */ + tmp_coap_hdr_ptr = sn_coap_parser(stored_msg_ptr->coap, stored_msg_ptr->send_msg_ptr->packet_len, stored_msg_ptr->send_msg_ptr->packet_ptr, &coap_version); + + if (tmp_coap_hdr_ptr != 0) { + tmp_coap_hdr_ptr->coap_status = COAP_STATUS_BUILDER_MESSAGE_SENDING_FAILED; + stored_msg_ptr->coap->sn_coap_rx_callback(tmp_coap_hdr_ptr, stored_msg_ptr->send_msg_ptr->dst_addr_ptr, stored_msg_ptr->param); + + sn_coap_parser_release_allocated_coap_msg_mem(stored_msg_ptr->coap, tmp_coap_hdr_ptr); + } + } + + /* Free memory of stored message */ + sn_coap_protocol_release_allocated_send_msg_mem(handle, stored_msg_ptr); + } else { + /* Send message */ + stored_msg_ptr->coap->sn_coap_tx_callback(stored_msg_ptr->send_msg_ptr->packet_ptr, + stored_msg_ptr->send_msg_ptr->packet_len, stored_msg_ptr->send_msg_ptr->dst_addr_ptr, stored_msg_ptr->param); + + /* * * Count new Resending time * * */ + stored_msg_ptr->resending_time = sn_coap_calculate_new_resend_time(current_time, + handle->sn_coap_resending_intervall, + stored_msg_ptr->resending_counter); + } + /* Callback routine could have wiped the list (eg as a response to sending failed) */ + /* Be super cautious and rescan from the start */ + goto rescan; + } + } + } + +#endif /* ENABLE_RESENDINGS */ + + return 0; +} + +#if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ + +/**************************************************************************//** + * \fn static uint8_t sn_coap_protocol_linked_list_send_msg_store(sn_nsdl_addr_s *dst_addr_ptr, uint16_t send_packet_data_len, uint8_t *send_packet_data_ptr, uint32_t sending_time) + * + * \brief Stores message to Linked list for sending purposes. + + * \param *dst_addr_ptr is pointer to destination address where CoAP message will be sent + * + * \param send_packet_data_len is length of Packet data to be stored + * + * \param *send_packet_data_ptr is Packet data to be stored + * + * \param sending_time is stored sending time + * + * \return 0 Allocation or buffer limit reached + * + * \return 1 Msg stored properly + *****************************************************************************/ + +static uint8_t sn_coap_protocol_linked_list_send_msg_store(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint16_t send_packet_data_len, + uint8_t *send_packet_data_ptr, uint32_t sending_time, void *param) +{ + + coap_send_msg_s *stored_msg_ptr = NULL; + + /* If both queue parameters are "0" or resending count is "0", then re-sending is disabled */ + if (((handle->sn_coap_resending_queue_msgs == 0) && (handle->sn_coap_resending_queue_bytes == 0)) || (handle->sn_coap_resending_count == 0)) { + return 1; + } + + if (handle->sn_coap_resending_queue_msgs > 0) { + if (handle->count_resent_msgs >= handle->sn_coap_resending_queue_msgs) { + tr_error("sn_coap_protocol_linked_list_send_msg_store - resend queue full!"); + return 0; + } + } + + /* Count resending queue size, if buffer size is defined */ + if (handle->sn_coap_resending_queue_bytes > 0) { + if ((sn_coap_count_linked_list_size(&handle->linked_list_resent_msgs) + send_packet_data_len) > handle->sn_coap_resending_queue_bytes) { + tr_error("sn_coap_protocol_linked_list_send_msg_store - resend buffer size reached!"); + return 0; + } + } + + /* Allocating memory for stored message */ + stored_msg_ptr = sn_coap_protocol_allocate_mem_for_msg(handle, dst_addr_ptr, send_packet_data_len); + + if (stored_msg_ptr == 0) { + tr_error("sn_coap_protocol_linked_list_send_msg_store - failed to allocate message!"); + return 0; + } + + /* Filling of coap_send_msg_s with initialization values */ + stored_msg_ptr->resending_counter = 0; + stored_msg_ptr->resending_time = sending_time; + + /* Filling of sn_nsdl_transmit_s */ + stored_msg_ptr->send_msg_ptr->protocol = SN_NSDL_PROTOCOL_COAP; + stored_msg_ptr->send_msg_ptr->packet_len = send_packet_data_len; + memcpy(stored_msg_ptr->send_msg_ptr->packet_ptr, send_packet_data_ptr, send_packet_data_len); + + /* Filling of sn_nsdl_addr_s */ + stored_msg_ptr->send_msg_ptr->dst_addr_ptr->type = dst_addr_ptr->type; + stored_msg_ptr->send_msg_ptr->dst_addr_ptr->addr_len = dst_addr_ptr->addr_len; + memcpy(stored_msg_ptr->send_msg_ptr->dst_addr_ptr->addr_ptr, dst_addr_ptr->addr_ptr, dst_addr_ptr->addr_len); + stored_msg_ptr->send_msg_ptr->dst_addr_ptr->port = dst_addr_ptr->port; + + stored_msg_ptr->coap = handle; + stored_msg_ptr->param = param; + + /* Storing Resending message to Linked list */ + ns_list_add_to_end(&handle->linked_list_resent_msgs, stored_msg_ptr); + ++handle->count_resent_msgs; + return 1; +} + +/**************************************************************************//** + * \fn static sn_nsdl_transmit_s *sn_coap_protocol_linked_list_send_msg_search(sn_nsdl_addr_s *src_addr_ptr, uint16_t msg_id) + * + * \brief Searches stored resending message from Linked list + * + * \param *src_addr_ptr is searching key for searched message + * + * \param msg_id is searching key for searched message + * + * \return Return value is pointer to found stored resending message in Linked + * list or NULL if message not found + *****************************************************************************/ + +static sn_nsdl_transmit_s *sn_coap_protocol_linked_list_send_msg_search(struct coap_s *handle, + sn_nsdl_addr_s *src_addr_ptr, uint16_t msg_id) +{ + /* Loop all stored resending messages Linked list */ + ns_list_foreach(coap_send_msg_s, stored_msg_ptr, &handle->linked_list_resent_msgs) { + /* Get message ID from stored resending message */ + uint16_t temp_msg_id = (stored_msg_ptr->send_msg_ptr->packet_ptr[2] << 8); + temp_msg_id += (uint16_t)stored_msg_ptr->send_msg_ptr->packet_ptr[3]; + + /* If message's Message ID is same than is searched */ + if (temp_msg_id == msg_id) { + /* If message's Source address is same than is searched */ + if (0 == memcmp(src_addr_ptr->addr_ptr, stored_msg_ptr->send_msg_ptr->dst_addr_ptr->addr_ptr, src_addr_ptr->addr_len)) { + /* If message's Source address port is same than is searched */ + if (stored_msg_ptr->send_msg_ptr->dst_addr_ptr->port == src_addr_ptr->port) { + /* * * Message found, return pointer to that stored resending message * * * */ + return stored_msg_ptr->send_msg_ptr; + } + } + } + } + + /* Message not found */ + return NULL; +} +/**************************************************************************//** + * \fn static void sn_coap_protocol_linked_list_send_msg_remove(sn_nsdl_addr_s *src_addr_ptr, uint16_t msg_id) + * + * \brief Removes stored resending message from Linked list + * + * \param *src_addr_ptr is searching key for searched message + * \param msg_id is searching key for removed message + *****************************************************************************/ + +static void sn_coap_protocol_linked_list_send_msg_remove(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t msg_id) +{ + /* Loop all stored resending messages in Linked list */ + ns_list_foreach(coap_send_msg_s, stored_msg_ptr, &handle->linked_list_resent_msgs) { + /* Get message ID from stored resending message */ + uint16_t temp_msg_id = (stored_msg_ptr->send_msg_ptr->packet_ptr[2] << 8); + temp_msg_id += (uint16_t)stored_msg_ptr->send_msg_ptr->packet_ptr[3]; + + /* If message's Message ID is same than is searched */ + if (temp_msg_id == msg_id) { + /* If message's Source address is same than is searched */ + if (0 == memcmp(src_addr_ptr->addr_ptr, stored_msg_ptr->send_msg_ptr->dst_addr_ptr->addr_ptr, src_addr_ptr->addr_len)) { + /* If message's Source address port is same than is searched */ + if (stored_msg_ptr->send_msg_ptr->dst_addr_ptr->port == src_addr_ptr->port) { + /* * * Message found * * */ + + /* Remove message from Linked list */ + ns_list_remove(&handle->linked_list_resent_msgs, stored_msg_ptr); + --handle->count_resent_msgs; + + /* Free memory of stored message */ + sn_coap_protocol_release_allocated_send_msg_mem(handle, stored_msg_ptr); + + return; + } + } + } + } +} + +uint32_t sn_coap_calculate_new_resend_time(const uint32_t current_time, const uint8_t interval, const uint8_t counter) +{ + uint32_t resend_time = interval << counter; + uint16_t random_factor = randLIB_get_random_in_range(100, RESPONSE_RANDOM_FACTOR * 100); + return current_time + ((resend_time * random_factor) / 100); +} + +#endif /* ENABLE_RESENDINGS */ + +static void sn_coap_protocol_send_rst(struct coap_s *handle, uint16_t msg_id, sn_nsdl_addr_s *addr_ptr, void *param) +{ + uint8_t packet_ptr[4]; + + /* Add CoAP version and message type */ + packet_ptr[0] = COAP_VERSION_1; + packet_ptr[0] |= COAP_MSG_TYPE_RESET; + + /* Add message code */ + packet_ptr[1] = COAP_MSG_CODE_EMPTY; + + /* Add message ID */ + packet_ptr[2] = msg_id >> 8; + packet_ptr[3] = (uint8_t)msg_id; + + /* Send RST */ + handle->sn_coap_tx_callback(packet_ptr, 4, addr_ptr, param); + +} +#if SN_COAP_DUPLICATION_MAX_MSGS_COUNT /* If Message duplication detection is not used at all, this part of code will not be compiled */ + +/**************************************************************************//** + * \fn static void sn_coap_protocol_linked_list_duplication_info_store(sn_nsdl_addr_s *addr_ptr, uint16_t msg_id) + * + * \brief Stores Duplication info to Linked list + * + * \param msg_id is Message ID to be stored + * \param *addr_ptr is pointer to Address information to be stored + *****************************************************************************/ + +static void sn_coap_protocol_linked_list_duplication_info_store(struct coap_s *handle, sn_nsdl_addr_s *addr_ptr, + uint16_t msg_id, void *param) +{ + coap_duplication_info_s *stored_duplication_info_ptr = NULL; + + /* * * * Allocating memory for stored Duplication info * * * */ + + /* Allocate memory for stored Duplication info's structure */ + stored_duplication_info_ptr = handle->sn_coap_protocol_malloc(sizeof(coap_duplication_info_s)); + + if (stored_duplication_info_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_duplication_info_store - failed to allocate duplication info!"); + return; + } + memset(stored_duplication_info_ptr, 0, sizeof(coap_duplication_info_s)); + + /* Allocate memory for stored Duplication info's address */ + stored_duplication_info_ptr->address = handle->sn_coap_protocol_malloc(sizeof(sn_nsdl_addr_s)); + if (stored_duplication_info_ptr->address == NULL) { + tr_error("sn_coap_protocol_linked_list_duplication_info_store - failed to allocate address!"); + handle->sn_coap_protocol_free(stored_duplication_info_ptr); + stored_duplication_info_ptr = 0; + return; + } + memset(stored_duplication_info_ptr->address, 0, sizeof(sn_nsdl_addr_s)); + + stored_duplication_info_ptr->address->addr_ptr = handle->sn_coap_protocol_malloc(addr_ptr->addr_len); + + if (stored_duplication_info_ptr->address->addr_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_duplication_info_store - failed to allocate address pointer!"); + handle->sn_coap_protocol_free(stored_duplication_info_ptr->address); + stored_duplication_info_ptr->address = 0; + handle->sn_coap_protocol_free(stored_duplication_info_ptr); + stored_duplication_info_ptr = 0; + return; + } + + /* * * * Filling fields of stored Duplication info * * * */ + stored_duplication_info_ptr->timestamp = handle->system_time; + stored_duplication_info_ptr->address->addr_len = addr_ptr->addr_len; + memcpy(stored_duplication_info_ptr->address->addr_ptr, addr_ptr->addr_ptr, addr_ptr->addr_len); + stored_duplication_info_ptr->address->port = addr_ptr->port; + stored_duplication_info_ptr->msg_id = msg_id; + + stored_duplication_info_ptr->coap = handle; + + stored_duplication_info_ptr->param = param; + /* * * * Storing Duplication info to Linked list * * * */ + + ns_list_add_to_end(&handle->linked_list_duplication_msgs, stored_duplication_info_ptr); + ++handle->count_duplication_msgs; +} + +/**************************************************************************//** + * \fn static int8_t sn_coap_protocol_linked_list_duplication_info_search(sn_nsdl_addr_s *addr_ptr, uint16_t msg_id) + * + * \brief Searches stored message from Linked list (Address and Message ID as key) + * + * \param *addr_ptr is pointer to Address key to be searched + * \param msg_id is Message ID key to be searched + * + * \return Return value is 0 when message found and -1 if not found + *****************************************************************************/ + +static coap_duplication_info_s* sn_coap_protocol_linked_list_duplication_info_search(struct coap_s *handle, + sn_nsdl_addr_s *addr_ptr, uint16_t msg_id) +{ + /* Loop all nodes in Linked list for searching Message ID */ + ns_list_foreach(coap_duplication_info_s, stored_duplication_info_ptr, &handle->linked_list_duplication_msgs) { + /* If message's Message ID is same than is searched */ + if (stored_duplication_info_ptr->msg_id == msg_id) { + /* If message's Source address is same than is searched */ + if (0 == memcmp(addr_ptr->addr_ptr, stored_duplication_info_ptr->address->addr_ptr, addr_ptr->addr_len)) { + /* If message's Source address port is same than is searched */ + if (stored_duplication_info_ptr->address->port == addr_ptr->port) { + /* * * Correct Duplication info found * * * */ + return stored_duplication_info_ptr; + } + } + } + } + return NULL; +} + +/**************************************************************************//** + * \fn static void sn_coap_protocol_linked_list_duplication_info_remove(struct coap_s *handle, uint8_t *addr_ptr, uint16_t port, uint16_t msg_id) + * + * \brief Removes stored Duplication info from Linked list + * + * \param *addr_ptr is pointer to Address key to be removed + * + * \param port is Port key to be removed + * + * \param msg_id is Message ID key to be removed + *****************************************************************************/ + +static void sn_coap_protocol_linked_list_duplication_info_remove(struct coap_s *handle, uint8_t *addr_ptr, uint16_t port, uint16_t msg_id) +{ + /* Loop all stored duplication messages in Linked list */ + ns_list_foreach(coap_duplication_info_s, removed_duplication_info_ptr, &handle->linked_list_duplication_msgs) { + /* If message's Address is same than is searched */ + if (handle == removed_duplication_info_ptr->coap && 0 == memcmp(addr_ptr, + removed_duplication_info_ptr->address->addr_ptr, + removed_duplication_info_ptr->address->addr_len)) { + /* If message's Address prt is same than is searched */ + if (removed_duplication_info_ptr->address->port == port) { + /* If Message ID is same than is searched */ + if (removed_duplication_info_ptr->msg_id == msg_id) { + /* * * * Correct Duplication info found, remove it from Linked list * * * */ + ns_list_remove(&handle->linked_list_duplication_msgs, removed_duplication_info_ptr); + --handle->count_duplication_msgs; + + /* Free memory of stored Duplication info */ + handle->sn_coap_protocol_free(removed_duplication_info_ptr->address->addr_ptr); + removed_duplication_info_ptr->address->addr_ptr = 0; + handle->sn_coap_protocol_free(removed_duplication_info_ptr->address); + removed_duplication_info_ptr->address = 0; + handle->sn_coap_protocol_free(removed_duplication_info_ptr->packet_ptr); + removed_duplication_info_ptr->packet_ptr = 0; + handle->sn_coap_protocol_free(removed_duplication_info_ptr); + removed_duplication_info_ptr = 0; + return; + } + } + } + } +} + +/**************************************************************************//** + * \fn static void sn_coap_protocol_linked_list_duplication_info_remove_old_ones(struct coap_s *handle) + * + * \brief Removes old stored Duplication detection infos from Linked list + *****************************************************************************/ + +static void sn_coap_protocol_linked_list_duplication_info_remove_old_ones(struct coap_s *handle) +{ + /* Loop all stored duplication messages in Linked list */ + ns_list_foreach_safe(coap_duplication_info_s, removed_duplication_info_ptr, &handle->linked_list_duplication_msgs) { + if ((handle->system_time - removed_duplication_info_ptr->timestamp) > SN_COAP_DUPLICATION_MAX_TIME_MSGS_STORED) { + /* * * * Old Duplication info found, remove it from Linked list * * * */ + ns_list_remove(&handle->linked_list_duplication_msgs, removed_duplication_info_ptr); + --handle->count_duplication_msgs; + + /* Free memory of stored Duplication info */ + handle->sn_coap_protocol_free(removed_duplication_info_ptr->address->addr_ptr); + removed_duplication_info_ptr->address->addr_ptr = 0; + handle->sn_coap_protocol_free(removed_duplication_info_ptr->address); + removed_duplication_info_ptr->address = 0; + handle->sn_coap_protocol_free(removed_duplication_info_ptr->packet_ptr); + removed_duplication_info_ptr->packet_ptr = 0; + handle->sn_coap_protocol_free(removed_duplication_info_ptr); + removed_duplication_info_ptr = 0; + } + } +} + +#endif /* SN_COAP_DUPLICATION_MAX_MSGS_COUNT */ + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE +/**************************************************************************//** + * \fn static void sn_coap_protocol_linked_list_blockwise_msg_remove(struct coap_s *handle, coap_blockwise_msg_s *removed_msg_ptr) + * + * \brief Removes stored blockwise message from Linked list + * + * \param removed_msg_ptr is message to be removed + *****************************************************************************/ + +static void sn_coap_protocol_linked_list_blockwise_msg_remove(struct coap_s *handle, coap_blockwise_msg_s *removed_msg_ptr) +{ + if( removed_msg_ptr->coap == handle ){ + ns_list_remove(&handle->linked_list_blockwise_sent_msgs, removed_msg_ptr); + + if( removed_msg_ptr->coap_msg_ptr ){ + if (removed_msg_ptr->coap_msg_ptr->payload_ptr) { + handle->sn_coap_protocol_free(removed_msg_ptr->coap_msg_ptr->payload_ptr); + removed_msg_ptr->coap_msg_ptr->payload_ptr = 0; + } + + sn_coap_parser_release_allocated_coap_msg_mem(handle, removed_msg_ptr->coap_msg_ptr); + } + + handle->sn_coap_protocol_free(removed_msg_ptr); + removed_msg_ptr = 0; + } +} + +/**************************************************************************//** + * \fn static void sn_coap_protocol_linked_list_blockwise_payload_store(sn_nsdl_addr_s *addr_ptr, uint16_t stored_payload_len, uint8_t *stored_payload_ptr) + * + * \brief Stores blockwise payload to Linked list + * + * \param *addr_ptr is pointer to Address information to be stored + * \param stored_payload_len is length of stored Payload + * \param *stored_payload_ptr is pointer to stored Payload + *****************************************************************************/ + +static void sn_coap_protocol_linked_list_blockwise_payload_store(struct coap_s *handle, sn_nsdl_addr_s *addr_ptr, + uint16_t stored_payload_len, + uint8_t *stored_payload_ptr, + uint32_t block_number) +{ + if (!addr_ptr || !stored_payload_len || !stored_payload_ptr) { + return; + } + + coap_blockwise_payload_s *stored_blockwise_payload_ptr = NULL; + + /* * * * Allocating memory for stored Payload * * * */ + + /* Allocate memory for stored Payload's structure */ + stored_blockwise_payload_ptr = handle->sn_coap_protocol_malloc(sizeof(coap_blockwise_payload_s)); + + if (stored_blockwise_payload_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate blockwise!"); + return; + } + + + /* Allocate memory for stored Payload's data */ + stored_blockwise_payload_ptr->payload_ptr = handle->sn_coap_protocol_malloc(stored_payload_len); + + if (stored_blockwise_payload_ptr->payload_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate payload!"); + handle->sn_coap_protocol_free(stored_blockwise_payload_ptr); + stored_blockwise_payload_ptr = 0; + return; + } + + /* Allocate memory for stored Payload's address */ + stored_blockwise_payload_ptr->addr_ptr = handle->sn_coap_protocol_malloc(addr_ptr->addr_len); + + if (stored_blockwise_payload_ptr->addr_ptr == NULL) { + tr_error("sn_coap_protocol_linked_list_blockwise_payload_store - failed to allocate address pointer!"); + handle->sn_coap_protocol_free(stored_blockwise_payload_ptr->payload_ptr); + stored_blockwise_payload_ptr->payload_ptr = 0; + handle->sn_coap_protocol_free(stored_blockwise_payload_ptr); + stored_blockwise_payload_ptr = 0; + + return; + } + + /* * * * Filling fields of stored Payload * * * */ + + stored_blockwise_payload_ptr->timestamp = handle->system_time; + + memcpy(stored_blockwise_payload_ptr->addr_ptr, addr_ptr->addr_ptr, addr_ptr->addr_len); + stored_blockwise_payload_ptr->port = addr_ptr->port; + memcpy(stored_blockwise_payload_ptr->payload_ptr, stored_payload_ptr, stored_payload_len); + stored_blockwise_payload_ptr->payload_len = stored_payload_len; + + stored_blockwise_payload_ptr->coap = handle; + + stored_blockwise_payload_ptr->block_number = block_number; + + /* * * * Storing Payload to Linked list * * * */ + + ns_list_add_to_end(&handle->linked_list_blockwise_received_payloads, stored_blockwise_payload_ptr); +} + +/**************************************************************************//** + * \fn static uint8_t *sn_coap_protocol_linked_list_blockwise_payload_search(sn_nsdl_addr_s *src_addr_ptr, uint16_t *payload_length) + * + * \brief Searches stored blockwise payload from Linked list (Address as key) + * + * \param *addr_ptr is pointer to Address key to be searched + * \param *payload_length is pointer to returned Payload length + * + * \return Return value is pointer to found stored blockwise payload in Linked + * list or NULL if payload not found + *****************************************************************************/ + +static uint8_t *sn_coap_protocol_linked_list_blockwise_payload_search(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, uint16_t *payload_length) +{ + /* Loop all stored blockwise payloads in Linked list */ + ns_list_foreach(coap_blockwise_payload_s, stored_payload_info_ptr, &handle->linked_list_blockwise_received_payloads) { + /* If payload's Source address is same than is searched */ + if (0 == memcmp(src_addr_ptr->addr_ptr, stored_payload_info_ptr->addr_ptr, src_addr_ptr->addr_len)) { + /* If payload's Source address port is same than is searched */ + if (stored_payload_info_ptr->port == src_addr_ptr->port) { + /* * * Correct Payload found * * * */ + *payload_length = stored_payload_info_ptr->payload_len; + + return stored_payload_info_ptr->payload_ptr; + } + } + } + + return NULL; +} + +static bool sn_coap_protocol_linked_list_blockwise_payload_compare_block_number(struct coap_s *handle, + sn_nsdl_addr_s *src_addr_ptr, + uint32_t block_number) +{ + /* Loop all stored blockwise payloads in Linked list */ + ns_list_foreach(coap_blockwise_payload_s, stored_payload_info_ptr, &handle->linked_list_blockwise_received_payloads) { + /* If payload's Source address is same than is searched */ + if (0 == memcmp(src_addr_ptr->addr_ptr, stored_payload_info_ptr->addr_ptr, src_addr_ptr->addr_len)) { + /* If payload's Source address port is same than is searched */ + if (stored_payload_info_ptr->port == src_addr_ptr->port) { + // Check that incoming block number matches to last received one + if (block_number - 1 == stored_payload_info_ptr->block_number) { + return true; + } + } + } + } + return false; +} + +/**************************************************************************//** + * \fn static void sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(struct coap_s *handle) + * + * \brief Removes current stored blockwise paylod from Linked list + *****************************************************************************/ + +static void sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(struct coap_s *handle) +{ + coap_blockwise_payload_s *removed_payload_ptr; + + /* Remove oldest node in Linked list*/ + removed_payload_ptr = ns_list_get_first(&handle->linked_list_blockwise_received_payloads); + + if (removed_payload_ptr != NULL) { + sn_coap_protocol_linked_list_blockwise_payload_remove(handle, removed_payload_ptr); + } +} + +/**************************************************************************//** + * \fn static void sn_coap_protocol_linked_list_blockwise_payload_remove(struct coap_s *handle, + * coap_blockwise_msg_s *removed_msg_ptr) + * + * \brief Removes stored blockwise payload from Linked list + * + * \param removed_payload_ptr is payload to be removed + *****************************************************************************/ + +static void sn_coap_protocol_linked_list_blockwise_payload_remove(struct coap_s *handle, + coap_blockwise_payload_s *removed_payload_ptr) +{ + ns_list_remove(&handle->linked_list_blockwise_received_payloads, removed_payload_ptr); + /* Free memory of stored payload */ + if (removed_payload_ptr->addr_ptr != NULL) { + handle->sn_coap_protocol_free(removed_payload_ptr->addr_ptr); + removed_payload_ptr->addr_ptr = 0; + } + + if (removed_payload_ptr->payload_ptr != NULL) { + handle->sn_coap_protocol_free(removed_payload_ptr->payload_ptr); + removed_payload_ptr->payload_ptr = 0; + } + + handle->sn_coap_protocol_free(removed_payload_ptr); + removed_payload_ptr = 0; +} + +/**************************************************************************//** + * \fn static uint32_t sn_coap_protocol_linked_list_blockwise_payloads_get_len(sn_nsdl_addr_s *src_addr_ptr) + * + * \brief Counts length of Payloads in Linked list (Address as key) + * + * \param *addr_ptr is pointer to Address key + * + * \return Return value is length of Payloads as bytes + *****************************************************************************/ + +static uint32_t sn_coap_protocol_linked_list_blockwise_payloads_get_len(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr) +{ + uint32_t ret_whole_payload_len = 0; + /* Loop all stored blockwise payloads in Linked list */ + ns_list_foreach(coap_blockwise_payload_s, searched_payload_info_ptr, &handle->linked_list_blockwise_received_payloads) { + /* If payload's Source address is same than is searched */ + if (0 == memcmp(src_addr_ptr->addr_ptr, searched_payload_info_ptr->addr_ptr, src_addr_ptr->addr_len)) { + /* If payload's Source address port is same than is searched */ + if (searched_payload_info_ptr->port == src_addr_ptr->port) { + /* * * Correct Payload found * * * */ + ret_whole_payload_len += searched_payload_info_ptr->payload_len; + } + } + } + + return ret_whole_payload_len; +} + +/**************************************************************************//** + * \fn static void sn_coap_protocol_linked_list_blockwise_remove_old_data(struct coap_s *handle) + * + * \brief Removes old stored Blockwise messages and payloads from Linked list + *****************************************************************************/ + +static void sn_coap_protocol_linked_list_blockwise_remove_old_data(struct coap_s *handle) +{ + /* Loop all stored Blockwise messages in Linked list */ + ns_list_foreach_safe(coap_blockwise_msg_s, removed_blocwise_msg_ptr, &handle->linked_list_blockwise_sent_msgs) { + if ((handle->system_time - removed_blocwise_msg_ptr->timestamp) > SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED) { + //TODO: Check do we need to check handle == removed_blocwise_msg_ptr->coap here? + + /* * * * Old Blockise message found, remove it from Linked list * * * */ + if( removed_blocwise_msg_ptr->coap_msg_ptr ){ + if(removed_blocwise_msg_ptr->coap_msg_ptr->payload_ptr){ + handle->sn_coap_protocol_free(removed_blocwise_msg_ptr->coap_msg_ptr->payload_ptr); + removed_blocwise_msg_ptr->coap_msg_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle, removed_blocwise_msg_ptr->coap_msg_ptr); + removed_blocwise_msg_ptr->coap_msg_ptr = 0; + } + sn_coap_protocol_linked_list_blockwise_msg_remove(handle, removed_blocwise_msg_ptr); + } + } + + /* Loop all stored Blockwise payloads in Linked list */ + ns_list_foreach_safe(coap_blockwise_payload_s, removed_blocwise_payload_ptr, &handle->linked_list_blockwise_received_payloads) { + if ((handle->system_time - removed_blocwise_payload_ptr->timestamp) > SN_COAP_BLOCKWISE_MAX_TIME_DATA_STORED) { + /* * * * Old Blockise payload found, remove it from Linked list * * * */ + sn_coap_protocol_linked_list_blockwise_payload_remove(handle, removed_blocwise_payload_ptr); + } + } +} + +#endif /* SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE */ + + +#if ENABLE_RESENDINGS /* If Message resending is not used at all, this part of code will not be compiled */ +/***************************************************************************//** + * \fn int8_t sn_coap_protocol_allocate_mem_for_msg(sn_nsdl_addr_s *dst_addr_ptr, uint16_t packet_data_len, coap_send_msg_s *msg_ptr) + * + * \brief Allocates memory for given message (send or blockwise message) + * + * \param *dst_addr_ptr is pointer to destination address where message will be sent + * \param packet_data_len is length of allocated Packet data + * \param uri_path_len is length of messages path url + * + * \return pointer to allocated struct + *****************************************************************************/ + +coap_send_msg_s *sn_coap_protocol_allocate_mem_for_msg(struct coap_s *handle, sn_nsdl_addr_s *dst_addr_ptr, uint16_t packet_data_len) +{ + + coap_send_msg_s *msg_ptr = handle->sn_coap_protocol_malloc(sizeof(coap_send_msg_s)); + + if (msg_ptr == NULL) { + return NULL; + } + + //Locall structure for 1 malloc for send msg + struct + { + sn_nsdl_transmit_s transmit; + sn_nsdl_addr_s addr; + uint8_t trail_data[]; + } *m; + int trail_size = dst_addr_ptr->addr_len + packet_data_len; + + m = handle->sn_coap_protocol_malloc(sizeof *m + trail_size); + if (!m) { + handle->sn_coap_protocol_free(msg_ptr); + return NULL; + } + //Init data + memset(m, 0, sizeof(*m) + trail_size); + memset(msg_ptr, 0, sizeof(coap_send_msg_s)); + + msg_ptr->send_msg_ptr = &m->transmit; + msg_ptr->send_msg_ptr->dst_addr_ptr = &m->addr; + + msg_ptr->send_msg_ptr->dst_addr_ptr->addr_ptr = m->trail_data; + if (packet_data_len) { + msg_ptr->send_msg_ptr->packet_ptr = m->trail_data + dst_addr_ptr->addr_len; + } + + return msg_ptr; +} + + +/**************************************************************************//** + * \fn static void sn_coap_protocol_release_allocated_send_msg_mem(struct coap_s *handle, coap_send_msg_s *freed_send_msg_ptr) + * + * \brief Releases memory of given Sending message (coap_send_msg_s) + * + * \param *freed_send_msg_ptr is pointer to released Sending message + *****************************************************************************/ + +static void sn_coap_protocol_release_allocated_send_msg_mem(struct coap_s *handle, coap_send_msg_s *freed_send_msg_ptr) +{ + if (freed_send_msg_ptr != NULL) { + handle->sn_coap_protocol_free(freed_send_msg_ptr->send_msg_ptr); + freed_send_msg_ptr->send_msg_ptr = NULL; + handle->sn_coap_protocol_free(freed_send_msg_ptr); + freed_send_msg_ptr = NULL; + } +} + +/**************************************************************************//** + * \fn static uint16_t sn_coap_count_linked_list_size(const coap_send_msg_list_t *linked_list_ptr) + * + * \brief Counts total message size of all messages in linked list + * + * \param const coap_send_msg_list_t *linked_list_ptr pointer to linked list + *****************************************************************************/ +static uint16_t sn_coap_count_linked_list_size(const coap_send_msg_list_t *linked_list_ptr) +{ + uint16_t total_size = 0; + + ns_list_foreach(coap_send_msg_s, stored_msg_ptr, linked_list_ptr) { + if (stored_msg_ptr->send_msg_ptr) { + total_size += stored_msg_ptr->send_msg_ptr->packet_len; + } + } + + return total_size; +} + +#endif + +#if SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE +void sn_coap_protocol_block_remove(struct coap_s *handle, sn_nsdl_addr_s *source_address, uint16_t payload_length, void *payload) +{ + if(!handle || !source_address || !payload){ + return; + } + + /* Loop all stored blockwise payloads in Linked list */ + ns_list_foreach(coap_blockwise_payload_s, stored_payload_info_ptr, &handle->linked_list_blockwise_received_payloads) { + /* If payload's Source address is not the same than is searched */ + if (memcmp(source_address->addr_ptr, stored_payload_info_ptr->addr_ptr, source_address->addr_len)) { + continue; + } + + /* If payload's Source address port is not the same than is searched */ + if (stored_payload_info_ptr->port != source_address->port) { + continue; + } + + /* Check the payload */ + if(payload_length != stored_payload_info_ptr->payload_len){ + continue; + } + + if(!memcmp(stored_payload_info_ptr->payload_ptr, payload, stored_payload_info_ptr->payload_len)) + { + /* Everything matches, remove and return. */ + sn_coap_protocol_linked_list_blockwise_payload_remove(handle, stored_payload_info_ptr); + return; + } + } +} +/**************************************************************************//** + * \fn static int8_t sn_coap_handle_blockwise_message(void) + * + * \brief Handles all received blockwise messages + * + * \param *src_addr_ptr pointer to source address information struct + * \param *received_coap_msg_ptr pointer to parsed CoAP message structure + *****************************************************************************/ + +static sn_coap_hdr_s *sn_coap_handle_blockwise_message(struct coap_s *handle, sn_nsdl_addr_s *src_addr_ptr, sn_coap_hdr_s *received_coap_msg_ptr, void *param) +{ + sn_coap_hdr_s *src_coap_blockwise_ack_msg_ptr = NULL; + uint16_t dst_packed_data_needed_mem = 0; + uint8_t *dst_ack_packet_data_ptr = NULL; + uint8_t block_temp = 0; + + uint16_t original_payload_len = 0; + uint8_t *original_payload_ptr = NULL; + + /* Block1 Option in a request (e.g., PUT or POST) */ + // Blocked request sending, received ACK, sending next block.. + if (received_coap_msg_ptr->options_list_ptr->block1 != COAP_OPTION_BLOCK_NONE) { + if (received_coap_msg_ptr->msg_code > COAP_MSG_CODE_REQUEST_DELETE) { + if (received_coap_msg_ptr->options_list_ptr->block1 & 0x08) { + coap_blockwise_msg_s *stored_blockwise_msg_temp_ptr = NULL; + + /* Get */ + ns_list_foreach(coap_blockwise_msg_s, msg, &handle->linked_list_blockwise_sent_msgs) { + if (msg->coap_msg_ptr && received_coap_msg_ptr->msg_id == msg->coap_msg_ptr->msg_id) { + stored_blockwise_msg_temp_ptr = msg; + break; + } + } + + if (stored_blockwise_msg_temp_ptr) { + /* Build response message */ + + uint16_t block_size; + uint32_t block_number; + + /* Get block option parameters from received message */ + block_number = received_coap_msg_ptr->options_list_ptr->block1 >> 4; + block_temp = received_coap_msg_ptr->options_list_ptr->block1 & 0x07; + block_size = 1u << (block_temp + 4); + + /* Build next block message */ + src_coap_blockwise_ack_msg_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr; + + if (src_coap_blockwise_ack_msg_ptr->options_list_ptr) { + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 = COAP_OPTION_BLOCK_NONE; + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block2 = COAP_OPTION_BLOCK_NONE; + } else { + if (!sn_coap_parser_alloc_options(handle, src_coap_blockwise_ack_msg_ptr)) { + tr_error("sn_coap_handle_blockwise_message - (send block1) failed to allocate ack message!"); + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + return 0; + } + } + + block_number++; + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 = (block_number << 4) | block_temp; + + original_payload_len = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len; + original_payload_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr; + + if ((block_size * (block_number + 1)) > stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len) { + src_coap_blockwise_ack_msg_ptr->payload_len = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len - (block_size * (block_number)); + src_coap_blockwise_ack_msg_ptr->payload_ptr = src_coap_blockwise_ack_msg_ptr->payload_ptr + (block_size * block_number); + } + + /* Not last block */ + else { + /* set more - bit */ + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 |= 0x08; + src_coap_blockwise_ack_msg_ptr->payload_len = block_size; + src_coap_blockwise_ack_msg_ptr->payload_ptr = src_coap_blockwise_ack_msg_ptr->payload_ptr + (block_size * block_number); + } + /* Build and send block message */ + dst_packed_data_needed_mem = sn_coap_builder_calc_needed_packet_data_size_2(src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); + + dst_ack_packet_data_ptr = handle->sn_coap_protocol_malloc(dst_packed_data_needed_mem); + if (!dst_ack_packet_data_ptr) { + tr_error("sn_coap_handle_blockwise_message - (send block1) failed to allocate ack message!"); + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->options_list_ptr); + src_coap_blockwise_ack_msg_ptr->options_list_ptr = 0; + handle->sn_coap_protocol_free(original_payload_ptr); + original_payload_ptr = 0; + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); + src_coap_blockwise_ack_msg_ptr = 0; + stored_blockwise_msg_temp_ptr->coap_msg_ptr = NULL; + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + return NULL; + } + src_coap_blockwise_ack_msg_ptr->msg_id = message_id++; + if (message_id == 0) { + message_id = 1; + } + + sn_coap_builder_2(dst_ack_packet_data_ptr, src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); + handle->sn_coap_tx_callback(dst_ack_packet_data_ptr, dst_packed_data_needed_mem, src_addr_ptr, param); + + handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); + dst_ack_packet_data_ptr = 0; + + stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len = original_payload_len; + stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr = original_payload_ptr; + + received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_ACK; + } + } else { + // XXX what was this trying to free? + received_coap_msg_ptr->coap_status = COAP_STATUS_OK; + + } + } + + // Blocked request receiving + else { + if (received_coap_msg_ptr->payload_len > handle->sn_coap_block_data_size) { + received_coap_msg_ptr->payload_len = handle->sn_coap_block_data_size; + } + + // Check that incoming block number is in order. + uint32_t block_number = received_coap_msg_ptr->options_list_ptr->block1 >> 4; + bool blocks_in_order = true; + if (block_number > 0 && + !sn_coap_protocol_linked_list_blockwise_payload_compare_block_number(handle, + src_addr_ptr, + block_number)) { + blocks_in_order = false; + } + + sn_coap_protocol_linked_list_blockwise_payload_store(handle, + src_addr_ptr, + received_coap_msg_ptr->payload_len, + received_coap_msg_ptr->payload_ptr, + block_number); + + /* If not last block (more value is set) */ + /* Block option length can be 1-3 bytes. First 4-20 bits are for block number. Last 4 bits are ALWAYS more bit + block size. */ + if (received_coap_msg_ptr->options_list_ptr->block1 & 0x08) { + src_coap_blockwise_ack_msg_ptr = sn_coap_parser_alloc_message(handle); + if (src_coap_blockwise_ack_msg_ptr == NULL) { + tr_error("sn_coap_handle_blockwise_message - (recv block1) failed to allocate ack message!"); + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + return NULL; + } + + if (sn_coap_parser_alloc_options(handle, src_coap_blockwise_ack_msg_ptr) == NULL) { + tr_error("sn_coap_handle_blockwise_message - (recv block1) failed to allocate options!"); + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); + src_coap_blockwise_ack_msg_ptr = 0; + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + return NULL; + } + + if (!blocks_in_order) { + tr_error("sn_coap_handle_blockwise_message - (recv block1) COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE!"); + src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_INCOMPLETE; + } else if (received_coap_msg_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET) { + src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_CONTENT; + } else if (received_coap_msg_ptr->msg_code == COAP_MSG_CODE_REQUEST_POST) { + src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_CONTINUE; + } else if (received_coap_msg_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT) { + src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_CONTINUE; + } else if (received_coap_msg_ptr->msg_code == COAP_MSG_CODE_REQUEST_DELETE) { + src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_DELETED; + } + + // Response with COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE if the payload size is more than we can handle + if (received_coap_msg_ptr->options_list_ptr->size1 > SN_COAP_MAX_INCOMING_BLOCK_MESSAGE_SIZE) { + // Include maximum size that stack can handle into response + tr_error("sn_coap_handle_blockwise_message - (recv block1) COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE!"); + src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; + } + else { + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 = received_coap_msg_ptr->options_list_ptr->block1; + src_coap_blockwise_ack_msg_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT; + + /* Check block size */ + block_temp = (src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 & 0x07); + uint16_t block_size = 1u << (block_temp + 4); + if (block_size > handle->sn_coap_block_data_size) { + // Include maximum size that stack can handle into response + tr_error("sn_coap_handle_blockwise_message - (recv block1) COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE!"); + src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_RESPONSE_REQUEST_ENTITY_TOO_LARGE; + src_coap_blockwise_ack_msg_ptr->options_list_ptr->size1 = handle->sn_coap_block_data_size; + sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(handle); + } + + if (block_temp > sn_coap_convert_block_size(handle->sn_coap_block_data_size)) { + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 &= 0xFFFFF8; + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 |= sn_coap_convert_block_size(handle->sn_coap_block_data_size); + } + } + + src_coap_blockwise_ack_msg_ptr->msg_id = received_coap_msg_ptr->msg_id; + + // Copy token to response + src_coap_blockwise_ack_msg_ptr->token_ptr = handle->sn_coap_protocol_malloc(received_coap_msg_ptr->token_len); + if (src_coap_blockwise_ack_msg_ptr->token_ptr) { + memcpy(src_coap_blockwise_ack_msg_ptr->token_ptr, received_coap_msg_ptr->token_ptr, received_coap_msg_ptr->token_len); + src_coap_blockwise_ack_msg_ptr->token_len = received_coap_msg_ptr->token_len; + } + + dst_packed_data_needed_mem = sn_coap_builder_calc_needed_packet_data_size_2(src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); + + dst_ack_packet_data_ptr = handle->sn_coap_protocol_malloc(dst_packed_data_needed_mem); + if (!dst_ack_packet_data_ptr) { + tr_error("sn_coap_handle_blockwise_message - (recv block1) message allocation failed!"); + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->options_list_ptr); + src_coap_blockwise_ack_msg_ptr->options_list_ptr = 0; + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); + src_coap_blockwise_ack_msg_ptr = 0; + return NULL; + } + + sn_coap_builder_2(dst_ack_packet_data_ptr, src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); + handle->sn_coap_tx_callback(dst_ack_packet_data_ptr, dst_packed_data_needed_mem, src_addr_ptr, param); + + sn_coap_parser_release_allocated_coap_msg_mem(handle, src_coap_blockwise_ack_msg_ptr); + handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); + dst_ack_packet_data_ptr = 0; + + received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING; + + } else { + /* * * This is the last block when whole Blockwise payload from received * * */ + /* * * blockwise messages is gathered and returned to User * * */ + + /* Store last Blockwise payload to Linked list */ + uint16_t payload_len = 0; + uint8_t *payload_ptr = sn_coap_protocol_linked_list_blockwise_payload_search(handle, src_addr_ptr, &payload_len); + uint32_t whole_payload_len = sn_coap_protocol_linked_list_blockwise_payloads_get_len(handle, src_addr_ptr); + uint8_t *temp_whole_payload_ptr = NULL; + + temp_whole_payload_ptr = handle->sn_coap_protocol_malloc(whole_payload_len); + if (temp_whole_payload_ptr == NULL || whole_payload_len > UINT16_MAX) { + tr_error("sn_coap_handle_blockwise_message - (recv block1) failed to allocate all blocks!"); + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + handle->sn_coap_protocol_free(temp_whole_payload_ptr); + return 0; + } + + // In block message case, payload_ptr freeing must be done in application level + received_coap_msg_ptr->payload_ptr = temp_whole_payload_ptr; + received_coap_msg_ptr->payload_len = whole_payload_len; + + /* Copy stored Blockwise payloads to returned whole Blockwise payload pointer */ + while (payload_ptr != NULL) { + memcpy(temp_whole_payload_ptr, payload_ptr, payload_len); + temp_whole_payload_ptr += payload_len; + sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(handle); + payload_ptr = sn_coap_protocol_linked_list_blockwise_payload_search(handle, src_addr_ptr, &payload_len); + } + received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED; + } + } + } + + + /* Block2 Option in a response (e.g., a 2.05 response for GET) */ + /* Message ID must be same than in received message */ + else { + //This is response to request we made + if (received_coap_msg_ptr->msg_code > COAP_MSG_CODE_REQUEST_DELETE) { + if (handle->sn_coap_internal_block2_resp_handling) { + uint32_t block_number = 0; + + /* Store blockwise payload to Linked list */ + //todo: add block number to stored values - just to make sure all packets are in order + sn_coap_protocol_linked_list_blockwise_payload_store(handle, + src_addr_ptr, + received_coap_msg_ptr->payload_len, + received_coap_msg_ptr->payload_ptr, + received_coap_msg_ptr->options_list_ptr->block2 >> 4); + /* If not last block (more value is set) */ + if (received_coap_msg_ptr->options_list_ptr->block2 & 0x08) { + coap_blockwise_msg_s *previous_blockwise_msg_ptr = NULL; + //build and send ack + received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVING; + + ns_list_foreach(coap_blockwise_msg_s, msg, &handle->linked_list_blockwise_sent_msgs) { + if (received_coap_msg_ptr->msg_id == msg->coap_msg_ptr->msg_id) { + previous_blockwise_msg_ptr = msg; + break; + } + } + + if (!previous_blockwise_msg_ptr || !previous_blockwise_msg_ptr->coap_msg_ptr) { + tr_error("sn_coap_handle_blockwise_message - (send block2) previous message null!"); + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + return 0; + } + + src_coap_blockwise_ack_msg_ptr = sn_coap_parser_alloc_message(handle); + if (src_coap_blockwise_ack_msg_ptr == NULL) { + tr_error("sn_coap_handle_blockwise_message - (send block2) failed to allocate message!"); + return 0; + } + + /* * * Then build CoAP Acknowledgement message * * */ + + if (sn_coap_parser_alloc_options(handle, src_coap_blockwise_ack_msg_ptr) == NULL) { + tr_error("sn_coap_handle_blockwise_message - (send block2) failed to allocate options!"); + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); + src_coap_blockwise_ack_msg_ptr = 0; + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + return NULL; + } + + src_coap_blockwise_ack_msg_ptr->msg_id = message_id++; + if (message_id == 0) { + message_id = 1; + } + + /* Update block option */ + block_temp = received_coap_msg_ptr->options_list_ptr->block2 & 0x07; + + block_number = received_coap_msg_ptr->options_list_ptr->block2 >> 4; + block_number ++; + + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block2 = (block_number << 4) | block_temp; + + + /* Set BLOCK2 (subsequent) GET msg code and copy uri path from previous msg*/ + if (received_coap_msg_ptr->msg_code == COAP_MSG_CODE_RESPONSE_CONTENT) { + src_coap_blockwise_ack_msg_ptr->msg_code = COAP_MSG_CODE_REQUEST_GET; + if (previous_blockwise_msg_ptr->coap_msg_ptr->uri_path_ptr) { + src_coap_blockwise_ack_msg_ptr->uri_path_len = previous_blockwise_msg_ptr->coap_msg_ptr->uri_path_len; + src_coap_blockwise_ack_msg_ptr->uri_path_ptr = handle->sn_coap_protocol_malloc(previous_blockwise_msg_ptr->coap_msg_ptr->uri_path_len); + if (!src_coap_blockwise_ack_msg_ptr->uri_path_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle, src_coap_blockwise_ack_msg_ptr); + tr_error("sn_coap_handle_blockwise_message - failed to allocate for uri path ptr!"); + return NULL; + } + memcpy(src_coap_blockwise_ack_msg_ptr->uri_path_ptr, previous_blockwise_msg_ptr->coap_msg_ptr->uri_path_ptr, previous_blockwise_msg_ptr->coap_msg_ptr->uri_path_len); + } + if (previous_blockwise_msg_ptr->coap_msg_ptr->token_ptr) { + src_coap_blockwise_ack_msg_ptr->token_len = previous_blockwise_msg_ptr->coap_msg_ptr->token_len; + src_coap_blockwise_ack_msg_ptr->token_ptr = handle->sn_coap_protocol_malloc(previous_blockwise_msg_ptr->coap_msg_ptr->token_len); + if (!src_coap_blockwise_ack_msg_ptr->token_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle, src_coap_blockwise_ack_msg_ptr); + tr_error("sn_coap_handle_blockwise_message - failed to allocate for token ptr!"); + return NULL; + } + memcpy(src_coap_blockwise_ack_msg_ptr->token_ptr, previous_blockwise_msg_ptr->coap_msg_ptr->token_ptr, previous_blockwise_msg_ptr->coap_msg_ptr->token_len); + } + } + + ns_list_remove(&handle->linked_list_blockwise_sent_msgs, previous_blockwise_msg_ptr); + if (previous_blockwise_msg_ptr->coap_msg_ptr) { + if (previous_blockwise_msg_ptr->coap_msg_ptr->payload_ptr) { + handle->sn_coap_protocol_free(previous_blockwise_msg_ptr->coap_msg_ptr->payload_ptr); + previous_blockwise_msg_ptr->coap_msg_ptr->payload_ptr = 0; + } + sn_coap_parser_release_allocated_coap_msg_mem(handle, previous_blockwise_msg_ptr->coap_msg_ptr); + previous_blockwise_msg_ptr->coap_msg_ptr = 0; + } + handle->sn_coap_protocol_free(previous_blockwise_msg_ptr); + previous_blockwise_msg_ptr = 0; + + /* Then get needed memory count for Packet data */ + dst_packed_data_needed_mem = sn_coap_builder_calc_needed_packet_data_size_2(src_coap_blockwise_ack_msg_ptr ,handle->sn_coap_block_data_size); + + /* Then allocate memory for Packet data */ + dst_ack_packet_data_ptr = handle->sn_coap_protocol_malloc(dst_packed_data_needed_mem); + + if (dst_ack_packet_data_ptr == NULL) { + tr_error("sn_coap_handle_blockwise_message - (send block2) failed to allocate packet!"); + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->options_list_ptr); + src_coap_blockwise_ack_msg_ptr->options_list_ptr = 0; + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); + src_coap_blockwise_ack_msg_ptr = 0; + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + return NULL; + } + memset(dst_ack_packet_data_ptr, 0, dst_packed_data_needed_mem); + + /* * * Then build Acknowledgement message to Packed data * * */ + if ((sn_coap_builder_2(dst_ack_packet_data_ptr, src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size)) < 0) { + tr_error("sn_coap_handle_blockwise_message - (send block2) builder failed!"); + handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); + dst_ack_packet_data_ptr = 0; + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->options_list_ptr); + src_coap_blockwise_ack_msg_ptr->options_list_ptr = 0; + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); + src_coap_blockwise_ack_msg_ptr = 0; + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + return NULL; + } + + /* * * Save to linked list * * */ + coap_blockwise_msg_s *stored_blockwise_msg_ptr; + + stored_blockwise_msg_ptr = handle->sn_coap_protocol_malloc(sizeof(coap_blockwise_msg_s)); + if (!stored_blockwise_msg_ptr) { + tr_error("sn_coap_handle_blockwise_message - (send block2) failed to allocate blockwise message!"); + handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); + dst_ack_packet_data_ptr = 0; + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->options_list_ptr); + src_coap_blockwise_ack_msg_ptr->options_list_ptr = 0; + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); + src_coap_blockwise_ack_msg_ptr = 0; + sn_coap_parser_release_allocated_coap_msg_mem(handle, received_coap_msg_ptr); + return 0; + } + memset(stored_blockwise_msg_ptr, 0, sizeof(coap_blockwise_msg_s)); + + stored_blockwise_msg_ptr->timestamp = handle->system_time; + + stored_blockwise_msg_ptr->coap_msg_ptr = src_coap_blockwise_ack_msg_ptr; + stored_blockwise_msg_ptr->coap = handle; + ns_list_add_to_end(&handle->linked_list_blockwise_sent_msgs, stored_blockwise_msg_ptr); + + /* * * Then release memory of CoAP Acknowledgement message * * */ + handle->sn_coap_tx_callback(dst_ack_packet_data_ptr, + dst_packed_data_needed_mem, src_addr_ptr, param); + + #if ENABLE_RESENDINGS + uint32_t resend_time = sn_coap_calculate_new_resend_time(handle->system_time, handle->sn_coap_resending_intervall, 0); + sn_coap_protocol_linked_list_send_msg_store(handle, src_addr_ptr, + dst_packed_data_needed_mem, + dst_ack_packet_data_ptr, + resend_time, param); + #endif + handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); + dst_ack_packet_data_ptr = 0; + } + + //Last block received + else { + /* * * This is the last block when whole Blockwise payload from received * * */ + /* * * blockwise messages is gathered and returned to User * * */ + + /* Store last Blockwise payload to Linked list */ + uint16_t payload_len = 0; + uint8_t *payload_ptr = sn_coap_protocol_linked_list_blockwise_payload_search(handle, src_addr_ptr, &payload_len); + uint16_t whole_payload_len = sn_coap_protocol_linked_list_blockwise_payloads_get_len(handle, src_addr_ptr); + uint8_t *temp_whole_payload_ptr = NULL; + + temp_whole_payload_ptr = handle->sn_coap_protocol_malloc(whole_payload_len); + if (!temp_whole_payload_ptr) { + tr_error("sn_coap_handle_blockwise_message - (send block2) failed to allocate whole payload!"); + return 0; + } + + received_coap_msg_ptr->payload_ptr = temp_whole_payload_ptr; + received_coap_msg_ptr->payload_len = whole_payload_len; + + /* Copy stored Blockwise payloads to returned whole Blockwise payload pointer */ + while (payload_ptr != NULL) { + memcpy(temp_whole_payload_ptr, payload_ptr, payload_len); + + temp_whole_payload_ptr += payload_len; + + sn_coap_protocol_linked_list_blockwise_payload_remove_oldest(handle); + payload_ptr = sn_coap_protocol_linked_list_blockwise_payload_search(handle, src_addr_ptr, &payload_len); + } + received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_MSG_RECEIVED; + + //todo: remove previous msg from list + } + } + } + + //Now we send data to request + else { + //Get message by using block number + //NOTE: Getting the first from list might not be correct one + coap_blockwise_msg_s *stored_blockwise_msg_temp_ptr = ns_list_get_first(&handle->linked_list_blockwise_sent_msgs); + if (stored_blockwise_msg_temp_ptr) { + uint16_t block_size; + uint32_t block_number; + + /* Resolve block parameters */ + block_number = received_coap_msg_ptr->options_list_ptr->block2 >> 4; + block_temp = received_coap_msg_ptr->options_list_ptr->block2 & 0x07; + block_size = 1u << (block_temp + 4); + + /* Build response message */ + src_coap_blockwise_ack_msg_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr; + + if (src_coap_blockwise_ack_msg_ptr->options_list_ptr) { + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block1 = COAP_OPTION_BLOCK_NONE; + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block2 = COAP_OPTION_BLOCK_NONE; + } else { + if (sn_coap_parser_alloc_options(handle, src_coap_blockwise_ack_msg_ptr) == NULL) { + tr_error("sn_coap_handle_blockwise_message - (recv block2) failed to allocate options!"); + return 0; + } + } + + src_coap_blockwise_ack_msg_ptr->msg_id = received_coap_msg_ptr->msg_id; + + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block2 = received_coap_msg_ptr->options_list_ptr->block2; + + /* * Payload part * */ + + /* Check if last block */ + + original_payload_len = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len; + original_payload_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr; + + if ((block_size * (block_number + 1)) >= stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len) { + src_coap_blockwise_ack_msg_ptr->payload_len = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len - (block_size * block_number); + src_coap_blockwise_ack_msg_ptr->payload_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr + (block_size * block_number); + } + /* Not last block */ + else { + /* set more - bit */ + src_coap_blockwise_ack_msg_ptr->options_list_ptr->block2 |= 0x08; + src_coap_blockwise_ack_msg_ptr->payload_len = block_size; + src_coap_blockwise_ack_msg_ptr->payload_ptr = stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr + (block_size * block_number); + } + + /* Update token to match one which is in GET request. + * This is needed only in case of notification message. + */ + if (src_coap_blockwise_ack_msg_ptr->options_list_ptr && + src_coap_blockwise_ack_msg_ptr->options_list_ptr->observe != COAP_OBSERVE_NONE) { + if (received_coap_msg_ptr->token_len && src_coap_blockwise_ack_msg_ptr->token_ptr) { + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->token_ptr); + src_coap_blockwise_ack_msg_ptr->token_ptr = handle->sn_coap_protocol_malloc(received_coap_msg_ptr->token_len); + if (src_coap_blockwise_ack_msg_ptr->token_ptr) { + memcpy(src_coap_blockwise_ack_msg_ptr->token_ptr, received_coap_msg_ptr->token_ptr, received_coap_msg_ptr->token_len); + src_coap_blockwise_ack_msg_ptr->token_len = received_coap_msg_ptr->token_len; + } + } + } + + /* Build and send block message */ + dst_packed_data_needed_mem = sn_coap_builder_calc_needed_packet_data_size_2(src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); + + dst_ack_packet_data_ptr = handle->sn_coap_protocol_malloc(dst_packed_data_needed_mem); + if (!dst_ack_packet_data_ptr) { + tr_error("sn_coap_handle_blockwise_message - (recv block2) failed to allocate packet!"); + if(original_payload_ptr){ + handle->sn_coap_protocol_free(original_payload_ptr); + original_payload_ptr = NULL; + } + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr->options_list_ptr); + src_coap_blockwise_ack_msg_ptr->options_list_ptr = 0; + handle->sn_coap_protocol_free(src_coap_blockwise_ack_msg_ptr); + stored_blockwise_msg_temp_ptr->coap_msg_ptr = NULL; + return NULL; + } + + sn_coap_builder_2(dst_ack_packet_data_ptr, src_coap_blockwise_ack_msg_ptr, handle->sn_coap_block_data_size); + handle->sn_coap_tx_callback(dst_ack_packet_data_ptr, dst_packed_data_needed_mem, src_addr_ptr, param); + + handle->sn_coap_protocol_free(dst_ack_packet_data_ptr); + dst_ack_packet_data_ptr = 0; + + stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len = original_payload_len; + stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_ptr = original_payload_ptr; + + if ((block_size * (block_number + 1)) >= stored_blockwise_msg_temp_ptr->coap_msg_ptr->payload_len) { + sn_coap_protocol_linked_list_blockwise_msg_remove(handle, stored_blockwise_msg_temp_ptr); + } + + received_coap_msg_ptr->coap_status = COAP_STATUS_PARSER_BLOCKWISE_ACK; + } + } + } + return received_coap_msg_ptr; +} + +int8_t sn_coap_convert_block_size(uint16_t block_size) +{ + if (block_size == 16) { + return 0; + } else if (block_size == 32) { + return 1; + } else if (block_size == 64) { + return 2; + } else if (block_size == 128) { + return 3; + } else if (block_size == 256) { + return 4; + } else if (block_size == 512) { + return 5; + } else if (block_size == 1024) { + return 6; + } + + return 0; +} + +static sn_coap_hdr_s *sn_coap_protocol_copy_header(struct coap_s *handle, sn_coap_hdr_s *source_header_ptr) +{ + sn_coap_hdr_s *destination_header_ptr; + + destination_header_ptr = sn_coap_parser_alloc_message(handle); + if (!destination_header_ptr) { + tr_error("sn_coap_protocol_copy_header - failed to allocate message!"); + return 0; + } + + destination_header_ptr->coap_status = source_header_ptr->coap_status; + destination_header_ptr->msg_type = source_header_ptr->msg_type; + destination_header_ptr->msg_code = source_header_ptr->msg_code; + destination_header_ptr->msg_id = source_header_ptr->msg_id; + + if (source_header_ptr->uri_path_ptr) { + destination_header_ptr->uri_path_len = source_header_ptr->uri_path_len; + destination_header_ptr->uri_path_ptr = handle->sn_coap_protocol_malloc(source_header_ptr->uri_path_len); + if (!destination_header_ptr->uri_path_ptr) { + tr_error("sn_coap_protocol_copy_header - failed to allocate uri path!"); + sn_coap_parser_release_allocated_coap_msg_mem(handle, destination_header_ptr); + return 0; + } + memcpy(destination_header_ptr->uri_path_ptr, source_header_ptr->uri_path_ptr, source_header_ptr->uri_path_len); + } + + if (source_header_ptr->token_ptr) { + destination_header_ptr->token_len = source_header_ptr->token_len; + destination_header_ptr->token_ptr = handle->sn_coap_protocol_malloc(source_header_ptr->token_len); + if (!destination_header_ptr->token_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle, destination_header_ptr); + tr_error("sn_coap_protocol_copy_header - failed to allocate token!"); + return 0; + } + memcpy(destination_header_ptr->token_ptr, source_header_ptr->token_ptr, source_header_ptr->token_len); + } + + destination_header_ptr->content_format = source_header_ptr->content_format; + + /* Options list */ + if (source_header_ptr->options_list_ptr) { + if (sn_coap_parser_alloc_options(handle, destination_header_ptr) == NULL) { + sn_coap_parser_release_allocated_coap_msg_mem(handle, destination_header_ptr); + tr_error("sn_coap_protocol_copy_header - failed to allocate options!"); + return 0; + } + + destination_header_ptr->options_list_ptr->max_age = source_header_ptr->options_list_ptr->max_age; + + if (source_header_ptr->options_list_ptr->proxy_uri_ptr) { + destination_header_ptr->options_list_ptr->proxy_uri_len = source_header_ptr->options_list_ptr->proxy_uri_len; + destination_header_ptr->options_list_ptr->proxy_uri_ptr = handle->sn_coap_protocol_malloc(source_header_ptr->options_list_ptr->proxy_uri_len); + if (!destination_header_ptr->options_list_ptr->proxy_uri_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle, destination_header_ptr); + tr_error("sn_coap_protocol_copy_header - failed to allocate proxy uri!"); + return 0; + } + memcpy(destination_header_ptr->options_list_ptr->proxy_uri_ptr, source_header_ptr->options_list_ptr->proxy_uri_ptr, source_header_ptr->options_list_ptr->proxy_uri_len); + } + + if (source_header_ptr->options_list_ptr->etag_ptr) { + destination_header_ptr->options_list_ptr->etag_len = source_header_ptr->options_list_ptr->etag_len; + destination_header_ptr->options_list_ptr->etag_ptr = handle->sn_coap_protocol_malloc(source_header_ptr->options_list_ptr->etag_len); + if (!destination_header_ptr->options_list_ptr->etag_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle, destination_header_ptr); + tr_error("sn_coap_protocol_copy_header - failed to allocate etag!"); + return 0; + } + memcpy(destination_header_ptr->options_list_ptr->etag_ptr, source_header_ptr->options_list_ptr->etag_ptr, source_header_ptr->options_list_ptr->etag_len); + } + + if (source_header_ptr->options_list_ptr->uri_host_ptr) { + destination_header_ptr->options_list_ptr->uri_host_len = source_header_ptr->options_list_ptr->uri_host_len; + destination_header_ptr->options_list_ptr->uri_host_ptr = handle->sn_coap_protocol_malloc(source_header_ptr->options_list_ptr->uri_host_len); + if (!destination_header_ptr->options_list_ptr->uri_host_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle, destination_header_ptr); + tr_error("sn_coap_protocol_copy_header - failed to allocate uri host!"); + return 0; + } + memcpy(destination_header_ptr->options_list_ptr->uri_host_ptr, source_header_ptr->options_list_ptr->uri_host_ptr, source_header_ptr->options_list_ptr->uri_host_len); + } + + if (source_header_ptr->options_list_ptr->location_path_ptr) { + destination_header_ptr->options_list_ptr->location_path_len = source_header_ptr->options_list_ptr->location_path_len; + destination_header_ptr->options_list_ptr->location_path_ptr = handle->sn_coap_protocol_malloc(source_header_ptr->options_list_ptr->location_path_len); + if (!destination_header_ptr->options_list_ptr->location_path_ptr) { + tr_error("sn_coap_protocol_copy_header - failed to allocate location path!"); + sn_coap_parser_release_allocated_coap_msg_mem(handle, destination_header_ptr); + return 0; + } + memcpy(destination_header_ptr->options_list_ptr->location_path_ptr, source_header_ptr->options_list_ptr->location_path_ptr, source_header_ptr->options_list_ptr->location_path_len); + } + + destination_header_ptr->options_list_ptr->uri_port = source_header_ptr->options_list_ptr->uri_port; + + if (source_header_ptr->options_list_ptr->location_query_ptr) { + destination_header_ptr->options_list_ptr->location_query_len = source_header_ptr->options_list_ptr->location_query_len; + destination_header_ptr->options_list_ptr->location_query_ptr = handle->sn_coap_protocol_malloc(source_header_ptr->options_list_ptr->location_query_len); + if (!destination_header_ptr->options_list_ptr->location_query_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle, destination_header_ptr); + tr_error("sn_coap_protocol_copy_header - failed to allocate location query!"); + return 0; + } + memcpy(destination_header_ptr->options_list_ptr->location_query_ptr, source_header_ptr->options_list_ptr->location_query_ptr, source_header_ptr->options_list_ptr->location_query_len); + } + + destination_header_ptr->options_list_ptr->observe = source_header_ptr->options_list_ptr->observe; + destination_header_ptr->options_list_ptr->accept = source_header_ptr->options_list_ptr->accept; + + if (source_header_ptr->options_list_ptr->uri_query_ptr) { + destination_header_ptr->options_list_ptr->uri_query_len = source_header_ptr->options_list_ptr->uri_query_len; + destination_header_ptr->options_list_ptr->uri_query_ptr = handle->sn_coap_protocol_malloc(source_header_ptr->options_list_ptr->uri_query_len); + if (!destination_header_ptr->options_list_ptr->uri_query_ptr) { + sn_coap_parser_release_allocated_coap_msg_mem(handle, destination_header_ptr); + tr_error("sn_coap_protocol_copy_header - failed to allocate uri query!"); + return 0; + } + memcpy(destination_header_ptr->options_list_ptr->uri_query_ptr, source_header_ptr->options_list_ptr->uri_query_ptr, source_header_ptr->options_list_ptr->uri_query_len); + } + + destination_header_ptr->options_list_ptr->block1 = source_header_ptr->options_list_ptr->block1; + destination_header_ptr->options_list_ptr->block2 = source_header_ptr->options_list_ptr->block2; + } + + return destination_header_ptr; +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,4 @@ +build/* +yotta_modules/* +yotta_targets/* +test/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/CMakeLists.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,18 @@ +INCLUDE(CMakeForceCompiler) + +cmake_minimum_required (VERSION 2.8) +SET(CMAKE_SYSTEM_NAME Generic) + +project(mbedTrace) + + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/mbed-trace/) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../nanostack-libservice/mbed-client-libservice/) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../nanostack-libservice/) + +set (MBED_TRACE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/source/mbed_trace.c) + + +CREATE_LIBRARY(mbedTrace "${MBED_TRACE_SRC}" "") +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/mbed-trace/mbed_trace.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/mbed-trace/mbed_trace.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file mbed_trace.h + * Trace interface for MbedOS applications. + * This file provide simple but flexible way to handle software traces. + * Trace library are abstract layer, which use stdout (printf) by default, + * but outputs can be easily redirect to custom function, for example to + * store traces to memory or other interfaces. + * + * usage example: + * \code(main.c:) + * #include "mbed_trace.h" + * #define TRACE_GROUP "main" + * + * int main(void){ + * mbed_trace_init(); // initialize trace library + * tr_debug("this is debug msg"); //print debug message to stdout: "[DBG] + * tr_info("this is info msg"); + * tr_warn("this is warning msg"); + * tr_err("this is error msg"); + * return 0; + * } + * \endcode + * Activate with compiler flag: YOTTA_CFG_MBED_TRACE + * Configure trace line buffer size with compiler flag: YOTTA_CFG_MBED_TRACE_LINE_LENGTH. Default length: 1024. + * Limit the size of flash by setting MBED_TRACE_MAX_LEVEL value. Default is TRACE_LEVEL_DEBUG (all included) + * + */ +#ifndef MBED_TRACE_H_ +#define MBED_TRACE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef YOTTA_CFG +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#else +#include "ns_types.h" +#endif + +#include <stdarg.h> + +#ifndef YOTTA_CFG_MBED_TRACE +#define YOTTA_CFG_MBED_TRACE 0 +#endif + +#ifndef YOTTA_CFG_MBED_TRACE_FEA_IPV6 +#define YOTTA_CFG_MBED_TRACE_FEA_IPV6 1 +#else +#warning YOTTA_CFG_MBED_TRACE_FEA_IPV6 is deprecated and will be removed in the future! Use MBED_CONF_MBED_TRACE_FEA_IPV6 instead. +#define MBED_CONF_MBED_TRACE_FEA_IPV6 YOTTA_CFG_MBED_TRACE_FEA_IPV6 +#endif + +#ifndef MBED_CONF_MBED_TRACE_ENABLE +#define MBED_CONF_MBED_TRACE_ENABLE 0 +#endif + +#ifndef MBED_CONF_MBED_TRACE_FEA_IPV6 +#define MBED_CONF_MBED_TRACE_FEA_IPV6 1 +#endif + +/** 3 upper bits are trace modes related, + and 5 lower bits are trace level configuration */ + +/** Config mask */ +#define TRACE_MASK_CONFIG 0xE0 +/** Trace level mask */ +#define TRACE_MASK_LEVEL 0x1F + +/** plain trace data instead of "headers" */ +#define TRACE_MODE_PLAIN 0x80 +/** color mode */ +#define TRACE_MODE_COLOR 0x40 +/** Use print CR before trace line */ +#define TRACE_CARRIAGE_RETURN 0x20 + +/** used to activate all trace levels */ +#define TRACE_ACTIVE_LEVEL_ALL 0x1F +/** print all traces same as above */ +#define TRACE_ACTIVE_LEVEL_DEBUG 0x1f +/** print info,warn and error traces */ +#define TRACE_ACTIVE_LEVEL_INFO 0x0f +/** print warn and error traces */ +#define TRACE_ACTIVE_LEVEL_WARN 0x07 +/** print only error trace */ +#define TRACE_ACTIVE_LEVEL_ERROR 0x03 +/** print only cmd line data */ +#define TRACE_ACTIVE_LEVEL_CMD 0x01 +/** trace nothing */ +#define TRACE_ACTIVE_LEVEL_NONE 0x00 + +/** this print is some deep information for debug purpose */ +#define TRACE_LEVEL_DEBUG 0x10 +/** Info print, for general purpose prints */ +#define TRACE_LEVEL_INFO 0x08 +/** warning prints, which shouldn't causes any huge problems */ +#define TRACE_LEVEL_WARN 0x04 +/** Error prints, which causes probably problems, e.g. out of mem. */ +#define TRACE_LEVEL_ERROR 0x02 +/** special level for cmdline. Behaviours like "plain mode" */ +#define TRACE_LEVEL_CMD 0x01 + +#ifndef MBED_TRACE_MAX_LEVEL +#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_DEBUG +#endif + +//usage macros: +#if MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_DEBUG +#define tr_debug(...) mbed_tracef(TRACE_LEVEL_DEBUG, TRACE_GROUP, __VA_ARGS__) //!< Print debug message +#else +#define tr_debug(...) +#endif + +#if MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_INFO +#define tr_info(...) mbed_tracef(TRACE_LEVEL_INFO, TRACE_GROUP, __VA_ARGS__) //!< Print info message +#else +#define tr_info(...) +#endif + +#if MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_WARN +#define tr_warning(...) mbed_tracef(TRACE_LEVEL_WARN, TRACE_GROUP, __VA_ARGS__) //!< Print warning message +#define tr_warn(...) mbed_tracef(TRACE_LEVEL_WARN, TRACE_GROUP, __VA_ARGS__) //!< Alternative warning message +#else +#define tr_warning(...) +#define tr_warn(...) +#endif + +#if MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_ERROR +#define tr_error(...) mbed_tracef(TRACE_LEVEL_ERROR, TRACE_GROUP, __VA_ARGS__) //!< Print Error Message +#define tr_err(...) mbed_tracef(TRACE_LEVEL_ERROR, TRACE_GROUP, __VA_ARGS__) //!< Alternative error message +#else +#define tr_error(...) +#define tr_err(...) +#endif + +#define tr_cmdline(...) mbed_tracef(TRACE_LEVEL_CMD, TRACE_GROUP, __VA_ARGS__) //!< Special print for cmdline. See more from TRACE_LEVEL_CMD -level + +//aliases for the most commonly used functions and the helper functions +#define tracef(dlevel, grp, ...) mbed_tracef(dlevel, grp, __VA_ARGS__) //!< Alias for mbed_tracef() +#define vtracef(dlevel, grp, fmt, ap) mbed_vtracef(dlevel, grp, fmt, ap) //!< Alias for mbed_vtracef() +#define tr_array(buf, len) mbed_trace_array(buf, len) //!< Alias for mbed_trace_array() +#define tr_ipv6(addr_ptr) mbed_trace_ipv6(addr_ptr) //!< Alias for mbed_trace_ipv6() +#define tr_ipv6_prefix(prefix, prefix_len) mbed_trace_ipv6_prefix(prefix, prefix_len) //!< Alias for mbed_trace_ipv6_prefix() +#define trace_array(buf, len) mbed_trace_array(buf, len) //!< Alias for mbed_trace_array() +#define trace_ipv6(addr_ptr) mbed_trace_ipv6(addr_ptr) //!< Alias for mbed_trace_ipv6() +#define trace_ipv6_prefix(prefix, prefix_len) mbed_trace_ipv6_prefix(prefix, prefix_len) //!< Alias for mbed_trace_ipv6_prefix() + + +/** + * Allow specification of default TRACE_GROUP to be used if not specified by application + */ + +#ifndef TRACE_GROUP +#ifdef YOTTA_CFG_MBED_TRACE_GROUP +#define TRACE_GROUP_STR_HELPER(x) #x +#define TRACE_GROUP_STR(x) TRACE_GROUP_STR_HELPER(x) +#define TRACE_GROUP TRACE_GROUP_STR(YOTTA_CFG_MBED_TRACE_GROUP) +#endif +#endif + +/** + * Initialize trace functionality + * @return 0 when all success, otherwise non zero + */ +int mbed_trace_init( void ); +/** + * Free trace memory + */ +void mbed_trace_free( void ); +/** + * Resize buffers (line / tmp ) sizes + * @param lineLength new maximum length for trace line (0 = do no resize) + * @param tmpLength new maximum length for trace tmp buffer (used for trace_array, etc) (0 = do no resize) + */ +void mbed_trace_buffer_sizes(int lineLength, int tmpLength); +/** + * Set trace configurations + * Possible parameters: + * + * TRACE_MODE_COLOR + * TRACE_MODE_PLAIN (this exclude color mode) + * TRACE_CARRIAGE_RETURN (print CR before trace line) + * + * TRACE_ACTIVE_LEVEL_ALL - to activate all trace levels + * or TRACE_ACTIVE_LEVEL_DEBUG (alternative) + * TRACE_ACTIVE_LEVEL_INFO + * TRACE_ACTIVE_LEVEL_WARN + * TRACE_ACTIVE_LEVEL_ERROR + * TRACE_ACTIVE_LEVEL_CMD + * TRACE_LEVEL_NONE - to deactivate all traces + * + * @param config Byte size Bit-mask. Bits are descripted above. + * usage e.g. + * @code + * mbed_trace_config_set( TRACE_ACTIVE_LEVEL_ALL|TRACE_MODE_COLOR ); + * @endcode + */ +void mbed_trace_config_set(uint8_t config); +/** get trace configurations + * @return trace configuration byte + */ +uint8_t mbed_trace_config_get(void); +/** + * Set trace prefix function + * pref_f -function return string with null terminated + * Can be used for e.g. time string + * e.g. + * char* trace_time(){ return "rtc-time-in-string"; } + * mbed_trace_prefix_function_set( &trace_time ); + */ +void mbed_trace_prefix_function_set( char* (*pref_f)(size_t) ); +/** + * Set trace suffix function + * suffix -function return string with null terminated + * Can be used for e.g. time string + * e.g. + * char* trace_suffix(){ return " END"; } + * mbed_trace_suffix_function_set( &trace_suffix ); + */ +void mbed_trace_suffix_function_set(char* (*suffix_f)(void) ); +/** + * Set trace print function + * By default, trace module print using printf() function, + * but with this you can write own print function, + * for e.g. to other IO device. + */ +void mbed_trace_print_function_set( void (*print_f)(const char*) ); +/** + * Set trace print function for tr_cmdline() + */ +void mbed_trace_cmdprint_function_set( void (*printf)(const char*) ); +/** + * Set trace mutex wait function + * By default, trace calls are not thread safe. + * If thread safety is required this can be used to set a callback function that will be called before each trace call. + * The specific implementation is up to the application developer, but the mutex must count so it can + * be acquired from a single thread repeatedly. + */ +void mbed_trace_mutex_wait_function_set(void (*mutex_wait_f)(void)); +/** + * Set trace mutex release function + * By default, trace calls are not thread safe. + * If thread safety is required this can be used to set a callback function that will be called before returning from + * each trace call. The specific implementation is up to the application developer, but the mutex must count so it can + * be acquired from a single thread repeatedly. + */ +void mbed_trace_mutex_release_function_set(void (*mutex_release_f)(void)); +/** + * When trace group contains text in filters, + * trace print will be ignored. + * e.g.: + * mbed_trace_exclude_filters_set("mygr"); + * mbed_tracef(TRACE_ACTIVE_LEVEL_DEBUG, "ougr", "This is not printed"); + */ +void mbed_trace_exclude_filters_set(char* filters); +/** get trace exclude filters + */ +const char* mbed_trace_exclude_filters_get(void); +/** + * When trace group contains text in filter, + * trace will be printed. + * e.g.: + * set_trace_include_filters("mygr"); + * mbed_tracef(TRACE_ACTIVE_LEVEL_DEBUG, "mygr", "Hi There"); + * mbed_tracef(TRACE_ACTIVE_LEVEL_DEBUG, "grp2", "This is not printed"); + */ +void mbed_trace_include_filters_set(char* filters); +/** get trace include filters + */ +const char* mbed_trace_include_filters_get(void); +/** + * General trace function + * This should be used every time when user want to print out something important thing + * Usage e.g. + * mbed_tracef( TRACE_LEVEL_INFO, "mygr", "Hello world!"); + * + * @param dlevel debug level + * @param grp trace group + * @param fmt trace format (like printf) + * @param ... variable arguments related to fmt + */ +#if defined(__GNUC__) || defined(__CC_ARM) +void mbed_tracef(uint8_t dlevel, const char* grp, const char *fmt, ...) __attribute__ ((__format__(__printf__, 3, 4))); +#else +void mbed_tracef(uint8_t dlevel, const char* grp, const char *fmt, ...); +#endif +/** + * General trace function + * This should be used every time when user want to print out something important thing + * and vprintf functionality is desired + * Usage e.g. + * va_list ap; + * va_start (ap, fmt); + * mbed_vtracef( TRACE_LEVEL_INFO, "mygr", fmt, ap ); + * va_end (ap); + * + * @param dlevel debug level + * @param grp trace group + * @param fmt trace format (like vprintf) + * @param ap variable arguments list (like vprintf) + */ +#if defined(__GNUC__) || defined(__CC_ARM) +void mbed_vtracef(uint8_t dlevel, const char* grp, const char *fmt, va_list ap) __attribute__ ((__format__(__printf__, 3, 0))); +#else +void mbed_vtracef(uint8_t dlevel, const char* grp, const char *fmt, va_list ap); +#endif + + +/** + * Get last trace from buffer + */ +const char* mbed_trace_last(void); +#if MBED_CONF_MBED_TRACE_FEA_IPV6 == 1 +/** + * mbed_tracef helping function for convert ipv6 + * table to human readable string. + * usage e.g. + * char ipv6[16] = {...}; // ! array length is 16 bytes ! + * mbed_tracef(TRACE_LEVEL_INFO, "mygr", "ipv6 addr: %s", mbed_trace_ipv6(ipv6)); + * + * @param add_ptr IPv6 Address pointer + * @return temporary buffer where ipv6 is in string format + */ +char* mbed_trace_ipv6(const void *addr_ptr); +/** + * mbed_tracef helping function for print ipv6 prefix + * usage e.g. + * char ipv6[16] = {...}; // ! array length is 16 bytes ! + * mbed_tracef(TRACE_LEVEL_INFO, "mygr", "ipv6 addr: %s", mbed_trace_ipv6_prefix(ipv6, 4)); + * + * @param prefix IPv6 Address pointer + * @param prefix_len prefix length + * @return temporary buffer where ipv6 is in string format + */ +char* mbed_trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len); +#endif +/** + * mbed_tracef helping function for convert hex-array to string. + * usage e.g. + * char myarr[] = {0x10, 0x20}; + * mbed_tracef(TRACE_LEVEL_INFO, "mygr", "arr: %s", mbed_trace_array(myarr, 2)); + * + * @param buf hex array pointer + * @param len buffer length + * @return temporary buffer where string copied + * if array as string not fit to temp buffer, this function write '*' as last character, + * which indicate that buffer is too small for array. + */ +char* mbed_trace_array(const uint8_t* buf, uint16_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* MBED_TRACE_H_ */ + +/* These macros are outside the inclusion guard so they will be re-evaluated for every inclusion of the header. + * If tracing is disabled, the dummies will hide the real functions. The real functions can still be reached by + * surrounding the name of the function with brackets, e.g. "(mbed_tracef)(dlevel, grp, "like so");" + * */ +#if defined(FEA_TRACE_SUPPORT) || MBED_CONF_MBED_TRACE_ENABLE || YOTTA_CFG_MBED_TRACE || (defined(YOTTA_CFG) && !defined(NDEBUG)) +// Make sure FEA_TRACE_SUPPORT is always set whenever traces are enabled. +#ifndef FEA_TRACE_SUPPORT +#define FEA_TRACE_SUPPORT +#endif +// undefine dummies, revealing the real functions +#undef MBED_TRACE_DUMMIES_DEFINED +#undef mbed_trace_init +#undef mbed_trace_free +#undef mbed_trace_buffer_sizes +#undef mbed_trace_config_set +#undef mbed_trace_config_get +#undef mbed_trace_prefix_function_set +#undef mbed_trace_suffix_function_set +#undef mbed_trace_print_function_set +#undef mbed_trace_cmdprint_function_set +#undef mbed_trace_mutex_wait_function_set +#undef mbed_trace_mutex_release_function_set +#undef mbed_trace_exclude_filters_set +#undef mbed_trace_exclude_filters_get +#undef mbed_trace_include_filters_set +#undef mbed_trace_include_filters_get +#undef mbed_tracef +#undef mbed_vtracef +#undef mbed_trace_last +#undef mbed_trace_ipv6 +#undef mbed_trace_ipv6_prefix +#undef mbed_trace_array + +#elif !defined(MBED_TRACE_DUMMIES_DEFINED) +// define dummies, hiding the real functions +#define MBED_TRACE_DUMMIES_DEFINED +#define mbed_trace_init(...) ((int) 0) +#define mbed_trace_free(...) ((void) 0) +#define mbed_trace_buffer_sizes(...) ((void) 0) +#define mbed_trace_config_set(...) ((void) 0) +#define mbed_trace_config_get(...) ((uint8_t) 0) +#define mbed_trace_prefix_function_set(...) ((void) 0) +#define mbed_trace_suffix_function_set(...) ((void) 0) +#define mbed_trace_print_function_set(...) ((void) 0) +#define mbed_trace_cmdprint_function_set(...) ((void) 0) +#define mbed_trace_mutex_wait_function_set(...) ((void) 0) +#define mbed_trace_mutex_release_function_set(...) ((void) 0) +#define mbed_trace_exclude_filters_set(...) ((void) 0) +#define mbed_trace_exclude_filters_get(...) ((const char *) 0) +#define mbed_trace_include_filters_set(...) ((void) 0) +#define mbed_trace_include_filters_get(...) ((const char *) 0) +#define mbed_trace_last(...) ((const char *) 0) +#define mbed_tracef(...) ((void) 0) +#define mbed_vtracef(...) ((void) 0) +/** + * These helper functions accumulate strings in a buffer that is only flushed by actual trace calls. Using these + * functions outside trace calls could cause the buffer to overflow. + */ +#define mbed_trace_ipv6(...) dont_use_trace_helpers_outside_trace_calls +#define mbed_trace_ipv6_prefix(...) dont_use_trace_helpers_outside_trace_calls +#define mbed_trace_array(...) dont_use_trace_helpers_outside_trace_calls + +#endif /* FEA_TRACE_SUPPORT */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,14 @@ +{ + "name": "mbed-trace", + "config": { + "enable": { + "help": "Used to globally enable traces.", + "value": null + }, + "fea-ipv6": { + "help": "Used to globally disable ipv6 tracing features.", + "value": null + } + + } +} \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/source/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/source/CMakeLists.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,12 @@ +if(DEFINED TARGET_LIKE_X86_LINUX_NATIVE) + add_library( mbed-trace + mbed_trace.c + ) + add_definitions("-g -O0 -fprofile-arcs -ftest-coverage") + target_link_libraries(mbed-trace gcov nanostack-libservice) +else() + add_library( mbed-trace + mbed_trace.c + ) + target_link_libraries(mbed-trace nanostack-libservice) +endif()
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/source/mbed_trace.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed-trace/source/mbed_trace.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#ifdef MBED_CONF_MBED_TRACE_ENABLE +#undef MBED_CONF_MBED_TRACE_ENABLE +#endif +#define MBED_CONF_MBED_TRACE_ENABLE 1 +#ifndef MBED_CONF_MBED_TRACE_FEA_IPV6 +#define MBED_CONF_MBED_TRACE_FEA_IPV6 1 +#endif + +#include "mbed-trace/mbed_trace.h" +#if MBED_CONF_MBED_TRACE_FEA_IPV6 == 1 +#include "mbed-client-libservice/ip6string.h" +#include "mbed-client-libservice/common_functions.h" +#endif + +#if defined(YOTTA_CFG_MBED_TRACE_MEM) +#define MBED_TRACE_MEM_INCLUDE YOTTA_CFG_MBED_TRACE_MEM_INCLUDE +#define MBED_TRACE_MEM_ALLOC YOTTA_CFG_MBED_TRACE_MEM_ALLOC +#define MBED_TRACE_MEM_FREE YOTTA_CFG_MBED_TRACE_MEM_FREE +#else /* YOTTA_CFG_MEMLIB */ +// Default options +#ifndef MBED_TRACE_MEM_INCLUDE +#define MBED_TRACE_MEM_INCLUDE <stdlib.h> +#endif +#include MBED_TRACE_MEM_INCLUDE +#ifndef MBED_TRACE_MEM_ALLOC +#define MBED_TRACE_MEM_ALLOC malloc +#endif +#ifndef MBED_TRACE_MEM_FREE +#define MBED_TRACE_MEM_FREE free +#endif +#endif /* YOTTA_CFG_MEMLIB */ + +#define VT100_COLOR_ERROR "\x1b[31m" +#define VT100_COLOR_WARN "\x1b[33m" +#define VT100_COLOR_INFO "\x1b[39m" +#define VT100_COLOR_DEBUG "\x1b[90m" + +/** default max trace line size in bytes */ +#ifdef MBED_TRACE_LINE_LENGTH +#define DEFAULT_TRACE_LINE_LENGTH MBED_TRACE_LINE_LENGTH +#elif defined YOTTA_CFG_MBED_TRACE_LINE_LENGTH +#warning YOTTA_CFG_MBED_TRACE_LINE_LENGTH is deprecated and will be removed in the future! Use MBED_TRACE_LINE_LENGTH instead. +#define DEFAULT_TRACE_LINE_LENGTH YOTTA_CFG_MBED_TRACE_LINE_LENGTH +#else +#define DEFAULT_TRACE_LINE_LENGTH 1024 +#endif + +/** default max temporary buffer size in bytes, used in + trace_ipv6, trace_ipv6_prefix and trace_array */ +#ifdef MBED_TRACE_TMP_LINE_LENGTH +#define DEFAULT_TRACE_TMP_LINE_LEN MBED_TRACE_TMP_LINE_LENGTH +#elif defined YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN +#warning The YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN flag is deprecated and will be removed in the future! Use MBED_TRACE_TMP_LINE_LENGTH instead. +#define DEFAULT_TRACE_TMP_LINE_LEN YOTTA_CFG_MBED_TRACE_TMP_LINE_LEN +#elif defined YOTTA_CFG_MTRACE_TMP_LINE_LEN +#warning The YOTTA_CFG_MTRACE_TMP_LINE_LEN flag is deprecated and will be removed in the future! Use MBED_TRACE_TMP_LINE_LENGTH instead. +#define DEFAULT_TRACE_TMP_LINE_LEN YOTTA_CFG_MTRACE_TMP_LINE_LEN +#else +#define DEFAULT_TRACE_TMP_LINE_LEN 128 +#endif + +/** default max filters (include/exclude) length in bytes */ +#ifdef MBED_TRACE_FILTER_LENGTH +#define DEFAULT_TRACE_FILTER_LENGTH MBED_TRACE_FILTER_LENGTH +#else +#define DEFAULT_TRACE_FILTER_LENGTH 24 +#endif + +/** default trace configuration bitmask */ +#ifdef MBED_TRACE_CONFIG +#define DEFAULT_TRACE_CONFIG MBED_TRACE_CONFIG +#else +#define DEFAULT_TRACE_CONFIG TRACE_MODE_COLOR | TRACE_ACTIVE_LEVEL_ALL | TRACE_CARRIAGE_RETURN +#endif + +/** default print function, just redirect str to printf */ +static void mbed_trace_realloc( char **buffer, int *length_ptr, int new_length); +static void mbed_trace_default_print(const char *str); +static void mbed_trace_reset_tmp(void); + +typedef struct trace_s { + /** trace configuration bits */ + uint8_t trace_config; + /** exclude filters list, related group name */ + char *filters_exclude; + /** include filters list, related group name */ + char *filters_include; + /** Filters length */ + int filters_length; + /** trace line */ + char *line; + /** trace line length */ + int line_length; + /** temporary data */ + char *tmp_data; + /** temporary data array length */ + int tmp_data_length; + /** temporary data pointer */ + char *tmp_data_ptr; + + /** prefix function, which can be used to put time to the trace line */ + char *(*prefix_f)(size_t); + /** suffix function, which can be used to some string to the end of trace line */ + char *(*suffix_f)(void); + /** print out function. Can be redirect to flash for example. */ + void (*printf)(const char *); + /** print out function for TRACE_LEVEL_CMD */ + void (*cmd_printf)(const char *); + /** mutex wait function which can be called to lock against a mutex. */ + void (*mutex_wait_f)(void); + /** mutex release function which must be used to release the mutex locked by mutex_wait_f. */ + void (*mutex_release_f)(void); + /** number of times the mutex has been locked */ + int mutex_lock_count; +} trace_t; + +static trace_t m_trace = { + .trace_config = DEFAULT_TRACE_CONFIG, + .filters_exclude = 0, + .filters_include = 0, + .filters_length = DEFAULT_TRACE_FILTER_LENGTH, + .line = 0, + .line_length = DEFAULT_TRACE_LINE_LENGTH, + .tmp_data = 0, + .tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN, + .prefix_f = 0, + .suffix_f = 0, + .printf = mbed_trace_default_print, + .cmd_printf = 0, + .mutex_wait_f = 0, + .mutex_release_f = 0, + .mutex_lock_count = 0 +}; + +int mbed_trace_init(void) +{ + if (m_trace.line == NULL) { + m_trace.line = MBED_TRACE_MEM_ALLOC(m_trace.line_length); + } + + if (m_trace.tmp_data == NULL) { + m_trace.tmp_data = MBED_TRACE_MEM_ALLOC(m_trace.tmp_data_length); + } + m_trace.tmp_data_ptr = m_trace.tmp_data; + + if (m_trace.filters_exclude == NULL) { + m_trace.filters_exclude = MBED_TRACE_MEM_ALLOC(m_trace.filters_length); + } + if (m_trace.filters_include == NULL) { + m_trace.filters_include = MBED_TRACE_MEM_ALLOC(m_trace.filters_length); + } + + if (m_trace.line == NULL || + m_trace.tmp_data == NULL || + m_trace.filters_exclude == NULL || + m_trace.filters_include == NULL) { + //memory allocation fail + mbed_trace_free(); + return -1; + } + memset(m_trace.tmp_data, 0, m_trace.tmp_data_length); + memset(m_trace.filters_exclude, 0, m_trace.filters_length); + memset(m_trace.filters_include, 0, m_trace.filters_length); + memset(m_trace.line, 0, m_trace.line_length); + + return 0; +} +void mbed_trace_free(void) +{ + // release memory + MBED_TRACE_MEM_FREE(m_trace.line); + MBED_TRACE_MEM_FREE(m_trace.tmp_data); + MBED_TRACE_MEM_FREE(m_trace.filters_exclude); + MBED_TRACE_MEM_FREE(m_trace.filters_include); + + // reset to default values + m_trace.trace_config = DEFAULT_TRACE_CONFIG; + m_trace.filters_exclude = 0; + m_trace.filters_include = 0; + m_trace.filters_length = DEFAULT_TRACE_FILTER_LENGTH; + m_trace.line = 0; + m_trace.line_length = DEFAULT_TRACE_LINE_LENGTH; + m_trace.tmp_data = 0; + m_trace.tmp_data_length = DEFAULT_TRACE_TMP_LINE_LEN; + m_trace.prefix_f = 0; + m_trace.suffix_f = 0; + m_trace.printf = mbed_trace_default_print; + m_trace.cmd_printf = 0; + m_trace.mutex_wait_f = 0; + m_trace.mutex_release_f = 0; + m_trace.mutex_lock_count = 0; +} +static void mbed_trace_realloc( char **buffer, int *length_ptr, int new_length) +{ + MBED_TRACE_MEM_FREE(*buffer); + *buffer = MBED_TRACE_MEM_ALLOC(new_length); + *length_ptr = new_length; +} +void mbed_trace_buffer_sizes(int lineLength, int tmpLength) +{ + if( lineLength > 0 ) { + mbed_trace_realloc( &(m_trace.line), &m_trace.line_length, lineLength ); + } + if( tmpLength > 0 ) { + mbed_trace_realloc( &(m_trace.tmp_data), &m_trace.tmp_data_length, tmpLength); + mbed_trace_reset_tmp(); + } +} +void mbed_trace_config_set(uint8_t config) +{ + m_trace.trace_config = config; +} +uint8_t mbed_trace_config_get(void) +{ + return m_trace.trace_config; +} +void mbed_trace_prefix_function_set(char *(*pref_f)(size_t)) +{ + m_trace.prefix_f = pref_f; +} +void mbed_trace_suffix_function_set(char *(*suffix_f)(void)) +{ + m_trace.suffix_f = suffix_f; +} +void mbed_trace_print_function_set(void (*printf)(const char *)) +{ + m_trace.printf = printf; +} +void mbed_trace_cmdprint_function_set(void (*printf)(const char *)) +{ + m_trace.cmd_printf = printf; +} +void mbed_trace_mutex_wait_function_set(void (*mutex_wait_f)(void)) +{ + m_trace.mutex_wait_f = mutex_wait_f; +} +void mbed_trace_mutex_release_function_set(void (*mutex_release_f)(void)) +{ + m_trace.mutex_release_f = mutex_release_f; +} +void mbed_trace_exclude_filters_set(char *filters) +{ + if (filters) { + (void)strncpy(m_trace.filters_exclude, filters, m_trace.filters_length); + } else { + m_trace.filters_exclude[0] = 0; + } +} +const char *mbed_trace_exclude_filters_get(void) +{ + return m_trace.filters_exclude; +} +const char *mbed_trace_include_filters_get(void) +{ + return m_trace.filters_include; +} +void mbed_trace_include_filters_set(char *filters) +{ + if (filters) { + (void)strncpy(m_trace.filters_include, filters, m_trace.filters_length); + } else { + m_trace.filters_include[0] = 0; + } +} +static int8_t mbed_trace_skip(int8_t dlevel, const char *grp) +{ + if (dlevel >= 0 && grp != 0) { + // filter debug prints only when dlevel is >0 and grp is given + + /// @TODO this could be much better.. + if (m_trace.filters_exclude[0] != '\0' && + strstr(m_trace.filters_exclude, grp) != 0) { + //grp was in exclude list + return 1; + } + if (m_trace.filters_include[0] != '\0' && + strstr(m_trace.filters_include, grp) == 0) { + //grp was in include list + return 1; + } + } + return 0; +} +static void mbed_trace_default_print(const char *str) +{ + puts(str); +} +void mbed_tracef(uint8_t dlevel, const char *grp, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + mbed_vtracef(dlevel, grp, fmt, ap); + va_end(ap); +} +void mbed_vtracef(uint8_t dlevel, const char* grp, const char *fmt, va_list ap) +{ + if ( m_trace.mutex_wait_f ) { + m_trace.mutex_wait_f(); + m_trace.mutex_lock_count++; + } + + if (NULL == m_trace.line) { + goto end; + } + + m_trace.line[0] = 0; //by default trace is empty + + if (mbed_trace_skip(dlevel, grp) || fmt == 0 || grp == 0 || !m_trace.printf) { + //return tmp data pointer back to the beginning + mbed_trace_reset_tmp(); + goto end; + } + if ((m_trace.trace_config & TRACE_MASK_LEVEL) & dlevel) { + bool color = (m_trace.trace_config & TRACE_MODE_COLOR) != 0; + bool plain = (m_trace.trace_config & TRACE_MODE_PLAIN) != 0; + bool cr = (m_trace.trace_config & TRACE_CARRIAGE_RETURN) != 0; + + int retval = 0, bLeft = m_trace.line_length; + char *ptr = m_trace.line; + if (plain == true || dlevel == TRACE_LEVEL_CMD) { + //add trace data + retval = vsnprintf(ptr, bLeft, fmt, ap); + if (dlevel == TRACE_LEVEL_CMD && m_trace.cmd_printf) { + m_trace.cmd_printf(m_trace.line); + m_trace.cmd_printf("\n"); + } else { + //print out whole data + m_trace.printf(m_trace.line); + } + } else { + if (color) { + if (cr) { + retval = snprintf(ptr, bLeft, "\r\x1b[2K"); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + if (bLeft > 0) { + //include color in ANSI/VT100 escape code + switch (dlevel) { + case (TRACE_LEVEL_ERROR): + retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_ERROR); + break; + case (TRACE_LEVEL_WARN): + retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_WARN); + break; + case (TRACE_LEVEL_INFO): + retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_INFO); + break; + case (TRACE_LEVEL_DEBUG): + retval = snprintf(ptr, bLeft, "%s", VT100_COLOR_DEBUG); + break; + default: + color = 0; //avoid unneeded color-terminate code + retval = 0; + break; + } + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0 && color) { + ptr += retval; + bLeft -= retval; + } + } + + } + if (bLeft > 0 && m_trace.prefix_f) { + //find out length of body + size_t sz = 0; + va_list ap2; + va_copy(ap2, ap); + sz = vsnprintf(NULL, 0, fmt, ap2) + retval + (retval ? 4 : 0); + va_end(ap2); + //add prefix string + retval = snprintf(ptr, bLeft, "%s", m_trace.prefix_f(sz)); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + if (bLeft > 0) { + //add group tag + switch (dlevel) { + case (TRACE_LEVEL_ERROR): + retval = snprintf(ptr, bLeft, "[ERR ][%-4s]: ", grp); + break; + case (TRACE_LEVEL_WARN): + retval = snprintf(ptr, bLeft, "[WARN][%-4s]: ", grp); + break; + case (TRACE_LEVEL_INFO): + retval = snprintf(ptr, bLeft, "[INFO][%-4s]: ", grp); + break; + case (TRACE_LEVEL_DEBUG): + retval = snprintf(ptr, bLeft, "[DBG ][%-4s]: ", grp); + break; + default: + retval = snprintf(ptr, bLeft, " "); + break; + } + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + if (retval > 0 && bLeft > 0) { + //add trace text + retval = vsnprintf(ptr, bLeft, fmt, ap); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + + if (retval > 0 && bLeft > 0 && m_trace.suffix_f) { + //add suffix string + retval = snprintf(ptr, bLeft, "%s", m_trace.suffix_f()); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + ptr += retval; + bLeft -= retval; + } + } + + if (retval > 0 && bLeft > 0 && color) { + //add zero color VT100 when color mode + retval = snprintf(ptr, bLeft, "\x1b[0m"); + if (retval >= bLeft) { + retval = 0; + } + if (retval > 0) { + // not used anymore + //ptr += retval; + //bLeft -= retval; + } + } + //print out whole data + m_trace.printf(m_trace.line); + } + //return tmp data pointer back to the beginning + mbed_trace_reset_tmp(); + } + +end: + if ( m_trace.mutex_release_f ) { + // Store the mutex lock count to temp variable so that it won't get + // clobbered during last loop iteration when mutex gets released + int count = m_trace.mutex_lock_count; + m_trace.mutex_lock_count = 0; + // Since the helper functions (eg. mbed_trace_array) are used like this: + // mbed_tracef(TRACE_LEVEL_INFO, "grp", "%s", mbed_trace_array(some_array)) + // The helper function MUST acquire the mutex if it modifies any buffers. However + // it CANNOT unlock the mutex because that would allow another thread to acquire + // the mutex after helper function unlocks it and before mbed_tracef acquires it + // for itself. This means that here we have to unlock the mutex as many times + // as it was acquired by trace function and any possible helper functions. + do { + m_trace.mutex_release_f(); + } while (--count > 0); + } +} +static void mbed_trace_reset_tmp(void) +{ + m_trace.tmp_data_ptr = m_trace.tmp_data; +} +const char *mbed_trace_last(void) +{ + return m_trace.line; +} +/* Helping functions */ +#define tmp_data_left() m_trace.tmp_data_length-(m_trace.tmp_data_ptr-m_trace.tmp_data) +#if MBED_CONF_MBED_TRACE_FEA_IPV6 == 1 +char *mbed_trace_ipv6(const void *addr_ptr) +{ + /** Acquire mutex. It is released before returning from mbed_vtracef. */ + if ( m_trace.mutex_wait_f ) { + m_trace.mutex_wait_f(); + m_trace.mutex_lock_count++; + } + char *str = m_trace.tmp_data_ptr; + if (str == NULL) { + return ""; + } + if (tmp_data_left() < 41) { + return ""; + } + if (addr_ptr == NULL) { + return "<null>"; + } + str[0] = 0; + m_trace.tmp_data_ptr += ip6tos(addr_ptr, str) + 1; + return str; +} +char *mbed_trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len) +{ + /** Acquire mutex. It is released before returning from mbed_vtracef. */ + if ( m_trace.mutex_wait_f ) { + m_trace.mutex_wait_f(); + m_trace.mutex_lock_count++; + } + char *str = m_trace.tmp_data_ptr; + if (str == NULL) { + return ""; + } + if (tmp_data_left() < 45) { + return ""; + } + + if ((prefix_len != 0 && prefix == NULL) || prefix_len > 128) { + return "<err>"; + } + + m_trace.tmp_data_ptr += ip6_prefix_tos(prefix, prefix_len, str) + 1; + return str; +} +#endif //MBED_CONF_MBED_TRACE_FEA_IPV6 +char *mbed_trace_array(const uint8_t *buf, uint16_t len) +{ + /** Acquire mutex. It is released before returning from mbed_vtracef. */ + if ( m_trace.mutex_wait_f ) { + m_trace.mutex_wait_f(); + m_trace.mutex_lock_count++; + } + int i, bLeft = tmp_data_left(); + char *str, *wptr; + str = m_trace.tmp_data_ptr; + if (len == 0 || str == NULL || bLeft == 0) { + return ""; + } + if (buf == NULL) { + return "<null>"; + } + wptr = str; + wptr[0] = 0; + const uint8_t *ptr = buf; + char overflow = 0; + for (i = 0; i < len; i++) { + if (bLeft <= 3) { + overflow = 1; + break; + } + int retval = snprintf(wptr, bLeft, "%02x:", *ptr++); + if (retval <= 0 || retval > bLeft) { + break; + } + bLeft -= retval; + wptr += retval; + } + if (wptr > str) { + if( overflow ) { + // replace last character as 'star', + // which indicate buffer len is not enough + *(wptr - 1) = '*'; + } else { + //null to replace last ':' character + *(wptr - 1) = 0; + } + } + m_trace.tmp_data_ptr = wptr; + return str; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,18 @@ +{ + "name": "mbed-cloud-client", + "macros" : [ + "MBEDTLS_PEM_WRITE_C", + "MBEDTLS_CMAC_C", + "MBEDTLS_CIPHER_MODE_CTR", + "SA_PV_PLAT_K64F_MBEDOS_GNUC", + "PB_FIELD_32BIT", + "PB_ENABLE_MALLOC", + "PB_BUFFER_ONLY", + "PV_PROFILE_STD" + ], + "target_overrides": { + "*": { + "target.features_add": ["COMMON_PAL"] + } + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +test/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/apache-2.0.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/common_functions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/common_functions.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef COMMON_FUNCTIONS_H_ +#define COMMON_FUNCTIONS_H_ + +#include "ns_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Common write 64-bit variable to 8-bit pointer. + * + * Write 64 bits in big-endian (network) byte order. + * + * \param value 64-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_64_bit(uint64_t value, uint8_t ptr[__static 8]); + +/* + * Common read 64-bit variable from 8-bit pointer. + * + * Read 64 bits in big-endian (network) byte order. + * + * \param data_buf pointer where data to be read + * + * \return 64-bit variable + */ +NS_INLINE uint64_t common_read_64_bit(const uint8_t data_buf[__static 8]); + +/* + * Common write 32-bit variable to 8-bit pointer. + * + * Write 32 bits in big-endian (network) byte order. + * + * \param value 32-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_32_bit(uint32_t value, uint8_t ptr[__static 4]); + +/* + * Common read 32-bit variable from 8-bit pointer. + * + * Read 32 bits in big-endian (network) byte order. + * + * \param data_buf pointer where data to be read + * + * \return 32-bit variable + */ +NS_INLINE uint32_t common_read_32_bit(const uint8_t data_buf[__static 4]); + +/* + * Common write 32-bit variable to 8-bit pointer. + * + * Write 32 bits in little-endian byte order. + * + * \param value 32-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_32_bit_inverse(uint32_t value, uint8_t ptr[__static 4]); + +/* + * Common read 32-bit variable from 8-bit pointer. + * + * Read 32 bits in little-endian byte order. + * + * \param data_buf pointer where data to be read + * + * \return 32-bit variable + */ +NS_INLINE uint32_t common_read_32_bit_inverse(const uint8_t data_buf[__static 4]); + +/* + * Common write 24-bit variable to 8-bit pointer. + * + * Write 24 bits in big-endian (network) byte order. + * + * \param value 24-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_24_bit(uint_fast24_t value, uint8_t ptr[__static 3]); + +/* + * Common read 24-bit variable from 8-bit pointer. + * + * Read 24 bits in big-endian (network) byte order. + * + * \param data_buf pointer where data to be read + * + * \return 24-bit variable + */ +NS_INLINE uint_fast24_t common_read_24_bit(const uint8_t data_buf[__static 3]); + +/* + * Common write 16-bit variable to 8-bit pointer. + * + * Write 16 bits in big-endian (network) byte order. + * + * \param value 16-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_16_bit(uint16_t value, uint8_t ptr[__static 2]); + +/* + * Common read 16-bit variable from 8-bit pointer. + * + * Read 16 bits in big-endian (network) byte order. + * + * \param data_buf pointer where data to be read + * + * \return 16-bit variable + */ +NS_INLINE uint16_t common_read_16_bit(const uint8_t data_buf[__static 2]); + +/* + * Common write 16-bit variable to 8-bit pointer. + * + * Write 16 bits in little-endian byte order. + * + * \param value 16-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_16_bit_inverse(uint16_t value, uint8_t ptr[__static 2]); + +/* + * Common read 16-bit variable from 8-bit pointer. + * + * Read 16 bits in little-endian byte order. + * + * \param data_buf pointer where data to be read + * + * \return 16-bit variable + */ +NS_INLINE uint16_t common_read_16_bit_inverse(const uint8_t data_buf[__static 2]); + +/* + * Count bits in a byte + * + * \param byte byte to inspect + * + * \return number of 1-bits in byte + */ +NS_INLINE uint_fast8_t common_count_bits(uint8_t byte); + +/* + * Count leading zeros in a byte + * + * \deprecated Use common_count_leading_zeros_8 + * + * \param byte byte to inspect + * + * \return number of leading zeros in byte (0-8) + */ +NS_INLINE uint_fast8_t common_count_leading_zeros(uint8_t byte); + +/* + * Count leading zeros in a byte + * + * \param byte byte to inspect + * + * \return number of leading zeros in byte (0-8) + */ +NS_INLINE uint_fast8_t common_count_leading_zeros_8(uint8_t byte); + +/* + * Count leading zeros in a 16-bit value + * + * \param value value to inspect + * + * \return number of leading zeros in byte (0-16) + */ +NS_INLINE uint_fast8_t common_count_leading_zeros_16(uint16_t value); + +/* + * Count leading zeros in a 32-bit value + * + * \param value value to inspect + * + * \return number of leading zeros in byte (0-32) + */ +NS_INLINE uint_fast8_t common_count_leading_zeros_32(uint32_t value); + +/* + * Compare 8-bit serial numbers + * + * Compare two 8-bit serial numbers, according to RFC 1982 Serial Number + * Arithmetic. + * + * \param s1 first serial number + * \param s2 second serial number + * + * \return true if s1 > s2 + * \return false if s1 <= s2, or the comparison is undefined + */ +NS_INLINE bool common_serial_number_greater_8(uint8_t s1, uint8_t s2); + +/* + * Compare 16-bit serial numbers + * + * Compare two 16-bit serial numbers, according to RFC 1982 Serial Number + * Arithmetic. + * + * \param s1 first serial number + * \param s2 second serial number + * + * \return true if s1 > s2 + * \return false if s1 <= s2, or the comparison is undefined + */ +NS_INLINE bool common_serial_number_greater_16(uint16_t s1, uint16_t s2); + +/* + * Compare 32-bit serial numbers + * + * Compare two 32-bit serial numbers, according to RFC 1982 Serial Number + * Arithmetic. + * + * \param s1 first serial number + * \param s2 second serial number + * + * \return true if s1 > s2 + * \return false if s1 <= s2, or the comparison is undefined + */ +NS_INLINE bool common_serial_number_greater_32(uint32_t s1, uint32_t s2); + +/* + * Test a bit in an bit array. + * + * Check whether a particular bit is set in a bit string. The bit array + * is in big-endian (network) bit order. + * + * \param bitset pointer to bit array + * \param bit index of bit - 0 is the most significant bit of the first byte + * + * \return true if the bit is set + */ +NS_INLINE bool bit_test(const uint8_t *bitset, uint_fast8_t bit); + +/* + * Set a bit in an bit array. + * + * Set a bit in a bit array. The array is in big-endian (network) bit order. + * + * \param bitset pointer to bit array + * \param bit index of bit - 0 is the most significant bit of the first byte + */ +NS_INLINE void bit_set(uint8_t *bitset, uint_fast8_t bit); + +/* + * Clear a bit in an bit array. + * + * Clear a bit in a bit array. The bit array is in big-endian (network) bit order. + * + * \param bitset pointer to bit array + * \param bit index of bit - 0 is the most significant bit of the first byte + */ +NS_INLINE void bit_clear(uint8_t *bitset, uint_fast8_t bit); + +/* + * Compare two bitstrings. + * + * Compare two bitstrings of specified length. The bit strings are in + * big-endian (network) bit order. + * + * \param a pointer to first string + * \param b pointer to second string + * \param bits number of bits to compare + * + * \return true if the strings compare equal + */ +bool bitsequal(const uint8_t *a, const uint8_t *b, uint_fast8_t bits); + +/* + * Copy a bitstring + * + * Copy a bitstring of specified length. The bit string is in big-endian + * (network) bit order. Bits beyond the bitlength at the destination are not + * modified. + * + * For example, copying 4 bits sets the first 4 bits of dst[0] from src[0], + * the lower 4 bits of dst[0] are unmodified. + * + * \param dst destination pointer + * \param src source pointer + * \param bits number of bits to copy + * + * \return the value of dst + */ +uint8_t *bitcopy(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits); + +/* + * Copy a bitstring and pad last byte with zeros + * + * Copy a bitstring of specified length. The bit string is in big-endian + * (network) bit order. Bits beyond the bitlength in the last destination byte are + * zeroed. + * + * For example, copying 4 bits sets the first 4 bits of dst[0] from src[0], and + * the lower 4 bits of dst[0] are set to 0. + * + * \param dst destination pointer + * \param src source pointer + * \param bits number of bits to copy + * + * \return the value of dst + */ +uint8_t *bitcopy0(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits); + +/* Provide definitions, either for inlining, or for common_functions.c */ +#if defined NS_ALLOW_INLINING || defined COMMON_FUNCTIONS_FN +#ifndef COMMON_FUNCTIONS_FN +#define COMMON_FUNCTIONS_FN NS_INLINE +#endif + +COMMON_FUNCTIONS_FN uint8_t *common_write_64_bit(uint64_t value, uint8_t ptr[__static 8]) +{ + *ptr++ = value >> 56; + *ptr++ = value >> 48; + *ptr++ = value >> 40; + *ptr++ = value >> 32; + *ptr++ = value >> 24; + *ptr++ = value >> 16; + *ptr++ = value >> 8; + *ptr++ = value; + return ptr; +} + +COMMON_FUNCTIONS_FN uint64_t common_read_64_bit(const uint8_t data_buf[__static 8]) +{ + uint64_t temp_64; + temp_64 = (uint64_t)(*data_buf++) << 56; + temp_64 += (uint64_t)(*data_buf++) << 48; + temp_64 += (uint64_t)(*data_buf++) << 40; + temp_64 += (uint64_t)(*data_buf++) << 32; + temp_64 += (uint64_t)(*data_buf++) << 24; + temp_64 += (uint64_t)(*data_buf++) << 16; + temp_64 += (uint64_t)(*data_buf++) << 8; + temp_64 += *data_buf++; + return temp_64; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_32_bit(uint32_t value, uint8_t ptr[__static 4]) +{ + *ptr++ = value >> 24; + *ptr++ = value >> 16; + *ptr++ = value >> 8; + *ptr++ = value; + return ptr; +} + +COMMON_FUNCTIONS_FN uint32_t common_read_32_bit(const uint8_t data_buf[__static 4]) +{ + uint32_t temp_32; + temp_32 = (uint32_t)(*data_buf++) << 24; + temp_32 += (uint32_t)(*data_buf++) << 16; + temp_32 += (uint32_t)(*data_buf++) << 8; + temp_32 += *data_buf++; + return temp_32; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_32_bit_inverse(uint32_t value, uint8_t ptr[__static 4]) +{ + *ptr++ = value; + *ptr++ = value >> 8; + *ptr++ = value >> 16; + *ptr++ = value >> 24; + return ptr; +} + +COMMON_FUNCTIONS_FN uint32_t common_read_32_bit_inverse(const uint8_t data_buf[__static 4]) +{ + uint32_t temp_32; + temp_32 = *data_buf++; + temp_32 += (uint32_t)(*data_buf++) << 8; + temp_32 += (uint32_t)(*data_buf++) << 16; + temp_32 += (uint32_t)(*data_buf++) << 24; + return temp_32; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_24_bit(uint_fast24_t value, uint8_t ptr[__static 3]) +{ + *ptr++ = value >> 16; + *ptr++ = value >> 8; + *ptr++ = value; + return ptr; +} + +COMMON_FUNCTIONS_FN uint_fast24_t common_read_24_bit(const uint8_t data_buf[__static 3]) +{ + uint_fast24_t temp_24; + temp_24 = (uint_fast24_t)(*data_buf++) << 16; + temp_24 += (uint_fast24_t)(*data_buf++) << 8; + temp_24 += *data_buf++; + return temp_24; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_16_bit(uint16_t value, uint8_t ptr[__static 2]) +{ + *ptr++ = value >> 8; + *ptr++ = value; + return ptr; +} + +COMMON_FUNCTIONS_FN uint16_t common_read_16_bit(const uint8_t data_buf[__static 2]) +{ + uint16_t temp_16; + temp_16 = (uint16_t)(*data_buf++) << 8; + temp_16 += *data_buf++; + return temp_16; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_16_bit_inverse(uint16_t value, uint8_t ptr[__static 2]) +{ + *ptr++ = value; + *ptr++ = value >> 8; + return ptr; +} + +COMMON_FUNCTIONS_FN uint16_t common_read_16_bit_inverse(const uint8_t data_buf[__static 2]) +{ + uint16_t temp_16; + temp_16 = *data_buf++; + temp_16 += (uint16_t)(*data_buf++) << 8; + return temp_16; +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_bits(uint8_t byte) +{ + /* First step sets each bit pair to be count of bits (00,01,10) */ + /* [00-00 = 00, 01-00 = 01, 10-01 = 01, 11-01 = 10] */ + uint_fast8_t count = byte - ((byte >> 1) & 0x55); + /* Add bit pairs to make each nibble contain count of bits (0-4) */ + count = (count & 0x33) + ((count >> 2) & 0x33); + /* Final result is sum of nibbles (0-8) */ + count = (count >> 4) + (count & 0x0F); + return count; +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros(uint8_t byte) +{ + return common_count_leading_zeros_8(byte); +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_8(uint8_t byte) +{ +#ifdef __CC_ARM + return byte ? __clz((unsigned int) byte << 24) : 8; +#elif defined __GNUC__ + return byte ? __builtin_clz((unsigned int) byte << 24) : 8; +#else + uint_fast8_t cnt = 0; + if (byte == 0) { + return 8; + } + if ((byte & 0xF0) == 0) { + byte <<= 4; + cnt += 4; + } + if ((byte & 0xC0) == 0) { + byte <<= 2; + cnt += 2; + } + if ((byte & 0x80) == 0) { + cnt += 1; + } + + return cnt; +#endif +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_16(uint16_t value) +{ +#ifdef __CC_ARM + return value ? __clz((unsigned int) value << 16) : 16; +#elif defined __GNUC__ + return value ? __builtin_clz((unsigned int) value << 16) : 16; +#else + uint_fast8_t cnt = 0; + if (value == 0) { + return 16; + } + if ((value & 0xFF00) == 0) { + value <<= 8; + cnt += 8; + } + if ((value & 0xF000) == 0) { + value <<= 4; + cnt += 4; + } + if ((value & 0xC000) == 0) { + value <<= 2; + cnt += 2; + } + if ((value & 0x8000) == 0) { + cnt += 1; + } + + return cnt; +#endif +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_32(uint32_t value) +{ +#ifdef __CC_ARM + return __clz(value); +#elif defined __GNUC__ + return value ? __builtin_clz(value) : 32; +#else + uint_fast8_t cnt = 0; + if (value == 0) { + return 32; + } + if ((value & 0xFFFF0000) == 0) { + value <<= 16; + cnt += 16; + } + if ((value & 0xFF000000) == 0) { + value <<= 8; + cnt += 8; + } + if ((value & 0xF0000000) == 0) { + value <<= 4; + cnt += 4; + } + if ((value & 0xC0000000) == 0) { + value <<= 2; + cnt += 2; + } + if ((value & 0x80000000) == 0) { + cnt += 1; + } + + return cnt; +#endif +} + +COMMON_FUNCTIONS_FN bool common_serial_number_greater_8(uint8_t s1, uint8_t s2) +{ + return (s1 > s2 && s1 - s2 < UINT8_C(0x80)) || (s1 < s2 && s2 - s1 > UINT8_C(0x80)); +} + +COMMON_FUNCTIONS_FN bool common_serial_number_greater_16(uint16_t s1, uint16_t s2) +{ + return (s1 > s2 && s1 - s2 < UINT16_C(0x8000)) || (s1 < s2 && s2 - s1 > UINT16_C(0x8000)); +} + +COMMON_FUNCTIONS_FN bool common_serial_number_greater_32(uint32_t s1, uint32_t s2) +{ + return (s1 > s2 && s1 - s2 < UINT32_C(0x80000000)) || (s1 < s2 && s2 - s1 > UINT32_C(0x80000000)); +} + +COMMON_FUNCTIONS_FN bool bit_test(const uint8_t *bitset, uint_fast8_t bit) +{ + return bitset[bit >> 3] & (0x80 >> (bit & 7)); +} + +COMMON_FUNCTIONS_FN void bit_set(uint8_t *bitset, uint_fast8_t bit) +{ + bitset[bit >> 3] |= (0x80 >> (bit & 7)); +} + +COMMON_FUNCTIONS_FN void bit_clear(uint8_t *bitset, uint_fast8_t bit) +{ + bitset[bit >> 3] &= ~(0x80 >> (bit & 7)); +} + +#endif /* defined NS_ALLOW_INLINING || defined COMMON_FUNCTIONS_FN */ + +#ifdef __cplusplus +} +#endif +#endif /*__COMMON_FUNCTIONS_H_*/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ip6string.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ip6string.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef IP6STRING_H +#define IP6STRING_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "ns_types.h" + +#define MAX_IPV6_STRING_LEN_WITH_TRAILING_NULL 40 + +/** + * Print binary IPv6 address to a string. + * + * String must contain enough room for full address, 40 bytes exact. + * IPv4 tunneling addresses are not covered. + * + * \param ip6addr IPv6 address. + * \param p buffer to write string to. + * \return length of generated string excluding the terminating null character + */ +uint_fast8_t ip6tos(const void *ip6addr, char *p); + +/** + * Print binary IPv6 prefix to a string. + * + * String buffer `p` must contain enough room for a full address and prefix length, 44 bytes exact. + * Bits in the `prefix` buffer beyond `prefix_len` bits are not shown and only the bytes containing the + * prefix bits are read. I.e. for a 20 bit prefix 3 bytes are read, and for a 0 bit prefix 0 bytes are + * read (thus if `prefix_len` is zero, `prefix` can be NULL). + * `prefix_len` must be 0 to 128. + * + * \param prefix IPv6 prefix. + * \param prefix_len length of `prefix` in bits. + * \param p buffer to write string to. + * \return length of generated string excluding the terminating null character, or 0 for an error, such as 'prefix_len' > 128 + */ +uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p); + +/** + * Convert numeric IPv6 address string to a binary. + * + * IPv4 tunneling addresses are not covered. + * + * \param ip6addr IPv6 address in string format. + * \param len Lenght of ipv6 string, maximum of 41. + * \param dest buffer for address. MUST be 16 bytes. + */ +void stoip6(const char *ip6addr, size_t len, void *dest); +/** + * Find out numeric IPv6 address prefix length. + * + * \param ip6addr IPv6 address in string format + * \return prefix length or 0 if it not given + */ +unsigned char sipv6_prefixlength(const char *ip6addr); + +#ifdef __cplusplus +} +#endif +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ip_fsc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ip_fsc.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _NS_FSC_H +#define _NS_FSC_H + +#include "ns_types.h" + +#define NEXT_HEADER_TCP 0x06 +#define NEXT_HEADER_UDP 0x11 +#define NEXT_HEADER_ICMP6 0x3A + +extern uint16_t ip_fcf_v(uint_fast8_t count, const ns_iovec_t vec[static count]); +extern uint16_t ipv6_fcf(const uint8_t src_address[static 16], const uint8_t dest_address[static 16], + uint16_t data_length, const uint8_t data_ptr[static data_length], uint8_t next_protocol); + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ns_list.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ns_list.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,738 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NS_LIST_H_ +#define NS_LIST_H_ + +#include "ns_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file + * \brief Linked list support library + * + * The ns_list.h file provides a doubly-linked list/queue, providing O(1) + * performance for all insertion/removal operations, and access to either + * end of the list. + * + * Memory footprint is two pointers for the list head, and two pointers in each + * list entry. It is similar in concept to BSD's TAILQ. + * + * Although the API is symmetrical and O(1) in both directions, due to internal + * pointer design, it is *slightly* more efficient to insert at the end when + * used as a queue, and to iterate forwards rather than backwards. + * + * Example of an entry type that can be stored to this list. + * ~~~ + * typedef struct example_entry + * { + * uint8_t *data; + * uint32_t data_count; + * ns_list_link_t link; + * } + * example_entry_t; + * + * static NS_LIST_HEAD(example_entry_t, link) my_list; + * ns_list_init(&my_list); + * ~~~ + * OR + * ~~~ + * NS_LIST_HEAD(example_entry_t, link) my_list = NS_LIST_INIT(my_list); + * ~~~ + * OR + * ~~~ + * static NS_LIST_DEFINE(my_list, example_entry_t, link); + * ~~~ + * OR + * ~~~ + * typedef NS_LIST_HEAD(example_entry_t, link) example_list_t; + * example_list_t NS_LIST_NAME_INIT(my_list); + * ~~~ + * NOTE: the link field SHALL NOT be accessed by the user. + * + * An entry can exist on multiple lists by having multiple link fields. + * + * All the list operations are implemented as macros, most of which are backed + * by optionally-inline functions. The macros do not evaluate any arguments more + * than once, unless documented. + * + * In macro documentation, `list_t` refers to a list type defined using + * NS_LIST_HEAD(), and `entry_t` to the entry type that was passed to it. + */ + +/** \brief Underlying generic linked list head. + * + * Users should not use this type directly, but use the NS_LIST_HEAD() macro. + */ +typedef struct ns_list { + void *first_entry; ///< Pointer to first entry, or NULL if list is empty + void **last_nextptr; ///< Pointer to last entry's `next` pointer, or + ///< to head's `first_entry` pointer if list is empty +} ns_list_t; + +/** \brief Declare a list head type + * + * This union stores the real list head, and also encodes as compile-time type + * information the offset of the link pointer, and the type of the entry. + * + * Note that type information is compiler-dependent; this means + * ns_list_get_first() could return either `void *`, or a pointer to the actual + * entry type. So `ns_list_get_first()->data` is not a portable construct - + * always assign returned entry pointers to a properly typed pointer variable. + * This assignment will be then type-checked where the compiler supports it, and + * will dereference correctly on compilers that don't support this extension. + * ~~~ + * NS_LIST_HEAD(example_entry_t, link) my_list; + * + * example_entry_t *entry = ns_list_get_first(&my_list); + * do_something(entry->data); + * ~~~ + * Each use of this macro generates a new anonymous union, so these two lists + * have different types: + * ~~~ + * NS_LIST_HEAD(example_entry_t, link) my_list1; + * NS_LIST_HEAD(example_entry_t, link) my_list2; + * ~~~ + * If you need to use a list type in multiple places, eg as a function + * parameter, use typedef: + * ~~~ + * typedef NS_LIST_HEAD(example_entry_t, link) example_list_t; + * + * void example_function(example_list_t *); + * ~~~ + */ +#define NS_LIST_HEAD(entry_type, field) \ + NS_LIST_HEAD_BY_OFFSET_(entry_type, offsetof(entry_type, field)) + +/** \brief Declare a list head type for an incomplete entry type. + * + * This declares a list head, similarly to NS_LIST_HEAD(), but unlike that + * this can be used in contexts where the entry type may be incomplete. + * + * To use this, the link pointer must be the first member in the + * actual complete structure. This is NOT checked - the definition of the + * element should probably test NS_STATIC_ASSERT(offsetof(type, link) == 0) + * if outside users are known to be using NS_LIST_HEAD_INCOMPLETE(). + * ~~~ + * struct opaque; + * NS_LIST_HEAD_INCOMPLETE(struct opaque) opaque_list; + * ~~~ + */ +#define NS_LIST_HEAD_INCOMPLETE(entry_type) \ + NS_LIST_HEAD_BY_OFFSET_(entry_type, 0) + +/// \privatesection +/** \brief Internal macro defining a list head, given the offset to the link pointer + * The +1 allows for link_offset being 0 - we can't declare a 0-size array + */ +#define NS_LIST_HEAD_BY_OFFSET_(entry_type, link_offset) \ +union \ +{ \ + ns_list_t slist; \ + NS_FUNNY_COMPARE_OK \ + NS_STATIC_ASSERT(link_offset <= UINT_FAST8_MAX, "link offset too large") \ + NS_FUNNY_COMPARE_RESTORE \ + char (*offset)[link_offset + 1]; \ + entry_type *type; \ +} + +/** \brief Get offset of link field in entry. + * \return `(ns_list_offset_t)` The offset of the link field for entries on the specified list + */ +#define NS_LIST_OFFSET_(list) ((ns_list_offset_t) (sizeof *(list)->offset - 1)) + +/** \brief Get the entry pointer type. + * \def NS_LIST_PTR_TYPE_ + * + * \return An unqualified pointer type to an entry on the specified list. + * + * Only available if the compiler provides a "typeof" operator. + */ +#if defined __cplusplus && __cplusplus >= 201103L +#define NS_LIST_PTR_TYPE_(list) decltype((list)->type) +#elif defined __GNUC__ +#define NS_LIST_PTR_TYPE_(list) __typeof__((list)->type) +#endif + +/** \brief Check for compatible pointer types + * + * This test will produce a diagnostic about a pointer mismatch on + * the == inside the sizeof operator. For example ARM/Norcroft C gives the error: + * + * operand types are incompatible ("entry_t *" and "other_t *") + */ +#ifdef CPPCHECK +#define NS_PTR_MATCH_(a, b, str) ((void) 0) +#else +#define NS_PTR_MATCH_(a, b, str) ((void) sizeof ((a) == (b))) +#endif + +/** \brief Internal macro to cast returned entry pointers to correct type. + * + * Not portable in C, alas. With GCC or C++11, the "get entry" macros return + * correctly-typed pointers. Otherwise, the macros return `void *`. + * + * The attempt at a portable version would work if the C `?:` operator wasn't + * broken - `x ? (t *) : (void *)` should really have type `(t *)` in C, but + * it has type `(void *)`, which only makes sense for C++. The `?:` is left in, + * in case some day it works. Some compilers may still warn if this is + * assigned to a different type. + */ +#ifdef NS_LIST_PTR_TYPE_ +#define NS_LIST_TYPECAST_(list, val) ((NS_LIST_PTR_TYPE_(list)) (val)) +#else +#define NS_LIST_TYPECAST_(list, val) (0 ? (list)->type : (val)) +#endif + +/** \brief Internal macro to check types of input entry pointer. */ +#define NS_LIST_TYPECHECK_(list, entry) \ + (NS_PTR_MATCH_((list)->type, (entry), "incorrect entry type for list"), (entry)) + +/** \brief Type used to pass link offset to underlying functions + * + * We could use size_t, but it would be unnecessarily large on 8-bit systems, + * where we can be (pretty) confident we won't have next pointers more than + * 256 bytes into a structure. + */ +typedef uint_fast8_t ns_list_offset_t; + +/// \publicsection +/** \brief The type for the link member in the user's entry structure. + * + * Users should not access this member directly - just pass its name to the + * list head macros. The funny prev pointer simplifies common operations + * (eg insertion, removal), at the expense of complicating rare reverse iteration. + * + * NB - the list implementation relies on next being the first member. + */ +typedef struct ns_list_link { + void *next; ///< Pointer to next entry, or NULL if none + void **prev; ///< Pointer to previous entry's (or head's) next pointer +} ns_list_link_t; + +/** \brief "Poison" value placed in unattached entries' link pointers. + * \internal What are good values for this? Platform dependent, maybe just NULL + */ +#define NS_LIST_POISON ((void *) 0xDEADBEEF) + +/** \brief Initialiser for an entry's link member + * + * This initialiser is not required by the library, but a user may want an + * initialiser to include in their own entry initialiser. See + * ns_list_link_init() for more discussion. + */ +#define NS_LIST_LINK_INIT(name) \ + NS_FUNNY_INTPTR_OK \ + { NS_LIST_POISON, NS_LIST_POISON } \ + NS_FUNNY_INTPTR_RESTORE + +/** \hideinitializer \brief Initialise an entry's list link + * + * This "initialises" an unattached entry's link by filling the fields with + * poison. This is optional, as unattached entries field pointers are not + * meaningful, and it is not valid to call ns_list_get_next or similar on + * an unattached entry. + * + * \param entry Pointer to an entry + * \param field The name of the link member to initialise + */ +#define ns_list_link_init(entry, field) ns_list_link_init_(&(entry)->field) + +/** \hideinitializer \brief Initialise a list + * + * Initialise a list head before use. A list head must be initialised using this + * function or one of the NS_LIST_INIT()-type macros before use. A zero-initialised + * list head is *not* valid. + * + * If used on a list containing existing entries, those entries will + * become detached. (They are not modified, but their links are now effectively + * undefined). + * + * \param list Pointer to a NS_LIST_HEAD() structure. + */ +#define ns_list_init(list) ns_list_init_(&(list)->slist) + +/** \brief Initialiser for an empty list + * + * Usage in an enclosing initialiser: + * ~~~ + * static my_type_including_list_t x = { + * "Something", + * 23, + * NS_LIST_INIT(x), + * }; + * ~~~ + * NS_LIST_DEFINE() or NS_LIST_NAME_INIT() may provide a shorter alternative + * in simpler cases. + */ +#define NS_LIST_INIT(name) { { NULL, &(name).slist.first_entry } } + +/** \brief Name and initialiser for an empty list + * + * Usage: + * ~~~ + * list_t NS_LIST_NAME_INIT(foo); + * ~~~ + * acts as + * ~~~ + * list_t foo = { empty list }; + * ~~~ + * Also useful with designated initialisers: + * ~~~ + * .NS_LIST_NAME_INIT(foo), + * ~~~ + * acts as + * ~~~ + * .foo = { empty list }, + * ~~~ + */ +#define NS_LIST_NAME_INIT(name) name = NS_LIST_INIT(name) + +/** \brief Define a list, and initialise to empty. + * + * Usage: + * ~~~ + * static NS_LIST_DEFINE(my_list, entry_t, link); + * ~~~ + * acts as + * ~~~ + * static list_type my_list = { empty list }; + * ~~~ + */ +#define NS_LIST_DEFINE(name, type, field) \ + NS_LIST_HEAD(type, field) NS_LIST_NAME_INIT(name) + +/** \hideinitializer \brief Add an entry to the start of the linked list. + * + * ns_list_add_to_end() is *slightly* more efficient than ns_list_add_to_start(). + * + * \param list `(list_t *)` Pointer to list. + * \param entry `(entry_t * restrict)` Pointer to new entry to add. + */ +#define ns_list_add_to_start(list, entry) \ + ns_list_add_to_start_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry)) + +/** \hideinitializer \brief Add an entry to the end of the linked list. + * + * \param list `(list_t *)` Pointer to list. + * \param entry `(entry_t * restrict)` Pointer to new entry to add. + */ +#define ns_list_add_to_end(list, entry) \ + ns_list_add_to_end_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry)) + +/** \hideinitializer \brief Add an entry before a specified entry. + * + * \param list `(list_t *)` Pointer to list. + * \param before `(entry_t *)` Existing entry before which to place the new entry. + * \param entry `(entry_t * restrict)` Pointer to new entry to add. + */ +#define ns_list_add_before(list, before, entry) \ + ns_list_add_before_(NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, before), NS_LIST_TYPECHECK_(list, entry)) + +/** \hideinitializer \brief Add an entry after a specified entry. + * + * ns_list_add_before() is *slightly* more efficient than ns_list_add_after(). + * + * \param list `(list_t *)` Pointer to list. + * \param after `(entry_t *)` Existing entry after which to place the new entry. + * \param entry `(entry_t * restrict)` Pointer to new entry to add. + */ +#define ns_list_add_after(list, after, entry) \ + ns_list_add_after_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, after), NS_LIST_TYPECHECK_(list, entry)) + +/** \brief Check if a list is empty. + * + * \param list `(const list_t *)` Pointer to list. + * + * \return `(bool)` true if the list is empty. + */ +#define ns_list_is_empty(list) ((bool) ((list)->slist.first_entry == NULL)) + +/** \brief Get the first entry. + * + * \param list `(const list_t *)` Pointer to list. + * + * \return `(entry_t *)` Pointer to first entry. + * \return NULL if list is empty. + */ +#define ns_list_get_first(list) NS_LIST_TYPECAST_(list, (list)->slist.first_entry) + +/** \hideinitializer \brief Get the previous entry. + * + * \param list `(const list_t *)` Pointer to list. + * \param current `(const entry_t *)` Pointer to current entry. + * + * \return `(entry_t *)` Pointer to previous entry. + * \return NULL if current entry is first. + */ +#define ns_list_get_previous(list, current) \ + NS_LIST_TYPECAST_(list, ns_list_get_previous_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current))) + +/** \hideinitializer \brief Get the next entry. + * + * \param list `(const list_t *)` Pointer to list. + * \param current `(const entry_t *)` Pointer to current entry. + * + * \return `(entry_t *)` Pointer to next entry. + * \return NULL if current entry is last. + */ +#define ns_list_get_next(list, current) \ + NS_LIST_TYPECAST_(list, ns_list_get_next_(NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current))) + +/** \hideinitializer \brief Get the last entry. + * + * \param list `(const list_t *)` Pointer to list. + * + * \return `(entry_t *)` Pointer to last entry. + * \return NULL if list is empty. + */ +#define ns_list_get_last(list) \ + NS_LIST_TYPECAST_(list, ns_list_get_last_(&(list)->slist, NS_LIST_OFFSET_(list))) + +/** \hideinitializer \brief Remove an entry. + * + * \param list `(list_t *)` Pointer to list. + * \param entry `(entry_t *)` Entry on list to be removed. + */ +#define ns_list_remove(list, entry) \ + ns_list_remove_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry)) + +/** \hideinitializer \brief Replace an entry. + * + * \param list `(list_t *)` Pointer to list. + * \param current `(entry_t *)` Existing entry on list to be replaced. + * \param replacement `(entry_t * restrict)` New entry to be the replacement. + */ +#define ns_list_replace(list, current, replacement) \ + ns_list_replace_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current), NS_LIST_TYPECHECK_(list, replacement)) + +/** \hideinitializer \brief Concatenate two lists. + * + * Attach the entries on the source list to the end of the destination + * list, leaving the source list empty. + * + * \param dst `(list_t *)` Pointer to destination list. + * \param src `(list_t *)` Pointer to source list. + * + */ +#define ns_list_concatenate(dst, src) \ + (NS_PTR_MATCH_(dst, src, "concatenating different list types"), \ + ns_list_concatenate_(&(dst)->slist, &(src)->slist, NS_LIST_OFFSET_(src))) + +/** \brief Iterate forwards over a list. + * + * Example: + * ~~~ + * ns_list_foreach(const my_entry_t, cur, &my_list) + * { + * printf("%s\n", cur->name); + * } + * ~~~ + * Deletion of the current entry is not permitted as its next is checked after + * running user code. + * + * The iteration pointer is declared inside the loop, using C99/C++, so it + * is not accessible after the loop. This encourages good code style, and + * matches the semantics of C++11's "ranged for", which only provides the + * declaration form: + * ~~~ + * for (const my_entry_t cur : my_list) + * ~~~ + * If you need to see the value of the iteration pointer after a `break`, + * you will need to assign it to a variable declared outside the loop before + * breaking: + * ~~~ + * my_entry_t *match = NULL; + * ns_list_foreach(my_entry_t, cur, &my_list) + * { + * if (cur->id == id) + * { + * match = cur; + * break; + * } + * } + * ~~~ + * + * The user has to specify the entry type for the pointer definition, as type + * extraction from the list argument isn't portable. On the other hand, this + * also permits const qualifiers, as in the example above, and serves as + * documentation. The entry type will be checked against the list type where the + * compiler supports it. + * + * \param type Entry type `([const] entry_t)`. + * \param e Name for iteration pointer to be defined + * inside the loop. + * \param list `(const list_t *)` Pointer to list - evaluated multiple times. + */ +#define ns_list_foreach(type, e, list) \ + for (type *e = ns_list_get_first(list); e; e = ns_list_get_next(list, e)) + +/** \brief Iterate forwards over a list, where user may delete. + * + * As ns_list_foreach(), but deletion of current entry is permitted as its + * next pointer is recorded before running user code. + * + * Example: + * ~~~ + * ns_list_foreach_safe(my_entry_t, cur, &my_list) + * { + * ns_list_remove(cur); + * } + * ~~~ + * \param type Entry type `(entry_t)`. + * \param e Name for iteration pointer to be defined + * inside the loop. + * \param list `(list_t *)` Pointer to list - evaluated multiple times. + */ +#define ns_list_foreach_safe(type, e, list) \ + for (type *e = ns_list_get_first(list), *_next##e; \ + e && (_next##e = ns_list_get_next(list, e), true); e = _next##e) + +/** \brief Iterate backwards over a list. + * + * As ns_list_foreach(), but going backwards - see its documentation. + * Iterating forwards is *slightly* more efficient. + */ +#define ns_list_foreach_reverse(type, e, list) \ + for (type *e = ns_list_get_last(list); e; e = ns_list_get_previous(list, e)) + +/** \brief Iterate backwards over a list, where user may delete. + * + * As ns_list_foreach_safe(), but going backwards - see its documentation. + * Iterating forwards is *slightly* more efficient. + */ +#define ns_list_foreach_reverse_safe(type, e, list) \ + for (type *e = ns_list_get_last(list), *_next##e; \ + e && (_next##e = ns_list_get_previous(list, e), true); e = _next##e) + +/** \hideinitializer \brief Count entries on a list + * + * Unlike other operations, this is O(n). Note: if list might contain over + * 65535 entries, this function **must not** be used to get the entry count. + * + * \param list `(const list_t *)` Pointer to list. + + * \return `(uint_fast16_t)` Number of entries that are stored in list. + */ +#define ns_list_count(list) ns_list_count_(&(list)->slist, NS_LIST_OFFSET_(list)) + +/** \privatesection + * Internal functions - designed to be accessed using corresponding macros above + */ +NS_INLINE void ns_list_init_(ns_list_t *list); +NS_INLINE void ns_list_link_init_(ns_list_link_t *link); +NS_INLINE void ns_list_add_to_start_(ns_list_t *list, ns_list_offset_t link_offset, void *restrict entry); +NS_INLINE void ns_list_add_to_end_(ns_list_t *list, ns_list_offset_t link_offset, void *restrict entry); +NS_INLINE void ns_list_add_before_(ns_list_offset_t link_offset, void *before, void *restrict entry); +NS_INLINE void ns_list_add_after_(ns_list_t *list, ns_list_offset_t link_offset, void *after, void *restrict entry); +NS_INLINE void *ns_list_get_next_(ns_list_offset_t link_offset, const void *current); +NS_INLINE void *ns_list_get_previous_(const ns_list_t *list, ns_list_offset_t link_offset, const void *current); +NS_INLINE void *ns_list_get_last_(const ns_list_t *list, ns_list_offset_t offset); +NS_INLINE void ns_list_remove_(ns_list_t *list, ns_list_offset_t link_offset, void *entry); +NS_INLINE void ns_list_replace_(ns_list_t *list, ns_list_offset_t link_offset, void *current, void *restrict replacement); +NS_INLINE void ns_list_concatenate_(ns_list_t *dst, ns_list_t *src, ns_list_offset_t offset); +NS_INLINE uint_fast16_t ns_list_count_(const ns_list_t *list, ns_list_offset_t link_offset); + +/* Provide definitions, either for inlining, or for ns_list.c */ +#if defined NS_ALLOW_INLINING || defined NS_LIST_FN +#ifndef NS_LIST_FN +#define NS_LIST_FN NS_INLINE +#endif + +/* Pointer to the link member in entry e */ +#define NS_LIST_LINK_(e, offset) ((ns_list_link_t *)((char *)(e) + offset)) + +/* Lvalue of the next link pointer in entry e */ +#define NS_LIST_NEXT_(e, offset) (NS_LIST_LINK_(e, offset)->next) + +/* Lvalue of the prev link pointer in entry e */ +#define NS_LIST_PREV_(e, offset) (NS_LIST_LINK_(e, offset)->prev) + +/* Convert a pointer to a link member back to the entry; + * works for linkptr either being a ns_list_link_t pointer, or its next pointer, + * as the next pointer is first in the ns_list_link_t */ +#define NS_LIST_ENTRY_(linkptr, offset) ((void *)((char *)(linkptr) - offset)) + +NS_LIST_FN void ns_list_init_(ns_list_t *list) +{ + list->first_entry = NULL; + list->last_nextptr = &list->first_entry; +} + +NS_LIST_FN void ns_list_link_init_(ns_list_link_t *link) +{ + NS_FUNNY_INTPTR_OK + link->next = NS_LIST_POISON; + link->prev = NS_LIST_POISON; + NS_FUNNY_INTPTR_RESTORE +} + +NS_LIST_FN void ns_list_add_to_start_(ns_list_t *list, ns_list_offset_t offset, void *restrict entry) +{ + void *next; + + NS_LIST_PREV_(entry, offset) = &list->first_entry; + NS_LIST_NEXT_(entry, offset) = next = list->first_entry; + + if (next) { + NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(entry, offset); + } else { + list->last_nextptr = &NS_LIST_NEXT_(entry, offset); + } + + list->first_entry = entry; +} + +NS_LIST_FN void ns_list_add_after_(ns_list_t *list, ns_list_offset_t offset, void *current, void *restrict entry) +{ + void *next; + + NS_LIST_PREV_(entry, offset) = &NS_LIST_NEXT_(current, offset); + NS_LIST_NEXT_(entry, offset) = next = NS_LIST_NEXT_(current, offset); + + if (next) { + NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(entry, offset); + } else { + list->last_nextptr = &NS_LIST_NEXT_(entry, offset); + } + + NS_LIST_NEXT_(current, offset) = entry; +} + +NS_LIST_FN void ns_list_add_before_(ns_list_offset_t offset, void *current, void *restrict entry) +{ + void **prev_nextptr; + + NS_LIST_NEXT_(entry, offset) = current; + NS_LIST_PREV_(entry, offset) = prev_nextptr = NS_LIST_PREV_(current, offset); + *prev_nextptr = entry; + NS_LIST_PREV_(current, offset) = &NS_LIST_NEXT_(entry, offset); +} + +NS_LIST_FN void ns_list_add_to_end_(ns_list_t *list, ns_list_offset_t offset, void *restrict entry) +{ + void **prev_nextptr; + + NS_LIST_NEXT_(entry, offset) = NULL; + NS_LIST_PREV_(entry, offset) = prev_nextptr = list->last_nextptr; + *prev_nextptr = entry; + list->last_nextptr = &NS_LIST_NEXT_(entry, offset); +} + +NS_LIST_FN void *ns_list_get_next_(ns_list_offset_t offset, const void *current) +{ + return NS_LIST_NEXT_(current, offset); +} + +NS_LIST_FN void *ns_list_get_previous_(const ns_list_t *list, ns_list_offset_t offset, const void *current) +{ + if (current == list->first_entry) { + return NULL; + } + + // Tricky. We don't have a direct previous pointer, but a pointer to the + // pointer that points to us - ie &head->first_entry OR &{prev}->next. + // This makes life easier on insertion and removal, but this is where we + // pay the price. + + // We have to check manually for being the first entry above, so we know it's + // a real link's next pointer. Then next is the first field of + // ns_list_link_t, so we can use the normal offset value. + + return NS_LIST_ENTRY_(NS_LIST_PREV_(current, offset), offset); +} + +NS_LIST_FN void *ns_list_get_last_(const ns_list_t *list, ns_list_offset_t offset) +{ + if (!list->first_entry) { + return NULL; + } + + // See comments in ns_list_get_previous_() + return NS_LIST_ENTRY_(list->last_nextptr, offset); +} + +NS_LIST_FN void ns_list_remove_(ns_list_t *list, ns_list_offset_t offset, void *removed) +{ + void *next; + void **prev_nextptr; + + next = NS_LIST_NEXT_(removed, offset); + prev_nextptr = NS_LIST_PREV_(removed, offset); + if (next) { + NS_LIST_PREV_(next, offset) = prev_nextptr; + } else { + list->last_nextptr = prev_nextptr; + } + *prev_nextptr = next; + + ns_list_link_init_(NS_LIST_LINK_(removed, offset)); +} + +NS_LIST_FN void ns_list_replace_(ns_list_t *list, ns_list_offset_t offset, void *current, void *restrict replacement) +{ + void *next; + void **prev_nextptr; + + NS_LIST_PREV_(replacement, offset) = prev_nextptr = NS_LIST_PREV_(current, offset); + NS_LIST_NEXT_(replacement, offset) = next = NS_LIST_NEXT_(current, offset); + + if (next) { + NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(replacement, offset); + } else { + list->last_nextptr = &NS_LIST_NEXT_(replacement, offset); + } + *prev_nextptr = replacement; + + ns_list_link_init_(NS_LIST_LINK_(current, offset)); +} + +NS_LIST_FN void ns_list_concatenate_(ns_list_t *dst, ns_list_t *src, ns_list_offset_t offset) +{ + ns_list_link_t *src_first; + + src_first = src->first_entry; + if (!src_first) { + return; + } + + *dst->last_nextptr = src_first; + NS_LIST_PREV_(src_first, offset) = dst->last_nextptr; + dst->last_nextptr = src->last_nextptr; + + ns_list_init_(src); +} + +NS_LIST_FN uint_fast16_t ns_list_count_(const ns_list_t *list, ns_list_offset_t offset) +{ + uint_fast16_t count = 0; + + for (void *p = list->first_entry; p; p = NS_LIST_NEXT_(p, offset)) { + count++; + } + + return count; +} +#endif /* defined NS_ALLOW_INLINING || defined NS_LIST_FN */ + +#ifdef __cplusplus +} +#endif + +#endif /* NS_LIST_H_ */ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ns_nvm_helper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ns_nvm_helper.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,100 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +/** + * NanoStack NVM helper functions to read, write and delete key-value pairs to platform NVM. + * + * Client can use following methods: + * -ns_nvm_data_write to write data to a key in platform NVM + * -ns_nvm_data_read to read data from key in platform NVM + * -ns_nvm_key_delete to delete a key from platform NVM + * + * If a API call returns NS_NVM_OK then a provided callback function will be called + * and status argument indicates success or failure of the operation. If API call + * returns error then callback will not be called. + * + * When client writes data this module will: + * -initialize the NVM if not already initialized + * -(re)create the key with a given size + * -write data to the key + * -flush data to the NVM + * + * When client reads data this module will: + * -initialize the NVM if not initialized + * -read data from the key + * + * When client deletes a key this module will: + * -initialize the NVM if not initialized + * -delete the key from NVM + */ + +/* + * API function and callback function return statuses + */ +#define NS_NVM_OK 0 +#define NS_NVM_DATA_NOT_FOUND -1 +#define NS_NVM_ERROR -2 +#define NS_NVM_MEMORY -3 + +/** + * callback type for NanoStack NVM + */ +typedef void (ns_nvm_callback)(int status, void *context); + +/** + * \brief Delete key from NVM + * + * \param callback function to be called when key deletion is ready + * \param key_name Name of the key to be deleted from NVM + * \param context argument will be provided as an argument when callback is called + * + * \return NS_NVM_OK if key deletion is in progress and callback will be called + * \return NS_NVM_ERROR in error case, callback will not be called + * \return provided callback function will be called with status indicating success or failure. + */ +int ns_nvm_key_delete(ns_nvm_callback *callback, const char *key_name, void *context); + +/** + * \brief Read data from NVM + * + * \param callback function to be called when data is read + * \param key_name Name of the key whose data will be read + * \param buf buffer where data will be stored + * \param buf_len address of variable containing provided buffer length + * \param context argument will be provided as an argument when callback is called + * + * \return NS_NVM_OK if read is in progress and callback will be called + * \return NS_NVM_ERROR in error case, callback will not be called + * \return provided callback function will be called with status indicating success or failure. + */ +int ns_nvm_data_read(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context); + +/** + * \brief Write data to NVM + * + * \param callback function to be called when data writing is completed + * \param key_name Name of the key whose data will be read + * \param buf buffer where data will be stored + * \param buf_len address of variable containing provided buffer length + * \param context argument will be provided as an argument when callback is called + * + * \return NS_NVM_OK if read is in progress and callback will be called + * \return NS_NVM_ERROR in error case, callback will not be called + * \return provided callback function will be called with status indicating success or failure. + */ +int ns_nvm_data_write(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context);
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ns_trace.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ns_trace.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015-2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file ns_trace.h + * Trace interface abstraction for NanoStack library as well as application. + * + * Actual used trace library is mbed-trace. For usage details check mbed_trace.h. + * + */ +#ifndef NS_TRACE_H_ +#define NS_TRACE_H_ + +#if defined(HAVE_DEBUG) && !defined(FEA_TRACE_SUPPORT) +#define FEA_TRACE_SUPPORT +#endif + +#include "mbed-trace/mbed_trace.h" + +#endif /* NS_TRACE_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ns_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/ns_types.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * ns_types.h - Basic compiler and type setup for Nanostack libraries. + */ +#ifndef NS_TYPES_H_ +#define NS_TYPES_H_ + +/** \file + * \brief Basic compiler and type setup + * + * We currently assume C99 or later. + * + * C99 features being relied on: + * + * - <inttypes.h> and <stdbool.h> + * - inline (with C99 semantics, not C++ as per default GCC); + * - designated initialisers; + * - compound literals; + * - restrict; + * - [static N] in array parameters; + * - declarations in for statements; + * - mixing declarations and statements + * + * Compilers should be set to C99 or later mode when building Nanomesh source. + * For GCC this means "-std=gnu99" (C99 with usual GNU extensions). + * + * Also, a little extra care is required for public header files that could be + * included from C++, especially as C++ lacks some C99 features. + * + * (TODO: as this is exposed to API users, do we need a predefine to distinguish + * internal and external use, for finer control? Not yet, but maybe...) + */ + +/* Make sure <stdint.h> defines its macros if C++ */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif + +#include <stddef.h> +#include <inttypes.h> // includes <stdint.h>; debugf() users need PRIu32 etc +#include <stdbool.h> + +/* + * Create the optional <stdint.h> 24-bit types if they don't exist (worth trying + * to use them, as they could exist and be more efficient than 32-bit on 8-bit + * systems...) + */ +#ifndef UINT_LEAST24_MAX +typedef uint_least32_t uint_least24_t; +#define UINT_LEAST24_MAX UINT_LEAST32_MAX +#define UINT24_C(x) UINT32_C(x) +#define PRIoLEAST24 PRIoLEAST32 +#define PRIuLEAST24 PRIuLEAST32 +#define PRIxLEAST24 PRIxLEAST32 +#define PRIXLEAST24 PRIXLEAST32 +#endif + +#ifndef INT_LEAST24_MAX +typedef int_least32_t int_least24_t; +#define INT_LEAST24_MIN INT_LEAST32_MIN +#define INT_LEAST24_MAX INT_LEAST32_MAX +#define INT24_C(x) INT32_C(x) +#define PRIdLEAST24 PRIdLEAST32 +#define PRIiLEAST24 PRIiLEAST32 +#endif + +#ifndef UINT_FAST24_MAX +typedef uint_fast32_t uint_fast24_t; +#define UINT_FAST24_MAX UINT_FAST32_MAX +#define PRIoFAST24 PRIoFAST32 +#define PRIuFAST24 PRIuFAST32 +#define PRIxFAST24 PRIxFAST32 +#define PRIXFAST24 PRIXFAST32 +#endif + +#ifndef INT_FAST24_MAX +typedef int_fast32_t int_fast24_t; +#define INT_FAST24_MIN INT_FAST32_MIN +#define INT_FAST24_MAX INT_FAST32_MAX +#define PRIdFAST24 PRIdFAST32 +#define PRIiFAST24 PRIiFAST32 +#endif + +/* Function attribute - C11 "noreturn" or C++11 "[[noreturn]]" */ +#ifndef NS_NORETURN +#if defined __cplusplus && __cplusplus >= 201103L +#define NS_NORETURN [[noreturn]] +#elif !defined __cplusplus && __STDC_VERSION__ >= 201112L +#define NS_NORETURN _Noreturn +#elif defined __GNUC__ +#define NS_NORETURN __attribute__((__noreturn__)) +#elif defined __CC_ARM +#define NS_NORETURN __declspec(noreturn) +#elif defined __IAR_SYSTEMS_ICC__ +#define NS_NORETURN __noreturn +#else +#define NS_NORETURN +#endif +#endif + +/* C11's "alignas" macro, emulated for integer expressions if necessary */ +#ifndef __alignas_is_defined +#if defined __CC_ARM || defined __TASKING__ +#define alignas(n) __align(n) +#define __alignas_is_defined 1 +#elif (__STDC_VERSION__ >= 201112L) || (defined __cplusplus && __cplusplus >= 201103L) +#include <stdalign.h> +#elif defined __GNUC__ +#define alignas(n) __attribute__((__aligned__(n))) +#define __alignas_is_defined 1 +#elif defined __IAR_SYSTEMS_ICC__ +/* Does this really just apply to the next variable? */ +#define alignas(n) __Alignas(data_alignment=n) +#define __Alignas(x) _Pragma(#x) +#define __alignas_is_defined 1 +#endif +#endif + +/** + * Marker for functions or objects that may be unused, suppressing warnings. + * Place after the identifier: + * ~~~ + * static int X MAYBE_UNUSED = 3; + * static int foo(void) MAYBE_UNUSED; + * ~~~ + */ +#if defined __CC_ARM || defined __GNUC__ +#define MAYBE_UNUSED __attribute__((unused)) +#else +#define MAYBE_UNUSED +#endif + +/* + * C++ (even C++11) doesn't provide restrict: define away or provide + * alternative. + */ +#ifdef __cplusplus +#ifdef __GNUC__ +#define restrict __restrict +#else +#define restrict +#endif +#endif /* __cplusplus */ + + +/** + * C++ doesn't allow "static" in function parameter types: ie + * ~~~ + * entry_t *find_entry(const uint8_t address[static 16]) + * ~~~ + * If a header file may be included from C++, use this __static define instead. + * + * (Syntax introduced in C99 - `uint8_t address[16]` in a prototype was always + * equivalent to `uint8_t *address`, but the C99 addition of static tells the + * compiler that address is never NULL, and always points to at least 16 + * elements. This adds no new type-checking, but the information could aid + * compiler optimisation, and it can serve as documentation). + */ +#ifdef __cplusplus +#define __static +#else +#define __static static +#endif + +#ifdef __GNUC__ +#define NS_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#endif + +/** \brief Compile-time assertion + * + * C11 provides _Static_assert, as does GCC even in C99 mode (and + * as a freestanding implementation, we can't rely on <assert.h> to get + * the static_assert macro). + * C++11 provides static_assert as a keyword, as does G++ in C++0x mode. + * + * The assertion acts as a declaration that can be placed at file scope, in a + * code block (except after a label), or as a member of a struct/union. It + * produces a compiler error if "test" evaluates to 0. + * + * Note that this *includes* the required semicolon when defined, else it + * is totally empty, permitting use in structs. (If the user provided the `;`, + * it would leave an illegal stray `;` if unavailable). + */ +#ifdef __cplusplus +# if __cplusplus >= 201103L || __cpp_static_assert >= 200410 +# define NS_STATIC_ASSERT(test, str) static_assert(test, str); +# elif defined __GXX_EXPERIMENTAL_CXX0X__ && NS_GCC_VERSION >= 40300 +# define NS_STATIC_ASSERT(test, str) __extension__ static_assert(test, str); +# else +# define NS_STATIC_ASSERT(test, str) +# endif +#else /* C */ +# if __STDC_VERSION__ >= 201112L +# define NS_STATIC_ASSERT(test, str) _Static_assert(test, str); +# elif defined __GNUC__ && NS_GCC_VERSION >= 40600 && !defined __CC_ARM +# ifdef _Static_assert + /* + * Some versions of glibc cdefs.h (which comes in via <stdint.h> above) + * attempt to define their own _Static_assert (if GCC < 4.6 or + * __STRICT_ANSI__) using an extern declaration, which doesn't work in a + * struct/union. + * + * For GCC >= 4.6 and __STRICT_ANSI__, we can do better - just use + * the built-in _Static_assert with __extension__. We have to do this, as + * ns_list.h needs to use it in a union. No way to get at it though, without + * overriding their define. + */ +# undef _Static_assert +# define _Static_assert(x, y) __extension__ _Static_assert(x, y) +# endif +# define NS_STATIC_ASSERT(test, str) __extension__ _Static_assert(test, str); +# else +# define NS_STATIC_ASSERT(test, str) +#endif +#endif + +/** \brief Pragma to suppress warnings about unusual pointer values. + * + * Useful if using "poison" values. + */ +#ifdef __IAR_SYSTEMS_ICC__ +#define NS_FUNNY_INTPTR_OK _Pragma("diag_suppress=Pe1053") +#define NS_FUNNY_INTPTR_RESTORE _Pragma("diag_default=Pe1053") +#else +#define NS_FUNNY_INTPTR_OK +#define NS_FUNNY_INTPTR_RESTORE +#endif + +/** \brief Pragma to suppress warnings about always true/false comparisons + */ +#if defined __GNUC__ && NS_GCC_VERSION >= 40600 && !defined __CC_ARM +#define NS_FUNNY_COMPARE_OK _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") +#define NS_FUNNY_COMPARE_RESTORE _Pragma("GCC diagnostic pop") +#else +#define NS_FUNNY_COMPARE_OK +#define NS_FUNNY_COMPARE_RESTORE +#endif + +/** \brief Pragma to suppress warnings arising from dummy definitions. + * + * Useful when you have function-like macros that returning constants + * in cut-down builds. Can be fairly cavalier about disabling as we + * do not expect every build to use this macro. Generic builds of + * components should ensure this is not included by only using it in + * a ifdef blocks providing dummy definitions. + */ +#ifdef __CC_ARM +// statement is unreachable(111), controlling expression is constant(236), expression has no effect(174), +// function was declared but never referenced(177), variable was set but never used(550) +#define NS_DUMMY_DEFINITIONS_OK _Pragma("diag_suppress=111,236,174,177,550") +#elif defined __IAR_SYSTEMS_ICC__ +// controlling expression is constant +#define NS_DUMMY_DEFINITIONS_OK _Pragma("diag_suppress=Pe236") +#else +#define NS_DUMMY_DEFINITIONS_OK +#endif + +/** \brief Convert pointer to member to pointer to containing structure */ +#define NS_CONTAINER_OF(ptr, type, member) \ + ((type *) ((char *) (ptr) - offsetof(type, member))) + +/* + * Inlining could cause problems when mixing with C++; provide a mechanism to + * disable it. This could also be turned off for other reasons (although + * this can usually be done through a compiler flag, eg -O0 on gcc). + */ +#ifndef __cplusplus +#define NS_ALLOW_INLINING +#endif + +/* There is inlining problem in GCC version 4.1.x and we know it works in 4.6.3 */ +#if defined __GNUC__ && NS_GCC_VERSION < 40600 +#undef NS_ALLOW_INLINING +#endif + +/** \brief Mark a potentially-inlineable function. + * + * We follow C99 semantics, which requires precisely one external definition. + * To also allow inlining to be totally bypassed under control of + * NS_ALLOW_INLINING, code can be structured as per the example of ns_list: + * + * foo.h + * ----- + * ~~~ + * NS_INLINE int my_func(int); + * + * #if defined NS_ALLOW_INLINING || defined FOO_FN + * #ifndef FOO_FN + * #define FOO_FN NS_INLINE + * #endif + * FOO_FN int my_func(int a) + * { + * definition; + * } + * #endif + * ~~~ + * foo.c + * ----- + * ~~~ + * #define FOO_FN extern + * #include "foo.h" + * ~~~ + * Which generates: + * ~~~ + * NS_ALLOW_INLINING set NS_ALLOW_INLINING unset + * ===================== ======================= + * Include foo.h Include foo.h + * ------------- ------------- + * inline int my_func(int); int my_func(int); + * + * // inline definition + * inline int my_func(int a) + * { + * definition; + * } + * + * Compile foo.c Compile foo.c + * ------------- ------------- + * (from .h) inline int my_func(int); int my_func(int); + * + * // external definition + * // because of no "inline" // normal external definition + * extern int my_func(int a) extern int my_func(int a) + * { { + * definition; definition; + * } } + * ~~~ + * + * Note that even with inline keywords, whether the compiler inlines or not is + * up to it. For example, gcc at "-O0" will not inline at all, and will always + * call the real functions in foo.o, just as if NS_ALLOW_INLINING was unset. + * At "-O2", gcc could potentially inline everything, meaning that foo.o is not + * referenced at all. + * + * Alternatively, you could use "static inline", which gives every caller its + * own internal definition. This is compatible with C++ inlining (which expects + * the linker to eliminate duplicates), but in C it's less efficient if the code + * ends up non-inlined, and it's harder to breakpoint. I don't recommend it + * except for the most trivial functions (which could then probably be macros). + */ +#ifdef NS_ALLOW_INLINING +#define NS_INLINE inline +#else +#define NS_INLINE +#endif + +#if defined __SDCC_mcs51 || defined __ICC8051__ || defined __C51__ + +/* The 8051 environments: SDCC (historic), IAR (current), Keil (future?) */ + +#define NS_LARGE __xdata +#define NS_LARGE_PTR __xdata +#ifdef __ICC8051__ +#define NS_REENTRANT +#define NS_REENTRANT_PREFIX __idata_reentrant +#else +#define NS_REENTRANT __reentrant +#define NS_REENTRANT_PREFIX +#endif +#define NS_NEAR_FUNC __near_func + +#else + +/* "Normal" systems. Define it all away. */ +#define NS_LARGE +#define NS_LARGE_PTR +#define NS_REENTRANT +#define NS_REENTRANT_PREFIX +#define NS_NEAR_FUNC + +#endif + +/** \brief Scatter-gather descriptor + * + * Slightly optimised for small platforms - we assume we won't need any + * element bigger than 64K. + */ +typedef struct ns_iovec { + void *iov_base; + uint_fast16_t iov_len; +} ns_iovec_t; + +#endif /* NS_TYPES_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/nsdynmemLIB.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/nsdynmemLIB.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014-2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * \file nsdynmemLIB.h + * \brief Dynamical Memory API for library model + * nsdynmemlib provides access to one default heap, along with the ability to use extra user heaps. + * ns_dyn_mem_alloc/free always access the default heap initialised by ns_dyn_mem_init. + * ns_mem_alloc/free access a user heap initialised by ns_mem_init. User heaps are identified by a book-keeping pointer. + */ + +#ifndef NSDYNMEMLIB_H_ +#define NSDYNMEMLIB_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include "ns_types.h" + +// Added to maintain backward compatibility with older implementation of ns_dyn_mem APIs +#define NSDYNMEMLIB_API_VERSION 2 + +typedef uint16_t ns_mem_block_size_t; //external interface unsigned heap block size type +typedef uint16_t ns_mem_heap_size_t; //total heap size type. + +/*! + * \enum heap_fail_t + * \brief Dynamically heap system failure call back event types. + */ +typedef enum { + NS_DYN_MEM_NULL_FREE, /**< ns_dyn_mem_free(), NULL pointer free [obsolete - no longer faulted] */ + NS_DYN_MEM_DOUBLE_FREE, /**< ns_dyn_mem_free(), Possible double pointer free */ + NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID, /**< Allocate size is 0 or smaller or size is bigger than max heap size */ + NS_DYN_MEM_POINTER_NOT_VALID, /**< ns_dyn_mem_free(), try to free pointer which not at heap sector */ + NS_DYN_MEM_HEAP_SECTOR_CORRUPTED, /**< Heap system detect sector corruption */ + NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED /**< ns_dyn_mem_free(), ns_dyn_mem_temporary_alloc() or ns_dyn_mem_alloc() called before ns_dyn_mem_init() */ +} heap_fail_t; + +/** + * /struct mem_stat_t + * /brief Struct for Memory stats Buffer structure + */ +typedef struct mem_stat_t { + /*Heap stats*/ + ns_mem_heap_size_t heap_sector_size; /**< Heap total Sector len. */ + ns_mem_heap_size_t heap_sector_alloc_cnt; /**< Reserved Heap sector cnt. */ + ns_mem_heap_size_t heap_sector_allocated_bytes; /**< Reserved Heap data in bytes. */ + ns_mem_heap_size_t heap_sector_allocated_bytes_max; /**< Reserved Heap data in bytes max value. */ + uint32_t heap_alloc_total_bytes; /**< Total Heap allocated bytes. */ + uint32_t heap_alloc_fail_cnt; /**< Counter for Heap allocation fail. */ +} mem_stat_t; + + +typedef struct ns_mem_book ns_mem_book_t; + +/** + * \brief Init and set Dynamical heap pointer and length. + * + * \param heap_ptr Pointer to dynamically heap buffer + * \param heap_size size of the heap buffer + * \return None + */ +extern void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr); + + +/** + * \brief Free allocated memory. + * + * \param heap_ptr Pointer to allocated memory + * + * \return 0, Free OK + * \return <0, Free Fail + */ +extern void ns_dyn_mem_free(void *heap_ptr); +/** + * \brief Allocate temporary data. + * + * Space allocate started from beginning of the heap sector + * + * \param alloc_size Allocated data size + * + * \return 0, Allocate Fail + * \return >0, Pointer to allocated data sector. + */ +extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size); +/** + * \brief Allocate long period data. + * + * Space allocate started from end of the heap sector + * + * \param alloc_size Allocated data size + * + * \return 0, Allocate Fail + * \return >0, Pointer to allocated data sector. + */ +extern void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size); + +/** + * \brief Get pointer to the current mem_stat_t set via ns_dyn_mem_init. + * + * Get pointer to the statistics information, if one is set during the + * initialization. This may be useful for statistics collection purposes. + * + * Note: the caller may not modify the returned structure. + * + * \return NULL, no mem_stat_t was given on initialization + * \return !=0, Pointer to mem_stat_t. + */ +extern const mem_stat_t *ns_dyn_mem_get_mem_stat(void); + +/** + * \brief Init and set Dynamical heap pointer and length. + * + * \param heap_ptr Pointer to dynamically heap buffer + * \param heap_size size of the heap buffer + * \return !=0, Pointer to ns_mem_book_t. + */ +extern ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr); + +/** + * \brief Free allocated memory. + * + * \param book Address of book keeping structure + * \param heap_ptr Pointer to allocated memory + * + * \return 0, Free OK + * \return <0, Free Fail + */ +extern void ns_mem_free(ns_mem_book_t *book, void *heap_ptr); +/** + * \brief Allocate temporary data. + * + * Space allocate started from beginning of the heap sector + * + * \param book Address of book keeping structure + * \param alloc_size Allocated data size + * + * \return 0, Allocate Fail + * \return >0, Pointer to allocated data sector. + */ +extern void *ns_mem_temporary_alloc(ns_mem_book_t *book, ns_mem_block_size_t alloc_size); +/** + * \brief Allocate long period data. + * + * Space allocate started from end of the heap sector + * + * \param book Address of book keeping structure + * \param alloc_size Allocated data size + * + * \return 0, Allocate Fail + * \return >0, Pointer to allocated data sector. + */ +extern void *ns_mem_alloc(ns_mem_book_t *book, ns_mem_block_size_t alloc_size); + +/** + * \brief Get pointer to the current mem_stat_t set via ns_mem_init. + * + * Get pointer to the statistics information, if one is set during the + * initialization. This may be useful for statistics collection purposes. + * + * Note: the caller may not modify the returned structure. + * + * \param book Address of book keeping structure + * + * \return NULL, no mem_stat_t was given on initialization + * \return !=0, Pointer to mem_stat_t. + */ +extern const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *book); + +#ifdef __cplusplus +} +#endif +#endif /* NSDYNMEMLIB_H_ */ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/platform/arm_hal_interrupt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/platform/arm_hal_interrupt.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ARM_HAL_API_H_ +#define ARM_HAL_API_H_ +#ifdef __cplusplus +extern "C" { +#endif +#include <stdint.h> + +/** + * \brief This function disable global interrupts. + */ +extern void platform_enter_critical(void); +/** + * \brief This function enable global interrupts. + */ +extern void platform_exit_critical(void); + +/** + * \brief This function increments the disable IRQ counter. + * The function must be called inside interrupt routines + * before any routine that uses platform_enter_critical() + * is called. + * + * This routine may not be need to do anything on some platforms, + * but requiring the call to be made before using + * platform_enter_critical() in an interrupt can simplify some + * implementations of platform_enter/exit_critical(). + */ +extern void platform_interrupts_disabled(void); + +/** + * \brief This function decrements the disable IRQ counter. + */ +extern void platform_interrupts_enabling(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ARM_HAL_API_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/platform/arm_hal_nvm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/mbed-client-libservice/platform/arm_hal_nvm.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2016 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Nanostack NVM API. + * + * After NVM initialization (platform_nvm_init(...)) a user can: + * -create key to the NVM by using method platform_nvm_key_create(...) + * -write data to the NVM by using method platform_nvm_write(...) + * -read data from the NVM by using method platform_nvm_read(...) + * -delete the created key by using platform_nvm_key_delete(...) + * -store changed data to the underlying backing store by using method platform_nvm_flush(...). + * + * This NVM API is asynchronous. If API function returns PLATFORM_NVM_OK then provided callback function will be + * called once operation is completed. Callback function carries status parameter that indicates status of the + * operation. If platform API function returns error code then callback will not be called. A new operation can not + * be started until the previous operation has completed. + * + */ + +#ifndef _PLATFORM_NVM_H_ +#define _PLATFORM_NVM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enumeration for nvm API function return values */ +typedef enum { + PLATFORM_NVM_OK, + PLATFORM_NVM_KEY_NOT_FOUND, + PLATFORM_NVM_ERROR +} platform_nvm_status; + +/** \brief Client registered API callback type. + * + * \param status operation completion status + * \param context client provided context that was used when requesting operation + */ +typedef void (nvm_callback)(platform_nvm_status status, void *context); + +/** \brief Initialize NVM. Allocates module static resources and initializes underlying NMV. + * + * \param callback callback function that will be called once initialization is completed. + * \param context A client registered context that will be supplied as an argument to the callback when called. + * + * \return NVM_OK if initialization is in progress and callback will be called. + * \return NVM_ERROR if initialization failed and callback will not be called. + */ +platform_nvm_status platform_nvm_init(nvm_callback *callback, void *context); + +/** \brief Free resources reserved by NVM init. + * + * \param callback callback function that will be called once deinitialization is completed. + * \param context A client registered context that will be supplied as an argument to the callback when called. + * + * \return NVM_OK if initialization is in progress and callback will be called. + * \return NVM_ERROR if initialization failed and callback will not be called. + */ +platform_nvm_status platform_nvm_finalize(nvm_callback *callback, void *context); + +/** \brief Create key to the NMV. If the key exists then the key will be recreated with new length. + * + * \param callback callback function that will be called once key creation is finished + * \param key_name name of the key to be created + * \param value_len length of data reserved for the key + * \param flags reserved for future use + * \param context A client registered context that will be supplied as an argument to the callback when called + * + * \return NVM_OK if key creation is in progress and callback will be called. + * \return NVM_ERROR if key creation failed and callback will not be called. + * \return Provided callback function will be called once operation is completed. + */ +platform_nvm_status platform_nvm_key_create(nvm_callback *callback, const char *key_name, uint16_t value_len, uint32_t flags, void *context); + +/** \brief Delete key from NMV. + * + * \param callback callback function that will be called once key creation is finished + * \param key_name name of the key to be deleted + * \param context A client registered context that will be supplied as an argument to the callback when called + * + * \return NVM_OK if key creation is in progress and callback will be called. + * \return NVM_ERROR if key creation failed and callback will not be called. + * \return Provided callback function will be called once operation is completed. + */ +platform_nvm_status platform_nvm_key_delete(nvm_callback *callback, const char *key_name, void *context); + +/** \brief Write data to the NVM. Data will be truncated if the key does not have enough space for the data. + * + * \param callback callback function that will be called once writing is complete + * \param key_name name of the key where data will be written + * \param data buffer to data to be write. Data must be valid until callback is called. + * \param data_len [IN] length of data in bytes. [OUT] number of bytes written. Argument must be valid until a callback is called. + * \param context A client registered context that will be supplied as an argument to the callback when called. + * + * \return NVM_OK if data writing is in progress and callback will be called. + * \return NVM_ERROR if data writing failed and callback will not be called. + * \return Provided callback function will be called once operation is completed. + */ +platform_nvm_status platform_nvm_write(nvm_callback *callback, const char *key_name, const void *data, uint16_t *data_len, void *context); + +/** \brief Read key value from the NVM. + * + * \param callback callback function that will be called once reading is complete + * \param key_name name of the key whose data will be read + * \param buf buffer where data will be copied. Argument must be valid until a callback is called. + * \param buf_len [IN] provided buffer length in bytes. [OUT] bytes read. Argument must be valid until callback is called. + * \param context A client registered context that will be supplied as an argument to the callback when called. + * + * \return NVM_OK if data reading is in progress and callback will be called. + * \return NVM_ERROR if data reading failed and callback will not be called. + * \return Provided callback function will be called once operation is completed. + */ +platform_nvm_status platform_nvm_read(nvm_callback *callback, const char *key_name, void *buf, uint16_t *buf_len, void *context); + +/** \brief Store changed data to the backing store. This operation will write changed data to SRAM/Flash. + * + * \param callback callback function that will be called once flushing is complete + * \param context A client registered context that will be supplied as an argument to the callback when called. + * + * \return NVM_OK if data flushing is in progress and callback will be called. + * \return NVM_ERROR if data flushing failed and callback will not be called. + * \return Provided callback function will be called once operation is completed. + */ +platform_nvm_status platform_nvm_flush(nvm_callback *callback, void *context); + +#ifdef __cplusplus +} +#endif +#endif /* _PLATFORM_NVM_H_ */ +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/IPv6_fcf_lib/ip_fsc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/IPv6_fcf_lib/ip_fsc.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "stdint.h" +#include "ip_fsc.h" + +/** \brief Compute IP checksum for arbitary data + * + * Compute an IP checksum, given a arbitrary gather list. + * + * See ipv6_fcf for discussion of use. + * + * This will work for any arbitrary gather list - it can handle odd + * alignments. The one limitation is that the 32-bit accumulator limits + * it to basically 64K of total data. + */ +uint16_t ip_fcf_v(uint_fast8_t count, const ns_iovec_t vec[static count]) +{ + uint_fast32_t acc32 = 0; + bool odd = false; + while (count) { + const uint8_t *data_ptr = vec->iov_base; + uint_fast16_t data_length = vec->iov_len; + if (odd && data_length > 0) { + acc32 += *data_ptr++; + data_length--; + odd = false; + } + while (data_length >= 2) { + acc32 += (uint_fast16_t) data_ptr[0] << 8 | data_ptr[1]; + data_ptr += 2; + data_length -= 2; + } + if (data_length) { + acc32 += (uint_fast16_t) data_ptr[0] << 8; + odd = true; + } + vec++; + count--; + } + + // Fold down up to 0xffff carries in the 32-bit accumulator + acc32 = (acc32 >> 16) + (acc32 & 0xffff); + + // Could be one more carry from the previous addition (result <= 0x1fffe) + uint16_t sum16 = (uint16_t)((acc32 >> 16) + (acc32 & 0xffff)); + return ~sum16; +} + +/** \brief Compute IPv6 checksum + * + * Compute an IPv6 checksum, given fields of an IPv6 pseudoheader and payload. + * + * This returns the 1's-complement of the checksum, as required when + * generating the checksum for transmission. The result can be 0x0000; + * for UDP (only) this must be transformed to 0xFFFF to distinguish from + * a packet with no checksum. + * + * To check a packet, this function will return 0 when run on a + * packet with a valid checksum. Checksums should be checked like this rather + * than setting the checksum field to zero and comparing generated checksum with + * the original value - this would fail in the case the received packet had + * checksum 0xFFFF. + */ +uint16_t ipv6_fcf(const uint8_t src_address[static 16], const uint8_t dest_address[static 16], + uint16_t data_length, const uint8_t data_ptr[static data_length], uint8_t next_protocol) +{ + // Use gather vector to lay out IPv6 pseudo-header (RFC 2460) and data + uint8_t hdr_data[] = { data_length >> 8, data_length, 0, next_protocol }; + ns_iovec_t vec[4] = { + { (void *) src_address, 16 }, + { (void *) dest_address, 16 }, + { hdr_data, 4 }, + { (void *) data_ptr, data_length } + }; + + return ip_fcf_v(4, vec); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/libBits/common_functions.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/libBits/common_functions.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Most functions can be inlined, and definitions are in common_functions.h. + * Define COMMON_FUNCTIONS_FN before including it to generate external definitions. + */ +#define COMMON_FUNCTIONS_FN extern + +#include "common_functions.h" + +#include <string.h> + +/* Returns mask for <split_value> (0-8) most-significant bits of a byte */ +static inline uint8_t context_split_mask(uint_fast8_t split_value) +{ + return (uint8_t) - (0x100u >> split_value); +} + +bool bitsequal(const uint8_t *a, const uint8_t *b, uint_fast8_t bits) +{ + uint_fast8_t bytes = bits / 8; + bits %= 8; + + if (memcmp(a, b, bytes)) { + return false; + } + + if (bits) { + uint_fast8_t split_bit = context_split_mask(bits); + if ((a[bytes] & split_bit) != (b[bytes] & split_bit)) { + return false; + } + } + + return true; +} + +uint8_t *bitcopy(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits) +{ + uint_fast8_t bytes = bits / 8; + bits %= 8; + + if (bytes) { + dst = (uint8_t *) memcpy(dst, src, bytes) + bytes; + src += bytes; + } + + if (bits) { + uint_fast8_t split_bit = context_split_mask(bits); + *dst = (*src & split_bit) | (*dst & ~ split_bit); + } + + return dst; +} + +uint8_t *bitcopy0(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits) +{ + uint_fast8_t bytes = bits / 8; + bits %= 8; + + if (bytes) { + dst = (uint8_t *) memcpy(dst, src, bytes) + bytes; + src += bytes; + } + + if (bits) { + uint_fast8_t split_bit = context_split_mask(bits); + *dst = (*src & split_bit); + } + + return dst; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/libList/ns_list.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/libList/ns_list.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * All functions can be inlined, and definitions are in ns_list.h. + * Define NS_LIST_FN before including it to generate external definitions. + */ +#define NS_LIST_FN extern + +#include "ns_list.h"
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/libip6string/ip6tos.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/libip6string/ip6tos.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdio.h> +#include <string.h> +#include "common_functions.h" +#include "ip6string.h" + +/** + * Print binary IPv6 address to a string. + * String must contain enough room for full address, 40 bytes exact. + * IPv4 tunneling addresses are not covered. + * \param addr IPv6 address. + * \p buffer to write string to. + */ +uint_fast8_t ip6tos(const void *ip6addr, char *p) +{ + char *p_orig = p; + uint_fast8_t zero_start = 255, zero_len = 1; + const uint8_t *addr = ip6addr; + uint_fast16_t part; + + /* Follow RFC 5952 - pre-scan for longest run of zeros */ + for (uint_fast8_t n = 0; n < 8; n++) { + part = *addr++; + part = (part << 8) | *addr++; + if (part != 0) { + continue; + } + + /* We're at the start of a run of zeros - scan to non-zero (or end) */ + uint_fast8_t n0 = n; + for (n = n0 + 1; n < 8; n++) { + part = *addr++; + part = (part << 8) | *addr++; + if (part != 0) { + break; + } + } + + /* Now n0->initial zero of run, n->after final zero in run. Is this the + * longest run yet? If equal, we stick with the previous one - RFC 5952 + * S4.2.3. Note that zero_len being initialised to 1 stops us + * shortening a 1-part run (S4.2.2.) + */ + if (n - n0 > zero_len) { + zero_start = n0; + zero_len = n - n0; + } + + /* Continue scan for initial zeros from part n+1 - we've already + * consumed part n, and know it's non-zero. */ + } + + /* Now go back and print, jumping over any zero run */ + addr = ip6addr; + for (uint_fast8_t n = 0; n < 8;) { + if (n == zero_start) { + if (n == 0) { + *p++ = ':'; + } + *p++ = ':'; + addr += 2 * zero_len; + n += zero_len; + continue; + } + + part = *addr++; + part = (part << 8) | *addr++; + n++; + + p += sprintf(p, "%"PRIxFAST16, part); + + /* One iteration writes "part:" rather than ":part", and has the + * explicit check for n == 8 below, to allow easy extension for + * IPv4-in-IPv6-type addresses ("xxxx::xxxx:a.b.c.d"): we'd just + * run the same loop for 6 parts, and output would then finish with the + * required : or ::, ready for "a.b.c.d" to be tacked on. + */ + if (n != 8) { + *p++ = ':'; + } + } + *p = '\0'; + + // Return length of generated string, excluding the terminating null character + return p - p_orig; +} + +uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p) +{ + char *wptr = p; + uint8_t addr[16] = {0}; + + if (prefix_len > 128) { + return 0; + } + + // Generate prefix part of the string + bitcopy(addr, prefix, prefix_len); + wptr += ip6tos(addr, wptr); + // Add the prefix length part of the string + wptr += sprintf(wptr, "/%"PRIuFAST8, prefix_len); + + // Return total length of generated string + return wptr - p; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/libip6string/stoip6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/libip6string/stoip6.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include "common_functions.h" +#include "ip6string.h" + +static uint16_t hex(const char *p); + +/** + * Convert numeric IPv6 address string to a binary. + * IPv4 tunnelling addresses are not covered. + * \param ip6addr IPv6 address in string format. + * \param len Length of ipv6 string. + * \param dest buffer for address. MUST be 16 bytes. + */ +void stoip6(const char *ip6addr, size_t len, void *dest) +{ + uint8_t *addr; + const char *p, *q; + int_fast8_t field_no, coloncolon = -1; + + addr = dest; + + if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses + return; + } + + // First go forward the string, until end, noting :: position if any + for (field_no = 0, p = ip6addr; (len > (size_t)(p - ip6addr)) && *p && field_no < 8; p = q + 1) { + q = p; + // Seek for ':' or end + while (*q && (*q != ':')) { + q++; + } + //Convert and write this part, (high-endian AKA network byte order) + addr = common_write_16_bit(hex(p), addr); + field_no++; + //Check if we reached "::" + if ((len > (size_t)(q - ip6addr)) && *q && (q[0] == ':') && (q[1] == ':')) { + coloncolon = field_no; + q++; + } + } + + if (coloncolon != -1) { + /* Insert zeros in the appropriate place */ + uint_fast8_t head_size = 2 * coloncolon; + uint_fast8_t inserted_size = 2 * (8 - field_no); + uint_fast8_t tail_size = 16 - head_size - inserted_size; + addr = dest; + memmove(addr + head_size + inserted_size, addr + head_size, tail_size); + memset(addr + head_size, 0, inserted_size); + } else if (field_no != 8) { + /* Should really report an error if we didn't get 8 fields */ + memset(addr, 0, 16 - field_no * 2); + } +} +unsigned char sipv6_prefixlength(const char *ip6addr) +{ + char *ptr = strchr(ip6addr, '/'); + if (ptr) { + return (unsigned char)strtoul(ptr + 1, 0, 10); + } + return 0; +} +static uint16_t hex(const char *p) +{ + uint16_t val = 0; + + for (;;) { + char c = *p++; + if ((c >= '0') && (c <= '9')) { + val = (val << 4) | (c - '0'); + } else if ((c >= 'A') && (c <= 'F')) { + val = (val << 4) | (10 + (c - 'A')); + } else if ((c >= 'a') && (c <= 'f')) { + val = (val << 4) | (10 + (c - 'a')); + } else { + break; // Non hex character + } + } + return val; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/nsdynmemLIB/nsdynmemLIB.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/nsdynmemLIB/nsdynmemLIB.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdint.h> +#include <string.h> +#include "nsdynmemLIB.h" +#include "platform/arm_hal_interrupt.h" +#include <stdlib.h> +#include "ns_list.h" + +#ifndef STANDARD_MALLOC +typedef enum mem_stat_update_t { + DEV_HEAP_ALLOC_OK, + DEV_HEAP_ALLOC_FAIL, + DEV_HEAP_FREE, +} mem_stat_update_t; + +typedef struct { + ns_list_link_t link; +} hole_t; + +typedef int ns_mem_word_size_t; // internal signed heap block size type + +/* struct for book keeping variables */ +struct ns_mem_book { + ns_mem_word_size_t *heap_main; + ns_mem_word_size_t *heap_main_end; + mem_stat_t *mem_stat_info_ptr; + void (*heap_failure_callback)(heap_fail_t); + NS_LIST_HEAD(hole_t, link) holes_list; + ns_mem_heap_size_t heap_size; +}; + +static ns_mem_book_t *default_book; // heap pointer for original "ns_" API use + +// size of a hole_t in our word units +#define HOLE_T_SIZE ((ns_mem_word_size_t) ((sizeof(hole_t) + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t))) + +static NS_INLINE hole_t *hole_from_block_start(ns_mem_word_size_t *start) +{ + return (hole_t *)(start + 1); +} + +static NS_INLINE ns_mem_word_size_t *block_start_from_hole(hole_t *start) +{ + return ((ns_mem_word_size_t *)start) - 1; +} + +static void heap_failure(ns_mem_book_t *book, heap_fail_t reason) +{ + if (book->heap_failure_callback) { + book->heap_failure_callback(reason); + } +} + +#endif + +void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size, + void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr) +{ + default_book = ns_mem_init(heap, h_size, passed_fptr, info_ptr); +} + +const mem_stat_t *ns_dyn_mem_get_mem_stat(void) +{ +#ifndef STANDARD_MALLOC + return ns_mem_get_mem_stat(default_book); +#else + return NULL; +#endif +} + + +ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size, + void (*passed_fptr)(heap_fail_t), + mem_stat_t *info_ptr) +{ +#ifndef STANDARD_MALLOC + ns_mem_book_t *book; + + ns_mem_word_size_t *ptr; + ns_mem_word_size_t temp_int; + /* Do memory alignment */ + temp_int = ((uintptr_t)heap % sizeof(ns_mem_word_size_t)); + if (temp_int) { + heap = (uint8_t *) heap + (sizeof(ns_mem_word_size_t) - temp_int); + h_size -= (sizeof(ns_mem_word_size_t) - temp_int); + } + + /* Make correction for total length also */ + temp_int = (h_size % sizeof(ns_mem_word_size_t)); + if (temp_int) { + h_size -= (sizeof(ns_mem_word_size_t) - temp_int); + } + book = heap; + book->heap_main = (ns_mem_word_size_t *)&(book[1]); // SET Heap Pointer + book->heap_size = h_size - sizeof(ns_mem_book_t); //Set Heap Size + temp_int = (book->heap_size / sizeof(ns_mem_word_size_t)); + temp_int -= 2; + ptr = book->heap_main; + *ptr = -(temp_int); + ptr += (temp_int + 1); + *ptr = -(temp_int); + book->heap_main_end = ptr; + + ns_list_init(&book->holes_list); + ns_list_add_to_start(&book->holes_list, hole_from_block_start(book->heap_main)); + + book->mem_stat_info_ptr = info_ptr; + //RESET Memory by Hea Len + if (info_ptr) { + memset(book->mem_stat_info_ptr, 0, sizeof(mem_stat_t)); + book->mem_stat_info_ptr->heap_sector_size = book->heap_size; + } +#endif + //There really is no support to standard malloc in this library anymore + book->heap_failure_callback = passed_fptr; + + return book; +} + +const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *heap) +{ +#ifndef STANDARD_MALLOC + return heap->mem_stat_info_ptr; +#else + return NULL; +#endif +} + +#ifndef STANDARD_MALLOC +static void dev_stat_update(mem_stat_t *mem_stat_info_ptr, mem_stat_update_t type, ns_mem_block_size_t size) +{ + if (mem_stat_info_ptr) { + switch (type) { + case DEV_HEAP_ALLOC_OK: + mem_stat_info_ptr->heap_sector_alloc_cnt++; + mem_stat_info_ptr->heap_sector_allocated_bytes += size; + if (mem_stat_info_ptr->heap_sector_allocated_bytes_max < mem_stat_info_ptr->heap_sector_allocated_bytes) { + mem_stat_info_ptr->heap_sector_allocated_bytes_max = mem_stat_info_ptr->heap_sector_allocated_bytes; + } + mem_stat_info_ptr->heap_alloc_total_bytes += size; + break; + case DEV_HEAP_ALLOC_FAIL: + mem_stat_info_ptr->heap_alloc_fail_cnt++; + break; + case DEV_HEAP_FREE: + mem_stat_info_ptr->heap_sector_alloc_cnt--; + mem_stat_info_ptr->heap_sector_allocated_bytes -= size; + break; + } + } +} + +static ns_mem_word_size_t convert_allocation_size(ns_mem_book_t *book, ns_mem_block_size_t requested_bytes) +{ + if (book->heap_main == 0) { + heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED); + } else if (requested_bytes < 1) { + heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID); + } else if (requested_bytes > (book->heap_size - 2 * sizeof(ns_mem_word_size_t)) ) { + heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID); + } + return (requested_bytes + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t); +} + +// Checks that block length indicators are valid +// Block has format: Size of data area [1 word] | data area [abs(size) words]| Size of data area [1 word] +// If Size is negative it means area is unallocated +// For direction, use 1 for direction up and -1 for down +static int8_t ns_mem_block_validate(ns_mem_word_size_t *block_start, int direction) +{ + int8_t ret_val = -1; + ns_mem_word_size_t *end = block_start; + ns_mem_word_size_t size_start = *end; + end += (1 + abs(size_start)); + if (size_start != 0 && size_start == *end) { + ret_val = 0; + } + return ret_val; +} +#endif + +// For direction, use 1 for direction up and -1 for down +static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_t alloc_size, int direction) +{ +#ifndef STANDARD_MALLOC + if (!book) { + /* We can not do anything except return NULL because we can't find book + keeping block */ + return NULL; + } + + ns_mem_word_size_t *block_ptr = NULL; + + platform_enter_critical(); + + ns_mem_word_size_t data_size = convert_allocation_size(book, alloc_size); + if (!data_size) { + goto done; + } + + // ns_list_foreach, either forwards or backwards, result to ptr + for (hole_t *cur_hole = direction > 0 ? ns_list_get_first(&book->holes_list) + : ns_list_get_last(&book->holes_list); + cur_hole; + cur_hole = direction > 0 ? ns_list_get_next(&book->holes_list, cur_hole) + : ns_list_get_previous(&book->holes_list, cur_hole) + ) { + ns_mem_word_size_t *p = block_start_from_hole(cur_hole); + if (ns_mem_block_validate(p, direction) != 0 || *p >= 0) { + //Validation failed, or this supposed hole has positive (allocated) size + heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); + break; + } + if (-*p >= data_size) { + // Found a big enough block + block_ptr = p; + break; + } + } + + if (!block_ptr) { + goto done; + } + + ns_mem_word_size_t block_data_size = -*block_ptr; + if (block_data_size >= (data_size + 2 + HOLE_T_SIZE)) { + ns_mem_word_size_t hole_size = block_data_size - data_size - 2; + ns_mem_word_size_t *hole_ptr; + //There is enough room for a new hole so create it first + if ( direction > 0 ) { + hole_ptr = block_ptr + 1 + data_size + 1; + // Hole will be left at end of area. + // Would like to just replace this block_ptr with new descriptor, but + // they could overlap, so ns_list_replace might fail + //ns_list_replace(&holes_list, block_ptr, hole_from_block_start(hole_ptr)); + hole_t *before = ns_list_get_previous(&book->holes_list, hole_from_block_start(block_ptr)); + ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr)); + if (before) { + ns_list_add_after(&book->holes_list, before, hole_from_block_start(hole_ptr)); + } else { + ns_list_add_to_start(&book->holes_list, hole_from_block_start(hole_ptr)); + } + } else { + hole_ptr = block_ptr; + // Hole remains at start of area - keep existing descriptor in place. + block_ptr += 1 + hole_size + 1; + } + + hole_ptr[0] = -hole_size; + hole_ptr[1 + hole_size] = -hole_size; + } else { + // Not enough room for a left-over hole, so use the whole block + data_size = block_data_size; + ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr)); + } + block_ptr[0] = data_size; + block_ptr[1 + data_size] = data_size; + + done: + if (book->mem_stat_info_ptr) { + if (block_ptr) { + //Update Allocate OK + dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(ns_mem_word_size_t)); + + } else { + //Update Allocate Fail, second parameter is not used for stats + dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0); + } + } + platform_exit_critical(); + + return block_ptr ? block_ptr + 1 : NULL; +#else + void *retval = NULL; + if (alloc_size) { + platform_enter_critical(); + retval = malloc(alloc_size); + platform_exit_critical(); + } + return retval; +#endif +} + +void *ns_mem_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size) +{ + return ns_mem_internal_alloc(heap, alloc_size, -1); +} + +void *ns_mem_temporary_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size) +{ + return ns_mem_internal_alloc(heap, alloc_size, 1); +} + +void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size) +{ + return ns_mem_alloc(default_book, alloc_size); +} + +void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size) +{ + return ns_mem_temporary_alloc(default_book, alloc_size); +} + +#ifndef STANDARD_MALLOC +static void ns_mem_free_and_merge_with_adjacent_blocks(ns_mem_book_t *book, ns_mem_word_size_t *cur_block, ns_mem_word_size_t data_size) +{ + // Theory of operation: Block is always in form | Len | Data | Len | + // So we need to check length of previous (if current not heap start) + // and next (if current not heap end) blocks. Negative length means + // free memory so we can merge freed block with those. + + hole_t *existing_start = NULL; + hole_t *existing_end = NULL; + ns_mem_word_size_t *start = cur_block; + ns_mem_word_size_t *end = cur_block + data_size + 1; + //invalidate current block + *start = -data_size; + *end = -data_size; + ns_mem_word_size_t merged_data_size = data_size; + + if (start != book->heap_main) { + if (*(start - 1) < 0) { + ns_mem_word_size_t *block_end = start - 1; + ns_mem_word_size_t block_size = 1 + (-*block_end) + 1; + merged_data_size += block_size; + start -= block_size; + if (*start != *block_end) { + heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); + } + if (block_size >= 1 + HOLE_T_SIZE + 1) { + existing_start = hole_from_block_start(start); + } + } + } + + if (end != book->heap_main_end) { + if (*(end + 1) < 0) { + ns_mem_word_size_t *block_start = end + 1; + ns_mem_word_size_t block_size = 1 + (-*block_start) + 1; + merged_data_size += block_size; + end += block_size; + if (*end != *block_start) { + heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); + } + if (block_size >= 1 + HOLE_T_SIZE + 1) { + existing_end = hole_from_block_start(block_start); + } + } + } + + hole_t *to_add = hole_from_block_start(start); + hole_t *before = NULL; + if (existing_end) { + // Extending hole described by "existing_end" downwards. + // Will replace with descriptor at bottom of merged block. + // (Can't use ns_list_replace, because of danger of overlap) + // Optimisation - note our position for insertion below. + before = ns_list_get_next(&book->holes_list, existing_end); + ns_list_remove(&book->holes_list, existing_end); + } + if (existing_start) { + // Extending hole described by "existing_start" upwards. + // No need to modify that descriptor - it remains at the bottom + // of the merged block to describe it. + } else { + // Didn't find adjacent descriptors, but may still + // be merging with small blocks without descriptors. + if ( merged_data_size >= HOLE_T_SIZE ) { + // Locate hole position in list, if we don't already know + // from merging with the block above. + if (!existing_end) { + ns_list_foreach(hole_t, ptr, &book->holes_list) { + if (ptr > to_add) { + before = ptr; + break; + } + } + } + if (before) { + ns_list_add_before(&book->holes_list, before, to_add); + } else { + ns_list_add_to_end(&book->holes_list, to_add); + } + + } + } + *start = -merged_data_size; + *end = -merged_data_size; +} +#endif + +void ns_mem_free(ns_mem_book_t *book, void *block) +{ +#ifndef STANDARD_MALLOC + + if (!block) { + return; + } + + ns_mem_word_size_t *ptr = block; + ns_mem_word_size_t size; + + platform_enter_critical(); + ptr --; + //Read Current Size + size = *ptr; + if (ptr < book->heap_main || ptr >= book->heap_main_end) { + heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID); + } else if ((ptr + size) >= book->heap_main_end) { + heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID); + } else if (size < 0) { + heap_failure(book, NS_DYN_MEM_DOUBLE_FREE); + } else { + if (ns_mem_block_validate(ptr, 1) != 0) { + heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED); + } else { + ns_mem_free_and_merge_with_adjacent_blocks(book, ptr, size); + if (book->mem_stat_info_ptr) { + //Update Free Counter + dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t)); + } + } + } + platform_exit_critical(); +#else + platform_enter_critical(); + free(block); + platform_exit_critical(); +#endif +} + +void ns_dyn_mem_free(void *block) +{ + ns_mem_free(default_book, block); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/nvmHelper/ns_nvm_helper.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/nanostack-libservice/source/nvmHelper/ns_nvm_helper.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,229 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <string.h> +#include <ns_types.h> +#include <nsdynmemLIB.h> +#include "ns_list.h" +#include "platform/arm_hal_nvm.h" +#include "ns_nvm_helper.h" + +#define TRACE_GROUP "nnvm" + +/* NVM operations */ +#define NS_NVM_NONE 0x00 +#define NS_NVM_INIT 0x01 +#define NS_NVM_KEY_CREATE 0x02 +#define NS_NVM_KEY_READ 0x03 +#define NS_NVM_KEY_WRITE 0x04 +#define NS_NVM_FLUSH 0x05 +#define NS_NVM_KEY_DELETE 0x06 + +typedef struct { + ns_nvm_callback *callback; + const char *client_key_name; + void *client_context; + int operation; + uint8_t *buffer; + uint16_t *buffer_len; + void *original_request; + ns_list_link_t link; +} ns_nvm_request_t; + +static bool ns_nvm_initialized = false; +static bool ns_nvm_operation_in_progress = false; + +static ns_nvm_request_t *ns_nvm_create_request(ns_nvm_callback *callback, void *context, const char *key_name, uint8_t *buf, uint16_t *buf_len, uint8_t operation); +static int ns_nvm_operation_start(ns_nvm_request_t *request); +static int ns_nvm_operation_continue(ns_nvm_request_t *request, bool free_request); +static void ns_nvm_operation_end(ns_nvm_request_t *ns_nvm_request_ptr, int client_retval); + +static NS_LIST_DEFINE(ns_nvm_request_list, ns_nvm_request_t, link); + +/* + * Callback from platform NVM adaptation + */ +void ns_nvm_callback_func(platform_nvm_status status, void *args) +{ + ns_nvm_request_t *ns_nvm_request_ptr = (ns_nvm_request_t*)args; + int client_retval = NS_NVM_OK; + + if (status == PLATFORM_NVM_ERROR) { + client_retval = NS_NVM_ERROR; + } else if (status == PLATFORM_NVM_KEY_NOT_FOUND) { + client_retval = NS_NVM_DATA_NOT_FOUND; + } + + switch(ns_nvm_request_ptr->operation) { + case NS_NVM_INIT: + ns_nvm_operation_continue(ns_nvm_request_ptr->original_request, true); + ns_dyn_mem_free(ns_nvm_request_ptr); + break; + case NS_NVM_FLUSH: + case NS_NVM_KEY_READ: + ns_nvm_operation_end(ns_nvm_request_ptr, client_retval); + break; + case NS_NVM_KEY_CREATE: + if (status == PLATFORM_NVM_OK) { + ns_nvm_request_ptr->operation = NS_NVM_KEY_WRITE; + platform_nvm_write(ns_nvm_callback_func, ns_nvm_request_ptr->client_key_name, ns_nvm_request_ptr->buffer, ns_nvm_request_ptr->buffer_len, ns_nvm_request_ptr); + } else { + ns_nvm_operation_end(ns_nvm_request_ptr, client_retval); + } + break; + case NS_NVM_KEY_DELETE: + case NS_NVM_KEY_WRITE: + if (status == PLATFORM_NVM_OK) { + // write ok, flush the changes + ns_nvm_request_ptr->operation = NS_NVM_FLUSH; + platform_nvm_flush(ns_nvm_callback_func, ns_nvm_request_ptr); + } else { + // write failed, inform client + ns_nvm_operation_end(ns_nvm_request_ptr, client_retval); + } + break; + } +} + +int ns_nvm_key_delete(ns_nvm_callback *callback, const char *key_name, void *context) +{ + if (!callback || !key_name) { + return NS_NVM_ERROR; + } + ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, NULL, NULL, NS_NVM_KEY_DELETE); + return ns_nvm_operation_start(ns_nvm_request_ptr); +} + +int ns_nvm_data_read(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context) +{ + if (!callback || !key_name || !buf || !buf_len) { + return NS_NVM_ERROR; + } + ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, buf, buf_len, NS_NVM_KEY_READ); + return ns_nvm_operation_start(ns_nvm_request_ptr); +} + +int ns_nvm_data_write(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context) +{ + if (!callback || !key_name || !buf || !buf_len) { + return NS_NVM_ERROR; + } + ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, buf, buf_len, NS_NVM_KEY_WRITE); + return ns_nvm_operation_start(ns_nvm_request_ptr); +} + +static int ns_nvm_operation_start(ns_nvm_request_t *nvm_request) +{ + int ret = NS_NVM_OK; + platform_nvm_status pnvm_status; + + if (!nvm_request) { + return NS_NVM_MEMORY; + } + if (ns_nvm_initialized == true) { + // NVM already initialized, continue directly + if (!ns_nvm_operation_in_progress) { + ret = ns_nvm_operation_continue(nvm_request, true); + } else { + // add request to list and handle when existing calls has been handled. + ns_list_add_to_end(&ns_nvm_request_list, nvm_request); + } + } else { + ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(NULL, NULL, NULL, NULL, NULL, NS_NVM_INIT); + if (!ns_nvm_request_ptr) { + ns_dyn_mem_free(nvm_request); + ns_dyn_mem_free(ns_nvm_request_ptr); + return NS_NVM_MEMORY; + } + ns_nvm_request_ptr->original_request = nvm_request; + pnvm_status = platform_nvm_init(ns_nvm_callback_func, ns_nvm_request_ptr); + if (pnvm_status != PLATFORM_NVM_OK) { + ns_dyn_mem_free(nvm_request); + ns_dyn_mem_free(ns_nvm_request_ptr); + return NS_NVM_ERROR; + } + ns_list_init(&ns_nvm_request_list); + ns_nvm_initialized = true; + ns_nvm_operation_in_progress = true; + } + return ret; +} + +static ns_nvm_request_t *ns_nvm_create_request(ns_nvm_callback *callback, void *context, const char *key_name, uint8_t *buf, uint16_t *buf_len, uint8_t operation) +{ + ns_nvm_request_t *ns_nvm_request_ptr = ns_dyn_mem_temporary_alloc(sizeof(ns_nvm_request_t)); + if (!ns_nvm_request_ptr) { + return NULL; + } + ns_nvm_request_ptr->client_context = context; + ns_nvm_request_ptr->callback = callback; + ns_nvm_request_ptr->client_key_name = key_name; + ns_nvm_request_ptr->operation = operation; + ns_nvm_request_ptr->buffer = buf; + ns_nvm_request_ptr->buffer_len = buf_len; + + return ns_nvm_request_ptr; +} + +static int ns_nvm_operation_continue(ns_nvm_request_t *request, bool free_request) +{ + platform_nvm_status ret = PLATFORM_NVM_OK; + + ns_nvm_operation_in_progress = true; + switch(request->operation) { + case NS_NVM_KEY_WRITE: + request->operation = NS_NVM_KEY_CREATE; + ret = platform_nvm_key_create(ns_nvm_callback_func, request->client_key_name, *request->buffer_len, 0, request); + break; + case NS_NVM_KEY_READ: + ret = platform_nvm_read(ns_nvm_callback_func, request->client_key_name, request->buffer, request->buffer_len, request); + break; + case NS_NVM_KEY_DELETE: + ret = platform_nvm_key_delete(ns_nvm_callback_func, request->client_key_name, request); + break; + } + + if (ret != PLATFORM_NVM_OK) { + if (free_request == true) { + // free request if requested + ns_dyn_mem_free(request); + } + ns_nvm_operation_in_progress = false; + return NS_NVM_ERROR; + } + + return NS_NVM_OK; +} + +static void ns_nvm_operation_end(ns_nvm_request_t *ns_nvm_request_ptr, int client_retval) +{ + ns_nvm_request_ptr->callback(client_retval, ns_nvm_request_ptr->client_context); + ns_dyn_mem_free(ns_nvm_request_ptr); + ns_nvm_operation_in_progress = false; + + ns_list_foreach_safe(ns_nvm_request_t, pending_req, &ns_nvm_request_list) { + // there are pending requests to be processed + ns_list_remove(&ns_nvm_request_list, pending_req); + int ret = ns_nvm_operation_continue(pending_req, false); + if (ret != NS_NVM_OK) { + ns_nvm_operation_end(pending_req, ret); + } else { + break; + } + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/arm_hal_interrupt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/arm_hal_interrupt.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,52 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "platform/arm_hal_interrupt.h" + +#include "arm_hal_interrupt_private.h" +#include "pal.h" + +#include <assert.h> + + +static uint8_t sys_irq_disable_counter; + +static palMutexID_t critical_mutex_id; + +void platform_critical_init(void) +{ + palStatus_t status; + status = pal_osMutexCreate(&critical_mutex_id); + assert(PAL_SUCCESS == status); +} + +void platform_enter_critical(void) +{ + palStatus_t status; + status = pal_osMutexWait(critical_mutex_id, UINT32_MAX); + assert(PAL_SUCCESS == status); + sys_irq_disable_counter++; +} + +void platform_exit_critical(void) +{ + palStatus_t status; + --sys_irq_disable_counter; + status = pal_osMutexRelease(critical_mutex_id); + assert(PAL_SUCCESS == status); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/arm_hal_interrupt_private.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/arm_hal_interrupt_private.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_HAL_INTERRUPT_PRIVATE_H_ +#define ARM_HAL_INTERRUPT_PRIVATE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void platform_critical_init(void); + +#ifdef __cplusplus +} +#endif + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/arm_hal_random.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/arm_hal_random.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <assert.h> +#include "ns_types.h" +#include "platform/arm_hal_random.h" +#include "pal.h" + +void arm_random_module_init(void) +{ + palStatus_t status = pal_init(); + assert(status == PAL_SUCCESS); +} + +uint32_t arm_random_seed_get(void) +{ + uint32_t result = 0; + palStatus_t status = pal_osRandom32bit(&result); + assert(status == PAL_SUCCESS); + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/arm_hal_timer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/arm_hal_timer.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,92 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// Include before mbed.h to properly get UINT*_C() +#include "ns_types.h" + +#include "pal.h" +#include "pal_rtos.h" + +#include "platform/arm_hal_timer.h" +#include "platform/arm_hal_interrupt.h" + +#include <assert.h> + +// Low precision platform tick timer variables +static void (*tick_timer_callback)(void); +static palTimerID_t tick_timer_id; +#define TICK_TIMER_ID 1 + +void timer_callback(void const *funcArgument) +{ + (void)funcArgument; + if (tick_timer_callback != NULL) { + tick_timer_callback(); + } +} + +#ifdef MBED_CONF_NANOSTACK_EVENTLOOP_EXCLUDE_HIGHRES_TIMER +extern "C" int8_t ns_timer_sleep(void); +#endif + +// static method for creating the timer, called implicitly by platform_tick_timer_register if +// timer was not enabled already +static void tick_timer_create(void) +{ + palStatus_t status; + status = pal_init(); + assert(PAL_SUCCESS == status); + status = pal_osTimerCreate(timer_callback, NULL, palOsTimerPeriodic, &tick_timer_id); + assert(PAL_SUCCESS == status); + +} + +// Low precision platform tick timer +int8_t platform_tick_timer_register(void (*tick_timer_cb_handler)(void)) +{ + if (tick_timer_id == 0) { + tick_timer_create(); + } + tick_timer_callback = tick_timer_cb_handler; + return TICK_TIMER_ID; +} + +int8_t platform_tick_timer_start(uint32_t period_ms) +{ + int8_t retval = -1; + if ((tick_timer_id != 0) && (PAL_SUCCESS == pal_osTimerStart(tick_timer_id, period_ms))) { + retval = 0; + } + return retval; +} + +int8_t platform_tick_timer_stop(void) +{ + int8_t retval = -1; + if ((tick_timer_id != 0) && (PAL_SUCCESS == pal_osTimerStop(tick_timer_id))) { + retval = 0; + } + + // release PAL side resources + pal_osTimerDelete(&tick_timer_id); + pal_destroy(); + + return retval; +} + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,13 @@ +{ + "name": "ns-hal-pal", + "config": { + "nvm_cfstore": { + "help": "Use cfstore as a NVM storage. Else RAM simulation will be used", + "value": false + }, + "event_loop_thread_stack_size": { + "help": "Define event-loop thread stack size.", + "value": 6144 + } + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/ns_event_loop.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/ns_event_loop.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,155 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "ns_event_loop.h" + +#include "pal.h" +#include "ns_trace.h" + +#include "eventOS_scheduler.h" + +#include <assert.h> + + +#define TRACE_GROUP "evlp" + +static void event_loop_thread(const void *arg); + +static palThreadID_t event_thread_id = 0; +static palMutexID_t event_mutex_id = 0; +static palSemaphoreID_t event_start_sema_id = 0; +static palSemaphoreID_t event_signal_sema_id = 0; +static palSemaphoreID_t event_stop_sema_id = 0; +static volatile bool event_stop_loop; + +void eventOS_scheduler_mutex_wait(void) +{ + palStatus_t status; + status = pal_osMutexWait(event_mutex_id, UINT32_MAX); + assert(PAL_SUCCESS == status); +} + +void eventOS_scheduler_mutex_release(void) +{ + palStatus_t status; + status = pal_osMutexRelease(event_mutex_id); + assert(PAL_SUCCESS == status); +} + +void eventOS_scheduler_signal(void) +{ + palStatus_t status; + status = pal_osSemaphoreRelease(event_signal_sema_id); + assert(PAL_SUCCESS == status); +} + +void eventOS_scheduler_idle(void) +{ + int32_t counters = 0; + palStatus_t status; + + eventOS_scheduler_mutex_release(); + + status = pal_osSemaphoreWait(event_signal_sema_id, UINT32_MAX, &counters); + assert(PAL_SUCCESS == status); + + eventOS_scheduler_mutex_wait(); +} + +static void event_loop_thread(const void *arg) +{ + int32_t counters = 0; + palStatus_t status; + + tr_debug("event_loop_thread create"); + + event_stop_loop = false; + + status = pal_osSemaphoreWait(event_start_sema_id, UINT32_MAX, &counters); + assert(PAL_SUCCESS == status); + + // TODO: Delete start semaphore? + eventOS_scheduler_mutex_wait(); + tr_debug("event_loop_thread loop start"); + + // A stoppable version of eventOS_scheduler_run(void) + while (event_stop_loop == false) { + if (!eventOS_scheduler_dispatch_event()) { + eventOS_scheduler_idle(); + } + } + tr_debug("event_loop_thread loop end"); + + // cleanup the scheduler timer resources which are not needed anymore + eventOS_scheduler_timer_stop(); + + // signal the ns_event_loop_thread_stop() that it can continue + status = pal_osSemaphoreRelease(event_stop_sema_id); + assert(PAL_SUCCESS == status); +} + +void ns_event_loop_thread_create(void) +{ + int32_t counters = 0; + palStatus_t status; + + status = pal_osSemaphoreCreate(1, &event_start_sema_id); + assert(PAL_SUCCESS == status); + + status = pal_osSemaphoreWait(event_start_sema_id, UINT32_MAX, &counters); + assert(PAL_SUCCESS == status); + + status = pal_osSemaphoreCreate(0, &event_stop_sema_id); + assert(PAL_SUCCESS == status); + + status = pal_osSemaphoreCreate(1, &event_signal_sema_id); + assert(PAL_SUCCESS == status); + + status = pal_osMutexCreate(&event_mutex_id); + assert(PAL_SUCCESS == status); + + status = pal_osThreadCreateWithAlloc(event_loop_thread, NULL, PAL_osPriorityNormal, MBED_CONF_NS_HAL_PAL_EVENT_LOOP_THREAD_STACK_SIZE, NULL, &event_thread_id); + assert(PAL_SUCCESS == status); +} + +void ns_event_loop_thread_start(void) +{ + palStatus_t status; + status = pal_osSemaphoreRelease(event_start_sema_id); + assert(PAL_SUCCESS == status); +} + +void ns_event_loop_thread_stop(void) +{ + palStatus_t status; + + // request loop to stop + event_stop_loop = true; + + // Ping the even loop at least once more so it will notice the flag and + // hopefully end the loop soon. + eventOS_scheduler_signal(); + + // wait until the event loop has been stopped and the thread is shutting down. + // Note: the PAL API does not have any better means to join with a thread termination. + status = pal_osSemaphoreWait(event_stop_sema_id, UINT32_MAX, NULL); + assert(PAL_SUCCESS == status); + + pal_osSemaphoreDelete(&event_start_sema_id); + pal_osSemaphoreDelete(&event_stop_sema_id); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/ns_event_loop.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/ns_event_loop.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef NS_EVENT_LOOP_H_ +#define NS_EVENT_LOOP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void ns_event_loop_thread_create(void); +void ns_event_loop_thread_start(void); + +// A extension to original event loop API, which is useful on Linux only +void ns_event_loop_thread_stop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* NS_EVENT_LOOP_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/ns_hal_init.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/ns_hal_init.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,54 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "ns_hal_init.h" + +#include "ns_types.h" +#include <stdlib.h> +#include <assert.h> + +#include "arm_hal_interrupt_private.h" +#include "ns_event_loop.h" +#include "eventOS_scheduler.h" +#include "platform/arm_hal_timer.h" +#include "ns_trace.h" + + +void ns_hal_init(void *heap, size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr) +{ + static bool initted; + if (initted) { + return; + } + if (!heap) { + heap = malloc(h_size); + assert(heap); + if (!heap) { + return; + } + } + platform_critical_init(); + ns_dyn_mem_init(heap, h_size, passed_fptr, info_ptr); + eventOS_scheduler_init(); + // We do not initialise randlib, as it should be done after + // RF driver has started, to get MAC address and RF noise as seed. + // We do not initialise trace - left to application. + ns_event_loop_thread_create(); + ns_event_loop_thread_start(); + initted = true; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/ns_hal_init.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/ns-hal-pal/ns_hal_init.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,49 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef NS_HAL_INIT_H_ +#define NS_HAL_INIT_H_ + +#include <stddef.h> +#include "nsdynmemLIB.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initialise core Nanostack HAL components. + * + * Calls after the first do nothing. So "major" users should make sure + * they call this first with a "large" heap size, before anyone + * requests a smaller one. + * + * Parameters are as for ns_dyn_mem_init (but note that nsdynmemlib + * currently limits heap size to 16-bit, so be wary of passing large + * sizes. + * + * If heap is NULL, h_size will be allocated from the malloc() heap, + * else the passed-in pointer will be used. + */ +void ns_hal_init(void *heap, size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* NS_HAL_INIT_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, files are licensed +under the Apache 2.0 license, as can be found in: apache-2.0.txt \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/apache-2.0.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/apache-2.0.txt Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ + + +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of this License; and + You must cause any modified files to carry prominent notices stating that You changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,13 @@ +{ + "name": "nanostack-eventloop", + "config": { + "use_platform_tick_timer": { + "help": "Use platform provided low resolution tick timer for eventloop", + "value": null + }, + "exclude_highres_timer": { + "help": "Exclude high resolution timer from build", + "value": null + } + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/eventOS_callback_timer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/eventOS_callback_timer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EVENTOS_CALLBACK_TIMER_H_ +#define EVENTOS_CALLBACK_TIMER_H_ +#ifdef __cplusplus +extern "C" { +#endif +#include "ns_types.h" + +extern int8_t eventOS_callback_timer_register(void (*timer_interrupt_handler)(int8_t, uint16_t)); +extern int8_t eventOS_callback_timer_unregister(int8_t ns_timer_id); + +extern int8_t eventOS_callback_timer_stop(int8_t ns_timer_id); +extern int8_t eventOS_callback_timer_start(int8_t ns_timer_id, uint16_t slots); +#ifdef __cplusplus +} +#endif + +#endif /* EVENTOS_CALLBACK_TIMER_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/eventOS_event.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/eventOS_event.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EVENTOS_EVENT_H_ +#define EVENTOS_EVENT_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include "ns_types.h" +#include "ns_list.h" + +/** + * \enum arm_library_event_priority_e + * \brief Event Priority level. + */ +typedef enum arm_library_event_priority_e { + ARM_LIB_HIGH_PRIORITY_EVENT = 0, /**< High Priority Event (Function CB) */ + ARM_LIB_MED_PRIORITY_EVENT = 1, /**< Medium Priority (Timer) */ + ARM_LIB_LOW_PRIORITY_EVENT = 2, /*!*< Normal Event and ECC / Security */ +} arm_library_event_priority_e; + +/** + * \struct arm_event_s + * \brief Event structure. + */ +typedef struct arm_event_s { + int8_t receiver; /**< Event handler Tasklet ID */ + int8_t sender; /**< Event sender Tasklet ID */ + uint8_t event_type; /**< This will be typecast arm_library_event_type_e, arm_internal_event_type_e or application specific define */ + uint8_t event_id; /**< Timer ID, NWK interface ID or application specific ID */ + void *data_ptr; /**< Application could share data pointer tasklet to tasklet */ + arm_library_event_priority_e priority; + uint32_t event_data; +} arm_event_t; + +/* Backwards compatibility */ +typedef arm_event_t arm_event_s; + +/** + * \struct arm_event_storage + * \brief Event structure storage, including list link. + +@startuml + +partition "Event loop" { +(*) -->[event created] "UNQUEUED" +"UNQUEUED" -->[event_core_write()] "QUEUED" +"QUEUED" -->[event_core_read()] "RUNNING" +"RUNNING" ->[event_core_free_push()] "UNQUEUED" +} + +partition "system_timer.c" { + "UNQUEUED:timer" -->[eventOS_event_send_timer_allocated()] "QUEUED" +} +@enduml + + */ +typedef struct arm_event_storage { + arm_event_s data; + enum { + ARM_LIB_EVENT_STARTUP_POOL, + ARM_LIB_EVENT_DYNAMIC, + ARM_LIB_EVENT_USER, + ARM_LIB_EVENT_TIMER, + } allocator; + enum { + ARM_LIB_EVENT_UNQUEUED, + ARM_LIB_EVENT_QUEUED, + ARM_LIB_EVENT_RUNNING, + } state; + ns_list_link_t link; +} arm_event_storage_t; + +/** + * \brief Send event to event scheduler. + * + * \param event pointer to pushed event. + * + * Event data is copied by the call, and this copy persists until the + * recipient's callback function returns. The callback function is passed + * a pointer to a copy of the data, not the original pointer. + * + * \return 0 Event push OK + * \return -1 Memory allocation Fail + */ +extern int8_t eventOS_event_send(const arm_event_t *event); + +/* Alternate names for timer function from eventOS_event_timer.h; + * implementations may one day merge */ +#define eventOS_event_send_at(event, at) eventOS_event_timer_request_at(event, at) +#define eventOS_event_send_in(event, in) eventOS_event_timer_request_in(event, in) +#define eventOS_event_send_after(event, after) eventOS_event_timer_request_after(event, after) +#define eventOS_event_send_every(event, every) eventOS_event_timer_request_every(event, every) + +/** + * \brief Send user-allocated event to event scheduler. + * + * \param event pointer to pushed event storage. + * + * The event structure is not copied by the call, the event system takes + * ownership and it is threaded directly into the event queue. This avoids the + * possibility of event sending failing due to memory exhaustion. + * + * event->data must be filled in on entry - the rest of the structure (link and + * allocator) need not be. + * + * The structure must remain valid until the recipient is called - the + * event system passes ownership to the receiving event handler, who may then + * invalidate it, or send it again. + * + * The recipient receives a pointer to the arm_event_t data member of the + * event - it can use NS_CONTAINER_OF() to get a pointer to the original + * event passed to this call, or to its outer container. + * + * It is a program error to send a user-allocated event to a non-existent task. + */ +extern void eventOS_event_send_user_allocated(arm_event_storage_t *event); + +/** + * \brief Event handler callback register + * + * Function will register and allocate unique event id handler + * + * \param handler_func_ptr function pointer for event handler + * \param init_event_type generated event type for init purpose + * + * \return >= 0 Unique event ID for this handler + * \return < 0 Register fail + * + * */ +extern int8_t eventOS_event_handler_create(void (*handler_func_ptr)(arm_event_t *), uint8_t init_event_type); + +/** + * Cancel an event. + * + * Queued events are removed from the event-loop queue and/or the timer queue. + * + * Passing a NULL pointer is allowed, and does nothing. + * + * Event pointers are valid from the time they are queued until the event + * has finished running or is cancelled. + * + * Cancelling a currently-running event is only useful to stop scheduling + * it if it is on a periodic timer; it has no other effect. + * + * Cancelling an already-cancelled or already-run single-shot event + * is undefined behaviour. + * + * \param event Pointer to event handle or NULL. + */ +extern void eventOS_cancel(arm_event_storage_t *event); + +#ifdef __cplusplus +} +#endif +#endif /* EVENTOS_EVENT_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/eventOS_event_timer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/eventOS_event_timer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EVENTOS_EVENT_TIMER_H_ +#define EVENTOS_EVENT_TIMER_H_ +#ifdef __cplusplus +extern "C" { +#endif +#include "ns_types.h" +#include "eventOS_event.h" + +struct arm_event_s; +typedef struct sys_timer_struct_s sys_timer_struct_t; + +/* 100 Hz ticker, so 10 milliseconds per tick */ +#define EVENTOS_EVENT_TIMER_HZ 100 + +static inline uint32_t eventOS_event_timer_ticks_to_ms(uint32_t ticks) +{ + NS_STATIC_ASSERT(1000 % EVENTOS_EVENT_TIMER_HZ == 0, "Assuming whole number of ms per tick") + return ticks * (1000 / EVENTOS_EVENT_TIMER_HZ); +} + +/* Convert ms to ticks, rounding up (so 9ms = 1 tick, 10ms = 1 tick, 11ms = 2 ticks) */ +static inline uint32_t eventOS_event_timer_ms_to_ticks(uint32_t ms) +{ + NS_STATIC_ASSERT(1000 % EVENTOS_EVENT_TIMER_HZ == 0, "Assuming whole number of ms per tick") + return (ms + (1000 / EVENTOS_EVENT_TIMER_HZ) - 1) / (1000 / EVENTOS_EVENT_TIMER_HZ); +} + +/** + * Read current timer tick count. + * + * Can be used as a monotonic time source, and to schedule events with + * eventOS_event_timer_send. + * + * Note that the value will wrap, so take care on comparisons. + * + * \return tick count. + */ +extern uint32_t eventOS_event_timer_ticks(void); + +/* Comparison macros handling wrap efficiently (assuming a conventional compiler + * which converts 0x80000000 to 0xFFFFFFFF to negative when casting to int32_t). + */ +#define TICKS_AFTER(a, b) ((int32_t) ((a)-(b)) > 0) +#define TICKS_BEFORE(a, b) ((int32_t) ((a)-(b)) < 0) +#define TICKS_AFTER_OR_AT(a, b) ((int32_t) ((a)-(b)) >= 0) +#define TICKS_BEFORE_OR_AT(a, b) ((int32_t) ((a)-(b)) <= 0) + +/** + * Send an event after time expired (in milliseconds) + * + * Note that the current implementation has the "feature" that rounding + * varies depending on the precise timing requested: + * 0-20 ms => 2 x 10ms tick + * 21-29 ms => 3 x 10ms tick + * 30-39 ms => 4 x 10ms tick + * 40-49 ms => 5 x 10ms tick + * ... etc + * + * For improved flexibility on the event, and for more control of time, + * you should use eventOS_event_timer_request_at(). + * + * \param event_id event_id for event + * \param event_type event_type for event + * \param tasklet_id receiver for event + * \param time time to sleep in milliseconds + * + * \return 0 on success + * \return -1 on error (invalid tasklet_id or allocation failure) + * + * */ +extern int8_t eventOS_event_timer_request(uint8_t event_id, uint8_t event_type, int8_t tasklet_id, uint32_t time); + +/** + * Send an event at specified time + * + * The event will be sent when eventOS_event_timer_ticks() reaches the + * specified value. + * + * If the specified time is in the past (ie "at" is before or at the current + * tick value), the event will be sent immediately. + * + * Can also be invoked using the eventOS_event_send_at() macro in eventOS_event.h + * + * \param event event to send + * \param at absolute tick time to run event at + * + * \return pointer to timer structure on success + * \return NULL on error (invalid tasklet_id or allocation failure) + * + */ +extern arm_event_storage_t *eventOS_event_timer_request_at(const struct arm_event_s *event, uint32_t at); + +/** + * Send an event in a specified time + * + * The event will be sent in the specified number of ticks - to + * be precise, it is equivalent to requesting an event at + * + * eventOS_event_timer_ticks() + ticks + * + * Because of timer granularity, the elapsed time between issuing the request + * and it running may be up to 1 tick less than the specified time. + * + * eg requesting 2 ticks will cause the event to be sent on the second tick from + * now. If requested just after a tick, the delay will be nearly 2 ticks, but if + * requested just before a tick, the delay will be just over 1 tick. + * + * If `in` is <= 0, the event will be sent immediately. + * + * Can also be invoked using the eventOS_event_send_in() macro in eventOS_event.h + * + * \param event event to send + * \param in tick delay for event + * + * \return pointer to timer structure on success + * \return NULL on error (invalid tasklet_id or allocation failure) + * + */ +extern arm_event_storage_t *eventOS_event_timer_request_in(const struct arm_event_s *event, int32_t in); + +/** + * Send an event after a specified time + * + * The event will be sent after the specified number of ticks - to + * be precise, it is equivalent to requesting an event at + * + * eventOS_event_timer_ticks() + ticks + 1 + * + * Because of timer granularity, the elapsed time between issuing the request + * and it running may be up to 1 tick more than the specified time. + * + * eg requesting 2 ticks will cause the event to be sent on the third tick from + * now. If requested just after a tick, the delay will be nearly 3 ticks, but if + * requested just before a tick, the delay will be just over 2 ticks. + * + * If `after` is < 0, the event will be sent immediately. If it is 0, the event + * is sent on the next tick. + * + * Can also be invoked using the eventOS_event_send_after() macro in eventOS_event.h + * + * \param event event to send + * \param after tick delay for event + * + * \return pointer to timer structure on success + * \return NULL on error (invalid tasklet_id or allocation failure) + * + */ +#define eventOS_event_timer_request_after(event, after) \ + eventOS_event_timer_request_in(event, (after) + 1) + +/** + * Send an event periodically + * + * The event will be sent repeatedly using the specified ticks period. + * + * The first call is sent at + * + * eventOS_event_timer_ticks() + ticks + * + * Subsequent events will be sent at N*ticks from the initial time. + * + * Period will be maintained while the device is awake, regardless of delays to + * event scheduling. If an event has not been delivered and completed by the + * next scheduled time, the next event will be sent immediately when it + * finishes. This could cause a continuous stream of events if unable to keep + * up with the period. + * + * Can also be invoked using the eventOS_event_send_every() macro in eventOS_event.h + * + * \param event event to send + * \param period period for event + * + * \return pointer to timer structure on success + * \return NULL on error (invalid tasklet_id or allocation failure) + * + */ +extern arm_event_storage_t *eventOS_event_timer_request_every(const struct arm_event_s *event, int32_t period); + +/** + * Cancel an event timer + * + * This cancels a pending timed event, matched by event_id and tasklet_id. + * + * \param event_id event_id for event + * \param tasklet_id receiver for event + * + * \return 0 on success + * \return -1 on error (event not found) + * + * */ +extern int8_t eventOS_event_timer_cancel(uint8_t event_id, int8_t tasklet_id); + +/** + * System Timer shortest time in milli seconds + * + * \param ticks Time in 10 ms resolution + * + * \return none + * + * */ +extern uint32_t eventOS_event_timer_shortest_active_timer(void); + + +/** Timeout structure. Not to be modified by user */ +typedef struct timeout_entry_t timeout_t; + +/** Request timeout callback. + * + * Create timeout request for specific callback. + * + * \param ms timeout in milliseconds. Maximum range is same as for eventOS_event_timer_request(). + * \param callback function to call after timeout + * \param arg arquement to pass to callback + * \return pointer to timeout structure or NULL on errors + */ +timeout_t *eventOS_timeout_ms(void (*callback)(void *), uint32_t ms, void *arg); + +/** Request periodic callback. + * + * Create timeout request for specific callback. Called periodically until eventOS_timeout_cancel() is called. + * + * \param every period in milliseconds. Maximum range is same as for eventOS_event_timer_request(). + * \param callback function to call after timeout + * \param arg arquement to pass to callback + * \return pointer to timeout structure or NULL on errors + */ +timeout_t *eventOS_timeout_every_ms(void (*callback)(void *), uint32_t every, void *arg); + +/** Cancell timeout request. + * + * \param t timeout request id. + */ +void eventOS_timeout_cancel(timeout_t *t); + + +#ifdef __cplusplus +} +#endif + +#endif /* EVENTOS_EVENT_TIMER_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/eventOS_scheduler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/eventOS_scheduler.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EVENTOS_SCHEDULER_H_ +#define EVENTOS_SCHEDULER_H_ + +#ifdef __cplusplus +extern "C" { +#endif +#include "ns_types.h" + +/* Compatibility with older ns_types.h */ +#ifndef NS_NORETURN +#define NS_NORETURN +#endif + +/** + * \brief Initialise event scheduler. + * + */ +extern void eventOS_scheduler_init(void); + +/** + * Process one event from event queue. + * Do not call this directly from application. Requires to be public so that simulator can call this. + * Use eventOS_scheduler_run() or eventOS_scheduler_run_until_idle(). + * \return true If there was event processed, false if the event queue was empty. + */ +bool eventOS_scheduler_dispatch_event(void); + +/** + * \brief Process events until no more events to process. + */ +extern void eventOS_scheduler_run_until_idle(void); + +/** + * \brief Start Event scheduler. + * Loops forever processing events from the queue. + * Calls eventOS_scheduler_idle() whenever event queue is empty. + */ +NS_NORETURN extern void eventOS_scheduler_run(void); +/** + * \brief Disable Event scheduler Timers + * + * \return 0 Timer Stop OK + * \return -1 Timer Stop Fail + * + * */ +int eventOS_scheduler_timer_stop(void); + +/** + * \brief Synch Event scheduler timer after sleep + * + * \param sleep_ticks time in milli seconds + * + * \return 0 Timer Synch OK + * \return -1 Timer Synch & Start Fail + * + * */ +int eventOS_scheduler_timer_synch_after_sleep(uint32_t sleep_ticks); + +/** + * \brief Read current active Tasklet ID + * + * This function not return valid information called inside interrupt + * + * \return curret active tasklet id + * + * */ +extern int8_t eventOS_scheduler_get_active_tasklet(void); + +/** + * \brief Set manually Active Tasklet ID + * + * \param tasklet requested tasklet ID + * + * */ +extern void eventOS_scheduler_set_active_tasklet(int8_t tasklet); + +/** + * \brief Event scheduler loop idle Callback. + + * Note! This method is called only by eventOS_scheduler_run, needs to be + * ported for the platform only if you are using eventOS_scheduler_run(). + */ +extern void eventOS_scheduler_idle(void); + +/** + * \brief This function will be called when stack enter idle state and start + * waiting signal. + * + * Note! This method is called only by reference implementation of idle. Needs + * to be ported for the platform only if you are using reference implementation. + */ +extern void eventOS_scheduler_wait(void); + +/** + * \brief This function will be called when stack receives an event. + */ +extern void eventOS_scheduler_signal(void); + +/** + * \brief This function will be called when stack can enter deep sleep state in detected time. + * + * Note! This method is called only by reference implementation of idle. Needs to be + * ported for the platform only if you are using reference implementation. + * + * \param sleep_time_ms Time in milliseconds to sleep + * \return time slept in milliseconds + */ +extern uint32_t eventOS_scheduler_sleep(uint32_t sleep_time_ms); + +/** + * \brief Lock a thread against the event loop thread + * + * This method can be provided by multi-threaded platforms to allow + * mutual exclusion with the event loop thread, for cases where + * code wants to work with both the event loop and other threads. + * + * A typical platform implementation would claim the same mutex + * before calling eventOS_scheduler_run() or + * eventOS_scheduler_dispatch(), and release it during + * eventOS_scheduler_idle(). + * + * The mutex must count - nested calls from one thread return + * immediately. Thus calling this from inside an event callback + * is harmless. + */ +extern void eventOS_scheduler_mutex_wait(void); + +/** + * \brief Release the event loop mutex + * + * Release the mutex claimed with eventOS_scheduler_mutex_wait(), + * allowing the event loop to continue processing. + */ +extern void eventOS_scheduler_mutex_release(void); + +/** + * \brief Check if the current thread owns the event mutex + * + * Check if the calling thread owns the scheduler mutex. + * This allows the ownership to be asserted if a function + * requires the mutex to be locked externally. + * + * The function is only intended as a debugging aid for + * users of eventOS_scheduler_mutex_wait() - it is not + * used by the event loop core itself. + * + * If the underlying mutex system does not support it, + * this may be implemented to always return true. + * + * \return true if the current thread owns the mutex + */ +extern bool eventOS_scheduler_mutex_am_owner(void); + +#ifdef __cplusplus +} +#endif + +#endif /* EVENTOS_SCHEDULER_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/platform/arm_hal_timer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/platform/arm_hal_timer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ARM_HAL_TIMER_H_ +#define ARM_HAL_TIMER_H_ + +#include "eventloop_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NS_EXCLUDE_HIGHRES_TIMER +/** + * \brief This function perform timer init. + */ +extern void platform_timer_enable(void); + +/** + * \brief This function is API for set Timer interrupt handler for stack + * + * \param new_fp Function pointer for stack giving timer handler + * + */ +typedef void (*platform_timer_cb)(void); +extern void platform_timer_set_cb(platform_timer_cb new_fp); + +/** + * \brief This function is API for stack timer start + * + * \param slots define how many 50us slot time period will be started + * + */ +extern void platform_timer_start(uint16_t slots); + +/** + * \brief This function is API for stack timer stop + * + */ +extern void platform_timer_disable(void); + +/** + * \brief This function is API for stack timer to read active timer remaining slot count + * + * \return 50us time slot remaining + */ +extern uint16_t platform_timer_get_remaining_slots(void); + +#endif // NS_EXCLUDE_HIGHRES_TIMER + +#ifdef NS_EVENTLOOP_USE_TICK_TIMER +/** + * \brief This function is API for registering low resolution tick timer callback. Also does + * any necessary initialization of the tick timer. + * + * \return -1 for failure, success otherwise + */ +extern int8_t platform_tick_timer_register(void (*tick_timer_cb_handler)(void)); + +/** + * \brief This function is API for starting the low resolution tick timer. The callback + * set with platform_tick_timer_register gets called periodically until stopped + * by calling platform_tick_timer_stop. + * + * \param period_ms define how many milliseconds time period will be started + * \return -1 for failure, success otherwise + */ +extern int8_t platform_tick_timer_start(uint32_t period_ms); + +/** + * \brief This function is API for stopping the low resolution tick timer + * + * \return -1 for failure, success otherwise + */ +extern int8_t platform_tick_timer_stop(void); + +#endif // NS_EVENTLOOP_USE_TICK_TIMER + +#ifdef __cplusplus +} +#endif + +#endif /* ARM_HAL_TIMER_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/platform/eventloop_config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/nanostack-event-loop/platform/eventloop_config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EVENTLOOP_CONFIG_H_ +#define EVENTLOOP_CONFIG_H_ + +/* + * Options can be picked up from mbed-cli JSON configuration, or from + * Yotta JSON configuration, or from a user configuration file - see below. + * + * Undefine all internal flags before evaluating the configuration. + */ + +/* Use platform-provided low-resolution tick timer for eventloop (requires "platform_tick_timer" API) */ +#undef NS_EVENTLOOP_USE_TICK_TIMER +/* Exclude high resolution timer from build (removes need for "platform_timer" API) */ +#undef NS_EXCLUDE_HIGHRES_TIMER + +/* + * mbedOS 5 specific configuration flag mapping to internal flags + */ +#ifdef MBED_CONF_NANOSTACK_EVENTLOOP_USE_PLATFORM_TICK_TIMER +#define NS_EVENTLOOP_USE_TICK_TIMER 1 +#endif + +#ifdef MBED_CONF_NANOSTACK_EVENTLOOP_EXCLUDE_HIGHRES_TIMER +#define NS_EXCLUDE_HIGHRES_TIMER 1 +#endif + +/* + * For mbedOS 3 and minar use platform tick timer by default, highres timers should come from eventloop adaptor + */ +#ifdef YOTTA_CFG_MINAR +#define NS_EVENTLOOP_USE_TICK_TIMER 1 +#endif + +/* + * Include the user config file if defined + */ +#ifdef NS_EVENTLOOP_USER_CONFIG_FILE +#include NS_EVENTLOOP_USER_CONFIG_FILE +#endif + +#endif /* EVENTLOOP_CONFIG_H_ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/event.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/event.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <string.h> +#include "ns_types.h" +#include "ns_list.h" +#include "eventOS_event.h" +#include "eventOS_scheduler.h" +#include "timer_sys.h" +#include "nsdynmemLIB.h" +#include "ns_timer.h" +#include "event.h" +#include "platform/arm_hal_interrupt.h" + + +typedef struct arm_core_tasklet { + int8_t id; /**< Event handler Tasklet ID */ + void (*func_ptr)(arm_event_s *); + ns_list_link_t link; +} arm_core_tasklet_t; + +static NS_LIST_DEFINE(arm_core_tasklet_list, arm_core_tasklet_t, link); +static NS_LIST_DEFINE(event_queue_active, arm_event_storage_t, link); +static NS_LIST_DEFINE(free_event_entry, arm_event_storage_t, link); + +// Statically allocate initial pool of events. +#define STARTUP_EVENT_POOL_SIZE 10 +static arm_event_storage_t startup_event_pool[STARTUP_EVENT_POOL_SIZE]; + +/** Curr_tasklet tell to core and platform which task_let is active, Core Update this automatic when switch Tasklet. */ +int8_t curr_tasklet = 0; + + +static arm_core_tasklet_t *tasklet_dynamically_allocate(void); +static arm_event_storage_t *event_dynamically_allocate(void); +static arm_event_storage_t *event_core_get(void); +static void event_core_write(arm_event_storage_t *event); + +static arm_core_tasklet_t *event_tasklet_handler_get(uint8_t tasklet_id) +{ + ns_list_foreach(arm_core_tasklet_t, cur, &arm_core_tasklet_list) { + if (cur->id == tasklet_id) { + return cur; + } + } + return NULL; +} + +bool event_tasklet_handler_id_valid(uint8_t tasklet_id) +{ + return event_tasklet_handler_get(tasklet_id); +} + +// XXX this can return 0, but 0 seems to mean "none" elsewhere? Or at least +// curr_tasklet is reset to 0 in various places. +static int8_t tasklet_get_free_id(void) +{ + /*(Note use of uint8_t to avoid overflow if we reach 0x7F)*/ + for (uint8_t i = 0; i <= INT8_MAX; i++) { + if (!event_tasklet_handler_get(i)) { + return i; + } + } + return -1; +} + + +int8_t eventOS_event_handler_create(void (*handler_func_ptr)(arm_event_s *), uint8_t init_event_type) +{ + arm_event_storage_t *event_tmp; + + // XXX Do we really want to prevent multiple tasklets with same function? + ns_list_foreach(arm_core_tasklet_t, cur, &arm_core_tasklet_list) { + if (cur->func_ptr == handler_func_ptr) { + return -1; + } + } + + //Allocate new + arm_core_tasklet_t *new = tasklet_dynamically_allocate(); + if (!new) { + return -2; + } + + event_tmp = event_core_get(); + if (!event_tmp) { + ns_dyn_mem_free(new); + return -2; + } + + //Fill in tasklet; add to list + new->id = tasklet_get_free_id(); + new->func_ptr = handler_func_ptr; + ns_list_add_to_end(&arm_core_tasklet_list, new); + + //Queue "init" event for the new task + event_tmp->data.receiver = new->id; + event_tmp->data.sender = 0; + event_tmp->data.event_type = init_event_type; + event_tmp->data.event_data = 0; + event_core_write(event_tmp); + + return new->id; +} + +int8_t eventOS_event_send(const arm_event_t *event) +{ + if (event_tasklet_handler_get(event->receiver)) { + arm_event_storage_t *event_tmp = event_core_get(); + if (event_tmp) { + event_tmp->data = *event; + event_core_write(event_tmp); + return 0; + } + } + return -1; +} + +void eventOS_event_send_user_allocated(arm_event_storage_t *event) +{ + event->allocator = ARM_LIB_EVENT_USER; + event_core_write(event); +} + +void eventOS_event_send_timer_allocated(arm_event_storage_t *event) +{ + event->allocator = ARM_LIB_EVENT_TIMER; + event_core_write(event); +} + +void eventOS_event_cancel_critical(arm_event_storage_t *event) +{ + ns_list_remove(&event_queue_active, event); +} + +static arm_event_storage_t *event_dynamically_allocate(void) +{ + arm_event_storage_t *event = ns_dyn_mem_temporary_alloc(sizeof(arm_event_storage_t)); + if (event) { + event->allocator = ARM_LIB_EVENT_DYNAMIC; + } + return event; +} + +static arm_core_tasklet_t *tasklet_dynamically_allocate(void) +{ + return ns_dyn_mem_alloc(sizeof(arm_core_tasklet_t)); +} + +arm_event_storage_t *event_core_get(void) +{ + arm_event_storage_t *event; + platform_enter_critical(); + event = ns_list_get_first(&free_event_entry); + if (event) { + ns_list_remove(&free_event_entry, event); + } else { + event = event_dynamically_allocate(); + } + if (event) { + event->data.data_ptr = NULL; + event->data.priority = ARM_LIB_LOW_PRIORITY_EVENT; + } + platform_exit_critical(); + return event; +} + +void event_core_free_push(arm_event_storage_t *free) +{ + free->state = ARM_LIB_EVENT_UNQUEUED; + + switch (free->allocator) { + case ARM_LIB_EVENT_STARTUP_POOL: + platform_enter_critical(); + ns_list_add_to_start(&free_event_entry, free); + platform_exit_critical(); + break; + case ARM_LIB_EVENT_DYNAMIC: + // Free all dynamically allocated events. + ns_dyn_mem_free(free); + break; + case ARM_LIB_EVENT_TIMER: + // Hand it back to the timer system + timer_sys_event_free(free); + break; + case ARM_LIB_EVENT_USER: + default: + break; + } +} + + +static arm_event_storage_t *event_core_read(void) +{ + platform_enter_critical(); + arm_event_storage_t *event = ns_list_get_first(&event_queue_active); + if (event) { + event->state = ARM_LIB_EVENT_RUNNING; + ns_list_remove(&event_queue_active, event); + } + platform_exit_critical(); + return event; +} + +void event_core_write(arm_event_storage_t *event) +{ + platform_enter_critical(); + bool added = false; + ns_list_foreach(arm_event_storage_t, event_tmp, &event_queue_active) { + // note enum ordering means we're checking if event_tmp is LOWER priority than event + if (event_tmp->data.priority > event->data.priority) { + ns_list_add_before(&event_queue_active, event_tmp, event); + added = true; + break; + } + } + if (!added) { + ns_list_add_to_end(&event_queue_active, event); + } + event->state = ARM_LIB_EVENT_QUEUED; + + /* Wake From Idle */ + platform_exit_critical(); + eventOS_scheduler_signal(); +} + +// Requires lock to be held +arm_event_storage_t *eventOS_event_find_by_id_critical(uint8_t tasklet_id, uint8_t event_id) +{ + ns_list_foreach(arm_event_storage_t, cur, &event_queue_active) { + if (cur->data.receiver == tasklet_id && cur->data.event_id == event_id) { + return cur; + } + } + + return NULL; +} + +/** + * + * \brief Initialize Nanostack Core. + * + * Function Initialize Nanostack Core, Socket Interface,Buffer memory and Send Init event to all Tasklett which are Defined. + * + */ +void eventOS_scheduler_init(void) +{ + /* Reset Event List variables */ + ns_list_init(&free_event_entry); + ns_list_init(&event_queue_active); + ns_list_init(&arm_core_tasklet_list); + + //Add first 10 entries to "free" list + for (unsigned i = 0; i < (sizeof(startup_event_pool) / sizeof(startup_event_pool[0])); i++) { + startup_event_pool[i].allocator = ARM_LIB_EVENT_STARTUP_POOL; + ns_list_add_to_start(&free_event_entry, &startup_event_pool[i]); + } + + /* Init Generic timer module */ + timer_sys_init(); //initialize timer + /* Set Tasklett switcher to Idle */ + curr_tasklet = 0; + +} + +int8_t eventOS_scheduler_get_active_tasklet(void) +{ + return curr_tasklet; +} + +void eventOS_scheduler_set_active_tasklet(int8_t tasklet) +{ + curr_tasklet = tasklet; +} + +int eventOS_scheduler_timer_stop(void) +{ + timer_sys_disable(); + if (ns_timer_sleep() != 0) { + return 1; + } + return 0; +} + +int eventOS_scheduler_timer_synch_after_sleep(uint32_t sleep_ticks) +{ + //Update MS to 10ms ticks + sleep_ticks /= 10; + sleep_ticks++; + system_timer_tick_update(sleep_ticks); + if (timer_sys_wakeup() == 0) { + return 0; + } + return -1; +} + +/** + * + * \brief Infinite Event Read Loop. + * + * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep + * + */ +bool eventOS_scheduler_dispatch_event(void) +{ + curr_tasklet = 0; + + arm_event_storage_t *cur_event = event_core_read(); + if (!cur_event) { + return false; + } + + curr_tasklet = cur_event->data.receiver; + + arm_core_tasklet_t *tasklet = event_tasklet_handler_get(curr_tasklet); + /* Do not bother with check for NULL - tasklets cannot be deleted, + * and user-facing API eventOS_event_send() has already checked the tasklet + * exists, so there is no possible issue there. + * + * For eventOS_event_send_user_allocated(), it would be a non-recoverable + * error to not deliver the message - we have to have a receiver to pass + * ownership to. If the lookup fails, let it crash. We want the send call + * itself to return void to simplify logic. + */ + + /* Tasklet Scheduler Call */ + tasklet->func_ptr(&cur_event->data); + event_core_free_push(cur_event); + + /* Set Current Tasklet to Idle state */ + curr_tasklet = 0; + + return true; +} + +void eventOS_scheduler_run_until_idle(void) +{ + while (eventOS_scheduler_dispatch_event()); +} + +/** + * + * \brief Infinite Event Read Loop. + * + * Function Read and handle Cores Event and switch/enable tasklet which are event receiver. WhenEvent queue is empty it goes to sleep + * + */ +NS_NORETURN void eventOS_scheduler_run(void) +{ + while (1) { + if (!eventOS_scheduler_dispatch_event()) { + eventOS_scheduler_idle(); + } + } +} + +void eventOS_cancel(arm_event_storage_t *event) +{ + if (!event) { + return; + } + + platform_enter_critical(); + + /* + * Notify timer of cancellation. + */ + if (event->allocator == ARM_LIB_EVENT_TIMER) { + timer_sys_event_cancel_critical(event); + } + + /* + * Remove event from the list, + * Only queued can be removed, unqued are either timers or stale pointers + * RUNNING cannot be removed, we are currenly "in" that event. + */ + if (event->state == ARM_LIB_EVENT_QUEUED) { + eventOS_event_cancel_critical(event); + } + + /* + * Push back to "free" state + */ + if (event->state != ARM_LIB_EVENT_RUNNING) { + event_core_free_push(event); + } + + platform_exit_critical(); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/event.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/event.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef NS_EVENT_H_ +#define NS_EVENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +bool event_tasklet_handler_id_valid(uint8_t tasklet_id); +void eventOS_event_send_timer_allocated(arm_event_storage_t *event); + +// This requires lock to be held +arm_event_storage_t *eventOS_event_find_by_id_critical(uint8_t tasklet_id, uint8_t event_id); + +#ifdef __cplusplus +} +#endif + +#endif /*NS_EVENT_H_*/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/minar_hal_timer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/minar_hal_timer.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 ARM Limited, All Rights Reserved + */ + +// Include before mbed.h to properly get UINT*_C() + +#include "ns_types.h" + +#include "platform/arm_hal_timer.h" +#include "platform/arm_hal_interrupt.h" + +#if defined(NS_EVENTLOOP_USE_TICK_TIMER) && defined(YOTTA_CFG_MINAR) + +#include "minar/minar.h" +#include "mbed-drivers/mbed.h" +#include "core-util/FunctionPointer.h" +#include "core-util/Event.h" + +#define TICK_TIMER_ID 1 + +using minar::Scheduler; +using minar::milliseconds; +using minar::callback_handle_t; +using namespace mbed::util; + +static callback_handle_t sys_timer_handle; +static void (*tick_timer_callback)(void); + +void timer_callback(void const *funcArgument) +{ + (void)funcArgument; + if (NULL != tick_timer_callback) { + tick_timer_callback(); + } +} + +// Low precision platform tick timer +int8_t platform_tick_timer_register(void (*tick_timer_cb_handler)(void)) +{ + tick_timer_callback = tick_timer_cb_handler; + return TICK_TIMER_ID; +} + +int8_t platform_tick_timer_start(uint32_t period_ms) +{ + int8_t retval = -1; + if (sys_timer_handle != NULL) { + return 0; // Timer already started already so return success + } + Event e = FunctionPointer1<void, void const *>(timer_callback).bind(NULL); + if (e != NULL) { + sys_timer_handle = Scheduler::postCallback(e).period(milliseconds(period_ms)).getHandle(); + if (sys_timer_handle != NULL) { + retval = 0; + } + } + return retval; +} + +int8_t platform_tick_timer_stop(void) +{ + int8_t retval = -1; + if (sys_timer_handle != NULL) { + Scheduler::cancelCallback(sys_timer_handle); + sys_timer_handle = NULL; + retval = 0; + } + return retval; +} + +#endif // defined(NS_EVENTLOOP_USE_TICK_TIMER) && defined(YOTTA_CFG)
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/ns_timer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/ns_timer.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ns_types.h" +#include "ns_list.h" +#include "ns_timer.h" +#include "eventOS_callback_timer.h" +#include "platform/arm_hal_interrupt.h" +#include "platform/arm_hal_timer.h" +#include "nsdynmemLIB.h" + +#ifndef NS_EXCLUDE_HIGHRES_TIMER +typedef enum ns_timer_state_e { + NS_TIMER_ACTIVE = 0, // Will run on the next HAL interrupt + NS_TIMER_HOLD, // Will run on a later HAL interrupt + NS_TIMER_RUN_INTERRUPT, // Running on the interrupt we're currently handling + NS_TIMER_STOP // Timer not scheduled ("start" not called since last callback) +} ns_timer_state_e; + +typedef struct ns_timer_struct { + int8_t ns_timer_id; + ns_timer_state_e timer_state; + uint16_t slots; + uint16_t remaining_slots; + void (*interrupt_handler)(int8_t, uint16_t); + ns_list_link_t link; +} ns_timer_struct; + +static NS_LIST_DEFINE(ns_timer_list, ns_timer_struct, link); + +#define NS_TIMER_RUNNING 1 +static uint8_t ns_timer_state = 0; + +#ifdef ATMEGA256RFR2 +#define COMPENSATION 3 +#define COMPENSATION_TUNE 1 +#else +#define COMPENSATION 0 +#define COMPENSATION_TUNE 0 +#endif + +static void ns_timer_interrupt_handler(void); +static ns_timer_struct *ns_timer_get_pointer_to_timer_struct(int8_t timer_id); +static bool ns_timer_initialized = 0; + +int8_t eventOS_callback_timer_register(void (*timer_interrupt_handler)(int8_t, uint16_t)) +{ + int8_t retval = -1; + + if (!ns_timer_initialized) { + /*Set interrupt handler in HAL driver*/ + platform_timer_set_cb(ns_timer_interrupt_handler); + ns_timer_initialized = 1; + } + + /*Find first free timer ID in timer list*/ + /*(Note use of uint8_t to avoid overflow if we reach 0x7F)*/ + for (uint8_t i = 0; i <= INT8_MAX; i++) { + if (!ns_timer_get_pointer_to_timer_struct(i)) { + retval = i; + break; + } + } + + if (retval == -1) { + return -1; + } + + ns_timer_struct *new_timer = ns_dyn_mem_alloc(sizeof(ns_timer_struct)); + if (!new_timer) { + return -1; + } + + /*Initialise new timer*/ + new_timer->ns_timer_id = retval; + new_timer->timer_state = NS_TIMER_STOP; + new_timer->remaining_slots = 0; + new_timer->interrupt_handler = timer_interrupt_handler; + + // Critical section sufficient as long as list can't be reordered from + // interrupt, otherwise will need to cover whole routine + platform_enter_critical(); + ns_list_add_to_end(&ns_timer_list, new_timer); + platform_exit_critical(); + + /*Return timer ID*/ + return retval; +} + +int8_t eventOS_callback_timer_unregister(int8_t ns_timer_id) +{ + ns_timer_struct *current_timer; + + current_timer = ns_timer_get_pointer_to_timer_struct(ns_timer_id); + if (!current_timer) { + return -1; + } + + // Critical section sufficient as long as list can't be reordered from + // interrupt, otherwise will need to cover whole routine + platform_enter_critical(); + ns_list_remove(&ns_timer_list, current_timer); + platform_exit_critical(); + + ns_dyn_mem_free(current_timer); + return 0; +} + + +static int8_t ns_timer_start_pl_timer(uint16_t pl_timer_start_slots) +{ + /*Don't start timer with 0 slots*/ + if (!pl_timer_start_slots) { + pl_timer_start_slots = 1; + } + + /*Start HAL timer*/ + platform_timer_start(pl_timer_start_slots); + /*Set HAL timer state to running*/ + ns_timer_state |= NS_TIMER_RUNNING; + return 0; +} + +int8_t ns_timer_sleep(void) +{ + int8_t ret_val = -1; + if (ns_timer_state & NS_TIMER_RUNNING) { + /*Start HAL timer*/ + platform_timer_disable(); + /*Set HAL timer state to running*/ + ns_timer_state &= ~NS_TIMER_RUNNING; + ret_val = 0; + } + return ret_val; +} + +static int8_t ns_timer_get_next_running_to(void) +{ + uint8_t hold_count = 0; + ns_timer_struct *first_timer = NULL; + + /*Find hold-labelled timer with the least remaining slots*/ + ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { + if (current_timer->timer_state == NS_TIMER_HOLD) { + if (!first_timer || current_timer->remaining_slots < first_timer->remaining_slots) { + first_timer = current_timer; + } + /*For optimisation, count the found timers*/ + hold_count++; + } + } + + if (!first_timer) { + return 0; + } + + /*If hold-labelled timer found, set it active and start the HAL driver*/ + hold_count--; + first_timer->timer_state = NS_TIMER_ACTIVE; + /*Compensate time spent in timer function*/ + if (first_timer->remaining_slots > COMPENSATION) { + first_timer->remaining_slots -= COMPENSATION; + } + /*Start HAL timer*/ + ns_timer_start_pl_timer(first_timer->remaining_slots); + + /*Update other hold-labelled timers*/ + ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { + if (hold_count == 0) { // early termination optimisation + break; + } + if (current_timer->timer_state == NS_TIMER_HOLD) { + if (current_timer->remaining_slots == first_timer->remaining_slots) { + current_timer->timer_state = NS_TIMER_ACTIVE; + } else { + current_timer->remaining_slots -= first_timer->remaining_slots; + /*Compensate time spent in timer function*/ + if (current_timer->remaining_slots > COMPENSATION) { + current_timer->remaining_slots -= COMPENSATION; + } + } + hold_count--; + } + } + + return 0; +} + + +static ns_timer_struct *ns_timer_get_pointer_to_timer_struct(int8_t timer_id) +{ + /*Find timer with the given ID*/ + ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { + if (current_timer->ns_timer_id == timer_id) { + return current_timer; + } + } + return NULL; +} + +int8_t eventOS_callback_timer_start(int8_t ns_timer_id, uint16_t slots) +{ + int8_t ret_val = 0; + uint16_t pl_timer_remaining_slots; + ns_timer_struct *timer; + platform_enter_critical(); + + /*Find timer to be activated*/ + timer = ns_timer_get_pointer_to_timer_struct(ns_timer_id); + if (!timer) { + ret_val = -1; + goto exit; + } + + // XXX this assumes the timer currently isn't running? + // Is event.c relying on this restarting HAL timer after ns_timer_sleep()? + + /*If any timers are active*/ + if (ns_timer_state & NS_TIMER_RUNNING) { + /*Get remaining slots of the currently activated timeout*/ + pl_timer_remaining_slots = platform_timer_get_remaining_slots(); + + /*New timeout is shorter than currently enabled timeout*/ + if (pl_timer_remaining_slots > slots) { + /*Start HAL timer*/ + ns_timer_start_pl_timer(slots - 0); + + ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { + /*Switch active timers to hold*/ + if (current_timer->timer_state == NS_TIMER_ACTIVE) { + current_timer->timer_state = NS_TIMER_HOLD; + current_timer->remaining_slots = 0; + } + /*Update hold-labelled timers*/ + if (current_timer->timer_state == NS_TIMER_HOLD) { + current_timer->remaining_slots += (pl_timer_remaining_slots - slots); + /*Compensate time spent in timer function*/ + if (current_timer->remaining_slots > (COMPENSATION - COMPENSATION_TUNE)) { + current_timer->remaining_slots -= (COMPENSATION - COMPENSATION_TUNE); + } + } + } + /*Mark active and start the timer*/ + timer->timer_state = NS_TIMER_ACTIVE; + timer->slots = slots; + timer->remaining_slots = slots; + } + + /*New timeout is longer than currently enabled timeout*/ + else if (pl_timer_remaining_slots < slots) { + /*Mark hold and update remaining slots*/ + timer->timer_state = NS_TIMER_HOLD; + timer->slots = slots; + timer->remaining_slots = (slots - pl_timer_remaining_slots); + } + /*New timeout is equal to currently enabled timeout*/ + else { + /*Mark it active and it will be handled in next interrupt*/ + timer->timer_state = NS_TIMER_ACTIVE; + timer->slots = slots; + timer->remaining_slots = slots; + } + } else { + /*No timers running*/ + timer->timer_state = NS_TIMER_HOLD; + timer->slots = slots; + timer->remaining_slots = slots; + /*Start next timeout*/ + ns_timer_get_next_running_to(); + } +exit: + platform_exit_critical(); + return ret_val; +} + +static void ns_timer_interrupt_handler(void) +{ + uint8_t i = 0; + + platform_enter_critical(); + /*Clear timer running state*/ + ns_timer_state &= ~NS_TIMER_RUNNING; + /*Mark active timers as NS_TIMER_RUN_INTERRUPT, interrupt functions are called at the end of this function*/ + ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { + if (current_timer->timer_state == NS_TIMER_ACTIVE) { + current_timer->timer_state = NS_TIMER_RUN_INTERRUPT; + /*For optimisation, count the found timers*/ + i++; + } + } + + /*Start next timeout*/ + ns_timer_get_next_running_to(); + + /*Call interrupt functions*/ + ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { + if (i == 0) { + break; + } + if (current_timer->timer_state == NS_TIMER_RUN_INTERRUPT) { + current_timer->timer_state = NS_TIMER_STOP; + current_timer->interrupt_handler(current_timer->ns_timer_id, current_timer->slots); + i--; + } + } + + platform_exit_critical(); +} + +int8_t eventOS_callback_timer_stop(int8_t ns_timer_id) +{ + uint16_t pl_timer_remaining_slots; + bool active_timer_found = false; + ns_timer_struct *current_timer; + ns_timer_struct *first_timer = NULL; + int8_t retval = -1; + + platform_enter_critical(); + /*Find timer with given timer ID*/ + current_timer = ns_timer_get_pointer_to_timer_struct(ns_timer_id); + if (!current_timer) { + goto exit; + } + + retval = 0; + + /*Check if already stopped*/ + if (current_timer->timer_state == NS_TIMER_STOP) { + goto exit; + } + + current_timer->timer_state = NS_TIMER_STOP; + current_timer->remaining_slots = 0; + + /*Check if some timer is already active*/ + ns_list_foreach(ns_timer_struct, curr_timer, &ns_timer_list) { + if (curr_timer->timer_state == NS_TIMER_ACTIVE) { + active_timer_found = true; + break; + } + } + /*If no active timers found, start one*/ + if (!active_timer_found) { + pl_timer_remaining_slots = platform_timer_get_remaining_slots(); + /*Find hold-labelled timer with the least remaining slots*/ + ns_list_foreach(ns_timer_struct, cur_timer, &ns_timer_list) { + if (cur_timer->timer_state == NS_TIMER_HOLD) { + cur_timer->remaining_slots += pl_timer_remaining_slots; + + if (!first_timer || cur_timer->remaining_slots < first_timer->remaining_slots) { + first_timer = cur_timer; + } + } + } + /*If hold-labelled timer found, set it active and start the HAL driver*/ + if (first_timer) { + first_timer->timer_state = NS_TIMER_ACTIVE; + /*Start HAL timer*/ + ns_timer_start_pl_timer(first_timer->remaining_slots); + /*If some of the other hold-labelled timers have the same remaining slots as the timer_tmp, mark them active*/ + ns_list_foreach(ns_timer_struct, cur_timer, &ns_timer_list) { + if (cur_timer->timer_state == NS_TIMER_HOLD) { + if (cur_timer->remaining_slots == first_timer->remaining_slots) { + cur_timer->timer_state = NS_TIMER_ACTIVE; + } else { + cur_timer->remaining_slots -= first_timer->remaining_slots; + } + } + } + } + } + +exit: + platform_exit_critical(); + + return retval; +} +#endif // NS_EXCLUDE_HIGHRES_TIMER
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/ns_timer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/ns_timer.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef NS_TIMER_H_ +#define NS_TIMER_H_ + +#include "platform/eventloop_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NS_EXCLUDE_HIGHRES_TIMER +extern int8_t ns_timer_sleep(void); +#else +#define ns_timer_sleep() ((int8_t) 0) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*NS_TIMER_H_*/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/system_timer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/system_timer.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ns_types.h" +#include "ns_list.h" +#include "timer_sys.h" +#include "platform/arm_hal_interrupt.h" +#include "platform/arm_hal_timer.h" +#include "nsdynmemLIB.h" +#include "eventOS_event.h" +#include "eventOS_event_timer.h" +#include "event.h" +#include "eventOS_callback_timer.h" + +#include "ns_timer.h" + +#ifndef ST_MAX +#define ST_MAX 6 +#endif + +static sys_timer_struct_s startup_sys_timer_pool[ST_MAX]; + +#define TIMER_SLOTS_PER_MS 20 +NS_STATIC_ASSERT(1000 % EVENTOS_EVENT_TIMER_HZ == 0, "Need whole number of ms per tick") +#define TIMER_SYS_TICK_PERIOD (1000 / EVENTOS_EVENT_TIMER_HZ) // milliseconds + +// timer_sys_ticks must be read in critical section to guarantee +// atomicity on 16-bit platforms +static volatile uint32_t timer_sys_ticks; + +static NS_LIST_DEFINE(system_timer_free, sys_timer_struct_s, event.link); +static NS_LIST_DEFINE(system_timer_list, sys_timer_struct_s, event.link); + + +static sys_timer_struct_s *sys_timer_dynamically_allocate(void); +static void timer_sys_interrupt(void); +static void timer_sys_add(sys_timer_struct_s *timer); + +#ifndef NS_EVENTLOOP_USE_TICK_TIMER +static int8_t platform_tick_timer_start(uint32_t period_ms); +/* Implement platform tick timer using eventOS timer */ +// platform tick timer callback function +static void (*tick_timer_callback)(void); +static int8_t tick_timer_id = -1; // eventOS timer id for tick timer + +// EventOS timer callback function +static void tick_timer_eventOS_callback(int8_t timer_id, uint16_t slots) +{ + // Not interested in timer id or slots + (void)slots; + // Call the tick timer callback + if (tick_timer_callback != NULL && timer_id == tick_timer_id) { + platform_tick_timer_start(TIMER_SYS_TICK_PERIOD); + tick_timer_callback(); + } +} + +static int8_t platform_tick_timer_register(void (*tick_timer_cb)(void)) +{ + tick_timer_callback = tick_timer_cb; + tick_timer_id = eventOS_callback_timer_register(tick_timer_eventOS_callback); + return tick_timer_id; +} + +static int8_t platform_tick_timer_start(uint32_t period_ms) +{ + return eventOS_callback_timer_start(tick_timer_id, TIMER_SLOTS_PER_MS * period_ms); +} + +static int8_t platform_tick_timer_stop(void) +{ + return eventOS_callback_timer_stop(tick_timer_id); +} +#endif // !NS_EVENTLOOP_USE_TICK_TIMER + +/* + * Initializes timers and starts system timer + */ +void timer_sys_init(void) +{ + for (uint8_t i = 0; i < ST_MAX; i++) { + ns_list_add_to_start(&system_timer_free, &startup_sys_timer_pool[i]); + } + + platform_tick_timer_register(timer_sys_interrupt); + platform_tick_timer_start(TIMER_SYS_TICK_PERIOD); +} + + + +/*-------------------SYSTEM TIMER FUNCTIONS--------------------------*/ +void timer_sys_disable(void) +{ + platform_tick_timer_stop(); +} + +/* + * Starts ticking system timer interrupts every 10ms + */ +int8_t timer_sys_wakeup(void) +{ + return platform_tick_timer_start(TIMER_SYS_TICK_PERIOD); +} + + +static void timer_sys_interrupt(void) +{ + system_timer_tick_update(1); +} + + + +/* * * * * * * * * */ + +static sys_timer_struct_s *sys_timer_dynamically_allocate(void) +{ + return ns_dyn_mem_alloc(sizeof(sys_timer_struct_s)); +} + +static sys_timer_struct_s *timer_struct_get(void) +{ + sys_timer_struct_s *timer; + platform_enter_critical(); + timer = ns_list_get_first(&system_timer_free); + if (timer) { + ns_list_remove(&system_timer_free, timer); + } else { + timer = sys_timer_dynamically_allocate(); + } + platform_exit_critical(); + return timer; +} + +void timer_sys_event_free(arm_event_storage_t *event) +{ + platform_enter_critical(); + sys_timer_struct_s *timer = NS_CONTAINER_OF(event, sys_timer_struct_s, event); + if (timer->period == 0) { + // Non-periodic - return to free list + ns_list_add_to_start(&system_timer_free, timer); + } else { + // Periodic - check due time of next launch + timer->launch_time += timer->period; + if (TICKS_BEFORE_OR_AT(timer->launch_time, timer_sys_ticks)) { + // next event is overdue - queue event now + eventOS_event_send_timer_allocated(&timer->event); + } else { + // add back to timer queue for the future + timer_sys_add(timer); + } + } + platform_exit_critical(); +} + +void timer_sys_event_cancel_critical(struct arm_event_storage *event) +{ + sys_timer_struct_s *timer = NS_CONTAINER_OF(event, sys_timer_struct_s, event); + timer->period = 0; + // If its unqueued it is on my timer list, otherwise it is in event-loop. + if (event->state == ARM_LIB_EVENT_UNQUEUED) { + ns_list_remove(&system_timer_list, timer); + } +} + +uint32_t eventOS_event_timer_ticks(void) +{ + uint32_t ret_val; + // Enter/exit critical is a bit clunky, but necessary on 16-bit platforms, + // which won't be able to do an atomic 32-bit read. + platform_enter_critical(); + ret_val = timer_sys_ticks; + platform_exit_critical(); + return ret_val; +} + +/* Called internally with lock held */ +static void timer_sys_add(sys_timer_struct_s *timer) +{ + uint32_t at = timer->launch_time; + + // Find first timer scheduled to run after us, and insert before it. + // (This means timers scheduled for same time run in order of request) + ns_list_foreach(sys_timer_struct_s, t, &system_timer_list) { + if (TICKS_BEFORE(at, t->launch_time)) { + ns_list_add_before(&system_timer_list, t, timer); + return; + } + } + + // Didn't insert before another timer, so must be last. + ns_list_add_to_end(&system_timer_list, timer); +} + +/* Called internally with lock held */ +static arm_event_storage_t *eventOS_event_timer_request_at_(const arm_event_t *event, uint32_t at, uint32_t period) +{ + // Because we use user-allocated events, they must get delivered to avoid + // a leak. Previously this call queued timers for invalid tasks, then they + // would go undelivered. Now it returns an error. + if (!event_tasklet_handler_id_valid(event->receiver)) { + return NULL; + } + + sys_timer_struct_s *timer = timer_struct_get(); + if (!timer) { + return NULL; + } + + timer->event.data = *event; + timer->event.allocator = ARM_LIB_EVENT_TIMER; + timer->event.state = ARM_LIB_EVENT_UNQUEUED; + timer->launch_time = at; + timer->period = period; + + if (TICKS_BEFORE_OR_AT(at, timer_sys_ticks)) { + eventOS_event_send_timer_allocated(&timer->event); + } else { + timer_sys_add(timer); + } + + return &timer->event; +} + +arm_event_storage_t *eventOS_event_timer_request_at(const arm_event_t *event, uint32_t at) +{ + platform_enter_critical(); + + arm_event_storage_t *ret = eventOS_event_timer_request_at_(event, at, 0); + + platform_exit_critical(); + + return ret; +} + +arm_event_storage_t *eventOS_event_timer_request_in(const arm_event_t *event, int32_t in) +{ + platform_enter_critical(); + + arm_event_storage_t *ret = eventOS_event_timer_request_at_(event, timer_sys_ticks + in, 0); + + platform_exit_critical(); + + return ret; + +} + +arm_event_storage_t *eventOS_event_timer_request_every(const arm_event_t *event, int32_t period) +{ + if (period <= 0) { + return NULL; + } + + platform_enter_critical(); + + arm_event_storage_t *ret = eventOS_event_timer_request_at_(event, timer_sys_ticks + period, period); + + platform_exit_critical(); + + return ret; + +} + +int8_t eventOS_event_timer_request(uint8_t event_id, uint8_t event_type, int8_t tasklet_id, uint32_t time) +{ + const arm_event_t event = { + .event_id = event_id, + .event_type = event_type, + .receiver = tasklet_id, + .sender = 0, + .data_ptr = NULL, + .event_data = 0, + .priority = ARM_LIB_MED_PRIORITY_EVENT, + }; + + // Legacy time behaviour preserved + + // Note that someone wanting 20ms gets 2 ticks, thanks to this test. 30ms would be 4 ticks. + // And why shouldn't they be able to get a 1-tick callback? + if (time > 2 * TIMER_SYS_TICK_PERIOD) { + time /= TIMER_SYS_TICK_PERIOD; + // XXX Why this? Someone wanting 50ms shouldn't get 6 ticks. Round to nearest, maybe? + time++; + } else { + time = 2; + } + + platform_enter_critical(); + arm_event_storage_t *ret = eventOS_event_timer_request_at_(&event, timer_sys_ticks + time, 0); + platform_exit_critical(); + return ret?0:-1; +} + +int8_t eventOS_event_timer_cancel(uint8_t event_id, int8_t tasklet_id) +{ + platform_enter_critical(); + + /* First check pending timers */ + ns_list_foreach(sys_timer_struct_s, cur, &system_timer_list) { + if (cur->event.data.receiver == tasklet_id && cur->event.data.event_id == event_id) { + eventOS_cancel(&cur->event); + goto done; + } + } + + /* No pending timer, so check for already-pending event */ + arm_event_storage_t *event = eventOS_event_find_by_id_critical(tasklet_id, event_id); + if (event && event->allocator == ARM_LIB_EVENT_TIMER) { + eventOS_cancel(event); + goto done; + } + + /* No match found */ + platform_exit_critical(); + return -1; + +done: + platform_exit_critical(); + return 0; +} + +uint32_t eventOS_event_timer_shortest_active_timer(void) +{ + uint32_t ret_val = 0; + + platform_enter_critical(); + sys_timer_struct_s *first = ns_list_get_first(&system_timer_list); + if (first == NULL) { + // Weird API has 0 for "no events" + ret_val = 0; + } else if (TICKS_BEFORE_OR_AT(first->launch_time, timer_sys_ticks)) { + // Which means an immediate/overdue event has to be 1 + ret_val = 1; + } else { + ret_val = first->launch_time - timer_sys_ticks; + } + + platform_exit_critical(); + return eventOS_event_timer_ticks_to_ms(ret_val); +} + +void system_timer_tick_update(uint32_t ticks) +{ + platform_enter_critical(); + //Keep runtime time + timer_sys_ticks += ticks; + ns_list_foreach_safe(sys_timer_struct_s, cur, &system_timer_list) { + if (TICKS_BEFORE_OR_AT(cur->launch_time, timer_sys_ticks)) { + // Unthread from our list + ns_list_remove(&system_timer_list, cur); + // Make it an event (can't fail - no allocation) + // event system will call our timer_sys_event_free on event delivery. + eventOS_event_send_timer_allocated(&cur->event); + } else { + // List is ordered, so as soon as we see a later event, we're done. + break; + } + } + + platform_exit_critical(); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/timeout.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/timeout.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "eventOS_event.h" +#include "eventOS_event_timer.h" +#include "nsdynmemLIB.h" +#include "ns_list.h" +#include "timer_sys.h" + +#define STARTUP_EVENT 0 +#define TIMER_EVENT 1 + +// Timeout structure, already typedefed to timeout_t +struct timeout_entry_t { + void (*callback)(void *); + void *arg; + arm_event_storage_t *event; +}; + +static int8_t timeout_tasklet_id = -1; + +static void timeout_tasklet(arm_event_s *event) +{ + if (TIMER_EVENT != event->event_type) { + return; + } + + timeout_t *t = event->data_ptr; + arm_event_storage_t *storage = t->event; + sys_timer_struct_s *timer = NS_CONTAINER_OF(storage, sys_timer_struct_s, event); + + t->callback(t->arg); + + + // Check if this was periodic timer + if (timer->period == 0) { + ns_dyn_mem_free(event->data_ptr); + } +} + +static timeout_t *eventOS_timeout_at_(void (*callback)(void *), void *arg, uint32_t at, uint32_t period) +{ + arm_event_storage_t *storage; + + timeout_t *timeout = ns_dyn_mem_alloc(sizeof(timeout_t)); + if (!timeout) { + return NULL; + } + timeout->callback = callback; + timeout->arg = arg; + + // Start timeout taskled if it is not running + if (-1 == timeout_tasklet_id) { + timeout_tasklet_id = eventOS_event_handler_create(timeout_tasklet, STARTUP_EVENT); + if (timeout_tasklet_id < 0) { + timeout_tasklet_id = -1; + goto FAIL; + } + } + + arm_event_t event = { + .receiver = timeout_tasklet_id, + .sender = timeout_tasklet_id, + .event_type = TIMER_EVENT, + .event_id = TIMER_EVENT, + .data_ptr = timeout + }; + + if (period) + storage = eventOS_event_timer_request_every(&event, period); + else + storage = eventOS_event_timer_request_at(&event, at); + + timeout->event = storage; + if (storage) + return timeout; +FAIL: + ns_dyn_mem_free(timeout); + return NULL; +} + +timeout_t *eventOS_timeout_ms(void (*callback)(void *), uint32_t ms, void *arg) +{ + return eventOS_timeout_at_(callback, arg, eventOS_event_timer_ms_to_ticks(ms)+eventOS_event_timer_ticks(), 0); +} + +timeout_t *eventOS_timeout_every_ms(void (*callback)(void *), uint32_t every, void *arg) +{ + return eventOS_timeout_at_(callback, arg, 0, eventOS_event_timer_ms_to_ticks(every)); +} + +void eventOS_timeout_cancel(timeout_t *t) +{ + if (!t) + return; + + eventOS_cancel(t->event); + + // Defer the freeing until returning from the callback + if (t->event->state != ARM_LIB_EVENT_RUNNING) { + ns_dyn_mem_free(t); + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/timer_sys.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/sal-stack-nanostack-eventloop/source/timer_sys.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _PL_NANO_TIMER_SYS_H_ +#define _PL_NANO_TIMER_SYS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "eventOS_event.h" + +/* We borrow base event storage, including its list link, and add a time field */ +typedef struct sys_timer_struct_s { + arm_event_storage_t event; + uint32_t launch_time; // tick value + uint32_t period; +} sys_timer_struct_s; + + +/** + * Initialize system timer + * */ +extern void timer_sys_init(void); + +extern uint32_t timer_get_runtime_ticks(void); +int8_t timer_sys_wakeup(void); +void timer_sys_disable(void); +void timer_sys_event_free(struct arm_event_storage *event); + +// This require lock to be held +void timer_sys_event_cancel_critical(struct arm_event_storage *event); + +/** + * System Timer update and synch after sleep + * + * \param ticks Time in 10 ms resolution + * + * \return none + * + * */ +void system_timer_tick_update(uint32_t ticks); + +#ifdef __cplusplus +} +#endif + +#endif /*_PL_NANO_TIMER_SYS_H_*/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/CertificateParser.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/CertificateParser.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,53 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <stdint.h> +#include "pal.h" +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "mClt" + +bool extract_cn_from_certificate(const uint8_t* cer, size_t cer_len, char* common_name) +{ + tr_debug("extract_cn_from_certificate"); + palX509Handle_t cert; + size_t len; + palStatus_t ret; + + ret = pal_x509Initiate(&cert); + if (ret != PAL_SUCCESS) { + tr_error("extract_cn_from_certificate - cert init failed: %d", (int)ret); + pal_x509Free(&cert); + return false; + } + ret = pal_x509CertParse(cert, cer, cer_len); + if (ret != PAL_SUCCESS) { + tr_error("extract_cn_from_certificate - cert parse failed: %d", (int)ret); + pal_x509Free(&cert); + return false; + } + ret = pal_x509CertGetAttribute(cert, PAL_X509_CN_ATTR, common_name, 64, &len); + if (ret != PAL_SUCCESS) { + tr_error("extract_cn_from_certificate - cert attr get failed: %d", (int)ret); + pal_x509Free(&cert); + return false; + } + pal_x509Free(&cert); + return true; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/CloudClientStorage.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/CloudClientStorage.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,384 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <string.h> +#include "key_config_manager.h" +#include "CloudClientStorage.h" +#include "mbed-trace/mbed_trace.h" + +#define TRACE_GROUP "mClt" + +ccs_status_e uninitialize_storage(void) +{ + tr_debug("CloudClientStorage::uninitialize_storage"); + + kcm_status_e status = kcm_finalize(); + if(status != KCM_STATUS_SUCCESS) { + tr_error("CloudClientStorage::uninitialize_storage - error %d", status); + return CCS_STATUS_ERROR; + } + return CCS_STATUS_SUCCESS; +} + +ccs_status_e initialize_storage(void) +{ + tr_debug("CloudClientStorage::initialize_storage"); + kcm_status_e status = kcm_init(); + if(status != KCM_STATUS_SUCCESS) { + tr_error("CloudClientStorage::::initialize_storage - error %d", status); + return CCS_STATUS_ERROR; + } + return CCS_STATUS_SUCCESS; +} + +ccs_status_e get_config_parameter(const char* key, uint8_t *buffer, const size_t buffer_size, size_t *value_length) +{ + if (key == NULL || buffer == NULL || buffer_size == 0) { + tr_error("CloudClientStorage::get_config_parameter error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::get_config_parameter [%s]", key); + + // Get parameter value to buffer + kcm_status_e kcm_status = kcm_item_get_data((const uint8_t*)key, + strlen(key), + KCM_CONFIG_ITEM, + buffer, + buffer_size, + value_length); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::get_config_parameter [%s] kcm get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e get_config_parameter_string(const char* key, uint8_t *buffer, const size_t buffer_size) +{ + size_t len = 0; + ccs_status_e status = get_config_parameter(key, buffer, buffer_size - 1, &len); + + if (status == CCS_STATUS_SUCCESS) { + // Null terminate after buffer value + buffer[len] = 0; + } + + return status; +} + + +ccs_status_e set_config_parameter(const char* key, const uint8_t *buffer, const size_t buffer_size) +{ + if (key == NULL || buffer == NULL || buffer_size == 0) { + tr_error("CloudClientStorage::set_config_parameter error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::set_config_parameter [%s]", key); + + // Set parameter to storage + kcm_status_e kcm_status = kcm_item_store((const uint8_t*)key, + strlen(key), + KCM_CONFIG_ITEM, + false, + buffer, + buffer_size, + NULL); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::set_config_parameter [%s] kcm get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e delete_config_parameter(const char* key) +{ + if (key == NULL) { + tr_error("CloudClientStorage::delete_config_parameter error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::delete_config_parameter [%s]", key); + + // Delete parameter from storage + kcm_status_e kcm_status = kcm_item_delete((const uint8_t*)key, + strlen(key), + KCM_CONFIG_ITEM); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::delete_config_parameter [%s] kcm get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e size_config_parameter(const char* key, size_t* size_out) +{ + if (key == NULL) { + tr_error("CloudClientStorage::size_config_parameter error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::size_config_parameter [%s]", key); + + // Delete parameter from storage + kcm_status_e kcm_status = kcm_item_get_data_size((const uint8_t*)key, + strlen(key), + KCM_CONFIG_ITEM, + size_out); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::size_config_parameter [%s] kcm get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e get_config_private_key(const char* key, uint8_t *buffer, const size_t buffer_size, size_t *value_length) +{ + if (key == NULL || buffer == NULL || buffer_size == 0) { + tr_error("CloudClientStorage::get_connector_private_key error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::get_connector_private_key [%s]", key); + + // Get private key from storage + kcm_status_e kcm_status = kcm_item_get_data((const uint8_t*)key, + strlen(key), + KCM_PRIVATE_KEY_ITEM, + buffer, + buffer_size, + value_length); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::get_connector_private_key [%s] kcm get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e set_config_private_key(const char* key, const uint8_t *buffer, const size_t buffer_size) +{ + if (key == NULL || buffer == NULL || buffer_size == 0) { + tr_error("CloudClientStorage::set_connector_private_key error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::set_connector_private_key kcm [%s]", key); + + // Set private key to storage + kcm_status_e kcm_status = kcm_item_store((const uint8_t*)key, + strlen(key), + KCM_PRIVATE_KEY_ITEM, + false, + buffer, + buffer_size, + NULL); + + if (kcm_status == KCM_CRYPTO_STATUS_PRIVATE_KEY_VERIFICATION_FAILED) { + tr_error("CloudClientStorage::set_connector_private_key kcm validation error"); + return CCS_STATUS_VALIDATION_FAIL; + } + else if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::set_connector_private_key kcm [%s] get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e delete_config_private_key(const char* key) +{ + if (key == NULL) { + tr_error("CloudClientStorage::delete_config_private_key error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::delete_config_private_key [%s]", key); + + // Delete private key from storage + kcm_status_e kcm_status = kcm_item_delete((const uint8_t*)key, + strlen(key), + KCM_PRIVATE_KEY_ITEM); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::delete_config_private_key [%s] kcm get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e get_config_public_key(const char* key, uint8_t *buffer, const size_t buffer_size, size_t *value_length) +{ + if (key == NULL || buffer == NULL || buffer_size == 0) { + tr_error("CloudClientStorage::get_config_public_key error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::get_config_public_key [%s]", key); + + // Get parameter value to buffer + kcm_status_e kcm_status = kcm_item_get_data((const uint8_t*)key, + strlen(key), + KCM_PUBLIC_KEY_ITEM, + buffer, + buffer_size, + value_length); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::get_config_public_key [%s] kcm get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e set_config_public_key(const char* key, const uint8_t *buffer, const size_t buffer_size) +{ + if (key == NULL || buffer == NULL || buffer_size == 0) { + tr_error("CloudClientStorage::set_config_public_key error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::set_config_public_key - kcm [%s]", key); + + // Set public key to storage + kcm_status_e kcm_status = kcm_item_store((const uint8_t*)key, + strlen(key), + KCM_PUBLIC_KEY_ITEM, + false, + buffer, + buffer_size, + NULL); + + if (kcm_status == KCM_CRYPTO_STATUS_PUBLIC_KEY_VERIFICATION_FAILED) { + tr_error("CloudClientStorage::set_config_public_key - kcm validation error"); + return CCS_STATUS_VALIDATION_FAIL; + } + else if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::set_config_public_key - kcm [%s] get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e delete_config_public_key(const char* key) +{ + if (key == NULL) { + tr_error("CloudClientStorage::delete_config_public_key error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::delete_config_public_key [%s]", key); + + // Delete the public key + kcm_status_e kcm_status = kcm_item_delete((const uint8_t*)key, + strlen(key), + KCM_PUBLIC_KEY_ITEM); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::delete_config_public_key [%s] kcm get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e get_config_certificate(const char* key, uint8_t *buffer, const size_t buffer_size, size_t *value_length) +{ + if (key == NULL || buffer == NULL || buffer_size == 0) { + tr_error("CloudClientStorage::get_config_certificate error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::get_config_certificate kcm [%s]", key); + + // Get parameter value to buffer + kcm_status_e kcm_status = kcm_item_get_data((const uint8_t*)key, + strlen(key), + KCM_CERTIFICATE_ITEM, + buffer, + buffer_size, + value_length); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::get_config_certificate kcm [%s] get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e set_config_certificate(const char* key, const uint8_t *buffer, const size_t buffer_size) +{ + if (key == NULL || buffer == NULL || buffer_size == 0) { + tr_error("CloudClientStorage::set_config_certificate error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::set_config_certificate kcm [%s]", key); + + // Get parameter value to buffer + kcm_status_e kcm_status = kcm_item_store((const uint8_t*)key, + strlen(key), + KCM_CERTIFICATE_ITEM, + false, + buffer, + buffer_size, + NULL); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::set_config_certificate kcm [%s] get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +} + +ccs_status_e delete_config_certificate(const char* key) +{ + if (key == NULL) { + tr_error("CloudClientStorage::delete_config_certificate error, invalid parameters"); + return CCS_STATUS_ERROR; + } + + tr_debug("CloudClientStorage::delete_config_certificate kcm [%s]", key); + + // Get parameter value to buffer + kcm_status_e kcm_status = kcm_item_delete((const uint8_t*)key, + strlen(key), + KCM_CERTIFICATE_ITEM); + + if (kcm_status != KCM_STATUS_SUCCESS) { + tr_debug("CloudClientStorage::delete_config_certificate kcm [%s] get error %d", key, kcm_status); + return CCS_STATUS_ERROR; + } + + return CCS_STATUS_SUCCESS; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/ConnectorClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/ConnectorClient.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,896 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <string> +#include <assert.h> +#include <stdio.h> +#include "include/ConnectorClient.h" +#include "include/CloudClientStorage.h" +#include "include/CertificateParser.h" +#include "MbedCloudClient.h" +#include "mbed-client/m2minterfacefactory.h" +#include "mbed-client/m2mdevice.h" +#include "mbed-trace/mbed_trace.h" +#include "factory_configurator_client.h" + +#define TRACE_GROUP "mClt" + +#define INTERNAL_ENDPOINT_PARAM "&iep=" +#define DEFAULT_ENDPOINT "endpoint" +#define INTERFACE_ERROR "Client interface is not created. Restart" +#define CREDENTIAL_ERROR "Failed to read credentials from storage" +#define DEVICE_NOT_PROVISIONED "Device not provisioned" +#define ERROR_NO_MEMORY "Not enough memory to stroe LWM2M credentials" + +// XXX: nothing here yet +class EventData { + +}; + +ConnectorClient::ConnectorClient(ConnectorClientCallback* callback) +: _callback(callback), + _current_state(State_Bootstrap_Start), + _event_generated(false), _state_engine_running(false), + _interface(NULL), _security(NULL), + _endpoint_info(M2MSecurity::Certificate), _client_objs(NULL), + _rebootstrap_timer(*this), _bootstrap_security_instance(1), _lwm2m_security_instance(0) +{ + assert(_callback != NULL); + + // Create the lwm2m server security object we need always + _security = M2MInterfaceFactory::create_security(M2MSecurity::M2MServer); + _interface = M2MInterfaceFactory::create_interface(*this, + DEFAULT_ENDPOINT, // endpoint name string + MBED_CLOUD_CLIENT_ENDPOINT_TYPE, // endpoint type string + MBED_CLOUD_CLIENT_LIFETIME, // lifetime + MBED_CLOUD_CLIENT_LISTEN_PORT, // listen port + _endpoint_info.account_id, // domain string + transport_mode(), // binding mode + M2MInterface::LwIP_IPv4); // network stack + + initialize_storage(); +} + + +ConnectorClient::~ConnectorClient() +{ + M2MDevice::delete_instance(); + M2MSecurity::delete_instance(); + delete _interface; +} + +void ConnectorClient::start_bootstrap() +{ + tr_debug("ConnectorClient::start_bootstrap()"); + assert(_callback != NULL); + // Stop rebootstrap timer if it was running + _rebootstrap_timer.stop_timer(); + if (create_bootstrap_object()) { + _interface->update_endpoint(_endpoint_info.endpoint_name); + _interface->update_domain(_endpoint_info.account_id); + internal_event(State_Bootstrap_Start); + } else { + tr_error("ConnectorClient::start_bootstrap() - bootstrap object fail"); + } + state_engine(); +} + +void ConnectorClient::start_registration(M2MObjectList* client_objs) +{ + tr_debug("ConnectorClient::start_registration()"); + assert(_callback != NULL); + _client_objs = client_objs; + + // XXX: actually this call should be external_event() to match the pattern used in other m2m classes + create_register_object(); + if(_security->get_security_instance_id(M2MSecurity::M2MServer) >= 0) { + if(use_bootstrap()) { + // Bootstrap registration always uses iep + _interface->update_endpoint(_endpoint_info.internal_endpoint_name); + } else { + // Registration without bootstrap always uses external id + _interface->update_endpoint(_endpoint_info.endpoint_name); + } + _interface->update_domain(_endpoint_info.account_id); + internal_event(State_Registration_Start); + } else { + tr_error("ConnectorClient::state_init(): failed to create objs"); + _callback->connector_error(M2MInterface::InvalidParameters, INTERFACE_ERROR); + } + state_engine(); +} + +M2MInterface * ConnectorClient::m2m_interface() +{ + return _interface; +} + +void ConnectorClient::update_registration() +{ + if(_interface && _security && _security->get_security_instance_id(M2MSecurity::M2MServer) >= 0) { + if (_client_objs != NULL) { + _interface->update_registration(_security, *_client_objs); + } + else { + _interface->update_registration(_security); + } + } +} + +// generates an internal event. called from within a state +// function to transition to a new state +void ConnectorClient::internal_event(StartupSubStateRegistration new_state) +{ + tr_debug("ConnectorClient::internal_event: state: %d -> %d", _current_state, new_state); + _event_generated = true; + _current_state = new_state; + + // Avoid recursive chain which eats too much of stack + if (!_state_engine_running) { + state_engine(); + } +} + +// the state engine executes the state machine states +void ConnectorClient::state_engine(void) +{ + tr_debug("ConnectorClient::state_engine"); + + // this simple flagging gets rid of recursive calls to this method + _state_engine_running = true; + + // while events are being generated keep executing states + while (_event_generated) { + _event_generated = false; // event used up, reset flag + + state_function(_current_state); + } + + _state_engine_running = false; +} + +void ConnectorClient::state_function(StartupSubStateRegistration current_state) +{ + switch (current_state) { + case State_Bootstrap_Start: + state_bootstrap_start(); + break; + case State_Bootstrap_Started: + state_bootstrap_started(); + break; + case State_Bootstrap_Success: + state_bootstrap_success(); + break; + case State_Bootstrap_Failure: + state_bootstrap_failure(); + break; + case State_Registration_Start: + state_registration_start(); + break; + case State_Registration_Started: + state_registration_started(); + break; + case State_Registration_Success: + state_registration_success(); + break; + case State_Registration_Failure: + state_registration_failure(); + break; + case State_Unregistered: + state_unregistered(); + break; + default: + break; + } +} + +/* +* Creates register server object with mbed device server address and other parameters +* required for client to connect to mbed device server. +*/ +void ConnectorClient::create_register_object() +{ + tr_debug("ConnectorClient::create_register_object()"); + if(_security && _security->get_security_instance_id(M2MSecurity::M2MServer) == -1) { + _security->create_object_instance(M2MSecurity::M2MServer); + int32_t m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer); + _security->set_resource_value(M2MSecurity::BootstrapServer, M2MSecurity::M2MServer, m2m_id); + // Add ResourceID's and values to the security ObjectID/ObjectInstance + _security->set_resource_value(M2MSecurity::SecurityMode, _endpoint_info.mode, m2m_id); + + // Allocate scratch buffer, this will be used to copy parameters from storage to security object + const int max_size = 2048; + uint8_t *buffer = (uint8_t*)malloc(max_size); + size_t real_size = 0; + bool success = false; + if (buffer != NULL) { + success = true; + } + + // Connector CA + if (success) { + success = false; + if (get_config_certificate(g_fcc_lwm2m_server_ca_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + tr_info("ConnectorClient::create_register_object - ServerPublicKey %d", (int)real_size); + success = true; + _security->set_resource_value(M2MSecurity::ServerPublicKey, + buffer, + (uint32_t)real_size, + m2m_id); + } + else { + tr_error("KEY_CONNECTOR_CA cert failed."); + } + } + + // Connector device public key + if (success) { + success = false; + if (get_config_certificate(g_fcc_lwm2m_device_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + tr_info("ConnectorClient::create_register_object - PublicKey %d", (int)real_size); + success = true; + _security->set_resource_value(M2MSecurity::PublicKey, buffer, (uint32_t)real_size, m2m_id); + } + else { + tr_error("KEY_CONNECTOR__DEVICE_CERT failed."); + } + } + + // Connector device private key + if (success) { + success = false; + if (get_config_private_key(g_fcc_lwm2m_device_private_key_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + tr_info("ConnectorClient::create_register_object - SecretKey %d", (int)real_size); + success = true; + _security->set_resource_value(M2MSecurity::Secretkey, buffer, (uint32_t)real_size, m2m_id); + } + else + tr_error("KEY_CONNECTOR_DEVICE_PRIV failed."); + } + + // Connector URL + if (success) { + success = false; + if (get_config_parameter(g_fcc_lwm2m_server_uri_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + tr_info("ConnectorClient::create_register_object - M2MServerUri %.*s", (int)real_size, buffer); + success = true; + _security->set_resource_value(M2MSecurity::M2MServerUri, buffer, (uint32_t)real_size, m2m_id); + } + else + tr_error("KEY_CONNECTOR_URL failed."); + } + + // Endpoint + if (success) { + success = false; + if (get_config_parameter(g_fcc_endpoint_parameter_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + tr_info("ConnectorClient::create_register_object - endpoint name %.*s", (int)real_size, buffer); + success = true; + _endpoint_info.endpoint_name = String((const char*)buffer, real_size); + } + else + tr_error("KEY_ENDPOINT_NAME failed."); + } + + // Try to get internal endpoint name + if (success) { + if (get_config_parameter(KEY_INTERNAL_ENDPOINT, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + _endpoint_info.internal_endpoint_name = String((const char*)buffer, real_size); + tr_info("Using internal endpoint name instead: %s", _endpoint_info.internal_endpoint_name.c_str()); + } + else { + tr_debug("KEY_INTERNAL_ENDPOINT failed."); + } + } + + // Account ID, not mandatory + if (success) { + if (get_config_parameter(KEY_ACCOUNT_ID, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + tr_info("ConnectorClient::create_register_object - AccountId %.*s", (int)real_size, buffer); + _endpoint_info.account_id = String((const char*)buffer, real_size); + } + else + tr_debug("KEY_ACCOUNT_ID failed."); + } + + free(buffer); + if (!success) { + tr_error("ConnectorClient::create_register_object - Failed to read credentials"); + _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorFailedToReadCredentials,CREDENTIAL_ERROR); + // TODO: what to do with the m2mserver security instance + } + } else { + tr_info("ConnectorClient::create_register_object() - Credentials already exists"); + } +} + +/* +* Creates bootstrap server object with bootstrap server address and other parameters +* required for connecting to mbed Cloud bootstrap server. +*/ +bool ConnectorClient::create_bootstrap_object() +{ + tr_debug("ConnectorClient::create_bootstrap_object"); + bool success = false; + + // Check if bootstrap credentials are already stored in KCM + if (bootstrap_credentials_stored_in_kcm() && _security) { + if (_security->get_security_instance_id(M2MSecurity::Bootstrap) == -1) { + _security->create_object_instance(M2MSecurity::Bootstrap); + int32_t bs_id = _security->get_security_instance_id(M2MSecurity::Bootstrap); + _security->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::Certificate, bs_id); + tr_info("ConnectorClient::create_bootstrap_object - bs_id = %d", bs_id); + tr_info("ConnectorClient::create_bootstrap_object - use credentials from storage"); + + // Allocate scratch buffer, this will be used to copy parameters from storage to security object + size_t real_size = 0; + const int max_size = 2048; + uint8_t *buffer = (uint8_t*)malloc(max_size); + if (buffer != NULL) { + success = true; + } + + // Read internal endpoint name if it exists, we need to append + // it to bootstrap uri if device already bootstrapped + uint8_t *iep = NULL; + if (success && get_config_parameter_string(KEY_INTERNAL_ENDPOINT, buffer, max_size) == CCS_STATUS_SUCCESS) { + iep = (uint8_t*)malloc(strlen((const char*)buffer) + strlen(INTERNAL_ENDPOINT_PARAM) + 1); + if (iep != NULL) { + strcpy((char*)iep, INTERNAL_ENDPOINT_PARAM); + strcat((char*)iep, (const char*)buffer); + tr_info("ConnectorClient::create_bootstrap_object - iep: %s", buffer); + } + //TODO: Should handle error if iep exists but allocation fails? + } + + // Bootstrap URI + if (success) { + success = false; + if (get_config_parameter_string(g_fcc_bootstrap_server_uri_name, buffer, max_size) == CCS_STATUS_SUCCESS) { + success = true; + + real_size = strlen((const char*)buffer); + // Append iep if we 1. have it 2. it doesn't already exist in uri 3. it fits + if (iep && + strstr((const char*)buffer, (const char*)iep) == NULL && + (real_size + strlen((const char*)iep) + 1) <= max_size) { + strcat((char*)buffer, (const char*)iep); + real_size += strlen((const char*)iep) + 1; + } + + tr_info("ConnectorClient::create_bootstrap_object - M2MServerUri %.*s", (int)real_size, buffer); + _security->set_resource_value(M2MSecurity::M2MServerUri, buffer, real_size, bs_id); + } + } + + free(iep); + + // Bootstrap server public key (certificate) + if (success) { + success = false; + if (get_config_certificate(g_fcc_bootstrap_server_ca_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + success = true; + tr_info("ConnectorClient::create_bootstrap_object - ServerPublicKey %d", (int)real_size); + _security->set_resource_value(M2MSecurity::ServerPublicKey, buffer, real_size, bs_id); + } + } + + // Bootstrap client public key (certificate) + if (success) { + success = false; + if (get_config_certificate(g_fcc_bootstrap_device_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + success = true; + tr_info("ConnectorClient::create_bootstrap_object - PublicKey %d", (int)real_size); + _security->set_resource_value(M2MSecurity::PublicKey, buffer, real_size, bs_id); + } + } + + // Bootstrap client private key + if (success) { + success = false; + if (get_config_private_key(g_fcc_bootstrap_device_private_key_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + success = true; + tr_info("ConnectorClient::create_bootstrap_object - Secretkey %d", (int)real_size); + _security->set_resource_value(M2MSecurity::Secretkey, buffer, real_size, bs_id); + } + } + + // Endpoint + if (success) { + success = false; + if (get_config_parameter(g_fcc_endpoint_parameter_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + success = true; + _endpoint_info.endpoint_name = String((const char*)buffer, real_size); + tr_info("ConnectorClient::create_bootstrap_object - Endpoint %s", _endpoint_info.endpoint_name.c_str()); + } + } + + // Account ID, not mandatory + if (success) { + if (get_config_parameter(KEY_ACCOUNT_ID, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { + _endpoint_info.account_id = String((const char*)buffer, real_size); + tr_info("ConnectorClient::create_bootstrap_object - AccountId %s", _endpoint_info.account_id.c_str()); + } + } + free(buffer); + + if (!success) { + tr_error("ConnectorClient::create_bootstrap_object - Failed to read credentials"); + _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorFailedToReadCredentials,CREDENTIAL_ERROR); + _security->remove_object_instance(bs_id); + } + } else { + success = true; + tr_info("ConnectorClient::create_bootstrap_object - bootstrap object already done"); + } + // Device not provisioned + } else { + _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorInvalidCredentials, DEVICE_NOT_PROVISIONED); + tr_error("ConnectorClient::create_bootstrap_object - device not provisioned!"); + } + return success; +} + +void ConnectorClient::state_bootstrap_start() +{ + tr_info("ConnectorClient::state_bootstrap_start()"); + assert(_interface != NULL); + assert(_security != NULL); + + _interface->bootstrap(_security); + + internal_event(State_Bootstrap_Started); +} + +void ConnectorClient::state_bootstrap_started() +{ + // this state may be useful only for verifying the callbacks? +} + +void ConnectorClient::state_bootstrap_success() +{ + assert(_callback != NULL); + // Parse internal endpoint name from mDS cert + _callback->registration_process_result(State_Bootstrap_Success); +} + +void ConnectorClient::state_bootstrap_failure() +{ + assert(_callback != NULL); + // maybe some additional canceling and/or leanup is needed here? + _callback->registration_process_result(State_Bootstrap_Failure); +} + +void ConnectorClient::state_registration_start() +{ + tr_info("ConnectorClient::state_registration_start()"); + assert(_interface != NULL); + assert(_security != NULL); + _interface->register_object(_security, *_client_objs); + internal_event(State_Registration_Started); +} + +void ConnectorClient::state_registration_started() +{ + // this state may be useful only for verifying the callbacks? +} + +void ConnectorClient::state_registration_success() +{ + assert(_callback != NULL); + _endpoint_info.internal_endpoint_name = _interface->internal_endpoint_name(); + //The endpoint is maximum 32 character long, we put bigger buffer for future extensions + size_t real_size = 0; + + //If this returns success, don't do anything else delete old value and set new one + if (size_config_parameter(KEY_INTERNAL_ENDPOINT, &real_size) != CCS_STATUS_SUCCESS) { + delete_config_parameter(KEY_INTERNAL_ENDPOINT); + set_config_parameter(KEY_INTERNAL_ENDPOINT,(const uint8_t*)_endpoint_info.internal_endpoint_name.c_str(), + (size_t)_endpoint_info.internal_endpoint_name.size()); + } + _callback->registration_process_result(State_Registration_Success); +} + +void ConnectorClient::state_registration_failure() +{ + assert(_callback != NULL); + // maybe some additional canceling and/or leanup is needed here? + _callback->registration_process_result(State_Registration_Failure); +} + +void ConnectorClient::state_unregistered() +{ + assert(_callback != NULL); + _callback->registration_process_result(State_Unregistered); +} + +void ConnectorClient::bootstrap_done(M2MSecurity *security_object) +{ + tr_info("ConnectorClient::bootstrap_done"); + ccs_status_e status = CCS_STATUS_ERROR; + StartupSubStateRegistration state = State_Bootstrap_Success; + if(security_object) { + // Update bootstrap credentials (we could skip this if we knew whether they were updated) + // This will also update the address in case of first to claim + status = set_bootstrap_credentials(security_object); + if (status != CCS_STATUS_SUCCESS) { + // TODO: what now? + tr_error("ConnectorClient::bootstrap_done - couldn't store bootstrap credentials"); + } + + // Clear the first to claim flag if it's active + if (is_first_to_claim()) { + status = clear_first_to_claim(); + if (status != CCS_STATUS_SUCCESS) { + // TODO: what now? + tr_error("ConnectorClient::bootstrap_done - couldn't clear first to claim flag!"); + } + } + + // Bootstrap might delete m2mserver security object instance completely to force bootstrap + // with new credentials, in that case delete the stored lwm2m credentials as well and re-bootstrap + if (security_object->get_security_instance_id(M2MSecurity::M2MServer) == -1) { + tr_info("ConnectorClient::bootstrap_done() - Clearing lwm2m credentials"); + // delete the old connector credentials when BS sends re-direction. + delete_config_parameter(g_fcc_lwm2m_server_uri_name); + delete_config_certificate(g_fcc_lwm2m_server_ca_certificate_name); + delete_config_certificate(g_fcc_lwm2m_device_certificate_name); + delete_config_private_key(g_fcc_lwm2m_device_private_key_name); + // Start re-bootstrap timer + tr_info("ConnectorClient::bootstrap_done() - Re-directing bootstrap in 100 milliseconds"); + _rebootstrap_timer.start_timer(100, M2MTimerObserver::BootstrapFlowTimer, true); + return; + } + // Bootstrap wrote M2MServer credentials, store them and also update first to claim status if it's configured + else { + tr_info("ConnectorClient::bootstrap_done() - Storing lwm2m credentials"); + status = set_connector_credentials(security_object); + } + } + if (status != CCS_STATUS_SUCCESS) { + internal_event(State_Bootstrap_Failure); + //Failed to store credentials, bootstrap failed + _callback->connector_error(M2MInterface::MemoryFail, ERROR_NO_MEMORY); // Translated to error code ConnectMemoryConnectFail + return; + } else { + tr_error("ConnectorClient::bootstrap_done - set_credentials status %d", status); + } + internal_event(state); +} + +void ConnectorClient::object_registered(M2MSecurity *security_object, const M2MServer &server_object) +{ + internal_event(State_Registration_Success); +} + +void ConnectorClient::object_unregistered(M2MSecurity *server_object) +{ + internal_event(State_Unregistered); +} + +void ConnectorClient::registration_updated(M2MSecurity *security_object, const M2MServer & server_object) +{ + _callback->registration_process_result(State_Registration_Updated); +} + +void ConnectorClient::error(M2MInterface::Error error) +{ + tr_error("ConnectorClient::error() - error: %d", error); + assert(_callback != NULL); + if (_current_state >= State_Registration_Start && + use_bootstrap() && + (error == M2MInterface::SecureConnectionFailed || + error == M2MInterface::InvalidParameters)) { + tr_info("ConnectorClient::error() - Error during lwm2m registration"); + tr_info("ConnectorClient::error() - Clearing lwm2m credentials"); + // delete the old connector credentials when DTLS handshake fails or + // server rejects the registration. + delete_config_parameter(g_fcc_lwm2m_server_uri_name); + delete_config_certificate(g_fcc_lwm2m_server_ca_certificate_name); + delete_config_certificate(g_fcc_lwm2m_device_certificate_name); + delete_config_private_key(g_fcc_lwm2m_device_private_key_name); + // Delete the lwm2m security instance + int32_t id = _security->get_security_instance_id(M2MSecurity::M2MServer); + if (id >= 0) { + _security->remove_object_instance(id); + } + // Delete bootstrap security instance + id = _security->get_security_instance_id(M2MSecurity::Bootstrap); + if (id >= 0) { + _security->remove_object_instance(id); + } + // Start re-bootstrap timer + tr_info("ConnectorClient::error() - Re-bootstrapping in 100 milliseconds"); + _rebootstrap_timer.start_timer(100, M2MTimerObserver::BootstrapFlowTimer, true); + } + else { + _callback->connector_error(error, _interface->error_description()); + } +} + +void ConnectorClient::value_updated(M2MBase *base, M2MBase::BaseType type) +{ + assert(_callback != NULL); + _callback->value_updated(base, type); +} + +bool ConnectorClient::connector_credentials_available() +{ + tr_debug("ConnectorClient::connector_credentials_available"); + const int max_size = 2048; + uint8_t *buffer = (uint8_t*)malloc(max_size); + size_t real_size = 0; + get_config_private_key(g_fcc_lwm2m_device_private_key_name, buffer, max_size, &real_size); + free(buffer); + if (real_size > 0) { + return true; + } + return false; +} + +bool ConnectorClient::use_bootstrap() +{ + tr_debug("ConnectorClient::use_bootstrap"); + const int max_size = 32; + uint8_t *buffer = (uint8_t*)malloc(max_size); + bool ret = false; + if (buffer != NULL) { + memset(buffer, 0, max_size); + size_t real_size = 0; + ccs_status_e status = get_config_parameter(g_fcc_use_bootstrap_parameter_name, buffer, max_size, &real_size); + if (status == CCS_STATUS_SUCCESS && real_size > 0 && buffer[0] > 0) { + ret = true; + } + free(buffer); + } + return ret; +} + + +bool ConnectorClient::get_key(const char *key, const char *endpoint, char *&key_name) +{ + if(key_name) { + free(key_name); + key_name = NULL; + } + + key_name = (char*)malloc(strlen(key)+strlen(endpoint)+1); + if(key_name) { + strcpy(key_name, key); + strcat(key_name, endpoint); + tr_debug("key %s", key_name); + return true; + } + return false; +} + +ccs_status_e ConnectorClient::set_connector_credentials(M2MSecurity *security) +{ + tr_debug("ConnectorClient::set_connector_credentials"); + ccs_status_e status = CCS_STATUS_ERROR; + + const uint8_t *srv_public_key = NULL; + const uint8_t *public_key = NULL; + const uint8_t *sec_key = NULL; + + int32_t m2m_id = security->get_security_instance_id(M2MSecurity::M2MServer); + if (m2m_id == -1) { + return status; + } + + uint32_t srv_public_key_size = security->resource_value_buffer(M2MSecurity::ServerPublicKey, srv_public_key, m2m_id); + uint32_t public_key_size = security->resource_value_buffer(M2MSecurity::PublicKey, public_key, m2m_id); + uint32_t sec_key_size = security->resource_value_buffer(M2MSecurity::Secretkey, sec_key, m2m_id); + + if(srv_public_key && public_key && sec_key) { + // Parse common name + char common_name[64]; + memset(common_name, 0, 64); + if (extract_cn_from_certificate(public_key, public_key_size, common_name)){ + tr_info("ConnectorClient::set_connector_credentials - CN: %s", common_name); + _endpoint_info.internal_endpoint_name = String(common_name); + delete_config_parameter(KEY_INTERNAL_ENDPOINT); + status = set_config_parameter(KEY_INTERNAL_ENDPOINT,(uint8_t*)common_name, strlen(common_name)); + } + + if(status == CCS_STATUS_SUCCESS) { + delete_config_certificate(g_fcc_lwm2m_server_ca_certificate_name); + status = set_config_certificate(g_fcc_lwm2m_server_ca_certificate_name, + srv_public_key, + (size_t)srv_public_key_size); + } + if(status == CCS_STATUS_SUCCESS) { + status = set_config_certificate(g_fcc_lwm2m_device_certificate_name, + public_key, + (size_t)public_key_size); + } + if(status == CCS_STATUS_SUCCESS) { + status = set_config_private_key(g_fcc_lwm2m_device_private_key_name, + sec_key, + (size_t)sec_key_size); + } + + if(status == CCS_STATUS_SUCCESS) { + delete_config_parameter(KEY_ACCOUNT_ID); + // AccountID optional so don't fail if unable to store + set_config_parameter(KEY_ACCOUNT_ID, + (const uint8_t*)_endpoint_info.account_id.c_str(), + (size_t)_endpoint_info.account_id.size()); + } + if(status == CCS_STATUS_SUCCESS) { + status = set_config_parameter(g_fcc_lwm2m_server_uri_name, + (const uint8_t*)security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id).c_str(), + (size_t)security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id).size()); + } + M2MDevice *device = M2MInterfaceFactory::create_device(); + if (device) { + String temp = ""; + uint32_t currenttime = (uint32_t)device->resource_value_int(M2MDevice::CurrentTime, 0); + uint8_t data[4]; + memcpy(data, ¤ttime, 4); + delete_config_parameter(g_fcc_current_time_parameter_name); + set_config_parameter(g_fcc_current_time_parameter_name, data, 4); + + temp = device->resource_value_string(M2MDevice::Timezone, 0); + delete_config_parameter(g_fcc_device_time_zone_parameter_name); + set_config_parameter(g_fcc_device_time_zone_parameter_name, (const uint8_t*)temp.c_str(), temp.size()); + + temp = device->resource_value_string(M2MDevice::UTCOffset, 0); + delete_config_parameter(g_fcc_offset_from_utc_parameter_name); + set_config_parameter(g_fcc_offset_from_utc_parameter_name, (const uint8_t*)temp.c_str(), temp.size()); + + status = CCS_STATUS_SUCCESS; + } + else { + tr_debug("No device object to store!"); + } + } + + return status; +} + +ccs_status_e ConnectorClient::set_bootstrap_credentials(M2MSecurity *security) +{ + tr_debug("ConnectorClient::set_bootstrap_credentials"); + ccs_status_e status = CCS_STATUS_ERROR; + + const uint8_t *srv_public_key = NULL; + const uint8_t *public_key = NULL; + const uint8_t *sec_key = NULL; + + int32_t bs_id = security->get_security_instance_id(M2MSecurity::Bootstrap); + if (bs_id == -1) { + return status; + } + + uint32_t srv_public_key_size = security->resource_value_buffer(M2MSecurity::ServerPublicKey, srv_public_key, bs_id); + uint32_t public_key_size = security->resource_value_buffer(M2MSecurity::PublicKey, public_key, bs_id); + uint32_t sec_key_size = security->resource_value_buffer(M2MSecurity::Secretkey, sec_key, bs_id); + + if(srv_public_key && public_key && sec_key) { + delete_config_certificate(g_fcc_bootstrap_server_ca_certificate_name); + status = set_config_certificate(g_fcc_bootstrap_server_ca_certificate_name, + srv_public_key, + (size_t)srv_public_key_size); + if(status == CCS_STATUS_SUCCESS) { + delete_config_certificate(g_fcc_bootstrap_device_certificate_name); + status = set_config_certificate(g_fcc_bootstrap_device_certificate_name, + public_key, + (size_t)public_key_size); + } + if(status == CCS_STATUS_SUCCESS) { + delete_config_private_key(g_fcc_bootstrap_device_private_key_name); + status = set_config_private_key(g_fcc_bootstrap_device_private_key_name, + sec_key, + (size_t)sec_key_size); + } + if(status == CCS_STATUS_SUCCESS) { + delete_config_parameter(g_fcc_bootstrap_server_uri_name); + status = set_config_parameter(g_fcc_bootstrap_server_uri_name, + (const uint8_t*)security->resource_value_string(M2MSecurity::M2MServerUri, bs_id).c_str(), + (size_t)security->resource_value_string(M2MSecurity::M2MServerUri, bs_id).size()); + } + } + + return status; +} + +ccs_status_e ConnectorClient::store_bootstrap_address(M2MSecurity *security) +{ + tr_debug("ConnectorClient::store_bootstrap_address"); + ccs_status_e status = CCS_STATUS_ERROR; + + const uint8_t *srv_address = NULL; + int32_t bs_id = security->get_security_instance_id(M2MSecurity::Bootstrap); + if (bs_id == -1) { + return status; + } + + uint32_t srv_address_size = security->resource_value_buffer(M2MSecurity::M2MServerUri, srv_address, bs_id); + + if(srv_address) { + delete_config_parameter(g_fcc_bootstrap_server_uri_name); + status = set_config_parameter(g_fcc_bootstrap_server_uri_name, + srv_address, + (size_t)srv_address_size); + } + + return status; +} + +ccs_status_e ConnectorClient::clear_first_to_claim() +{ + tr_debug("ConnectorClient::clear_first_to_claim"); + return delete_config_parameter(KEY_FIRST_TO_CLAIM); +} + + +const ConnectorClientEndpointInfo *ConnectorClient::endpoint_info() const +{ + return &_endpoint_info; +} + +bool ConnectorClient::bootstrap_credentials_stored_in_kcm() +{ + size_t real_size = 0; + ccs_status_e success = size_config_parameter(g_fcc_bootstrap_server_uri_name, &real_size); + // Return true if bootstrap uri exists in KCM + if ((success == CCS_STATUS_SUCCESS) && real_size > 0) { + return true; + } else { + return false; + } +} + +bool ConnectorClient::is_first_to_claim() +{ + size_t real_size = 0; + uint8_t data[4] = {0}; + uint32_t value = 0; + ccs_status_e status = get_config_parameter(KEY_FIRST_TO_CLAIM, data, 4, &real_size); + if (status == CCS_STATUS_SUCCESS) { + memcpy(&value, data, 4); + // Return true if bootstrap uri exists in KCM + if (value == 1) { + return true; + } + } + return false; +} + +void ConnectorClient::timer_expired(M2MTimerObserver::Type type) +{ + if (type == M2MTimerObserver::BootstrapFlowTimer) { + start_bootstrap(); + } +} + +M2MInterface::BindingMode ConnectorClient::transport_mode() +{ +#ifdef MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP + return M2MInterface::UDP; +#elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP + return M2MInterface::TCP; +#elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE + return M2MInterface::UDP_QUEUE; +#elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE + return M2MInterface::TCP_QUEUE; +#else + return M2MInterface::UDP; +#endif +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/MbedCloudClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/MbedCloudClient.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,214 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "mbed-cloud-client/MbedCloudClientConfig.h" +#include "mbed-cloud-client/MbedCloudClient.h" +#include "mbed-cloud-client/SimpleM2MResource.h" + +#include "ns_hal_init.h" +#include "mbed-trace/mbed_trace.h" + +#include <assert.h> + +#define xstr(s) str(s) +#define str(s) #s + +#define TRACE_GROUP "mClt" + +#ifdef MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE + #define MBED_CLIENT_EVENT_LOOP_SIZE MBED_CONF_MBED_CLIENT_EVENT_LOOP_SIZE +#else + #define MBED_CLIENT_EVENT_LOOP_SIZE 1024 +#endif + +MbedCloudClient::MbedCloudClient() +:_client(*this), + _value_callback(NULL), + _error_description(NULL) +{ + ns_hal_init(NULL, MBED_CLIENT_EVENT_LOOP_SIZE, NULL, NULL); +} + +MbedCloudClient::~MbedCloudClient() +{ + _object_list.clear(); +} + +void MbedCloudClient::add_objects(const M2MObjectList& object_list) +{ + if(!object_list.empty()) { + M2MObjectList::const_iterator it; + it = object_list.begin(); + for (; it!= object_list.end(); it++) { + _object_list.push_back(*it); + } + } +} + +void MbedCloudClient::set_update_callback(MbedCloudClientCallback *callback) +{ + _value_callback = callback; +} + +bool MbedCloudClient::setup(void* iface) +{ + tr_debug("MbedCloudClient setup()"); + // Add objects to list + map<string, M2MObject*>::iterator it; + for (it = _objects.begin(); it != _objects.end(); it++) + { + _object_list.push_back(it->second); + } + _client.connector_client().m2m_interface()->set_platform_network_handler(iface); + + _client.initialize_and_register(_object_list); + return true; +} + +void MbedCloudClient::on_registered(void(*fn)(void)) +{ + FP0<void> fp(fn); + _on_registered = fp; +} + + +void MbedCloudClient::on_error(void(*fn)(int)) +{ + _on_error = fn; +} + + +void MbedCloudClient::on_unregistered(void(*fn)(void)) +{ + FP0<void> fp(fn); + _on_unregistered = fp; +} + +void MbedCloudClient::on_registration_updated(void(*fn)(void)) +{ + FP0<void> fp(fn); + _on_registration_updated = fp; +} + +void MbedCloudClient::keep_alive() +{ + _client.connector_client().update_registration(); +} + +void MbedCloudClient::register_update() +{ + _client.connector_client().update_registration(); +} + +void MbedCloudClient::close() +{ + _client.connector_client().m2m_interface()->unregister_object(NULL); +} + +const ConnectorClientEndpointInfo *MbedCloudClient::endpoint_info() const +{ + return _client.connector_client().endpoint_info(); +} + +void MbedCloudClient::set_queue_sleep_handler(callback_handler handler) +{ + _client.connector_client().m2m_interface()->set_queue_sleep_handler(handler); +} + +void MbedCloudClient::set_random_number_callback(random_number_cb callback) +{ + _client.connector_client().m2m_interface()->set_random_number_callback(callback); +} + +void MbedCloudClient::set_entropy_callback(entropy_cb callback) +{ + _client.connector_client().m2m_interface()->set_entropy_callback(callback); +} + +bool MbedCloudClient::set_device_resource_value(M2MDevice::DeviceResource resource, + const std::string &value) +{ + return _client.set_device_resource_value(resource, value); +} + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE +void MbedCloudClient::set_update_authorize_handler(void (*handler)(int32_t request)) +{ + _client.set_update_authorize_handler(handler); +} + +void MbedCloudClient::set_update_progress_handler(void (*handler)(uint32_t progress, uint32_t total)) +{ + _client.set_update_progress_handler(handler); +} + +void MbedCloudClient::update_authorize(int32_t request) +{ + _client.update_authorize(request); +} +#endif + +const char *MbedCloudClient::error_description() const +{ + return _error_description; +} + + +void MbedCloudClient::register_update_callback(string route, + SimpleM2MResourceBase* resource) +{ + _update_values[route] = resource; +} + +void MbedCloudClient::complete(ServiceClientCallbackStatus status) +{ + tr_info("MbedCloudClient::complete status (%d)", status); + if (status == Service_Client_Status_Registered) { + _on_registered.call(); + } else if (status == Service_Client_Status_Unregistered) { + _object_list.clear(); + _on_unregistered.call(); + } else if (status == Service_Client_Status_Register_Updated) { + _on_registration_updated.call(); + } +} + +void MbedCloudClient::error(int error, const char *reason) +{ + tr_error("MbedCloudClient::error code (%d)", error); + _error_description = reason; + _on_error(error); +} + +void MbedCloudClient::value_updated(M2MBase *base, M2MBase::BaseType type) +{ + if (base) { + tr_info("MbedCloudClient::value_updated path %s", base->uri_path()); + if (base->uri_path()) { + if (_update_values.count(base->uri_path()) != 0) { + tr_debug("MbedCloudClient::value_updated calling update() for %s", base->uri_path()); + _update_values[base->uri_path()]->update(); + } else { + // way to tell application that there is a value update + if (_value_callback) { + _value_callback->value_updated(base, type); + } + } + } + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/ServiceClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/ServiceClient.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,527 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include <inttypes.h> + +#include <string> +#include "include/ServiceClient.h" +#include "include/CloudClientStorage.h" +#include "include/UpdateClientResources.h" +#include "include/UpdateClient.h" +#include "factory_configurator_client.h" +#include "mbed-trace/mbed_trace.h" +#include <assert.h> + +#define TRACE_GROUP "mClt" + +#define CONNECT 0 +#define ERROR_UPDATE "Update has failed, check MbedCloudClient::Error" + +/* lookup table for printing hexadecimal values */ +const uint8_t ServiceClient::hex_table[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +ServiceClient::ServiceClient(ServiceClientCallback& callback) +: _service_callback(callback), + _service_uri(NULL), + _stack(NULL), + _client_objs(NULL), + _current_state(State_Init), + _event_generated(false), + _state_engine_running(false), +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + _setup_update_client(false), +#endif + _connector_client(this) +{ +} + +ServiceClient::~ServiceClient() +{ +} + +void ServiceClient::initialize_and_register(M2MObjectList& client_objs) +{ + tr_debug("ServiceClient::initialize_and_register"); + if(_current_state == State_Init || + _current_state == State_Unregister || + _current_state == State_Failure) { + _client_objs = &client_objs; + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + tr_debug("ServiceClient::initialize_and_register: update client supported"); + + if(!_setup_update_client) { + _setup_update_client = true; + +#ifdef MBED_CLOUD_DEV_UPDATE_ID + /* Overwrite values stored in KCM. This is for development only + since these IDs should be provisioned in the factory. + */ + tr_debug("ServiceClient::initialize_and_register: update IDs defined"); + + /* Delete VendorId */ + delete_config_parameter("mbed.VendorId"); + /* Store Vendor Id to mbed.VendorId. No conversion is performed. */ + set_device_resource_value(M2MDevice::Manufacturer, + (const char*) arm_uc_vendor_id, + arm_uc_vendor_id_size); + + /* Delete ClassId */ + delete_config_parameter("mbed.ClassId"); + /* Store Class Id to mbed.ClassId. No conversion is performed. */ + set_device_resource_value(M2MDevice::ModelNumber, + (const char*) arm_uc_class_id, + arm_uc_class_id_size); +#endif /* MBED_CLOUD_DEV_UPDATE_ID */ + +#ifdef ARM_UPDATE_CLIENT_VERSION + /* Inject Update Client version number if no other software + version is present in the KCM. + */ + tr_debug("ServiceClient::initialize_and_register: update version defined"); +; + const size_t buffer_size = 16; + uint8_t buffer[buffer_size]; + size_t size = 0; + + /* check if software version is already set */ + ccs_status_e status = get_config_parameter(KEY_DEVICE_SOFTWAREVERSION, + buffer, buffer_size, &size); + + if (status == CCS_STATUS_KEY_DOESNT_EXIST) { + tr_debug("ServiceClient::initialize_and_register: insert update version"); + + /* insert value from Update Client Common */ + set_config_parameter(KEY_DEVICE_SOFTWAREVERSION, + (const uint8_t*) ARM_UPDATE_CLIENT_VERSION, + sizeof(ARM_UPDATE_CLIENT_VERSION)); + } +#endif /* ARM_UPDATE_CLIENT_VERSION */ + + /* Update Client adds the OMA LWM2M Firmware Update object */ + UpdateClient::populate_object_list(*_client_objs); + + /* Initialize Update Client */ + FP1<void, int32_t> callback(this, &ServiceClient::update_error_callback); + UpdateClient::UpdateClient(callback); + } +#endif /* MBED_CLOUD_CLIENT_SUPPORT_UPDATE */ + + /* Device Object is mandatory. + Get instance and add it to object list + */ + M2MDevice *device_object = device_object_from_storage(); + + if (device_object) { + /* Publish device object resource to mds */ + M2MResourceList list = device_object->object_instance()->resources(); + if(!list.empty()) { + M2MResourceList::const_iterator it; + it = list.begin(); + for ( ; it != list.end(); it++ ) { + (*it)->set_register_uri(true); + } + } + + /* Add Device Object to object list. */ + _client_objs->push_back(device_object); + } + + internal_event(State_Bootstrap); + } else if (_current_state == State_Success) { + state_success(); + } +} + +ConnectorClient &ServiceClient::connector_client() +{ + return _connector_client; +} + +const ConnectorClient &ServiceClient::connector_client() const +{ + return _connector_client; +} + +// generates an internal event. called from within a state +// function to transition to a new state +void ServiceClient::internal_event(StartupMainState new_state) +{ + tr_debug("ServiceClient::internal_event: state: %d -> %d", _current_state, new_state); + + _event_generated = true; + _current_state = new_state; + + if (!_state_engine_running) { + state_engine(); + } +} + +// the state engine executes the state machine states +void ServiceClient::state_engine(void) +{ + tr_debug("ServiceClient::state_engine"); + + // this simple flagging gets rid of recursive calls to this method + _state_engine_running = true; + + // while events are being generated keep executing states + while (_event_generated) { + _event_generated = false; // event used up, reset flag + + state_function(_current_state); + } + + _state_engine_running = false; +} + +void ServiceClient::state_function(StartupMainState current_state) +{ + switch (current_state) { + case State_Init: // -> Goes to bootstrap state + case State_Bootstrap: // -> State_Register OR State_Failure + state_bootstrap(); + break; + case State_Register: // -> State_Succes OR State_Failure + state_register(); + break; + case State_Success: // return success to user + state_success(); + break; + case State_Failure: // return error to user + state_failure(); + break; + case State_Unregister: // return error to user + state_unregister(); + break; + } +} + +void ServiceClient::state_bootstrap() +{ + tr_info("ServiceClient::state_bootstrap()"); + bool credentials_ready = _connector_client.connector_credentials_available(); + bool bootstrap = _connector_client.use_bootstrap(); + tr_info("ServiceClient::state_bootstrap() - lwm2m credentials available: %d", credentials_ready); + tr_info("ServiceClient::state_bootstrap() - use bootstrap: %d", bootstrap); + if (credentials_ready || !bootstrap) { + internal_event(State_Register); + } else { + _connector_client.start_bootstrap(); + } +} + +void ServiceClient::state_register() +{ + tr_info("ServiceClient::state_register()"); + _connector_client.start_registration(_client_objs); +} + +void ServiceClient::registration_process_result(ConnectorClient::StartupSubStateRegistration status) +{ + tr_debug("ServiceClient::registration_process_result(): status: %d", status); + if (status == ConnectorClient::State_Registration_Success) { + internal_event(State_Success); + } else if(status == ConnectorClient::State_Registration_Failure || + status == ConnectorClient::State_Bootstrap_Failure){ + internal_event(State_Failure); // XXX: the status should be saved to eg. event object + } + if(status == ConnectorClient::State_Bootstrap_Success) { + internal_event(State_Register); + } + if(status == ConnectorClient::State_Unregistered) { + internal_event(State_Unregister); + } + if (status == ConnectorClient::State_Registration_Updated) { + _service_callback.complete(ServiceClientCallback::Service_Client_Status_Register_Updated); + } +} + +void ServiceClient::connector_error(M2MInterface::Error error, const char *reason) +{ + tr_error("ServiceClient::connector_error() error %d", (int)error); + if (_current_state == State_Register) { + registration_process_result(ConnectorClient::State_Registration_Failure); + } + else if (_current_state == State_Bootstrap) { + registration_process_result(ConnectorClient::State_Bootstrap_Failure); + } + _service_callback.error(int(error),reason); + internal_event(State_Failure); +} + +void ServiceClient::value_updated(M2MBase *base, M2MBase::BaseType type) +{ + tr_debug("ServiceClient::value_updated()"); + _service_callback.value_updated(base, type); +} + +void ServiceClient::state_success() +{ + tr_info("ServiceClient::state_success()"); + // this is verified already at client API level, but this might still catch some logic failures + _service_callback.complete(ServiceClientCallback::Service_Client_Status_Registered); +} + +void ServiceClient::state_failure() +{ + tr_error("ServiceClient::state_failure()"); + _service_callback.complete(ServiceClientCallback::Service_Client_Status_Failure); +} + +void ServiceClient::state_unregister() +{ + tr_debug("ServiceClient::state_unregister()"); + _service_callback.complete(ServiceClientCallback::Service_Client_Status_Unregistered); +} + +M2MDevice* ServiceClient::device_object_from_storage() +{ + M2MDevice *device_object = M2MInterfaceFactory::create_device(); + if (device_object == NULL) { + return NULL; + } + + const size_t buffer_size = 128; + uint8_t buffer[buffer_size]; + size_t size = 0; + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + uint8_t guid[sizeof(arm_uc_guid_t)] = {0}; + // Read out the binary Vendor UUID + ccs_status_e status = (ccs_status_e)UpdateClient::getVendorId(guid, sizeof(arm_uc_guid_t), &size); + + // Format the binary Vendor UUID into a hex string + if (status == CCS_STATUS_SUCCESS) { + size_t j = 0; + for(size_t i = 0; i < size; i++) + { + buffer[j++] = hex_table[(guid[i] >> 4) & 0xF]; + buffer[j++] = hex_table[(guid[i] >> 0) & 0xF]; + } + buffer[j] = '\0'; + device_object->create_resource(M2MDevice::Manufacturer, String((char*)buffer, size * 2)); + } + + // Read out the binary Class UUID + status = (ccs_status_e)UpdateClient::getClassId(guid, sizeof(arm_uc_guid_t), &size); + + // Format the binary Class UUID into a hex string + if (status == CCS_STATUS_SUCCESS) { + size_t j = 0; + for(size_t i = 0; i < size; i++) + { + buffer[j++] = hex_table[(guid[i] >> 4) & 0xF]; + buffer[j++] = hex_table[(guid[i] >> 0) & 0xF]; + } + buffer[j] = '\0'; + device_object->create_resource(M2MDevice::ModelNumber, String((char*)buffer, size * 2)); + } +#else + ccs_status_e status = get_config_parameter(g_fcc_manufacturer_parameter_name, buffer, buffer_size, &size); + if (status == CCS_STATUS_SUCCESS) { + device_object->create_resource(M2MDevice::Manufacturer, String((char*)buffer, size)); + } + status = get_config_parameter(g_fcc_model_number_parameter_name, buffer, buffer_size, &size); + if (status == CCS_STATUS_SUCCESS) { + device_object->create_resource(M2MDevice::ModelNumber, String((char*)buffer, size)); + } +#endif + status = get_config_parameter(g_fcc_device_serial_number_parameter_name, buffer, buffer_size, &size); + if (status == CCS_STATUS_SUCCESS) { + device_object->create_resource(M2MDevice::SerialNumber, String((char*)buffer, size)); + } + status = get_config_parameter(g_fcc_device_type_parameter_name, buffer, buffer_size, &size); + if (status == CCS_STATUS_SUCCESS) { + device_object->create_resource(M2MDevice::DeviceType, String((char*)buffer, size)); + } + status = get_config_parameter(g_fcc_hardware_version_parameter_name, buffer, buffer_size, &size); + if (status == CCS_STATUS_SUCCESS) { + device_object->create_resource(M2MDevice::HardwareVersion, String((char*)buffer, size)); + } + status = get_config_parameter(KEY_DEVICE_SOFTWAREVERSION, buffer, buffer_size, &size); + if (status == CCS_STATUS_SUCCESS) { + device_object->create_resource(M2MDevice::SoftwareVersion, String((char*)buffer, size)); + } + uint8_t data[4] = {0}; + uint32_t value; + status = get_config_parameter(g_fcc_memory_size_parameter_name, data, 4, &size); + if (status == CCS_STATUS_SUCCESS) { + memcpy(&value, data, 4); + device_object->create_resource(M2MDevice::MemoryTotal, value); + tr_debug("ServiceClient::device_object_from_storage() - setting memory total value %" PRIu32 " (%s)", value, tr_array(data, 4)); + } + status = get_config_parameter(g_fcc_current_time_parameter_name, data, 4, &size); + if (status == CCS_STATUS_SUCCESS) { + memcpy(&value, data, 4); + device_object->create_resource(M2MDevice::CurrentTime, value); + tr_debug("ServiceClient::device_object_from_storage() - setting current time value %" PRIu32 " (%s)", value, tr_array(data, 4)); + } + status = get_config_parameter(g_fcc_device_time_zone_parameter_name, buffer, buffer_size, &size); + if (status == CCS_STATUS_SUCCESS) { + device_object->create_resource(M2MDevice::Timezone, String((char*)buffer, size)); + } + status = get_config_parameter(g_fcc_offset_from_utc_parameter_name, buffer, buffer_size, &size); + if (status == CCS_STATUS_SUCCESS) { + device_object->create_resource(M2MDevice::UTCOffset, String((char*)buffer, size)); + } + return device_object; +} + +/** + * \brief Set resource value in the Device Object + * + * \param resource Device enum to have value set. + * \param value String object. + * \return True if successful, false otherwise. + */ +bool ServiceClient::set_device_resource_value(M2MDevice::DeviceResource resource, + const std::string& value) +{ + return set_device_resource_value(resource, + value.c_str(), + value.size() - 1); +} + +/** + * \brief Set resource value in the Device Object + * + * \param resource Device enum to have value set. + * \param value Byte buffer. + * \param length Buffer length. + * \return True if successful, false otherwise. + */ +bool ServiceClient::set_device_resource_value(M2MDevice::DeviceResource resource, + const char* value, + uint32_t length) +{ + bool retval = false; + + /* sanity check */ + if (value && (length < 256) && (length > 0)) + { +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + /* Pass resource value to Update Client. + Used for validating the manifest. + */ + switch (resource) { + case M2MDevice::Manufacturer: + ARM_UC_SetVendorId((const uint8_t*) value, length); + break; + case M2MDevice::ModelNumber: + ARM_UC_SetClassId((const uint8_t*) value, length); + break; + default: + break; + } +#endif + + /* Convert resource to printable string if necessary */ + + /* Getting object instance from factory */ + M2MDevice *device_object = M2MInterfaceFactory::create_device(); + + /* Check device object and resource both are present */ + if (device_object && device_object->is_resource_present(resource)) { + /* set counter to not-zero */ + uint8_t printable_length = 0xFF; + + /* set printable_length to 0 if the buffer is not printable */ + for (uint8_t index = 0; index < length; index++) { + /* break if character is not printable */ + if ((value[index] < ' ') || (value[index] > '~')) { + printable_length = 0; + break; + } + } + + /* resource is a string */ + if (printable_length != 0) { + /* reset counter */ + printable_length = 0; + + /* find actual printable length */ + for ( ; printable_length < length; printable_length++) { + /* break prematurely if end-of-string character is found */ + if (value[printable_length] == '\0') { + break; + } + } + + /* convert to string and set value in object */ + String string_value(value, printable_length); + retval = device_object->set_resource_value(resource, string_value); + } + else + { + /* resource is a byte array */ + char value_buffer[0xFF] = { 0 }; + + /* count length */ + uint8_t index = 0; + + /* convert byte array to string */ + for ( ; + (index < length) && ((2*index +1) < 0xFF); + index++) { + + uint8_t byte = value[index]; + + value_buffer[2 * index] = hex_table[byte >> 4]; + value_buffer[2 * index + 1] = hex_table[byte & 0x0F]; + } + + /* convert to string and set value in object */ + String string_value(value_buffer, 2 * (index - 1)); + retval = device_object->set_resource_value(resource, string_value); + } + } + } + + return retval; +} + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE +void ServiceClient::set_update_authorize_handler(void (*handler)(int32_t request)) +{ + UpdateClient::set_update_authorize_handler(handler); +} + +void ServiceClient::update_authorize(int32_t request) +{ + UpdateClient::update_authorize(request); +} + +void ServiceClient::set_update_progress_handler(void (*handler)(uint32_t progress, uint32_t total)) +{ + UpdateClient::set_update_progress_handler(handler); +} + +void ServiceClient::update_error_callback(int32_t error) +{ + _service_callback.error(error, ERROR_UPDATE); +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/SimpleM2MResource.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/SimpleM2MResource.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,321 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "mbed-cloud-client/SimpleM2MResource.h" +#include "mbed-trace/mbed_trace.h" + +#include <ctype.h> + +#include<stdio.h> + +#define TRACE_GROUP "mClt" + + +SimpleM2MResourceBase::SimpleM2MResourceBase() +: _client(NULL), _route("") +{ + tr_debug("SimpleM2MResourceBase::SimpleM2MResourceBase()"); +} + +SimpleM2MResourceBase::SimpleM2MResourceBase(MbedCloudClient* client, string route) +: _client(client),_route(route) +{ + tr_debug("SimpleM2MResourceBase::SimpleM2MResourceBase(), resource name %s\r\n", _route.c_str()); +} + +SimpleM2MResourceBase::~SimpleM2MResourceBase() +{ +} + +bool SimpleM2MResourceBase::define_resource_internal(std::string v, M2MBase::Operation opr, bool observable) +{ + tr_debug("SimpleM2MResourceBase::define_resource_internal(), resource name %s!\r\n", _route.c_str()); + + vector<string> segments = parse_route(_route.c_str()); + if (segments.size() != 3) { + tr_debug("[SimpleM2MResourceBase] [ERROR] define_resource_internal(), Route needs to have three segments, split by '/' (%s)\r\n", _route.c_str()); + return false; + } + + // segments[1] should be one digit and numeric + if (!isdigit(segments.at(1).c_str()[0])) { + tr_debug("[SimpleM2MResourceBase] [ERROR] define_resource_internal(), second route segment should be numeric, but was not (%s)\r\n", _route.c_str()); + return false; + } + + int inst_id = atoi(segments.at(1).c_str()); + + // Check if object exists + M2MObject* obj; + map<string,M2MObject*>::iterator obj_it = _client->_objects.find(segments[0]) ; + if(obj_it != _client->_objects.end()) { + tr_debug("Found object... %s\r\n", segments.at(0).c_str()); + obj = obj_it->second; + } else { + tr_debug("Create new object... %s\r\n", segments.at(0).c_str()); + obj = M2MInterfaceFactory::create_object(segments.at(0).c_str()); + if (!obj) { + return false; + } + _client->_objects.insert(std::pair<string, M2MObject*>(segments.at(0), obj)); + } + + // Check if object instance exists + M2MObjectInstance* inst = obj->object_instance(inst_id); + if(!inst) { + tr_debug("Create new object instance... %s\r\n", segments.at(1).c_str()); + inst = obj->create_object_instance(inst_id); + if(!inst) { + return false; + } + } + + // @todo check if the resource exists yet + M2MResource* res = inst->resource(segments.at(2).c_str()); + if(!res) { + res = inst->create_dynamic_resource(segments.at(2).c_str(), "", + M2MResourceInstance::STRING, observable); + if(!res) { + return false; + } + res->set_operation(opr); + res->set_value((uint8_t*)v.c_str(), v.length()); + + _client->_resources.insert(pair<string, M2MResource*>(_route, res)); + _client->register_update_callback(_route, this); + } + + return true; +} + +vector<string> SimpleM2MResourceBase::parse_route(const char* route) +{ + string s(route); + vector<string> v; + std::size_t found = s.find_first_of("/"); + + while (found!=std::string::npos) { + v.push_back(s.substr(0,found)); + s = s.substr(found+1); + found=s.find_first_of("/"); + if(found == std::string::npos) { + v.push_back(s); + } + } + return v; +} + +string SimpleM2MResourceBase::get() const +{ + tr_debug("SimpleM2MResourceBase::get() resource (%s)", _route.c_str()); + if (!_client->_resources.count(_route)) { + tr_debug("[SimpleM2MResourceBase] [ERROR] No such route (%s)\r\n", _route.c_str()); + return string(); + } + + // otherwise ask mbed Client... + uint8_t* buffIn = NULL; + uint32_t sizeIn; + _client->_resources[_route]->get_value(buffIn, sizeIn); + + string s((char*)buffIn, sizeIn); + tr_debug("SimpleM2MResourceBase::get() resource value (%s)", s.c_str()); + free(buffIn); + return s; +} + +bool SimpleM2MResourceBase::set(string v) +{ + // Potentially set() happens in InterruptContext. That's not good. + tr_debug("SimpleM2MResourceBase::set() resource (%s)", _route.c_str()); + if (!_client->_resources.count(_route)) { + tr_debug("[SimpleM2MResourceBase] [ERROR] No such route (%s)\r\n", _route.c_str()); + return false; + } + + if (v.length() == 0) { + _client->_resources[_route]->clear_value(); + } + else { + _client->_resources[_route]->set_value((uint8_t*)v.c_str(), v.length()); + } + + return true; +} + +bool SimpleM2MResourceBase::set(const int& v) +{ + char buffer[20]; + int size = sprintf(buffer,"%d",v); + std::string stringified(buffer,size); + + return set(stringified); +} + +bool SimpleM2MResourceBase::set_post_function(void(*fn)(void*)) +{ + //TODO: Check the resource exists with right operation being set or append the operation into it. + M2MResource *resource = get_resource(); + if(!resource) { + return false; + } + M2MBase::Operation op = resource->operation(); + op = (M2MBase::Operation)(op | M2MBase::POST_ALLOWED); + resource->set_operation(op); + + _client->_resources[_route]->set_execute_function(execute_callback_2(fn)); + return true; +} + +bool SimpleM2MResourceBase::set_post_function(execute_callback fn) +{ + //TODO: Check the resource exists with right operation being set or append the operation into it. + M2MResource *resource = get_resource(); + if(!resource) { + return false; + } + M2MBase::Operation op = resource->operation(); + op = (M2MBase::Operation)(op | M2MBase::POST_ALLOWED); + resource->set_operation(op); + + // No clue why this is not working?! It works with class member, but not with static function... + _client->_resources[_route]->set_execute_function(fn); + return true; +} + +M2MResource* SimpleM2MResourceBase::get_resource() +{ + if (!_client->_resources.count(_route)) { + tr_debug("[SimpleM2MResourceBase] [ERROR] No such route (%s)\r\n", _route.c_str()); + return NULL; + } + return _client->_resources[_route]; +} + +SimpleM2MResourceString::SimpleM2MResourceString(MbedCloudClient* client, + const char* route, + string v, + M2MBase::Operation opr, + bool observable, + FP1<void, string> on_update) +: SimpleM2MResourceBase(client,route),_on_update(on_update) +{ + tr_debug("SimpleM2MResourceString::SimpleM2MResourceString() creating (%s)\r\n", route); + define_resource_internal(v, opr, observable); +} + +SimpleM2MResourceString::SimpleM2MResourceString(MbedCloudClient* client, + const char* route, + string v, + M2MBase::Operation opr, + bool observable, + void(*on_update)(string)) + +: SimpleM2MResourceBase(client,route) +{ + tr_debug("SimpleM2MResourceString::SimpleM2MResourceString() overloaded creating (%s)\r\n", route); + FP1<void, string> fp; + fp.attach(on_update); + _on_update = fp; + define_resource_internal(v, opr, observable); +} + +SimpleM2MResourceString::~SimpleM2MResourceString() +{ +} + +string SimpleM2MResourceString::operator=(const string& new_value) +{ + tr_debug("SimpleM2MResourceString::operator=()"); + set(new_value); + return new_value; +} + +SimpleM2MResourceString::operator string() const +{ + tr_debug("SimpleM2MResourceString::operator string()"); + string value = get(); + return value; +} + +void SimpleM2MResourceString::update() +{ + string v = get(); + _on_update(v); +} + +SimpleM2MResourceInt::SimpleM2MResourceInt(MbedCloudClient* client, + const char* route, + int v, + M2MBase::Operation opr, + bool observable, + FP1<void, int> on_update) +: SimpleM2MResourceBase(client,route),_on_update(on_update) +{ + tr_debug("SimpleM2MResourceInt::SimpleM2MResourceInt() creating (%s)\r\n", route); + char buffer[20]; + int size = sprintf(buffer,"%d",v); + std::string stringified(buffer,size); + define_resource_internal(stringified, opr, observable); +} + +SimpleM2MResourceInt::SimpleM2MResourceInt(MbedCloudClient* client, + const char* route, + int v, + M2MBase::Operation opr, + bool observable, + void(*on_update)(int)) +: SimpleM2MResourceBase(client,route) +{ + tr_debug("SimpleM2MResourceInt::SimpleM2MResourceInt() overloaded creating (%s)\r\n", route); + FP1<void, int> fp; + fp.attach(on_update); + _on_update = fp; + char buffer[20]; + int size = sprintf(buffer,"%d",v); + std::string stringified(buffer,size); + define_resource_internal(stringified, opr, observable); +} + +SimpleM2MResourceInt::~SimpleM2MResourceInt() +{ +} + +int SimpleM2MResourceInt::operator=(int new_value) +{ + set(new_value); + return new_value; +} + +SimpleM2MResourceInt::operator int() const +{ + string v = get(); + if (v.empty()) return 0; + + return atoi((const char*)v.c_str()); +} + +void SimpleM2MResourceInt::update() +{ + string v = get(); + if (v.empty()) { + _on_update(0); + } else { + _on_update(atoi((const char*)v.c_str())); + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/UpdateClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/UpdateClient.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,356 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// Needed for PRIu64 on FreeRTOS +#include <stdio.h> +// Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +// Note: this macro is needed on armcc to get the the PRI*32 macros +// from inttypes.h in a C++ code. +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#include MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#endif + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE +#include "update-client-hub/update_client_hub.h" + +#include "update-client-source-http/arm_uc_source_http.h" +#include "update-client-lwm2m/lwm2m-source.h" +#include "update-client-lwm2m/lwm2m-monitor.h" +#include "update-client-lwm2m/lwm2m-control.h" +#include "update-client-lwm2m/FirmwareUpdateResource.h" +#include "update-client-lwm2m/DeviceMetadataResource.h" + +#include "eventOS_scheduler.h" +#include "eventOS_event.h" + +#include "include/UpdateClient.h" +#include "include/UpdateClientResources.h" +#include "include/CloudClientStorage.h" + +#include "pal.h" + +#if (!defined(MBED_CONF_MBED_TRACE_ENABLE) || MBED_CONF_MBED_TRACE_ENABLE == 0) \ + && ARM_UC_ALL_TRACE_ENABLE == 1 +#define tr_info(...) { printf(__VA_ARGS__); printf("\r\n"); } +#else +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "uccc" +#endif + +/* To be removed once update storage is defined in user config file. + Default to filesystem in the meantime. +*/ +#ifndef MBED_CLOUD_CLIENT_UPDATE_STORAGE +#define MBED_CLOUD_CLIENT_UPDATE_STORAGE ARM_UCP_FILESYSTEM +#endif + +#ifdef MBED_CLOUD_CLIENT_UPDATE_STORAGE +extern ARM_UC_PAAL_UPDATE MBED_CLOUD_CLIENT_UPDATE_STORAGE; +#else +#error Update client storage must be defined in user configuration file +#endif + +namespace UpdateClient +{ + enum UpdateClientEventType { + UPDATE_CLIENT_EVENT_INITIALIZE, + UPDATE_CLIENT_EVENT_PROCESS_QUEUE + }; + + static int8_t update_client_tasklet_id = -1; + static FP1<void, int32_t> error_callback; + + static void certificate_done(arm_uc_error_t error, + const arm_uc_buffer_t* fingerprint); + static void initialization(void); + static void initialization_done(int32_t); + static void event_handler(arm_event_s* event); + static void queue_handler(void); + static void schedule_event(void); + static void error_handler(int32_t error); +} + +void UpdateClient::UpdateClient(FP1<void, int32_t> callback) +{ + tr_info("Update Client External Initialization: %p", (void*)pal_osThreadGetId()); + + /* store callback handler */ + error_callback = callback; + + /* create event */ + eventOS_scheduler_mutex_wait(); + if (update_client_tasklet_id == -1) { + update_client_tasklet_id = eventOS_event_handler_create(UpdateClient::event_handler, + UPDATE_CLIENT_EVENT_INITIALIZE); + + tr_info("UpdateClient::update_client_tasklet_id: %d", + update_client_tasklet_id); + } + eventOS_scheduler_mutex_release(); +} + +/** + * @brief Populate M2MObjectList with Update Client objects. + */ +void UpdateClient::populate_object_list(M2MObjectList& list) +{ + /* Setup Firmware Update LWM2M object */ + list.push_back(FirmwareUpdateResource::getObject()); + list.push_back(DeviceMetadataResource::getObject()); +} + +void UpdateClient::set_update_authorize_handler(void (*handler)(int32_t request)) +{ + ARM_UC_SetAuthorizeHandler(handler); +} + +void UpdateClient::update_authorize(int32_t request) +{ + switch (request) + { + case RequestDownload: + ARM_UC_Authorize(ARM_UCCC_REQUEST_DOWNLOAD); + break; + case RequestInstall: + ARM_UC_Authorize(ARM_UCCC_REQUEST_INSTALL); + break; + case RequestInvalid: + default: + break; + } +} + +void UpdateClient::set_update_progress_handler(void (*handler)(uint32_t progress, uint32_t total)) +{ + ARM_UC_SetProgressHandler(handler); +} + +static void UpdateClient::initialization(void) +{ + tr_info("internal initialization: %p", (void*)pal_osThreadGetId()); + + /* Register sources */ + static const ARM_UPDATE_SOURCE* sources[] = { + &ARM_UCS_HTTPSource, + &ARM_UCS_LWM2M_SOURCE + }; + + ARM_UC_HUB_SetSources(sources, sizeof(sources)/sizeof(ARM_UPDATE_SOURCE*)); + + /* Register sink for telemetry */ + ARM_UC_HUB_AddMonitor(&ARM_UCS_LWM2M_MONITOR); + + /* Register local error handler */ + ARM_UC_HUB_AddErrorCallback(UpdateClient::error_handler); + + /* Link internal queue with external scheduler. + The callback handler is called whenever a task is posted to + an empty queue. This will trigger the queue to be processed. + */ + ARM_UC_HUB_AddNotificationHandler(UpdateClient::queue_handler); + + /* The override function enables the LWM2M Firmware Update Object + to authorize both download and installation. The intention is + that a buggy user application can't block an update. + */ + ARM_UC_CONTROL_SetOverrideCallback(ARM_UC_OverrideAuthorization); + +#ifdef MBED_CLOUD_CLIENT_UPDATE_STORAGE + /* Set implementation for storing firmware */ + ARM_UC_HUB_SetStorage(&MBED_CLOUD_CLIENT_UPDATE_STORAGE); +#endif + +#ifdef MBED_CLOUD_DEV_UPDATE_PSK + /* Add pre shared key */ + ARM_UC_AddPreSharedKey(arm_uc_default_psk, arm_uc_default_psk_bits); +#endif + + /* Insert default certificate if defined otherwise initialze + Update client immediately. + */ +#ifdef MBED_CLOUD_DEV_UPDATE_CERT + /* Add verification certificate */ + arm_uc_error_t result = ARM_UC_AddCertificate(arm_uc_default_certificate, + arm_uc_default_certificate_size, + arm_uc_default_fingerprint, + arm_uc_default_fingerprint_size, + UpdateClient::certificate_done); + + /* Certificate insertion failed, most likely because the certificate + has already been inserted once before. + + Continue initialization regardlessly, since the Update Client can still + work if verification certificates are inserted through the Factory + Client or by other means. + */ + if (result.code != ARM_UC_CM_ERR_NONE) + { + tr_info("ARM_UC_AddCertificate failed"); + + ARM_UC_HUB_Initialize(UpdateClient::initialization_done); + } +#else + ARM_UC_HUB_Initialize(UpdateClient::initialization_done); +#endif +} + +static void UpdateClient::certificate_done(arm_uc_error_t error, + const arm_uc_buffer_t* fingerprint) +{ + (void) fingerprint; + + /* Certificate insertion failure is not necessarily fatal. + If verification certificates have been injected by other means + it is still possible to perform updates, which is why the + Update client initializes anyway. + */ + if (error.code != ARM_UC_CM_ERR_NONE) + { + error_callback.call(WarningCertificateInsertion); + } + + ARM_UC_HUB_Initialize(UpdateClient::initialization_done); +} + +static void UpdateClient::initialization_done(int32_t result) +{ + tr_info("internal initialization done: %" PRIu32 " %p", result, (void*)pal_osThreadGetId()); +} + +static void UpdateClient::event_handler(arm_event_s* event) +{ + switch (event->event_type) + { + case UPDATE_CLIENT_EVENT_INITIALIZE: + UpdateClient::initialization(); + break; + + case UPDATE_CLIENT_EVENT_PROCESS_QUEUE: + { + /* process a single callback, for better cooperability */ + bool queue_not_empty = ARM_UC_ProcessSingleCallback(); + + if (queue_not_empty) + { + /* reschedule event handler, if queue is not empty */ + UpdateClient::schedule_event(); + } + } + break; + + default: + break; + } +} + +static void UpdateClient::queue_handler(void) +{ + /* warning: queue_handler can be called from interrupt context. + */ + UpdateClient::schedule_event(); +} + +static void UpdateClient::schedule_event() +{ + /* schedule event */ + arm_event_s event = { + .receiver = update_client_tasklet_id, + .sender = 0, + .event_type = UPDATE_CLIENT_EVENT_PROCESS_QUEUE, + .event_id = 0, + .data_ptr = NULL, + .priority = ARM_LIB_LOW_PRIORITY_EVENT, + .event_data = 0, + }; + + eventOS_event_send(&event); +} + +static void UpdateClient::error_handler(int32_t error) +{ + tr_info("error reported: %" PRIi32, error); + + /* add warning base if less severe than error */ + if (error < ARM_UC_ERROR) + { + error_callback.call(WarningBase + error); + } + /* add error base if less severe than fatal */ + else if (error < ARM_UC_FATAL) + { + error_callback.call(ErrorBase + error); + } + /* add fatal base */ + else + { + error_callback.call(FatalBase + error); + } +} + +int UpdateClient::getVendorId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size) +{ + arm_uc_error_t err = ARM_UC_GetVendorId(buffer, buffer_size_max, value_size); + if (err.code == ARM_UC_DI_ERR_SIZE) + { + return CCS_STATUS_MEMORY_ERROR; + } + if (err.error == ERR_NONE) + { + *value_size = 16; + return CCS_STATUS_SUCCESS; + } + return CCS_STATUS_KEY_DOESNT_EXIST; +} +int UpdateClient::getClassId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size) +{ + arm_uc_error_t err = ARM_UC_GetClassId(buffer, buffer_size_max, value_size); + if (err.code == ARM_UC_DI_ERR_SIZE) + { + return CCS_STATUS_MEMORY_ERROR; + } + if (err.error == ERR_NONE) + { + *value_size = 16; + return CCS_STATUS_SUCCESS; + } + return CCS_STATUS_KEY_DOESNT_EXIST; +} +int UpdateClient::getDeviceId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size) +{ + arm_uc_error_t err = ARM_UC_GetDeviceId(buffer, buffer_size_max, value_size); + if (err.code == ARM_UC_DI_ERR_SIZE) + { + return CCS_STATUS_MEMORY_ERROR; + } + if (err.error == ERR_NONE) + { + *value_size = 16; + return CCS_STATUS_SUCCESS; + } + return CCS_STATUS_KEY_DOESNT_EXIST; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/include/CertificateParser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/include/CertificateParser.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,39 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef CERTIFICATE_PARSER_H +#define CERTIFICATE_PARSER_H + +#include "ns_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* \brief A utility function to extract CN field from the mDS certificate and store it to KCM. +* \param certificate, The certificate to be extracted. +* \param common_name [OUT], buffer containing CN value. Maximum common name can be 64 bytes. +* \return True if success, False if failure. +*/ +bool extract_cn_from_certificate(const uint8_t* cer, size_t cer_len, char *common_name); + +#ifdef __cplusplus +} +#endif +#endif // CERTIFICATE_PARSER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/include/CloudClientStorage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/include/CloudClientStorage.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,73 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef CLOUD_CLIENT_STORAGE_H +#define CLOUD_CLIENT_STORAGE_H + +#define KEY_ACCOUNT_ID "mbed.AccountID" +#define KEY_INTERNAL_ENDPOINT "mbed.InternalEndpoint" +#define KEY_DEVICE_SOFTWAREVERSION "mbed.SoftwareVersion" +#define KEY_FIRST_TO_CLAIM "mbed.FirstToClaim" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + CCS_STATUS_MEMORY_ERROR = -4, + CCS_STATUS_VALIDATION_FAIL = -3, + CCS_STATUS_KEY_DOESNT_EXIST = -2, + CCS_STATUS_ERROR = -1, + CCS_STATUS_SUCCESS = 0 +} ccs_status_e; + +/** +* \brief Uninitializes the CFStore handle. +*/ +ccs_status_e uninitialize_storage(void); + +/** +* \brief Initializes the CFStore handle. +*/ +ccs_status_e initialize_storage(void); + +/* Bootstrap credential handling methods */ +ccs_status_e get_config_parameter(const char* key, uint8_t *buffer, const size_t buffer_size, size_t *value_length); +ccs_status_e get_config_parameter_string(const char* key, uint8_t *buffer, const size_t buffer_size); +ccs_status_e set_config_parameter(const char* key, const uint8_t *buffer, const size_t buffer_size); +ccs_status_e delete_config_parameter(const char* key); +ccs_status_e size_config_parameter(const char* key, size_t* size_out); + +ccs_status_e get_config_private_key(const char* key, uint8_t *buffer, const size_t buffer_size, size_t *value_length); +ccs_status_e set_config_private_key(const char* key, const uint8_t *buffer, const size_t buffer_size); +ccs_status_e delete_config_private_key(const char* key); + +ccs_status_e get_config_public_key(const char* key, uint8_t *buffer, const size_t buffer_size, size_t *value_length); +ccs_status_e set_config_public_key(const char* key, const uint8_t *buffer, const size_t buffer_size); +ccs_status_e delete_config_public_key(const char* key); + +ccs_status_e get_config_certificate(const char* key, uint8_t *buffer, const size_t buffer_size, size_t *value_length); +ccs_status_e set_config_certificate(const char* key, const uint8_t *buffer, const size_t buffer_size); +ccs_status_e delete_config_certificate(const char* key); + + + +#ifdef __cplusplus +} +#endif +#endif // CLOUD_CLIENT_STORAGE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/include/ConnectorClient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/include/ConnectorClient.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,369 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __CONNECTOR_CLIENT_H__ +#define __CONNECTOR_CLIENT_H__ + +#include "mbed-client/functionpointer.h" +#include "mbed-client/m2minterfacefactory.h" +#include "mbed-client/m2mdevice.h" +#include "mbed-client/m2minterfaceobserver.h" +#include "mbed-client/m2minterface.h" +#include "mbed-client/m2mobjectinstance.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mtimerobserver.h" +#include "mbed-client/m2mtimer.h" +#include "include/CloudClientStorage.h" + +class ConnectorClientCallback; + +using namespace std; + + +/** + * \brief ConnectorClientEndpointInfo + * A structure that contains the needed endpoint information to register with the Cloud service. + * Note: this should be changed to a class instead of struct and/or members changed to "const char*". + */ +struct ConnectorClientEndpointInfo { + +public: + ConnectorClientEndpointInfo(M2MSecurity::SecurityModeType m) : mode(m) {}; + ~ConnectorClientEndpointInfo() {}; + +public: + + String endpoint_name; + String account_id; + String internal_endpoint_name; + M2MSecurity::SecurityModeType mode; +}; + +/** + * \brief ConnectorClient + * This class is an interface towards the M2MInterface client to handle all + * data flow towards Connector through this client. + * This class is intended to be used via ServiceClient, not directly. + * This class contains also the bootstrap functionality. + */ +class ConnectorClient : public M2MInterfaceObserver, public M2MTimerObserver { + +public: + /** + * \brief An enum defining the different states of + * ConnectorClient during the client flow. + */ + enum StartupSubStateRegistration { + State_Bootstrap_Start, + State_Bootstrap_Started, + State_Bootstrap_Success, + State_Bootstrap_Failure, + State_Registration_Start, + State_Registration_Started, + State_Registration_Success, + State_Registration_Failure, + State_Registration_Updated, + State_Unregistered + }; + +public: + + /** + * \brief Constructor. + * \param callback, A callback for the status from ConnectorClient. + */ + ConnectorClient(ConnectorClientCallback* callback); + + /** + * \brief Destructor. + */ + ~ConnectorClient(); + + /** + * \brief Starts the bootstrap sequence from the Service Client. + */ + void start_bootstrap(); + + /** + * \brief Starts the registration sequence from the Service Client. + * \param client_objs, A list of objects to be registered with Cloud. + */ + void start_registration(M2MObjectList* client_objs); + + /** + * \brief Sends an update registration message to the LWM2M server. + */ + void update_registration(); + + /** + * \brief Returns the M2MInterface handler. + * \return M2MInterface, Handled for M2MInterface. + */ + M2MInterface * m2m_interface(); + + /** + * \brief Checks whether to use Bootstrap or direct Connector mode. + * \return True if bootstrap mode, False if direct Connector flow + */ + bool use_bootstrap(); + + /** + * \brief Checks whether to go connector registration flow + * \return True if connector credentials available otherwise false. + */ + bool connector_credentials_available(); + + /** + * \brief A utility function to generate the key name. + * \param key, The key to get the value for. + * \param endpoint, The name of the endpoint to be appended + * to the key. + * \param key_name, The [OUT] final key name. + * \return True if available, else false. + */ + bool get_key(const char *key, const char *endpoint, char *&key_name); + + /** + * \brief Returns pointer to the ConnectorClientEndpointInfo object. + * \return ConnectorClientEndpointInfo pointer. + */ + const ConnectorClientEndpointInfo *endpoint_info() const; + +public: + // implementation of M2MInterfaceObserver: + + /** + * \brief A callback indicating that the bootstap has been performed successfully. + * \param server_object, The server object that contains the information fetched + * about the LWM2M server from the bootstrap server. This object can be used + * to register with the LWM2M server. The object ownership is passed. + */ + virtual void bootstrap_done(M2MSecurity *server_object); + + /** + * \brief A callback indicating that the device object has been registered + * successfully with the LWM2M server. + * \param security_object, The server object on which the device object is + * registered. The object ownership is passed. + * \param server_object, An object containing information about the LWM2M server. + * The client maintains the object. + */ + virtual void object_registered(M2MSecurity *security_object, const M2MServer &server_object); + + /** + * \brief A callback indicating that the device object has been successfully unregistered + * from the LWM2M server. + * \param server_object, The server object from which the device object is + * unregistered. The object ownership is passed. + */ + virtual void object_unregistered(M2MSecurity *server_object); + + /** + * \brief A callback indicating that the device object registration has been successfully + * updated on the LWM2M server. + * \param security_object, The server object on which the device object registration is + * updated. The object ownership is passed. + * \param server_object, An object containing information about the LWM2M server. + * The client maintains the object. + */ + virtual void registration_updated(M2MSecurity *security_object, const M2MServer & server_object); + + /** + * \brief A callback indicating that there was an error during the operation. + * \param error, An error code for the occurred error. + */ + virtual void error(M2MInterface::Error error); + + /** + * \brief A callback indicating that the value of the resource object is updated by the server. + * \param base, The object whose value is updated. + * \param type, The type of the object. + */ + virtual void value_updated(M2MBase *base, M2MBase::BaseType type); + +protected: // from M2MTimerObserver + + virtual void timer_expired(M2MTimerObserver::Type type); + +private: + /** + * \brief Redirects the state machine to right function. + * \param current_state, The current state to be set. + * \param data, The data to be passed to the state function. + */ + void state_function(StartupSubStateRegistration current_state); + + /** + * \brief The state engine maintaining the state machine logic. + */ + void state_engine(void); + + /** + * \brief An internal event generated by the state machine. + * \param new_state, The new state to which the state machine should go. + * \param data, The data to be passed to the state machine. + */ + void internal_event(StartupSubStateRegistration new_state); + + /** + * When the bootstrap starts. + */ + void state_bootstrap_start(); + + /** + * When the bootstrap is started. + */ + void state_bootstrap_started(); + + /** + * When the bootstrap is successful. + */ + void state_bootstrap_success(); + + /** + * When the bootstrap failed. + */ + void state_bootstrap_failure(); + + /** + * When the registration starts. + */ + void state_registration_start(); + + /** + * When the registration started. + */ + void state_registration_started(); + + /** + * When the registration is successful. + */ + void state_registration_success(); + + /** + * When the registration failed. + */ + void state_registration_failure(); + + /** + * When the client is unregistered. + */ + void state_unregistered(); + + /** + * \brief A utility function to create an M2MSecurity object + * for registration. + */ + void create_register_object(); + + /** + * \brief A utility function to create an M2MSecurity object + * for bootstrap. + */ + bool create_bootstrap_object(); + + /** + * \brief A utility function to set the connector credentials + * in storage. This includes endpoint, domain, connector URI + * and certificates. + * \param security, The Connector certificates. + */ + ccs_status_e set_connector_credentials(M2MSecurity *security); + + /** + * \brief A utility function to set the bootstrap credentials + * in storage. This includes Bootstrap URI and certificates. + * \param security, The Bootstrap certificates. + */ + ccs_status_e set_bootstrap_credentials(M2MSecurity *security); + + /** + * \brief A utility function to set the bootstrap address in storage. + * \param security, The bootstrap security object containing the address. + */ + ccs_status_e store_bootstrap_address(M2MSecurity *security); + + /** + * \brief A utility function to check whether bootstrap credentials are stored in KCM. + */ + bool bootstrap_credentials_stored_in_kcm(); + + /** + * \brief A utility function to check whether first to claim feature is configured. + */ + bool is_first_to_claim(); + + /** + * \brief A utility function to clear the first to claim parameter in storage. + */ + ccs_status_e clear_first_to_claim(); + + /** + * \brief Returns the binding mode selected by the client + * through the configuration. + * \return Binding mode of the client. + */ + static M2MInterface::BindingMode transport_mode(); + +private: + // A callback to be called after the sequence is complete. + ConnectorClientCallback* _callback; + StartupSubStateRegistration _current_state; + bool _event_generated; + bool _state_engine_running; + M2MInterface *_interface; + M2MSecurity *_security; + ConnectorClientEndpointInfo _endpoint_info; + M2MObjectList *_client_objs; + M2MTimer _rebootstrap_timer; + uint16_t _bootstrap_security_instance; + uint16_t _lwm2m_security_instance; +}; + +/** + * \brief ConnectorClientCallback + * A callback class for passing the client progress and error condition to the + * ServiceClient class object. + */ +class ConnectorClientCallback { +public: + + /** + * \brief Indicates that the registration or unregistration operation is complete + * with success or failure. + * \param status, Indicates success or failure in terms of status code. + */ + virtual void registration_process_result(ConnectorClient::StartupSubStateRegistration status) = 0; + + /** + * \brief Indicates the Connector error condition of an underlying M2MInterface client. + * \param error, Indicates an error code translated from M2MInterface::Error. + * \param reason, Indicates human readable text for error description. + */ + virtual void connector_error(M2MInterface::Error error, const char *reason) = 0; + + /** + * \brief A callback indicating that the value of the resource object is updated + * by the LWM2M Cloud server. + * \param base, The object whose value is updated. + * \param type, The type of the object. + */ + virtual void value_updated(M2MBase *base, M2MBase::BaseType type) = 0; +}; + +#endif // !__CONNECTOR_CLIENT_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/include/ServiceClient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/include/ServiceClient.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,279 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __SERVICE_CLIENT_H__ +#define __SERVICE_CLIENT_H__ + +#include "mbed-cloud-client/MbedCloudClientConfig.h" +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE +#include "UpdateClient.h" +#endif +#include "mbed-client/m2minterface.h" +#include "mbed-client/m2mdevice.h" +#include "ConnectorClient.h" + +#include <string> + +class M2MSecurity; +class ConnectorClientCallback; +struct MbedClientDeviceInfo; +struct MBedClientInterfaceInfo; + +/** + * \brief ServiceClientCallback + * A callback class for passing the client progress and error condition to the + * MbedCloudClient class object. + */ +class ServiceClientCallback { +public: + + typedef enum { + Service_Client_Status_Failure = -1, + Service_Client_Status_Registered = 0, + Service_Client_Status_Unregistered = 1, + Service_Client_Status_Register_Updated = 2 + } ServiceClientCallbackStatus; + + /** + * \brief Indicates that the setup or close operation is complete + * with success or failure. + * \param status, Indicates success or failure in terms of status code. + */ + virtual void complete(ServiceClientCallbackStatus status) = 0; + + /** + * \brief Indicates an error condition from one of the underlying clients, including + * identity, connector or update client. + * \param error, Indicates an error code translated to MbedCloudClient::Error. + * \param reason, Indicates human readable text for error description. + */ + virtual void error(int error, const char *reason) = 0; + + /** + * \brief A callback indicating that the value of the resource object is updated + * by the LWM2M Cloud server. + * \param base, The object whose value is updated. + * \param type, The type of the object. + */ + virtual void value_updated(M2MBase *base, M2MBase::BaseType type) = 0; +}; + + +/** + * \brief ServiceClient + * This class handles all internal interactions between various client + * components including connector, identity and update. + * This class maintains the state machine for the use case flow of mbed Cloud + * Client. + */ + +class ServiceClient : private ConnectorClientCallback +{ +public: + + /** + * \brief An enum defining the different states of + * ServiceClient during the client flow. + */ + enum StartupMainState { + State_Init, + State_Bootstrap, + State_Register, + State_Success, + State_Failure, + State_Unregister + }; + +public: + + /** + * \brief Constructor. + * \param interface, Takes the structure that contains the + * needed information for an endpoint client to register. + */ + ServiceClient(ServiceClientCallback& callback); + + /** + * \brief Destructor. + */ + virtual ~ServiceClient(); + + /** + * \brief Starts the registration or bootstrap sequence from MbedCloudClient. + * \param callback, Takes the callback for the status from ConnectorClient. + * \param client_objs, A list of objects to be registered to Cloud. + */ + void initialize_and_register(M2MObjectList& client_objs); + + /** + * \brief Returns the ConnectorClient handler. + * \return ConnectorClient, handled for ConnectorClient. + */ + ConnectorClient &connector_client(); + + /** + * \brief Returns const ConnectorClient handler. + * \return const ConnectorClient, handled for ConnectorClient. + */ + const ConnectorClient &connector_client() const; + + /** + * \brief Set resource value in the Device Object + * + * \param resource Device enum to have value set. + * \param value String object. + * \return True if successful, false otherwise. + */ + bool set_device_resource_value(M2MDevice::DeviceResource resource, + const std::string& value); + + /** + * \brief Set resource value in the Device Object + * + * \param resource Device enum to have value set. + * \param value Byte buffer. + * \param length Buffer length. + * \return True if successful, false otherwise. + */ + bool set_device_resource_value(M2MDevice::DeviceResource resource, + const char* value, + uint32_t length); + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + /** + * \brief Registers a callback function for authorizing firmware downloads and reboots. + * \param handler Callback function. + */ + void set_update_authorize_handler(void (*handler)(int32_t request)); + + /** + * \brief Authorize request passed to authorization handler. + * \param request Request being authorized. + */ + void update_authorize(int32_t request); + + /** + * \brief Registers a callback function for monitoring download progress. + * \param handler Callback function. + */ + void set_update_progress_handler(void (*handler)(uint32_t progress, uint32_t total)); + + /** + * \brief Callback function for the Update Client. + * \param error Internal Update Client error code. + */ + void update_error_callback(int32_t error); +#endif + +protected : + + // Implementation of ConnectorClientCallback + /** + * \brief Indicates that the registration or unregistration operation is complete + * with success or failure. + * \param status, Indicates success or failure in terms of status code. + */ + virtual void registration_process_result(ConnectorClient::StartupSubStateRegistration status); + + /** + * \brief Indicates a connector error condition from an underlying M2MInterface client. + * \param error, Indicates an error code translated from M2MInterface::Error. + */ + virtual void connector_error(M2MInterface::Error error, const char *reason); + + /** + * \brief A callback indicating that the value of the resource object is updated + * by the LWM2M Cloud server. + * \param base, The object whose value is updated. + * \param type, The type of the object. + */ + virtual void value_updated(M2MBase *base, M2MBase::BaseType type); + + /** + * \brief Redirects the state machine to the right function. + * \param current_state, The current state to be set. + * \param data, The data to be passed to the state function. + */ + void state_function(StartupMainState current_state); + + /** + * \brief The state engine maintaining the state machine logic. + */ + void state_engine(void); + + /** + * An external event that can trigger the state machine. + * \param new_state, The new state to which the state machine should go. + * \param data, The data to be passed to the state machine. + */ + void external_event(StartupMainState new_state); + + /** + * An internal event generated by the state machine. + * \param new_state, The new state to which the state machine should go. + * \param data, The data to be passed to the state machine. + */ + void internal_event(StartupMainState new_state); + + /** + * When the bootstrap is started. + */ + void state_bootstrap(); + + /** + * When the registration is started. + */ + void state_register(); + + /** + * When the registration is successful. + */ + void state_success(); + + /** + * When the registration has failed. + */ + + void state_failure(); + + /** + * When the client unregisters. + */ + void state_unregister(); + +private: + M2MDevice* device_object_from_storage(); + + /* lookup table for printing hexadecimal values */ + static const uint8_t hex_table[16]; + + ServiceClientCallback &_service_callback; + // data which is pending for the registration + const char *_service_uri; + void *_stack; + M2MObjectList *_client_objs; + StartupMainState _current_state; + bool _event_generated; + bool _state_engine_running; +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + bool _setup_update_client; +#endif + ConnectorClient _connector_client; +}; + +#endif // !__SERVICE_CLIENT_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/include/UpdateClient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/include/UpdateClient.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,127 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MBED_CLOUD_CLIENT_UPDATE_CLIENT_H +#define MBED_CLOUD_CLIENT_UPDATE_CLIENT_H + +#include "mbed-client/m2minterface.h" +#include "update-client-hub/update_client_public.h" + +namespace UpdateClient +{ + /** + * Error codes used by the Update Client. + * + * Warning: a recoverable error occured, no user action required. + * Error : a recoverable error occured, action required. E.g. the + * application has to free some space and let the Update + * Service try again. + * Fatal : a non-recoverable error occured, application should safe + * ongoing work and reboot the device. + */ + enum { + WarningBase = 0x0400, // Range reserved for Update Error from 0x0400 - 0x04FF + WarningCertificateNotFound = WarningBase + ARM_UC_WARNING_CERTIFICATE_NOT_FOUND, + WarningIdentityNotFound = WarningBase + ARM_UC_WARNING_IDENTITY_NOT_FOUND, + WarningVendorMismatch = WarningBase + ARM_UC_WARNING_VENDOR_MISMATCH, + WarningClassMismatch = WarningBase + ARM_UC_WARNING_CLASS_MISMATCH, + WarningDeviceMismatch = WarningBase + ARM_UC_WARNING_DEVICE_MISMATCH, + WarningCertificateInvalid = WarningBase + ARM_UC_WARNING_CERTIFICATE_INVALID, + WarningSignatureInvalid = WarningBase + ARM_UC_WARNING_SIGNATURE_INVALID, + WarningURINotFound = WarningBase + ARM_UC_WARNING_URI_NOT_FOUND, + WarningRollbackProtection = WarningBase + ARM_UC_WARNING_ROLLBACK_PROTECTION, + WarningUnknown = WarningBase + ARM_UC_WARNING_UNKNOWN, + WarningCertificateInsertion, + ErrorBase, + ErrorWriteToStorage = ErrorBase + ARM_UC_ERROR_WRITE_TO_STORAGE, + ErrorInvalidHash = ErrorBase + ARM_UC_ERROR_INVALID_HASH, + FatalBase + }; + + enum { + RequestInvalid = ARM_UCCC_REQUEST_INVALID, + RequestDownload = ARM_UCCC_REQUEST_DOWNLOAD, + RequestInstall = ARM_UCCC_REQUEST_INSTALL + }; + + /** + * \brief Initialization function for the Update Client. + * \param Callback to error handler. + */ + void UpdateClient(FP1<void, int32_t> callback); + + /** + * \brief Populate M2MObjectList with Update Client objects. + * \details The function takes an existing object list and adds LWM2M + * objects needed by the Update Client. + * + * \param list M2MObjectList reference. + */ + void populate_object_list(M2MObjectList& list); + + /** + * \brief Registers a callback function for authorizing firmware downloads and reboots. + * \param handler Callback function. + */ + void set_update_authorize_handler(void (*handler)(int32_t request)); + + /** + * \brief Authorize request passed to authorization handler. + * \param request Request being authorized. + */ + void update_authorize(int32_t request); + + /** + * \brief Registers a callback function for monitoring download progress. + * \param handler Callback function. + */ + void set_update_progress_handler(void (*handler)(uint32_t progress, uint32_t total)); + + /** + * \brief Fills the buffer with the 16-byte vendor UUID + * \param buffer The buffer to fill with the UUID + * \param buffer_size_max The maximum avaliable space in the buffer + * \param value_size A pointer to a length variable to populate with the length of the UUID (always 16) + * \retval CCS_STATUS_MEMORY_ERROR when the buffer is less than 16 bytes + * \retval CCS_STATUS_KEY_DOESNT_EXIST when no vendor ID is present + * \retval CCS_STATUS_SUCCESS on success + */ + int getVendorId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size); + /** + * \brief Fills the buffer with the 16-byte device class UUID + * \param buffer The buffer to fill with the UUID + * \param buffer_size_max The maximum avaliable space in the buffer + * \param value_size A pointer to a length variable to populate with the length of the UUID (always 16) + * \retval CCS_STATUS_MEMORY_ERROR when the buffer is less than 16 bytes + * \retval CCS_STATUS_KEY_DOESNT_EXIST when no device class ID is present + * \retval CCS_STATUS_SUCCESS on success + */ + int getClassId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size); + /** + * \brief Fills the buffer with the 16-byte device UUID + * \param buffer The buffer to fill with the UUID + * \param buffer_size_max The maximum avaliable space in the buffer + * \param value_size A pointer to a length variable to populate with the length of the UUID (always 16) + * \retval CCS_STATUS_MEMORY_ERROR when the buffer is less than 16 bytes + * \retval CCS_STATUS_KEY_DOESNT_EXIST when no device ID is present + * \retval CCS_STATUS_SUCCESS on success + */ + int getDeviceId(uint8_t* buffer, size_t buffer_size_max, size_t* value_size); +} + +#endif // MBED_CLOUD_CLIENT_UPDATE_CLIENT_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/source/include/UpdateClientResources.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/source/include/UpdateClientResources.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,59 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MBED_CLOUD_CLIENT_UPDATE_RESOURCES_H +#define MBED_CLOUD_CLIENT_UPDATE_RESOURCES_H + +#ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#include MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#endif + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE +#include "update-client-hub/update_client_hub.h" +#endif + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MBED_CLOUD_DEV_UPDATE_ID +extern const uint8_t arm_uc_vendor_id[]; +extern const uint16_t arm_uc_vendor_id_size; +extern const uint8_t arm_uc_class_id[]; +extern const uint16_t arm_uc_class_id_size; +#endif + +#ifdef MBED_CLOUD_DEV_UPDATE_CERT +extern const uint8_t arm_uc_default_fingerprint[]; +extern const uint16_t arm_uc_default_fingerprint_size; +extern const uint8_t arm_uc_default_certificate[]; +extern const uint16_t arm_uc_default_certificate_size; +#endif + +#ifdef MBED_CLOUD_DEV_UPDATE_PSK +extern const uint8_t arm_uc_default_psk[]; +extern uint16_t arm_uc_default_psk_bits; +#endif + +#ifdef __cplusplus +} +#endif + +#endif // MBED_CLOUD_CLIENT_UPDATE_RESOURCES_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ +*/test/* +*/Test/* +*/test-utils/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability.
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/atomic-queue/atomic-queue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/atomic-queue/atomic-queue.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,107 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ATOMIC_QUEUE_H__ +#define __ATOMIC_QUEUE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +#if defined(ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK) && ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK == 0 +#undef ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK +#else +#undef ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK +#define ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK +#endif + +#ifndef ATOMIC_QUEUE_CUSTOM_ELEMENT +struct atomic_queue_element { + struct atomic_queue_element * volatile next; +#ifdef ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK + uintptr_t lock; +#endif + void * data; +}; +#endif + +struct atomic_queue { + struct atomic_queue_element * volatile tail; +}; + +enum aq_failure_codes { + ATOMIC_QUEUE_SUCCESS = 0, + ATOMIC_QUEUE_NULL_QUEUE, + ATOMIC_QUEUE_DUPLICATE_ELEMENT, +}; + +/** + * \brief Add an element to the tail of the queue + * + * Since the queue only maintains a tail pointer, this simply inserts the new element before the tail pointer + * + * @param[in,out] q the queue structure to operate on + * @param[in] e The element to add to the queue + */ +int aq_push_tail(struct atomic_queue * q, struct atomic_queue_element * e); +/** + * \brief Get an element from the head of the queue + * + * This function iterates over the queue and removes an element from the head when it finds the head. This is slower + * than maintaining a head pointer, but it is necessary to ensure that a pop is completely atomic. + * + * @param[in,out] q The queue to pop from + * @return The popped element or NULL if the queue was empty + */ +struct atomic_queue_element * aq_pop_head(struct atomic_queue * q); +/** + * Check if there are any elements in the queue + * + * Note that there is no guarantee that a queue which is not empty when this API is called will not be become empty + * before aq_pop_head is called + * + * @retval non-zero when the queue is empty + * @retval 0 when the queue is not empty + */ +int aq_empty(struct atomic_queue * q); +/** + * Iterates over the queue and counts the elements in the queue + * + * The value returned by this function may be invalid by the time it returns. Do not depend on this value except in + * a critical section. + * + * @return the number of elements in the queue + */ +unsigned aq_count(struct atomic_queue * q); + +/** + * Initialize an atomic queue element. + * + * WARNING: Only call this function one time per element, or it may result in undefined behaviour. + * + * @param[in] element Element to initialize + */ +void aq_initialize_element(struct atomic_queue_element* e); + +#ifdef __cplusplus +} +#endif + +#endif // __ATOMIC_QUEUE_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/aq_critical.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/aq_critical.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ATOMIC_QUEUE_CRITICAL_H__ +#define __ATOMIC_QUEUE_CRITICAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Mark the start of a critical section + * + * This function should be called to mark the start of a critical section of code. + * \note + * NOTES: + * 1) The use of this style of critical section is targetted at C based implementations. + * 2) These critical sections can be nested. + * 3) The interrupt enable state on entry to the first critical section (of a nested set, or single + * section) will be preserved on exit from the section. + * 4) This implementation will currently only work on code running in privileged mode. + */ +void aq_critical_section_enter(); + +/** Mark the end of a critical section + * + * This function should be called to mark the end of a critical section of code. + * \note + * NOTES: + * 1) The use of this style of critical section is targetted at C based implementations. + * 2) These critical sections can be nested. + * 3) The interrupt enable state on entry to the first critical section (of a nested set, or single + * section) will be preserved on exit from the section. + * 4) This implementation will currently only work on code running in privileged mode. + */ +void aq_critical_section_exit(); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif // __ATOMIC_QUEUE_CRITICAL_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/atomic-cm3.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/atomic-cm3.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,58 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "atomic.h" + +#if defined(TARGET_LIKE_MBED) +#include "cmsis.h" +#endif + +#if defined(__CORTEX_M) && (__CORTEX_M >= 0x03) + +#define STATIC_ASSERT(STATIC_ASSERT_FAILED,MSG)\ + switch(0){\ + case 0:case (STATIC_ASSERT_FAILED): \ + break;} + +#include <stddef.h> +#include <stdint.h> + +int aq_atomic_cas_deref_uintptr(uintptr_t* volatile * ptrAddr, + uintptr_t** currentPtrValue, + uintptr_t expectedDerefValue, + uintptr_t* newPtrValue, + uintptr_t valueOffset) +{ + STATIC_ASSERT(sizeof(uintptr_t) == sizeof(uint32_t), Error: Pointer size mismatch) + uint32_t *current; + current = (uint32_t *)__LDREXW((volatile uint32_t *)ptrAddr); + if (currentPtrValue != NULL) { + *currentPtrValue = (uintptr_t *)current; + } + if (current == NULL) { + return AQ_ATOMIC_CAS_DEREF_NULLPTR; + } else if ( *(uint32_t *)((uintptr_t)current + valueOffset) != expectedDerefValue) { + return AQ_ATOMIC_CAS_DEREF_VALUE; + } else if(__STREXW((uint32_t)newPtrValue, (volatile uint32_t *)ptrAddr)) { + return AQ_ATOMIC_CAS_DEREF_INTERUPTED; + } else { + return AQ_ATOMIC_CAS_DEREF_SUCCESS; + } +} +#endif +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/atomic-queue.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/atomic-queue.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,133 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "atomic-queue/atomic-queue.h" +#include "atomic.h" + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#define CORE_UTIL_ASSERT_MSG(test, msg) + + +int aq_push_tail(struct atomic_queue * q, struct atomic_queue_element * e) +{ + CORE_UTIL_ASSERT_MSG(q != NULL, "null queue used"); + if (q == NULL) { + return ATOMIC_QUEUE_NULL_QUEUE; + } + +/* duplicate element check using lock */ +#ifdef ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK + uintptr_t lock; + // Check/obtain a lock on the element. + do { + lock = e->lock; + if (lock) { + return ATOMIC_QUEUE_DUPLICATE_ELEMENT; + } + } while (!aq_atomic_cas_uintptr(&e->lock, lock, 1)); +#endif + + do { +/* duplicate element check by searching */ +#ifndef ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK + // Make sure the new element does not exist in the current queue + struct atomic_queue_element* te = q->tail; + while (te != NULL) + { + CORE_UTIL_ASSERT_MSG(te != e, "duplicate queue element"); + if (te == e) { + return ATOMIC_QUEUE_DUPLICATE_ELEMENT; + } + te = te->next; + } +#endif + e->next = q->tail; + } while (!aq_atomic_cas_uintptr((uintptr_t *)&q->tail, (uintptr_t)e->next, (uintptr_t)e)); + + return ATOMIC_QUEUE_SUCCESS; +} + +struct atomic_queue_element * aq_pop_head(struct atomic_queue * q) +{ + CORE_UTIL_ASSERT_MSG(q != NULL, "null queue used"); + if (q == NULL) { + return NULL; + } + struct atomic_queue_element * current; + int fail = AQ_ATOMIC_CAS_DEREF_VALUE; + while (fail != AQ_ATOMIC_CAS_DEREF_SUCCESS) { + // Set the element reference pointer to the tail pointer + struct atomic_queue_element * volatile * px = &q->tail; + if (*px == NULL) { + return NULL; + } + fail = AQ_ATOMIC_CAS_DEREF_VALUE; + while (fail == AQ_ATOMIC_CAS_DEREF_VALUE) { + fail = aq_atomic_cas_deref_uintptr((uintptr_t * volatile *)px, + (uintptr_t **)¤t, + (uintptr_t) NULL, + NULL, + offsetof(struct atomic_queue_element, next)); + if (fail == AQ_ATOMIC_CAS_DEREF_VALUE) { + if (current->next == q->tail) { + return NULL; + } + px = ¤t->next; + } + } + } + +#ifdef ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK + // Release element lock + current->lock = 0; +#endif + + return current; +} + + +int aq_empty(struct atomic_queue * q) +{ + return q->tail == NULL; +} + +unsigned aq_count(struct atomic_queue *q) +{ + unsigned x; + struct atomic_queue_element * volatile e; + if (aq_empty(q)) { + return 0; + } + e = q->tail; + for (x = 1; e->next != NULL; x++, e = e->next) { + if (e->next == q->tail){ + return (unsigned)-1; + } + } + return x; +} + +void aq_initialize_element(struct atomic_queue_element* e) +{ +#ifdef ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK + e->lock = 0; +#endif +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/atomic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/atomic.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,74 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <stddef.h> +#include "atomic.h" + +#if defined(TARGET_LIKE_MBED) +#include "cmsis.h" +#endif + +#if !defined(__CORTEX_M) || (__CORTEX_M < 0x03) +#include "aq_critical.h" + +int aq_atomic_cas_deref_uintptr(uintptr_t* volatile * ptrAddr, + uintptr_t** currentPtrValue, + uintptr_t expectedDerefValue, + uintptr_t* newPtrValue, + uintptr_t valueOffset) +{ + int rc; + aq_critical_section_enter(); + uintptr_t *current = *ptrAddr; + if (currentPtrValue != NULL) { + *currentPtrValue = current; + } + if (current == NULL) { + rc = AQ_ATOMIC_CAS_DEREF_NULLPTR; + } else if ( *(uintptr_t *)((uintptr_t)current + valueOffset) != expectedDerefValue) { + rc = AQ_ATOMIC_CAS_DEREF_VALUE; + } else { + *ptrAddr = newPtrValue; + rc = AQ_ATOMIC_CAS_DEREF_SUCCESS; + } + aq_critical_section_exit(); + return rc; +} +#endif + + +#if defined(__GNUC__) && (!defined(__CORTEX_M) || (__CORTEX_M >= 0x03)) +int aq_atomic_cas_uintptr(uintptr_t *ptr, uintptr_t oldval, uintptr_t newval) { + return __sync_bool_compare_and_swap(ptr, oldval, newval); +} +#else +int aq_atomic_cas_uintptr(uintptr_t *ptr, uintptr_t oldval, uintptr_t newval) +{ + int rc; + aq_critical_section_enter(); + if (*ptr == oldval) { + rc = 1; + *ptr = newval; + } else { + rc = 0; + } + aq_critical_section_exit(); + return rc; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/atomic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/atomic.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,70 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ATOMIC_QUEUE_ATOMIC_H +#define ATOMIC_QUEUE_ATOMIC_H +#include <stdint.h> + + + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + AQ_ATOMIC_CAS_DEREF_SUCCESS = 0, + AQ_ATOMIC_CAS_DEREF_NULLPTR, + AQ_ATOMIC_CAS_DEREF_VALUE, + AQ_ATOMIC_CAS_DEREF_INTERUPTED, +}; + +int aq_atomic_cas_uintptr(uintptr_t *ptr, uintptr_t oldval, uintptr_t newval); + +/** + * @brief Atomically compares the value of a dereferenced pointer, replacing the pointer on success. + * @detail aq_atomic_cas_deref_uintptr provides a mechanism to atomically change a pointer based on a value contained + * in the structure referenced by the pointer. This is done in the following sequence of operations: + * + * 1. Load the value of `*ptrAddr` + * 2. Optionally store the current value of `*ptrAddr` + * 3. Check that the pointer is valid: `*ptrAddr != NULL` + * 4. Check the value of the referenced location: `*(*ptrAddr + valueOffset) == expectedDerefValue` (casts omitted) + * 5. If 3 and 4 succeeded, store newPtrValue: `*ptrAddr = newPtrValue` (NOTE: in non-blocking implementations, this step can fail) + * 6. Return a status code based on the results of 3, 4, 5. + * + * @param[in,out] ptrAddr The address of the pointer to manipulate + * @param[out] currentPtrValue A pointer to a container for the current value of *ptrAddr + * @param[in] expectedDerefValue This is the value that is expected at *(uintptr_t *)((uintptr_t)*ptrAddr + valueOffset) + * @param[in] newPtrValue The value to store to *ptrAddr if the comparison is successful + * @param[in] valueOffset The offset of the target value from *ptrAddr + * + * @retval AQ_ATOMIC_CAS_DEREF_SUCCESS The compare and set has succeeded + * @retval AQ_ATOMIC_CAS_DEREF_NULLPTR `*ptrAddr` was `NULL` + * @retval AQ_ATOMIC_CAS_DEREF_VALUE The value test failed (*(*ptrAddr + valueOffset) != expectedDerefValue`) + * @retval AQ_ATOMIC_CAS_DEREF_INTERUPTED Another context modified `*ptrAddr` + */ +int aq_atomic_cas_deref_uintptr(uintptr_t* volatile * ptrAddr, + uintptr_t** currentPtrValue, + uintptr_t expectedDerefValue, + uintptr_t* newPtrValue, + uintptr_t valueOffset); + +#ifdef __cplusplus +} // extern "C" +#endif +#endif // ATOMIC_QUEUE_ATOMIC_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/critical-nordic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/critical-nordic.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,90 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifdef TARGET_NORDIC + +#include <stdint.h> // uint32_t, UINT32_MAX +#include <stddef.h> // NULL +#include <cmsis-core/core_generic.h> //__disable_irq, __enable_irq +#include <assert.h> +#include <stdbool.h> +#include <nrf_soc.h> +#include <nrf_sdm.h> + +// Module include +#include "aq_critical.h" + +static volatile union { + uint32_t _PRIMASK_state; + uint8_t _sd_state; +} _state = { 0 } ; +static volatile uint32_t _entry_count = 0; +static volatile bool _use_softdevice_routine = false; + +void aq_critical_section_enter() +{ + // if a critical section has already been entered, just update the counter + if (_entry_count) { + ++_entry_count; + return; + } + + // in this path, a critical section has never been entered + uint32_t primask = __get_PRIMASK(); + + // if interrupts are enabled, try to use the soft device + uint8_t sd_enabled; + if ((primask == 0) && (sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) && sd_enabled == 1) { + // if the soft device can be use, use it + sd_nvic_critical_region_enter(&_state._sd_state); + _use_softdevice_routine = true; + } else { + // if interrupts where enabled, disable them + if(primask == 0) { + __disable_irq(); + } + + // store the PRIMASK state, it will be restored at the end of the critical section + _state._PRIMASK_state = primask; + _use_softdevice_routine = false; + } + + assert(_entry_count == 0); // entry count should always be equal to 0 at this point + ++_entry_count; +} + +void aq_critical_section_exit() +{ + assert(_entry_count > 0); + --_entry_count; + + // If their is other segments which have entered the critical section, just leave + if (_entry_count) { + return; + } + + // This is the last segment of the critical section, state should be restored as before entering + // the critical section + if (_use_softdevice_routine) { + sd_nvic_critical_region_exit(_state._sd_state); + } else { + __set_PRIMASK(_state._PRIMASK_state); + } +} + +#endif //TARGET_NORDIC
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/critical-pal.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/critical-pal.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,52 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(ATOMIC_QUEUE_USE_PAL) && !defined(TARGET_LIKE_MBED) + +#include <stdint.h> +#include <assert.h> +#include <unistd.h> + +#include "pal.h" +// Module include +#include "aq_critical.h" + +static palMutexID_t mutex = NULLPTR; +static volatile unsigned irq_nesting_depth = 0; + +void aq_critical_section_enter() { + if (mutex == NULLPTR) { + palStatus_t rc = pal_osMutexCreate(&mutex); + assert(rc == PAL_SUCCESS); + } + if (++irq_nesting_depth > 1) { + return; + } + palStatus_t rc = pal_osMutexWait(mutex, PAL_RTOS_WAIT_FOREVER); + assert(rc == PAL_SUCCESS); +} + +void aq_critical_section_exit() { + assert(irq_nesting_depth > 0); + if (--irq_nesting_depth == 0) { + palStatus_t rc = pal_osMutexRelease(mutex); + assert(rc == PAL_SUCCESS); + } +} + +#endif // defined(ATOMIC_QUEUE_USE_PAL)
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/critical-posix.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/critical-posix.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,72 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_LIKE_POSIX) && !defined(ATOMIC_QUEUE_USE_PAL) + +// It's probably a better idea to define _POSIX_SOURCE in the target description +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#endif + +#include <stdint.h> +#include <assert.h> +#include <unistd.h> +#include <signal.h> +#include <pthread.h> + +// Module include +#include "aq_critical.h" + +static pthread_mutex_t* get_mutex() { + static int initialized = 0; + static pthread_mutex_t Mutex; + if (!initialized) + { + pthread_mutexattr_t Attr; + pthread_mutexattr_init(&Attr); + pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&Mutex, &Attr); + initialized = 1; + } + return &Mutex; +} + +static volatile unsigned irq_nesting_depth = 0; +static sigset_t old_sig_set; + +void aq_critical_section_enter() { + pthread_mutex_lock(get_mutex()); + if (++irq_nesting_depth == 1) { + int rc; + sigset_t full_set; + rc = sigfillset(&full_set); + assert(rc == 0); + rc = sigprocmask(SIG_BLOCK, &full_set, &old_sig_set); + assert(rc == 0); + } +} + +void aq_critical_section_exit() { + assert(irq_nesting_depth > 0); + if (--irq_nesting_depth == 0) { + int rc = sigprocmask(SIG_SETMASK, &old_sig_set, NULL); + assert(rc == 0); + } + pthread_mutex_unlock(get_mutex()); +} +#endif // defined(TARGET_LIKE_POSIX)
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/critical.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/critical.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,90 @@ +// ---------------------------------------------------------------------------- +// Copyright 2015-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// This critical section implementation is generic for mbed OS targets, +// except Nordic ones +#if defined(TARGET_LIKE_MBED) && !defined(TARGET_NORDIC) + +#include <stdint.h> // uint32_t, UINT32_MAX +#include <stddef.h> // NULL + +#if defined(YOTTA_CFG_MBED_OS) +#include "cmsis-core/core_generic.h" //__disable_irq, __enable_irq +#else +#include "cmsis.h" +#endif + +#include <assert.h> + +// Module include +#include "aq_critical.h" + +static volatile uint32_t interruptEnableCounter = 0; +static volatile uint32_t critical_primask = 0; + +void aq_critical_section_enter() +{ + uint32_t primask = __get_PRIMASK(); // get the current interrupt enabled state + __disable_irq(); + + // Save the interrupt enabled state as it was prior to any nested critical section lock use + if (!interruptEnableCounter) { + critical_primask = primask & 0x1; + } + + /* If the interruptEnableCounter overflows or we are in a nested critical section and interrupts + are enabled, then something has gone badly wrong thus assert an error. + */ + + /* FIXME: This assertion needs to be commented out for the moment, as it + * triggers a fault when uVisor is enabled. For more information on + * the fault please checkout ARMmbed/mbed-drivers#176. */ + /* assert(interruptEnableCounter < UINT32_MAX); */ + if (interruptEnableCounter > 0) { + /* FIXME: This assertion needs to be commented out for the moment, as it + * triggers a fault when uVisor is enabled. For more information + * on the fault please checkout ARMmbed/mbed-drivers#176. */ + /* assert(primask & 0x1); */ + } + interruptEnableCounter++; +} + +void aq_critical_section_exit() +{ + // If critical_section_enter has not previously been called, do nothing + if (interruptEnableCounter) { + + uint32_t primask = __get_PRIMASK(); // get the current interrupt enabled state + + /* FIXME: This assertion needs to be commented out for the moment, as it + * triggers a fault when uVisor is enabled. For more information + * on the fault please checkout ARMmbed/mbed-drivers#176. */ + /* assert(primask & 0x1); // Interrupts must be disabled on invoking an exit from a critical section */ + + interruptEnableCounter--; + + /* Only re-enable interrupts if we are exiting the last of the nested critical sections and + interrupts were enabled on entry to the first critical section. + */ + if (!interruptEnableCounter && !critical_primask) { + __enable_irq(); + } + } +} + +#endif // defined(TARGET_LIKE_MBED) && !defined(TARGET_NORDIC)
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/posix.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/atomic-queue/source/posix.cmake Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,23 @@ +# ---------------------------------------------------------------------------- +# Copyright 2015-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +if(TARGET_LIKE_POSIX) + target_link_libraries(${YOTTA_MODULE_NAME} "-pthread") + set_target_properties(${YOTTA_MODULE_NAME} PROPERTIES + COMPILE_FLAGS " -pthread ") +endif()
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/mbed_lib.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/mbed_lib.json Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,29 @@ +{ + "name": "update-client", + "config": { + "application-details": { + "help": "Location in memory where the application information can be read.", + "value": "0" + }, + "bootloader-details": { + "help": "Location in memory where the bootloader information can be read.", + "value": "0" + }, + "storage-address": { + "help": "When using address based storage (FlashIAP, Block Device), this is the starting address.", + "value": "0" + }, + "storage-size": { + "help": "Total storage allocated.", + "value": "0" + }, + "storage-locations": { + "help": "Number of equally sized locations the storage space should be split into.", + "value": "1" + }, + "storage-page": { + "help": "Smallest write unit on storage device. Used for compile time check of download/write buffers.", + "value": "512" + } + } +} \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_crypto.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_crypto.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,324 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-common/arm_uc_config.h" +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_crypto.h" + +#include <string.h> + + +#if ARM_UC_USE_PAL_CRYPTO +#include "pal.h" +#ifndef palMDHandle_t +#include "pal_Crypto.h" +#endif + +#define ARM_UC_CU_SHA256 PAL_SHA256 +arm_uc_error_t ARM_UC_verifyPkSignature(const arm_uc_buffer_t* ca, const arm_uc_buffer_t* hash, const arm_uc_buffer_t* sig) +{ + arm_uc_error_t err = {MFST_ERR_CERT_INVALID}; + palX509Handle_t x509Cert; + if (PAL_SUCCESS == pal_x509Initiate(&x509Cert)) + { + err.code = MFST_ERR_CERT_INVALID; + if (PAL_SUCCESS == pal_x509CertParse(x509Cert, ca->ptr, ca->size)) + { + // if (PAL_SUCCESS == pal_x509CertVerify(x509Cert, palX509Handle_t x509CertChain)) + // { + err.code = MFST_ERR_INVALID_SIGNATURE; + if (PAL_SUCCESS == pal_verifySignature(x509Cert, PAL_SHA256, hash->ptr, hash->size, sig->ptr, sig->size)) + { + err.code = MFST_ERR_NONE; + } + // } + } + pal_x509Free(&x509Cert); + } + return err; +} + +arm_uc_error_t ARM_UC_cryptoHashSetup(arm_uc_mdHandle_t* hDigest, arm_uc_mdType_t mdType) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + if (hDigest) + { + palStatus_t rc = pal_mdInit(hDigest, mdType); + if (rc == PAL_SUCCESS) + { + result.code = ARM_UC_CU_ERR_NONE; + } + } + return result; +} + +arm_uc_error_t ARM_UC_cryptoHashUpdate(arm_uc_mdHandle_t* hDigest, arm_uc_buffer_t* input) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + if (hDigest && input) + { + palStatus_t rc = pal_mdUpdate(*hDigest, input->ptr, input->size); + if (rc == PAL_SUCCESS) + { + result = (arm_uc_error_t){ ARM_UC_CU_ERR_NONE }; + } + } + return result; +} + +arm_uc_error_t ARM_UC_cryptoHashFinish(arm_uc_mdHandle_t* hDigest, arm_uc_buffer_t* output) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + + // TODO: validate buffer size? I guess we just hope for the best! + if (hDigest && output && output->size_max >= 256/8) // FIXME:PAL does not provide a method to extract this + { + palStatus_t rc = pal_mdFinal(*hDigest, output->ptr); + + if (rc == PAL_SUCCESS) + { + result = (arm_uc_error_t){ ARM_UC_CU_ERR_NONE }; + output->size = 256/8; // FIXME:PAL does not provide a method to extract this + } + } + if (hDigest) + { + palStatus_t rc = pal_mdFree(hDigest); + if (rc != PAL_SUCCESS && result.error == ERR_NONE) + { + result.module = TWO_CC('P','A'); + result.error = rc; + } + } + return result; +} +arm_uc_error_t ARM_UC_cryptoDecryptSetup(arm_uc_cipherHandle_t* hCipher, arm_uc_buffer_t* key, arm_uc_buffer_t* iv, int32_t aesKeySize) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + + if (key && key->ptr && iv && iv->ptr) + { + palStatus_t rc = 1; + + switch (aesKeySize) + { + case 128: + case 256: + { + rc = pal_initAes(&hCipher->aes_context); + /* NOTE: From the mbedtls documentation: + * Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + */ + if (rc == PAL_SUCCESS) + { + rc = pal_setAesKey(hCipher->aes_context, key->ptr, aesKeySize, PAL_KEY_TARGET_DECRYPTION); + } + hCipher->aes_iv = iv->ptr; + break; + } + default: + // rc is still 1, this means the function returns Invalid Parameter + break; + } + + if (rc == PAL_SUCCESS) + { + result = (arm_uc_error_t){ ARM_UC_CU_ERR_NONE }; + } + } + + return result; +} +arm_uc_error_t ARM_UC_cryptoDecryptUpdate(arm_uc_cipherHandle_t* hCipher, const uint8_t* input_ptr, uint32_t input_size, arm_uc_buffer_t* output) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + size_t data_size = input_size < output->size_max ? input_size : output->size_max; + output->size = 0; + palStatus_t rc = pal_aesCTR( + hCipher->aes_context, + input_ptr, + output->ptr, + data_size, + hCipher->aes_iv + ); + if (rc == PAL_SUCCESS) + { + result = (arm_uc_error_t){ ARM_UC_CU_ERR_NONE }; + output->size = data_size; + } + return result; +} +arm_uc_error_t ARM_UC_cryptoDecryptFinish(arm_uc_cipherHandle_t* hCipher, arm_uc_buffer_t* output) +{ + pal_freeAes(&hCipher->aes_context); + (void) output; + return (arm_uc_error_t){ARM_UC_CU_ERR_NONE}; +} + +#else +arm_uc_error_t ARM_UC_verifyPkSignature(const arm_uc_buffer_t* ca, const arm_uc_buffer_t* hash, const arm_uc_buffer_t* sig) +{ + int rc = 1; + arm_uc_error_t err = {MFST_ERR_NONE}; + mbedtls_x509_crt crt; + mbedtls_x509_crt_init(&crt); + rc = mbedtls_x509_crt_parse_der(&crt, ca->ptr, ca->size); + if (rc < 0) { + err.code = MFST_ERR_CERT_INVALID; + } else { + rc = mbedtls_pk_verify(&crt.pk, MBEDTLS_MD_SHA256, hash->ptr, hash->size, sig->ptr, sig->size); + if (rc < 0) { + err.code = MFST_ERR_INVALID_SIGNATURE; + } + } + return err; +} +arm_uc_error_t ARM_UC_cryptoHashSetup(arm_uc_mdHandle_t* hDigest, arm_uc_mdType_t mdType) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + + const mbedtls_md_info_t* md_info = NULL; + int mbedtls_result = 1; + + if (hDigest) + { + mbedtls_md_init(hDigest); + md_info = mbedtls_md_info_from_type(mdType); + mbedtls_result = mbedtls_md_setup(hDigest, md_info, 0); + mbedtls_result |= mbedtls_md_starts(hDigest); + + if (mbedtls_result == 0) + { + result = (arm_uc_error_t){ ARM_UC_CU_ERR_NONE }; + } + } + + return result; +} + +arm_uc_error_t ARM_UC_cryptoHashUpdate(arm_uc_mdHandle_t* hDigest, arm_uc_buffer_t* input) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + + if (hDigest && input) + { + int mbedtls_result = 1; + + mbedtls_result = mbedtls_md_update(hDigest, input->ptr, input->size); + + if (mbedtls_result == 0) + { + result = (arm_uc_error_t){ ARM_UC_CU_ERR_NONE }; + } + } + + return result; +} +arm_uc_error_t ARM_UC_cryptoHashFinish(arm_uc_mdHandle_t* hDigest, arm_uc_buffer_t* output) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + + if (hDigest && output && (output->size_max >= (unsigned)hDigest->md_info->size)) + { + int mbedtls_result = 1; + + mbedtls_result = mbedtls_md_finish(hDigest, output->ptr); + + if (mbedtls_result == 0) + { + result = (arm_uc_error_t){ ARM_UC_CU_ERR_NONE }; + + output->size = hDigest->md_info->size; + } + } + + // free memory + mbedtls_md_free(hDigest); + + return result; +} + +arm_uc_error_t ARM_UC_cryptoDecryptSetup(arm_uc_cipherHandle_t* hCipher, arm_uc_buffer_t* key, arm_uc_buffer_t* iv, int32_t aesKeySize) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + + if (key && key->ptr && iv && iv->ptr) + { + int mbedtls_result = 1; + + switch (aesKeySize) + { + case 128: + case 256: + { + memset(hCipher->aes_partial, 0, sizeof(hCipher->aes_partial)); + hCipher->aes_nc_off = 0; + mbedtls_aes_init(&hCipher->aes_context); + /* NOTE: From the mbedtls documentation: + * Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + */ + mbedtls_result = mbedtls_aes_setkey_enc(&hCipher->aes_context, key->ptr, aesKeySize); + hCipher->aes_iv = iv->ptr; + break; + } + default: + // mbedtls_result is still 1, this means the function returns Invalid Parameter + break; + } + + if (mbedtls_result == 0) + { + result = (arm_uc_error_t){ ARM_UC_CU_ERR_NONE }; + } + } + + return result; +} +arm_uc_error_t ARM_UC_cryptoDecryptUpdate(arm_uc_cipherHandle_t* hCipher, const uint8_t* input_ptr, uint32_t input_size, arm_uc_buffer_t* output) +{ + arm_uc_error_t result = (arm_uc_error_t){ ARM_UC_CU_ERR_INVALID_PARAMETER }; + size_t data_size = input_size < output->size_max ? input_size : output->size_max; + output->size = 0; + int mbedtls_result = mbedtls_aes_crypt_ctr( + &hCipher->aes_context, + data_size, + &hCipher->aes_nc_off, + hCipher->aes_iv, + hCipher->aes_partial, + input_ptr, + output->ptr + + ); + if (mbedtls_result == 0) + { + result = (arm_uc_error_t){ ARM_UC_CU_ERR_NONE }; + output->size = data_size; + } + return result; +} +arm_uc_error_t ARM_UC_cryptoDecryptFinish(arm_uc_cipherHandle_t* hCipher, arm_uc_buffer_t* output) +{ + (void) output; + return (arm_uc_error_t){ARM_UC_CU_ERR_NONE}; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_error.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_error.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-common/arm_uc_error.h" + +const char* ARM_UC_err2Str(arm_uc_error_t err) +{ + switch (err.code) { + #define ENUM_AUTO(name) case name: return #name; + #define ENUM_FIXED(name, val) ENUM_AUTO(name) + ARM_UC_ERR_LIST + #undef ENUM_FIXED + #undef ENUM_AUTO + default: + return "Unknown Error Code"; + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_metadata_header_v2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_metadata_header_v2.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,241 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-common/arm_uc_metadata_header_v2.h" + +#include "update-client-common/arm_uc_utilities.h" +#include "pal.h" + +#define PAL_DEVICE_KEY_SIZE 32 + +arm_uc_error_t arm_uc_parse_internal_header_v2(const uint8_t* input, + arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (input && details) + { + /* calculate CRC */ + uint32_t calculatedChecksum = arm_uc_crc32(input, ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2); + + /* read out CRC */ + uint32_t temp32 = arm_uc_parse_uint32(&input[ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2]); + + if (temp32 == calculatedChecksum) + { + /* parse content */ + details->version = arm_uc_parse_uint64(&input[ARM_UC_INTERNAL_FIRMWARE_VERSION_OFFSET_V2]); + details->size = arm_uc_parse_uint64(&input[ARM_UC_INTERNAL_FIRMWARE_SIZE_OFFSET_V2]); + + memcpy(details->hash, + &input[ARM_UC_INTERNAL_FIRMWARE_HASH_OFFSET_V2], + ARM_UC_SHA256_SIZE); + + memcpy(details->campaign, + &input[ARM_UC_INTERNAL_CAMPAIGN_OFFSET_V2], + ARM_UC_GUID_SIZE); + + /* set result */ + result.code = ERR_NONE; + } + } + + return result; +} + +arm_uc_error_t arm_uc_create_internal_header_v2(const arm_uc_firmware_details_t* input, + arm_uc_buffer_t* output) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (input && + output && + (output->size_max >= ARM_UC_INTERNAL_HEADER_SIZE_V2)) + { + /* zero buffer */ + memset(output->ptr, 0, ARM_UC_INTERNAL_HEADER_SIZE_V2); + + /* MSB encode header magic and version */ + arm_uc_write_uint32(&output->ptr[0], + ARM_UC_INTERNAL_HEADER_MAGIC_V2); + arm_uc_write_uint32(&output->ptr[4], + ARM_UC_INTERNAL_HEADER_VERSION_V2); + + /* MSB encode firmware version */ + arm_uc_write_uint64(&output->ptr[ARM_UC_INTERNAL_FIRMWARE_VERSION_OFFSET_V2], + input->version); + + /* MSB encode firmware size to header */ + arm_uc_write_uint64(&output->ptr[ARM_UC_INTERNAL_FIRMWARE_SIZE_OFFSET_V2], + input->size); + + /* raw copy firmware hash to header */ + memcpy(&output->ptr[ARM_UC_INTERNAL_FIRMWARE_HASH_OFFSET_V2], + input->hash, + ARM_UC_SHA256_SIZE); + + /* raw copy campaign ID to header */ + memcpy(&output->ptr[ARM_UC_INTERNAL_CAMPAIGN_OFFSET_V2], + input->campaign, + ARM_UC_GUID_SIZE); + + /* calculate CRC */ + uint32_t checksum = arm_uc_crc32(output->ptr, + ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2); + + /* MSB encode checksum to header */ + arm_uc_write_uint32(&output->ptr[ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2], + checksum); + + /* set output size */ + output->size = ARM_UC_INTERNAL_HEADER_SIZE_V2; + + /* set error code */ + result.code = ERR_NONE; + } + + return result; +} + +arm_uc_error_t arm_uc_parse_external_header_v2(const uint8_t* input, + arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (input && details) + { + + /* read 128 bit root-of-trust from PAL */ + uint8_t key[PAL_DEVICE_KEY_SIZE] = { 0 }; + palStatus_t status = pal_osGetDeviceKey(palOsStorageHmacSha256, + key, + PAL_DEVICE_KEY_SIZE); + + if (status == PAL_SUCCESS) + { + arm_uc_hash_t hmac = { 0 }; + size_t length = 0; + + /* calculate header HMAC */ + status = pal_mdHmacSha256(key, PAL_DEVICE_KEY_SIZE, + input, ARM_UC_EXTERNAL_HMAC_OFFSET_V2, + hmac, &length); + + if ((status == PAL_SUCCESS) && (length == ARM_UC_SHA256_SIZE)) + { + int diff = memcmp(&input[ARM_UC_EXTERNAL_HMAC_OFFSET_V2], + hmac, + ARM_UC_SHA256_SIZE); + + if (diff == 0) + { + details->version = arm_uc_parse_uint64(&input[ARM_UC_EXTERNAL_FIRMWARE_VERSION_OFFSET_V2]); + details->size = arm_uc_parse_uint64(&input[ARM_UC_EXTERNAL_FIRMWARE_SIZE_OFFSET_V2]); + + memcpy(details->hash, + &input[ARM_UC_EXTERNAL_FIRMWARE_HASH_OFFSET_V2], + ARM_UC_SHA256_SIZE); + + memcpy(details->campaign, + &input[ARM_UC_EXTERNAL_CAMPAIGN_OFFSET_V2], + ARM_UC_GUID_SIZE); + + details->signatureSize = 0; + + result.code = ERR_NONE; + } + } + } + } + + return result; +} + +arm_uc_error_t arm_uc_create_external_header_v2(const arm_uc_firmware_details_t* input, + arm_uc_buffer_t* output) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (input && + output && + (output->size_max >= ARM_UC_EXTERNAL_HEADER_SIZE_V2)) + { + /* zero buffer and reset size*/ + memset(output->ptr, 0, ARM_UC_EXTERNAL_HEADER_SIZE_V2); + output->size = 0; + + /* MSB encode header magic and version */ + arm_uc_write_uint32(&output->ptr[0], + ARM_UC_EXTERNAL_HEADER_MAGIC_V2); + arm_uc_write_uint32(&output->ptr[4], + ARM_UC_EXTERNAL_HEADER_VERSION_V2); + + /* MSB encode firmware version */ + arm_uc_write_uint64(&output->ptr[ARM_UC_EXTERNAL_FIRMWARE_VERSION_OFFSET_V2], + input->version); + + /* MSB encode firmware size to header */ + arm_uc_write_uint64(&output->ptr[ARM_UC_EXTERNAL_FIRMWARE_SIZE_OFFSET_V2], + input->size); + + /* raw copy firmware hash to header */ + memcpy(&output->ptr[ARM_UC_EXTERNAL_FIRMWARE_HASH_OFFSET_V2], + input->hash, + ARM_UC_SHA256_SIZE); + + /* MSB encode payload size to header */ + arm_uc_write_uint64(&output->ptr[ARM_UC_EXTERNAL_PAYLOAD_SIZE_OFFSET_V2], + input->size); + + /* raw copy payload hash to header */ + memcpy(&output->ptr[ARM_UC_EXTERNAL_PAYLOAD_HASH_OFFSET_V2], + input->hash, + ARM_UC_SHA256_SIZE); + + /* raw copy campaign ID to header */ + memcpy(&output->ptr[ARM_UC_EXTERNAL_CAMPAIGN_OFFSET_V2], + input->campaign, + ARM_UC_GUID_SIZE); + + /* read 128 bit root-of-trust from PAL */ + uint8_t key[PAL_DEVICE_KEY_SIZE] = { 0 }; + palStatus_t status = pal_osGetDeviceKey(palOsStorageHmacSha256, + key, + PAL_DEVICE_KEY_SIZE); + + if (status == PAL_SUCCESS) + { + /* calculate header HMAC */ + size_t length = 0; + status = pal_mdHmacSha256(key, PAL_DEVICE_KEY_SIZE, + output->ptr, ARM_UC_EXTERNAL_HMAC_OFFSET_V2, + &output->ptr[ARM_UC_EXTERNAL_HMAC_OFFSET_V2], + &length); + + /* set buffer size and return code upon success */ + if ((status == PAL_SUCCESS) && (length == ARM_UC_SHA256_SIZE)) + { + output->size = ARM_UC_EXTERNAL_HEADER_SIZE_V2; + + result.code = ERR_NONE; + } + } + } + + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_scheduler.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_scheduler.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,146 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-common/arm_uc_common.h" + +#include "pal.h" + +static struct atomic_queue arm_uc_queue = { 0 }; +static void (*arm_uc_notificationHandler)(void) = NULL; +static int32_t arm_uc_queue_counter = 0; + +void ARM_UC_AddNotificationHandler(void (*handler)(void)) +{ + arm_uc_notificationHandler = handler; +} + +bool ARM_UC_PostCallback(arm_uc_callback_t* _storage, + void (*_callback)(uint32_t), + uint32_t _parameter) +{ + bool success = false; + + if (_storage) + { + /* push struct to atomic queue */ + int result = aq_push_tail(&arm_uc_queue, (void *) _storage); + + if (result == ATOMIC_QUEUE_SUCCESS) + { + /* populate callback struct */ + /* WARNING: This is a dangerous pattern. The atomic queue should own + all memory referenced by the storage element. + + This only works when ARM_UC_ProcessQueue and + ARM_UC_ProcessSingleCallback are guaranteed to be called only from + lower priority than ARM_UC_PostCallback. In the update client, + this is expected to be true, but it cannot be assumed to be true in + all environments. This requires further rework, possibly including + a critical section in ARM_UC_PostCallback, or a "taken" flag on the + callback storage. + */ + _storage->callback = _callback; + _storage->parameter = _parameter; + + success = true; + + /* The queue is processed by removing an element first and then + decrementing the queue counter. This continues until the counter + reaches 0 (process single callback) or the queue is empty + (process queue). + + If the counter is zero at this point, there is one element in + the queue, and incrementing the counter will return 1 and which + triggers a notification. + + If the queue is empty at this point, the counter is -1 and + incrementing the counter will return 0. This does not trigger + a notification, which is correct since the queue is empty. + */ + int32_t count = pal_osAtomicIncrement(&arm_uc_queue_counter, 1); + + /* if notification handler is set, check if this is the first + insertion + */ + if ((arm_uc_notificationHandler) && (count == 1)) + { + /* disable: UC_COMM_TRACE("notify nanostack scheduler"); */ + arm_uc_notificationHandler(); + } + } +/* disable when not debugging */ +#if 0 + else + { + UC_COMM_ERR_MSG("failed to add callback to queue: %p %p", + _storage, + _callback); + } +#endif + } + + return success; +} + +void ARM_UC_ProcessQueue(void) +{ + arm_uc_callback_t* element = (arm_uc_callback_t*) aq_pop_head(&arm_uc_queue); + + while (element != NULL) + { + /* execute callback */ + element->callback(element->parameter); + + /* decrement element counter after executing the callback. + otherwise further callbacks posted inside this callback could + trigger notifications eventhough we are still processing the queue. + */ + pal_osAtomicIncrement(&arm_uc_queue_counter, -1); + + /* get next element */ + element = (arm_uc_callback_t*) aq_pop_head(&arm_uc_queue); + } +} + +bool ARM_UC_ProcessSingleCallback(void) +{ + /* elements in queue */ + int32_t count = 0; + + /* get first element */ + arm_uc_callback_t* element = (arm_uc_callback_t*) aq_pop_head(&arm_uc_queue); + + if (element != NULL) + { + /* execute callback */ + element->callback(element->parameter); + + /* decrement element counter after executing the callback. + otherwise further callbacks posted inside this callback could + trigger notifications eventhough we are still processing the queue. + + when this function returns false, the counter is 0 and there are + either 1 or 0 elements in the queue. if there is 1 element in + the queue, it means the counter hasn't been incremented yet, and + incrmenting it will return 1, which will trigger a notification. + */ + count = pal_osAtomicIncrement(&arm_uc_queue_counter, -1); + } + + return (count > 0); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_utilities.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_utilities.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,554 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-common/arm_uc_utilities.h" +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_config.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +/* lookup table for printing hexadecimal values */ +const uint8_t arm_uc_hex_table[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + +/** + * @brief Parse a uri string to populate a arm_uc_uri_t struct + * @detail Format of uri scheme:[//]host[:port]/path + * [] means optional, path will always start with a '/' + * + * @param str Pointer to string containing URI. + * @param size String length. + * @param uri The arm_uc_uri_t struct to be populated + * @return Error code. + */ +arm_uc_error_t arm_uc_str2uri(const uint8_t* buffer, + uint32_t buffer_size, + arm_uc_uri_t* uri) +{ + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + if (buffer && + uri && + uri->ptr && + (buffer_size < uri->size_max)) + { + const uint8_t* str = buffer; + uint8_t* colon = NULL; + uint8_t* slash = NULL; + uint32_t len = 0; + + /* find scheme by searching for first colon */ + colon = memchr(str, ':', buffer_size); + len = colon - str; + + if (len < uri->size_max) + { + /* copy scheme to temporary uri buffer and convert to lower case. + */ + for (uint32_t index = 0; index < len; index++) + { + /* lower case characters have higher ASCII value */ + if (str[index] < 'a') + { + uri->ptr[index] = str[index] + ('a' - 'A'); + } + else + { + uri->ptr[index] = str[index]; + } + } + + /* copy ':' */ + uri->ptr[len] = str[len]; + + /* convert scheme string to scheme type */ + if (memcmp(uri->ptr, "http:", 5) == 0) + { + uri->scheme = URI_SCHEME_HTTP; + + /* set default port based on scheme - can be overwritten */ + uri->port = 80; + } + else + { + uri->scheme = URI_SCHEME_NONE; + } + + /* only continue if scheme is supported */ + if (uri->scheme != URI_SCHEME_NONE) + { + /* strip any leading '/' */ + str = colon + 1; + for (str += 1; + (str[0] == '/') && (str < (buffer + buffer_size)); + ++str); + + /* find separation between host and path */ + slash = memchr(str, '/', buffer_size - (str - buffer)); + + if (slash != NULL) + { + bool parsed = true; + + /* find optional port */ + colon = memchr(str, ':', buffer_size - (slash - buffer)); + + if (colon != NULL) + { + uri->port = arm_uc_str2uint32(colon + 1, + buffer_size - (colon - buffer), + &parsed); + len = colon - str; + } + else + { + len = slash - str; + } + + /* check */ + if ((parsed == 1) && (len < uri->size_max)) + { + /* copy host name to URI buffer */ + memcpy(uri->ptr, str, len); + + /* \0 terminate string */ + uri->ptr[len] = '\0'; + + /* update length */ + uri->size = len + 1; + + /* set host pointer */ + uri->host = (char*) uri->ptr; + + /* find remaining path length */ + str = slash; + len = arm_uc_strnlen(str, buffer_size - (str - buffer)); + + /* check */ + if ((len > 0) && (len < (uri->size_max - uri->size))) + { + /* copy path to URI buffer */ + memcpy(&uri->ptr[uri->size], str, len); + + /* set path pointer */ + uri->path = (char*) &uri->ptr[uri->size]; + + /* \0 terminate string */ + uri->ptr[uri->size + len] = '\0'; + + /* update length after path pointer is set */ + uri->size += len + 1; + + /* parsing passed all checks */ + result = (arm_uc_error_t){ ERR_NONE }; + } + } + } + } + } + } + + return result; +} + +/** + * @brief Find substring inside string. + * @details The size of both string and substring is explicitly passed so no + * assumptions are made about NULL termination. + * + * @param big_buffer Pointer to the string to be searched. + * @param big_length Length of the string to be searched. + * @param little_buffer Pointer to the substring being searched for. + * @param little_length Length of the substring being searched for. + * @return Index to where the substring was found inside the string. If the + * string doesn't contain the subtring, UINT32_MAX is returned. + */ + uint32_t arm_uc_strnstrn(const uint8_t* big_buffer, + uint32_t big_length, + const uint8_t* little_buffer, + uint32_t little_length) +{ + uint32_t result = UINT32_MAX; + + /* Sanity check. Pointers are not NULL. The little buffer is smaller than + the big buffer. The little buffer is not empty. + */ + if (big_buffer && + little_buffer && + (big_length >= little_length) && + (little_length > 0)) + { + uint8_t little_hash = 0; + uint8_t big_hash = 0; + uint32_t little_length_m1 = little_length - 1; + + /* Prepare hashes. The last byte for the big hash is added in the + comparison loop. + */ + for (uint32_t index = 0; index < little_length_m1; index++) + { + little_hash ^= little_buffer[index]; + big_hash ^= big_buffer[index]; + } + + /* Add the last byte for the little hash. */ + little_hash ^= little_buffer[little_length_m1]; + + /* Comparison loop. In each loop the big hash is updated and compared + to the little hash. If the hash matches, a more thorough byte-wise + comparison is performed. The complexity of the hash determines how + often a collision occures and how often a full comparison is done. + */ + for (uint32_t index = 0; + index < (big_length - (little_length_m1)); + index++) + { + /* update hash */ + big_hash ^= big_buffer[index + (little_length_m1)]; + + /* cursory check */ + if (little_hash == big_hash) + { + /* hash checks out do comprehensive check */ + uint32_t checks = 0; + + for ( ; checks < little_length; checks++) + { + /* stop counting if bytes differ */ + if (big_buffer[index + checks] != little_buffer[checks]) + { + break; + } + } + + /* check if all bytes matched */ + if (checks == little_length) + { + /* save pointer and break loop */ + result = index; + break; + } + } + + /* update hash - remove tail */ + big_hash ^= big_buffer[index]; + } + } + + return result; +} + +/** + * @brief Find string length. + * @details Custom implementation of strnlen which is a GNU extension. + * Returns either the string length or max_length. + * + * @param buffer Pointer to string. + * @param max_length Maximum buffer length. + * + * @return String length or max_length. + */ +uint32_t arm_uc_strnlen(const uint8_t* buffer, uint32_t max_length) +{ + uint32_t length = 0; + + for ( ; length < max_length; length++) + { + if (buffer[length] == '\0') + { + break; + } + } + + return length; +} + +/** + * @brief Convert string to unsigned 32 bit integer. + * @details Function tries to parse string as an unsigned 32 bit integer + * and return the value. The function expects the first byte to be an + * integer and will continue until: + * 1. the buffer is empty + * 2. the intermediate result is larger then UINT32_MAX + * 3. the next byte is not a number + * + * If a valid 32 bit unsigned integer is found the third parameter is + * set to true and the return value holds the parsed number. Otherwise, + * the third parameter will be false and the return value will be 0. + * + * @param buffer Pointer to string. + * @param max_length Maximum buffer length. + * @param success Pointer to boolean indicating whether the parsing was successful. + * @return Parsed value. Only valid if success it true. + */ +uint32_t arm_uc_str2uint32(const uint8_t* buffer, + uint32_t max_length, + bool* success) +{ + uint64_t result = 0; + bool found = false; + + /* default output and return status is 0 and false */ + uint32_t output = 0; + + if (success) + { + *success = false; + } + + /* null pointer and length check */ + if (buffer && (max_length > 0)) + { + /* loop through string */ + for (uint32_t index = 0; index < max_length; index++) + { + /* check if character is a number */ + if (('0' <= buffer[index]) && + (buffer[index] <= '9') && + (result < UINT64_MAX)) + { + /* shift one decimal position and append next digit */ + result *= 10; + result += buffer[index] - '0'; + + /* found at least one integer, mark as found */ + found = true; + } + else + { + /* character is not a number, stop loop */ + break; + } + } + + /* set output and return value only if a valid number was found */ + if (found && (result <= UINT64_MAX)) + { + output = result; + + if (success) + { + *success = true; + } + } + } + + return output; +} + +uint32_t arm_uc_crc32(const uint8_t* buffer, uint32_t length) +{ + const uint8_t* current = buffer; + uint32_t crc = 0xFFFFFFFF; + + while (length--) + { + crc ^= *current++; + + for (uint32_t counter = 0; counter < 8; counter++) + { + if (crc & 1) + { + crc = (crc >> 1) ^ 0xEDB88320; + } + else + { + crc = crc >> 1; + } + } + } + + return (crc ^ 0xFFFFFFFF); +} + +uint32_t arm_uc_parse_uint32(const uint8_t* input) +{ + uint32_t result = 0; + + if (input) + { + result = input[0]; + result = (result << 8) | input[1]; + result = (result << 8) | input[2]; + result = (result << 8) | input[3]; + } + + return result; +} + +uint64_t arm_uc_parse_uint64(const uint8_t* input) +{ + uint64_t result = 0; + + if (input) + { + result = input[0]; + result = (result << 8) | input[1]; + result = (result << 8) | input[2]; + result = (result << 8) | input[3]; + result = (result << 8) | input[4]; + result = (result << 8) | input[5]; + result = (result << 8) | input[6]; + result = (result << 8) | input[7]; + } + + return result; +} + +void arm_uc_write_uint32(uint8_t* buffer, uint32_t value) +{ + if (buffer) + { + buffer[3] = value; + buffer[2] = (value >> 8); + buffer[1] = (value >> 16); + buffer[0] = (value >> 24); + } +} + +void arm_uc_write_uint64(uint8_t* buffer, uint64_t value) +{ + if (buffer) + { + buffer[7] = value; + buffer[6] = (value >> 8); + buffer[5] = (value >> 16); + buffer[4] = (value >> 24); + buffer[3] = (value >> 32); + buffer[2] = (value >> 40); + buffer[1] = (value >> 48); + buffer[0] = (value >> 56); + } +} + +// Constant time binary comparison +uint32_t ARM_UC_BinCompareCT(const arm_uc_buffer_t* a, const arm_uc_buffer_t* b) +{ + uint32_t result; + uint32_t i; + const uint32_t *wa = (uint32_t *)a->ptr; + const uint32_t *wb = (uint32_t *)b->ptr; + const uint32_t bytes_aligned = a->size & ~((1 << sizeof(uint32_t)) - 1); + const uint32_t bytes = a->size; + + // Check sizes + if (a->size != b->size) + { + return 1; + } + result = 0; + for (i = 0; i < bytes_aligned; i += sizeof(uint32_t)) + { + const uint32_t idx = i/sizeof(uint32_t); + result = result | (wa[idx] ^ wb[idx]); + } + for (; i < bytes; i++) + { + result = result | (a->ptr[i] ^ b->ptr[i]); + } + // Reduce to 0 or 1 in constant time + return (result | -result) >> 31; +} + +static const uint8_t base64EncodeArray[65] = {MBED_CLOUD_UPDATE_BASE64_CHARSET}; + +uint8_t * ARM_UC_Base64Enc(uint8_t* buf, const uint32_t size, const arm_uc_buffer_t* bin) +{ + uint32_t partial = 0; + const uint8_t * lastPos = buf + size; + uint32_t i; + uint32_t pad2 = (bin->size - bin->size % 3); + uint32_t pad1 = (bin->size - bin->size % 3) + 1; + for (i = 0; i < bin->size && buf <= lastPos - 4; i+=3) { + partial = (bin->ptr[i] << 16); + if ( i < pad1 ) + { + partial = partial | (bin->ptr[i+1] << 8); + } + if ( i < pad2) + { + partial = partial | (bin->ptr[i+2] << 0); + } + buf[0] = base64EncodeArray[(partial >> 18) & 0x3f]; + buf[1] = base64EncodeArray[(partial >> 12) & 0x3f]; + buf[2] = (i < pad1) ? base64EncodeArray[(partial >> 6) & 0x3f] : base64EncodeArray[64]; + buf[3] = (i < pad2) ? base64EncodeArray[(partial >> 0) & 0x3f] : base64EncodeArray[64]; + buf += 4; + } + buf[0] = 0; + return buf; +} + +uint32_t ARM_UC_Base64DecodeChar(uint8_t c) +{ + if (c == MBED_CLOUD_UPDATE_BASE64_CHARSET[64] || c == MBED_CLOUD_UPDATE_BASE64_CHARSET[0]) + { + return 0; + } + uint32_t idx = 0; + int32_t i; + for (i = 5; i >= 0; i--) + { + uint32_t tmpidx = idx | 1 << i; + uint8_t ct = MBED_CLOUD_UPDATE_BASE64_CHARSET[tmpidx]; + if (c == ct) + { + return tmpidx; + } + else if (c > ct) + { + idx = tmpidx; + } + } + return (uint32_t) -1; +} + +void ARM_UC_Base64Dec(arm_uc_buffer_t* bin, const uint32_t size, const uint8_t* buf) +{ + uintptr_t optr = (uintptr_t)bin->ptr; + const uint8_t* iptr = buf; + while ((uintptr_t)iptr + 4 < (uintptr_t) buf + size && optr + 1 < (uintptr_t)bin->ptr + bin->size_max) { + uint8_t partial[3]; + uint8_t a = (ARM_UC_Base64DecodeChar(iptr[0])); + uint8_t b = (ARM_UC_Base64DecodeChar(iptr[1])); + uint8_t c = (ARM_UC_Base64DecodeChar(iptr[2])); + uint8_t d = (ARM_UC_Base64DecodeChar(iptr[3])); + uint8_t l = 3; + if (d == MBED_CLOUD_UPDATE_BASE64_CHARSET[64]) + { + l--; + } + if (c == MBED_CLOUD_UPDATE_BASE64_CHARSET[64]) + { + l--; + } + partial[0] = ((a << 2) & 0xfc) | ((b >> 4) & 0x3); + partial[1] = ((b << 4) & 0xf0) | ((c >> 2) & 0xf); + partial[2] = ((c << 6) & 0xc0) | ((d >> 0) & 0x3f); + memcpy((void*)optr, partial, l); + iptr += 4; + optr += l; + if (d == MBED_CLOUD_UPDATE_BASE64_CHARSET[64]) + { + break; + } + } + bin->size = optr - (uintptr_t)bin->ptr; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_common.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,31 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_COMMON_H +#define ARM_UPDATE_COMMON_H + +#include "update-client-common/arm_uc_config.h" +#include "update-client-common/arm_uc_crypto.h" +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_public.h" +#include "update-client-common/arm_uc_scheduler.h" +#include "update-client-common/arm_uc_trace.h" +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_utilities.h" + +#endif // ARM_UPDATE_COMMON_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_config.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_config.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,68 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_CONFIG_H +#define ARM_UPDATE_CONFIG_H + +#ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#include MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#endif + +#ifndef MAX_SOURCES +#define MAX_SOURCES 10 +#endif + +#ifndef ARM_UC_SOCKET_MAX_RETRY +#define ARM_UC_SOCKET_MAX_RETRY 3 +#endif + +/* Total memory allocated for download buffers. + For HTTP sources, this number cannot be below 1 KiB. +*/ +#ifdef MBED_CLOUD_CLIENT_UPDATE_BUFFER +#if MBED_CLOUD_CLIENT_UPDATE_BUFFER < 1024 +#error MBED_CLOUD_CLIENT_UPDATE_BUFFER must be 1024 bytes or more +#else +#define ARM_UC_BUFFER_SIZE MBED_CLOUD_CLIENT_UPDATE_BUFFER +#endif +#endif + +#ifndef ARM_UC_BUFFER_SIZE +#define ARM_UC_BUFFER_SIZE 1024 +#endif + +#ifndef ARM_UC_USE_KCM +#define ARM_UC_USE_KCM 1 +#define ARM_UPDATE_USE_KCM 1 +#endif + +#ifndef ARM_UC_USE_PAL_CRYPTO +#define ARM_UC_USE_PAL_CRYPTO 1 +#endif + +#define MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX "mbed.UpdateAuthCert." +#define MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT "mbed.UpdateAuthCert" +#define MBED_CLOUD_SHA256_BYTES (256/8) +#define MBED_CLOUD_BASE64_SIZE(X) (((X + 2)/3)*4) +#define MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE (MBED_CLOUD_BASE64_SIZE(MBED_CLOUD_SHA256_BYTES) + sizeof(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX)) + + +// NOTE: The charset must be sorted except for the trailing character which is used as a padding character. +#define MBED_CLOUD_UPDATE_BASE64_CHARSET "0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-" + +#endif // ARM_UPDATE_CONFIG_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_crypto.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_crypto.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,98 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_CRYPTO_H +#define ARM_UPDATE_CRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "arm_uc_error.h" +#include "arm_uc_types.h" +#include "arm_uc_config.h" + +#ifndef ARM_UC_USE_PAL_CRYPTO +#define ARM_UC_USE_PAL_CRYPTO 0 +#endif + +#if ARM_UC_USE_PAL_CRYPTO +#include "pal.h" +#ifndef palMDHandle_t +#include "pal_Crypto.h" +#endif + +typedef palMDHandle_t arm_uc_mdHandle_t; +typedef palMDType_t arm_uc_mdType_t; +typedef struct arm_uc_cipherHandle_t { + palAesHandle_t aes_context; + uint8_t* aes_iv; +} arm_uc_cipherHandle_t; + +#define ARM_UC_CU_SHA256 PAL_SHA256 + +#else // ARM_UC_USE_PAL_CRYPTO + +#include "mbedtls/md_internal.h" +#include "mbedtls/sha256.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/aes.h" +#include "mbedtls/cipher.h" +typedef mbedtls_md_context_t arm_uc_mdHandle_t; +typedef mbedtls_md_type_t arm_uc_mdType_t; +typedef struct arm_uc_cipherHandle_t { + mbedtls_aes_context aes_context; + uint8_t aes_partial[MBEDTLS_MAX_BLOCK_LENGTH]; + uint8_t* aes_iv; + size_t aes_nc_off; +} arm_uc_cipherHandle_t; + +#define ARM_UC_CU_SHA256 MBEDTLS_MD_SHA256 + +#endif // ARM_UC_USE_PAL_CRYPTO + +/** + * @brief Verify a public key signature + * @details This function loads a certificate out of `ca`, and validates `hash` using the certificate and `sig`. If the + * certificate used by this function requires a certificate chain validation (i.e. it is not the root of trust, + * or it has not been previously validated), certificate chain validation should be done prior to calling this + * function. + * + * WARNING: this function is to be used only inside a function where its arguments have been error checked. + * WARNING: This is an internal utility function and is not accessible outside of the manifest manager. + * + * @param[in] ca A pointer to a buffer that contains the signing certificate. + * @param[in] hash A pointer to a buffer containing the hash to verify. + * @param[in] sig A pointer to a buffer containing a signature by `ca` + * @retval MFST_ERR_CERT_INVALID when the certificate fails to load + * @retval MFST_ERR_INVALID_SIGNATURE when signature verification fails + * @retval MFST_ERR_NONE for a valid signature + */ +arm_uc_error_t ARM_UC_verifyPkSignature(const arm_uc_buffer_t* ca, const arm_uc_buffer_t* hash, const arm_uc_buffer_t* sig); +arm_uc_error_t ARM_UC_cryptoHashSetup(arm_uc_mdHandle_t* h, arm_uc_mdType_t mdType); +arm_uc_error_t ARM_UC_cryptoHashUpdate(arm_uc_mdHandle_t* h, arm_uc_buffer_t* input); +arm_uc_error_t ARM_UC_cryptoHashFinish(arm_uc_mdHandle_t* h, arm_uc_buffer_t* output); +arm_uc_error_t ARM_UC_cryptoDecryptSetup(arm_uc_cipherHandle_t* h, arm_uc_buffer_t* key, arm_uc_buffer_t* iv, int32_t bits); +arm_uc_error_t ARM_UC_cryptoDecryptUpdate(arm_uc_cipherHandle_t* h, const uint8_t* input_ptr, uint32_t input_size, arm_uc_buffer_t* output); +arm_uc_error_t ARM_UC_cryptoDecryptFinish(arm_uc_cipherHandle_t* h, arm_uc_buffer_t* output); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UPDATE_CRYPTO_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_error.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_error.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,179 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_ERROR_H +#define ARM_UPDATE_ERROR_H + +#include <stdint.h> + +// Use two characters to form the 16bit module code +#define TWO_CC(A,B) (((A) & 0xFF) | (((B) & 0xFF) << 8)) + +#define MANIFEST_MANAGER_PREFIX TWO_CC('M','M') +#define CERTIFICATE_MANAGER_PREFIX TWO_CC('C','M') +#define SOURCE_MANAGER_PREFIX TWO_CC('S','M') +#define SOURCE_PREFIX TWO_CC('S','E') +#define FIRMWARE_MANAGER_PREFIX TWO_CC('F','M') +#define DER_PARSER_PREFIX TWO_CC('D','P') +#define MBED_TLS_ERROR_PREFIX TWO_CC('M','T') +#define UPDATE_CRYPTO_PREFIX TWO_CC('C','U') +#define DEVICE_IDENTITY_PREFIX TWO_CC('D','I') +#define HUB_PREFIX TWO_CC('H','B') + +#define ARM_UC_COMMON_ERR_LIST\ + ENUM_FIXED(ERR_NONE,0)\ + ENUM_AUTO(ERR_INVALID_PARAMETER)\ + ENUM_AUTO(ERR_NOT_READY)\ + +// Manifest manager +#define ARM_UC_MM_ERR_LIST\ + ENUM_FIXED(MFST_ERR_NONE, MANIFEST_MANAGER_PREFIX << 16)\ + ENUM_AUTO(MFST_ERR_NULL_PTR)\ + ENUM_AUTO(MFST_ERR_PENDING)\ + ENUM_AUTO(MFST_ERR_SIZE)\ + ENUM_AUTO(MFST_ERR_DER_FORMAT)\ + ENUM_AUTO(MFST_ERR_FORMAT)\ + ENUM_AUTO(MFST_ERR_VERSION)\ + ENUM_AUTO(MFST_ERR_ROLLBACK)\ + ENUM_AUTO(MFST_ERR_CRYPTO_MODE)\ + ENUM_AUTO(MFST_ERR_HASH)\ + ENUM_AUTO(MFST_ERR_GUID_VENDOR)\ + ENUM_AUTO(MFST_ERR_GUID_DEVCLASS)\ + ENUM_AUTO(MFST_ERR_GUID_DEVICE)\ + ENUM_AUTO(MFST_ERR_CFG_CREATE_FAILED)\ + ENUM_AUTO(MFST_ERR_KEY_SIZE)\ + ENUM_AUTO(MFST_ERR_CERT_INVALID)\ + ENUM_AUTO(MFST_ERR_CERT_NOT_FOUND)\ + ENUM_AUTO(MFST_ERR_CERT_READ)\ + ENUM_AUTO(MFST_ERR_INVALID_SIGNATURE)\ + ENUM_AUTO(MFST_ERR_INVALID_STATE)\ + ENUM_AUTO(MFST_ERR_BAD_EVENT)\ + ENUM_AUTO(MFST_ERR_EMPTY_FIELD)\ + ENUM_AUTO(MFST_ERR_NO_MANIFEST)\ + ENUM_AUTO(MFST_ERR_SIGNATURE_ALGORITHM)\ + ENUM_AUTO(MFST_ERR_UNSUPPORTED_CONDITION)\ + +// Certificate Manager +#define ARM_UC_CM_ERR_LIST\ + ENUM_FIXED(ARM_UC_CM_ERR_NONE, CERTIFICATE_MANAGER_PREFIX << 16)\ + ENUM_AUTO(ARM_UC_CM_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(ARM_UC_CM_ERR_NOT_FOUND)\ + ENUM_AUTO(ARM_UC_CM_ERR_INVALID_CERT)\ + ENUM_AUTO(ARM_UC_CM_ERR_BLACKLISTED)\ + +// DER Parser +#define ARM_UC_DP_ERR_LIST\ + ENUM_FIXED(ARM_UC_DP_ERR_NONE, DER_PARSER_PREFIX << 16)\ + ENUM_AUTO(ARM_UC_DP_ERR_UNKNOWN)\ + ENUM_AUTO(ARM_UC_DP_ERR_NOT_FOUND)\ + ENUM_AUTO(ARM_UC_DP_ERR_NO_MORE_ELEMENTS)\ + +// Source Manager +#define ARM_UC_SM_ERR_LIST\ + ENUM_FIXED(SOMA_ERR_NONE, SOURCE_MANAGER_PREFIX << 16)\ + ENUM_AUTO(SOMA_ERR_NO_ROUTE_TO_SOURCE)\ + ENUM_AUTO(SOMA_ERR_SOURCE_REGISTRY_FULL)\ + ENUM_AUTO(SOMA_ERR_SOURCE_NOT_FOUND)\ + ENUM_AUTO(SOMA_ERR_INVALID_PARAMETER) + +// Source +#define ARM_UC_SRC_ERR_LIST\ + ENUM_FIXED(SRCE_ERR_NONE, SOURCE_PREFIX << 16)\ + ENUM_AUTO(SRCE_ERR_UNINITIALIZED)\ + ENUM_AUTO(SRCE_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(SRCE_ERR_FAILED)\ + ENUM_AUTO(SRCE_ERR_BUSY) + +// Firmware Manager +#define ARM_UC_FM_ERR_LIST\ + ENUM_FIXED(FIRM_ERR_NONE, FIRMWARE_MANAGER_PREFIX << 16)\ + ENUM_AUTO(FIRM_ERR_WRITE)\ + ENUM_AUTO(FIRM_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(FIRM_ERR_ACTIVATE)\ + ENUM_AUTO(FIRM_ERR_UNINITIALIZED)\ + ENUM_AUTO(FIRM_ERR_INVALID_HASH) + +#define ARM_UC_CU_ERR_LIST\ + ENUM_FIXED(ARM_UC_CU_ERR_NONE, UPDATE_CRYPTO_PREFIX << 16)\ + ENUM_AUTO(ARM_UC_CU_ERR_INVALID_PARAMETER)\ + +#define ARM_UC_DI_ERR_LIST\ + ENUM_FIXED(ARM_UC_DI_ERR_NONE, DEVICE_IDENTITY_PREFIX << 16)\ + ENUM_AUTO(ARM_UC_DI_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(ARM_UC_DI_ERR_NOT_READY)\ + ENUM_AUTO(ARM_UC_DI_ERR_NOT_FOUND)\ + ENUM_AUTO(ARM_UC_DI_ERR_SIZE)\ + +#define ARM_UC_HB_ERR_LIST\ + ENUM_FIXED(HUB_ERR_NONE, HUB_PREFIX << 16)\ + ENUM_AUTO(HUB_ERR_ROLLBACK_PROTECTION)\ + +#define ARM_UC_ERR_LIST\ + ARM_UC_COMMON_ERR_LIST\ + ARM_UC_MM_ERR_LIST\ + ARM_UC_CM_ERR_LIST\ + ARM_UC_DP_ERR_LIST\ + ARM_UC_SM_ERR_LIST\ + ARM_UC_SRC_ERR_LIST\ + ARM_UC_FM_ERR_LIST\ + ARM_UC_CU_ERR_LIST\ + ARM_UC_DI_ERR_LIST\ + ARM_UC_HB_ERR_LIST\ + +enum arm_uc_error { + #define ENUM_AUTO(name) name, + #define ENUM_FIXED(name, val) name = val, + ARM_UC_ERR_LIST + #undef ENUM_AUTO + #undef ENUM_FIXED +}; +union arm_uc_error_code { + int32_t code; + struct { + int16_t error; + union { + uint16_t module; + uint8_t modulecc[2]; + }; + }; +}; + +typedef union arm_uc_error_code arm_uc_error_t; + +#ifndef ARM_UC_ERR_TRACE +#define ARM_UC_ERR_TRACE 0 +#endif + +#if ARM_UC_ERR_TRACE +#define ARM_UC_SET_ERROR(ERR, CODE) + do {(ERR).code = (CODE);} while (0) +#else +#define ARM_UC_SET_ERROR(ERR, CODE)\ + (ERR).code = (CODE) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +const char* ARM_UC_err2Str(arm_uc_error_t err); + +#ifdef __cplusplus +} +#endif +#endif // ARM_UPDATE_ERROR_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_metadata_header_v2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_metadata_header_v2.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,190 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_METADATA_HEADER_V2_H +#define ARM_UC_METADATA_HEADER_V2_H + +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARM_UC_INTERNAL_HEADER_MAGIC_V2 (0x5a51b3d4UL) +#define ARM_UC_INTERNAL_HEADER_VERSION_V2 (2) + +#define ARM_UC_EXTERNAL_HEADER_MAGIC_V2 (0x5a51b3d4UL) +#define ARM_UC_EXTERNAL_HEADER_VERSION_V2 (2) + +#define ARM_UC_INTERNAL_FIRMWARE_VERSION_OFFSET_V2 (8) +#define ARM_UC_INTERNAL_FIRMWARE_SIZE_OFFSET_V2 (16) +#define ARM_UC_INTERNAL_FIRMWARE_HASH_OFFSET_V2 (24) +#define ARM_UC_INTERNAL_CAMPAIGN_OFFSET_V2 (88) +#define ARM_UC_INTERNAL_SIGNATURE_SIZE_OFFSET_V2 (104) +#define ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2 (108) + +#define ARM_UC_INTERNAL_HEADER_SIZE_V2 (112) + +#define ARM_UC_EXTERNAL_FIRMWARE_VERSION_OFFSET_V2 (8) +#define ARM_UC_EXTERNAL_FIRMWARE_SIZE_OFFSET_V2 (16) +#define ARM_UC_EXTERNAL_FIRMWARE_HASH_OFFSET_V2 (24) +#define ARM_UC_EXTERNAL_PAYLOAD_SIZE_OFFSET_V2 (88) +#define ARM_UC_EXTERNAL_PAYLOAD_HASH_OFFSET_V2 (96) +#define ARM_UC_EXTERNAL_CAMPAIGN_OFFSET_V2 (160) +#define ARM_UC_EXTERNAL_HMAC_OFFSET_V2 (232) + +#define ARM_UC_EXTERNAL_HEADER_SIZE_V2 (296) + +typedef struct _arm_uc_internal_header_t +{ + /* Metadata-header specific magic code */ + uint32_t headerMagic; + + /* Revision number for metadata header. */ + uint32_t headerVersion; + + /* Version number accompanying the firmware. Larger numbers imply more + recent and preferred versions. This is used for determining the + selection order when multiple versions are available. For downloaded + firmware the manifest timestamp is used as the firmware version. + */ + uint64_t firmwareVersion; + + /* Total space (in bytes) occupied by the firmware BLOB. */ + uint64_t firmwareSize; + + /* Firmware hash calculated over the firmware size. Should match the hash + generated by standard command line tools, e.g., shasum on Linux/Mac. + */ + uint8_t firmwareHash[ARM_UC_SHA512_SIZE]; + + /* The ID for the update campaign that resulted in the firmware update. + */ + uint8_t campaign[ARM_UC_GUID_SIZE]; + + /* Size of the firmware signature. Must be 0 if no signature is supplied. */ + uint32_t firmwareSignatureSize; + + /* Header 32 bit CRC. Calculated over the entire header, including the CRC + field, but with the CRC set to zero. + */ + uint32_t headerCRC; + + /* Optional firmware signature. Hashing algorithm should be the same as the + one used for the firmware hash. The firmwareSignatureSize must be set. + */ + uint8_t firmwareSignature[0]; +} arm_uc_internal_header_t; + +typedef struct _arm_uc_external_header_t +{ + /* Metadata-header specific magic code */ + uint32_t headerMagic; + + /* Revision number for metadata header. */ + uint32_t headerVersion; + + /* Version number accompanying the firmware. Larger numbers imply more + recent and preferred versions. This is used for determining the + selection order when multiple versions are available. For downloaded + firmware the manifest timestamp is used as the firmware version. + */ + uint64_t firmwareVersion; + + /* Total space (in bytes) occupied by the firmware BLOB. */ + uint64_t firmwareSize; + + /* Firmware hash calculated over the firmware size. Should match the hash + generated by standard command line tools, e.g., shasum on Linux/Mac. + */ + uint8_t firmwareHash[ARM_UC_SHA512_SIZE]; + + /* Total space (in bytes) occupied by the payload BLOB. + The payload is the firmware after some form of transformation like + encryption and/or compression. + */ + uint64_t payloadSize; + + /* Payload hash calculated over the payload size. Should match the hash + generated by standard command line tools, e.g., shasum on Linux/Mac. + The payload is the firmware after some form of transformation like + encryption and/or compression. + */ + uint8_t payloadHash[ARM_UC_SHA512_SIZE]; + + /* The ID for the update campaign that resulted in the firmware update. + */ + uint8_t campaign[ARM_UC_GUID_SIZE]; + + /* Type of transformation used to turn the payload into the firmware image. + Possible values are: + * * NONE + * * AES128_CTR + * * AES128_CBC + * * AES256_CTR + * * AES256_CBC + */ + uint32_t firmwareTransformationMode; + + /* Encrypted firmware encryption key. + * To decrypt the firmware, the bootloader combines the bootloader secret + * and the firmwareKeyDerivationFunctionSeed to create an AES key. It uses + * This AES key to decrypt the firmwareCipherKey. The decrypted + * firmwareCipherKey is the FirmwareKey, which is used with the + * firmwareInitVector to decrypt the firmware. + */ + uint8_t firmwareCipherKey[ARM_UC_AES256_KEY_SIZE]; + + /* AES Initialization vector. This is a random number used to protect the + encryption algorithm from attack. It must be unique for every firmware. + */ + uint8_t firmwareInitVector[ARM_UC_AES_BLOCK_SIZE]; + + /* Size of the firmware signature. Must be 0 if no signature is supplied. */ + uint32_t firmwareSignatureSize; + + /* Hash based message authentication code for the metadata header. Uses per + device secret as key. Should use same hash algorithm as firmware hash. + The headerHMAC field and firmwareSignature field are not part of the hash. + */ + uint8_t headerHMAC[ARM_UC_SHA512_SIZE]; + + /* Optional firmware signature. Hashing algorithm should be the same as the + one used for the firmware hash. The firmwareSignatureSize must be set. + */ + uint8_t firmwareSignature[0]; +} arm_uc_external_header_t; + +arm_uc_error_t arm_uc_parse_internal_header_v2(const uint8_t* input, + arm_uc_firmware_details_t* output); + +arm_uc_error_t arm_uc_create_internal_header_v2(const arm_uc_firmware_details_t* input, + arm_uc_buffer_t* output); + +arm_uc_error_t arm_uc_parse_external_header_v2(const uint8_t* input, + arm_uc_firmware_details_t* output); + +arm_uc_error_t arm_uc_create_external_header_v2(const arm_uc_firmware_details_t* input, + arm_uc_buffer_t* output); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UC_METADATA_HEADER_V2_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_public.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_public.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,63 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_COMMON_PUBLIC_H +#define ARM_UPDATE_COMMON_PUBLIC_H + +#include <stdint.h> + +#ifndef ARM_UPDATE_CLIENT_VERSION +#define ARM_UPDATE_CLIENT_VERSION "Update Client 1.1" +#endif + +#ifndef ARM_UPDATE_CLIENT_VERSION_VALUE +#define ARM_UPDATE_CLIENT_VERSION_VALUE 101001UL +#endif + +/** + * Public error codes for the Update Client. + */ +enum { + ARM_UC_WARNING, + ARM_UC_WARNING_CERTIFICATE_NOT_FOUND, + ARM_UC_WARNING_IDENTITY_NOT_FOUND, + ARM_UC_WARNING_VENDOR_MISMATCH, + ARM_UC_WARNING_CLASS_MISMATCH, + ARM_UC_WARNING_DEVICE_MISMATCH, + ARM_UC_WARNING_CERTIFICATE_INVALID, + ARM_UC_WARNING_SIGNATURE_INVALID, + ARM_UC_WARNING_URI_NOT_FOUND, + ARM_UC_WARNING_ROLLBACK_PROTECTION, + ARM_UC_WARNING_UNKNOWN, + ARM_UC_ERROR, + ARM_UC_ERROR_WRITE_TO_STORAGE, + ARM_UC_ERROR_INVALID_HASH, + ARM_UC_FATAL, + ARM_UC_UNKNOWN +}; + +/** + * Public update requests + */ +typedef enum { + ARM_UCCC_REQUEST_INVALID, + ARM_UCCC_REQUEST_DOWNLOAD, + ARM_UCCC_REQUEST_INSTALL, +} arm_uc_request_t; + +#endif // ARM_UPDATE_COMMON_PUBLIC_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_scheduler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_scheduler.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,100 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_SCHEDULER_H +#define ARM_UPDATE_SCHEDULER_H + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +/** + * Simple scheduler useful for collecting events from different threads and + * interrupt context so they can be executed from the same thread/context. + * + * This can reduce the calldepth, ensure functions are executed from the same + * thread, and provide a method for breaking out of interrupt context. + * + * Callbacks are executed FIFO. + * + * The notification handler should be used for processing the queue whenever it + * is non-empty. + */ + +/** + * Use custom struct for the lockfree queue. + * Struct contains function pointer callback and uint32_t parameter. + */ +#define ATOMIC_QUEUE_CUSTOM_ELEMENT + +struct lockfree_queue_element { + struct lockfree_queue_element * volatile next; + uintptr_t lock; + void (*callback)(uint32_t); + uint32_t parameter; +}; + +#include "atomic-queue/atomic-queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct lockfree_queue_element arm_uc_callback_t; + +/** + * @brief Add function to be executed to the queue. + * @details The caller is responsible for managing the memory for each element + * in the queue, i.e., allocating enough struct lockfree_queue_element + * to hold the number of outstanding callbacks in the queue. + * + * @param storage Pointer to struct lockfree_queue_element. + * @param callback Function pointer to function being scheduled to run later. + * @param parameter uint32_t value to be passed as parameter to the callback function. + * @return True when the callback was successfully scheduled. + */ +bool ARM_UC_PostCallback(arm_uc_callback_t* storage, void (*callback)(uint32_t), uint32_t parameter); + +/** + * @brief Calling this function processes all callbacks in the queue. + */ +void ARM_UC_ProcessQueue(void); + +/** + * @brief Calling this function processes a single callback in the queue. + * @details The return value indicates whether there are more callbacks + * in the queue that needs handling. + * @return True when there are more callbacks in the queue, false otherwise. + */ +bool ARM_UC_ProcessSingleCallback(void); + +/** + * @brief Register callback function for when callbacks are added to an empty queue. + * @details This function is called at least once (maybe more) when callbacks are + * added to an empty queue. Useful for scheduling when the queue needs + * to be processed. + * @param handler Function pointer to function to be called when elements are + * added to an empty queue. + */ +void ARM_UC_AddNotificationHandler(void (*handler)(void)); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UPDATE_SCHEDULER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_trace.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_trace.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,157 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_TRACE_H +#define ARM_UPDATE_TRACE_H + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include <stdio.h> +#include <inttypes.h> + +/* + Available update client trace flags: + ARM_UC_ALL_TRACE_ENABLE + ARM_UC_HUB_TRACE_ENABLE + ARM_UC_FIRMWARE_MANAGER_TRACE_ENABLE + ARM_UC_CONTROL_CENTER_TRACE_ENABLE +*/ + +/* if the global trace flag is enabled, enable trace for all hub modules */ +#if defined(MBED_CONF_MBED_TRACE_ENABLE) && MBED_CONF_MBED_TRACE_ENABLE == 1 +#include "mbed-trace/mbed_trace.h" +#undef ARM_UC_ALL_TRACE_ENABLE +#define ARM_UC_ALL_TRACE_ENABLE 1 +#endif // if MBED_CONF_MBED_TRACE_ENABLE + +#if defined(ARM_UC_ALL_TRACE_ENABLE) && ARM_UC_ALL_TRACE_ENABLE == 1 +#undef ARM_UC_HUB_TRACE_ENABLE +#define ARM_UC_HUB_TRACE_ENABLE 1 +#undef ARM_UC_FIRMWARE_MANAGER_TRACE_ENABLE +#define ARM_UC_FIRMWARE_MANAGER_TRACE_ENABLE 1 +#undef ARM_UC_MANIFEST_MANAGER_TRACE_ENABLE +#define ARM_UC_MANIFEST_MANAGER_TRACE_ENABLE 1 +#undef ARM_UC_SOURCE_MANAGER_TRACE_ENABLE +#define ARM_UC_SOURCE_MANAGER_TRACE_ENABLE 1 +#undef ARM_UC_CONTROL_CENTER_TRACE_ENABLE +#define ARM_UC_CONTROL_CENTER_TRACE_ENABLE 1 +#undef ARM_UC_COMMON_TRACE_ENABLE +#define ARM_UC_COMMON_TRACE_ENABLE 1 +#endif // if ARM_UC_ALL_TRACE_ENABLE + +#if ARM_UC_HUB_TRACE_ENABLE +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#if MBED_CONF_MBED_TRACE_ENABLE +#define UC_HUB_TRACE(fmt, ...) mbed_tracef(TRACE_LEVEL_DEBUG, "HUB ", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_HUB_ERR_MSG(fmt, ...) mbed_tracef(TRACE_LEVEL_ERROR, "HUB ", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#else +#define UC_HUB_TRACE(fmt, ...) printf("[TRACE]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_HUB_ERR_MSG(fmt, ...) printf("[ERROR]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#endif // if MBED_CONF_MBED_TRACE_ENABLE +#else +#define UC_HUB_TRACE(...) +#define UC_HUB_ERR_MSG(...) +#endif // if ARM_UC_FIRMWARE_MANAGER_TRACE_ENABLE + +#if ARM_UC_FIRMWARE_MANAGER_TRACE_ENABLE +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#if MBED_CONF_MBED_TRACE_ENABLE +#define UC_FIRM_TRACE(fmt, ...) mbed_tracef(TRACE_LEVEL_DEBUG, "FIRM", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_FIRM_ERR_MSG(fmt, ...) mbed_tracef(TRACE_LEVEL_ERROR, "FIRM", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#else +#define UC_FIRM_TRACE(fmt, ...) printf("[TRACE]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_FIRM_ERR_MSG(fmt, ...) printf("[ERROR]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#endif // if MBED_CONF_MBED_TRACE_ENABLE +#else +#define UC_FIRM_TRACE(fmt, ...) +#define UC_FIRM_ERR_MSG(fmt, ...) +#endif // if ARM_UC_FIRMWARE_MANAGER_TRACE_ENABLE + +#if ARM_UC_MANIFEST_MANAGER_TRACE_ENABLE +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#if MBED_CONF_MBED_TRACE_ENABLE +#define UC_MMGR_TRACE(fmt, ...) mbed_tracef(TRACE_LEVEL_DEBUG, "MMGR", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_MMGR_ERR_MSG(fmt, ...) mbed_tracef(TRACE_LEVEL_ERROR, "MMGR", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#else +#define UC_MMGR_TRACE(fmt, ...) printf("[TRACE]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_MMGR_ERR_MSG(fmt, ...) printf("[ERROR]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#endif // if MBED_CONF_MBED_TRACE_ENABLE +#else +#define UC_MMGR_TRACE(fmt, ...) +#define UC_MMGR_ERR_MSG(fmt, ...) +#endif // if ARM_UC_MANIFEST_MANAGER_TRACE_ENABLE + +#if ARM_UC_SOURCE_MANAGER_TRACE_ENABLE +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#if MBED_CONF_MBED_TRACE_ENABLE +#define UC_SRCE_TRACE(fmt, ...) mbed_tracef(TRACE_LEVEL_DEBUG, "SRCE", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_SRCE_ERR_MSG(fmt, ...) mbed_tracef(TRACE_LEVEL_ERROR, "SRCE", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#else +#define UC_SRCE_TRACE(fmt, ...) printf("[TRACE]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_SRCE_ERR_MSG(fmt, ...) printf("[ERROR]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#endif // if MBED_CONF_MBED_TRACE_ENABLE +#else +#define UC_SRCE_TRACE(fmt, ...) +#define UC_SRCE_ERR_MSG(fmt, ...) +#endif // if ARM_UC_SOURCE_MANAGER_TRACE_ENABLE + +#if ARM_UC_CONTROL_CENTER_TRACE_ENABLE +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#if MBED_CONF_MBED_TRACE_ENABLE +#define UC_CONT_TRACE(fmt, ...) mbed_tracef(TRACE_LEVEL_DEBUG, "CTRL", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_CONT_ERR_MSG(fmt, ...) mbed_tracef(TRACE_LEVEL_ERROR, "CTRL", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#else +#define UC_CONT_TRACE(fmt, ...) printf("[TRACE]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_CONT_ERR_MSG(fmt, ...) printf("[ERROR]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#endif // if MBED_CONF_MBED_TRACE_ENABLE +#else +#define UC_CONT_TRACE(fmt, ...) +#define UC_CONT_ERR_MSG(fmt, ...) +#endif // if ARM_UC_FIRMWARE_MANAGER_TRACE_ENABLE + +#if ARM_UC_COMMON_TRACE_ENABLE +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#if MBED_CONF_MBED_TRACE_ENABLE +#define UC_COMM_TRACE(fmt, ...) mbed_tracef(TRACE_LEVEL_DEBUG, "COMM", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_COMM_ERR_MSG(fmt, ...) mbed_tracef(TRACE_LEVEL_ERROR, "COMM", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#else +#define UC_COMM_TRACE(fmt, ...) printf("[TRACE]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_COMM_ERR_MSG(fmt, ...) printf("[ERROR]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#endif // if MBED_CONF_MBED_TRACE_ENABLE +#else +#define UC_COMM_TRACE(fmt, ...) +#define UC_COMM_ERR_MSG(fmt, ...) +#endif // if ARM_UC_COMMON_TRACE_ENABLE + +#if ARM_UC_PAAL_TRACE_ENABLE +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) +#if MBED_CONF_MBED_TRACE_ENABLE +#define UC_PAAL_TRACE(fmt, ...) mbed_tracef(TRACE_LEVEL_DEBUG, "PAAL", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_PAAL_ERR_MSG(fmt, ...) mbed_tracef(TRACE_LEVEL_ERROR, "PAAL", "%s:%d: " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__) +#else +#define UC_PAAL_TRACE(fmt, ...) printf("[TRACE]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#define UC_PAAL_ERR_MSG(fmt, ...) printf("[ERROR]" "%s:%d: " fmt "\r\n", __FILENAME__, __LINE__, ##__VA_ARGS__) +#endif // if MBED_CONF_MBED_TRACE_ENABLE +#else +#define UC_PAAL_TRACE(fmt, ...) +#define UC_PAAL_ERR_MSG(fmt, ...) +#endif // if ARM_UC_COMMON_TRACE_ENABLE + +#endif // ARM_UPDATE_TRACE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_types.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,89 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_COMMON_TYPES_H +#define ARM_UPDATE_COMMON_TYPES_H + +#include <stdint.h> + +typedef struct +{ + uint32_t size_max; // maximum size of the buffer + uint32_t size; // index of the first empty byte in the buffer + uint8_t* ptr; // pointer to buffer's memory +} arm_uc_buffer_t; + +typedef enum { + URI_SCHEME_NONE, + URI_SCHEME_HTTP, +} arm_uc_uri_scheme_t; + +typedef struct +{ + uint32_t size_max; // maximum size of the buffer + uint32_t size; // index of the first empty byte in the buffer + uint8_t* ptr; // pointer to buffer's memory + arm_uc_uri_scheme_t scheme; // URI type + uint16_t port; // connection port + char* host; // \0 terminated string with host name + char* path; // \0 terminated string with resource path +} arm_uc_uri_t; + +#define ARM_UC_GUID_SIZE (128/8) +#define ARM_UC_SHA256_SIZE (256/8) +#define ARM_UC_SHA512_SIZE (512/8) +#define ARM_UC_AES256_KEY_SIZE (256/8) +#define ARM_UC_AES_BLOCK_SIZE (128/8) + +/** + * @brief GUID type + */ +typedef uint8_t arm_uc_guid_t[ARM_UC_GUID_SIZE]; + +/** + * @brief SHA256 hash + */ +typedef uint8_t arm_uc_hash_t[ARM_UC_SHA256_SIZE]; + +/** + * @brief Firmware details struct. + * @details Struct for passing information between the Update client and the + * PAAL implementation describing the firmware image. + */ +typedef struct _arm_uc_firmware_details_t +{ + uint64_t version; + uint64_t size; + arm_uc_hash_t hash; + arm_uc_guid_t campaign; + uint32_t signatureSize; + uint8_t signature[0]; +} arm_uc_firmware_details_t; + +/** + * @brief Installer details struct. + * @details Struct for reading the installer information. + */ +typedef struct _arm_uc_installer_details_t +{ + arm_uc_hash_t arm_hash; + arm_uc_hash_t oem_hash; + uint32_t layout; +} arm_uc_installer_details_t; + +#endif // ARM_UPDATE_COMMON_TYPES_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_utilities.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/common/update-client-common/arm_uc_utilities.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,202 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_COMMON_UTILITIES_H +#define ARM_UPDATE_COMMON_UTILITIES_H + +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_error.h" +#include <string.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARM_UC_util_min(A,B)\ + ((A) < (B) ? (A) : (B)) + +/* lookup table for printing hexadecimal characters. */ +extern const uint8_t arm_uc_hex_table[16]; + +/** + * @brief Parse a uri string to populate a arm_uc_uri_t struct + * @detail Format of uri scheme:[//]host[:port]/path + * [] means optional, path will always start with a '/' + * + * @param str Pointer to string containing URI. + * @param size String length. + * @param uri The arm_uc_uri_t struct to be populated + */ +arm_uc_error_t arm_uc_str2uri(const uint8_t* str, uint32_t size, arm_uc_uri_t* uri); + +/** + * @brief Find substring inside string. + * @details The size of both string and substring is explicitly passed so no + * assumptions are made about NULL termination. + * + * @param big_buffer Pointer to the string to be searched. + * @param big_length Length of the string to be searched. + * @param little_buffer Pointer to the substring being searched for. + * @param little_length Length of the substring being searched for. + * @return Index to where the substring was found inside the string. If the + * string doesn't contain the subtring, UINT32_MAX is returned. + */ +uint32_t arm_uc_strnstrn(const uint8_t* big_buffer, + uint32_t big_length, + const uint8_t* little_buffer, + uint32_t little_length); + +/** + * @brief Find string length. + * @details Custom implementation of strnlen which is a GNU extension. + * Returns either the string length or max_length. + * + * @param buffer Pointer to string. + * @param max_length Maximum buffer length. + * + * @return String length or max_length. + */ +uint32_t arm_uc_strnlen(const uint8_t* buffer, uint32_t max_length); + +/** + * @brief Convert string to unsigned 32 bit integer. + * @details Function tries to parse string as an unsigned 32 bit integer + * and return the value. The function will set the third parameter + * to true if the parsing was successful. + * + * @param buffer Pointer to string. + * @param max_length Maximum buffer length. + * @param success Pointer to boolean indicating whether the parsing was successful. + * @return Parsed value. Only valid if success it true. + */ +uint32_t arm_uc_str2uint32(const uint8_t* buffer, + uint32_t max_length, + bool* success); + +/** + * @brief Calculate CRC 32 + * + * @param buffer Input array. + * @param length Length of array in bytes. + * + * @return 32 bit CRC. + */ +uint32_t arm_uc_crc32(const uint8_t* buffer, uint32_t length); + +/** + * @brief Parse 4 byte array into uint32_t + * + * @param input 4 byte array. + * @return uint32_t + */ +uint32_t arm_uc_parse_uint32(const uint8_t* input); + +/** + * @brief Parse 8 byte array into uint64_t + * + * @param input 8 byte array. + * @return uint64_t + */ +uint64_t arm_uc_parse_uint64(const uint8_t* input); + +/** + * @brief Write uint32_t to array. + * + * @param buffer Pointer to buffer. + * @param value Value to be written. + */ +void arm_uc_write_uint32(uint8_t* buffer, uint32_t value); + +/** + * @brief Write uint64_t to array. + * + * @param buffer Pointer to buffer. + * @param value Value to be written. + */ +void arm_uc_write_uint64(uint8_t* buffer, uint64_t value); + +/** + * @brief Do a shallow copy of a buffer. + * @details Copies each field of a buffer from `src` to `dest`. This creates another reference to the buffer that + * backs `src` and drops any reference to a buffer that backs `dest`. + * + * @param[out] dest Pointer to a buffer structure that will receive a reference to the buffer that backs `src` + * @param[in] src Pointer to a buffer to copy into dest + */ +static inline void ARM_UC_buffer_shallow_copy(arm_uc_buffer_t* dest, arm_uc_buffer_t* src) { + dest->size_max = src->size_max; + dest->size = src->size; + dest->ptr = src->ptr; +} + +/** + * @brief Do a deep copy of a buffer. + * @details Copies the content of `src->ptr` to `dest->ptr` + * If the space used in the source memory, referenced by the source buffer, is less than the maximum space available in + * the destination memory, referenced by the destination buffer, copies the source into the destination. + * + * @param[out] dest Pointer to a buffer structure that references destination memory + * @param[in] src Pointer to a buffer that references the data to copy into the destination memory + * @retval MFST_ERR_SIZE when the source size is larger than the destination's maximum size + * @retval MFST_ERR_NULL_PTR when any expected pointer is NULL + * @retval MFST_ERR_NONE on success + */ +static inline arm_uc_error_t ARM_UC_buffer_deep_copy(arm_uc_buffer_t* dest, arm_uc_buffer_t* src) +{ + arm_uc_error_t retval = { .code = MFST_ERR_NULL_PTR }; + + /* NULL pointer check */ + if (dest && + dest->ptr && + src && + src->ptr) + { + /* destination buffer is large enough */ + if (src->size <= dest->size_max) + { + /* copy content and set new size */ + memcpy(dest->ptr, src->ptr, src->size); + dest->size = src->size; + + retval.code = MFST_ERR_NONE; + } + else + { + retval.code = MFST_ERR_SIZE; + } + } + else + { + retval.code = MFST_ERR_NULL_PTR; + } + + return retval; +} + +uint32_t ARM_UC_BinCompareCT(const arm_uc_buffer_t* a, const arm_uc_buffer_t* b); +uint8_t * ARM_UC_Base64Enc(uint8_t *buf, const uint32_t size, const arm_uc_buffer_t* bin); +void ARM_UC_Base64Dec(arm_uc_buffer_t* bin, const uint32_t size, const uint8_t* buf); + + + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UPDATE_COMMON_UTILITIES_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_certificate.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_certificate.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,92 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-control-center/arm_uc_certificate.h" +#include "update-client-common/arm_uc_config.h" + +#if ARM_UC_USE_KCM +extern const struct arm_uc_certificate_api arm_uc_certificate_kcm_api; +static const struct arm_uc_certificate_api* arm_uc_registered_certificate_api = + &arm_uc_certificate_kcm_api; +#elif ARM_UC_USE_CFSTORE +extern const struct arm_uc_certificate_api arm_uc_certificate_cfstore_api; +static const struct arm_uc_certificate_api* arm_uc_registered_certificate_api = + &arm_uc_certificate_cfstore_api; +#else +#error No configuration store set +#endif + +/** + * @brief Add certificate. + * @details [long description] + * + * @param certificate Pointer to certiface being added. + * @param certificate_size Certificate length. + * @param fingerprint Pointer to the fingerprint of the certificate being added. + * @param fingerprint_size Fingerprint length. + * @return Error code. + */ +arm_uc_error_t ARM_UC_Certificate_Add(const uint8_t* certificate, + uint16_t certificate_size, + const uint8_t* fingerprint, + uint16_t fingerprint_size, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*)) +{ + //cert Name: base64(fingerprint) + const arm_uc_buffer_t fingerprintBuffer = { + .size = fingerprint_size, + .size_max = fingerprint_size, + .ptr = (uint8_t *)fingerprint /* Const Cast safe because target is in a const struct */ + }; + + const arm_uc_buffer_t certBuffer = { + .size = certificate_size, + .size_max = certificate_size, + .ptr = (uint8_t *)certificate /* Const Cast safe because target is in a const struct */ + }; + + const struct arm_uc_certificate_api* api = arm_uc_registered_certificate_api; + + if (api == NULL || api->store == NULL) + { + return (arm_uc_error_t){ ARM_UC_CM_ERR_INVALID_PARAMETER}; + } + + arm_uc_error_t err = api->store(&certBuffer, &fingerprintBuffer, callback); + + if (err.error != 0) + { + return err; + } + + return (arm_uc_error_t){ARM_UC_CM_ERR_NONE}; +} + +arm_uc_error_t ARM_UC_certificateFetch(arm_uc_buffer_t* certificate, + const arm_uc_buffer_t* fingerprint, + const arm_uc_buffer_t* DERCertificateList, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*, const arm_uc_buffer_t*)) +{ + if (arm_uc_registered_certificate_api == NULL || + arm_uc_registered_certificate_api->fetch == NULL) + { + return (arm_uc_error_t){ARM_UC_CM_ERR_INVALID_PARAMETER}; + } + + return arm_uc_registered_certificate_api->fetch(certificate, fingerprint, DERCertificateList, callback); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_certificate_cfstore_api.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_certificate_cfstore_api.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,108 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ----------------------------------------------------------------------------- + +#include "update-client-control-center/arm_uc_certificate.h" +#include "update-client-common/arm_uc_config.h" + +#ifndef ARM_UC_USE_CFSTORE +#define ARM_UC_USE_CFSTORE 0 +#endif + +#if ARM_UC_USE_CFSTORE + +#include <string.h> + +static const uint8_t* arm_uc_certificate = NULL; +static uint16_t arm_uc_certificate_size = 0; +static const uint8_t* arm_uc_fingerprint = NULL; +static uint16_t arm_uc_fingerprint_size = 0; + +static arm_uc_error_t arm_uc_cfstore_cert_storer(const arm_uc_buffer_t* cert, + const arm_uc_buffer_t* fingerprint, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*)) +{ + if (cert == NULL || + cert->ptr == NULL || + fingerprint == NULL || + fingerprint->ptr == NULL) + { + return (arm_uc_error_t){ARM_UC_CM_ERR_INVALID_PARAMETER}; + } + if (cert->size == 0 || fingerprint->size == 0) + { + return (arm_uc_error_t){ARM_UC_CM_ERR_INVALID_PARAMETER}; + } + + arm_uc_error_t err = (arm_uc_error_t){ARM_UC_CM_ERR_NONE}; + + arm_uc_certificate = cert->ptr; + arm_uc_certificate_size = cert->size; + arm_uc_fingerprint = fingerprint->ptr; + arm_uc_fingerprint_size = fingerprint->size; + + if (err.code == ARM_UC_CM_ERR_NONE && callback) + { + callback(err, fingerprint); + } + + return err; +} + +static arm_uc_error_t arm_uc_cfstore_cert_fetcher(arm_uc_buffer_t* certificate, + const arm_uc_buffer_t* fingerprint, + const arm_uc_buffer_t* DERCertificateList, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*, const arm_uc_buffer_t*)) +{ + arm_uc_error_t err = {ARM_UC_CM_ERR_INVALID_PARAMETER}; + + if (fingerprint->size != arm_uc_fingerprint_size) + { + err.code = ARM_UC_CM_ERR_NOT_FOUND; + } + else if (fingerprint != NULL && + fingerprint->ptr != NULL && + fingerprint->size == arm_uc_fingerprint_size && + certificate != NULL) + { + if (0 == memcmp(fingerprint->ptr, arm_uc_fingerprint, arm_uc_fingerprint_size)) + { + err.code = ARM_UC_CM_ERR_NONE; + certificate->ptr = (uint8_t*) arm_uc_certificate; + certificate->size = arm_uc_certificate_size; + certificate->size_max = arm_uc_certificate_size; + } + else + { + err.code = ARM_UC_CM_ERR_NOT_FOUND; + } + } + + if (err.error == ERR_NONE && callback) + { + callback(err, certificate, fingerprint); + } + + return err; +} + +const struct arm_uc_certificate_api arm_uc_certificate_cfstore_api = { + .fetch = arm_uc_cfstore_cert_fetcher, + .store = arm_uc_cfstore_cert_storer, +}; + +#endif // ARM_UC_USE_KCM
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_certificate_kcm_api.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_certificate_kcm_api.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,197 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-control-center/arm_uc_certificate.h" +#include "update-client-common/arm_uc_config.h" +#include "update-client-common/arm_uc_crypto.h" + +#ifndef ARM_UC_USE_KCM +#define ARM_UC_USE_KCM 0 +#endif + +#if ARM_UC_USE_KCM + +#include "key-config-manager/key_config_manager.h" + +static arm_uc_error_t kerr2ucerr(int kerr) +{ + arm_uc_error_t err; + switch(kerr) + { + case KCM_STATUS_SUCCESS: + err.code = ARM_UC_CM_ERR_NONE; + break; + case KCM_STATUS_INVALID_PARAMETER: + err.code = ARM_UC_CM_ERR_INVALID_PARAMETER; + break; + case KCM_STATUS_ITEM_NOT_FOUND: + case KCM_STATUS_ESFS_ERROR: + err.code = ARM_UC_CM_ERR_NOT_FOUND; + break; + case KCM_CRYPTO_STATUS_PARSING_DER_CERT: + err.code = ARM_UC_CM_ERR_INVALID_CERT; + break; + case KCM_STATUS_OUT_OF_MEMORY: + case KCM_STATUS_INSUFFICIENT_BUFFER: + default: + err.modulecc[0] = 'K'; + err.modulecc[1] = 'C'; + err.error = kerr; + break; + } + return err; +} + +static arm_uc_error_t arm_uc_kcm_cert_fetcher(arm_uc_buffer_t* certificate, + const arm_uc_buffer_t* fingerprint, + const arm_uc_buffer_t* DERCertificateList, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*, const arm_uc_buffer_t*)) +{ + uint8_t certName[MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE] = MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT; + // uint8_t certName[MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE] = MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX; + // uint8_t* b64hash = &certName[sizeof(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX)-1]; + // uint8_t defaultInUse = 0; + + UC_CONT_TRACE("Attempting to fetch certificate from: %s", certName); + // Format the certificate name into the certName buffer + // ARM_UC_Base64Enc(b64hash, sizeof(b64hash), fingerprint); + + // The arm_uc_buffer_t's size variable is 32bit, but kcm_item_get_data() needs + // a pointer to size_t, so we need to use a temp variable for it or we would get + // a corrupted arm_uc_buffer_t structure. + size_t cert_data_size = 0; + + // Look up the certificate by fingerprint + kcm_status_e kerr = kcm_item_get_data(certName, + strlen((char*)certName), + KCM_CERTIFICATE_ITEM, + certificate->ptr, + certificate->size_max, + &cert_data_size); + + // Check if the certificate was found. + // if (kerr == KCM_STATUS_ITEM_NOT_FOUND || kerr == KCM_STATUS_ESFS_ERROR) + // { + // printf("fingerprinted certificate not found. Checking for default...\n"); + // // If not, try the default location. + // kerr = kcm_item_get_data(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT, + // sizeof(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT) - 1, + // KCM_CERTIFICATE_ITEM, + // certificate->ptr, + // certificate->size_max, + // &cert_data_size); + // defaultInUse = 1; + // } + // Translate the KCM error to an update client error + arm_uc_error_t err = kerr2ucerr(kerr); + arm_uc_error_t errFinish = {ARM_UC_CM_ERR_INVALID_PARAMETER}; + + // Prepare to calculate the fingerprint of the certificate. + arm_uc_mdHandle_t h = { 0 }; + uint8_t fingerprintLocal[MBED_CLOUD_SHA256_BYTES]; + arm_uc_buffer_t fingerprintLocalBuffer = { + .size_max = sizeof(fingerprintLocal), + .size = 0, + .ptr = fingerprintLocal}; + + // Check for overflow before continuing. This is actually unnecessary + // belts and suspenders type of code, as the max value given to kcm_item_get_data() + // is at most UINT32_MAX, but the Coverity might point this as a error. + if (cert_data_size <= UINT32_MAX) + { + certificate->size = (uint32_t)cert_data_size; + } + else + { + err.code = ARM_UC_CM_ERR_INVALID_CERT; + } + + // Calculate the fingerprint of the certificate + if (err.error == ERR_NONE) + { + err = ARM_UC_cryptoHashSetup(&h, ARM_UC_CU_SHA256); + } + if (err.error == ERR_NONE) + { + err = ARM_UC_cryptoHashUpdate(&h, certificate); + + // The cryptoHashFinish needs to be called no matter if the update succeeded or not as + // it will do memory freeing. But in order to have valid result, the update & finish + // must both have succeeded. + errFinish = ARM_UC_cryptoHashFinish(&h, &fingerprintLocalBuffer); + + // Compare the calculated fingerprint to the requested fingerprint. + if ((err.error == ERR_NONE) && (errFinish.error == ERR_NONE)) + { + uint32_t rc = ARM_UC_BinCompareCT(fingerprint, &fingerprintLocalBuffer); + if (rc) + { + err.code = ARM_UC_CM_ERR_NOT_FOUND; + } + else + { + UC_CONT_TRACE("Certificate lookup fingerprint matched."); + err.code = ARM_UC_CM_ERR_NONE; + } + + if (callback && (err.error == ERR_NONE)) + { + callback(err, certificate, fingerprint); + } + } + } + + return err; +} + +static arm_uc_error_t arm_uc_kcm_cert_storer( + const arm_uc_buffer_t* cert, + const arm_uc_buffer_t* fingerprint, + void(*callback)(arm_uc_error_t, const arm_uc_buffer_t*)) +{ + // uint8_t certName[MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE] = MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX; + // uint8_t* b64hash = &certName[sizeof(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX)-1]; + uint8_t certName[MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE] = MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT; + + UC_CONT_TRACE("Storing certificate to: %s\n", certName); + // ARM_UC_Base64Enc(b64hash, sizeof(b64hash), fingerprint); + + kcm_status_e kerr = kcm_item_store(certName, + strlen((char*) certName), + KCM_CERTIFICATE_ITEM, + true, + cert->ptr, + cert->size, + NULL); + + arm_uc_error_t err = kerr2ucerr(kerr); + + if (callback && (err.code == ARM_UC_CM_ERR_NONE)) + { + callback(err, fingerprint); + } + + return err; +} + +const struct arm_uc_certificate_api arm_uc_certificate_kcm_api = { + .fetch = arm_uc_kcm_cert_fetcher, + .store = arm_uc_kcm_cert_storer +}; + +#endif // ARM_UC_USE_KCM
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_control_center.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_control_center.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,419 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-control-center/arm_uc_control_center.h" + +#include <stdbool.h> + +/* event handler */ +static void (*arm_uccc_event_handler)(uint32_t) = NULL; +static arm_uc_callback_t arm_uccc_authorize_callback = { 0 }; +static arm_uc_callback_t arm_uccc_monitor_callback = { 0 }; + +/* authorization callback */ +static void (*arm_uc_authority_callback)(int32_t) = NULL; +static bool arm_uc_download_token_armed = false; +static bool arm_uc_install_token_armed = false; + +/* force authorization */ +static arm_uc_callback_t arm_uccc_override_callback = { 0 }; + +static void arm_uccc_override_task(uint32_t unused); + +/* progress callback */ +static void (*arm_uc_progress_callback)(uint32_t, uint32_t) = NULL; + +/* function pointer structs */ +static const ARM_UPDATE_MONITOR* arm_uc_monitor_struct = NULL; + +static void ARM_UC_ControlCenter_Notification_Handler(void) +{ + if (arm_uccc_event_handler) + { + ARM_UC_PostCallback(&arm_uccc_monitor_callback, + arm_uccc_event_handler, + ARM_UCCC_EVENT_MONITOR_SEND_DONE); + } +} + +/** + * @brief Initialize Control Center. + * + * @param callback Event handler to signal authorizations. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_Initialize(void (*callback)(uint32_t)) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_Initialize: %p", callback); + + arm_uccc_event_handler = callback; + + return (arm_uc_error_t){ ERR_NONE }; +} + +/** + * @brief Add monitor struct for sending status and results remotely. + * + * @param monitor Pointer to an ARM_UPDATE_MONITOR struct. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_AddMonitor(const ARM_UPDATE_MONITOR* monitor) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_AddMonitor: %p", monitor); + + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + arm_uc_monitor_struct = monitor; + + if (arm_uc_monitor_struct) + { + result = arm_uc_monitor_struct->Initialize(ARM_UC_ControlCenter_Notification_Handler); + } + + return result; +} + +/** + * @brief Set callback for receiving download progress. + * @details User application call for setting callback handler. + * The callback function takes the progreess in percent as argument. + * + * @param callback Function pointer to the progress function. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_SetProgressHandler(void (*callback)(uint32_t progress, uint32_t total)) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_SetProgressHandler: %p", callback); + + arm_uc_progress_callback = callback; + + return (arm_uc_error_t){ ERR_NONE }; +} + +/** + * @brief Set callback function for authorizing requests. + * @details The callback function takes an enum request and an authorization + * function pointer. To authorize the given request, the caller + * invokes the authorization function. + * + * @param callback Function pointer to the authorization function. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_SetAuthorityHandler(void (*callback)(int32_t)) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_SetAuthorityHandler: %p", callback); + + arm_uc_authority_callback = callback; + + return (arm_uc_error_t){ ERR_NONE }; +} + +/** + * @brief Request authorization from Control Center. + * + * @param type Request type. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_GetAuthorization(arm_uc_request_t request) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_GetAuthorization: %d", (int) request); + + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + switch (request) + { + case ARM_UCCC_REQUEST_DOWNLOAD: + /* Arm callback token */ + arm_uc_download_token_armed = true; + + if (arm_uc_authority_callback) + { + arm_uc_authority_callback(ARM_UCCC_REQUEST_DOWNLOAD); + } + else + { + ARM_UC_ControlCenter_Authorize(ARM_UCCC_REQUEST_DOWNLOAD); + } + result.code = ERR_NONE; + break; + + case ARM_UCCC_REQUEST_INSTALL: + /* Arm callback token */ + arm_uc_install_token_armed = true; + + if (arm_uc_authority_callback) + { + arm_uc_authority_callback(ARM_UCCC_REQUEST_INSTALL); + } + else + { + ARM_UC_ControlCenter_Authorize(ARM_UCCC_REQUEST_INSTALL); + } + result.code = ERR_NONE; + break; + default: + break; + } + + return result; +} + +/** + * @brief Authorize request. + * + * @param request Request type. Must match the type in callback function. + */ +arm_uc_error_t ARM_UC_ControlCenter_Authorize(arm_uc_request_t request) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_Authorize: %d", (int) request); + + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + switch (request) + { + case ARM_UCCC_REQUEST_DOWNLOAD: + if (arm_uccc_event_handler && arm_uc_download_token_armed) + { + arm_uc_download_token_armed = false; + + ARM_UC_PostCallback(&arm_uccc_authorize_callback, + arm_uccc_event_handler, + ARM_UCCC_EVENT_AUTHORIZE_DOWNLOAD); + + result.code = ERR_NONE; + } + break; + + case ARM_UCCC_REQUEST_INSTALL: + if (arm_uccc_event_handler && arm_uc_install_token_armed) + { + arm_uc_install_token_armed = false; + + ARM_UC_PostCallback(&arm_uccc_authorize_callback, + arm_uccc_event_handler, + ARM_UCCC_EVENT_AUTHORIZE_INSTALL); + + result.code = ERR_NONE; + } + break; + + default: + break; + } + + return result; +} + +/** + * @brief Override update authorization handler. + * @details Force download and update to progress regardless of authorization + * handler. This function is used for unblocking an update in a buggy + * application. + */ +void ARM_UC_ControlCenter_OverrideAuthorization(void) +{ + ARM_UC_PostCallback(&arm_uccc_override_callback, + arm_uccc_override_task, + 0); +} + +static void arm_uccc_override_task(uint32_t unused) +{ + (void) unused; + + UC_CONT_TRACE("arm_uccc_override_task"); + + if (arm_uc_download_token_armed) + { + arm_uc_download_token_armed = false; + + /* force authorization */ + if (arm_uccc_event_handler) + { + arm_uccc_event_handler(ARM_UCCC_EVENT_AUTHORIZE_DOWNLOAD); + } + } + else if (arm_uc_install_token_armed) + { + arm_uc_install_token_armed = false; + + /* force authorization */ + if (arm_uccc_event_handler) + { + arm_uccc_event_handler(ARM_UCCC_EVENT_AUTHORIZE_INSTALL); + } + } + + /* disable authorization function */ + arm_uc_authority_callback = NULL; +} + +/** + * @brief Report download progress. + * @details Update Client call for informing the Control Center about the + * current download progress. The Control Center will send this to the + * appication handler and the monitor if either/both are attached. + * + * @param progrss Bytes already downloaded. + * @param total Total amount of bytes in download. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportProgress(uint32_t progress, uint32_t total) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_ReportProgress: %" PRIu32 " / %" PRIu32, progress, total); + + /* only forward request if callback is set. */ + if (arm_uc_progress_callback) + { + arm_uc_progress_callback(progress, total); + } + + return (arm_uc_error_t){ ERR_NONE }; +} + +/** + * @brief Send Update Client state. + * @param state Update Client state. + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportState(arm_uc_monitor_state_t state) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_ReportState: %d", (int) state); + + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + if (arm_uc_monitor_struct) + { + arm_uc_monitor_struct->SendState(state); + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Set update result. + * @param result Update result. + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportUpdateResult(arm_uc_monitor_result_t updateResult) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_ReportUpdateResult: %d", (int) updateResult); + + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + if (arm_uc_monitor_struct) + { + arm_uc_monitor_struct->SendUpdateResult(updateResult); + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Set current firmware name. + * @details Update Client call for informing the Control Center about the + * current firmware name. The Control Center will send this to the + * monitor. The firmware name is the SHA256 hash. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportName(arm_uc_buffer_t* name) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_ReportName: %p", name); + + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + if (arm_uc_monitor_struct) + { + arm_uc_monitor_struct->SendName(name); + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Set current firmware version. + * @details The firmware version is the SHA256 hash. + * + * @param version Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportVersion(uint64_t version) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_ReportVersion: %llu", version); + + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + if (arm_uc_monitor_struct) + { + arm_uc_monitor_struct->SendVersion(version); + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Send bootloader hash to monitor. + * @details The bootloader hash is a hash of the bootloader. This is + * used for tracking the version of the bootloader used. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportBootloaderHash(arm_uc_buffer_t* hash) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_ReportBootloaderHash"); + + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + if (arm_uc_monitor_struct && arm_uc_monitor_struct->SetBootloaderHash) + { + result = arm_uc_monitor_struct->SetBootloaderHash(hash); + } + + return result; +} + +/** + * @brief Send the OEM bootloader hash to monitor. + * @details If the end-user has modified the bootloader the hash of the + * modified bootloader can be set here. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportOEMBootloaderHash(arm_uc_buffer_t* hash) +{ + UC_CONT_TRACE("ARM_UC_ControlCenter_ReportOEMBootloaderHash"); + + arm_uc_error_t result = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + if (arm_uc_monitor_struct && arm_uc_monitor_struct->SetOEMBootloaderHash) + { + result = arm_uc_monitor_struct->SetOEMBootloaderHash(hash); + } + + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_pre_shared_key.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/source/arm_uc_pre_shared_key.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,74 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-control-center/arm_uc_pre_shared_key.h" + +/* Pointer to the pre-shared-key. Module only supports 1 key at a time. */ +static const uint8_t* arm_uc_psk_key = NULL; +static uint16_t arm_uc_psk_size = 0; + +/** + * @brief Register event handler. + * + * @param callback Event handler to signal result. + * @return Error code. + */ +arm_uc_error_t ARM_UC_PreSharedKey_Initialize(void (*callback)(uint32_t)) +{ + return (arm_uc_error_t){ ERR_NONE}; +} + +/** + * @brief Set pointer to pre-shared-key with the given size. + * + * @param key Pointer to pre-shared-key. + * @param bits Key size in bits. + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_PreSharedKey_SetKey(const uint8_t* key, uint16_t bits) +{ + arm_uc_psk_key = key; + arm_uc_psk_size = bits; + + return (arm_uc_error_t){ ERR_NONE}; +} + +/** + * @brief Get pointer to pre-shared-key with the given size. + * + * @param key Pointer-pointer to the shared key. + * @param bits Key size in bits. + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_PreSharedKey_GetKey(const uint8_t** key, uint16_t bits) +{ + arm_uc_error_t retval = (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + + if (key && (bits == arm_uc_psk_size)) + { + /* set return value */ + retval = (arm_uc_error_t){ ERR_NONE }; + + /* assign PSK pointer */ + *key = arm_uc_psk_key; + } + + return retval; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/update-client-control-center/arm_uc_certificate.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/update-client-control-center/arm_uc_certificate.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,82 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_CERTIFICATES_H +#define ARM_UPDATE_CERTIFICATES_H + +#include "update-client-common/arm_uc_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Add certificate. + * @details [long description] + * + * @param certificate Pointer to certiface being added. + * @param certificate_length Certificate length. + * @param fingerprint Pointer to the fingerprint of the certificate being added. + * @param fingerprint_length Fingerprint length. + * @return Error code. + */ + arm_uc_error_t ARM_UC_Certificate_Add(const uint8_t* certificate, + uint16_t certificate_size, + const uint8_t* fingerprint, + uint16_t fingerprint_size, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*)); + +typedef arm_uc_error_t (* arm_uc_certificateStorer)(const arm_uc_buffer_t* certificate, + const arm_uc_buffer_t* fingerprint, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*)); + +/** + * @brief Fetch a certificate by fingerprint + * @details This API is registered with the hub by the application. The application must handle any required certificate + * chain validation. The API for parsing a certificate chain will be provided by the manifest manager, but the API + * is TBD, so the DERCertificateList should be ignored for now. + * + * @param[out] certificates A pointer to the buffer to populate with the certificate. The buffer's ptr should be updated + * to point to the certificate. + * @param[in] fingerprint The fingerprint of the certificate + * @param[in] DERCertificateList The encoded list of certificate fingerprint/URL pairs that define the chain of + * certificates used to verify the requested certificate (The requested certificate will + * always be the first in the list) + * @param[in] callback The function to call when the certificate is available + */ +typedef arm_uc_error_t (*arm_uc_certificateFetcher)(arm_uc_buffer_t* certificate, + const arm_uc_buffer_t* fingerprint, + const arm_uc_buffer_t* DERCertificateList, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*, const arm_uc_buffer_t*)); + + +struct arm_uc_certificate_api { + arm_uc_certificateFetcher fetch; + arm_uc_certificateStorer store; +}; + +arm_uc_error_t ARM_UC_certificateFetch(arm_uc_buffer_t* certificate, + const arm_uc_buffer_t* fingerprint, + const arm_uc_buffer_t* DERCertificateList, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*, const arm_uc_buffer_t*)); + +#ifdef __cplusplus +}; +#endif + +#endif // ARM_UPDATE_CERTIFICATES_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/update-client-control-center/arm_uc_control_center.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/update-client-control-center/arm_uc_control_center.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,228 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_CONTROL_CENTER_H +#define ARM_UPDATE_CONTROL_CENTER_H + +#include "update-client-monitor/arm_uc_monitor.h" +#include "update-client-common/arm_uc_common.h" + +#include <stdint.h> + +typedef enum { + ARM_UCCC_EVENT_AUTHORIZE_DOWNLOAD, + ARM_UCCC_EVENT_AUTHORIZE_INSTALL, + ARM_UCCC_EVENT_MONITOR_SEND_DONE, +} arm_uc_contro_center_event_t; + +/** + * @brief Initialize Control Center. + * + * @param callback Event handler to signal authorizations. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_Initialize(void (*callback)(uint32_t)); + +/** + * @brief Add monitor struct for sending status and results remotely. + * @details Update Client call for adding remote monitor. + * + * @param monitor Pointer to an ARM_UPDATE_MONITOR struct. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_AddMonitor(const ARM_UPDATE_MONITOR* monitor); + +/** + * @brief Set callback for receiving download progress. + * @details User application call for setting callback handler. + * The callback function takes the progreess in percent as argument. + * + * @param callback Function pointer to the progress function. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_SetProgressHandler(void (*callback)(uint32_t progress, uint32_t total)); + +/** + * @brief Set callback function for authorizing requests. + * @details User application call for setting callback handler. + * The callback function takes an enum request and an authorization + * function pointer. To authorize the given request, the caller + * invokes the authorization function. + * + * @param callback Function pointer to the authorization function. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_SetAuthorityHandler(void (*callback)(int32_t)); + +/** + * @brief Request authorization from Control Center. + * @details Update Client call for asking user application for permission. + * + * @param type Request type. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_GetAuthorization(arm_uc_request_t request); + +/** + * @brief Authorize request. + * @details User application call for authorizing request. + * + * @param request Request type. Must match the type in callback function. + */ +arm_uc_error_t ARM_UC_ControlCenter_Authorize(arm_uc_request_t request); + +/** + * @brief Override update authorization handler. + * @details Force download and update to progress regardless of authorization + * handler. This function is used for unblocking an update in a buggy + * application. + */ +void ARM_UC_ControlCenter_OverrideAuthorization(void); + +/** + * @brief Report download progress. + * @details Update Client call for informing the Control Center about the + * current download progress. The Control Center will send this to the + * appication handler and the monitor if either/both are attached. + * + * @param progress Bytes already downloaded. + * @param total Total bytes in download. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportProgress(uint32_t progress, uint32_t total); + +/** + * @brief Send Update Client state. + * @details Update Client call for informing the Control Center about the + * current state. The Control Center will send this to the monitor. + * + * From the OMA LWM2M Technical Specification: + * + * Indicates current state with respect to this firmware update. + * This value is set by the LWM2M Client. + * 0: Idle (before downloading or after successful updating) + * 1: Downloading (The data sequence is on the way) + * 2: Downloaded + * 3: Updating + * + * If writing the firmware package to Package Resource is done, + * or, if the device has downloaded the firmware package from the + * Package URI the state changes to Downloaded. + * + * If writing an empty string to Package Resource is done or + * writing an empty string to Package URI is done, the state + * changes to Idle. + * + * When in Downloaded state, and the executable Resource Update is + * triggered, the state changes to Updating. + * If the Update Resource failed, the state returns at Downloaded. + * If performing the Update Resource was successful, the state + * changes from Updating to Idle. + * + * @param state Valid states: ARM_UC_MONITOR_STATE_IDLE + * ARM_UC_MONITOR_STATE_DOWNLOADING + * ARM_UC_MONITOR_STATE_DOWNLOADED + * ARM_UC_MONITOR_STATE_UPDATING + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportState(arm_uc_monitor_state_t state); + +/** + * @brief Set update result. + * @details Update Client call for informing the Control Center about the + * latest update result. The Control Center will send this to the monitor. + * + * From the OMA LWM2M Technical Specification: + * + * Contains the result of downloading or updating the firmware + * 0: Initial value. Once the updating process is initiated + * (Download /Update), this Resource MUST be reset to Initial + * value. + * 1: Firmware updated successfully, + * 2: Not enough storage for the new firmware package. + * 3. Out of memory during downloading process. + * 4: Connection lost during downloading process. + * 5: CRC check failure for new downloaded package. + * 6: Unsupported package type. + * 7: Invalid URI + * 8: Firmware update failed + * + * This Resource MAY be reported by sending Observe operation. + * + * @param result Valid results: ARM_UC_MONITOR_RESULT_INITIAL + * ARM_UC_MONITOR_RESULT_SUCCESS + * ARM_UC_MONITOR_RESULT_ERROR_STORAGE + * ARM_UC_MONITOR_RESULT_ERROR_MEMORY + * ARM_UC_MONITOR_RESULT_ERROR_CONNECTION + * ARM_UC_MONITOR_RESULT_ERROR_CRC + * ARM_UC_MONITOR_RESULT_ERROR_TYPE + * ARM_UC_MONITOR_RESULT_ERROR_URI + * ARM_UC_MONITOR_RESULT_ERROR_UPDATE + * ARM_UC_MONITOR_RESULT_ERROR_HASH + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportUpdateResult(arm_uc_monitor_result_t updateResult); + +/** + * @brief Set current firmware name. + * @details Update Client call for informing the Control Center about the + * current firmware name. The Control Center will send this to the + * monitor. The firmware name is the SHA256 hash. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportName(arm_uc_buffer_t* name); + +/** + * @brief Set current firmware version. + * @details Update Client call for informing the Control Center about the + * current firmware version. The Control Center will send this to the + * monitor. The firmware version is the manifest timestamp that + * authorized the installation. + * + * @param version Timestamp, 64 bit unsigned integer. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportVersion(uint64_t version); + +/** + * @brief Send bootloader hash to monitor. + * @details The bootloader hash is a hash of the bootloader. This is + * used for tracking the version of the bootloader used. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportBootloaderHash(arm_uc_buffer_t* hash); + +/** + * @brief Send the OEM bootloader hash to monitor. + * @details If the end-user has modified the bootloader the hash of the + * modified bootloader can be set here. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UC_ControlCenter_ReportOEMBootloaderHash(arm_uc_buffer_t* hash); + +#endif // __ARM_UPDATE_CONTROL_CENTER_H__ + +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/update-client-control-center/arm_uc_pre_shared_key.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/control-center/update-client-control-center/arm_uc_pre_shared_key.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,64 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PRE_SHARED_KEY_H +#define ARM_UC_PRE_SHARED_KEY_H + +#include "update-client-common/arm_uc_common.h" + +#include <stdint.h> + +typedef enum { + ARM_UC_PSK_GET_DONE, + ARM_UC_PSK_GET_ERROR +} arm_uc_psk_event_t; + +/** + * @brief Register event handler. + * + * @param callback Event handler to signal result. + * @return Error code. + */ +arm_uc_error_t ARM_UC_PreSharedKey_Initialize(void (*callback)(uint32_t)); + +/** + * @brief Set pointer to pre-shared-key with the given size. + * + * @param key Pointer to pre-shared-key. + * @param bits Key size in bits. + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_PreSharedKey_SetKey(const uint8_t* key, uint16_t bits); + +/** + * @brief Get pointer to pre-shared-key with the given size. + * @details This call will generate an event upon completion because the key + * pointing to might have to be loaded from asynchronous storage. + * + * If the event is ARM_UC_PSK_GET_DONE, key will point to a valid + * pre-shared-key, which memory is handled internally. + * + * @param key Pointer-pointer to the shared key. + * @param bits Key size in bits. + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_PreSharedKey_GetKey(const uint8_t** key, uint16_t bits); + +#endif // ARM_UC_PRE_SHARED_KEY_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1 @@ +TESTS/tests/sanity/* \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/TESTS/tests/sanity/sanity.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/TESTS/tests/sanity/sanity.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,58 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <greentea-client/test_env.h> +#include <utest/utest.h> +#include <unity/unity.h> + +#include "pal4life-device-identity/pal_device_identity.h" + +using namespace utest::v1; + +void print_guid(const arm_uc_guid_t* guid) +{ + for (size_t index = 0; index < sizeof(arm_uc_guid_t); index++) + { + printf("%02X", ((uint8_t*)guid)[index]); + } + printf("\r\n"); +} + +void test_unit() +{ + arm_uc_guid_t guid = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; + + print_guid(&guid); +} + +Case cases[] = { + Case("test_init", test_unit) +}; + +Specification specification(cases, verbose_continue_handlers); + +#if defined(TARGET_LIKE_MBED) +int main() +#elif defined(TARGET_LIKE_POSIX) +void app_start(int argc __unused, char** argv __unused) +#endif +{ + // Run the test specification + Harness::run(specification); +} \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/pal4life-device-identity/pal_device_identity.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/pal4life-device-identity/pal_device_identity.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,154 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef PAL4LIFE_DEVICE_IDENTITY_H +#define PAL4LIFE_DEVICE_IDENTITY_H + +#include "update-client-common/arm_uc_common.h" + +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Function for setting the vendor GUID. + * @details The GUID is copied. + * @param vendor_guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ +arm_uc_error_t pal_setVendorGuid(const arm_uc_guid_t* vendor_guid); + +/** + * @brief Function for getting a pointer to the vendor GUID. + * @param vendor_guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ +arm_uc_error_t pal_getVendorGuid(arm_uc_guid_t* vendor_guid); + +/** + * @brief Function for setting the device class GUID. + * @details The GUID is copied. + * @param class_guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ +arm_uc_error_t pal_setClassGuid(const arm_uc_guid_t* class_guid); + +/** + * @brief Function for getting a pointer to the device class GUID. + * @param class_guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ +arm_uc_error_t pal_getClassGuid(arm_uc_guid_t* class_guid); + +/** + * @brief Function for setting the device GUID. + * @details The GUID is copied. + * @param device_guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ +arm_uc_error_t pal_setDeviceGuid(const arm_uc_guid_t* device_guid); + +/** + * @brief Function for getting a pointer to the device GUID. + * @param device_guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ +arm_uc_error_t pal_getDeviceGuid(arm_uc_guid_t* device_guid); + +/** + * @brief Check whether the three GUIDs provided are valid on the device. + * @details + * @param vendor_guid Buffer pointer to the Vendor GUID. + * @param class_guid Buffer pointer to the device class GUID. + * @param device_guid Buffer pointer to the device GUID. + * @return Error code. + */ +arm_uc_error_t pal_deviceIdentityCheck(const arm_uc_buffer_t* vendor_guid, + const arm_uc_buffer_t* class_guid, + const arm_uc_buffer_t* device_guid); + +/** + * @brief Structure definition holding API function pointers. + */ +typedef struct _ARM_PAL_DEVICE_IDENTITY { + /** + * @brief Function for setting the vendor GUID. + * @details The GUID is copied. + * @param vendor_guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ + arm_uc_error_t (*SetVendorGuid)(const arm_uc_guid_t* vendor_guid); + + /** + * @brief Function for getting a pointer to the vendor GUID. + * @param vendor_guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ + arm_uc_error_t (*GetVendorGuid)(arm_uc_guid_t* vendor_guid); + + /** + * @brief Function for setting the device class GUID. + * @details The GUID is copied. + * @param class_guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ + arm_uc_error_t (*SetClassGuid)(const arm_uc_guid_t* class_guid); + + /** + * @brief Function for getting a pointer to the device class GUID. + * @param class_guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ + arm_uc_error_t (*GetClassGuid)(arm_uc_guid_t* class_guid); + + /** + * @brief Function for setting the device GUID. + * @details The GUID is copied. + * @param device_guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ + arm_uc_error_t (*SetDeviceGuid)(const arm_uc_guid_t* device_guid); + + /** + * @brief Function for getting a pointer to the device GUID. + * @param device_guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ + arm_uc_error_t (*GetDeviceGuid)(arm_uc_guid_t* device_guid); + + /** + * @brief Check whether the three GUIDs provided are valid on the device. + * @details + * @param vendor_guid Buffer pointer to the Vendor GUID. + * @param class_guid Buffer pointer to the device class GUID. + * @param device_guid Buffer pointer to the device GUID. + * @return Error code. + */ + arm_uc_error_t (*DeviceIdentityCheck)(const arm_uc_buffer_t* vendor_guid, + const arm_uc_buffer_t* class_guid, + const arm_uc_buffer_t* device_guid); +} ARM_PAL_DEVICE_IDENTITY; + +#ifdef __cplusplus +} +#endif + +#endif // PAL4LIFE_DEVICE_IDENTITY_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/source/arm_uc_device_identity.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/source/arm_uc_device_identity.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,161 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "pal4life-device-identity/pal_device_identity.h" +#include "update-client-common/arm_uc_config.h" + +#if ARM_UC_USE_KCM +extern const ARM_PAL_DEVICE_IDENTITY arm_uc_device_identity_kcm; +static const ARM_PAL_DEVICE_IDENTITY* arm_uc_device_identity = + &arm_uc_device_identity_kcm; +#elif ARM_UC_USE_CFSTORE +extern const ARM_PAL_DEVICE_IDENTITY arm_uc_device_identity_cfstore; +static const ARM_PAL_DEVICE_IDENTITY* arm_uc_device_identity = + &arm_uc_device_identity_cfstore; +#else +#error No configuration store set +#endif + +/** + * @brief Function for setting the vendor GUID. + * @details The GUID is copied. + * @param vendor_guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ +arm_uc_error_t pal_setVendorGuid(const arm_uc_guid_t* vendor_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (arm_uc_device_identity) + { + result = arm_uc_device_identity->SetVendorGuid(vendor_guid); + } + + return result; +} + +/** + * @brief Function for getting a pointer to the vendor GUID. + * @param vendor_guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ +arm_uc_error_t pal_getVendorGuid(arm_uc_guid_t* vendor_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (arm_uc_device_identity) + { + result = arm_uc_device_identity->GetVendorGuid(vendor_guid); + } + + return result; +} + +/** + * @brief Function for setting the device class GUID. + * @details The GUID is copied. + * @param class_guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ +arm_uc_error_t pal_setClassGuid(const arm_uc_guid_t* class_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (arm_uc_device_identity) + { + result = arm_uc_device_identity->SetClassGuid(class_guid); + } + + return result; +} + +/** + * @brief Function for getting a pointer to the device class GUID. + * @param class_guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ +arm_uc_error_t pal_getClassGuid(arm_uc_guid_t* class_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (arm_uc_device_identity) + { + result = arm_uc_device_identity->GetClassGuid(class_guid); + } + + return result; +} + +/** + * @brief Function for setting the device GUID. + * @details The GUID is copied. + * @param device_guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ +arm_uc_error_t pal_setDeviceGuid(const arm_uc_guid_t* device_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (arm_uc_device_identity) + { + result = arm_uc_device_identity->SetDeviceGuid(device_guid); + } + + return result; +} + +/** + * @brief Function for getting a pointer to the device GUID. + * @param device_guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ +arm_uc_error_t pal_getDeviceGuid(arm_uc_guid_t* device_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (arm_uc_device_identity) + { + result = arm_uc_device_identity->GetDeviceGuid(device_guid); + } + + return result; +} + +/** + * @brief Check whether the three GUIDs provided are valid on the device. + * @details + * @param vendor_guid Buffer pointer to the Vendor GUID. + * @param class_guid Buffer pointer to the device class GUID. + * @param device_guid Buffer pointer to the device GUID. + * @return Error code. + */ +arm_uc_error_t pal_deviceIdentityCheck(const arm_uc_buffer_t* vendor_guid, + const arm_uc_buffer_t* class_guid, + const arm_uc_buffer_t* device_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (arm_uc_device_identity) + { + result = arm_uc_device_identity->DeviceIdentityCheck(vendor_guid, + class_guid, + device_guid); + } + + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/source/arm_uc_device_identity_cfstore.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/source/arm_uc_device_identity_cfstore.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,286 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "pal4life-device-identity/pal_device_identity.h" +#include "update-client-common/arm_uc_config.h" + +#ifndef ARM_UC_USE_CFSTORE +#define ARM_UC_USE_CFSTORE 0 +#endif + +#if ARM_UC_USE_CFSTORE + +#include <string.h> + +static arm_uc_guid_t arm_uc_vendor_guid = {0}; +static int arm_uc_vendor_guid_set = 0; +static arm_uc_guid_t arm_uc_class_guid = {0}; +static int arm_uc_class_guid_set = 0; +static arm_uc_guid_t arm_uc_device_guid = {0}; +static int arm_uc_device_guid_set = 0; + +/** + * @brief Function for setting the vendor GUID. + * @details The GUID is copied. + * @param guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ +arm_uc_error_t pal_cfstore_setVendorGuid(const arm_uc_guid_t* vendor_guid) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + if (vendor_guid) + { + memcpy(&arm_uc_vendor_guid, vendor_guid, sizeof(arm_uc_guid_t)); + arm_uc_vendor_guid_set = 1; + } + else + { + memset(&arm_uc_vendor_guid, 0, sizeof(arm_uc_guid_t)); + arm_uc_vendor_guid_set = 0; + } + return result; +} + +/** + * @brief Function for getting a pointer to the vendor GUID. + * @param guid Pointer to a arm_uc_guid_t. + * @return Error code. + */ +arm_uc_error_t pal_cfstore_getVendorGuid(arm_uc_guid_t* vendor_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (vendor_guid && arm_uc_vendor_guid_set) + { + result.code = ERR_NONE; + memcpy(vendor_guid, &arm_uc_vendor_guid, sizeof(arm_uc_guid_t)); + } + + return result; +} + +/** + * @brief Function for setting the device class GUID. + * @details The GUID is copied/ + * @param guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ +arm_uc_error_t pal_cfstore_setClassGuid(const arm_uc_guid_t* class_guid) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + if (class_guid) + { + memcpy(&arm_uc_class_guid, class_guid, sizeof(arm_uc_guid_t)); + arm_uc_class_guid_set = 1; + } + else + { + memset(&arm_uc_class_guid, 0, sizeof(arm_uc_guid_t)); + arm_uc_class_guid_set = 0; + } + return result; +} + +/** + * @brief Function for getting a pointer to the device class GUID. + * @param guid Pointer to a arm_uc_guid_t. + * @return Error code. + */ +arm_uc_error_t pal_cfstore_getClassGuid(arm_uc_guid_t* class_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (class_guid && arm_uc_class_guid_set) + { + result.code = ERR_NONE; + memcpy(class_guid, &arm_uc_class_guid, sizeof(arm_uc_guid_t)); + } + + return result; +} + +/** + * @brief Function for setting the device GUID. + * @details The GUID is copied. + * @param guid Pointer to a arm_uc_guid_t GUID. + * @return Error code. + */ +arm_uc_error_t pal_cfstore_setDeviceGuid(const arm_uc_guid_t* device_guid) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + if (device_guid) + { + memcpy(&arm_uc_device_guid, device_guid, sizeof(arm_uc_guid_t)); + arm_uc_device_guid_set = 1; + } + else + { + memset(&arm_uc_device_guid, 0, sizeof(arm_uc_guid_t)); + arm_uc_device_guid_set = 0; + } + return result; +} + +/** + * @brief Function for getting a pointer to the device GUID. + * @param guid Pointer to a arm_uc_guid_t. + * @return Error code. + */ +arm_uc_error_t pal_cfstore_getDeviceGuid(arm_uc_guid_t* device_guid) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (device_guid && arm_uc_device_guid_set) + { + result.code = ERR_NONE; + memcpy(device_guid, &arm_uc_device_guid, sizeof(arm_uc_guid_t)); + } + + return result; +} + +static bool pal_cfstore_internal_compare(const arm_uc_guid_t* guid, + const arm_uc_buffer_t* buffer) +{ + // count how many bytes match + uint8_t index = 0; + + if (guid && buffer) + { + for ( ; (index < sizeof(arm_uc_guid_t)) && (index < buffer->size); index++) + { + if (((const uint8_t*) guid)[index] != buffer->ptr[index]) + { + break; + } + } + } + + // return true if all bytes matched + return (index == sizeof(arm_uc_guid_t)); +} + +/** + * @brief Check whether the three GUIDs provided are valid on the device. + * @details + * @param vendor_buffer Buffer pointer to the Vendor GUID. + * @param class_buffer Buffer pointer to the device class GUID. + * @param device_buffer Buffer pointer to the device GUID. + * @param isValid Pointer to the boolean return value. + * @return Error code. + */ +arm_uc_error_t pal_cfstore_deviceIdentityCheck(const arm_uc_buffer_t* vendor_buffer, + const arm_uc_buffer_t* class_buffer, + const arm_uc_buffer_t* device_buffer) +{ + arm_uc_error_t result = { .code = MFST_ERR_NULL_PTR }; + + uint8_t parameters_set = 0; + uint8_t parameters_ok = 0; + + /* check device - device is optional */ + if (arm_uc_device_guid_set) + { + if (device_buffer && device_buffer->ptr) + { + bool is_same = pal_cfstore_internal_compare(&arm_uc_device_guid, + device_buffer); + + if (is_same) + { + parameters_ok++; + } + else + { + result.code = MFST_ERR_GUID_DEVICE; + } + + parameters_set++; + } + } + + /* check class - class is optional */ + if (arm_uc_class_guid_set) + { + if (class_buffer && class_buffer->ptr) + { + bool is_same = pal_cfstore_internal_compare(&arm_uc_class_guid, + class_buffer); + + if (is_same) + { + parameters_ok++; + } + else + { + result.code = MFST_ERR_GUID_DEVCLASS; + } + + parameters_set++; + } + } + + /* check vendor - vendor is mandatory and has mask 0x10. */ + if (arm_uc_vendor_guid_set) + { + if (vendor_buffer && vendor_buffer->ptr) + { + bool is_same = pal_cfstore_internal_compare(&arm_uc_vendor_guid, + vendor_buffer); + + if (is_same) + { + parameters_ok += 0x10; + } + else + { + result.code = MFST_ERR_GUID_VENDOR; + } + + parameters_set += 0x10; + } + } + + /* Device ID checks out when: + - vendor match and neither class nor device is passed + - vendor and class match and no device is passed + - vendor and device match and no class is passed + - vendor and class and device match + */ + if ((parameters_set >= 0x10) && (parameters_set == parameters_ok)) + { + result.code = MFST_ERR_NONE; + } + + return result; +} + +const ARM_PAL_DEVICE_IDENTITY arm_uc_device_identity_cfstore = { + .SetVendorGuid = pal_cfstore_setVendorGuid, + .GetVendorGuid = pal_cfstore_getVendorGuid, + .SetClassGuid = pal_cfstore_setClassGuid, + .GetClassGuid = pal_cfstore_getClassGuid, + .SetDeviceGuid = pal_cfstore_setDeviceGuid, + .GetDeviceGuid = pal_cfstore_getDeviceGuid, + .DeviceIdentityCheck = pal_cfstore_deviceIdentityCheck +}; + +#endif // ARM_UC_USE_CFSTORE
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/source/arm_uc_device_identity_kcm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/device-identity/source/arm_uc_device_identity_kcm.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,341 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "pal4life-device-identity/pal_device_identity.h" +#include "update-client-common/arm_uc_config.h" +#include <stdint.h> + +#ifndef ARM_UC_USE_KCM +#define ARM_UC_USE_KCM 0 +#endif + +#if ARM_UC_USE_KCM + +#include "key-config-manager/key_config_manager.h" + +#define SIZE_OF_GUID (sizeof(arm_uc_guid_t)) +// Hex encoded GUIDs with up to 4 hyphens. +#define SIZE_OF_TEXT_GUID ((SIZE_OF_GUID) * 2 + 4) + +/* these defines are copied from: + mbed-cloud-client/source/include/CloudClientStorage.h +*/ +#define KEY_DEVICE_MANUFACTURER_DEPRECATED "mbed.Manufacturer" +#define KEY_DEVICE_MODELNUMBER_DEPRECATED "mbed.ModelNumber" +#define KEY_ENDPOINT_NAME "mbed.EndpointName" +#define KEY_VENDOR_ID "mbed.VendorId" +#define KEY_CLASS_ID "mbed.ClassId" + +static arm_uc_error_t pal_kcm_internal_set_guid(const arm_uc_guid_t* guid, + const char* key, + size_t key_length) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (guid && key) + { + kcm_status_e kcm_status = kcm_item_store((const uint8_t*) key, + key_length, + KCM_CONFIG_ITEM, + true, + (const uint8_t*) guid, + SIZE_OF_GUID, + NULL); + + if (kcm_status == KCM_STATUS_SUCCESS) + { + result.code = ERR_NONE; + } + } + + return result; +} + +static arm_uc_error_t pal_kcm_internal_get_guid(arm_uc_guid_t* guid, + const char* key, + size_t key_length) +{ + arm_uc_error_t result = { .module = TWO_CC('D', 'I'), .error = ERR_INVALID_PARAMETER }; + + if (guid && key) + { + uint8_t buffer[SIZE_OF_GUID] = { 0 }; + size_t value_length = 0; + memset(guid, 0, SIZE_OF_GUID); + + kcm_status_e kcm_status = kcm_item_get_data((const uint8_t*) key, + key_length, + KCM_CONFIG_ITEM, + buffer, + SIZE_OF_GUID, + &value_length); + if (kcm_status == KCM_STATUS_ITEM_NOT_FOUND) + { + result.code = ARM_UC_DI_ERR_NOT_FOUND; + } + + if (kcm_status == KCM_STATUS_SUCCESS) + { + result.code = ERR_NONE; + memcpy(guid, buffer, SIZE_OF_GUID); + } + } + + return result; +} + +static bool pal_kcm_internal_compare(const arm_uc_guid_t* guid, + const arm_uc_buffer_t* buffer) +{ + // count how many bytes match + uint8_t index = 0; + + if (guid && buffer) + { + for ( ; (index < sizeof(arm_uc_guid_t)) && (index < buffer->size); index++) + { + // printf("%02X %02X\r\n", ((uint8_t*) guid)[index], buffer->ptr[index]); + + if (((uint8_t*) guid)[index] != buffer->ptr[index]) + { + break; + } + } + } + + // return true if all bytes matched + return (index == sizeof(arm_uc_guid_t)); +} + +/** + * @brief Function for setting the vendor GUID. + * @details The GUID is copied. + * @param guid Pointer to a arm_uc_guid_t GUID. + * @param copy Boolean value indicating whether the value should be copied or + * referenced. + * @return Error code. + */ +arm_uc_error_t pal_kcm_setVendorGuid(const arm_uc_guid_t* guid) +{ + return pal_kcm_internal_set_guid(guid, + KEY_VENDOR_ID, + sizeof(KEY_VENDOR_ID) - 1); +} + +/** + * @brief Function for getting a pointer to the vendor GUID. + * @param guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ +arm_uc_error_t pal_kcm_getVendorGuid(arm_uc_guid_t* guid) +{ + arm_uc_error_t err = pal_kcm_internal_get_guid(guid, + KEY_VENDOR_ID, + sizeof(KEY_VENDOR_ID) - 1); + if (err.code == ARM_UC_DI_ERR_NOT_FOUND) + { + err = pal_kcm_internal_get_guid(guid, + KEY_DEVICE_MANUFACTURER_DEPRECATED, + sizeof(KEY_DEVICE_MANUFACTURER_DEPRECATED) - 1); + } + return err; +} + +/** + * @brief Function for setting the device class GUID. + * @details The GUID is copied. + * @param guid Pointer to a arm_uc_guid_t GUID. + * @param copy Boolean value indicating whether the value should be copied or + * referenced. + * @return Error code. + */ +arm_uc_error_t pal_kcm_setClassGuid(const arm_uc_guid_t* guid) +{ + return pal_kcm_internal_set_guid(guid, + KEY_CLASS_ID, + sizeof(KEY_CLASS_ID) - 1); +} + +/** + * @brief Function for getting a pointer to the device class GUID. + * @param guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ +arm_uc_error_t pal_kcm_getClassGuid(arm_uc_guid_t* guid) +{ + arm_uc_error_t err = pal_kcm_internal_get_guid(guid, + KEY_CLASS_ID, + sizeof(KEY_CLASS_ID) - 1); + if (err.code == ARM_UC_DI_ERR_NOT_FOUND) + { + err = pal_kcm_internal_get_guid(guid, + KEY_DEVICE_MODELNUMBER_DEPRECATED, + sizeof(KEY_DEVICE_MODELNUMBER_DEPRECATED) - 1); + } + return err; +} + +/** + * @brief Function for setting the device GUID. + * @details The GUID is copied. + * @param guid Pointer to a arm_uc_guid_t GUID. + * @param copy Boolean value indicating whether the value should be copied or + * referenced. + * @return Error code. + */ +arm_uc_error_t pal_kcm_setDeviceGuid(const arm_uc_guid_t* guid) +{ + return pal_kcm_internal_set_guid(guid, + KEY_ENDPOINT_NAME, + sizeof(KEY_ENDPOINT_NAME) - 1); +} + +/** + * @brief Function for getting a pointer to the device GUID. + * @param guid Pointer to a arm_uc_guid_t pointer. + * @return Error code. + */ +arm_uc_error_t pal_kcm_getDeviceGuid(arm_uc_guid_t* guid) +{ + return pal_kcm_internal_get_guid(guid, + KEY_ENDPOINT_NAME, + sizeof(KEY_ENDPOINT_NAME) - 1); +} + + +/** + * @brief Check whether the three GUIDs provided are valid on the device. + * @details + * @param vendor_buffer Buffer pointer to the Vendor GUID. + * @param class_buffer Buffer pointer to the device class GUID. + * @param device_buffer Buffer pointer to the device GUID. + * @param isValid Pointer to the boolean return value. + * @return Error code. + */ +arm_uc_error_t pal_kcm_deviceIdentityCheck(const arm_uc_buffer_t* vendor_buffer, + const arm_uc_buffer_t* class_buffer, + const arm_uc_buffer_t* device_buffer) +{ + arm_uc_error_t result = { .code = MFST_ERR_NULL_PTR }; + + uint8_t parameters_set = 0; + uint8_t parameters_ok = 0; + + /* check device - device is optional */ + if (device_buffer && + device_buffer->ptr && + (device_buffer->size > 0)) + { + parameters_set++; + + arm_uc_guid_t guid = { 0 }; + + arm_uc_error_t retval = pal_kcm_getDeviceGuid(&guid); + + if (retval.code == ERR_NONE) + { + bool is_same = pal_kcm_internal_compare(&guid, device_buffer); + + if (is_same) + { + parameters_ok++; + } + else + { + result.code = MFST_ERR_GUID_DEVICE; + } + } + } + + /* check class - class is optional */ + if (class_buffer && + class_buffer->ptr && + (class_buffer->size > 0)) + { + parameters_set++; + + arm_uc_guid_t guid = { 0 }; + + arm_uc_error_t retval = pal_kcm_getClassGuid(&guid); + + if (retval.code == ERR_NONE) + { + bool is_same = pal_kcm_internal_compare(&guid, class_buffer); + + if (is_same) + { + parameters_ok++; + } + else + { + result.code = MFST_ERR_GUID_DEVCLASS; + } + } + } + + /* check vendor - vendor is mandatory and has mask 0x10. */ + if (vendor_buffer && + vendor_buffer->ptr && + (vendor_buffer->size > 0)) + { + parameters_set += 0x10; + + arm_uc_guid_t guid = { 0 }; + + arm_uc_error_t retval = pal_kcm_getVendorGuid(&guid); + + if (retval.code == ERR_NONE) + { + bool is_same = pal_kcm_internal_compare(&guid, vendor_buffer); + + if (is_same) + { + parameters_ok += 0x10; + } + else + { + result.code = MFST_ERR_GUID_VENDOR; + } + } + } + + /* Device ID checks out when: + - vendor match and neither class nor device is passed + - vendor and class match and no device is passed + - vendor and device match and no class is passed + - vendor and class and device match + */ + if ((parameters_set >= 0x10) && (parameters_set == parameters_ok)) + { + result.code = MFST_ERR_NONE; + } + + return result; +} + +const ARM_PAL_DEVICE_IDENTITY arm_uc_device_identity_kcm = { + .SetVendorGuid = pal_kcm_setVendorGuid, + .GetVendorGuid = pal_kcm_getVendorGuid, + .SetClassGuid = pal_kcm_setClassGuid, + .GetClassGuid = pal_kcm_getClassGuid, + .SetDeviceGuid = pal_kcm_setDeviceGuid, + .GetDeviceGuid = pal_kcm_getDeviceGuid, + .DeviceIdentityCheck = pal_kcm_deviceIdentityCheck +}; + +#endif // ARM_UC_USE_KCM
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +*/test/* +test/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/source/arm_uc_firmware_manager.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/source/arm_uc_firmware_manager.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,631 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-firmware-manager/arm_uc_firmware_manager.h" +#include "update-client-common/arm_uc_common.h" + +#include "update-client-paal/arm_uc_paal_update.h" + +#include <stdio.h> +#include <stdbool.h> + +#include "pal.h" + +static ARM_UCFM_SignalEvent_t ucfm_handler = NULL; + +static ARM_UCFM_Setup_t* package_configuration = NULL; +static uint32_t package_offset = 0; +static bool ready_to_receive = false; + +static arm_uc_callback_t arm_uc_event_handler_callback = { 0 }; + +static arm_uc_mdHandle_t mdHandle = { 0 }; +static arm_uc_cipherHandle_t cipherHandle = { 0 }; +static arm_uc_buffer_t* front_buffer = NULL; +static arm_uc_buffer_t* back_buffer = NULL; + +#define UCFM_DEBUG_OUTPUT 0 + +typedef enum { + UCFM_STATE_IDLE, + UCFM_STATE_FINISH, + UCFM_STATE_GET_STORED_HASH, + UCFM_STATE_GET_ACTIVE_HASH, + UCFM_STATE_GET_ACTIVE_VERSION +} ucfm_state_t; + +static ucfm_state_t ucfm_state; + +static void arm_uc_signal_ucfm_handler(uint32_t event); + +/******************************************************************************/ +/* Debug output functions for writing formatted output */ +/******************************************************************************/ + +#if UCFM_DEBUG_OUTPUT + +static void debug_output_decryption(const uint8_t* encrypted, + arm_uc_buffer_t* decrypted) +{ + for (size_t index = 0; index < UCFM_MAX_BLOCK_SIZE; index++) + { + if (index < decrypted->size) + { + uint8_t symbol = encrypted[index]; + + printf("%02X", symbol); + } + else + { + printf(" "); + } + } + + printf("\t:\t"); + + for (size_t index = 0; index < UCFM_MAX_BLOCK_SIZE; index++) + { + if (index < decrypted->size) + { + uint8_t symbol = encrypted[index]; + + if ((symbol > 32) && (symbol < 127)) + { + printf("%c", symbol); + } + else + { + printf(" "); + } + } + else + { + printf(" "); + } + } + + printf("\t:\t"); + + for (size_t index = 0; index < decrypted->size_max; index++) + { + if (index < decrypted->size) + { + uint8_t symbol = decrypted->ptr[index]; + + if ((symbol > 32) && (symbol < 127)) + { + printf("%c", symbol); + } + else + { + printf(" "); + } + } + else + { + printf(" "); + } + } + + printf("\r\n"); +} + +static void debug_output_validation(arm_uc_buffer_t* hash, + arm_uc_buffer_t* output_buffer) +{ + printf("\r\n"); + printf("expected hash : "); + for (size_t index = 0; index < hash->size; index++) + { + printf("%02X", hash->ptr[index]); + } + printf("\r\n"); + + printf("calculated hash: "); + for (size_t index = 0; index < output_buffer->size; index++) + { + printf("%02X", output_buffer->ptr[index]); + } + printf("\r\n"); + printf("\r\n"); +} + +#endif + +/******************************************************************************/ + +/* Hash calculation is performed using the output buffer. This function fills + the output buffer with data from the PAL. +*/ +static void arm_uc_internal_process_hash(void) +{ + bool double_buffering = (front_buffer != back_buffer); + bool needs_more_data = (package_offset < package_configuration->package_size); + arm_uc_error_t status = { .code = ERR_NONE }; + uint32_t error_event = UCFM_EVENT_FINALIZE_ERROR; + + if (double_buffering && needs_more_data) + { +#if UCFM_DEBUG_OUTPUT + printf("double buffering: %p %" PRIX32 "\r\n", back_buffer, back_buffer->size_max); +#endif + + /* if using double buffering, initiate a new data read as soon as possible */ + /* reset buffer */ + back_buffer->size = 0; + + /* initiate read from PAL */ + status = ARM_UCP_Read(package_configuration->package_id, + package_offset, + back_buffer); + } + + if (status.error == ERR_NONE) + { + /* process data in front buffer */ + ARM_UC_cryptoHashUpdate(&mdHandle, front_buffer); + + if (needs_more_data) + { + /* if we're actually using two buffers, the read operation was initiated earlier, + * otherwise it needs to be initiated now, after we're done hashing the only + * buffer that we're using + */ + if (!double_buffering) + { +#if UCFM_DEBUG_OUTPUT + printf("single buffering: %p\r\n", front_buffer); +#endif + + /* reset buffer */ + back_buffer->size = 0; + + /* initiate read from PAL */ + status = ARM_UCP_Read(package_configuration->package_id, + package_offset, + back_buffer); + } + } + else + { + /* invert status code so that it has to be set explicitly for success */ + status.code = ERR_INVALID_PARAMETER; + + /* finalize hash calculation */ + uint8_t hash_output_ptr[2 * UCFM_MAX_BLOCK_SIZE]; + arm_uc_buffer_t hash_buffer = { + .size_max = sizeof(hash_output_ptr), + .size = 0, + .ptr = hash_output_ptr + }; + + ARM_UC_cryptoHashFinish(&mdHandle, &hash_buffer); + + /* size check before memcmp call */ + if (hash_buffer.size == package_configuration->hash->size) + { + int diff = memcmp(hash_buffer.ptr, + package_configuration->hash->ptr, + package_configuration->hash->size); + +#if UCFM_DEBUG_OUTPUT + debug_output_validation(package_configuration->hash, + &hash_buffer); +#endif + + /* hash matches */ + if (diff == 0) + { + UC_FIRM_TRACE("UCFM_EVENT_FINALIZE_DONE"); + + arm_uc_signal_ucfm_handler(UCFM_EVENT_FINALIZE_DONE); + status.code = ERR_NONE; + } + else + { + /* use specific event for "invalid hash" */ + UC_FIRM_ERR_MSG("Invalid image hash"); + + error_event = UCFM_EVENT_FINALIZE_INVALID_HASH_ERROR; + } + } + } + + /* Front buffer is processed, back buffer might be reading more data. + Swap buffer so that data will be ready in front buffer + */ + arm_uc_buffer_t* temp = front_buffer; + front_buffer = back_buffer; + back_buffer = temp; + } + + /* signal error if status is not clean */ + if (status.error != ERR_NONE) + { + UC_FIRM_TRACE("UCFM_EVENT_FINALIZE_ERROR"); + arm_uc_signal_ucfm_handler(error_event); + } +} + +/******************************************************************************/ + +/* Function for decoupling PAL callbacks using the internal task queue. */ +/* Write commit done */ +static void event_handler_finalize(void) +{ + UC_FIRM_TRACE("event_handler_finalize"); + + /* setup mandatory hash */ + arm_uc_mdType_t mdtype = ARM_UC_CU_SHA256; + arm_uc_error_t result = ARM_UC_cryptoHashSetup(&mdHandle, mdtype); + + if (result.error == ERR_NONE) + { + /* initiate hash calculation */ + package_offset = 0; + + /* initiate read from PAL */ + result = ARM_UCP_Read(package_configuration->package_id, + package_offset, + front_buffer); + } + + if (result.error != ERR_NONE) + { + UC_FIRM_ERR_MSG("ARM_UC_cryptoHashSetup failed"); + arm_uc_signal_ucfm_handler(UCFM_EVENT_FINALIZE_ERROR); + } +} + +/* Function for decoupling PAL callbacks using the internal task queue. */ +static void event_handler_read(void) +{ +#if UCFM_DEBUG_OUTPUT + printf("event_handler_read: %" PRIX32 "\r\n", front_buffer->size); +#endif + + /* check that read succeeded in reading data into buffer */ + if (front_buffer->size > 0) + { + /* check if read over shot */ + if ((package_offset + front_buffer->size) > + package_configuration->package_size) + { + /* trim buffer */ + front_buffer->size = package_configuration->package_size - package_offset; + } + + /* update offset and continue reading data from PAL */ + package_offset += front_buffer->size; + arm_uc_internal_process_hash(); + } + else + { + /* error - no data processed */ + UC_FIRM_TRACE("UCFM_EVENT_FINALIZE_ERROR"); + arm_uc_signal_ucfm_handler(UCFM_EVENT_FINALIZE_ERROR); + } +} + +static void arm_uc_signal_ucfm_handler(uint32_t event) +{ + if (ucfm_handler) + { + ucfm_handler(event); + } +} + +static void arm_uc_internal_event_handler(uint32_t event) +{ + switch (event) + { + case ARM_UC_PAAL_EVENT_FINALIZE_DONE: + event_handler_finalize(); + break; + case ARM_UC_PAAL_EVENT_READ_DONE: + event_handler_read(); + break; + default: + /* pass all other events directly */ + arm_uc_signal_ucfm_handler(event); + break; + } +} + +static void ARM_UCFM_PALEventHandler(uint32_t event) +{ + /* decouple event handler from callback */ + ARM_UC_PostCallback(&arm_uc_event_handler_callback, + arm_uc_internal_event_handler, event); +} + +/******************************************************************************/ +static arm_uc_error_t ARM_UCFM_Initialize(ARM_UCFM_SignalEvent_t handler) +{ + UC_FIRM_TRACE("ARM_UCFM_Initialize"); + + arm_uc_error_t result = (arm_uc_error_t){ FIRM_ERR_INVALID_PARAMETER }; + + if (handler) + { + result = ARM_UCP_Initialize(ARM_UCFM_PALEventHandler); + + if (result.error == ERR_NONE) + { + ucfm_handler = handler; + } + } + + return result; +} + +static arm_uc_error_t ARM_UCFM_Prepare(ARM_UCFM_Setup_t* configuration, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer) +{ + UC_FIRM_TRACE("ARM_UCFM_Setup"); + + arm_uc_error_t result = (arm_uc_error_t){ FIRM_ERR_NONE }; + + /* sanity checks */ + if (!ucfm_handler) + { + UC_FIRM_ERR_MSG("Event handler not set. Should call Initialise before calling Setup"); + result = (arm_uc_error_t){ FIRM_ERR_UNINITIALIZED }; + } + /* check configuration is defined and contains key and iv. */ + else if ((!(configuration && + ((configuration->mode == UCFM_MODE_NONE_SHA_256) || + (configuration->key && configuration->iv)))) || + !buffer || + !buffer->ptr) + { + result = (arm_uc_error_t){ FIRM_ERR_INVALID_PARAMETER }; + } + + /* allocate space using PAL */ + if (result.error == ERR_NONE) + { + result = ARM_UCP_Prepare(configuration->package_id, + details, + buffer); + + if (result.error != ERR_NONE) + { + UC_FIRM_ERR_MSG("ARM_UCP_Prepare failed"); + } + } + + /* setup encryption if requested by mode */ + if ((result.error == ERR_NONE) && + (configuration->mode != UCFM_MODE_NONE_SHA_256)) + { + /* A previously aborted firmware write will have left the cipherHandler + in an inconsistent state. If the IV is not NULL, clear the context + using the call to finish and set the struct to zero. + */ + if (cipherHandle.aes_iv != NULL) + { + ARM_UC_cryptoDecryptFinish(&cipherHandle, buffer); + memset(&cipherHandle, 0, sizeof(arm_uc_cipherHandle_t)); + } + + /* setup cipherHanlde with decryption keys */ + uint32_t bits = (configuration->mode == UCFM_MODE_AES_CTR_128_SHA_256) ? 128 : 256; + result = ARM_UC_cryptoDecryptSetup(&cipherHandle, + configuration->key, + configuration->iv, + bits); + + if (result.error != ERR_NONE) + { + UC_FIRM_ERR_MSG("ARM_UC_cryptoDecryptSetup failed in %" PRIu32 " bit mode", bits); + } + } + + /* Initialise the internal state */ + if (result.error == ERR_NONE) + { + package_configuration = configuration; + package_offset = 0; + ready_to_receive = true; + } + + return result; +} + +static arm_uc_error_t ARM_UCFM_Write(const arm_uc_buffer_t* fragment) +{ + UC_FIRM_TRACE("ARM_UCFM_Write"); + + arm_uc_error_t result = (arm_uc_error_t){ FIRM_ERR_NONE }; + + if (!fragment || fragment->size_max == 0 || fragment->size > fragment->size_max || !fragment->ptr) + { + result = (arm_uc_error_t){ FIRM_ERR_INVALID_PARAMETER }; + } + else if (!ready_to_receive) + { + result = (arm_uc_error_t){ FIRM_ERR_UNINITIALIZED }; + } + else + { + /* decrypt fragment before writing to PAL */ + if (package_configuration->mode != UCFM_MODE_NONE_SHA_256) + { + /* temporary buffer for decrypting in place */ + uint8_t decrypt_output_ptr[2 * UCFM_MAX_BLOCK_SIZE]; + arm_uc_buffer_t decrypt_buffer = { + .size_max = sizeof(decrypt_output_ptr), + .size = 0, + .ptr = decrypt_output_ptr + }; + + uint32_t fragment_offset = 0; + while (fragment_offset < fragment->size) + { + /* default to max length */ + uint32_t length_update = decrypt_buffer.size_max; + + /* adjust size to not overshoot */ + if (fragment_offset + length_update > fragment->size) + { + length_update = fragment->size - fragment_offset; + } + + /* decrypt part of the fragment using the offset */ + ARM_UC_cryptoDecryptUpdate(&cipherHandle, + &fragment->ptr[fragment_offset], + length_update, + &decrypt_buffer); + +#if 0 +UCFM_DEBUG_OUTPUT + debug_output_decryption(&fragment->ptr[fragment_offset], + &decrypt_buffer); +#endif + + /* overwrite the encrypted data with the decrypted data */ + memcpy(&fragment->ptr[fragment_offset], + decrypt_buffer.ptr, + length_update); + + /* update offset */ + fragment_offset += length_update; + } + } + + /* store fragment using PAL */ + result = ARM_UCP_Write(package_configuration->package_id, + package_offset, + fragment); + + if (result.error == ERR_NONE) + { + package_offset += fragment->size; + } + } + + return result; +} + +static arm_uc_error_t ARM_UCFM_Finalize(arm_uc_buffer_t* front, arm_uc_buffer_t* back) +{ + UC_FIRM_TRACE("ARM_UCFM_Finish"); + + arm_uc_error_t result = (arm_uc_error_t){ FIRM_ERR_NONE }; + + if (!ready_to_receive) + { + result = (arm_uc_error_t){ FIRM_ERR_UNINITIALIZED }; + } + else if ((front == NULL) || + (front != NULL && ((front->size_max % ARM_UC_SHA256_SIZE) != 0)) || + (back != NULL && ((back->size_max % ARM_UC_SHA256_SIZE) != 0))) + { + result = (arm_uc_error_t){ FIRM_ERR_INVALID_PARAMETER }; + } + else + { + ucfm_state = UCFM_STATE_FINISH; + + /* flush decryption buffer, discard data */ + ARM_UC_cryptoDecryptFinish(&cipherHandle, front); + memset(&cipherHandle, 0, sizeof(arm_uc_cipherHandle_t)); + + /* save buffers, checking if the buffers actually exist */ + front_buffer = front; + back_buffer = (back == NULL) ? front_buffer : back; + + /* flush to PAL */ + result = ARM_UCP_Finalize(package_configuration->package_id); + + /* disable module until next setup call is received */ + ready_to_receive = false; + } + + return result; +} + +static arm_uc_error_t ARM_UCFM_Activate(uint32_t location) +{ + UC_FIRM_TRACE("ARM_UCFM_Activate"); + + arm_uc_error_t result = { .code = FIRM_ERR_ACTIVATE }; + + if (ucfm_handler) + { + result = ARM_UCP_Activate(location); + } + + return result; +} + +static arm_uc_error_t ARM_UCFM_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details) +{ + UC_FIRM_TRACE("ARM_UCFM_GetActiveFirmwareDetails"); + + arm_uc_error_t result = { .code = FIRM_ERR_INVALID_PARAMETER }; + + if (ucfm_handler && details) + { + result = ARM_UCP_GetActiveFirmwareDetails(details); + } + + return result; +} + +static arm_uc_error_t ARM_UCFM_GetFirmwareDetails(uint32_t location, + arm_uc_firmware_details_t* details) +{ + UC_FIRM_TRACE("ARM_UCFM_GetFirmwareDetails"); + + arm_uc_error_t result = { .code = FIRM_ERR_INVALID_PARAMETER }; + + if (ucfm_handler && details) + { + result = ARM_UCP_GetFirmwareDetails(location, details); + } + + return result; +} + +static arm_uc_error_t ARM_UCFM_GetInstallerDetails(arm_uc_installer_details_t* details) +{ + UC_FIRM_TRACE("ARM_UCFM_GetInstallerDetails"); + + arm_uc_error_t result = { .code = FIRM_ERR_INVALID_PARAMETER }; + + if (ucfm_handler && details) + { + result = ARM_UCP_GetInstallerDetails(details); + } + + return result; +} + +ARM_UC_FIRMWARE_MANAGER_t ARM_UC_FirmwareManager = { + .Initialize = ARM_UCFM_Initialize, + .Prepare = ARM_UCFM_Prepare, + .Write = ARM_UCFM_Write, + .Finalize = ARM_UCFM_Finalize, + .Activate = ARM_UCFM_Activate, + .GetActiveFirmwareDetails = ARM_UCFM_GetActiveFirmwareDetails, + .GetFirmwareDetails = ARM_UCFM_GetFirmwareDetails, + .GetInstallerDetails = ARM_UCFM_GetInstallerDetails +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_alice.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_alice.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33561 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +static const uint8_t key[32] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 +}; + +static const uint8_t nc[16] = { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +static const uint8_t hash[32] = { + 0x0f, 0x9e, 0xa0, 0xb1, 0x48, 0xd5, 0x53, 0x17, + 0x79, 0x62, 0xa2, 0x5e, 0xdd, 0x2f, 0x56, 0xd3, + 0x63, 0x42, 0xc2, 0x25, 0x76, 0xa3, 0x25, 0x3a, + 0x12, 0x7b, 0x4f, 0xbe, 0xff, 0xa5, 0x68, 0x7d +}; + +/* hash of the first 5*1024 bytes of the alice */ +static const uint8_t short_alice_hash[32] = { + 0x2d, 0xa7, 0x38, 0x44, 0xd3, 0x9e, 0xad, 0xd9, + 0xee, 0x82, 0x3c, 0xdb, 0x40, 0x9a, 0xdf, 0xfb, + 0xe6, 0x63, 0xa9, 0xf7, 0x0d, 0x80, 0x8e, 0x40, + 0x58, 0x82, 0x49, 0x6e, 0x31, 0xec, 0xae, 0x55, +}; + +static const uint8_t ecila[] = { + 0x5B, 0xAD, 0x12, 0x9B, 0x3C, 0x74, 0x62, 0x13, 0x19, 0xEF, + 0xFF, 0x70, 0xA6, 0x02, 0xA0, 0x70, 0x3D, 0x49, 0x1A, 0xBD, + 0x12, 0x0D, 0x70, 0x65, 0x31, 0x14, 0xF5, 0x1C, 0xCE, 0x01, + 0x0D, 0xF1, 0x75, 0xB5, 0x59, 0xEE, 0x64, 0x12, 0x2D, 0x34, + 0x63, 0xAB, 0x81, 0xCC, 0x59, 0xEA, 0xAF, 0x10, 0x45, 0x37, + 0x8F, 0xAC, 0x45, 0x15, 0x54, 0xC8, 0x9E, 0xA5, 0xF9, 0x04, + 0xCA, 0x66, 0x56, 0xF5, 0xEA, 0x05, 0x8D, 0x8F, 0xB5, 0x10, + 0x04, 0x98, 0xDA, 0xFD, 0x5A, 0x74, 0x80, 0xBC, 0xE3, 0xD2, + 0x0E, 0x84, 0x08, 0xE9, 0x40, 0x6F, 0x7B, 0xA3, 0x0A, 0xCD, + 0xB9, 0x65, 0x51, 0xF2, 0xE0, 0x8D, 0x6C, 0xBD, 0x36, 0xDC, + 0x5F, 0x73, 0xA1, 0x13, 0xBB, 0x2E, 0x73, 0x2E, 0x8B, 0x61, + 0x38, 0x06, 0x4D, 0x18, 0x41, 0x6C, 0xCC, 0xA8, 0x41, 0x62, + 0x10, 0x07, 0xB2, 0xF4, 0x0B, 0xB4, 0x02, 0x95, 0xAA, 0x9D, + 0xF2, 0x13, 0x2E, 0x4E, 0x9A, 0x60, 0xA2, 0x27, 0xFE, 0x23, + 0x4A, 0xAD, 0xE3, 0x1F, 0xE9, 0xB8, 0x09, 0xC6, 0x3E, 0xC3, + 0x03, 0x68, 0xB8, 0x9B, 0x8F, 0x1C, 0x71, 0x9A, 0x77, 0x58, + 0xA3, 0x7F, 0xBA, 0xA7, 0xAE, 0xB5, 0xA4, 0x5E, 0xFA, 0x92, + 0x9E, 0x60, 0x66, 0xFE, 0xEF, 0x5C, 0xF4, 0x49, 0x10, 0x49, + 0x88, 0x21, 0x46, 0xB1, 0x36, 0x93, 0xBF, 0x4A, 0xF9, 0xBD, + 0xCC, 0x7B, 0xDD, 0x97, 0x29, 0x55, 0x05, 0x67, 0xD6, 0x43, + 0xAC, 0xD4, 0x8B, 0xE0, 0x65, 0xC8, 0xB2, 0x8D, 0xC7, 0xC5, + 0xF2, 0xEA, 0xF7, 0x44, 0xCD, 0x21, 0x47, 0xAE, 0xF4, 0xB8, + 0x68, 0x55, 0xC5, 0x30, 0x65, 0x3E, 0x2E, 0x1E, 0xC0, 0xAE, + 0xBA, 0x3E, 0xB0, 0x28, 0x07, 0x45, 0xFC, 0xF7, 0x0F, 0x42, + 0x75, 0x9F, 0x80, 0xF6, 0xAE, 0xF6, 0x28, 0x87, 0x0D, 0x33, + 0x26, 0x55, 0x74, 0xB3, 0x1F, 0x58, 0xB4, 0x2B, 0x30, 0x80, + 0xC4, 0x10, 0xAB, 0x9A, 0x0F, 0xED, 0x55, 0xD5, 0xE1, 0xA6, + 0x3B, 0x27, 0x2F, 0x03, 0x7B, 0xB5, 0x1D, 0x17, 0x7B, 0x9E, + 0x51, 0x1A, 0x31, 0xA3, 0xFA, 0x66, 0x62, 0x63, 0x9B, 0x68, + 0x2B, 0xE5, 0x18, 0x64, 0xB4, 0x98, 0x28, 0x6D, 0x1B, 0xD7, + 0x3F, 0x61, 0x9E, 0x40, 0x83, 0x16, 0x45, 0x20, 0x9F, 0x01, + 0x0E, 0xE3, 0x5F, 0xC6, 0xB2, 0x95, 0x10, 0x62, 0x04, 0x68, + 0x9B, 0xCD, 0x55, 0xEC, 0x1E, 0x44, 0xCE, 0x18, 0x9A, 0x4E, + 0x72, 0xF1, 0xE2, 0xE1, 0x64, 0x0E, 0x09, 0xB2, 0x20, 0x85, + 0x5B, 0x3D, 0x13, 0x04, 0xED, 0x7F, 0x40, 0x13, 0xC0, 0x3E, + 0xDD, 0x1D, 0xCF, 0xAF, 0x38, 0x1A, 0xF4, 0xA9, 0xA5, 0x97, + 0xE9, 0x9C, 0x37, 0x46, 0xB7, 0xA9, 0x96, 0xAC, 0xF1, 0x97, + 0xDB, 0x62, 0xF8, 0x0E, 0x8E, 0xE8, 0x3B, 0xEF, 0x56, 0x41, + 0xE7, 0x6D, 0xA0, 0x75, 0x9E, 0xAD, 0x37, 0x54, 0x1A, 0xE9, + 0xE4, 0xCE, 0x96, 0xBC, 0x6A, 0x7A, 0x9E, 0x72, 0xCC, 0xFE, + 0x0C, 0x8E, 0x4E, 0x50, 0xC9, 0x0D, 0x42, 0xEB, 0x6F, 0xB6, + 0xCB, 0xE2, 0xC3, 0x1B, 0x77, 0x76, 0xF3, 0xBA, 0x06, 0xA8, + 0x92, 0x3A, 0xF9, 0x36, 0x11, 0xD3, 0x39, 0x49, 0x8D, 0x71, + 0x62, 0x2F, 0xED, 0xDB, 0xD0, 0x3B, 0x26, 0x51, 0x16, 0x19, + 0x33, 0xEF, 0x7B, 0x7B, 0x67, 0x8F, 0x58, 0x8D, 0x41, 0x32, + 0x4E, 0xCC, 0xEE, 0xC5, 0x95, 0x46, 0x47, 0x42, 0xCF, 0x1B, + 0xA6, 0x80, 0x85, 0x89, 0xB0, 0x91, 0xD8, 0x5D, 0xA6, 0xDE, + 0x8D, 0x37, 0xE9, 0x26, 0x92, 0x50, 0x08, 0x1F, 0x48, 0x04, + 0x08, 0x7F, 0x55, 0x98, 0x0C, 0x68, 0x87, 0x77, 0x10, 0x34, + 0x35, 0x49, 0x90, 0x4B, 0x8A, 0x70, 0x19, 0x4B, 0x5A, 0xE9, + 0x9C, 0xCE, 0x8F, 0x4F, 0x90, 0x2B, 0xF9, 0x4F, 0xC3, 0xD0, + 0x80, 0x6C, 0x15, 0x72, 0x6A, 0xD5, 0x66, 0xBA, 0x12, 0x27, + 0xA9, 0xC3, 0x7E, 0x05, 0xED, 0xB2, 0x7E, 0x58, 0x80, 0x3B, + 0xBE, 0x9A, 0x99, 0xF0, 0xE8, 0xBC, 0x3F, 0xED, 0x3F, 0x09, + 0xFE, 0x92, 0x64, 0xD5, 0x6A, 0x5C, 0xAD, 0xBC, 0x18, 0xAE, + 0x45, 0x04, 0xED, 0x40, 0xA1, 0xFE, 0x81, 0xF0, 0x8C, 0x29, + 0x3D, 0xB1, 0xEE, 0xFE, 0x56, 0xFB, 0x73, 0xBE, 0x91, 0x35, + 0xE6, 0x65, 0xFD, 0xD0, 0x0D, 0x8B, 0xB9, 0x3D, 0x4D, 0x6B, + 0x23, 0xD4, 0xBC, 0x56, 0x44, 0x4E, 0x32, 0x51, 0x98, 0xD9, + 0x5F, 0x45, 0x1F, 0xD0, 0x80, 0x0D, 0x33, 0xF5, 0x4E, 0x2A, + 0x73, 0x5E, 0x14, 0xFF, 0x7B, 0x7C, 0xBF, 0xD7, 0x95, 0x37, + 0xAE, 0x36, 0x38, 0x93, 0xD0, 0x37, 0xE3, 0xF9, 0xED, 0x51, + 0x65, 0xBC, 0xC2, 0xEB, 0x49, 0x80, 0x04, 0xA0, 0x81, 0xC3, + 0x41, 0x2E, 0xCB, 0x7E, 0x7E, 0x45, 0xE5, 0x72, 0x45, 0x94, + 0xCC, 0x46, 0x53, 0x0A, 0x8C, 0x65, 0x27, 0xEC, 0x6C, 0x66, + 0x45, 0xFC, 0xD2, 0xC3, 0xE6, 0x0F, 0xB8, 0x96, 0x67, 0xB9, + 0x9E, 0x8A, 0x6C, 0xDD, 0xB4, 0x79, 0x9D, 0x74, 0x61, 0x23, + 0xDE, 0x19, 0xC6, 0x2C, 0x80, 0xFA, 0x9B, 0xC5, 0xC1, 0xEB, + 0xE2, 0xD4, 0x99, 0xD5, 0x16, 0xEF, 0xBB, 0xFE, 0x87, 0x9D, + 0xB5, 0xBD, 0xB4, 0xA3, 0xB4, 0x32, 0xA2, 0xCB, 0x90, 0x67, + 0xDC, 0xB7, 0x50, 0xA7, 0x71, 0xB2, 0xB2, 0x51, 0xC2, 0xD4, + 0x43, 0xCD, 0x51, 0xE8, 0x94, 0xB5, 0xAA, 0x2F, 0x5D, 0xFC, + 0x19, 0x34, 0xFF, 0x82, 0x4B, 0x36, 0x6E, 0xCD, 0x01, 0xDD, + 0x7A, 0x98, 0x80, 0x26, 0x9B, 0xCD, 0x1D, 0x23, 0xA4, 0xB2, + 0xB2, 0x03, 0x18, 0x6A, 0xF1, 0x6A, 0x30, 0x15, 0xE9, 0x65, + 0xCB, 0x42, 0x1D, 0x70, 0xEA, 0x9C, 0x60, 0x31, 0xAD, 0x4C, + 0x0E, 0xD6, 0x83, 0x35, 0x78, 0xC0, 0x46, 0x4E, 0xA7, 0xD3, + 0x6E, 0x9F, 0x25, 0x71, 0x76, 0xA0, 0x16, 0x9B, 0x2B, 0xB4, + 0xDD, 0x69, 0x3C, 0xB0, 0x6E, 0x5A, 0x26, 0x1E, 0x06, 0x5C, + 0xA3, 0xC3, 0xEE, 0xE1, 0xC5, 0x1D, 0x7B, 0x6F, 0x07, 0x0C, + 0x46, 0x4C, 0xEC, 0x2D, 0xDC, 0x65, 0x2E, 0x15, 0x3A, 0x39, + 0xCA, 0xD7, 0xDC, 0xC5, 0x1E, 0xB8, 0xE1, 0x33, 0x9D, 0x96, + 0xDF, 0xF1, 0xF0, 0x50, 0x9B, 0x56, 0x11, 0x97, 0xB9, 0x34, + 0x80, 0x8C, 0x93, 0xF6, 0xCC, 0xDD, 0xCC, 0xCE, 0xD6, 0xAE, + 0xFE, 0x4E, 0xCD, 0x00, 0xC3, 0x5D, 0x35, 0xE8, 0x8D, 0x8E, + 0xBF, 0x14, 0x67, 0x81, 0x4B, 0x49, 0x37, 0xFA, 0xF3, 0x41, + 0x8D, 0xD4, 0x41, 0xE5, 0x64, 0x5F, 0x18, 0x38, 0xBA, 0xD0, + 0x31, 0x44, 0x80, 0x95, 0xEE, 0x7C, 0x7E, 0xAE, 0x87, 0x91, + 0xF4, 0xB5, 0xF3, 0xA6, 0x7D, 0x02, 0x4E, 0xF6, 0x0B, 0xB6, + 0x5B, 0xE9, 0xAD, 0x14, 0xF0, 0x55, 0xF6, 0xBC, 0x33, 0xB2, + 0xAA, 0x15, 0x3C, 0x26, 0xFA, 0xAB, 0x76, 0xEF, 0x9B, 0x26, + 0x42, 0x9B, 0xE7, 0xCC, 0xAD, 0x29, 0xB2, 0xF9, 0x70, 0xFA, + 0x92, 0x75, 0xA2, 0xCE, 0xD0, 0x2F, 0x2B, 0x8D, 0x05, 0xCE, + 0x2F, 0xEA, 0x66, 0xE5, 0x59, 0xC2, 0x14, 0xD5, 0x85, 0xDA, + 0xA2, 0x53, 0xB2, 0x6B, 0xB0, 0x76, 0x0A, 0x6A, 0xC0, 0x92, + 0xA5, 0x5D, 0x9F, 0xFD, 0x68, 0x84, 0xD3, 0x94, 0xCF, 0xAE, + 0x49, 0x02, 0x7E, 0xBC, 0xB9, 0xB0, 0x36, 0xC9, 0xB2, 0x22, + 0xC5, 0x08, 0x33, 0x97, 0x9E, 0xEE, 0x50, 0x64, 0x01, 0x30, + 0x2C, 0x64, 0x9D, 0xC9, 0xBD, 0x44, 0x9B, 0x9C, 0xB6, 0xDA, + 0x9F, 0x9D, 0x6B, 0x99, 0x8C, 0x5F, 0xB1, 0xE1, 0x91, 0xD4, + 0x7F, 0xA8, 0x72, 0xD5, 0x6B, 0xC3, 0x5E, 0x9A, 0xD4, 0x9C, + 0x27, 0x5A, 0x47, 0xA9, 0x1E, 0xDF, 0x3A, 0xDE, 0x11, 0xF3, + 0x03, 0x0E, 0x6A, 0x5B, 0x56, 0x55, 0x95, 0x40, 0xB7, 0x57, + 0xB0, 0x6F, 0x41, 0x2B, 0x45, 0xE9, 0xA1, 0xD3, 0x2F, 0x40, + 0xF6, 0xEA, 0x17, 0xB2, 0xC5, 0x1D, 0x9D, 0x4E, 0xD9, 0xDD, + 0x3F, 0xD4, 0x79, 0x4E, 0xBE, 0x9A, 0x4E, 0x08, 0xEA, 0xD7, + 0x77, 0x89, 0xBC, 0x78, 0x4A, 0xDA, 0x37, 0x02, 0x56, 0x08, + 0xEA, 0x49, 0x06, 0x3B, 0x27, 0xE3, 0x8B, 0x15, 0xCA, 0x64, + 0x95, 0xAE, 0x57, 0x41, 0x9B, 0xE7, 0x03, 0x00, 0x09, 0xFE, + 0x06, 0x19, 0x72, 0xA8, 0x9B, 0xDE, 0xCC, 0xA8, 0x51, 0xA9, + 0x00, 0x2B, 0x58, 0x92, 0x47, 0x35, 0x3F, 0xD9, 0x4A, 0xBB, + 0x10, 0x60, 0x6E, 0x2D, 0xC2, 0x9D, 0xBF, 0x6F, 0x6C, 0xF8, + 0x28, 0x2D, 0x91, 0x91, 0x59, 0xA5, 0x35, 0x9D, 0x89, 0x1E, + 0x61, 0xFC, 0x27, 0xD4, 0xDB, 0x55, 0x47, 0x7E, 0xF5, 0xB6, + 0x58, 0x96, 0xF7, 0x82, 0x8C, 0x57, 0x57, 0x9C, 0x09, 0x26, + 0xFD, 0x44, 0x12, 0x11, 0xF4, 0xBD, 0x1C, 0x11, 0xC4, 0x20, + 0x2F, 0x3E, 0x50, 0x73, 0x5C, 0xE0, 0x55, 0x06, 0x29, 0x0C, + 0x71, 0x7C, 0x83, 0x46, 0xC1, 0xD9, 0x18, 0xBA, 0xFA, 0xE7, + 0x3C, 0x10, 0x01, 0x61, 0xB9, 0x61, 0xE2, 0x2B, 0x94, 0x75, + 0xAE, 0xD6, 0xAE, 0x04, 0x81, 0xED, 0xB5, 0x58, 0x1F, 0xC8, + 0xF0, 0x24, 0x73, 0x9F, 0xFE, 0x7C, 0x4F, 0x5F, 0x6F, 0x68, + 0xAE, 0x21, 0x5B, 0x5F, 0xEE, 0xC9, 0x25, 0xB2, 0xEC, 0x3D, + 0xA6, 0xCF, 0x85, 0xC7, 0xD7, 0x61, 0xB0, 0x4D, 0x73, 0x24, + 0x9C, 0x55, 0x65, 0x7C, 0x8E, 0x32, 0xE4, 0x50, 0x99, 0x28, + 0x31, 0x9B, 0x15, 0x2A, 0xD3, 0x63, 0x3E, 0x0F, 0xE6, 0xDB, + 0xFE, 0xE2, 0xF7, 0xA2, 0x43, 0x9F, 0x4F, 0xB1, 0xD8, 0x66, + 0x00, 0x05, 0x03, 0x04, 0xCB, 0x7C, 0x1F, 0xC1, 0x27, 0x0B, + 0x7E, 0x3D, 0x54, 0xC0, 0x04, 0x6F, 0x7D, 0x99, 0x46, 0x07, + 0xBD, 0x64, 0x9C, 0x34, 0xB5, 0xFC, 0x05, 0x5B, 0x6D, 0x37, + 0x7E, 0x42, 0xB2, 0xC2, 0xB6, 0x5D, 0x73, 0xBF, 0xBD, 0x1B, + 0x0D, 0x0E, 0x88, 0x81, 0xBE, 0xC0, 0xAB, 0x81, 0x9C, 0xA2, + 0x58, 0x27, 0x4E, 0xD7, 0xF9, 0x38, 0x42, 0x12, 0x7C, 0xED, + 0x8B, 0xC6, 0x44, 0x32, 0x46, 0x7B, 0x2E, 0x8C, 0x71, 0x63, + 0x96, 0xF6, 0x0D, 0x9D, 0xF3, 0xF3, 0x7A, 0x30, 0x1D, 0x77, + 0x76, 0x0D, 0x6B, 0x5E, 0x59, 0x40, 0x2E, 0x83, 0x33, 0xB0, + 0x8D, 0x71, 0xBC, 0xD7, 0x12, 0xE1, 0x02, 0x68, 0x57, 0x71, + 0x54, 0xA9, 0xBC, 0x83, 0x76, 0x89, 0xF9, 0xF8, 0x02, 0x4B, + 0xD3, 0x71, 0x66, 0x04, 0x53, 0x20, 0xDE, 0x6A, 0x04, 0x1B, + 0xD3, 0x05, 0xE4, 0xC4, 0x20, 0x50, 0x72, 0x44, 0x16, 0x98, + 0x5D, 0x8B, 0x6D, 0x70, 0xB0, 0x23, 0xDC, 0x84, 0xB6, 0x4D, + 0x15, 0xDF, 0xF4, 0xDE, 0xD1, 0x97, 0xB1, 0xDC, 0xB1, 0x51, + 0x82, 0x74, 0xC8, 0x39, 0x0E, 0x42, 0x99, 0x2E, 0x82, 0x6A, + 0x2E, 0x27, 0xC2, 0x58, 0x7A, 0xDC, 0xCF, 0x8D, 0xDD, 0x2B, + 0x9A, 0x1A, 0x43, 0x13, 0x0D, 0xC9, 0x43, 0x50, 0xF5, 0x5D, + 0x6B, 0xDB, 0x3B, 0xE6, 0x61, 0xF1, 0x27, 0xAF, 0x20, 0xE3, + 0x57, 0x1E, 0x33, 0x8E, 0x35, 0x0D, 0x46, 0x2C, 0xD7, 0x71, + 0xDE, 0x55, 0xB9, 0x99, 0x7C, 0x88, 0xBE, 0xAE, 0x1A, 0xAE, + 0xD8, 0x47, 0x1E, 0x19, 0xBA, 0x2E, 0x93, 0x99, 0xEC, 0x3E, + 0x15, 0x2C, 0x93, 0x4D, 0x80, 0x09, 0xD6, 0xD4, 0xEA, 0xE6, + 0xCB, 0x78, 0x4F, 0x26, 0xA7, 0x27, 0xF6, 0xE0, 0xD3, 0xC7, + 0x27, 0x22, 0x4F, 0x16, 0x75, 0x60, 0x4F, 0x0F, 0xFD, 0x2D, + 0x01, 0x50, 0xB6, 0xB1, 0x17, 0xC8, 0x44, 0x77, 0xB7, 0xA3, + 0x30, 0x64, 0xE2, 0xA9, 0x88, 0x7E, 0xFE, 0x99, 0xB2, 0x29, + 0x6F, 0x5E, 0x91, 0x1B, 0xD7, 0xD9, 0x6B, 0x90, 0x83, 0x23, + 0xD5, 0x64, 0x5B, 0x00, 0x6D, 0x0E, 0xBD, 0x5C, 0xB6, 0xED, + 0x6C, 0x7E, 0x18, 0xE9, 0x6B, 0x4C, 0x81, 0x7A, 0x3D, 0x69, + 0x38, 0xA5, 0xBA, 0xB4, 0x14, 0x7C, 0x11, 0x69, 0x50, 0x35, + 0x62, 0xEC, 0x51, 0x6E, 0x89, 0xAD, 0xCF, 0xEB, 0x46, 0x6C, + 0xBB, 0x87, 0xBA, 0x90, 0xB5, 0x86, 0x91, 0x4B, 0x56, 0xBD, + 0x30, 0x33, 0x87, 0xE9, 0x96, 0xFA, 0x95, 0x49, 0x5C, 0xA6, + 0xB7, 0x29, 0xBB, 0xA7, 0x7D, 0xA4, 0x97, 0xF4, 0x6C, 0x1A, + 0x06, 0x7B, 0x6F, 0xDC, 0x46, 0xB0, 0x7B, 0x70, 0x20, 0xD7, + 0x62, 0xB2, 0xA8, 0xF7, 0xFC, 0xFF, 0x4A, 0xAE, 0x2A, 0xB7, + 0x25, 0x61, 0xD6, 0x33, 0xF5, 0x3C, 0xFC, 0x3D, 0xC2, 0xCC, + 0x3A, 0xDB, 0x4B, 0x78, 0x70, 0xE4, 0x42, 0xF0, 0xB7, 0x18, + 0xE8, 0xF3, 0xE2, 0xD4, 0x1D, 0xCA, 0x55, 0x96, 0x2C, 0x31, + 0x62, 0x01, 0xD9, 0xD5, 0xA2, 0xF7, 0x6D, 0x6C, 0xE0, 0x58, + 0x45, 0x9E, 0x2A, 0x8A, 0x6A, 0x2F, 0x47, 0xF4, 0x35, 0xBA, + 0x5D, 0xB0, 0x53, 0xE7, 0x67, 0x7F, 0xAB, 0x4E, 0x37, 0x23, + 0x30, 0xB3, 0xD5, 0xD2, 0x9F, 0x90, 0x40, 0xB9, 0x8C, 0x4B, + 0xEC, 0xC2, 0x44, 0x14, 0xFD, 0x14, 0x89, 0x96, 0x4E, 0x50, + 0xE9, 0x19, 0xE4, 0x99, 0xBA, 0x23, 0x06, 0x3D, 0x3B, 0x73, + 0x78, 0x77, 0x2F, 0xD0, 0x5E, 0x23, 0x11, 0x3C, 0x29, 0x10, + 0x96, 0xA9, 0xBC, 0x12, 0xA0, 0xD4, 0xD3, 0x2D, 0xFD, 0xB2, + 0x61, 0x72, 0x38, 0xD8, 0x44, 0x23, 0x93, 0x45, 0x43, 0x52, + 0x6A, 0x76, 0x18, 0x01, 0x94, 0x6C, 0x5F, 0xE1, 0x6C, 0xAA, + 0x1B, 0xE6, 0x42, 0x4F, 0x60, 0xE5, 0xD9, 0x7B, 0x29, 0x80, + 0xE5, 0x10, 0x10, 0x6F, 0x25, 0x5E, 0xD3, 0xE6, 0x6E, 0xD1, + 0x09, 0x05, 0x4C, 0xE6, 0x5B, 0x3D, 0x94, 0x26, 0x9B, 0xAC, + 0x29, 0x30, 0x32, 0xB5, 0x99, 0x7A, 0x76, 0x57, 0x06, 0xA2, + 0x5F, 0x0A, 0x9E, 0x9D, 0x06, 0xA3, 0x49, 0x3F, 0x1C, 0x0B, + 0x06, 0xE3, 0xA0, 0xE3, 0x5A, 0x66, 0x66, 0x12, 0x0A, 0x81, + 0xDF, 0x88, 0x9D, 0x37, 0x5B, 0x3A, 0x31, 0xC8, 0x34, 0xF0, + 0x29, 0x7F, 0x8E, 0x36, 0x42, 0xE0, 0x47, 0x8C, 0x41, 0x81, + 0x8E, 0xDA, 0x79, 0x66, 0x08, 0xF2, 0x19, 0xB5, 0xF1, 0x24, + 0x81, 0x67, 0x31, 0xFF, 0x03, 0x0D, 0xC6, 0xC1, 0xCA, 0x22, + 0x8F, 0x4F, 0xE0, 0x03, 0x8D, 0x56, 0x64, 0x1A, 0xD6, 0x3C, + 0x12, 0x04, 0x20, 0xC5, 0xDA, 0x86, 0x81, 0x04, 0x83, 0xB0, + 0x52, 0x86, 0x6C, 0x8F, 0x99, 0xE6, 0x05, 0x2E, 0x4C, 0x83, + 0x89, 0xDF, 0x2E, 0x0B, 0x6D, 0x05, 0xFA, 0xF9, 0xDF, 0xE1, + 0x14, 0x3C, 0x4A, 0xE5, 0xD2, 0x6F, 0x7F, 0x28, 0x14, 0x66, + 0x44, 0xA5, 0x88, 0xA6, 0x7D, 0xBC, 0x17, 0x97, 0x0D, 0xB0, + 0xB8, 0xE7, 0x84, 0x68, 0x0F, 0xCD, 0x0B, 0xCF, 0x73, 0xF0, + 0x83, 0xFB, 0xF2, 0x3B, 0x94, 0x28, 0x69, 0x98, 0xE5, 0xF1, + 0xF2, 0x34, 0x28, 0x48, 0xD2, 0xA6, 0x14, 0xA8, 0x22, 0xAF, + 0xA3, 0xDB, 0x9D, 0xDF, 0x60, 0x66, 0xAD, 0xEF, 0x9F, 0xA0, + 0x88, 0xC7, 0xA5, 0x16, 0x8A, 0x5B, 0x8F, 0x26, 0xC0, 0x05, + 0xE9, 0x8D, 0xEE, 0xDD, 0xAC, 0xFF, 0x7C, 0xAC, 0xB1, 0xB8, + 0x97, 0x0C, 0x35, 0xD1, 0xBE, 0x20, 0x88, 0x4A, 0x35, 0xB2, + 0xD1, 0xEB, 0x5C, 0x3B, 0x90, 0x11, 0x4A, 0x2D, 0xBA, 0x86, + 0x03, 0x06, 0xA8, 0x4F, 0xDE, 0x21, 0x29, 0x01, 0x9B, 0x30, + 0x20, 0x53, 0x12, 0x97, 0xC8, 0x16, 0x9E, 0xAC, 0x65, 0x00, + 0x02, 0x65, 0x98, 0x0D, 0x31, 0x0D, 0x9B, 0x14, 0x27, 0x55, + 0x90, 0x6E, 0xBA, 0x22, 0x6C, 0xA1, 0xAC, 0xB2, 0x01, 0xCE, + 0x68, 0xFF, 0x11, 0x68, 0x50, 0x9B, 0x28, 0x91, 0x91, 0x05, + 0x28, 0x66, 0x58, 0x1D, 0xED, 0x01, 0xBC, 0x36, 0xE2, 0xD8, + 0xAD, 0x64, 0xA0, 0xD2, 0x2C, 0x82, 0xD1, 0x92, 0x32, 0x05, + 0x82, 0x02, 0xB0, 0xD4, 0xFB, 0x26, 0xBF, 0xB2, 0xFC, 0x80, + 0xBF, 0xB3, 0x1A, 0x2B, 0x1B, 0x54, 0xCB, 0xD8, 0xDE, 0x83, + 0xFD, 0x91, 0xD7, 0x67, 0x11, 0x6B, 0x17, 0x93, 0x0E, 0x9B, + 0xDA, 0x5C, 0x5E, 0xBC, 0xAB, 0x80, 0x04, 0x82, 0xF7, 0x26, + 0x1A, 0xD1, 0x98, 0x48, 0xCD, 0x2E, 0x4C, 0x2B, 0xDE, 0x70, + 0xA3, 0x35, 0x19, 0x32, 0x91, 0x0F, 0x2F, 0x96, 0x22, 0xDB, + 0x15, 0xF0, 0x11, 0xC8, 0x5C, 0xF1, 0x7A, 0x01, 0xBE, 0x81, + 0x41, 0x41, 0x99, 0x42, 0xFD, 0xC5, 0xA2, 0xAF, 0x35, 0x39, + 0x2B, 0x3B, 0x11, 0x59, 0xF6, 0x40, 0x5B, 0x70, 0xE0, 0x50, + 0x39, 0xFE, 0x44, 0xA4, 0x6F, 0x58, 0x00, 0xBB, 0xAA, 0x6F, + 0xB5, 0x36, 0x93, 0xB4, 0x69, 0x20, 0xFD, 0x7B, 0x0C, 0xE2, + 0x27, 0xAD, 0x10, 0xF9, 0xF8, 0x38, 0x2B, 0x72, 0xB9, 0x17, + 0x6F, 0xA6, 0xD7, 0x27, 0xB0, 0x25, 0x3A, 0x8A, 0x69, 0xB9, + 0xD4, 0x58, 0x49, 0xA8, 0x5A, 0x03, 0xC4, 0xBF, 0x9E, 0xA4, + 0x34, 0xF0, 0xE5, 0x6E, 0xF2, 0x08, 0x89, 0xC9, 0xCA, 0xC0, + 0xB7, 0xF2, 0xC4, 0x4F, 0xD8, 0x36, 0x2B, 0xFF, 0xFC, 0xC7, + 0x0C, 0xF2, 0x0F, 0x7B, 0x2D, 0xA5, 0x28, 0xE5, 0x8F, 0x67, + 0x61, 0x44, 0x6F, 0xDD, 0xBC, 0x6F, 0xEF, 0x47, 0xC1, 0xDD, + 0x96, 0x7F, 0x9D, 0x81, 0xF5, 0xB9, 0xAD, 0x88, 0x76, 0x82, + 0xB8, 0xF9, 0x0D, 0xBA, 0x42, 0x18, 0x53, 0x94, 0x3D, 0x3A, + 0xCD, 0x42, 0x89, 0x7B, 0x5B, 0xA6, 0xDF, 0x1F, 0x03, 0x9A, + 0x74, 0x0E, 0x04, 0x58, 0x43, 0x70, 0x2B, 0xBA, 0x33, 0x90, + 0x0D, 0xC5, 0xAE, 0x8E, 0xC4, 0x1C, 0x34, 0x7C, 0xF9, 0x39, + 0x34, 0xEA, 0x3B, 0x7E, 0x74, 0x37, 0xD4, 0x82, 0x36, 0x6E, + 0x74, 0x76, 0xBF, 0x7E, 0x77, 0x2B, 0xFB, 0x65, 0x7A, 0xF9, + 0xC1, 0xEC, 0xAC, 0x4E, 0x50, 0xEE, 0xC7, 0x3C, 0x30, 0x81, + 0x59, 0xCD, 0x00, 0xDE, 0x36, 0x02, 0x48, 0xF2, 0x81, 0x81, + 0x74, 0x7F, 0x86, 0xAF, 0x86, 0xDD, 0x6B, 0x50, 0xF7, 0xF6, + 0x4F, 0xC7, 0xC5, 0xBC, 0xA4, 0x3C, 0x69, 0x94, 0x24, 0x80, + 0x76, 0xF8, 0xF5, 0x31, 0x39, 0xE9, 0x4E, 0xFA, 0xB9, 0x17, + 0xC8, 0x54, 0x69, 0xFA, 0xB5, 0x3F, 0xE5, 0x38, 0xCF, 0x50, + 0xE8, 0x72, 0x4A, 0xDE, 0xC7, 0x3C, 0xF8, 0x4E, 0x05, 0x33, + 0x3E, 0x23, 0x99, 0x36, 0x90, 0x03, 0x3C, 0xCB, 0xB8, 0xD6, + 0x51, 0x57, 0x6F, 0x01, 0xF9, 0xB2, 0x2C, 0x53, 0xA2, 0x22, + 0x0A, 0x3F, 0x8B, 0x0D, 0xB0, 0xE5, 0x03, 0xD9, 0x3C, 0x75, + 0xAD, 0xA5, 0x52, 0x89, 0x79, 0xFD, 0x49, 0xC2, 0x9B, 0x01, + 0x05, 0xB5, 0x2E, 0xBC, 0x10, 0x0D, 0x32, 0x07, 0xA7, 0x6B, + 0x21, 0x83, 0xC4, 0x4A, 0xB7, 0x26, 0x4E, 0xF7, 0x9F, 0x3E, + 0xEC, 0x7B, 0x13, 0xEB, 0xBE, 0xF1, 0xED, 0xA3, 0xD3, 0xC3, + 0x73, 0xCE, 0x82, 0x43, 0xC1, 0xED, 0xEF, 0x50, 0xEF, 0xB5, + 0x82, 0x7A, 0x79, 0x09, 0x95, 0x26, 0xE9, 0x47, 0xB8, 0x2D, + 0x48, 0x0C, 0x0C, 0xA7, 0x72, 0x5D, 0xC5, 0x26, 0xB1, 0x08, + 0xE6, 0x88, 0x07, 0xC6, 0xB1, 0x65, 0xFD, 0x05, 0x19, 0xEC, + 0xAB, 0xCA, 0x7E, 0x2F, 0xD1, 0xFE, 0xCA, 0x01, 0x24, 0xA6, + 0x12, 0x16, 0xD3, 0x2D, 0x25, 0x07, 0xB9, 0xD7, 0xE3, 0x6D, + 0x2B, 0x86, 0x07, 0x8A, 0x1C, 0xDB, 0x24, 0x22, 0xDE, 0x7B, + 0xFE, 0x80, 0xFE, 0x8A, 0x79, 0x34, 0x9D, 0x39, 0xBC, 0xEC, + 0x8E, 0x73, 0x5A, 0x1D, 0x5E, 0xC8, 0x81, 0xC4, 0x32, 0x59, + 0xD6, 0x2A, 0x1B, 0x50, 0x50, 0x5C, 0x3F, 0xC9, 0x6A, 0xCA, + 0x37, 0x18, 0xF2, 0xB1, 0xEA, 0xF3, 0x6D, 0x24, 0xB9, 0x13, + 0x01, 0xD5, 0xA5, 0x95, 0xAE, 0x23, 0x42, 0x4A, 0x69, 0xDB, + 0xC9, 0x7B, 0x88, 0xEE, 0x46, 0xA2, 0x19, 0x42, 0x79, 0x1A, + 0x56, 0xC4, 0x0C, 0xAB, 0xD9, 0xED, 0x6A, 0x2F, 0x91, 0x46, + 0xC5, 0x78, 0x6E, 0x7A, 0xC9, 0x5F, 0x16, 0x4B, 0xB0, 0x77, + 0xE6, 0xB4, 0x25, 0xB5, 0x86, 0xD8, 0xC2, 0x68, 0xE8, 0xD9, + 0x64, 0x73, 0xE0, 0xCA, 0x48, 0x79, 0x15, 0x86, 0x69, 0x1E, + 0xEB, 0xA4, 0x09, 0x98, 0x71, 0x08, 0xBE, 0x1D, 0xA1, 0x74, + 0x5C, 0x8E, 0x2B, 0x7F, 0x4F, 0xB4, 0x45, 0xD2, 0xDF, 0x44, + 0xBA, 0xB5, 0x7D, 0x8B, 0xE2, 0x5E, 0x9E, 0xF8, 0xED, 0x31, + 0x0D, 0x36, 0xC3, 0xFB, 0xF1, 0xF1, 0xA5, 0x8A, 0x1E, 0xFE, + 0x16, 0x80, 0x9E, 0xB8, 0x34, 0xA5, 0x17, 0xC1, 0x1A, 0xD2, + 0x52, 0x9E, 0x87, 0xF5, 0x86, 0x0B, 0x81, 0x7A, 0xCE, 0xA3, + 0xAD, 0xBF, 0xEE, 0xF4, 0x14, 0x44, 0x66, 0x8F, 0x5D, 0xD5, + 0x23, 0x82, 0x0D, 0x17, 0x86, 0xA9, 0xC0, 0x1D, 0x3A, 0xBA, + 0x83, 0xBB, 0x5A, 0xD7, 0xF6, 0x8A, 0x91, 0x50, 0x7B, 0xE5, + 0xF9, 0x33, 0xD3, 0xD4, 0xCA, 0xE0, 0x0B, 0x60, 0x89, 0x84, + 0xE9, 0xE0, 0x2A, 0xC2, 0x31, 0x47, 0x18, 0x8F, 0xCF, 0x4C, + 0xF6, 0x97, 0xC0, 0xEA, 0xE9, 0x5A, 0xC9, 0x4C, 0x0E, 0xF6, + 0x1A, 0x0F, 0x0C, 0x26, 0x38, 0x43, 0x31, 0x86, 0xCE, 0xD0, + 0x18, 0x06, 0xC4, 0x34, 0x4F, 0x1E, 0xC6, 0x54, 0x5C, 0xA9, + 0xFB, 0xFC, 0xD4, 0x38, 0xCA, 0x32, 0xB7, 0xD0, 0x91, 0x75, + 0x7A, 0xAE, 0xC4, 0xD8, 0x2D, 0xFB, 0xBF, 0x44, 0x58, 0x02, + 0x5C, 0xFA, 0x65, 0x35, 0xD2, 0xC4, 0xC0, 0x88, 0xEF, 0x31, + 0x51, 0xF6, 0x78, 0x1D, 0x69, 0x0B, 0x8C, 0xD6, 0x43, 0x19, + 0x70, 0x3C, 0xEE, 0x11, 0x0F, 0xB8, 0xCD, 0xCE, 0x66, 0xFA, + 0x76, 0x8B, 0xC9, 0x48, 0x1E, 0x26, 0xC0, 0x50, 0xA0, 0xD0, + 0x39, 0xC2, 0x84, 0x49, 0xE0, 0x24, 0x03, 0x2C, 0x0E, 0x30, + 0x82, 0xC6, 0x40, 0x96, 0x8E, 0x42, 0x6C, 0x6C, 0xF9, 0x7E, + 0x08, 0x43, 0x59, 0xAD, 0x44, 0x34, 0xAB, 0x01, 0xD2, 0x59, + 0xBA, 0xFE, 0xB9, 0xC6, 0xE4, 0x3A, 0xF8, 0x0F, 0x38, 0xDD, + 0x8D, 0xCE, 0xAD, 0xD4, 0xA4, 0x91, 0xFD, 0xF0, 0x58, 0x13, + 0x9A, 0x5D, 0x59, 0x33, 0xFA, 0x66, 0x34, 0x91, 0xF1, 0x51, + 0x75, 0xD4, 0xA6, 0x89, 0x77, 0x9B, 0xA0, 0x3F, 0x1E, 0xB5, + 0x99, 0x17, 0x25, 0xED, 0x83, 0x73, 0xF4, 0x29, 0x37, 0xB5, + 0x60, 0xE3, 0x65, 0x95, 0x1C, 0x02, 0xC4, 0x93, 0x81, 0x4E, + 0x01, 0xA9, 0x04, 0x97, 0x58, 0x8B, 0xB2, 0x39, 0x3D, 0xAA, + 0x27, 0xC1, 0x4F, 0x3D, 0xA0, 0x29, 0x17, 0x99, 0xA2, 0x2E, + 0xD8, 0x9F, 0xEC, 0xAF, 0xD0, 0x83, 0x71, 0xDB, 0xEC, 0xDA, + 0x5F, 0x79, 0xDB, 0x5B, 0x2C, 0x82, 0x15, 0xE8, 0x1D, 0x91, + 0xE9, 0xC9, 0x5B, 0x9A, 0xAA, 0x65, 0x12, 0xA9, 0x62, 0xF5, + 0x8A, 0xC4, 0x52, 0x95, 0x1A, 0x80, 0x8C, 0x8E, 0x78, 0x61, + 0x01, 0x2C, 0x6A, 0xDD, 0x11, 0xD7, 0x5C, 0x17, 0x0E, 0x77, + 0x8D, 0xF5, 0x92, 0x85, 0x9E, 0xB8, 0xF5, 0x0D, 0xE6, 0x3D, + 0xE4, 0x07, 0x80, 0x78, 0xCE, 0xE3, 0x10, 0x65, 0xFE, 0x79, + 0x94, 0xEC, 0xE1, 0xEB, 0xDA, 0xA6, 0x97, 0x9A, 0xCB, 0xA5, + 0x1F, 0x2A, 0x77, 0x8E, 0xE6, 0xF1, 0xC5, 0xDF, 0x7E, 0xE4, + 0x2E, 0x31, 0x49, 0xFF, 0xE8, 0xCA, 0x44, 0xE3, 0xF7, 0xDD, + 0x57, 0xED, 0x0A, 0xF7, 0x05, 0x7D, 0x43, 0xCD, 0x6F, 0x15, + 0x1B, 0xED, 0x72, 0x0C, 0xC9, 0x4A, 0xC8, 0x39, 0xA8, 0xA0, + 0x78, 0xAA, 0x71, 0x37, 0x08, 0x36, 0x8A, 0x94, 0x9E, 0xEA, + 0x41, 0xF2, 0x5E, 0xC0, 0xCB, 0x18, 0x12, 0x64, 0x59, 0xDC, + 0x63, 0x03, 0x14, 0xA7, 0x82, 0x49, 0x39, 0x8B, 0x8B, 0xF1, + 0x2C, 0x66, 0x80, 0xBE, 0x5D, 0x24, 0xDA, 0x09, 0x6A, 0x1B, + 0x9B, 0x78, 0xF8, 0xAF, 0x38, 0x58, 0xB3, 0xC3, 0x48, 0xCD, + 0x3A, 0x9D, 0x33, 0xEA, 0x84, 0x4C, 0xF8, 0x45, 0xCD, 0x45, + 0x72, 0xC4, 0xCA, 0x28, 0xC0, 0x58, 0x6E, 0xD1, 0x10, 0x82, + 0x10, 0xA6, 0xE1, 0xA0, 0x5D, 0x52, 0xA7, 0x8D, 0xA9, 0x11, + 0xDA, 0x41, 0xAD, 0x16, 0x36, 0x75, 0xEC, 0x05, 0x1E, 0x5A, + 0x43, 0xF5, 0x54, 0x39, 0x04, 0xFF, 0x57, 0x98, 0x4E, 0x38, + 0xB6, 0x49, 0x28, 0xCE, 0x86, 0xFB, 0xBF, 0x96, 0x4C, 0x71, + 0xD7, 0xE5, 0xB1, 0xD9, 0xD3, 0x13, 0x6C, 0x35, 0xB4, 0x2C, + 0x1A, 0xDB, 0xB3, 0xE7, 0xFA, 0x2D, 0x4C, 0xC3, 0x1A, 0xBA, + 0xEC, 0x47, 0x6E, 0x31, 0x64, 0x3B, 0xC0, 0x88, 0x42, 0x07, + 0xA9, 0x67, 0x0C, 0x2C, 0x8C, 0xF7, 0xE9, 0x93, 0xFF, 0x59, + 0x68, 0xA5, 0xE5, 0x8B, 0x9F, 0x45, 0x40, 0x90, 0xB8, 0xBC, + 0x65, 0x1C, 0x80, 0x78, 0x02, 0x24, 0x07, 0x37, 0x66, 0xA6, + 0x0D, 0xC5, 0x7E, 0x53, 0x9B, 0x4B, 0x04, 0x47, 0x25, 0x74, + 0x67, 0xC2, 0x1A, 0x18, 0x8D, 0x56, 0xE7, 0x03, 0xB4, 0x1D, + 0xF0, 0x4F, 0xA4, 0x0B, 0xC8, 0x17, 0x4C, 0x6D, 0xC9, 0xE8, + 0x83, 0x3D, 0xD7, 0xF5, 0x2D, 0xB0, 0x55, 0xB7, 0xA5, 0x02, + 0xFC, 0xE8, 0x11, 0x2F, 0x30, 0x1F, 0x03, 0x87, 0xBB, 0x2D, + 0x48, 0x5D, 0x59, 0x63, 0xE7, 0x8F, 0x89, 0xCE, 0x5B, 0xBA, + 0x3E, 0x76, 0xFA, 0xD2, 0xD5, 0xD0, 0xB1, 0xAF, 0xFC, 0x65, + 0xD7, 0xFC, 0xEC, 0xDE, 0x4E, 0xCC, 0x5D, 0x8F, 0xE6, 0x83, + 0x0F, 0xEB, 0x37, 0x43, 0x08, 0xE1, 0x84, 0x87, 0x0D, 0xD8, + 0xDA, 0x64, 0x0F, 0x80, 0x93, 0x3F, 0x0F, 0x8A, 0xE4, 0xBC, + 0x2A, 0x65, 0x80, 0x13, 0x04, 0x2C, 0x31, 0x6C, 0x52, 0x33, + 0x37, 0x1D, 0x3E, 0xEB, 0xCA, 0xB0, 0x9A, 0xEF, 0x82, 0xE2, + 0x6E, 0xE3, 0xFF, 0x7A, 0x22, 0x80, 0x23, 0x21, 0xCF, 0x34, + 0x75, 0x74, 0x3E, 0x47, 0xCD, 0x5C, 0xFF, 0x9F, 0x0F, 0x16, + 0xCA, 0x78, 0x2C, 0xDE, 0xDC, 0xEA, 0xE4, 0x8F, 0xF1, 0x0C, + 0x44, 0x9A, 0x92, 0xBC, 0xFE, 0xEE, 0xDA, 0xE3, 0xEE, 0x98, + 0x8B, 0x34, 0x5D, 0xD7, 0xEB, 0x16, 0x92, 0x71, 0x46, 0x65, + 0xDA, 0x05, 0x31, 0xDE, 0x20, 0xDC, 0x5C, 0x12, 0x8C, 0x8F, + 0x57, 0xDF, 0x8B, 0x3B, 0x2D, 0x10, 0x97, 0xF2, 0xBC, 0x5F, + 0x50, 0x2F, 0x4C, 0x70, 0xC2, 0x47, 0x82, 0x9C, 0x0F, 0xD7, + 0x50, 0xD6, 0x96, 0x4D, 0x3D, 0x30, 0x18, 0xE1, 0x13, 0x30, + 0xD8, 0x57, 0xDD, 0x36, 0x9C, 0x14, 0x6E, 0xF1, 0x92, 0x5B, + 0xD9, 0x9E, 0xA9, 0x8F, 0x2F, 0x0A, 0x2A, 0x30, 0xF8, 0x2C, + 0x7F, 0x63, 0x08, 0x33, 0x08, 0xC3, 0xF6, 0x8B, 0xB7, 0x42, + 0x89, 0x3F, 0xE2, 0xBD, 0x18, 0x58, 0xAE, 0x8D, 0x8C, 0x42, + 0xD1, 0x1D, 0x3E, 0x36, 0xFB, 0x04, 0x63, 0x70, 0xCB, 0x0F, + 0x72, 0xF8, 0xE3, 0x64, 0x5F, 0x8B, 0x36, 0xF8, 0xB0, 0xEE, + 0x88, 0xC4, 0x5B, 0x62, 0x66, 0x5F, 0x98, 0xDC, 0x5B, 0x2A, + 0xA3, 0x35, 0x03, 0x37, 0xEB, 0x77, 0xCB, 0x55, 0x42, 0xC1, + 0xC2, 0x2D, 0x79, 0xE9, 0x5F, 0xB1, 0x8D, 0x94, 0x86, 0x7F, + 0xE0, 0x58, 0x5D, 0xEB, 0x4F, 0x3C, 0xC8, 0xD3, 0xBD, 0x1E, + 0x0E, 0xE6, 0x90, 0xC1, 0xC1, 0x53, 0xD6, 0x49, 0x4C, 0x21, + 0x38, 0x65, 0x7B, 0xC2, 0x7F, 0xE7, 0xAC, 0xE3, 0x74, 0x27, + 0x28, 0x5E, 0x39, 0xE6, 0xEF, 0x7D, 0xF8, 0xCF, 0x56, 0xB8, + 0xAC, 0x4C, 0xED, 0x29, 0x1E, 0xD8, 0xCE, 0xD5, 0x23, 0xA1, + 0x0A, 0x6B, 0x3B, 0x50, 0xCF, 0x55, 0x05, 0x1C, 0x9D, 0xA6, + 0x3E, 0x2C, 0xD5, 0x7B, 0xD6, 0x81, 0xB0, 0x69, 0x78, 0xF2, + 0x18, 0xE8, 0x47, 0xE5, 0x18, 0x50, 0x4A, 0x11, 0x62, 0x86, + 0x1D, 0xFA, 0x40, 0xBA, 0x89, 0xE5, 0xA7, 0x38, 0xCE, 0x69, + 0x6B, 0xDB, 0xEE, 0xE3, 0x53, 0xB0, 0x28, 0x03, 0xF6, 0x8B, + 0x48, 0x20, 0xE9, 0xD5, 0x3F, 0x03, 0x03, 0xE5, 0x6C, 0x95, + 0x84, 0x77, 0x0C, 0x02, 0xD2, 0xA6, 0x63, 0x5F, 0xD0, 0x9D, + 0x3E, 0x00, 0x3D, 0xB0, 0x27, 0x3E, 0x37, 0x89, 0x41, 0x7B, + 0x74, 0x94, 0xF7, 0x67, 0xE9, 0x38, 0xB0, 0xE9, 0xBD, 0x75, + 0x2D, 0x7D, 0xA9, 0xC8, 0x68, 0xD9, 0x8B, 0x4D, 0xE4, 0x06, + 0x5F, 0x95, 0x84, 0xAE, 0xC2, 0xC9, 0xEA, 0x55, 0x53, 0xB1, + 0x7B, 0xE6, 0xC4, 0x89, 0x6C, 0x61, 0x47, 0x13, 0x5A, 0x7B, + 0xFB, 0xCC, 0x1D, 0x6D, 0x94, 0x16, 0x7E, 0xCB, 0x3F, 0xAE, + 0xF9, 0x34, 0x2E, 0xEC, 0x75, 0xB9, 0x13, 0xDA, 0xDA, 0x2A, + 0xD3, 0xE0, 0x3B, 0xCE, 0x58, 0x87, 0xC5, 0xBB, 0xFE, 0x78, + 0x0F, 0x6A, 0xBB, 0x22, 0x2C, 0xA0, 0x65, 0x9A, 0x35, 0x46, + 0xAF, 0xE2, 0x6F, 0x94, 0x8C, 0x56, 0xDA, 0x94, 0x5D, 0x7E, + 0x66, 0x4D, 0x42, 0xB0, 0x3B, 0xDE, 0xDA, 0xEB, 0x75, 0xCB, + 0xB4, 0x1A, 0x0B, 0xF3, 0xA4, 0x07, 0x68, 0x1F, 0x1F, 0x29, + 0x02, 0x9F, 0xAE, 0xF7, 0xA8, 0xA3, 0xF3, 0xA1, 0xAB, 0xE2, + 0xD1, 0xAE, 0x96, 0x4D, 0xD0, 0x83, 0x00, 0xC8, 0x42, 0x47, + 0x3A, 0xD1, 0x71, 0xA9, 0xBA, 0xD0, 0x9C, 0xEA, 0x01, 0xE7, + 0xE2, 0x17, 0x33, 0xD7, 0xDB, 0x03, 0xFA, 0x40, 0x31, 0x87, + 0x71, 0x03, 0xE0, 0x88, 0xE8, 0xFB, 0xFA, 0xC7, 0x47, 0x23, + 0x55, 0xCC, 0xFF, 0x0F, 0x73, 0x33, 0xFF, 0x63, 0x94, 0x7A, + 0xAF, 0x63, 0x36, 0xA4, 0x7F, 0x98, 0xC1, 0xEC, 0xBA, 0xC5, + 0xF0, 0xF5, 0x45, 0x6B, 0x68, 0x4D, 0xA3, 0x33, 0xE0, 0x41, + 0x6D, 0xC8, 0xD5, 0x71, 0x5F, 0x8C, 0x78, 0xD6, 0xC3, 0x15, + 0xE9, 0xDE, 0x26, 0xFB, 0x66, 0x0A, 0xEC, 0x6F, 0x68, 0xBE, + 0xE3, 0x04, 0x3C, 0x71, 0x9D, 0x24, 0xD5, 0x73, 0x7F, 0x8E, + 0xA3, 0xBB, 0x43, 0x94, 0x71, 0xDB, 0xB4, 0x9A, 0xE4, 0xEC, + 0x6C, 0xEA, 0x7C, 0xDC, 0x6F, 0xC6, 0xBB, 0xF8, 0xEB, 0x7D, + 0x27, 0x29, 0xB2, 0x3F, 0xA7, 0x5F, 0xDF, 0x30, 0x6A, 0x1C, + 0x41, 0x84, 0xD4, 0x71, 0x95, 0x6F, 0x98, 0xEF, 0x7B, 0x0F, + 0x6E, 0x5A, 0x1C, 0x9F, 0x2B, 0x48, 0xE1, 0x45, 0x3D, 0x57, + 0x4A, 0x5D, 0xA3, 0x5D, 0x9F, 0x8F, 0x73, 0x28, 0xA0, 0xB7, + 0x0F, 0xB2, 0xFD, 0xE6, 0x44, 0xF3, 0xF1, 0x77, 0x16, 0x07, + 0x9B, 0x22, 0x27, 0x45, 0x65, 0x1F, 0xAC, 0x6B, 0x44, 0x9F, + 0x0A, 0xEB, 0x75, 0x92, 0x86, 0xC1, 0xC4, 0x25, 0x01, 0x6F, + 0xD3, 0x3B, 0x77, 0xE3, 0xA9, 0xF5, 0xFD, 0x33, 0x85, 0x4B, + 0xF2, 0x10, 0x89, 0x1C, 0xC8, 0xE3, 0x37, 0xC5, 0x9C, 0xE0, + 0x8E, 0xFE, 0xDF, 0xCA, 0x9C, 0x02, 0x6A, 0x42, 0xCF, 0x54, + 0xCF, 0x4E, 0x80, 0x53, 0xA2, 0x3D, 0x47, 0xE1, 0xC2, 0x15, + 0xE7, 0x66, 0x7F, 0x50, 0xA7, 0x50, 0xA0, 0x29, 0x8A, 0x3F, + 0x44, 0xEB, 0x54, 0x67, 0x48, 0x8B, 0xC2, 0xA2, 0xC4, 0x38, + 0x32, 0xF1, 0x30, 0x55, 0x62, 0x27, 0xF0, 0x75, 0x09, 0xB5, + 0x12, 0x18, 0x23, 0xA8, 0x01, 0xCC, 0x35, 0x77, 0x00, 0x9F, + 0xAB, 0x03, 0xCE, 0x8A, 0xBD, 0x52, 0xB1, 0xED, 0x33, 0x10, + 0x9D, 0x27, 0x0F, 0x9D, 0x50, 0x14, 0x0C, 0xAA, 0x30, 0xA0, + 0x3A, 0xDD, 0x91, 0x02, 0xDE, 0xF0, 0x2F, 0x0D, 0x79, 0x6A, + 0x2E, 0x9C, 0xFE, 0xF0, 0xDB, 0x98, 0x7D, 0xAC, 0x07, 0x29, + 0x5C, 0xC3, 0xA0, 0x2A, 0x83, 0xCA, 0x06, 0xC0, 0xFF, 0x4C, + 0x91, 0x44, 0x01, 0x3A, 0x21, 0xF4, 0x98, 0x32, 0x43, 0x68, + 0x1D, 0x42, 0xC9, 0x5C, 0x87, 0xA9, 0xA2, 0x4E, 0xF8, 0xEA, + 0xB8, 0x40, 0xBF, 0xD7, 0x6F, 0x58, 0xF1, 0xEE, 0x9A, 0x26, + 0x94, 0x3D, 0x52, 0x07, 0x8E, 0x1D, 0x95, 0xCD, 0x79, 0x56, + 0xF8, 0x26, 0x35, 0x6D, 0x07, 0x24, 0x0D, 0x6E, 0x26, 0xA3, + 0x4D, 0x76, 0x58, 0x0E, 0x69, 0x2D, 0xB8, 0x28, 0xEF, 0x20, + 0x9F, 0x47, 0x71, 0x7A, 0x8A, 0xC7, 0xC1, 0x33, 0xD8, 0x50, + 0x68, 0x3C, 0xB8, 0xE7, 0x6A, 0xC3, 0x07, 0x5B, 0x9F, 0x4A, + 0xBE, 0x72, 0xE8, 0x8E, 0x2A, 0x0A, 0xFD, 0xE7, 0x78, 0x66, + 0x10, 0xD1, 0x1D, 0xD5, 0xC2, 0x2D, 0x69, 0xBA, 0xBC, 0x3A, + 0x21, 0x1B, 0x01, 0x2E, 0x6C, 0x83, 0x70, 0x96, 0x24, 0x11, + 0xCC, 0x99, 0x56, 0x2D, 0x96, 0x6D, 0xBC, 0x07, 0xA7, 0x9E, + 0x2F, 0x0D, 0x56, 0x10, 0x89, 0x14, 0xC8, 0xF9, 0x21, 0xF6, + 0x2B, 0xCD, 0x81, 0x32, 0xBC, 0x4B, 0xCF, 0x7F, 0x95, 0x48, + 0xB2, 0x67, 0xEE, 0x25, 0x03, 0x08, 0x15, 0xD2, 0x96, 0x67, + 0x55, 0x17, 0xFB, 0x75, 0xAC, 0xCA, 0xC1, 0xFC, 0xFB, 0x85, + 0x97, 0x78, 0x51, 0x75, 0x14, 0x22, 0xA1, 0x71, 0x57, 0x74, + 0xEC, 0x40, 0x68, 0x6A, 0xBA, 0x0F, 0x8F, 0xB2, 0xFB, 0xFD, + 0x91, 0x3B, 0xE5, 0xA1, 0xBF, 0x91, 0x68, 0x91, 0x5D, 0x66, + 0xA5, 0xDA, 0x53, 0x91, 0x66, 0xC8, 0x01, 0x2F, 0xE1, 0x61, + 0x82, 0x0B, 0xD4, 0x74, 0x35, 0x97, 0x56, 0x06, 0x24, 0x59, + 0xD9, 0x48, 0x77, 0xC2, 0x69, 0x0A, 0xC4, 0xB5, 0xF4, 0xDD, + 0x63, 0x7E, 0x40, 0x2D, 0x1C, 0xBE, 0x8D, 0x8C, 0xF2, 0x92, + 0x7B, 0xA7, 0x4A, 0x60, 0x6E, 0x01, 0x26, 0x80, 0x31, 0x3D, + 0x01, 0xF8, 0x56, 0x93, 0x9D, 0xF1, 0xEF, 0x3B, 0x75, 0xD3, + 0xF8, 0x4C, 0x1B, 0x8E, 0x8F, 0x6E, 0x56, 0x5B, 0x10, 0x50, + 0x4A, 0x26, 0xAF, 0xB2, 0xDF, 0x52, 0xFA, 0x15, 0xF4, 0x3C, + 0x8F, 0x65, 0x18, 0xD4, 0xE1, 0xF1, 0x55, 0x0A, 0x88, 0xA6, + 0xC7, 0x8E, 0x48, 0x3D, 0xE4, 0x74, 0xC9, 0x6F, 0x80, 0x5E, + 0x3D, 0x3C, 0x36, 0xBC, 0x57, 0x35, 0xB2, 0x4A, 0xDF, 0x75, + 0x37, 0x30, 0x15, 0xF2, 0xFB, 0xD9, 0x06, 0x9B, 0x81, 0x5B, + 0x67, 0xBB, 0x94, 0x84, 0x3C, 0x64, 0x62, 0x64, 0x1D, 0xAA, + 0x39, 0xBD, 0x22, 0xDB, 0x36, 0x06, 0xA3, 0x52, 0x85, 0xA7, + 0x65, 0x33, 0xE4, 0xFF, 0x6D, 0x83, 0x4C, 0x55, 0x4E, 0xB2, + 0x40, 0x5D, 0xB7, 0xA9, 0xC8, 0x2D, 0x46, 0xEF, 0x84, 0x63, + 0xCB, 0x91, 0xA5, 0x31, 0x4D, 0x0D, 0xEC, 0x6B, 0x86, 0x3E, + 0x50, 0x31, 0x20, 0x5B, 0xEC, 0x2B, 0x8F, 0x2D, 0xC9, 0xEC, + 0xF2, 0xE9, 0x1A, 0xDA, 0x37, 0x01, 0x0A, 0xA5, 0x34, 0x9B, + 0x9C, 0x17, 0xB0, 0xAE, 0xD5, 0x1D, 0x87, 0xB9, 0x50, 0xB1, + 0x3D, 0xB3, 0x2B, 0x68, 0xE6, 0xBC, 0xBC, 0xEC, 0xA0, 0x55, + 0xE8, 0x77, 0x27, 0x4C, 0x46, 0xC2, 0x5A, 0x86, 0x54, 0x4B, + 0x31, 0x5B, 0xDE, 0x63, 0x5D, 0xF5, 0x7C, 0xA2, 0x90, 0x4F, + 0xD7, 0x7D, 0x8D, 0x8C, 0x23, 0x10, 0x41, 0x76, 0xB3, 0xD7, + 0x20, 0xE5, 0x47, 0x2D, 0xB0, 0x7B, 0xB1, 0x94, 0xD6, 0x14, + 0x97, 0x11, 0x71, 0x2F, 0x22, 0x30, 0x01, 0x09, 0x6B, 0x85, + 0x75, 0x04, 0xA1, 0x02, 0xD6, 0x20, 0xE6, 0x4D, 0x98, 0xB4, + 0x76, 0x74, 0x26, 0x97, 0x65, 0x32, 0x3B, 0xC6, 0x38, 0x3E, + 0x26, 0x0A, 0x7B, 0x82, 0x01, 0x4C, 0x9F, 0x2A, 0xD1, 0xB4, + 0xCB, 0xD6, 0x33, 0x6E, 0xAF, 0x0B, 0xF6, 0x97, 0x1C, 0xC7, + 0xAB, 0x0F, 0xA0, 0x6A, 0xBE, 0xAD, 0x30, 0x19, 0x64, 0xDB, + 0x1B, 0xAF, 0x07, 0xD0, 0x34, 0x27, 0x68, 0x5B, 0x36, 0x18, + 0x91, 0xF8, 0xCA, 0xA4, 0xB0, 0xE7, 0x66, 0x79, 0xF5, 0x25, + 0xC8, 0xBF, 0x52, 0x89, 0x4C, 0x61, 0xC1, 0xFD, 0x25, 0x64, + 0x25, 0x67, 0xA6, 0x7D, 0xE7, 0xB2, 0xFE, 0x2C, 0x65, 0x9D, + 0xCD, 0x07, 0xF3, 0x17, 0x7F, 0x94, 0xBC, 0x3A, 0x3F, 0x15, + 0xFD, 0xC7, 0x5B, 0x15, 0x51, 0x08, 0xDC, 0x54, 0xDB, 0x2B, + 0xAE, 0xB9, 0xC6, 0xF9, 0x6D, 0x17, 0xC1, 0x4D, 0x7F, 0x91, + 0xF0, 0x1E, 0x55, 0x11, 0x28, 0xD5, 0x32, 0x50, 0x99, 0x9D, + 0x08, 0x23, 0xA5, 0xF2, 0xFC, 0x59, 0x3E, 0x0F, 0xCC, 0xAA, + 0x4C, 0x01, 0x98, 0x6E, 0x82, 0xD9, 0x79, 0x78, 0x33, 0x30, + 0xE7, 0xA1, 0xEE, 0x39, 0x00, 0xBA, 0xD0, 0xA4, 0x1D, 0xE9, + 0x20, 0xE7, 0x18, 0xB3, 0xDA, 0x2D, 0xE1, 0x88, 0xC1, 0x69, + 0x9F, 0x11, 0x4A, 0x42, 0xFA, 0x27, 0x79, 0x54, 0x72, 0x9B, + 0xBC, 0xEB, 0xA5, 0xBE, 0x05, 0xB2, 0x7A, 0x19, 0x37, 0x2A, + 0xA8, 0x0F, 0x3B, 0x6C, 0x8E, 0x4E, 0xD2, 0x94, 0xC0, 0x2D, + 0xDD, 0x19, 0xD7, 0xF7, 0x88, 0xE2, 0xCA, 0x3A, 0xE7, 0xAB, + 0xE1, 0x68, 0x7D, 0x79, 0x9D, 0x75, 0x67, 0x1D, 0x2C, 0x2B, + 0x20, 0x3E, 0x3B, 0x02, 0x87, 0x8B, 0x6B, 0xB7, 0x3F, 0x52, + 0x52, 0x3A, 0xF6, 0x12, 0x42, 0x57, 0x84, 0xCA, 0x9A, 0xEF, + 0xAB, 0xA3, 0x7D, 0xBD, 0xDC, 0xE9, 0xD7, 0x2B, 0x38, 0x7F, + 0x15, 0x09, 0xB6, 0x4F, 0xF4, 0x20, 0x1A, 0xAC, 0x11, 0xEE, + 0xEB, 0xF2, 0x9B, 0xFF, 0xD8, 0x86, 0xA7, 0x0E, 0x63, 0xB9, + 0xFA, 0x23, 0x31, 0x04, 0x98, 0xFB, 0x07, 0x9B, 0xB3, 0x7E, + 0xC7, 0x23, 0xA4, 0x49, 0x78, 0xCC, 0xC2, 0x29, 0x64, 0xCF, + 0x8A, 0xAF, 0xBE, 0xCD, 0x0D, 0x00, 0x74, 0x2C, 0x10, 0xFC, + 0xD6, 0x4F, 0x1D, 0x64, 0xA5, 0xDC, 0x9D, 0xD7, 0x3E, 0xCE, + 0xE8, 0x6E, 0xD4, 0x00, 0xAE, 0x4F, 0x76, 0x2B, 0x06, 0xD2, + 0x24, 0x53, 0x01, 0x6E, 0x08, 0xB5, 0x0B, 0xDE, 0x80, 0x5B, + 0xFD, 0x2B, 0x04, 0x77, 0xBB, 0x31, 0xE5, 0x85, 0xAF, 0x65, + 0x34, 0x9F, 0xF1, 0x40, 0xEE, 0xE0, 0x7C, 0xAB, 0xF1, 0x44, + 0xB2, 0xC9, 0x33, 0xF1, 0xA7, 0xD6, 0x87, 0x37, 0xF1, 0x31, + 0xF6, 0x3E, 0xDF, 0xAF, 0x93, 0x44, 0xA5, 0x9B, 0x12, 0x82, + 0xEB, 0x1A, 0x39, 0xCC, 0x45, 0xC4, 0xA2, 0x24, 0x19, 0x29, + 0x77, 0x11, 0xF4, 0xF7, 0x9C, 0x2C, 0x0D, 0x36, 0x7D, 0x4B, + 0xEA, 0x34, 0x0B, 0x72, 0x63, 0xB3, 0x6C, 0xB1, 0x9A, 0x85, + 0x42, 0x2A, 0x3B, 0xC1, 0xE4, 0xB5, 0x03, 0x37, 0x5B, 0x96, + 0x07, 0x5E, 0x47, 0xBD, 0xB2, 0xFE, 0xB8, 0x13, 0x00, 0x9D, + 0xF7, 0xEF, 0x4A, 0xE2, 0x90, 0x58, 0x82, 0x8D, 0x46, 0xE5, + 0x39, 0x46, 0x1E, 0xAB, 0xA3, 0x0F, 0x60, 0x9F, 0x8A, 0x66, + 0x94, 0x75, 0x6B, 0x92, 0x4B, 0x83, 0xA9, 0x4E, 0xEE, 0xE7, + 0x48, 0xE3, 0x2A, 0x71, 0x69, 0x35, 0xEA, 0x1F, 0xD1, 0x05, + 0x3D, 0x67, 0xA4, 0x45, 0xE2, 0xA4, 0xB3, 0x26, 0xA7, 0xCF, + 0x7D, 0x7D, 0x4C, 0x4B, 0xFE, 0xD8, 0x2F, 0xED, 0x1A, 0xCC, + 0x7B, 0x11, 0xD0, 0x94, 0xE8, 0x65, 0xE9, 0x64, 0x15, 0x85, + 0xD4, 0x04, 0x06, 0x77, 0xE9, 0x13, 0x7F, 0x97, 0x6E, 0x75, + 0xB1, 0x78, 0x7E, 0xC1, 0xA9, 0xD4, 0x74, 0xE7, 0x55, 0x5F, + 0xE6, 0x2A, 0x93, 0x14, 0xFA, 0x0F, 0x56, 0xB4, 0x3C, 0xDE, + 0x54, 0xB7, 0xDC, 0x69, 0x5D, 0xF4, 0x5E, 0x17, 0x5C, 0x0E, + 0xC8, 0xCC, 0x0B, 0x2F, 0x38, 0xBF, 0x40, 0xC9, 0x38, 0x23, + 0x5A, 0xBB, 0x12, 0x22, 0x36, 0xD1, 0x1E, 0x7C, 0xEE, 0x07, + 0x46, 0x2F, 0x3E, 0xA4, 0x53, 0x09, 0x43, 0xE7, 0x24, 0xEE, + 0x01, 0x9C, 0x87, 0x8E, 0x9B, 0xB5, 0x95, 0x69, 0x24, 0x46, + 0x1D, 0xB6, 0xD5, 0x64, 0x6B, 0x6C, 0x4B, 0x48, 0x20, 0x52, + 0xB9, 0x18, 0xD1, 0xFB, 0xF5, 0xEA, 0xB4, 0xF6, 0x00, 0xEA, + 0xF6, 0x7F, 0xFB, 0x28, 0xDF, 0x74, 0xEC, 0x93, 0xA8, 0x3B, + 0x83, 0xBA, 0x3D, 0x7C, 0x9B, 0x46, 0xCA, 0xA1, 0xB9, 0xDD, + 0x8E, 0x2B, 0x70, 0xAB, 0x6B, 0x00, 0xE7, 0xB3, 0xDF, 0x86, + 0xC1, 0xA2, 0x18, 0xA0, 0xDE, 0x20, 0x00, 0xCE, 0xF4, 0x57, + 0xC8, 0xF5, 0xEA, 0x17, 0x30, 0x3B, 0x50, 0x84, 0x83, 0x9C, + 0x4B, 0x07, 0x1A, 0x5C, 0xFB, 0xB9, 0x48, 0xF9, 0x2A, 0x26, + 0x76, 0x93, 0x26, 0x29, 0x61, 0x3E, 0x24, 0x7D, 0xE8, 0x30, + 0xF8, 0x52, 0x5F, 0xB8, 0x75, 0xFE, 0x60, 0x3A, 0xD8, 0xAE, + 0xD9, 0x0D, 0x43, 0xB8, 0x1F, 0x89, 0x9A, 0x90, 0x80, 0x04, + 0xDE, 0xAD, 0x17, 0xEB, 0xC7, 0x6B, 0xF8, 0xEF, 0xCD, 0xF6, + 0xE7, 0x07, 0x69, 0xDC, 0xA2, 0xEF, 0xAB, 0xEC, 0x0E, 0x5F, + 0x0D, 0x1D, 0x68, 0x31, 0xE5, 0xE2, 0xD8, 0xE3, 0x83, 0x08, + 0x86, 0x38, 0xF0, 0x78, 0x36, 0x49, 0x37, 0xCE, 0x68, 0x03, + 0x0E, 0x9D, 0x45, 0x98, 0x84, 0x4A, 0xCC, 0xD1, 0xFE, 0x49, + 0x9A, 0x73, 0x78, 0x7F, 0xF3, 0x50, 0x93, 0xF3, 0xAD, 0x51, + 0x59, 0x07, 0xAF, 0x03, 0x21, 0xD8, 0x33, 0xE5, 0x84, 0x90, + 0x8F, 0x12, 0x0A, 0xC0, 0xC9, 0xC3, 0x34, 0x7B, 0xA7, 0xB3, + 0x91, 0x85, 0x53, 0x0A, 0xCC, 0x8E, 0xC9, 0xC2, 0xDA, 0x7F, + 0x96, 0x09, 0x1B, 0x01, 0xD3, 0x94, 0x70, 0xF3, 0xF4, 0xE8, + 0x3A, 0x04, 0x94, 0x20, 0x93, 0xB7, 0x61, 0x46, 0x27, 0x1A, + 0xD0, 0xBB, 0xF2, 0xF9, 0xA6, 0x3C, 0x2C, 0xD0, 0xF4, 0xBA, + 0xB8, 0x37, 0x15, 0xD7, 0xBC, 0xA0, 0x5F, 0xA8, 0x52, 0x38, + 0xEE, 0x52, 0x80, 0x44, 0x8B, 0x2B, 0xB7, 0xFB, 0x12, 0x7F, + 0x8F, 0x7E, 0x61, 0x71, 0x54, 0x6B, 0x90, 0x02, 0x5A, 0x86, + 0xE7, 0x5A, 0xFF, 0x2E, 0xB7, 0x9D, 0xA9, 0x06, 0xF0, 0x67, + 0xEB, 0x14, 0xDB, 0x82, 0x3B, 0x0E, 0xE6, 0x0D, 0xB3, 0xD3, + 0xA8, 0x87, 0x2B, 0x3D, 0xA2, 0xC4, 0x1F, 0x93, 0x02, 0x53, + 0x9D, 0x7E, 0x63, 0xCE, 0x88, 0xCA, 0x7D, 0x65, 0x4B, 0xD3, + 0x97, 0x64, 0x6C, 0x67, 0x9E, 0xF7, 0x29, 0x89, 0x04, 0x37, + 0xD4, 0xEB, 0x8B, 0x87, 0xA3, 0x22, 0xAF, 0x29, 0xFD, 0xEA, + 0x4E, 0xAB, 0x02, 0x8E, 0x1C, 0x53, 0xA8, 0xC8, 0x44, 0x9D, + 0xFF, 0x47, 0xC3, 0x8C, 0x16, 0xC6, 0x23, 0x05, 0x44, 0x35, + 0xBC, 0x97, 0x20, 0x7A, 0xC5, 0xD8, 0x98, 0x21, 0xAE, 0x50, + 0x8F, 0xDC, 0x32, 0xFE, 0xC3, 0x3F, 0xA9, 0x21, 0x36, 0x07, + 0xB8, 0x20, 0x62, 0x39, 0xE3, 0x63, 0xDF, 0xCC, 0x8B, 0x6F, + 0xC9, 0x2C, 0xA1, 0xFC, 0x63, 0xC0, 0x36, 0x3B, 0x13, 0x90, + 0x7B, 0xBF, 0x4E, 0xD1, 0x77, 0x5B, 0x03, 0x3A, 0x53, 0x88, + 0xE9, 0x8E, 0x8F, 0x8E, 0x60, 0xD1, 0xA5, 0xF8, 0xE8, 0x9B, + 0x10, 0x19, 0xF4, 0xEB, 0xDE, 0xFF, 0xB2, 0x29, 0xFB, 0x91, + 0x07, 0x8C, 0x18, 0x45, 0xF2, 0x54, 0x05, 0x35, 0x1D, 0xF3, + 0x27, 0xB2, 0x32, 0x46, 0x05, 0x9C, 0x34, 0xB7, 0xDA, 0xD5, + 0x44, 0x87, 0x89, 0x3C, 0x1C, 0x77, 0xEA, 0x5C, 0x9F, 0x3D, + 0x55, 0x64, 0x97, 0x37, 0x15, 0xD2, 0x29, 0x3D, 0x23, 0x2B, + 0x34, 0x23, 0x98, 0x2D, 0xF9, 0x15, 0x71, 0x6A, 0xA0, 0xA2, + 0xBF, 0x43, 0xC1, 0x0B, 0xC7, 0xAC, 0x6F, 0x30, 0xFE, 0xBB, + 0xB2, 0x06, 0x51, 0xA6, 0xF0, 0xA1, 0xB1, 0x6E, 0xCE, 0xF3, + 0x5D, 0xB7, 0xEE, 0x5A, 0xA1, 0xB9, 0x54, 0x80, 0xAA, 0x63, + 0x49, 0x5D, 0xA1, 0x83, 0x53, 0x6F, 0xF2, 0xC7, 0x7D, 0xDC, + 0x47, 0x8D, 0x07, 0xF1, 0x7A, 0xEA, 0x64, 0xE2, 0x66, 0xE8, + 0x7B, 0x3B, 0x8E, 0x71, 0x15, 0x77, 0xE5, 0xBF, 0x69, 0xC4, + 0xBC, 0x28, 0xB5, 0x3D, 0x33, 0xF1, 0x23, 0x7E, 0x3D, 0xA3, + 0x6C, 0x7A, 0x65, 0x08, 0xA0, 0x46, 0x2B, 0x72, 0xF8, 0x5C, + 0xF2, 0xE7, 0x02, 0x33, 0xC7, 0x68, 0x8C, 0x4D, 0xB8, 0x84, + 0x1C, 0x5F, 0xBB, 0xFC, 0xCF, 0xA9, 0x71, 0x2C, 0xCE, 0xB7, + 0x9C, 0x95, 0x3D, 0xC4, 0x92, 0x84, 0x04, 0x26, 0x26, 0x45, + 0x67, 0xA0, 0x23, 0x10, 0xE9, 0xCA, 0x52, 0x01, 0x4C, 0x71, + 0xD1, 0x61, 0x5B, 0x13, 0xE8, 0x13, 0x17, 0x7F, 0x5E, 0xA5, + 0x3A, 0x27, 0xBE, 0x10, 0x5C, 0x3D, 0x0D, 0x0A, 0x7C, 0xFA, + 0xF1, 0xE9, 0x35, 0xB4, 0x89, 0x28, 0xB0, 0xF1, 0xCF, 0xBE, + 0xD6, 0xF0, 0x8C, 0x04, 0x41, 0xB0, 0x9A, 0xD6, 0x84, 0x21, + 0x42, 0xE5, 0x80, 0xB0, 0x3E, 0xB2, 0x73, 0x2E, 0xE4, 0xDD, + 0x86, 0xD5, 0x2C, 0x81, 0x9C, 0x77, 0x0B, 0x4E, 0xEC, 0xE7, + 0x65, 0xCE, 0x09, 0x6C, 0x44, 0x3D, 0xE5, 0xC5, 0x0E, 0xA6, + 0xF9, 0xC0, 0x91, 0x9B, 0x64, 0x92, 0xC5, 0xA6, 0xFD, 0x4E, + 0x40, 0x6E, 0xAC, 0x8D, 0x29, 0x39, 0x7A, 0x78, 0x0C, 0xA6, + 0x3E, 0x60, 0xB2, 0x5C, 0xA7, 0xC1, 0x50, 0x05, 0x81, 0x3E, + 0xA8, 0xE9, 0x50, 0xDF, 0x27, 0xE0, 0xCB, 0x95, 0x15, 0x86, + 0xE5, 0x4D, 0x86, 0x0E, 0x1B, 0x44, 0xAD, 0x8B, 0x64, 0x9A, + 0x38, 0x4B, 0xB6, 0xD2, 0xE0, 0x64, 0xB3, 0x06, 0xF5, 0x03, + 0xAE, 0x84, 0xB7, 0x83, 0x19, 0x2D, 0xD8, 0x79, 0x9F, 0x18, + 0xAA, 0x20, 0x3A, 0xD9, 0xF8, 0x74, 0x05, 0x9E, 0x78, 0x66, + 0xD9, 0x47, 0xBC, 0xB0, 0x87, 0x29, 0xCC, 0xF0, 0x7F, 0xD5, + 0x5F, 0x2B, 0x25, 0x54, 0x12, 0xF7, 0xD8, 0xC0, 0x3F, 0x50, + 0xC1, 0xEA, 0xC4, 0x01, 0x07, 0xFF, 0x8D, 0x34, 0x75, 0x45, + 0x10, 0x3C, 0x34, 0x4E, 0xD1, 0x22, 0x2F, 0xA3, 0x36, 0x6E, + 0xC1, 0xF9, 0x0B, 0x27, 0xD6, 0x94, 0x6B, 0xC1, 0xEB, 0x98, + 0x37, 0xF2, 0x2F, 0x3F, 0x7A, 0x05, 0x4D, 0xCB, 0x72, 0x21, + 0x0E, 0x2B, 0x40, 0xB2, 0xF2, 0xA7, 0xBF, 0x97, 0x3B, 0x50, + 0xD5, 0x8F, 0x9C, 0xF4, 0x69, 0x0A, 0xB7, 0xDB, 0x46, 0x24, + 0xEC, 0x58, 0x6F, 0x72, 0x60, 0xC0, 0x61, 0x20, 0xE8, 0x5C, + 0xCB, 0x8D, 0xBE, 0xF5, 0x5E, 0x08, 0x77, 0x01, 0xF5, 0xE7, + 0x69, 0xE1, 0xF5, 0x17, 0x0F, 0x87, 0x0D, 0x5C, 0xBB, 0x74, + 0x85, 0xEB, 0x8C, 0xB9, 0xE3, 0xA6, 0x82, 0xE2, 0x50, 0x75, + 0xCD, 0x0B, 0x56, 0xF8, 0x9C, 0xDD, 0xAF, 0x86, 0x27, 0x57, + 0xDE, 0x14, 0x05, 0x75, 0x55, 0x90, 0xA2, 0xB3, 0xF6, 0xD4, + 0x87, 0xB8, 0x47, 0x61, 0x8E, 0x30, 0x98, 0xF1, 0x06, 0x28, + 0x8E, 0xA1, 0xE7, 0xA2, 0x7B, 0x40, 0x44, 0x58, 0x3E, 0xEF, + 0x7F, 0x93, 0x3F, 0xDE, 0xC6, 0xAC, 0xDB, 0x62, 0x8C, 0xC3, + 0x15, 0xA9, 0xA6, 0xEC, 0xE2, 0x31, 0x32, 0xD1, 0x95, 0xDA, + 0x54, 0x30, 0x38, 0xCC, 0x95, 0x48, 0x70, 0x90, 0x58, 0x54, + 0x9F, 0x32, 0x21, 0x8A, 0x22, 0x05, 0xFB, 0xE9, 0x49, 0x46, + 0x36, 0x58, 0x5A, 0xA5, 0x63, 0xB3, 0x54, 0xB5, 0xA2, 0xBB, + 0xA9, 0xF5, 0x82, 0x82, 0x87, 0xB6, 0x07, 0x1F, 0xB8, 0xDD, + 0xB4, 0x43, 0x02, 0x5D, 0xFB, 0x08, 0x89, 0x8B, 0xC8, 0xA8, + 0x11, 0xA1, 0x86, 0xAC, 0x61, 0x2D, 0x43, 0x3D, 0x0C, 0xC9, + 0x37, 0x13, 0x9E, 0xA3, 0x97, 0xA5, 0x2C, 0xCB, 0xF0, 0xC1, + 0xB5, 0x3D, 0x11, 0x61, 0x83, 0x89, 0xBE, 0x70, 0xCE, 0xB1, + 0x1B, 0x64, 0xDF, 0xBE, 0xF6, 0x39, 0x3F, 0x22, 0xBE, 0x38, + 0xC0, 0x96, 0xE2, 0xB8, 0x3B, 0xB4, 0x12, 0xEC, 0x25, 0x95, + 0x27, 0x88, 0x2C, 0x2E, 0x11, 0xEA, 0xB0, 0x9E, 0x68, 0x5D, + 0x1B, 0x9D, 0x55, 0x13, 0x24, 0x65, 0x86, 0xC5, 0xF7, 0xC8, + 0x04, 0x74, 0x02, 0xA4, 0x1F, 0xE0, 0x42, 0xC5, 0x3F, 0x6F, + 0x52, 0xAF, 0xDA, 0x14, 0x9A, 0x13, 0xCA, 0xC8, 0xEB, 0x0E, + 0xDF, 0xFB, 0x83, 0x1F, 0x82, 0x30, 0x7C, 0x9D, 0xEA, 0x83, + 0xE5, 0xB2, 0xB8, 0x7F, 0x42, 0x10, 0xD2, 0x74, 0x94, 0xA8, + 0xFC, 0xFA, 0x7F, 0x78, 0x93, 0xD8, 0xEB, 0x68, 0xD0, 0xA4, + 0x48, 0xC6, 0xCD, 0x94, 0x90, 0x13, 0xC1, 0x3E, 0x7D, 0x45, + 0x06, 0xAE, 0x02, 0x7C, 0xD4, 0xAD, 0x06, 0x0F, 0x88, 0xFA, + 0xEF, 0x2E, 0x81, 0x91, 0x01, 0xE8, 0x68, 0x90, 0x32, 0xCE, + 0x9C, 0x50, 0x52, 0x1E, 0xBA, 0x68, 0x23, 0x04, 0x79, 0x08, + 0x28, 0xCA, 0x34, 0xF9, 0x93, 0x28, 0x30, 0xAF, 0x37, 0x92, + 0x0D, 0xA8, 0x92, 0x44, 0xB2, 0x26, 0x79, 0x5F, 0xEA, 0x2E, + 0x2D, 0xF9, 0xA8, 0x03, 0x66, 0xE9, 0x24, 0xF7, 0x43, 0xDF, + 0x01, 0x5E, 0xE2, 0x49, 0x98, 0x8A, 0x9E, 0xBD, 0xFD, 0x61, + 0xF3, 0x5A, 0xF2, 0x7A, 0x04, 0x12, 0xC7, 0xC2, 0x9B, 0x9A, + 0x36, 0x9F, 0x76, 0x08, 0x48, 0xFE, 0x1C, 0x1F, 0x21, 0xBB, + 0xC6, 0x96, 0xA2, 0x13, 0xCC, 0xE4, 0x58, 0xD9, 0xD6, 0xC3, + 0xB3, 0x47, 0x10, 0x9A, 0x58, 0xA6, 0x9D, 0xFB, 0x60, 0xA3, + 0x86, 0x3B, 0xCD, 0xE5, 0xD6, 0x2A, 0x13, 0x54, 0xF8, 0x14, + 0x54, 0x3F, 0x78, 0x9A, 0xE1, 0x84, 0xCB, 0xF6, 0x9A, 0x45, + 0xA4, 0xD6, 0xAC, 0xEB, 0x39, 0xFE, 0x5A, 0x2B, 0x26, 0xBD, + 0x3D, 0xDE, 0xBE, 0xED, 0x35, 0x9C, 0x8D, 0xA2, 0x77, 0xD6, + 0xC5, 0xD9, 0x64, 0x0E, 0x1B, 0xC1, 0xCE, 0x72, 0x46, 0x4E, + 0xB2, 0x91, 0xC5, 0xD4, 0xC5, 0x4C, 0xCE, 0xAB, 0x44, 0x50, + 0x7D, 0x41, 0xF5, 0x0C, 0x3D, 0x19, 0xA1, 0x7C, 0xE1, 0x5E, + 0x5F, 0x48, 0xEE, 0x19, 0x38, 0x4E, 0x7D, 0xAE, 0x23, 0x46, + 0x1D, 0xDD, 0x78, 0x82, 0xCA, 0x4A, 0x2E, 0x1B, 0xBD, 0x88, + 0x55, 0xF8, 0x3E, 0xB2, 0x0E, 0xD2, 0x82, 0x80, 0x7E, 0x24, + 0x5A, 0x4B, 0xA5, 0xF8, 0xCF, 0x0E, 0x46, 0x80, 0x0A, 0x4B, + 0x9D, 0xF9, 0x91, 0x3E, 0x50, 0x91, 0xFE, 0xB3, 0x08, 0x7A, + 0xB2, 0xB9, 0x24, 0x8B, 0xCF, 0xE1, 0xD8, 0x1B, 0x93, 0x3E, + 0x99, 0x32, 0x67, 0x77, 0xCF, 0x80, 0xED, 0xCD, 0x82, 0x25, + 0xA5, 0xB0, 0x8A, 0x6C, 0x53, 0x7D, 0xF7, 0x4B, 0xC1, 0xAB, + 0xB8, 0xBB, 0xE7, 0x42, 0xFD, 0xC0, 0xFE, 0x1F, 0x3F, 0x2E, + 0x64, 0x39, 0x56, 0xCD, 0xF3, 0x6F, 0x05, 0x9E, 0x22, 0x12, + 0x6F, 0x9F, 0xEA, 0x5A, 0x0C, 0xCB, 0x46, 0x04, 0x77, 0x0B, + 0xAA, 0x5D, 0xFE, 0x7D, 0xE6, 0x20, 0xA8, 0xC3, 0xF4, 0x65, + 0x1F, 0x07, 0x0C, 0x37, 0x72, 0x10, 0x7E, 0x0C, 0xC6, 0xEA, + 0xF2, 0xFF, 0xFD, 0x32, 0x0C, 0x0F, 0x47, 0x57, 0x06, 0x20, + 0x68, 0x99, 0x55, 0xBB, 0x80, 0x2F, 0x9D, 0x07, 0x6C, 0x4E, + 0xB1, 0xC8, 0x70, 0xDF, 0x6E, 0x72, 0xB1, 0x3E, 0xE9, 0x78, + 0xC1, 0x2C, 0xC3, 0xB5, 0x3C, 0x0E, 0x4B, 0xFB, 0x75, 0xE3, + 0x4B, 0x3D, 0x47, 0xA2, 0xC2, 0x68, 0x65, 0xED, 0x98, 0x30, + 0x8E, 0x36, 0x90, 0x3F, 0xAF, 0x80, 0x4A, 0x9D, 0xB8, 0xF6, + 0x70, 0xDF, 0xB3, 0x46, 0x17, 0x42, 0x17, 0x3A, 0xA0, 0x5F, + 0x68, 0xF4, 0xEE, 0x0A, 0xF8, 0xCC, 0xE6, 0x84, 0xEB, 0xCC, + 0x87, 0xFE, 0xB0, 0x43, 0x6C, 0x7C, 0xFE, 0xFA, 0xC0, 0x44, + 0xA9, 0x73, 0x1B, 0x56, 0xAF, 0xE4, 0x29, 0x8B, 0x2C, 0x73, + 0x28, 0xD7, 0xEA, 0xFE, 0xC1, 0xF6, 0x06, 0xF3, 0x0D, 0x54, + 0x08, 0xD6, 0x7F, 0x05, 0xD7, 0xE6, 0x59, 0x6E, 0x6F, 0xD4, + 0xB2, 0x83, 0x91, 0xC8, 0x30, 0x66, 0x97, 0x9D, 0x7A, 0x3D, + 0x5F, 0x90, 0xEE, 0xA8, 0xF2, 0x2E, 0x00, 0x02, 0xE1, 0x9F, + 0x3D, 0x7F, 0x70, 0x8D, 0xBB, 0xF2, 0xC4, 0xCC, 0x5A, 0xCC, + 0x8B, 0x87, 0xCF, 0xAD, 0x0B, 0x60, 0x85, 0xC3, 0x24, 0xA8, + 0x11, 0x83, 0xF6, 0xE6, 0x2A, 0xE2, 0xA3, 0x0D, 0xAC, 0x87, + 0x08, 0x9C, 0xF3, 0xB5, 0xE2, 0x8E, 0x71, 0x3E, 0x9F, 0x5C, + 0xBC, 0xB3, 0xB0, 0xD7, 0xB0, 0xE7, 0x7F, 0x3A, 0x4B, 0x20, + 0xEE, 0x21, 0x7D, 0x6E, 0x8C, 0x36, 0xFD, 0xC5, 0x45, 0xCF, + 0x75, 0xB9, 0x90, 0x59, 0x0D, 0xF5, 0x52, 0xAC, 0x99, 0xD1, + 0xBC, 0xCF, 0x98, 0x3D, 0x9E, 0xDC, 0xB5, 0xEE, 0x8F, 0x02, + 0x88, 0x28, 0xEC, 0xBC, 0x93, 0x6C, 0xB0, 0x91, 0xCE, 0x38, + 0x96, 0x26, 0x9C, 0xF0, 0x78, 0xA1, 0x8D, 0x5C, 0x85, 0x16, + 0xF5, 0x6F, 0x24, 0xF3, 0xB3, 0xAD, 0x30, 0xC4, 0x5B, 0xDC, + 0xF2, 0xB1, 0xD2, 0x29, 0xC2, 0x0C, 0xA1, 0xDF, 0x66, 0xB0, + 0xD3, 0x41, 0x75, 0xBA, 0x65, 0x05, 0x94, 0x05, 0x1A, 0xF5, + 0xFE, 0x3D, 0x7F, 0x6F, 0x4A, 0xA8, 0xBE, 0xD8, 0x9A, 0x4F, + 0xB7, 0xF7, 0x60, 0x3D, 0xB3, 0x5B, 0xFE, 0x36, 0x4C, 0xEB, + 0x08, 0x5A, 0xE4, 0x7B, 0x0D, 0xF0, 0x86, 0xF4, 0x55, 0x0E, + 0x9A, 0x75, 0xCE, 0xDF, 0x72, 0x1E, 0xFC, 0xC1, 0xA1, 0x56, + 0x5A, 0xDB, 0x38, 0x79, 0xDD, 0x81, 0x59, 0x6F, 0xEA, 0x79, + 0xB4, 0xAC, 0x4C, 0x1B, 0x12, 0xF1, 0x8A, 0xAA, 0x58, 0xAE, + 0x8E, 0x9F, 0xB4, 0x4A, 0x87, 0xE0, 0x94, 0x5C, 0x02, 0x7A, + 0x52, 0xB7, 0xAB, 0x2C, 0x92, 0x3A, 0xA9, 0x4C, 0x9B, 0x1F, + 0x50, 0x4B, 0x7F, 0xF5, 0x46, 0x87, 0x1C, 0x57, 0xAA, 0x81, + 0x4C, 0x59, 0x15, 0xCF, 0xC7, 0xAC, 0x84, 0xF8, 0xC8, 0x8C, + 0xDA, 0x13, 0x3E, 0x15, 0xC7, 0x33, 0xE2, 0xAD, 0xA2, 0x25, + 0x09, 0x1C, 0xC5, 0xA5, 0xF1, 0x9C, 0xE3, 0x7E, 0xFF, 0xB6, + 0x99, 0x5A, 0xEC, 0xD4, 0xC6, 0x8B, 0x5D, 0x84, 0x35, 0xC9, + 0xDF, 0x2A, 0xF8, 0x72, 0x82, 0xDD, 0x28, 0x7D, 0xC8, 0xA8, + 0xA8, 0x15, 0x6F, 0xCE, 0x85, 0x5A, 0x69, 0x67, 0xEF, 0x68, + 0x33, 0xA6, 0xD4, 0x08, 0x20, 0xB4, 0xD8, 0xDB, 0x72, 0x3A, + 0xA8, 0x70, 0x51, 0xC1, 0x64, 0x0C, 0x8C, 0xC6, 0x29, 0x08, + 0xB0, 0xA3, 0xA3, 0x17, 0x2D, 0x8D, 0xBB, 0x80, 0xA4, 0xA6, + 0xD4, 0xA1, 0x37, 0xA3, 0x55, 0x60, 0x07, 0xBF, 0xEC, 0xF6, + 0xFE, 0x0D, 0x68, 0x18, 0x66, 0x3C, 0x95, 0xDE, 0x6E, 0x41, + 0xD3, 0xB3, 0xBD, 0x84, 0x0D, 0x32, 0x75, 0xE7, 0x32, 0x13, + 0xA5, 0xCF, 0x01, 0x17, 0x45, 0xC8, 0x49, 0xB3, 0x31, 0x79, + 0x63, 0xFE, 0x2A, 0x2F, 0x07, 0x65, 0x7E, 0x8F, 0x25, 0x2A, + 0xA4, 0xCB, 0x72, 0x80, 0x49, 0x6F, 0x15, 0x06, 0x3D, 0x69, + 0x1D, 0x36, 0x89, 0xB4, 0x08, 0xB7, 0x67, 0x15, 0x34, 0x2F, + 0xB8, 0xB7, 0x53, 0x9D, 0x10, 0x30, 0xD2, 0x5C, 0xC5, 0x56, + 0x0E, 0xCA, 0xDE, 0x2A, 0xDB, 0x17, 0xD2, 0x23, 0x35, 0x5B, + 0x2F, 0xD5, 0x09, 0x94, 0xD9, 0xD6, 0xE0, 0xE8, 0x52, 0xDC, + 0xDB, 0x51, 0x66, 0xF2, 0x27, 0xD0, 0x60, 0x63, 0xBF, 0xFE, + 0xEB, 0x7F, 0xC7, 0x59, 0x5B, 0xB6, 0x27, 0x36, 0xF9, 0x13, + 0xC5, 0xAC, 0xBE, 0x09, 0x56, 0xD3, 0x30, 0x07, 0xD3, 0x8B, + 0x4E, 0x67, 0xB3, 0x43, 0x49, 0xE2, 0xC0, 0x75, 0xBC, 0xF4, + 0x35, 0xCB, 0x64, 0x93, 0xA7, 0xC7, 0xC4, 0xF6, 0x21, 0xE0, + 0xBB, 0xE2, 0xE4, 0x44, 0x34, 0xF1, 0x6C, 0x62, 0x44, 0x89, + 0x69, 0xA7, 0x76, 0x4F, 0x22, 0x4C, 0x65, 0x2C, 0x29, 0xB1, + 0xC9, 0xBC, 0xBE, 0x3D, 0x2D, 0x9F, 0xD6, 0x3D, 0x20, 0x50, + 0x42, 0x9A, 0x05, 0x06, 0x02, 0xCC, 0x20, 0xE2, 0x0F, 0x40, + 0xE6, 0xA9, 0x63, 0xB8, 0xAE, 0x6D, 0xB1, 0x03, 0xAE, 0x88, + 0xEF, 0xA4, 0xE1, 0x01, 0x58, 0xC7, 0x8D, 0x34, 0x5B, 0x4E, + 0x6F, 0xBA, 0xAD, 0x74, 0xCE, 0xA0, 0x4B, 0x01, 0xFC, 0xE7, + 0xED, 0x8A, 0x96, 0x68, 0x29, 0x53, 0xFC, 0x9F, 0x1F, 0x40, + 0x12, 0xF1, 0x1B, 0x64, 0xFF, 0xF6, 0x47, 0x63, 0x05, 0xEF, + 0xEF, 0x98, 0x0D, 0xF5, 0xEF, 0x49, 0x06, 0x0A, 0x94, 0x39, + 0x75, 0x6C, 0x48, 0xC9, 0xC3, 0x92, 0x28, 0xD9, 0xEB, 0xD1, + 0xEE, 0x10, 0x73, 0xA8, 0xFB, 0x56, 0x81, 0x8F, 0x4E, 0x70, + 0x19, 0x59, 0x47, 0xF3, 0x6E, 0x56, 0x05, 0xE1, 0x75, 0x46, + 0x60, 0xE9, 0xE1, 0x19, 0x0A, 0xB6, 0x5A, 0xDE, 0xD4, 0x4C, + 0x2F, 0x5C, 0x18, 0x44, 0x87, 0x10, 0x14, 0x1B, 0x97, 0xCC, + 0xA6, 0xE2, 0xC6, 0xB0, 0xE0, 0x3C, 0x23, 0x95, 0xE2, 0x51, + 0xD5, 0x5E, 0x57, 0xAE, 0x88, 0x16, 0xAC, 0x8A, 0xCF, 0xC4, + 0x0D, 0xC8, 0xB7, 0x08, 0x67, 0x9F, 0xD1, 0x78, 0x7D, 0x7F, + 0x01, 0x30, 0x32, 0x64, 0xFC, 0xDD, 0x33, 0x7C, 0xEA, 0x38, + 0x0E, 0xF1, 0xBE, 0x4C, 0x98, 0x8F, 0x6F, 0xB8, 0x45, 0x4B, + 0x8D, 0x95, 0x2E, 0xBD, 0x07, 0x3A, 0xBD, 0x10, 0x07, 0xE9, + 0x48, 0xD4, 0x1F, 0x2D, 0x59, 0xDB, 0x54, 0x57, 0xA0, 0xEB, + 0x31, 0x42, 0x1D, 0xE4, 0x73, 0xB9, 0xB4, 0xAC, 0xB1, 0xD7, + 0xD4, 0x60, 0xBA, 0x7E, 0xF0, 0x4B, 0x73, 0xBA, 0xEC, 0x82, + 0x48, 0x4C, 0xB6, 0xCC, 0x4B, 0x40, 0x8B, 0xB1, 0x1F, 0xD6, + 0xB3, 0xC7, 0xE1, 0x89, 0x52, 0x22, 0x76, 0xAF, 0x14, 0xCA, + 0x34, 0x07, 0x7D, 0x8E, 0xD1, 0x2F, 0xF1, 0x53, 0x43, 0x9C, + 0x5E, 0xFA, 0x50, 0x84, 0xDE, 0x24, 0x41, 0x63, 0xDF, 0x6F, + 0x6D, 0x29, 0x30, 0x01, 0xC9, 0x08, 0xE2, 0x2E, 0xA4, 0x61, + 0xD9, 0xA0, 0x8C, 0xA5, 0x1F, 0xB8, 0x99, 0x35, 0x41, 0xA3, + 0x67, 0x85, 0x0C, 0x08, 0xC7, 0x6A, 0x4D, 0xE5, 0x47, 0x91, + 0xE5, 0x8F, 0x93, 0x0F, 0xA4, 0x38, 0xAE, 0x86, 0xAC, 0x73, + 0x4A, 0x6E, 0x27, 0x59, 0xCC, 0x3F, 0x03, 0x7A, 0x10, 0x54, + 0x45, 0x67, 0x3F, 0x7C, 0x81, 0x73, 0x96, 0x5D, 0x03, 0xD0, + 0x44, 0x63, 0x48, 0xC8, 0xDE, 0x05, 0xF1, 0xDA, 0x84, 0x5A, + 0x89, 0xE1, 0xFE, 0xF6, 0x8D, 0x45, 0xAA, 0x69, 0x04, 0xB8, + 0x58, 0x9D, 0xCA, 0x95, 0x0E, 0x62, 0x0A, 0x73, 0x1D, 0xB3, + 0xAB, 0xE8, 0x94, 0xA5, 0xFA, 0x9C, 0x4B, 0xD5, 0xF2, 0xF0, + 0x61, 0xB7, 0x2A, 0x5A, 0x67, 0x95, 0xC6, 0xEE, 0xD1, 0x61, + 0x37, 0x59, 0x6B, 0xDB, 0x9E, 0x67, 0x04, 0x97, 0x9A, 0xE0, + 0x9E, 0x45, 0x4D, 0x57, 0x0B, 0xE6, 0xF9, 0x1D, 0xBC, 0x36, + 0xFA, 0xE4, 0x64, 0x87, 0xCE, 0x3D, 0x88, 0x1B, 0x91, 0x7E, + 0x87, 0xD8, 0x4A, 0xBD, 0xB7, 0xB5, 0x2A, 0xAD, 0xD4, 0xFF, + 0x1E, 0x7D, 0xA7, 0x9C, 0x25, 0xBD, 0x81, 0xB1, 0x4E, 0x10, + 0xC0, 0x73, 0xE1, 0x89, 0xEE, 0x40, 0x79, 0x26, 0x87, 0x4B, + 0x34, 0x95, 0xFC, 0x61, 0xD8, 0x69, 0x4C, 0x81, 0x22, 0x55, + 0x0A, 0x8C, 0x49, 0xF3, 0x30, 0x7F, 0xA3, 0xB9, 0x46, 0x1C, + 0xC5, 0x7C, 0xFD, 0xF6, 0x6F, 0xF2, 0xB5, 0x9C, 0x2C, 0x5B, + 0x07, 0x65, 0x9A, 0xC0, 0x70, 0x1C, 0x11, 0x0C, 0xBC, 0x6B, + 0xE2, 0xE6, 0x60, 0x9C, 0xCC, 0xB6, 0x41, 0x80, 0x33, 0x6E, + 0x7F, 0xD4, 0xC8, 0x07, 0x48, 0x73, 0xC6, 0x0A, 0x01, 0x2B, + 0x02, 0xF3, 0x81, 0xBE, 0xFA, 0xAB, 0x04, 0x35, 0xC9, 0xAD, + 0xE4, 0x69, 0xE0, 0x5A, 0xE1, 0x18, 0x3D, 0x1E, 0x14, 0x43, + 0xEF, 0x64, 0xC4, 0x26, 0x4B, 0x79, 0x1F, 0x5E, 0x93, 0x1F, + 0x6F, 0xDA, 0x7B, 0x63, 0xA8, 0x92, 0xA8, 0x2B, 0x5F, 0x5F, + 0xD7, 0xAE, 0x88, 0x6B, 0xB6, 0x6E, 0x7D, 0xC9, 0x12, 0xFE, + 0xBE, 0xA1, 0x6B, 0xEF, 0x5C, 0xBC, 0x20, 0xC2, 0xE4, 0xAE, + 0x50, 0x3F, 0xD3, 0x58, 0xBC, 0x5B, 0x24, 0x49, 0x5A, 0x68, + 0x7C, 0xCB, 0x3C, 0x5A, 0x9A, 0x8F, 0x41, 0x7B, 0xC2, 0x93, + 0x37, 0x7F, 0xE3, 0x1A, 0x24, 0x64, 0xF3, 0xB4, 0x94, 0xEB, + 0x29, 0xE3, 0xE4, 0xBB, 0x3A, 0xA9, 0x73, 0xDD, 0xF5, 0xFE, + 0x7F, 0x75, 0x91, 0x7B, 0xC5, 0x90, 0x78, 0x3C, 0x86, 0x46, + 0x9B, 0x5F, 0x8E, 0xCC, 0x22, 0xE0, 0x93, 0x05, 0x0C, 0x62, + 0xC6, 0xB1, 0x7D, 0x92, 0x59, 0x10, 0x8F, 0x25, 0x28, 0xA5, + 0xA0, 0x2A, 0x7E, 0xB8, 0x22, 0x6E, 0x9F, 0xF2, 0x75, 0x8B, + 0x28, 0xA5, 0xA4, 0x62, 0x82, 0x56, 0x87, 0xAF, 0x7C, 0xC6, + 0x99, 0x36, 0x95, 0x58, 0x45, 0x08, 0x12, 0x4E, 0x39, 0x92, + 0xCB, 0xD7, 0xF3, 0x18, 0xA8, 0x4E, 0xB0, 0x32, 0x93, 0xA5, + 0xE7, 0x03, 0x38, 0xD3, 0x08, 0xFF, 0x83, 0xB8, 0x05, 0x37, + 0xAD, 0xF0, 0x62, 0x2F, 0x98, 0x11, 0xC7, 0x0A, 0x58, 0x02, + 0x3F, 0x1C, 0x54, 0x3F, 0x8C, 0x03, 0xF2, 0xFB, 0xBD, 0x3F, + 0xDC, 0xC2, 0x27, 0x19, 0x30, 0x83, 0x58, 0xE8, 0x06, 0x18, + 0x6D, 0x36, 0xE4, 0x41, 0x30, 0x6F, 0x94, 0x9B, 0x76, 0x0C, + 0x02, 0xE0, 0x52, 0x5C, 0x71, 0xC4, 0x56, 0xF7, 0x20, 0x5A, + 0x03, 0xC3, 0x2C, 0x50, 0xCB, 0xA7, 0x11, 0xAA, 0xD4, 0x4B, + 0x07, 0xB5, 0x22, 0xD6, 0xA5, 0x4B, 0xCE, 0xA7, 0x90, 0xCC, + 0x29, 0xA3, 0x33, 0xB3, 0xA0, 0x0E, 0xF6, 0x23, 0x12, 0xFE, + 0xAF, 0x20, 0xD0, 0x48, 0x57, 0xFA, 0xBA, 0x75, 0x3B, 0xA4, + 0x0D, 0x20, 0x66, 0x31, 0x91, 0xB1, 0x14, 0x81, 0xF0, 0x43, + 0x13, 0xF3, 0x6F, 0x09, 0xAA, 0x76, 0x66, 0xC4, 0x61, 0xC0, + 0xFD, 0x79, 0x40, 0x9B, 0x12, 0xE7, 0xC9, 0xA2, 0xBC, 0x32, + 0x6A, 0x72, 0x2E, 0x0A, 0x84, 0xB6, 0x36, 0xCA, 0x99, 0x38, + 0xB4, 0xC4, 0xDD, 0xBF, 0x53, 0xE4, 0xBB, 0xD2, 0xD3, 0x1B, + 0x62, 0x56, 0xC8, 0xD7, 0x7A, 0x0A, 0xD1, 0xD0, 0x7F, 0x65, + 0xB2, 0xE1, 0xA2, 0xCB, 0xFE, 0xE3, 0x69, 0x67, 0x97, 0xE9, + 0x27, 0x80, 0x6B, 0x5B, 0xFF, 0x5C, 0x64, 0x5C, 0x9C, 0xEA, + 0x80, 0xDD, 0x10, 0x3E, 0x4A, 0xE8, 0xD0, 0xAD, 0x3C, 0xB7, + 0xFD, 0xC5, 0x25, 0x68, 0x15, 0xFC, 0xB4, 0xB8, 0xC5, 0x30, + 0x56, 0x63, 0xB7, 0xA9, 0x57, 0x3B, 0x17, 0xE3, 0x55, 0x78, + 0x48, 0xA2, 0x9B, 0x9F, 0x49, 0x00, 0x41, 0x59, 0x72, 0x96, + 0xCB, 0x92, 0x8C, 0x58, 0x0F, 0x22, 0x4A, 0x40, 0x01, 0x1C, + 0xD0, 0xE8, 0x70, 0x85, 0x92, 0x32, 0xDC, 0x55, 0x08, 0x05, + 0x22, 0x26, 0xB3, 0x12, 0xD2, 0xF7, 0x9A, 0xD6, 0x62, 0xF6, + 0x43, 0x4A, 0xCA, 0x5C, 0xFF, 0x04, 0x43, 0x45, 0xA0, 0x85, + 0x25, 0xA5, 0x2F, 0xC6, 0x9E, 0xA8, 0xB9, 0xC0, 0xCB, 0xB1, + 0x33, 0xC8, 0x57, 0xAF, 0xB7, 0x83, 0xF8, 0xC6, 0x72, 0x8E, + 0x90, 0x45, 0x89, 0x67, 0x2C, 0x10, 0xAB, 0xBF, 0x89, 0x94, + 0xC3, 0x6F, 0x55, 0xCE, 0xE3, 0xB1, 0x9A, 0xC7, 0xA1, 0xAE, + 0x4C, 0x80, 0xC6, 0xB0, 0xF8, 0x15, 0x97, 0x66, 0xAD, 0xB7, + 0xC4, 0xFA, 0xA9, 0xF3, 0x17, 0xCD, 0x26, 0xBB, 0x9C, 0xAF, + 0x11, 0x2A, 0x32, 0xBE, 0xD1, 0x76, 0xCE, 0xF3, 0xE2, 0xCB, + 0x87, 0x2F, 0xB4, 0x90, 0x89, 0x37, 0x7F, 0x70, 0xDA, 0x64, + 0x48, 0xC3, 0x54, 0x75, 0x51, 0xC4, 0x2E, 0x98, 0x60, 0x9C, + 0x97, 0x0D, 0xD1, 0x6A, 0x75, 0xB5, 0xF0, 0x9E, 0xB5, 0x85, + 0x9A, 0x56, 0xA5, 0x9C, 0x07, 0xB7, 0x9F, 0x16, 0x52, 0xBD, + 0x8C, 0xDC, 0xB5, 0x1C, 0x3D, 0x28, 0xA4, 0x60, 0xF6, 0x73, + 0x94, 0x94, 0x96, 0xE4, 0x9A, 0x46, 0x98, 0xEC, 0x0B, 0x96, + 0x43, 0x03, 0xE9, 0x46, 0x3F, 0xC0, 0x06, 0x0B, 0xDB, 0xC2, + 0xFB, 0xAB, 0xF9, 0xA9, 0xC1, 0xDA, 0xC8, 0x60, 0x8D, 0xFC, + 0x0D, 0xDD, 0x85, 0x18, 0x8C, 0x3D, 0xF2, 0x40, 0x2F, 0x4B, + 0xA4, 0x0C, 0xFE, 0x2A, 0x9D, 0xEE, 0xA3, 0xED, 0xA1, 0x05, + 0xC7, 0xA9, 0x35, 0xF7, 0x7A, 0x94, 0xF5, 0xF0, 0x6F, 0xC4, + 0x26, 0x20, 0xBE, 0x11, 0x29, 0x98, 0x08, 0x33, 0x76, 0x04, + 0xE1, 0x2B, 0x60, 0xFD, 0x9C, 0xD1, 0x26, 0xDC, 0x1A, 0x9C, + 0x9D, 0x55, 0x21, 0xB3, 0x45, 0x32, 0x60, 0xBF, 0x97, 0x4C, + 0xBF, 0x3E, 0x34, 0x78, 0x5C, 0x09, 0x7A, 0xA2, 0xD9, 0xAF, + 0xA0, 0x43, 0xBA, 0x52, 0xC2, 0x11, 0xAD, 0x59, 0xA3, 0xE8, + 0x29, 0x37, 0x84, 0xD0, 0x0B, 0xBC, 0xC3, 0x15, 0x7E, 0x66, + 0xF9, 0x03, 0x8E, 0x50, 0x08, 0xDB, 0x2D, 0x0F, 0xED, 0x30, + 0xF6, 0x5D, 0x7D, 0xB7, 0x03, 0x5C, 0x1D, 0x3B, 0x43, 0x55, + 0x7E, 0xDB, 0x39, 0x9D, 0xD4, 0x50, 0x17, 0xF9, 0x1A, 0x20, + 0xA7, 0xA3, 0x5B, 0xA1, 0x44, 0x1C, 0xD0, 0xF9, 0x13, 0x1A, + 0x5B, 0x8F, 0x7F, 0x1F, 0x9F, 0xFF, 0x87, 0x2E, 0x29, 0xE4, + 0xE3, 0xFE, 0x51, 0x0B, 0x2C, 0x81, 0x54, 0xF9, 0xE5, 0x60, + 0xBF, 0x68, 0xAF, 0xBA, 0x1E, 0x28, 0x32, 0x31, 0x1D, 0x23, + 0x27, 0x6D, 0x24, 0xA5, 0x13, 0xB8, 0x53, 0xF6, 0xF3, 0xA6, + 0x95, 0x76, 0x35, 0xA6, 0x1B, 0x53, 0x21, 0x99, 0x91, 0xF9, + 0xD7, 0x75, 0x1C, 0x35, 0x7D, 0xED, 0x90, 0x1E, 0x0D, 0x76, + 0x46, 0xEE, 0x39, 0xE9, 0x74, 0x12, 0xB9, 0xE2, 0xEF, 0x92, + 0xBD, 0x2F, 0x20, 0x6C, 0xDF, 0x16, 0xD4, 0xCA, 0xCC, 0x5D, + 0x09, 0x0B, 0xD2, 0x9A, 0xAD, 0x64, 0xE8, 0x57, 0x5E, 0xE5, + 0x1B, 0x3D, 0xD2, 0xE0, 0x1A, 0x8C, 0x63, 0xE1, 0x8D, 0x2B, + 0x3F, 0x81, 0x77, 0xEE, 0x60, 0xBF, 0x59, 0xBE, 0xC9, 0x9A, + 0x69, 0x18, 0x01, 0xE2, 0x93, 0x19, 0x57, 0x28, 0x13, 0xFD, + 0x08, 0x05, 0xE9, 0x6C, 0x9B, 0xBE, 0x46, 0xB7, 0xCC, 0x81, + 0xBF, 0xAB, 0xF6, 0x11, 0x95, 0x35, 0xE2, 0xCB, 0xF0, 0x22, + 0x56, 0x2A, 0xD2, 0x57, 0x55, 0x77, 0x2F, 0x72, 0xE6, 0x62, + 0xFD, 0xAB, 0x90, 0xF4, 0xA4, 0x38, 0x71, 0x79, 0xA3, 0x23, + 0x58, 0xA0, 0x1C, 0x7C, 0xA4, 0x27, 0xA9, 0x4F, 0x3D, 0x1D, + 0xE7, 0x6E, 0x17, 0x04, 0x0D, 0xC2, 0x4B, 0xD7, 0x0B, 0x23, + 0x6D, 0x77, 0xCB, 0x6D, 0x16, 0x0B, 0x83, 0x4A, 0x51, 0x28, + 0xE2, 0x36, 0xFB, 0x24, 0xBA, 0x16, 0x06, 0x80, 0x5E, 0xB0, + 0x43, 0xEE, 0x3B, 0xC5, 0x03, 0x5C, 0xB4, 0xB0, 0xD8, 0x55, + 0xF2, 0x32, 0xA0, 0x30, 0x8B, 0xDD, 0xF1, 0x2C, 0x23, 0xA6, + 0x7F, 0x5F, 0xB2, 0x96, 0xED, 0x20, 0x59, 0x5D, 0x63, 0x86, + 0x26, 0xB4, 0x29, 0x01, 0x36, 0x5E, 0x0F, 0x00, 0x04, 0x8B, + 0xD5, 0x13, 0x9A, 0xB9, 0xC4, 0x8B, 0x7C, 0x78, 0xCE, 0x99, + 0x20, 0x63, 0x6D, 0x31, 0x1C, 0x00, 0x7D, 0x3E, 0x10, 0xD4, + 0x76, 0xA0, 0x5A, 0x9D, 0x3C, 0x65, 0xAA, 0xD1, 0x10, 0x2D, + 0xD6, 0x69, 0xF4, 0x28, 0xBF, 0xC7, 0x69, 0xC3, 0xE8, 0x1A, + 0xBB, 0xEC, 0xA3, 0x66, 0xC1, 0x8C, 0x81, 0x8F, 0xC3, 0xF2, + 0xCB, 0x21, 0x31, 0x43, 0xBA, 0x84, 0xEE, 0xA5, 0x7C, 0x0A, + 0x2C, 0x97, 0xA2, 0xFB, 0xFA, 0x89, 0xB5, 0xD9, 0x2E, 0x0D, + 0x29, 0xC0, 0xEC, 0x1C, 0x98, 0x58, 0xE2, 0xC0, 0xFA, 0x04, + 0xFA, 0x0A, 0xA3, 0x79, 0x0D, 0xA4, 0x3F, 0x08, 0x8A, 0x59, + 0xDA, 0x3D, 0xD1, 0x0A, 0x26, 0x7A, 0x4B, 0x52, 0xB3, 0x9D, + 0x4C, 0x43, 0x20, 0x61, 0x2B, 0x1A, 0x8C, 0x3F, 0x6F, 0xCA, + 0xB0, 0x9C, 0x36, 0xEB, 0x95, 0x47, 0x97, 0x51, 0x0B, 0x91, + 0xF1, 0xE8, 0xA7, 0x65, 0x0E, 0x90, 0x10, 0xEC, 0xB1, 0xA0, + 0xEE, 0x4D, 0xEE, 0x17, 0xEF, 0xE6, 0xF9, 0x60, 0x8E, 0xF6, + 0x51, 0xCA, 0x82, 0x90, 0x24, 0x82, 0xA7, 0xBA, 0x56, 0xA9, + 0x30, 0xA7, 0x0C, 0x1A, 0xE7, 0x2D, 0xF4, 0xF2, 0x17, 0xAA, + 0xC9, 0xEC, 0xEE, 0xAF, 0x0A, 0x75, 0x33, 0xD3, 0x7D, 0x66, + 0x72, 0x0E, 0x91, 0x1B, 0x15, 0x06, 0xCB, 0x0A, 0x99, 0xA3, + 0x7A, 0x50, 0xA1, 0x0D, 0xAD, 0x90, 0xA3, 0xCF, 0x3E, 0xE6, + 0xA8, 0x08, 0x0C, 0xDB, 0x45, 0x4D, 0x61, 0x47, 0xBF, 0x26, + 0xA7, 0xC4, 0xED, 0x36, 0x2B, 0xA9, 0x49, 0xF4, 0x18, 0xD9, + 0x63, 0x79, 0x53, 0xBC, 0xED, 0xC0, 0x45, 0x49, 0x76, 0x9D, + 0x09, 0x24, 0xC6, 0x68, 0x79, 0x76, 0x42, 0xA1, 0x4B, 0xEA, + 0x0B, 0x6A, 0x67, 0x8A, 0xFE, 0xAF, 0x44, 0x50, 0xAC, 0x9C, + 0xA1, 0x60, 0x1F, 0xC4, 0x6E, 0x32, 0x57, 0xE4, 0x3F, 0x60, + 0x9D, 0x85, 0xFA, 0x55, 0x9C, 0xDE, 0x1C, 0x28, 0xEB, 0xF9, + 0x97, 0x9F, 0xA9, 0x8F, 0x45, 0x11, 0xD0, 0x02, 0x12, 0xCB, + 0x82, 0xB5, 0x41, 0x3D, 0x65, 0x31, 0xD3, 0xFF, 0x64, 0x54, + 0x6E, 0xC3, 0xF7, 0x26, 0x5C, 0xB8, 0xC6, 0x6B, 0xD1, 0x13, + 0x54, 0xB6, 0x60, 0xD3, 0xA4, 0x57, 0xF3, 0x21, 0x7A, 0xB8, + 0x0C, 0xBE, 0x5F, 0x61, 0xB1, 0xD4, 0xD1, 0x09, 0x29, 0x1A, + 0x6B, 0x57, 0x04, 0x9B, 0xFD, 0x74, 0x7E, 0x52, 0x39, 0xC0, + 0xA4, 0xAF, 0x31, 0xC9, 0x89, 0x1A, 0x95, 0x18, 0xBA, 0x38, + 0xC9, 0x94, 0xEE, 0x11, 0x22, 0x04, 0x91, 0x49, 0x6D, 0xAA, + 0x18, 0x4B, 0xF2, 0xA2, 0x2F, 0x73, 0x99, 0xCA, 0x80, 0x7C, + 0x80, 0x8D, 0xB2, 0x20, 0x90, 0x71, 0xB4, 0x2D, 0xF8, 0xDE, + 0xA9, 0x6E, 0x17, 0x93, 0xA6, 0x7F, 0x79, 0x2D, 0xCB, 0xF1, + 0x0F, 0x50, 0x39, 0x97, 0xDD, 0xD5, 0x7E, 0x17, 0x2C, 0xBA, + 0x39, 0x5F, 0x84, 0x65, 0x02, 0x68, 0x16, 0x89, 0x4D, 0x2A, + 0x59, 0x12, 0x59, 0x7E, 0xEE, 0x61, 0x95, 0x88, 0x8D, 0x98, + 0xEA, 0x58, 0x2D, 0x3B, 0x47, 0xB0, 0x5C, 0xAB, 0x92, 0x4F, + 0x2C, 0x71, 0x17, 0xCD, 0x20, 0xE1, 0xF3, 0xB1, 0x17, 0xAA, + 0xF8, 0x6C, 0x3A, 0x68, 0x7D, 0xFD, 0x40, 0x16, 0x67, 0xEE, + 0xE3, 0xF3, 0xEF, 0xE3, 0x26, 0x5B, 0xDD, 0x5E, 0xD3, 0x94, + 0xE2, 0xC2, 0xA0, 0xCA, 0x1D, 0x21, 0xC9, 0x86, 0x31, 0x9B, + 0x98, 0x95, 0xA9, 0x0E, 0xC7, 0xD4, 0xD8, 0xAE, 0x99, 0xA4, + 0x64, 0xE9, 0x51, 0x95, 0x28, 0x08, 0xA2, 0x16, 0x06, 0x49, + 0x6D, 0x58, 0xD4, 0x13, 0x09, 0xEA, 0x50, 0xBE, 0xBB, 0xB7, + 0x8A, 0x67, 0x8E, 0x1E, 0x9E, 0x28, 0x23, 0xE8, 0x5E, 0x5A, + 0xF8, 0x7D, 0x92, 0x40, 0x5C, 0xA2, 0xA8, 0x3C, 0xC3, 0x7F, + 0xD3, 0x6F, 0x24, 0x1B, 0xEB, 0xD5, 0x99, 0xC2, 0x8F, 0x9A, + 0x04, 0xF0, 0x92, 0xC5, 0x9E, 0xB2, 0x09, 0x0E, 0x5B, 0x2F, + 0xC1, 0x57, 0xEA, 0xAB, 0x72, 0x12, 0xFA, 0x5B, 0x29, 0x9A, + 0x60, 0x9F, 0x71, 0xF4, 0x8B, 0x9A, 0x0F, 0x9C, 0xCE, 0xB9, + 0x9D, 0xBC, 0xA5, 0xEE, 0x09, 0x93, 0x2F, 0xD3, 0xF6, 0x63, + 0x34, 0x38, 0xD0, 0x10, 0x73, 0x70, 0xEC, 0xAC, 0xB2, 0x69, + 0xF9, 0xEC, 0x2A, 0xAB, 0xCA, 0xF5, 0x27, 0xB1, 0xAC, 0x84, + 0xA1, 0xC8, 0x1B, 0x3A, 0xEC, 0x2E, 0x92, 0x9B, 0xD9, 0xE5, + 0x2C, 0x8F, 0x41, 0x7F, 0x9B, 0x0C, 0x17, 0xC3, 0xAD, 0xEC, + 0xC7, 0x18, 0x38, 0x0F, 0xC7, 0xE2, 0x80, 0x85, 0xD9, 0x71, + 0x7A, 0x14, 0x03, 0x9D, 0x4C, 0x0A, 0xDD, 0x17, 0x42, 0xAD, + 0x1F, 0xC9, 0x3F, 0xA2, 0x70, 0x83, 0x16, 0x13, 0xC9, 0xBD, + 0x4F, 0x2B, 0x4D, 0xAE, 0x04, 0xC7, 0xF6, 0xC3, 0xC7, 0xEA, + 0x02, 0xFC, 0xDC, 0x2C, 0x05, 0x08, 0x3F, 0x20, 0xE7, 0xA1, + 0xB7, 0xC5, 0x2D, 0xEC, 0xE4, 0xFC, 0xBD, 0x97, 0x3B, 0xDB, + 0x4E, 0xBC, 0x81, 0x48, 0x6A, 0xCE, 0x43, 0x53, 0x96, 0xD0, + 0x46, 0xA1, 0xBF, 0xAE, 0x2D, 0x9B, 0x21, 0xA7, 0x19, 0xB5, + 0x89, 0xA4, 0xCB, 0x6E, 0xD5, 0x7E, 0xEB, 0x15, 0xE5, 0x55, + 0x99, 0x7E, 0x48, 0x6B, 0x9C, 0xF6, 0xF3, 0xE0, 0xB0, 0x2A, + 0xE0, 0x04, 0xD3, 0xFB, 0x81, 0xE4, 0x1A, 0x46, 0x5C, 0x4E, + 0xF5, 0x26, 0xBF, 0xE3, 0x75, 0x86, 0x22, 0xBC, 0xD7, 0x9B, + 0xE1, 0x52, 0x54, 0x93, 0x4D, 0xE8, 0x71, 0x2D, 0xFB, 0x07, + 0xC9, 0xDB, 0x82, 0xED, 0xB4, 0xC4, 0xD6, 0x8E, 0x91, 0xD9, + 0x2F, 0x8F, 0x85, 0x13, 0x75, 0x6B, 0xC3, 0x63, 0xC4, 0x24, + 0xF1, 0x5D, 0x55, 0x67, 0x57, 0x4F, 0x25, 0x73, 0x78, 0x42, + 0xE1, 0x45, 0x3E, 0x6E, 0x8A, 0x5F, 0x15, 0x53, 0xD7, 0x5F, + 0x66, 0xC6, 0x47, 0xE2, 0xFD, 0x17, 0x09, 0x15, 0x32, 0xA4, + 0x86, 0x8F, 0x8E, 0x00, 0x86, 0x6E, 0x06, 0x42, 0x3A, 0xBE, + 0xBB, 0xD9, 0xEA, 0x00, 0x95, 0x42, 0xA8, 0x50, 0xD0, 0xA9, + 0x71, 0x8E, 0x94, 0x09, 0xD8, 0x35, 0x31, 0x8D, 0x7E, 0x36, + 0xE7, 0x8D, 0x44, 0x78, 0x5B, 0x9D, 0xC3, 0x0D, 0x96, 0x03, + 0xEF, 0x49, 0x07, 0xA7, 0x43, 0x41, 0x8E, 0xF7, 0xD6, 0x42, + 0x06, 0x92, 0x0A, 0x6F, 0xDC, 0xDC, 0xA8, 0xB1, 0xF0, 0x60, + 0xA0, 0x6F, 0xB6, 0xA2, 0x42, 0x9E, 0xC0, 0xCB, 0x6C, 0x84, + 0x8A, 0x99, 0x60, 0x66, 0xE2, 0x05, 0xD0, 0x02, 0xBC, 0xEC, + 0xE5, 0x43, 0x67, 0x85, 0x0C, 0x54, 0x5D, 0x3C, 0x7B, 0x9D, + 0x77, 0xBB, 0x16, 0x5C, 0x51, 0x31, 0xF8, 0x27, 0xE0, 0xFC, + 0x36, 0xC9, 0xCA, 0xBB, 0x44, 0x19, 0xF5, 0xCF, 0x01, 0xA6, + 0xDD, 0x5D, 0x64, 0x26, 0xFC, 0xDE, 0x49, 0xED, 0xCF, 0x3F, + 0x67, 0xF1, 0x1D, 0xA9, 0xB9, 0x8C, 0x3D, 0xC0, 0x7C, 0xF0, + 0x67, 0x6D, 0x75, 0xA7, 0x2E, 0xA6, 0x0D, 0xCC, 0xE9, 0xE9, + 0x05, 0x7F, 0xFE, 0x4F, 0x51, 0x83, 0xCA, 0xC0, 0xF5, 0x29, + 0x93, 0xAC, 0x8B, 0x83, 0xB2, 0x67, 0xA3, 0xFB, 0x5B, 0x2D, + 0xD1, 0x96, 0xD8, 0x50, 0xE4, 0xB0, 0xC9, 0xF2, 0xF0, 0xE4, + 0x07, 0x7E, 0x7C, 0xD2, 0x76, 0x6B, 0x46, 0x57, 0x27, 0x09, + 0x24, 0x27, 0xE7, 0x00, 0x3E, 0x35, 0x9D, 0x93, 0x67, 0x4F, + 0xC7, 0x01, 0xD4, 0x49, 0x42, 0x6F, 0x78, 0xF5, 0x07, 0x99, + 0x65, 0x11, 0x00, 0xF3, 0x6A, 0x5C, 0xFB, 0x0C, 0x2F, 0xD6, + 0xEB, 0x29, 0x7D, 0x59, 0x6A, 0x52, 0xB6, 0x82, 0x07, 0x04, + 0x8D, 0x39, 0x93, 0x3E, 0xFC, 0x80, 0xF9, 0x87, 0x78, 0xBD, + 0x06, 0xEA, 0x9E, 0x09, 0xFB, 0x5B, 0x25, 0x96, 0x3B, 0xB5, + 0x34, 0x50, 0x9C, 0x6E, 0xED, 0xBA, 0x6D, 0xCA, 0x49, 0xE9, + 0x12, 0xEF, 0xE9, 0xA6, 0x0B, 0x28, 0xAF, 0x33, 0xB0, 0x73, + 0x2A, 0x4D, 0xBE, 0xBE, 0xD6, 0x73, 0x13, 0xA9, 0x38, 0x6B, + 0xA3, 0xBA, 0xDC, 0x3F, 0xE3, 0x6D, 0x82, 0x0D, 0x18, 0x1A, + 0x36, 0xA2, 0x2F, 0xBE, 0xD0, 0xD4, 0x6C, 0xCD, 0x56, 0x18, + 0xD5, 0xC6, 0x92, 0x5C, 0xF7, 0x80, 0x32, 0xDF, 0xF7, 0xE4, + 0x78, 0x0C, 0xED, 0x4D, 0xC0, 0x4A, 0x0D, 0x21, 0x8E, 0xB2, + 0xCD, 0xB9, 0x73, 0xC1, 0xD7, 0x45, 0x7E, 0xCB, 0x60, 0x31, + 0x7A, 0xD9, 0x54, 0x71, 0x0E, 0xE1, 0x09, 0x74, 0x02, 0x5C, + 0xE4, 0xF1, 0xD4, 0xF9, 0x35, 0x11, 0x0F, 0xF5, 0xA9, 0x04, + 0x11, 0xB1, 0x9B, 0x13, 0xC5, 0x93, 0x69, 0x89, 0xBC, 0x5E, + 0x45, 0x1A, 0x36, 0xF9, 0x6E, 0x80, 0xCD, 0xA1, 0x2F, 0xE1, + 0x62, 0xFE, 0x6D, 0x27, 0x75, 0xF7, 0x21, 0x61, 0xF6, 0x0A, + 0x12, 0x79, 0x5E, 0x7C, 0x98, 0x7C, 0xC0, 0x2E, 0xF9, 0x14, + 0xC6, 0x58, 0x20, 0xAB, 0xB5, 0x17, 0x96, 0x55, 0xF0, 0x61, + 0x95, 0x04, 0x30, 0xB5, 0x58, 0xD6, 0x00, 0x53, 0x55, 0x09, + 0x64, 0xDF, 0x2D, 0xA2, 0x98, 0xEA, 0x9F, 0x28, 0x11, 0xF7, + 0x54, 0x7D, 0x05, 0xDC, 0xF8, 0xD0, 0x1A, 0xE6, 0x58, 0xC2, + 0x2A, 0x95, 0x05, 0x81, 0xB7, 0xE1, 0x12, 0x90, 0xE1, 0x03, + 0xC3, 0x28, 0x4D, 0x23, 0x2C, 0x5C, 0x9A, 0xB0, 0x01, 0xC7, + 0xB8, 0x82, 0x11, 0x31, 0x6E, 0x1D, 0x62, 0x38, 0xBD, 0xFD, + 0xED, 0xCF, 0x54, 0x07, 0xE6, 0xF7, 0xAE, 0x96, 0x1A, 0x10, + 0xD8, 0x2C, 0xE4, 0xFF, 0xD7, 0xAF, 0x0A, 0xEB, 0xDF, 0x3D, + 0x36, 0x77, 0x52, 0x5E, 0x25, 0x85, 0x2A, 0x75, 0x39, 0x00, + 0xD4, 0x28, 0x20, 0x51, 0x0F, 0x4F, 0xBD, 0xFD, 0xF7, 0xE9, + 0x45, 0x4B, 0x3E, 0x47, 0x57, 0x41, 0x70, 0xA6, 0x40, 0x1F, + 0x9E, 0x48, 0xD0, 0x24, 0xFD, 0x58, 0x3A, 0xC7, 0xB3, 0xF3, + 0x5A, 0x2A, 0x34, 0xC8, 0x30, 0x84, 0x91, 0x63, 0x63, 0x49, + 0x1B, 0x4E, 0x74, 0x22, 0xDE, 0xF2, 0x8C, 0x54, 0x5A, 0xF2, + 0x4B, 0x22, 0xCE, 0xCD, 0x79, 0x1C, 0x42, 0xC8, 0xB8, 0x85, + 0x5D, 0x11, 0xC7, 0x44, 0xA8, 0x50, 0x25, 0xB2, 0x0D, 0x39, + 0x0F, 0x68, 0x0C, 0x22, 0x0F, 0xE4, 0xAB, 0x51, 0x79, 0xC5, + 0x22, 0x32, 0x4B, 0x90, 0xBB, 0xEF, 0x04, 0xC8, 0x64, 0x87, + 0xCA, 0x8F, 0x72, 0x60, 0xCE, 0x0A, 0xA3, 0x39, 0x29, 0x68, + 0x7E, 0x27, 0xE1, 0x41, 0x09, 0x70, 0x95, 0xA0, 0xE3, 0x06, + 0x00, 0xF4, 0x7B, 0xC2, 0x72, 0xFD, 0xF7, 0x6B, 0x2C, 0x50, + 0x0A, 0xE2, 0x6E, 0x10, 0x52, 0x2A, 0x0B, 0xAF, 0xD1, 0xA9, + 0x8C, 0xF7, 0x91, 0xB6, 0xFE, 0x1E, 0x2F, 0xA0, 0xC0, 0x73, + 0xF5, 0x98, 0x09, 0x78, 0x33, 0xC9, 0xC4, 0xF7, 0x89, 0x5F, + 0xEF, 0x4A, 0xE3, 0x60, 0x42, 0xC7, 0x22, 0xFF, 0x78, 0xA4, + 0x28, 0x30, 0xC1, 0xF5, 0xDF, 0x5E, 0x7D, 0x2E, 0xE3, 0x8E, + 0xFA, 0x22, 0xBA, 0x0B, 0xE8, 0x4C, 0xB8, 0x2F, 0x44, 0x63, + 0x5A, 0xF3, 0x5D, 0x87, 0x50, 0x59, 0x6B, 0x91, 0x3F, 0xD1, + 0x4C, 0xEA, 0x79, 0xDE, 0xB6, 0x63, 0xAC, 0x43, 0xE1, 0x58, + 0x57, 0x5C, 0x9B, 0x43, 0xE2, 0x71, 0xB3, 0x79, 0x79, 0xC8, + 0x39, 0xEE, 0xC6, 0x85, 0xC6, 0x62, 0x2F, 0x25, 0xA2, 0x13, + 0x91, 0xC7, 0xE2, 0xF5, 0xE5, 0x93, 0x86, 0xB8, 0x2E, 0xEF, + 0x4F, 0xC5, 0x72, 0x4F, 0x5E, 0xA4, 0x50, 0x03, 0xDD, 0x8B, + 0x5E, 0x37, 0x73, 0xB1, 0xD8, 0xDC, 0x08, 0xCF, 0x1A, 0x39, + 0xFD, 0x53, 0x96, 0x1C, 0x26, 0xBE, 0x3C, 0xD8, 0xBF, 0xEF, + 0x93, 0x5F, 0x1D, 0x97, 0x4B, 0xCB, 0xED, 0x4F, 0xD6, 0xC6, + 0x19, 0x01, 0x77, 0xD3, 0xFB, 0xC4, 0x4B, 0xEC, 0x5C, 0x00, + 0xD1, 0x0C, 0xD4, 0x71, 0x35, 0x6C, 0x58, 0xE5, 0x8C, 0x9D, + 0x08, 0xF5, 0xC8, 0xDD, 0x41, 0x6C, 0x58, 0x15, 0x8A, 0x03, + 0xA2, 0xE1, 0x9B, 0x02, 0xC7, 0xD6, 0xD1, 0x3E, 0x9C, 0xB7, + 0x02, 0xCC, 0x1D, 0x0B, 0xCC, 0xB8, 0x34, 0x85, 0xA6, 0x21, + 0x21, 0xF5, 0xED, 0x8D, 0xFB, 0x10, 0x4C, 0xD5, 0x7E, 0x62, + 0x2A, 0x22, 0x3A, 0xE6, 0x24, 0x3A, 0x76, 0x4C, 0x39, 0xC9, + 0xE2, 0x4A, 0x07, 0x6B, 0x99, 0xB0, 0x01, 0x36, 0x8B, 0x48, + 0x03, 0x85, 0xDC, 0x61, 0xBC, 0x3A, 0x71, 0x3B, 0xC7, 0x05, + 0x26, 0xA3, 0x8C, 0x1C, 0x5C, 0x2B, 0x3D, 0xC0, 0xC2, 0xCA, + 0xA4, 0xD0, 0x94, 0xD6, 0x11, 0x5B, 0xBC, 0xA7, 0xA2, 0xF6, + 0x66, 0x0D, 0x08, 0x91, 0x15, 0x94, 0x57, 0xC1, 0x49, 0xD2, + 0xDD, 0x44, 0x53, 0x57, 0x70, 0x5F, 0xB4, 0x62, 0x84, 0x9D, + 0x28, 0x42, 0x54, 0x55, 0xB5, 0xB1, 0xEA, 0xF3, 0xAE, 0xCB, + 0xB7, 0x59, 0xBF, 0xE1, 0x14, 0xE7, 0xD6, 0xB3, 0x68, 0xA4, + 0xE2, 0x97, 0xC7, 0x98, 0x6E, 0x21, 0xEC, 0x59, 0xC0, 0x9C, + 0x1C, 0x65, 0x8D, 0x07, 0x2F, 0x8D, 0xC2, 0x89, 0xD5, 0xE1, + 0x3C, 0x5E, 0xBB, 0x53, 0xDB, 0x2A, 0xAC, 0xB2, 0xF6, 0x2A, + 0x5C, 0x5C, 0x85, 0x0D, 0xCE, 0xBB, 0x50, 0xFF, 0xBB, 0x7D, + 0x5D, 0xDA, 0xBD, 0x50, 0x34, 0xCF, 0x8F, 0x72, 0x6B, 0x77, + 0xF6, 0x04, 0xA6, 0x1D, 0xCD, 0x74, 0x5C, 0x9D, 0x84, 0xD2, + 0x81, 0x47, 0x90, 0x12, 0xD0, 0x55, 0xE5, 0x1D, 0x4F, 0xD9, + 0x2D, 0x60, 0x1C, 0xC5, 0xCC, 0x64, 0xA5, 0x85, 0x34, 0x64, + 0x2F, 0x18, 0x9C, 0x0D, 0x08, 0x16, 0x0F, 0x22, 0xBC, 0x36, + 0x95, 0x8B, 0x96, 0x8E, 0xA5, 0x71, 0xDC, 0xB1, 0x8F, 0x4E, + 0xE0, 0x7E, 0xA4, 0x81, 0xE2, 0x02, 0x3C, 0x5D, 0x25, 0xE3, + 0x37, 0xED, 0xDA, 0x06, 0xB5, 0xC5, 0x4C, 0x46, 0x39, 0xD2, + 0x6D, 0x1A, 0x72, 0xAB, 0xFE, 0xA1, 0x30, 0xFE, 0x41, 0x05, + 0xB3, 0x45, 0x5B, 0xEE, 0x71, 0x19, 0xC1, 0x26, 0xC6, 0x53, + 0x55, 0xFD, 0x0F, 0xAE, 0x70, 0x4D, 0x0E, 0xDC, 0xA7, 0x14, + 0x56, 0x6D, 0xA9, 0xC2, 0x72, 0x09, 0x36, 0x1C, 0x7E, 0xB0, + 0xD7, 0x99, 0x04, 0x68, 0xCC, 0xFD, 0xE2, 0x8B, 0x69, 0x8E, + 0xC6, 0x7E, 0x89, 0x5B, 0x50, 0x0E, 0xB0, 0x50, 0x7D, 0x5B, + 0x38, 0xC6, 0x74, 0x93, 0x35, 0x6D, 0x71, 0x8C, 0xD1, 0xEE, + 0x7C, 0x42, 0x33, 0x77, 0xF9, 0x51, 0xF1, 0x58, 0xE0, 0x67, + 0xF0, 0xEC, 0x72, 0xA9, 0x9B, 0x7E, 0x13, 0xD8, 0xB4, 0x15, + 0xC9, 0x5F, 0x3E, 0x7A, 0x99, 0x0D, 0x6F, 0x0B, 0x9B, 0xE2, + 0x6D, 0xA9, 0xD0, 0x33, 0x4A, 0x40, 0xA9, 0x14, 0xB2, 0x4A, + 0x85, 0xB4, 0xDD, 0xC7, 0x29, 0xBA, 0xEE, 0xED, 0x5E, 0x93, + 0x96, 0x19, 0x3F, 0xEC, 0xA4, 0x8B, 0x08, 0x6C, 0x79, 0x7E, + 0xC5, 0x7D, 0x82, 0x2C, 0x7F, 0xAC, 0x94, 0x68, 0x9E, 0xA4, + 0x21, 0x8A, 0x54, 0x81, 0x3A, 0xD8, 0xBA, 0x1A, 0xBB, 0xE8, + 0x00, 0x6B, 0x4D, 0xC4, 0x36, 0x64, 0x7E, 0x2F, 0x59, 0xCC, + 0x0F, 0xFE, 0x61, 0xC0, 0x47, 0xD6, 0xC8, 0xC2, 0x3D, 0xFF, + 0x85, 0x0C, 0xB7, 0x6A, 0x45, 0xCB, 0x96, 0xF4, 0xFB, 0x3D, + 0xF9, 0x33, 0x2C, 0x6C, 0x05, 0xD6, 0x1E, 0x5B, 0xA6, 0x3E, + 0x2F, 0x14, 0xBE, 0xC2, 0x63, 0x9E, 0xC8, 0xC2, 0xBC, 0x2A, + 0x8B, 0x21, 0x9B, 0x44, 0xD2, 0x2D, 0xD8, 0x02, 0x41, 0x32, + 0xBD, 0x58, 0x31, 0x62, 0xC1, 0x8A, 0xD5, 0x37, 0xBB, 0x11, + 0xBC, 0x9D, 0xEB, 0xCF, 0x80, 0x88, 0x37, 0xE2, 0x64, 0xA0, + 0x06, 0xFA, 0x4A, 0x79, 0xFD, 0x4E, 0x50, 0xA3, 0x39, 0xCF, + 0x33, 0x14, 0xD2, 0x5C, 0xD1, 0x20, 0xFA, 0x64, 0xAC, 0x31, + 0xD5, 0x70, 0x0A, 0xCB, 0xF9, 0x02, 0x5C, 0xE4, 0xAA, 0xE9, + 0xF8, 0xE0, 0xF0, 0x0E, 0xB7, 0xCE, 0x3A, 0x98, 0x98, 0x88, + 0x85, 0xA1, 0xD8, 0x1C, 0xEC, 0x41, 0xB1, 0x19, 0x1E, 0x68, + 0x52, 0x3A, 0xDE, 0xE2, 0x82, 0x15, 0x41, 0x28, 0x59, 0x78, + 0xD1, 0xEE, 0x2D, 0x4F, 0x87, 0x9F, 0x0C, 0x8A, 0x2C, 0x2C, + 0x7D, 0x90, 0xDF, 0x15, 0x76, 0xED, 0x66, 0x39, 0x09, 0xE3, + 0xB9, 0x61, 0x72, 0x41, 0x02, 0x4F, 0x1D, 0x10, 0x52, 0xDB, + 0x98, 0x5F, 0xF6, 0x3D, 0x7C, 0x3C, 0xB5, 0x45, 0x25, 0xA5, + 0xDB, 0x6A, 0x03, 0xDE, 0x71, 0x18, 0x42, 0x2A, 0x5F, 0xE2, + 0xD0, 0xF8, 0xFE, 0xAD, 0xD2, 0xC3, 0x52, 0x79, 0x55, 0x42, + 0xA2, 0x0D, 0xE0, 0x77, 0xB2, 0x3A, 0xD2, 0x63, 0x47, 0xA4, + 0xE7, 0xE8, 0x9B, 0x93, 0xD1, 0xE9, 0x6D, 0x75, 0xE6, 0x1D, + 0xF8, 0xE1, 0x43, 0x09, 0x7A, 0xFE, 0xCA, 0xEE, 0x4C, 0xA5, + 0x62, 0x93, 0x94, 0xD4, 0x6A, 0x7C, 0xA1, 0xB6, 0xFC, 0xFE, + 0x6B, 0xE0, 0xF4, 0x8A, 0x33, 0x06, 0x33, 0xD6, 0x3D, 0xC5, + 0x4E, 0x20, 0xDD, 0x7E, 0xCA, 0xA5, 0x68, 0x18, 0x60, 0x65, + 0xF2, 0x7D, 0x9A, 0x5F, 0xE6, 0x8B, 0x9C, 0x9A, 0xF1, 0x7B, + 0x7C, 0x00, 0x86, 0xCF, 0xAF, 0x55, 0x85, 0xF7, 0x71, 0xAE, + 0x5E, 0x15, 0xB1, 0x02, 0x27, 0xEF, 0xC1, 0x01, 0xF0, 0xB6, + 0x1E, 0x31, 0x9B, 0xCC, 0xAD, 0xD5, 0x9B, 0x0D, 0x70, 0x0F, + 0x8C, 0x3E, 0xDB, 0xE4, 0x2C, 0xF6, 0xE7, 0xC5, 0x63, 0x00, + 0xF6, 0xC7, 0xF1, 0x42, 0xBE, 0xBE, 0xD2, 0x9A, 0x5C, 0x28, + 0x5E, 0xE8, 0x77, 0x95, 0x85, 0xB5, 0x26, 0x41, 0x0C, 0xD7, + 0xD0, 0x37, 0x8D, 0x9A, 0x9E, 0x71, 0xA5, 0x23, 0x43, 0xF3, + 0xF8, 0x2F, 0x07, 0xE8, 0x49, 0x9D, 0x7C, 0xE0, 0xB8, 0xA5, + 0xFB, 0x2B, 0x7F, 0x5F, 0x21, 0xD7, 0x85, 0xFA, 0xBF, 0x32, + 0x74, 0x35, 0x88, 0x08, 0xAC, 0x0E, 0x83, 0x62, 0xE8, 0xFC, + 0xE0, 0x57, 0x9A, 0x7A, 0x3E, 0xF0, 0xF2, 0x5D, 0x0E, 0xA5, + 0x0C, 0x5E, 0xFD, 0x49, 0xCA, 0x5C, 0xA6, 0x81, 0x2E, 0xA3, + 0xAE, 0xBB, 0x2D, 0xEF, 0xFD, 0x7F, 0x79, 0x94, 0x16, 0xA9, + 0x4A, 0xC8, 0x6C, 0xAB, 0x20, 0xE4, 0x5D, 0xAF, 0xB2, 0x7D, + 0x13, 0xCC, 0x47, 0xD8, 0x0B, 0xD6, 0x5C, 0x67, 0x1D, 0x41, + 0xE7, 0x14, 0x62, 0x67, 0xD4, 0x37, 0x3F, 0x4B, 0xEB, 0xD2, + 0x7C, 0x68, 0x3F, 0x23, 0xB0, 0xE9, 0xA4, 0xFE, 0xE6, 0x18, + 0x33, 0x64, 0xB6, 0x1C, 0x2F, 0x6E, 0xF8, 0x04, 0xAB, 0x1C, + 0x08, 0x7C, 0x0A, 0x08, 0xC9, 0x32, 0x86, 0x9D, 0x75, 0x6F, + 0x59, 0xCC, 0x7C, 0xFD, 0xF8, 0x47, 0xC9, 0x56, 0x59, 0x50, + 0x69, 0x65, 0xA1, 0xB1, 0xDE, 0x08, 0xF6, 0x41, 0x4D, 0x9D, + 0x68, 0x70, 0x77, 0x64, 0xAA, 0x8B, 0xD2, 0x4B, 0x53, 0x69, + 0x78, 0x60, 0x58, 0x77, 0xDC, 0x4D, 0xCB, 0x02, 0xEF, 0x3A, + 0x2E, 0xD6, 0x5D, 0x02, 0x7C, 0x39, 0x5F, 0xFE, 0x6C, 0x18, + 0xAD, 0xD3, 0x57, 0x9A, 0x81, 0x1C, 0x7C, 0x17, 0xA4, 0x68, + 0xC6, 0x9A, 0xBD, 0x79, 0xA9, 0xA4, 0xA3, 0x32, 0xF1, 0x4B, + 0xA7, 0x59, 0x30, 0xB0, 0xEF, 0x5F, 0x22, 0xD2, 0xE3, 0x32, + 0xA3, 0xBB, 0x90, 0x83, 0xCB, 0xCC, 0x33, 0x38, 0x50, 0x64, + 0x70, 0xCC, 0xDB, 0x84, 0x7F, 0xBB, 0xBC, 0xB6, 0x39, 0x59, + 0xC0, 0x0D, 0x07, 0x69, 0x98, 0xCB, 0xA5, 0x1A, 0xFF, 0xF2, + 0x85, 0x45, 0xC2, 0x70, 0x87, 0x03, 0xA4, 0x51, 0x88, 0xC4, + 0xB5, 0x02, 0xFB, 0x05, 0x15, 0xA2, 0x8A, 0x0A, 0x67, 0x18, + 0xBC, 0x0A, 0x5B, 0x35, 0x1B, 0xDA, 0x2A, 0xA3, 0xCD, 0x62, + 0x52, 0x57, 0xEE, 0x20, 0xA7, 0x56, 0xB7, 0xB3, 0xA5, 0x4A, + 0xB5, 0xAD, 0x63, 0x68, 0xCB, 0x85, 0x9C, 0xA2, 0xBC, 0x72, + 0x4F, 0x3D, 0xC3, 0x10, 0xBB, 0xCF, 0x1D, 0x49, 0x21, 0xD9, + 0x51, 0x4C, 0x6A, 0xAE, 0xA3, 0x6A, 0x40, 0x24, 0xE9, 0x89, + 0xC0, 0x09, 0x3F, 0x40, 0x28, 0x96, 0x46, 0xDA, 0x36, 0x4B, + 0x57, 0xA7, 0xAC, 0xC3, 0x26, 0xEB, 0x79, 0x93, 0x02, 0x9B, + 0xAA, 0x5F, 0xDE, 0x3A, 0x63, 0xD7, 0x8F, 0x0D, 0x29, 0xE7, + 0xC7, 0xEE, 0xA8, 0x34, 0x5B, 0xE1, 0xC3, 0x4D, 0x38, 0xB1, + 0x30, 0x37, 0x11, 0xB8, 0xA3, 0x29, 0x7F, 0x09, 0x5E, 0xD4, + 0x45, 0x6E, 0x3C, 0x87, 0x73, 0x61, 0xE0, 0x84, 0xF8, 0xEA, + 0xD5, 0xBE, 0xD1, 0xD6, 0x6E, 0x0D, 0x0B, 0xD7, 0x3E, 0x44, + 0x36, 0xB3, 0x33, 0x5C, 0x80, 0x01, 0x0A, 0x4C, 0xD3, 0xEA, + 0x9E, 0x05, 0xCA, 0x65, 0x7B, 0x06, 0x97, 0x35, 0xF0, 0x51, + 0x32, 0x91, 0x2D, 0x3D, 0x62, 0x45, 0x37, 0x9B, 0xCB, 0x3B, + 0x45, 0x25, 0xDA, 0xA6, 0x6A, 0x7D, 0x2B, 0x83, 0xC0, 0x38, + 0x61, 0x21, 0xA1, 0x8D, 0x6F, 0x7A, 0xF6, 0x19, 0xDD, 0xC2, + 0x5C, 0x5B, 0x04, 0x92, 0x29, 0x00, 0x9F, 0x25, 0x4C, 0x96, + 0x5F, 0x6D, 0xAB, 0x94, 0x8E, 0x58, 0x4F, 0x5E, 0xB8, 0x3A, + 0x4E, 0x93, 0x52, 0x31, 0xF5, 0x4C, 0x18, 0x8E, 0x69, 0x31, + 0xF1, 0x06, 0xA9, 0xCC, 0x7D, 0x25, 0x1A, 0xFC, 0xF3, 0x05, + 0x6F, 0xAC, 0xC2, 0xEA, 0x15, 0x58, 0xE8, 0x59, 0x9C, 0xB6, + 0x13, 0xEF, 0x01, 0xA2, 0x8B, 0xD0, 0x9B, 0xC3, 0x17, 0xEC, + 0xAD, 0x10, 0x2E, 0x76, 0x7A, 0x7D, 0x06, 0x2D, 0x25, 0x88, + 0x74, 0x22, 0x84, 0x67, 0x77, 0xA9, 0x12, 0x03, 0x5C, 0x49, + 0xE4, 0x55, 0x38, 0x41, 0xD6, 0x96, 0x54, 0x57, 0x86, 0x89, + 0x96, 0x59, 0x0A, 0x3A, 0x1B, 0x2A, 0x86, 0x8F, 0xA1, 0x77, + 0xAA, 0xC9, 0x31, 0xB7, 0x79, 0xDE, 0x5E, 0x52, 0x26, 0x12, + 0xB8, 0x81, 0xFB, 0x72, 0xD2, 0x44, 0x1D, 0xF9, 0xBC, 0x8A, + 0x87, 0x1A, 0xB1, 0x13, 0xAD, 0xB7, 0x31, 0x19, 0x76, 0xB5, + 0x8D, 0x43, 0x8B, 0x9C, 0x72, 0xB1, 0xDF, 0xAD, 0xE3, 0x64, + 0x4E, 0x16, 0x07, 0xD8, 0x86, 0xED, 0x39, 0x83, 0x17, 0xE9, + 0xA1, 0xB7, 0x16, 0x0E, 0x95, 0x60, 0xF8, 0x6A, 0xCC, 0x40, + 0xE2, 0xDA, 0xBE, 0x31, 0xCF, 0x27, 0x7F, 0x4C, 0xA7, 0x35, + 0xA6, 0x83, 0x27, 0x3C, 0x2F, 0xC0, 0x0C, 0xD6, 0x5A, 0x9B, + 0xC3, 0xEF, 0x60, 0x30, 0x07, 0xB0, 0xD2, 0x44, 0xEC, 0x7A, + 0x3F, 0xC4, 0x7F, 0xF3, 0x88, 0xB8, 0xF1, 0xC0, 0x35, 0x37, + 0x49, 0xE9, 0xB0, 0x2F, 0xEF, 0x0E, 0xFF, 0xC9, 0x8A, 0xD7, + 0x7E, 0xA1, 0x55, 0x63, 0x09, 0xE5, 0xCE, 0xF8, 0xB9, 0xB2, + 0xC1, 0xA5, 0x28, 0x6A, 0xFB, 0xBA, 0xC4, 0x98, 0x10, 0x0C, + 0xF3, 0x65, 0x4A, 0xC5, 0x2F, 0x98, 0x23, 0x66, 0x61, 0x88, + 0x17, 0x10, 0xFE, 0x84, 0x68, 0x5D, 0x4A, 0xA7, 0x68, 0x3B, + 0x9F, 0x1D, 0x5E, 0x82, 0x32, 0x35, 0xBA, 0x5B, 0x7F, 0x0F, + 0x51, 0x47, 0x4E, 0x59, 0xFF, 0xDF, 0x30, 0x3D, 0xEC, 0x51, + 0xEC, 0xD4, 0x99, 0x13, 0x7B, 0x97, 0x78, 0x19, 0x93, 0xB5, + 0x63, 0x11, 0xC4, 0x60, 0x62, 0xC6, 0xAC, 0x8E, 0xF1, 0x49, + 0x23, 0xA4, 0xCA, 0x9C, 0x66, 0xC9, 0x55, 0xA6, 0x3B, 0x12, + 0x01, 0xDD, 0x3C, 0x3B, 0xB6, 0x43, 0x0B, 0x1A, 0x40, 0x15, + 0xF9, 0x3F, 0x4A, 0xBA, 0xDE, 0xE2, 0x69, 0x05, 0x05, 0x87, + 0x8B, 0xDE, 0xDF, 0x79, 0x13, 0xBF, 0x16, 0xE0, 0xB6, 0x67, + 0x8C, 0x1B, 0x04, 0x86, 0xF7, 0xF9, 0x43, 0x20, 0xC8, 0x11, + 0xF2, 0x93, 0x28, 0x24, 0xE8, 0x41, 0x49, 0xB1, 0xA9, 0xEE, + 0x7A, 0xD1, 0x09, 0x5D, 0xBA, 0x74, 0x92, 0x08, 0xC5, 0x49, + 0x16, 0x2D, 0x71, 0x51, 0x3C, 0x61, 0xFE, 0x8E, 0x02, 0x23, + 0xC0, 0xA0, 0xA0, 0xDD, 0x7A, 0x9C, 0xB7, 0x48, 0x98, 0x91, + 0x47, 0x8F, 0xC7, 0x31, 0xCD, 0xB8, 0x99, 0x06, 0xF6, 0xAD, + 0xCD, 0x6C, 0x3C, 0x7D, 0xFE, 0xB3, 0xC8, 0x26, 0x85, 0x1C, + 0xC0, 0x75, 0x89, 0xC0, 0x89, 0xC7, 0xA7, 0x85, 0x51, 0x43, + 0x3F, 0xA2, 0xCE, 0x6A, 0xF8, 0x97, 0xE8, 0xA4, 0x43, 0x0E, + 0xE0, 0xA2, 0x03, 0x32, 0x8F, 0x1B, 0x9C, 0x59, 0x41, 0x84, + 0x07, 0x4A, 0x0A, 0xA4, 0xFE, 0xB8, 0xF6, 0xC5, 0xD0, 0xDA, + 0x16, 0xC9, 0x0F, 0x89, 0xCF, 0xC6, 0x00, 0x75, 0xE7, 0x50, + 0x6E, 0xED, 0xE3, 0x36, 0xDC, 0x68, 0xBF, 0x93, 0xA0, 0xE0, + 0xEF, 0xFF, 0x40, 0xC7, 0x7E, 0x33, 0x6A, 0xE9, 0x8F, 0xEC, + 0x51, 0x19, 0xB4, 0x0B, 0xE7, 0x62, 0x56, 0x1E, 0xBA, 0x48, + 0xFE, 0x1B, 0x42, 0xBC, 0xFD, 0x53, 0xE0, 0x92, 0x8C, 0x8A, + 0x4B, 0x23, 0x16, 0x8D, 0xCD, 0x9E, 0xB4, 0x2E, 0x7B, 0x22, + 0xA2, 0x5B, 0x9A, 0x87, 0x50, 0x19, 0xBA, 0xAB, 0x91, 0xD7, + 0x41, 0xF7, 0xF0, 0x84, 0xDF, 0x8E, 0x53, 0x10, 0x9C, 0x7E, + 0x78, 0xBE, 0xCF, 0xAA, 0xA8, 0xF6, 0x2F, 0x88, 0x14, 0x34, + 0x29, 0xA6, 0x7D, 0x05, 0x50, 0x73, 0x00, 0xE4, 0x0C, 0x19, + 0x62, 0x18, 0x17, 0xDC, 0x56, 0xEE, 0x87, 0xB5, 0x65, 0xB3, + 0xA4, 0x7F, 0x82, 0xF4, 0x19, 0x3F, 0xE7, 0x2B, 0x86, 0xDF, + 0x39, 0x9E, 0x5E, 0x5D, 0x09, 0x0D, 0x99, 0xCC, 0x74, 0x46, + 0x82, 0xAC, 0xB9, 0xAA, 0x58, 0x26, 0xF8, 0xD3, 0xCC, 0xFE, + 0xD6, 0xE7, 0x23, 0xA3, 0x1B, 0x97, 0x7A, 0xB5, 0xA7, 0xC2, + 0xFC, 0xCD, 0x41, 0x39, 0xB8, 0x0B, 0x11, 0x93, 0x7B, 0x73, + 0x6F, 0x80, 0xD4, 0xD8, 0x2B, 0x3E, 0x39, 0xFA, 0x2A, 0x29, + 0x19, 0x1D, 0xF1, 0x42, 0x09, 0x46, 0x73, 0x34, 0x46, 0xF7, + 0xAA, 0x95, 0xF9, 0x3C, 0xDC, 0x01, 0x77, 0xAB, 0xA5, 0x33, + 0x76, 0xC3, 0xA0, 0x44, 0x09, 0x02, 0x93, 0xC8, 0x5D, 0x07, + 0xCF, 0x94, 0x1D, 0xDB, 0x99, 0xBB, 0xDA, 0x43, 0xE9, 0xF6, + 0x6B, 0x69, 0x92, 0x6C, 0x02, 0x7A, 0x8C, 0x34, 0x74, 0xF4, + 0xDD, 0x76, 0xD0, 0x4D, 0x1B, 0x1B, 0x0B, 0x0D, 0xFA, 0xDF, + 0xA1, 0x93, 0x45, 0xA3, 0x8F, 0x48, 0x0B, 0x28, 0xF5, 0xBD, + 0x98, 0x79, 0x63, 0xAD, 0xF1, 0x53, 0x06, 0xA5, 0xC7, 0xC0, + 0x01, 0x3B, 0xB9, 0xE2, 0x8F, 0x09, 0x80, 0xCC, 0x43, 0x09, + 0xFD, 0x07, 0x80, 0x4E, 0xFF, 0xF9, 0xFD, 0x77, 0x02, 0xE8, + 0x1C, 0x2E, 0xB4, 0x64, 0x67, 0x80, 0x5B, 0x07, 0x08, 0x5F, + 0xA7, 0x91, 0x6C, 0xEB, 0x50, 0x66, 0x35, 0x3B, 0xC8, 0x76, + 0x36, 0x62, 0xC4, 0xCE, 0x50, 0xE2, 0x7B, 0x06, 0x0F, 0xBB, + 0xE5, 0x1F, 0x44, 0xF1, 0x20, 0x55, 0x16, 0x8F, 0x5B, 0x45, + 0xD8, 0x07, 0x79, 0xFE, 0xD2, 0x1F, 0xDB, 0xEF, 0x4C, 0x51, + 0x87, 0x11, 0xF3, 0x42, 0xF9, 0xED, 0xB6, 0x84, 0x61, 0xFC, + 0xC8, 0xF7, 0x82, 0xA0, 0x6E, 0xD6, 0xCB, 0xA5, 0x47, 0xFD, + 0xD9, 0x0C, 0x40, 0x74, 0x45, 0xF6, 0xA8, 0x26, 0x24, 0x73, + 0xCD, 0x92, 0xCD, 0x7D, 0x43, 0x7B, 0x97, 0xD9, 0x77, 0xC2, + 0xE5, 0x7D, 0x09, 0x48, 0x2B, 0xA6, 0x59, 0x4D, 0xD3, 0xEC, + 0x54, 0xF0, 0x7D, 0xFC, 0x4E, 0x0F, 0x04, 0xE1, 0x55, 0x81, + 0xE9, 0xF1, 0xD1, 0x11, 0x5C, 0xA9, 0xDA, 0xC3, 0x76, 0x8F, + 0x8B, 0xE5, 0x1B, 0x32, 0x54, 0x76, 0xF9, 0xE6, 0x36, 0x67, + 0x9F, 0x87, 0x96, 0xA1, 0xCA, 0xE4, 0xC9, 0x15, 0x33, 0xD9, + 0x14, 0xCD, 0xC1, 0xBD, 0x6B, 0x74, 0xF5, 0xDE, 0xB1, 0x93, + 0xD2, 0x08, 0x2A, 0x77, 0x9E, 0xED, 0x14, 0xB1, 0x9B, 0x2A, + 0x60, 0x01, 0x4C, 0x41, 0x3E, 0xA7, 0x84, 0x20, 0xFF, 0x22, + 0x20, 0xF9, 0xB0, 0xF9, 0x36, 0xB4, 0x5E, 0xC1, 0xD7, 0x26, + 0xB3, 0xAC, 0xF1, 0xD5, 0xA9, 0xDA, 0xDC, 0x7A, 0x0D, 0x76, + 0x69, 0x0B, 0xD7, 0xF4, 0x2C, 0x1F, 0xF9, 0x85, 0x83, 0x67, + 0xE8, 0x97, 0x2E, 0x2C, 0x62, 0xD8, 0x37, 0x36, 0xE4, 0xD8, + 0x5B, 0x87, 0xAD, 0x27, 0xCA, 0xFA, 0x20, 0xD7, 0xAB, 0x71, + 0x72, 0xEF, 0x0F, 0xAA, 0x79, 0x08, 0xFF, 0x03, 0x45, 0x77, + 0x9C, 0xC6, 0x55, 0xB9, 0xF5, 0xC2, 0xCD, 0xD0, 0x48, 0xEC, + 0x5F, 0x75, 0x45, 0x28, 0x91, 0x64, 0xC2, 0xD4, 0xB2, 0x0E, + 0xD6, 0x0D, 0x6D, 0xB1, 0x2F, 0xF7, 0x7D, 0x43, 0x1B, 0xDA, + 0x81, 0xF0, 0xBA, 0x98, 0xC6, 0x35, 0x03, 0xE1, 0x8D, 0x33, + 0x2C, 0x9E, 0x44, 0x87, 0x37, 0xE4, 0xF4, 0x7C, 0x1B, 0xB4, + 0x1F, 0xA0, 0x29, 0xE5, 0x59, 0x95, 0xE9, 0x1A, 0xC4, 0x1B, + 0xEF, 0x62, 0xE3, 0xE8, 0x66, 0x2D, 0xB4, 0x95, 0x19, 0x49, + 0xC2, 0x54, 0x85, 0x32, 0x86, 0x80, 0xD3, 0x29, 0x66, 0x54, + 0x91, 0x55, 0xF0, 0x70, 0x08, 0x6A, 0x2D, 0x5D, 0x63, 0x5C, + 0xF8, 0xD9, 0xAC, 0x40, 0xD9, 0x08, 0x44, 0x3B, 0xDC, 0xBA, + 0x9F, 0x5E, 0x4E, 0x4D, 0x50, 0x0C, 0x2F, 0x6D, 0x51, 0x6B, + 0xDE, 0xFB, 0x2D, 0x73, 0xF1, 0x36, 0xF7, 0x60, 0x23, 0x4E, + 0x42, 0x41, 0x02, 0x19, 0x03, 0x1A, 0xDA, 0x8C, 0x10, 0x48, + 0xBB, 0xFF, 0x71, 0xA3, 0xD9, 0x44, 0x81, 0x70, 0x33, 0xBE, + 0x71, 0x2E, 0x0F, 0xC2, 0xBB, 0xE7, 0xDD, 0xDA, 0xFB, 0x02, + 0x91, 0x90, 0x04, 0x68, 0x8A, 0x44, 0x07, 0x38, 0x40, 0x5E, + 0xF2, 0x1E, 0x79, 0x2B, 0x58, 0xA3, 0x39, 0xB5, 0xFB, 0xEE, + 0x3E, 0xD1, 0xDA, 0x9F, 0x2B, 0x5C, 0xD3, 0xC5, 0x38, 0x22, + 0xFC, 0xC8, 0x3A, 0x29, 0x94, 0xC8, 0xA8, 0x01, 0xF8, 0x71, + 0xB7, 0x51, 0xDA, 0xB2, 0x71, 0x2B, 0x5E, 0xB6, 0xA8, 0x3F, + 0x71, 0x9A, 0x72, 0x56, 0x60, 0x2A, 0x8C, 0x07, 0x67, 0x37, + 0x29, 0x1D, 0x47, 0x8A, 0xEB, 0x7F, 0x2F, 0xBF, 0x47, 0x1A, + 0x1F, 0x19, 0xB3, 0x4E, 0x8C, 0x9F, 0x9C, 0xB0, 0x1A, 0xDE, + 0xC0, 0xE1, 0x58, 0xE1, 0x03, 0x56, 0x22, 0x5E, 0x4E, 0x49, + 0xF3, 0x0A, 0x58, 0xBF, 0xD9, 0x08, 0xDD, 0x13, 0xB4, 0xAA, + 0x5A, 0x48, 0xAC, 0x0E, 0x97, 0x8C, 0xEC, 0x41, 0x7B, 0xDC, + 0xC4, 0xA7, 0x0D, 0xA0, 0x30, 0x98, 0xA8, 0x3D, 0x8F, 0xB3, + 0x1F, 0xD3, 0x11, 0x4E, 0xB1, 0xD2, 0x82, 0x25, 0xFA, 0x77, + 0xD6, 0xF8, 0x99, 0x37, 0x20, 0x9B, 0xD1, 0xE1, 0x56, 0x84, + 0xFC, 0x0F, 0x9C, 0x52, 0xBC, 0x25, 0x87, 0x54, 0x7F, 0xB4, + 0x03, 0x91, 0xA7, 0xA1, 0xF4, 0x1F, 0x4E, 0x60, 0x2E, 0x68, + 0x1D, 0xFB, 0x93, 0x98, 0xB7, 0x85, 0x53, 0xA4, 0x58, 0x2B, + 0x41, 0x7D, 0xAF, 0x53, 0x2B, 0xEE, 0x42, 0x27, 0xF5, 0x0C, + 0xA6, 0x53, 0x60, 0x9D, 0x44, 0x62, 0x01, 0x71, 0x39, 0x8A, + 0x15, 0xEC, 0xDB, 0xBA, 0xCB, 0x6D, 0x9C, 0xB5, 0x05, 0xF4, + 0x6F, 0xF2, 0x18, 0xDB, 0x90, 0x90, 0x43, 0x33, 0x8B, 0x2B, + 0x2E, 0xAF, 0xA4, 0x16, 0x48, 0x4A, 0xF0, 0x1A, 0x9E, 0x41, + 0xC2, 0x7A, 0xFA, 0x13, 0xFC, 0xE0, 0xE0, 0x6D, 0x80, 0x30, + 0xA4, 0x86, 0x2B, 0xB2, 0x73, 0x28, 0xF2, 0x41, 0xDC, 0x14, + 0xBF, 0x9F, 0x9E, 0x2C, 0x2B, 0x28, 0x17, 0x1D, 0x69, 0xF2, + 0xD1, 0x47, 0xF1, 0x40, 0x71, 0x1B, 0x3C, 0x32, 0xDF, 0x2F, + 0xC0, 0x4B, 0x45, 0xF8, 0xB4, 0x57, 0x11, 0x72, 0x4F, 0x88, + 0x79, 0xB3, 0xEB, 0x3D, 0x56, 0x45, 0x4D, 0x66, 0x49, 0x4B, + 0xE9, 0x25, 0x28, 0x0F, 0x99, 0x9E, 0xA7, 0x79, 0xFC, 0x2E, + 0xF2, 0x10, 0x6B, 0xC7, 0x13, 0x94, 0x71, 0x35, 0xC2, 0x94, + 0xFD, 0xF5, 0x17, 0x61, 0x37, 0xF6, 0x43, 0xBC, 0x1A, 0xC6, + 0x44, 0x0F, 0xC2, 0x3F, 0x79, 0xDF, 0xC8, 0xAF, 0x8D, 0xC8, + 0x67, 0xE5, 0x10, 0x3F, 0x5A, 0x1A, 0xA1, 0x3B, 0xC0, 0xF7, + 0x71, 0x76, 0xC9, 0xA2, 0xB9, 0xAC, 0xB9, 0xDE, 0xD6, 0x73, + 0x4D, 0xA1, 0xBC, 0x26, 0x1F, 0xCD, 0xDD, 0xBA, 0x79, 0xD1, + 0xCF, 0x1D, 0x14, 0x28, 0x72, 0x78, 0x89, 0xD3, 0xA0, 0xE4, + 0x2E, 0x32, 0x24, 0x95, 0xE6, 0xF3, 0x88, 0xB7, 0x30, 0x74, + 0x3F, 0x18, 0xE0, 0x1A, 0x54, 0x7F, 0xCC, 0xF5, 0x27, 0xC2, + 0xE8, 0x0A, 0x9D, 0x7A, 0x88, 0xB5, 0xAF, 0xAF, 0x5C, 0xA0, + 0x70, 0x4A, 0x04, 0x30, 0x52, 0xE6, 0xBC, 0x4A, 0x86, 0x1E, + 0xD5, 0xFC, 0xBE, 0x41, 0xDC, 0x78, 0x2F, 0x86, 0xEF, 0xFB, + 0x04, 0x67, 0x57, 0x61, 0xE1, 0xE0, 0x4A, 0x41, 0x35, 0xE7, + 0xA2, 0x79, 0x15, 0x8F, 0xA4, 0x73, 0x22, 0x23, 0x03, 0x42, + 0x41, 0x35, 0x2E, 0x09, 0x06, 0x62, 0x26, 0x3D, 0x69, 0xCA, + 0xCA, 0x9F, 0x33, 0xA4, 0x52, 0xFE, 0x66, 0x66, 0x12, 0xA4, + 0xED, 0x90, 0x86, 0x6E, 0xF6, 0x27, 0xA2, 0xE1, 0x2B, 0xFB, + 0x3D, 0x65, 0x76, 0x1C, 0x1C, 0x86, 0x7A, 0x7E, 0xA7, 0xF9, + 0x1E, 0xE4, 0x7B, 0xD7, 0xC6, 0x2A, 0x69, 0x9D, 0x15, 0xCE, + 0x55, 0xE5, 0x93, 0x83, 0x0A, 0xD7, 0xDF, 0x6B, 0x0F, 0x2D, + 0x4C, 0x8D, 0x38, 0x2D, 0x01, 0xB3, 0x54, 0xA9, 0x8D, 0xB5, + 0x52, 0x04, 0x71, 0x66, 0x4A, 0xBA, 0x8D, 0x56, 0x97, 0x42, + 0xC7, 0x01, 0xC3, 0xF5, 0x72, 0x3B, 0x01, 0xE5, 0xCD, 0xA9, + 0x61, 0x34, 0xE4, 0x5F, 0x32, 0xF8, 0xCD, 0xE0, 0x4B, 0x89, + 0x08, 0x37, 0x86, 0xDA, 0x6A, 0x87, 0x70, 0x52, 0x07, 0xC5, + 0x4B, 0xE4, 0x4E, 0xC1, 0x08, 0x89, 0x39, 0xE9, 0x4C, 0x96, + 0xA8, 0x2F, 0xAF, 0x56, 0x9D, 0xA1, 0x03, 0x27, 0x39, 0xED, + 0x09, 0xB4, 0x83, 0x53, 0x39, 0xC5, 0xE5, 0x6E, 0x1B, 0x8A, + 0x4E, 0xC1, 0xCE, 0xE9, 0x36, 0xF8, 0xD0, 0x60, 0xF9, 0x1B, + 0x4A, 0xD5, 0xDC, 0x4B, 0x25, 0xB5, 0x33, 0xCF, 0x6A, 0x65, + 0xAD, 0x9B, 0xC7, 0xCA, 0xF8, 0x04, 0xA3, 0x84, 0x57, 0xF6, + 0x2D, 0xDE, 0x14, 0xE0, 0x59, 0xA0, 0xC2, 0xCD, 0xEA, 0xA2, + 0xC4, 0x3D, 0x71, 0xE0, 0x8C, 0x52, 0xE0, 0xFE, 0x34, 0x1F, + 0x61, 0x71, 0xB6, 0xED, 0xDF, 0x49, 0x72, 0xA5, 0x4E, 0xE3, + 0x8D, 0x7C, 0x1D, 0x16, 0xA4, 0x9F, 0x0D, 0xB7, 0x6E, 0x49, + 0x28, 0xB4, 0xB4, 0x8C, 0x63, 0x63, 0x1A, 0xC1, 0xB1, 0x43, + 0x3A, 0xC1, 0x6C, 0x6A, 0xFA, 0x8E, 0x55, 0x0D, 0xC0, 0x4A, + 0x7F, 0xEC, 0xF9, 0xC1, 0x69, 0xA7, 0x02, 0x8B, 0x57, 0x03, + 0x33, 0xD9, 0xBA, 0x06, 0x7C, 0x79, 0xD5, 0x89, 0x89, 0xEC, + 0xD9, 0x1D, 0x83, 0x20, 0xBA, 0x35, 0x23, 0xF0, 0xEA, 0x01, + 0xC9, 0x73, 0xDB, 0x03, 0x44, 0x45, 0x54, 0xA9, 0x9C, 0xB6, + 0x5A, 0x61, 0xFC, 0xF9, 0xA0, 0x32, 0xBF, 0x15, 0xB7, 0xD2, + 0xBD, 0x67, 0xF3, 0x1A, 0x20, 0x52, 0x5E, 0x2B, 0x51, 0x37, + 0x76, 0x09, 0x45, 0xD5, 0x14, 0x66, 0x8B, 0x9D, 0x3E, 0x4E, + 0xA3, 0xE0, 0xF7, 0xC7, 0x54, 0x60, 0x3D, 0xE0, 0xC0, 0x95, + 0x32, 0xC0, 0x5A, 0x20, 0xB7, 0xBA, 0x76, 0xA3, 0x3E, 0x47, + 0x1E, 0x1A, 0xD5, 0x36, 0xD2, 0x1C, 0x8D, 0x08, 0x41, 0xFE, + 0x24, 0x4F, 0x35, 0x8C, 0x1E, 0xF5, 0xAE, 0x0D, 0xB1, 0xDB, + 0x78, 0x99, 0x94, 0x76, 0xD3, 0x33, 0x4F, 0xB2, 0x4D, 0x4F, + 0xAE, 0x33, 0x40, 0x1F, 0x8B, 0x4A, 0x7F, 0xFF, 0x4A, 0x46, + 0xE8, 0x3C, 0x65, 0x35, 0x30, 0x0E, 0x43, 0x04, 0x3B, 0x8E, + 0xEB, 0x47, 0xD1, 0x69, 0x3E, 0x25, 0x10, 0x4D, 0x91, 0xF5, + 0x72, 0xAE, 0xF6, 0x39, 0x2C, 0xCA, 0x96, 0xA0, 0x3A, 0x46, + 0xBA, 0x98, 0x2F, 0xD6, 0x60, 0x63, 0x57, 0xBC, 0x18, 0x5D, + 0x1F, 0xA9, 0xDD, 0x1A, 0x69, 0x99, 0x57, 0x84, 0xF8, 0xE7, + 0x28, 0x12, 0xC7, 0x29, 0x39, 0x69, 0xB3, 0x7A, 0xB4, 0x06, + 0xC6, 0x80, 0x64, 0x0E, 0xB8, 0xAD, 0xB0, 0x48, 0xED, 0x42, + 0x7F, 0xBD, 0x6B, 0xF8, 0xDE, 0x22, 0x36, 0xE3, 0xE1, 0x96, + 0x93, 0xE5, 0x87, 0x0B, 0x6E, 0x3B, 0x04, 0x2D, 0x2D, 0x8C, + 0x60, 0x8D, 0xD8, 0x1F, 0x24, 0x62, 0x7D, 0xBE, 0x56, 0xA7, + 0x14, 0x73, 0x8A, 0xC4, 0x33, 0x24, 0x87, 0xBF, 0xB3, 0xA2, + 0xBE, 0xB0, 0xCE, 0x34, 0x98, 0x68, 0x9F, 0xE9, 0x0A, 0x01, + 0x73, 0xDA, 0xD5, 0xD3, 0xF6, 0x63, 0x5B, 0xB3, 0xD0, 0x75, + 0x23, 0x34, 0x97, 0x3A, 0xDC, 0xD9, 0x5E, 0x03, 0x76, 0xA2, + 0xF6, 0xA4, 0x0D, 0x73, 0x6D, 0x09, 0xB3, 0xF9, 0x28, 0xC0, + 0x06, 0xCF, 0x30, 0xEA, 0x85, 0xC8, 0x1C, 0x06, 0x7A, 0x69, + 0x44, 0x82, 0x37, 0x52, 0x1F, 0x2B, 0xB9, 0x96, 0x9A, 0xCC, + 0x4F, 0x0A, 0xF2, 0x62, 0x34, 0x64, 0x67, 0x45, 0x6C, 0x3A, + 0x7F, 0x26, 0xB4, 0xBE, 0xE4, 0x9E, 0x10, 0x55, 0x66, 0x5B, + 0xE0, 0x3C, 0x31, 0x33, 0xB6, 0xBA, 0x93, 0x6E, 0xA8, 0x5F, + 0x53, 0xC8, 0x8A, 0x62, 0x41, 0x80, 0x62, 0x70, 0x36, 0xE8, + 0xD5, 0x1B, 0xB1, 0x84, 0x92, 0x37, 0xD8, 0xA8, 0xEE, 0x9B, + 0xF8, 0xAC, 0x71, 0xE8, 0xFE, 0x50, 0x2D, 0x41, 0x3D, 0xF6, + 0xC2, 0xAF, 0xC5, 0x79, 0x64, 0x6F, 0x7C, 0xE7, 0x49, 0xB2, + 0x68, 0xEA, 0xA8, 0x4D, 0xFA, 0x51, 0x8F, 0x85, 0x75, 0xFC, + 0x6E, 0xFB, 0x00, 0xA7, 0xBE, 0x68, 0xDC, 0x37, 0x6F, 0x47, + 0x32, 0x34, 0xF1, 0xCD, 0x02, 0xDA, 0xD0, 0xAF, 0x8D, 0x7E, + 0x0A, 0x2D, 0x3F, 0x03, 0x02, 0xCA, 0x4F, 0x17, 0xA5, 0x9A, + 0x30, 0x5A, 0xD0, 0x68, 0x3D, 0x5E, 0xD1, 0x93, 0x4F, 0x18, + 0xF0, 0xC9, 0xBA, 0xC7, 0xBC, 0xE2, 0xE4, 0x9A, 0x48, 0xB9, + 0x52, 0xFC, 0x47, 0xD4, 0xBF, 0x22, 0x79, 0xC2, 0x9E, 0x68, + 0x70, 0x81, 0x03, 0x0C, 0x21, 0xA8, 0x77, 0x5F, 0xF3, 0x38, + 0xEE, 0x76, 0x57, 0x13, 0x2B, 0x2B, 0xAC, 0xE6, 0x78, 0x3B, + 0x29, 0xE0, 0xB0, 0x35, 0xA9, 0xB6, 0x5F, 0x0B, 0xD5, 0xA0, + 0x37, 0xDA, 0x93, 0x7A, 0xBA, 0xDC, 0x8E, 0xC0, 0xCD, 0x5C, + 0xBC, 0x7D, 0x89, 0x6C, 0x63, 0x4C, 0x27, 0x3E, 0xB3, 0xCB, + 0x28, 0x5A, 0x7A, 0x73, 0x88, 0x2B, 0x07, 0xE5, 0xA1, 0x4B, + 0x65, 0x9B, 0x8D, 0x1E, 0x92, 0x04, 0x6F, 0xFE, 0xA7, 0x82, + 0xD1, 0x4F, 0x02, 0x55, 0x86, 0x6A, 0x1F, 0x10, 0x6D, 0x30, + 0x19, 0xF9, 0x3F, 0xBA, 0x70, 0xEF, 0xFD, 0xEB, 0x81, 0x7D, + 0x68, 0xE8, 0x68, 0x9B, 0x27, 0xE4, 0xB8, 0xED, 0xE5, 0x56, + 0xB6, 0x8B, 0x06, 0xBC, 0xFE, 0xA4, 0x83, 0x26, 0x7B, 0x5A, + 0x65, 0xE6, 0x03, 0xC4, 0x67, 0x51, 0x21, 0x95, 0x9C, 0xE2, + 0x56, 0x52, 0xBD, 0x8A, 0x3D, 0xAA, 0x7F, 0x4B, 0x5E, 0x20, + 0x00, 0xDC, 0x53, 0xB5, 0x65, 0x1C, 0x1F, 0xDB, 0x68, 0x14, + 0x94, 0xCF, 0x3D, 0x2D, 0x9A, 0xEE, 0x19, 0xE4, 0xD6, 0x2C, + 0x34, 0x88, 0xAD, 0xAA, 0x14, 0xC0, 0x3A, 0xE9, 0xBE, 0x2D, + 0x29, 0xBA, 0xDA, 0x67, 0x02, 0x28, 0x5A, 0x82, 0xBE, 0x6D, + 0x22, 0x23, 0xC4, 0x93, 0x79, 0x66, 0xDF, 0xB5, 0xED, 0x49, + 0x55, 0xB8, 0x01, 0x60, 0x7C, 0xEC, 0xE6, 0x96, 0x1C, 0x1B, + 0x46, 0x73, 0x4E, 0xBC, 0x43, 0x39, 0x65, 0x43, 0x47, 0x0D, + 0x94, 0x97, 0x4B, 0x21, 0x65, 0xB7, 0xED, 0xE0, 0xA5, 0x2E, + 0x62, 0x36, 0xA7, 0xF0, 0x3E, 0x06, 0xE9, 0xDF, 0x7C, 0x87, + 0x28, 0x18, 0xB6, 0x33, 0x37, 0x71, 0x43, 0xED, 0x99, 0x18, + 0xC4, 0xDB, 0x3B, 0x7C, 0x8C, 0xB6, 0x70, 0x82, 0x05, 0x49, + 0xA0, 0x07, 0xF0, 0xC9, 0x95, 0xE8, 0x62, 0xC4, 0xE9, 0xFE, + 0x90, 0xA9, 0xD1, 0x95, 0x73, 0xEB, 0x7B, 0xC4, 0x2F, 0xEB, + 0x02, 0x1D, 0xD0, 0xB4, 0x96, 0x59, 0xA2, 0x02, 0x79, 0xEC, + 0xAF, 0xB4, 0x6B, 0x39, 0x60, 0xAC, 0xD4, 0x5D, 0x7B, 0xA0, + 0x44, 0x8E, 0x56, 0x87, 0x8D, 0x31, 0xA1, 0x50, 0xA5, 0xDB, + 0xD8, 0xA6, 0xAC, 0xA1, 0x53, 0x20, 0x20, 0x74, 0x04, 0xE0, + 0xAB, 0xE4, 0x4E, 0x52, 0x8D, 0x4E, 0x3C, 0xFF, 0xA4, 0xA9, + 0x2F, 0x7E, 0xB8, 0x1B, 0xB4, 0x6B, 0x5C, 0x1A, 0xB1, 0x3D, + 0x55, 0x24, 0x85, 0x9B, 0x3D, 0x28, 0xC0, 0x70, 0x0D, 0xB4, + 0x69, 0xD1, 0x0C, 0x91, 0x22, 0x16, 0xAE, 0xCF, 0xB7, 0x4D, + 0x99, 0x64, 0x1A, 0xE0, 0x00, 0x30, 0x3B, 0xE5, 0xC2, 0x85, + 0xEA, 0x73, 0x4F, 0xFF, 0xCB, 0x12, 0x10, 0x7E, 0x14, 0x9F, + 0x66, 0xA5, 0xB6, 0xE8, 0xB3, 0x39, 0xA0, 0x4A, 0x91, 0xC7, + 0x63, 0x23, 0x2E, 0x26, 0x6B, 0x57, 0x4E, 0x74, 0xED, 0x82, + 0xF5, 0x1B, 0x1B, 0x54, 0xCD, 0xD7, 0xA2, 0x46, 0x3C, 0xB0, + 0x75, 0xAC, 0xA8, 0xF5, 0x52, 0xCF, 0x3C, 0x4C, 0x20, 0xE0, + 0x66, 0xEB, 0xE0, 0x31, 0x33, 0x93, 0x74, 0x60, 0x4C, 0xB1, + 0xCF, 0x19, 0x2E, 0x18, 0xC0, 0xC9, 0x6E, 0xBA, 0x71, 0x92, + 0x13, 0x66, 0x9B, 0x3F, 0x2C, 0x74, 0xC3, 0x37, 0x95, 0xBA, + 0x75, 0xFE, 0xF5, 0x16, 0x3D, 0x37, 0x96, 0x63, 0x0B, 0xD9, + 0x66, 0xFF, 0xA0, 0xE9, 0xEC, 0xA1, 0x17, 0x28, 0xE8, 0x55, + 0x0F, 0x13, 0xE9, 0x9A, 0x04, 0x75, 0xBB, 0x8B, 0x1F, 0x5C, + 0x15, 0x5A, 0x71, 0x97, 0x23, 0xDF, 0xE5, 0x46, 0xDC, 0x89, + 0x54, 0x5E, 0xCD, 0x72, 0xD8, 0xD2, 0x27, 0x6A, 0x2C, 0x2C, + 0x6D, 0x33, 0x9F, 0x67, 0x54, 0x4D, 0x84, 0xB9, 0xCF, 0x9B, + 0x4B, 0xD4, 0x97, 0xF4, 0x2A, 0xA3, 0xBA, 0xFA, 0x1C, 0x66, + 0x51, 0xF1, 0x92, 0x25, 0x50, 0xB4, 0x26, 0x73, 0xC0, 0x80, + 0x3D, 0x06, 0x08, 0xA6, 0x57, 0x93, 0xBF, 0x0E, 0xD2, 0x84, + 0x02, 0xD0, 0xF8, 0xCE, 0xCF, 0xBF, 0x1D, 0x6D, 0x76, 0xE7, + 0xE6, 0x0D, 0xCF, 0x87, 0x79, 0x26, 0xE9, 0xA5, 0xDE, 0x50, + 0x3D, 0xF3, 0xE4, 0x93, 0xC7, 0xEB, 0x2E, 0xD2, 0x13, 0x80, + 0x83, 0x79, 0x27, 0x8B, 0xED, 0x2F, 0xD6, 0xBC, 0xC8, 0xF7, + 0x60, 0x8F, 0x6F, 0x95, 0xBA, 0x97, 0x91, 0x69, 0x34, 0xC1, + 0x16, 0xE8, 0xFE, 0xE3, 0xA8, 0xBA, 0xD1, 0x86, 0x9D, 0x94, + 0x5E, 0x87, 0x8D, 0x9D, 0x06, 0xA8, 0x24, 0xDB, 0x45, 0x0A, + 0x19, 0xB2, 0x8C, 0xEB, 0x03, 0x17, 0xEB, 0x19, 0xC1, 0x8D, + 0x6C, 0x8E, 0x98, 0x24, 0xA4, 0xFE, 0x37, 0x64, 0x73, 0xA9, + 0xDE, 0x08, 0xC4, 0x52, 0x02, 0xE3, 0x52, 0xD6, 0x91, 0xDE, + 0xA8, 0x2F, 0xDB, 0x8A, 0xD5, 0x53, 0x8C, 0xE3, 0x98, 0x14, + 0x79, 0x0B, 0x60, 0xB6, 0xBB, 0xD5, 0x44, 0x61, 0xEB, 0xAF, + 0xA0, 0x92, 0xFD, 0x5E, 0xDD, 0x06, 0x57, 0x21, 0x64, 0x88, + 0x3C, 0x78, 0x97, 0x13, 0x40, 0xF8, 0xDD, 0xB7, 0xC5, 0x22, + 0x75, 0x92, 0x5E, 0xC9, 0x20, 0xCA, 0x27, 0x17, 0x23, 0xFD, + 0x21, 0x9C, 0x65, 0x9E, 0xA3, 0x5F, 0x9E, 0x5F, 0x96, 0xFD, + 0x98, 0x13, 0x15, 0x3D, 0x30, 0xB1, 0xD4, 0xB2, 0x55, 0xA7, + 0x37, 0xCD, 0xEF, 0xAD, 0x50, 0x39, 0x33, 0x88, 0x37, 0x8C, + 0x14, 0x10, 0x23, 0xD9, 0x9C, 0x75, 0xBC, 0x84, 0x6B, 0xC2, + 0xBB, 0x1D, 0x10, 0x16, 0xA5, 0x85, 0xDD, 0x09, 0x78, 0xBF, + 0xFA, 0xA0, 0xEC, 0x0A, 0x47, 0xBE, 0x9B, 0xA7, 0x36, 0x9E, + 0xDB, 0x99, 0x3D, 0x8A, 0xC2, 0xE3, 0xB3, 0x24, 0xD0, 0xCC, + 0x5A, 0x6C, 0x57, 0x4D, 0x4B, 0x77, 0xD9, 0x0B, 0x5A, 0xB8, + 0xDB, 0xE0, 0xA2, 0x31, 0xBE, 0x03, 0x32, 0x10, 0xA3, 0x35, + 0x2A, 0xB0, 0xE1, 0xAF, 0x7B, 0xCE, 0x94, 0xBE, 0x6D, 0x4C, + 0x11, 0x93, 0xEC, 0x3E, 0x1D, 0x01, 0x24, 0x87, 0x0A, 0xD8, + 0xD2, 0xFA, 0xBD, 0x40, 0xF1, 0xFF, 0x09, 0x03, 0xF1, 0xE4, + 0x40, 0xBB, 0xB9, 0x8E, 0x2B, 0x8E, 0x73, 0x66, 0xBF, 0x9B, + 0x4F, 0x55, 0x07, 0xD7, 0x4E, 0xE9, 0x98, 0x43, 0x0E, 0xFA, + 0x97, 0x6F, 0xF6, 0xD0, 0xF7, 0x60, 0xD5, 0x8D, 0x44, 0x03, + 0xC5, 0x35, 0x7D, 0xCB, 0xB1, 0xCF, 0x31, 0x2C, 0x24, 0x90, + 0x8F, 0xE2, 0x91, 0xC6, 0x60, 0x7C, 0xA0, 0xC4, 0x11, 0x73, + 0x51, 0xC2, 0xC5, 0xD4, 0x2D, 0x60, 0x3E, 0x21, 0xEB, 0x1D, + 0xDD, 0x95, 0x8C, 0xE0, 0x66, 0x31, 0x11, 0x88, 0xBF, 0x19, + 0x93, 0xA4, 0x10, 0xB2, 0xC2, 0x91, 0xEB, 0x6C, 0x0C, 0x63, + 0x0C, 0x30, 0xCB, 0x1E, 0x63, 0xFA, 0x75, 0xBF, 0x26, 0x0B, + 0x63, 0x11, 0xDE, 0xFB, 0x94, 0x4E, 0xD1, 0xCB, 0x1F, 0x17, + 0x63, 0x76, 0x9B, 0x48, 0xAC, 0x31, 0xEF, 0x60, 0x0C, 0xA9, + 0xD3, 0xDC, 0x98, 0x3B, 0x06, 0x42, 0x6E, 0x21, 0x77, 0xB7, + 0xF5, 0x7C, 0x72, 0x4E, 0xB9, 0x1A, 0xEE, 0x96, 0x04, 0xB5, + 0x52, 0x40, 0x15, 0xD5, 0x7D, 0x39, 0xB8, 0x98, 0x72, 0xFB, + 0x2D, 0xC8, 0x92, 0x91, 0xCF, 0x88, 0xEE, 0x08, 0x6F, 0x57, + 0x2A, 0x07, 0xB0, 0x5D, 0xCB, 0x69, 0x15, 0x28, 0x1E, 0xAE, + 0x09, 0xB8, 0x9C, 0x29, 0x8D, 0x4E, 0x59, 0x1A, 0x64, 0x9D, + 0xEA, 0xED, 0x60, 0x2F, 0x04, 0x37, 0x89, 0x6D, 0xB1, 0x2E, + 0xE8, 0x56, 0xB2, 0xB2, 0x10, 0xC2, 0xA8, 0x90, 0xC5, 0x34, + 0xEE, 0x7B, 0x3A, 0xD7, 0x76, 0x19, 0x0F, 0x18, 0xC7, 0x07, + 0xCF, 0xD1, 0xD7, 0x93, 0x42, 0x16, 0x4D, 0x7C, 0xF3, 0x74, + 0x25, 0xD0, 0x6B, 0x70, 0xC8, 0x49, 0x52, 0x21, 0xF1, 0x54, + 0xCF, 0x65, 0x21, 0xF0, 0xE3, 0xE8, 0x85, 0x01, 0x2B, 0x3E, + 0xFF, 0xB8, 0xC0, 0x48, 0xE8, 0xBD, 0xFA, 0xCC, 0x3A, 0x53, + 0x98, 0x23, 0x7A, 0x0F, 0x79, 0x34, 0x8E, 0x65, 0x17, 0x4E, + 0x80, 0x48, 0x19, 0x52, 0x31, 0x22, 0xB1, 0xD8, 0x36, 0x7A, + 0xF9, 0x77, 0xB2, 0x56, 0x28, 0x15, 0xA0, 0xE8, 0xD7, 0x77, + 0x9B, 0x12, 0xB5, 0xAC, 0xF2, 0x67, 0x49, 0x66, 0x29, 0x9B, + 0x3B, 0x9A, 0x27, 0xB0, 0xA1, 0x5A, 0x59, 0x7D, 0x24, 0x39, + 0xC0, 0x96, 0xEF, 0x0D, 0x5C, 0x67, 0x5D, 0x13, 0xAD, 0xED, + 0x4F, 0xE4, 0x8D, 0xE4, 0xC1, 0x17, 0x82, 0x83, 0xC6, 0x14, + 0x2B, 0x41, 0x89, 0x30, 0x25, 0x2F, 0x10, 0x04, 0x34, 0x6B, + 0xD0, 0x31, 0x90, 0xD6, 0x07, 0x9B, 0xE8, 0xC3, 0xE4, 0x0F, + 0x87, 0xFD, 0xC6, 0x81, 0x15, 0x58, 0x02, 0x77, 0xAA, 0x2B, + 0xF5, 0x30, 0x94, 0xB4, 0x71, 0x37, 0xFE, 0xDE, 0xAC, 0x15, + 0xD3, 0x12, 0x1C, 0x77, 0x42, 0xF5, 0xA3, 0x6F, 0xD5, 0xC5, + 0x00, 0x7E, 0xAC, 0x7C, 0x04, 0xBC, 0x0B, 0x21, 0xE4, 0xFA, + 0x4E, 0x72, 0xF2, 0xF5, 0x8A, 0xEC, 0x86, 0x47, 0x4A, 0x80, + 0x5E, 0x7E, 0x48, 0xEA, 0x07, 0xCC, 0x12, 0x42, 0x4B, 0xF9, + 0x4A, 0x59, 0x1C, 0xB9, 0x1A, 0x85, 0x8D, 0x28, 0xA3, 0x37, + 0x8E, 0x1C, 0x10, 0xBE, 0x42, 0x79, 0xBB, 0xE0, 0x41, 0x8E, + 0x81, 0xCC, 0x40, 0x66, 0xC7, 0xB2, 0x80, 0xE8, 0xC5, 0xB5, + 0xE8, 0xA0, 0xAB, 0x69, 0xE6, 0x58, 0x72, 0x6E, 0x23, 0x95, + 0xA8, 0x26, 0x23, 0x53, 0x61, 0xD4, 0x81, 0x4F, 0x34, 0xAC, + 0x16, 0xED, 0x27, 0x39, 0x0F, 0x48, 0x8B, 0x5C, 0xE7, 0x48, + 0xEE, 0xBC, 0xE7, 0x05, 0xDD, 0x66, 0x70, 0x17, 0x14, 0x94, + 0xDC, 0xAD, 0x9C, 0x8F, 0xF4, 0x93, 0x0F, 0x90, 0xD4, 0xC0, + 0x12, 0xF3, 0x63, 0xA1, 0x28, 0xD4, 0xB2, 0x03, 0xEC, 0x60, + 0xE4, 0x03, 0x38, 0x65, 0x3A, 0x4C, 0x93, 0x68, 0xCE, 0x09, + 0x04, 0x5E, 0xD4, 0x97, 0x3E, 0xBE, 0x0F, 0xA1, 0x24, 0x74, + 0x3C, 0xBA, 0x70, 0x16, 0x9B, 0x45, 0x7C, 0xAA, 0xE4, 0x18, + 0x2D, 0x7C, 0x44, 0x0F, 0xD9, 0xD9, 0xFE, 0xE7, 0xC6, 0x90, + 0x3E, 0xA7, 0xE5, 0x6E, 0x7C, 0x48, 0x3F, 0xE5, 0x82, 0xA4, + 0xB4, 0xC5, 0x67, 0xCE, 0x03, 0xCD, 0x9B, 0xFC, 0xA8, 0x7A, + 0xA1, 0x93, 0x16, 0xAB, 0x80, 0x0A, 0xD5, 0x98, 0xC5, 0xB6, + 0xA7, 0xCA, 0xBB, 0x11, 0xED, 0x7F, 0x8F, 0x3D, 0x26, 0x1E, + 0xA6, 0x49, 0xAB, 0x91, 0x7A, 0x02, 0xF6, 0x5C, 0x08, 0x46, + 0xDB, 0x2E, 0xF9, 0x95, 0x79, 0x3A, 0x23, 0x6F, 0xE5, 0x89, + 0x4A, 0xCE, 0x97, 0x1C, 0xDF, 0x59, 0x70, 0x93, 0xB6, 0xFC, + 0x60, 0x5B, 0x0E, 0x9E, 0x63, 0x30, 0xBF, 0x31, 0x9E, 0xD1, + 0x64, 0xED, 0x90, 0xCD, 0xD1, 0x32, 0xEC, 0x34, 0x21, 0xA1, + 0xC9, 0x7A, 0x2A, 0x31, 0x8B, 0x57, 0x8D, 0x64, 0x29, 0x6C, + 0x27, 0x40, 0xDC, 0xE1, 0xA5, 0x00, 0xD9, 0x6B, 0x46, 0xAC, + 0x6E, 0xE5, 0xF7, 0xC3, 0x49, 0x93, 0x79, 0x5A, 0x65, 0x49, + 0xBF, 0x5B, 0x72, 0x75, 0x61, 0x78, 0x4B, 0xD1, 0xD8, 0xDF, + 0x9C, 0x29, 0xCC, 0x81, 0x6C, 0x8F, 0x63, 0x56, 0x0E, 0xFE, + 0xD8, 0x0D, 0x27, 0xD9, 0x4E, 0x0D, 0x35, 0xFC, 0x28, 0x0E, + 0x81, 0xF6, 0xBF, 0x3B, 0xFD, 0x42, 0x09, 0x74, 0x9D, 0xFB, + 0xA4, 0x60, 0x9B, 0x08, 0xAF, 0xE4, 0x83, 0x46, 0x69, 0xB8, + 0x8D, 0x5D, 0xEA, 0x27, 0xC9, 0x64, 0x8C, 0xA5, 0xCB, 0xE1, + 0x31, 0xA1, 0x1B, 0xF1, 0x6A, 0x6B, 0xE7, 0x8C, 0xE5, 0x00, + 0x45, 0x92, 0x81, 0xDA, 0xE6, 0xDA, 0x9F, 0x05, 0x99, 0x25, + 0xC4, 0xA0, 0xFD, 0x1B, 0x20, 0x17, 0xB9, 0xBF, 0x4A, 0xFA, + 0x6E, 0xD1, 0xAB, 0xD8, 0xB2, 0x4A, 0x1E, 0xC5, 0x1F, 0x58, + 0x26, 0xE1, 0x37, 0x8C, 0xAB, 0xE6, 0x21, 0x0D, 0xF2, 0x85, + 0xB5, 0xFE, 0x7D, 0x4B, 0xBB, 0x30, 0xED, 0xAE, 0xE7, 0x4A, + 0x83, 0x08, 0x4F, 0xA5, 0x8A, 0x33, 0x0D, 0x1B, 0xFB, 0x50, + 0xAB, 0xC4, 0x48, 0xAE, 0xC2, 0x6F, 0x9C, 0xDC, 0x03, 0x08, + 0xB6, 0x85, 0xBD, 0x13, 0x40, 0x7A, 0x65, 0xC1, 0x3E, 0x5F, + 0x72, 0x8A, 0x94, 0x56, 0x33, 0x93, 0x1D, 0x7D, 0x02, 0xE5, + 0xFC, 0xA8, 0xF0, 0x78, 0x2A, 0xDC, 0x9A, 0xAF, 0x9C, 0xCB, + 0x5F, 0xAF, 0xB5, 0x68, 0x5B, 0xCC, 0xF0, 0xCF, 0x10, 0x3F, + 0xE3, 0xED, 0xF2, 0x23, 0xD0, 0x67, 0x06, 0x40, 0xE1, 0xA7, + 0x33, 0xB0, 0xBF, 0x53, 0x73, 0xF1, 0x0F, 0x2B, 0x7D, 0xF9, + 0xA8, 0x45, 0x9B, 0x04, 0x2D, 0x7E, 0x35, 0x9D, 0xCE, 0xAD, + 0x38, 0xE4, 0x57, 0x8F, 0x22, 0x46, 0x70, 0x08, 0xA5, 0xD6, + 0x3F, 0x17, 0xE9, 0x46, 0x0A, 0x39, 0x3C, 0x75, 0xAD, 0x3B, + 0xC1, 0x6E, 0xA7, 0xC3, 0x2F, 0x1B, 0xA6, 0xE9, 0x8D, 0xE3, + 0xE5, 0x0A, 0xE0, 0x49, 0x29, 0xBE, 0xAF, 0x4B, 0x20, 0xE6, + 0xE8, 0xCC, 0xE9, 0x9D, 0xEB, 0x5C, 0x7D, 0x3C, 0x24, 0x5F, + 0x7A, 0x9A, 0xA5, 0x34, 0x9C, 0x4C, 0xD9, 0xF8, 0xED, 0xF0, + 0x92, 0x76, 0x18, 0xF9, 0x30, 0x68, 0x37, 0x2E, 0xA4, 0x18, + 0x54, 0x81, 0xE8, 0x6A, 0x81, 0x61, 0xCD, 0x0B, 0xA2, 0x97, + 0x56, 0x2B, 0x78, 0xF5, 0xA5, 0x4B, 0x4F, 0x73, 0x04, 0x94, + 0xB6, 0x95, 0xAF, 0x84, 0x93, 0xB8, 0x72, 0xE5, 0xC3, 0x18, + 0x2E, 0xF2, 0x23, 0x31, 0xD4, 0x99, 0x9E, 0xDB, 0x57, 0x7F, + 0x8E, 0x55, 0x62, 0x63, 0x63, 0x07, 0x65, 0x37, 0x55, 0xE6, + 0x7B, 0xC0, 0x8D, 0xF8, 0xCA, 0x05, 0xA4, 0x3A, 0xFC, 0x1E, + 0x1F, 0xCF, 0x4E, 0x8D, 0xD4, 0xFE, 0x19, 0xDE, 0xE4, 0x58, + 0x6B, 0xFF, 0x30, 0x7E, 0xF9, 0x58, 0xA6, 0xC5, 0xE1, 0xA5, + 0x08, 0xE9, 0x8A, 0x7F, 0x77, 0x58, 0x81, 0x32, 0x02, 0xDF, + 0xE7, 0x48, 0x0B, 0x8E, 0xF9, 0xE8, 0xD1, 0x95, 0xC4, 0xED, + 0x52, 0xB0, 0xFA, 0x6F, 0x88, 0xF8, 0xA2, 0xAC, 0x57, 0x7B, + 0x69, 0xB4, 0x78, 0xA5, 0x87, 0x37, 0x6B, 0xAA, 0xBC, 0x49, + 0xFD, 0x62, 0x64, 0x8E, 0x27, 0x89, 0x98, 0x1E, 0xE2, 0x09, + 0xCC, 0x1F, 0x75, 0x66, 0x12, 0x93, 0x34, 0x77, 0xB5, 0x6E, + 0x07, 0x47, 0x21, 0x69, 0x76, 0x0C, 0x22, 0xFA, 0xA8, 0x80, + 0xEE, 0x78, 0xAA, 0xF0, 0x10, 0x47, 0x6F, 0x37, 0xAD, 0x4C, + 0x5C, 0x51, 0x8F, 0xDE, 0xF6, 0x60, 0xA8, 0x93, 0xB3, 0x8C, + 0xA9, 0x8B, 0xE4, 0x93, 0x1D, 0xF7, 0x4B, 0x41, 0x5D, 0xF0, + 0x56, 0xD4, 0xE0, 0x16, 0x08, 0x61, 0x12, 0xA5, 0xDA, 0x43, + 0xE6, 0x9F, 0x42, 0x48, 0xB8, 0xDB, 0xD0, 0x17, 0xA4, 0x85, + 0xC4, 0x7D, 0xE0, 0x82, 0x5E, 0x63, 0x76, 0x70, 0x44, 0xAF, + 0x14, 0xAA, 0xB2, 0x0D, 0x2C, 0xED, 0x96, 0xF0, 0x7B, 0x5F, + 0x69, 0xDF, 0x32, 0xB4, 0xC8, 0x8A, 0xDB, 0x9A, 0xF2, 0xB5, + 0xF3, 0x15, 0xAA, 0x16, 0xB0, 0x1F, 0x13, 0xD5, 0x07, 0x74, + 0xFA, 0x74, 0xEE, 0x0A, 0xAA, 0xE8, 0x10, 0x38, 0x9D, 0x37, + 0x5D, 0xAC, 0xE6, 0x78, 0x44, 0xB8, 0x24, 0x0C, 0x16, 0x5B, + 0x62, 0x3E, 0x2A, 0x28, 0x66, 0xA2, 0x34, 0x49, 0xF1, 0xB3, + 0x2D, 0x31, 0xEF, 0x67, 0xBF, 0xE9, 0x63, 0xDC, 0x8A, 0x6B, + 0xE3, 0x67, 0xF4, 0x9C, 0x85, 0xCE, 0x52, 0xE8, 0x8A, 0x18, + 0x9E, 0xA2, 0xD5, 0xDF, 0x44, 0xB5, 0x3B, 0xE4, 0x89, 0xAE, + 0x3A, 0xBA, 0x21, 0x93, 0x32, 0x81, 0x17, 0xD1, 0xDB, 0xEC, + 0x1D, 0xE2, 0x23, 0xEA, 0x62, 0x77, 0x00, 0x7A, 0xA1, 0x2A, + 0x43, 0x61, 0x68, 0xA8, 0x31, 0xEB, 0x99, 0x77, 0x59, 0x83, + 0x6B, 0xB4, 0xDB, 0x9B, 0xF2, 0xC7, 0x30, 0x18, 0x42, 0x12, + 0x8D, 0x95, 0xFA, 0xD8, 0x77, 0xF2, 0xC9, 0x7A, 0x65, 0x9D, + 0x07, 0xE6, 0x6D, 0x78, 0x5F, 0x44, 0x30, 0xE5, 0xD1, 0xDA, + 0x56, 0x18, 0xC8, 0x28, 0x52, 0x14, 0x86, 0xB9, 0x9B, 0x60, + 0xE8, 0x6D, 0x73, 0x2B, 0xF3, 0x61, 0xA1, 0xEE, 0x06, 0x07, + 0x3B, 0x4E, 0x73, 0x6E, 0xC3, 0xDE, 0x2B, 0x2A, 0x72, 0x84, + 0xB0, 0x50, 0xA3, 0xAD, 0xB1, 0x49, 0xB3, 0x06, 0xD4, 0x5F, + 0xF0, 0x8E, 0x36, 0x10, 0x34, 0xB3, 0xCD, 0xB9, 0x84, 0xBE, + 0x13, 0xC8, 0xC3, 0xE2, 0x53, 0x08, 0x94, 0x16, 0x85, 0xEC, + 0x51, 0x5E, 0xE5, 0xAE, 0x22, 0x6F, 0x32, 0xD0, 0x49, 0x49, + 0x8D, 0xA5, 0x0A, 0x25, 0xB6, 0xD3, 0xB4, 0xF1, 0x3C, 0x60, + 0x35, 0x8E, 0x6D, 0x1B, 0xA4, 0x58, 0xC3, 0xC0, 0x51, 0x97, + 0xC5, 0xBF, 0x6A, 0x50, 0x8B, 0x71, 0xA9, 0x39, 0x43, 0x93, + 0xEB, 0x55, 0xA2, 0x22, 0xD0, 0x25, 0x02, 0x8C, 0x4F, 0x56, + 0x99, 0xA1, 0xAC, 0x29, 0xE8, 0xD0, 0xD1, 0xDB, 0x2C, 0x80, + 0x98, 0xBA, 0xF2, 0xF7, 0xC7, 0x61, 0x3F, 0x8A, 0xE9, 0xBD, + 0x71, 0x34, 0x29, 0xC1, 0xA8, 0x8E, 0x95, 0x68, 0xEA, 0x67, + 0xAE, 0xC4, 0x23, 0x4C, 0x67, 0xD7, 0xA4, 0x65, 0x9B, 0x43, + 0xDC, 0x6A, 0x4F, 0x83, 0x09, 0x30, 0x6E, 0xB8, 0x5E, 0xA0, + 0xED, 0xF8, 0xCA, 0x0B, 0x8D, 0x4B, 0x2A, 0x07, 0x19, 0x7B, + 0x4F, 0x5E, 0x25, 0xD4, 0xA1, 0x8D, 0xAF, 0xF6, 0x3E, 0xF7, + 0x43, 0x75, 0x3A, 0x6B, 0xBD, 0x68, 0x65, 0x80, 0x14, 0x20, + 0x0A, 0x39, 0x2D, 0x88, 0xD8, 0x32, 0x63, 0xB7, 0xEA, 0x18, + 0x7D, 0xC7, 0xDC, 0x30, 0x74, 0xD7, 0x4E, 0xE9, 0x30, 0x67, + 0x86, 0x94, 0xC6, 0x75, 0x13, 0xBC, 0x6B, 0x42, 0x56, 0x9D, + 0xA2, 0x26, 0x76, 0x28, 0x79, 0xE3, 0xEE, 0x2F, 0xE5, 0xEF, + 0x45, 0x7E, 0x8D, 0x39, 0x5B, 0xFD, 0x7A, 0x7C, 0xB7, 0xC1, + 0xEE, 0x6D, 0xBF, 0x59, 0xEB, 0x69, 0xFC, 0xBC, 0xB6, 0xB7, + 0xF5, 0xB6, 0x17, 0x3F, 0xB4, 0x22, 0xFE, 0x5C, 0x3C, 0xB1, + 0xD3, 0xA6, 0x7E, 0xE0, 0x6E, 0x9B, 0xCF, 0x25, 0x30, 0xF9, + 0x3E, 0x6C, 0x43, 0x32, 0x9F, 0x32, 0x88, 0x89, 0x47, 0x25, + 0x0F, 0xBC, 0x16, 0xCB, 0xF5, 0x63, 0x13, 0x18, 0x69, 0x94, + 0x76, 0x57, 0x0C, 0xFA, 0x67, 0x29, 0xE3, 0x2C, 0x63, 0xF4, + 0xDA, 0xBF, 0x38, 0x9F, 0x01, 0xDC, 0xA3, 0x42, 0xA0, 0x1D, + 0x40, 0xC7, 0xAA, 0xD9, 0xED, 0xE2, 0x8E, 0x02, 0x1A, 0x3A, + 0xAA, 0x9C, 0xFA, 0xA1, 0x32, 0x85, 0x4B, 0x86, 0x67, 0x34, + 0xBB, 0x78, 0xDA, 0x66, 0xAB, 0x47, 0x82, 0x1E, 0xF0, 0x70, + 0x38, 0x13, 0xD3, 0xCB, 0xE5, 0x3C, 0x02, 0xA9, 0xFD, 0xDE, + 0xBF, 0x5C, 0x9E, 0xC9, 0x82, 0x99, 0xEF, 0xF6, 0xC1, 0x3B, + 0x53, 0x53, 0xF1, 0x67, 0xD0, 0x28, 0xE3, 0xA6, 0x95, 0x99, + 0x05, 0xAC, 0x0B, 0xEE, 0x7F, 0x47, 0x31, 0x53, 0x3A, 0xEC, + 0xEB, 0x35, 0x5B, 0xFF, 0xFA, 0xFC, 0xF1, 0x79, 0x71, 0xAE, + 0xF3, 0x95, 0x0C, 0x05, 0xF2, 0xCD, 0x4B, 0x7B, 0x7F, 0xDE, + 0xE3, 0x75, 0x57, 0x78, 0x17, 0x50, 0xB1, 0x25, 0x18, 0xE3, + 0x99, 0xE1, 0x00, 0x69, 0x9B, 0xB8, 0x57, 0xBB, 0x61, 0xBE, + 0xBB, 0x6E, 0x63, 0x82, 0x16, 0x37, 0xA3, 0xCA, 0xAC, 0xF4, + 0x3A, 0x26, 0x64, 0x68, 0xF5, 0x2D, 0x38, 0xD0, 0x6E, 0x87, + 0x3C, 0xC6, 0x74, 0xBF, 0xED, 0xB9, 0xF2, 0xA9, 0x32, 0x9B, + 0x41, 0x54, 0x7B, 0x58, 0x79, 0xF0, 0x33, 0xD3, 0x9D, 0x16, + 0x14, 0xEF, 0x9B, 0xF2, 0xC8, 0x32, 0x37, 0x8D, 0xF0, 0x69, + 0xDE, 0x6E, 0xCE, 0x7A, 0xA1, 0x21, 0xA0, 0xDC, 0x14, 0x83, + 0x2B, 0xDF, 0x7E, 0xDF, 0x39, 0x6F, 0x04, 0x6E, 0xAE, 0xAB, + 0x6E, 0x68, 0xB5, 0xB2, 0x21, 0x9C, 0x5D, 0x5B, 0xDA, 0xB1, + 0xF7, 0x68, 0x97, 0xFA, 0xB9, 0x40, 0xB9, 0x11, 0xC2, 0xD0, + 0xF6, 0xF6, 0xB0, 0x6C, 0xAE, 0xEE, 0xC5, 0x6E, 0x31, 0xE8, + 0x0F, 0x82, 0x96, 0x83, 0xA8, 0xEE, 0x6B, 0xA1, 0x00, 0x6E, + 0xDB, 0xC9, 0xD4, 0x79, 0x8F, 0xAA, 0x87, 0x49, 0x55, 0xF7, + 0x42, 0x5E, 0x96, 0xFC, 0xD7, 0x7C, 0x4D, 0xDA, 0xAE, 0x48, + 0xEF, 0x66, 0x63, 0x61, 0x63, 0xA2, 0xC4, 0x03, 0x8E, 0xAD, + 0xAB, 0xD1, 0x94, 0x36, 0xA9, 0x37, 0x40, 0x21, 0xCE, 0x60, + 0x0A, 0x88, 0xDC, 0x4E, 0x77, 0xD2, 0xAC, 0xAF, 0x24, 0x5A, + 0x0D, 0x40, 0xBC, 0x1C, 0x49, 0x58, 0x72, 0xCE, 0x6F, 0x62, + 0x1D, 0x26, 0xE7, 0xB3, 0x6D, 0x19, 0xB0, 0x94, 0x2A, 0x3B, + 0x7E, 0x74, 0x1F, 0xDD, 0xD4, 0x43, 0x74, 0x72, 0xBA, 0xE0, + 0x0F, 0xBB, 0xEC, 0xC4, 0x15, 0x4A, 0xB7, 0x60, 0x99, 0x94, + 0xDC, 0x70, 0xFD, 0x99, 0x64, 0x57, 0x1D, 0xE2, 0x06, 0x29, + 0x7D, 0xC5, 0xBA, 0xAC, 0xBE, 0xF7, 0xD4, 0x5E, 0xB2, 0xBE, + 0xFF, 0x0A, 0x38, 0xF9, 0xA0, 0x12, 0xB2, 0x5B, 0xA1, 0xF3, + 0xDA, 0x1E, 0x51, 0xD2, 0xF2, 0x81, 0x22, 0x1A, 0xEE, 0xEB, + 0xBA, 0xF9, 0x10, 0x51, 0x3F, 0xD9, 0x6C, 0xBD, 0x92, 0xCA, + 0x79, 0xF8, 0xB1, 0x08, 0x28, 0xFA, 0x6F, 0xC3, 0x13, 0xC6, + 0x8E, 0x19, 0x6D, 0x5D, 0xC0, 0x18, 0xB8, 0x3F, 0xC5, 0x81, + 0xCE, 0xC2, 0x08, 0x90, 0x36, 0xE5, 0x45, 0x3A, 0x7A, 0x3C, + 0x63, 0x52, 0xF8, 0xE9, 0xFC, 0x7B, 0xFC, 0xDF, 0xF5, 0xF8, + 0xA4, 0xD6, 0x74, 0x60, 0x32, 0xF8, 0x6C, 0x45, 0x43, 0x5F, + 0x08, 0x38, 0xD0, 0xAA, 0x37, 0x3A, 0xFE, 0xC1, 0xDC, 0x0E, + 0x3C, 0x22, 0xC0, 0x12, 0x91, 0x08, 0xDE, 0xA6, 0x26, 0x03, + 0xF1, 0xAA, 0xB0, 0xE7, 0xF3, 0x20, 0xE6, 0xE7, 0x1A, 0x2E, + 0x49, 0x98, 0x2D, 0xCC, 0x46, 0xE6, 0xDC, 0x93, 0x52, 0xE1, + 0x44, 0x00, 0x87, 0xF9, 0x14, 0xDE, 0x4C, 0xF6, 0x4B, 0x36, + 0xEA, 0x33, 0xF9, 0x15, 0xF7, 0x1D, 0x60, 0x04, 0xE4, 0xF8, + 0x56, 0xDB, 0xBA, 0x3F, 0x52, 0x6C, 0x19, 0xE5, 0x11, 0x1B, + 0x81, 0x1B, 0xFA, 0x96, 0xB8, 0x0D, 0x45, 0xB6, 0x9B, 0x51, + 0x85, 0x94, 0xB0, 0x53, 0x35, 0xEA, 0xA0, 0x60, 0x30, 0x38, + 0x4B, 0xD7, 0x63, 0xA0, 0xDF, 0x74, 0x3A, 0x04, 0xE4, 0x15, + 0xC6, 0x57, 0x2D, 0x91, 0xA3, 0xE9, 0x53, 0xE2, 0xF6, 0xD1, + 0x4D, 0x22, 0x1B, 0x72, 0x74, 0x9D, 0x3F, 0xD0, 0xEE, 0x9A, + 0xAA, 0x5B, 0xEB, 0xF3, 0x60, 0xD5, 0xF8, 0xE9, 0xC7, 0x20, + 0x71, 0x29, 0xBC, 0x16, 0xD9, 0xF4, 0xFF, 0xF7, 0xAF, 0x52, + 0x0D, 0x57, 0x97, 0xB7, 0x48, 0xFE, 0xDE, 0x05, 0xD3, 0x99, + 0x7C, 0x86, 0x79, 0x5D, 0x9C, 0x40, 0x4C, 0xA8, 0xD8, 0xC6, + 0x67, 0x5D, 0x69, 0x4E, 0x9E, 0x39, 0xF3, 0xB4, 0xA5, 0x28, + 0xC0, 0xDC, 0xD2, 0x9B, 0xDC, 0xE6, 0xF4, 0x17, 0xD1, 0x59, + 0x1B, 0x7F, 0x52, 0xA2, 0x7B, 0xCC, 0xE3, 0xEA, 0xF5, 0xAD, + 0x40, 0x7E, 0x6A, 0xBC, 0xA8, 0x6A, 0xD0, 0x39, 0xEA, 0x73, + 0x50, 0x13, 0xE9, 0x3D, 0xD7, 0x91, 0x4D, 0x8B, 0x9F, 0x71, + 0x85, 0xF4, 0x0A, 0xCC, 0x95, 0x41, 0xD2, 0x8C, 0x4D, 0x40, + 0xD9, 0x7C, 0x1C, 0x0F, 0xCD, 0x8E, 0x3E, 0x00, 0x8A, 0xDA, + 0x49, 0xE6, 0x95, 0x04, 0x5E, 0xC9, 0xE9, 0x88, 0x18, 0x61, + 0x85, 0x61, 0x2D, 0xE4, 0x9C, 0xE6, 0x6B, 0xF5, 0x47, 0x3C, + 0xF5, 0x6E, 0x11, 0x5C, 0x93, 0x8F, 0xBF, 0xEA, 0x18, 0x5B, + 0xFC, 0x07, 0x20, 0x4E, 0xC6, 0x30, 0x7D, 0x17, 0xD9, 0x5B, + 0xDF, 0xF3, 0xA8, 0x2A, 0x33, 0xF3, 0x57, 0x6A, 0xAF, 0xAE, + 0x5A, 0x83, 0x5E, 0x22, 0x00, 0x85, 0x9D, 0x58, 0x4C, 0xC4, + 0xC6, 0x05, 0x97, 0x00, 0x1C, 0x15, 0xBC, 0x25, 0x3A, 0x74, + 0x0E, 0xD7, 0x3F, 0x34, 0x2E, 0xDC, 0x08, 0x4C, 0xAE, 0x11, + 0x47, 0x5A, 0xCF, 0xDF, 0x99, 0x4B, 0xCF, 0x9E, 0xC3, 0x5C, + 0xD5, 0x1D, 0xBF, 0xEB, 0x3A, 0x90, 0xF9, 0x13, 0xE1, 0x5B, + 0x0E, 0xC7, 0x73, 0xDE, 0xA3, 0x02, 0x31, 0xEB, 0x9E, 0x33, + 0xFE, 0x89, 0x0A, 0x29, 0xF9, 0x68, 0x8E, 0xB4, 0xEB, 0x5E, + 0xA7, 0xC8, 0xB4, 0xE9, 0xE7, 0x10, 0x02, 0xA5, 0xB0, 0x8B, + 0x18, 0x42, 0xE6, 0xB0, 0xE5, 0x52, 0x4B, 0xFF, 0x4C, 0xA9, + 0xCE, 0xB6, 0x9E, 0xCC, 0xF6, 0x91, 0x72, 0x4C, 0x4D, 0xDD, + 0xE0, 0xEA, 0x27, 0x06, 0x1A, 0x1F, 0xAC, 0x52, 0x76, 0x72, + 0x52, 0xEB, 0xE5, 0xDE, 0x19, 0xDA, 0x4D, 0x57, 0x53, 0xE5, + 0xC0, 0x8E, 0x61, 0x16, 0x0F, 0x00, 0xF0, 0x70, 0x92, 0xFE, + 0x95, 0x45, 0x72, 0xB9, 0x70, 0x75, 0x3D, 0xE6, 0x03, 0x0C, + 0x51, 0x3B, 0x03, 0x54, 0x79, 0xA6, 0xBF, 0x4B, 0x0E, 0xB5, + 0x82, 0x4A, 0x66, 0xD5, 0x8F, 0x6A, 0x17, 0x6C, 0x31, 0x26, + 0x50, 0x8C, 0xAA, 0x85, 0x85, 0x50, 0x6A, 0x85, 0xE2, 0xE9, + 0x94, 0x1D, 0x3F, 0x63, 0x5A, 0xB1, 0xA0, 0xB8, 0xA5, 0xAE, + 0xCD, 0x4F, 0x40, 0xCC, 0x61, 0x4E, 0x9D, 0x20, 0xDF, 0x45, + 0x9D, 0x1E, 0x91, 0xB5, 0x62, 0x92, 0x8E, 0x59, 0x90, 0x9F, + 0xB3, 0x11, 0x8A, 0xA9, 0xBD, 0xFD, 0x4A, 0x06, 0x07, 0x30, + 0xC2, 0xD8, 0x5A, 0x69, 0xBA, 0xE1, 0xB3, 0x19, 0x97, 0xC6, + 0x55, 0xE9, 0xC8, 0x70, 0xB2, 0xDF, 0x65, 0x78, 0xC1, 0x3A, + 0xD1, 0x76, 0x32, 0xAA, 0x27, 0x2E, 0x43, 0xCC, 0x74, 0xCA, + 0xD0, 0x02, 0x1A, 0xC1, 0x19, 0x0B, 0x49, 0xA1, 0xE3, 0xFB, + 0xE3, 0x0A, 0xBA, 0x16, 0x38, 0x1A, 0x67, 0xCF, 0x1D, 0x68, + 0x9A, 0xB6, 0x3A, 0x9B, 0xEE, 0x7E, 0x00, 0xBD, 0xA7, 0x66, + 0x1C, 0xF4, 0x4B, 0xAB, 0xC9, 0xF7, 0x33, 0xC3, 0x12, 0xCB, + 0xC3, 0x0D, 0x0F, 0xCE, 0xF9, 0x85, 0x4C, 0x44, 0x2B, 0x4B, + 0x00, 0xA3, 0xFD, 0xA7, 0xCE, 0x74, 0x86, 0x39, 0xD6, 0x7E, + 0xB5, 0xC3, 0x20, 0xDD, 0x20, 0xB0, 0x33, 0x02, 0xFF, 0x4A, + 0x28, 0x01, 0xCF, 0xA1, 0xEE, 0x29, 0x2A, 0x46, 0x3F, 0x01, + 0xA4, 0x1A, 0xC3, 0xAF, 0xB9, 0xB2, 0x06, 0x57, 0xDA, 0x6E, + 0x70, 0xBE, 0x25, 0xF4, 0xCC, 0x3A, 0xA3, 0x83, 0xC8, 0x59, + 0xDC, 0x5F, 0xD1, 0xEF, 0xCA, 0xB8, 0xFD, 0xD0, 0x40, 0x6B, + 0xC0, 0x5D, 0x95, 0xAC, 0xA8, 0x32, 0x0C, 0x79, 0xC7, 0x30, + 0x36, 0xEB, 0x05, 0x72, 0x6A, 0xF3, 0x09, 0x5C, 0x85, 0x64, + 0x27, 0x64, 0xBA, 0xB8, 0x10, 0x8C, 0x3C, 0x3B, 0x9F, 0xA7, + 0x58, 0x39, 0x79, 0xD9, 0x87, 0x68, 0x3E, 0x6D, 0xFF, 0x21, + 0x7F, 0xD3, 0x16, 0xA9, 0x14, 0x5D, 0xC5, 0x24, 0x6E, 0x74, + 0x7C, 0xA9, 0x95, 0x72, 0x77, 0xCB, 0xB0, 0x92, 0x0B, 0xEB, + 0xB8, 0x11, 0xF3, 0xC7, 0x36, 0x57, 0x83, 0xEA, 0x3F, 0x0E, + 0x3F, 0x80, 0x0B, 0x67, 0xF5, 0x8E, 0x46, 0x1E, 0xFE, 0xBB, + 0x71, 0xB7, 0x50, 0x9D, 0xFB, 0x0A, 0xC9, 0xB8, 0x3D, 0x83, + 0x2D, 0xFE, 0x65, 0x9D, 0xB9, 0xD3, 0xBC, 0x2F, 0x2F, 0xDE, + 0x42, 0x07, 0x32, 0xFB, 0x9B, 0x99, 0x28, 0xF4, 0x6C, 0xAF, + 0xC4, 0x35, 0xC4, 0xC8, 0xEE, 0x0D, 0xC7, 0x19, 0xB7, 0xEF, + 0x75, 0xFB, 0xAA, 0x76, 0xBB, 0x43, 0x1A, 0x9A, 0xA4, 0x34, + 0x10, 0x95, 0x49, 0xAF, 0xEC, 0x96, 0xE1, 0x0E, 0x98, 0xBB, + 0xEB, 0x0B, 0x14, 0x28, 0x27, 0x72, 0x91, 0x1A, 0x45, 0x25, + 0x1C, 0x79, 0xD0, 0x0D, 0x77, 0xEA, 0xB3, 0x69, 0xCA, 0xE3, + 0xED, 0x75, 0x59, 0xF9, 0xF2, 0xDF, 0x8C, 0x32, 0xBA, 0x17, + 0x50, 0x03, 0x95, 0x4F, 0x9B, 0x7C, 0xAF, 0x08, 0x9D, 0xDB, + 0x6B, 0x33, 0xCE, 0x6F, 0xFD, 0x68, 0x3D, 0x42, 0x53, 0x4D, + 0x6F, 0x08, 0xF8, 0xCF, 0x43, 0xC6, 0x37, 0x55, 0x07, 0xE6, + 0x39, 0x7B, 0x4D, 0x79, 0x82, 0x91, 0x32, 0x6B, 0xE6, 0x1F, + 0xCC, 0xDB, 0xF8, 0xC3, 0x9D, 0x01, 0x28, 0xAA, 0xB4, 0xC6, + 0xE2, 0x06, 0x4B, 0x48, 0xA7, 0xB1, 0x76, 0xAA, 0xFD, 0xC4, + 0x3F, 0xD3, 0x9B, 0xCA, 0x8B, 0x7D, 0xAE, 0xA2, 0xF3, 0xBD, + 0x54, 0x03, 0x2A, 0xAE, 0xD4, 0x2C, 0x50, 0x59, 0xA5, 0x02, + 0x4D, 0xA3, 0xD0, 0xC8, 0x65, 0x33, 0xA6, 0x85, 0x72, 0x0A, + 0xCE, 0xF3, 0x53, 0x40, 0x9C, 0x2F, 0x98, 0xC3, 0xF5, 0x7C, + 0x60, 0xCB, 0xD7, 0xBE, 0xF2, 0x87, 0x92, 0x3B, 0x27, 0xB7, + 0x56, 0x5B, 0xA3, 0xAB, 0x68, 0x52, 0x25, 0xF3, 0x89, 0x28, + 0x9C, 0x1C, 0x73, 0xDE, 0x4A, 0xA1, 0xB8, 0xCF, 0xD3, 0x0E, + 0x51, 0x55, 0xF4, 0x06, 0x7C, 0x51, 0xDC, 0x4F, 0x68, 0xF2, + 0x82, 0x60, 0x84, 0xC4, 0xFF, 0x87, 0xA4, 0x7A, 0x83, 0x5A, + 0xE0, 0x4E, 0xA8, 0xD4, 0x11, 0x87, 0x3B, 0xF2, 0x52, 0xD1, + 0x18, 0xD3, 0xC2, 0xAA, 0x7A, 0x19, 0xC4, 0xC2, 0x47, 0x9E, + 0x86, 0xED, 0xAD, 0xD5, 0xD8, 0x23, 0x6D, 0x6D, 0xAE, 0x27, + 0xCE, 0x64, 0x2A, 0x62, 0xFE, 0x74, 0xFF, 0x50, 0x4D, 0x6F, + 0xD0, 0x6B, 0x37, 0x61, 0x3F, 0x32, 0xF9, 0x7C, 0x2A, 0xD6, + 0x79, 0xDE, 0xE6, 0xBB, 0xF0, 0x61, 0xE5, 0xF6, 0x3B, 0x18, + 0x82, 0xBB, 0x2C, 0xF4, 0x23, 0xBA, 0x38, 0x30, 0xDA, 0xA3, + 0x37, 0xAC, 0x5B, 0xDD, 0x3D, 0xE1, 0xEE, 0x49, 0xB9, 0xA6, + 0x28, 0xA1, 0xDC, 0x90, 0x14, 0x8B, 0x95, 0x1D, 0x40, 0xFF, + 0xDC, 0x85, 0xEA, 0xCF, 0x4A, 0x2C, 0xB4, 0x2C, 0xC5, 0x05, + 0x09, 0xBF, 0xD5, 0x91, 0x23, 0x9A, 0x90, 0x6A, 0xE7, 0x9F, + 0x96, 0xDC, 0x10, 0x40, 0x26, 0xB3, 0xB6, 0xFF, 0x36, 0x8C, + 0xDD, 0xCA, 0xD7, 0x82, 0x3B, 0x25, 0x16, 0x6D, 0xC9, 0x53, + 0x78, 0xA7, 0x5D, 0x02, 0x8C, 0xD3, 0x0A, 0xC2, 0x71, 0x8B, + 0xA9, 0xAF, 0xD6, 0x3B, 0xB9, 0xF8, 0xD6, 0xB3, 0xC1, 0xA3, + 0x66, 0x34, 0x47, 0x87, 0x6D, 0x5F, 0xBD, 0x0F, 0x21, 0x6F, + 0x16, 0xCB, 0x1F, 0x56, 0xE3, 0x3F, 0x92, 0xD8, 0xBC, 0xC3, + 0xCB, 0x5E, 0x20, 0x11, 0xE7, 0xDF, 0x83, 0x73, 0x20, 0x14, + 0xBB, 0x52, 0x5D, 0xD0, 0xC0, 0x2D, 0x77, 0x5B, 0x01, 0xAC, + 0x10, 0xAA, 0x57, 0x0A, 0x89, 0x50, 0x70, 0x96, 0xD0, 0x10, + 0xAE, 0x46, 0x55, 0x93, 0x9E, 0x81, 0xAC, 0x24, 0xD5, 0x96, + 0xE1, 0xA7, 0xDD, 0x69, 0x1A, 0xC8, 0x2F, 0xFF, 0x8C, 0xDC, + 0x92, 0x96, 0x73, 0x39, 0x38, 0xE3, 0x80, 0x28, 0xE8, 0xA3, + 0x64, 0xC5, 0xF4, 0xE1, 0x26, 0xA1, 0x7E, 0xDE, 0x09, 0x7A, + 0xB5, 0x14, 0x34, 0xDE, 0x1A, 0x22, 0x3F, 0x93, 0x54, 0x20, + 0x97, 0x5F, 0xF1, 0xE1, 0xCC, 0xE4, 0x7F, 0x96, 0xC1, 0x8A, + 0x40, 0xBC, 0x4E, 0x76, 0x86, 0x5A, 0x26, 0xB4, 0x41, 0x0F, + 0x69, 0x5B, 0xC5, 0x69, 0xC5, 0x8A, 0x36, 0x96, 0x23, 0x8E, + 0x65, 0x31, 0x7E, 0x4C, 0xCC, 0x0D, 0x03, 0x3D, 0xD6, 0x9C, + 0x19, 0x93, 0x01, 0xB2, 0xDD, 0xB4, 0x18, 0x49, 0xD1, 0x6E, + 0xC0, 0x73, 0x23, 0xA0, 0xFB, 0x99, 0x01, 0xE4, 0xAA, 0x68, + 0xC7, 0x2A, 0x35, 0x67, 0xEF, 0x37, 0x87, 0x44, 0x14, 0x96, + 0x21, 0x3D, 0x19, 0x0C, 0x2B, 0x75, 0x6E, 0x5A, 0x33, 0x26, + 0x2B, 0x8C, 0x1E, 0x9A, 0x67, 0x87, 0x61, 0x5C, 0x84, 0x1A, + 0x13, 0x55, 0x99, 0xB9, 0x35, 0x34, 0x98, 0x85, 0xFA, 0x5E, + 0x7B, 0xC3, 0x39, 0x9A, 0xEA, 0x0C, 0xF1, 0x2D, 0xD6, 0x56, + 0xC4, 0xF6, 0x36, 0xA2, 0x41, 0xA2, 0x67, 0x22, 0xAE, 0x91, + 0xAF, 0xF2, 0x0D, 0xFA, 0x6E, 0x28, 0xF1, 0xFC, 0xCF, 0x9C, + 0x01, 0xF6, 0x79, 0x45, 0xFC, 0xB2, 0x96, 0xD0, 0x14, 0x56, + 0x77, 0x01, 0xF8, 0x50, 0x3B, 0xBC, 0xF4, 0x13, 0xB7, 0xB4, + 0xA0, 0x1A, 0xE9, 0x85, 0x00, 0xF1, 0x0E, 0xB7, 0x97, 0x74, + 0x14, 0x65, 0xB1, 0xEF, 0x7F, 0x32, 0x3D, 0xF8, 0xFB, 0x95, + 0xED, 0x5A, 0xA4, 0x24, 0x3C, 0x56, 0x9A, 0x33, 0xCE, 0x55, + 0xC4, 0x1C, 0xF6, 0x1C, 0x61, 0xEB, 0x8A, 0x42, 0x15, 0x8A, + 0x28, 0x00, 0x7F, 0x5B, 0x32, 0xC1, 0xDA, 0x3E, 0x77, 0xB0, + 0x7E, 0x9B, 0x88, 0x47, 0xE5, 0x6C, 0xD1, 0x02, 0x6D, 0xB0, + 0xC1, 0x3C, 0x9F, 0x13, 0x79, 0x88, 0xEA, 0xD9, 0x18, 0xD0, + 0x9B, 0x10, 0x69, 0x17, 0x55, 0x46, 0x52, 0x89, 0xD9, 0x80, + 0x55, 0x9D, 0x1F, 0x0B, 0x43, 0xB8, 0x1F, 0xD4, 0x91, 0xEC, + 0xD7, 0xF9, 0xF8, 0xB5, 0x74, 0x17, 0xC3, 0xFE, 0x99, 0xA0, + 0x48, 0xBF, 0x1A, 0xF4, 0x9A, 0x91, 0x54, 0x9C, 0x40, 0xE4, + 0x13, 0xBA, 0x96, 0x28, 0x33, 0xC2, 0x7E, 0x6F, 0x94, 0xE8, + 0x76, 0x29, 0x5F, 0xE4, 0xB9, 0xD9, 0xB6, 0xF7, 0xC2, 0x88, + 0xF7, 0xBE, 0xC2, 0x9D, 0x53, 0x1F, 0x06, 0xB0, 0x7A, 0xE3, + 0x05, 0xDB, 0x99, 0xEC, 0x5A, 0xD5, 0xEA, 0x50, 0xCC, 0xFC, + 0x5F, 0xDD, 0xD9, 0xC3, 0x1F, 0xA1, 0x7A, 0xFE, 0x40, 0x55, + 0x63, 0x7D, 0x48, 0x35, 0xC4, 0x31, 0x3A, 0xCC, 0x5F, 0x41, + 0xD5, 0x1C, 0x6D, 0x84, 0x7E, 0x8F, 0xD6, 0xD6, 0xE5, 0x47, + 0xFB, 0x57, 0x7B, 0x31, 0x27, 0x1B, 0xB9, 0x41, 0x97, 0x70, + 0x19, 0x50, 0x4E, 0x80, 0x94, 0x42, 0xC1, 0xF0, 0x09, 0x99, + 0xF4, 0x43, 0xAD, 0xCD, 0x5D, 0xD5, 0x44, 0xFC, 0x86, 0xD9, + 0x0D, 0x32, 0x6F, 0xD5, 0x05, 0xB2, 0x62, 0xD5, 0x67, 0xC2, + 0xB3, 0x23, 0x60, 0xD1, 0x2A, 0x62, 0x81, 0x28, 0x09, 0xA3, + 0x59, 0x71, 0xBA, 0xEF, 0x17, 0x74, 0x37, 0xFE, 0x5B, 0xCF, + 0x89, 0x71, 0x05, 0x1A, 0x4F, 0x6A, 0x07, 0x29, 0xB4, 0xF8, + 0xCA, 0x33, 0x3B, 0x7C, 0x5F, 0xDD, 0xA9, 0x9D, 0xBE, 0x52, + 0xE3, 0x69, 0x6C, 0x3D, 0x87, 0x7F, 0x5A, 0x8A, 0xA5, 0xF2, + 0x7D, 0xC2, 0xC4, 0xF7, 0x68, 0x47, 0x6A, 0x1C, 0xC9, 0x69, + 0x47, 0x33, 0x70, 0x47, 0xC1, 0x3C, 0x45, 0xDB, 0xA1, 0x58, + 0x0E, 0xE0, 0xEF, 0x41, 0xFF, 0x43, 0x54, 0x87, 0x92, 0x44, + 0x47, 0xB1, 0xCD, 0x13, 0x0D, 0x85, 0x23, 0x39, 0xC0, 0xD0, + 0x56, 0xB2, 0xC4, 0x78, 0xBF, 0xA1, 0x2A, 0x7D, 0x71, 0x13, + 0x39, 0x39, 0x2F, 0x8E, 0x7E, 0xB3, 0x9B, 0x3A, 0x5F, 0xCB, + 0xC3, 0x95, 0x65, 0x43, 0x13, 0xC9, 0x26, 0x36, 0x08, 0x65, + 0xAF, 0x42, 0xED, 0xF1, 0x74, 0xCF, 0x25, 0x99, 0xBF, 0x6F, + 0x92, 0x4D, 0x88, 0xAB, 0x25, 0x36, 0xAE, 0x4B, 0xF6, 0x93, + 0xC8, 0x95, 0x7D, 0x41, 0xB1, 0xBF, 0x25, 0x48, 0xA4, 0xB0, + 0x50, 0x0C, 0x0D, 0x1C, 0x98, 0x40, 0xB3, 0x6C, 0xFA, 0x22, + 0xE6, 0xD0, 0xB7, 0xE5, 0xD8, 0x55, 0x09, 0xCE, 0x22, 0xB5, + 0x0A, 0x7F, 0xFA, 0x86, 0x6A, 0xDA, 0xC8, 0x56, 0x90, 0xE3, + 0x09, 0x99, 0x1E, 0x77, 0x8B, 0xF7, 0x4A, 0x00, 0xD6, 0xAE, + 0xEC, 0xF4, 0x5F, 0x37, 0xA5, 0x08, 0x48, 0x51, 0x0B, 0x62, + 0x8A, 0x93, 0x5C, 0xA5, 0x8D, 0xAF, 0x88, 0xB8, 0xC7, 0xC0, + 0x5B, 0xA3, 0x7E, 0xA6, 0xD2, 0xA7, 0x2B, 0x44, 0x80, 0xEA, + 0x36, 0x52, 0x75, 0xBC, 0xF6, 0xC4, 0xB6, 0x07, 0xB2, 0xAA, + 0xCA, 0x3F, 0x97, 0xE3, 0x88, 0xB3, 0x19, 0x52, 0x1A, 0x63, + 0x83, 0x8F, 0xEF, 0x5C, 0x7C, 0xA9, 0x69, 0xE2, 0xA2, 0xC1, + 0x49, 0xE9, 0x2A, 0x4E, 0x31, 0xB0, 0x4B, 0xC0, 0x25, 0x14, + 0x7B, 0x5B, 0x16, 0xA2, 0x8D, 0x63, 0xFD, 0x53, 0x31, 0x72, + 0xE8, 0xA3, 0x29, 0x87, 0x22, 0x25, 0x63, 0x68, 0x8A, 0xCA, + 0xC9, 0x87, 0x64, 0xA8, 0xB0, 0xB9, 0x6B, 0x00, 0x00, 0x8C, + 0x54, 0x89, 0xAC, 0x6F, 0x6B, 0x12, 0x33, 0x6D, 0xF7, 0x07, + 0x1A, 0x7C, 0xCF, 0xD4, 0xF9, 0x8A, 0x65, 0x3B, 0x3F, 0x71, + 0x88, 0x68, 0x25, 0x9D, 0x6C, 0xFB, 0x14, 0xD5, 0xC0, 0xBF, + 0xCD, 0x45, 0x77, 0xB3, 0x27, 0x75, 0x5C, 0x06, 0xF8, 0x81, + 0xD3, 0x6E, 0xD3, 0xD7, 0x1E, 0xB3, 0x32, 0xBF, 0x88, 0x9E, + 0xD1, 0xBD, 0x5C, 0xD6, 0x28, 0x67, 0x39, 0x78, 0x3D, 0x5F, + 0xB8, 0x47, 0x3A, 0x41, 0x22, 0x3A, 0xF8, 0x1C, 0x52, 0x84, + 0x8A, 0x89, 0x45, 0x01, 0x06, 0xBA, 0x8C, 0x00, 0x91, 0x1F, + 0xA7, 0x91, 0xC1, 0xA5, 0x2B, 0x7A, 0x94, 0xF2, 0xFF, 0x89, + 0xE8, 0xD4, 0xB0, 0xC6, 0xB3, 0xF8, 0x59, 0x33, 0x36, 0x8D, + 0x7D, 0x43, 0xD3, 0x82, 0x60, 0x6C, 0x35, 0x7B, 0xBD, 0xE7, + 0x0B, 0x11, 0xB9, 0x4D, 0xBD, 0x80, 0x35, 0x92, 0x22, 0x29, + 0x10, 0xA7, 0xDA, 0x95, 0x0E, 0x53, 0xD2, 0x10, 0x3C, 0x23, + 0x48, 0x99, 0xA4, 0x18, 0xF8, 0xE1, 0x32, 0xF8, 0x9A, 0x82, + 0x24, 0x19, 0x47, 0x5D, 0x99, 0x33, 0x44, 0x14, 0x6D, 0x16, + 0xD5, 0x84, 0x1E, 0x16, 0xA7, 0xEB, 0xC5, 0x4B, 0x10, 0x96, + 0x76, 0x76, 0x06, 0x32, 0x31, 0x6B, 0xCE, 0x77, 0xA3, 0x0E, + 0xBB, 0xD8, 0xE0, 0xA7, 0xE2, 0xAA, 0xA8, 0x3F, 0x50, 0x10, + 0x87, 0xEA, 0xC0, 0x63, 0xA1, 0xE5, 0x09, 0xA2, 0xB8, 0xB1, + 0x94, 0x83, 0x28, 0x08, 0x8A, 0x22, 0xBD, 0x55, 0xE2, 0x2E, + 0x57, 0x9C, 0x4A, 0x42, 0x65, 0x10, 0x45, 0xEC, 0x2D, 0xCA, + 0x5B, 0xF8, 0x1A, 0xE2, 0x09, 0xD6, 0xF7, 0xCE, 0xA1, 0x5D, + 0x64, 0xDA, 0x49, 0xD6, 0x00, 0x37, 0x20, 0x15, 0x24, 0x98, + 0x98, 0xB6, 0x5C, 0xAD, 0xFF, 0x41, 0xA0, 0x95, 0x1A, 0x02, + 0xC5, 0xEB, 0x77, 0x27, 0x2C, 0x67, 0x90, 0x81, 0xAC, 0xB3, + 0x1E, 0x37, 0x32, 0xE3, 0xB5, 0x06, 0xD7, 0x77, 0x5F, 0x4C, + 0x44, 0x0E, 0x0E, 0x3A, 0xCC, 0x87, 0x0F, 0xB1, 0xDA, 0xDF, + 0x64, 0x29, 0xE0, 0xD5, 0x86, 0xC9, 0x67, 0xFA, 0x56, 0xDD, + 0xDA, 0xCA, 0x39, 0x0A, 0xC1, 0xB2, 0xB0, 0x34, 0x77, 0x1A, + 0xB7, 0x0E, 0x81, 0x5F, 0xDA, 0x30, 0x75, 0xF2, 0xF5, 0xC6, + 0x80, 0x0B, 0xF1, 0x55, 0x2F, 0x3C, 0xF3, 0xA6, 0xD0, 0x85, + 0xDF, 0x17, 0xA6, 0x7C, 0xDB, 0xAF, 0x4C, 0xBE, 0xD6, 0x13, + 0x3F, 0x16, 0x90, 0xE4, 0xA6, 0x08, 0xDC, 0x46, 0xF3, 0x9C, + 0xB1, 0x08, 0x7E, 0x2A, 0xBC, 0xCE, 0xDA, 0xB0, 0x83, 0x39, + 0x5C, 0x86, 0x65, 0x86, 0x3A, 0x0A, 0x08, 0x5C, 0x08, 0x1C, + 0x49, 0x29, 0xCD, 0x64, 0x84, 0x73, 0xB6, 0xA1, 0x00, 0xAC, + 0x0F, 0x07, 0x28, 0x33, 0x8C, 0x36, 0x24, 0xDA, 0xFC, 0xEF, + 0xF4, 0x88, 0x40, 0x14, 0xDF, 0x4A, 0x1F, 0xCA, 0x24, 0xD5, + 0x68, 0xFB, 0xEF, 0x82, 0xBA, 0xBE, 0x4B, 0x4C, 0xE8, 0xE9, + 0x40, 0x20, 0x8D, 0x2B, 0xF8, 0x76, 0x4E, 0xB5, 0x3A, 0x76, + 0xA6, 0xC1, 0x5C, 0x9F, 0xCB, 0x4C, 0x21, 0x05, 0xC9, 0xE9, + 0x64, 0x8E, 0x4E, 0x68, 0x9A, 0x6A, 0x7B, 0x8E, 0xA7, 0xCF, + 0x08, 0xEF, 0x1C, 0x9D, 0xEA, 0x5E, 0x82, 0x48, 0x12, 0xD9, + 0x74, 0x2F, 0xE1, 0x46, 0x3B, 0x12, 0x8F, 0xB6, 0x66, 0x09, + 0xA3, 0xBE, 0x93, 0xF7, 0xFF, 0x95, 0x3A, 0xC8, 0x51, 0x46, + 0x3C, 0xC5, 0x0E, 0x16, 0x86, 0x58, 0x8F, 0xA9, 0x74, 0xF3, + 0x82, 0xC2, 0xB4, 0x63, 0xD2, 0x37, 0x66, 0x0B, 0x44, 0x35, + 0x30, 0x32, 0x12, 0xBB, 0xF6, 0xC6, 0x85, 0x7B, 0x4B, 0xEC, + 0xF8, 0x58, 0x7A, 0xC8, 0x7F, 0xA7, 0x0D, 0x41, 0x9B, 0x92, + 0xA8, 0x88, 0xCC, 0x87, 0xB3, 0x62, 0x28, 0x5F, 0xED, 0x37, + 0x56, 0xED, 0x24, 0x2F, 0xE9, 0x2C, 0x12, 0x56, 0x50, 0x3D, + 0xE3, 0x52, 0xE4, 0xE1, 0xA8, 0xCD, 0x75, 0xA8, 0x30, 0xBA, + 0xC2, 0xD7, 0x70, 0xD9, 0x5C, 0xD2, 0x5D, 0x85, 0x6B, 0x1F, + 0x9C, 0xA5, 0xB3, 0x77, 0x62, 0xF3, 0x48, 0xC7, 0xC0, 0x60, + 0x27, 0xFA, 0x09, 0x7B, 0xE5, 0x53, 0x01, 0x2C, 0x59, 0xA2, + 0x2E, 0xBE, 0xBD, 0x08, 0xA5, 0xB0, 0xEF, 0xDB, 0x04, 0xA8, + 0x6F, 0x2A, 0xDC, 0x41, 0x5C, 0xA5, 0xBE, 0xBD, 0x8D, 0xAC, + 0xF0, 0x92, 0x96, 0xA1, 0x6F, 0xF1, 0xD5, 0x13, 0xBB, 0x1E, + 0x8D, 0x62, 0x52, 0x4A, 0xA6, 0x63, 0x19, 0x78, 0x37, 0x18, + 0xE4, 0xDF, 0xCE, 0x4B, 0x3C, 0x76, 0xBD, 0x68, 0x36, 0x1C, + 0x10, 0xAE, 0x46, 0x27, 0x1C, 0x88, 0x43, 0x39, 0x78, 0x2A, + 0x19, 0xFC, 0x61, 0xDE, 0xA8, 0x19, 0x52, 0xC1, 0x2B, 0x8C, + 0x87, 0xDF, 0x18, 0xD8, 0x17, 0x0F, 0xA4, 0xD3, 0x5A, 0x6B, + 0x63, 0xB9, 0x94, 0x6D, 0x58, 0xE3, 0xBF, 0x6B, 0xE7, 0x11, + 0xE9, 0xFC, 0x99, 0x67, 0xD5, 0x10, 0xF9, 0x2E, 0x08, 0x6E, + 0x39, 0x6C, 0x80, 0x9B, 0xA8, 0x4D, 0xC4, 0x55, 0xDF, 0xBF, + 0x8F, 0xB7, 0x0D, 0xB0, 0xDC, 0xB9, 0x1D, 0xD3, 0xE5, 0x9F, + 0xE4, 0x65, 0xE0, 0x63, 0x8E, 0xDE, 0x54, 0x78, 0x4D, 0x36, + 0xF8, 0x46, 0x9D, 0xD5, 0x66, 0x5E, 0x09, 0xB2, 0x1B, 0x91, + 0xAC, 0x5F, 0x87, 0x3D, 0x72, 0x67, 0xAA, 0xAC, 0xB8, 0xE2, + 0x49, 0x7D, 0xA7, 0x81, 0x5E, 0xB1, 0x58, 0x96, 0x3D, 0xDD, + 0xA4, 0x75, 0x41, 0x44, 0x50, 0x6A, 0x71, 0x36, 0x25, 0xF0, + 0xDA, 0x09, 0x1C, 0xCE, 0x05, 0x13, 0x73, 0x70, 0x2C, 0xAB, + 0x9F, 0xDE, 0xF9, 0x17, 0xD6, 0xA3, 0x86, 0x1F, 0xCD, 0x03, + 0x4A, 0x9F, 0x1C, 0xB0, 0xAA, 0x1B, 0x2C, 0xA8, 0xE5, 0x7B, + 0x61, 0x71, 0x43, 0x56, 0x07, 0x2A, 0x23, 0x58, 0xE3, 0x7B, + 0xE4, 0xD4, 0xF1, 0x76, 0xF2, 0x41, 0xD5, 0xCB, 0x29, 0x2B, + 0xB7, 0xA9, 0x77, 0x98, 0xB5, 0x3F, 0xAE, 0xE5, 0xF5, 0xAA, + 0x87, 0x9E, 0x7F, 0x1A, 0xB1, 0x3B, 0xD9, 0xD5, 0xDB, 0x64, + 0xDF, 0x4D, 0xD9, 0xF4, 0xF2, 0xE2, 0xBE, 0xDE, 0xCE, 0x6C, + 0xBC, 0x7B, 0x84, 0x81, 0x3B, 0xAD, 0xCB, 0x53, 0xC6, 0xF6, + 0x6D, 0x28, 0x3D, 0x30, 0x28, 0x52, 0x26, 0x78, 0x5B, 0x1A, + 0x22, 0x39, 0xE5, 0x38, 0xAA, 0x92, 0x7C, 0x1F, 0xD5, 0x99, + 0x33, 0x26, 0xFF, 0x97, 0x55, 0x2F, 0xA0, 0x85, 0x57, 0xD5, + 0x84, 0x43, 0xAB, 0x64, 0xD3, 0x48, 0x78, 0xA0, 0x73, 0xF8, + 0x5A, 0xBE, 0x6D, 0xA1, 0xC9, 0x02, 0x8A, 0xD5, 0x06, 0x32, + 0xF4, 0x72, 0xE1, 0x54, 0x96, 0xF3, 0x36, 0x57, 0xEE, 0x69, + 0x67, 0xE6, 0x19, 0x86, 0x8C, 0xF8, 0xB2, 0xA9, 0x2D, 0x49, + 0x4F, 0x27, 0x48, 0xF0, 0x5E, 0x25, 0x4B, 0xC8, 0xFA, 0x5C, + 0x80, 0xD5, 0x0B, 0x24, 0x27, 0x68, 0x0B, 0xED, 0x9E, 0xC7, + 0x67, 0x3A, 0x25, 0x99, 0xD9, 0x3C, 0xD3, 0xCB, 0xB2, 0x69, + 0x2E, 0x85, 0xA5, 0x3C, 0xF2, 0x8A, 0x01, 0x0C, 0xB4, 0xED, + 0x97, 0xBD, 0xB5, 0x0C, 0xA2, 0x1A, 0x13, 0x7F, 0x02, 0xDD, + 0x2E, 0x0C, 0x2F, 0x66, 0x23, 0xB9, 0x75, 0xA9, 0x7E, 0xBC, + 0x37, 0x8F, 0xAC, 0xDC, 0x19, 0xAF, 0xC2, 0xF2, 0xC7, 0x88, + 0xB8, 0x9A, 0xFE, 0xD7, 0x4F, 0x58, 0x01, 0x7C, 0x5B, 0x08, + 0xB5, 0x43, 0xC8, 0x68, 0x69, 0xDF, 0xFD, 0x1F, 0x9D, 0x34, + 0x37, 0xBD, 0xDA, 0xFF, 0xDB, 0x52, 0xBE, 0x7D, 0x81, 0x55, + 0xEC, 0x0A, 0xEA, 0x59, 0x0D, 0xCF, 0xC8, 0xB5, 0xFE, 0xB8, + 0xFB, 0x1F, 0xBC, 0x27, 0x5F, 0x6E, 0xD3, 0x7F, 0xC1, 0x38, + 0x6A, 0x42, 0x58, 0x71, 0x86, 0x25, 0x50, 0xDA, 0x04, 0xAF, + 0x62, 0xBB, 0xC2, 0xD0, 0xA3, 0x60, 0x8A, 0xFC, 0xB5, 0x5E, + 0xE8, 0x87, 0xD6, 0x27, 0x24, 0x6C, 0xB2, 0x27, 0x63, 0x80, + 0x64, 0x9D, 0x58, 0xF4, 0x99, 0x79, 0x88, 0x48, 0x7A, 0x39, + 0x1B, 0x48, 0xB1, 0x40, 0x34, 0xC4, 0x9A, 0x31, 0x07, 0xB2, + 0x06, 0xE0, 0xFB, 0x2D, 0xBF, 0x14, 0xDC, 0x6F, 0xAE, 0x37, + 0x1D, 0xA5, 0x84, 0x45, 0x78, 0x30, 0x91, 0xF3, 0x54, 0x78, + 0x51, 0x8D, 0x33, 0xAB, 0x1F, 0xA5, 0x52, 0x51, 0x85, 0xD3, + 0x79, 0x77, 0x9F, 0xF3, 0x9B, 0xD7, 0xB2, 0x3D, 0xA9, 0x3D, + 0xFF, 0xCD, 0x2C, 0x88, 0x25, 0xBE, 0x19, 0xCC, 0x9E, 0xC3, + 0x25, 0x60, 0xDB, 0x1E, 0xB3, 0x56, 0x39, 0xF4, 0x8A, 0x9C, + 0xE0, 0xEA, 0x10, 0xEE, 0xF9, 0x6D, 0x43, 0xAC, 0x59, 0xEE, + 0x6A, 0x42, 0x24, 0x1C, 0x12, 0x1C, 0xBF, 0xF3, 0x66, 0x0C, + 0xA7, 0x01, 0x6A, 0x17, 0xC9, 0x55, 0x89, 0x0B, 0x2D, 0x61, + 0x62, 0xE1, 0x11, 0x4D, 0x83, 0x07, 0x81, 0x21, 0x6A, 0x33, + 0xDE, 0x24, 0xAF, 0x49, 0x23, 0x09, 0x74, 0xC7, 0xF0, 0x61, + 0x97, 0x08, 0xFF, 0x76, 0xCA, 0x17, 0xA3, 0x46, 0x24, 0xD1, + 0x8B, 0x38, 0x6D, 0x71, 0xAA, 0x0F, 0xDE, 0x70, 0x4F, 0x9C, + 0xA7, 0x70, 0xF3, 0x88, 0x03, 0xAA, 0x9A, 0xB8, 0x61, 0x4D, + 0x83, 0x70, 0x75, 0xCC, 0xB5, 0xA6, 0xEA, 0xBA, 0x08, 0x3B, + 0x57, 0x12, 0xE2, 0x87, 0x0A, 0xC1, 0x66, 0x52, 0x7F, 0xB2, + 0x93, 0x77, 0x57, 0xC6, 0x7A, 0x08, 0xE4, 0x62, 0x81, 0xD5, + 0x7E, 0x7B, 0x3B, 0x1C, 0x02, 0x8F, 0xB9, 0xEA, 0x4D, 0x4F, + 0xB1, 0x63, 0xC7, 0x94, 0xFF, 0x4C, 0x71, 0x49, 0x17, 0x6D, + 0x87, 0x48, 0x4D, 0x94, 0x65, 0x75, 0xDD, 0xDF, 0x90, 0x47, + 0xB2, 0x76, 0xE2, 0x1F, 0xD5, 0x55, 0x38, 0xAF, 0x20, 0x5E, + 0xF2, 0x04, 0xF9, 0xE1, 0x4E, 0x9D, 0xBC, 0x1B, 0x6C, 0x47, + 0xB2, 0x6C, 0x9C, 0xF5, 0xFD, 0x25, 0xAB, 0x91, 0xBD, 0x2A, + 0x18, 0xFA, 0xBD, 0x20, 0xE2, 0x52, 0xF1, 0x5E, 0xC4, 0x69, + 0x6E, 0x26, 0x0D, 0x88, 0x14, 0xB8, 0x7A, 0x3B, 0xB8, 0xD9, + 0x9A, 0x33, 0x3A, 0x7B, 0x62, 0xCC, 0x47, 0x7F, 0x25, 0xF1, + 0xED, 0x58, 0x6A, 0x5F, 0xE9, 0x60, 0x64, 0xC7, 0xE0, 0x40, + 0x09, 0x97, 0x22, 0x6B, 0xF2, 0x46, 0xBD, 0xF4, 0xB1, 0x73, + 0xE0, 0x15, 0xE9, 0x40, 0x8A, 0x78, 0x20, 0x66, 0x69, 0x5B, + 0x03, 0xF3, 0xCF, 0xAA, 0x23, 0x7F, 0x03, 0x23, 0x1B, 0xA2, + 0xC6, 0x68, 0xBC, 0x2C, 0x99, 0xD8, 0x3B, 0x09, 0x8E, 0x06, + 0xD0, 0x03, 0xAB, 0x8D, 0x60, 0x65, 0x26, 0xDE, 0xB9, 0x95, + 0xA7, 0xEC, 0x18, 0xA9, 0x2B, 0x40, 0x18, 0xE3, 0x8E, 0x55, + 0x97, 0x32, 0x0F, 0x5D, 0x53, 0x2E, 0xD3, 0x6B, 0x01, 0x22, + 0x1A, 0xFE, 0x9E, 0xF5, 0x39, 0x0E, 0x86, 0xEB, 0x78, 0xE9, + 0x99, 0x16, 0xFD, 0x2A, 0x34, 0x66, 0x0D, 0x88, 0x35, 0x6D, + 0x36, 0xDA, 0x8E, 0x19, 0x36, 0xA4, 0x54, 0xDD, 0xAD, 0x59, + 0x04, 0x26, 0x60, 0x51, 0x50, 0x34, 0x7B, 0x98, 0x51, 0x73, + 0xE1, 0xDE, 0x11, 0x4C, 0x64, 0x55, 0x7D, 0x4E, 0x1A, 0x0E, + 0xA1, 0xF6, 0x8B, 0x54, 0xF0, 0x59, 0x01, 0x47, 0x8B, 0x38, + 0x18, 0x43, 0x04, 0xC4, 0x8C, 0x18, 0x9E, 0x57, 0x80, 0x35, + 0xAA, 0xFE, 0x39, 0x52, 0xC9, 0x51, 0xD5, 0xBD, 0x3E, 0x96, + 0x7B, 0x83, 0x9C, 0x53, 0xCF, 0x98, 0x10, 0xB4, 0x4F, 0x05, + 0x6E, 0x0C, 0x22, 0xDE, 0xDB, 0xFB, 0xAD, 0xEC, 0xA1, 0xF3, + 0x05, 0x2D, 0x28, 0xBD, 0x47, 0x77, 0x6F, 0xAA, 0xF9, 0x00, + 0x13, 0x5F, 0x9E, 0x2E, 0x00, 0x79, 0x7D, 0x77, 0x38, 0xE5, + 0x57, 0x41, 0xF3, 0x51, 0xAC, 0xBD, 0x40, 0xDD, 0x26, 0x74, + 0x90, 0x61, 0xF9, 0xDC, 0x8F, 0xE0, 0x9F, 0x16, 0x39, 0x69, + 0x07, 0x80, 0x1C, 0x83, 0xE2, 0xAE, 0xD6, 0x5E, 0x62, 0xBC, + 0xD5, 0x10, 0x31, 0x47, 0xDE, 0x88, 0xDB, 0x58, 0x8A, 0x80, + 0xD1, 0x2B, 0x16, 0x7B, 0x75, 0x23, 0xFD, 0xAF, 0x23, 0x9F, + 0xB8, 0x9C, 0x7F, 0x84, 0xA9, 0x5D, 0x5E, 0xB8, 0xBF, 0x9F, + 0x8B, 0xB7, 0x30, 0x78, 0x20, 0xC1, 0xF9, 0x6C, 0x63, 0xC1, + 0x62, 0x3C, 0xB5, 0xB7, 0x27, 0xCA, 0x01, 0x0F, 0xE3, 0xCC, + 0x1E, 0x3A, 0x6E, 0xD6, 0x8C, 0x0B, 0xD0, 0xBF, 0xF8, 0x5A, + 0x77, 0xA4, 0xD3, 0xF6, 0xF5, 0x1A, 0x3F, 0x41, 0x39, 0xC2, + 0x74, 0x4E, 0xD4, 0xC4, 0xA7, 0x90, 0x0A, 0xC6, 0x0B, 0x80, + 0xA7, 0x0C, 0x54, 0x78, 0xAA, 0x14, 0x53, 0x35, 0x22, 0xDD, + 0x9C, 0x0F, 0x97, 0xC6, 0x23, 0xB4, 0x02, 0xAC, 0xBE, 0x40, + 0x47, 0x21, 0x3C, 0xBD, 0x0F, 0x63, 0x82, 0x1B, 0xAA, 0x94, + 0xDA, 0x0A, 0xC9, 0xFA, 0x81, 0x15, 0xA9, 0x0F, 0x21, 0x71, + 0xA9, 0x8E, 0x84, 0x9E, 0x6A, 0xA5, 0x74, 0x77, 0x0E, 0xC3, + 0xB6, 0xEB, 0x25, 0x7C, 0xF7, 0x6A, 0xB4, 0x09, 0xC5, 0x7B, + 0x90, 0x58, 0x7C, 0xBD, 0xE4, 0x48, 0x03, 0xAC, 0x42, 0x1A, + 0x40, 0x0C, 0x12, 0xFB, 0xF3, 0x32, 0x3F, 0x64, 0x8D, 0x0B, + 0x9B, 0x4F, 0x06, 0xCB, 0x21, 0x38, 0xDA, 0x79, 0x51, 0x95, + 0xFB, 0x76, 0xFA, 0xAC, 0x02, 0x0B, 0x34, 0x93, 0x01, 0x67, + 0x03, 0xD4, 0xAC, 0x64, 0x3C, 0xCB, 0xD3, 0xEE, 0xBC, 0x8A, + 0x8F, 0x79, 0xFE, 0xE9, 0xEA, 0xFA, 0xE1, 0x87, 0x08, 0x46, + 0x40, 0x55, 0x72, 0xF8, 0xD8, 0x40, 0x59, 0x36, 0xDF, 0x8D, + 0x9B, 0x73, 0x8D, 0x5A, 0x4D, 0x3F, 0x8E, 0xDC, 0x12, 0x3B, + 0xE9, 0x24, 0x37, 0xAF, 0xF8, 0x6F, 0x35, 0x10, 0xF9, 0x7A, + 0x7E, 0xF0, 0xC2, 0x6A, 0x39, 0xE1, 0x46, 0xD7, 0x10, 0xFF, + 0x65, 0xCA, 0x35, 0xBC, 0x55, 0x19, 0xE0, 0xF6, 0x64, 0x89, + 0x8C, 0xA2, 0x67, 0x5F, 0xD7, 0x21, 0x04, 0x76, 0x4C, 0x48, + 0xB0, 0x68, 0xC7, 0x0A, 0x0F, 0xDD, 0x32, 0x8A, 0x5D, 0x74, + 0x77, 0x12, 0xAA, 0x1C, 0x83, 0x26, 0x32, 0xC5, 0x8B, 0x8F, + 0x81, 0x82, 0x42, 0xC0, 0x3F, 0x1F, 0x94, 0x08, 0x4C, 0xD7, + 0xD4, 0x2D, 0xAF, 0x52, 0xDD, 0xCD, 0x04, 0xC3, 0x1B, 0xEF, + 0xAB, 0x52, 0xB5, 0xA7, 0xD6, 0x38, 0xE3, 0xC5, 0xD2, 0xF8, + 0x33, 0x11, 0x89, 0xFA, 0x76, 0xC2, 0xB1, 0x68, 0x27, 0xB3, + 0x10, 0xAA, 0xD4, 0xBB, 0xAC, 0x5F, 0x0C, 0xDF, 0x5A, 0xE5, + 0xB5, 0x44, 0x48, 0x5A, 0x69, 0x53, 0xC0, 0x2B, 0x19, 0xB2, + 0x4D, 0x78, 0xFB, 0xC9, 0x76, 0x7F, 0x93, 0x90, 0x5A, 0x7D, + 0x92, 0x44, 0x01, 0xC7, 0x3F, 0x6D, 0xB4, 0xA9, 0xD4, 0xF1, + 0xB9, 0xF4, 0xD6, 0x67, 0xEF, 0x3A, 0xF9, 0x1E, 0x6A, 0x61, + 0x13, 0x95, 0x75, 0x50, 0x3D, 0xA0, 0x35, 0x5B, 0xF4, 0x7A, + 0x65, 0xED, 0x43, 0x35, 0xD4, 0x36, 0x3C, 0x00, 0xBD, 0x21, + 0xD9, 0xDE, 0x58, 0x1F, 0x56, 0x52, 0xCB, 0x3F, 0x96, 0x44, + 0x60, 0x02, 0x93, 0x7B, 0xA8, 0x62, 0xF2, 0x03, 0xE3, 0xDB, + 0x51, 0x54, 0x43, 0x53, 0x71, 0xBD, 0x9B, 0x53, 0x3F, 0x7E, + 0x0C, 0x19, 0x1C, 0x88, 0xD1, 0x20, 0xD1, 0x7D, 0x93, 0x64, + 0xAC, 0xFE, 0xC8, 0x71, 0x7A, 0xB7, 0x10, 0x95, 0x1A, 0xE4, + 0xA8, 0xEF, 0x70, 0x72, 0x24, 0xF7, 0xF2, 0xF8, 0x7C, 0x49, + 0x56, 0x5B, 0x3B, 0xC3, 0xFD, 0x53, 0x67, 0xA2, 0x80, 0x38, + 0xE8, 0x5A, 0x4E, 0x26, 0x5B, 0x88, 0x73, 0xDC, 0x71, 0xDD, + 0x13, 0xB2, 0x9A, 0xD5, 0x31, 0x32, 0x43, 0x95, 0x8D, 0xB8, + 0x19, 0x23, 0x81, 0x61, 0xE0, 0xEE, 0x3A, 0xFD, 0xE1, 0x0B, + 0x6B, 0x40, 0x5B, 0x7D, 0xB3, 0xB2, 0xEB, 0xD7, 0x7C, 0xEE, + 0xF2, 0x85, 0xE7, 0x78, 0xB1, 0x67, 0xED, 0x04, 0x0D, 0x24, + 0x0D, 0x88, 0x1B, 0xB3, 0x64, 0x92, 0xBA, 0xEF, 0x66, 0x89, + 0xFB, 0xDE, 0x65, 0x91, 0xF9, 0x36, 0xC6, 0x6E, 0xDD, 0xDF, + 0xFB, 0xFD, 0x40, 0x61, 0x72, 0x44, 0xB2, 0xE7, 0xA7, 0x52, + 0x12, 0xCB, 0x60, 0x13, 0x2D, 0xDD, 0x2D, 0x47, 0xF0, 0x56, + 0x8E, 0xC1, 0x88, 0x5A, 0x09, 0xB9, 0x2F, 0x21, 0xB0, 0x27, + 0x7A, 0x9E, 0x5A, 0xF2, 0xD9, 0x0E, 0xFE, 0xFA, 0x31, 0xD3, + 0x9B, 0xB3, 0x3F, 0x65, 0x38, 0x3B, 0x69, 0x75, 0xEE, 0x6E, + 0x23, 0x8D, 0x8B, 0x36, 0x80, 0x51, 0x37, 0x25, 0x26, 0x1D, + 0x1E, 0x5B, 0x8E, 0x61, 0x2C, 0x2D, 0xC8, 0xDA, 0x25, 0xD4, + 0x70, 0xB4, 0x0B, 0xF5, 0xA9, 0xE7, 0x1E, 0x57, 0x2D, 0xA8, + 0x9B, 0xCE, 0xF1, 0xDF, 0xC9, 0x57, 0x22, 0xF0, 0x86, 0x3B, + 0x3A, 0xFA, 0xFA, 0x39, 0x21, 0x29, 0xC3, 0x8E, 0x58, 0xAB, + 0xFB, 0x55, 0x88, 0x9C, 0x6E, 0xFB, 0xB4, 0x0F, 0xD8, 0x83, + 0xAB, 0x05, 0x86, 0xAD, 0x98, 0x5E, 0x36, 0x58, 0x90, 0x95, + 0x60, 0x7D, 0x9F, 0x73, 0xF9, 0xD3, 0x29, 0xF7, 0x7B, 0xA2, + 0x06, 0x73, 0x53, 0x78, 0xEB, 0xC1, 0x51, 0x58, 0x63, 0x61, + 0xF6, 0x6D, 0x8F, 0x1F, 0xEA, 0x7C, 0xEE, 0x70, 0x28, 0x6C, + 0x0B, 0xE4, 0xA7, 0xE2, 0xB4, 0xBC, 0x94, 0x06, 0xCF, 0x9F, + 0x0E, 0x4C, 0x26, 0xD0, 0x9F, 0xA8, 0x17, 0x2F, 0xF4, 0xFF, + 0xA4, 0x41, 0xDF, 0xBF, 0x8F, 0xDC, 0xD7, 0x48, 0x49, 0xB6, + 0x21, 0xB7, 0x0F, 0xF0, 0xCA, 0x10, 0x39, 0xAD, 0x98, 0x02, + 0x5E, 0x16, 0x79, 0x8D, 0xEB, 0x34, 0x90, 0x47, 0x59, 0x2B, + 0x2D, 0x1F, 0x24, 0x71, 0xF5, 0x16, 0x1B, 0x1B, 0xEC, 0x91, + 0x51, 0x7F, 0x60, 0x3E, 0xF3, 0x10, 0xA4, 0x62, 0x3F, 0x93, + 0x9C, 0x4E, 0x9E, 0xAE, 0xE4, 0x32, 0xFB, 0x58, 0xD8, 0x71, + 0x50, 0x74, 0x2A, 0xD7, 0xE2, 0xE1, 0x6A, 0x48, 0xB5, 0x38, + 0x1F, 0x07, 0x5B, 0xD5, 0x60, 0xD5, 0x29, 0xF3, 0x5E, 0x19, + 0x9B, 0x72, 0x7B, 0xD7, 0xF3, 0xD8, 0xD2, 0xB4, 0xFF, 0x87, + 0x15, 0x82, 0x7D, 0x92, 0xFB, 0xF9, 0x6C, 0xC5, 0x4B, 0x48, + 0x29, 0xF1, 0xFF, 0x75, 0x1C, 0xF9, 0x74, 0x65, 0xEF, 0x74, + 0xF4, 0xB0, 0x4E, 0xDC, 0x9C, 0x42, 0xCE, 0x93, 0x90, 0x90, + 0x86, 0x3A, 0xE3, 0xA5, 0x36, 0xB7, 0x2A, 0x6E, 0xCF, 0x90, + 0x86, 0xF2, 0x4C, 0x90, 0x01, 0x0A, 0x6B, 0x9F, 0x3A, 0x70, + 0x02, 0xA0, 0x18, 0x20, 0x3A, 0xA4, 0xEC, 0x3E, 0x55, 0x2A, + 0x2E, 0xFC, 0x72, 0x45, 0xC3, 0x0A, 0x38, 0xBD, 0xC9, 0xD7, + 0x33, 0xDD, 0x83, 0x3B, 0xD8, 0xF6, 0x31, 0x0F, 0xC7, 0x85, + 0x5A, 0xA9, 0x70, 0x62, 0x38, 0x9C, 0x39, 0x54, 0x33, 0x6F, + 0xBD, 0xB6, 0xBE, 0xE9, 0xD3, 0x6B, 0x3F, 0x7F, 0x00, 0xCC, + 0x06, 0xBA, 0x39, 0xD5, 0x80, 0xAC, 0xDF, 0x53, 0x3B, 0x1C, + 0x4A, 0xD1, 0xA1, 0xE7, 0x96, 0x6C, 0x54, 0x7C, 0x91, 0x3F, + 0x07, 0x2B, 0xFB, 0x8D, 0x3A, 0x88, 0xB8, 0xBD, 0x64, 0x9F, + 0x21, 0x21, 0x36, 0xDB, 0xFF, 0x4D, 0x4A, 0x3F, 0xA5, 0x71, + 0x1E, 0x3D, 0xC1, 0x95, 0x1C, 0x38, 0xD8, 0xDE, 0x22, 0x84, + 0x2D, 0x3C, 0xFD, 0x3C, 0x50, 0xCA, 0x61, 0x18, 0xDE, 0x51, + 0x8C, 0x18, 0xCF, 0x04, 0xEB, 0xF1, 0x79, 0x28, 0x39, 0x91, + 0x56, 0xA2, 0xFD, 0x31, 0xF3, 0x34, 0x97, 0xAE, 0xE3, 0xF6, + 0x03, 0x71, 0x40, 0xB5, 0x81, 0x03, 0xC8, 0x24, 0xC4, 0x8D, + 0xAF, 0x0A, 0x59, 0x09, 0xAB, 0xAE, 0x8E, 0xD1, 0x44, 0xAC, + 0xCF, 0x04, 0xD4, 0x81, 0x45, 0x19, 0x47, 0x44, 0xBD, 0x16, + 0x69, 0x56, 0xBA, 0x40, 0x73, 0xD2, 0x2C, 0x86, 0x44, 0x68, + 0xBF, 0x64, 0xD6, 0x46, 0xBB, 0x1C, 0xA2, 0x90, 0xE1, 0xFA, + 0xAE, 0xC1, 0x66, 0xF7, 0xC1, 0x88, 0x7E, 0x69, 0x09, 0x26, + 0xDB, 0x71, 0xDE, 0x3E, 0xD9, 0x06, 0xE0, 0xC6, 0x2D, 0xB3, + 0x9A, 0xDF, 0x04, 0xFF, 0x83, 0x8D, 0x73, 0x71, 0xF4, 0x5C, + 0x3F, 0xAB, 0xB5, 0xF1, 0x17, 0x9E, 0xD5, 0x31, 0x23, 0x59, + 0xC5, 0x5A, 0xFE, 0x9A, 0x19, 0xCF, 0xF6, 0x72, 0xED, 0xB2, + 0x64, 0x74, 0x2A, 0x6B, 0xB9, 0x2A, 0xDA, 0x93, 0xB6, 0x63, + 0x9A, 0xF7, 0xBC, 0x04, 0x1F, 0x94, 0x8A, 0x40, 0xD8, 0x01, + 0x8A, 0x0C, 0x07, 0x44, 0x8E, 0xC1, 0x3F, 0x0E, 0xD1, 0x5D, + 0xD9, 0x7A, 0xE3, 0x5C, 0xF9, 0x53, 0x36, 0xF8, 0x72, 0x6C, + 0xDD, 0x4E, 0x70, 0x20, 0x9F, 0x52, 0x58, 0x43, 0x49, 0xD8, + 0x40, 0x72, 0xD9, 0xC5, 0x50, 0x10, 0xE9, 0x6E, 0xD8, 0xB8, + 0xF4, 0xA0, 0x40, 0x7D, 0x21, 0x1A, 0xDC, 0x05, 0x1E, 0x42, + 0x85, 0x45, 0xC1, 0x9B, 0x39, 0xBB, 0x19, 0x4B, 0xE8, 0xD3, + 0xB4, 0x2C, 0x82, 0x48, 0x5A, 0xF6, 0x52, 0x15, 0x1B, 0x65, + 0xD3, 0x72, 0x21, 0x87, 0x4C, 0x2D, 0x92, 0xE0, 0x73, 0xA8, + 0xEA, 0xE9, 0x52, 0xBB, 0x01, 0x22, 0x3D, 0x29, 0xEA, 0xB3, + 0x00, 0xE3, 0xFD, 0x92, 0xCF, 0x03, 0x2F, 0xF6, 0x87, 0x9B, + 0x9B, 0xD5, 0x77, 0xC2, 0x28, 0x5B, 0xCF, 0x65, 0x1C, 0x16, + 0xEC, 0x1A, 0xE8, 0x3A, 0x5D, 0x9D, 0x96, 0x2B, 0xBE, 0xC8, + 0xE3, 0x40, 0x24, 0xAE, 0x0A, 0x80, 0x1B, 0x57, 0x15, 0x5A, + 0xC0, 0x91, 0x70, 0x99, 0x0E, 0x0C, 0xD3, 0x56, 0x1F, 0xBE, + 0x6F, 0xC5, 0xEE, 0x0E, 0xE0, 0xAC, 0x24, 0x9F, 0xB1, 0x63, + 0x6D, 0x3D, 0xB8, 0x95, 0xAD, 0xAA, 0xDC, 0x67, 0x93, 0x2D, + 0xFE, 0x71, 0xF7, 0xE8, 0xCB, 0x3F, 0xDB, 0x4F, 0x72, 0xD3, + 0x40, 0xF0, 0x57, 0x1F, 0x21, 0xCB, 0xCF, 0xFB, 0xE8, 0x65, + 0xC1, 0x5C, 0x77, 0xF9, 0xF5, 0xE0, 0xDC, 0xE1, 0x23, 0x05, + 0xE6, 0x6B, 0x61, 0x88, 0x87, 0x57, 0x09, 0x93, 0x6E, 0x1B, + 0x72, 0x90, 0x21, 0x70, 0xA2, 0xFD, 0x7B, 0x60, 0xE6, 0xB4, + 0x70, 0x35, 0x10, 0x20, 0x66, 0xBD, 0xE8, 0x37, 0xFA, 0xC2, + 0xEE, 0x97, 0x78, 0x02, 0xC5, 0x6F, 0x55, 0x28, 0xAC, 0xDB, + 0x92, 0x6E, 0x3B, 0x8A, 0xA8, 0x8D, 0x0E, 0xE9, 0xE0, 0xB9, + 0x36, 0x04, 0x5A, 0x07, 0xCF, 0x71, 0x14, 0x12, 0x11, 0x15, + 0xD4, 0x9D, 0xF6, 0x01, 0x8C, 0xFA, 0xDD, 0x17, 0xDB, 0xDE, + 0xBA, 0xF8, 0x79, 0x2E, 0xFC, 0x5C, 0x48, 0xAF, 0x41, 0xC4, + 0xCE, 0x0C, 0x84, 0xAF, 0x7A, 0x11, 0xFF, 0x4A, 0x39, 0x75, + 0x3E, 0x2E, 0x6A, 0xBC, 0x12, 0xA1, 0xA4, 0xD3, 0x62, 0xFA, + 0x60, 0x26, 0xD4, 0xF8, 0x0B, 0x12, 0xCD, 0x44, 0x30, 0x58, + 0x70, 0xF1, 0x33, 0x5A, 0x7D, 0xFD, 0xFE, 0xBF, 0x6D, 0x81, + 0xA2, 0xF7, 0xB8, 0xE2, 0xFA, 0xC7, 0xD9, 0xA0, 0x84, 0x59, + 0x12, 0xD2, 0x64, 0xE0, 0x88, 0x1A, 0x13, 0x3A, 0xF3, 0x5D, + 0xB4, 0x72, 0x7A, 0xDD, 0x77, 0x14, 0x08, 0x4F, 0x23, 0xD2, + 0x63, 0xF1, 0xC0, 0x34, 0x28, 0xBF, 0xE1, 0x4F, 0xCB, 0x59, + 0x8D, 0xAB, 0xE0, 0x1A, 0x30, 0xE2, 0x74, 0x64, 0xDD, 0xF9, + 0xFB, 0x59, 0x54, 0x6B, 0x32, 0x77, 0xD4, 0x23, 0x65, 0xB8, + 0x2C, 0xE5, 0xA0, 0x4E, 0xF9, 0xF9, 0x7F, 0x55, 0xCA, 0x2C, + 0xDD, 0xB4, 0x24, 0x7C, 0x5A, 0xFF, 0x39, 0x19, 0xB3, 0x9E, + 0x90, 0x32, 0x43, 0xF4, 0xB5, 0x88, 0x5D, 0x42, 0xBD, 0xD1, + 0x15, 0xEF, 0x3E, 0x3C, 0x98, 0x1D, 0xDE, 0x5A, 0xB5, 0xA5, + 0xC1, 0x54, 0xD9, 0x9B, 0x65, 0xE9, 0xCE, 0xE0, 0x7C, 0x0D, + 0xF1, 0x42, 0x1A, 0xDD, 0xA4, 0xB9, 0xF0, 0xAF, 0x93, 0xA7, + 0x57, 0x6E, 0x84, 0x8F, 0x8F, 0xB2, 0xE0, 0xF3, 0x5A, 0xDC, + 0x90, 0x62, 0xE2, 0xA3, 0xA7, 0x4C, 0xDB, 0xA5, 0x8B, 0x6D, + 0x32, 0x30, 0x64, 0x45, 0xD9, 0x51, 0x1B, 0xB3, 0x7F, 0x5C, + 0xC9, 0xFE, 0x07, 0xC2, 0x71, 0x1B, 0x72, 0x7F, 0x90, 0x47, + 0x00, 0x56, 0xD1, 0xE3, 0xF6, 0x11, 0x0C, 0x44, 0x5E, 0xE6, + 0x27, 0xDB, 0x8E, 0x30, 0xB9, 0xE0, 0x60, 0x02, 0xEA, 0x87, + 0xCF, 0x49, 0x1A, 0x4B, 0x2E, 0xF5, 0x41, 0x53, 0xB3, 0xC6, + 0xE9, 0xCF, 0x8E, 0x77, 0x91, 0xE6, 0x44, 0x92, 0xE5, 0x7B, + 0x83, 0xA3, 0x2D, 0x07, 0xDB, 0xBC, 0x50, 0x22, 0x03, 0xD0, + 0x67, 0xDA, 0xD7, 0xD3, 0x69, 0x18, 0x31, 0x1F, 0xCE, 0xAF, + 0x9F, 0x6A, 0xE9, 0xC0, 0xEE, 0x6A, 0x8B, 0x5C, 0x51, 0x2E, + 0x96, 0x3D, 0x65, 0xFF, 0x8D, 0x65, 0x2D, 0xB7, 0x76, 0x69, + 0x6B, 0x3A, 0x02, 0x08, 0x91, 0xC5, 0x48, 0xDF, 0x34, 0xCE, + 0xC5, 0x95, 0xBE, 0xCB, 0xB3, 0xA2, 0x84, 0x8D, 0xC3, 0xF8, + 0xEC, 0x05, 0xF4, 0xD4, 0xD6, 0xE4, 0x95, 0x29, 0xCE, 0x86, + 0xDD, 0x3B, 0x1B, 0x34, 0x32, 0xB0, 0x82, 0xD6, 0x08, 0x1A, + 0xF3, 0xF3, 0xF8, 0x28, 0xB0, 0xF4, 0xD1, 0xA9, 0x73, 0x82, + 0x0E, 0xAF, 0x88, 0xF0, 0x11, 0xB2, 0x8B, 0xC7, 0x54, 0xBB, + 0x4A, 0x83, 0xE7, 0xCF, 0x98, 0xB4, 0x03, 0x7B, 0x13, 0xBA, + 0xC6, 0xBF, 0xD8, 0xCF, 0x15, 0x91, 0xCB, 0xFA, 0x46, 0xB6, + 0x30, 0x22, 0xB5, 0x3E, 0xFC, 0xE4, 0xDD, 0x59, 0x4C, 0x50, + 0x15, 0xEB, 0x91, 0xF5, 0xBF, 0xF5, 0x37, 0x1C, 0xD9, 0x4F, + 0xA8, 0xE7, 0xF6, 0x6E, 0xED, 0x69, 0x0A, 0xFE, 0x8C, 0x95, + 0xDE, 0x3B, 0x96, 0x5B, 0x6A, 0xC8, 0x48, 0x0E, 0xF1, 0xE6, + 0x1D, 0xE0, 0xDF, 0x7B, 0x4C, 0x95, 0x6A, 0xC2, 0x16, 0xF8, + 0x35, 0xB6, 0xED, 0x19, 0x97, 0xE5, 0xDC, 0xCC, 0x8B, 0xA8, + 0x4E, 0x27, 0x8F, 0xE8, 0x6C, 0x62, 0x43, 0x76, 0x6B, 0x17, + 0x0B, 0x3F, 0x62, 0xA8, 0xFB, 0x90, 0xD7, 0x79, 0x4B, 0x4A, + 0xBB, 0x0C, 0xCD, 0x93, 0x77, 0x28, 0x31, 0xA8, 0xD5, 0xC8, + 0x48, 0x94, 0xDF, 0xD6, 0x11, 0x73, 0x82, 0x7D, 0x74, 0xCC, + 0xBC, 0xB9, 0x48, 0x72, 0x81, 0x6E, 0xA5, 0x3E, 0xAB, 0x5D, + 0xBA, 0xE5, 0xF9, 0xA2, 0x6B, 0x21, 0x29, 0x15, 0x0D, 0xEF, + 0x90, 0xC6, 0xF7, 0x69, 0xFE, 0xEE, 0x4F, 0xD7, 0x3A, 0xFF, + 0xBE, 0xAF, 0x21, 0x2D, 0x67, 0xA0, 0x30, 0x64, 0x62, 0xCA, + 0xB1, 0x6A, 0x78, 0x7D, 0x44, 0x56, 0xB1, 0x7F, 0x18, 0xEC, + 0xD1, 0xE0, 0x4A, 0xA8, 0xE4, 0x3E, 0x7A, 0x1D, 0x60, 0xBE, + 0x7D, 0x4F, 0xAB, 0x2A, 0xA1, 0xC0, 0x84, 0xC1, 0x82, 0xB5, + 0xB2, 0x82, 0x40, 0x36, 0x78, 0x76, 0xDA, 0x88, 0xE8, 0xFF, + 0xDA, 0xDF, 0x41, 0x7B, 0xD9, 0x4B, 0x64, 0x98, 0x19, 0xE1, + 0xCB, 0x6B, 0x7D, 0x31, 0x2B, 0xD0, 0x2D, 0x85, 0x39, 0xF5, + 0x94, 0x5F, 0x57, 0x53, 0x82, 0x05, 0x29, 0xD5, 0x57, 0xAA, + 0x2A, 0xE7, 0xEE, 0x29, 0x0D, 0xFF, 0xFC, 0x69, 0x6E, 0x14, + 0xA9, 0x00, 0x31, 0x70, 0x47, 0x1A, 0xA3, 0x04, 0xBE, 0x5E, + 0x81, 0xB2, 0xD3, 0x00, 0x21, 0xEE, 0xD4, 0xD7, 0x47, 0x62, + 0x4C, 0x9F, 0xD0, 0x4F, 0x50, 0x12, 0xEF, 0x3B, 0x38, 0x7A, + 0x02, 0x64, 0x61, 0xDD, 0xB5, 0xA0, 0x90, 0x2C, 0x81, 0xE2, + 0xD2, 0x99, 0x60, 0xA5, 0x12, 0x2C, 0x19, 0x45, 0x45, 0xCF, + 0x17, 0x58, 0x40, 0xA7, 0x8B, 0x94, 0xEC, 0xFF, 0x41, 0xB9, + 0xDF, 0x7A, 0x15, 0x9B, 0x57, 0x10, 0xDA, 0x21, 0x9F, 0x2A, + 0x53, 0x27, 0x7F, 0xFB, 0xA0, 0x94, 0xD5, 0xA7, 0xBA, 0xBF, + 0x6A, 0x0C, 0x19, 0xB3, 0xCD, 0xC4, 0xFB, 0x6C, 0xCA, 0xE8, + 0xBD, 0x66, 0xBE, 0xB1, 0x93, 0xC0, 0xEA, 0x1A, 0xA2, 0xBE, + 0xCC, 0x17, 0xAE, 0x10, 0xF0, 0x14, 0x71, 0x25, 0x0D, 0xFA, + 0xFE, 0x35, 0x52, 0xDC, 0x70, 0x44, 0x46, 0xBC, 0x2D, 0xC6, + 0x71, 0x6E, 0xE9, 0x7B, 0x43, 0x20, 0xD4, 0x3D, 0x37, 0x99, + 0xFE, 0x24, 0xAC, 0x12, 0x2F, 0x4A, 0x56, 0xB4, 0x48, 0xEE, + 0xB9, 0xAD, 0x0F, 0x2F, 0x08, 0xFB, 0x8F, 0x3B, 0x05, 0x12, + 0x2E, 0x74, 0x27, 0xAA, 0x41, 0x8D, 0x8F, 0x7C, 0x05, 0x01, + 0xA0, 0x81, 0x12, 0xB2, 0x49, 0xE6, 0xF5, 0x20, 0x6C, 0x24, + 0xA1, 0xED, 0x47, 0x44, 0x72, 0xA6, 0x26, 0x1C, 0x3D, 0x69, + 0x46, 0x6A, 0x98, 0xE5, 0x5C, 0xD3, 0xA2, 0x9F, 0x18, 0x23, + 0xAA, 0x5C, 0x39, 0xC0, 0xFC, 0xA2, 0x1C, 0x51, 0xB7, 0x19, + 0xED, 0xF8, 0xE5, 0x2E, 0x8E, 0xCE, 0x86, 0x22, 0xB9, 0x36, + 0x71, 0x45, 0x4E, 0x42, 0x81, 0x6D, 0x2C, 0xD9, 0x2E, 0x90, + 0x13, 0x85, 0x12, 0x93, 0xC8, 0x02, 0xC8, 0x3E, 0xFC, 0x32, + 0xAE, 0xE9, 0x95, 0xBA, 0x50, 0xA8, 0x89, 0x55, 0x54, 0xEB, + 0x30, 0xBE, 0x46, 0x52, 0x79, 0x6F, 0x23, 0xB3, 0xD8, 0x0B, + 0xE2, 0xD2, 0xF1, 0xAB, 0xDA, 0x41, 0x3A, 0xBF, 0x55, 0x44, + 0x23, 0xD9, 0x55, 0x2E, 0x66, 0x38, 0x7A, 0x6D, 0xF7, 0x8D, + 0xFD, 0x77, 0x8D, 0x99, 0x22, 0x89, 0x44, 0x53, 0x98, 0x88, + 0x83, 0xFB, 0x5F, 0x81, 0xF6, 0x49, 0x31, 0x6B, 0xA3, 0x54, + 0xF3, 0x2C, 0xE1, 0x72, 0x1E, 0xF4, 0x41, 0xDB, 0xFE, 0xE1, + 0xFA, 0x1A, 0xA1, 0x2F, 0x68, 0xBF, 0x99, 0x2A, 0x30, 0x52, + 0x25, 0x70, 0x26, 0xD5, 0x16, 0x7E, 0x36, 0xDB, 0xCD, 0x03, + 0x0B, 0x21, 0x6D, 0x95, 0xF2, 0x8B, 0x28, 0x0E, 0x1C, 0x71, + 0xAE, 0x7C, 0x7C, 0xBF, 0x97, 0xDC, 0x78, 0x9C, 0x92, 0xBC, + 0xF2, 0x5C, 0x9A, 0x13, 0x6F, 0xCC, 0x60, 0x87, 0x80, 0x79, + 0xAA, 0x6C, 0x69, 0xB0, 0xFE, 0x9B, 0x9C, 0x70, 0x21, 0x13, + 0x04, 0x5C, 0x2A, 0x87, 0xA3, 0x9A, 0x9C, 0xB2, 0xFE, 0xBB, + 0x42, 0x19, 0x66, 0xFF, 0xFF, 0x83, 0xB8, 0x05, 0xC2, 0x34, + 0x15, 0xCF, 0xFE, 0x80, 0x1B, 0x1D, 0xAC, 0xAA, 0xB6, 0xDD, + 0x80, 0x3D, 0x73, 0x55, 0x83, 0x16, 0x9A, 0xCB, 0x02, 0xA0, + 0xF3, 0x38, 0x25, 0x3B, 0xB5, 0x7D, 0x55, 0xB4, 0xB5, 0xF2, + 0x42, 0xDB, 0xEB, 0x23, 0xD2, 0xB6, 0x6E, 0x5C, 0xD2, 0x55, + 0x42, 0x7F, 0x9D, 0xA5, 0x98, 0xE0, 0x8F, 0x90, 0xCC, 0x6B, + 0xDE, 0x63, 0x67, 0x89, 0xFB, 0x73, 0x51, 0x9C, 0xEF, 0x24, + 0x5E, 0x3E, 0x45, 0x23, 0xDB, 0xAD, 0x23, 0x5C, 0xAF, 0x98, + 0xCF, 0xB1, 0xE8, 0x86, 0x0A, 0xF7, 0x23, 0xA8, 0x7B, 0x5D, + 0xC8, 0xF0, 0x59, 0x75, 0x8A, 0xE3, 0x80, 0xA2, 0x2E, 0xDF, + 0x37, 0xF2, 0x1D, 0x6E, 0x2E, 0x08, 0xCB, 0xE7, 0x43, 0xA0, + 0x03, 0x52, 0x6E, 0x27, 0x6F, 0x09, 0x53, 0x30, 0x97, 0xD6, + 0xBF, 0xE3, 0x3E, 0x8C, 0xB2, 0x5C, 0x13, 0xC9, 0xCE, 0x7E, + 0xC6, 0x0A, 0x21, 0xAF, 0x0C, 0x54, 0x3A, 0x3A, 0xD2, 0xA9, + 0x5D, 0x92, 0x35, 0xAF, 0xE6, 0x7B, 0xBC, 0xCC, 0x57, 0x73, + 0x2A, 0x03, 0xD5, 0x4D, 0x4B, 0xCE, 0x0D, 0x90, 0x26, 0xFB, + 0x47, 0x63, 0xA9, 0x6D, 0x37, 0x00, 0x0C, 0x8F, 0xF4, 0x9A, + 0x25, 0xB1, 0x13, 0xA1, 0xD3, 0xC4, 0x91, 0x05, 0x59, 0xBD, + 0x9C, 0x0D, 0x6C, 0x1E, 0x41, 0x90, 0x14, 0x93, 0x40, 0x69, + 0xFC, 0xDF, 0x12, 0xB7, 0xAB, 0x3E, 0xF3, 0x47, 0xBF, 0xAC, + 0x43, 0xE8, 0x1A, 0xC4, 0xF9, 0xE8, 0x7C, 0x21, 0x38, 0x70, + 0x1E, 0x96, 0x13, 0x2D, 0x3C, 0x4C, 0x81, 0x91, 0x0D, 0x00, + 0x8E, 0xFF, 0x97, 0x27, 0xA4, 0x90, 0x9F, 0xE3, 0x17, 0x1A, + 0x14, 0x34, 0xF3, 0x54, 0x48, 0x2E, 0x1E, 0xF9, 0x2F, 0x7F, + 0xC7, 0x3C, 0x24, 0x15, 0x28, 0xB8, 0x39, 0x93, 0x6A, 0x04, + 0x6D, 0x6F, 0x8C, 0xE8, 0xA2, 0xB3, 0xC9, 0xDC, 0x27, 0x7D, + 0xD1, 0x68, 0x73, 0x3B, 0x25, 0x3C, 0x45, 0xEC, 0x2B, 0x8A, + 0x0E, 0x98, 0xD9, 0x9A, 0x76, 0x89, 0xF0, 0x23, 0x35, 0x65, + 0x5F, 0x11, 0xA2, 0xFA, 0x6A, 0xC0, 0x39, 0xB7, 0x75, 0x44, + 0x10, 0x80, 0x02, 0x44, 0x87, 0x61, 0x03, 0xE9, 0x8C, 0x82, + 0x9D, 0xC2, 0x21, 0x26, 0x11, 0x1B, 0xE6, 0x13, 0xDE, 0xB5, + 0x5D, 0x0F, 0x07, 0x2A, 0x00, 0x11, 0xF1, 0xB4, 0x94, 0x3A, + 0xB0, 0x49, 0x52, 0x80, 0xA1, 0x1D, 0x07, 0xDD, 0x16, 0x19, + 0xDF, 0x3B, 0xEB, 0xBA, 0x66, 0x66, 0xBC, 0x5F, 0x9F, 0x32, + 0xFE, 0xD0, 0xC0, 0x59, 0x40, 0x48, 0xAF, 0x26, 0x6E, 0x5E, + 0x42, 0x5D, 0x25, 0xFE, 0xDD, 0x4A, 0x1F, 0x81, 0x6C, 0x27, + 0x62, 0xDA, 0xE7, 0x14, 0x2B, 0xFD, 0x03, 0xAC, 0xF9, 0xBD, + 0xD3, 0x6D, 0xE4, 0x11, 0xC5, 0x94, 0x36, 0x14, 0x41, 0xF1, + 0xA2, 0x4F, 0x64, 0xD3, 0xF6, 0x84, 0x45, 0xDE, 0x2B, 0x62, + 0x7D, 0x77, 0xF2, 0x95, 0x68, 0x42, 0x14, 0x79, 0x99, 0x20, + 0xAC, 0x58, 0x39, 0x39, 0x94, 0xAB, 0x5F, 0xE8, 0xB4, 0x62, + 0xD4, 0x3E, 0x39, 0x15, 0x6E, 0xC0, 0x65, 0xBF, 0xAB, 0xD2, + 0x6E, 0xC2, 0x18, 0x04, 0xCC, 0xBF, 0x1E, 0x4B, 0x85, 0x90, + 0xC6, 0x37, 0xAC, 0xDA, 0x81, 0x15, 0xBF, 0x2B, 0x68, 0x55, + 0xC1, 0xC7, 0xBB, 0x59, 0x04, 0x2F, 0xE0, 0x33, 0x14, 0x92, + 0xAA, 0x15, 0x15, 0xD5, 0x10, 0xD0, 0x5A, 0xA8, 0x83, 0x68, + 0x55, 0x0D, 0x43, 0xA5, 0xA8, 0x2D, 0xBE, 0x4F, 0x79, 0xCE, + 0x46, 0xBB, 0x79, 0x15, 0x02, 0x4D, 0x7D, 0xA9, 0xD4, 0x16, + 0xBB, 0x7B, 0x47, 0x73, 0x17, 0xC7, 0x66, 0xF7, 0x5A, 0xCE, + 0xB3, 0xF0, 0x79, 0x87, 0xAF, 0x01, 0x4C, 0xAF, 0x50, 0x5B, + 0x41, 0xE8, 0x51, 0xA1, 0x8E, 0x8F, 0x32, 0x4E, 0xAC, 0x84, + 0x10, 0x6E, 0x67, 0x66, 0x4D, 0xBB, 0xDE, 0xBF, 0x46, 0xD8, + 0x84, 0x3D, 0x35, 0x3F, 0xC5, 0xBB, 0xF1, 0x0A, 0xD5, 0x5E, + 0x57, 0x46, 0x99, 0x69, 0x6B, 0xE5, 0x0D, 0xA5, 0x9D, 0x0C, + 0xB7, 0xE5, 0xE5, 0x88, 0x22, 0x60, 0x44, 0xA4, 0x44, 0xD5, + 0xA3, 0xD0, 0x80, 0xA2, 0x98, 0xA3, 0xDB, 0x80, 0x26, 0x0D, + 0x61, 0x21, 0xC2, 0x8C, 0x18, 0x78, 0x0D, 0xD8, 0xE7, 0xD3, + 0xE5, 0xEF, 0x03, 0x75, 0x64, 0x53, 0x7D, 0xCD, 0xE2, 0x82, + 0xBA, 0xB9, 0xBD, 0x82, 0x1E, 0xE5, 0x45, 0x71, 0xF5, 0x90, + 0xDE, 0xB8, 0x32, 0x90, 0x9F, 0x92, 0x86, 0x4C, 0x65, 0x26, + 0x89, 0x5B, 0xE5, 0x1D, 0xD9, 0x6B, 0x8D, 0xE4, 0x65, 0x34, + 0xC0, 0xBB, 0x15, 0xC8, 0x9A, 0x12, 0xF9, 0xF1, 0x23, 0x73, + 0x4A, 0x37, 0x99, 0x15, 0x8F, 0x57, 0xAC, 0x07, 0x0D, 0x25, + 0x58, 0xFE, 0x06, 0x17, 0xD5, 0xAB, 0xFB, 0xC5, 0x4B, 0x8C, + 0x06, 0x50, 0x6D, 0x3A, 0x7A, 0xD9, 0x74, 0x20, 0xA2, 0x88, + 0xFF, 0x0D, 0x79, 0xE5, 0xA8, 0x8A, 0x85, 0xDB, 0x97, 0x97, + 0x33, 0x44, 0x7E, 0x00, 0xC3, 0xE9, 0x69, 0xC6, 0xD4, 0x88, + 0x65, 0x75, 0x4C, 0x5C, 0x5F, 0xC1, 0x3A, 0x75, 0xD8, 0x19, + 0x67, 0xF3, 0xAF, 0xD2, 0x19, 0xB7, 0xA2, 0xA2, 0x61, 0xAE, + 0xF2, 0x68, 0x61, 0x03, 0x59, 0x7C, 0x52, 0x85, 0x43, 0x4B, + 0x5E, 0x2C, 0x97, 0x8D, 0xB8, 0x7A, 0x1A, 0x32, 0xB5, 0x84, + 0x23, 0x09, 0xAF, 0x70, 0xB1, 0xA3, 0xDE, 0x14, 0x02, 0xCD, + 0x4C, 0x71, 0x99, 0x15, 0x2B, 0xD4, 0xD4, 0x25, 0xB5, 0x1C, + 0x4A, 0x4A, 0xFB, 0xA4, 0xBB, 0x93, 0x87, 0x43, 0xC6, 0x29, + 0x77, 0x47, 0xA8, 0x2E, 0x40, 0x69, 0xCB, 0x14, 0xD4, 0x8E, + 0xE2, 0x45, 0x02, 0xE2, 0x34, 0x02, 0x12, 0xD1, 0x9B, 0x1B, + 0xB4, 0x3F, 0x42, 0x27, 0x74, 0x3A, 0x1B, 0xBD, 0x62, 0x11, + 0xFB, 0xBE, 0x0E, 0x7A, 0xB9, 0xAB, 0x7F, 0xB8, 0x3D, 0xC9, + 0x0E, 0x69, 0x90, 0x00, 0x51, 0x2F, 0x90, 0xC5, 0xA4, 0x1A, + 0x93, 0xE4, 0x83, 0x00, 0x8B, 0xAC, 0xAB, 0xBD, 0x99, 0x33, + 0x2D, 0x39, 0x20, 0xAD, 0x4E, 0x6E, 0xBF, 0x87, 0x8B, 0xB3, + 0x34, 0x34, 0x8F, 0x70, 0xA5, 0x7D, 0xD6, 0x86, 0x49, 0xE0, + 0x97, 0x60, 0xAA, 0x44, 0x91, 0x31, 0xAE, 0xC5, 0xE3, 0x53, + 0xCE, 0xA2, 0xA0, 0xA9, 0x67, 0xDF, 0xF0, 0x4B, 0xC8, 0xC4, + 0x14, 0xEC, 0x82, 0xCF, 0x7C, 0x97, 0x6E, 0x86, 0x87, 0x19, + 0xFE, 0xDA, 0x50, 0x96, 0x55, 0x93, 0x6E, 0xE1, 0xA7, 0xBD, + 0x8E, 0xB3, 0x8D, 0x35, 0x61, 0x75, 0x3E, 0xB1, 0x5A, 0x3B, + 0x02, 0x93, 0xD8, 0x7F, 0x57, 0x4E, 0xDC, 0x12, 0x5D, 0x05, + 0xBC, 0xB1, 0xF4, 0x65, 0x87, 0xFA, 0x97, 0xBA, 0x46, 0x5B, + 0x09, 0x7A, 0xF4, 0xE3, 0x5C, 0xD0, 0x23, 0xB0, 0xB1, 0xB4, + 0xA3, 0x4E, 0xDD, 0xC7, 0x68, 0xA2, 0xCE, 0xA6, 0xE9, 0x31, + 0x8B, 0x7D, 0xD9, 0xEE, 0xF2, 0xC4, 0x51, 0xC3, 0x39, 0x09, + 0x64, 0x5C, 0x72, 0x48, 0x2C, 0xFA, 0xDD, 0x0F, 0x70, 0x8D, + 0x34, 0x4A, 0xD5, 0xA4, 0xB7, 0xC2, 0xFA, 0x07, 0x6A, 0x0C, + 0x3B, 0x6A, 0x7F, 0x85, 0x77, 0x3C, 0x15, 0xC9, 0x15, 0xA3, + 0x76, 0xD7, 0x55, 0x2C, 0x65, 0xF4, 0x49, 0x18, 0x62, 0xDF, + 0xBA, 0x9E, 0xF2, 0x03, 0xEF, 0xB0, 0x4B, 0x70, 0x7C, 0x1A, + 0x19, 0x1A, 0xCC, 0xF0, 0x91, 0x09, 0x97, 0x72, 0x84, 0x81, + 0x21, 0xEB, 0x40, 0x4A, 0x73, 0xA6, 0x8B, 0x81, 0x04, 0x96, + 0xB1, 0x6A, 0xBA, 0xF1, 0xDC, 0x96, 0xAB, 0xA2, 0xEA, 0xC1, + 0xF5, 0x67, 0x89, 0xF3, 0x91, 0xD4, 0x1A, 0x2E, 0x7A, 0xCA, + 0x93, 0xCC, 0x28, 0x48, 0x14, 0xCB, 0x03, 0x4B, 0xD0, 0x2D, + 0x81, 0x61, 0x6F, 0x78, 0x2E, 0x89, 0xA5, 0xCC, 0x60, 0x76, + 0x47, 0x6B, 0x08, 0xAD, 0x94, 0x98, 0xF0, 0x77, 0xA3, 0x7E, + 0x34, 0x48, 0x72, 0xB7, 0xBA, 0xF5, 0xF4, 0x06, 0x6D, 0x5E, + 0x76, 0xF4, 0x5F, 0x50, 0x4E, 0x82, 0x07, 0x07, 0xC6, 0x98, + 0xE4, 0xEC, 0x61, 0x3C, 0x23, 0xA3, 0x75, 0xE2, 0xBB, 0xAB, + 0xB6, 0xF9, 0x56, 0xBD, 0xE1, 0x90, 0xFC, 0xC0, 0x69, 0xE0, + 0xD8, 0x96, 0x3E, 0xE2, 0xAB, 0x28, 0x0D, 0xFD, 0xC4, 0xB0, + 0x24, 0x19, 0x26, 0x60, 0x14, 0xBC, 0x8F, 0x54, 0x33, 0x9E, + 0x07, 0x4C, 0x04, 0xD0, 0xCD, 0x98, 0x84, 0xA8, 0x83, 0xAE, + 0xA1, 0x8F, 0x21, 0x5C, 0x7A, 0x6C, 0x35, 0xA3, 0x9B, 0x85, + 0x66, 0xB8, 0x18, 0x59, 0x7C, 0x9E, 0x0E, 0xD7, 0x32, 0x2F, + 0x18, 0xEF, 0xC5, 0x1A, 0x2A, 0x10, 0xBC, 0x1F, 0x39, 0xCD, + 0x0B, 0xC1, 0xF5, 0x7C, 0xBD, 0xD6, 0x58, 0xC5, 0x71, 0xD4, + 0x4A, 0x28, 0x27, 0xA1, 0xE5, 0xB2, 0xC1, 0xCD, 0xA9, 0x20, + 0xEC, 0x91, 0xCA, 0xA5, 0xB9, 0x53, 0xD2, 0xEB, 0x1E, 0x44, + 0x71, 0x45, 0x84, 0x74, 0x4A, 0x58, 0x99, 0xF7, 0xD4, 0xEB, + 0xE3, 0x21, 0x08, 0xF6, 0x0D, 0x13, 0x26, 0xEF, 0xC8, 0xE7, + 0x12, 0x63, 0x3C, 0x46, 0x1D, 0x2D, 0x73, 0x3A, 0x51, 0xAD, + 0xBD, 0x1D, 0x35, 0x06, 0x2E, 0x7E, 0xEB, 0x2C, 0x8F, 0x43, + 0x47, 0xB1, 0x11, 0x6C, 0xDA, 0xEB, 0xF1, 0x3E, 0xEE, 0x95, + 0x29, 0xB8, 0xAD, 0xA5, 0x87, 0x73, 0xE5, 0xA3, 0xAB, 0xCE, + 0xF9, 0x0B, 0xF0, 0x7C, 0x5F, 0xE1, 0x7E, 0x22, 0x15, 0xE9, + 0x4B, 0xAA, 0x91, 0x7E, 0x1B, 0xFF, 0x60, 0x64, 0x23, 0x33, + 0xAA, 0x53, 0x57, 0x1D, 0x29, 0xC2, 0x4E, 0xDC, 0x7E, 0x3A, + 0x98, 0xEA, 0x51, 0xE3, 0xBD, 0xDD, 0xB3, 0x61, 0x41, 0x0F, + 0xB4, 0x22, 0x12, 0x9A, 0x59, 0x56, 0x6D, 0x9C, 0xCB, 0x21, + 0x71, 0xFB, 0xFF, 0x90, 0x07, 0x92, 0xB9, 0x1E, 0x9C, 0x03, + 0xBB, 0x58, 0x16, 0x25, 0x34, 0xF5, 0x22, 0x56, 0xDA, 0xF4, + 0xCC, 0x73, 0x63, 0xAD, 0xD1, 0x21, 0x9C, 0x8E, 0xEB, 0x0F, + 0x59, 0x7B, 0x84, 0xAF, 0xC2, 0x0A, 0x85, 0x20, 0x5C, 0xC3, + 0xD2, 0x33, 0xD4, 0xF0, 0x6E, 0xBE, 0x54, 0x70, 0xB1, 0x3E, + 0x17, 0xBB, 0x11, 0x61, 0x3A, 0xF7, 0xE6, 0x14, 0xBA, 0x6E, + 0x3B, 0x52, 0x8A, 0x2E, 0x83, 0xDE, 0x14, 0x79, 0xC1, 0x4F, + 0x9E, 0x22, 0x11, 0x26, 0x54, 0x0E, 0x62, 0x01, 0x6E, 0x37, + 0x26, 0xA5, 0xA1, 0x08, 0xD7, 0x41, 0x5F, 0xF5, 0xA4, 0xBD, + 0x14, 0x89, 0xF9, 0x14, 0x97, 0x2A, 0xDD, 0x8A, 0xD5, 0x4C, + 0x92, 0x43, 0x5A, 0x7B, 0xF0, 0xAC, 0x93, 0x36, 0xF7, 0x22, + 0xD1, 0xC8, 0x4B, 0x8C, 0xFD, 0x65, 0x72, 0xCC, 0x91, 0xE4, + 0xF5, 0x8F, 0x45, 0x50, 0xCF, 0x5B, 0x3B, 0xAC, 0x3B, 0x92, + 0x05, 0x7C, 0x36, 0x7B, 0x15, 0x9E, 0x9F, 0x89, 0xF5, 0x1A, + 0x50, 0xF6, 0xF8, 0xF7, 0x29, 0x39, 0x7F, 0x9F, 0x85, 0x8D, + 0x6A, 0x71, 0xBF, 0x71, 0x05, 0x56, 0x79, 0x13, 0x39, 0xEB, + 0x8A, 0xE8, 0xD8, 0x48, 0x6A, 0xE9, 0xBD, 0x2D, 0x75, 0x4A, + 0x0D, 0x1B, 0x20, 0x1C, 0x97, 0x25, 0xFC, 0x23, 0xE4, 0x94, + 0xA6, 0x91, 0xF2, 0xAD, 0xEC, 0xF8, 0x56, 0x2E, 0x3A, 0x7C, + 0x78, 0xCD, 0xC9, 0x7E, 0x64, 0xCC, 0xBA, 0x8A, 0x56, 0xBB, + 0xAF, 0xB5, 0x37, 0x81, 0xCA, 0x9D, 0x9B, 0x53, 0xE2, 0xED, + 0x24, 0xE5, 0xB6, 0x59, 0x1F, 0xC6, 0xAE, 0x47, 0xAE, 0x90, + 0x2E, 0x45, 0x1B, 0xDE, 0x92, 0xE4, 0xC7, 0x43, 0x4A, 0xA8, + 0x5A, 0xD7, 0x74, 0x25, 0x9D, 0xE1, 0x53, 0x5D, 0xB5, 0x53, + 0xC3, 0x07, 0x87, 0xA2, 0x6D, 0xF7, 0x5B, 0x8C, 0xD1, 0x8A, + 0x5A, 0x11, 0x95, 0xDC, 0x02, 0x91, 0xF5, 0x58, 0x8B, 0x9E, + 0x24, 0xEB, 0x3C, 0xED, 0xDB, 0x7D, 0x89, 0x8D, 0xCC, 0x96, + 0xFD, 0x01, 0xDF, 0x4F, 0xA0, 0x31, 0x7A, 0x71, 0xAB, 0xB7, + 0x3B, 0xA1, 0xE7, 0xB8, 0x4C, 0x84, 0xBB, 0x09, 0x88, 0xC0, + 0x54, 0x5B, 0x4C, 0xBC, 0x27, 0xBB, 0x70, 0x58, 0x81, 0x81, + 0xAB, 0x24, 0xDF, 0xD2, 0x2B, 0x07, 0x7F, 0xF9, 0x91, 0x31, + 0x11, 0x86, 0x8B, 0xC0, 0x4F, 0x31, 0x1E, 0x54, 0x36, 0x47, + 0x39, 0xC4, 0xB6, 0x1B, 0xEF, 0x8B, 0x5B, 0x5D, 0xCD, 0x26, + 0xE2, 0x57, 0x88, 0x91, 0x75, 0x1A, 0xC6, 0x5E, 0x5D, 0x48, + 0xAF, 0x8B, 0x5F, 0x21, 0x17, 0xA3, 0x3D, 0xA5, 0xFB, 0x51, + 0x55, 0xEB, 0x20, 0x91, 0x08, 0xE5, 0x6C, 0xD9, 0x4F, 0xDA, + 0xE8, 0x2B, 0xDA, 0xB9, 0xE9, 0xA8, 0x78, 0x49, 0xB6, 0x54, + 0x1F, 0x25, 0xD0, 0x67, 0x3F, 0x3D, 0xFC, 0x80, 0x5F, 0xF0, + 0xC3, 0x32, 0xEB, 0xB4, 0xB2, 0x4B, 0x10, 0x5B, 0x14, 0x79, + 0xE0, 0xEA, 0x01, 0x25, 0xC0, 0xE0, 0xA6, 0xC5, 0x3D, 0x07, + 0xC2, 0x3D, 0x35, 0xD5, 0xCC, 0x6B, 0xDE, 0x1C, 0x08, 0xA5, + 0x0B, 0xBB, 0x02, 0x0F, 0x7D, 0xFB, 0x30, 0x9B, 0x83, 0xA0, + 0x14, 0xB2, 0x25, 0x88, 0xBA, 0x2D, 0xC8, 0xA4, 0x04, 0xB4, + 0x22, 0x1D, 0xC6, 0xA9, 0xF3, 0xD8, 0xCD, 0xB7, 0xCE, 0x5B, + 0x88, 0x40, 0x21, 0x03, 0xF9, 0x35, 0xC3, 0x9F, 0x01, 0x39, + 0x1C, 0xE1, 0x56, 0x02, 0xC4, 0x31, 0xBE, 0x3F, 0x55, 0xD7, + 0xC6, 0x3B, 0x0A, 0xA7, 0xA9, 0xB3, 0x87, 0xDF, 0x89, 0x66, + 0xD0, 0x3F, 0x83, 0x86, 0xF9, 0xBC, 0x78, 0xA3, 0x26, 0x4E, + 0x08, 0x87, 0x40, 0xB4, 0x77, 0x47, 0xAF, 0x89, 0x38, 0xFD, + 0x69, 0xA6, 0x6B, 0x61, 0xDB, 0xD7, 0xD9, 0x37, 0x69, 0x02, + 0x98, 0xF3, 0xC2, 0xFE, 0x33, 0x0F, 0xE1, 0x57, 0xB1, 0x28, + 0x8C, 0x84, 0xA4, 0x1C, 0x08, 0x98, 0xAB, 0x16, 0x65, 0x24, + 0x42, 0x19, 0x40, 0xB5, 0x6F, 0xAF, 0xBD, 0xF7, 0xE1, 0xAB, + 0xE6, 0x89, 0x98, 0xDA, 0x71, 0xDA, 0x58, 0x66, 0x98, 0x6D, + 0xDD, 0xB8, 0x1F, 0x1B, 0x87, 0xE3, 0x15, 0xCA, 0xC3, 0xAB, + 0x91, 0x34, 0x05, 0xAE, 0xB7, 0x5F, 0xCF, 0x97, 0x40, 0xB4, + 0x75, 0x1D, 0x6C, 0x2F, 0x48, 0x7F, 0x7F, 0x25, 0x83, 0xA9, + 0xA3, 0xCC, 0xB8, 0x10, 0xDC, 0x8D, 0x02, 0x71, 0xFE, 0x1D, + 0x82, 0xF3, 0x33, 0x14, 0x8A, 0xB6, 0x89, 0xC1, 0x8B, 0x04, + 0xB8, 0x45, 0x25, 0x4C, 0xAE, 0x4A, 0x28, 0x54, 0xA5, 0x64, + 0x2E, 0x6A, 0x8D, 0xE5, 0xF6, 0x6E, 0xB2, 0x5C, 0xF6, 0x77, + 0x60, 0xC4, 0x34, 0x07, 0x89, 0x06, 0x15, 0x20, 0x19, 0x58, + 0x5A, 0x49, 0x10, 0x70, 0xA4, 0xD8, 0xE0, 0x50, 0x03, 0xBB, + 0x3C, 0x11, 0x63, 0xBD, 0x1A, 0x40, 0xBB, 0x87, 0xE0, 0x5B, + 0x18, 0x24, 0x10, 0x56, 0x29, 0xEC, 0xFC, 0xB1, 0x1B, 0x34, + 0xB0, 0x9F, 0x76, 0x86, 0x9E, 0x1E, 0x68, 0xCC, 0xE6, 0xF9, + 0xDC, 0x84, 0x3F, 0x16, 0xE2, 0xCD, 0x0D, 0x12, 0xA2, 0x3F, + 0x58, 0xC9, 0x34, 0x7C, 0x4B, 0x9D, 0x73, 0x41, 0x6E, 0x60, + 0x73, 0xA3, 0x52, 0xD8, 0x9B, 0xDA, 0x91, 0xAE, 0x98, 0xAC, + 0xCF, 0x2B, 0x6F, 0xE0, 0x0B, 0x85, 0x34, 0xE3, 0x08, 0x6F, + 0x74, 0xCC, 0x0C, 0x43, 0xE0, 0x24, 0x1C, 0x61, 0x40, 0x9D, + 0xEF, 0x34, 0x95, 0x78, 0xBD, 0xE4, 0x89, 0xA3, 0x70, 0x02, + 0x2D, 0x51, 0x5A, 0x96, 0x20, 0x74, 0x69, 0x7B, 0xEB, 0x3D, + 0xAA, 0xD8, 0x0F, 0x42, 0xE0, 0x28, 0x84, 0x03, 0x86, 0x0A, + 0x6E, 0xB0, 0x81, 0x38, 0x05, 0x5B, 0x40, 0x16, 0x79, 0x09, + 0x35, 0x8C, 0x58, 0x05, 0x72, 0x96, 0xEC, 0xE1, 0xF7, 0xAB, + 0x0B, 0x22, 0xE7, 0xC2, 0x8F, 0x74, 0x40, 0xC4, 0x28, 0xDD, + 0x9B, 0x62, 0xA7, 0x4C, 0x59, 0x17, 0xB4, 0xEB, 0x3C, 0xE3, + 0x45, 0x31, 0xE5, 0x76, 0xC2, 0x2A, 0xD2, 0xDC, 0x62, 0xFB, + 0x59, 0xF3, 0xBB, 0x8D, 0xD3, 0x70, 0xB0, 0x72, 0x22, 0x4C, + 0xD9, 0xAA, 0x73, 0x59, 0xF6, 0x6C, 0xEC, 0xE0, 0x3E, 0x39, + 0xDF, 0x81, 0x4C, 0x40, 0x38, 0xE8, 0x34, 0x37, 0x78, 0x4F, + 0x68, 0x24, 0xD2, 0xF6, 0xF6, 0x5A, 0xCE, 0xA1, 0xC7, 0x06, + 0xBB, 0xCC, 0x82, 0x1F, 0x80, 0x2F, 0xA8, 0xAE, 0x1C, 0x20, + 0xB9, 0xA5, 0xE2, 0x9D, 0x25, 0x0B, 0x11, 0xE1, 0xCC, 0x7C, + 0x71, 0xC2, 0xCF, 0x49, 0xAC, 0x64, 0x52, 0x36, 0x8F, 0x42, + 0xB4, 0x23, 0x06, 0x51, 0x89, 0x6E, 0x50, 0x2A, 0x1D, 0x21, + 0x38, 0x0C, 0x61, 0xC5, 0x76, 0x31, 0x77, 0x41, 0xC6, 0xD0, + 0x4F, 0x38, 0xDD, 0xBD, 0x87, 0xA5, 0xCD, 0xFE, 0x49, 0x9C, + 0x0D, 0x38, 0xE4, 0x59, 0x6F, 0x1C, 0x2E, 0x53, 0x0A, 0x60, + 0xFE, 0x08, 0x3E, 0x6D, 0x1B, 0xAF, 0x00, 0xAE, 0xA8, 0xAF, + 0x9A, 0x2E, 0xA4, 0xDF, 0x46, 0xFA, 0x4C, 0x94, 0x13, 0x6F, + 0x2D, 0x5E, 0x5A, 0x60, 0x37, 0x94, 0x78, 0xAC, 0x32, 0x0C, + 0xB9, 0xA3, 0x90, 0x9D, 0x41, 0xA0, 0x9D, 0xC7, 0x6D, 0x45, + 0xB8, 0x8B, 0x7B, 0x35, 0xCA, 0xE9, 0x8C, 0x6C, 0xC6, 0xA1, + 0x6E, 0xA7, 0x8D, 0x6F, 0xDD, 0xEA, 0x96, 0x78, 0xCE, 0x18, + 0x79, 0x2E, 0x8B, 0x1D, 0x84, 0xAE, 0xBF, 0xA5, 0xCB, 0x20, + 0x57, 0xBB, 0x1E, 0xDC, 0x10, 0xEA, 0x36, 0xD9, 0x1B, 0x41, + 0x34, 0x35, 0xAA, 0x88, 0x6F, 0x74, 0x25, 0xAF, 0xEE, 0x60, + 0x6F, 0x64, 0x98, 0x37, 0x7B, 0xE0, 0xFB, 0xCC, 0xE5, 0x5A, + 0x21, 0x46, 0x4A, 0xF1, 0x46, 0x5D, 0xFE, 0x93, 0x0B, 0xD7, + 0x11, 0xFA, 0x8B, 0x49, 0xD8, 0x24, 0x3F, 0x16, 0xD0, 0xA7, + 0xBB, 0x90, 0x10, 0x57, 0x0B, 0x8B, 0x3D, 0x17, 0x81, 0x8F, + 0xEF, 0x57, 0xCF, 0xD8, 0xC4, 0x3F, 0x6B, 0xA5, 0xB2, 0xC7, + 0x20, 0xBF, 0x2B, 0x50, 0x95, 0x27, 0x92, 0xF8, 0xDC, 0xD2, + 0xE0, 0xB0, 0x8B, 0x80, 0x56, 0xC4, 0xA3, 0x75, 0x2F, 0x43, + 0xAF, 0x4E, 0x3D, 0x32, 0x04, 0x79, 0x2D, 0x1F, 0x35, 0xD3, + 0x07, 0x86, 0x2B, 0x38, 0x14, 0x7A, 0xB0, 0x09, 0x97, 0x73, + 0xD8, 0xCB, 0x75, 0x1D, 0x46, 0x29, 0x9C, 0x95, 0xE3, 0xDC, + 0x82, 0xA1, 0xD4, 0xD3, 0x5D, 0x73, 0x54, 0xD6, 0xFC, 0x9C, + 0x3D, 0x1B, 0x34, 0xBC, 0x6B, 0x16, 0x0F, 0x86, 0x81, 0x01, + 0x49, 0xB7, 0x71, 0x02, 0x8D, 0xA5, 0x2F, 0x9F, 0x68, 0x9A, + 0xC1, 0x5F, 0x3A, 0x20, 0x52, 0x3A, 0x02, 0xB8, 0xCD, 0xBD, + 0xE2, 0x12, 0x93, 0xD8, 0x21, 0xF8, 0x3B, 0x54, 0xBC, 0x85, + 0x06, 0xF0, 0x37, 0x05, 0x29, 0x3D, 0x58, 0x5B, 0x36, 0x48, + 0xA8, 0x8A, 0xAC, 0xF6, 0x81, 0x50, 0xD3, 0x1A, 0x78, 0xD6, + 0xA6, 0x83, 0x2E, 0xB9, 0x48, 0x2F, 0x14, 0x08, 0xDC, 0x76, + 0xB6, 0x8E, 0x7E, 0x0A, 0x87, 0xF7, 0x28, 0x19, 0x9A, 0x50, + 0x63, 0xDF, 0x9B, 0xAC, 0xBF, 0x67, 0x95, 0x5D, 0x84, 0x37, + 0xE0, 0x32, 0x99, 0xFF, 0x75, 0x26, 0x6B, 0x41, 0x96, 0xB3, + 0xD9, 0x64, 0x4A, 0x1B, 0x51, 0x77, 0x7C, 0xA2, 0x6B, 0xF9, + 0xD3, 0xAC, 0x9B, 0xBC, 0x76, 0x52, 0x1A, 0x37, 0xDA, 0x44, + 0x90, 0xBB, 0x3E, 0x38, 0x67, 0x10, 0x58, 0xA4, 0x8A, 0x9D, + 0x95, 0x4A, 0x80, 0x03, 0x36, 0x62, 0x77, 0x3E, 0x4C, 0x4D, + 0x47, 0xDA, 0x5C, 0x15, 0x8E, 0x4C, 0x00, 0xBB, 0x8A, 0x38, + 0x4D, 0x85, 0xA5, 0x43, 0xA4, 0x67, 0x0B, 0x96, 0x2D, 0x73, + 0xCD, 0x57, 0x1C, 0x4D, 0x33, 0x5A, 0xF8, 0x5E, 0xFB, 0xE5, + 0xCB, 0xAC, 0x7D, 0xC9, 0xE7, 0x38, 0x69, 0xB0, 0x3A, 0xF9, + 0x72, 0xDD, 0x1D, 0xFF, 0xCA, 0x5A, 0x61, 0xD0, 0x70, 0xDA, + 0x25, 0xCF, 0xC9, 0x24, 0x64, 0xF1, 0x60, 0xD4, 0x55, 0x1F, + 0xDE, 0xC4, 0x19, 0xB3, 0xC4, 0x9A, 0x94, 0x50, 0x30, 0x57, + 0xD5, 0x17, 0xAA, 0x3A, 0x44, 0xF5, 0xBB, 0xF5, 0xCF, 0x26, + 0xA3, 0x1B, 0xC9, 0xF4, 0xA1, 0x7B, 0x7C, 0xEA, 0xF6, 0xA0, + 0xE7, 0x8B, 0xCC, 0x99, 0x30, 0x4A, 0x85, 0x5C, 0xF8, 0x43, + 0x6F, 0x12, 0xB9, 0xF5, 0x26, 0x9B, 0x7A, 0xC7, 0x37, 0x34, + 0x6B, 0x04, 0x97, 0xE9, 0xD6, 0xD5, 0x75, 0x1E, 0xF9, 0x42, + 0x89, 0xAE, 0xE5, 0xB4, 0x51, 0x39, 0xC6, 0x86, 0x4B, 0x75, + 0xE2, 0x3C, 0xF2, 0x5A, 0xA6, 0x2D, 0xD3, 0xC2, 0xB7, 0x8E, + 0xEE, 0x65, 0xF7, 0x96, 0x27, 0xCA, 0x8E, 0x79, 0x8F, 0x82, + 0x1B, 0x37, 0x89, 0x49, 0x93, 0x3D, 0xB3, 0x11, 0x7E, 0xBA, + 0x86, 0xEC, 0x01, 0xA8, 0x3E, 0x11, 0x14, 0x3C, 0xA4, 0x40, + 0x46, 0xE2, 0x86, 0x94, 0xDB, 0xEB, 0xA3, 0x50, 0x2E, 0x6C, + 0xB7, 0x8D, 0x5D, 0x4B, 0xF7, 0xF6, 0x02, 0x2F, 0x65, 0x82, + 0x9F, 0xB9, 0x28, 0xCB, 0xD1, 0x79, 0x99, 0x59, 0xEA, 0x17, + 0x84, 0x72, 0xB3, 0x0B, 0xDD, 0xF7, 0xF0, 0xA2, 0x1E, 0x6F, + 0xBE, 0xD4, 0x2F, 0x1A, 0xC0, 0xE2, 0xA5, 0x9A, 0xB2, 0x81, + 0xDF, 0x2D, 0x1F, 0x9D, 0x40, 0xAB, 0xE0, 0xEC, 0xBB, 0x98, + 0xAD, 0x30, 0xB2, 0xF0, 0xB2, 0x8E, 0x39, 0xE4, 0x7B, 0x96, + 0x03, 0x26, 0xED, 0x80, 0x9C, 0x84, 0x58, 0xD1, 0x4E, 0x3D, + 0xCC, 0x4E, 0xBA, 0x83, 0xBC, 0x3F, 0x3F, 0xE4, 0xB2, 0xF2, + 0xC6, 0x08, 0x85, 0xF3, 0xAC, 0x46, 0x09, 0x89, 0x19, 0xFE, + 0xAB, 0x3A, 0xC2, 0xFA, 0xB6, 0x96, 0x69, 0xE9, 0x0A, 0x2E, + 0x78, 0xB8, 0x3A, 0x15, 0x7E, 0x15, 0xFB, 0x53, 0x19, 0x0A, + 0xAE, 0xAE, 0xC1, 0x87, 0xAB, 0xF3, 0xA4, 0x26, 0xDA, 0x4C, + 0xA9, 0x71, 0xF8, 0x9B, 0xF5, 0x4E, 0xC1, 0xF8, 0x9C, 0x8F, + 0x54, 0xA0, 0x44, 0xE4, 0x3E, 0xE5, 0xEE, 0xCC, 0x4D, 0xFA, + 0x8E, 0x74, 0xB8, 0x25, 0x38, 0x1C, 0x27, 0x33, 0x33, 0x1C, + 0x13, 0xFF, 0xDF, 0xD6, 0x31, 0x54, 0xD9, 0xE5, 0x07, 0x63, + 0xA3, 0xED, 0x4D, 0xF1, 0x89, 0x31, 0x81, 0x52, 0x04, 0xD5, + 0x59, 0x2C, 0x29, 0x78, 0xAA, 0xF3, 0x6F, 0xDA, 0x51, 0xB9, + 0x92, 0x49, 0x94, 0x77, 0x43, 0xB2, 0x17, 0x8B, 0x32, 0x77, + 0x7E, 0x1C, 0x2C, 0xEE, 0x8A, 0x8B, 0x9D, 0x5D, 0x2E, 0xFF, + 0x89, 0x5A, 0x75, 0xE5, 0x04, 0xE9, 0x5F, 0x0E, 0x68, 0xD4, + 0xA4, 0xBC, 0x0C, 0xB4, 0xAF, 0x59, 0x24, 0xD5, 0x3A, 0xA0, + 0x75, 0x48, 0x4F, 0x24, 0x1F, 0xF2, 0x19, 0x20, 0xDE, 0xB2, + 0x55, 0x25, 0xD6, 0x45, 0x97, 0xEF, 0xFF, 0xDB, 0x9B, 0xAA, + 0xFB, 0x5C, 0x2A, 0xC1, 0x2C, 0xD7, 0xFA, 0x4F, 0x9B, 0xFD, + 0xA4, 0x69, 0x3F, 0xD4, 0x83, 0x26, 0x5C, 0x48, 0xA8, 0xB5, + 0xDF, 0x81, 0x02, 0x2A, 0xB8, 0x2A, 0xAF, 0xBF, 0x1E, 0xA8, + 0xB5, 0x23, 0x5E, 0x64, 0x93, 0xCD, 0x31, 0x71, 0x2C, 0x3B, + 0xA9, 0xD1, 0x40, 0xEE, 0xBD, 0x60, 0x4C, 0x7F, 0x75, 0x3B, + 0x96, 0x12, 0x73, 0x72, 0x17, 0xE7, 0xD7, 0xBC, 0xD2, 0x3D, + 0xB0, 0x55, 0xDD, 0xA8, 0x90, 0x56, 0x74, 0x3B, 0x4B, 0x05, + 0xE4, 0x08, 0x6E, 0xFD, 0x0F, 0x51, 0xBA, 0x6A, 0xF5, 0x6A, + 0xC2, 0x0B, 0x78, 0x94, 0x47, 0xA3, 0x54, 0x3C, 0x19, 0xE0, + 0x17, 0x39, 0xC4, 0xFD, 0x9F, 0xE4, 0xD9, 0xD1, 0xA5, 0x45, + 0xCF, 0x9E, 0xB7, 0x03, 0x34, 0xFC, 0x9E, 0xA7, 0x2B, 0xCF, + 0x30, 0x51, 0x30, 0x85, 0xC9, 0x5A, 0xA5, 0x6C, 0xC9, 0x41, + 0x28, 0x3C, 0x0C, 0xAF, 0x02, 0x4F, 0x8F, 0xDA, 0xED, 0x28, + 0x84, 0x6A, 0x2A, 0x18, 0xB6, 0xD5, 0xE8, 0x03, 0xD7, 0xD0, + 0xBF, 0xE6, 0xD8, 0x74, 0x9A, 0x41, 0x3A, 0x2D, 0x99, 0x28, + 0xEB, 0xB9, 0xF3, 0xAC, 0x1F, 0x0B, 0xAA, 0x63, 0x44, 0xAD, + 0x92, 0x9C, 0x2A, 0x25, 0x78, 0xF1, 0xD5, 0x83, 0xC4, 0xC5, + 0x3C, 0xC4, 0x56, 0xD2, 0xCA, 0xDD, 0x41, 0x90, 0xA7, 0xBF, + 0xA8, 0x3B, 0x61, 0x5B, 0xC5, 0x81, 0xEE, 0xA1, 0xC1, 0xAD, + 0xF9, 0xC6, 0x24, 0xC0, 0xB3, 0x33, 0xA5, 0x6C, 0x63, 0xF9, + 0xF9, 0x91, 0xC2, 0xE5, 0x47, 0x1A, 0x69, 0x27, 0x5E, 0xD8, + 0x95, 0x7A, 0xC3, 0x1E, 0x92, 0x5B, 0xDA, 0x3F, 0xB6, 0x9E, + 0x02, 0x1F, 0x24, 0x7C, 0x44, 0xAF, 0x98, 0xC2, 0x83, 0x18, + 0xD5, 0x9C, 0xF3, 0xA8, 0x29, 0xE2, 0xFC, 0x12, 0xD3, 0xB7, + 0x31, 0xB3, 0x86, 0x04, 0x12, 0x35, 0x3B, 0xFA, 0xD8, 0xD6, + 0x6F, 0x80, 0xEB, 0xF2, 0x48, 0xCB, 0xDF, 0xA0, 0x28, 0x62, + 0xC1, 0xDA, 0x4E, 0x7A, 0xCF, 0x3D, 0xC4, 0x66, 0xE4, 0x7A, + 0x2C, 0x06, 0xE4, 0x50, 0xE2, 0x9C, 0xA0, 0x6C, 0x52, 0x34, + 0x1B, 0x9D, 0x2D, 0x55, 0x24, 0x89, 0xE4, 0x56, 0x05, 0xDE, + 0xFD, 0x73, 0x36, 0x46, 0xD3, 0x07, 0x76, 0x19, 0xE7, 0x35, + 0x4B, 0xDD, 0xB4, 0xF1, 0xC4, 0x2A, 0xEA, 0xBE, 0x08, 0xB8, + 0x3B, 0x92, 0xB6, 0x28, 0x6B, 0xF6, 0x08, 0xA1, 0x25, 0x72, + 0x79, 0x7B, 0x1E, 0x89, 0x61, 0x88, 0x39, 0xFA, 0x10, 0x67, + 0xB8, 0x1C, 0xA7, 0xFD, 0xBF, 0x16, 0xD3, 0xB9, 0xD9, 0xF8, + 0x4D, 0x06, 0xE9, 0xAB, 0x5F, 0xD5, 0x40, 0x48, 0x37, 0x41, + 0x4B, 0xA0, 0xC4, 0x2C, 0x04, 0x98, 0x2B, 0x15, 0xE2, 0xE4, + 0xCC, 0x08, 0x0F, 0xE9, 0xEE, 0xF9, 0x63, 0x5A, 0x11, 0xD4, + 0xDC, 0x4A, 0x4F, 0x20, 0x13, 0x19, 0x70, 0xDF, 0xCB, 0x32, + 0xBA, 0x74, 0x54, 0x7D, 0x91, 0xAD, 0x94, 0x85, 0x4F, 0xBE, + 0x5B, 0xA0, 0x1C, 0x51, 0x97, 0xE0, 0x56, 0xB6, 0xF4, 0x92, + 0x52, 0x47, 0x8F, 0xE6, 0x92, 0xBB, 0x68, 0x2A, 0x32, 0xFC, + 0x10, 0xB3, 0x74, 0xD0, 0xC9, 0x50, 0x75, 0x74, 0x6B, 0x90, + 0x40, 0xFD, 0xC6, 0x65, 0x9B, 0xB1, 0xD4, 0x77, 0x75, 0x56, + 0x2E, 0x8E, 0x44, 0x4A, 0xB9, 0x1A, 0xE8, 0x08, 0x1F, 0xAC, + 0xE5, 0x85, 0xD3, 0x7B, 0x19, 0xBA, 0x28, 0x7F, 0xD4, 0x8E, + 0x50, 0xB3, 0x57, 0x8A, 0x3E, 0xE8, 0xD5, 0x52, 0xB5, 0x6A, + 0x36, 0xBE, 0x7D, 0xEF, 0x5F, 0xF9, 0xCA, 0x74, 0x69, 0xEC, + 0x6E, 0x88, 0xBD, 0x6F, 0x53, 0x73, 0x34, 0xF5, 0x77, 0x7E, + 0x61, 0xF6, 0x88, 0x64, 0x6B, 0x1D, 0x3F, 0x8C, 0xCD, 0x7B, + 0x58, 0xBD, 0x85, 0x02, 0xBF, 0x3F, 0xDA, 0xD4, 0x1D, 0xD7, + 0xC1, 0x5C, 0x33, 0xCD, 0xE0, 0xEA, 0x7A, 0x3D, 0xBD, 0x09, + 0xA2, 0x11, 0xEA, 0xE3, 0x14, 0x0E, 0xDF, 0xF1, 0x83, 0x4A, + 0x42, 0x3C, 0xA7, 0x0F, 0x3C, 0x14, 0x7A, 0x97, 0x7C, 0x90, + 0x5F, 0x3B, 0xE8, 0xEE, 0x09, 0x3F, 0x2B, 0x8F, 0x0C, 0x76, + 0xA2, 0x0E, 0xA8, 0xB9, 0xF9, 0x64, 0x45, 0x96, 0xEB, 0x4A, + 0x4D, 0x0E, 0xCA, 0xFB, 0x8C, 0xE3, 0xC9, 0xD4, 0x8A, 0x4E, + 0x61, 0x04, 0x98, 0x34, 0x72, 0xD5, 0xE6, 0xAB, 0xB9, 0x61, + 0x57, 0x08, 0x6A, 0x97, 0x7F, 0xFB, 0x19, 0xB4, 0x8D, 0x73, + 0x25, 0xE7, 0x09, 0xBC, 0x1A, 0xB3, 0xCC, 0xA0, 0x58, 0xF0, + 0xF2, 0xE8, 0x01, 0xF6, 0x86, 0xAB, 0xE9, 0x72, 0x7B, 0x3D, + 0xD2, 0x74, 0xC0, 0xE1, 0xE9, 0xA2, 0x15, 0xA7, 0x58, 0xAA, + 0xFC, 0x61, 0x21, 0x09, 0x37, 0xDC, 0x01, 0x62, 0x89, 0x48, + 0x4A, 0x31, 0x89, 0x51, 0xF1, 0xCF, 0xDB, 0x5E, 0x6F, 0x52, + 0x67, 0xD4, 0x90, 0x17, 0xA0, 0x01, 0xA4, 0x92, 0xE5, 0x57, + 0x07, 0xD9, 0xED, 0x68, 0xC9, 0xC3, 0xAE, 0x06, 0x65, 0x09, + 0x02, 0x51, 0x69, 0xA8, 0x62, 0xA9, 0xE3, 0xD9, 0xB2, 0x08, + 0xC9, 0xD2, 0x41, 0x21, 0xC2, 0xD0, 0xD9, 0x5A, 0x26, 0x5A, + 0x19, 0x9D, 0xA5, 0x70, 0x6A, 0x57, 0x74, 0xFC, 0x67, 0x72, + 0x21, 0x49, 0x86, 0xE3, 0x1A, 0xD4, 0xCB, 0x16, 0x55, 0x10, + 0x01, 0x59, 0xD4, 0x7B, 0x9F, 0x05, 0xB4, 0x78, 0xBC, 0x33, + 0x91, 0x0B, 0x99, 0x1E, 0x5E, 0x19, 0x68, 0x0D, 0x03, 0x3B, + 0xDA, 0xDC, 0x52, 0x2C, 0x77, 0xE5, 0xAA, 0x2D, 0x10, 0x40, + 0x19, 0x32, 0x44, 0x45, 0x6D, 0xF4, 0x1A, 0xDE, 0x2F, 0xEF, + 0x88, 0x7C, 0x13, 0x5E, 0x94, 0x30, 0x2B, 0x04, 0x6D, 0x00, + 0x04, 0x82, 0xD9, 0x79, 0xDE, 0xDD, 0xBF, 0xB3, 0x9D, 0x59, + 0x58, 0xB9, 0x39, 0xE5, 0x4F, 0xEA, 0xB1, 0x9B, 0x8C, 0x47, + 0x03, 0x4B, 0x39, 0xCB, 0x39, 0xD7, 0xD1, 0x6C, 0xD3, 0xC7, + 0xF3, 0x98, 0xDC, 0x0C, 0xAE, 0x76, 0x03, 0xAF, 0x1F, 0x50, + 0x01, 0xE3, 0x42, 0x87, 0x3E, 0xB2, 0x33, 0xA6, 0xEA, 0xFB, + 0x38, 0x9E, 0xAF, 0xA0, 0xFA, 0xB4, 0x1B, 0x8D, 0x27, 0xBF, + 0xDA, 0xF6, 0x2C, 0xEC, 0xAB, 0x04, 0x07, 0x56, 0xD5, 0x75, + 0xEB, 0x0A, 0x51, 0x01, 0x97, 0x67, 0x8B, 0x77, 0x60, 0x25, + 0x04, 0x4D, 0x18, 0xC3, 0x41, 0x1B, 0x52, 0xEE, 0xEC, 0xE3, + 0x33, 0xB7, 0x2A, 0xC1, 0xA7, 0x0C, 0xCA, 0xD4, 0x08, 0x39, + 0x26, 0x2B, 0xFB, 0x3E, 0xEA, 0x4C, 0x5D, 0x22, 0x57, 0x75, + 0xB1, 0xD2, 0xC4, 0x12, 0xDD, 0x5B, 0x3B, 0xAE, 0xC3, 0x5D, + 0xEE, 0x30, 0x67, 0xC0, 0xD6, 0x38, 0xDC, 0x75, 0xCA, 0x2C, + 0x3F, 0x84, 0xE0, 0xED, 0xEC, 0xE1, 0xC8, 0xF2, 0xA4, 0xDF, + 0x7B, 0xF2, 0x1B, 0xDE, 0x62, 0x11, 0xD8, 0x8B, 0xF9, 0xF5, + 0x20, 0xDE, 0xE5, 0x12, 0x4C, 0x89, 0x45, 0xA8, 0xD2, 0xA1, + 0xF6, 0x11, 0xC1, 0x37, 0xCE, 0x89, 0x63, 0xDD, 0x7A, 0xAB, + 0xDF, 0xEE, 0xCB, 0x56, 0x05, 0x96, 0x40, 0xA8, 0x16, 0xCC, + 0x4F, 0x29, 0x7E, 0xE1, 0xD5, 0xBE, 0x3B, 0xB3, 0x9F, 0x38, + 0xE7, 0x08, 0x19, 0x9D, 0x27, 0x42, 0x43, 0xD2, 0x49, 0x8E, + 0xC2, 0xF3, 0x83, 0x81, 0xBC, 0xC1, 0x4D, 0xB2, 0x13, 0xB4, + 0xBB, 0xC2, 0x23, 0x2E, 0x00, 0xFD, 0x3C, 0x57, 0x46, 0x6B, + 0x30, 0xDA, 0xA4, 0x3A, 0xD2, 0x5E, 0x00, 0x60, 0xE5, 0x60, + 0x5B, 0xE5, 0x2C, 0xFE, 0x50, 0x40, 0x7A, 0x46, 0x95, 0x43, + 0x7F, 0x85, 0xA1, 0xB1, 0x9A, 0x67, 0x1E, 0x8A, 0xEF, 0x54, + 0x37, 0x17, 0x7F, 0xB8, 0xD2, 0x17, 0x41, 0x1B, 0x4F, 0x73, + 0xE0, 0x83, 0x7C, 0x1B, 0xFA, 0xD9, 0x4B, 0x00, 0x42, 0x00, + 0x7D, 0x2B, 0xE6, 0x03, 0xCB, 0x68, 0x0B, 0xB1, 0x36, 0x4A, + 0xE6, 0x54, 0x8A, 0x88, 0xB1, 0x22, 0x24, 0xC8, 0x84, 0x38, + 0x00, 0x6D, 0x61, 0x09, 0xCD, 0x8D, 0xE0, 0x77, 0x7E, 0xFA, + 0x71, 0x5E, 0x23, 0xB9, 0xA9, 0x07, 0x4B, 0x24, 0xD6, 0x45, + 0x66, 0x7F, 0xC4, 0x7E, 0xAB, 0x00, 0xD4, 0xAA, 0xF7, 0x75, + 0x39, 0x90, 0xCC, 0x79, 0xBB, 0xDC, 0x51, 0xF0, 0x80, 0x02, + 0xA9, 0x8D, 0x3C, 0x13, 0x4E, 0xE6, 0x56, 0xD1, 0x5C, 0x52, + 0x50, 0x37, 0x4B, 0x4E, 0x2B, 0xDC, 0x03, 0x6C, 0xA1, 0xD5, + 0x79, 0x48, 0xF5, 0x39, 0x57, 0x18, 0x27, 0xCA, 0x52, 0x0B, + 0x79, 0x96, 0x49, 0x50, 0xF9, 0xE3, 0x61, 0x95, 0x7F, 0x15, + 0xCE, 0xDA, 0xD9, 0xFB, 0xB9, 0xA3, 0xC4, 0x5D, 0xCF, 0x51, + 0xEB, 0xA2, 0x9E, 0xEF, 0xE9, 0x49, 0xCD, 0x26, 0x30, 0x68, + 0x9B, 0x5F, 0xEC, 0xA2, 0x3B, 0xBE, 0x35, 0x81, 0xDE, 0xC0, + 0x37, 0x93, 0x58, 0x98, 0x28, 0x1E, 0x10, 0x1F, 0x85, 0x5C, + 0xE3, 0xFF, 0x78, 0x96, 0xDB, 0xEE, 0x31, 0x6D, 0x8C, 0x75, + 0xB1, 0xDE, 0xD9, 0x17, 0x55, 0x66, 0x99, 0xE5, 0x1D, 0x0F, + 0x86, 0x60, 0x81, 0x39, 0x51, 0xA8, 0x16, 0x1C, 0x03, 0xAC, + 0xA3, 0xB1, 0xB5, 0x1F, 0xD9, 0x7C, 0xAC, 0xBE, 0x3E, 0xCD, + 0xD3, 0xBF, 0xB6, 0x5C, 0x9C, 0xA9, 0x00, 0x12, 0xC4, 0xE7, + 0xDF, 0x36, 0xE1, 0xD6, 0xF5, 0x34, 0x39, 0x36, 0x9B, 0x59, + 0xD4, 0x71, 0x2D, 0xD1, 0x9E, 0x00, 0x32, 0x9D, 0x1F, 0xE4, + 0x11, 0xBE, 0x6E, 0xF9, 0xF0, 0x4A, 0xAB, 0xC5, 0x05, 0x53, + 0xAB, 0x8D, 0x73, 0xBB, 0xF8, 0x35, 0x6F, 0xA0, 0x96, 0x1D, + 0x0A, 0x92, 0x00, 0x6D, 0xF8, 0xE2, 0xFA, 0x88, 0x8E, 0xC1, + 0x56, 0x41, 0x3B, 0xBB, 0xD5, 0x76, 0x36, 0x26, 0xC6, 0x8D, + 0xC4, 0xBE, 0xE5, 0xD6, 0x74, 0x39, 0xFC, 0xF1, 0xDE, 0x49, + 0xC7, 0x6C, 0x7D, 0x92, 0xB1, 0x9D, 0x3A, 0xE0, 0x89, 0x3E, + 0x45, 0x4A, 0x38, 0xE1, 0x37, 0x18, 0x72, 0x77, 0xE3, 0x33, + 0xF0, 0xF4, 0x9A, 0x26, 0xA3, 0xA5, 0x44, 0x32, 0x27, 0x89, + 0xA5, 0x56, 0x3A, 0x54, 0xD6, 0x80, 0x63, 0x2F, 0xDE, 0x19, + 0x63, 0x2A, 0x00, 0xC5, 0x01, 0xF5, 0xD9, 0x49, 0x3C, 0xBC, + 0x4D, 0xEA, 0x39, 0xE1, 0x89, 0xC3, 0xE3, 0x0D, 0x4F, 0xBE, + 0x70, 0xDE, 0x29, 0x3D, 0x91, 0x0C, 0xDA, 0xBD, 0x69, 0x12, + 0xAD, 0xF7, 0xDD, 0x7E, 0xAA, 0x23, 0xD7, 0xE0, 0xF4, 0xD7, + 0x1B, 0x30, 0x19, 0xE9, 0x07, 0x4C, 0x82, 0x9A, 0xD2, 0x12, + 0xDA, 0xD2, 0xEC, 0xFC, 0x21, 0x68, 0xF9, 0x11, 0x56, 0xEE, + 0x57, 0xF6, 0x03, 0x56, 0xBF, 0x05, 0x21, 0xB2, 0x9A, 0x1A, + 0xF4, 0x78, 0x67, 0xDD, 0x8B, 0x3F, 0xCB, 0x29, 0x2B, 0x47, + 0xAD, 0x3C, 0x35, 0xAF, 0x55, 0xB1, 0x80, 0xED, 0x1D, 0x9D, + 0xFD, 0x6B, 0x0B, 0x35, 0x75, 0xC9, 0xBB, 0xF5, 0xA0, 0xDB, + 0xE9, 0x5B, 0x86, 0x01, 0x5E, 0xCA, 0x8E, 0x88, 0xC4, 0xAE, + 0x07, 0x47, 0x9D, 0x9A, 0xE7, 0x8E, 0x11, 0x88, 0x4D, 0xCC, + 0x2C, 0xB6, 0x63, 0x72, 0xA5, 0xCE, 0x0C, 0xF7, 0x03, 0xF9, + 0x60, 0x9D, 0xEC, 0xA0, 0xD3, 0x78, 0x84, 0xA2, 0x3A, 0xCB, + 0xA4, 0x83, 0x77, 0xEB, 0xD9, 0xBA, 0xDE, 0x9F, 0x64, 0x08, + 0x25, 0xEE, 0x66, 0x40, 0xD4, 0x22, 0xB2, 0x19, 0x6A, 0x77, + 0xC4, 0x18, 0x28, 0x06, 0x51, 0xF6, 0x51, 0x78, 0x88, 0xB6, + 0xFF, 0xE2, 0x87, 0x5E, 0x43, 0xED, 0xD9, 0x18, 0x19, 0x1F, + 0xDE, 0x84, 0x9A, 0x53, 0x2B, 0xCC, 0xC8, 0x71, 0x1A, 0xD0, + 0xF2, 0xF4, 0x53, 0x8F, 0x87, 0x42, 0x6B, 0xA3, 0x0E, 0xEB, + 0x49, 0x70, 0xCC, 0xF4, 0x0E, 0xAF, 0x27, 0x9E, 0xF5, 0xD4, + 0xA7, 0x83, 0xEB, 0xB3, 0xB2, 0x57, 0x58, 0x45, 0xBB, 0x41, + 0x35, 0xEB, 0x4B, 0xD4, 0x67, 0xBB, 0x4F, 0xAA, 0xF6, 0x59, + 0xFB, 0x5F, 0x13, 0x91, 0x16, 0x68, 0xE1, 0x3B, 0xFE, 0x0D, + 0xF4, 0xEC, 0x30, 0x29, 0x42, 0x24, 0x71, 0x12, 0xF4, 0xCE, + 0x38, 0x06, 0x60, 0xDA, 0xCC, 0x71, 0x08, 0x28, 0x7D, 0xDA, + 0x76, 0x16, 0xB8, 0x37, 0x50, 0xC8, 0xC7, 0xB2, 0x98, 0x71, + 0xA0, 0x0D, 0xEF, 0x64, 0x00, 0x55, 0xBB, 0x35, 0x44, 0x28, + 0x74, 0xA1, 0xA9, 0x1B, 0xF9, 0xAC, 0x4A, 0x41, 0xA7, 0x54, + 0x21, 0xD7, 0x23, 0xB2, 0x6B, 0x33, 0xB2, 0x46, 0x4F, 0x5C, + 0xDD, 0x2F, 0xF1, 0x87, 0x93, 0xA9, 0x01, 0x4B, 0xF3, 0x0D, + 0x9A, 0xB9, 0x70, 0xF7, 0xE0, 0x1A, 0xA1, 0x8B, 0xDB, 0x8B, + 0x16, 0x05, 0x8A, 0xC4, 0x1E, 0x17, 0x6E, 0x29, 0x88, 0xFD, + 0xE1, 0x95, 0x4C, 0x28, 0x72, 0xF8, 0x96, 0x4F, 0x98, 0x87, + 0xA6, 0x9F, 0xDA, 0xE2, 0xBB, 0x01, 0x53, 0xF7, 0xEE, 0xCF, + 0xB5, 0xEC, 0xD4, 0x3F, 0xEB, 0x00, 0x8F, 0x2B, 0xB9, 0x67, + 0x36, 0x50, 0x13, 0xD9, 0xD6, 0xB9, 0x10, 0x50, 0xD8, 0x32, + 0x87, 0x83, 0x4D, 0x97, 0x52, 0x3A, 0xD5, 0x3A, 0x1C, 0xF9, + 0xFF, 0x29, 0x20, 0xCB, 0xD7, 0xD3, 0x3B, 0x5F, 0x9C, 0x76, + 0xD3, 0x06, 0x6F, 0xD9, 0xC6, 0x54, 0xAA, 0xF6, 0xEC, 0xEF, + 0x72, 0x43, 0x61, 0xA2, 0xDC, 0xC8, 0xB2, 0xC7, 0xBA, 0x06, + 0xF9, 0x37, 0x2A, 0xA8, 0xEB, 0x11, 0x0D, 0xBB, 0xDE, 0xB7, + 0xFC, 0x81, 0x2D, 0xF0, 0x2B, 0x87, 0x43, 0xF7, 0x51, 0x05, + 0xEE, 0x13, 0x70, 0x41, 0x99, 0xEF, 0xB0, 0xB9, 0x25, 0x00, + 0x0A, 0x9F, 0x7A, 0x0D, 0x23, 0x57, 0x92, 0xF5, 0xDD, 0x9C, + 0x22, 0x20, 0xD8, 0x7F, 0x7A, 0xEA, 0x09, 0xF5, 0xDE, 0x38, + 0x51, 0x47, 0x6A, 0x7E, 0x60, 0x6F, 0x8F, 0x57, 0x1E, 0x4B, + 0xC1, 0x47, 0x33, 0xCD, 0x12, 0x44, 0x52, 0xA5, 0xA2, 0x52, + 0x44, 0xE9, 0xFF, 0x00, 0xB5, 0xEC, 0x28, 0x71, 0x8B, 0xDC, + 0xDF, 0x6A, 0x99, 0xDA, 0xD2, 0x19, 0x33, 0x4A, 0x2E, 0xF1, + 0x9F, 0xA5, 0xA8, 0xE3, 0xD5, 0xF1, 0xC2, 0xF6, 0x3C, 0xA2, + 0x4F, 0x13, 0xEB, 0xA5, 0x42, 0xED, 0xDB, 0x95, 0x3F, 0x43, + 0x6D, 0x74, 0xEA, 0x43, 0x09, 0x20, 0x6E, 0xA3, 0x6F, 0x22, + 0x1D, 0xE6, 0x16, 0x96, 0xFD, 0x78, 0x45, 0x9A, 0x8B, 0x05, + 0xA5, 0x5E, 0xB3, 0xB9, 0x6F, 0xB4, 0xC6, 0x58, 0xE5, 0x93, + 0x3B, 0xCA, 0x31, 0x6C, 0x59, 0xCD, 0x27, 0x0B, 0x79, 0x0E, + 0xA3, 0x59, 0x11, 0x85, 0x5A, 0x42, 0x12, 0x8D, 0x02, 0x51, + 0x9F, 0xE9, 0x15, 0xB0, 0x18, 0x85, 0xFA, 0x2A, 0x2D, 0x68, + 0x29, 0x09, 0x78, 0xB6, 0xA8, 0x22, 0x1E, 0xB8, 0xC0, 0x8C, + 0xF0, 0x79, 0xFE, 0x0D, 0xAC, 0x27, 0x3E, 0x7C, 0x25, 0x78, + 0xA1, 0x57, 0x7A, 0xD4, 0x42, 0x6A, 0xE6, 0x6D, 0x7F, 0x38, + 0x7B, 0xD2, 0x56, 0xAA, 0xEF, 0x14, 0xF0, 0x00, 0x4B, 0x24, + 0x07, 0x61, 0x4E, 0x6A, 0x2D, 0xEE, 0xEE, 0x41, 0x75, 0x34, + 0x6D, 0xF8, 0xE2, 0x55, 0x05, 0x63, 0x82, 0x53, 0x57, 0x88, + 0x9C, 0x86, 0xD2, 0xAB, 0x05, 0x65, 0x03, 0x62, 0xA1, 0xAA, + 0x2A, 0x8A, 0x9D, 0x1B, 0xFC, 0x15, 0x37, 0x8F, 0xE6, 0x2A, + 0x12, 0x84, 0xEF, 0x3F, 0x82, 0x94, 0x37, 0x1B, 0x4B, 0x83, + 0x3B, 0xEB, 0x68, 0x5D, 0xB8, 0x98, 0x52, 0x92, 0x28, 0xB8, + 0x45, 0xAE, 0xC2, 0x07, 0xBE, 0xE7, 0x37, 0x99, 0xAA, 0x45, + 0x96, 0x4C, 0xF0, 0x22, 0x84, 0x1A, 0x3C, 0x23, 0xB1, 0xC7, + 0xEC, 0xE9, 0x52, 0xC0, 0x7A, 0x38, 0xE5, 0xC0, 0x64, 0xA0, + 0xA6, 0x24, 0xCF, 0xCD, 0x63, 0x24, 0xF0, 0xE4, 0x27, 0x03, + 0x2B, 0xA8, 0x15, 0x2C, 0xE0, 0x5F, 0x01, 0x0F, 0x70, 0x01, + 0x9D, 0x00, 0x57, 0xB6, 0xC4, 0x0D, 0x09, 0x66, 0xAD, 0x94, + 0x79, 0x5F, 0xD0, 0xE8, 0x34, 0xD2, 0xE9, 0xDD, 0xFA, 0x54, + 0xDD, 0xFD, 0x9B, 0x24, 0x02, 0x59, 0x03, 0x7D, 0x8B, 0x30, + 0xB2, 0xA8, 0xDC, 0xDF, 0xE1, 0xC0, 0x8D, 0xD0, 0x0D, 0xB2, + 0xE5, 0xBC, 0x3C, 0x26, 0xF4, 0x55, 0x84, 0x76, 0x08, 0x64, + 0x74, 0x50, 0x6A, 0xF4, 0x2B, 0x99, 0x95, 0xF6, 0xB8, 0xDC, + 0xE8, 0x70, 0x3A, 0xF1, 0xED, 0xE6, 0x9B, 0x58, 0x4B, 0x5F, + 0xF8, 0x0F, 0x36, 0xB8, 0xAB, 0xCC, 0x36, 0x8C, 0x7D, 0xC3, + 0xDE, 0x17, 0x7A, 0xF9, 0x7D, 0xE8, 0xFE, 0xCD, 0xD5, 0xD7, + 0x7B, 0x03, 0x29, 0x57, 0xFF, 0xE4, 0xAC, 0x53, 0x24, 0x61, + 0xF9, 0x0C, 0x01, 0x37, 0x17, 0xC7, 0xB3, 0x14, 0xB5, 0xAE, + 0x3B, 0xA7, 0xE0, 0x4F, 0xB1, 0x63, 0x80, 0xC1, 0x9B, 0x4D, + 0xB3, 0x50, 0x92, 0xDE, 0x65, 0x1F, 0x70, 0xAE, 0x30, 0x91, + 0xD6, 0xCA, 0xF8, 0x2A, 0x1D, 0x42, 0xB0, 0x21, 0x8B, 0x1B, + 0x8E, 0x99, 0x67, 0x60, 0xA2, 0x05, 0x1B, 0xA6, 0x95, 0x4B, + 0xCD, 0x1A, 0x68, 0x9F, 0x05, 0xA4, 0x8A, 0xCF, 0x71, 0x53, + 0x56, 0x0E, 0x66, 0x7D, 0x49, 0xED, 0xDC, 0xCF, 0x4D, 0x91, + 0x51, 0x80, 0x0D, 0x89, 0x74, 0x11, 0x7E, 0x92, 0x92, 0x86, + 0x4C, 0x80, 0xC1, 0xBC, 0x3B, 0xB7, 0xFA, 0x9F, 0x0E, 0xDE, + 0x85, 0xA5, 0x29, 0xE1, 0xAC, 0xC7, 0xA5, 0x5C, 0x13, 0xBA, + 0xCB, 0x31, 0x16, 0x63, 0xE1, 0xDF, 0x44, 0x5F, 0xAE, 0x06, + 0x76, 0x9A, 0x9B, 0x74, 0x10, 0xF4, 0xBE, 0x98, 0x2E, 0x37, + 0x08, 0xC6, 0x95, 0x44, 0x69, 0x27, 0x90, 0xE5, 0xB0, 0x51, + 0x4A, 0x80, 0x44, 0x21, 0xED, 0xF6, 0x06, 0x27, 0xA9, 0xF5, + 0x40, 0x00, 0x51, 0xCD, 0x85, 0x1B, 0x97, 0xEB, 0x8F, 0xB6, + 0xAD, 0xEE, 0x40, 0xA5, 0x1D, 0x22, 0x89, 0x1D, 0xD5, 0xEF, + 0x1E, 0xEC, 0x0A, 0x02, 0x56, 0x9E, 0x60, 0x82, 0x5D, 0xDA, + 0xC3, 0x0C, 0xCA, 0xF7, 0x8F, 0xB5, 0x56, 0x06, 0xCF, 0x2E, + 0x9F, 0xB7, 0x85, 0x6E, 0x98, 0x5C, 0xB1, 0x79, 0x3B, 0xA3, + 0x8A, 0x8F, 0x54, 0xD9, 0x44, 0xAF, 0x7A, 0xC6, 0x15, 0x23, + 0xD3, 0x02, 0x31, 0x7E, 0x62, 0xB0, 0x28, 0x5C, 0xB0, 0xA5, + 0x39, 0x42, 0xBF, 0x76, 0x32, 0x77, 0x71, 0x2A, 0x26, 0xF1, + 0x74, 0xB3, 0x25, 0xED, 0xA4, 0x29, 0xE9, 0x89, 0x81, 0xF6, + 0x16, 0xC1, 0x48, 0x49, 0xC7, 0xBD, 0x9F, 0xBD, 0x2D, 0x71, + 0x12, 0x88, 0xB1, 0x0D, 0x11, 0xB6, 0xC3, 0x34, 0xB1, 0xB0, + 0x92, 0xE8, 0x9F, 0x87, 0xF7, 0xCD, 0x33, 0x52, 0x35, 0x3A, + 0x7F, 0x17, 0xD7, 0x40, 0x5F, 0xCA, 0xE7, 0xB0, 0x2B, 0xDD, + 0xCC, 0x14, 0x0E, 0xE4, 0x19, 0xBF, 0xE0, 0xE3, 0x4E, 0xF6, + 0x76, 0xEB, 0x1A, 0xBF, 0x61, 0xEB, 0xB5, 0x32, 0xCF, 0x7A, + 0x64, 0xFD, 0x1F, 0x6F, 0xA1, 0x23, 0x02, 0x68, 0x14, 0x48, + 0xC3, 0xB9, 0x0B, 0xD2, 0xB8, 0x69, 0x31, 0xEB, 0xB5, 0x38, + 0xE7, 0x44, 0xCD, 0xDC, 0xA8, 0x25, 0x30, 0xEC, 0x8F, 0xB4, + 0x6A, 0x80, 0xF7, 0xA3, 0x37, 0x4E, 0xB5, 0x3B, 0x6E, 0x82, + 0xF2, 0xA8, 0xDA, 0x1F, 0xAE, 0x40, 0xD7, 0x2A, 0xBF, 0xD5, + 0x04, 0x02, 0xF8, 0xCB, 0x27, 0x61, 0xEE, 0x13, 0xAA, 0x9E, + 0x46, 0xCC, 0xCE, 0x68, 0xA7, 0x06, 0xEA, 0x19, 0xE4, 0x06, + 0x2A, 0x4D, 0xDF, 0x54, 0xFC, 0x6E, 0xB4, 0x22, 0x6A, 0x62, + 0x8D, 0x8F, 0x37, 0xAE, 0xC9, 0xD9, 0xD2, 0x85, 0xD7, 0xFC, + 0x10, 0x80, 0x4F, 0xD8, 0x60, 0x92, 0x0D, 0x0E, 0x9F, 0x6E, + 0x2E, 0xE1, 0x4A, 0x82, 0x51, 0xA0, 0x92, 0x81, 0x4B, 0xBC, + 0x6B, 0xD2, 0x2D, 0x7E, 0xF4, 0x76, 0x36, 0xAB, 0x8E, 0x98, + 0xF7, 0x08, 0xCC, 0x97, 0xDA, 0xE2, 0xCA, 0xBD, 0xFB, 0xC1, + 0x41, 0x0B, 0x74, 0xD3, 0xE9, 0xCB, 0x3A, 0x14, 0xCC, 0xC7, + 0x51, 0x6B, 0x2D, 0xF5, 0x83, 0xA6, 0xFA, 0x7A, 0xFD, 0x08, + 0x99, 0x16, 0xAB, 0xE9, 0x4F, 0x44, 0x58, 0xAC, 0xD4, 0x7B, + 0x96, 0xD3, 0xDA, 0xCD, 0xE1, 0x2B, 0x16, 0x70, 0xCE, 0x7A, + 0x59, 0xC4, 0x28, 0x06, 0x33, 0x9C, 0xD9, 0xAE, 0xD6, 0xED, + 0xD2, 0x74, 0xFC, 0x2A, 0x33, 0xE0, 0x2E, 0xA3, 0x8B, 0x32, + 0xB8, 0xA3, 0xE2, 0x4E, 0xBE, 0x44, 0x77, 0x19, 0xBF, 0x13, + 0xE6, 0x29, 0xEC, 0xC9, 0x0D, 0x8E, 0x05, 0x35, 0x3C, 0x7A, + 0xD1, 0xB9, 0x3F, 0x13, 0xDD, 0x80, 0xDD, 0x90, 0x60, 0x92, + 0x31, 0xB8, 0x5E, 0x92, 0x14, 0x56, 0xB1, 0x14, 0xF6, 0x68, + 0x1D, 0x5A, 0xAB, 0x6D, 0x73, 0x83, 0xCF, 0x40, 0xCE, 0x06, + 0x74, 0x85, 0x28, 0x19, 0xEA, 0x52, 0xA5, 0x0F, 0x8F, 0x2E, + 0x3C, 0xE9, 0xE3, 0x64, 0xB2, 0x7D, 0x6C, 0x35, 0x74, 0xAE, + 0x4D, 0x69, 0xC6, 0x97, 0xC1, 0x94, 0x14, 0xD8, 0x71, 0x4B, + 0xDD, 0x0D, 0xC6, 0x40, 0x81, 0xED, 0x7C, 0x54, 0x6D, 0xE8, + 0xF8, 0xBA, 0x4C, 0x4B, 0x6E, 0x94, 0x1D, 0x74, 0x93, 0x8D, + 0x21, 0xF1, 0x1C, 0xB4, 0xFA, 0xB3, 0x08, 0xB0, 0x09, 0xD8, + 0x62, 0x3C, 0x5C, 0x7C, 0x92, 0x85, 0x57, 0x6F, 0x64, 0x19, + 0x3B, 0xB2, 0xC6, 0x91, 0xE8, 0x7B, 0x60, 0xCD, 0xD5, 0xC7, + 0xA4, 0x6E, 0xD3, 0x2C, 0xA6, 0xEF, 0x8C, 0xA5, 0x38, 0xB8, + 0x18, 0x41, 0x69, 0x00, 0x65, 0x7C, 0x5C, 0xF1, 0xE0, 0x97, + 0xB4, 0x8D, 0xA8, 0xC0, 0x65, 0x3D, 0x28, 0x1D, 0x8A, 0xCF, + 0x36, 0x89, 0xE7, 0xB9, 0xC1, 0x81, 0x91, 0xD3, 0x3E, 0x45, + 0xBE, 0x86, 0x05, 0x30, 0x9A, 0xFA, 0x2C, 0x56, 0xEA, 0x64, + 0x5C, 0x85, 0x25, 0x11, 0xDD, 0x8E, 0xD8, 0x3A, 0x6F, 0xA4, + 0xF4, 0xF0, 0x69, 0x6A, 0x7F, 0xED, 0x3E, 0x6A, 0x26, 0x5A, + 0x7C, 0xFE, 0x18, 0x98, 0x48, 0x9D, 0xE2, 0xD4, 0x9F, 0x77, + 0xF3, 0x8E, 0x1F, 0xC1, 0xCD, 0x6B, 0x66, 0xF5, 0xA1, 0xCB, + 0x67, 0x41, 0xEF, 0xB4, 0xFB, 0x5F, 0x02, 0x41, 0x93, 0x20, + 0xB0, 0x08, 0x32, 0x92, 0xF1, 0xD0, 0x31, 0xB7, 0x6D, 0x12, + 0xBF, 0xE7, 0xE3, 0xCC, 0xB8, 0xAD, 0x43, 0x1B, 0x70, 0x04, + 0x48, 0xD3, 0x94, 0x65, 0xA1, 0xF4, 0x12, 0x14, 0x76, 0xB8, + 0xFC, 0x32, 0x8A, 0x72, 0xD8, 0x05, 0xFC, 0xBD, 0xE5, 0xAA, + 0xF6, 0x95, 0xFF, 0x33, 0x3E, 0x86, 0x9C, 0x2A, 0xEC, 0x0C, + 0xE3, 0x41, 0x0D, 0x85, 0x8C, 0x2A, 0xF6, 0xF8, 0x35, 0x18, + 0x48, 0x9F, 0xFB, 0xA2, 0xDD, 0xDF, 0xBE, 0x25, 0xE1, 0xD0, + 0x1E, 0x58, 0x57, 0x00, 0x9F, 0x6F, 0x1A, 0x5B, 0xD6, 0xF5, + 0x2F, 0xE8, 0x24, 0xC7, 0xC5, 0x90, 0x47, 0x28, 0x02, 0xE9, + 0x1D, 0xB0, 0x0A, 0x73, 0xF8, 0x56, 0x76, 0x7B, 0xB3, 0x8E, + 0x34, 0x1F, 0xAA, 0x75, 0xC8, 0xB5, 0xC8, 0x64, 0x42, 0x79, + 0xCE, 0xF6, 0x2E, 0xE1, 0x1C, 0x2F, 0x21, 0x3E, 0x58, 0xA4, + 0x7A, 0xB9, 0x51, 0x0D, 0xD4, 0x3C, 0xCA, 0x15, 0x09, 0x6F, + 0x93, 0xE5, 0x6B, 0x63, 0x83, 0x04, 0xE3, 0xB1, 0x66, 0x74, + 0x28, 0x2D, 0x42, 0x78, 0x74, 0x62, 0x0F, 0x35, 0xDA, 0x17, + 0x8E, 0xAA, 0xD1, 0x12, 0x30, 0x59, 0xE7, 0x1A, 0xD2, 0xC9, + 0xCA, 0xCA, 0x71, 0x5B, 0x1D, 0xCC, 0x16, 0xF0, 0x52, 0x5B, + 0xD7, 0x16, 0x6C, 0x4B, 0xAF, 0x5D, 0xD2, 0xE4, 0x39, 0xE5, + 0x04, 0x31, 0x3D, 0x5C, 0xCE, 0x5A, 0x46, 0x07, 0x3B, 0x2F, + 0xFB, 0x5C, 0x65, 0xFB, 0xAE, 0xEC, 0xC8, 0x3B, 0x0E, 0x36, + 0x90, 0x05, 0xDD, 0xF4, 0xB4, 0xD6, 0x84, 0x8D, 0xF9, 0x96, + 0xB3, 0x75, 0xBF, 0x6B, 0xD6, 0xBD, 0x52, 0x77, 0x2B, 0x9A, + 0x45, 0x59, 0x45, 0xE0, 0xCB, 0x8E, 0xB3, 0x4A, 0x63, 0x6F, + 0x39, 0x74, 0x0E, 0x36, 0xFA, 0xBF, 0x76, 0x96, 0x2F, 0xFC, + 0xFB, 0x9F, 0xFC, 0x1A, 0x15, 0x55, 0xCB, 0x48, 0x68, 0xB7, + 0xEE, 0xDC, 0x82, 0xBF, 0x6B, 0xFE, 0xE8, 0xA0, 0x40, 0x1F, + 0xFE, 0xC4, 0xCC, 0x13, 0x8A, 0x08, 0xBC, 0x5A, 0x52, 0x60, + 0x12, 0x5A, 0x08, 0x8E, 0xA4, 0xD7, 0x53, 0x8B, 0x93, 0x1E, + 0x83, 0x11, 0x07, 0x6B, 0x0C, 0x1E, 0xB5, 0xBE, 0xBF, 0xA0, + 0x57, 0x4E, 0xEA, 0x6A, 0xDB, 0x50, 0x4A, 0x7A, 0x4C, 0x97, + 0xF3, 0x5C, 0x34, 0xBB, 0x2B, 0xE2, 0xCE, 0x78, 0x04, 0xAD, + 0x3E, 0x76, 0x58, 0x59, 0x73, 0x7F, 0x0F, 0x54, 0x09, 0x40, + 0x0B, 0x30, 0x3A, 0x6B, 0xE1, 0x66, 0xA6, 0x77, 0xBA, 0xB4, + 0x0D, 0xF2, 0x6A, 0xA4, 0x2B, 0xAE, 0xD0, 0xB8, 0x3D, 0xB0, + 0xB6, 0xE7, 0xF1, 0x2B, 0x21, 0x13, 0x00, 0x22, 0xFB, 0x8C, + 0xB4, 0x48, 0xC4, 0x37, 0xC1, 0x6C, 0xDF, 0x92, 0xAF, 0x23, + 0x3A, 0x3D, 0xA7, 0x8E, 0x5B, 0xD6, 0x43, 0xE3, 0x5B, 0xDC, + 0xB4, 0x9C, 0x2A, 0x53, 0xD8, 0x5F, 0x9E, 0xF8, 0x37, 0xB4, + 0xEE, 0x10, 0x23, 0x36, 0x84, 0xD0, 0x29, 0xEB, 0x5E, 0xC1, + 0x12, 0x41, 0xBE, 0x6A, 0x3B, 0x52, 0xCA, 0x39, 0x29, 0x8B, + 0xE7, 0x2D, 0xC6, 0x6D, 0x4E, 0x42, 0x36, 0x8A, 0x6F, 0x93, + 0xD9, 0x50, 0xEE, 0x3F, 0x56, 0x36, 0xA2, 0x4B, 0x0B, 0xEC, + 0xDE, 0x60, 0x26, 0xC0, 0xA1, 0x23, 0x5D, 0x58, 0x91, 0x52, + 0x42, 0x39, 0xE9, 0xEC, 0xCF, 0xA0, 0x6C, 0x02, 0xA6, 0xE1, + 0xC8, 0x50, 0x78, 0x18, 0x2A, 0xCE, 0x21, 0xD9, 0x63, 0xEF, + 0x03, 0x15, 0xFB, 0x93, 0xEE, 0x4A, 0xC9, 0xF8, 0xC7, 0xE6, + 0xEE, 0xD9, 0x92, 0xA6, 0xB5, 0x8A, 0x6E, 0x6E, 0x9F, 0x66, + 0x84, 0x54, 0x16, 0xCA, 0x9A, 0x36, 0x10, 0x36, 0xE8, 0x28, + 0x12, 0x9B, 0x2A, 0x82, 0xD3, 0xAD, 0xF4, 0xC7, 0xCC, 0xFC, + 0xBB, 0xDD, 0xB0, 0xB4, 0x64, 0x20, 0xB8, 0x72, 0x10, 0x04, + 0x5F, 0xB7, 0xFA, 0xE0, 0xA6, 0xAE, 0x62, 0xCE, 0xB7, 0x44, + 0x02, 0x0F, 0x75, 0xF2, 0xDE, 0x68, 0x32, 0xD6, 0xE6, 0xE3, + 0x0F, 0x0F, 0xBA, 0xFC, 0x72, 0xC6, 0xAA, 0x94, 0x78, 0x18, + 0x9C, 0x8A, 0x40, 0x6E, 0x7B, 0xAB, 0xAC, 0xBC, 0xA4, 0xAF, + 0xA7, 0x7C, 0xA5, 0x5F, 0x90, 0xCB, 0x81, 0x98, 0x22, 0x56, + 0xFD, 0x01, 0x27, 0x10, 0xB9, 0x35, 0xC4, 0x6E, 0x9D, 0x81, + 0xDE, 0x1C, 0xEB, 0xCF, 0xAF, 0xB5, 0xBE, 0xE1, 0x8C, 0x8A, + 0x87, 0xA1, 0x24, 0x38, 0xAE, 0x48, 0x7D, 0xFC, 0x0C, 0x38, + 0xC3, 0x97, 0x7F, 0x1B, 0x2F, 0x42, 0x78, 0xE4, 0x0E, 0x4B, + 0x7B, 0x09, 0x96, 0x10, 0x30, 0x10, 0x57, 0x06, 0x1B, 0xFD, + 0xF2, 0x09, 0xD7, 0x6D, 0x2C, 0xB6, 0xDA, 0xB3, 0x4B, 0x87, + 0xF6, 0x18, 0x1B, 0xE6, 0xDE, 0x1F, 0x8D, 0xF3, 0xBE, 0x7F, + 0xCA, 0x82, 0x8E, 0x35, 0x71, 0x87, 0xD1, 0x75, 0x20, 0x02, + 0x4B, 0x2A, 0x83, 0x87, 0xE3, 0x41, 0x77, 0x48, 0xB4, 0x6D, + 0xF8, 0x9E, 0xEA, 0xA1, 0xE5, 0x7C, 0xB2, 0xB2, 0x35, 0xF8, + 0x84, 0x0A, 0xDE, 0x5A, 0xBA, 0x0B, 0x1D, 0x7C, 0xFC, 0xEE, + 0x94, 0x19, 0x57, 0x31, 0x8E, 0x14, 0xC2, 0xA3, 0x9A, 0x40, + 0x39, 0x28, 0x26, 0x0A, 0x5A, 0x96, 0x6A, 0x34, 0xAE, 0x3D, + 0x33, 0x41, 0xD3, 0x25, 0x83, 0xAB, 0xD0, 0x44, 0x61, 0x00, + 0x80, 0xBB, 0x88, 0x9E, 0xE6, 0x24, 0x22, 0x28, 0x69, 0xE5, + 0xC9, 0xF1, 0xE7, 0x4B, 0x5E, 0x85, 0xD7, 0x84, 0xC5, 0x21, + 0x14, 0xE1, 0xC1, 0x04, 0x39, 0x54, 0x50, 0xA9, 0x75, 0xF8, + 0x9B, 0x44, 0xCF, 0xD8, 0x5A, 0xFC, 0x87, 0x6A, 0x2F, 0xDD, + 0x90, 0xEC, 0x7A, 0x0B, 0x42, 0x01, 0x23, 0x18, 0x4E, 0x8F, + 0x35, 0xC0, 0xAB, 0xEE, 0x62, 0x07, 0x78, 0xB2, 0x3D, 0xEB, + 0xA8, 0x9C, 0x4B, 0x6C, 0xF5, 0xA6, 0xF5, 0x03, 0x54, 0x61, + 0xE5, 0x04, 0x65, 0xAD, 0x92, 0x12, 0xCD, 0x67, 0x24, 0x4B, + 0x1B, 0x77, 0x14, 0x91, 0x2D, 0xCF, 0xE3, 0xC8, 0x86, 0xB5, + 0x72, 0x5D, 0xAC, 0x47, 0xDD, 0xC6, 0x9C, 0x7E, 0x4E, 0x87, + 0x01, 0xD2, 0x46, 0xB8, 0xD7, 0xFC, 0x37, 0x43, 0xDB, 0xA6, + 0x84, 0xD8, 0x58, 0x34, 0x15, 0xC1, 0x12, 0x71, 0x9D, 0xC2, + 0x6F, 0x88, 0x30, 0xF5, 0x48, 0xEB, 0xEE, 0xAB, 0x94, 0x3C, + 0x02, 0x08, 0xFF, 0xDC, 0x84, 0xB7, 0x4B, 0x95, 0x6A, 0x00, + 0xD9, 0xD2, 0x3B, 0xC8, 0x37, 0x11, 0x18, 0x3B, 0xE4, 0xF6, + 0x8E, 0xA6, 0x72, 0x55, 0x6D, 0xFA, 0x0D, 0x1A, 0xF5, 0x44, + 0xC8, 0x18, 0xF4, 0x6C, 0x86, 0x80, 0x87, 0xAE, 0xFF, 0x26, + 0x0C, 0x61, 0x04, 0x36, 0x8A, 0xAC, 0xDF, 0x76, 0x83, 0xC8, + 0x90, 0x6F, 0xAE, 0x22, 0x28, 0x03, 0xEE, 0xAE, 0x48, 0x58, + 0x82, 0x78, 0x86, 0x04, 0x62, 0x39, 0x72, 0xCD, 0x02, 0xF9, + 0x61, 0x60, 0xCC, 0x83, 0x5B, 0x72, 0xED, 0x32, 0xC2, 0xB3, + 0xEF, 0x6A, 0x05, 0x0C, 0x20, 0x9A, 0x7C, 0xE4, 0xE7, 0xCA, + 0x7E, 0x2F, 0x59, 0xA4, 0x59, 0xBB, 0x18, 0x1C, 0xC1, 0x8F, + 0xBE, 0xA7, 0xBA, 0x61, 0x8A, 0x35, 0x58, 0x9C, 0xFE, 0x72, + 0x95, 0xBA, 0x59, 0x49, 0xFE, 0xC6, 0x1F, 0x8C, 0xD5, 0x41, + 0x9A, 0xE4, 0x28, 0x63, 0x34, 0x07, 0x3D, 0x96, 0xCC, 0xF9, + 0xC8, 0xF5, 0xB9, 0xBD, 0x10, 0x05, 0xA7, 0xB0, 0x8D, 0xA3, + 0x20, 0x10, 0x26, 0x0F, 0xEC, 0xD0, 0x03, 0xCB, 0x9E, 0x68, + 0x25, 0x76, 0x56, 0x51, 0x31, 0xBA, 0x47, 0x26, 0x89, 0x92, + 0xBA, 0xB5, 0x91, 0x2C, 0x90, 0x94, 0x1D, 0xFB, 0x27, 0x18, + 0x2C, 0x3F, 0x1A, 0x5B, 0xD9, 0xDF, 0x4C, 0x68, 0x82, 0xAD, + 0x56, 0xEE, 0xA5, 0x4B, 0xFD, 0x1A, 0x54, 0xA0, 0xC0, 0x53, + 0xEC, 0x6C, 0x33, 0x50, 0x3E, 0xC9, 0x97, 0xF1, 0x01, 0xAE, + 0x2B, 0x24, 0x89, 0x3E, 0x32, 0x19, 0x70, 0xE3, 0x0D, 0x65, + 0xD0, 0x5E, 0x0C, 0x6A, 0xEE, 0x43, 0x71, 0xC6, 0x9F, 0x2E, + 0xE5, 0x49, 0xFB, 0x4A, 0x79, 0xF9, 0xF0, 0x46, 0x63, 0x25, + 0xFE, 0x22, 0xA7, 0x26, 0x00, 0xB4, 0x24, 0x0E, 0x9F, 0x73, + 0x3E, 0x5A, 0x23, 0xC3, 0x19, 0x49, 0xB7, 0xD6, 0xDD, 0xA7, + 0xF0, 0x0A, 0x2E, 0x4A, 0x3F, 0x7F, 0x60, 0x85, 0xF1, 0x58, + 0x0A, 0x00, 0x07, 0x57, 0xA3, 0x01, 0x6A, 0x5F, 0xF9, 0x30, + 0xCE, 0xD1, 0x3A, 0x85, 0x3F, 0x46, 0xA3, 0x13, 0xD8, 0x6A, + 0x04, 0x7F, 0x7D, 0x42, 0xF0, 0x4B, 0x8B, 0x3C, 0x6B, 0x34, + 0x6B, 0x2C, 0x75, 0xC4, 0x6B, 0xFA, 0xDE, 0xDA, 0xA9, 0x3C, + 0xC8, 0x50, 0x06, 0x51, 0x63, 0xB1, 0x24, 0xAD, 0xBD, 0x08, + 0x63, 0xBD, 0x02, 0x41, 0x8F, 0x26, 0x28, 0xEF, 0xDC, 0x59, + 0xA9, 0x11, 0xAC, 0x9A, 0x85, 0xE6, 0x24, 0x3E, 0xB1, 0x3A, + 0xE2, 0x38, 0x66, 0x50, 0x35, 0x94, 0x13, 0x1F, 0xFA, 0x21, + 0x09, 0x92, 0x27, 0xBC, 0x24, 0x05, 0xC3, 0xC2, 0x04, 0x07, + 0xF7, 0x92, 0x6A, 0xD2, 0x73, 0x53, 0x4B, 0xDB, 0xBB, 0xCA, + 0xC7, 0x08, 0xD2, 0x92, 0xB0, 0xC9, 0xE2, 0xD3, 0xBE, 0x33, + 0xD6, 0x45, 0x51, 0xBE, 0x73, 0x32, 0x44, 0xEE, 0x03, 0x99, + 0x5E, 0x67, 0xDC, 0x17, 0x3C, 0x2B, 0x7D, 0x75, 0x29, 0x2A, + 0x03, 0x6C, 0x42, 0x46, 0x9A, 0x45, 0xB5, 0x27, 0x22, 0xFB, + 0xA6, 0xC9, 0xFF, 0x16, 0xBD, 0x99, 0xE9, 0x3A, 0x9E, 0x14, + 0x35, 0x2E, 0x7F, 0xF0, 0x46, 0x12, 0x1D, 0xDD, 0xF2, 0xA6, + 0x26, 0xCE, 0x36, 0x23, 0x4D, 0x6B, 0x21, 0xB0, 0xC6, 0xC8, + 0x99, 0x5A, 0x77, 0x4C, 0x64, 0x4C, 0x0A, 0x31, 0x61, 0x6F, + 0xC5, 0x0C, 0xBA, 0x11, 0xFE, 0x5C, 0xA9, 0x6F, 0x6D, 0x36, + 0x36, 0x52, 0x42, 0x1B, 0x75, 0x31, 0x28, 0x30, 0x16, 0x00, + 0x23, 0x00, 0x9E, 0x9C, 0xCF, 0xB8, 0x69, 0x06, 0x17, 0x78, + 0xC7, 0x1A, 0x5D, 0x2C, 0x37, 0x0C, 0x36, 0xA5, 0xDA, 0xE0, + 0xA5, 0xA0, 0x0F, 0xF3, 0xAF, 0x7A, 0x2A, 0x71, 0x0E, 0x98, + 0xD7, 0x7F, 0x98, 0xBE, 0x5F, 0x2F, 0x71, 0xBC, 0xAB, 0x48, + 0x4F, 0x03, 0x5E, 0x59, 0xB4, 0xD1, 0x98, 0x04, 0xCF, 0x1C, + 0x32, 0x96, 0x30, 0x25, 0x51, 0x03, 0x1F, 0x07, 0x6E, 0x11, + 0xFF, 0xDA, 0xA4, 0xBE, 0xE6, 0xC5, 0x7C, 0x40, 0xF7, 0x82, + 0x5E, 0xC6, 0xDC, 0x3C, 0x0E, 0xF3, 0x42, 0xD0, 0xA8, 0x5E, + 0xDD, 0x1F, 0xED, 0x7F, 0x8F, 0x14, 0xEE, 0x03, 0x80, 0xA3, + 0x23, 0x5E, 0x60, 0x80, 0x93, 0x89, 0x2D, 0x7F, 0xA6, 0x4B, + 0x1E, 0xB4, 0xD0, 0xF1, 0x54, 0xA3, 0x6F, 0xA6, 0x4B, 0xC2, + 0x91, 0x20, 0x02, 0x14, 0xD3, 0x27, 0x81, 0x29, 0x4E, 0x23, + 0x80, 0xD5, 0xF8, 0xC9, 0x68, 0x11, 0x1C, 0xD5, 0xD6, 0x8E, + 0x92, 0x91, 0xC0, 0xED, 0xA9, 0x01, 0x2A, 0x65, 0xA7, 0x33, + 0x4F, 0x1F, 0x91, 0xF9, 0xB9, 0x31, 0xD0, 0x83, 0xD7, 0xC7, + 0x69, 0xE3, 0x8B, 0x98, 0x99, 0x1D, 0x04, 0x6A, 0xA8, 0x08, + 0xC5, 0xCB, 0x74, 0x2F, 0xC6, 0x01, 0x73, 0x54, 0x0B, 0xCC, + 0x5E, 0x0D, 0x2C, 0xA0, 0x4C, 0x10, 0x5D, 0x22, 0xFC, 0xC1, + 0x1E, 0x0C, 0x21, 0x19, 0x5B, 0x3C, 0x44, 0x79, 0x11, 0xC4, + 0xFB, 0x65, 0xA6, 0x98, 0xCF, 0x08, 0xEB, 0xD7, 0xC2, 0xE0, + 0x88, 0xB2, 0x93, 0x5B, 0xD9, 0x43, 0x29, 0x1E, 0x2D, 0x79, + 0x7F, 0xB2, 0xD6, 0xB2, 0x7F, 0x7D, 0xC0, 0x44, 0x2D, 0xF5, + 0x8D, 0x29, 0x02, 0xF1, 0xFB, 0xE2, 0x6A, 0xF6, 0x4A, 0x8B, + 0x93, 0x9F, 0xC3, 0x7D, 0xE2, 0x04, 0x77, 0xE0, 0x77, 0x08, + 0x6A, 0x6F, 0xBC, 0x06, 0x27, 0xC6, 0xF1, 0xA5, 0x80, 0xBB, + 0x6B, 0x02, 0x4E, 0x1F, 0x22, 0x94, 0x74, 0x9F, 0xE6, 0xFF, + 0x8E, 0x2D, 0x4A, 0x84, 0x8A, 0xA9, 0xB0, 0x0C, 0x4B, 0x11, + 0x9D, 0x1A, 0xE3, 0x92, 0x18, 0x4F, 0x40, 0xB1, 0xFC, 0x0B, + 0x71, 0x89, 0x49, 0x8B, 0x94, 0xDC, 0xBC, 0xC2, 0x13, 0x31, + 0xD8, 0x7E, 0x9F, 0xB5, 0xAB, 0x92, 0x70, 0x45, 0x54, 0xCD, + 0xDB, 0x56, 0x08, 0xBD, 0xDF, 0x39, 0x73, 0x0B, 0x24, 0x0A, + 0x28, 0x0F, 0xB3, 0x0C, 0x4F, 0xED, 0xF3, 0xBA, 0x89, 0x9F, + 0xEA, 0xBA, 0xBE, 0x9B, 0x15, 0x91, 0xD5, 0x6C, 0x69, 0xE1, + 0x92, 0x6A, 0x64, 0xE2, 0x03, 0x69, 0x26, 0x30, 0x88, 0xE8, + 0x2E, 0xF7, 0xB0, 0x2E, 0xD6, 0x20, 0x81, 0xED, 0x53, 0x31, + 0x47, 0xEB, 0xBA, 0xA7, 0x7F, 0x71, 0x15, 0xCD, 0x2F, 0x39, + 0x37, 0xF6, 0xD7, 0x62, 0x25, 0x4F, 0x88, 0x35, 0x94, 0xDA, + 0x7A, 0x2B, 0x41, 0xEB, 0x77, 0x90, 0xA9, 0xB4, 0x71, 0xC3, + 0xF9, 0xFC, 0x2C, 0x17, 0xD0, 0x94, 0x3D, 0x6E, 0x3A, 0xBC, + 0xD7, 0x0C, 0x21, 0x7B, 0xD4, 0x74, 0xE6, 0x3D, 0x8F, 0xC9, + 0x88, 0x4A, 0xD0, 0x17, 0x8F, 0x18, 0x0C, 0x76, 0x5E, 0xE1, + 0x0F, 0xEC, 0x17, 0x0B, 0x6D, 0xC3, 0x99, 0x7F, 0x62, 0x94, + 0xCD, 0xFB, 0x70, 0xBE, 0xE0, 0xB7, 0xF1, 0xB6, 0xEE, 0x63, + 0xD4, 0x4A, 0x84, 0xBE, 0x8E, 0x89, 0xAC, 0x85, 0x45, 0x1E, + 0x27, 0x98, 0x97, 0x6A, 0xA2, 0x3F, 0x25, 0x7F, 0x9B, 0xCD, + 0x4B, 0x89, 0xD3, 0x4A, 0x32, 0x11, 0x69, 0xBB, 0x12, 0x6A, + 0xAC, 0x02, 0x21, 0x36, 0x2D, 0x1C, 0x3A, 0x71, 0x34, 0xFA, + 0xC4, 0xCD, 0x64, 0x60, 0x3B, 0xEA, 0x16, 0xB0, 0x9D, 0x09, + 0x0C, 0xD5, 0xAD, 0x6C, 0x8B, 0xDE, 0x25, 0x00, 0x58, 0xC1, + 0x04, 0x7E, 0xF9, 0x65, 0x86, 0x1E, 0xDE, 0x5D, 0xC7, 0x53, + 0x6E, 0x33, 0x6B, 0x1E, 0x39, 0x7B, 0x34, 0xD9, 0x51, 0x05, + 0xF3, 0x7D, 0xFF, 0x3F, 0xE1, 0xF2, 0x07, 0x6D, 0xEB, 0x98, + 0xBD, 0x46, 0xD2, 0x34, 0xDB, 0x0A, 0x13, 0x5B, 0x98, 0x48, + 0x31, 0x91, 0x67, 0x7D, 0xBA, 0x8B, 0x8A, 0x21, 0xC4, 0xAC, + 0xA8, 0x9C, 0xAE, 0xDC, 0x79, 0x7F, 0x36, 0x3C, 0xE7, 0x0A, + 0xA0, 0x79, 0xE2, 0xC9, 0x1C, 0xF9, 0x02, 0x9E, 0xE6, 0xE1, + 0xEC, 0xC6, 0x9B, 0x4A, 0xE1, 0x99, 0x87, 0x87, 0x06, 0x07, + 0xA8, 0x88, 0x2A, 0x28, 0xB1, 0xFF, 0x37, 0x27, 0x95, 0x56, + 0xD7, 0xEB, 0xB7, 0xE4, 0x61, 0x99, 0xEA, 0xF7, 0x84, 0x2F, + 0x1A, 0x81, 0xC2, 0xD5, 0xF0, 0x26, 0x69, 0xA6, 0x9B, 0x21, + 0xBF, 0xC2, 0x0D, 0x72, 0xBD, 0x50, 0xCB, 0xEE, 0x77, 0x6E, + 0xDE, 0x82, 0x2E, 0x71, 0xA1, 0xDB, 0xB5, 0xF8, 0xE9, 0x08, + 0x6C, 0xCF, 0x41, 0x0E, 0x98, 0xE7, 0x19, 0x8A, 0x31, 0xAB, + 0x15, 0xD6, 0x66, 0xBF, 0xEF, 0x11, 0x8B, 0xF1, 0x32, 0x24, + 0xDE, 0x49, 0x27, 0xD8, 0xAC, 0x72, 0x6C, 0x95, 0x5C, 0xB1, + 0x26, 0xAA, 0x7D, 0x7D, 0x04, 0xB7, 0x51, 0x3F, 0x4B, 0x55, + 0xE4, 0xA5, 0xFA, 0x7D, 0xD6, 0x9E, 0xEB, 0x29, 0x93, 0x8E, + 0xBE, 0xC3, 0xE7, 0x4F, 0xDD, 0x7B, 0x5F, 0x84, 0x72, 0xB6, + 0xDD, 0xBD, 0xE7, 0xAE, 0x52, 0x0B, 0x9F, 0xA7, 0xDC, 0x93, + 0x23, 0x30, 0x43, 0xBF, 0xAF, 0x39, 0x26, 0x25, 0x31, 0xC1, + 0xC7, 0xB1, 0x99, 0xE7, 0x46, 0xE2, 0x2A, 0x38, 0x14, 0xE2, + 0x40, 0x85, 0x03, 0x69, 0x8B, 0x2C, 0x2B, 0x72, 0xD6, 0x63, + 0xFA, 0x6E, 0x1F, 0x62, 0x8D, 0x18, 0xF5, 0xC3, 0x1F, 0xC4, + 0xB1, 0xD0, 0x46, 0xE9, 0x60, 0x0D, 0x80, 0x01, 0x98, 0x5B, + 0xD8, 0x4A, 0x1B, 0x15, 0x81, 0x99, 0x2B, 0x7B, 0x25, 0x35, + 0x0F, 0xD7, 0x6F, 0xFB, 0x53, 0x01, 0x7C, 0x96, 0x35, 0x52, + 0xF7, 0x23, 0xC1, 0x8A, 0xB6, 0xDD, 0x90, 0xEC, 0x89, 0xF1, + 0x76, 0x0D, 0x2F, 0x7D, 0x8D, 0xA8, 0x04, 0x14, 0x29, 0xAD, + 0xBA, 0x4D, 0x48, 0x54, 0x17, 0x14, 0xCE, 0x12, 0xCE, 0xC5, + 0xF9, 0x19, 0x82, 0x10, 0x0B, 0x65, 0x3F, 0x42, 0xC3, 0x4D, + 0xD2, 0x56, 0xDD, 0x56, 0x9F, 0x57, 0x74, 0xFE, 0x8B, 0xBC, + 0xE0, 0x4F, 0xD0, 0x26, 0x47, 0xF6, 0x83, 0x8C, 0x0F, 0xCA, + 0x5F, 0x3D, 0x7A, 0xD0, 0x13, 0xE7, 0xC0, 0xEF, 0xA4, 0x68, + 0xA6, 0xA7, 0x28, 0x94, 0xD1, 0x3B, 0x1A, 0x4C, 0xBD, 0x0D, + 0xE2, 0x13, 0x2F, 0x6A, 0x49, 0x32, 0x93, 0x87, 0x8F, 0x4F, + 0xA8, 0x8B, 0xA6, 0xFB, 0x2E, 0x51, 0xEE, 0x73, 0xA2, 0xC2, + 0xD4, 0xF5, 0xF1, 0x00, 0x2B, 0x4E, 0x2A, 0x0E, 0xC0, 0xBA, + 0x82, 0xAA, 0x10, 0x49, 0x05, 0xFC, 0x2F, 0x53, 0xF8, 0xF9, + 0x6A, 0xD9, 0x4E, 0xA8, 0xAA, 0xA8, 0x49, 0x17, 0x87, 0xFE, + 0xB5, 0x7E, 0x96, 0xB0, 0xFF, 0x82, 0xB5, 0x88, 0x37, 0x53, + 0x2A, 0xEF, 0x76, 0x4C, 0xC6, 0x75, 0xDC, 0xE4, 0xF0, 0xDD, + 0xEC, 0x9B, 0x27, 0xC5, 0x06, 0xEC, 0x3C, 0x65, 0x9C, 0x0E, + 0x3F, 0x41, 0x27, 0xD7, 0x07, 0xDE, 0x99, 0xF7, 0x7F, 0xFB, + 0x40, 0x8E, 0x97, 0x3B, 0xFF, 0x2E, 0xFE, 0xE0, 0x0B, 0xDD, + 0xC0, 0x57, 0xB6, 0x0B, 0x16, 0xA6, 0xD6, 0xFE, 0x25, 0x9D, + 0x7F, 0xD7, 0x33, 0x19, 0xD6, 0x3D, 0x5C, 0x7A, 0x9B, 0x2F, + 0xB0, 0x5A, 0x49, 0xC7, 0xB0, 0x6F, 0x3A, 0xB6, 0x4B, 0x0A, + 0x69, 0x58, 0xBE, 0xD3, 0x74, 0x87, 0xCD, 0x98, 0x79, 0x21, + 0xD4, 0xB9, 0xDC, 0xD6, 0x61, 0xB6, 0xFB, 0x81, 0x0A, 0x9B, + 0x0F, 0x26, 0x72, 0x62, 0x67, 0x06, 0x3C, 0x44, 0xF9, 0x36, + 0x3B, 0xA3, 0x66, 0x8E, 0x11, 0x31, 0x05, 0xDE, 0xA7, 0x66, + 0x74, 0x60, 0x29, 0x32, 0xD8, 0x23, 0x23, 0x90, 0x3C, 0xDC, + 0x17, 0xFE, 0x53, 0xD6, 0x82, 0x07, 0x68, 0xCE, 0xA7, 0x24, + 0x24, 0x6A, 0x9A, 0x02, 0x84, 0xB3, 0x3A, 0xF9, 0xEF, 0x31, + 0x25, 0xF2, 0x9D, 0x34, 0xF5, 0xC2, 0x27, 0x07, 0xAA, 0x93, + 0xDA, 0x32, 0x16, 0xCD, 0x08, 0xA7, 0xC0, 0x5B, 0x9D, 0xFB, + 0xC4, 0xBD, 0xDF, 0x78, 0x8F, 0x6F, 0x04, 0x73, 0x2B, 0x72, + 0xDE, 0xAB, 0x66, 0x40, 0xC5, 0x26, 0xD6, 0x67, 0xE2, 0x99, + 0x40, 0x40, 0x3D, 0xE0, 0xB4, 0xDB, 0xD9, 0xBB, 0xA3, 0x54, + 0x0C, 0xBB, 0x85, 0xB4, 0x52, 0x5D, 0xEE, 0xA4, 0xAA, 0xCB, + 0x3F, 0x71, 0xE9, 0x23, 0x34, 0x5A, 0x98, 0xFC, 0x1C, 0xEC, + 0x70, 0x43, 0xBC, 0x8C, 0x79, 0x24, 0xCE, 0x0A, 0xDB, 0x53, + 0x65, 0x7A, 0xA8, 0x05, 0xA5, 0x84, 0xEE, 0xF0, 0x97, 0x6C, + 0xF3, 0x8A, 0xBF, 0xCE, 0xB1, 0x4B, 0x98, 0x53, 0x22, 0xA1, + 0xD5, 0xCD, 0x4E, 0x2C, 0x17, 0xD6, 0x3C, 0x47, 0xF6, 0x41, + 0xE2, 0x59, 0x6F, 0xFE, 0x58, 0xA6, 0x99, 0x16, 0x4D, 0x2B, + 0xCD, 0x29, 0xE8, 0xD7, 0x22, 0xCB, 0x25, 0xDF, 0x48, 0xF3, + 0xC7, 0x95, 0x69, 0xBC, 0x09, 0x33, 0x96, 0x65, 0x64, 0xB0, + 0x12, 0xC4, 0xB8, 0xBC, 0xAC, 0x70, 0x67, 0xAD, 0x98, 0x42, + 0xC8, 0x6F, 0x75, 0xE1, 0x39, 0xB0, 0x0A, 0x2A, 0x14, 0x6F, + 0x3A, 0xEC, 0xEC, 0x7C, 0xAC, 0x65, 0x81, 0x81, 0x1E, 0x3B, + 0x9F, 0x35, 0xF2, 0x51, 0x9F, 0x31, 0x1E, 0x29, 0x1C, 0x6C, + 0xE4, 0xBE, 0x67, 0x3D, 0x69, 0xA8, 0x57, 0xE2, 0xB0, 0x65, + 0xAC, 0xA9, 0xED, 0x6B, 0xAA, 0x6F, 0xA9, 0xAC, 0x0D, 0x2F, + 0x62, 0xFD, 0xAC, 0x16, 0x46, 0xAF, 0xDC, 0x75, 0xB7, 0x3F, + 0x89, 0xE5, 0x93, 0x3A, 0xDD, 0x51, 0xA7, 0xE6, 0xBE, 0x7A, + 0x63, 0x73, 0x8E, 0x5E, 0x51, 0x92, 0x1C, 0x7E, 0xB8, 0x35, + 0xF5, 0x03, 0x2D, 0x38, 0x31, 0xDB, 0x2F, 0x1D, 0x0E, 0xF7, + 0xA3, 0x08, 0x28, 0x50, 0x4B, 0x4E, 0x79, 0xAE, 0x6D, 0xC8, + 0xA8, 0xAD, 0x06, 0xDA, 0x79, 0xA5, 0xF5, 0x6B, 0x5A, 0xF2, + 0x04, 0xE6, 0xE5, 0x50, 0xCA, 0x64, 0x5D, 0x70, 0xD7, 0xF8, + 0x1F, 0x90, 0x61, 0x95, 0x9B, 0x2F, 0x76, 0xE3, 0xAE, 0x7E, + 0xDA, 0xBB, 0x8C, 0x3D, 0xA2, 0x5C, 0x30, 0x3A, 0xA1, 0xB9, + 0x7C, 0x7C, 0xA2, 0x0B, 0x80, 0x4E, 0x29, 0x2C, 0x90, 0xD3, + 0x13, 0xE0, 0x94, 0x7C, 0xCB, 0xAC, 0x16, 0xBF, 0x7E, 0x54, + 0x6D, 0x2A, 0xC7, 0x4F, 0xFC, 0x0F, 0x72, 0x8C, 0xDD, 0x0B, + 0x48, 0x16, 0xF4, 0xA8, 0x38, 0xC1, 0x13, 0x78, 0x8A, 0x32, + 0x20, 0x43, 0x11, 0xD5, 0xBA, 0x71, 0xE5, 0x5C, 0xFB, 0x69, + 0x91, 0x8A, 0x87, 0x9E, 0x6C, 0xB2, 0x07, 0x01, 0x48, 0xB6, + 0xA4, 0x84, 0x47, 0xAD, 0xED, 0x37, 0xAA, 0x8D, 0x6B, 0x95, + 0xE6, 0xC4, 0xC7, 0x23, 0x43, 0x23, 0x48, 0xDB, 0xF9, 0x3C, + 0xBD, 0xAF, 0x85, 0x1B, 0x6D, 0xC7, 0x70, 0x86, 0xEC, 0xF5, + 0x0E, 0xCF, 0xA4, 0xE2, 0xBF, 0x7C, 0xE3, 0xEE, 0x44, 0x36, + 0x9A, 0x42, 0xB8, 0x6B, 0x2E, 0xE4, 0x83, 0x2A, 0xC2, 0xEC, + 0x7F, 0x7A, 0xB4, 0xD4, 0xD0, 0x1B, 0x23, 0xA1, 0x3B, 0xC2, + 0x61, 0xB4, 0xD9, 0x4E, 0x71, 0x36, 0xE9, 0x5F, 0x16, 0x8F, + 0x26, 0xD7, 0x34, 0x81, 0xBC, 0xCA, 0x7C, 0xA8, 0x35, 0x37, + 0x88, 0x1E, 0xCE, 0xF1, 0xB3, 0xBD, 0xF9, 0xAF, 0x24, 0x68, + 0xF4, 0x58, 0xEB, 0x1F, 0xC4, 0x41, 0x5D, 0xBD, 0xF6, 0xAF, + 0xF4, 0xF9, 0x28, 0xEB, 0x79, 0xAC, 0xEB, 0x7F, 0xB3, 0xF2, + 0x70, 0x93, 0x33, 0xD0, 0xFB, 0xFE, 0x55, 0x54, 0xF0, 0xA2, + 0x07, 0x94, 0xCF, 0x16, 0x2D, 0x1C, 0xF9, 0x1C, 0xD4, 0x0C, + 0x2E, 0x2B, 0xA0, 0xAD, 0x47, 0xAC, 0x14, 0xB2, 0x84, 0x27, + 0xD5, 0x74, 0x5C, 0x79, 0x59, 0x69, 0xA1, 0x5E, 0xA5, 0xEC, + 0x17, 0xDE, 0x6F, 0x9C, 0x24, 0x7F, 0x91, 0x7E, 0xA0, 0x39, + 0xF0, 0x89, 0x83, 0x86, 0x5D, 0xAB, 0x61, 0x5D, 0xCA, 0x16, + 0x7B, 0x77, 0xF9, 0x0A, 0xF4, 0x44, 0xDD, 0x0F, 0x74, 0x9B, + 0x71, 0xC6, 0x36, 0xD5, 0xD1, 0xF7, 0x36, 0xE6, 0x7F, 0xDA, + 0x20, 0x65, 0xE8, 0x69, 0x76, 0x4A, 0x84, 0xFC, 0x8D, 0xA3, + 0x47, 0x24, 0x2F, 0x7A, 0xD0, 0x9D, 0x9B, 0xD6, 0x03, 0x90, + 0xED, 0x64, 0x28, 0xCA, 0xF9, 0xD7, 0x12, 0xA7, 0x90, 0xB5, + 0x1B, 0x62, 0x40, 0x4D, 0xEC, 0x03, 0x8A, 0x40, 0xC8, 0xB4, + 0x37, 0x8E, 0xF7, 0x2C, 0x09, 0x79, 0x78, 0x11, 0x00, 0x82, + 0x9F, 0xC9, 0xB2, 0xAE, 0x21, 0x4B, 0x08, 0x20, 0xD0, 0x6B, + 0x8F, 0xED, 0x93, 0x1A, 0xAE, 0xCC, 0xE7, 0x5E, 0x79, 0xEB, + 0xB0, 0x5A, 0xE3, 0x2C, 0x44, 0xB6, 0x3F, 0x82, 0x85, 0x0E, + 0x66, 0xD8, 0x95, 0x21, 0xB6, 0x25, 0xEF, 0x24, 0x60, 0x1D, + 0x49, 0x40, 0xAA, 0x21, 0x50, 0x2F, 0x4C, 0x5B, 0x4C, 0xA2, + 0xAC, 0xA2, 0xD5, 0x83, 0x4C, 0x7A, 0x7A, 0x5E, 0xE9, 0xAC, + 0x2A, 0xB1, 0xDF, 0xA9, 0xF7, 0xD9, 0x48, 0x6C, 0xF0, 0x4F, + 0xAD, 0x19, 0x84, 0x87, 0x29, 0xBF, 0x25, 0x38, 0x50, 0xD6, + 0x2B, 0xD2, 0xB0, 0x4C, 0x2C, 0xD0, 0xFF, 0xC1, 0x78, 0x00, + 0x0E, 0x68, 0x89, 0xBD, 0xD6, 0xFC, 0xB2, 0xC6, 0xC0, 0xCF, + 0x59, 0x4B, 0xE4, 0x3C, 0x18, 0x74, 0xA7, 0x8A, 0xA1, 0x57, + 0xA1, 0x8E, 0xF6, 0x70, 0x46, 0x7F, 0x71, 0x4E, 0x5F, 0xA7, + 0x19, 0x5D, 0xAA, 0x85, 0xC5, 0x61, 0x9D, 0x02, 0x85, 0xDA, + 0x3E, 0x3C, 0x11, 0xD5, 0xF4, 0x21, 0x5F, 0x46, 0x03, 0x92, + 0x64, 0x78, 0xA8, 0xC4, 0xBF, 0x5E, 0x21, 0x49, 0xE2, 0x83, + 0x66, 0x5F, 0xF8, 0x30, 0x48, 0xF5, 0x40, 0x88, 0x36, 0xCB, + 0xA2, 0xAB, 0x57, 0xAB, 0x67, 0x8C, 0x40, 0xB2, 0xE4, 0xD3, + 0xEF, 0x19, 0x2B, 0x1D, 0x25, 0x58, 0x9B, 0xC8, 0x23, 0xBA, + 0xF5, 0xF1, 0x40, 0x79, 0xD4, 0x87, 0x0A, 0x19, 0xC8, 0xB1, + 0xC5, 0xD7, 0xC5, 0x6F, 0x0E, 0x36, 0x7F, 0x09, 0x16, 0xF7, + 0xE2, 0x0B, 0x9B, 0xBE, 0x58, 0xEB, 0x95, 0xC4, 0x28, 0x11, + 0x6A, 0x70, 0xBF, 0xE2, 0x69, 0x61, 0x8F, 0x5C, 0xAA, 0x7C, + 0xED, 0x7B, 0x8C, 0x23, 0xF6, 0x5D, 0x42, 0x75, 0xA5, 0x43, + 0xF1, 0xE3, 0xE3, 0xBB, 0xD9, 0x22, 0x23, 0x7D, 0x1D, 0x49, + 0x59, 0x58, 0x2F, 0x61, 0x71, 0xC9, 0xC8, 0x8C, 0xEB, 0x38, + 0xF0, 0x14, 0x88, 0x5C, 0x5E, 0x81, 0xDF, 0x32, 0xB8, 0x6F, + 0xB2, 0x0C, 0x21, 0x54, 0x8E, 0x34, 0xC8, 0x93, 0x44, 0x18, + 0xAB, 0xC7, 0xB9, 0x92, 0x72, 0x02, 0x8A, 0x2D, 0x47, 0xA4, + 0x33, 0xFE, 0x0A, 0x70, 0x08, 0x4B, 0x32, 0xA4, 0x9D, 0x29, + 0xEA, 0x9B, 0x45, 0x8C, 0x22, 0xD4, 0xEB, 0xD5, 0x4C, 0x6D, + 0xB3, 0x46, 0x57, 0x3A, 0x6D, 0xD5, 0x09, 0xBE, 0x51, 0x52, + 0xC8, 0x61, 0x1A, 0x94, 0x66, 0xA1, 0x22, 0x13, 0x69, 0x05, + 0x82, 0x63, 0x75, 0x4B, 0x3A, 0x72, 0x2E, 0xA1, 0x16, 0x45, + 0x8F, 0xBF, 0x8C, 0xA6, 0xB9, 0xCC, 0x0F, 0x5D, 0x6F, 0x3D, + 0x21, 0x4A, 0xAA, 0x53, 0xF1, 0x92, 0x0F, 0x66, 0xF0, 0xB5, + 0x42, 0x31, 0xDB, 0x4B, 0xCA, 0x41, 0xF3, 0xE4, 0x58, 0x76, + 0x93, 0xEA, 0x1E, 0x53, 0x0F, 0x56, 0xDC, 0xCF, 0xBA, 0x17, + 0x60, 0x34, 0x01, 0xF9, 0x3A, 0x36, 0x20, 0x84, 0x80, 0xEE, + 0xEF, 0x4D, 0xBC, 0xF4, 0x71, 0x62, 0x9C, 0xE1, 0xDC, 0x71, + 0x3B, 0x5F, 0x92, 0x5D, 0x6F, 0x3B, 0xE9, 0x7A, 0x73, 0x5B, + 0x57, 0x9D, 0x48, 0x17, 0x7A, 0x23, 0x3E, 0x9E, 0x83, 0x2D, + 0xFD, 0x06, 0x34, 0xD5, 0x21, 0x22, 0x66, 0xB7, 0x9F, 0xFF, + 0x9C, 0x60, 0xBD, 0xDC, 0x26, 0x34, 0xA4, 0xD7, 0x0C, 0x4F, + 0xCD, 0x97, 0x3C, 0xE4, 0x8C, 0x40, 0x17, 0xBF, 0xF9, 0xCE, + 0x40, 0x89, 0x4C, 0xAA, 0x7B, 0x71, 0x8F, 0xD3, 0x62, 0x8E, + 0xA5, 0xEB, 0x35, 0x49, 0x2B, 0x08, 0xC9, 0xC4, 0x68, 0x18, + 0x35, 0xDA, 0xCC, 0xE4, 0x95, 0xE2, 0x62, 0xD1, 0x35, 0x78, + 0xA9, 0xCB, 0x79, 0x4C, 0x11, 0xF4, 0x01, 0xE1, 0x2C, 0xD5, + 0x85, 0x80, 0x8A, 0xED, 0x07, 0x61, 0xCC, 0x75, 0xFA, 0xAB, + 0x82, 0xB0, 0xDB, 0xD8, 0xAE, 0xCB, 0xF9, 0xAC, 0xDB, 0xDB, + 0xD1, 0xFB, 0x05, 0xA2, 0xF0, 0xB8, 0x98, 0xB1, 0xED, 0xB6, + 0xF6, 0xB4, 0xEF, 0xF7, 0x1F, 0x5F, 0x2C, 0x25, 0xFB, 0x6E, + 0x5F, 0x26, 0xF4, 0xB2, 0xCC, 0x3A, 0xD5, 0x74, 0xD0, 0xD7, + 0xAE, 0x55, 0xB7, 0xE7, 0xEA, 0x77, 0xC8, 0xAB, 0x53, 0x71, + 0x9A, 0xE3, 0x36, 0xF9, 0xBD, 0x2C, 0x22, 0xF2, 0x27, 0xAD, + 0xB4, 0xB2, 0xE1, 0x1D, 0x50, 0x8E, 0x1E, 0x30, 0x46, 0x0A, + 0xFA, 0x02, 0x93, 0xA7, 0xCA, 0x73, 0x91, 0xC4, 0x1D, 0x1B, + 0xBD, 0x00, 0x2D, 0xF7, 0xA7, 0x53, 0xFD, 0xCD, 0x9C, 0x73, + 0xE3, 0xA8, 0x51, 0x53, 0x3C, 0xB6, 0x10, 0x68, 0x6C, 0x4F, + 0x7A, 0xD3, 0xB2, 0x92, 0x33, 0x9B, 0x91, 0x0F, 0x92, 0x17, + 0x94, 0x1C, 0x6C, 0x9C, 0xEC, 0x39, 0x2D, 0x3A, 0xD9, 0xDE, + 0x37, 0x49, 0xA9, 0x7C, 0xC0, 0xAA, 0x2D, 0x8C, 0xC6, 0xCF, + 0x05, 0x2F, 0x35, 0xA6, 0x06, 0xB7, 0xAC, 0xBF, 0x90, 0xF7, + 0xD0, 0x66, 0x27, 0xC2, 0x99, 0xAF, 0xD4, 0xCE, 0x39, 0xE9, + 0xEC, 0x99, 0xA8, 0xC3, 0xB2, 0x4F, 0xED, 0xC4, 0x13, 0xBD, + 0x71, 0xA1, 0x8D, 0xB5, 0x7C, 0x66, 0xFC, 0xB6, 0x8F, 0x15, + 0xE3, 0x5D, 0x20, 0xA5, 0x0B, 0x3A, 0x94, 0x6F, 0x4F, 0x7C, + 0x0D, 0xEF, 0xCA, 0x88, 0x1A, 0x0B, 0x7D, 0x4A, 0x91, 0xF8, + 0xA7, 0xE8, 0x9D, 0x4C, 0x22, 0xC2, 0x27, 0x5B, 0x55, 0x3F, + 0xAF, 0x2D, 0xFE, 0xD9, 0xC0, 0x02, 0x5A, 0x90, 0x39, 0xF7, + 0xAD, 0x38, 0xB6, 0x10, 0xD0, 0x59, 0x15, 0x08, 0x25, 0x2A, + 0x42, 0x67, 0xD9, 0x3D, 0xAD, 0x7D, 0x17, 0xD5, 0x26, 0xA2, + 0x2A, 0x28, 0xF5, 0x2E, 0x9E, 0xDA, 0x71, 0x70, 0xB9, 0x4E, + 0x03, 0x1F, 0xFE, 0xE2, 0x3D, 0xF4, 0x76, 0xE8, 0xF4, 0x00, + 0x9B, 0x70, 0x89, 0x62, 0xB7, 0x5B, 0x0E, 0xA6, 0x90, 0x02, + 0xA2, 0x5E, 0x12, 0x2D, 0x2E, 0x63, 0xFF, 0x97, 0x1A, 0xC6, + 0x4C, 0x16, 0x13, 0x0E, 0xC7, 0x89, 0xA9, 0x1D, 0x81, 0x69, + 0x5F, 0x41, 0x14, 0xAA, 0xF4, 0xF6, 0x58, 0x27, 0x87, 0x82, + 0xEF, 0xE9, 0xC9, 0xFB, 0x82, 0x49, 0xEE, 0x39, 0x95, 0x69, + 0xD3, 0x50, 0x51, 0x46, 0x71, 0xA2, 0x48, 0x99, 0x86, 0x9A, + 0x76, 0x99, 0xC9, 0xDF, 0x17, 0x44, 0xE0, 0x7C, 0xAD, 0x20, + 0x4E, 0x47, 0x28, 0x18, 0x57, 0xE7, 0xF9, 0x8F, 0xF8, 0x5A, + 0xAE, 0x4E, 0x03, 0x5F, 0xEC, 0x99, 0x2D, 0xEB, 0x12, 0xD2, + 0x59, 0x7F, 0x9B, 0x42, 0x9C, 0x9D, 0xBC, 0x1A, 0xAF, 0x09, + 0xB3, 0x28, 0x5F, 0xAD, 0xD4, 0x1F, 0x7A, 0xC1, 0x7B, 0x8B, + 0x39, 0x95, 0x0D, 0x57, 0xCA, 0x7F, 0x34, 0x14, 0x26, 0xFF, + 0xFD, 0xE2, 0x8A, 0x57, 0x29, 0x71, 0xF6, 0x82, 0x7F, 0xE7, + 0xE8, 0xE5, 0x89, 0x0D, 0xEF, 0x41, 0xF4, 0xB4, 0xE6, 0x71, + 0xC1, 0xDE, 0xCD, 0x38, 0xE1, 0x64, 0x92, 0xBE, 0x60, 0xA3, + 0x2E, 0xC0, 0xF7, 0x8A, 0x8D, 0x25, 0x4F, 0xFD, 0xA4, 0xB1, + 0xBD, 0x53, 0x83, 0xCE, 0xC9, 0xFC, 0xD6, 0xEE, 0xA3, 0x27, + 0x73, 0x15, 0x39, 0x9C, 0xB4, 0xEE, 0xD0, 0x20, 0x03, 0x84, + 0x03, 0xC7, 0xCC, 0xA2, 0x0D, 0xF6, 0x5B, 0xE7, 0x17, 0x81, + 0x58, 0xC0, 0xA2, 0x43, 0xDB, 0xB8, 0xE1, 0x48, 0x4D, 0xC2, + 0x0C, 0x9F, 0x9F, 0xF2, 0xED, 0xDA, 0x1D, 0x48, 0x28, 0x84, + 0xE7, 0xA5, 0x2A, 0x45, 0xBF, 0xA2, 0x78, 0x8C, 0xD2, 0xAF, + 0xB9, 0x66, 0x2F, 0x72, 0xF7, 0xBB, 0x80, 0xCD, 0xA6, 0xBC, + 0xA9, 0x5F, 0x43, 0x0B, 0xA0, 0x49, 0x55, 0x2D, 0xC9, 0x6F, + 0xB0, 0x72, 0x6C, 0x6E, 0x6A, 0xB6, 0xE5, 0xA3, 0x40, 0x51, + 0x89, 0x73, 0x39, 0x69, 0xB6, 0x45, 0x76, 0x2C, 0xC4, 0x45, + 0x7D, 0xDA, 0x1F, 0xAF, 0x1F, 0x5E, 0x56, 0x0E, 0x64, 0xFA, + 0xE0, 0xC6, 0x4C, 0x2B, 0xC3, 0x0C, 0x72, 0x61, 0x80, 0xB9, + 0x9F, 0xDD, 0x3F, 0x29, 0x73, 0x6B, 0x41, 0x3A, 0x91, 0x18, + 0xC2, 0x4E, 0x7C, 0xD2, 0x9F, 0x22, 0x05, 0x49, 0x56, 0x73, + 0x45, 0xD3, 0x99, 0x84, 0xA0, 0x19, 0x14, 0x11, 0xFE, 0x31, + 0x79, 0x50, 0x54, 0x88, 0x04, 0x14, 0x1D, 0xA1, 0x09, 0xAD, + 0xF5, 0x19, 0xAD, 0x2D, 0xA3, 0x0A, 0x5C, 0xEE, 0x26, 0x33, + 0xA0, 0x06, 0x09, 0x8A, 0x77, 0x59, 0xF1, 0x0F, 0x6C, 0x63, + 0x11, 0xE9, 0xEF, 0xAC, 0xCC, 0x0C, 0x77, 0x38, 0x37, 0xC9, + 0x1C, 0x2D, 0x3A, 0x52, 0xE6, 0xC5, 0x58, 0x08, 0x9C, 0x6C, + 0xF7, 0xB7, 0x32, 0x87, 0xF3, 0xEC, 0x82, 0xB4, 0xF2, 0xE1, + 0x41, 0x45, 0x47, 0xDF, 0xEF, 0x43, 0xA2, 0x1A, 0x85, 0x40, + 0xEE, 0x16, 0x0E, 0x1B, 0x9E, 0x6C, 0x76, 0x6F, 0xA1, 0xBE, + 0xB9, 0xBA, 0x9F, 0xB3, 0xCD, 0x9E, 0x21, 0x25, 0xB5, 0x3C, + 0x62, 0xF9, 0xCA, 0x17, 0x02, 0xB1, 0xA6, 0xA4, 0xAA, 0x61, + 0x3D, 0xB4, 0xE1, 0x53, 0xD3, 0xB9, 0xCD, 0xCC, 0xD8, 0xE4, + 0xF7, 0x1D, 0xCD, 0x47, 0xEA, 0x02, 0xD1, 0xEF, 0x38, 0x13, + 0xDE, 0x9E, 0xBA, 0x0E, 0x0C, 0x01, 0x9E, 0x59, 0x6F, 0xF6, + 0x4E, 0x7E, 0x26, 0x08, 0xC6, 0x28, 0x66, 0xB2, 0x1C, 0x09, + 0xB5, 0x38, 0x6C, 0xB0, 0x87, 0xB6, 0xB4, 0x4B, 0x86, 0x68, + 0x47, 0x1E, 0xB9, 0x36, 0x44, 0xA9, 0x36, 0x71, 0xA0, 0x0F, + 0xEC, 0x88, 0x90, 0x78, 0x49, 0xD1, 0x6A, 0xAE, 0x51, 0xEC, + 0x8C, 0x0A, 0xB2, 0x6D, 0xD7, 0xA3, 0xD7, 0xF3, 0xF9, 0x98, + 0x5E, 0x4A, 0x42, 0xD1, 0x51, 0xED, 0x46, 0xB0, 0x9B, 0x9F, + 0xF9, 0x60, 0xCA, 0x6A, 0x13, 0x04, 0x2D, 0x84, 0xE9, 0x19, + 0x3E, 0x08, 0x70, 0x41, 0x91, 0xF9, 0xC5, 0xB4, 0x97, 0xE2, + 0x01, 0x0A, 0x44, 0xAC, 0x2F, 0x55, 0xD1, 0x5C, 0x01, 0x68, + 0x52, 0x2A, 0x82, 0x20, 0xAA, 0x8D, 0xE6, 0xAA, 0x35, 0x4A, + 0x9C, 0xF2, 0x31, 0xCB, 0xB2, 0x55, 0x88, 0x7D, 0x3C, 0x04, + 0xAF, 0xFA, 0xC7, 0x18, 0x53, 0xDF, 0x42, 0x83, 0x2A, 0x45, + 0x20, 0x89, 0xFD, 0x1A, 0xA8, 0x96, 0x75, 0x64, 0x69, 0x7A, + 0x30, 0xFB, 0x2F, 0x44, 0xE6, 0x94, 0xDC, 0x2C, 0x68, 0xD0, + 0xD1, 0x28, 0x50, 0xFD, 0xA0, 0x71, 0x2D, 0x9F, 0xD0, 0x07, + 0x8C, 0xB7, 0xE5, 0x36, 0xD4, 0xC6, 0x30, 0x26, 0xA3, 0xCC, + 0x47, 0x77, 0x5E, 0x6E, 0xE5, 0xE9, 0x22, 0x94, 0x88, 0xFB, + 0x6E, 0x80, 0x67, 0xAC, 0xA8, 0x59, 0x06, 0xF4, 0xE4, 0xAF, + 0x60, 0xF3, 0x07, 0x17, 0x0E, 0x18, 0x95, 0x69, 0x5B, 0xD9, + 0xE2, 0xC8, 0xA2, 0x13, 0x7F, 0xD1, 0xED, 0x9D, 0x20, 0x91, + 0x52, 0xEF, 0x69, 0x60, 0x25, 0xFC, 0x3C, 0xA6, 0x40, 0x22, + 0x29, 0xAC, 0x04, 0x0B, 0x95, 0x03, 0x19, 0xEF, 0xAE, 0x3B, + 0x59, 0x26, 0x65, 0x12, 0x48, 0x28, 0xBD, 0xC6, 0x92, 0xF4, + 0xA5, 0x98, 0x0E, 0xB6, 0x4C, 0x0F, 0x7E, 0xCD, 0xFA, 0x3D, + 0xE9, 0x5C, 0x4E, 0xED, 0xC1, 0xBC, 0xDE, 0xC5, 0x1D, 0x6B, + 0x4F, 0x11, 0x3B, 0x9D, 0x73, 0x66, 0xB6, 0x4E, 0x89, 0x21, + 0xA8, 0x9E, 0xF8, 0x95, 0xCF, 0x48, 0x2D, 0xAF, 0x3A, 0xCC, + 0x61, 0x0B, 0x9B, 0xCF, 0xA1, 0x3A, 0x49, 0x67, 0x0B, 0x85, + 0xB0, 0x1C, 0x9D, 0x7A, 0x1B, 0x0A, 0xF4, 0xB1, 0x6B, 0xED, + 0x0E, 0x8B, 0x1C, 0x8F, 0x24, 0x7F, 0xFB, 0x41, 0xD6, 0x04, + 0xB1, 0x30, 0x5F, 0x02, 0xFB, 0x19, 0xCB, 0x02, 0x3C, 0xD6, + 0x5A, 0x5E, 0xB6, 0x5B, 0xA5, 0x30, 0xB2, 0xDB, 0x93, 0xDC, + 0x10, 0xC1, 0x78, 0x3C, 0x0F, 0x84, 0xFF, 0xD0, 0x11, 0x1A, + 0x96, 0xE7, 0x15, 0x2A, 0x73, 0x3A, 0x7A, 0xD9, 0x79, 0xF1, + 0x91, 0x02, 0x7D, 0xE0, 0x43, 0x7D, 0x7D, 0x16, 0x24, 0xB6, + 0xA5, 0x74, 0xF1, 0xB1, 0x83, 0xF3, 0x60, 0xDF, 0x3F, 0x07, + 0x73, 0x31, 0xB4, 0x6A, 0x64, 0x37, 0x59, 0xDC, 0x28, 0xBF, + 0x0C, 0x4C, 0x9D, 0x82, 0x5F, 0x48, 0x22, 0x3D, 0x48, 0xB7, + 0x1B, 0x5C, 0x89, 0x66, 0xAD, 0x78, 0xA2, 0xC0, 0x56, 0xA4, + 0x64, 0xCB, 0x01, 0x08, 0xC5, 0x10, 0xC7, 0x4A, 0x11, 0x9D, + 0xCD, 0x71, 0x97, 0x62, 0xFF, 0xAE, 0x71, 0x10, 0x2C, 0xEA, + 0xA6, 0xCA, 0x37, 0xAD, 0xD4, 0x6C, 0xBC, 0xB5, 0xE1, 0x39, + 0xF0, 0x86, 0x71, 0x7D, 0x31, 0xC5, 0x1D, 0x54, 0x1B, 0x79, + 0x2D, 0x82, 0x92, 0xDD, 0xE0, 0xAF, 0xB6, 0xBA, 0x80, 0x03, + 0xD2, 0x2F, 0xA7, 0xDE, 0x38, 0xDB, 0xEA, 0x98, 0x35, 0xE0, + 0x0C, 0xCA, 0xB6, 0x92, 0xBC, 0x32, 0xE3, 0x55, 0xB5, 0x42, + 0xDC, 0xB1, 0xF3, 0x6C, 0x24, 0xBE, 0xEB, 0xE3, 0x06, 0xC7, + 0xBA, 0xD0, 0x59, 0x7C, 0x46, 0xD5, 0xEC, 0x0E, 0xD8, 0x31, + 0x9D, 0x99, 0xB8, 0x99, 0x76, 0xBE, 0x36, 0x68, 0x66, 0x60, + 0x63, 0xA9, 0x83, 0x91, 0xD1, 0x1C, 0x10, 0x15, 0x2F, 0x4A, + 0x98, 0xC6, 0x61, 0xFA, 0x46, 0x9F, 0xE1, 0xED, 0x85, 0xD8, + 0x3C, 0x7A, 0xBF, 0xC7, 0x19, 0xDF, 0x82, 0x8D, 0xEC, 0xC5, + 0x1E, 0x5D, 0x25, 0x25, 0xC5, 0x13, 0x01, 0x36, 0xBA, 0xD1, + 0x9E, 0xE5, 0x7A, 0x3B, 0xFE, 0x12, 0xC4, 0x27, 0x33, 0xD2, + 0x79, 0xC6, 0x63, 0x64, 0x69, 0x7F, 0xE7, 0x70, 0xC5, 0xDC, + 0xBF, 0xBF, 0x4D, 0x1D, 0x33, 0x80, 0xEF, 0x9A, 0x41, 0x5C, + 0x4E, 0x90, 0x30, 0x32, 0xC0, 0x35, 0xF9, 0xFA, 0x64, 0x2B, + 0x76, 0x15, 0x16, 0x3C, 0x6C, 0x93, 0x91, 0x7A, 0x1C, 0x0C, + 0xEA, 0xA7, 0xC5, 0x7A, 0xF3, 0x01, 0xB9, 0xE4, 0x6A, 0x05, + 0x2B, 0x27, 0x74, 0x63, 0xB3, 0x44, 0xB6, 0x15, 0x80, 0xED, + 0x76, 0xDC, 0x70, 0x77, 0x8A, 0xA9, 0xA7, 0x97, 0x11, 0xDC, + 0xDA, 0x58, 0x52, 0x18, 0xAE, 0x2C, 0x20, 0xD0, 0x6F, 0xF7, + 0xA4, 0x4D, 0xDA, 0x5A, 0xE6, 0xE5, 0x3A, 0x22, 0xE5, 0x1F, + 0xD7, 0x35, 0xA0, 0x0D, 0x76, 0x7A, 0x70, 0x2B, 0x63, 0xCC, + 0xBA, 0x51, 0x90, 0x3B, 0xD4, 0xAF, 0xA8, 0x5F, 0x9D, 0xB8, + 0xF5, 0xDA, 0x07, 0xFD, 0x34, 0x12, 0xA5, 0x55, 0x85, 0x46, + 0xE1, 0x99, 0x33, 0xA7, 0x01, 0xC7, 0xD8, 0x6B, 0x82, 0x06, + 0xB5, 0xA0, 0xD2, 0x46, 0x52, 0x23, 0x9C, 0x8C, 0x34, 0xC9, + 0x60, 0xC9, 0x69, 0x39, 0x31, 0xED, 0x30, 0x99, 0x9F, 0x37, + 0x42, 0x66, 0xBD, 0x14, 0x9E, 0xDF, 0xBF, 0xF2, 0xE7, 0x5F, + 0x3A, 0x8E, 0xD2, 0xA1, 0xB0, 0x1B, 0xF3, 0xE7, 0x8B, 0xC6, + 0x6C, 0xBA, 0x34, 0x16, 0xB3, 0x43, 0x89, 0x3F, 0x31, 0x88, + 0x6F, 0x4F, 0xE1, 0x12, 0x5D, 0x31, 0x9F, 0x33, 0xA6, 0x63, + 0x4C, 0xAF, 0x7E, 0x57, 0x76, 0xD4, 0x40, 0x49, 0x39, 0xED, + 0xAD, 0x36, 0x16, 0xDC, 0xF3, 0xC3, 0xE1, 0x65, 0x36, 0x13, + 0xB6, 0xD2, 0x85, 0xCD, 0xEA, 0xAC, 0xFD, 0x5E, 0x34, 0x43, + 0xCC, 0xB6, 0xF9, 0x6A, 0x5E, 0xC2, 0xF7, 0x7D, 0xB4, 0x54, + 0xA6, 0x65, 0x1C, 0x1F, 0x67, 0x1C, 0x81, 0xEE, 0x46, 0x16, + 0xBA, 0xA8, 0x55, 0xBE, 0x64, 0x71, 0xF4, 0x9E, 0x3F, 0x6F, + 0x3C, 0xF6, 0x24, 0xD9, 0xDD, 0x86, 0x69, 0x64, 0x9A, 0xCD, + 0x09, 0x43, 0x0E, 0x11, 0x41, 0x09, 0xC4, 0x4A, 0x62, 0x18, + 0x6A, 0xEB, 0x67, 0xE2, 0xCE, 0xA9, 0x2C, 0x8C, 0x18, 0x8B, + 0xD6, 0xBE, 0xDB, 0x35, 0xDD, 0x95, 0xE9, 0x02, 0xD8, 0xD2, + 0xF6, 0x33, 0x3C, 0xBF, 0x50, 0xEE, 0x34, 0x35, 0xD2, 0x1A, + 0xBE, 0x5A, 0x1C, 0x6A, 0x16, 0xB3, 0x73, 0x9C, 0xA1, 0xFE, + 0xDF, 0xC8, 0xC4, 0x52, 0x04, 0xA9, 0x1C, 0x1D, 0x7E, 0x63, + 0xAB, 0xAA, 0x3E, 0xD9, 0x7D, 0x1F, 0x6B, 0xE5, 0x9F, 0xA9, + 0x12, 0x45, 0x43, 0xAE, 0xC6, 0x2C, 0x5F, 0x7F, 0xE2, 0x99, + 0xB2, 0x65, 0x50, 0xBC, 0x87, 0x2F, 0x48, 0x12, 0x4F, 0xA4, + 0x26, 0xDE, 0xC0, 0x7E, 0x21, 0xB6, 0x55, 0x36, 0x74, 0x5E, + 0xD2, 0x7B, 0xF9, 0x24, 0x32, 0xAE, 0x7D, 0x33, 0xA7, 0x70, + 0x4D, 0xDF, 0xC1, 0x52, 0xF2, 0xFA, 0xEC, 0x0C, 0x44, 0xA1, + 0x6F, 0x2E, 0x19, 0xFA, 0x14, 0x3C, 0xF1, 0xD8, 0x09, 0xF9, + 0xD6, 0xAC, 0x51, 0x76, 0xAF, 0x57, 0x43, 0xBB, 0xDF, 0xF6, + 0xD3, 0x7F, 0xE0, 0xAF, 0x22, 0x2C, 0x3E, 0xE6, 0x68, 0xA7, + 0x33, 0x1D, 0x8F, 0x8A, 0x45, 0x1C, 0x8C, 0xB5, 0x5E, 0xF9, + 0x8F, 0x76, 0x6C, 0xB8, 0x8E, 0x2B, 0xCE, 0x07, 0x00, 0x3B, + 0x53, 0xD4, 0x42, 0x3A, 0x6F, 0x5F, 0xD4, 0xFB, 0x11, 0xE8, + 0x89, 0x7B, 0xE9, 0x6C, 0x5F, 0xD8, 0xCD, 0x55, 0x78, 0xBA, + 0xBD, 0xF3, 0x48, 0xE0, 0xBD, 0xE0, 0x65, 0xF7, 0x02, 0xAA, + 0x12, 0xBF, 0xCB, 0xA2, 0x97, 0x77, 0xDD, 0x69, 0x95, 0x5B, + 0x05, 0x95, 0xFB, 0x35, 0xCF, 0xEA, 0x34, 0x4D, 0xEC, 0xBB, + 0x8E, 0x31, 0xF9, 0x07, 0xB0, 0x37, 0xB4, 0x14, 0xE1, 0x1A, + 0x7F, 0x6F, 0x3A, 0xA7, 0x8A, 0x37, 0xB3, 0x42, 0x7C, 0x2E, + 0x67, 0x20, 0xC3, 0x01, 0xF8, 0xD7, 0x00, 0x9B, 0x44, 0x53, + 0x69, 0xC5, 0x2A, 0x10, 0xCC, 0x8C, 0xA6, 0x33, 0x60, 0x2E, + 0x7C, 0xE1, 0x70, 0xE9, 0x51, 0x3C, 0xEA, 0xA3, 0x65, 0x84, + 0x15, 0xE8, 0x2A, 0x17, 0xA3, 0x2C, 0xF1, 0x8A, 0xF3, 0x86, + 0x1A, 0xDF, 0xBE, 0x71, 0x31, 0x95, 0x35, 0xF2, 0x5D, 0xAE, + 0xA7, 0x31, 0xDE, 0x6F, 0x13, 0x61, 0x71, 0x58, 0x2A, 0x76, + 0x16, 0xCE, 0x4A, 0x92, 0x10, 0x20, 0x1F, 0xC1, 0x3E, 0x36, + 0xAB, 0xEF, 0xD8, 0x99, 0x81, 0xAC, 0xFB, 0xBD, 0x92, 0x2D, + 0x67, 0xFE, 0xB5, 0x75, 0xB8, 0x45, 0x72, 0x55, 0x96, 0xF5, + 0x85, 0xFA, 0xCE, 0x79, 0x45, 0xB7, 0xD6, 0x94, 0xEE, 0x8B, + 0x74, 0xD0, 0xFD, 0x83, 0x3E, 0xF2, 0x83, 0x5D, 0xC7, 0x15, + 0xD0, 0xDD, 0x8F, 0x93, 0x82, 0x2E, 0x0C, 0x6B, 0x3A, 0xB4, + 0xCE, 0xF4, 0xC3, 0xC3, 0x02, 0xC5, 0x9F, 0x87, 0xA0, 0x5C, + 0xAD, 0x09, 0x6C, 0xE5, 0xD7, 0xAC, 0xBB, 0x0A, 0xF0, 0xD4, + 0x77, 0x04, 0x9A, 0x42, 0xD3, 0xE5, 0x9E, 0x3A, 0x0A, 0x62, + 0x25, 0x11, 0x4B, 0x7B, 0x6D, 0x50, 0x5D, 0xD1, 0x73, 0x3D, + 0x92, 0x62, 0x7E, 0x3B, 0x07, 0xA2, 0xD9, 0xE9, 0x51, 0x5A, + 0x1A, 0x3A, 0xC2, 0x36, 0x30, 0x3E, 0x75, 0xA0, 0xA8, 0xCF, + 0x60, 0x31, 0x27, 0x4E, 0xE4, 0x2F, 0xB2, 0x5C, 0x3D, 0x18, + 0x9B, 0xC1, 0x21, 0x75, 0x4D, 0x08, 0x22, 0xD1, 0xB0, 0xED, + 0xBF, 0x59, 0x9B, 0x49, 0x9A, 0xDD, 0xFB, 0x62, 0x3A, 0xA8, + 0x61, 0x34, 0xA5, 0x3D, 0x64, 0x56, 0x60, 0xD2, 0x16, 0x32, + 0xA4, 0x38, 0xD1, 0xFC, 0x45, 0x37, 0x49, 0xD6, 0x8C, 0x5B, + 0x49, 0x02, 0x18, 0x2E, 0x35, 0x47, 0x99, 0xF4, 0x61, 0xF8, + 0x70, 0x6D, 0xF6, 0xCF, 0xCA, 0x9E, 0x79, 0x02, 0x8F, 0x04, + 0x50, 0x7E, 0xC1, 0x33, 0x1B, 0x63, 0xDD, 0xF1, 0x0A, 0x09, + 0x85, 0xF5, 0x2F, 0x96, 0x30, 0x24, 0x51, 0xFF, 0x77, 0x2D, + 0x25, 0x91, 0xFE, 0xD9, 0x37, 0xD0, 0x83, 0x8D, 0xE9, 0x8E, + 0xE7, 0xF5, 0xD5, 0x40, 0x20, 0xDB, 0x24, 0x34, 0x7B, 0xAA, + 0x32, 0xC6, 0xFC, 0xD2, 0xCC, 0xB9, 0xC9, 0x9A, 0x03, 0xF5, + 0xE1, 0x6C, 0x56, 0x16, 0x0D, 0xCE, 0x8A, 0x5B, 0xFB, 0x20, + 0xDE, 0xCF, 0x87, 0x20, 0xF5, 0xFE, 0x6C, 0x85, 0x77, 0x1C, + 0xCE, 0x50, 0xA3, 0x67, 0xAE, 0x26, 0x2C, 0x33, 0x93, 0xB6, + 0xD4, 0x92, 0xFE, 0x6A, 0x94, 0x56, 0xDB, 0xBB, 0xD4, 0x45, + 0x18, 0x84, 0x32, 0x29, 0x48, 0xE7, 0xB7, 0x1C, 0x98, 0xBA, + 0x52, 0x26, 0x1D, 0xA4, 0x37, 0x95, 0x90, 0x0A, 0xD2, 0x9D, + 0x03, 0x51, 0x9A, 0x9F, 0x4E, 0x53, 0x1A, 0x85, 0x81, 0x25, + 0x05, 0x25, 0x0A, 0x6A, 0x03, 0x15, 0x4A, 0x5A, 0x33, 0x8F, + 0x8E, 0xE8, 0x09, 0x10, 0xA8, 0x10, 0xCE, 0x81, 0xD4, 0xB2, + 0x6B, 0x04, 0x26, 0xA2, 0xE5, 0x3A, 0x1B, 0x23, 0x5C, 0x89, + 0x61, 0xC2, 0x5B, 0x74, 0xA7, 0xA0, 0x68, 0x5A, 0xB4, 0xAB, + 0x71, 0xC4, 0x8C, 0x61, 0xD2, 0x0A, 0x22, 0xFB, 0x00, 0x6C, + 0x0A, 0x04, 0xAA, 0xDF, 0xBE, 0x4A, 0x47, 0x43, 0x5B, 0x71, + 0x8D, 0x0D, 0x70, 0x3D, 0x27, 0xFC, 0x4D, 0x71, 0x61, 0x39, + 0x09, 0xEF, 0xD6, 0x68, 0x34, 0xF3, 0x55, 0x45, 0xEF, 0xEF, + 0xE3, 0x71, 0x3A, 0x46, 0x02, 0xE0, 0x3B, 0x9F, 0x3B, 0xDC, + 0xCA, 0x6F, 0x63, 0x64, 0x96, 0x3C, 0x3C, 0x4D, 0x43, 0xA2, + 0x4E, 0x28, 0x99, 0x9C, 0xDB, 0x69, 0x96, 0x53, 0x1E, 0xDD, + 0xE9, 0x22, 0x56, 0x8B, 0x81, 0x8A, 0xBD, 0x41, 0xB2, 0x02, + 0xA8, 0xA3, 0xE5, 0xF0, 0x3F, 0x6B, 0x9C, 0x97, 0xA1, 0x46, + 0xED, 0x20, 0x66, 0x56, 0x01, 0xBA, 0x35, 0xEB, 0x2D, 0x54, + 0x38, 0x5F, 0x48, 0x18, 0x60, 0xF5, 0x5F, 0x32, 0xDA, 0x3D, + 0xDD, 0xF0, 0xF8, 0xC2, 0x81, 0x4D, 0x52, 0x3E, 0xD2, 0xDD, + 0x28, 0x00, 0xA2, 0x41, 0x3C, 0x0A, 0x11, 0x20, 0xD5, 0x84, + 0x21, 0x93, 0x88, 0x8F, 0xD3, 0x18, 0xCC, 0x41, 0xE5, 0x5B, + 0x60, 0x45, 0x9F, 0x20, 0x47, 0xE6, 0x8A, 0x8E, 0x48, 0x71, + 0x98, 0x69, 0x63, 0x8A, 0x08, 0x59, 0x96, 0x4C, 0xC8, 0x47, + 0xD8, 0x2B, 0x42, 0xEE, 0x52, 0x0A, 0x95, 0x3C, 0x95, 0xC2, + 0x64, 0x6C, 0x17, 0x8D, 0xCF, 0x43, 0x1F, 0x23, 0x94, 0x45, + 0xD0, 0xB5, 0x6B, 0x2E, 0x73, 0xBC, 0x80, 0xEA, 0xF5, 0x18, + 0x3E, 0x86, 0x94, 0x41, 0x90, 0xCA, 0x51, 0x38, 0x51, 0xD1, + 0x2B, 0x0C, 0xC2, 0xF3, 0x0A, 0x15, 0x98, 0xB9, 0x96, 0x81, + 0x4D, 0x23, 0xC4, 0xF4, 0xA3, 0xE7, 0x1E, 0xBA, 0x2E, 0x6B, + 0xD0, 0x2B, 0x2F, 0x4B, 0xB8, 0xD3, 0x28, 0x08, 0xF4, 0x10, + 0x1A, 0xEA, 0xE4, 0xD7, 0xC0, 0x03, 0x9A, 0x18, 0x09, 0x0E, + 0xCC, 0x9C, 0xB1, 0xE8, 0x02, 0xFF, 0x17, 0x5B, 0x7D, 0xF5, + 0x67, 0xD9, 0x83, 0x40, 0x7B, 0x04, 0x1F, 0x85, 0xB8, 0x4A, + 0x28, 0x6C, 0x26, 0x20, 0x97, 0xFD, 0xA0, 0xDF, 0xBC, 0x41, + 0x66, 0x04, 0x2F, 0x11, 0x57, 0xBE, 0xBA, 0x8F, 0xB9, 0x04, + 0x2F, 0xFD, 0x9D, 0x81, 0x94, 0x9A, 0x82, 0x7A, 0x18, 0xD3, + 0xD2, 0x72, 0xAA, 0x52, 0x18, 0xE6, 0x70, 0xE7, 0xD1, 0xA0, + 0x10, 0x11, 0x8D, 0xF8, 0xDD, 0x60, 0xC0, 0x0A, 0x9E, 0x42, + 0x38, 0xCF, 0xA4, 0xFD, 0x2C, 0xA0, 0xC9, 0x51, 0xC0, 0x6D, + 0xC7, 0x04, 0x74, 0x6B, 0x96, 0xAE, 0x49, 0x44, 0xEA, 0x27, + 0x0C, 0xE0, 0x63, 0x11, 0x90, 0xB6, 0xDC, 0xC7, 0x90, 0x18, + 0x28, 0x6C, 0x33, 0xFE, 0x7A, 0x88, 0x7C, 0xF6, 0x24, 0x59, + 0x8C, 0xFF, 0x3B, 0xE9, 0xCC, 0x6D, 0xB4, 0x7E, 0xCC, 0x0A, + 0x33, 0x24, 0xFC, 0x96, 0xBF, 0x45, 0x2E, 0x07, 0xBF, 0xA5, + 0x14, 0x7B, 0x85, 0x92, 0x8A, 0x1D, 0xDF, 0x8E, 0x4C, 0xB6, + 0x71, 0x54, 0xFC, 0x52, 0xD1, 0x8D, 0xF5, 0xF5, 0x3E, 0x2C, + 0xD6, 0xC2, 0xA7, 0x66, 0x58, 0x36, 0xCE, 0x19, 0x28, 0x0B, + 0xD1, 0xC6, 0x5E, 0xB2, 0xE5, 0x76, 0x5B, 0x71, 0x42, 0x1F, + 0xAF, 0xFB, 0xDB, 0xF0, 0xA6, 0x8F, 0x62, 0x26, 0xDE, 0xA2, + 0x3D, 0x29, 0xDB, 0xF8, 0xCE, 0xBB, 0xB1, 0x21, 0xB8, 0x60, + 0x3C, 0x47, 0x08, 0x1A, 0x3F, 0x2F, 0x50, 0x71, 0xDE, 0x7D, + 0x8E, 0x8E, 0xEB, 0xFB, 0x0D, 0x8F, 0x3A, 0x23, 0x54, 0x8C, + 0x11, 0x28, 0x97, 0xAE, 0xF8, 0xBE, 0x7B, 0x53, 0x9F, 0x54, + 0x2E, 0x5C, 0x67, 0x11, 0x46, 0x4C, 0x80, 0x8F, 0x4D, 0xE5, + 0xDE, 0xF7, 0xFD, 0x78, 0xFA, 0xCD, 0xE5, 0x9F, 0x82, 0x75, + 0x35, 0x71, 0xD4, 0xBA, 0x9A, 0x11, 0x69, 0xF9, 0xC6, 0xAA, + 0x31, 0xC4, 0xA5, 0xE2, 0xC3, 0x27, 0x24, 0x4A, 0xA8, 0x63, + 0xD1, 0x9A, 0x37, 0xB1, 0x33, 0x80, 0x09, 0xD0, 0x3A, 0xE5, + 0xBB, 0xAF, 0x80, 0xC6, 0xEF, 0x30, 0x14, 0x48, 0x10, 0x2C, + 0xC0, 0x5A, 0x74, 0xAB, 0xE7, 0x27, 0xD9, 0x13, 0x63, 0xCC, + 0x37, 0x54, 0x20, 0x8C, 0x0E, 0x47, 0xAE, 0x0C, 0x2A, 0xB2, + 0xFC, 0x34, 0xE7, 0x48, 0x2E, 0x6A, 0x99, 0xBF, 0x30, 0x34, + 0xEF, 0x9A, 0x84, 0xBB, 0x07, 0xC1, 0x66, 0x2E, 0x9B, 0xD2, + 0x12, 0xE0, 0x02, 0xC7, 0x75, 0x27, 0x91, 0x3A, 0xD7, 0x4D, + 0x36, 0x8A, 0x6F, 0x79, 0x51, 0xEF, 0xAE, 0x02, 0xE3, 0x03, + 0x3B, 0x65, 0x80, 0x0C, 0x99, 0xA8, 0x2E, 0x9E, 0xE8, 0xE9, + 0x66, 0x11, 0xA2, 0x7C, 0xE5, 0x31, 0x2F, 0x5A, 0x9C, 0x99, + 0xD5, 0x7F, 0x0C, 0xE2, 0x1C, 0x21, 0x86, 0x3F, 0xDE, 0x46, + 0x5E, 0x92, 0x9C, 0x74, 0x5A, 0x8D, 0xBF, 0xED, 0xC1, 0xC1, + 0xCF, 0xA0, 0x59, 0xDB, 0x2A, 0xC0, 0x0A, 0x9C, 0xDA, 0x78, + 0x81, 0x6F, 0xD9, 0x49, 0x62, 0xCE, 0x70, 0x0F, 0x65, 0x1B, + 0xE7, 0x26, 0x42, 0x90, 0x0F, 0xD9, 0xD9, 0x92, 0xCC, 0xE8, + 0xD6, 0x48, 0x1D, 0xDE, 0x71, 0xE0, 0x71, 0xDA, 0xDB, 0x4B, + 0x34, 0x8D, 0xDD, 0x68, 0x99, 0x60, 0x47, 0x52, 0x7C, 0x2F, + 0x3F, 0x52, 0xAD, 0x8A, 0x24, 0x2B, 0xF2, 0x48, 0x1F, 0x24, + 0x66, 0x58, 0xE4, 0xA9, 0x1B, 0x88, 0x32, 0x14, 0x79, 0xFF, + 0x42, 0x3B, 0xDE, 0x72, 0xDD, 0x0C, 0xF9, 0xBA, 0x20, 0xF3, + 0xC4, 0x56, 0x2B, 0x38, 0x9C, 0xEC, 0x6E, 0x55, 0xF9, 0xC6, + 0x76, 0x61, 0xC8, 0x05, 0x49, 0xAF, 0x7D, 0x25, 0x76, 0xC1, + 0xE1, 0xAE, 0x36, 0x5C, 0x15, 0x37, 0xAF, 0x16, 0xEB, 0x79, + 0xE0, 0xC7, 0x39, 0xA5, 0xBA, 0x03, 0x07, 0x45, 0xA6, 0x62, + 0x20, 0x38, 0x7E, 0x7D, 0x7E, 0x1F, 0x71, 0x20, 0xA3, 0xFF, + 0x98, 0xD4, 0x18, 0x7C, 0x56, 0xFB, 0xE1, 0xF3, 0x46, 0x4C, + 0x1B, 0x55, 0x44, 0xE7, 0xD8, 0x38, 0x18, 0xF9, 0x31, 0x7B, + 0xAC, 0xCF, 0x03, 0xCB, 0xC8, 0x5A, 0x75, 0x96, 0x5A, 0x82, + 0xCC, 0x5D, 0x70, 0x6B, 0x07, 0x19, 0x38, 0x9A, 0x35, 0x4B, + 0x09, 0x64, 0xF4, 0xCB, 0x56, 0x1B, 0xF4, 0xED, 0x0B, 0x26, + 0x90, 0x78, 0xCA, 0x89, 0xBF, 0x62, 0x63, 0x12, 0x17, 0x1E, + 0xEE, 0x81, 0x11, 0x15, 0xC6, 0x1B, 0xEA, 0x2D, 0xA6, 0xBF, + 0xA9, 0x7F, 0x7E, 0x0B, 0x1E, 0x56, 0x09, 0xF5, 0xEF, 0x4F, + 0xC8, 0xE5, 0xD4, 0x14, 0xB1, 0xDE, 0xD5, 0x95, 0xFA, 0xC4, + 0x89, 0x45, 0x4F, 0x5D, 0x3E, 0x47, 0xF0, 0xD9, 0xF0, 0x2F, + 0xAF, 0xC1, 0xF3, 0x8B, 0xD7, 0xF7, 0x40, 0x39, 0xE2, 0xC2, + 0xC8, 0x88, 0x56, 0x4C, 0xA4, 0x8F, 0x92, 0x2F, 0x0C, 0x21, + 0x37, 0xB5, 0x9D, 0xCA, 0x17, 0x88, 0x25, 0x88, 0xF3, 0xEB, + 0xE0, 0xCF, 0x45, 0xC1, 0x36, 0x09, 0xB8, 0x54, 0xD6, 0xE0, + 0xF1, 0x54, 0x0A, 0xC7, 0xD2, 0x57, 0xB0, 0x5D, 0xDF, 0xAD, + 0xF8, 0xB2, 0x02, 0xE3, 0x85, 0xFF, 0x73, 0xE6, 0x92, 0x5D, + 0x12, 0xBE, 0x5F, 0x67, 0x0A, 0x29, 0x93, 0x19, 0x0B, 0xEF, + 0xF8, 0x45, 0x00, 0x94, 0x09, 0xDB, 0xAB, 0xFF, 0x90, 0x61, + 0xC8, 0x10, 0x52, 0x66, 0x6A, 0x59, 0xAA, 0x3A, 0xAB, 0x49, + 0x91, 0x0B, 0xC8, 0x13, 0x9A, 0x63, 0x4E, 0xC1, 0xD2, 0xF6, + 0x8A, 0x21, 0xD6, 0xDB, 0xE1, 0x19, 0x27, 0xCE, 0xBF, 0x21, + 0x4B, 0x1B, 0x13, 0x44, 0x13, 0x78, 0x19, 0xB2, 0xBF, 0x4A, + 0x61, 0x80, 0x5B, 0xDF, 0x7B, 0x83, 0x8F, 0x01, 0xE5, 0xF7, + 0xF8, 0x9D, 0xFE, 0x17, 0x38, 0x9D, 0xBD, 0x4B, 0x2B, 0x48, + 0xAE, 0xBB, 0xCE, 0xD4, 0xDB, 0xD8, 0x33, 0x7A, 0xC1, 0xB6, + 0x06, 0x22, 0xB1, 0xD8, 0x9B, 0xFA, 0x87, 0xD0, 0x0E, 0xA1, + 0x9D, 0xD7, 0xA1, 0x0A, 0xA2, 0x3D, 0xE3, 0x1B, 0x43, 0xE9, + 0x88, 0x82, 0x7D, 0xA7, 0xDA, 0x5B, 0x46, 0x03, 0x7E, 0xA5, + 0x9B, 0x46, 0x0C, 0x67, 0xD3, 0x45, 0xCA, 0x7F, 0x00, 0x23, + 0xB7, 0xBE, 0xDC, 0x1D, 0xE5, 0x0B, 0x80, 0x1D, 0x8D, 0x74, + 0x03, 0xBE, 0xE6, 0xA3, 0xF9, 0x1A, 0xDC, 0xD1, 0xB9, 0x08, + 0x62, 0xDF, 0xE9, 0xBC, 0xAF, 0x5A, 0x7D, 0x3F, 0x1C, 0xED, + 0xE1, 0x23, 0x54, 0x6D, 0x18, 0xEA, 0x91, 0x4B, 0x47, 0x98, + 0xC6, 0xE6, 0xDA, 0x99, 0x13, 0x6B, 0xCF, 0x6D, 0x56, 0xCF, + 0xA1, 0x8D, 0xDE, 0x3C, 0x3B, 0x1F, 0x28, 0xD4, 0x3F, 0x13, + 0xD8, 0x91, 0x8C, 0x68, 0xA2, 0xC7, 0x94, 0x4D, 0xD6, 0x7E, + 0x68, 0x89, 0xAA, 0x37, 0x95, 0xF3, 0xEC, 0x0E, 0x6B, 0xD3, + 0xC0, 0x25, 0xA1, 0x43, 0x5C, 0x26, 0x30, 0x5A, 0xE0, 0x77, + 0x0E, 0x07, 0xC3, 0x04, 0xE2, 0x50, 0x2F, 0x29, 0x30, 0x4A, + 0x42, 0x66, 0xD0, 0xE8, 0x1C, 0x4B, 0x5A, 0xE2, 0x78, 0xF8, + 0xAC, 0x65, 0xE2, 0x2D, 0x4B, 0xB1, 0x4F, 0x79, 0x3E, 0xF7, + 0x4A, 0x96, 0x2C, 0x0D, 0xA7, 0xE1, 0x15, 0x08, 0xB0, 0xF8, + 0x79, 0x94, 0xDC, 0x1D, 0xFE, 0x73, 0x44, 0xBE, 0x8B, 0x10, + 0x26, 0x24, 0xB7, 0x10, 0xD1, 0x23, 0xBA, 0x2E, 0x86, 0x12, + 0x35, 0x77, 0x6E, 0x80, 0xAA, 0x21, 0x91, 0x83, 0x28, 0x8F, + 0x23, 0xAF, 0x48, 0xAA, 0xA8, 0xA7, 0x36, 0xBA, 0x1A, 0xB3, + 0xDC, 0x08, 0x12, 0x01, 0x49, 0xFE, 0xFE, 0x64, 0xD1, 0x5B, + 0x66, 0x57, 0x78, 0x22, 0xCC, 0x1B, 0xA3, 0xBB, 0x17, 0x1B, + 0x2C, 0x65, 0xDE, 0xDF, 0xAB, 0xC9, 0xC7, 0xCF, 0x69, 0x80, + 0xD0, 0xB1, 0x71, 0xF0, 0xB4, 0x29, 0xAA, 0x93, 0x4C, 0x3E, + 0x6E, 0xDE, 0x41, 0x19, 0xFF, 0x78, 0x6B, 0xE5, 0x8F, 0x00, + 0x02, 0x82, 0x56, 0x95, 0x1E, 0x62, 0x73, 0xAA, 0x17, 0x5E, + 0x5A, 0x1D, 0x22, 0xAB, 0x51, 0xE7, 0xD0, 0x14, 0x7A, 0xDE, + 0x23, 0x4D, 0x6F, 0x24, 0xE6, 0xFD, 0x77, 0x7C, 0x24, 0x1B, + 0xB4, 0x2C, 0x5F, 0x1F, 0x02, 0x0F, 0xD1, 0x58, 0xE5, 0xB7, + 0x87, 0x41, 0xB9, 0xEA, 0x6C, 0x0F, 0xFE, 0x19, 0xC6, 0x9B, + 0x89, 0x2D, 0xB3, 0xB3, 0xE9, 0x81, 0x6D, 0xB1, 0x27, 0xED, + 0xFA, 0x73, 0xB8, 0x1F, 0xBF, 0x43, 0xBC, 0x9C, 0xAF, 0x78, + 0x3E, 0x06, 0xB9, 0x8B, 0xF3, 0x2D, 0x19, 0x31, 0xD6, 0xFC, + 0x8B, 0x3D, 0x0A, 0xA9, 0x52, 0x33, 0xB8, 0xF6, 0x09, 0x3A, + 0x46, 0x8A, 0xD1, 0x06, 0xE4, 0xAF, 0xFD, 0xA6, 0xA5, 0x59, + 0x25, 0x47, 0xC7, 0xB8, 0x26, 0xC9, 0x9F, 0xED, 0xB1, 0xF4, + 0x2B, 0x2A, 0xD3, 0x75, 0x71, 0x5F, 0x29, 0xE2, 0xC3, 0x8F, + 0x14, 0xAF, 0x39, 0x07, 0x84, 0x79, 0xF6, 0xA1, 0x62, 0x12, + 0x8E, 0x17, 0x5B, 0xA4, 0x93, 0x4F, 0x2D, 0x7A, 0xCF, 0x6D, + 0x58, 0xC7, 0xFB, 0xF6, 0xC3, 0x3C, 0x19, 0x20, 0x21, 0xB7, + 0xCA, 0xD2, 0xE5, 0x8C, 0xF8, 0xB5, 0x05, 0x71, 0x9E, 0x7D, + 0xCF, 0xD0, 0x0A, 0xE0, 0xBC, 0xD2, 0x96, 0xCA, 0xE5, 0x85, + 0x38, 0x1D, 0x4F, 0x6A, 0xFD, 0x83, 0xA6, 0x3C, 0xFC, 0x70, + 0x18, 0xE7, 0x5D, 0xD3, 0xA9, 0xEF, 0xE1, 0x35, 0x19, 0x82, + 0xC0, 0x1D, 0x74, 0xAB, 0x28, 0x73, 0xC2, 0x10, 0x1A, 0x05, + 0x71, 0x3B, 0x2C, 0x06, 0xB3, 0x03, 0x6C, 0x9B, 0xDD, 0x1B, + 0x7E, 0x52, 0x82, 0x18, 0x8D, 0xEC, 0x99, 0xF2, 0x13, 0x62, + 0x0D, 0x54, 0x44, 0xDC, 0x2F, 0xD2, 0x4B, 0x61, 0x35, 0x7B, + 0xE6, 0x5A, 0x4D, 0x8F, 0x00, 0x7A, 0xB6, 0x01, 0x81, 0x5E, + 0x78, 0x11, 0x7D, 0x8B, 0x59, 0x4D, 0x7A, 0x9E, 0x70, 0x5C, + 0x39, 0xC1, 0xB9, 0x61, 0xEB, 0x30, 0xAD, 0x81, 0xC7, 0x68, + 0xA6, 0x98, 0x91, 0xB4, 0x25, 0xCF, 0x03, 0xC5, 0xA4, 0xF8, + 0x80, 0x5A, 0x12, 0xE2, 0x4D, 0x41, 0x56, 0xC6, 0x4E, 0x9A, + 0x59, 0x94, 0x11, 0x6B, 0xE8, 0x6D, 0x1B, 0x53, 0xFB, 0xC4, + 0x9D, 0xB3, 0x3B, 0xCF, 0xE3, 0x1A, 0x19, 0xEE, 0x18, 0x62, + 0xA1, 0x33, 0x6F, 0x92, 0x44, 0xD6, 0x1E, 0xE0, 0x92, 0xA5, + 0xF3, 0x73, 0x79, 0x98, 0xC3, 0xFB, 0x01, 0x71, 0x0C, 0x68, + 0x47, 0x57, 0x66, 0x07, 0x17, 0xC5, 0x4B, 0x62, 0x6C, 0xB4, + 0x9A, 0xB2, 0x71, 0x79, 0xCA, 0xCD, 0x63, 0x09, 0xA1, 0xAF, + 0x3D, 0x7B, 0x4F, 0x4C, 0xF3, 0x7D, 0xE5, 0x18, 0x99, 0xBA, + 0xDD, 0xA4, 0xD2, 0x66, 0x2E, 0xEF, 0xE2, 0xC1, 0x6F, 0x36, + 0xAC, 0xB7, 0xFE, 0x48, 0x9A, 0xF6, 0x79, 0xB9, 0x5D, 0x0A, + 0x4A, 0xE4, 0xC4, 0x85, 0xAB, 0x4D, 0xD5, 0xA0, 0x7A, 0x08, + 0x6C, 0x16, 0x90, 0xCC, 0x08, 0x02, 0x1B, 0xE5, 0x1F, 0x83, + 0xAC, 0x24, 0x62, 0x67, 0xB6, 0xA1, 0xEE, 0x18, 0xCE, 0xC4, + 0x81, 0x8B, 0xEB, 0x3A, 0x13, 0x98, 0x68, 0x56, 0x8D, 0x14, + 0x42, 0x3D, 0xA7, 0x18, 0x19, 0x01, 0xD9, 0x05, 0x3F, 0x21, + 0xE8, 0x21, 0x8A, 0x86, 0x91, 0x65, 0x0C, 0x01, 0x19, 0xE2, + 0xE4, 0x03, 0xA6, 0xE8, 0x95, 0x03, 0x89, 0x2C, 0x27, 0xD3, + 0x7B, 0x3E, 0x2C, 0xB6, 0x9D, 0x28, 0x65, 0x3C, 0x00, 0x88, + 0xD4, 0x3A, 0xC4, 0x01, 0x9A, 0x56, 0xFA, 0xBC, 0x94, 0xDC, + 0x66, 0xC4, 0x16, 0x49, 0xC2, 0x08, 0x37, 0x5A, 0xE7, 0x42, + 0x14, 0xBD, 0xF9, 0xC7, 0x9A, 0xD6, 0xF6, 0xB1, 0x58, 0xDF, + 0x73, 0xCE, 0x22, 0xD2, 0x92, 0xF9, 0x33, 0xE6, 0xAE, 0x7A, + 0x8F, 0xBA, 0xA6, 0x38, 0xBD, 0x5E, 0x35, 0x2C, 0x40, 0xF9, + 0xEA, 0xEB, 0x26, 0x5A, 0x18, 0xAA, 0x1C, 0x04, 0x1B, 0xAF, + 0xA0, 0x2C, 0xF5, 0x78, 0x0C, 0xA3, 0xDD, 0xAF, 0xDE, 0x2F, + 0x05, 0xC1, 0xBB, 0x8B, 0x55, 0x69, 0xAF, 0xAE, 0x1A, 0x81, + 0x48, 0xF2, 0x22, 0x11, 0x3A, 0x45, 0x92, 0xAB, 0x0B, 0xD1, + 0x07, 0x2E, 0xC6, 0x0D, 0xB8, 0x7E, 0x69, 0xC5, 0xB6, 0x33, + 0x01, 0x38, 0xFB, 0x08, 0x1D, 0x17, 0x0B, 0xF5, 0xD2, 0xCE, + 0x16, 0x9B, 0xA5, 0x30, 0xDB, 0xB2, 0xDB, 0x1F, 0x5B, 0xDA, + 0xBD, 0x27, 0x40, 0x7A, 0x99, 0x31, 0x91, 0xE8, 0xDC, 0x46, + 0x84, 0xDD, 0x4A, 0x33, 0xE8, 0x7F, 0x36, 0x10, 0x94, 0xC2, + 0x51, 0xFC, 0xAD, 0x8C, 0xD8, 0x45, 0xE0, 0xD4, 0xBB, 0xAB, + 0x0E, 0xE5, 0x9A, 0x15, 0xD5, 0x9D, 0x89, 0x1A, 0x4D, 0xAD, + 0x56, 0x4C, 0x30, 0x3B, 0x17, 0x60, 0xAA, 0xD1, 0x82, 0xD8, + 0xD5, 0x16, 0x4E, 0xFE, 0xD7, 0xF1, 0x09, 0xF0, 0x76, 0x1B, + 0x97, 0xE2, 0x9E, 0x5F, 0x3A, 0x64, 0x44, 0x8D, 0x95, 0x08, + 0x37, 0x6F, 0x9F, 0xA3, 0x64, 0x2F, 0x6D, 0xBA, 0xAD, 0xAC, + 0xEC, 0xE3, 0x9B, 0x05, 0x67, 0xAB, 0xF4, 0x7E, 0x1E, 0x07, + 0xBC, 0x4F, 0x2E, 0xD9, 0xE4, 0x9F, 0xF0, 0xAC, 0x83, 0xCE, + 0x2C, 0xF0, 0x6C, 0x24, 0xE8, 0x79, 0xF5, 0x98, 0xA2, 0x21, + 0x0C, 0x84, 0xD6, 0xB2, 0xCD, 0x2F, 0x85, 0x17, 0x16, 0x87, + 0xE0, 0x09, 0x59, 0x84, 0x11, 0xEC, 0xC3, 0xF4, 0x2A, 0x0F, + 0x9C, 0x72, 0x6B, 0xC7, 0xF0, 0x41, 0x83, 0xE1, 0xEB, 0x50, + 0x38, 0xE5, 0x3F, 0x8E, 0xB4, 0xE8, 0x6C, 0xD4, 0x5A, 0xAD, + 0xB9, 0x2C, 0x0F, 0x27, 0x57, 0x05, 0xD3, 0x92, 0xE2, 0x4D, + 0xA7, 0x4C, 0x11, 0xC8, 0xE6, 0x5F, 0x46, 0xDE, 0xE1, 0x23, + 0xA3, 0xE4, 0x18, 0x91, 0x40, 0xC6, 0xD1, 0x3B, 0x1F, 0x6B, + 0xFC, 0x6C, 0x52, 0x40, 0xC1, 0x8D, 0x3B, 0x2E, 0xEE, 0xF4, + 0xB0, 0xCB, 0x60, 0x97, 0xC5, 0x86, 0x6E, 0xF2, 0x51, 0x43, + 0xD4, 0x2B, 0xD2, 0x5E, 0x06, 0xAD, 0xFF, 0x13, 0x89, 0x08, + 0xFF, 0xE8, 0x6E, 0xCD, 0x56, 0x89, 0x22, 0xED, 0xB8, 0xC6, + 0x13, 0x97, 0x89, 0x9E, 0xB3, 0x53, 0xA2, 0xED, 0x91, 0xD9, + 0x00, 0x0F, 0xDB, 0x55, 0xA6, 0xE9, 0x77, 0x85, 0xCE, 0x3B, + 0x3E, 0x0E, 0x9F, 0xB2, 0x91, 0x73, 0x01, 0x87, 0x41, 0x14, + 0x39, 0x38, 0x5D, 0xB2, 0xF6, 0xE8, 0xEB, 0x5F, 0xB3, 0xC8, + 0xB9, 0x1C, 0x0D, 0x9E, 0x28, 0xD9, 0x39, 0xF7, 0x0C, 0x6D, + 0xE5, 0x9A, 0xE9, 0x54, 0x5A, 0xE5, 0xB7, 0x22, 0x21, 0x4D, + 0xB0, 0xAA, 0x50, 0x1F, 0xB3, 0xA1, 0x24, 0x34, 0x45, 0x62, + 0x17, 0x3B, 0xF3, 0xC3, 0x50, 0xCB, 0x97, 0xB2, 0x85, 0x06, + 0xA4, 0xB8, 0x0E, 0xF2, 0x0C, 0x52, 0x1C, 0xF4, 0x6B, 0xF5, + 0x21, 0xD5, 0x27, 0xBA, 0xFD, 0x6C, 0x76, 0x1E, 0xF5, 0xCA, + 0xD2, 0xD4, 0xE1, 0x9C, 0xC7, 0x1E, 0x32, 0x22, 0x0D, 0xBC, + 0x5C, 0x4B, 0xE7, 0x7D, 0x09, 0xCD, 0xA5, 0xF2, 0x8D, 0x86, + 0x7E, 0xE5, 0xA9, 0xE6, 0xAA, 0x98, 0xC2, 0x00, 0x41, 0x67, + 0xE9, 0x3B, 0x89, 0x4D, 0x53, 0xDF, 0x52, 0xF0, 0xC4, 0x20, + 0xEC, 0x85, 0x56, 0x1D, 0x10, 0xEE, 0xDA, 0xF9, 0xFE, 0xFD, + 0x60, 0x3E, 0x8F, 0xF3, 0x79, 0x5B, 0x2B, 0xAE, 0xE4, 0x8C, + 0x0B, 0x30, 0xAD, 0x45, 0xD2, 0x76, 0xE6, 0xEA, 0x84, 0xE2, + 0xDC, 0x8E, 0xCB, 0x50, 0x0F, 0x5E, 0x18, 0x24, 0xFA, 0x65, + 0x74, 0x91, 0x94, 0x26, 0x06, 0x69, 0xA8, 0x10, 0x05, 0x42, + 0x17, 0x20, 0x8F, 0x89, 0xC5, 0xD4, 0xCC, 0xF1, 0x0E, 0x6E, + 0x95, 0x11, 0xB4, 0x61, 0xE3, 0x8C, 0x73, 0x0B, 0xF1, 0x03, + 0xF6, 0x0A, 0xCF, 0xC4, 0x8E, 0xCB, 0x0E, 0x5A, 0xDE, 0x01, + 0x7A, 0xD3, 0x5A, 0xEB, 0x1F, 0xDC, 0xFE, 0x60, 0xAE, 0xB6, + 0xF6, 0xE6, 0x7B, 0xBA, 0x84, 0x1F, 0x97, 0xDD, 0x61, 0x81, + 0x17, 0x28, 0xAE, 0x71, 0x0A, 0x61, 0xC8, 0x49, 0x0E, 0xB1, + 0xC0, 0x39, 0xEC, 0x1F, 0x5C, 0xF4, 0xC4, 0xA4, 0x62, 0x20, + 0x8A, 0x30, 0x42, 0xED, 0xA2, 0xB2, 0xF7, 0x4D, 0x31, 0x7A, + 0x37, 0x5F, 0x59, 0x9F, 0x03, 0x7B, 0x2D, 0xD0, 0x30, 0x78, + 0x15, 0x77, 0x67, 0xDB, 0xE9, 0xF9, 0x13, 0xE0, 0xB9, 0x64, + 0x31, 0x31, 0xF4, 0xC1, 0xE5, 0x6E, 0x32, 0xA9, 0xEE, 0xCE, + 0xE9, 0x57, 0xC0, 0x8A, 0x1C, 0x63, 0xB4, 0x8A, 0x4B, 0x41, + 0x1D, 0xF5, 0x50, 0xF5, 0x00, 0xCA, 0x66, 0xA4, 0x36, 0x8E, + 0x81, 0x44, 0xF9, 0x32, 0x43, 0xAB, 0xA7, 0x35, 0x79, 0xCC, + 0xEC, 0xA8, 0x79, 0xDA, 0x8B, 0x6F, 0x80, 0x8F, 0x48, 0xC6, + 0xD6, 0xA6, 0x98, 0x31, 0xB3, 0xC3, 0xDD, 0x66, 0xC2, 0x58, + 0x4A, 0x8F, 0x2E, 0xD4, 0x1A, 0x18, 0xB2, 0x10, 0x96, 0x2B, + 0x9E, 0x3B, 0xDD, 0xE5, 0xD1, 0xEB, 0x07, 0x5A, 0x25, 0x43, + 0xA4, 0x58, 0xE6, 0x1C, 0xF8, 0x0B, 0x2F, 0xE9, 0x13, 0x39, + 0x2F, 0xC2, 0x22, 0x24, 0xDB, 0x45, 0x72, 0x9A, 0x8A, 0xB3, + 0x53, 0xEC, 0x03, 0x62, 0xE4, 0xC9, 0x3B, 0x3C, 0xBC, 0x7D, + 0x1E, 0xCB, 0x28, 0x71, 0x2E, 0x28, 0xD0, 0xEF, 0x0F, 0x77, + 0x2B, 0x8C, 0x69, 0x1D, 0xC1, 0x7C, 0xB4, 0xBD, 0xF9, 0xE9, + 0x09, 0x15, 0xEA, 0xC7, 0xA7, 0x8D, 0xA9, 0xAF, 0xF9, 0xBC, + 0x27, 0xE9, 0xF0, 0x4F, 0xFB, 0xB3, 0xCD, 0x04, 0xB4, 0x8E, + 0x50, 0xB1, 0x3A, 0xD5, 0xEB, 0x7E, 0x6C, 0xD6, 0x59, 0x30, + 0xB9, 0xAB, 0x42, 0x7C, 0x21, 0x2F, 0x8B, 0xB7, 0x43, 0xFE, + 0x5A, 0x67, 0x76, 0x37, 0x31, 0x7E, 0x0C, 0x75, 0xDF, 0xE4, + 0x38, 0xFB, 0x76, 0xBA, 0xF4, 0xF2, 0xD9, 0xD9, 0x2E, 0xE2, + 0xE7, 0x19, 0xB0, 0x7F, 0xC0, 0x9F, 0x9F, 0xA6, 0x40, 0x20, + 0xA6, 0x93, 0x75, 0x5F, 0x2E, 0x49, 0x9D, 0x60, 0xE4, 0xFD, + 0x75, 0x41, 0x45, 0x9E, 0x7A, 0x5A, 0x82, 0xA9, 0x90, 0x0C, + 0xF9, 0xD0, 0x0E, 0x1C, 0x8E, 0xDC, 0x1D, 0x92, 0x69, 0x37, + 0x11, 0x10, 0x23, 0xED, 0x4C, 0xB3, 0x0B, 0x73, 0x53, 0x6D, + 0xCF, 0x02, 0x15, 0xF6, 0x26, 0xF6, 0x8B, 0xF8, 0xA2, 0xBD, + 0xA5, 0x15, 0xC5, 0x5A, 0x73, 0xB8, 0xCA, 0x93, 0xA2, 0x3B, + 0x2A, 0x8D, 0xB6, 0xD1, 0x2D, 0xDC, 0xD4, 0xA9, 0x16, 0x9B, + 0x31, 0x7D, 0x99, 0xEF, 0x3D, 0xCF, 0xF7, 0xFA, 0x2D, 0xE6, + 0x5E, 0xF6, 0x8F, 0x29, 0x54, 0xD4, 0xD1, 0xB4, 0x41, 0xA1, + 0x9F, 0xB1, 0xBE, 0x78, 0x44, 0xE2, 0x4E, 0x4C, 0x28, 0x79, + 0xAB, 0xA3, 0x73, 0x5A, 0xA5, 0xE3, 0x1F, 0x5C, 0x4E, 0x0B, + 0x3C, 0x61, 0x0D, 0xE1, 0x82, 0x78, 0xF3, 0x15, 0x16, 0xD2, + 0x4A, 0x2B, 0x7D, 0x6E, 0xEA, 0x8C, 0xCF, 0xD7, 0x4B, 0xDE, + 0xC0, 0x0D, 0x1D, 0x28, 0x38, 0x1C, 0xC0, 0x0E, 0x30, 0xAD, + 0x64, 0xF9, 0xE2, 0x60, 0x6E, 0xF0, 0x22, 0xAF, 0xE5, 0x66, + 0x35, 0x51, 0x1A, 0x99, 0x20, 0x26, 0x14, 0x7E, 0x14, 0x55, + 0xE6, 0x82, 0x70, 0x62, 0x49, 0xA5, 0xB8, 0x3D, 0x3E, 0x57, + 0xE5, 0x1F, 0x0A, 0x26, 0x09, 0xFC, 0x22, 0x1C, 0xF4, 0x7A, + 0x2D, 0xBC, 0x53, 0xB2, 0xE7, 0xFF, 0x60, 0x31, 0xED, 0xE6, + 0xDC, 0x18, 0x64, 0x36, 0xC1, 0xD9, 0x39, 0xF3, 0xE0, 0x2E, + 0xA1, 0x1A, 0x7F, 0x58, 0x57, 0xE0, 0x9F, 0x32, 0x23, 0x31, + 0xED, 0x50, 0x64, 0x87, 0x28, 0xC5, 0x52, 0xA2, 0xDA, 0xC3, + 0xD0, 0x38, 0x8C, 0x97, 0x8F, 0xF7, 0x68, 0xBC, 0xF3, 0x54, + 0xAA, 0x16, 0xA8, 0x73, 0xD5, 0x9B, 0xBC, 0x7D, 0xE0, 0x71, + 0x52, 0x6E, 0x4E, 0xB4, 0x10, 0xF6, 0x15, 0xEB, 0x64, 0xA0, + 0x88, 0xDE, 0xEB, 0xB8, 0x5E, 0x02, 0x8A, 0xA7, 0x1E, 0x1E, + 0xB1, 0x8A, 0xBC, 0x2A, 0xC3, 0x79, 0xFC, 0x6A, 0x9B, 0x58, + 0x5D, 0x6E, 0x57, 0x46, 0x12, 0x0B, 0x4C, 0x99, 0x04, 0x5B, + 0x3E, 0x1D, 0x63, 0x16, 0x0F, 0x05, 0xAA, 0x86, 0x7F, 0xCB, + 0x8A, 0x61, 0x9F, 0xF7, 0xF0, 0xFE, 0x03, 0x43, 0x48, 0x65, + 0x4B, 0xA3, 0x8B, 0x42, 0xA0, 0x6D, 0xB2, 0x71, 0x4F, 0x66, + 0x3E, 0xB6, 0x35, 0xF5, 0xB2, 0xD0, 0xF1, 0xB0, 0xBD, 0xB4, + 0x60, 0xA7, 0x82, 0x3A, 0x14, 0xC2, 0x13, 0xAF, 0xC4, 0x99, + 0xCB, 0x17, 0xCC, 0xDA, 0x15, 0x16, 0xE1, 0xA1, 0xB6, 0x2A, + 0x23, 0x61, 0x58, 0x09, 0x44, 0xDA, 0x1F, 0x07, 0x4D, 0x38, + 0x07, 0xA7, 0xE1, 0x35, 0xC7, 0x31, 0x3A, 0xC6, 0x37, 0x3E, + 0xA0, 0x33, 0xAA, 0x44, 0x91, 0x5F, 0x7F, 0x86, 0x8D, 0x13, + 0xE6, 0x18, 0x7E, 0xBC, 0x61, 0x38, 0x39, 0x11, 0x64, 0x91, + 0xCD, 0x3B, 0x48, 0x49, 0x13, 0x08, 0xAD, 0xA5, 0xE6, 0xF4, + 0xED, 0x6E, 0x34, 0x4E, 0x0C, 0x43, 0xB8, 0xC0, 0xF0, 0x2A, + 0xCD, 0x2D, 0x2A, 0x0F, 0x67, 0x34, 0x60, 0xDD, 0xA6, 0x58, + 0x25, 0x1F, 0xC2, 0xB0, 0x18, 0xF3, 0x53, 0x4A, 0xE6, 0xA0, + 0x4D, 0x8B, 0xE1, 0x53, 0x5F, 0x08, 0x33, 0x61, 0x85, 0xF3, + 0x2F, 0x94, 0xC6, 0x24, 0x8E, 0x67, 0xC0, 0x59, 0xC9, 0x77, + 0x15, 0x7B, 0x1B, 0x7B, 0xC7, 0xFD, 0xAC, 0x30, 0xFB, 0x1D, + 0x7D, 0x9E, 0xBF, 0x20, 0x9F, 0x3D, 0xE4, 0x03, 0xFA, 0x6E, + 0xAC, 0x65, 0x9A, 0x9D, 0xDC, 0xE7, 0xA4, 0x88, 0x44, 0x57, + 0xF2, 0x7B, 0xF3, 0xD7, 0x3E, 0x41, 0x7B, 0x0F, 0x87, 0xA9, + 0xC8, 0xCC, 0x73, 0x07, 0x66, 0xDE, 0xE7, 0x5E, 0xFD, 0xCA, + 0xFF, 0x4D, 0x68, 0x4F, 0xFA, 0x0D, 0xDB, 0x77, 0x5F, 0xDF, + 0x91, 0x03, 0x3F, 0x93, 0xE3, 0x41, 0x29, 0x81, 0x1C, 0x9F, + 0xEB, 0x7D, 0xD9, 0x9E, 0x86, 0x4F, 0x94, 0x1E, 0x7A, 0xC6, + 0xD8, 0x02, 0xC9, 0x93, 0x6B, 0xF8, 0x9E, 0xA6, 0x7E, 0xAE, + 0xCB, 0x93, 0xD6, 0x97, 0x63, 0xAA, 0x14, 0x4C, 0x2E, 0x3D, + 0xB1, 0xEE, 0xC5, 0xCB, 0x0B, 0xD6, 0x6E, 0x39, 0x4D, 0xFD, + 0x80, 0x6A, 0xA0, 0x6E, 0xE9, 0x95, 0x00, 0xC8, 0x0B, 0x25, + 0x53, 0xEE, 0xA7, 0x83, 0xA9, 0x75, 0x11, 0x5B, 0xA4, 0x92, + 0x62, 0x62, 0x58, 0x49, 0x70, 0x00, 0x8A, 0xF2, 0x6E, 0xBF, + 0x0B, 0x1F, 0x49, 0xF7, 0x50, 0x39, 0x12, 0xC1, 0xA7, 0x7F, + 0xAA, 0x47, 0x4C, 0x7A, 0x4F, 0x07, 0xBA, 0x6C, 0x55, 0x95, + 0x6D, 0x54, 0x7B, 0xFD, 0xD2, 0x82, 0x6E, 0x81, 0x93, 0x83, + 0x87, 0x74, 0x06, 0xCA, 0x86, 0xD1, 0x8D, 0xE5, 0xBD, 0x10, + 0xD2, 0xC5, 0xFB, 0x8B, 0xBE, 0xF6, 0xB3, 0xC0, 0x77, 0x24, + 0x48, 0x35, 0x21, 0x46, 0x9C, 0x14, 0x60, 0x15, 0x1C, 0xC8, + 0x80, 0x66, 0x58, 0x23, 0xE0, 0x33, 0x6C, 0x7D, 0xFD, 0x9D, + 0x86, 0x5D, 0x30, 0xD8, 0xE0, 0xE9, 0x9F, 0xAF, 0x16, 0x47, + 0xCB, 0x96, 0x10, 0xDC, 0x0A, 0x0F, 0x83, 0x2E, 0x6A, 0xE3, + 0x8E, 0x5F, 0xA9, 0xDF, 0x52, 0x86, 0x89, 0x5C, 0xEA, 0x79, + 0x7E, 0xA6, 0xB1, 0xA8, 0x7A, 0x2A, 0x17, 0x4C, 0x84, 0x65, + 0x4B, 0x12, 0x84, 0xB9, 0x76, 0x72, 0x8D, 0xE4, 0xF9, 0x0D, + 0x7A, 0xA6, 0xD2, 0x42, 0x4A, 0x28, 0x18, 0x3A, 0x44, 0x5F, + 0xCA, 0xA2, 0x53, 0x0F, 0xF3, 0x51, 0x70, 0x09, 0x95, 0x87, + 0x66, 0xF5, 0x64, 0x58, 0x0B, 0xA5, 0x09, 0x71, 0xB3, 0x72, + 0x71, 0x7E, 0xB7, 0xE2, 0x77, 0x68, 0xB5, 0x85, 0x1B, 0x72, + 0x00, 0x2C, 0x49, 0x0F, 0x65, 0xBE, 0x6D, 0x11, 0x4C, 0x14, + 0x55, 0x91, 0xA1, 0x9D, 0x5C, 0xC3, 0x76, 0xD8, 0x44, 0x4D, + 0x0D, 0xC1, 0x4A, 0xDA, 0xEF, 0xAD, 0x6B, 0xDB, 0x3A, 0x44, + 0x96, 0xA2, 0x87, 0x73, 0x2D, 0xF2, 0xA0, 0x53, 0x27, 0x22, + 0xDF, 0xE0, 0xC5, 0xD2, 0xBC, 0x0B, 0xE0, 0xCC, 0x00, 0x9A, + 0xFD, 0x46, 0xF7, 0x5E, 0xE4, 0x1D, 0xB9, 0xB3, 0x1B, 0x6F, + 0x4B, 0x40, 0x22, 0x5F, 0xA8, 0xF7, 0x68, 0xE2, 0x4D, 0x27, + 0x27, 0x8F, 0x42, 0x2A, 0x5F, 0x19, 0xFC, 0x8A, 0x55, 0x4F, + 0x9B, 0x26, 0x60, 0x7E, 0x2B, 0xF8, 0x61, 0xAA, 0x0F, 0xB8, + 0x02, 0xA6, 0x58, 0x71, 0xA1, 0x3B, 0xF0, 0xC9, 0xCB, 0x5A, + 0x80, 0x8A, 0xF8, 0x5A, 0x07, 0x3C, 0x98, 0x94, 0x22, 0x1A, + 0xA8, 0x35, 0x38, 0xFA, 0xF4, 0xE2, 0x13, 0xF5, 0x28, 0x7B, + 0x41, 0xDB, 0xFD, 0x13, 0xF1, 0x08, 0x1C, 0xA6, 0xB6, 0x68, + 0x8E, 0x0F, 0xF1, 0x22, 0x6C, 0x4E, 0xF4, 0xE5, 0xFC, 0x6B, + 0xE2, 0xB7, 0x26, 0x81, 0x84, 0xC8, 0x66, 0x3C, 0xF1, 0x98, + 0xED, 0xBC, 0x09, 0x30, 0x57, 0xC1, 0x0C, 0xDC, 0x09, 0xF1, + 0x4D, 0x09, 0xB8, 0xD1, 0xDC, 0xCD, 0xD8, 0x84, 0xD1, 0x99, + 0x95, 0x4D, 0x1C, 0xF0, 0x05, 0x8A, 0x69, 0x83, 0x86, 0xC5, + 0x23, 0x53, 0x9E, 0xE6, 0x49, 0x4D, 0x60, 0x37, 0xA9, 0xDE, + 0x0C, 0xE2, 0xB9, 0xA7, 0x53, 0xAE, 0x65, 0x45, 0xDC, 0x5B, + 0xA0, 0x0E, 0x66, 0xE2, 0x01, 0xBA, 0xCA, 0xCE, 0xA7, 0xE2, + 0x6F, 0x9F, 0x17, 0xB2, 0x9C, 0xC1, 0x66, 0xE4, 0xA5, 0x89, + 0xF0, 0xD7, 0xF6, 0x49, 0x06, 0xCF, 0x14, 0x64, 0xBF, 0x20, + 0x73, 0x18, 0x27, 0xAB, 0x2D, 0xA6, 0xF0, 0x09, 0xAA, 0x51, + 0x70, 0xF9, 0x43, 0x08, 0x05, 0x85, 0x00, 0x15, 0x03, 0xC6, + 0xAB, 0xD6, 0x9C, 0xCF, 0x10, 0xAB, 0xE4, 0xC8, 0x09, 0x27, + 0xC6, 0xA5, 0xCF, 0xCD, 0x39, 0xA1, 0x8C, 0x6E, 0x93, 0x97, + 0x1D, 0xE5, 0x2D, 0xF4, 0xCD, 0x41, 0xCA, 0x83, 0x22, 0xB2, + 0x85, 0x7A, 0x9C, 0x40, 0x38, 0xF2, 0xDE, 0xE0, 0x7B, 0xF4, + 0xB6, 0x7A, 0x6E, 0x76, 0xA6, 0x56, 0x6A, 0x8B, 0x63, 0xF5, + 0xC6, 0xAF, 0x4B, 0xE8, 0xE1, 0x84, 0xC5, 0xA7, 0xA1, 0xE7, + 0xFC, 0xFE, 0x99, 0x6D, 0xAC, 0xF7, 0xF0, 0x36, 0x5C, 0x68, + 0xB2, 0xE5, 0x64, 0x7A, 0x97, 0x8E, 0xE7, 0x4D, 0x93, 0x23, + 0xC3, 0x37, 0x12, 0xA0, 0x63, 0x0A, 0x5C, 0xFA, 0x41, 0xD1, + 0x8B, 0xAB, 0xA3, 0x92, 0xBF, 0xB0, 0x7C, 0x40, 0x07, 0xB2, + 0xBD, 0x49, 0xD7, 0x85, 0xFC, 0xA0, 0x71, 0x35, 0x96, 0xA2, + 0x72, 0x46, 0x31, 0xEF, 0x75, 0xDB, 0x9D, 0x68, 0xA7, 0xB3, + 0x6C, 0x8C, 0x09, 0x63, 0x94, 0x41, 0xE2, 0xC5, 0x83, 0x94, + 0xAA, 0x76, 0xBA, 0xA4, 0xD5, 0x0E, 0x65, 0xCC, 0x18, 0x61, + 0xCE, 0x82, 0xD7, 0xDE, 0xE6, 0x96, 0xE2, 0x84, 0x0D, 0x7A, + 0xE4, 0xA1, 0x06, 0x4C, 0x86, 0x65, 0x24, 0xC3, 0x91, 0xE9, + 0x0B, 0xBC, 0xA6, 0x6F, 0x7E, 0xFB, 0x5D, 0x16, 0xBB, 0x13, + 0xAA, 0x85, 0x75, 0x2A, 0x97, 0x15, 0x6D, 0x42, 0x5A, 0xDE, + 0x31, 0x15, 0x30, 0xF8, 0x8D, 0x6B, 0x8E, 0xD6, 0xC7, 0x94, + 0x33, 0x0F, 0x22, 0xBD, 0xEE, 0x38, 0x34, 0x51, 0x6D, 0xD1, + 0xCC, 0x90, 0x96, 0x96, 0xDD, 0x67, 0xEA, 0x4F, 0x05, 0xF8, + 0x7A, 0xB3, 0x1D, 0x01, 0x37, 0xA1, 0xDC, 0xF1, 0x8E, 0xF8, + 0x85, 0xB9, 0x4D, 0xAC, 0xD2, 0xE5, 0xE0, 0x3D, 0x05, 0x93, + 0x02, 0x2D, 0x84, 0xF6, 0xA9, 0x0A, 0x92, 0xBE, 0x45, 0x85, + 0x75, 0x36, 0x27, 0x20, 0x9B, 0xFA, 0x08, 0x86, 0x8E, 0x77, + 0xE2, 0x2D, 0x34, 0xA8, 0xB9, 0x02, 0x64, 0x9C, 0xC0, 0xA9, + 0x5E, 0x92, 0x7C, 0x77, 0x92, 0xCE, 0x20, 0x07, 0x36, 0xA4, + 0xA9, 0x30, 0x26, 0xAD, 0x83, 0xFD, 0x14, 0x29, 0x33, 0x14, + 0xA1, 0x67, 0xF6, 0x37, 0x59, 0x24, 0x0C, 0x40, 0x4A, 0x3C, + 0xCD, 0xEB, 0x78, 0xD1, 0x72, 0x12, 0xE1, 0x02, 0x04, 0x22, + 0x81, 0x57, 0x28, 0x82, 0x3A, 0xCB, 0xDF, 0x05, 0xAC, 0x62, + 0xAC, 0x72, 0x59, 0x57, 0x44, 0xFF, 0x0D, 0x26, 0x7B, 0xFA, + 0x35, 0x59, 0x34, 0x92, 0xC3, 0x6E, 0xA8, 0x40, 0x84, 0x97, + 0x74, 0x31, 0x10, 0xF7, 0x23, 0x6A, 0x80, 0x15, 0xF7, 0x5D, + 0xB9, 0xEF, 0x6A, 0xFC, 0x02, 0x62, 0x61, 0xAE, 0xDB, 0x06, + 0xD4, 0x58, 0x42, 0x4F, 0x8B, 0x1B, 0xA9, 0x84, 0x03, 0x33, + 0xA2, 0x23, 0x7B, 0x87, 0xF9, 0xDA, 0xF4, 0xE9, 0x3C, 0x55, + 0x0A, 0x2D, 0x18, 0xEE, 0x08, 0xDA, 0x3D, 0x56, 0x83, 0xCE, + 0x36, 0x9E, 0x02, 0x5B, 0x29, 0x2B, 0xEB, 0x32, 0x1C, 0x84, + 0x18, 0x62, 0xB4, 0x7B, 0xD6, 0x08, 0xBF, 0x0C, 0x85, 0xB2, + 0xB1, 0x97, 0x47, 0x35, 0x59, 0xDD, 0x30, 0xEE, 0xEF, 0x82, + 0x48, 0x10, 0x72, 0x3E, 0xBF, 0x64, 0xF1, 0x26, 0x84, 0x6E, + 0x17, 0x65, 0xC8, 0x0A, 0xBD, 0xE3, 0x83, 0x9C, 0xE2, 0xC3, + 0xAC, 0xE4, 0x00, 0xD3, 0x6A, 0x60, 0x6A, 0x1E, 0x45, 0x67, + 0x6E, 0xA7, 0xE8, 0x89, 0x7D, 0x87, 0x79, 0x30, 0x2E, 0x6C, + 0x4F, 0x7D, 0xB9, 0x23, 0x60, 0x95, 0xA6, 0x5C, 0x85, 0x9E, + 0xD2, 0x8C, 0x9B, 0xFC, 0xFD, 0x5D, 0x43, 0x74, 0x01, 0x78, + 0xD7, 0xC9, 0x78, 0x7F, 0xD5, 0x95, 0x3F, 0xB7, 0x79, 0x3B, + 0x28, 0xF9, 0xE9, 0xCB, 0xDE, 0x0D, 0x4C, 0xD1, 0xE4, 0xE8, + 0x22, 0x60, 0xFC, 0x20, 0x23, 0xEC, 0xB2, 0x11, 0x4C, 0x20, + 0x59, 0x82, 0x40, 0xCF, 0x56, 0x41, 0x33, 0x79, 0x05, 0xD8, + 0x98, 0x5C, 0x7F, 0xAE, 0xA4, 0x73, 0xC4, 0x27, 0x90, 0xAE, + 0x50, 0xBD, 0xBD, 0x30, 0x6A, 0xDB, 0x0B, 0xD6, 0x6F, 0x43, + 0x61, 0x6B, 0x50, 0xC1, 0x16, 0x1C, 0xBF, 0x7F, 0x4C, 0xEB, + 0x2B, 0xB3, 0xAA, 0xF5, 0xF6, 0x07, 0x45, 0x5A, 0xB4, 0x4D, + 0x7A, 0xC6, 0x4A, 0xC6, 0x66, 0x15, 0xE6, 0x31, 0xA5, 0x60, + 0x22, 0x28, 0xF1, 0x0E, 0xC3, 0xF4, 0xAD, 0xD2, 0xF0, 0xFA, + 0x03, 0x7C, 0x28, 0xFA, 0x12, 0x77, 0x19, 0x71, 0xA7, 0x72, + 0x44, 0x13, 0x67, 0x5B, 0xB3, 0x8B, 0x42, 0xEE, 0x9F, 0xD6, + 0x73, 0x04, 0xBA, 0x31, 0x4E, 0xA8, 0x4B, 0xC0, 0x5F, 0xFA, + 0x54, 0x27, 0x0B, 0x17, 0x9F, 0xB2, 0xD4, 0x39, 0x5B, 0x47, + 0x76, 0x42, 0x4C, 0xC8, 0x4C, 0x3A, 0x2A, 0x88, 0xAF, 0x20, + 0xB2, 0xE2, 0x94, 0x15, 0x37, 0xB3, 0x4E, 0xDD, 0x82, 0x81, + 0x8A, 0x99, 0x13, 0x5A, 0x01, 0xA2, 0x0C, 0xD4, 0xD6, 0x89, + 0xBE, 0x00, 0x01, 0x64, 0xF2, 0xA4, 0x99, 0xF3, 0x90, 0x45, + 0x5B, 0x3C, 0x63, 0x1C, 0x14, 0x25, 0x8D, 0x21, 0x00, 0xC7, + 0x25, 0x60, 0xE7, 0xF5, 0x27, 0xAE, 0xA6, 0xC9, 0x92, 0x39, + 0x54, 0xE3, 0x6C, 0x5C, 0x64, 0x00, 0x92, 0x79, 0x1F, 0x3E, + 0x8A, 0x3B, 0xE7, 0xEF, 0x7A, 0xF5, 0xFC, 0x9C, 0xBE, 0x5D, + 0x38, 0xEC, 0xF0, 0xF1, 0x1E, 0x9C, 0xF1, 0x3A, 0x19, 0xCB, + 0x40, 0xF9, 0x84, 0xD6, 0x97, 0xD1, 0x02, 0x27, 0x5F, 0xE0, + 0x0F, 0x02, 0xDA, 0x34, 0x5B, 0x22, 0xA0, 0x43, 0x64, 0x82, + 0xEA, 0x9B, 0xAA, 0xBA, 0xA0, 0xDB, 0xE7, 0x7D, 0xD0, 0x4F, + 0x23, 0x98, 0xEA, 0x13, 0xFC, 0xB2, 0x01, 0xC1, 0xF0, 0xC9, + 0x7C, 0x58, 0x74, 0x5E, 0x85, 0x3D, 0x59, 0x69, 0x15, 0x66, + 0x02, 0x0F, 0xD1, 0x2A, 0x34, 0x38, 0x7A, 0x5D, 0xD9, 0x32, + 0xDA, 0xA5, 0x7A, 0x18, 0xDD, 0x7D, 0xDB, 0x25, 0xC8, 0x6D, + 0x00, 0x37, 0xE0, 0x2B, 0x01, 0x5E, 0xCC, 0xC3, 0x43, 0x3D, + 0xCA, 0x5D, 0xDC, 0x02, 0xD5, 0x0C, 0x87, 0x06, 0x87, 0x3E, + 0xBB, 0xA7, 0xEC, 0x31, 0x96, 0x65, 0xA0, 0xC9, 0x8A, 0xC0, + 0x0A, 0xFD, 0x1C, 0xE9, 0x1A, 0x26, 0xB4, 0x5D, 0xA0, 0xAE, + 0x74, 0x66, 0x2B, 0x9D, 0x56, 0xA0, 0xE8, 0x51, 0x23, 0x52, + 0x75, 0x86, 0x56, 0x86, 0x15, 0xEC, 0xB6, 0xDE, 0xC2, 0x0F, + 0x2E, 0x4D, 0xF9, 0xF9, 0x40, 0x69, 0xA9, 0x28, 0x3B, 0x39, + 0x94, 0x30, 0xE4, 0xB3, 0x53, 0xB5, 0x19, 0xFF, 0x39, 0xCE, + 0xAB, 0x0D, 0x30, 0x62, 0x4C, 0xE3, 0x73, 0x17, 0x6D, 0x41, + 0xB8, 0xFB, 0x3B, 0x10, 0xF7, 0x39, 0x1A, 0x60, 0xED, 0x3A, + 0x59, 0x2A, 0xF2, 0x23, 0x4C, 0x60, 0x51, 0xB3, 0x2D, 0xC5, + 0xEC, 0x35, 0xF0, 0xC1, 0x73, 0xB8, 0x96, 0x4F, 0x62, 0x2D, + 0x37, 0x3E, 0xB1, 0x38, 0x43, 0xC6, 0x0F, 0xAD, 0xA2, 0x7E, + 0x5D, 0x8C, 0x37, 0x78, 0xFD, 0xE3, 0x53, 0x3C, 0x32, 0xCC, + 0xCD, 0x07, 0xF5, 0xB2, 0xA9, 0x9A, 0xE6, 0x41, 0x3E, 0x0E, + 0x6E, 0x5B, 0xF3, 0x80, 0x81, 0x0B, 0xBC, 0x1D, 0xF0, 0x14, + 0x88, 0x6A, 0xC5, 0x00, 0x6E, 0x5D, 0x47, 0xE0, 0xD4, 0x26, + 0xE7, 0x26, 0x15, 0xD8, 0xDE, 0x38, 0x46, 0xBC, 0x34, 0x97, + 0x76, 0x6B, 0xB5, 0xE0, 0x56, 0x89, 0xD9, 0x54, 0x6C, 0x76, + 0x62, 0x1C, 0xDD, 0x0C, 0xE6, 0x21, 0x45, 0xE6, 0xD5, 0x1B, + 0xFA, 0x43, 0x49, 0xFC, 0xE5, 0xFF, 0x59, 0x27, 0x24, 0x84, + 0x97, 0x71, 0xC7, 0x49, 0x9E, 0xA6, 0x25, 0x55, 0xE8, 0xDE, + 0x08, 0xDF, 0x8D, 0xFF, 0xC4, 0x90, 0x9B, 0x6E, 0xBC, 0xD3, + 0x0E, 0xC7, 0x66, 0x16, 0xB3, 0x18, 0x2A, 0x4E, 0x14, 0xCD, + 0x3A, 0x77, 0x40, 0xE2, 0xD0, 0xBF, 0x69, 0xBE, 0x8B, 0x8B, + 0xBB, 0xC5, 0xC7, 0xE2, 0x3F, 0x9C, 0xD1, 0xB6, 0x4D, 0xCB, + 0xBC, 0xB9, 0x65, 0xE9, 0x4C, 0x40, 0x21, 0xA2, 0x91, 0xDF, + 0x4C, 0xD8, 0x81, 0x13, 0xEA, 0x20, 0xDC, 0x22, 0xC9, 0xA0, + 0xFA, 0x45, 0xC4, 0x6A, 0x6F, 0x68, 0xD7, 0x4E, 0xFF, 0x12, + 0xF6, 0xBF, 0xED, 0xE0, 0xCB, 0x84, 0x19, 0x50, 0xA6, 0x22, + 0xB7, 0x45, 0xEB, 0x90, 0x2D, 0x49, 0xB3, 0x01, 0x31, 0x83, + 0x41, 0x29, 0x39, 0xBF, 0xAB, 0x52, 0x19, 0x8D, 0x71, 0x4D, + 0x28, 0xA8, 0x83, 0x0D, 0x23, 0x40, 0xDB, 0x7D, 0x28, 0x0A, + 0x07, 0xEF, 0xCE, 0x31, 0xA9, 0x11, 0x60, 0x11, 0x66, 0xBC, + 0x88, 0xB4, 0xD0, 0xD1, 0x7A, 0xEC, 0x9A, 0x35, 0x5C, 0x7B, + 0x4F, 0xB9, 0x75, 0x4C, 0xFB, 0x06, 0x6B, 0x0D, 0x90, 0x37, + 0x58, 0x02, 0x71, 0x25, 0xD8, 0xE8, 0xB3, 0x08, 0xE0, 0x39, + 0x0F, 0x82, 0xE6, 0xB0, 0x81, 0xEA, 0x35, 0x90, 0x0D, 0x30, + 0x16, 0xE9, 0x39, 0xE5, 0xBC, 0xC4, 0x4C, 0x6B, 0x2E, 0x53, + 0xD7, 0xD4, 0x3D, 0xD9, 0x5F, 0xFD, 0x45, 0x4B, 0xAF, 0xB3, + 0x19, 0x2D, 0xB0, 0x00, 0x88, 0xA0, 0x5C, 0x44, 0xBC, 0x6B, + 0xE8, 0x08, 0xF0, 0x66, 0xFB, 0x29, 0x70, 0x04, 0x59, 0xAE, + 0x58, 0x1A, 0x34, 0xD3, 0xA2, 0x31, 0x73, 0xEE, 0xC2, 0x2F, + 0xBD, 0x6E, 0xEB, 0xFF, 0xAF, 0xCC, 0xE5, 0xC7, 0x40, 0x62, + 0x1E, 0xEE, 0x74, 0xB7, 0x49, 0x81, 0xD0, 0xDF, 0xEB, 0x43, + 0x4E, 0x7A, 0xEE, 0x64, 0xDD, 0xE4, 0xA9, 0x72, 0xF9, 0x29, + 0xA1, 0x1A, 0x01, 0x67, 0x3A, 0xC3, 0xE9, 0xAA, 0x69, 0xCD, + 0xFE, 0x25, 0x9F, 0x04, 0xAF, 0xC3, 0x81, 0xB5, 0x37, 0x73, + 0x31, 0x43, 0x11, 0x7C, 0xDD, 0xC1, 0xA2, 0xBB, 0xD2, 0x5D, + 0x0C, 0x3E, 0x11, 0x60, 0xF7, 0x3B, 0xEC, 0xCF, 0x88, 0x56, + 0x83, 0xE4, 0x87, 0xFA, 0xA0, 0xD5, 0xC8, 0x15, 0x22, 0xF5, + 0xDC, 0x29, 0xE0, 0x7D, 0x74, 0x2B, 0x9F, 0xD3, 0x5D, 0xF4, + 0x61, 0x03, 0xF9, 0xA1, 0x86, 0x30, 0xD1, 0xFF, 0xEA, 0x1F, + 0x15, 0x4C, 0x1A, 0xBE, 0xA8, 0xAB, 0x95, 0x39, 0xF5, 0xDA, + 0x93, 0x63, 0xE0, 0xDD, 0xEF, 0x54, 0x29, 0x81, 0x0B, 0x6C, + 0xAB, 0x11, 0x3F, 0x5D, 0xC6, 0x46, 0xEC, 0xB5, 0x58, 0x6A, + 0x92, 0xF1, 0x0D, 0x7E, 0xDB, 0xEA, 0x4B, 0xD1, 0xF2, 0x7B, + 0xFC, 0x06, 0xFA, 0xE8, 0xEE, 0x8C, 0x33, 0xCA, 0x21, 0xE1, + 0xD3, 0xF0, 0xB5, 0x5D, 0x50, 0xBD, 0x1A, 0x57, 0x94, 0xCB, + 0xF9, 0xF5, 0xC4, 0xA9, 0xEC, 0x6A, 0x52, 0xF3, 0x37, 0x3C, + 0x94, 0xBE, 0x1D, 0x0B, 0x6E, 0x43, 0xF6, 0xAF, 0xBE, 0xEC, + 0x12, 0xF1, 0xAA, 0xFB, 0xBB, 0x45, 0x05, 0xB9, 0x72, 0x69, + 0x11, 0xDA, 0xE3, 0x34, 0x55, 0x1B, 0x5F, 0x23, 0x6B, 0x35, + 0x2F, 0x41, 0xE3, 0xA0, 0xAE, 0xB0, 0x29, 0xAD, 0x38, 0x21, + 0x30, 0xA3, 0x17, 0xB2, 0x27, 0xCD, 0x43, 0xEF, 0x45, 0x7C, + 0x2A, 0x1F, 0x4E, 0xFD, 0x5F, 0x5D, 0xB6, 0xBC, 0x14, 0x04, + 0x94, 0x02, 0x53, 0xA4, 0xCA, 0xA5, 0x1F, 0x8A, 0x30, 0x00, + 0x23, 0xD0, 0xA4, 0x11, 0xF4, 0xD1, 0xDB, 0x4E, 0x13, 0x18, + 0x62, 0x09, 0x84, 0x54, 0x3C, 0x04, 0xF3, 0x4D, 0xBE, 0x73, + 0x09, 0x4B, 0xAF, 0xD8, 0xCE, 0x2E, 0xC6, 0xF4, 0x13, 0x64, + 0x28, 0xC9, 0xF4, 0xF4, 0xE5, 0x06, 0xF5, 0x7F, 0xDB, 0xE8, + 0xB4, 0xA6, 0xFE, 0x24, 0x5A, 0x9B, 0x4D, 0x86, 0x32, 0xC4, + 0x87, 0x89, 0x25, 0xDA, 0x3C, 0xE8, 0x98, 0x9E, 0xEF, 0x3A, + 0x20, 0x5A, 0x11, 0x79, 0x18, 0x61, 0xF5, 0xD7, 0xCC, 0x71, + 0x7F, 0x98, 0x4A, 0x5E, 0x78, 0x7F, 0x50, 0xBB, 0x74, 0xD5, + 0x2C, 0xB4, 0x2B, 0x8D, 0xB7, 0xAD, 0x1B, 0x80, 0x2C, 0xDB, + 0x92, 0x2B, 0x7D, 0x82, 0x2B, 0xF6, 0xE3, 0x4C, 0xE8, 0x56, + 0x0F, 0x07, 0x70, 0xD3, 0x26, 0x3E, 0x22, 0x2E, 0x17, 0x1E, + 0x46, 0x72, 0x94, 0x57, 0xA3, 0xCE, 0xBD, 0x0B, 0xC2, 0x83, + 0xC9, 0x24, 0xBD, 0x52, 0x09, 0xDA, 0x6B, 0xD0, 0x8E, 0xE6, + 0x83, 0x03, 0xE5, 0x1A, 0xD3, 0x91, 0xFD, 0x72, 0x11, 0x94, + 0xDC, 0x21, 0xE5, 0xA9, 0xB9, 0xE9, 0xC2, 0xB5, 0x35, 0x11, + 0x13, 0x2B, 0xDD, 0xD5, 0x05, 0xDD, 0x10, 0x68, 0xC1, 0xF6, + 0xF7, 0xA6, 0xD3, 0x7D, 0x85, 0x64, 0x21, 0xB2, 0xE0, 0x8F, + 0xB7, 0x12, 0xE8, 0x67, 0x80, 0x52, 0x81, 0x32, 0xCC, 0xD8, + 0xDF, 0xE2, 0x11, 0x17, 0x9A, 0xF3, 0x20, 0x46, 0x22, 0x5A, + 0xEC, 0xAC, 0xBC, 0x2F, 0x07, 0x70, 0xED, 0x1F, 0x85, 0x2F, + 0x4D, 0xB3, 0x51, 0x4E, 0x27, 0x2F, 0x7C, 0xE1, 0xDE, 0x67, + 0x61, 0xE8, 0x8E, 0xBC, 0xA0, 0x02, 0x7C, 0x0E, 0x07, 0x98, + 0x6A, 0xD8, 0x8C, 0x61, 0x5F, 0xEB, 0x95, 0x1C, 0x2C, 0x4C, + 0x9C, 0xEA, 0xCB, 0xD6, 0x56, 0x21, 0x80, 0xF4, 0x52, 0xCD, + 0xE1, 0x73, 0x7E, 0x74, 0x43, 0x3F, 0xEA, 0x13, 0xB7, 0xBA, + 0x40, 0x6B, 0x72, 0x22, 0xD0, 0xAE, 0xDA, 0x61, 0xE4, 0xDD, + 0xDF, 0xB9, 0xE3, 0xF1, 0x89, 0x02, 0xE4, 0x9B, 0xED, 0x44, + 0xEB, 0x79, 0x61, 0x0B, 0x7A, 0x3A, 0x8B, 0x3F, 0x13, 0x68, + 0x7D, 0x0B, 0x99, 0x39, 0xEE, 0xD5, 0x40, 0xB0, 0x2C, 0xE5, + 0x26, 0x97, 0xB3, 0x52, 0x9A, 0x8D, 0x01, 0xA5, 0x8C, 0xAF, + 0x73, 0xF2, 0x14, 0x18, 0x1C, 0x7D, 0x54, 0xB8, 0x03, 0x69, + 0xD5, 0x19, 0x03, 0xF8, 0xE3, 0x8A, 0x99, 0xB5, 0x33, 0xA2, + 0x45, 0xA8, 0x5B, 0x79, 0x9F, 0x72, 0x5D, 0x16, 0xD5, 0x71, + 0x33, 0x3F, 0xA5, 0xBB, 0x27, 0x07, 0x02, 0xCC, 0xD5, 0x20, + 0xCF, 0xB1, 0x9C, 0xCC, 0xC2, 0x3B, 0x77, 0xE3, 0x1D, 0x5E, + 0x9D, 0xE4, 0x13, 0xFE, 0x09, 0x81, 0x02, 0x62, 0x3B, 0x2C, + 0x4E, 0x48, 0xB6, 0xEB, 0xB0, 0x89, 0xC5, 0xA6, 0xE8, 0x48, + 0xC8, 0x7F, 0xB4, 0x54, 0x47, 0x56, 0x05, 0x0B, 0x65, 0x8C, + 0x21, 0x7A, 0x1B, 0x83, 0xE6, 0x2E, 0xA7, 0xC5, 0xB1, 0xB7, + 0xA0, 0x79, 0xFB, 0x33, 0xC2, 0xF2, 0x40, 0x36, 0x9E, 0x87, + 0x2B, 0x90, 0xF4, 0x24, 0xBE, 0x89, 0x2B, 0x1B, 0xE1, 0xFA, + 0xFA, 0x37, 0x6E, 0xE5, 0x7F, 0x07, 0x2C, 0xBF, 0x8E, 0xA0, + 0x10, 0x4F, 0x6F, 0x59, 0x3F, 0x4C, 0xD4, 0xE7, 0x3E, 0x80, + 0x1F, 0xA4, 0x83, 0xE4, 0xBE, 0x6F, 0x80, 0xD5, 0x1E, 0x26, + 0xCD, 0xC9, 0xFB, 0xC6, 0xDC, 0x37, 0xB2, 0x3E, 0xCF, 0x2A, + 0xF2, 0xB7, 0x2B, 0xEC, 0xD8, 0xD5, 0xB1, 0xA3, 0x8E, 0x68, + 0x4D, 0xED, 0x66, 0x36, 0x51, 0x1D, 0x1A, 0x45, 0xB5, 0x40, + 0x34, 0x6C, 0xD5, 0xF8, 0x63, 0xB8, 0xE0, 0x78, 0xE0, 0x35, + 0x4C, 0x09, 0x33, 0xAD, 0xB5, 0xAF, 0x56, 0x2B, 0x05, 0x24, + 0xED, 0xDE, 0x7E, 0xBC, 0x0A, 0xE4, 0x0D, 0xD1, 0xA8, 0xF0, + 0x96, 0x90, 0xA9, 0x3E, 0xB3, 0x1E, 0x3B, 0x72, 0x3D, 0x6D, + 0x83, 0x05, 0x8D, 0x3D, 0x0D, 0xA8, 0x75, 0x65, 0xDB, 0x9F, + 0x5E, 0xB4, 0xE9, 0xAB, 0x4A, 0x78, 0x69, 0x8B, 0x3E, 0x10, + 0xE4, 0x7C, 0x91, 0x25, 0x1A, 0xB3, 0x91, 0x43, 0x82, 0x4D, + 0xF5, 0x5F, 0x07, 0xE4, 0xE0, 0x3C, 0x02, 0xC0, 0xB6, 0x5C, + 0xC4, 0x21, 0x61, 0x7F, 0xAF, 0xFE, 0xB1, 0x10, 0x18, 0x2F, + 0x90, 0x26, 0x6A, 0x98, 0x79, 0x94, 0x62, 0x36, 0xF8, 0x6D, + 0x48, 0xF0, 0x1A, 0x0D, 0xD3, 0xFF, 0x84, 0x98, 0x08, 0x4C, + 0x0E, 0x47, 0x38, 0x90, 0xB4, 0x66, 0xD3, 0x25, 0xCA, 0x8D, + 0x1E, 0xD6, 0x88, 0xBF, 0x13, 0x5C, 0xA9, 0xDD, 0xB1, 0x9F, + 0x4C, 0xC2, 0xCD, 0x7A, 0x65, 0x48, 0xF1, 0x70, 0x59, 0xC8, + 0x4D, 0x2D, 0x7F, 0xDF, 0x1E, 0xA0, 0xDC, 0xA6, 0x90, 0x42, + 0x2D, 0x49, 0xF8, 0x8D, 0x19, 0x19, 0x34, 0x6D, 0xC4, 0x2D, + 0xEB, 0xAC, 0x4B, 0xA8, 0x10, 0xFA, 0x6E, 0xB3, 0x20, 0xB0, + 0xD5, 0x6D, 0x14, 0x4B, 0x7A, 0x63, 0x5A, 0x15, 0xA8, 0xE7, + 0xA7, 0xA9, 0xD3, 0x3B, 0xBF, 0x2D, 0x95, 0x97, 0x45, 0x1E, + 0xE1, 0x3A, 0x0E, 0x5B, 0x46, 0xB5, 0xE6, 0x50, 0x57, 0x5F, + 0x33, 0xA5, 0xF1, 0xDC, 0xB7, 0x5F, 0x22, 0x9D, 0x0E, 0xBF, + 0x3E, 0x95, 0x48, 0x71, 0x0C, 0x6D, 0xFE, 0xF0, 0xE4, 0xF2, + 0xD0, 0x56, 0x75, 0xA1, 0xD8, 0xA5, 0x5C, 0xBE, 0xFA, 0xC4, + 0xD7, 0xAF, 0x7E, 0xF0, 0x7D, 0x0F, 0x21, 0x3F, 0xC0, 0xDF, + 0xD3, 0x30, 0x9B, 0xFC, 0xEA, 0x42, 0x90, 0x6B, 0x3F, 0xD9, + 0x19, 0xB6, 0x09, 0x6E, 0x0E, 0x95, 0x05, 0xC1, 0xEF, 0x90, + 0x54, 0x98, 0xA4, 0xB4, 0x15, 0x46, 0xB7, 0x94, 0x0F, 0xB9, + 0xEF, 0x33, 0x13, 0x0D, 0xC7, 0x7C, 0x71, 0x11, 0x32, 0x59, + 0xF0, 0xBA, 0x62, 0x63, 0x01, 0xC5, 0x4B, 0xD2, 0x66, 0xC4, + 0x95, 0xBF, 0xE8, 0xFE, 0x41, 0xEB, 0xC2, 0x42, 0x5C, 0xB1, + 0x1D, 0x3C, 0x92, 0x85, 0x56, 0x80, 0x62, 0x59, 0xDA, 0x9A, + 0x7B, 0x03, 0xB6, 0x97, 0x6A, 0x23, 0xE8, 0x39, 0x0A, 0xEC, + 0x77, 0xE2, 0x5D, 0x21, 0xCA, 0xC5, 0x09, 0x46, 0x58, 0x9B, + 0xCC, 0xC6, 0x0A, 0x1E, 0x75, 0xAB, 0x8B, 0xD5, 0xB0, 0x71, + 0x83, 0x5E, 0x2B, 0x03, 0xC7, 0xF3, 0xBA, 0xCB, 0xCF, 0xD9, + 0x19, 0x92, 0x42, 0xBE, 0x3B, 0xE5, 0x28, 0x89, 0xC4, 0xA1, + 0xD6, 0x36, 0x77, 0xEF, 0x16, 0x68, 0xE1, 0xC3, 0x66, 0x08, + 0xBC, 0x09, 0x69, 0xD8, 0xFB, 0xCC, 0x4B, 0xE0, 0x75, 0x23, + 0xA9, 0x7B, 0xE1, 0x0B, 0xDF, 0xCE, 0x44, 0xE0, 0x4E, 0x06, + 0x5A, 0x55, 0x86, 0x01, 0x88, 0xCF, 0x4E, 0x87, 0xA7, 0x6D, + 0x16, 0x02, 0xEA, 0x92, 0x32, 0x8E, 0xB1, 0x97, 0xEC, 0xE0, + 0x76, 0x8A, 0x65, 0x5A, 0x20, 0xF3, 0x4E, 0x2D, 0x0A, 0x6D, + 0x62, 0xB6, 0x09, 0x49, 0x8A, 0xDB, 0xB5, 0xB8, 0x9B, 0x52, + 0x9F, 0xB4, 0x71, 0x95, 0x16, 0xBD, 0x74, 0x2B, 0x9C, 0x1D, + 0x88, 0x1B, 0x10, 0xDF, 0x8E, 0x06, 0x9B, 0x32, 0xCF, 0x8E, + 0x4F, 0xF3, 0x36, 0x81, 0x98, 0xF8, 0x6A, 0x59, 0x0A, 0xFE, + 0x54, 0xC5, 0xA6, 0xE1, 0x4F, 0x02, 0x3F, 0xE2, 0x10, 0xA6, + 0x35, 0x52, 0x59, 0x23, 0x39, 0xD4, 0xEF, 0xEA, 0xA7, 0x9A, + 0xF0, 0x4A, 0xE0, 0xE6, 0xBF, 0x40, 0x01, 0x46, 0x08, 0x23, + 0x45, 0x39, 0xA4, 0x8E, 0xB3, 0x0A, 0x9D, 0xB7, 0x9E, 0x0F, + 0x12, 0x63, 0x1C, 0x68, 0x8B, 0x2A, 0x71, 0x2B, 0x88, 0xE2, + 0xF8, 0x75, 0xCC, 0xAC, 0x8B, 0x21, 0x02, 0x88, 0x04, 0xD4, + 0xD4, 0x35, 0x88, 0xB2, 0x54, 0x49, 0x98, 0x97, 0xA9, 0x49, + 0x76, 0x9F, 0xB7, 0x19, 0x28, 0xA4, 0xDD, 0x2C, 0xF0, 0xFD, + 0xBD, 0xC3, 0x94, 0xA7, 0x47, 0x74, 0x54, 0x24, 0xAE, 0xDF, + 0x36, 0x88, 0x6B, 0xE3, 0xA3, 0xAF, 0x80, 0x20, 0xB6, 0x40, + 0x33, 0xCB, 0x65, 0xDE, 0x41, 0x0B, 0xBB, 0x21, 0xAB, 0xF1, + 0xD4, 0xB2, 0x24, 0x3D, 0x6F, 0xF2, 0x75, 0x36, 0xCB, 0xDE, + 0x52, 0x83, 0x90, 0x2F, 0x09, 0xB9, 0x1E, 0x2E, 0xEA, 0x2C, + 0x16, 0xA9, 0xF1, 0x0D, 0x92, 0xE9, 0xAC, 0x5B, 0xC9, 0x52, + 0x5B, 0xDE, 0x9B, 0xB8, 0x60, 0xE3, 0x3B, 0x91, 0x42, 0x87, + 0x1C, 0xBD, 0x2C, 0x82, 0xB8, 0x58, 0xE0, 0x6A, 0xC2, 0x54, + 0x08, 0x37, 0x55, 0x2A, 0x4A, 0x51, 0x79, 0x06, 0x9F, 0x0F, + 0xD9, 0xC2, 0x44, 0x57, 0xAE, 0x34, 0x33, 0x2C, 0x8A, 0xFD, + 0x86, 0x90, 0xFE, 0xF6, 0xB9, 0xB6, 0xD6, 0xBC, 0x22, 0x6D, + 0x24, 0xA5, 0xDE, 0x93, 0x68, 0xD4, 0x69, 0xD3, 0x08, 0x39, + 0xD2, 0x40, 0xEB, 0x76, 0xC7, 0x59, 0xAD, 0x56, 0x8A, 0x2C, + 0x61, 0x53, 0x82, 0x65, 0x1B, 0x7D, 0x20, 0xBB, 0x8F, 0x18, + 0x96, 0xC0, 0xB3, 0xA1, 0xE0, 0x5F, 0xC0, 0xFF, 0xC8, 0xD4, + 0x61, 0x11, 0x23, 0x4D, 0x79, 0xA1, 0xCA, 0xDB, 0xC0, 0x35, + 0xD8, 0x9F, 0x7E, 0x7D, 0x53, 0x72, 0x63, 0xC3, 0x96, 0xEA, + 0x0B, 0x0B, 0x36, 0x55, 0xD8, 0x9F, 0xBB, 0x4A, 0x65, 0x83, + 0xFC, 0x1D, 0x20, 0x79, 0xF1, 0x5F, 0x39, 0xC6, 0x03, 0xCD, + 0x52, 0xE4, 0xED, 0x07, 0x0B, 0x64, 0x70, 0x4E, 0x96, 0x88, + 0x01, 0x9B, 0xCB, 0x3C, 0x66, 0x72, 0x59, 0xD6, 0x1E, 0x92, + 0x9C, 0x9F, 0xDC, 0x2C, 0x11, 0xDF, 0x1B, 0xFC, 0x67, 0x0A, + 0xEC, 0x09, 0x72, 0xE5, 0xB4, 0x94, 0x5F, 0x82, 0xDC, 0xCF, + 0xE4, 0x86, 0xC3, 0x8F, 0x2B, 0x0A, 0x23, 0x4A, 0xC7, 0x24, + 0x0C, 0x37, 0xD4, 0x69, 0xDE, 0x40, 0x07, 0x04, 0xB4, 0x09, + 0xE4, 0xC9, 0x60, 0xF6, 0x88, 0xF8, 0xEA, 0xA9, 0x1F, 0x75, + 0x63, 0x40, 0xF5, 0x04, 0x57, 0xD8, 0xCC, 0x40, 0xBD, 0x8E, + 0x7D, 0x24, 0x16, 0xA1, 0x2A, 0xEB, 0x1F, 0xDD, 0x86, 0xE5, + 0x48, 0x67, 0xAB, 0x04, 0xEC, 0x5B, 0xB7, 0xE5, 0x43, 0xC7, + 0xA2, 0xED, 0x1C, 0x93, 0x0B, 0xBB, 0x24, 0x64, 0x58, 0x2F, + 0x44, 0x45, 0x87, 0x76, 0xF2, 0xDA, 0x21, 0x07, 0xDB, 0x23, + 0x88, 0xE1, 0x6A, 0x4E, 0x8D, 0x04, 0x08, 0x18, 0xD8, 0xF0, + 0x07, 0xDB, 0x78, 0x29, 0x21, 0x3C, 0x65, 0x6A, 0x3C, 0x38, + 0xB4, 0x35, 0xE6, 0x64, 0xEB, 0x3F, 0x59, 0x62, 0x58, 0xFE, + 0xC2, 0xFA, 0x59, 0x1E, 0x5D, 0x9F, 0x02, 0xDD, 0x96, 0x4E, + 0xB7, 0x8E, 0xEA, 0xAB, 0x3B, 0x58, 0x52, 0xBF, 0xC2, 0x74, + 0x07, 0xED, 0xEF, 0x6A, 0xE9, 0x82, 0x0B, 0xC3, 0xA5, 0x03, + 0xC6, 0x78, 0xD4, 0x15, 0x3B, 0x98, 0x84, 0xEC, 0x68, 0xEC, + 0x16, 0x18, 0xB0, 0xD8, 0xF0, 0xC6, 0x60, 0x40, 0x1A, 0xDF, + 0x90, 0xF6, 0x1B, 0x81, 0x45, 0x41, 0x8E, 0x73, 0x19, 0x87, + 0x27, 0xEA, 0x85, 0x10, 0x36, 0x09, 0x86, 0x3E, 0xEB, 0xDF, + 0x04, 0x49, 0x31, 0x8A, 0xE2, 0xA3, 0x79, 0x7D, 0xB2, 0x8D, + 0xEC, 0x0E, 0x59, 0x5C, 0x2C, 0x41, 0xA7, 0xDF, 0xA2, 0x94, + 0xAC, 0xC9, 0x50, 0x09, 0xE0, 0x0C, 0x3A, 0xF3, 0x34, 0xF1, + 0x51, 0x41, 0xC6, 0x74, 0x87, 0x96, 0x5F, 0xAC, 0x23, 0xEB, + 0xC1, 0xB2, 0x75, 0x8A, 0xCF, 0x22, 0xA4, 0x72, 0xED, 0x9D, + 0x9A, 0x3A, 0x61, 0xBF, 0xC8, 0x01, 0xA6, 0x76, 0x8A, 0xAC, + 0x60, 0x00, 0xD5, 0xF2, 0x38, 0x2F, 0x24, 0x67, 0xEC, 0x0C, + 0x5B, 0x90, 0xEA, 0xC6, 0x73, 0xDC, 0xA4, 0xB1, 0xFD, 0x09, + 0xD7, 0x48, 0x88, 0x29, 0x13, 0x49, 0xFA, 0x28, 0xAA, 0x94, + 0x09, 0x5F, 0x4B, 0xE4, 0x3B, 0x0E, 0x51, 0xB2, 0x70, 0x1E, + 0xFF, 0x22, 0xE9, 0x88, 0x75, 0xC2, 0x98, 0x45, 0x76, 0x4B, + 0xFF, 0x14, 0x31, 0x81, 0x84, 0x1B, 0xE5, 0xFC, 0x72, 0x8C, + 0xD4, 0x36, 0xF2, 0x33, 0xFA, 0x11, 0xCA, 0xCD, 0xEC, 0xB6, + 0x53, 0x50, 0x9A, 0xB8, 0xC9, 0x5F, 0xEB, 0x7A, 0x3A, 0x5F, + 0x65, 0x0A, 0xBB, 0x38, 0x37, 0x0E, 0xF9, 0x34, 0x46, 0x01, + 0xF9, 0xEA, 0xF2, 0x9D, 0x85, 0x5A, 0xB0, 0x7B, 0x0A, 0xDB, + 0xD5, 0x5A, 0x90, 0x92, 0x5A, 0xE4, 0x73, 0xA2, 0xAF, 0x7E, + 0x03, 0xE0, 0x4A, 0x94, 0xC2, 0x02, 0xA8, 0x23, 0x81, 0xF3, + 0x68, 0x94, 0x26, 0x61, 0x86, 0xC0, 0x6F, 0x2A, 0x59, 0x75, + 0x01, 0x2E, 0xEA, 0x5F, 0x62, 0x68, 0x27, 0x29, 0x79, 0xE4, + 0xBE, 0x25, 0x2A, 0x91, 0xD1, 0x53, 0x25, 0xF5, 0xD3, 0x84, + 0x30, 0x8C, 0xC3, 0x8D, 0x6D, 0x9D, 0x6B, 0x46, 0xCF, 0x35, + 0x55, 0x3F, 0xD6, 0xFE, 0x33, 0x0B, 0xED, 0xFE, 0xB7, 0x34, + 0x98, 0xFC, 0xED, 0xDC, 0x56, 0x31, 0xBB, 0x85, 0x60, 0x69, + 0xC5, 0xCE, 0x67, 0xD3, 0xA9, 0xB6, 0x57, 0x4B, 0xB0, 0x77, + 0x70, 0xB3, 0x0A, 0x88, 0x02, 0x1E, 0x94, 0x99, 0xF2, 0xA2, + 0xDE, 0x40, 0x62, 0xB8, 0x2A, 0x79, 0xFD, 0xA8, 0x71, 0x57, + 0x4A, 0x8B, 0xF0, 0xA2, 0x42, 0xD5, 0x57, 0x09, 0xB2, 0x4A, + 0x39, 0x8C, 0xDF, 0x4C, 0x49, 0x1E, 0x90, 0xF7, 0xD7, 0x79, + 0xAF, 0xC3, 0x2B, 0x41, 0x13, 0xCD, 0x22, 0x51, 0x5F, 0x47, + 0x1F, 0x27, 0x1B, 0x7B, 0xEE, 0x47, 0x31, 0x69, 0xE6, 0x27, + 0x19, 0x4B, 0x8D, 0xAA, 0xE3, 0xDB, 0x00, 0x57, 0xBD, 0x6D, + 0xF3, 0xFD, 0x02, 0x45, 0xBC, 0x06, 0x7A, 0xE5, 0xA9, 0x20, + 0x2D, 0x20, 0x7E, 0x41, 0xBB, 0x92, 0xB6, 0x60, 0xF4, 0xBD, + 0xE1, 0xE8, 0x14, 0x20, 0xE1, 0x5C, 0x45, 0x66, 0x9B, 0x11, + 0x00, 0x9A, 0x04, 0x11, 0xE7, 0x95, 0x6C, 0xE3, 0xAF, 0x78, + 0x24, 0x6A, 0x17, 0xA1, 0x97, 0x59, 0x64, 0x50, 0xB2, 0xBF, + 0x87, 0x00, 0xC7, 0x32, 0x1B, 0x41, 0x4D, 0xD9, 0x24, 0xF4, + 0x4E, 0x7A, 0x8C, 0x18, 0x46, 0x77, 0xA8, 0x1F, 0x2C, 0xEE, + 0x8D, 0xBC, 0xE8, 0x2C, 0x5D, 0x87, 0x31, 0xD9, 0x76, 0xFE, + 0x7B, 0xB8, 0x77, 0xF4, 0x58, 0xD4, 0x48, 0x44, 0xFF, 0xE4, + 0x7C, 0x69, 0x47, 0x29, 0x36, 0xE6, 0x21, 0x8F, 0x8C, 0x3A, + 0x81, 0xFF, 0xDC, 0x66, 0x23, 0xEC, 0x33, 0xF9, 0x82, 0xFE, + 0xC2, 0xC6, 0xED, 0xE0, 0x2B, 0x7D, 0xF9, 0x16, 0x37, 0x84, + 0x47, 0x67, 0xAE, 0xB0, 0xB6, 0xCA, 0xCB, 0xD0, 0xBF, 0xB5, + 0x5F, 0xD1, 0xC8, 0xCD, 0xCE, 0xBF, 0x48, 0xB4, 0xDF, 0xC5, + 0x60, 0x65, 0x66, 0x71, 0x88, 0x50, 0x73, 0x95, 0x47, 0x60, + 0xC4, 0xA0, 0xAE, 0xFC, 0xC4, 0x36, 0xB9, 0xF5, 0xC0, 0xE0, + 0xBA, 0x3D, 0x76, 0x90, 0x89, 0x98, 0x75, 0x34, 0x6A, 0xD9, + 0x31, 0xC7, 0x47, 0x02, 0x88, 0x4F, 0x27, 0x2F, 0xB8, 0x67, + 0x1C, 0x0B, 0xB0, 0xDF, 0x21, 0xE3, 0x26, 0x0E, 0x5A, 0x27, + 0xF7, 0x34, 0x7D, 0x61, 0x59, 0x6B, 0xFB, 0x45, 0xA3, 0xA9, + 0xFD, 0x9A, 0x1E, 0x32, 0x91, 0x8D, 0xBA, 0xB3, 0x9C, 0x4A, + 0x8B, 0xBC, 0xE4, 0xF3, 0xF2, 0xA6, 0x7A, 0x49, 0x7D, 0x16, + 0x9D, 0xD7, 0xBC, 0xAD, 0x90, 0x41, 0xBA, 0x49, 0x24, 0x41, + 0x88, 0x46, 0xD1, 0x40, 0x11, 0x73, 0xFB, 0x6A, 0x16, 0x3C, + 0x6D, 0xDD, 0x9D, 0xB4, 0x07, 0x56, 0x63, 0xE4, 0x64, 0x2E, + 0x5A, 0x74, 0xD6, 0x98, 0x7D, 0xCF, 0x35, 0xE9, 0x41, 0x5E, + 0x10, 0x11, 0x79, 0x81, 0x8F, 0x1B, 0x67, 0x71, 0xFE, 0x05, + 0xC3, 0xDF, 0x5D, 0x08, 0x0A, 0x54, 0x1B, 0x6E, 0xB5, 0x53, + 0x77, 0xAF, 0xE8, 0x3A, 0x16, 0x57, 0x48, 0xAC, 0xB5, 0x12, + 0x9C, 0x3F, 0x44, 0xC7, 0x0A, 0xD0, 0x0E, 0xF2, 0xB2, 0xEB, + 0x54, 0x43, 0x45, 0x9C, 0x04, 0x2D, 0x32, 0xAB, 0x20, 0x9F, + 0x5C, 0x05, 0xC9, 0xD3, 0xA6, 0x15, 0xAA, 0x46, 0x36, 0x85, + 0x0E, 0xD5, 0x1F, 0x6F, 0xC3, 0xEE, 0xFD, 0xFC, 0xA1, 0x5B, + 0x80, 0xCD, 0x11, 0x9B, 0x47, 0x18, 0x01, 0x5B, 0x73, 0x06, + 0x83, 0xC8, 0xCB, 0x56, 0xD8, 0x8D, 0x3B, 0x22, 0x50, 0x7B, + 0xC8, 0x15, 0x6A, 0x33, 0xC6, 0x6A, 0xF2, 0x15, 0xC8, 0x22, + 0x49, 0x0E, 0x13, 0x95, 0x71, 0x77, 0x86, 0x7C, 0xD4, 0xF9, + 0x99, 0x8D, 0x7A, 0xCF, 0x42, 0xE3, 0x62, 0x79, 0x32, 0x5B, + 0x43, 0xDF, 0xB9, 0x9A, 0x03, 0x0E, 0x09, 0xCB, 0xBF, 0x9F, + 0x08, 0x49, 0xDB, 0x9A, 0xA5, 0x89, 0xD4, 0xE5, 0xCB, 0x48, + 0x28, 0x53, 0x67, 0x0A, 0x74, 0xA6, 0x31, 0xE6, 0xA9, 0xD7, + 0x87, 0xC3, 0xC4, 0x2B, 0xFF, 0x4F, 0x7C, 0x43, 0x67, 0xD9, + 0xAD, 0x27, 0xFB, 0xB7, 0xD7, 0xAA, 0x49, 0x1E, 0xD1, 0xB6, + 0x2D, 0xBF, 0x46, 0x71, 0xA0, 0x02, 0x8B, 0x90, 0xE1, 0x16, + 0x2A, 0x3A, 0x12, 0xC1, 0x8A, 0x79, 0x69, 0x1F, 0x79, 0xC0, + 0xB2, 0x54, 0x6D, 0x94, 0x04, 0x83, 0xC1, 0x5E, 0x96, 0x3A, + 0x13, 0xB2, 0x27, 0x19, 0x8F, 0xFE, 0xAF, 0x7A, 0x16, 0xB9, + 0xF6, 0x0E, 0x4D, 0xF7, 0xBE, 0x28, 0x9C, 0xCF, 0x07, 0xD6, + 0x1F, 0xCE, 0xED, 0xD3, 0x3B, 0xCC, 0xF0, 0xE9, 0x8C, 0x96, + 0xFD, 0x85, 0x89, 0xFB, 0x47, 0xAA, 0x98, 0xC0, 0x51, 0x2D, + 0x36, 0xEE, 0xF1, 0x5D, 0x8D, 0xD1, 0xB3, 0x0D, 0x0F, 0x9E, + 0x39, 0x1A, 0x08, 0xC1, 0x0F, 0x99, 0xD4, 0x0A, 0xD4, 0x09, + 0xCB, 0xD5, 0x29, 0xEA, 0x89, 0x66, 0x1E, 0xA7, 0xE7, 0x56, + 0xBE, 0x4B, 0xF7, 0x16, 0x2B, 0x9E, 0xD4, 0xA7, 0xF6, 0x50, + 0x08, 0x0B, 0xAA, 0x8A, 0x5E, 0x52, 0x3E, 0x49, 0x33, 0x3F, + 0x3A, 0x8D, 0xE8, 0x82, 0x1D, 0x31, 0x3A, 0x9F, 0x83, 0xAB, + 0xD8, 0xA6, 0x2C, 0xB0, 0x8A, 0x8B, 0x11, 0x5E, 0x91, 0x9F, + 0xF7, 0x0D, 0x6D, 0x80, 0x84, 0xE5, 0x62, 0x98, 0x48, 0x28, + 0xA1, 0xDA, 0xD5, 0xAD, 0x04, 0xB1, 0xB9, 0x97, 0x8D, 0xD4, + 0xDA, 0x7E, 0x6C, 0xFD, 0x2D, 0x48, 0x26, 0x15, 0x37, 0x79, + 0x8C, 0xE0, 0x84, 0x1D, 0xAD, 0xF4, 0x48, 0x9F, 0xBB, 0x53, + 0xA7, 0x87, 0x4F, 0x06, 0x24, 0x50, 0x61, 0x98, 0x0A, 0x0C, + 0x41, 0x22, 0x51, 0xB8, 0x56, 0xE8, 0x56, 0xF6, 0xD1, 0x17, + 0x1E, 0xBF, 0xBC, 0x57, 0xC8, 0x39, 0x63, 0xD8, 0xAE, 0xA1, + 0x52, 0x99, 0x8C, 0x29, 0xC5, 0x1A, 0x1B, 0xB1, 0x79, 0xD0, + 0xCB, 0xD8, 0x75, 0xA1, 0x63, 0x56, 0xA9, 0xE3, 0xC2, 0x2B, + 0x45, 0xC7, 0x05, 0x1D, 0xFD, 0x9B, 0xD6, 0x2E, 0x26, 0xC8, + 0x55, 0x81, 0xD4, 0xDA, 0x73, 0x32, 0x9F, 0x43, 0xDF, 0x03, + 0xEE, 0x3B, 0x0A, 0x02, 0x5C, 0xF8, 0x05, 0x3C, 0xBD, 0x31, + 0x38, 0x57, 0x42, 0x2F, 0x8B, 0x1F, 0xE5, 0x66, 0x35, 0x9B, + 0xD7, 0x69, 0xB7, 0x7F, 0xA5, 0x89, 0xFE, 0xD6, 0x6F, 0x8A, + 0x87, 0xB1, 0x1C, 0x2B, 0xDE, 0xAE, 0x82, 0x19, 0x3D, 0xE1, + 0xE1, 0x8F, 0xB4, 0x2E, 0x9B, 0x51, 0x61, 0xA9, 0xE2, 0x7F, + 0x14, 0x71, 0xDB, 0x37, 0x6C, 0xB1, 0xDE, 0x0A, 0x19, 0xA5, + 0x04, 0x86, 0xB0, 0x0A, 0xB6, 0x7B, 0x1B, 0x0D, 0x0C, 0xE0, + 0x0E, 0x50, 0xFB, 0x0F, 0xEA, 0xE5, 0x7C, 0x79, 0xF2, 0xC4, + 0x74, 0x82, 0xB9, 0x60, 0x69, 0xFE, 0x72, 0xB6, 0x57, 0x7C, + 0xAE, 0x1F, 0x0E, 0x97, 0x25, 0x45, 0x3D, 0xC4, 0x0D, 0x8B, + 0x64, 0x20, 0x13, 0x74, 0x47, 0x8F, 0x40, 0x98, 0xD9, 0xDB, + 0xF4, 0x7F, 0x76, 0x25, 0x4B, 0xD1, 0x58, 0x99, 0x5E, 0x8D, + 0x7D, 0x21, 0x88, 0x09, 0x30, 0x21, 0x98, 0x4D, 0xF6, 0x09, + 0x9B, 0x7C, 0x26, 0xE0, 0x92, 0x8B, 0x12, 0x1F, 0x72, 0x64, + 0xFE, 0xB3, 0xEE, 0x12, 0x52, 0x58, 0x61, 0xDA, 0x81, 0xCC, + 0x33, 0x92, 0xEC, 0x9D, 0x53, 0x97, 0x53, 0x78, 0x73, 0xE5, + 0xFE, 0xC8, 0x40, 0xBB, 0xF2, 0x1A, 0x12, 0x05, 0xCF, 0x3B, + 0x19, 0x04, 0xDB, 0xCE, 0x32, 0x60, 0x2C, 0x3A, 0x75, 0x2B, + 0xDB, 0x97, 0x9E, 0x19, 0x94, 0x49, 0xDD, 0x38, 0xAE, 0xBD, + 0x91, 0xDC, 0x31, 0x22, 0xC1, 0x97, 0xA5, 0x28, 0x2D, 0xBC, + 0x53, 0x02, 0x00, 0x79, 0x6D, 0xCB, 0xC5, 0xAF, 0x69, 0xF3, + 0x06, 0xAA, 0xBD, 0x03, 0x75, 0x8A, 0x9C, 0x62, 0xF1, 0x42, + 0x82, 0xBD, 0xC9, 0x47, 0xA3, 0xDD, 0x12, 0xAD, 0x1D, 0xEB, + 0xAE, 0x95, 0xBC, 0x88, 0xBF, 0x80, 0x16, 0x76, 0x80, 0xD3, + 0x43, 0x5A, 0x4C, 0x8A, 0x89, 0xBC, 0xD7, 0x8F, 0x21, 0x27, + 0x9E, 0x05, 0xC6, 0x56, 0x9F, 0x96, 0x1D, 0x81, 0x83, 0xDF, + 0x99, 0x12, 0xFE, 0xEA, 0x68, 0xC5, 0x9A, 0x24, 0xAE, 0xDB, + 0xA8, 0x56, 0x1F, 0xA0, 0xAC, 0xFA, 0x2D, 0xB2, 0x5D, 0xEE, + 0x49, 0xA7, 0xC8, 0x73, 0xBC, 0x91, 0x45, 0xF6, 0x6B, 0x1B, + 0x87, 0x17, 0xA4, 0x6D, 0xB8, 0x17, 0x23, 0x6B, 0x63, 0x33, + 0xE4, 0xA5, 0x06, 0xFD, 0xB2, 0x56, 0x6A, 0xEE, 0xD8, 0xD6, + 0x14, 0x30, 0x2A, 0xD6, 0x63, 0x78, 0x8B, 0x28, 0x18, 0xFA, + 0x07, 0x91, 0xAB, 0x5A, 0x3F, 0x7A, 0x37, 0xEA, 0x60, 0x81, + 0xD2, 0x72, 0x7E, 0x07, 0xEC, 0x3D, 0x87, 0x6D, 0x7F, 0x98, + 0x96, 0x07, 0x72, 0xE3, 0xFD, 0x4E, 0x60, 0x00, 0xC8, 0x6A, + 0x18, 0x8B, 0x7F, 0xA5, 0x7D, 0x59, 0x38, 0xD7, 0x57, 0x96, + 0xEA, 0xBC, 0xF2, 0xB0, 0xEF, 0x35, 0x00, 0xA2, 0x14, 0x21, + 0x00, 0xA9, 0x79, 0x35, 0x24, 0xF0, 0x3C, 0xCF, 0xB2, 0x7A, + 0xF1, 0xDF, 0x17, 0xE9, 0x54, 0xB0, 0xF3, 0x0D, 0xC8, 0xB8, + 0xB9, 0xB9, 0x34, 0xEE, 0x2A, 0x8B, 0x0B, 0x45, 0xA8, 0xDA, + 0x22, 0xFD, 0x7B, 0xCA, 0x73, 0x7A, 0x1C, 0x45, 0x47, 0x3B, + 0x0A, 0x72, 0xB1, 0xD9, 0xE2, 0xDF, 0xB1, 0xE2, 0x19, 0x96, + 0x0C, 0x98, 0xBD, 0x40, 0xDA, 0x3D, 0x28, 0xA6, 0x4A, 0x70, + 0x14, 0x4C, 0x83, 0xE8, 0x55, 0x21, 0xBF, 0xBF, 0xF4, 0x9B, + 0xED, 0x1D, 0x25, 0x32, 0x30, 0x0A, 0x34, 0x83, 0xAD, 0xD7, + 0x01, 0xD3, 0x0D, 0x58, 0xF2, 0xC6, 0x4D, 0x0A, 0x0D, 0x78, + 0xD9, 0xD7, 0xA9, 0xB6, 0x1E, 0xE0, 0xD7, 0x0E, 0xD2, 0x7B, + 0xE7, 0x70, 0x0D, 0x92, 0x83, 0x98, 0xE9, 0x46, 0x39, 0x6B, + 0xB2, 0x40, 0x84, 0x0D, 0x1E, 0x2F, 0x48, 0xBD, 0x58, 0x1E, + 0x78, 0xC2, 0xB6, 0x53, 0xB2, 0x6E, 0x45, 0x7D, 0xFD, 0xD6, + 0x32, 0xDC, 0xF4, 0x14, 0x81, 0xC3, 0x40, 0x7D, 0x51, 0xB1, + 0xF8, 0x8D, 0x2B, 0x2B, 0xE4, 0xD9, 0xB7, 0x8C, 0x20, 0xC3, + 0x51, 0x1B, 0x3B, 0xC2, 0x07, 0x0B, 0xC7, 0xD1, 0x3E, 0x04, + 0x03, 0x72, 0x2E, 0x36, 0x0E, 0x85, 0x96, 0x2B, 0x53, 0xBD, + 0x25, 0x5C, 0xED, 0x6C, 0x14, 0xB9, 0x78, 0x69, 0xFD, 0x04, + 0x19, 0x0D, 0x4B, 0x46, 0xF6, 0x6F, 0x94, 0x2A, 0x8C, 0xD6, + 0x6B, 0xBA, 0x24, 0x47, 0x91, 0xA7, 0x1B, 0xC7, 0x68, 0xAF, + 0x99, 0x8E, 0x44, 0x58, 0x3F, 0x09, 0xD4, 0x91, 0x5F, 0x74, + 0xE4, 0x9E, 0x08, 0x40, 0x26, 0x69, 0xDE, 0xC8, 0xE3, 0x62, + 0xAF, 0xE2, 0xAC, 0x9F, 0xD4, 0xB9, 0xF6, 0x38, 0x44, 0xD3, + 0x3D, 0x66, 0x5D, 0x3C, 0xA2, 0x3E, 0xE2, 0x9E, 0xA8, 0x0E, + 0x9B, 0x26, 0x50, 0x48, 0x3A, 0x2F, 0xD5, 0x0C, 0xBF, 0xEC, + 0x38, 0xC4, 0x7F, 0x96, 0xD6, 0x53, 0x1B, 0x84, 0x39, 0x32, + 0x45, 0x11, 0xC5, 0xA7, 0xAC, 0x74, 0x4E, 0xAA, 0x5E, 0x9F, + 0xC4, 0xD5, 0xC4, 0x5B, 0x80, 0x0A, 0x22, 0x4A, 0xB6, 0xF5, + 0xCD, 0x8C, 0x67, 0x11, 0xF3, 0x32, 0xA4, 0x5D, 0x85, 0x2C, + 0x56, 0x4D, 0x21, 0x94, 0x3B, 0x75, 0x88, 0x32, 0x13, 0x26, + 0x72, 0x47, 0x9E, 0x2C, 0xBC, 0x0A, 0xF9, 0xB0, 0x07, 0x93, + 0x21, 0x30, 0x0D, 0x06, 0x17, 0xAE, 0x0E, 0xBB, 0x5C, 0xAD, + 0x2A, 0x6D, 0x50, 0x66, 0x28, 0x3D, 0xE3, 0x32, 0x6B, 0x95, + 0x93, 0x4A, 0xF4, 0xB2, 0x2A, 0x35, 0xD6, 0x12, 0x35, 0xFE, + 0x82, 0x1D, 0x9E, 0xDA, 0x18, 0x97, 0x89, 0xBE, 0xE6, 0xF8, + 0x9C, 0x89, 0x31, 0x35, 0x53, 0x93, 0xEF, 0x51, 0x7C, 0xE3, + 0x2E, 0x83, 0x44, 0x02, 0xEB, 0x68, 0x66, 0x7E, 0xE7, 0xE5, + 0xD0, 0x9E, 0x12, 0xAB, 0x37, 0x48, 0x71, 0xEE, 0xE8, 0x8C, + 0xF4, 0x91, 0x85, 0x29, 0xFB, 0xCA, 0x49, 0x43, 0xC9, 0x2C, + 0x59, 0x8A, 0x24, 0xBD, 0x3F, 0x91, 0xD5, 0x86, 0x33, 0xC4, + 0x62, 0x9B, 0xB1, 0x99, 0x2A, 0x5A, 0x86, 0x6A, 0x78, 0x7B, + 0x9A, 0x1E, 0xC6, 0x08, 0x34, 0x57, 0x6B, 0x67, 0xA5, 0xE4, + 0xC9, 0x2D, 0x79, 0xEF, 0x74, 0xD6, 0xF0, 0x0B, 0xC7, 0x92, + 0x95, 0x45, 0xF0, 0x8E, 0x0C, 0x91, 0x87, 0x92, 0x4C, 0xFF, + 0xCF, 0x68, 0x30, 0xE3, 0xA1, 0x6C, 0xEE, 0x4D, 0xD1, 0xE9, + 0x76, 0xD0, 0xB2, 0x14, 0x9E, 0x41, 0x8C, 0x48, 0x84, 0xD0, + 0x74, 0x7A, 0xC6, 0xC7, 0x24, 0x28, 0x54, 0x5F, 0xED, 0x64, + 0xB6, 0x07, 0xC1, 0x7A, 0x24, 0xE5, 0x53, 0x32, 0x73, 0xF3, + 0x92, 0x2E, 0xBC, 0x41, 0x11, 0x23, 0x93, 0x90, 0x7C, 0x2C, + 0xDA, 0x08, 0x4F, 0x1E, 0xA5, 0xC4, 0xC1, 0xC6, 0x17, 0x53, + 0x8C, 0xD4, 0x05, 0x27, 0xCD, 0xDD, 0x8E, 0x8E, 0xC6, 0xFB, + 0x64, 0x14, 0x9F, 0xDF, 0x5E, 0x74, 0xFD, 0x60, 0x6C, 0xD1, + 0xC7, 0x7E, 0x09, 0xAE, 0xA7, 0x25, 0x3D, 0xE5, 0x1F, 0x85, + 0xA0, 0x34, 0x62, 0xE9, 0xE1, 0x59, 0x29, 0xEF, 0xD4, 0x0E, + 0xE0, 0x48, 0x78, 0x9A, 0x71, 0x9F, 0xFD, 0x2D, 0xD6, 0xB9, + 0xBB, 0x78, 0x70, 0x16, 0x4F, 0x74, 0xCC, 0x32, 0x07, 0x87, + 0xDD, 0x3D, 0x6E, 0x7B, 0x01, 0x67, 0x32, 0xB2, 0xAE, 0x5F, + 0x2A, 0xF7, 0xE0, 0x23, 0xCE, 0xF2, 0xDD, 0x85, 0x27, 0xBE, + 0x44, 0xC2, 0xC5, 0xE4, 0xB1, 0x92, 0xFF, 0xD6, 0x87, 0x49, + 0xF9, 0xDE, 0xCF, 0x5D, 0x95, 0xDD, 0xD9, 0x74, 0x06, 0xFE, + 0xC1, 0x6E, 0x31, 0x16, 0x6F, 0x4F, 0x6E, 0xC7, 0x4A, 0xCF, + 0x86, 0x75, 0xDD, 0xF9, 0x22, 0xA9, 0x44, 0xF5, 0x65, 0xE8, + 0xDE, 0x70, 0x84, 0x63, 0x9A, 0x92, 0x9C, 0x55, 0xA1, 0x2C, + 0xED, 0x8A, 0xD9, 0x27, 0x61, 0x2A, 0x7D, 0x53, 0x28, 0xF3, + 0xE6, 0x1F, 0xF1, 0xD2, 0x60, 0xEF, 0x04, 0x35, 0xAC, 0xF3, + 0x52, 0x43, 0x9F, 0x5E, 0xB5, 0xC8, 0xDB, 0xB9, 0x9F, 0x11, + 0x1F, 0x8E, 0x20, 0xE9, 0x03, 0x38, 0xA6, 0x90, 0x29, 0x4C, + 0x1F, 0xCE, 0xC0, 0x56, 0x88, 0x73, 0x53, 0xEF, 0x00, 0x3D, + 0x68, 0x62, 0x42, 0x02, 0x2A, 0x93, 0x98, 0x65, 0x95, 0x8B, + 0x77, 0x7A, 0xB9, 0xD8, 0xB3, 0xB3, 0x78, 0x6E, 0x88, 0x56, + 0x74, 0x25, 0x8B, 0x44, 0x4E, 0xC3, 0x98, 0xE0, 0xCC, 0xCE, + 0x40, 0xB7, 0x05, 0x8D, 0x18, 0x7A, 0x45, 0xFA, 0x90, 0xF6, + 0x0E, 0x9D, 0x98, 0x3F, 0xB6, 0x99, 0x4E, 0x16, 0x2F, 0x62, + 0x23, 0xB8, 0x8D, 0x6E, 0x43, 0x71, 0xAE, 0x3C, 0x2F, 0xA2, + 0x6C, 0x06, 0xDD, 0xF7, 0xB4, 0x53, 0x32, 0x34, 0xB0, 0x47, + 0x04, 0x2A, 0x1E, 0xDE, 0x0F, 0x47, 0xBF, 0xEF, 0xE9, 0xC8, + 0x5D, 0xE2, 0xBE, 0xE1, 0xCA, 0x73, 0xB3, 0xE0, 0x5A, 0xEA, + 0x75, 0x1D, 0x50, 0x90, 0xF2, 0xF6, 0xAC, 0x8F, 0x2A, 0xA0, + 0x88, 0x32, 0xB6, 0x2A, 0xAB, 0x2E, 0x46, 0xBE, 0x4D, 0x43, + 0x48, 0x41, 0x55, 0x9A, 0xAB, 0x46, 0x29, 0x74, 0xA3, 0xB3, + 0x31, 0x3B, 0x1A, 0x67, 0x41, 0x83, 0x70, 0x5A, 0x55, 0xB1, + 0xFF, 0x6A, 0x70, 0x65, 0x78, 0xAC, 0x4E, 0xD7, 0x60, 0x78, + 0x81, 0xC5, 0x80, 0xB3, 0x5E, 0x47, 0x11, 0xD5, 0xE1, 0xC7, + 0x87, 0x63, 0xA3, 0x60, 0x4B, 0xA4, 0xB2, 0x44, 0x4B, 0x35, + 0x14, 0x01, 0x19, 0x8B, 0x8A, 0x3A, 0x4A, 0x5A, 0x90, 0xA3, + 0x60, 0x78, 0xB1, 0x56, 0x5E, 0xB5, 0x85, 0x75, 0xCD, 0x65, + 0xA6, 0x84, 0xAE, 0x59, 0x49, 0x5D, 0x23, 0x80, 0x83, 0x78, + 0x1B, 0xED, 0x19, 0x8A, 0x88, 0xA2, 0x9F, 0x11, 0x70, 0xF3, + 0xB8, 0x20, 0x20, 0xDD, 0x79, 0x90, 0xCD, 0xB3, 0x9C, 0xB8, + 0x2C, 0xD3, 0xAD, 0x5F, 0xD7, 0x50, 0xBC, 0x5A, 0xE9, 0x46, + 0x75, 0x07, 0x92, 0xE3, 0x7D, 0x90, 0x22, 0x1C, 0x66, 0x20, + 0x92, 0x2A, 0x1D, 0x65, 0xA6, 0x40, 0x12, 0xDB, 0x7B, 0x54, + 0x5E, 0x69, 0x7E, 0xDD, 0x74, 0x54, 0xCF, 0xB7, 0xEC, 0xEC, + 0x4B, 0x02, 0x57, 0x9D, 0x01, 0x61, 0x38, 0x55, 0x9D, 0x79, + 0xFE, 0x1B, 0x18, 0xFA, 0x01, 0xDF, 0xBF, 0x39, 0x9C, 0xCF, + 0x0E, 0x45, 0xE0, 0x35, 0x87, 0x92, 0xC6, 0xF3, 0x5B, 0xE8, + 0xE0, 0xE8, 0x75, 0x4A, 0x0C, 0xDD, 0x61, 0x15, 0x0E, 0x8D, + 0x8F, 0x8C, 0xA1, 0x78, 0x6D, 0x41, 0x57, 0x26, 0x43, 0xC0, + 0x02, 0xC3, 0xAE, 0x34, 0x6E, 0x20, 0xF6, 0xA9, 0x8C, 0x0C, + 0x5D, 0xF0, 0xED, 0x9F, 0x1D, 0x93, 0xDD, 0xC4, 0xA8, 0xEE, + 0xE6, 0x57, 0x61, 0x53, 0xEF, 0x8B, 0x94, 0xC4, 0x35, 0xA8, + 0xD5, 0x3D, 0x7E, 0xD8, 0x0E, 0x04, 0x3E, 0xF6, 0x24, 0x38, + 0xB4, 0x85, 0xC9, 0xE4, 0xEE, 0x5C, 0xA1, 0x52, 0xA9, 0x4D, + 0x37, 0x24, 0xD1, 0xA0, 0x41, 0xF6, 0xF0, 0x68, 0x40, 0x9A, + 0x28, 0xC7, 0x24, 0x5F, 0x84, 0x5A, 0xBB, 0x60, 0x54, 0xAB, + 0x42, 0xDA, 0x39, 0x5D, 0x0B, 0xB9, 0x02, 0xF8, 0xB4, 0xF7, + 0x36, 0xCC, 0x77, 0x30, 0x78, 0xFF, 0x38, 0x4F, 0x5A, 0x08, + 0xAD, 0x54, 0x67, 0x4C, 0x50, 0xC2, 0x30, 0x96, 0xA2, 0xE0, + 0x24, 0x6D, 0x9D, 0xD2, 0x56, 0xE2, 0x8C, 0x80, 0x27, 0x45, + 0x48, 0xA5, 0x8F, 0x71, 0x4F, 0xA3, 0x72, 0x24, 0x98, 0xFE, + 0xD6, 0xF1, 0x1B, 0xD5, 0xFA, 0xC2, 0x50, 0x19, 0x44, 0x4E, + 0xF6, 0xFB, 0x78, 0x1D, 0x99, 0xED, 0x81, 0xD9, 0x5E, 0x0A, + 0x94, 0x03, 0x70, 0xA8, 0xFC, 0x32, 0x4D, 0xA7, 0x41, 0x43, + 0x84, 0x89, 0x5F, 0xE5, 0xCF, 0xD2, 0xB2, 0x7F, 0x99, 0xB2, + 0xAB, 0xB1, 0xA4, 0x29, 0x99, 0xC4, 0xD1, 0x9E, 0xE7, 0xF2, + 0x88, 0xB1, 0x93, 0xD8, 0xF3, 0xBF, 0xAE, 0xC9, 0x1A, 0xFF, + 0xEA, 0x77, 0xC2, 0xCF, 0xFF, 0xBB, 0xD5, 0x05, 0x12, 0xDC, + 0x17, 0xE2, 0xD9, 0x72, 0xF1, 0x0A, 0x18, 0x75, 0xA2, 0x97, + 0xAF, 0x4F, 0xF6, 0xDE, 0xBC, 0x61, 0xBD, 0xCC, 0x0F, 0xC2, + 0x59, 0x28, 0xB5, 0x9C, 0x97, 0xE8, 0x92, 0xC6, 0x6E, 0x42, + 0x08, 0x4D, 0x5F, 0x16, 0xC2, 0x26, 0xD1, 0xAD, 0x0E, 0x63, + 0x7E, 0x98, 0xC3, 0x63, 0xE1, 0xA5, 0x4F, 0xF1, 0x54, 0x3D, + 0x43, 0x3F, 0xBE, 0x31, 0x2A, 0xF3, 0x3F, 0x63, 0x00, 0x99, + 0xAC, 0x77, 0x20, 0xC5, 0x7F, 0x3E, 0x11, 0xC3, 0x11, 0x83, + 0x6D, 0xB0, 0x51, 0x24, 0x0E, 0xAF, 0x7D, 0xEE, 0x59, 0x68, + 0xE1, 0x87, 0x98, 0x05, 0x08, 0x92, 0x62, 0x70, 0xF5, 0xDF, + 0xBE, 0x77, 0xD1, 0x11, 0xF8, 0x48, 0x26, 0xBB, 0xFE, 0x74, + 0xA7, 0xE9, 0xC5, 0x9E, 0x7D, 0x2D, 0x74, 0x6E, 0x5F, 0xFB, + 0xA2, 0xF9, 0x53, 0x32, 0x68, 0x6F, 0x86, 0xF2, 0x76, 0x07, + 0x2B, 0xA6, 0x38, 0x86, 0xE9, 0x30, 0xB4, 0x60, 0x55, 0x62, + 0xDA, 0xF4, 0xB1, 0xC0, 0x48, 0x02, 0x2A, 0x77, 0x14, 0xA8, + 0x89, 0x51, 0xCB, 0x0D, 0xC4, 0xB4, 0x94, 0xD0, 0x2B, 0x8B, + 0x32, 0x17, 0x2E, 0xC9, 0xD2, 0x35, 0xCF, 0x30, 0xE8, 0x10, + 0x04, 0xBE, 0xA6, 0x2D, 0xF0, 0x73, 0x4E, 0x02, 0xDA, 0xD5, + 0x8F, 0x96, 0x88, 0x2D, 0x5D, 0xD0, 0xCC, 0x87, 0xE9, 0xD1, + 0xCE, 0x4B, 0xBE, 0xC1, 0x2E, 0xCB, 0xA7, 0x69, 0x4F, 0x41, + 0xF4, 0x7D, 0x36, 0x2B, 0xFF, 0x06, 0xD9, 0x7E, 0x5B, 0x89, + 0x0F, 0x89, 0x69, 0x3E, 0xF4, 0xD4, 0xB0, 0x34, 0xF0, 0x91, + 0x0D, 0xE2, 0x8B, 0x23, 0x95, 0x09, 0xD9, 0xE6, 0x15, 0xE9, + 0x8F, 0xA3, 0x1C, 0x6A, 0x8B, 0x12, 0x1E, 0x26, 0x38, 0x2E, + 0x3F, 0x08, 0x94, 0x59, 0xC0, 0x58, 0xCF, 0xB9, 0xC4, 0xB5, + 0xFD, 0xE2, 0x29, 0x81, 0xE5, 0x7A, 0x9B, 0x04, 0xFC, 0xC9, + 0x3D, 0xF5, 0xD3, 0x91, 0x3C, 0x49, 0x1D, 0xEB, 0x08, 0x64, + 0xAA, 0xF7, 0x3C, 0x56, 0x18, 0x13, 0x9C, 0x94, 0xAB, 0x49, + 0x59, 0xEB, 0x1F, 0x8C, 0x6B, 0x12, 0x0C, 0x3A, 0x22, 0x97, + 0x1A, 0xE9, 0x7C, 0xF7, 0xC4, 0x42, 0x1D, 0x4D, 0x9D, 0x2C, + 0x4E, 0x1C, 0xF1, 0x2E, 0x75, 0xDA, 0x8B, 0xE7, 0xCF, 0xB8, + 0x77, 0x5B, 0xF5, 0xBF, 0xB7, 0xF6, 0x23, 0x4F, 0xA9, 0x39, + 0x50, 0xB2, 0x12, 0xE7, 0x43, 0x69, 0x68, 0xD5, 0x3C, 0xEC, + 0xDC, 0x0C, 0x19, 0x67, 0xB6, 0x4A, 0x76, 0x3B, 0xA7, 0x41, + 0x83, 0xA2, 0x42, 0xB6, 0xC6, 0xD7, 0x99, 0x5C, 0x3A, 0x1A, + 0x05, 0xE6, 0x85, 0x3D, 0xFF, 0xA2, 0x6C, 0x4A, 0xD9, 0x60, + 0xA4, 0x3C, 0x17, 0x55, 0xFF, 0xAE, 0x59, 0xE7, 0x47, 0xE8, + 0xC3, 0xD9, 0xC0, 0xEF, 0x1F, 0xCF, 0xEA, 0xB3, 0xF5, 0x84, + 0xA8, 0x77, 0x27, 0xF4, 0xF7, 0x01, 0x07, 0x6F, 0x2F, 0x53, + 0x45, 0x4E, 0x73, 0x8C, 0xB2, 0x0E, 0x82, 0x8F, 0x3D, 0x71, + 0x85, 0xF8, 0xCF, 0xA0, 0x5F, 0x7B, 0x3D, 0x9D, 0x1A, 0x94, + 0xF6, 0xC0, 0xDC, 0xE7, 0xCC, 0xC6, 0xAC, 0x95, 0x76, 0x5A, + 0xA9, 0xAF, 0xA0, 0x82, 0x6C, 0x24, 0x6A, 0x50, 0x0E, 0xB7, + 0x49, 0x84, 0x08, 0x4C, 0x79, 0x6D, 0x5B, 0x4C, 0x13, 0xB7, + 0x1D, 0x4A, 0x83, 0xC2, 0x0A, 0x87, 0xB4, 0x1B, 0x15, 0xED, + 0x11, 0x1B, 0x3C, 0x08, 0xA1, 0x06, 0x1C, 0xE2, 0x9F, 0x32, + 0x01, 0x13, 0x47, 0x95, 0x63, 0xD5, 0xEF, 0xEA, 0xA3, 0xD3, + 0x03, 0xF2, 0x33, 0x17, 0xE3, 0x62, 0x0B, 0x02, 0xF2, 0xF5, + 0x2F, 0xB9, 0x17, 0xC1, 0xF7, 0xD2, 0x7F, 0x03, 0x46, 0x4A, + 0x5D, 0x71, 0xD9, 0xB5, 0x34, 0xAF, 0xDE, 0xBC, 0x86, 0xC9, + 0x4F, 0xE3, 0x6E, 0xE9, 0xF4, 0x13, 0x99, 0x3A, 0x04, 0xAF, + 0x7F, 0x82, 0xB1, 0xE4, 0x82, 0xD6, 0xFF, 0x5D, 0xAF, 0xC7, + 0xFF, 0x9C, 0xC9, 0xA5, 0xE1, 0xAC, 0xC6, 0xA5, 0xF3, 0x16, + 0x46, 0x22, 0xFD, 0x9A, 0x41, 0x17, 0x83, 0xA2, 0x5A, 0xD6, + 0x92, 0xE5, 0x36, 0x2C, 0x35, 0x44, 0x04, 0x7B, 0x86, 0x42, + 0xEB, 0x2D, 0xC9, 0xD9, 0xFB, 0x15, 0x4B, 0x22, 0x6F, 0x90, + 0x2F, 0xC9, 0x00, 0xA6, 0x51, 0xC0, 0xED, 0x8A, 0xCB, 0x28, + 0xD3, 0xC2, 0x7B, 0x19, 0xB6, 0x5B, 0x76, 0x05, 0xF8, 0xB8, + 0xB7, 0x59, 0x22, 0xFA, 0xCC, 0xEF, 0x85, 0xFA, 0xC6, 0x1D, + 0x8E, 0x3F, 0xEC, 0x08, 0xC1, 0x7F, 0xA3, 0xA4, 0xF1, 0xFE, + 0x89, 0xD2, 0xDD, 0x41, 0xD1, 0x59, 0x2B, 0xE3, 0x46, 0x99, + 0xAB, 0x8A, 0xB7, 0xB1, 0x36, 0x94, 0x02, 0x7B, 0x24, 0x06, + 0xB5, 0x02, 0xDB, 0x4F, 0x8D, 0x35, 0xC7, 0xA4, 0x92, 0xFD, + 0x68, 0xC9, 0x6E, 0x6D, 0xD2, 0x70, 0xAD, 0x31, 0x74, 0x07, + 0xC2, 0xE7, 0xC1, 0x62, 0x05, 0x75, 0xE9, 0x72, 0xC2, 0xAD, + 0xA3, 0xCF, 0x5B, 0x0F, 0xD3, 0x47, 0x3B, 0xA4, 0x0F, 0x67, + 0xDD, 0x3D, 0xD6, 0x58, 0x4D, 0x56, 0xD0, 0xA0, 0x9D, 0x90, + 0xC2, 0x18, 0x28, 0x3B, 0xA9, 0xEF, 0x90, 0x06, 0x8B, 0xB0, + 0xF5, 0x9A, 0xF3, 0x6E, 0x6B, 0x73, 0x80, 0xAA, 0xF6, 0xFD, + 0x67, 0xAB, 0x55, 0xB5, 0x48, 0x47, 0xA8, 0xF6, 0xA1, 0x20, + 0x63, 0xC7, 0x7A, 0x9B, 0x07, 0xBC, 0x31, 0x44, 0xD6, 0xFF, + 0x8F, 0x07, 0xA5, 0xCB, 0x9F, 0xF5, 0x5A, 0xEB, 0x13, 0x87, + 0x4B, 0xEF, 0xD4, 0xF3, 0x99, 0xCA, 0x7D, 0xE1, 0x28, 0xE9, + 0x56, 0xB4, 0x22, 0x5B, 0xB1, 0x98, 0x70, 0x0C, 0x77, 0x06, + 0x96, 0x49, 0xC9, 0x98, 0x1B, 0x13, 0x76, 0xAA, 0x6F, 0xEC, + 0x48, 0x0B, 0x49, 0xE9, 0x8C, 0x18, 0x1E, 0x3D, 0x81, 0x84, + 0xAD, 0xF2, 0xE2, 0x55, 0x6A, 0xB6, 0x98, 0x5A, 0x8D, 0x2A, + 0x31, 0x89, 0x79, 0x2B, 0x66, 0x62, 0x04, 0x57, 0xF1, 0x0C, + 0x10, 0x01, 0x54, 0xE9, 0xD2, 0xE9, 0x61, 0x6A, 0x42, 0x81, + 0x74, 0x4A, 0xFE, 0x19, 0xF2, 0x46, 0x6F, 0x4F, 0x9C, 0xF0, + 0xE4, 0xC6, 0xB9, 0x32, 0x65, 0xA7, 0x5F, 0xBE, 0xB0, 0x4A, + 0x4D, 0xF0, 0x74, 0x4E, 0x51, 0xBE, 0xC0, 0xB8, 0xDB, 0xB6, + 0x6E, 0xB1, 0xAD, 0x1D, 0xC4, 0xF7, 0x91, 0x68, 0x6A, 0xEF, + 0x38, 0xC3, 0xDE, 0x97, 0xB2, 0x3A, 0x45, 0xD5, 0x75, 0xB9, + 0xB8, 0xBC, 0x7A, 0x84, 0x70, 0x84, 0x41, 0x5F, 0xF6, 0x98, + 0xB8, 0x93, 0xAA, 0x69, 0x32, 0x66, 0x93, 0xB3, 0xC4, 0x80, + 0x50, 0x42, 0x8E, 0x1D, 0x29, 0x9E, 0xED, 0x56, 0x42, 0x77, + 0x06, 0xD9, 0x81, 0x40, 0x05, 0xFD, 0x2A, 0xC2, 0x52, 0x66, + 0x58, 0xD0, 0x95, 0x38, 0xD6, 0x3F, 0xE9, 0x57, 0xD7, 0xDC, + 0x4C, 0x3D, 0x4E, 0x75, 0xA8, 0x75, 0xEE, 0xB3, 0xB2, 0x4E, + 0x55, 0x85, 0xB2, 0x13, 0x14, 0x80, 0xA8, 0xB5, 0x38, 0x7F, + 0xFD, 0x86, 0x57, 0x43, 0x59, 0xE1, 0x2B, 0x9F, 0x72, 0xAA, + 0x1D, 0xCE, 0x03, 0x28, 0xE3, 0x39, 0x8E, 0x91, 0x36, 0x3B, + 0xDC, 0x80, 0x86, 0x2D, 0xB4, 0x4C, 0xA6, 0x9F, 0x4C, 0xA0, + 0x3F, 0x76, 0xB8, 0x1B, 0x4A, 0x9D, 0x6F, 0x50, 0x17, 0x35, + 0x90, 0x63, 0x7E, 0x45, 0xE4, 0xF6, 0xF8, 0x03, 0x59, 0x49, + 0xDB, 0x7B, 0x4B, 0xC9, 0x6A, 0x97, 0x6B, 0x04, 0xEF, 0xEB, + 0x7D, 0xCA, 0xA2, 0x9B, 0x42, 0x58, 0x3E, 0xAB, 0xFF, 0xC9, + 0xDB, 0xAD, 0xD3, 0xBB, 0x14, 0x31, 0x3B, 0xDA, 0x6C, 0x1B, + 0xC5, 0x12, 0xDA, 0x02, 0x76, 0x68, 0x58, 0xEB, 0xF0, 0x5E, + 0x6B, 0xAB, 0xC6, 0xE5, 0x16, 0x05, 0x89, 0x56, 0x3D, 0xA2, + 0x7D, 0x32, 0x8A, 0xD7, 0xD1, 0x51, 0xB2, 0xE8, 0x74, 0x1A, + 0xC2, 0x86, 0x4C, 0xF3, 0x2B, 0x24, 0xB6, 0x7F, 0x9B, 0x9B, + 0xD5, 0x67, 0x77, 0x43, 0xFA, 0xDA, 0xAC, 0x08, 0x40, 0x8A, + 0xA9, 0x19, 0xCF, 0x1D, 0xB1, 0x48, 0x32, 0x21, 0xA8, 0x0C, + 0x8C, 0xD0, 0x60, 0x38, 0xE3, 0xB9, 0x76, 0xA5, 0x20, 0xDB, + 0x8D, 0xB5, 0x08, 0xA1, 0x8E, 0x6F, 0xD7, 0xA8, 0x65, 0x49, + 0x53, 0x05, 0xFB, 0xD3, 0xE6, 0x36, 0x37, 0xD1, 0x06, 0xFA, + 0x4B, 0x53, 0x19, 0x3C, 0xC3, 0xD5, 0x2A, 0x0F, 0x4C, 0x7F, + 0x1B, 0x0B, 0xB4, 0x43, 0x16, 0xE0, 0xCE, 0xDF, 0x00, 0x1D, + 0x9C, 0xDB, 0xFB, 0x0B, 0x33, 0x0B, 0xC9, 0xA8, 0xDA, 0x28, + 0x03, 0x5C, 0x36, 0xE3, 0xE4, 0x45, 0x2D, 0x6C, 0x17, 0x50, + 0x67, 0xCE, 0x6A, 0x9E, 0x5E, 0x81, 0x9C, 0x27, 0xBC, 0x71, + 0x48, 0x24, 0x8C, 0x4E, 0x9E, 0x27, 0xC1, 0x6B, 0x82, 0xA6, + 0x50, 0x64, 0x7D, 0xD8, 0xD0, 0xD9, 0xA0, 0xE2, 0xCB, 0x59, + 0x57, 0xF8, 0x43, 0x20, 0x1D, 0xDB, 0x81, 0xB2, 0x39, 0x49, + 0x95, 0x17, 0xDD, 0x89, 0xED, 0x48, 0x71, 0xFF, 0x36, 0x10, + 0xCB, 0x16, 0xFF, 0x32, 0x03, 0xD2, 0x38, 0xDC, 0x43, 0xBF, + 0x76, 0xF3, 0x49, 0x6E, 0xB2, 0xAD, 0x6A, 0xF4, 0x29, 0xCF, + 0x7C, 0x7C, 0xD5, 0x86, 0xFC, 0xB5, 0x44, 0x77, 0x53, 0x2D, + 0x35, 0xFC, 0x18, 0xDC, 0xBA, 0x9F, 0x34, 0x0D, 0x33, 0xE2, + 0x5B, 0x80, 0x35, 0x4C, 0xCC, 0x3C, 0x65, 0xC2, 0x64, 0x29, + 0xD5, 0x29, 0x10, 0xEC, 0x3A, 0xCC, 0x5B, 0x47, 0x53, 0x3A, + 0xCB, 0x35, 0x01, 0xEC, 0x5D, 0xFF, 0x32, 0x0E, 0xBC, 0x9A, + 0x02, 0x35, 0xAA, 0xD3, 0x4F, 0x7C, 0x1B, 0xA1, 0x40, 0x06, + 0x54, 0xC2, 0x0A, 0xC2, 0x30, 0xFF, 0x16, 0x8E, 0xAF, 0x89, + 0xB4, 0x41, 0x58, 0x48, 0xD6, 0x1C, 0x02, 0x5C, 0x62, 0x7F, + 0x53, 0x23, 0x86, 0x81, 0x29, 0x69, 0x81, 0xE9, 0x87, 0x29, + 0x90, 0x6C, 0x46, 0xEA, 0x2F, 0x5B, 0x94, 0x44, 0x46, 0x37, + 0x7C, 0x62, 0x62, 0x3A, 0x5F, 0xF6, 0x16, 0x8F, 0xA1, 0x9D, + 0xE1, 0xDB, 0x0E, 0x43, 0xE4, 0x81, 0x8F, 0x84, 0xFA, 0xAE, + 0xB5, 0xD1, 0x62, 0x10, 0x15, 0x86, 0xB1, 0xB4, 0xAB, 0x2D, + 0x7B, 0x9C, 0xFF, 0xB2, 0x2C, 0xF4, 0x8D, 0x59, 0xCF, 0x25, + 0x85, 0x60, 0xBF, 0xEA, 0xD9, 0xA6, 0x93, 0x61, 0x47, 0xE2, + 0xAB, 0xD1, 0xE3, 0x35, 0x73, 0xC6, 0x48, 0x5A, 0x78, 0xA6, + 0x4A, 0xF9, 0x6E, 0x42, 0xB0, 0xC8, 0x2B, 0x7B, 0x30, 0x3A, + 0x6D, 0xF7, 0x33, 0x89, 0xF8, 0xB0, 0xCB, 0xF7, 0x45, 0x6D, + 0xDF, 0x47, 0x8F, 0xA3, 0x7B, 0x9D, 0x95, 0x1C, 0x81, 0xC0, + 0x36, 0xE1, 0xBC, 0x1F, 0x78, 0xDF, 0xC0, 0x63, 0x19, 0x3C, + 0xA9, 0xCF, 0x15, 0xEF, 0xCC, 0x34, 0x57, 0x6E, 0xD8, 0xB5, + 0x2C, 0x1C, 0xC9, 0x8B, 0x28, 0xEA, 0xBC, 0x8B, 0x76, 0x7A, + 0x03, 0x1A, 0x90, 0x28, 0x7E, 0x3F, 0xA7, 0xC1, 0x1C, 0xE6, + 0x9E, 0xB8, 0xA1, 0x4D, 0x8E, 0x34, 0x6F, 0x6C, 0xDB, 0x21, + 0xDD, 0xCD, 0xB8, 0xEB, 0x67, 0x34, 0xAD, 0x5F, 0xE5, 0x2C, + 0xA9, 0x1C, 0x04, 0x73, 0x51, 0xA5, 0x1E, 0x85, 0x39, 0x1D, + 0x1B, 0x0F, 0x44, 0x97, 0x1D, 0xD8, 0x3C, 0xE5, 0x33, 0x65, + 0x8A, 0xEA, 0x5B, 0xFD, 0x60, 0xA9, 0x9B, 0x4F, 0x1E, 0xCB, + 0xAB, 0xD0, 0x82, 0xB2, 0xF7, 0xF6, 0xE5, 0x0B, 0x9C, 0xCA, + 0xDA, 0x52, 0xD2, 0xBD, 0x03, 0x22, 0x14, 0x50, 0x0C, 0x00, + 0xDE, 0x9E, 0x17, 0xEF, 0x08, 0x70, 0x23, 0xE4, 0xD8, 0xAF, + 0x31, 0x2A, 0x81, 0x75, 0xC8, 0x55, 0x17, 0xBE, 0xB9, 0xC9, + 0x94, 0xD5, 0xC9, 0xA2, 0x17, 0x59, 0x8C, 0xA4, 0x69, 0x52, + 0x97, 0x22, 0x8D, 0x8F, 0x6D, 0x0B, 0x60, 0xB3, 0xE9, 0x18, + 0xE3, 0xAF, 0x19, 0xAA, 0xBB, 0xC8, 0x73, 0xD4, 0x21, 0x01, + 0x1A, 0xFF, 0x34, 0x40, 0x06, 0xD0, 0xF8, 0x57, 0x4D, 0x5F, + 0x9D, 0x9C, 0x0E, 0xCD, 0xCC, 0x54, 0xEE, 0x0F, 0x1F, 0x22, + 0xE5, 0xB8, 0x22, 0xE7, 0x64, 0x85, 0xC9, 0x50, 0x8C, 0xAD, + 0xB7, 0x97, 0x0A, 0x10, 0x99, 0x2D, 0xBD, 0x08, 0xCC, 0x1C, + 0x2A, 0x4A, 0xA7, 0xE0, 0xFE, 0xD8, 0x7E, 0x52, 0x3D, 0x08, + 0x46, 0x72, 0xE4, 0x6C, 0xC9, 0x12, 0x4E, 0x21, 0xFB, 0x14, + 0x0F, 0x54, 0x6E, 0xFF, 0xB1, 0x81, 0xAF, 0xA1, 0x25, 0xC1, + 0x27, 0x16, 0xF7, 0x24, 0x5C, 0x0A, 0x4D, 0xED, 0x5B, 0x81, + 0x47, 0x62, 0x5B, 0xA4, 0xE2, 0x4A, 0xD3, 0x50, 0xE1, 0x10, + 0xFB, 0x61, 0x0C, 0x55, 0x47, 0xAC, 0x03, 0xE2, 0x63, 0x5C, + 0x33, 0xA3, 0x59, 0xEE, 0x94, 0x20, 0x41, 0x52, 0xAD, 0xED, + 0x06, 0x7F, 0x46, 0x41, 0xE1, 0xF7, 0x66, 0x90, 0x56, 0x07, + 0xCF, 0x37, 0x15, 0xDC, 0x20, 0x60, 0x3B, 0x9D, 0xB7, 0x85, + 0x12, 0x62, 0x9D, 0x2A, 0xAE, 0x95, 0xD6, 0x05, 0x15, 0x31, + 0xEB, 0x86, 0xC8, 0x3F, 0xA6, 0x3F, 0xC1, 0xD1, 0x36, 0xA0, + 0xD2, 0x9A, 0xD3, 0x18, 0x4F, 0x4F, 0x59, 0x8B, 0xE9, 0x07, + 0xD9, 0xFE, 0x2D, 0xC2, 0xC1, 0x5B, 0x37, 0xD3, 0x89, 0xCE, + 0xDA, 0x0D, 0x5F, 0x93, 0xFB, 0x6D, 0xFE, 0x64, 0xCB, 0x1B, + 0x00, 0x66, 0x1E, 0xED, 0x62, 0x86, 0xF9, 0xC7, 0xA1, 0xDA, + 0x65, 0x94, 0x36, 0x74, 0x7F, 0x7E, 0xEB, 0x69, 0x5E, 0xE2, + 0x31, 0x14, 0x70, 0x96, 0xF6, 0x71, 0xBF, 0x41, 0x03, 0xA9, + 0x74, 0x91, 0xD3, 0x4F, 0xDC, 0x6F, 0xE7, 0x6E, 0x62, 0xC5, + 0xB3, 0xED, 0x97, 0xB6, 0x77, 0x04, 0x94, 0x3B, 0xFE, 0x48, + 0x7B, 0x55, 0x5E, 0xDB, 0x35, 0x23, 0xFA, 0xFB, 0x36, 0xE2, + 0xA1, 0x31, 0x10, 0x68, 0xA9, 0xEC, 0x82, 0xB8, 0xB9, 0x2B, + 0xD7, 0x5F, 0x22, 0x48, 0xE6, 0xD1, 0xEF, 0xD3, 0x07, 0x61, + 0x43, 0x3F, 0x22, 0x2E, 0xB5, 0xCA, 0x26, 0x98, 0xCD, 0x1F, + 0x9E, 0x22, 0xC8, 0x5E, 0xAF, 0xD1, 0x46, 0x12, 0x5F, 0x4C, + 0xC7, 0x57, 0x9B, 0x01, 0xA2, 0x52, 0x39, 0x3D, 0x84, 0xA7, + 0xFF, 0xA6, 0xCA, 0x4E, 0x49, 0x13, 0x37, 0x6E, 0xD6, 0xA9, + 0x04, 0xC8, 0x75, 0x4D, 0x5B, 0xB4, 0xBA, 0x51, 0xCD, 0x53, + 0x6B, 0xA8, 0xC8, 0x36, 0x23, 0x5D, 0x9A, 0x3C, 0xEA, 0x03, + 0x1C, 0xCE, 0xEB, 0xC6, 0xAB, 0xC0, 0x11, 0x0D, 0x58, 0x52, + 0xEF, 0x2B, 0x11, 0xE2, 0x70, 0xE1, 0x0E, 0x42, 0xD3, 0x5E, + 0x47, 0xE2, 0x30, 0xB7, 0xBD, 0xDE, 0x0B, 0xD9, 0x1E, 0x54, + 0xE2, 0x33, 0x46, 0x1C, 0xE4, 0xEA, 0xBC, 0xF1, 0x5A, 0xF7, + 0xA6, 0x82, 0x34, 0x92, 0xEB, 0x83, 0xF0, 0x59, 0x5D, 0x70, + 0x72, 0x58, 0x5B, 0x18, 0x27, 0xC3, 0xD3, 0x71, 0x35, 0x7F, + 0xC0, 0x47, 0xE2, 0xD2, 0xC6, 0x11, 0xE9, 0x5D, 0xA5, 0x2C, + 0x6A, 0x3A, 0x4B, 0xCA, 0x53, 0xC3, 0xDB, 0x9B, 0x5F, 0x03, + 0xBE, 0xB3, 0xE9, 0x9B, 0x60, 0x66, 0x00, 0x1E, 0xF7, 0x47, + 0x7D, 0x50, 0xA1, 0x54, 0x3D, 0xE4, 0x89, 0x54, 0xB1, 0xC0, + 0x6D, 0x34, 0x95, 0x10, 0xFF, 0xAE, 0xF9, 0xD4, 0x6C, 0x57, + 0x94, 0x0B, 0x51, 0xCB, 0xE3, 0x8F, 0x58, 0x9D, 0xD7, 0x03, + 0x52, 0xF8, 0x03, 0x81, 0x10, 0xCB, 0x64, 0x21, 0xE0, 0xCD, + 0x90, 0xB8, 0x6F, 0x2D, 0xE7, 0x2C, 0x62, 0x2A, 0x4F, 0x1D, + 0xA9, 0x52, 0x10, 0x13, 0x90, 0xC2, 0xB6, 0xD4, 0x82, 0xDD, + 0xBF, 0xAD, 0x68, 0x77, 0xB0, 0xE7, 0x7C, 0x0D, 0x9E, 0x7C, + 0xDC, 0xB7, 0x32, 0x31, 0x26, 0xEF, 0x57, 0x74, 0xAF, 0xBD, + 0x65, 0x46, 0x46, 0xC0, 0xE3, 0x52, 0x13, 0xFB, 0x06, 0xD2, + 0xC6, 0xB7, 0x51, 0x37, 0x26, 0xC5, 0x9F, 0x06, 0x17, 0xEA, + 0xF0, 0x85, 0x1E, 0x38, 0xDD, 0xFE, 0xD0, 0x97, 0x66, 0x3D, + 0x06, 0x28, 0x7A, 0xE6, 0xFF, 0x37, 0x8A, 0xD3, 0x94, 0xEB, + 0xD4, 0xC4, 0x12, 0xE8, 0x4A, 0x74, 0x65, 0x94, 0xCF, 0xBE, + 0xE4, 0x43, 0xA3, 0x11, 0xFC, 0x56, 0xFD, 0x80, 0x74, 0xB1, + 0xC9, 0x58, 0x64, 0x5D, 0x44, 0x6B, 0x8D, 0xA3, 0xCB, 0x20, + 0x7A, 0x4A, 0xD3, 0x93, 0x43, 0xD0, 0x9E, 0x5E, 0xE9, 0xEE, + 0xA2, 0x56, 0xD3, 0xE2, 0x35, 0x15, 0x1D, 0xFC, 0xE4, 0xF2, + 0x53, 0x5B, 0x23, 0x60, 0xC3, 0x59, 0xCD, 0x9F, 0x00, 0xCC, + 0xAE, 0x1D, 0xC1, 0xAB, 0xE1, 0x17, 0x22, 0x46, 0x9E, 0x4F, + 0x80, 0x1A, 0xF1, 0x06, 0x5C, 0xBD, 0x19, 0x13, 0xBA, 0x18, + 0xBB, 0xA0, 0x5E, 0x5B, 0x09, 0x2C, 0xDB, 0x68, 0xDC, 0xD3, + 0xEE, 0x3F, 0xD3, 0x24, 0x59, 0xF8, 0x7C, 0xAE, 0xEF, 0xB7, + 0xFF, 0x59, 0xF6, 0x8F, 0x23, 0x9C, 0x12, 0x78, 0xA9, 0x75, + 0x7D, 0x79, 0x71, 0x4B, 0x1B, 0x3A, 0x61, 0x00, 0x09, 0x0A, + 0x58, 0x38, 0x56, 0x8E, 0xB6, 0xD1, 0x69, 0x39, 0x4D, 0xE9, + 0xAA, 0x8B, 0x67, 0x53, 0x7A, 0x5D, 0x39, 0x85, 0x62, 0x3D, + 0x35, 0xAD, 0x1F, 0x92, 0x19, 0x9C, 0x60, 0xC4, 0x44, 0x07, + 0x9F, 0x1D, 0x3A, 0x64, 0xCB, 0xD8, 0x0E, 0xD7, 0x31, 0xBB, + 0xDE, 0x6B, 0x15, 0xA7, 0x56, 0xE0, 0x50, 0xAE, 0xD1, 0x4D, + 0xA0, 0x68, 0xB4, 0x9A, 0x79, 0xB4, 0xD2, 0x95, 0x64, 0x7A, + 0x19, 0x51, 0x6B, 0xA2, 0x0D, 0xE4, 0x74, 0x78, 0xBC, 0xB7, + 0xF2, 0x19, 0xCC, 0x8D, 0x2D, 0x88, 0x24, 0x4F, 0xEC, 0xBC, + 0x42, 0x03, 0x44, 0xB9, 0xA5, 0x72, 0x24, 0xAD, 0x7A, 0x8A, + 0x09, 0x0F, 0x40, 0x6F, 0xCB, 0xF9, 0xFC, 0xAC, 0x41, 0x38, + 0x59, 0xD6, 0xD3, 0x6D, 0x7A, 0xF8, 0xF6, 0x4A, 0x4D, 0x94, + 0x42, 0x64, 0xFC, 0x3D, 0x79, 0x07, 0x42, 0x33, 0xA9, 0xAF, + 0x93, 0xB1, 0x11, 0xD1, 0x21, 0x35, 0x19, 0x22, 0x34, 0xED, + 0x16, 0xAA, 0x57, 0xA4, 0x3D, 0x83, 0x63, 0x85, 0x7F, 0xD6, + 0xCD, 0x81, 0xF9, 0x34, 0xAA, 0x81, 0x62, 0x80, 0x86, 0x23, + 0x47, 0x9A, 0xFB, 0xD0, 0xF7, 0x0F, 0x19, 0x9E, 0xCE, 0x4F, + 0x1B, 0x16, 0x20, 0x80, 0xD0, 0x69, 0xD5, 0xBB, 0x10, 0x09, + 0x16, 0x25, 0x7B, 0x38, 0xE6, 0x0D, 0xF0, 0x42, 0x30, 0xF8, + 0xF9, 0x97, 0x00, 0xA7, 0x0E, 0x52, 0xDD, 0x87, 0x92, 0xE1, + 0xDF, 0x14, 0x2B, 0x5D, 0xF3, 0xC7, 0x59, 0xC0, 0x05, 0x38, + 0xB0, 0x04, 0x2C, 0x1C, 0xCE, 0x11, 0x0E, 0xC4, 0xAA, 0x49, + 0x0F, 0xB8, 0xFE, 0x99, 0x73, 0x01, 0xE8, 0x6A, 0xDD, 0x7B, + 0xCD, 0xF6, 0x96, 0x5C, 0x25, 0xAB, 0xCC, 0x68, 0x94, 0x91, + 0xDB, 0x8B, 0xBA, 0x77, 0x05, 0x98, 0xC3, 0x00, 0x87, 0xF3, + 0x50, 0x32, 0x7E, 0xFB, 0x9C, 0x20, 0x3C, 0xC1, 0xF0, 0x37, + 0xB2, 0xF1, 0x52, 0x62, 0x05, 0xAC, 0x5B, 0x4D, 0xB6, 0x42, + 0x53, 0xB9, 0xB5, 0x8B, 0x47, 0x0B, 0x66, 0x69, 0x93, 0xC8, + 0xFF, 0x21, 0x87, 0xDF, 0x5F, 0xC9, 0x0C, 0x11, 0x50, 0x06, + 0xAF, 0xEC, 0x26, 0x15, 0x0F, 0x25, 0xA1, 0x7B, 0xD6, 0x1E, + 0x05, 0x64, 0xE1, 0x75, 0x46, 0x03, 0x41, 0x01, 0x7A, 0xA7, + 0x58, 0x32, 0x92, 0x0D, 0x5E, 0x27, 0xFF, 0x84, 0xD1, 0x4B, + 0x57, 0x27, 0x2E, 0x10, 0x95, 0xE9, 0xE7, 0x3B, 0xE4, 0xFA, + 0xEF, 0x05, 0xC6, 0xE2, 0x0A, 0xA6, 0x61, 0xFB, 0x23, 0xAA, + 0x1D, 0xFA, 0xB4, 0x2F, 0xA2, 0x89, 0xC1, 0xAC, 0x64, 0x53, + 0xC4, 0x5A, 0x33, 0xDF, 0x3C, 0xAA, 0x1C, 0xB6, 0xC9, 0x2F, + 0x27, 0xDA, 0xAE, 0x6B, 0xA3, 0x2A, 0x0C, 0xDA, 0xC0, 0x79, + 0x0C, 0xE1, 0x50, 0xD3, 0xE5, 0x7B, 0xB5, 0xC5, 0xEC, 0x19, + 0x7D, 0xBD, 0x8B, 0x76, 0xA2, 0x75, 0x29, 0x3D, 0x46, 0x07, + 0xA6, 0xFC, 0xFC, 0x1F, 0xC3, 0xD7, 0x8A, 0x89, 0xA8, 0x86, + 0x59, 0x8F, 0x7C, 0x47, 0xE6, 0xAD, 0xE2, 0x0A, 0x6E, 0xAF, + 0xAA, 0x98, 0xD5, 0x89, 0xC1, 0x2B, 0x27, 0x53, 0x7D, 0xF5, + 0x5D, 0xFB, 0xDB, 0xE7, 0x61, 0x02, 0x77, 0x43, 0x0D, 0x6D, + 0x95, 0x4B, 0x5E, 0xDA, 0x3A, 0x5F, 0x5E, 0xA9, 0x63, 0x49, + 0x94, 0xCD, 0x74, 0xDF, 0x4D, 0x74, 0x78, 0xCA, 0x1E, 0xD1, + 0x7E, 0xFB, 0xCB, 0xB1, 0x0D, 0x00, 0xE4, 0x1A, 0x0E, 0x45, + 0xE1, 0x30, 0xBF, 0xB5, 0x4A, 0x42, 0xCE, 0x98, 0x68, 0xC1, + 0x14, 0x41, 0x96, 0xED, 0x66, 0x38, 0x66, 0x2C, 0x8C, 0x68, + 0xA7, 0x29, 0x4A, 0x4C, 0xA5, 0xFA, 0x45, 0xF0, 0xB8, 0x22, + 0xFD, 0x8F, 0x30, 0x19, 0x54, 0x6E, 0x78, 0x55, 0xB6, 0x90, + 0x15, 0x47, 0xB4, 0x52, 0xF4, 0xC0, 0xB2, 0xEF, 0xCD, 0xC9, + 0x17, 0xEA, 0x9F, 0xE0, 0x5D, 0xEB, 0x91, 0xFD, 0x34, 0x50, + 0xF8, 0xBE, 0xFB, 0xE1, 0x75, 0x55, 0xFB, 0xB3, 0x51, 0x89, + 0xF1, 0x8E, 0x04, 0x52, 0xC4, 0xE4, 0x5F, 0x9E, 0x0A, 0x72, + 0xAB, 0x1A, 0x79, 0x8B, 0x3D, 0xEB, 0x13, 0xA6, 0x38, 0xD9, + 0xF9, 0xCE, 0x25, 0x4C, 0x33, 0xE5, 0x85, 0x6F, 0xA8, 0x9A, + 0x27, 0x3B, 0xF7, 0xA6, 0x34, 0x01, 0x46, 0x85, 0xA1, 0x69, + 0xEB, 0xA5, 0x93, 0xC1, 0x80, 0x5C, 0xD2, 0x3A, 0x9E, 0xB3, + 0x5E, 0x70, 0x1E, 0x8A, 0x38, 0x98, 0x0D, 0x13, 0x09, 0x61, + 0xC7, 0x55, 0xB9, 0xC2, 0xF8, 0x25, 0xFE, 0x69, 0xB0, 0x59, + 0x06, 0x00, 0xC4, 0xB1, 0x79, 0xA8, 0x67, 0xFD, 0x96, 0x2F, + 0xEF, 0x05, 0x4E, 0xBE, 0x16, 0x6B, 0x1B, 0xD8, 0x23, 0x42, + 0x4A, 0x4E, 0x5A, 0x45, 0xB7, 0xFD, 0xC2, 0x6B, 0xC8, 0xD2, + 0xEC, 0x65, 0x4F, 0x75, 0x8B, 0x9E, 0x8C, 0x18, 0x4D, 0x21, + 0x86, 0xB9, 0x7A, 0xA4, 0x42, 0xBD, 0x59, 0x98, 0x09, 0x46, + 0x37, 0x54, 0x86, 0xAC, 0x60, 0x75, 0xE5, 0x4C, 0x91, 0x74, + 0xAB, 0x61, 0xC0, 0x7D, 0xB6, 0x80, 0xF7, 0x09, 0x35, 0x2C, + 0x14, 0x97, 0x26, 0x90, 0xF5, 0x63, 0xA2, 0x69, 0x1D, 0xEA, + 0xD9, 0x1F, 0xFB, 0x5B, 0xAA, 0x75, 0x1B, 0x33, 0x5D, 0x60, + 0x5A, 0x0A, 0x11, 0xB0, 0x23, 0xDF, 0xE4, 0x8A, 0xA0, 0xA8, + 0x76, 0x4C, 0xE0, 0xFE, 0x2F, 0xCE, 0xE9, 0xA5, 0xF8, 0xAC, + 0x95, 0x1C, 0x6A, 0xDC, 0x0C, 0x6E, 0xC9, 0x67, 0x4B, 0x25, + 0x6F, 0x63, 0x19, 0xE0, 0xDA, 0x2E, 0x67, 0x55, 0x5A, 0x76, + 0x88, 0xC6, 0x10, 0x37, 0xB1, 0xED, 0xE2, 0x67, 0x75, 0xE3, + 0x26, 0x29, 0xFF, 0xA9, 0x7A, 0x7D, 0xCE, 0x26, 0x79, 0x29, + 0x13, 0x8C, 0x0A, 0x42, 0xFD, 0xE7, 0xE8, 0x86, 0x3D, 0x20, + 0xE4, 0x5F, 0x06, 0x82, 0xD3, 0xDF, 0xE9, 0x9E, 0x4E, 0xD0, + 0xBC, 0xBB, 0x44, 0xB1, 0xF1, 0x71, 0x8A, 0x25, 0x86, 0x0A, + 0x4A, 0x35, 0xC3, 0xB5, 0x36, 0x1A, 0xCE, 0xF0, 0x79, 0x4D, + 0x22, 0xF2, 0xE8, 0x88, 0xEB, 0xB4, 0x96, 0x2D, 0xBC, 0x1B, + 0x9F, 0x25, 0xC0, 0xC7, 0xD5, 0xED, 0x42, 0x17, 0x78, 0xBB, + 0x97, 0x64, 0x6E, 0x3A, 0x54, 0x14, 0x6E, 0x38, 0xAA, 0xDA, + 0xFC, 0x21, 0x1A, 0xA1, 0xCA, 0x35, 0x98, 0x83, 0x0F, 0x19, + 0x07, 0x55, 0xD6, 0xE3, 0x9F, 0xCF, 0xF8, 0x66, 0x1E, 0x23, + 0xE4, 0x49, 0xC0, 0x59, 0x18, 0xB5, 0x56, 0xDB, 0x73, 0xDD, + 0x93, 0x86, 0x0D, 0xEF, 0xB4, 0x49, 0xC5, 0x26, 0x74, 0x5C, + 0x18, 0xC7, 0x96, 0xF4, 0x6D, 0xE1, 0x22, 0x23, 0x21, 0x54, + 0x39, 0x07, 0xD9, 0xBC, 0xAB, 0x8D, 0xE4, 0x2A, 0xB1, 0x10, + 0x52, 0xE0, 0x2B, 0xB6, 0x85, 0x06, 0x06, 0x02, 0x16, 0xE5, + 0x66, 0xD7, 0x64, 0xDF, 0x58, 0xB3, 0x03, 0xBA, 0xBE, 0x95, + 0x08, 0x6B, 0x3E, 0x6C, 0xF5, 0x67, 0xBB, 0x7D, 0x08, 0xBC, + 0xEA, 0xC8, 0x1A, 0xC2, 0xAF, 0xE5, 0xC8, 0x3E, 0xDF, 0xA1, + 0xD0, 0xB2, 0x5E, 0x8B, 0xCD, 0xA2, 0xC7, 0x3A, 0xB1, 0xCE, + 0x14, 0xA1, 0x7D, 0x19, 0x63, 0x9A, 0xC2, 0xC3, 0x9B, 0x66, + 0x3C, 0xDF, 0xE4, 0x42, 0xB7, 0x81, 0x29, 0x96, 0x5E, 0xBE, + 0xD2, 0x96, 0x2D, 0x7A, 0x92, 0x36, 0x95, 0x50, 0x5A, 0x53, + 0x5F, 0x43, 0x29, 0x29, 0xEF, 0x52, 0xF4, 0xED, 0x40, 0x0C, + 0x14, 0x3F, 0x00, 0x0D, 0x38, 0xB2, 0xA7, 0x14, 0xC3, 0x33, + 0xF8, 0x34, 0x82, 0x96, 0xC7, 0x83, 0xA5, 0x76, 0xE6, 0xF1, + 0x90, 0xB8, 0x7E, 0x51, 0xCB, 0xB9, 0xB9, 0xAD, 0x7E, 0xB3, + 0xAD, 0x22, 0x57, 0x29, 0xC9, 0x09, 0x91, 0x0B, 0x02, 0x76, + 0x5E, 0x43, 0xDB, 0x25, 0x22, 0x2B, 0x9E, 0x99, 0xF6, 0xDE, + 0xA5, 0x84, 0xB5, 0x8E, 0x30, 0x45, 0xCB, 0x60, 0x45, 0x83, + 0x5E, 0x07, 0xFA, 0x97, 0x65, 0x9C, 0x39, 0x67, 0xA7, 0x4F, + 0xB5, 0xB9, 0x4C, 0xD6, 0x3F, 0xC1, 0x27, 0x2D, 0x09, 0xC5, + 0xC7, 0x7E, 0xC9, 0xC1, 0xEA, 0x0A, 0xF5, 0x66, 0x21, 0x43, + 0x89, 0x21, 0xF4, 0x0D, 0x1E, 0x66, 0x22, 0xC9, 0xFA, 0x8F, + 0x99, 0xA5, 0x05, 0x10, 0x87, 0x3E, 0xE6, 0xC5, 0x12, 0xCF, + 0x74, 0x33, 0x4D, 0xFD, 0x4C, 0x6B, 0x96, 0x33, 0xD3, 0xCC, + 0xDC, 0x77, 0xD5, 0x51, 0xF6, 0xBD, 0x84, 0x48, 0x5D, 0x38, + 0x18, 0xBD, 0x78, 0x17, 0x5D, 0xC0, 0x92, 0xBF, 0x64, 0x6D, + 0xB3, 0x59, 0xCE, 0x5B, 0x19, 0xF7, 0xE6, 0x6B, 0x89, 0xE0, + 0x44, 0x97, 0xB9, 0x7F, 0x57, 0x29, 0x68, 0x5C, 0x9A, 0x4A, + 0x0F, 0x3F, 0x1B, 0x74, 0x28, 0x1F, 0xF8, 0x17, 0x96, 0x8B, + 0x74, 0x75, 0x7B, 0x78, 0xAA, 0x27, 0x8F, 0xF3, 0x57, 0x64, + 0x59, 0xC8, 0x75, 0x57, 0xC4, 0x31, 0x8D, 0xF3, 0x42, 0x4F, + 0xC8, 0x29, 0x65, 0x3E, 0xC0, 0x7F, 0x3F, 0x4D, 0x90, 0x6E, + 0xCF, 0xD1, 0xDA, 0x59, 0x1F, 0xB5, 0x48, 0xC1, 0x41, 0xC1, + 0xF2, 0x78, 0x34, 0xE1, 0x8C, 0x08, 0x08, 0xDC, 0x0A, 0x92, + 0x97, 0x21, 0x6B, 0x94, 0x9F, 0x89, 0x70, 0x6F, 0x70, 0x41, + 0xF6, 0xEA, 0x55, 0xFC, 0xC4, 0x24, 0x83, 0xF6, 0x55, 0x29, + 0x96, 0xA8, 0x11, 0x70, 0x40, 0xAA, 0x07, 0x3A, 0x57, 0xAF, + 0x2F, 0xF5, 0xD7, 0xD4, 0x47, 0xE0, 0xAD, 0xAE, 0x64, 0x40, + 0xAC, 0x9D, 0x27, 0x32, 0x84, 0x71, 0x3A, 0xE7, 0x28, 0x9C, + 0x80, 0x25, 0x33, 0xFA, 0xC5, 0x9B, 0xDA, 0xA5, 0xA7, 0x0C, + 0xE7, 0xB5, 0xAA, 0xAD, 0x57, 0x6E, 0xE1, 0x83, 0x69, 0x2F, + 0xEF, 0xFA, 0x60, 0x4C, 0x46, 0xEE, 0xD3, 0x31, 0x44, 0x8C, + 0xF0, 0x87, 0xD1, 0x60, 0x7B, 0x68, 0x6A, 0x7F, 0x66, 0x9B, + 0x0C, 0x99, 0x30, 0x66, 0xB0, 0x35, 0xB2, 0x7C, 0xC4, 0x7A, + 0xEE, 0xB9, 0x6E, 0x41, 0xCE, 0x26, 0xD5, 0xCA, 0x8E, 0x84, + 0x95, 0xEF, 0xD2, 0xE6, 0x1A, 0xC9, 0x16, 0x49, 0x42, 0x99, + 0x01, 0x4D, 0x3A, 0x93, 0x8B, 0x26, 0x83, 0x54, 0x50, 0xDF, + 0x6C, 0x7D, 0x38, 0xE0, 0x4C, 0x84, 0x5B, 0xA4, 0xF5, 0xB0, + 0xA6, 0xE0, 0x9F, 0x54, 0x1B, 0xAC, 0xE5, 0x2E, 0x8A, 0x27, + 0x80, 0xFF, 0x26, 0x63, 0x43, 0x04, 0x74, 0xE1, 0xE3, 0xB3, + 0x96, 0x91, 0xBB, 0xF4, 0x88, 0xEF, 0xBB, 0x79, 0x52, 0x08, + 0x51, 0x4A, 0x2E, 0x56, 0x88, 0xCB, 0x20, 0x1D, 0x95, 0x7C, + 0x35, 0x8C, 0xC1, 0x25, 0xC8, 0x6D, 0xC4, 0x41, 0x7D, 0xD5, + 0x45, 0x8D, 0x12, 0x8B, 0x41, 0x1D, 0x39, 0x39, 0xC0, 0x38, + 0x31, 0xD4, 0x1B, 0x33, 0x01, 0xEE, 0x2D, 0x9E, 0x45, 0xC1, + 0x45, 0xE4, 0xE7, 0x68, 0x7C, 0x37, 0x08, 0xDB, 0xC6, 0xF3, + 0xD7, 0x12, 0xBA, 0x6F, 0xCD, 0xCD, 0x67, 0x00, 0x9F, 0x73, + 0x0D, 0xBB, 0x93, 0x3B, 0xAC, 0x8A, 0x72, 0x2A, 0xA9, 0xE5, + 0xF0, 0xF4, 0xCA, 0xFE, 0xE5, 0xFD, 0x61, 0xFE, 0x87, 0xB6, + 0x71, 0x96, 0xE9, 0xF2, 0x1B, 0xF6, 0xED, 0x89, 0xE1, 0xDC, + 0x23, 0x96, 0x6D, 0x9F, 0x16, 0x33, 0xAF, 0x4D, 0x97, 0x6E, + 0x91, 0x17, 0xDE, 0x7C, 0x52, 0x25, 0xC7, 0xCE, 0x92, 0x82, + 0x9B, 0x3B, 0x29, 0x96, 0x06, 0x3D, 0xC4, 0x4B, 0xA0, 0x06, + 0xFF, 0x39, 0x61, 0x41, 0x94, 0xF9, 0xBD, 0xA9, 0x0F, 0x04, + 0xDE, 0x04, 0x53, 0x6E, 0x44, 0x47, 0xE4, 0x72, 0x5D, 0xCA, + 0x54, 0x90, 0x9A, 0x37, 0xEF, 0x7F, 0x59, 0xAD, 0xC2, 0x10, + 0x08, 0x81, 0x0F, 0xF5, 0xF7, 0x24, 0xAA, 0xC9, 0xD6, 0x27, + 0x65, 0x7E, 0x67, 0x79, 0x9C, 0x63, 0x5E, 0x0E, 0xDD, 0xFB, + 0xCF, 0xF4, 0xE7, 0x99, 0x13, 0xA7, 0x11, 0x22, 0x02, 0x50, + 0xBB, 0xFE, 0x9B, 0x56, 0x8D, 0xC3, 0x2F, 0x67, 0xEB, 0x1C, + 0xB4, 0x40, 0x11, 0x44, 0x06, 0x59, 0x16, 0xC7, 0x9B, 0xC3, + 0x7B, 0xF4, 0xB5, 0xDF, 0xFC, 0x25, 0x43, 0x60, 0xB5, 0x2D, + 0xF5, 0x36, 0xB7, 0xE8, 0xEB, 0x4F, 0x79, 0x1B, 0x3B, 0x67, + 0xFD, 0x09, 0x62, 0x59, 0x02, 0x54, 0xA7, 0x0E, 0x61, 0xFB, + 0xE2, 0x57, 0x15, 0x4D, 0x32, 0xE5, 0x5D, 0x3D, 0xF5, 0xF9, + 0xDF, 0xA1, 0x3F, 0xF2, 0xF4, 0xC7, 0x03, 0xD5, 0x9F, 0xFB, + 0xFC, 0xD4, 0xE8, 0x3C, 0xD4, 0x4A, 0x8B, 0x9D, 0xED, 0x6F, + 0xB6, 0xFC, 0x88, 0x7B, 0x10, 0xE5, 0x3E, 0xF2, 0x0B, 0x40, + 0x27, 0xC7, 0x6B, 0x86, 0x7E, 0x66, 0xE7, 0xC6, 0xD7, 0x9C, + 0xAD, 0x7F, 0xBE, 0xB5, 0x39, 0xDD, 0x15, 0x4E, 0x48, 0x6C, + 0xDC, 0x98, 0x2D, 0xC4, 0xF2, 0x49, 0x02, 0xE6, 0xF2, 0x46, + 0xD2, 0xDE, 0x09, 0x8B, 0x95, 0x80, 0x1D, 0x94, 0xB2, 0x6D, + 0x85, 0x4B, 0x47, 0x35, 0x12, 0xF7, 0xC6, 0x7B, 0x1F, 0x63, + 0x87, 0xC1, 0xA8, 0xE0, 0xDE, 0xB5, 0x9B, 0x18, 0x15, 0x78, + 0x6E, 0xEB, 0x7E, 0xDD, 0x62, 0x52, 0xF2, 0x3F, 0x3F, 0xA4, + 0x4A, 0xC6, 0xDF, 0x4B, 0x00, 0xAC, 0xF4, 0xE4, 0xF6, 0x70, + 0x05, 0xE4, 0xC3, 0xE6, 0x5C, 0x08, 0x4D, 0x4B, 0x75, 0xCC, + 0x6C, 0xC1, 0xE7, 0x33, 0x94, 0x36, 0x0E, 0x5D, 0x78, 0x03, + 0xB7, 0xA4, 0xF2, 0x6A, 0xE8, 0xB1, 0x33, 0x2A, 0xE5, 0xB5, + 0xA6, 0xC0, 0x0E, 0xE7, 0x9D, 0xCC, 0x40, 0xFF, 0x92, 0x67, + 0xC4, 0x7A, 0x4E, 0xFD, 0x76, 0x12, 0xD9, 0x61, 0x2F, 0x28, + 0xAF, 0x2D, 0xD4, 0xCF, 0x4D, 0xE2, 0x8A, 0x33, 0x28, 0xE6, + 0xA4, 0x41, 0xA4, 0x37, 0xB3, 0x23, 0xAF, 0x4B, 0x36, 0xE7, + 0xE3, 0x75, 0xB7, 0x86, 0x10, 0x0A, 0xF0, 0x4F, 0xEB, 0xB5, + 0xFC, 0xF7, 0x35, 0xD9, 0x1C, 0xD8, 0x96, 0x66, 0xD9, 0xD6, + 0xA7, 0xC9, 0x5F, 0xE9, 0x6A, 0x6A, 0x36, 0xC9, 0x9A, 0xCE, + 0xAD, 0x52, 0xB4, 0xA5, 0x9C, 0x88, 0x23, 0x25, 0x3B, 0x3D, + 0xEB, 0xDA, 0xEF, 0x44, 0x80, 0x62, 0x4F, 0xB5, 0x5F, 0x9B, + 0x67, 0xB3, 0xE1, 0xE6, 0x75, 0x07, 0xD7, 0xC1, 0x02, 0xE4, + 0xAC, 0x5F, 0xD8, 0x05, 0x60, 0xF2, 0x68, 0x33, 0xDD, 0x15, + 0xC7, 0xA6, 0x94, 0x38, 0x7D, 0xB1, 0x6B, 0xF8, 0x3E, 0x97, + 0x93, 0xA6, 0xA0, 0x10, 0xA4, 0x69, 0x3B, 0xDC, 0x4A, 0x97, + 0xA9, 0xC2, 0x0D, 0xD3, 0x55, 0x5F, 0xD1, 0xDB, 0x99, 0x43, + 0x76, 0x8A, 0x62, 0x80, 0x03, 0xC0, 0x71, 0xA0, 0x4A, 0xAF, + 0x92, 0xAB, 0x83, 0x29, 0x86, 0x52, 0x37, 0x6C, 0x3F, 0xC3, + 0xFA, 0xDB, 0xB2, 0xCE, 0x2E, 0x7C, 0x24, 0x5F, 0x34, 0xBC, + 0x58, 0x3D, 0x50, 0x2B, 0xCE, 0xA0, 0x39, 0x05, 0x85, 0x63, + 0xA2, 0x96, 0xF6, 0xBA, 0x4D, 0xDF, 0x21, 0x9F, 0x72, 0x89, + 0x62, 0x63, 0x50, 0x33, 0x64, 0xEC, 0xCE, 0xD3, 0x02, 0x09, + 0xE6, 0x73, 0xB4, 0x79, 0xDA, 0x6C, 0xC1, 0xAE, 0x46, 0xAF, + 0xA7, 0x7B, 0x74, 0x13, 0xCE, 0x11, 0x6E, 0x92, 0x53, 0x97, + 0x88, 0x9B, 0x5E, 0x6E, 0xFD, 0xF5, 0xF8, 0x19, 0x78, 0xE6, + 0x93, 0x6C, 0xF4, 0x45, 0xE2, 0x6E, 0x87, 0x94, 0xD1, 0xC0, + 0x5A, 0x8C, 0xB2, 0xD5, 0xBE, 0xA9, 0xC4, 0x0D, 0x70, 0x7A, + 0x13, 0xFB, 0xAC, 0x2E, 0x62, 0x00, 0xBB, 0xA9, 0x10, 0x07, + 0xFA, 0x9F, 0x5B, 0x9E, 0xF5, 0xE0, 0x6F, 0xA2, 0x41, 0x95, + 0xF5, 0xA7, 0x01, 0xFF, 0x46, 0x0F, 0x08, 0xBA, 0xFA, 0xF3, + 0x26, 0x26, 0x57, 0xA4, 0xCE, 0x4B, 0x41, 0x41, 0x85, 0xFA, + 0x32, 0xDB, 0xE0, 0xE0, 0xFE, 0x86, 0x2D, 0xE8, 0x8E, 0x45, + 0x8E, 0xCE, 0x76, 0x3D, 0x15, 0x64, 0x89, 0xC5, 0xFC, 0x8C, + 0x78, 0x1B, 0xCD, 0xE9, 0x18, 0xD7, 0x26, 0x39, 0xF0, 0x49, + 0x73, 0xA0, 0x67, 0xF7, 0x8D, 0x84, 0xE7, 0x21, 0x59, 0xC1, + 0xC4, 0xDC, 0x57, 0xDD, 0xA8, 0x36, 0x62, 0x32, 0x19, 0x4C, + 0xD0, 0x6B, 0xD9, 0xB8, 0xFD, 0x54, 0xE5, 0xE2, 0x0E, 0x55, + 0x86, 0xD0, 0x55, 0xF5, 0xB9, 0x24, 0x5B, 0xE8, 0xAE, 0x55, + 0x1A, 0x89, 0xA1, 0x6E, 0x21, 0x3D, 0x30, 0xD7, 0x92, 0xE8, + 0xD1, 0x7A, 0x07, 0x73, 0x4C, 0xB2, 0x66, 0x0B, 0x38, 0xD5, + 0x73, 0x98, 0xED, 0x40, 0xA3, 0x7F, 0x6F, 0xBA, 0x66, 0x55, + 0x0B, 0x71, 0x8B, 0x4A, 0x3A, 0x17, 0xD0, 0xE1, 0x09, 0x30, + 0x40, 0x92, 0xF0, 0xB8, 0x67, 0x84, 0xA2, 0xDA, 0x11, 0x07, + 0x45, 0x21, 0x7B, 0xBA, 0xB0, 0x65, 0x65, 0x64, 0x29, 0x17, + 0x72, 0x86, 0x48, 0x4A, 0x73, 0xC4, 0x2E, 0xE4, 0x14, 0x85, + 0xA8, 0x26, 0x9C, 0x55, 0x4B, 0x6C, 0xB2, 0x0B, 0x66, 0xA8, + 0x81, 0xDA, 0x35, 0xFF, 0xD8, 0x37, 0xAD, 0x09, 0x72, 0x3B, + 0x4D, 0xB5, 0x4F, 0x75, 0x1A, 0x22, 0x69, 0xA4, 0x4D, 0xDA, + 0x49, 0x89, 0xA9, 0xDC, 0xEC, 0xC6, 0x94, 0x72, 0x7C, 0x1C, + 0x4B, 0x38, 0x1F, 0xE4, 0x80, 0x67, 0x96, 0x8C, 0xEB, 0xC1, + 0xD0, 0x2B, 0x59, 0x2C, 0x01, 0x82, 0xA4, 0x6E, 0x85, 0x8B, + 0xFB, 0xE6, 0x8F, 0x3D, 0x5B, 0xBF, 0x43, 0x18, 0xF6, 0xC5, + 0x0A, 0xED, 0x64, 0x08, 0xC0, 0xC8, 0x49, 0x9F, 0x5E, 0xDA, + 0xED, 0xAE, 0xDC, 0x86, 0x71, 0x6F, 0xF7, 0x9F, 0x5C, 0x9F, + 0x95, 0x6A, 0x72, 0x66, 0x9F, 0xB4, 0xBD, 0xCC, 0x2F, 0x5E, + 0x96, 0xF8, 0x78, 0x09, 0x79, 0xBB, 0x3A, 0xE6, 0x28, 0x6B, + 0x34, 0x52, 0x7B, 0xAE, 0x38, 0x32, 0x92, 0x9B, 0x92, 0x68, + 0xF1, 0x4A, 0x37, 0x5C, 0x09, 0x6F, 0x00, 0x92, 0x27, 0x59, + 0x52, 0x6C, 0x65, 0x01, 0x59, 0x00, 0xE6, 0xB5, 0x82, 0x70, + 0xB1, 0xD3, 0x25, 0x41, 0x5E, 0x3C, 0x0F, 0x38, 0x2F, 0x13, + 0xDC, 0xD3, 0x32, 0x89, 0x69, 0xB6, 0x31, 0xE0, 0x75, 0xC8, + 0x44, 0xA7, 0xD6, 0x59, 0x9C, 0xE1, 0x10, 0x05, 0x84, 0x26, + 0x4D, 0xE7, 0x8B, 0x9A, 0x69, 0xB1, 0xA3, 0x68, 0x3B, 0x04, + 0x47, 0x5E, 0x2E, 0xC3, 0xAD, 0xEA, 0xD8, 0x27, 0x8A, 0xC5, + 0x7B, 0x2C, 0xC2, 0xFF, 0x6F, 0x6A, 0x72, 0xCA, 0x64, 0x03, + 0x6F, 0x13, 0x0A, 0x0D, 0x83, 0x9E, 0x0E, 0xB0, 0xDC, 0x35, + 0xA9, 0xB9, 0x99, 0x29, 0xE5, 0xA3, 0x65, 0x34, 0x5A, 0xBD, + 0xAF, 0x88, 0x23, 0x2B, 0x4C, 0xAC, 0xAF, 0x7D, 0x21, 0xC6, + 0xCB, 0x8C, 0xCD, 0x42, 0x74, 0x85, 0x9E, 0xE1, 0x4D, 0xC0, + 0x56, 0xA1, 0x91, 0xCF, 0x34, 0x38, 0x89, 0xD0, 0x09, 0x42, + 0x2E, 0x9F, 0x70, 0x70, 0x7E, 0x73, 0xFB, 0x82, 0xB3, 0x65, + 0xFC, 0x33, 0x57, 0xF7, 0x8F, 0xF9, 0x2C, 0x11, 0xF8, 0x64, + 0x31, 0x49, 0xCE, 0xCC, 0x64, 0xE9, 0xFC, 0x80, 0xEF, 0x39, + 0x27, 0x20, 0xB5, 0x75, 0x8C, 0x4B, 0xCE, 0x62, 0x73, 0xD2, + 0xCC, 0x43, 0x7A, 0x0D, 0x90, 0xB2, 0x1E, 0x4A, 0xEC, 0x49, + 0xED, 0x15, 0x52, 0xA0, 0xCF, 0x30, 0xA5, 0xE4, 0x7E, 0xB5, + 0x4A, 0x47, 0xFA, 0x4C, 0x4F, 0x63, 0xE6, 0x24, 0x71, 0x7B, + 0x49, 0x46, 0x16, 0xB2, 0x0A, 0x29, 0x93, 0x7E, 0xB8, 0x0B, + 0x37, 0xFA, 0x85, 0x7C, 0x00, 0x99, 0x13, 0xAA, 0x01, 0x1B, + 0x33, 0xB8, 0x1E, 0xF8, 0xC1, 0x51, 0xDF, 0x6C, 0x01, 0x90, + 0x8C, 0x46, 0xAA, 0xBB, 0x1C, 0xA5, 0x87, 0x02, 0x6A, 0x6E, + 0x56, 0x1B, 0xBE, 0x07, 0x7E, 0x40, 0xEC, 0x57, 0x30, 0x50, + 0xF7, 0xB0, 0xA6, 0xB7, 0x28, 0x65, 0xCF, 0x88, 0x85, 0xAB, + 0x81, 0x31, 0x2F, 0xFD, 0x54, 0xDB, 0x5E, 0x46, 0x0A, 0x25, + 0xB8, 0x84, 0x0A, 0x4D, 0xCF, 0xCD, 0xEE, 0x19, 0xCB, 0x0D, + 0xCD, 0xB6, 0xC1, 0x41, 0xE4, 0xD6, 0x33, 0xF3, 0xA7, 0x3B, + 0x7B, 0x33, 0xA4, 0x93, 0x52, 0xD0, 0xDC, 0x58, 0xC8, 0x0B, + 0x42, 0x45, 0xFB, 0xF3, 0xEE, 0x0E, 0x83, 0x25, 0x8B, 0x5F, + 0xC7, 0xCE, 0xD3, 0xC3, 0xF3, 0x92, 0x08, 0x28, 0xF7, 0xA8, + 0xBE, 0x59, 0x7A, 0x62, 0x40, 0x7D, 0x3B, 0x45, 0xA0, 0xCB, + 0x4E, 0x0D, 0xD4, 0xA2, 0x35, 0x26, 0x49, 0xFE, 0x54, 0x8A, + 0x10, 0x0C, 0xA7, 0xD7, 0x0A, 0x4C, 0xD9, 0xD0, 0x8E, 0xD4, + 0xD2, 0x98, 0xB3, 0x68, 0x18, 0xE6, 0x7D, 0x78, 0x2C, 0xB5, + 0x7A, 0x48, 0x55, 0x8A, 0x58, 0xB9, 0xFE, 0x68, 0x94, 0x8E, + 0x46, 0xFB, 0x73, 0xC9, 0x8F, 0xFD, 0xD3, 0xAC, 0xF1, 0x8B, + 0x87, 0x40, 0x0E, 0x5B, 0x72, 0x07, 0x96, 0x10, 0x66, 0x21, + 0xC0, 0x87, 0x6C, 0x70, 0xA8, 0x93, 0xE7, 0x75, 0x41, 0x8D, + 0xED, 0xDB, 0x6C, 0xF6, 0xA6, 0xD5, 0x1A, 0x67, 0x45, 0x8A, + 0x47, 0x76, 0x80, 0xF7, 0xFB, 0x64, 0x2E, 0x80, 0x76, 0x61, + 0x3F, 0xE0, 0xDA, 0xA3, 0x6E, 0x17, 0x6E, 0x4A, 0x29, 0x18, + 0x1F, 0xEF, 0x3B, 0xB3, 0x23, 0xF7, 0x31, 0x97, 0xD0, 0x2C, + 0xE5, 0x6D, 0x09, 0x95, 0x0A, 0xDE, 0x4F, 0xAD, 0xDA, 0x0C, + 0x96, 0x6B, 0xE6, 0x8C, 0x5A, 0x17, 0x00, 0x93, 0x34, 0xD0, + 0x8D, 0x6E, 0xA3, 0xFD, 0xF1, 0x98, 0x19, 0xF1, 0xE2, 0xD7, + 0x3B, 0x00, 0x5E, 0xDB, 0x8C, 0x59, 0x90, 0x4A, 0x7D, 0x75, + 0x76, 0xF7, 0x4B, 0x60, 0x11, 0x02, 0x19, 0xE9, 0x38, 0x85, + 0xFC, 0xEC, 0x6F, 0xC6, 0xB5, 0xCB, 0x0F, 0x98, 0x92, 0xED, + 0x67, 0xE9, 0xEB, 0xB8, 0x19, 0x76, 0xB4, 0x76, 0xE3, 0x47, + 0xE1, 0x0C, 0x0F, 0x0E, 0xD5, 0x24, 0x91, 0x7F, 0xE1, 0x83, + 0x9F, 0x74, 0x8A, 0x0C, 0x3D, 0x4B, 0xC4, 0xA9, 0xAC, 0x62, + 0xA0, 0xDF, 0x9E, 0xA9, 0x95, 0xD3, 0x04, 0x6A, 0xE6, 0xD6, + 0x37, 0x5B, 0xFB, 0x83, 0xAC, 0xD1, 0x6A, 0x6D, 0x6E, 0x63, + 0x3F, 0x3A, 0x03, 0x68, 0xE1, 0xC3, 0xF2, 0x9E, 0x04, 0x9D, + 0xFE, 0xFE, 0x34, 0x58, 0xD3, 0xC8, 0x18, 0xD1, 0xC0, 0xBA, + 0xBD, 0xD9, 0x4F, 0x29, 0xE9, 0x0F, 0x8C, 0x9A, 0x62, 0x30, + 0x05, 0xC6, 0x33, 0x10, 0x72, 0xEB, 0x2A, 0xFE, 0x06, 0xE7, + 0xF0, 0x2D, 0x88, 0x51, 0x86, 0x22, 0x43, 0x32, 0x45, 0xAB, + 0x98, 0xF2, 0x0A, 0x90, 0x0D, 0x4D, 0x38, 0x1E, 0x0F, 0xDD, + 0x30, 0x9C, 0x48, 0x67, 0x6A, 0x0D, 0x53, 0x5C, 0x5C, 0x02, + 0xEA, 0x96, 0xDB, 0x2A, 0x21, 0xAB, 0x71, 0xA7, 0x2D, 0xC2, + 0xDB, 0x86, 0x3B, 0x8E, 0x6D, 0xC5, 0x56, 0x2B, 0x9E, 0x2E, + 0x5D, 0xBB, 0x7C, 0xC9, 0x72, 0xF1, 0x85, 0x2E, 0x71, 0x1A, + 0x84, 0xA8, 0xA7, 0x2B, 0x25, 0x18, 0xCD, 0xE4, 0xA5, 0x09, + 0x37, 0xFE, 0x7A, 0x5E, 0xC1, 0x99, 0xB4, 0xC4, 0xDF, 0x8F, + 0x9A, 0xF7, 0x12, 0x13, 0x5C, 0x81, 0xA3, 0xB1, 0x6E, 0x52, + 0xCB, 0x12, 0x8F, 0xF1, 0x23, 0xB3, 0xF4, 0xE1, 0xC2, 0xD5, + 0x94, 0x98, 0x2B, 0x1F, 0x23, 0xBA, 0x32, 0xFB, 0xA6, 0xB8, + 0x9D, 0x20, 0x87, 0xA3, 0x18, 0xFB, 0x4B, 0xCB, 0x37, 0x2D, + 0x64, 0xB8, 0x4F, 0xBA, 0xF8, 0x87, 0xB0, 0x63, 0x74, 0xF7, + 0xD4, 0x12, 0xB4, 0x3F, 0x87, 0xCF, 0x36, 0x74, 0xA4, 0x41, + 0xD3, 0xA9, 0x84, 0xA9, 0xBA, 0xFD, 0x01, 0xB5, 0xA4, 0x3A, + 0x60, 0x63, 0x37, 0x09, 0x95, 0x50, 0x2D, 0x73, 0xD6, 0x92, + 0x24, 0x1F, 0x08, 0x5D, 0x69, 0x9F, 0x5F, 0x92, 0xA7, 0x38, + 0xD4, 0x59, 0xA2, 0xCC, 0x6A, 0xB5, 0x50, 0x50, 0x9D, 0x9A, + 0xC2, 0xF5, 0x00, 0x2D, 0x5F, 0xFE, 0x94, 0x9A, 0xC8, 0xA7, + 0xC2, 0x48, 0x1A, 0xEF, 0xDC, 0x1E, 0x6C, 0x49, 0x09, 0xA8, + 0x18, 0x0A, 0xB7, 0x7A, 0x3D, 0xA2, 0x88, 0xE7, 0x92, 0x70, + 0x75, 0x44, 0x33, 0x6F, 0x76, 0x81, 0xF5, 0xE6, 0x13, 0x70, + 0x11, 0xBB, 0x4A, 0x3C, 0xA2, 0x09, 0x84, 0xFD, 0x96, 0xC8, + 0xF4, 0x77, 0x43, 0x2F, 0xC1, 0xDC, 0x9C, 0x8B, 0xBE, 0x76, + 0x14, 0xB1, 0x10, 0xD6, 0x7D, 0x0D, 0xCE, 0x39, 0x51, 0xE1, + 0x8E, 0xDB, 0xE4, 0xDB, 0xA0, 0x34, 0x42, 0x0E, 0x5D, 0xA9, + 0xF5, 0xDA, 0xCE, 0x01, 0x80, 0x71, 0x8B, 0x9D, 0xA8, 0xCC, + 0x1E, 0xED, 0xCE, 0x82, 0x29, 0x4E, 0x25, 0x12, 0x9B, 0x01, + 0xB1, 0x82, 0xFA, 0x7A, 0x53, 0x1C, 0x36, 0x3F, 0x8B, 0x94, + 0x38, 0xB9, 0x0D, 0x9E, 0x84, 0x57, 0x93, 0x6B, 0xA8, 0xB6, + 0x16, 0x2D, 0xD6, 0xC9, 0x74, 0x72, 0x5F, 0x18, 0x55, 0xF0, + 0x81, 0x7F, 0xF3, 0x64, 0x38, 0x95, 0xD2, 0xD0, 0xC5, 0xE8, + 0xCA, 0x79, 0xF2, 0x7A, 0xDD, 0x02, 0x9E, 0x47, 0x95, 0xCD, + 0x7E, 0x83, 0x39, 0x32, 0xBE, 0x86, 0x45, 0xC4, 0x99, 0x7E, + 0x2F, 0xE1, 0x93, 0xCF, 0x4C, 0xB1, 0x72, 0x84, 0x88, 0x02, + 0x98, 0xF7, 0xC0, 0xC2, 0x2E, 0x70, 0xF4, 0x3A, 0x4E, 0x44, + 0x2F, 0x07, 0xB5, 0x15, 0x22, 0x06, 0x8C, 0xC9, 0x2B, 0xE3, + 0x0E, 0x55, 0xEE, 0x20, 0x52, 0xA3, 0x1A, 0x25, 0x32, 0x47, + 0xF6, 0x78, 0x28, 0x08, 0xEA, 0xFE, 0xC1, 0xBF, 0xC8, 0xB8, + 0x4C, 0x90, 0xB2, 0x1B, 0xB3, 0x98, 0x93, 0xA2, 0xA3, 0xD5, + 0x79, 0x94, 0xCF, 0x77, 0x1B, 0x34, 0x0C, 0x20, 0x6B, 0xD2, + 0x0E, 0x6A, 0x72, 0xB4, 0x5E, 0xE9, 0x1D, 0xEF, 0x46, 0x7D, + 0x12, 0x38, 0x21, 0xED, 0x80, 0x3C, 0xA6, 0xCA, 0x87, 0xF8, + 0x13, 0xC9, 0x5F, 0xA8, 0xC6, 0xB7, 0x3E, 0x1B, 0x87, 0xE8, + 0x94, 0xE9, 0xC0, 0xFD, 0xEC, 0xA1, 0x13, 0xA1, 0x76, 0x75, + 0x46, 0xF8, 0x70, 0x12, 0x2B, 0x79, 0x08, 0xAD, 0xAD, 0x7A, + 0xF4, 0x18, 0x7F, 0x9D, 0x62, 0xEC, 0xA0, 0x71, 0xB5, 0x1B, + 0xEF, 0x32, 0x61, 0x09, 0xE2, 0x8D, 0xA2, 0x11, 0x14, 0x4D, + 0x55, 0x32, 0x10, 0xBB, 0x4B, 0xB7, 0xC4, 0x6E, 0x29, 0xCA, + 0x88, 0xA1, 0x77, 0xBA, 0x7E, 0x52, 0x13, 0xEF, 0xC9, 0x3C, + 0x77, 0xFC, 0x5B, 0xB8, 0xAF, 0x19, 0x0C, 0x0D, 0x8D, 0x3F, + 0x2B, 0x33, 0x6D, 0x05, 0xB2, 0x9C, 0x17, 0x69, 0x9A, 0x9F, + 0x32, 0x65, 0xE1, 0xE9, 0x07, 0x3F, 0xA0, 0x8D, 0xE1, 0x27, + 0xB1, 0x85, 0x33, 0x28, 0x88, 0xDF, 0x93, 0x1A, 0xB1, 0x6F, + 0x86, 0x6F, 0x10, 0x30, 0x33, 0x7B, 0xD0, 0x43, 0xEF, 0x50, + 0xEE, 0xCD, 0x9C, 0xD4, 0xCD, 0xA9, 0x65, 0x4B, 0x7E, 0x48, + 0x88, 0xDD, 0x81, 0xDE, 0x9C, 0x2F, 0x04, 0x6F, 0x90, 0x4D, + 0x16, 0x14, 0xC4, 0x14, 0xE8, 0x3A, 0x80, 0x3E, 0xC3, 0xA8, + 0x2C, 0x3B, 0x91, 0x01, 0x72, 0x38, 0xE9, 0x3C, 0x35, 0x0C, + 0x1B, 0xA9, 0x4B, 0x9C, 0x24, 0x0E, 0xEC, 0x18, 0xBB, 0x83, + 0x73, 0x45, 0xA2, 0xF0, 0x5A, 0x73, 0xEA, 0x81, 0x22, 0x7D, + 0xCB, 0x52, 0x9E, 0xDC, 0x67, 0xB3, 0xDF, 0x13, 0x41, 0x57, + 0x39, 0x33, 0xFA, 0x19, 0xC3, 0x16, 0x91, 0x0E, 0xE4, 0xA4, + 0xED, 0x3F, 0xEA, 0xCE, 0xD6, 0xD8, 0xA3, 0x56, 0x10, 0x50, + 0x84, 0x75, 0x64, 0x4A, 0xB6, 0x83, 0xD7, 0x49, 0xBC, 0x59, + 0xD0, 0xC6, 0x21, 0xC3, 0x55, 0x91, 0x25, 0x12, 0xDF, 0x47, + 0xCA, 0x3B, 0x21, 0xF8, 0x51, 0xA2, 0x38, 0xE6, 0x46, 0x9F, + 0x69, 0x1B, 0x20, 0x5C, 0x85, 0x40, 0x97, 0xB3, 0xB7, 0xD3, + 0x34, 0x91, 0x50, 0x54, 0x99, 0xFA, 0x2F, 0x2B, 0x7F, 0xE3, + 0xB3, 0x4C, 0xE3, 0x35, 0x0C, 0xA8, 0x02, 0xFF, 0x42, 0x6F, + 0x34, 0x9B, 0x80, 0x88, 0xD2, 0xEF, 0xAE, 0xD3, 0xA5, 0x68, + 0xE6, 0x60, 0x36, 0x5F, 0xBF, 0x54, 0x0E, 0x31, 0x61, 0x1F, + 0x2A, 0x91, 0x74, 0x8B, 0x14, 0x7B, 0xE9, 0x5B, 0x36, 0x85, + 0xC4, 0x5B, 0x2F, 0xF6, 0x51, 0x9F, 0xF4, 0x8B, 0x2C, 0x4A, + 0x80, 0x74, 0x38, 0xBA, 0x92, 0x8E, 0x7C, 0x02, 0xA8, 0x84, + 0x50, 0x59, 0xA3, 0x6C, 0x52, 0x70, 0x73, 0x5A, 0xB2, 0x45, + 0x58, 0x50, 0x7B, 0x26, 0xC8, 0x38, 0x7A, 0xB9, 0x12, 0x66, + 0x7E, 0x11, 0xCD, 0x76, 0xEE, 0xC3, 0xBB, 0x55, 0x03, 0xC3, + 0x90, 0x23, 0xA6, 0x54, 0x97, 0xEA, 0x2B, 0xF7, 0x67, 0xC3, + 0xCF, 0x7E, 0x81, 0xE7, 0xD6, 0x76, 0x3C, 0xA1, 0x7F, 0xFE, + 0x85, 0x91, 0x88, 0x3A, 0x3E, 0x8D, 0x37, 0xE9, 0x68, 0x3D, + 0xE2, 0x20, 0x99, 0x24, 0xC6, 0x56, 0xD6, 0x38, 0xBB, 0x6E, + 0x72, 0x59, 0xDE, 0xEB, 0xD8, 0x2F, 0xAF, 0xFB, 0x03, 0x0F, + 0xCF, 0x4A, 0x8A, 0x5B, 0xB2, 0xB5, 0xCB, 0xB8, 0x21, 0x11, + 0xCD, 0x03, 0x4D, 0xE7, 0xE1, 0x97, 0xF1, 0xC8, 0x06, 0x3D, + 0x5B, 0x97, 0x3E, 0x6F, 0x8C, 0x89, 0x80, 0x8E, 0x0F, 0x7A, + 0xEA, 0xBF, 0x34, 0x11, 0x71, 0x2C, 0x82, 0x11, 0xEA, 0x67, + 0x55, 0xBB, 0x67, 0xBD, 0x04, 0x93, 0xD1, 0x25, 0xCE, 0xE2, + 0x3D, 0x2A, 0x8E, 0xD9, 0xB8, 0x1B, 0xAC, 0xC0, 0x6C, 0x33, + 0x2B, 0x85, 0x26, 0xD3, 0xF7, 0xFE, 0x70, 0x6D, 0x7B, 0xF3, + 0xE6, 0xA7, 0xBD, 0x17, 0x1B, 0xDF, 0x58, 0xDE, 0x72, 0x26, + 0x2A, 0x21, 0xF6, 0x26, 0x7A, 0x2C, 0x4F, 0x16, 0x5D, 0xF9, + 0x38, 0x77, 0xB7, 0xCE, 0x77, 0xAB, 0xB1, 0xF8, 0x16, 0xA0, + 0xA9, 0x01, 0x0E, 0xC6, 0x49, 0xB2, 0x41, 0x34, 0xA4, 0x80, + 0x4B, 0xC0, 0x9D, 0xC1, 0xC8, 0x37, 0xFC, 0x71, 0x38, 0xD4, + 0x2D, 0x3C, 0xCC, 0x2A, 0x57, 0xC3, 0xCD, 0x46, 0x73, 0x2B, + 0x4D, 0xF4, 0x5F, 0x92, 0x32, 0x81, 0xBE, 0xD9, 0xBC, 0x58, + 0x3A, 0xBB, 0xB9, 0x01, 0xCC, 0x94, 0x0A, 0xF5, 0x64, 0xF1, + 0x58, 0xB3, 0x29, 0xB1, 0x33, 0xF0, 0x0F, 0x17, 0xDA, 0xE6, + 0xEB, 0xE1, 0xD6, 0x91, 0x20, 0xCD, 0x45, 0x36, 0x0B, 0x7F, + 0xB5, 0x7E, 0x19, 0x3C, 0xCF, 0x8A, 0x11, 0x12, 0xBA, 0x3B, + 0x4E, 0xBD, 0x8A, 0xDE, 0xF6, 0x03, 0x23, 0xD0, 0xFA, 0x2F, + 0x1A, 0x0E, 0x3B, 0x28, 0xD8, 0xD8, 0x35, 0x79, 0x24, 0xE1, + 0x7F, 0x05, 0x32, 0x84, 0xD2, 0x5C, 0xF3, 0xA7, 0xA8, 0xA6, + 0xBC, 0x22, 0x9B, 0xCA, 0xDA, 0xC1, 0x0B, 0x08, 0x28, 0x30, + 0x36, 0x85, 0x38, 0x1E, 0x12, 0x05, 0x1B, 0xEF, 0x32, 0xC0, + 0xEE, 0x7A, 0x77, 0x21, 0xE4, 0x43, 0xB6, 0xFA, 0xCC, 0x9F, + 0x29, 0x25, 0x00, 0x2C, 0xE4, 0x8C, 0xB1, 0x74, 0x05, 0xFC, + 0x3C, 0xDA, 0x88, 0xF7, 0x40, 0x9F, 0x2D, 0xB6, 0x12, 0x4C, + 0xA9, 0x6A, 0xA8, 0xF4, 0xCE, 0xE8, 0x9E, 0x82, 0xF6, 0x5E, + 0x56, 0xB6, 0xE4, 0xA6, 0xAF, 0x59, 0xD9, 0xE0, 0x2B, 0xA6, + 0xBC, 0xDF, 0x43, 0x08, 0xF4, 0xDB, 0x22, 0x0C, 0x03, 0x7B, + 0x22, 0x06, 0xF6, 0x7E, 0x47, 0xEF, 0xA0, 0xED, 0xF9, 0xAB, + 0x8A, 0xA7, 0x8C, 0xE8, 0x80, 0x31, 0xE2, 0x7C, 0x5C, 0x8E, + 0x13, 0x2F, 0x0E, 0x83, 0xBD, 0x32, 0x6C, 0xA6, 0x99, 0x09, + 0x33, 0x37, 0x06, 0xBC, 0x8F, 0x95, 0x68, 0x51, 0x19, 0xA3, + 0x5E, 0x3E, 0xDE, 0x6D, 0x9E, 0x0D, 0x62, 0x91, 0xED, 0x43, + 0xF3, 0x34, 0x9F, 0x1D, 0x8C, 0x15, 0x1E, 0x20, 0x47, 0xC6, + 0x2E, 0x59, 0xE0, 0x1C, 0xB3, 0x5C, 0x20, 0xAE, 0x39, 0x61, + 0x5B, 0x70, 0xA9, 0x1C, 0xD6, 0xFC, 0xD4, 0xFE, 0xAE, 0xA4, + 0x1A, 0x80, 0x35, 0x12, 0xCF, 0x50, 0x9B, 0x12, 0x4B, 0xFE, + 0x91, 0x66, 0x7D, 0x6E, 0x8B, 0x0C, 0x39, 0x28, 0x11, 0x56, + 0xF1, 0xC3, 0x51, 0x1B, 0x70, 0x53, 0x44, 0xBD, 0x0F, 0x7C, + 0xAF, 0xD3, 0xF6, 0xFD, 0x24, 0x21, 0x35, 0x32, 0x56, 0xEB, + 0x06, 0x75, 0x42, 0x10, 0xEB, 0x64, 0x85, 0x6E, 0x2C, 0xEE, + 0x84, 0xD3, 0xD8, 0xEB, 0x5F, 0x1B, 0x31, 0x1E, 0x4C, 0x59, + 0x2F, 0xAF, 0xC8, 0xC7, 0x06, 0xD0, 0x0A, 0xC6, 0xD0, 0x27, + 0x01, 0xAC, 0x2C, 0x91, 0xCE, 0x03, 0xF2, 0x8F, 0x10, 0x79, + 0x20, 0xBE, 0x21, 0x5D, 0xDD, 0xAA, 0x72, 0xE9, 0x6F, 0xC0, + 0x28, 0xBC, 0x87, 0x0D, 0x0F, 0x0A, 0x61, 0x7A, 0x1E, 0xC0, + 0x0E, 0xC2, 0xF6, 0xDF, 0xA8, 0x9D, 0x37, 0xC4, 0x79, 0x26, + 0x2A, 0x13, 0xF2, 0x51, 0x48, 0x4F, 0xC3, 0x6D, 0x48, 0xD6, + 0x16, 0x3E, 0xAD, 0x38, 0x54, 0x1B, 0x3B, 0xB0, 0xAF, 0x88, + 0xA0, 0x57, 0x75, 0x13, 0xAD, 0x66, 0x3B, 0x09, 0x22, 0x03, + 0x19, 0x66, 0x93, 0xD7, 0x64, 0x6E, 0x52, 0xC7, 0x43, 0xD3, + 0x5F, 0x2F, 0x38, 0xA2, 0x9E, 0x2D, 0xF8, 0x36, 0x35, 0xB4, + 0x5B, 0xEF, 0x75, 0x4E, 0x9E, 0x3B, 0xF7, 0x3E, 0x46, 0x6B, + 0x11, 0x59, 0xB0, 0x68, 0x51, 0x7B, 0xDB, 0x10, 0x6A, 0x97, + 0x92, 0x98, 0xC2, 0xB8, 0x2F, 0x32, 0x03, 0x96, 0xEB, 0x3A, + 0x55, 0xC8, 0x8E, 0xD3, 0xDD, 0x4E, 0x96, 0x1E, 0x06, 0x9F, + 0x1C, 0xAB, 0xA5, 0x87, 0x81, 0x28, 0xD8, 0xF8, 0xAE, 0x81, + 0xB1, 0xDB, 0x2D, 0x8A, 0x19, 0x86, 0xDB, 0x29, 0x28, 0x0F, + 0x38, 0x47, 0xBD, 0x6C, 0xF3, 0xB9, 0xA2, 0x09, 0x51, 0x03, + 0x33, 0xA1, 0x9C, 0x60, 0x03, 0x0D, 0xD7, 0x2F, 0xFF, 0x65, + 0x4B, 0x5A, 0x28, 0xD6, 0x69, 0xF3, 0x38, 0x79, 0x0A, 0x9B, + 0x58, 0x3D, 0xEE, 0x7F, 0x8E, 0x27, 0xE6, 0x63, 0x59, 0x70, + 0x00, 0xD9, 0xE5, 0x05, 0x9E, 0x8D, 0x6D, 0xE0, 0xDC, 0xEC, + 0x63, 0xBB, 0xA7, 0x33, 0xF0, 0x41, 0x01, 0xED, 0xA9, 0xCE, + 0x78, 0x62, 0x45, 0x6F, 0xB3, 0x5B, 0x99, 0x46, 0x88, 0x42, + 0x1C, 0x6A, 0x59, 0x0A, 0x60, 0xF6, 0x90, 0x06, 0x41, 0x38, + 0x6F, 0x5E, 0xFD, 0x67, 0xA3, 0x5A, 0x2A, 0x18, 0x48, 0xE2, + 0xB0, 0x8D, 0x7D, 0x0E, 0x95, 0x01, 0x7A, 0x24, 0xC4, 0x67, + 0x83, 0xCC, 0x51, 0xD9, 0x01, 0x39, 0xF5, 0x4B, 0x16, 0x35, + 0x7D, 0x8E, 0x89, 0x91, 0xAC, 0x69, 0x47, 0xF4, 0xDB, 0x2E, + 0x40, 0xA9, 0xD8, 0xA6, 0x9C, 0x9E, 0xD9, 0xA2, 0x35, 0xAB, + 0x34, 0x63, 0x92, 0xEA, 0x86, 0x45, 0xEE, 0xBF, 0xCD, 0x35, + 0x2D, 0x7D, 0x84, 0x44, 0x3B, 0x9F, 0x67, 0x68, 0xE8, 0xB7, + 0xF2, 0x91, 0x56, 0xF2, 0xD3, 0x5E, 0xE8, 0xA1, 0x28, 0x6F, + 0x11, 0x33, 0x43, 0xD1, 0x24, 0x51, 0xAA, 0xF4, 0xDE, 0x95, + 0x05, 0xC7, 0x6F, 0x53, 0xDF, 0xE8, 0x53, 0xED, 0x26, 0x4A, + 0x04, 0x9E, 0x27, 0x1E, 0x49, 0x9C, 0x76, 0x4F, 0x5B, 0x62, + 0xC8, 0xDA, 0x83, 0x8A, 0x4F, 0x0F, 0xB5, 0x78, 0xA5, 0x1F, + 0x88, 0xAC, 0x6B, 0x6E, 0xF1, 0x62, 0x57, 0xA3, 0x56, 0xCB, + 0xBC, 0x90, 0xFC, 0x0D, 0xA3, 0x71, 0xBB, 0x4B, 0x4D, 0x90, + 0xCE, 0x1F, 0xDE, 0xE0, 0x81, 0x7D, 0xF5, 0x81, 0x0D, 0xA5, + 0x3A, 0x94, 0xC3, 0xE8, 0x1F, 0x0C, 0xD2, 0x75, 0xBF, 0x2D, + 0xB3, 0x63, 0x3D, 0x30, 0xD3, 0xED, 0xCE, 0xDF, 0xC6, 0x4A, + 0xB9, 0x69, 0x44, 0x38, 0xF4, 0x98, 0x00, 0xCA, 0x23, 0xBF, + 0x1B, 0x19, 0xD6, 0x35, 0x43, 0xDD, 0x78, 0x61, 0x01, 0x3C, + 0x9E, 0xFD, 0xDE, 0x0B, 0xA7, 0xF4, 0x97, 0x04, 0x1F, 0x1A, + 0x0C, 0xD5, 0xDE, 0x12, 0x01, 0x71, 0x0C, 0x83, 0xF6, 0x02, + 0x7D, 0x9E, 0xD7, 0x28, 0xC7, 0x95, 0x82, 0x69, 0x9F, 0xB7, + 0x37, 0x7C, 0x1C, 0x64, 0x81, 0xA6, 0xA2, 0xEB, 0xC2, 0xD7, + 0x49, 0xB5, 0xBC, 0x4A, 0xEE, 0xCA, 0xE8, 0x4C, 0xBA, 0xC3, + 0x0B, 0x3F, 0xBA, 0x01, 0x88, 0x09, 0xA7, 0x33, 0x12, 0x99, + 0xAD, 0xE3, 0x73, 0xED, 0x3E, 0x74, 0x14, 0x0C, 0xE5, 0x8A, + 0xB0, 0x5B, 0x5A, 0xD5, 0x78, 0xA3, 0x6C, 0x5E, 0x22, 0x9C, + 0x60, 0x3D, 0x37, 0x7F, 0x6A, 0x7E, 0x7B, 0xE8, 0x64, 0x26, + 0x5D, 0x11, 0x1B, 0xC6, 0xC2, 0x18, 0x3E, 0xE7, 0x88, 0x62, + 0xDC, 0xC0, 0xF4, 0x1A, 0x01, 0x1D, 0x8D, 0xF5, 0x49, 0x6E, + 0x89, 0x62, 0x39, 0xF0, 0x68, 0xB1, 0x0A, 0x5C, 0x71, 0x8C, + 0xEC, 0xBD, 0x11, 0xEC, 0x25, 0xD9, 0x33, 0xA9, 0x66, 0xCC, + 0x1D, 0xFA, 0x60, 0xAE, 0x65, 0x60, 0xB1, 0x1C, 0x9B, 0x0C, + 0xBF, 0xC1, 0x8C, 0x6A, 0xB9, 0x63, 0xB2, 0xE9, 0xB0, 0x97, + 0x0B, 0xA2, 0x0D, 0xB4, 0x48, 0x6D, 0xB6, 0xC0, 0xEC, 0xDE, + 0x83, 0xB3, 0xF0, 0x1A, 0x2E, 0x95, 0xA7, 0x08, 0x38, 0x95, + 0xF2, 0xBF, 0x47, 0x04, 0x70, 0xA9, 0xEB, 0x54, 0x5B, 0xA2, + 0x3B, 0xC6, 0x20, 0x8C, 0x94, 0x73, 0xFC, 0x5D, 0xB6, 0x2A, + 0xFD, 0x4C, 0x79, 0x73, 0xE2, 0x0A, 0xAA, 0xEF, 0x3C, 0x2D, + 0xDE, 0x49, 0xF7, 0x64, 0xA3, 0x11, 0xEA, 0x4D, 0xA7, 0x01, + 0xA2, 0x8F, 0x4E, 0xBA, 0xD1, 0x1A, 0xE7, 0x4F, 0x75, 0xAB, + 0xFF, 0x70, 0x13, 0x4D, 0x5E, 0xC0, 0xB3, 0x29, 0xCC, 0xDB, + 0x36, 0x98, 0xCA, 0xDF, 0x2E, 0xDB, 0x8F, 0x2F, 0xDB, 0x8F, + 0x7C, 0x77, 0xAF, 0x2B, 0xA5, 0xB8, 0x36, 0xAD, 0xEA, 0xAB, + 0xDF, 0xED, 0x67, 0xA0, 0x64, 0x8D, 0xE3, 0x96, 0xDA, 0x5C, + 0xE3, 0x4F, 0xD9, 0x03, 0xC1, 0xF3, 0x32, 0xC0, 0x74, 0x86, + 0xAB, 0xEB, 0x89, 0x0E, 0xF5, 0x96, 0x6B, 0x8D, 0x23, 0x9A, + 0xCD, 0x35, 0x24, 0xC5, 0x39, 0xF4, 0xFB, 0xEE, 0x58, 0x00, + 0x09, 0x5E, 0xFE, 0x44, 0x46, 0x6F, 0x5E, 0x00, 0x7B, 0xA7, + 0x72, 0xF7, 0x96, 0x58, 0xC5, 0x08, 0x89, 0x7F, 0x8A, 0xEA, + 0x65, 0x3F, 0x8E, 0x93, 0x4D, 0xBC, 0xAF, 0x36, 0x4E, 0xB6, + 0x01, 0xC9, 0xB2, 0x6C, 0x73, 0xAD, 0xB8, 0x7C, 0x11, 0xCB, + 0xB6, 0xD0, 0x4E, 0xE0, 0x8A, 0x78, 0x3B, 0x94, 0xB8, 0xE2, + 0x78, 0xB4, 0x57, 0xDD, 0xF0, 0x13, 0xD6, 0x46, 0xC2, 0x9F, + 0x8B, 0x43, 0xE1, 0x60, 0xB3, 0x9C, 0xB2, 0x8F, 0xE5, 0xF5, + 0xC5, 0x21, 0x75, 0xBB, 0x70, 0x8A, 0xC1, 0x17, 0xE2, 0xA2, + 0xC0, 0x86, 0xFD, 0xAC, 0x97, 0x39, 0x71, 0xD8, 0xBF, 0x24, + 0xE8, 0xA2, 0x9D, 0xE3, 0x63, 0xCF, 0x7B, 0x2A, 0x88, 0x25, + 0x19, 0xA9, 0xBE, 0x96, 0x00, 0xD2, 0x28, 0x65, 0x79, 0x61, + 0x95, 0x1A, 0x33, 0x7A, 0x1E, 0x0B, 0x45, 0xA8, 0xEE, 0x31, + 0x0F, 0xE0, 0xE0, 0xE1, 0x2B, 0x9B, 0x96, 0x3C, 0xAC, 0xFE, + 0x76, 0x94, 0xF3, 0x63, 0xF0, 0x0D, 0x05, 0x9D, 0xF1, 0x7A, + 0x93, 0xC6, 0x46, 0xCA, 0x15, 0xF6, 0xDF, 0x42, 0x85, 0x2F, + 0xEF, 0xB9, 0x20, 0x16, 0xFA, 0x33, 0xF9, 0x02, 0xBE, 0x64, + 0x69, 0x27, 0x76, 0x81, 0xCC, 0xAB, 0x17, 0x50, 0xD1, 0x0D, + 0x73, 0x93, 0x93, 0xEE, 0x99, 0x1C, 0x78, 0x2B, 0x71, 0x5C, + 0xD3, 0xC7, 0x17, 0xC9, 0x37, 0x5A, 0x16, 0x27, 0x79, 0x1B, + 0x2F, 0x38, 0x35, 0x51, 0xC9, 0x4B, 0x90, 0x13, 0x77, 0x93, + 0xDD, 0x1D, 0xE6, 0xDA, 0x3D, 0x2F, 0xE3, 0x82, 0xF3, 0x82, + 0x69, 0x1A, 0x7F, 0x5F, 0xD0, 0x26, 0x37, 0xB9, 0x47, 0xFE, + 0xE1, 0x3F, 0xC1, 0x20, 0x15, 0xB0, 0x96, 0x61, 0x31, 0x74, + 0xB3, 0xEA, 0x02, 0x49, 0x63, 0xCC, 0x29, 0xD3, 0x0B, 0xC7, + 0x02, 0x3F, 0xE1, 0x65, 0x9A, 0xD9, 0x86, 0x9B, 0x31, 0x1C, + 0x53, 0xAA, 0x47, 0x4F, 0x16, 0xA4, 0x28, 0x17, 0x40, 0x0C, + 0xDC, 0x2F, 0x24, 0xD3, 0x13, 0x99, 0xB9, 0x23, 0xA0, 0x5B, + 0x02, 0x8D, 0x5C, 0x4D, 0x7A, 0x9F, 0x5F, 0xB5, 0xF0, 0x49, + 0x03, 0xA1, 0xC9, 0xEE, 0xB0, 0xE2, 0x26, 0x71, 0x2C, 0x67, + 0xA3, 0xB2, 0x87, 0x7B, 0x2E, 0x41, 0xA1, 0x2B, 0xE0, 0x30, + 0x58, 0x93, 0x08, 0xB7, 0x5B, 0xBF, 0xAC, 0x58, 0xEB, 0x6A, + 0xF1, 0x7C, 0xF4, 0x9C, 0x6D, 0x60, 0xCC, 0x1E, 0x0E, 0x61, + 0x43, 0x99, 0xE4, 0xB7, 0x84, 0x81, 0xF7, 0xEC, 0xE5, 0x87, + 0xC2, 0xAF, 0x0A, 0x9B, 0x25, 0x3F, 0x31, 0x1F, 0xDC, 0x27, + 0xC9, 0x74, 0x18, 0xA3, 0x88, 0x5C, 0x2A, 0xEC, 0xDE, 0x9E, + 0x21, 0x0E, 0x68, 0xCB, 0x26, 0xBD, 0x17, 0xD6, 0xB6, 0x2A, + 0x1B, 0x87, 0x8D, 0x10, 0xB3, 0x4B, 0xF4, 0xCE, 0xC5, 0xA5, + 0x32, 0x8F, 0x53, 0xC6, 0x8A, 0xD9, 0x0A, 0x63, 0x98, 0x2D, + 0xFC, 0x70, 0x78, 0xC7, 0xDB, 0x75, 0xEC, 0x55, 0x54, 0xE1, + 0x8A, 0xE5, 0xF8, 0x3E, 0x01, 0xC1, 0x59, 0xE5, 0x16, 0xAA, + 0x6D, 0xDE, 0x21, 0xE0, 0x3A, 0xFE, 0x21, 0xA3, 0x0C, 0x57, + 0x7F, 0x08, 0xC4, 0x9F, 0xEA, 0x15, 0xA5, 0x77, 0xFB, 0x88, + 0x7A, 0x28, 0xEA, 0xE4, 0x74, 0x26, 0x45, 0x25, 0x8A, 0xDC, + 0x85, 0x54, 0x0B, 0xCE, 0x48, 0x5A, 0x76, 0x84, 0xE9, 0xBF, + 0x71, 0x1D, 0x12, 0x79, 0xF7, 0x95, 0xA5, 0x55, 0x15, 0xF5, + 0xC4, 0x7C, 0x60, 0x4D, 0x8C, 0xFB, 0xCA, 0x4A, 0xD8, 0x9E, + 0x3C, 0xA4, 0xA5, 0x96, 0x11, 0x5C, 0x79, 0xD5, 0x54, 0x08, + 0x49, 0x18, 0xCD, 0x3D, 0x73, 0x1E, 0x1F, 0x98, 0xD0, 0x7F, + 0x0B, 0xCA, 0xEF, 0xB8, 0xDC, 0xCC, 0x3E, 0x4B, 0x1F, 0x13, + 0x22, 0xF2, 0x6C, 0x44, 0x77, 0x3E, 0xAD, 0x60, 0x5E, 0x5A, + 0x34, 0x86, 0x52, 0xBA, 0xCC, 0x5D, 0xF5, 0xA2, 0x55, 0x8B, + 0x96, 0x34, 0x9D, 0xB8, 0x20, 0xA5, 0x1B, 0x33, 0x83, 0x5A, + 0x69, 0xFE, 0x79, 0x14, 0x3B, 0xED, 0x3F, 0xDB, 0xB4, 0x0A, + 0xFE, 0x8C, 0x3C, 0x8C, 0x08, 0x7C, 0x21, 0xD8, 0xA4, 0x50, + 0xA7, 0x59, 0xB5, 0x8E, 0x28, 0x81, 0x4A, 0x21, 0x44, 0x90, + 0x0B, 0x26, 0x82, 0x08, 0x2D, 0x4B, 0x05, 0x9F, 0xAB, 0xA7, + 0x2B, 0x33, 0x95, 0xDE, 0xFA, 0x3C, 0x3A, 0x2B, 0x04, 0xA1, + 0x28, 0x64, 0xFB, 0x6A, 0x2F, 0xD8, 0x0B, 0xDB, 0x3D, 0xF6, + 0x28, 0xA2, 0x1A, 0x85, 0x20, 0x7F, 0xEC, 0x55, 0x5E, 0x53, + 0xB7, 0x2D, 0x02, 0x50, 0x8D, 0xC2, 0xEC, 0x6F, 0x52, 0x1E, + 0xDE, 0x52, 0x07, 0xD5, 0x68, 0x62, 0xA7, 0xAB, 0xBB, 0x68, + 0xD7, 0x7E, 0xE4, 0x9D, 0xB5, 0x79, 0xBB, 0x1B, 0x17, 0x5D, + 0xE8, 0xE6, 0x45, 0xF0, 0x93, 0xE3, 0x03, 0x9A, 0xAE, 0xDB, + 0x10, 0x96, 0xE2, 0xBD, 0x8A, 0xBE, 0x12, 0xB4, 0x98, 0xA4, + 0x8B, 0x7B, 0xD1, 0x22, 0x15, 0x55, 0x6B, 0xC8, 0xFA, 0xAD, + 0xCA, 0x6A, 0x50, 0x09, 0x56, 0x4C, 0xA1, 0x9A, 0x4E, 0x54, + 0x11, 0xE8, 0xCD, 0x3C, 0x9F, 0x45, 0x61, 0x39, 0xDA, 0x76, + 0x01, 0x9B, 0x94, 0x84, 0xCB, 0xB1, 0xF8, 0xA5, 0xE8, 0x06, + 0xDD, 0xE9, 0x0C, 0xC7, 0x97, 0x71, 0x37, 0x40, 0x67, 0x9D, + 0xEE, 0xBD, 0x97, 0xDE, 0x17, 0x80, 0xF1, 0x96, 0x4B, 0x9F, + 0x1B, 0x98, 0x7D, 0x53, 0x66, 0xF5, 0x6C, 0x87, 0xAB, 0xD0, + 0xA8, 0x94, 0xCF, 0x50, 0x0E, 0xD1, 0x0E, 0xF2, 0x06, 0xA1, + 0x09, 0xA2, 0x38, 0x8F, 0x63, 0x82, 0xE0, 0xBE, 0x66, 0x5A, + 0xBD, 0xAA, 0x39, 0xAE, 0x8C, 0x44, 0xCC, 0x62, 0x5F, 0xC5, + 0x75, 0xD6, 0xC6, 0xB4, 0x65, 0x1E, 0x6F, 0xDB, 0x77, 0x62, + 0x3A, 0xFC, 0xFD, 0x57, 0x52, 0xE4, 0x63, 0x2D, 0x06, 0x68, + 0xB0, 0xC6, 0xD5, 0x49, 0x9D, 0x33, 0xB9, 0x2B, 0x4D, 0x41, + 0x78, 0x0B, 0xD5, 0x17, 0xD6, 0x7D, 0x9D, 0xB0, 0xB0, 0x4E, + 0x09, 0xF9, 0x0F, 0x18, 0x8B, 0x2B, 0x3A, 0xE4, 0x00, 0xE3, + 0x8C, 0x0D, 0xDB, 0x91, 0xD7, 0x5B, 0x86, 0x0F, 0x7E, 0x44, + 0xCD, 0x7B, 0x46, 0x4E, 0xC9, 0x67, 0xA6, 0x08, 0x18, 0xB7, + 0xBC, 0x26, 0x77, 0x97, 0x60, 0x54, 0xBE, 0x99, 0xBD, 0xBF, + 0xB1, 0x2D, 0xFF, 0x6D, 0xDE, 0xB7, 0x0F, 0x5F, 0xAC, 0x95, + 0xB3, 0x86, 0x98, 0xB2, 0xAB, 0x02, 0xE8, 0xD5, 0x55, 0xD9, + 0x58, 0x01, 0xF3, 0x07, 0x0D, 0x02, 0x45, 0xB1, 0xD0, 0x23, + 0xF5, 0x35, 0x17, 0x0F, 0x93, 0x1D, 0xCD, 0x1D, 0xFB, 0x63, + 0xB3, 0x82, 0x78, 0xBE, 0x91, 0xFD, 0xB4, 0xF5, 0x5D, 0x19, + 0xEC, 0xDE, 0xA1, 0xAF, 0x6B, 0x24, 0x62, 0xAA, 0x9E, 0x12, + 0x91, 0x53, 0x7C, 0x33, 0x32, 0xF1, 0xD7, 0x15, 0x68, 0x96, + 0x19, 0x64, 0xCC, 0x93, 0x34, 0xB0, 0x48, 0x0F, 0x32, 0x5B, + 0xD4, 0xFE, 0xF5, 0xF2, 0x65, 0xD9, 0x58, 0x27, 0x14, 0x39, + 0x33, 0x97, 0x1D, 0x7D, 0x48, 0x61, 0x86, 0x1F, 0x37, 0x30, + 0xFA, 0xCC, 0x4A, 0x3C, 0x53, 0xCE, 0xEF, 0x43, 0xBA, 0x3C, + 0x84, 0x1A, 0xC1, 0x94, 0x8D, 0x89, 0x59, 0x46, 0x5B, 0xC8, + 0x3B, 0xA1, 0x63, 0xB7, 0x5A, 0xC4, 0xAF, 0xA8, 0xB6, 0x1F, + 0x8E, 0x44, 0xAC, 0x9F, 0xC6, 0xD9, 0x30, 0xD9, 0x83, 0x4C, + 0xB7, 0x0B, 0x4A, 0x6C, 0x90, 0x00, 0x3D, 0xC6, 0x35, 0x5E, + 0xEE, 0x61, 0x86, 0xAD, 0x7A, 0xBC, 0x9F, 0x46, 0x51, 0xE9, + 0xA6, 0x58, 0xA7, 0x55, 0x7E, 0x36, 0xBA, 0x5E, 0xFA, 0x1D, + 0x34, 0x2E, 0x14, 0x96, 0x70, 0x1B, 0x47, 0x6A, 0x18, 0x04, + 0xBA, 0xE8, 0xF2, 0x37, 0xA1, 0xA0, 0x2E, 0xC4, 0xFF, 0x8C, + 0xCA, 0xA7, 0xD4, 0xBD, 0xD1, 0x18, 0x48, 0xC5, 0x9F, 0x47, + 0x22, 0x8E, 0x62, 0xF7, 0xE6, 0x8E, 0xC5, 0x3F, 0x5B, 0x04, + 0xD6, 0xD2, 0x5C, 0xF5, 0xE0, 0xA8, 0x28, 0x73, 0x8D, 0xB6, + 0x3C, 0x96, 0xE2, 0x14, 0x10, 0x6D, 0x78, 0xF0, 0x34, 0xF0, + 0x51, 0xB9, 0x72, 0xA0, 0x57, 0x43, 0x70, 0x72, 0xD7, 0xA3, + 0xDE, 0x2C, 0x50, 0x62, 0x85, 0x3B, 0x81, 0xFB, 0xD1, 0xBA, + 0x4B, 0x30, 0x07, 0x09, 0xC4, 0x6B, 0x2A, 0x8B, 0xE5, 0x7C, + 0x64, 0x3F, 0x8B, 0x62, 0xDA, 0x3C, 0x5C, 0x6D, 0x73, 0xA6, + 0xC1, 0xEF, 0x35, 0x22, 0xC0, 0xF8, 0x6E, 0x3F, 0x97, 0xAC, + 0xBA, 0x20, 0x34, 0x6C, 0xA3, 0xFA, 0xBE, 0x18, 0xE8, 0x7A, + 0x0D, 0x60, 0x6B, 0xAF, 0x68, 0x24, 0x84, 0xE5, 0x8B, 0x41, + 0xD3, 0xC0, 0xD1, 0x48, 0x7D, 0xB4, 0xB1, 0x18, 0xC3, 0xFE, + 0x88, 0x0E, 0xDB, 0x8C, 0xE5, 0xA2, 0xDB, 0x20, 0x26, 0x9B, + 0x8E, 0x61, 0x58, 0x7C, 0x9F, 0x5D, 0x4E, 0x85, 0xB3, 0x78, + 0x2B, 0x97, 0x0B, 0x30, 0xF4, 0x94, 0xE9, 0x18, 0xA1, 0x72, + 0x2C, 0xF5, 0x5F, 0x3E, 0xB7, 0x4F, 0x90, 0xB2, 0x07, 0x7E, + 0xB7, 0x02, 0x27, 0xB7, 0x23, 0xCF, 0x9C, 0x92, 0x87, 0x99, + 0x51, 0x3C, 0x74, 0x6F, 0x2F, 0xBD, 0xE9, 0xE5, 0xD9, 0x96, + 0x06, 0xA6, 0x88, 0x92, 0x78, 0xF3, 0xE2, 0x10, 0x50, 0x45, + 0x1D, 0x61, 0xFA, 0xD0, 0x2E, 0xAC, 0x3C, 0x80, 0xEF, 0xE7, + 0x9F, 0x76, 0xD8, 0x8D, 0x96, 0x07, 0xD9, 0x0D, 0xD3, 0x04, + 0xE1, 0x8C, 0xC7, 0xF6, 0x42, 0x4B, 0x03, 0x62, 0x12, 0x25, + 0xC4, 0x1D, 0x71, 0xB2, 0x9E, 0xB0, 0x5F, 0x76, 0x1E, 0x87, + 0x60, 0x03, 0x3D, 0x88, 0xD6, 0x9B, 0x10, 0xF8, 0xF2, 0xA1, + 0xAE, 0x35, 0x3A, 0x35, 0x2F, 0x65, 0xA5, 0xA7, 0x7D, 0x60, + 0x5F, 0xDE, 0xF3, 0x47, 0x32, 0x82, 0xE1, 0xB5, 0xFF, 0xFD, + 0x51, 0x9C, 0x87, 0xEA, 0x4D, 0xCA, 0xA7, 0xDE, 0x5A, 0x25, + 0x46, 0x39, 0x63, 0x68, 0xEF, 0x74, 0x7C, 0x0F, 0x51, 0xB8, + 0xD3, 0xB0, 0x07, 0xD1, 0x3B, 0xE4, 0xB1, 0xE5, 0x56, 0xF8, + 0xA9, 0x72, 0xB2, 0x37, 0xA3, 0xB0, 0xF2, 0x91, 0x1F, 0xCC, + 0x34, 0x85, 0x89, 0x4C, 0x1A, 0x2E, 0xFA, 0xC6, 0x82, 0xC7, + 0xA5, 0x9B, 0x99, 0xF7, 0xE4, 0x73, 0xBA, 0x4A, 0x3E, 0xDF, + 0x6A, 0xB6, 0x33, 0x13, 0x28, 0xF6, 0xAD, 0xC0, 0x04, 0x59, + 0xCB, 0x46, 0x1D, 0x56, 0x58, 0x7C, 0x03, 0xCA, 0x6D, 0xA1, + 0xA2, 0xAF, 0xFD, 0x3B, 0x3E, 0xBD, 0xF3, 0x0D, 0x74, 0xCE, + 0xE5, 0x4B, 0xB9, 0x29, 0xF9, 0xD8, 0x86, 0x30, 0x10, 0x8B, + 0xB4, 0x52, 0x37, 0x94, 0x48, 0xFC, 0x1A, 0x98, 0xCE, 0xC0, + 0x05, 0x69, 0x4B, 0x59, 0xC4, 0xCE, 0xF4, 0x14, 0xB5, 0xD3, + 0x59, 0x27, 0x68, 0xAB, 0xB0, 0x2E, 0x5A, 0x8A, 0x8C, 0x6D, + 0x60, 0x4B, 0x72, 0x01, 0xAE, 0x69, 0x2D, 0xBD, 0xD2, 0x18, + 0xDF, 0xEC, 0x6D, 0xF0, 0x52, 0xD1, 0x60, 0x81, 0x97, 0x80, + 0x71, 0xE5, 0xA0, 0x22, 0x7A, 0x67, 0x9D, 0x55, 0x3C, 0xDC, + 0x70, 0x91, 0x8B, 0xEB, 0xA8, 0x66, 0x77, 0x00, 0xAE, 0x12, + 0xE4, 0x77, 0xE8, 0x53, 0x9E, 0x3C, 0xD5, 0xD9, 0x3A, 0xA5, + 0x34, 0x80, 0x6B, 0xD7, 0x71, 0x4E, 0xDA, 0x0A, 0x6F, 0x3F, + 0xDC, 0x22, 0xAB, 0xA4, 0xD8, 0x63, 0x62, 0x73, 0x82, 0x33, + 0x97, 0xF8, 0xBF, 0xE9, 0x9B, 0x91, 0x6B, 0x01, 0xB1, 0x27, + 0xAC, 0xAD, 0xD1, 0x25, 0x4C, 0x26, 0x97, 0x45, 0xBD, 0xE1, + 0xBB, 0x29, 0x9D, 0x75, 0xB0, 0xF8, 0xD0, 0xBB, 0x75, 0x32, + 0x34, 0xA7, 0x2E, 0x54, 0x6A, 0xBF, 0xA3, 0x42, 0x87, 0xA5, + 0xB1, 0x3F, 0x1A, 0x87, 0x81, 0x94, 0xD0, 0xA4, 0x05, 0xC3, + 0x2A, 0x7C, 0x59, 0x58, 0x21, 0x65, 0xBF, 0xC0, 0x79, 0x56, + 0xC6, 0xCD, 0x4F, 0xCD, 0xE6, 0x4A, 0x8F, 0x1C, 0x7D, 0x62, + 0xD5, 0x09, 0x2D, 0x11, 0x82, 0x71, 0x6E, 0xBB, 0x80, 0x2C, + 0x47, 0x23, 0x0E, 0x0D, 0xE0, 0x68, 0x82, 0x34, 0x87, 0x03, + 0x7A, 0x08, 0xB7, 0x70, 0x71, 0x58, 0x40, 0xEB, 0x02, 0x2E, + 0x02, 0x32, 0x47, 0x76, 0x84, 0x53, 0xA7, 0xD9, 0x16, 0x7E, + 0x89, 0x2D, 0x40, 0xB2, 0x7A, 0x38, 0x81, 0x31, 0x5C, 0x75, + 0x26, 0x4E, 0xB3, 0xC6, 0xBB, 0x4C, 0x5A, 0xB5, 0xA6, 0xA1, + 0xD8, 0xB4, 0xE7, 0xC9, 0xF9, 0x72, 0x92, 0xC5, 0x12, 0xD8, + 0xFA, 0x45, 0x1C, 0x0F, 0x9E, 0xC5, 0x05, 0xA8, 0xBC, 0x0E, + 0x6D, 0xCF, 0x5F, 0x43, 0x21, 0x9E, 0xFE, 0x8C, 0xEC, 0xC5, + 0xC9, 0x4E, 0x3E, 0xF4, 0xCF, 0xD6, 0xEB, 0xFA, 0xB2, 0x97, + 0x41, 0x60, 0x18, 0x5A, 0x93, 0xF1, 0xE9, 0xCB, 0xB9, 0x26, + 0x48, 0xCD, 0x56, 0x23, 0x0A, 0xE3, 0x84, 0x1B, 0xFC, 0xBA, + 0x99, 0x8B, 0xCA, 0x35, 0xB3, 0xD4, 0x6E, 0x1D, 0x00, 0x2D, + 0xDD, 0x51, 0x4E, 0x96, 0x6A, 0xD2, 0x78, 0x79, 0x8E, 0xEB, + 0xAC, 0x81, 0xF1, 0x57, 0x8B, 0xD5, 0xD7, 0xFF, 0x87, 0x87, + 0x2D, 0xEE, 0x2F, 0x94, 0xB0, 0xEA, 0x0A, 0x1E, 0xF1, 0x9D, + 0xE9, 0x77, 0x01, 0x7C, 0x38, 0x02, 0xA0, 0xA2, 0x04, 0xFB, + 0xA9, 0x8B, 0xDB, 0x10, 0x8B, 0xDA, 0x13, 0x08, 0xD2, 0xE6, + 0x0A, 0x62, 0x72, 0x7C, 0x44, 0x09, 0xA8, 0x57, 0x55, 0x6E, + 0x43, 0x61, 0x27, 0x72, 0x61, 0xA6, 0xE4, 0x71, 0x03, 0x99, + 0xA7, 0x03, 0xA7, 0xC2, 0xDE, 0x08, 0x96, 0xA1, 0x60, 0x21, + 0x5E, 0x10, 0x34, 0xF1, 0x19, 0x79, 0x9A, 0xC5, 0xE2, 0x21, + 0x50, 0xD7, 0x5D, 0x8A, 0xBB, 0x0A, 0x9A, 0xC1, 0x23, 0x93, + 0xFF, 0x61, 0x32, 0x1B, 0xB3, 0xDB, 0x63, 0x7F, 0x4C, 0xAF, + 0x7F, 0xF1, 0x3E, 0xFE, 0x4A, 0x69, 0x73, 0x04, 0x0A, 0xA3, + 0x30, 0x78, 0x6F, 0x40, 0xB5, 0x25, 0x70, 0x1A, 0xD4, 0x8B, + 0x46, 0x11, 0x00, 0x32, 0x4A, 0x64, 0x4C, 0xBD, 0x14, 0x7E, + 0x1D, 0x81, 0x84, 0xFE, 0x19, 0x76, 0x8A, 0xB0, 0x44, 0x08, + 0x05, 0x47, 0xAB, 0xEF, 0x7E, 0x18, 0x6B, 0x77, 0x96, 0xBB, + 0x54, 0x15, 0xB5, 0x70, 0x34, 0x06, 0xD2, 0x81, 0x07, 0x71, + 0xCB, 0x72, 0xC4, 0xE7, 0xD5, 0xA3, 0xC7, 0xEF, 0xF5, 0x47, + 0x2A, 0xB6, 0xAD, 0xFD, 0xC8, 0xDD, 0x50, 0xD4, 0x2B, 0x7F, + 0xAC, 0x55, 0xB0, 0x26, 0xA0, 0xC8, 0xE3, 0x6C, 0x4E, 0xB8, + 0x59, 0x92, 0xBB, 0x40, 0xBF, 0xAD, 0xA1, 0x47, 0x6F, 0x67, + 0x28, 0xE3, 0xB2, 0xA4, 0xF5, 0xEA, 0x9B, 0xD6, 0x88, 0x18, + 0x77, 0xA2, 0x40, 0xDF, 0x96, 0x5C, 0x02, 0x75, 0x31, 0x62, + 0x6A, 0x44, 0x19, 0xE1, 0x0C, 0xC1, 0x4D, 0x39, 0x9E, 0x2F, + 0x1C, 0xFA, 0x3E, 0xC9, 0x75, 0x8C, 0x52, 0x3C, 0xB3, 0xA8, + 0x4A, 0xE6, 0xAC, 0x1E, 0x65, 0x89, 0x22, 0xC0, 0x54, 0x3B, + 0x93, 0xD2, 0x99, 0x79, 0x16, 0xD3, 0x6D, 0x6B, 0xC8, 0xBE, + 0x08, 0x24, 0xA2, 0x02, 0x2C, 0x9C, 0xBD, 0x08, 0x37, 0xFF, + 0xD2, 0x21, 0xA7, 0x28, 0xC5, 0x4B, 0xC7, 0x3B, 0xD5, 0xB8, + 0xF8, 0xC5, 0xAE, 0x3D, 0xD0, 0xA6, 0xDC, 0x55, 0x94, 0x81, + 0x9C, 0xD9, 0x5A, 0x0D, 0xAC, 0xDF, 0x22, 0xB0, 0x63, 0x42, + 0xD1, 0x18, 0x16, 0xC6, 0x9C, 0x4A, 0x69, 0x64, 0x2D, 0x21, + 0x62, 0xFB, 0xA2, 0x81, 0xB0, 0xB8, 0x53, 0xC7, 0x28, 0x6D, + 0xD2, 0xC1, 0x80, 0xAF, 0x25, 0xA9, 0x2A, 0xF3, 0xF6, 0x2F, + 0xB5, 0x30, 0xA2, 0x4B, 0x34, 0x10, 0x19, 0xFA, 0xD0, 0x05, + 0x88, 0x49, 0x8A, 0x9A, 0xA7, 0xD8, 0x13, 0xD6, 0x9F, 0x9B, + 0xA8, 0x40, 0x92, 0x7E, 0x15, 0x59, 0xDA, 0xE7, 0x32, 0xB1, + 0x0C, 0xD8, 0xC9, 0x2E, 0x96, 0x13, 0x6E, 0x84, 0x1B, 0xD3, + 0xAA, 0xD2, 0x0E, 0xC5, 0x61, 0xE6, 0xEC, 0xE9, 0xE6, 0x64, + 0x59, 0x0C, 0xE5, 0xE5, 0xF6, 0xE6, 0xC0, 0xFE, 0x58, 0x3A, + 0xFB, 0x98, 0x52, 0x97, 0xCF, 0x24, 0xB5, 0xA3, 0x32, 0x6C, + 0x71, 0xF7, 0x0B, 0x8A, 0x15, 0x22, 0xE7, 0x3E, 0xC1, 0xFC, + 0x8E, 0x35, 0xD6, 0xB2, 0x68, 0xEB, 0x12, 0x75, 0xAB, 0x41, + 0x02, 0xBB, 0xCB, 0xCC, 0x10, 0x37, 0xA0, 0x0F, 0xB7, 0x97, + 0x77, 0xB1, 0x9A, 0xAF, 0x43, 0x6C, 0x19, 0xC6, 0x30, 0xCC, + 0xBE, 0x40, 0x68, 0x60, 0x71, 0xF5, 0x91, 0x55, 0x84, 0x8B, + 0x30, 0x70, 0x55, 0xD2, 0x8E, 0xFC, 0x0A, 0x7E, 0xAA, 0xA1, + 0x24, 0xD1, 0xBC, 0x3D, 0x59, 0x93, 0x5E, 0xFE, 0xBE, 0xB5, + 0xB3, 0x49, 0x87, 0x65, 0xE2, 0x35, 0x11, 0xA4, 0x3E, 0xC1, + 0xA0, 0x35, 0x84, 0x71, 0x74, 0xE3, 0xC2, 0x66, 0x0E, 0xAB, + 0xBB, 0x51, 0xF3, 0x2E, 0xB8, 0x40, 0x81, 0xF0, 0xB7, 0x03, + 0xE8, 0x43, 0xCF, 0xBF, 0xEE, 0x35, 0xB3, 0x4F, 0xB5, 0xEA, + 0xCD, 0xDF, 0x51, 0x3A, 0x4A, 0x11, 0x31, 0x93, 0x7B, 0x91, + 0x1F, 0x30, 0x8B, 0x0D, 0xD7, 0x23, 0x72, 0xFE, 0xBE, 0x5D, + 0xB9, 0xFC, 0xAE, 0xE4, 0x29, 0x97, 0x0A, 0xB3, 0x82, 0x27, + 0x5A, 0xFE, 0x0C, 0xD2, 0x04, 0xD2, 0xD1, 0xB6, 0xB4, 0x9C, + 0x1B, 0xEF, 0x03, 0x84, 0x37, 0x6B, 0xD6, 0x54, 0x62, 0x30, + 0xC4, 0x64, 0xD2, 0x62, 0x4D, 0x8E, 0x24, 0x59, 0x00, 0x35, + 0x1E, 0x93, 0x19, 0xD3, 0x34, 0x0C, 0x26, 0x27, 0xB2, 0x71, + 0xAA, 0x94, 0xB2, 0x7F, 0x5A, 0xB3, 0x5F, 0xB9, 0x51, 0xB0, + 0xB6, 0x0B, 0xAB, 0xFE, 0xDB, 0xAA, 0xF8, 0x19, 0x0E, 0xCB, + 0x1C, 0x29, 0x69, 0x4D, 0x28, 0x83, 0x96, 0x07, 0x78, 0x2C, + 0xE6, 0xB1, 0x68, 0xB0, 0xF2, 0xA8, 0xF0, 0xC0, 0xB2, 0xBF, + 0x1D, 0x2D, 0xA5, 0x51, 0x63, 0x62, 0x64, 0x83, 0xF6, 0x26, + 0xC1, 0x11, 0x8F, 0x72, 0x83, 0x43, 0xF1, 0x26, 0xA5, 0x39, + 0xCA, 0x8E, 0x32, 0x87, 0xF0, 0x7A, 0x54, 0xA5, 0x3E, 0x8A, + 0x43, 0x9E, 0xBB, 0x81, 0x5F, 0x82, 0xA6, 0x58, 0xC7, 0x30, + 0xE9, 0x66, 0x99, 0xB7, 0xF7, 0x6F, 0xFC, 0x0D, 0x94, 0x01, + 0x2B, 0xCC, 0x8E, 0xAC, 0x13, 0x90, 0x04, 0x6A, 0x97, 0xA1, + 0x25, 0xCE, 0xD8, 0xCF, 0xB2, 0x87, 0x10, 0x88, 0xE7, 0x1C, + 0x46, 0x97, 0x3F, 0x6C, 0x77, 0x49, 0xF9, 0xB9, 0xCB, 0xD9, + 0x03, 0x0D, 0xD8, 0x23, 0x3A, 0x14, 0x88, 0xDD, 0x80, 0xB0, + 0x40, 0xB3, 0x3E, 0xA6, 0xC5, 0xC8, 0xF4, 0xAC, 0x27, 0xF6, + 0x30, 0x25, 0x13, 0x10, 0x14, 0x0B, 0x72, 0x0E, 0x33, 0xCD, + 0x4D, 0x94, 0x5E, 0xF9, 0xAB, 0x1A, 0x6D, 0x77, 0x18, 0x45, + 0xE4, 0x63, 0x53, 0x6F, 0xA7, 0xAD, 0x07, 0xC9, 0x94, 0x4A, + 0x7D, 0xFF, 0x60, 0x77, 0xD7, 0x88, 0xCF, 0xF6, 0xB5, 0x0D, + 0x40, 0xEB, 0xFD, 0xE5, 0x40, 0x0C, 0x94, 0xFD, 0x77, 0x68, + 0xFA, 0x12, 0x0C, 0xA4, 0x2A, 0x77, 0x1A, 0x06, 0xBF, 0x4C, + 0xEA, 0x79, 0xB0, 0x2C, 0x29, 0xF2, 0x25, 0x4B, 0x95, 0xF4, + 0x79, 0x16, 0x31, 0xF3, 0x25, 0x60, 0x53, 0x33, 0x03, 0xC6, + 0xD9, 0x74, 0x09, 0x9F, 0x86, 0x7C, 0xD7, 0xBF, 0xF5, 0xE6, + 0xF7, 0xA6, 0xE6, 0x99, 0xAB, 0x72, 0xA0, 0x32, 0x14, 0x3D, + 0xF0, 0x56, 0xAE, 0x18, 0x45, 0x10, 0xC8, 0x2B, 0xB8, 0x88, + 0x75, 0xD4, 0x71, 0x3A, 0xEB, 0x44, 0xF8, 0x4A, 0xE5, 0x6F, + 0xE4, 0x26, 0xCE, 0xE6, 0x81, 0x07, 0x5B, 0x77, 0xD4, 0x2B, + 0xEE, 0xC7, 0x80, 0x9E, 0x80, 0x46, 0xC7, 0x3D, 0xEB, 0x54, + 0x2E, 0xA1, 0x28, 0xDC, 0xBE, 0x5D, 0x4C, 0x68, 0x08, 0x63, + 0xF4, 0xBC, 0x40, 0xF9, 0xBC, 0xE5, 0xA6, 0xDC, 0x5E, 0x13, + 0x31, 0x56, 0x9D, 0xDB, 0x02, 0x9B, 0xE4, 0x77, 0xE3, 0x06, + 0x60, 0x84, 0x20, 0xAF, 0x59, 0xD7, 0x4F, 0x8F, 0x90, 0x46, + 0x7E, 0xD2, 0x6B, 0x6B, 0xCB, 0x96, 0x31, 0xE1, 0x33, 0xBF, + 0x0D, 0x90, 0xC4, 0xE7, 0xDA, 0x3F, 0x42, 0xAA, 0xDF, 0xCC, + 0x1A, 0xB6, 0xE5, 0xB1, 0xCF, 0x65, 0x61, 0x95, 0x4D, 0x9D, + 0xB6, 0xA6, 0x4E, 0xAD, 0x6E, 0x89, 0xB0, 0x63, 0x7B, 0x60, + 0x86, 0x51, 0x57, 0x8C, 0xFF, 0xA3, 0xD7, 0x9E, 0x8F, 0xFF, + 0x21, 0x9C, 0x23, 0x1B, 0x89, 0x1A, 0x6C, 0xDD, 0x0B, 0xC8, + 0xE7, 0xCB, 0x77, 0x62, 0xCD, 0x52, 0x04, 0x25, 0x0A, 0x24, + 0xCC, 0x08, 0x5E, 0x84, 0xC8, 0x70, 0xD9, 0x46, 0x68, 0x84, + 0xAD, 0xC0, 0xD2, 0x1C, 0x33, 0x04, 0x3C, 0x5E, 0xF7, 0x1A, + 0xD9, 0xB6, 0xE2, 0x2A, 0x50, 0x3B, 0x9F, 0x26, 0xDD, 0xE1, + 0xE8, 0xA5, 0x44, 0x55, 0xA3, 0xEE, 0x54, 0x18, 0x95, 0x4C, + 0xD4, 0x46, 0x7A, 0xF0, 0xCF, 0x69, 0x4D, 0xCF, 0x6C, 0x63, + 0xED, 0x84, 0xAF, 0x55, 0x72, 0x34, 0x2F, 0xED, 0x13, 0x2B, + 0x4C, 0xAF, 0x29, 0x43, 0xDD, 0xF1, 0x7D, 0x25, 0xD6, 0x71, + 0x9F, 0x03, 0x1E, 0x13, 0x4C, 0x36, 0x06, 0x7F, 0x38, 0xA5, + 0xF8, 0xC5, 0x55, 0x86, 0xD4, 0x25, 0xB1, 0x9C, 0x42, 0x57, + 0x8C, 0xAD, 0x60, 0x8D, 0xEC, 0x5A, 0xC6, 0xAC, 0x0C, 0x9B, + 0x66, 0xAA, 0xD9, 0xBF, 0x8C, 0x75, 0x6C, 0x0F, 0x42, 0xF8, + 0xFE, 0xA8, 0xB0, 0x26, 0x2C, 0xDE, 0x50, 0x2E, 0x0D, 0xD9, + 0xEC, 0x8A, 0x7C, 0xCC, 0x1C, 0x54, 0x60, 0x5D, 0x6B, 0x39, + 0x7F, 0x29, 0x4B, 0x46, 0xFC, 0xA4, 0x90, 0x45, 0x58, 0xF1, + 0x0C, 0x4E, 0xA8, 0xA3, 0xD9, 0x9B, 0x8D, 0x97, 0x31, 0xD6, + 0x98, 0xA5, 0x7C, 0x0D, 0x64, 0x1B, 0x20, 0xFA, 0xCB, 0xFB, + 0x33, 0x5B, 0x1D, 0xF8, 0x62, 0x34, 0xE8, 0xE0, 0xBA, 0x1F, + 0xAF, 0x52, 0x6A, 0xE3, 0x9C, 0xBC, 0xBA, 0xF7, 0xF6, 0x0C, + 0x6A, 0xF0, 0x39, 0x46, 0x5E, 0x6B, 0x8C, 0xAC, 0x28, 0x20, + 0x9A, 0x91, 0x1E, 0x3D, 0x8B, 0xEA, 0x78, 0x8E, 0x9C, 0x1B, + 0xD0, 0x19, 0x57, 0xF8, 0xBE, 0x74, 0xC7, 0x78, 0xC6, 0xFA, + 0x29, 0xC4, 0xD0, 0x3A, 0x3A, 0x91, 0xE7, 0x39, 0x12, 0xF2, + 0x68, 0xE9, 0x39, 0x3D, 0xDB, 0xD8, 0x8E, 0x15, 0x95, 0xF6, + 0x5C, 0xC3, 0x45, 0xC8, 0x57, 0x3F, 0xBE, 0x81, 0x52, 0xA1, + 0xB4, 0x68, 0x38, 0x1B, 0x15, 0x86, 0x5A, 0x1E, 0x6E, 0x5E, + 0x25, 0xE6, 0x14, 0xD5, 0x5C, 0x9E, 0xBB, 0x35, 0xA8, 0x42, + 0x29, 0xC5, 0x94, 0x05, 0xDE, 0xC1, 0x16, 0xEF, 0x18, 0xDE, + 0xF9, 0x26, 0xD9, 0x1E, 0x63, 0x2D, 0x25, 0xB6, 0x81, 0xE0, + 0x81, 0x19, 0x45, 0x5B, 0xD7, 0x0D, 0xEC, 0x61, 0x97, 0x07, + 0x8D, 0x4F, 0x49, 0xE1, 0xAC, 0x1C, 0xFC, 0x42, 0xAE, 0xED, + 0xCC, 0xD0, 0xC5, 0xDF, 0xFC, 0x0C, 0xE7, 0x38, 0x49, 0x15, + 0x2D, 0x7A, 0x2D, 0xD3, 0x78, 0x32, 0xE6, 0x37, 0x75, 0xC0, + 0xB4, 0x4D, 0x42, 0xE1, 0x0F, 0x94, 0xA1, 0xCF, 0x88, 0xB0, + 0xBF, 0x4D, 0x48, 0x98, 0x42, 0x0A, 0x41, 0xE4, 0x03, 0xC6, + 0x0A, 0x97, 0x1F, 0x79, 0xF2, 0x5D, 0x78, 0xAE, 0xE9, 0xCB, + 0xA1, 0x0D, 0xAA, 0x63, 0xFD, 0x91, 0x16, 0x57, 0x81, 0xAD, + 0x66, 0xC5, 0xBE, 0x13, 0x55, 0x98, 0xC7, 0x28, 0x02, 0x13, + 0xE7, 0x18, 0x73, 0x9A, 0xDC, 0x3D, 0x7E, 0x55, 0x23, 0xA6, + 0x91, 0x36, 0xA2, 0xAB, 0x51, 0xD2, 0x0B, 0xBF, 0x57, 0x84, + 0x2A, 0x77, 0x22, 0xE0, 0x4A, 0x7A, 0x20, 0xBF, 0xB6, 0x88, + 0x25, 0x5F, 0xD5, 0xCD, 0xF8, 0x5A, 0x8F, 0x2A, 0xA6, 0x70, + 0xE4, 0x0D, 0xF2, 0x9E, 0xC3, 0xCC, 0x75, 0x94, 0xFC, 0x9A, + 0x46, 0x9A, 0x65, 0x33, 0xC1, 0xB5, 0x55, 0x3A, 0xFD, 0x0A, + 0x3E, 0xEA, 0x0B, 0x38, 0xFD, 0xB8, 0xA8, 0x13, 0xD8, 0x5F, + 0xB2, 0xE1, 0x34, 0xB2, 0x48, 0xC2, 0x75, 0x02, 0x55, 0x27, + 0x37, 0x82, 0x90, 0x81, 0xBE, 0x05, 0x00, 0x7D, 0x59, 0x78, + 0x7A, 0xCE, 0x75, 0x1C, 0xAE, 0xB6, 0x53, 0x94, 0xF1, 0x17, + 0x02, 0x58, 0x2D, 0x46, 0xF1, 0x86, 0xE0, 0x96, 0xCA, 0xBE, + 0xEC, 0xD0, 0x98, 0x37, 0x70, 0x6B, 0xCB, 0xA8, 0xAA, 0x9F, + 0x78, 0x81, 0xA3, 0x9B, 0x88, 0x54, 0x19, 0xDC, 0xF0, 0xB5, + 0x81, 0x1D, 0x62, 0x09, 0x13, 0xE8, 0xFE, 0x4E, 0x32, 0x76, + 0xC5, 0xE8, 0x54, 0xFD, 0xE7, 0x54, 0x47, 0x75, 0x4B, 0x73, + 0xAC, 0x9C, 0x36, 0x97, 0xE3, 0x4A, 0xCB, 0x08, 0xD6, 0xA5, + 0x8C, 0x4B, 0x36, 0xBD, 0x49, 0x9C, 0xE3, 0x8A, 0x1B, 0x1F, + 0x38, 0x25, 0x0E, 0xD8, 0xBF, 0xB7, 0x33, 0x2F, 0xDA, 0x4B, + 0x87, 0xBA, 0x50, 0xD3, 0xA7, 0x05, 0x66, 0x35, 0xB8, 0x89, + 0xD3, 0x38, 0xE7, 0xE1, 0xA9, 0x3B, 0x6D, 0x58, 0xBE, 0x2C, + 0xF3, 0xFA, 0xDA, 0xDE, 0x51, 0x40, 0x34, 0x01, 0x3E, 0x1E, + 0x0E, 0x72, 0xB1, 0x2B, 0x8A, 0x68, 0x46, 0x11, 0xF0, 0x95, + 0xE3, 0xAC, 0xA2, 0x0A, 0x00, 0x65, 0xAC, 0x6C, 0xF2, 0xF3, + 0x27, 0xC8, 0x77, 0xE1, 0xCA, 0x38, 0x5C, 0xAD, 0x2D, 0xA8, + 0x61, 0x9F, 0xA0, 0xEB, 0x84, 0xA7, 0x74, 0x0E, 0x48, 0x5F, + 0xDB, 0x68, 0x06, 0x43, 0xEF, 0x4E, 0xF9, 0xCE, 0xB2, 0x04, + 0x6C, 0x8B, 0x4F, 0xB5, 0x36, 0x0D, 0xF9, 0x3F, 0x18, 0x22, + 0x4F, 0xD3, 0xCB, 0x4B, 0xC0, 0xF3, 0x5B, 0xA6, 0xF8, 0x0C, + 0x14, 0x93, 0x65, 0xB8, 0x93, 0xA0, 0x07, 0xB0, 0x70, 0x12, + 0x09, 0xFA, 0x03, 0xB3, 0x34, 0x5C, 0xF4, 0x63, 0xBC, 0xC4, + 0x39, 0xE4, 0x4F, 0x78, 0xFA, 0x94, 0xED, 0xAF, 0xC9, 0xEF, + 0x2D, 0xE3, 0x41, 0xF9, 0xD7, 0x25, 0x52, 0xD4, 0x91, 0x24, + 0xC5, 0x95, 0x48, 0xED, 0x11, 0xFD, 0x04, 0xFC, 0x7E, 0x3E, + 0xB4, 0xBA, 0xA7, 0x01, 0x20, 0xF8, 0x9C, 0x9C, 0x9D, 0x5E, + 0x9D, 0x16, 0x16, 0xCD, 0xA4, 0x10, 0xA8, 0x29, 0xEE, 0x98, + 0xBE, 0x7A, 0x66, 0xF4, 0xE5, 0x44, 0xB3, 0x16, 0x8A, 0xF4, + 0x35, 0xCD, 0x85, 0x68, 0x7F, 0x8E, 0x54, 0xEF, 0xA6, 0x5E, + 0x5E, 0x77, 0x94, 0x09, 0x18, 0xBA, 0x2F, 0xED, 0xA1, 0x72, + 0x2C, 0x7B, 0xC7, 0x33, 0x51, 0x89, 0xFF, 0x78, 0x91, 0x96, + 0x9B, 0x27, 0xE8, 0xCC, 0xF2, 0x8F, 0x13, 0x0D, 0x38, 0xF3, + 0x05, 0x08, 0x7C, 0xAC, 0xFC, 0xFA, 0x87, 0x95, 0xA5, 0xF8, + 0x3B, 0x72, 0x07, 0x7A, 0x74, 0x19, 0xA6, 0x56, 0xD8, 0xB1, + 0xA9, 0x73, 0x85, 0xCC, 0x29, 0x9E, 0x55, 0xE4, 0x0C, 0x63, + 0x1C, 0x0E, 0x96, 0xB0, 0x3A, 0xA5, 0x04, 0xF2, 0xC0, 0xB9, + 0x15, 0x30, 0xD3, 0xDA, 0x39, 0x8F, 0x85, 0xE7, 0x82, 0x35, + 0x5F, 0xBA, 0xC1, 0x04, 0x83, 0xC6, 0x07, 0xAB, 0xB0, 0x8A, + 0xFF, 0xA4, 0x93, 0x12, 0x7C, 0x0E, 0x6F, 0x4B, 0x12, 0xB4, + 0x87, 0xBF, 0xF6, 0xF6, 0x0D, 0xA4, 0xA9, 0x7E, 0x60, 0x8F, + 0x00, 0x30, 0x90, 0xC7, 0x4F, 0xA7, 0xBC, 0x46, 0x24, 0xB9, + 0xF2, 0xEE, 0x3E, 0x0E, 0x70, 0x5A, 0x6F, 0xC1, 0x0B, 0x6F, + 0xCB, 0xF0, 0x9A, 0x07, 0xFD, 0x5E, 0xCA, 0x8C, 0x98, 0xD6, + 0x08, 0x06, 0x67, 0xA5, 0xC0, 0x08, 0x38, 0x9C, 0xF6, 0xE9, + 0x75, 0x89, 0xE7, 0x93, 0x77, 0xB3, 0xD3, 0xF0, 0x19, 0x4E, + 0xA4, 0xA4, 0xF1, 0xBB, 0xF6, 0x43, 0x8D, 0x7C, 0x11, 0xD6, + 0x42, 0x0E, 0xCF, 0x0A, 0xCA, 0xBF, 0x64, 0xEB, 0x46, 0xF6, + 0x67, 0xBB, 0x9F, 0xD8, 0xC1, 0x7D, 0x12, 0x0A, 0x4A, 0x49, + 0x62, 0x0A, 0x93, 0x87, 0x06, 0x0A, 0xD2, 0x91, 0x33, 0x9C, + 0xBC, 0xCE, 0x11, 0x18, 0x4D, 0x17, 0x8F, 0xFD, 0x3B, 0x06, + 0x67, 0xD6, 0xBE, 0x78, 0xEE, 0xCE, 0x75, 0xDD, 0x21, 0xBF, + 0xCC, 0x53, 0x05, 0x15, 0x5F, 0xF5, 0x54, 0x05, 0xA5, 0x7E, + 0xDB, 0x0D, 0x80, 0x48, 0x52, 0x74, 0x08, 0xF3, 0x9F, 0xBB, + 0x47, 0x94, 0x5B, 0x39, 0x00, 0x50, 0x54, 0x2B, 0xBB, 0x02, + 0x5A, 0xE4, 0xE5, 0x91, 0x05, 0x8D, 0x70, 0x7F, 0xBF, 0xBD, + 0xF8, 0x0C, 0x72, 0x7C, 0xAA, 0xB1, 0xAB, 0xC9, 0x8D, 0x27, + 0x09, 0x92, 0x3B, 0x68, 0x47, 0xEA, 0xB3, 0x0B, 0xAE, 0x3B, + 0x65, 0x5B, 0x5D, 0xFD, 0xE7, 0xA7, 0x83, 0xD5, 0x68, 0x81, + 0xF1, 0xF1, 0x02, 0x81, 0x15, 0x5C, 0x30, 0xA8, 0xB1, 0xDD, + 0x6F, 0xCF, 0xDF, 0xA8, 0xEF, 0xD1, 0xF0, 0x7C, 0xB9, 0xED, + 0x0E, 0xFA, 0x87, 0x8A, 0x9C, 0x2C, 0x28, 0x0F, 0x37, 0x20, + 0x84, 0x7E, 0xDB, 0x74, 0x8B, 0xEB, 0x7E, 0x46, 0x7F, 0x99, + 0x73, 0xF3, 0xAD, 0xAC, 0x7D, 0xC3, 0xFB, 0x65, 0xB6, 0xB6, + 0x0E, 0xA1, 0x4E, 0x7A, 0x8E, 0xD6, 0x5A, 0xB1, 0x3F, 0x47, + 0x93, 0xB7, 0x30, 0x39, 0x7B, 0xAC, 0x27, 0xF6, 0x50, 0xAA, + 0xCF, 0xA4, 0x67, 0x80, 0xD2, 0xC3, 0x34, 0x47, 0x85, 0xBE, + 0x8E, 0x83, 0x0A, 0xEF, 0x8F, 0xBD, 0x16, 0x45, 0xA6, 0x1A, + 0xB9, 0xAE, 0x13, 0xC4, 0xCD, 0x31, 0xC6, 0xE4, 0xEB, 0x9E, + 0x1E, 0xA7, 0xE7, 0xFF, 0x6B, 0xCD, 0x42, 0x17, 0x7C, 0x37, + 0x2F, 0x47, 0xEB, 0x8F, 0xE8, 0x43, 0xEB, 0x09, 0xD9, 0xBF, + 0xCF, 0xEB, 0x46, 0x27, 0x06, 0x39, 0x2B, 0xB3, 0xDB, 0x1B, + 0xE8, 0x23, 0x23, 0xE2, 0xE4, 0x40, 0xD5, 0x45, 0x23, 0x9E, + 0xBB, 0x83, 0x7E, 0x0F, 0x75, 0x31, 0xD9, 0xA3, 0xAB, 0xC8, + 0x2F, 0x17, 0x1C, 0x04, 0x17, 0x46, 0xDA, 0x1F, 0x05, 0x62, + 0x2B, 0x89, 0xA6, 0x83, 0x17, 0x11, 0x1E, 0xF5, 0xA7, 0xD1, + 0x58, 0x57, 0x26, 0xDB, 0x48, 0x0C, 0x3D, 0x7D, 0xB0, 0x9F, + 0x1E, 0x78, 0x45, 0x3B, 0x27, 0x8C, 0x28, 0x28, 0xF7, 0x19, + 0x12, 0x3C, 0xC2, 0x28, 0xE6, 0xC3, 0xDE, 0x35, 0x75, 0x8E, + 0xCB, 0x35, 0x42, 0xF0, 0xCD, 0xA9, 0xA9, 0x46, 0x7E, 0xD3, + 0x68, 0xAF, 0x03, 0xF9, 0x9C, 0xA3, 0xCA, 0x05, 0x97, 0x66, + 0x09, 0xD7, 0xF8, 0x4F, 0xC2, 0x98, 0x8D, 0xC8, 0x16, 0x11, + 0xA1, 0x13, 0x07, 0x7D, 0x6F, 0x73, 0x6B, 0x95, 0x9D, 0x35, + 0x34, 0xAE, 0x18, 0x3B, 0xAF, 0xBB, 0xF1, 0x48, 0x26, 0x5A, + 0xE0, 0x86, 0x84, 0xAB, 0x91, 0x8A, 0xD0, 0x3D, 0x0C, 0x71, + 0x74, 0xD2, 0xD9, 0x89, 0x05, 0x6B, 0xB7, 0xE1, 0xD6, 0xF2, + 0xB6, 0x4D, 0x1A, 0x3E, 0x2B, 0x94, 0x44, 0xD3, 0x5C, 0xFD, + 0x0C, 0xBD, 0x73, 0x2E, 0x80, 0xF7, 0x7D, 0x09, 0x3B, 0x11, + 0x12, 0x0C, 0x9D, 0x19, 0x7C, 0x95, 0x35, 0x9B, 0x55, 0x43, + 0x73, 0xCC, 0xC7, 0x16, 0xFB, 0xC5, 0x06, 0xBA, 0x04, 0x03, + 0x15, 0x41, 0x91, 0x28, 0xD3, 0x33, 0xF9, 0x67, 0xE5, 0x29, + 0xC5, 0x47, 0x65, 0x61, 0x7D, 0x38, 0x84, 0x10, 0x95, 0x82, + 0x8A, 0xC7, 0x0E, 0x3B, 0xB2, 0x60, 0x4E, 0x90, 0x57, 0xCF, + 0x13, 0xF2, 0xD1, 0x7B, 0xA4, 0xCB, 0xDA, 0x05, 0xF2, 0x3C, + 0x60, 0x6F, 0x4A, 0x07, 0xBB, 0xF2, 0xEE, 0x19, 0x27, 0x59, + 0x0E, 0x02, 0xE4, 0xDD, 0x1B, 0xE9, 0x71, 0xE6, 0x2D, 0xE1, + 0x1F, 0xE8, 0x31, 0x64, 0x05, 0xAE, 0x82, 0xA8, 0x7F, 0xD8, + 0x47, 0xBE, 0x05, 0xFA, 0x11, 0xEC, 0xCE, 0x28, 0x68, 0xC2, + 0x41, 0x37, 0xAC, 0x7C, 0xF6, 0xF3, 0x56, 0x4D, 0x8E, 0x1C, + 0x4D, 0x51, 0xC4, 0x09, 0x32, 0xF9, 0x34, 0xA8, 0x5C, 0x50, + 0x95, 0xCD, 0x98, 0x30, 0xC2, 0xCB, 0xCE, 0xCD, 0xFE, 0x08, + 0xD4, 0x19, 0xE8, 0x13, 0x42, 0x03, 0x04, 0x14, 0x27, 0x9A, + 0x55, 0x3E, 0x60, 0x09, 0xD9, 0xA1, 0x05, 0x85, 0xE5, 0xBE, + 0xE5, 0x0C, 0xFD, 0x4B, 0x01, 0xF3, 0xDA, 0x43, 0x15, 0x87, + 0xB4, 0xE3, 0x96, 0xEE, 0x2B, 0x4F, 0x09, 0x63, 0x4E, 0xA1, + 0xE9, 0x4C, 0x1A, 0x64, 0x9D, 0x53, 0x23, 0x25, 0x9A, 0x90, + 0x2F, 0x62, 0xA4, 0x40, 0xF1, 0x97, 0x37, 0x0A, 0x51, 0xE9, + 0xC7, 0x32, 0x8A, 0x39, 0x77, 0xDD, 0x30, 0x44, 0x84, 0xFA, + 0x6E, 0x42, 0xA1, 0xC4, 0xAE, 0x50, 0xCE, 0xF1, 0x18, 0x4C, + 0x48, 0xDA, 0x72, 0xFC, 0xD8, 0x6E, 0x3D, 0xCD, 0xC6, 0x7B, + 0x33, 0x98, 0x9E, 0x3B, 0xAB, 0x57, 0xB9, 0x46, 0x5A, 0x92, + 0xFD, 0xE5, 0xCB, 0x62, 0xC9, 0x09, 0x5C, 0xAC, 0xCC, 0x6D, + 0xDA, 0x26, 0x9A, 0xD7, 0xF4, 0x6A, 0xB3, 0x17, 0x5A, 0xD1, + 0x84, 0xE4, 0x1B, 0x1E, 0xCA, 0x22, 0x62, 0x61, 0x6A, 0x80, + 0x73, 0xF6, 0x75, 0xF0, 0xBB, 0x72, 0x8A, 0xF7, 0xDA, 0xA6, + 0xEA, 0xFF, 0x84, 0xE0, 0x53, 0x6C, 0x50, 0xB6, 0x92, 0x75, + 0x2F, 0x03, 0x93, 0xDB, 0x91, 0xC9, 0x08, 0xA5, 0xF8, 0x51, + 0xD2, 0x28, 0xBB, 0x03, 0xF1, 0x1E, 0x1C, 0xAB, 0xCC, 0x6F, + 0x17, 0x86, 0x02, 0x64, 0x08, 0x34, 0xA0, 0xAD, 0x31, 0xE4, + 0x46, 0x38, 0x00, 0xE6, 0x65, 0xAE, 0xFF, 0xBB, 0xF3, 0xAA, + 0xF0, 0x76, 0x5F, 0xB6, 0x7E, 0xFD, 0xD7, 0x60, 0x28, 0x9A, + 0x72, 0x14, 0x00, 0xA4, 0xDC, 0x07, 0x68, 0x39, 0xC5, 0x72, + 0xF5, 0x9A, 0xF7, 0xF2, 0x64, 0x66, 0x2F, 0xFE, 0x73, 0x52, + 0x09, 0xF5, 0x5F, 0xE0, 0x95, 0x24, 0x9A, 0x98, 0x26, 0x41, + 0x34, 0xC6, 0xDE, 0xEC, 0x4D, 0x7D, 0x28, 0x06, 0x79, 0x9A, + 0x6B, 0xE8, 0x2C, 0xA2, 0x95, 0xEE, 0xF9, 0x0E, 0xBC, 0x6B, + 0x51, 0x55, 0x42, 0xA8, 0xCB, 0x6F, 0x22, 0x8A, 0x1F, 0x17, + 0x98, 0x34, 0x31, 0xE1, 0x53, 0xA2, 0xB1, 0xEA, 0x51, 0x3E, + 0xFB, 0x1C, 0xB8, 0x4E, 0xA5, 0x4B, 0x03, 0x5A, 0x35, 0x1D, + 0x90, 0x7F, 0x85, 0x6B, 0x24, 0x5B, 0x19, 0x71, 0xC0, 0x12, + 0xFE, 0x18, 0x68, 0x89, 0xBB, 0xBF, 0x8B, 0xC4, 0x55, 0x04, + 0x49, 0x59, 0x88, 0xEE, 0xB4, 0x0F, 0xE5, 0x9B, 0x70, 0x5B, + 0x23, 0xE1, 0x1F, 0x88, 0xF1, 0x6D, 0x47, 0x5E, 0xC7, 0x44, + 0x21, 0x63, 0xD5, 0xE4, 0x06, 0xF9, 0x15, 0x26, 0x76, 0x84, + 0x61, 0xC6, 0x1B, 0xEA, 0x63, 0x6F, 0x9D, 0x18, 0x8E, 0xD8, + 0x43, 0x24, 0x22, 0xF1, 0xB4, 0xD7, 0x46, 0x38, 0x7A, 0xC6, + 0x66, 0x35, 0x7D, 0xB3, 0x5E, 0x1B, 0x18, 0xF4, 0x46, 0x3C, + 0xB6, 0xE5, 0xD9, 0xB2, 0x48, 0x7B, 0x8B, 0xFF, 0x52, 0xA6, + 0x6F, 0x74, 0xF2, 0x1A, 0x49, 0x71, 0x8C, 0x5E, 0x8F, 0x44, + 0x61, 0x54, 0x5B, 0x15, 0x06, 0x23, 0xC2, 0x17, 0xC0, 0x70, + 0xC4, 0x5A, 0xCE, 0x66, 0xE5, 0xD6, 0x9F, 0xAB, 0xF6, 0xA0, + 0x16, 0x86, 0x9D, 0xEE, 0xFD, 0xFC, 0x00, 0xC2, 0xC5, 0x58, + 0x90, 0xE4, 0xE7, 0x8E, 0x50, 0xFF, 0x37, 0x07, 0xF6, 0xBC, + 0x4B, 0x64, 0xED, 0x08, 0xED, 0xE2, 0x96, 0x1A, 0x8D, 0xFA, + 0x4E, 0x09, 0x1D, 0xC5, 0x94, 0x88, 0xC5, 0x4E, 0x05, 0x90, + 0xA0, 0x4F, 0x24, 0x84, 0x3A, 0x77, 0x0C, 0xA8, 0xDC, 0xE3, + 0x02, 0x20, 0x9F, 0x3C, 0xDF, 0x55, 0xC5, 0x42, 0x5C, 0xD3, + 0x59, 0xC6, 0xD1, 0x2F, 0x3A, 0x79, 0x62, 0x6A, 0x9F, 0x71, + 0x40, 0x4E, 0x2C, 0x94, 0x5A, 0xFE, 0x62, 0x07, 0x7D, 0x19, + 0xFC, 0x57, 0x0F, 0xBD, 0x13, 0xB5, 0xD8, 0xFF, 0x75, 0x4D, + 0x10, 0xE7, 0xA8, 0x64, 0x3C, 0xA5, 0x54, 0x64, 0x33, 0x17, + 0x3F, 0x0C, 0xCF, 0xB6, 0x4E, 0x15, 0x50, 0x56, 0x99, 0x44, + 0xCA, 0x2D, 0x41, 0x4A, 0x15, 0x33, 0x14, 0x84, 0x17, 0xE3, + 0xB9, 0x77, 0x71, 0x69, 0xE9, 0xF5, 0xEA, 0x18, 0x7B, 0xFD, + 0xD8, 0xA2, 0x40, 0xB8, 0xE3, 0x40, 0xE4, 0x42, 0x90, 0x28, + 0xFF, 0x49, 0x44, 0x8F, 0xD4, 0xBE, 0x58, 0xD8, 0x04, 0x97, + 0xD9, 0x2F, 0xB5, 0x33, 0xD5, 0x54, 0xE9, 0x7E, 0x22, 0xC6, + 0x5D, 0xB8, 0xD5, 0xF5, 0x03, 0x8B, 0x9A, 0x28, 0x9B, 0xAF, + 0x60, 0xB6, 0xE6, 0x75, 0xEE, 0xDA, 0x70, 0xAD, 0x84, 0xBC, + 0xE6, 0xB3, 0x12, 0x39, 0x89, 0xC7, 0x7C, 0x53, 0xD1, 0x4F, + 0x4C, 0x60, 0x1E, 0x71, 0x4F, 0xF6, 0x50, 0xE2, 0x24, 0xB3, + 0xBB, 0xE3, 0xEB, 0xA6, 0x1C, 0x4A, 0xE3, 0xCE, 0x66, 0xB9, + 0x6D, 0x03, 0xC5, 0x03, 0xA9, 0x1C, 0x06, 0xEC, 0xAB, 0xDA, + 0x57, 0x18, 0xA5, 0x44, 0x91, 0x58, 0x6B, 0xB6, 0x1D, 0x47, + 0xF6, 0xF2, 0x70, 0xD3, 0x0C, 0xC1, 0xCC, 0x62, 0x52, 0xBB, + 0x5E, 0xCA, 0x09, 0x5F, 0x00, 0x84, 0x12, 0x0B, 0x04, 0xA4, + 0xB2, 0xB2, 0x1D, 0xE3, 0x35, 0x8B, 0x04, 0x9B, 0x74, 0xD1, + 0x1B, 0x8B, 0x84, 0x31, 0xE7, 0x8A, 0x16, 0xF1, 0xD6, 0x91, + 0x43, 0xFE, 0x4A, 0x39, 0x86, 0x29, 0x30, 0x81, 0x4D, 0xF3, + 0xA7, 0x7E, 0x23, 0xDF, 0xE4, 0x9A, 0xA4, 0xAA, 0xC4, 0x1E, + 0x79, 0x09, 0x42, 0x46, 0x20, 0x4E, 0xE4, 0x61, 0xDA, 0xEF, + 0xA0, 0xE7, 0x95, 0xF9, 0xD3, 0xA6, 0x11, 0x1B, 0xE4, 0x20, + 0xD8, 0x7E, 0x34, 0x95, 0x70, 0x69, 0x82, 0x90, 0x2F, 0xEC, + 0x17, 0xCD, 0x07, 0x23, 0xC9, 0x24, 0xD3, 0x85, 0x51, 0x10, + 0x24, 0x6E, 0x09, 0x7F, 0xEE, 0xD5, 0xF0, 0x61, 0x0A, 0xDD, + 0xFF, 0x29, 0x93, 0x18, 0x40, 0x5F, 0x93, 0x9A, 0xCA, 0x97, + 0x3F, 0x64, 0x37, 0xC2, 0x98, 0xEE, 0x80, 0xE5, 0x6C, 0x0F, + 0x2B, 0x5C, 0x0E, 0xEE, 0x8F, 0x72, 0xF6, 0xBF, 0x77, 0xFD, + 0x7A, 0x28, 0xF2, 0x57, 0x99, 0x55, 0x03, 0x16, 0x1C, 0x8B, + 0x06, 0x9D, 0xB9, 0xAD, 0x09, 0xE4, 0x19, 0x2E, 0x76, 0x0F, + 0x62, 0x37, 0x18, 0x48, 0xE5, 0x26, 0xE4, 0x29, 0x78, 0x9D, + 0x6D, 0xA5, 0xA8, 0x66, 0x42, 0xD5, 0x5B, 0xE4, 0x8A, 0xA7, + 0x91, 0x77, 0xDB, 0x11, 0x0E, 0xC1, 0x94, 0x70, 0x9E, 0x45, + 0xA1, 0x9D, 0xBF, 0x5E, 0x4C, 0xFB, 0x31, 0x4A, 0xB5, 0x45, + 0xE1, 0x32, 0xF1, 0x54, 0x8A, 0xA5, 0x93, 0xEE, 0x67, 0xAB, + 0x2E, 0xFE, 0xCF, 0xF5, 0x46, 0x5F, 0x3A, 0x6C, 0xA8, 0x2F, + 0xA0, 0xE0, 0x36, 0xA1, 0x7F, 0x87, 0x63, 0x9D, 0xCA, 0x18, + 0xAC, 0xC6, 0xCE, 0xD6, 0xC3, 0xA2, 0xB7, 0xF8, 0x4E, 0xFD, + 0x49, 0x73, 0x8F, 0x3A, 0xA0, 0x9D, 0xC3, 0x01, 0xBC, 0x3E, + 0x7F, 0x01, 0x1D, 0x82, 0x66, 0x7B, 0x1E, 0x38, 0x5A, 0x75, + 0xB4, 0xFF, 0x7E, 0xB0, 0x7D, 0x69, 0xA5, 0xC8, 0x46, 0x33, + 0x34, 0x16, 0x0E, 0x9E, 0x20, 0xA9, 0xDC, 0x4B, 0x3C, 0xCF, + 0xBB, 0xA8, 0xB8, 0x2F, 0xED, 0xEA, 0xCC, 0xC4, 0x5A, 0x72, + 0xB7, 0xB1, 0x0E, 0x98, 0xBC, 0xBD, 0xAF, 0x71, 0x2A, 0x85, + 0xAD, 0x36, 0xAF, 0x0F, 0x09, 0x53, 0xD2, 0x0A, 0x57, 0x98, + 0x55, 0x77, 0x11, 0x17, 0x89, 0x23, 0xE1, 0xC5, 0xEC, 0xC6, + 0x6B, 0x01, 0xDF, 0x5D, 0x4D, 0x55, 0x32, 0x96, 0x3E, 0x5F, + 0x52, 0xF0, 0x4D, 0x7E, 0x9E, 0xFA, 0x1F, 0x27, 0x85, 0x20, + 0xA5, 0xB1, 0x5D, 0x7F, 0xED, 0xCF, 0xFA, 0xFF, 0xFD, 0x45, + 0x03, 0x93, 0x24, 0xA2, 0x9A, 0x87, 0xDB, 0x5A, 0x85, 0x5B, + 0xFD, 0x6C, 0x22, 0x1D, 0x38, 0x74, 0xA5, 0x0B, 0x11, 0xD0, + 0xA8, 0x68, 0xC1, 0x30, 0x5C, 0xF8, 0x4F, 0x3C, 0x2A, 0x31, + 0xB5, 0xC2, 0x4E, 0xBC, 0xC7, 0xCA, 0xA1, 0x65, 0x99, 0x10, + 0x0E, 0xCE, 0xBD, 0x78, 0x98, 0xB1, 0x4D, 0x3B, 0x7D, 0xE8, + 0x16, 0x89, 0x99, 0x69, 0xC2, 0x22, 0xE3, 0x47, 0xB4, 0x31, + 0x65, 0x4C, 0x25, 0x54, 0x96, 0x55, 0xB0, 0xAF, 0xE6, 0x35, + 0xAA, 0x03, 0xB9, 0x1E, 0xA3, 0x75, 0xA9, 0x62, 0x53, 0x10, + 0x13, 0x3D, 0xF7, 0x2A, 0x0E, 0x9A, 0x8C, 0xB9, 0xEE, 0x61, + 0xF2, 0xB1, 0xEA, 0x27, 0xDB, 0x97, 0x4D, 0xE8, 0x64, 0xAC, + 0x8D, 0x5B, 0x83, 0xE7, 0x75, 0x6F, 0xEE, 0x59, 0x45, 0x40, + 0x0B, 0xF8, 0xF5, 0x8A, 0xBE, 0x2B, 0x2E, 0x0B, 0xE8, 0x60, + 0xC2, 0xD3, 0x15, 0x1B, 0x92, 0x10, 0x6E, 0xF6, 0x25, 0x3D, + 0x71, 0x0D, 0xFE, 0xE6, 0xE8, 0x7F, 0x35, 0x92, 0x42, 0x79, + 0x05, 0x2F, 0xDC, 0x6D, 0x57, 0x44, 0x4D, 0xA7, 0x86, 0x35, + 0x3A, 0xFE, 0xFF, 0x78, 0x8F, 0x86, 0xE8, 0xE1, 0xE6, 0x49, + 0xED, 0x04, 0xDA, 0x90, 0xFB, 0x54, 0x11, 0xDC, 0xE5, 0x49, + 0x8D, 0x5F, 0xC1, 0xD6, 0xB1, 0xA6, 0x85, 0x35, 0x61, 0xE5, + 0x6D, 0x97, 0xED, 0xB2, 0x8E, 0x6C, 0xFC, 0x60, 0xE4, 0xE8, + 0x89, 0x24, 0xA3, 0xEF, 0x20, 0xA4, 0x26, 0x61, 0xAE, 0xC3, + 0x33, 0x19, 0x3F, 0x2C, 0x8D, 0xDA, 0x9D, 0x3A, 0x93, 0x68, + 0x78, 0xA2, 0xC0, 0x9E, 0x27, 0xDD, 0xF3, 0x92, 0x11, 0xED, + 0xE5, 0x1B, 0x01, 0x87, 0xBE, 0x49, 0xA0, 0xE5, 0x83, 0xC3, + 0x4A, 0x9C, 0x3A, 0xF3, 0x2E, 0x5F, 0x8E, 0xAB, 0xAE, 0x4C, + 0x21, 0x0C, 0x42, 0x36, 0x6E, 0x8E, 0xA4, 0xB9, 0x94, 0x3B, + 0x79, 0xD5, 0x0E, 0x5D, 0x16, 0x5B, 0xCA, 0xD6, 0x78, 0xE4, + 0x43, 0x4D, 0x8A, 0xDD, 0xF9, 0xAF, 0xB7, 0x86, 0x1C, 0x90, + 0x6B, 0x91, 0xD5, 0x1F, 0x30, 0xAA, 0x3B, 0x65, 0x9B, 0x94, + 0x64, 0xE5, 0xEB, 0xC0, 0x67, 0x33, 0xC6, 0x08, 0x98, 0xF6, + 0xE3, 0x8B, 0x61, 0xD9, 0x67, 0xB6, 0xF9, 0xB9, 0xEC, 0x47, + 0x48, 0x40, 0xF6, 0x69, 0x9F, 0xD3, 0xC6, 0x00, 0x41, 0xFE, + 0x97, 0x29, 0xF4, 0xF8, 0xF7, 0xA2, 0x04, 0xC1, 0xFA, 0xD5, + 0x17, 0xEA, 0xD2, 0x7F, 0x50, 0xE2, 0xB1, 0xB1, 0x18, 0xF7, + 0x77, 0xDD, 0x0D, 0x3A, 0x04, 0xE8, 0x86, 0x38, 0x86, 0x9D, + 0xDB, 0x5F, 0x3A, 0xA6, 0x2D, 0x02, 0xBA, 0xFD, 0x30, 0x60, + 0xB9, 0x79, 0xA2, 0x00, 0xE5, 0x0E, 0xCC, 0x89, 0x0B, 0x43, + 0x81, 0xDF, 0x0A, 0x76, 0x70, 0xD3, 0x96, 0x5D, 0x26, 0xEC, + 0x80, 0x0E, 0x17, 0x90, 0xD4, 0xC8, 0x14, 0x23, 0xB4, 0x62, + 0x7D, 0x4B, 0xFB, 0x37, 0x18, 0x87, 0xBD, 0xC6, 0x3D, 0xE6, + 0x41, 0x25, 0x37, 0x0C, 0x76, 0xED, 0x9F, 0x3F, 0x19, 0xAD, + 0x33, 0xD6, 0x79, 0xA5, 0x59, 0x42, 0x67, 0x80, 0xE3, 0xA1, + 0x00, 0x1B, 0x03, 0xF3, 0x91, 0x97, 0x0F, 0x27, 0xF9, 0x6E, + 0x83, 0x6F, 0x0E, 0xF0, 0xB5, 0xF3, 0xCE, 0x56, 0xC6, 0xF6, + 0x53, 0x89, 0xB8, 0x81, 0x8C, 0xE0, 0x89, 0x28, 0xD0, 0x0F, + 0xC7, 0x7F, 0x78, 0xBB, 0x92, 0xBE, 0x73, 0x6B, 0xDD, 0xA3, + 0x79, 0xFF, 0x9D, 0xE2, 0x5A, 0xAE, 0xDC, 0xA8, 0x41, 0xE4, + 0x39, 0xD0, 0xB1, 0x77, 0x4B, 0x9B, 0xFA, 0x0A, 0x58, 0x94, + 0x5F, 0x27, 0x0F, 0x77, 0xFA, 0x23, 0x2B, 0xA1, 0xA5, 0xC7, + 0x11, 0xBC, 0x03, 0x3A, 0x04, 0x75, 0xAC, 0x2B, 0x2B, 0x54, + 0x06, 0xFC, 0x2D, 0x24, 0xD5, 0xB8, 0xC0, 0x4A, 0x98, 0x66, + 0xFA, 0x4E, 0x02, 0xCA, 0x1B, 0x28, 0xAC, 0xC5, 0xCC, 0x7B, + 0x6E, 0x81, 0xA0, 0x88, 0x55, 0xF8, 0x9A, 0x6F, 0x9A, 0x00, + 0xC7, 0xF5, 0x58, 0x1C, 0x93, 0xCD, 0xE0, 0x9F, 0x55, 0x9E, + 0xAB, 0x57, 0x9C, 0x0D, 0x71, 0xBA, 0xDD, 0x7F, 0xB6, 0x49, + 0xAF, 0x28, 0xD9, 0x29, 0x2B, 0x71, 0xC3, 0x7F, 0x6D, 0x61, + 0xF6, 0x16, 0xB2, 0x33, 0x4C, 0x2F, 0x99, 0x70, 0x23, 0x55, + 0xAF, 0x50, 0x99, 0xFF, 0x40, 0xE3, 0x74, 0x86, 0xA8, 0xF5, + 0xC1, 0x68, 0x7C, 0xA8, 0x2B, 0xA9, 0x7A, 0xF0, 0xE6, 0xDE, + 0x50, 0x18, 0xBC, 0x7C, 0x5A, 0xD5, 0x3D, 0x77, 0xC5, 0x74, + 0x93, 0x6B, 0xA4, 0x0C, 0x81, 0xD4, 0x86, 0x35, 0x95, 0x4E, + 0xE3, 0xB7, 0xDE, 0x90, 0xA2, 0x8D, 0x89, 0x4C, 0x74, 0x88, + 0x40, 0x1C, 0xBA, 0x6A, 0x7C, 0x44, 0x9A, 0x40, 0x76, 0xD2, + 0xD5, 0x6A, 0x65, 0xF2, 0x1F, 0x55, 0xE6, 0xE1, 0xD3, 0x3A, + 0xC9, 0x2B, 0xC9, 0x25, 0x39, 0xAE, 0xE0, 0x0A, 0xE7, 0xBD, + 0xFF, 0x56, 0x19, 0x9E, 0xD6, 0xE2, 0xDE, 0x66, 0x9E, 0x48, + 0x46, 0xC6, 0x6C, 0xF9, 0x95, 0x25, 0x08, 0x85, 0x45, 0x66, + 0xCE, 0x25, 0x8E, 0xBD, 0xB6, 0xF5, 0x7A, 0x72, 0x4D, 0x76, + 0x96, 0xEC, 0x2C, 0x7A, 0xE6, 0xB4, 0x8E, 0xC1, 0x91, 0x5D, + 0x6E, 0xE3, 0x42, 0x06, 0x56, 0xA4, 0x75, 0xDE, 0x12, 0x5E, + 0xE6, 0x3D, 0xB3, 0x8A, 0x06, 0x90, 0x04, 0x92, 0x1B, 0xB2, + 0x12, 0xCF, 0xFF, 0x9A, 0x95, 0xEB, 0x64, 0x72, 0xAE, 0x04, + 0xFD, 0x2F, 0xAF, 0xB1, 0x01, 0x56, 0xC7, 0xC3, 0x19, 0x6A, + 0xF1, 0x6B, 0xC2, 0x5C, 0x44, 0x3E, 0x13, 0x5E, 0x2A, 0xB0, + 0x7D, 0x2E, 0x7D, 0x80, 0xC2, 0xAF, 0x01, 0xCA, 0xBF, 0x47, + 0xC3, 0x7E, 0xAC, 0x8A, 0x5F, 0xE5, 0xED, 0x5B, 0x7A, 0x14, + 0xCD, 0xFA, 0x96, 0x8A, 0xA6, 0x11, 0x4F, 0x1B, 0x1E, 0x2C, + 0x50, 0xBA, 0xD3, 0x4F, 0x1A, 0x83, 0x89, 0xC2, 0xAB, 0x14, + 0x44, 0x02, 0x79, 0x6E, 0x94, 0x6F, 0x47, 0x4C, 0x2F, 0xF3, + 0xDC, 0xB6, 0x8C, 0x26, 0x62, 0x14, 0xCF, 0x80, 0x61, 0xEA, + 0xAF, 0xAA, 0x22, 0x56, 0x17, 0x96, 0x0B, 0x2C, 0x60, 0x9E, + 0xFD, 0x44, 0x0F, 0x66, 0xAA, 0x66, 0x06, 0x1D, 0xFC, 0x7B, + 0xCD, 0x4E, 0x17, 0x51, 0x6D, 0xEA, 0xCA, 0x3D, 0x3F, 0xC5, + 0x4F, 0x0B, 0x54, 0xE3, 0x40, 0x70, 0x31, 0xBB, 0x35, 0xAE, + 0x78, 0x94, 0x76, 0xE2, 0x21, 0x21, 0xC9, 0x73, 0x91, 0x8F, + 0xD7, 0xCD, 0x26, 0x0C, 0x82, 0x68, 0xA6, 0xEE, 0xEC, 0x9A, + 0x87, 0x1E, 0x59, 0xC7, 0x77, 0xA4, 0x04, 0xCA, 0x4B, 0x2E, + 0xE2, 0x97, 0x8F, 0x84, 0xEA, 0xC4, 0x2E, 0x03, 0x63, 0x47, + 0xB0, 0xFC, 0x12, 0xB7, 0xF6, 0xB3, 0x8D, 0xD1, 0xF0, 0xCF, + 0x24, 0x85, 0x21, 0x76, 0x5F, 0x8F, 0xA1, 0x1B, 0xB6, 0x7E, + 0xFA, 0xDD, 0x28, 0x08, 0x02, 0x4E, 0x63, 0xCD, 0x44, 0xB3, + 0xB0, 0xB3, 0x71, 0x8F, 0x8D, 0x92, 0x1A, 0x5C, 0x7A, 0x9A, + 0xBC, 0x02, 0x33, 0x5D, 0x66, 0x38, 0x6C, 0x8C, 0xA1, 0x0A, + 0xE6, 0x97, 0xD9, 0x72, 0x9F, 0xE6, 0x14, 0xE9, 0x6B, 0xCE, + 0x4A, 0x26, 0xC2, 0x2B, 0x6F, 0x32, 0xF7, 0x23, 0x93, 0x31, + 0xDB, 0xF0, 0x65, 0x4F, 0x3F, 0xA8, 0xC0, 0xD3, 0xA7, 0x31, + 0xA8, 0x93, 0x40, 0x45, 0x2F, 0x80, 0xDB, 0x0D, 0x8D, 0x94, + 0x5A, 0x2A, 0x28, 0x40, 0x1F, 0xF7, 0xAE, 0x1C, 0xCE, 0x8F, + 0x0E, 0xE1, 0x7F, 0xD6, 0x47, 0x4F, 0xEA, 0x37, 0xD6, 0xED, + 0x4D, 0x5A, 0x62, 0xC8, 0xBE, 0x4C, 0xF9, 0x53, 0x95, 0x6C, + 0x23, 0xFD, 0xBC, 0x34, 0x50, 0x93, 0x64, 0x5E, 0x9C, 0xA1, + 0x3E, 0x06, 0x6E, 0x4C, 0x67, 0x17, 0x08, 0x89, 0xBA, 0x11, + 0x80, 0xAF, 0xF0, 0x7E, 0x78, 0x94, 0x6B, 0x63, 0x17, 0xAD, + 0x98, 0xF1, 0x01, 0x44, 0x76, 0xC6, 0x24, 0xA5, 0x88, 0x4F, + 0x0D, 0x29, 0x01, 0xB9, 0x35, 0x4C, 0x1C, 0x4E, 0x06, 0x26, + 0xC1, 0x06, 0xA6, 0xED, 0xE9, 0x3C, 0x8A, 0x98, 0xF8, 0xA0, + 0x28, 0xEC, 0xAB, 0xEF, 0x55, 0x82, 0x68, 0xD2, 0x8B, 0x7D, + 0x88, 0xC9, 0xE2, 0x77, 0xD6, 0xD9, 0x20, 0x31, 0x30, 0xFE, + 0x50, 0x03, 0x78, 0x45, 0x3E, 0x2C, 0x8C, 0xDC, 0xF1, 0x02, + 0x67, 0x05, 0xD6, 0xB1, 0x00, 0x2F, 0xF7, 0x40, 0xB4, 0xF9, + 0x58, 0x5D, 0x71, 0xC2, 0x2C, 0x35, 0x9D, 0x49, 0xB4, 0x1E, + 0x5C, 0xDD, 0xA7, 0x6B, 0xCF, 0x65, 0x16, 0x20, 0x91, 0xB8, + 0x55, 0xE5, 0x33, 0xBA, 0xDB, 0xC3, 0xBF, 0xDD, 0xB1, 0x27, + 0x9D, 0x1D, 0xC5, 0x17, 0xF4, 0xC0, 0x69, 0x0E, 0xEB, 0x38, + 0x07, 0xF4, 0xFE, 0x22, 0xEF, 0x51, 0x50, 0xD3, 0xD0, 0xEB, + 0x40, 0x55, 0xCF, 0xA1, 0xD5, 0xE3, 0xDD, 0x95, 0x79, 0x58, + 0x1E, 0xF0, 0xF3, 0x21, 0x8A, 0x6F, 0x18, 0xF5, 0x26, 0x66, + 0x16, 0xB7, 0xE2, 0x8C, 0x5F, 0x91, 0x7E, 0x14, 0x21, 0xB3, + 0x73, 0x9F, 0x41, 0x87, 0xD4, 0x43, 0x19, 0x63, 0x01, 0x16, + 0x8A, 0xE7, 0x0F, 0x6A, 0x31, 0xB7, 0x70, 0x82, 0x84, 0x51, + 0x2F, 0x7F, 0xA7, 0x5D, 0x0D, 0x6A, 0xF8, 0xE4, 0xE9, 0x0B, + 0x9D, 0x98, 0xF7, 0x8C, 0x3F, 0x90, 0xC7, 0x53, 0x46, 0x16, + 0x17, 0x4A, 0x5D, 0x9D, 0xEF, 0x16, 0x8A, 0xB2, 0x9D, 0xF8, + 0xDE, 0x1D, 0x4F, 0xC1, 0x51, 0x47, 0xC2, 0x44, 0xD1, 0x5A, + 0x74, 0x7D, 0x18, 0x96, 0xDD, 0x1E, 0xC1, 0xF9, 0xB3, 0xCF, + 0x9C, 0x7E, 0xC9, 0xBF, 0x4E, 0x92, 0x35, 0x9D, 0x92, 0x1D, + 0x95, 0xC1, 0x9F, 0x76, 0x2E, 0x6E, 0xC1, 0xE1, 0x91, 0xC9, + 0xED, 0x49, 0x53, 0xA6, 0xD6, 0x3E, 0xBC, 0x7E, 0xC3, 0x91, + 0x87, 0xBD, 0x77, 0x83, 0xFB, 0x6C, 0x76, 0x75, 0x59, 0x01, + 0x37, 0x4A, 0x13, 0x3F, 0x64, 0x8B, 0x1A, 0xB3, 0xAD, 0x0B, + 0x72, 0xDD, 0x19, 0x75, 0xCD, 0x98, 0x3C, 0x6A, 0xEB, 0xED, + 0x6C, 0x38, 0x0E, 0x76, 0x98, 0x48, 0x93, 0xD4, 0x68, 0x2A, + 0x14, 0x4A, 0x46, 0x9E, 0xBE, 0x35, 0xB5, 0xB8, 0xA1, 0xB1, + 0xDC, 0xEE, 0xDA, 0x67, 0xE4, 0xCF, 0xD5, 0xB3, 0x1F, 0xC6, + 0xC3, 0xE0, 0x6E, 0x6E, 0x1F, 0xDE, 0x43, 0xBD, 0xBA, 0x75, + 0x84, 0xAC, 0x24, 0xCB, 0xCA, 0x31, 0xBB, 0x1E, 0x1B, 0xE3, + 0xA6, 0xDE, 0x49, 0xB6, 0xF4, 0x90, 0xF2, 0xE0, 0xD4, 0x8C, + 0x48, 0xD2, 0x7D, 0x71, 0xC5, 0x8F, 0x8A, 0x08, 0xED, 0x8D, + 0x22, 0x8E, 0x7D, 0xAF, 0x24, 0x6D, 0xF5, 0x0F, 0x88, 0x4D, + 0x7A, 0xFD, 0xCD, 0x3A, 0x11, 0xBE, 0x6D, 0x76, 0xD2, 0x0F, + 0x71, 0xCD, 0x25, 0x4E, 0x1B, 0xD2, 0x2A, 0xA4, 0x06, 0xD4, + 0x84, 0x76, 0x5F, 0xD8, 0xA3, 0x3A, 0x5F, 0x24, 0x18, 0xDE, + 0xBA, 0x23, 0x21, 0xB5, 0x9A, 0x66, 0x07, 0x48, 0x5E, 0xFE, + 0x2D, 0x60, 0xC0, 0xFA, 0x02, 0x53, 0x31, 0xE6, 0x53, 0x76, + 0x97, 0x31, 0x9C, 0xB3, 0x0C, 0x3E, 0xAB, 0xA4, 0x4A, 0xFA, + 0x11, 0x2B, 0x16, 0xF8, 0xED, 0x50, 0xD6, 0xBC, 0xCA, 0x04, + 0x62, 0xCD, 0x3E, 0x83, 0x8E, 0x23, 0x79, 0xB9, 0x7B, 0x37, + 0x59, 0xA8, 0x6B, 0x72, 0x97, 0x79, 0x70, 0x24, 0x7F, 0x65, + 0x92, 0xC6, 0xF1, 0xDF, 0x55, 0x1B, 0xFD, 0xBA, 0x65, 0x4A, + 0xAC, 0x16, 0x96, 0xD7, 0x9A, 0x2E, 0x51, 0xAD, 0x1C, 0x15, + 0x5E, 0xC3, 0x06, 0xB0, 0x4D, 0xD8, 0x54, 0xBD, 0xCD, 0xD2, + 0xDF, 0xCA, 0xB4, 0x61, 0xC6, 0x25, 0x6F, 0xC9, 0x2A, 0xD2, + 0x93, 0xCA, 0x86, 0xFE, 0x04, 0xD2, 0x7C, 0xB6, 0xE0, 0xBA, + 0x57, 0xD3, 0xDE, 0xA0, 0x5E, 0x63, 0xFD, 0x0C, 0xEC, 0xD3, + 0xBD, 0x20, 0x92, 0x3A, 0xD0, 0x42, 0x51, 0xED, 0xC2, 0xAB, + 0x67, 0x29, 0xA7, 0xD6, 0x1F, 0x3F, 0xDA, 0xC9, 0x3D, 0x25, + 0x82, 0x95, 0x74, 0x8A, 0xF3, 0x23, 0x81, 0x71, 0x10, 0x4C, + 0x49, 0x94, 0x1A, 0x35, 0x93, 0x6F, 0x0F, 0xDE, 0x3F, 0xD1, + 0x20, 0xD1, 0xAB, 0x96, 0xAF, 0x66, 0xEA, 0x96, 0xA8, 0xB8, + 0xD2, 0x30, 0x51, 0x6E, 0x7A, 0x1A, 0x9C, 0xF0, 0xBA, 0xB4, + 0x29, 0x37, 0x50, 0x04, 0x91, 0x1D, 0x8C, 0x33, 0x48, 0xED, + 0xEA, 0x17, 0xB7, 0x46, 0x2A, 0xBC, 0xAB, 0x02, 0xA3, 0xF8, + 0xBF, 0x13, 0xAC, 0x89, 0x85, 0x6D, 0x82, 0x78, 0x74, 0x9A, + 0x62, 0x8D, 0x6D, 0x62, 0xCC, 0x02, 0x50, 0x1B, 0x39, 0x2C, + 0x75, 0xEF, 0x16, 0x4E, 0x74, 0x5D, 0x29, 0xA1, 0xB3, 0x19, + 0x09, 0xE2, 0x6B, 0x22, 0x3B, 0x72, 0xB6, 0xB6, 0x33, 0x9C, + 0x00, 0x6E, 0x7B, 0xC9, 0x00, 0xC1, 0xDE, 0x50, 0xB0, 0xD2, + 0x05, 0xAD, 0xB3, 0x1D, 0x81, 0xE6, 0x5C, 0xE5, 0xE7, 0xDA, + 0xDF, 0x91, 0x63, 0x31, 0x65, 0x5F, 0x26, 0x92, 0x1F, 0x30, + 0x65, 0xF2, 0xA9, 0x4D, 0x1E, 0xE0, 0x6E, 0x3C, 0x7F, 0xBA, + 0x3D, 0xA1, 0xD6, 0x23, 0xAE, 0x38, 0x3B, 0x5B, 0x6F, 0xEE, + 0x5A, 0x31, 0x33, 0x77, 0xE4, 0x72, 0x26, 0xD8, 0x60, 0x6F, + 0xF8, 0x21, 0x8C, 0x35, 0x91, 0x6E, 0x1A, 0xA6, 0x41, 0x6B, + 0x84, 0x87, 0x7E, 0x5F, 0xBA, 0x30, 0x81, 0x09, 0x16, 0x44, + 0x33, 0x0D, 0xAF, 0x0E, 0x6B, 0xCE, 0xB2, 0x7A, 0x76, 0x5E, + 0x4C, 0xBE, 0x30, 0x32, 0x54, 0x20, 0x11, 0xB9, 0xD8, 0xB2, + 0xEE, 0x46, 0xA4, 0x42, 0x55, 0x81, 0x34, 0x41, 0x0A, 0x79, + 0x03, 0x30, 0x23, 0x80, 0x08, 0x55, 0xF9, 0xDD, 0x18, 0xF4, + 0x15, 0x3B, 0x46, 0x67, 0xEC, 0xF2, 0x86, 0x95, 0x41, 0xF4, + 0xD4, 0x73, 0xC9, 0x1E, 0x4D, 0x06, 0x7F, 0xD0, 0xBA, 0x83, + 0x2A, 0xF1, 0x40, 0xC8, 0x13, 0x64, 0x4D, 0xC2, 0x83, 0x48, + 0xE6, 0x7F, 0xA1, 0xC9, 0xC3, 0xE0, 0xC2, 0x11, 0xCE, 0xE4, + 0xCB, 0x07, 0x03, 0x6F, 0xDB, 0xB5, 0x8C, 0xEB, 0xF5, 0x99, + 0x9F, 0x6B, 0xE2, 0x94, 0x27, 0x67, 0xA9, 0x9E, 0x48, 0x6B, + 0x0D, 0xE3, 0x77, 0xC5, 0xF9, 0x48, 0xC0, 0x84, 0x14, 0x84, + 0x5D, 0x9C, 0xE6, 0x4F, 0x15, 0x67, 0x6E, 0x34, 0x81, 0x5E, + 0x3D, 0x0A, 0xB7, 0x5C, 0xE2, 0xD1, 0x2C, 0x80, 0x20, 0x69, + 0x8B, 0xB7, 0x7E, 0xB8, 0xEB, 0x6D, 0x7C, 0x3D, 0x73, 0x54, + 0x72, 0x57, 0xD5, 0x9E, 0xE8, 0xD8, 0x32, 0xE9, 0x45, 0x2B, + 0x29, 0x8E, 0x1B, 0xC4, 0x76, 0x93, 0x98, 0xFE, 0xD3, 0x25, + 0xF7, 0x66, 0x64, 0xB1, 0x83, 0x22, 0x6A, 0x83, 0xFB, 0x5E, + 0x4E, 0xB3, 0x56, 0x43, 0x4C, 0xB0, 0x35, 0x8C, 0x08, 0x2A, + 0x66, 0xBB, 0xAC, 0xAB, 0x79, 0x73, 0x47, 0x5D, 0x0F, 0xC2, + 0xBB, 0x4B, 0xA0, 0xC9, 0x80, 0xEC, 0xE8, 0x05, 0x22, 0xEF, + 0x40, 0x0E, 0xFA, 0xD2, 0x54, 0x04, 0x93, 0xFA, 0xFC, 0x33, + 0xEB, 0x25, 0xDB, 0x0A, 0xE5, 0xEF, 0x1A, 0xC2, 0x31, 0x97, + 0x00, 0xD7, 0xB6, 0xB9, 0x09, 0x85, 0x63, 0xB0, 0x0E, 0x7A, + 0x3E, 0x8F, 0x03, 0x2B, 0x7B, 0xCB, 0x26, 0x55, 0xFC, 0x9F, + 0xC4, 0x08, 0xB3, 0xBB, 0x92, 0xED, 0x01, 0x69, 0x29, 0x9B, + 0x0E, 0x52, 0x23, 0x02, 0xCC, 0x28, 0x60, 0xD3, 0x92, 0x90, + 0x9C, 0x25, 0x02, 0x8F, 0x61, 0x3A, 0xDB, 0x72, 0x7C, 0x3A, + 0x9D, 0x93, 0x9F, 0x37, 0xCA, 0xC4, 0xF7, 0x0E, 0x44, 0x68, + 0xA4, 0x89, 0x5A, 0x1B, 0xC4, 0x66, 0x3A, 0xEC, 0x16, 0x4F, + 0x88, 0x6B, 0x31, 0xE5, 0x93, 0x47, 0x2A, 0x3C, 0x22, 0xA4, + 0xCB, 0x4D, 0x48, 0xEE, 0x1B, 0x18, 0xA3, 0x17, 0x2A, 0x0C, + 0xE9, 0x08, 0x90, 0xAF, 0x0D, 0x8D, 0xFE, 0xD6, 0x53, 0x9A, + 0x0B, 0x85, 0x48, 0x9E, 0xFD, 0x0E, 0x89, 0x2B, 0x57, 0x83, + 0x1D, 0xC0, 0xD4, 0x44, 0xD5, 0x12, 0x50, 0x17, 0xD6, 0xD7, + 0x50, 0xAB, 0xD7, 0xDB, 0x60, 0x10, 0xAB, 0x47, 0x3B, 0xA6, + 0x0D, 0x37, 0x10, 0xA0, 0xE1, 0xCD, 0xD9, 0xC7, 0xEF, 0x26, + 0x24, 0x9E, 0xD4, 0xDA, 0x38, 0x88, 0xF4, 0xB0, 0xEF, 0x6B, + 0x20, 0xBF, 0xB3, 0xD5, 0xDA, 0x15, 0xE9, 0xFA, 0xC2, 0x14, + 0xB6, 0x5B, 0x0E, 0xE8, 0xE9, 0x9A, 0x8B, 0xE5, 0x8A, 0xBE, + 0x0D, 0x97, 0x3A, 0x15, 0xBB, 0x29, 0xE4, 0x26, 0x6C, 0x05, + 0x76, 0xB5, 0x3B, 0xA8, 0xD2, 0xA7, 0x42, 0x43, 0x0D, 0x7D, + 0x1C, 0xB4, 0xC3, 0x2F, 0x5B, 0xDA, 0x10, 0x33, 0x0E, 0x7D, + 0x5F, 0x00, 0x80, 0xB6, 0x08, 0xB1, 0xA8, 0x54, 0x14, 0xB0, + 0x49, 0xAC, 0x12, 0x7D, 0x88, 0xAF, 0xF0, 0x1B, 0xD6, 0xE3, + 0x19, 0x85, 0x1F, 0x80, 0xED, 0x83, 0x80, 0xB4, 0x35, 0xDE, + 0x56, 0x85, 0xC7, 0xF8, 0xA9, 0x93, 0xB0, 0xAB, 0xC6, 0x28, + 0x60, 0x9A, 0x16, 0xE5, 0x6B, 0xFF, 0x4A, 0x13, 0x4C, 0xCC, + 0x40, 0xFA, 0x5E, 0x2E, 0x65, 0x71, 0x4F, 0xC6, 0x39, 0x8E, + 0xA2, 0xFD, 0xA0, 0xED, 0x82, 0x58, 0xCA, 0x9B, 0xDC, 0xD5, + 0xB7, 0xC0, 0x12, 0x09, 0x0A, 0x26, 0xED, 0x94, 0x8C, 0x15, + 0x61, 0xEF, 0x7A, 0x12, 0x2F, 0xB8, 0xA9, 0x25, 0xD6, 0xF3, + 0xD3, 0xCE, 0x44, 0xD2, 0x5D, 0x95, 0x04, 0xDB, 0x43, 0x57, + 0x7B, 0x72, 0xD4, 0xEA, 0x80, 0x9E, 0xAA, 0x94, 0x6E, 0x07, + 0xB1, 0xA4, 0xD4, 0xED, 0x8A, 0x80, 0xE0, 0x2F, 0x67, 0xB7, + 0x08, 0x04, 0xCC, 0x0B, 0x0F, 0xFE, 0x96, 0x41, 0xC8, 0xA6, + 0xFE, 0x04, 0x7C, 0x07, 0x73, 0xCE, 0x7D, 0x92, 0xC5, 0x7A, + 0xC2, 0x03, 0x71, 0x0C, 0xBD, 0xE4, 0x24, 0x79, 0x28, 0xBC, + 0xCB, 0xF0, 0x33, 0xD7, 0xB2, 0x24, 0x88, 0x00, 0x94, 0xAF, + 0x72, 0x0F, 0x23, 0xFD, 0x08, 0xC1, 0xBE, 0x38, 0x92, 0x5F, + 0x0B, 0x78, 0x3F, 0x9B, 0xC2, 0x7C, 0x97, 0xDB, 0xD8, 0x85, + 0x75, 0xA5, 0x86, 0x3A, 0xA6, 0x6A, 0xFA, 0x72, 0x2D, 0xFF, + 0x2F, 0xA2, 0x61, 0xEA, 0x45, 0xDE, 0xD8, 0x63, 0x8C, 0x01, + 0x80, 0x5E, 0x07, 0x44, 0x8C, 0x77, 0x26, 0xFC, 0x43, 0x12, + 0x40, 0x81, 0x80, 0xE2, 0x60, 0xC3, 0x91, 0xE2, 0x21, 0x39, + 0x5D, 0x18, 0xFD, 0x3A, 0x86, 0x87, 0x21, 0xCF, 0x3C, 0x21, + 0x02, 0x0B, 0xCF, 0xDC, 0x93, 0x2D, 0x3F, 0x87, 0x14, 0xEE, + 0x8F, 0x08, 0x33, 0x40, 0xF6, 0x4E, 0xB6, 0x8F, 0xFD, 0xE5, + 0xD0, 0x16, 0x8D, 0xC6, 0xB4, 0x6B, 0xA3, 0x7F, 0xE1, 0x9F, + 0xFC, 0x2B, 0x0B, 0x6B, 0xB2, 0xCC, 0x31, 0x5F, 0xB8, 0x2C, + 0xD2, 0x0B, 0x99, 0x47, 0xDB, 0x68, 0x0A, 0x21, 0x55, 0xCF, + 0xA3, 0x72, 0xD4, 0x65, 0x35, 0xBA, 0xBA, 0x36, 0x2D, 0xEF, + 0x55, 0xA6, 0xB5, 0x73, 0x48, 0xF9, 0xE4, 0xA5, 0xE9, 0x50, + 0x63, 0xEE, 0x5C, 0xEA, 0x41, 0x2B, 0xC2, 0x7B, 0x4A, 0x98, + 0x66, 0x9F, 0x31, 0x9E, 0x5F, 0x70, 0x7F, 0x97, 0xD9, 0xC8, + 0xEB, 0xC6, 0x2F, 0x2F, 0x6F, 0x64, 0x47, 0x39, 0xDD, 0x6E, + 0x0C, 0xB9, 0x19, 0xC6, 0xF1, 0xB5, 0xD6, 0xBC, 0xBF, 0x2B, + 0x27, 0x6A, 0x02, 0x10, 0x04, 0xA2, 0xBE, 0x93, 0x56, 0x2A, + 0x17, 0x24, 0x49, 0x21, 0xFC, 0x3D, 0xCA, 0xC8, 0x2E, 0x6B, + 0x15, 0x63, 0x1E, 0xA9, 0xDA, 0x7D, 0x85, 0xD1, 0x46, 0x3E, + 0x40, 0xE4, 0x93, 0x47, 0x64, 0xB0, 0xA8, 0xDE, 0x7C, 0x42, + 0x29, 0xA0, 0xEB, 0xD6, 0x04, 0x8A, 0x58, 0xFE, 0xF1, 0x1B, + 0x6F, 0x69, 0x6C, 0x64, 0x12, 0x00, 0x6D, 0xAC, 0xD4, 0xB5, + 0xBA, 0xE3, 0x3B, 0x60, 0x21, 0xC7, 0x4F, 0x9E, 0xEB, 0xE6, + 0x94, 0x98, 0xF8, 0x75, 0x2B, 0xE7, 0xC3, 0x9F, 0x43, 0x80, + 0xD1, 0x3B, 0x3A, 0x18, 0xBC, 0xDE, 0xEC, 0xAB, 0x36, 0xC2, + 0xFA, 0x14, 0xC8, 0x31, 0x61, 0xB2, 0x88, 0x9E, 0xF9, 0xDF, + 0xDD, 0x57, 0x6D, 0x6A, 0x10, 0x63, 0x07, 0xD0, 0x2A, 0xCF, + 0x05, 0xF2, 0x00, 0x8E, 0xF4, 0x12, 0x2C, 0x56, 0x9D, 0xB9, + 0x50, 0xDC, 0xA5, 0x03, 0x06, 0x78, 0xD8, 0x93, 0xFC, 0xE4, + 0x2A, 0xB4, 0x0B, 0x43, 0x1B, 0xF1, 0xE3, 0x4C, 0xF6, 0xCC, + 0x01, 0xBC, 0x97, 0xBD, 0xA5, 0xC7, 0x3B, 0x91, 0x66, 0x61, + 0x59, 0xCF, 0x24, 0xB1, 0xB7, 0xBA, 0x0F, 0x5F, 0xF5, 0x77, + 0x3F, 0x60, 0xFB, 0x5C, 0x70, 0x04, 0x80, 0x51, 0x86, 0x5B, + 0xAF, 0xD0, 0xCE, 0x74, 0x94, 0x5E, 0x0D, 0x5B, 0x78, 0x51, + 0x35, 0x43, 0x37, 0x57, 0xA5, 0x49, 0x53, 0x93, 0xD0, 0xFC, + 0x00, 0x95, 0x90, 0x3A, 0x5E, 0x5B, 0x92, 0xDF, 0xE2, 0xF2, + 0x87, 0xDB, 0x34, 0x23, 0xD9, 0x26, 0xA1, 0xFC, 0x02, 0x13, + 0x40, 0x9A, 0x5F, 0x3E, 0xEE, 0xA5, 0x9D, 0xA3, 0xF7, 0x07, + 0x40, 0xCA, 0xA4, 0x23, 0xD4, 0x1D, 0xD7, 0xFD, 0x6A, 0x6E, + 0x34, 0x10, 0xFA, 0xAC, 0x68, 0xED, 0xF0, 0x3E, 0x8D, 0x77, + 0x0B, 0xFD, 0xAF, 0x7C, 0xC6, 0xE0, 0xF4, 0x38, 0xBE, 0x74, + 0x63, 0xAF, 0x46, 0x52, 0x44, 0x9D, 0x3C, 0x42, 0x6A, 0xB6, + 0xEE, 0xB8, 0xB1, 0xA2, 0xDA, 0x6D, 0x60, 0x04, 0x7D, 0xB8, + 0x09, 0xF3, 0x1F, 0xB8, 0xFC, 0xF0, 0xF8, 0x74, 0x82, 0x1F, + 0xDD, 0x45, 0x52, 0x1F, 0x01, 0x7C, 0x69, 0x75, 0xBE, 0xAD, + 0x31, 0x7B, 0xCC, 0x9C, 0x71, 0xDE, 0xD9, 0xD8, 0x54, 0x66, + 0x8C, 0x7D, 0xF0, 0x57, 0xB9, 0x37, 0x36, 0xE0, 0xD8, 0x49, + 0x4C, 0x15, 0x0A, 0x06, 0x63, 0x17, 0x48, 0x58, 0xFB, 0xAF, + 0x4A, 0x70, 0x22, 0xAA, 0xBF, 0xFA, 0x4E, 0x5D, 0x3F, 0xDC, + 0x4B, 0xE6, 0x9F, 0xB1, 0x69, 0xF9, 0x8E, 0x21, 0x06, 0x5B, + 0x06, 0x6A, 0x5C, 0x21, 0xEC, 0xD1, 0x59, 0x13, 0xE5, 0x7C, + 0x4B, 0xC8, 0xB8, 0xB9, 0x71, 0x15, 0xCD, 0xA4, 0xAF, 0x11, + 0x91, 0x05, 0xF6, 0xFE, 0x84, 0x51, 0xCD, 0x7D, 0x23, 0x83, + 0x8A, 0x70, 0xF2, 0xD3, 0xCA, 0x7B, 0x89, 0x79, 0x55, 0x59, + 0x6E, 0x95, 0xB7, 0xAF, 0xE1, 0xD5, 0x32, 0xDB, 0x4C, 0x67, + 0x77, 0xE2, 0x65, 0x07, 0x04, 0xB3, 0xF2, 0x86, 0x5C, 0x80, + 0x49, 0x80, 0x53, 0x6A, 0x43, 0xAE, 0xA5, 0x48, 0x44, 0x6B, + 0xD7, 0x4D, 0xE2, 0xC3, 0x3B, 0x04, 0x22, 0x4C, 0x7C, 0x01, + 0xDB, 0xC4, 0x28, 0xE0, 0x53, 0xEF, 0x30, 0x81, 0x3E, 0x7F, + 0x7D, 0x09, 0xC3, 0xB4, 0x86, 0x3E, 0xE7, 0x26, 0xF0, 0x5B, + 0x9F, 0xA8, 0xE2, 0x96, 0xCE, 0x45, 0xB5, 0x73, 0xBB, 0x29, + 0x61, 0x26, 0x2C, 0xB3, 0xC0, 0x76, 0x9D, 0x84, 0x83, 0x46, + 0x4B, 0xE7, 0x83, 0x22, 0xAC, 0x22, 0x72, 0x41, 0xAB, 0xC3, + 0xA9, 0x89, 0x2A, 0xC8, 0x35, 0xF3, 0xF5, 0xDC, 0x64, 0x89, + 0xDE, 0x8E, 0xEC, 0xE8, 0x0F, 0xEC, 0x7C, 0xB2, 0x2C, 0x82, + 0xCE, 0xE0, 0xA3, 0xE6, 0xBF, 0x0B, 0xF8, 0x06, 0x45, 0x59, + 0x56, 0xFA, 0x16, 0xFE, 0x40, 0x90, 0x21, 0x7B, 0x64, 0x18, + 0x1F, 0x61, 0x01, 0x93, 0xE3, 0xB5, 0x43, 0x2D, 0xEB, 0xE9, + 0xB6, 0xB3, 0x30, 0x79, 0x3D, 0x9E, 0x4F, 0x99, 0x30, 0x02, + 0xDC, 0xD0, 0xB9, 0x01, 0x5B, 0xED, 0x4F, 0xC9, 0xBE, 0x6F, + 0xAA, 0xBA, 0xA9, 0x49, 0xCC, 0x4C, 0x22, 0xF1, 0xB3, 0x7C, + 0x6E, 0xE5, 0xB8, 0xA2, 0x81, 0x1A, 0x7D, 0x8F, 0xBF, 0xC1, + 0xDC, 0xEA, 0x08, 0x28, 0x3B, 0xD4, 0xE5, 0x96, 0x6B, 0xF6, + 0xEA, 0xCE, 0xB7, 0xFB, 0xFC, 0x31, 0xC4, 0x44, 0x35, 0x29, + 0x3C, 0xDD, 0x51, 0xB7, 0x48, 0xEA, 0x69, 0xF8, 0x7C, 0xE9, + 0xE7, 0x6C, 0xCD, 0x2E, 0x6D, 0xAC, 0xE3, 0xB2, 0x5F, 0x82, + 0x52, 0xC6, 0x9A, 0xCD, 0xE3, 0xD3, 0x0D, 0x7A, 0xD3, 0xEF, + 0xF8, 0x2F, 0x96, 0xF7, 0x59, 0xA2, 0x42, 0x10, 0xE8, 0x6B, + 0x31, 0xA9, 0xDD, 0x6D, 0x6C, 0x67, 0x25, 0xBB, 0x58, 0x9F, + 0xB8, 0x78, 0xE6, 0xA2, 0x3A, 0xC8, 0x98, 0x9D, 0x45, 0xCA, + 0xBA, 0xD8, 0x10, 0x79, 0x78, 0xF9, 0x98, 0x39, 0x9A, 0xC3, + 0x4D, 0x95, 0x85, 0x55, 0xFA, 0xF1, 0xF6, 0x42, 0x0A, 0xBD, + 0x45, 0xBC, 0x47, 0xD6, 0x6B, 0x28, 0x6E, 0x50, 0x64, 0x20, + 0x4C, 0x25, 0x3C, 0xCE, 0xE9, 0xAE, 0x34, 0x73, 0xE6, 0xBA, + 0x92, 0x71, 0xB2, 0x6D, 0x50, 0xA2, 0x0C, 0x82, 0xE8, 0xF0, + 0xDC, 0x0A, 0xFE, 0xA6, 0x15, 0x4D, 0x50, 0x2E, 0x9F, 0x52, + 0x4E, 0x91, 0x8E, 0x0D, 0x1B, 0x96, 0xE9, 0x3D, 0x98, 0xC6, + 0x1F, 0x67, 0x61, 0x21, 0x3E, 0x80, 0x9C, 0x26, 0xB1, 0xA3, + 0x43, 0x4F, 0x87, 0xAE, 0xF4, 0x7F, 0x6D, 0x91, 0x53, 0xEC, + 0xEE, 0x08, 0xC4, 0xBF, 0xCD, 0x01, 0x90, 0xAC, 0xAB, 0x7F, + 0xA6, 0xDE, 0x46, 0x47, 0xCA, 0xBA, 0xE8, 0x87, 0xB7, 0xBF, + 0x14, 0xDE, 0x1B, 0xD5, 0xD6, 0x70, 0x73, 0x3F, 0xEB, 0xEA, + 0xB3, 0x6C, 0xDF, 0x1C, 0x67, 0x08, 0x81, 0x45, 0x18, 0x45, + 0xCE, 0xD6, 0x9C, 0x52, 0xDD, 0xF6, 0xBF, 0x60, 0xF2, 0x10, + 0x5D, 0x3C, 0x7B, 0x0E, 0xC7, 0x7B, 0xD2, 0x22, 0x42, 0x95, + 0xED, 0x04, 0xE7, 0xF3, 0x15, 0x06, 0x89, 0xC5, 0xC7, 0x3B, + 0x0C, 0x5B, 0xB8, 0x66, 0x35, 0x62, 0x1F, 0x83, 0xAC, 0x4F, + 0xB3, 0x12, 0x85, 0x18, 0xBD, 0x7B, 0xA2, 0xBC, 0x0E, 0x40, + 0xE3, 0xC8, 0x4B, 0xA8, 0xB6, 0xB0, 0xF2, 0xA1, 0xD0, 0x9C, + 0x4C, 0x2E, 0x6B, 0x6D, 0x4B, 0x3A, 0x90, 0x3F, 0xF4, 0x89, + 0x81, 0x49, 0x9D, 0x68, 0x9F, 0x3B, 0xC1, 0xFB, 0xE9, 0xC9, + 0xEB, 0xCD, 0xFF, 0xB7, 0xBA, 0x19, 0x4D, 0xBE, 0xDF, 0xD8, + 0x53, 0x27, 0xF9, 0x88, 0xCB, 0xA1, 0xEB, 0x9C, 0xD4, 0x84, + 0x08, 0x6E, 0xC2, 0xF4, 0x3F, 0x12, 0x19, 0x45, 0x86, 0x9F, + 0xD4, 0x63, 0x9B, 0x4D, 0x7C, 0xBE, 0x9A, 0x52, 0x45, 0x78, + 0xDA, 0x9A, 0x09, 0x2D, 0xC7, 0x33, 0x76, 0x9B, 0x7C, 0x90, + 0x93, 0xC0, 0x2B, 0x81, 0x70, 0xF1, 0x15, 0xB7, 0x3F, 0x9C, + 0x4A, 0xF0, 0x76, 0x80, 0x09, 0xA4, 0x11, 0x04, 0xE8, 0xD3, + 0xAD, 0x57, 0x88, 0x48, 0x5F, 0x60, 0x8D, 0x20, 0xB0, 0xE9, + 0xFC, 0xDC, 0xF9, 0xCB, 0x75, 0x01, 0x66, 0xF6, 0xC2, 0x38, + 0xFD, 0x8B, 0x94, 0xA1, 0x5C, 0x8B, 0x33, 0xE9, 0x27, 0xE6, + 0x96, 0xF5, 0x12, 0x88, 0x46, 0x12, 0x5D, 0x1F, 0xA8, 0xC5, + 0x7C, 0xE4, 0x74, 0x79, 0xEE, 0x2B, 0x60, 0xCB, 0xD0, 0x07, + 0x42, 0x20, 0x38, 0xA1, 0xCA, 0xC7, 0xBF, 0x02, 0xC3, 0x59, + 0x6D, 0xFC, 0xBE, 0x52, 0xAF, 0x19, 0x8D, 0xA0, 0x5E, 0xF8, + 0xE9, 0xE2, 0x1C, 0x51, 0x4F, 0xDA, 0x41, 0xBA, 0xCD, 0xFB, + 0x49, 0x91, 0xA9, 0xFA, 0x0C, 0xA1, 0x51, 0x9F, 0xAA, 0x17, + 0x29, 0x3B, 0x91, 0x84, 0x7C, 0xD8, 0xD4, 0x9D, 0xB8, 0x39, + 0xB4, 0x92, 0xD4, 0xEF, 0x10, 0x0D, 0x25, 0x72, 0x2A, 0x30, + 0xBD, 0xC2, 0x37, 0x5B, 0xE1, 0x04, 0xFA, 0xC2, 0xC4, 0x7D, + 0x8D, 0x4A, 0x46, 0xCC, 0xC3, 0xBE, 0xB2, 0xFA, 0x85, 0x65, + 0x19, 0x3D, 0xEB, 0x74, 0x03, 0xAC, 0x78, 0xEC, 0x53, 0xA8, + 0xE9, 0xF3, 0x4B, 0xA7, 0xDA, 0x2A, 0x1F, 0x1A, 0x06, 0x78, + 0x4D, 0xF5, 0x2E, 0x98, 0x0E, 0x73, 0x66, 0x44, 0x51, 0xC0, + 0x8C, 0x61, 0xC0, 0x23, 0x37, 0xCB, 0x8F, 0x61, 0xDD, 0xDF, + 0x95, 0xC9, 0x7B, 0x06, 0x9F, 0x8A, 0x53, 0x7E, 0xC1, 0xAE, + 0x47, 0xD3, 0x0C, 0x49, 0xF4, 0x35, 0xD9, 0xF4, 0x31, 0xA8, + 0x8A, 0x70, 0x1D, 0x47, 0x1E, 0xD0, 0x9F, 0xCC, 0xB7, 0x4F, + 0x07, 0x56, 0x2A, 0x0E, 0x9C, 0x67, 0xD2, 0xA4, 0xE9, 0x08, + 0x36, 0x42, 0x3A, 0xB7, 0x97, 0x40, 0x33, 0xB2, 0x5C, 0x9E, + 0x42, 0x77, 0x02, 0x76, 0x35, 0xC8, 0x9C, 0x61, 0x74, 0x7B, + 0x44, 0x27, 0x53, 0x86, 0x6A, 0x4D, 0x9D, 0x08, 0x4D, 0x81, + 0x18, 0xA5, 0x4A, 0x6A, 0x36, 0x9E, 0x4F, 0x7C, 0x3C, 0x7D, + 0x96, 0x1A, 0xD6, 0x63, 0x21, 0x7D, 0xA1, 0xC5, 0xD2, 0xEA, + 0xB8, 0x2C, 0xA1, 0x27, 0x81, 0x72, 0xB6, 0x57, 0x8F, 0x74, + 0xDE, 0xC0, 0xEB, 0x47, 0xAE, 0x29, 0xBA, 0xC9, 0x91, 0x65, + 0xF8, 0x18, 0xA5, 0x23, 0xE2, 0x47, 0x39, 0xEC, 0x06, 0x04, + 0x35, 0x41, 0xB0, 0xC9, 0x0E, 0xC4, 0xE6, 0x04, 0x5E, 0x55, + 0x7C, 0x39, 0xE7, 0x93, 0xD9, 0xA2, 0x44, 0x0F, 0xD5, 0xD4, + 0x73, 0x3A, 0xC5, 0xEC, 0xC1, 0xD5, 0x40, 0x40, 0xB3, 0xBE, + 0x2E, 0xAB, 0x0A, 0x85, 0x22, 0xC0, 0x0C, 0xA9, 0x02, 0x03, + 0xF5, 0x37, 0xAD, 0x0B, 0x33, 0xCD, 0xB5, 0x8F, 0x60, 0xA2, + 0x3B, 0xF4, 0x4F, 0x57, 0x4A, 0x58, 0x35, 0x6F, 0xA2, 0x20, + 0x55, 0x7F, 0xE7, 0xBE, 0x98, 0xC4, 0x23, 0xF2, 0x84, 0xC9, + 0x14, 0xF9, 0xEA, 0x79, 0xB7, 0x80, 0xE7, 0x3F, 0xD7, 0xD3, + 0x7E, 0xE7, 0xC9, 0xDA, 0x04, 0xF3, 0x82, 0xF7, 0xFC, 0x43, + 0x6B, 0xF0, 0xE5, 0xBA, 0x5B, 0xF1, 0x31, 0xA2, 0x13, 0xA3, + 0x52, 0x8F, 0x73, 0x08, 0xB2, 0x3F, 0x59, 0x1C, 0x5D, 0x49, + 0x7B, 0xD3, 0x52, 0x43, 0xA4, 0x0C, 0x88, 0xF4, 0x42, 0x78, + 0xB2, 0x72, 0x6B, 0xE1, 0x33, 0xC2, 0x03, 0xB7, 0x0D, 0xD3, + 0x1D, 0xDE, 0x74, 0x45, 0x05, 0x9C, 0x2E, 0x45, 0x34, 0xE0, + 0x99, 0x74, 0xEC, 0xF7, 0x23, 0xA3, 0x7E, 0xE3, 0x5B, 0x9A, + 0xCF, 0xD5, 0xA9, 0x68, 0x51, 0xDA, 0x2A, 0x6A, 0xC2, 0xED, + 0xD6, 0x54, 0xFA, 0x85, 0xDC, 0xE3, 0x8B, 0xE4, 0x20, 0xB5, + 0x6E, 0xB9, 0x71, 0x1F, 0xF0, 0x10, 0xF1, 0xE4, 0x0B, 0x76, + 0xF5, 0x3E, 0x3E, 0x13, 0xDF, 0x6C, 0x8B, 0xC3, 0x90, 0x50, + 0x15, 0xCF, 0x00, 0xB5, 0x51, 0xCF, 0x2B, 0x2E, 0x23, 0xA3, + 0xF6, 0x1F, 0x12, 0x2F, 0xDF, 0xB4, 0x5E, 0x0A, 0xEF, 0x05, + 0x24, 0x3D, 0xB3, 0xA7, 0xE2, 0x7F, 0xC9, 0x4D, 0xB2, 0x27, + 0x59, 0x0B, 0xB0, 0x02, 0x59, 0x4C, 0x03, 0x49, 0x9A, 0x30, + 0x4F, 0x73, 0x47, 0xAF, 0xA8, 0x2A, 0xEE, 0x3E, 0x2B, 0x70, + 0x70, 0x3E, 0x0D, 0x1B, 0x14, 0xE4, 0x53, 0x6B, 0xED, 0x3D, + 0xE5, 0x87, 0xB3, 0xC7, 0x36, 0xAE, 0x88, 0x02, 0xF1, 0x7A, + 0x7D, 0xC5, 0x8B, 0x01, 0xBC, 0x57, 0xD4, 0x80, 0x6C, 0x6D, + 0x6D, 0xE1, 0x2C, 0x78, 0x1F, 0x8E, 0x61, 0xD1, 0x4E, 0xE0, + 0x68, 0xB9, 0x88, 0xE8, 0x7E, 0x37, 0xA3, 0x5E, 0xA8, 0xBC, + 0x8C, 0x97, 0x96, 0x5B, 0xF4, 0x8D, 0x05, 0x50, 0x4F, 0x67, + 0x17, 0xB3, 0x81, 0x4C, 0x9E, 0x0F, 0xD0, 0x1B, 0x6B, 0x7E, + 0x22, 0x03, 0x56, 0x09, 0x6A, 0xDD, 0xD4, 0xEE, 0x9B, 0x4D, + 0xE8, 0x33, 0x9C, 0x80, 0x64, 0x61, 0x15, 0x32, 0x74, 0xAC, + 0x36, 0x4C, 0x17, 0xF2, 0x08, 0x7C, 0xDE, 0x5F, 0x37, 0x09, + 0xC6, 0x75, 0xB2, 0xE7, 0xBB, 0x82, 0x7A, 0x2A, 0x99, 0x83, + 0xF3, 0x18, 0xF0, 0xA4, 0xF3, 0x9B, 0x37, 0xBB, 0x70, 0x25, + 0x71, 0x13, 0x4D, 0x78, 0x60, 0xF4, 0x16, 0x4C, 0x0E, 0x33, + 0x0F, 0x11, 0xAA, 0xC6, 0x8B, 0xB9, 0x4A, 0x99, 0x2F, 0x26, + 0xC0, 0x8F, 0xF3, 0x54, 0xE8, 0x61, 0x91, 0x41, 0xA7, 0x78, + 0x70, 0x75, 0x44, 0xDD, 0x4E, 0xEB, 0x3C, 0xC6, 0x40, 0x20, + 0xC9, 0xFE, 0xAE, 0x6E, 0xAC, 0xC9, 0xD4, 0x4D, 0xF9, 0xCC, + 0x69, 0x8D, 0x29, 0xC2, 0x0E, 0x40, 0xEA, 0xBA, 0xBC, 0x71, + 0x43, 0x05, 0x00, 0xA8, 0x6D, 0x72, 0xA9, 0xD7, 0xC7, 0x0F, + 0x13, 0xB2, 0x77, 0x12, 0x96, 0x31, 0x1E, 0x84, 0x42, 0x3C, + 0x19, 0xE8, 0x71, 0xE5, 0x90, 0x88, 0x88, 0x40, 0xD3, 0xFC, + 0xBE, 0x01, 0x3B, 0xED, 0xD1, 0x26, 0x38, 0x0F, 0xA1, 0xB4, + 0xC3, 0x95, 0x32, 0x64, 0x79, 0x28, 0xEE, 0x38, 0x02, 0x03, + 0xA8, 0x5B, 0x03, 0x8E, 0xBB, 0x4E, 0xAC, 0x5A, 0x7A, 0xB8, + 0xA7, 0xCC, 0x98, 0xDF, 0x1E, 0xF9, 0x9E, 0xDB, 0xBA, 0xE4, + 0xC4, 0x4B, 0xC7, 0x7B, 0x5F, 0xAE, 0xF9, 0xCD, 0xAB, 0x90, + 0xE5, 0x9D, 0x8D, 0x25, 0xC5, 0x41, 0x84, 0xFF, 0x5A, 0x7D, + 0x84, 0x31, 0x4F, 0x31, 0x4A, 0xA9, 0x0C, 0x74, 0xFC, 0x3B, + 0xED, 0xC6, 0x32, 0xBF, 0x41, 0x05, 0x02, 0xC3, 0x10, 0xD4, + 0xCC, 0xB8, 0xD3, 0xA1, 0x4E, 0xC3, 0xCF, 0x15, 0xB4, 0xE6, + 0xB0, 0x63, 0x25, 0xEC, 0xC9, 0x32, 0x06, 0xBC, 0x13, 0x7F, + 0x02, 0xE7, 0x47, 0x95, 0x4C, 0x07, 0x63, 0x6E, 0xAB, 0xE4, + 0xBD, 0xEC, 0x19, 0xFB, 0x44, 0x09, 0x83, 0x1A, 0x2B, 0x64, + 0xE3, 0x9A, 0xFE, 0x58, 0x1A, 0xB3, 0x98, 0xF3, 0x66, 0xB9, + 0x34, 0xF5, 0xED, 0xF1, 0xDC, 0x19, 0xF9, 0xB6, 0xAC, 0x75, + 0x02, 0x2E, 0xBE, 0x96, 0x68, 0xA3, 0xAA, 0x3A, 0x3B, 0x60, + 0xF5, 0xC8, 0xD9, 0x62, 0xA1, 0xFD, 0xCC, 0xE5, 0xA6, 0xC9, + 0x6B, 0x75, 0x84, 0xDE, 0xB8, 0x42, 0x99, 0xC0, 0xE3, 0xDF, + 0x85, 0x81, 0xBE, 0x8A, 0x28, 0x52, 0xCA, 0x3D, 0xF7, 0xD7, + 0x6D, 0x0C, 0x96, 0xEC, 0xEB, 0x15, 0xC1, 0xFF, 0x64, 0x17, + 0x87, 0xC8, 0x71, 0x0B, 0x27, 0x02, 0x56, 0x0D, 0xBA, 0x19, + 0x81, 0x2F, 0x80, 0x70, 0x1B, 0xE2, 0x77, 0xAD, 0xB9, 0x61, + 0xFF, 0xE6, 0x9F, 0xF1, 0x78, 0xE6, 0x3D, 0x51, 0xBE, 0xCB, + 0x21, 0xBA, 0x01, 0xB5, 0x8E, 0x07, 0xF7, 0x1C, 0x20, 0x2D, + 0x9B, 0x88, 0x97, 0x74, 0x03, 0xF3, 0x76, 0x89, 0xB9, 0xF9, + 0xDB, 0x0B, 0x6A, 0x4C, 0xAD, 0xE8, 0x50, 0xAC, 0x3E, 0x06, + 0xCC, 0x75, 0xE3, 0x96, 0x5D, 0x43, 0xFB, 0x33, 0x41, 0x4B, + 0xAD, 0x53, 0x2A, 0xDF, 0x4B, 0x6D, 0x15, 0x1C, 0x9A, 0xDC, + 0x4E, 0x23, 0x76, 0xBB, 0xB5, 0x04, 0x39, 0x66, 0x09, 0xAD, + 0xEA, 0xE5, 0xFF, 0xFB, 0x95, 0x67, 0x3F, 0x81, 0xAC, 0xAC, + 0x55, 0x68, 0x06, 0xD1, 0x2C, 0xA0, 0xE3, 0x2D, 0x18, 0x49, + 0xCF, 0x8F, 0xF6, 0x8B, 0x7C, 0xF8, 0xBA, 0x01, 0xEA, 0x25, + 0x4C, 0xC5, 0x53, 0x4F, 0xCD, 0x78, 0x9F, 0x86, 0x44, 0x7D, + 0x8C, 0x2E, 0xF7, 0xFB, 0x71, 0x0D, 0xEB, 0x92, 0x77, 0x48, + 0x3A, 0xAE, 0x0E, 0x88, 0x5D, 0x88, 0x23, 0x46, 0xF1, 0x9D, + 0x73, 0x4D, 0x6C, 0x9C, 0xEB, 0x51, 0x1B, 0xB9, 0x8A, 0xA7, + 0xD7, 0x49, 0x37, 0xD2, 0x70, 0xAF, 0x85, 0xFD, 0x4D, 0x58, + 0x47, 0x95, 0x0D, 0x89, 0x1A, 0x6D, 0x90, 0xAE, 0x24, 0x9D, + 0x87, 0x72, 0x3A, 0x88, 0x70, 0x35, 0x58, 0x1D, 0xC4, 0x97, + 0xFD, 0x56, 0xD7, 0xC4, 0x93, 0xDA, 0xCB, 0x56, 0xCD, 0x51, + 0x54, 0x99, 0x45, 0xAC, 0x14, 0xD2, 0xB8, 0x0B, 0x0C, 0x99, + 0x82, 0x75, 0x86, 0x34, 0x0C, 0xD6, 0x10, 0x85, 0x86, 0x78, + 0x34, 0x8D, 0xA1, 0x44, 0xB5, 0x2F, 0x97, 0x59, 0x7C, 0x9F, + 0x4A, 0xCA, 0x07, 0x60, 0xA1, 0xBF, 0xC7, 0x80, 0xE1, 0xFC, + 0x0C, 0x33, 0xB3, 0x7B, 0x55, 0x4C, 0x6C, 0x85, 0xB8, 0xE4, + 0xF6, 0xC0, 0x9A, 0xDC, 0xA3, 0xA4, 0xAA, 0x36, 0xB1, 0xA0, + 0xE5, 0xB5, 0xEB, 0x18, 0x20, 0xDC, 0x2D, 0xEE, 0x91, 0x30, + 0x1C, 0x42, 0x52, 0x50, 0x25, 0x3D, 0x17, 0x8D, 0x75, 0x7F, + 0xB5, 0x30, 0x25, 0x88, 0x55, 0x55, 0xBF, 0xFF, 0x74, 0x24, + 0x54, 0x6A, 0x6C, 0xD7, 0x46, 0x0B, 0x08, 0x49, 0xFE, 0x5B, + 0xF8, 0xE5, 0x93, 0xC4, 0x50, 0x65, 0x2C, 0xBE, 0x01, 0x17, + 0x00, 0x30, 0x39, 0x54, 0xCC, 0xC1, 0x30, 0x74, 0x87, 0x0D, + 0x07, 0x11, 0x4C, 0x57, 0x7E, 0x0B, 0x72, 0x09, 0x0D, 0x04, + 0xD4, 0xAF, 0x60, 0x2F, 0x52, 0xF0, 0x05, 0xC0, 0x9C, 0x10, + 0x28, 0x9A, 0x31, 0x85, 0x82, 0x7F, 0x69, 0xE8, 0xB4, 0x77, + 0xC9, 0x5E, 0x91, 0x62, 0xF2, 0xFC, 0x6A, 0x58, 0xF3, 0x01, + 0xF3, 0x88, 0x74, 0x70, 0x23, 0x3A, 0x57, 0x27, 0x48, 0xE3, + 0x23, 0x64, 0xC4, 0x8A, 0x09, 0x76, 0x65, 0xEF, 0xA7, 0xCE, + 0x4B, 0xD2, 0x1D, 0xAF, 0xDF, 0xC8, 0x66, 0x72, 0x63, 0x16, + 0xD3, 0x24, 0xA3, 0xAF, 0xE8, 0xC7, 0x6F, 0xDC, 0x19, 0x43, + 0x49, 0xD0, 0x30, 0x61, 0x68, 0x99, 0x22, 0x1D, 0x6E, 0xC8, + 0x50, 0x51, 0x0C, 0xCB, 0x6F, 0x30, 0xFA, 0xB7, 0x39, 0x13, + 0x93, 0x10, 0xD0, 0x05, 0xB5, 0x8F, 0x3F, 0xA2, 0x73, 0x1A, + 0xF9, 0xE3, 0xE0, 0x41, 0x0F, 0x0C, 0x89, 0x85, 0xCE, 0x7B, + 0x2A, 0xB2, 0x88, 0x8F, 0xB6, 0xD2, 0x04, 0x67, 0xA9, 0x15, + 0xDB, 0x92, 0x91, 0x3A, 0xFF, 0xF9, 0x77, 0x78, 0xEB, 0x5A, + 0x44, 0xE8, 0xC6, 0x66, 0x73, 0x11, 0x8E, 0x77, 0x89, 0x20, + 0x38, 0x6E, 0xCB, 0xD8, 0xF3, 0x6D, 0xB2, 0x96, 0x5F, 0xBF, + 0x03, 0x61, 0x49, 0x2E, 0x08, 0xB8, 0x06, 0x29, 0x26, 0xFB, + 0x64, 0xF9, 0x9F, 0x11, 0xD4, 0xFD, 0xEF, 0x0D, 0x05, 0xB4, + 0xF1, 0x24, 0x6C, 0x06, 0xED, 0xC8, 0x5C, 0x23, 0xC6, 0x41, + 0xE4, 0x4F, 0x8A, 0xAA, 0x72, 0x40, 0xB1, 0x89, 0xAB, 0xA9, + 0x16, 0x6C, 0xEE, 0xFE, 0x70, 0x8F, 0x47, 0x92, 0x21, 0x0A, + 0x9B, 0x8C, 0x12, 0xAB, 0x20, 0x00, 0xAC, 0x17, 0x84, 0x0B, + 0xFB, 0x40, 0xA1, 0xD5, 0x57, 0xE7, 0xA0, 0xEF, 0xE4, 0xD8, + 0x8B, 0x53, 0x16, 0x0A, 0xDA, 0x69, 0x40, 0x81, 0xCF, 0xD9, + 0xB0, 0x9E, 0x4B, 0x31, 0xC0, 0x48, 0xC4, 0x36, 0x70, 0xF4, + 0x24, 0x63, 0x36, 0x9E, 0x93, 0xC8, 0x88, 0x61, 0x1D, 0x73, + 0x0B, 0x59, 0x04, 0x80, 0xFD, 0x9A, 0xED, 0x15, 0xAE, 0xFB, + 0x2A, 0xDA, 0x6E, 0x67, 0x60, 0x23, 0x81, 0xCE, 0x7E, 0x88, + 0x17, 0xD3, 0x55, 0x82, 0xF1, 0x6D, 0x99, 0x6D, 0x26, 0xAE, + 0xEB, 0x36, 0x94, 0x9A, 0xEF, 0x19, 0x01, 0x7D, 0x81, 0xFA, + 0xB4, 0x64, 0x5B, 0x19, 0xF1, 0x33, 0xF9, 0xEA, 0xBE, 0x75, + 0x7F, 0x34, 0xF8, 0x7D, 0x0F, 0xF1, 0xD2, 0x18, 0x77, 0xDB, + 0x46, 0xB9, 0xB2, 0x5A, 0x45, 0xD7, 0xA2, 0xE7, 0x73, 0x07, + 0x7B, 0xAA, 0x57, 0x80, 0x1F, 0x9C, 0xBD, 0x94, 0x06, 0x87, + 0x15, 0xBD, 0x7F, 0xEB, 0xC1, 0x3C, 0x83, 0x3F, 0x71, 0xE4, + 0x49, 0x0E, 0x60, 0xEA, 0xF0, 0x5C, 0x7D, 0xA7, 0xEE, 0xD7, + 0x31, 0x7A, 0x7D, 0x60, 0x92, 0xFB, 0x6D, 0x06, 0x7A, 0xD3, + 0x72, 0x30, 0x4A, 0x76, 0x66, 0x7C, 0xDC, 0x6F, 0x18, 0x06, + 0x89, 0xEB, 0xBF, 0xC4, 0x6C, 0x15, 0x84, 0x94, 0x37, 0x9D, + 0x6E, 0x0E, 0x58, 0x8F, 0x03, 0x71, 0xCA, 0xF4, 0xCA, 0xB1, + 0xA0, 0x6A, 0xE4, 0x6C, 0x72, 0x2A, 0x38, 0x69, 0x28, 0xF5, + 0xBD, 0x2D, 0x22, 0x53, 0x2E, 0x2F, 0x07, 0xC9, 0x1F, 0xBC, + 0xDA, 0xA1, 0x12, 0x00, 0x6E, 0xF1, 0xA0, 0xE0, 0x4B, 0x27, + 0xBB, 0xD7, 0xA2, 0x8E, 0x57, 0xAF, 0x63, 0x3D, 0xEF, 0xEE, + 0x22, 0x7F, 0x3D, 0x54, 0x60, 0x8D, 0xCE, 0xFF, 0x1E, 0xAE, + 0xD5, 0x79, 0x2F, 0xCF, 0x79, 0x00, 0xA4, 0x2F, 0x5B, 0x8A, + 0x05, 0xDF, 0x68, 0x41, 0xA5, 0x8A, 0xB8, 0x43, 0x81, 0xD5, + 0x10, 0xCE, 0xA8, 0x20, 0x3A, 0x85, 0x7A, 0x11, 0x8E, 0x98, + 0x2F, 0xA9, 0x62, 0x54, 0x73, 0x31, 0x25, 0x8F, 0xE3, 0x6C, + 0x28, 0xB5, 0x80, 0x3B, 0x3C, 0xA4, 0xB7, 0xB8, 0x09, 0x1A, + 0xCA, 0xAC, 0x2B, 0x03, 0x43, 0x1C, 0x7D, 0x0D, 0x89, 0xAD, + 0x6D, 0x60, 0xD0, 0x28, 0x55, 0xD5, 0x44, 0x7D, 0x5E, 0x0D, + 0x3F, 0x5E, 0x42, 0xE3, 0xA9, 0xD2, 0xB8, 0x81, 0x2D, 0x45, + 0x33, 0x1E, 0x1E, 0x8D, 0xCF, 0xE3, 0xB4, 0xDD, 0x8C, 0x46, + 0x20, 0x12, 0x5D, 0x83, 0x89, 0x2F, 0x5B, 0x97, 0xE1, 0x26, + 0xDF, 0xB1, 0x00, 0xD4, 0x26, 0x6A, 0xC6, 0x99, 0xF1, 0xE1, + 0x93, 0x43, 0x20, 0x92, 0x5C, 0x74, 0x29, 0xFD, 0xC8, 0x38, + 0x66, 0xC2, 0x22, 0x90, 0x92, 0xD8, 0xBF, 0xB4, 0x5F, 0x89, + 0x0B, 0xD8, 0xEB, 0xB7, 0xE2, 0xC2, 0x59, 0x02, 0x70, 0xC4, + 0x20, 0x31, 0x0C, 0xB0, 0xB3, 0xB8, 0x22, 0x2A, 0x04, 0x69, + 0xAB, 0xA0, 0xA5, 0xC6, 0x09, 0xB6, 0x77, 0x70, 0x2C, 0x45, + 0x54, 0x88, 0xB8, 0xB8, 0x71, 0xFE, 0x55, 0x77, 0xB5, 0x04, + 0xE5, 0xF4, 0x13, 0xED, 0x1D, 0xC1, 0x3C, 0x64, 0x7D, 0x7A, + 0xAA, 0xC7, 0x9B, 0x6A, 0x04, 0xF2, 0x63, 0xED, 0x87, 0xFB, + 0x42, 0x35, 0xBC, 0xDD, 0xC1, 0x40, 0x12, 0xAA, 0x4D, 0xFA, + 0x2F, 0xA8, 0xF9, 0x60, 0x3B, 0x3D, 0x6F, 0x17, 0x76, 0x9C, + 0xDE, 0xD8, 0xAE, 0x7D, 0x4C, 0x0F, 0xC0, 0x47, 0x79, 0x8E, + 0xF0, 0xA0, 0x66, 0xC2, 0xE4, 0xC4, 0x51, 0x6D, 0x63, 0x3F, + 0xDF, 0x6F, 0x30, 0x75, 0x9B, 0xB6, 0x3A, 0xB2, 0x1D, 0x13, + 0x04, 0x2B, 0xD0, 0x32, 0x71, 0x6C, 0xDE, 0x92, 0x16, 0xFE, + 0x55, 0xFF, 0x36, 0x5F, 0xA9, 0x53, 0xCE, 0x92, 0xF2, 0x77, + 0xFD, 0x0A, 0x08, 0xBE, 0xF4, 0x9D, 0x1B, 0xE9, 0x7E, 0x33, + 0xC6, 0xD7, 0xC0, 0x9F, 0x7F, 0xC6, 0x71, 0x61, 0xBE, 0xF2, + 0x91, 0x79, 0x58, 0x46, 0x1C, 0x98, 0x1D, 0xB2, 0x17, 0x48, + 0x08, 0xBE, 0x90, 0x44, 0x94, 0x19, 0x18, 0xB0, 0x9F, 0x96, + 0xB5, 0x22, 0x4C, 0x75, 0x00, 0x19, 0xB4, 0x6D, 0x1B, 0x2D, + 0x1B, 0xBC, 0x54, 0xCA, 0x3A, 0x5F, 0x77, 0x53, 0x53, 0xE7, + 0x38, 0x06, 0xE2, 0x9F, 0xA5, 0x0D, 0x90, 0x9E, 0xAD, 0xDD, + 0xF0, 0xA9, 0x3E, 0x06, 0xB7, 0x5E, 0x0C, 0xD3, 0x42, 0xB4, + 0x05, 0x01, 0x15, 0xD5, 0x83, 0xE8, 0xCB, 0xA9, 0x7A, 0xEA, + 0xDA, 0x34, 0x26, 0xB5, 0xFF, 0x49, 0x89, 0x89, 0xBF, 0xF0, + 0xDD, 0x42, 0x48, 0x8E, 0x2D, 0x45, 0x23, 0x84, 0xD7, 0x9C, + 0xE2, 0x5C, 0x8D, 0xBA, 0xB9, 0xBF, 0x5F, 0x51, 0x36, 0xCB, + 0x5B, 0xB8, 0x5F, 0x01, 0x42, 0xB6, 0x40, 0xA3, 0x76, 0x39, + 0xD8, 0xD2, 0x2C, 0x15, 0x0F, 0x3B, 0x7A, 0x29, 0x92, 0x26, + 0x43, 0x40, 0x6E, 0xA3, 0xF0, 0x4E, 0xB7, 0x06, 0x67, 0x03, + 0x8B, 0x97, 0x71, 0x25, 0x1F, 0xFB, 0xF1, 0xE7, 0x2D, 0x99, + 0xE6, 0x92, 0x13, 0xF3, 0x4E, 0x5B, 0x49, 0x0A, 0xB1, 0x27, + 0x12, 0x68, 0xCC, 0x09, 0x44, 0x0C, 0x67, 0xCE, 0x8D, 0x63, + 0x3A, 0x85, 0x71, 0xAA, 0xD6, 0xD2, 0x0F, 0x02, 0xD6, 0xF4, + 0xA9, 0x73, 0x52, 0xE9, 0x7B, 0x3C, 0xD9, 0x3B, 0x80, 0x2C, + 0x22, 0x94, 0xE5, 0xE8, 0x3D, 0xB2, 0x8E, 0xE0, 0xE3, 0x16, + 0x91, 0x1E, 0xA4, 0xC2, 0x13, 0x40, 0xF2, 0x5B, 0xE2, 0x7F, + 0xBC, 0xC6, 0x2C, 0x64, 0x25, 0x43, 0xD1, 0x87, 0xBA, 0xBF, + 0x04, 0x6F, 0x0D, 0x32, 0xA7, 0x2E, 0xE1, 0x8B, 0x88, 0xE0, + 0x13, 0x5F, 0x08, 0xB8, 0xDD, 0xAA, 0x4F, 0x08, 0x0F, 0x5C, + 0x8D, 0x07, 0x31, 0x26, 0x09, 0xC9, 0x38, 0x4A, 0x95, 0x65, + 0x33, 0x88, 0x63, 0xCB, 0xD0, 0x80, 0xF5, 0xE2, 0xBB, 0x70, + 0xC5, 0xA0, 0x6B, 0x37, 0xD7, 0xEF, 0x78, 0xD4, 0x78, 0x66, + 0x82, 0x26, 0xE3, 0x9D, 0x68, 0x48, 0xE0, 0xF9, 0x60, 0x68, + 0x31, 0xF3, 0x2A, 0x39, 0xF6, 0x5D, 0x3C, 0x8E, 0x72, 0x5C, + 0x49, 0x75, 0x1B, 0x4B, 0x1F, 0x0E, 0xBC, 0x1F, 0x0B, 0xC2, + 0x92, 0x4F, 0xAC, 0x44, 0xE7, 0x63, 0x58, 0xE0, 0xF9, 0x93, + 0xA9, 0x9A, 0x41, 0x51, 0x8B, 0x87, 0x1C, 0x26, 0x35, 0x20, + 0x5F, 0xCC, 0x6A, 0x22, 0x4C, 0x29, 0xCA, 0x5B, 0xBA, 0x29, + 0x60, 0xBD, 0x2F, 0x6F, 0xB3, 0x32, 0x4D, 0xFB, 0x73, 0x2C, + 0xBF, 0x7E, 0xA8, 0xF9, 0x19, 0xE2, 0xA1, 0x35, 0x2C, 0xEB, + 0xDB, 0x4F, 0xB2, 0x58, 0x84, 0xED, 0x8E, 0xFC, 0x86, 0xFF, + 0x0E, 0x63, 0xE6, 0xAA, 0xBE, 0x7D, 0xAE, 0xAD, 0xDC, 0x74, + 0x8C, 0xFD, 0x88, 0xCC, 0x72, 0x71, 0x7B, 0x77, 0xC2, 0x85, + 0xE7, 0x44, 0x6B, 0x9F, 0xE1, 0xD5, 0xA0, 0x21, 0xD9, 0xBD, + 0xA0, 0x25, 0xDD, 0xC8, 0xAD, 0x64, 0x89, 0x53, 0xA8, 0x4F, + 0xB3, 0xF7, 0x52, 0x60, 0x39, 0xE2, 0x7B, 0x8B, 0xF6, 0x40, + 0x2B, 0x4A, 0x79, 0x51, 0x5E, 0x6B, 0xAB, 0x5D, 0xD4, 0x34, + 0xF1, 0xA6, 0x71, 0x89, 0x06, 0xC7, 0xF1, 0x63, 0x2F, 0xEB, + 0x26, 0xF6, 0xEA, 0x89, 0xCC, 0xAC, 0x68, 0xD9, 0xBC, 0xCF, + 0x2E, 0x80, 0xBC, 0xBB, 0x81, 0xAF, 0xAF, 0x20, 0x78, 0xBB, + 0xF9, 0xEF, 0xF0, 0x6B, 0x79, 0x7A, 0x86, 0x86, 0x73, 0xDA, + 0x8A, 0x72, 0x4A, 0xDC, 0xF9, 0xD3, 0x8E, 0x8E, 0x4E, 0xA5, + 0x65, 0x38, 0x0A, 0xA8, 0xD6, 0xEC, 0x9E, 0x0E, 0x21, 0x5D, + 0x02, 0xD3, 0x36, 0x30, 0xB7, 0x33, 0xF2, 0xE3, 0x6F, 0xFC, + 0x59, 0x20, 0xFE, 0x13, 0x34, 0x35, 0x00, 0xD0, 0xFA, 0x97, + 0x1F, 0x60, 0x9C, 0x77, 0xA2, 0x4D, 0xE7, 0x2C, 0x5D, 0x40, + 0x82, 0xE1, 0x2B, 0xFF, 0x60, 0x1D, 0x59, 0x10, 0x2C, 0x43, + 0x49, 0x56, 0x09, 0x51, 0xF7, 0x8C, 0xAF, 0x4B, 0x80, 0xDB, + 0xDB, 0xF0, 0xE1, 0xB8, 0x5F, 0xB9, 0xA3, 0xAB, 0x76, 0x54, + 0x29, 0x5D, 0x12, 0x48, 0x5B, 0xCB, 0x21, 0xE7, 0x1C, 0x16, + 0xE6, 0x8E, 0x07, 0x3A, 0x70, 0x9E, 0xB4, 0x22, 0x06, 0x27, + 0x25, 0x6D, 0x6F, 0xF9, 0x78, 0xE3, 0x02, 0xE3, 0x04, 0x17, + 0x3E, 0xF1, 0xEF, 0x78, 0x1A, 0x95, 0x01, 0x20, 0x46, 0x06, + 0xA5, 0x4C, 0x7E, 0x0E, 0x6B, 0x83, 0xEB, 0x5C, 0x48, 0xBE, + 0x23, 0x5A, 0xC8, 0xBC, 0x9D, 0x8F, 0xE6, 0xCC, 0x9E, 0x27, + 0x9E, 0xB8, 0x13, 0xCF, 0xD9, 0x5C, 0x90, 0xF1, 0x7F, 0x36, + 0x1A, 0x91, 0x88, 0x58, 0x19, 0x2A, 0xA3, 0x00, 0x98, 0x54, + 0x27, 0x80, 0xBC, 0xA9, 0xEA, 0x66, 0x89, 0xD0, 0xEA, 0x88, + 0xBB, 0xE5, 0x11, 0x0D, 0x69, 0x39, 0x45, 0x9D, 0xB0, 0xDA, + 0x6F, 0xA5, 0x30, 0xC9, 0x2D, 0x5E, 0x3A, 0x00, 0xB9, 0xD9, + 0xEB, 0xA7, 0x2A, 0x69, 0x78, 0x79, 0x88, 0xC3, 0x63, 0xB9, + 0xA7, 0x49, 0x51, 0x18, 0xCC, 0x06, 0x31, 0xDB, 0xA2, 0xB1, + 0x30, 0x8F, 0x18, 0xD4, 0xC9, 0x82, 0xF0, 0x04, 0x30, 0x56, + 0x74, 0xD9, 0x3D, 0xCC, 0xEF, 0x4B, 0xA6, 0x8A, 0x88, 0x35, + 0x6C, 0xF9, 0xBA, 0x0A, 0x61, 0x28, 0x97, 0x4D, 0x04, 0xD8, + 0xFB, 0x42, 0x9D, 0x6A, 0xED, 0x90, 0x05, 0x3F, 0x62, 0xDE, + 0xE6, 0x45, 0xF8, 0xCB, 0x0A, 0x18, 0x73, 0x4B, 0xB9, 0x8C, + 0xF9, 0x4C, 0x39, 0x58, 0xA2, 0xA6, 0xEA, 0xBF, 0x3D, 0x7E, + 0x18, 0xC5, 0x50, 0x90, 0x7C, 0x17, 0xAB, 0xFE, 0xAB, 0x59, + 0x14, 0xC6, 0x53, 0xC4, 0xEF, 0x35, 0xAB, 0x8C, 0xB0, 0xE0, + 0x03, 0xBA, 0x51, 0x3E, 0xF8, 0x2B, 0x72, 0x95, 0xDE, 0x12, + 0x88, 0xFF, 0x4E, 0x05, 0xCC, 0x9B, 0xFF, 0xB6, 0x2D, 0x27, + 0xD6, 0xA2, 0xA4, 0x8F, 0xC0, 0xF8, 0x55, 0x5E, 0x3A, 0x97, + 0x8F, 0xAE, 0x09, 0x78, 0x3D, 0x5C, 0xB1, 0x53, 0x5C, 0xF4, + 0x4A, 0x9B, 0xB4, 0x23, 0x92, 0x97, 0xB4, 0x5F, 0x5A, 0x8C, + 0x32, 0x00, 0xEB, 0x47, 0xFA, 0x42, 0xB4, 0x1C, 0xAE, 0x6E, + 0xC6, 0x78, 0x60, 0xFC, 0x27, 0x9B, 0xDB, 0x45, 0x6B, 0x9E, + 0x17, 0x1A, 0xC1, 0x03, 0xCE, 0x34, 0x0C, 0xEA, 0x84, 0x7A, + 0xE0, 0xEB, 0x29, 0xB2, 0xB4, 0x8A, 0x1F, 0xF2, 0x8F, 0x15, + 0xA3, 0x34, 0xFE, 0x16, 0x46, 0x73, 0x24, 0xF8, 0xF9, 0x96, + 0xF3, 0x0F, 0x8A, 0xD1, 0x3B, 0x35, 0x7F, 0x05, 0xF2, 0x0A, + 0x27, 0x12, 0xD4, 0xE5, 0x35, 0x22, 0x78, 0x06, 0xBA, 0x04, + 0x3F, 0x60, 0xAE, 0x79, 0xF8, 0x59, 0xA8, 0x25, 0xBB, 0x69, + 0xE9, 0xB6, 0xE0, 0xB4, 0xD0, 0xE4, 0xFE, 0xD0, 0x98, 0x8C, + 0x18, 0xE4, 0xB6, 0x80, 0xA4, 0xFC, 0xB1, 0x91, 0x0D, 0xE9, + 0xE7, 0xA1, 0xA9, 0x85, 0xCF, 0x0D, 0x6D, 0x30, 0x05, 0x54, + 0x62, 0x18, 0x45, 0xE7, 0x7B, 0xFA, 0x14, 0xAB, 0xD1, 0x6A, + 0x25, 0x49, 0xA5, 0x16, 0x2F, 0x9A, 0x56, 0x0A, 0x69, 0x92, + 0x74, 0x1F, 0x91, 0x34, 0xFC, 0x7C, 0x5F, 0x3B, 0x5C, 0x01, + 0x1F, 0xF2, 0xB0, 0xC0, 0x24, 0xFB, 0x90, 0xE7, 0xAF, 0x56, + 0x48, 0x8D, 0xFF, 0x22, 0x95, 0xD0, 0xDA, 0x9D, 0xE7, 0xF6, + 0x52, 0xF7, 0xE6, 0xF2, 0x5D, 0x07, 0xB1, 0xF3, 0x60, 0x95, + 0x0D, 0x1B, 0x38, 0xE6, 0x7F, 0x7C, 0x7A, 0x65, 0xD9, 0xBA, + 0xAF, 0xE3, 0x17, 0x6C, 0xA4, 0xDA, 0x74, 0x52, 0x38, 0x54, + 0xA3, 0x7E, 0xDA, 0x17, 0xFF, 0x5F, 0x34, 0xD0, 0xFC, 0x23, + 0x40, 0x64, 0x9F, 0x55, 0xB2, 0x93, 0xDB, 0x10, 0x48, 0xED, + 0x95, 0xCD, 0xB2, 0x39, 0x3D, 0x11, 0x35, 0x83, 0x95, 0x67, + 0x63, 0xB4, 0xB7, 0x99, 0x03, 0x88, 0x01, 0x80, 0xE8, 0x1C, + 0xCE, 0xC1, 0x0F, 0x21, 0x99, 0xAB, 0x42, 0x89, 0x60, 0x44, + 0x75, 0xAF, 0x9D, 0x2E, 0x49, 0xC1, 0xF5, 0x4B, 0x22, 0x36, + 0x63, 0xDD, 0xCF, 0x51, 0x45, 0x13, 0xB7, 0xBB, 0xD1, 0x69, + 0x55, 0x0B, 0x54, 0x06, 0x7A, 0xD2, 0xA0, 0xA6, 0xC4, 0xD1, + 0x33, 0x7D, 0xA7, 0x5A, 0x16, 0x5A, 0x3D, 0x85, 0x65, 0x05, + 0xB4, 0xBA, 0x39, 0xD7, 0xB9, 0x52, 0x09, 0xE8, 0xCF, 0xDC, + 0x4F, 0x3D, 0x8D, 0x63, 0xC0, 0xF2, 0xCB, 0x52, 0xA4, 0xBE, + 0x0C, 0x3D, 0x20, 0x6D, 0x5A, 0x45, 0x6A, 0x14, 0x5E, 0xE9, + 0xCC, 0x85, 0x4A, 0xC4, 0xC8, 0x28, 0x70, 0x6E, 0x17, 0x7E, + 0x50, 0x93, 0xF5, 0x07, 0xBE, 0xAB, 0x1E, 0xD3, 0x94, 0xC3, + 0xF1, 0x26, 0x10, 0xDC, 0xE4, 0x88, 0x71, 0x5D, 0x79, 0x1B, + 0xEF, 0xE6, 0x48, 0xEC, 0x1D, 0xA0, 0xCA, 0xE7, 0xBA, 0x90, + 0x20, 0x5E, 0x5D, 0x62, 0xE1, 0x1F, 0x7F, 0x37, 0x09, 0xCC, + 0xBC, 0x1B, 0x3A, 0x08, 0x03, 0xC2, 0x0C, 0xA1, 0x95, 0x01, + 0xED, 0x7B, 0xF5, 0x90, 0x2B, 0x37, 0xF7, 0xCD, 0x31, 0xEF, + 0x72, 0xEE, 0x97, 0x2F, 0x3B, 0x77, 0xE9, 0x22, 0x45, 0x78, + 0x8A, 0xAA, 0x24, 0xBB, 0x0D, 0x54, 0x30, 0x30, 0xF6, 0x8D, + 0xEB, 0xD6, 0xBE, 0x0B, 0xDE, 0xC6, 0xF8, 0x33, 0x62, 0x91, + 0x91, 0xA2, 0xBB, 0x9D, 0x68, 0x25, 0x64, 0xB6, 0x04, 0x31, + 0x5E, 0x14, 0x99, 0x75, 0x94, 0xB1, 0x34, 0x81, 0x6D, 0x82, + 0xFD, 0x75, 0xF5, 0x68, 0x8A, 0x9A, 0x4A, 0x46, 0xFE, 0x84, + 0x5F, 0xB4, 0x6B, 0x90, 0xD1, 0x29, 0x48, 0x3D, 0xD4, 0xFE, + 0x81, 0x92, 0x6C, 0x67, 0x91, 0x2B, 0x70, 0xA3, 0x9C, 0xD0, + 0xC6, 0xDC, 0x38, 0x70, 0x36, 0xF5, 0x59, 0x02, 0x32, 0x34, + 0xFC, 0xF3, 0x68, 0xC2, 0x1B, 0x2B, 0xE3, 0x6D, 0x52, 0xC4, + 0x0C, 0x99, 0x0E, 0x20, 0x80, 0x3A, 0x94, 0x9E, 0x39, 0x90, + 0x39, 0x2B, 0x3C, 0x8B, 0xAA, 0xBA, 0x80, 0xAD, 0xBD, 0xE3, + 0xF3, 0xF3, 0x04, 0x23, 0x24, 0x33, 0x5B, 0xBB, 0x1B, 0x91, + 0xE7, 0x9A, 0x1E, 0xD9, 0x47, 0x9B, 0xF2, 0xAA, 0xCB, 0x91, + 0x54, 0x35, 0xB5, 0x60, 0x05, 0x55, 0x87, 0x2B, 0x65, 0x21, + 0xCF, 0x0E, 0x8D, 0x68, 0x41, 0xAE, 0x74, 0x15, 0xC5, 0x0E, + 0x78, 0x8A, 0xBD, 0x93, 0xE8, 0x2B, 0x3B, 0x23, 0xDA, 0x21, + 0xCA, 0xF5, 0xD2, 0xC8, 0xFB, 0x3E, 0x18, 0x31, 0x5D, 0x9F, + 0x6D, 0xCE, 0x0E, 0x2C, 0x77, 0x5C, 0xE8, 0xB5, 0xD5, 0xD5, + 0x73, 0x5B, 0x89, 0x41, 0xED, 0xBA, 0x04, 0x08, 0x5B, 0xFD, + 0x30, 0xA6, 0x0B, 0xE1, 0x6D, 0x21, 0x29, 0x9D, 0xCA, 0xBE, + 0x46, 0x7E, 0x66, 0xAA, 0x8A, 0xD9, 0xC7, 0x57, 0xEE, 0x0C, + 0x7E, 0x00, 0x7E, 0x5E, 0x7D, 0x4D, 0x73, 0x41, 0x2A, 0x6A, + 0x85, 0x99, 0x3E, 0xCF, 0x9C, 0x86, 0x8A, 0x58, 0xD3, 0x32, + 0x3A, 0xA9, 0x20, 0x35, 0x4B, 0x95, 0x05, 0x63, 0xD5, 0xEA, + 0x31, 0x31, 0x6D, 0x62, 0x23, 0xF7, 0xCE, 0x71, 0xB3, 0x78, + 0xCE, 0x5A, 0x3E, 0xE3, 0x27, 0x74, 0x16, 0xA5, 0xC4, 0x1C, + 0x1B, 0x7A, 0x62, 0xDD, 0xF4, 0xB4, 0x7A, 0x1E, 0xB6, 0x5B, + 0x65, 0xCC, 0xEF, 0x41, 0x7F, 0x1B, 0x54, 0x72, 0xFE, 0x1B, + 0xA3, 0xE7, 0xB0, 0x0E, 0x30, 0x06, 0x86, 0xBE, 0x59, 0x97, + 0x25, 0xF8, 0xB5, 0x1F, 0xA8, 0x09, 0x9C, 0xE3, 0x8D, 0x46, + 0x8C, 0x85, 0x77, 0x72, 0xB9, 0xB2, 0x3E, 0xA8, 0xF8, 0x78, + 0x95, 0x49, 0x5C, 0xAD, 0x53, 0x5C, 0x0F, 0x0F, 0x3D, 0x40, + 0x8A, 0x41, 0x12, 0x74, 0x42, 0x9A, 0x8C, 0xE9, 0x70, 0x23, + 0x79, 0x06, 0x24, 0x6A, 0xE5, 0x3B, 0x59, 0xBB, 0x62, 0xFE, + 0x86, 0x6B, 0x6E, 0xBF, 0x1F, 0x88, 0x5E, 0x85, 0xCD, 0x48, + 0x90, 0xC3, 0x6E, 0x99, 0x3D, 0x6C, 0xBD, 0xA2, 0x23, 0xFE, + 0xB3, 0xBD, 0xA7, 0x92, 0x09, 0xC9, 0xEB, 0x4B, 0x97, 0x78, + 0x85, 0x9A, 0xC4, 0xAE, 0x03, 0xEA, 0x64, 0xF7, 0x7A, 0x06, + 0x99, 0x73, 0x48, 0x6F, 0x60, 0x53, 0x40, 0xDE, 0xAC, 0xE5, + 0x0B, 0xA0, 0xF7, 0xDD, 0xB9, 0x8C, 0xC8, 0xEA, 0xB0, 0xBA, + 0x32, 0x08, 0x3A, 0x7A, 0xDC, 0x31, 0xB2, 0x04, 0x3A, 0xC4, + 0x90, 0x00, 0x5B, 0x74, 0x03, 0x13, 0xB6, 0x55, 0x46, 0xCE, + 0xA3, 0xF2, 0xAD, 0x2A, 0xAA, 0xC5, 0x81, 0x9B, 0x7F, 0x92, + 0x06, 0xA9, 0x27, 0xB3, 0xD9, 0x6F, 0x12, 0x36, 0x27, 0xC3, + 0xA9, 0xDC, 0x57, 0xBF, 0x07, 0x97, 0x48, 0x94, 0x94, 0x60, + 0xEB, 0x12, 0x92, 0x35, 0x51, 0x27, 0x72, 0x0A, 0x70, 0x2F, + 0x9E, 0xFB, 0x21, 0xE1, 0xA7, 0x29, 0x63, 0xD1, 0x35, 0xEC, + 0x00, 0x40, 0xDD, 0xEB, 0xB3, 0x6D, 0x3E, 0x93, 0x50, 0x87, + 0x25, 0xBB, 0x49, 0xF0, 0xA3, 0xA3, 0x3A, 0x15, 0xFE, 0x76, + 0x14, 0x07, 0x27, 0xBA, 0xC7, 0x17, 0x53, 0x97, 0x0E, 0x0F, + 0x73, 0x27, 0x81, 0xA1, 0xA9, 0xE4, 0x84, 0x35, 0x05, 0x4D, + 0x03, 0x92, 0x74, 0x49, 0xEF, 0xDD, 0x35, 0xC4, 0x40, 0xFD, + 0xEB, 0x97, 0x59, 0x2D, 0xDF, 0xD0, 0xF8, 0xAC, 0x0F, 0x50, + 0x6B, 0x6D, 0xD4, 0x3B, 0xC8, 0xD2, 0x68, 0xD2, 0x6D, 0x96, + 0x7C, 0xDF, 0x3E, 0x6C, 0x77, 0x9B, 0x35, 0x6F, 0x1B, 0x52, + 0x37, 0xE4, 0x61, 0x1C, 0x3B, 0xCD, 0xD3, 0xA3, 0x46, 0x63, + 0x38, 0x24, 0xC7, 0x87, 0x6B, 0x90, 0x61, 0xA4, 0xC1, 0x42, + 0xBD, 0x68, 0x26, 0xE4, 0xFE, 0x85, 0xFC, 0x4D, 0xF7, 0xE7, + 0x9E, 0x76, 0xF5, 0xA0, 0x5D, 0xBF, 0x79, 0x7E, 0x3F, 0xAB, + 0xC0, 0xD3, 0x19, 0xD7, 0xDD, 0x85, 0xD9, 0xF3, 0xE3, 0x09, + 0x07, 0xA9, 0x47, 0x30, 0xF2, 0xC4, 0xBB, 0xB5, 0x92, 0x01, + 0x31, 0x4B, 0xCF, 0xA6, 0xEC, 0x73, 0xEB, 0x88, 0xAB, 0x4C, + 0xC1, 0xB8, 0xD3, 0xBE, 0xCE, 0x66, 0x6C, 0xB2, 0x12, 0x1E, + 0xD2, 0xB8, 0xFC, 0x20, 0x88, 0xB6, 0xB1, 0x98, 0x0D, 0xC5, + 0x4B, 0x9A, 0x68, 0x1E, 0xF3, 0xC2, 0x23, 0xD4, 0xFD, 0x77, + 0xDF, 0x13, 0x90, 0x38, 0xED, 0x0B, 0x68, 0x06, 0x1D, 0xFE, + 0xAD, 0x82, 0xCF, 0x8B, 0xD8, 0x74, 0xC3, 0x39, 0x3F, 0x51, + 0xD0, 0x90, 0xD6, 0x31, 0x53, 0x3C, 0x1E, 0xBB, 0x49, 0x84, + 0xCF, 0x2C, 0xDB, 0x6B, 0x86, 0x04, 0x66, 0x7C, 0x0F, 0xC9, + 0x62, 0xAC, 0x44, 0xD4, 0xF0, 0xF6, 0x06, 0xC5, 0x1E, 0xA8, + 0xAD, 0xD0, 0xA6, 0xC7, 0xBE, 0x85, 0x95, 0x66, 0xAB, 0x59, + 0xC0, 0x84, 0x05, 0x43, 0x31, 0x43, 0x35, 0x71, 0x47, 0x5D, + 0x3D, 0x90, 0xB7, 0xC9, 0xC1, 0xDC, 0xC4, 0xBC, 0xEC, 0xF9, + 0xD6, 0x64, 0xE8, 0x93, 0x1F, 0x7A, 0xA1, 0xCF, 0x3F, 0x45, + 0x02, 0xEE, 0xE9, 0x19, 0x13, 0xA8, 0x90, 0xC5, 0x9C, 0x8B, + 0x57, 0xE7, 0xA0, 0x49, 0xEA, 0xD2, 0xC9, 0x77, 0x14, 0xCF, + 0x96, 0x47, 0x47, 0x78, 0x97, 0x46, 0x49, 0xAA, 0x6D, 0x05, + 0x39, 0xB5, 0x0D, 0x8C, 0x58, 0x14, 0xF9, 0x2A, 0xC0, 0x52, + 0xD6, 0xCC, 0x29, 0x1C, 0x31, 0x0F, 0x4E, 0xE4, 0x43, 0x92, + 0xFC, 0xE6, 0xA9, 0xEF, 0x84, 0xBF, 0x47, 0x45, 0x2D, 0xE6, + 0xC9, 0xF5, 0xFF, 0xC7, 0x46, 0x65, 0x7D, 0xDF, 0x41, 0xC1, + 0x38, 0xA2, 0x05, 0x20, 0x92, 0xE9, 0x5E, 0xB3, 0xDE, 0x3F, + 0xB5, 0x63, 0x80, 0xF2, 0xF8, 0x55, 0xF8, 0x48, 0xEB, 0x20, + 0x9E, 0xEA, 0xDE, 0x65, 0xA8, 0x86, 0x0F, 0x9E, 0xFA, 0x6D, + 0xB3, 0xE2, 0x01, 0x06, 0x24, 0xD0, 0x1E, 0x05, 0x3D, 0x51, + 0x4C, 0x5E, 0x28, 0x4E, 0xE9, 0x3F, 0xD1, 0x9E, 0x4F, 0x7A, + 0x93, 0x1A, 0xF2, 0x91, 0x53, 0x53, 0x56, 0x2E, 0x79, 0x01, + 0x38, 0x80, 0x28, 0x69, 0x10, 0x15, 0x38, 0xAB, 0xCF, 0x26, + 0x39, 0x45, 0x5C, 0xD0, 0x36, 0x6D, 0x6B, 0x1A, 0x5C, 0x96, + 0xAB, 0xAE, 0xC3, 0x2D, 0xCC, 0x6B, 0x63, 0x6F, 0xAC, 0xFD, + 0x8C, 0xEF, 0xCF, 0xC7, 0x98, 0xA7, 0x73, 0xBD, 0x87, 0xCF, + 0x8A, 0xF0, 0xBF, 0x02, 0x9C, 0xD8, 0x5A, 0xED, 0x55, 0xFA, + 0xDF, 0xA7, 0x5F, 0x92, 0xCB, 0x00, 0x37, 0x33, 0x9C, 0x87, + 0xE6, 0xF0, 0x62, 0xD9, 0xE8, 0xC0, 0xEE, 0xDF, 0xEB, 0xDB, + 0xF2, 0x0D, 0xA2, 0x3C, 0x70, 0x1E, 0x70, 0xFA, 0xF6, 0x9E, + 0x08, 0x3F, 0xFC, 0x11, 0x2D, 0x4D, 0xC7, 0x2A, 0xBD, 0x78, + 0x69, 0x51, 0x9D, 0x06, 0x85, 0x49, 0xE8, 0x38, 0xBF, 0xDF, + 0x33, 0xEA, 0xE9, 0xAB, 0xF0, 0x91, 0xFF, 0xFC, 0xBA, 0x72, + 0xE0, 0x48, 0xF0, 0x41, 0xD5, 0x87, 0x53, 0x4F, 0xFC, 0x69, + 0xFE, 0x81, 0x6C, 0x5E, 0xF8, 0xAC, 0xED, 0x5C, 0x10, 0x30, + 0x16, 0x91, 0xEE, 0xF3, 0x99, 0x8F, 0x67, 0x6F, 0x04, 0x0A, + 0x40, 0xF4, 0xF5, 0x54, 0x48, 0xE5, 0x89, 0xE6, 0xFD, 0x99, + 0x5B, 0xCF, 0x6E, 0xC9, 0x38, 0x2D, 0x92, 0x22, 0x2C, 0x35, + 0x39, 0xDE, 0xD7, 0x54, 0xAD, 0xF5, 0x3C, 0xE0, 0xF8, 0xB8, + 0x3B, 0x82, 0x1B, 0x59, 0xC4, 0x63, 0x4D, 0xEB, 0xBF, 0x29, + 0xA2, 0xB6, 0x3B, 0x2B, 0x05, 0x9C, 0x60, 0xD2, 0xB1, 0x34, + 0xD9, 0x39, 0x7D, 0x96, 0xA6, 0x8E, 0x6D, 0xBD, 0xD7, 0xD2, + 0x43, 0xD8, 0xE6, 0xC0, 0x78, 0x9B, 0xC6, 0xF2, 0xB9, 0x6F, + 0x34, 0xB2, 0xB3, 0x16, 0x5D, 0xA1, 0x36, 0x00, 0x9A, 0x61, + 0xED, 0x08, 0x04, 0x12, 0x0E, 0x5C, 0xCF, 0x97, 0x49, 0x1F, + 0x8B, 0x16, 0x9D, 0xB3, 0x84, 0x1A, 0xE7, 0xC5, 0x7D, 0xB6, + 0x87, 0xA9, 0x35, 0x63, 0x78, 0x4E, 0xB0, 0x29, 0x4F, 0x7A, + 0xE9, 0x1E, 0x9B, 0x41, 0xF5, 0xC8, 0x94, 0x1B, 0x32, 0x9A, + 0x82, 0x73, 0x85, 0xDE, 0x33, 0x96, 0x0C, 0x2D, 0xF6, 0xE3, + 0xFF, 0xD0, 0xB1, 0xAF, 0xF7, 0xAC, 0x37, 0x62, 0x5B, 0x55, + 0x0A, 0x6D, 0x83, 0xD4, 0x5F, 0x22, 0x15, 0x6F, 0x5E, 0x7B, + 0x17, 0x57, 0x11, 0xE5, 0x81, 0x10, 0xEE, 0x0D, 0x37, 0xCE, + 0x01, 0x4A, 0x52, 0x4C, 0x8C, 0x3F, 0x1B, 0xF5, 0x99, 0xE9, + 0xF9, 0x53, 0xE7, 0x6C, 0xE2, 0x52, 0x0D, 0x02, 0xE1, 0x0D, + 0xC1, 0x76, 0x92, 0xAA, 0x76, 0xA0, 0x97, 0xF5, 0x46, 0xB7, + 0x30, 0x9C, 0x5E, 0x72, 0x34, 0x75, 0x16, 0x5E, 0x85, 0xB4, + 0xDF, 0xC2, 0x52, 0xE1, 0xF1, 0xF4, 0x2B, 0xA5, 0x1F, 0x98, + 0x96, 0xCF, 0x6A, 0xB5, 0x21, 0x7D, 0x1F, 0x73, 0xE9, 0x1E, + 0xEB, 0x5F, 0x7D, 0x53, 0x3B, 0x53, 0x30, 0x80, 0xD4, 0x40, + 0xE9, 0x82, 0xE2, 0xE6, 0xB8, 0xCB, 0x5D, 0x85, 0x43, 0x84, + 0xD0, 0x71, 0x0C, 0x0C, 0x0B, 0x1E, 0xE3, 0x6F, 0x7E, 0xD3, + 0x62, 0xFB, 0xA3, 0xCF, 0xC5, 0x2B, 0xC6, 0x18, 0x96, 0xFD, + 0xF3, 0x4C, 0xB0, 0xAB, 0x0D, 0x03, 0x90, 0x9E, 0x99, 0x48, + 0x5F, 0x9B, 0xAC, 0x1E, 0x96, 0xB2, 0x0F, 0xAC, 0xE5, 0x44, + 0x46, 0xA6, 0x68, 0xC7, 0x6B, 0xC6, 0x92, 0x03, 0xBC, 0xED, + 0xDE, 0x7E, 0xBB, 0x81, 0x85, 0x34, 0x0A, 0x97, 0xC5, 0xAF, + 0xB5, 0x7B, 0x22, 0xF9, 0xFA, 0xE8, 0x28, 0x54, 0xE8, 0x12, + 0xA4, 0x27, 0x1A, 0xB1, 0x81, 0x74, 0x82, 0x27, 0x7D, 0x08, + 0x52, 0x98, 0x03, 0x2C, 0x51, 0xA2, 0xB3, 0x80, 0x63, 0x49, + 0xC0, 0x27, 0x85, 0x15, 0xE2, 0x32, 0xDA, 0x1B, 0xF8, 0x9B, + 0x7C, 0x38, 0xEC, 0xE7, 0x09, 0xC2, 0xE3, 0xFC, 0xC3, 0xD2, + 0x8C, 0x0D, 0x21, 0xDF, 0x8F, 0x4F, 0x1F, 0xF7, 0xF4, 0xD3, + 0x8C, 0xC2, 0xC3, 0xE2, 0x67, 0xA4, 0xF5, 0xB5, 0xC8, 0xA9, + 0x90, 0xA4, 0xCD, 0x82, 0x07, 0x24, 0x55, 0x01, 0x02, 0xB0, + 0x09, 0xD6, 0xE3, 0xCF, 0x02, 0xF8, 0x80, 0xC5, 0x19, 0xB2, + 0x1A, 0x6A, 0xDF, 0x92, 0xD2, 0xEF, 0xAA, 0x83, 0xE6, 0x78, + 0xAD, 0xAA, 0xC7, 0x9C, 0xE3, 0xB1, 0xD4, 0xF8, 0xAA, 0xBD, + 0xFD, 0x8E, 0xED, 0x07, 0x16, 0x7A, 0xF5, 0x70, 0x7F, 0x9E, + 0x08, 0xD0, 0x66, 0xB4, 0xE8, 0xC7, 0x77, 0x88, 0x9C, 0x50, + 0xA6, 0x02, 0x5C, 0x21, 0x26, 0x2C, 0xA2, 0x06, 0xBF, 0xD9, + 0x45, 0x47, 0xC3, 0xA2, 0xE0, 0x7F, 0xA6, 0x3B, 0xC6, 0xCE, + 0xF2, 0x3F, 0x39, 0xD3, 0xBA, 0xBF, 0x9D, 0x84, 0x61, 0x6E, + 0xB4, 0x04, 0xC4, 0xC2, 0x21, 0xF8, 0xAD, 0xE1, 0x97, 0x58, + 0xEB, 0xD8, 0xE2, 0x4D, 0xC8, 0xE1, 0x9E, 0x80, 0x1B, 0xEB, + 0xF1, 0x4F, 0x5A, 0x6F, 0x97, 0x52, 0x1B, 0xA9, 0x6B, 0x11, + 0x50, 0xBF, 0x2D, 0x19, 0x13, 0x14, 0xFA, 0x33, 0x56, 0x56, + 0x51, 0xFC, 0x64, 0xB8, 0x03, 0x81, 0x0A, 0x47, 0xEF, 0xBD, + 0xAA, 0x7D, 0x87, 0x62, 0x7D, 0xBD, 0x3E, 0xA9, 0x44, 0x73, + 0xF5, 0x1D, 0xFD, 0xBE, 0xF6, 0x0E, 0x72, 0xA1, 0x98, 0xE8, + 0x61, 0x7F, 0x14, 0xA0, 0xF4, 0xB2, 0xBE, 0x7B, 0x89, 0x6E, + 0xD0, 0x7C, 0x9A, 0xC4, 0xD2, 0xA1, 0xAE, 0x09, 0x08, 0x86, + 0x57, 0xFB, 0x96, 0xBD, 0xE7, 0x15, 0x08, 0xC7, 0xCE, 0xC4, + 0xE5, 0x85, 0xBE, 0x9D, 0x10, 0x2E, 0xA0, 0x29, 0x15, 0x7F, + 0x49, 0xED, 0xED, 0xB7, 0x28, 0x3B, 0x14, 0x51, 0x32, 0xB6, + 0x67, 0xE9, 0xFF, 0x35, 0x61, 0x6F, 0x83, 0xF5, 0x74, 0x5C, + 0xB5, 0x40, 0xDB, 0xA4, 0x04, 0xB4, 0xB9, 0x6E, 0x23, 0xCD, + 0x9B, 0xF7, 0x65, 0x74, 0x5E, 0x2D, 0x6A, 0x4F, 0x63, 0x25, + 0xB5, 0x21, 0x7E, 0xD7, 0x29, 0xB9, 0x12, 0x92, 0x74, 0x41, + 0x2A, 0x7B, 0xB8, 0x15, 0xE8, 0x33, 0xAA, 0x6A, 0xC7, 0xEC, + 0x60, 0xD2, 0xCE, 0x86, 0xF1, 0x1E, 0xE3, 0x10, 0xAA, 0xF4, + 0xFC, 0xBC, 0xEB, 0xCD, 0xF0, 0x55, 0xF8, 0x02, 0xBA, 0xB1, + 0xB2, 0xBC, 0x67, 0x22, 0x09, 0x3A, 0x4D, 0x3D, 0x7C, 0xF7, + 0x43, 0x2A, 0x96, 0x3D, 0x44, 0xDA, 0xF2, 0x18, 0xF0, 0xC0, + 0xAB, 0x45, 0xE9, 0x39, 0x07, 0x2B, 0x70, 0xC2, 0xA4, 0x27, + 0x61, 0xFB, 0xB3, 0xAB, 0x94, 0x0C, 0x51, 0x0C, 0x54, 0xAC, + 0xDF, 0xE3, 0xD6, 0x1D, 0x53, 0x36, 0x6F, 0x61, 0x48, 0xDF, + 0xEA, 0x7A, 0x86, 0x66, 0xC1, 0xFA, 0x73, 0x6E, 0x19, 0x8F, + 0xFB, 0xE8, 0x7E, 0xAC, 0xB7, 0xAD, 0x88, 0xFA, 0xDD, 0x79, + 0xCB, 0xA9, 0x46, 0xD1, 0x34, 0xB9, 0x0F, 0x80, 0x3A, 0xA6, + 0xAB, 0x62, 0x31, 0xAF, 0xFA, 0xA4, 0xED, 0x38, 0xCD, 0x06, + 0x05, 0x1E, 0x6F, 0x3F, 0x3E, 0x66, 0x46, 0x1D, 0x64, 0xE8, + 0xAE, 0x97, 0xD9, 0xE4, 0xAB, 0x81, 0x63, 0x65, 0xB9, 0xA3, + 0x0C, 0xE1, 0x0B, 0x41, 0x4C, 0x9D, 0xBA, 0x6F, 0x3D, 0xFD, + 0xA0, 0xCA, 0xBE, 0xD6, 0x70, 0x3E, 0x98, 0x7F, 0x3F, 0x3A, + 0xC4, 0x6F, 0x5B, 0xC9, 0x03, 0x8E, 0x8E, 0x84, 0xCF, 0xF5, + 0xE4, 0xAF, 0x01, 0x90, 0x76, 0x58, 0x9C, 0x4C, 0xB0, 0x72, + 0x53, 0x40, 0x6C, 0x64, 0x1C, 0x8F, 0x23, 0xDE, 0x9C, 0x03, + 0x2C, 0x24, 0x77, 0x33, 0xBF, 0x95, 0xFF, 0x21, 0xB9, 0x7E, + 0x78, 0x34, 0x61, 0x82, 0x5F, 0x04, 0x65, 0x2C, 0xA5, 0xD3, + 0xD0, 0x11, 0x1D, 0x4F, 0x23, 0x6C, 0xA7, 0xEB, 0x7D, 0x5B, + 0x8C, 0x4F, 0x87, 0xB2, 0x2D, 0x99, 0x74, 0x93, 0xB5, 0x47, + 0x7B, 0x40, 0x9E, 0x7B, 0xFE, 0x5D, 0xE4, 0xF8, 0x12, 0xDE, + 0xB2, 0x04, 0x1C, 0xD3, 0xC3, 0x86, 0x56, 0x08, 0x64, 0xD6, + 0x28, 0xCA, 0xE8, 0x7C, 0xA7, 0xA6, 0xA7, 0x5F, 0x2C, 0xED, + 0x03, 0xAD, 0x9B, 0xB8, 0x7C, 0x27, 0x71, 0x46, 0xA9, 0xB2, + 0x33, 0xE5, 0xEB, 0x88, 0xFE, 0x4D, 0xE5, 0x2D, 0xF7, 0x21, + 0xBE, 0xD8, 0xDE, 0xDB, 0xA0, 0xD1, 0xB3, 0x7B, 0x3A, 0x17, + 0x65, 0x7E, 0x17, 0x17, 0x95, 0x46, 0x04, 0x48, 0x67, 0x11, + 0x61, 0x8D, 0xDC, 0xE1, 0x1D, 0x4B, 0xDD, 0xB9, 0x3A, 0x67, + 0xEE, 0x3C, 0xA4, 0x41, 0x84, 0xAA, 0x9F, 0x98, 0x33, 0x6D, + 0x50, 0xA1, 0x74, 0xB0, 0x0C, 0x2E, 0x46, 0x73, 0x36, 0xDB, + 0xD8, 0x51, 0x34, 0xA3, 0x1A, 0x3D, 0xFF, 0x5C, 0x5D, 0x9D, + 0xD9, 0xE6, 0xDE, 0xB3, 0x01, 0x6F, 0x93, 0x74, 0xD8, 0xDE, + 0x83, 0xB2, 0x9B, 0xFE, 0xAE, 0xAD, 0x27, 0xB2, 0x77, 0x62, + 0x1A, 0x6D, 0x16, 0x52, 0xC7, 0x91, 0x72, 0x16, 0x98, 0xCF, + 0xA5, 0x35, 0x94, 0xD0, 0x32, 0x34, 0x9C, 0x33, 0xBB, 0x05, + 0xFC, 0x20, 0x59, 0x0F, 0x92, 0x25, 0xEB, 0x3A, 0xAA, 0x47, + 0x34, 0x8C, 0x75, 0xEE, 0x0C, 0x73, 0xFB, 0xEE, 0x12, 0xF5, + 0xE4, 0x6F, 0x1E, 0xC9, 0xA5, 0x48, 0xC1, 0x5C, 0x88, 0x2B, + 0x63, 0x77, 0xC6, 0x71, 0x40, 0x2D, 0x16, 0x83, 0x80, 0x87, + 0x4D, 0xA5, 0x6A, 0x6C, 0x37, 0xBC, 0x50, 0x5B, 0x59, 0x88, + 0xF1, 0x86, 0xBA, 0x90, 0x48, 0x0D, 0x05, 0xF8, 0x29, 0x4B, + 0x3B, 0x80, 0x76, 0x62, 0xAE, 0xF0, 0xCC, 0xD1, 0x28, 0x9D, + 0x77, 0x2C, 0x6F, 0xDB, 0x36, 0xE4, 0x44, 0xFA, 0x11, 0x1F, + 0x00, 0x08, 0x35, 0x5C, 0x2D, 0x70, 0x6D, 0x5B, 0x3C, 0xF4, + 0xB2, 0xAD, 0xD9, 0xFE, 0xC2, 0xE5, 0xFF, 0x96, 0xFA, 0x12, + 0xBD, 0x3D, 0xEB, 0x7C, 0xAE, 0x28, 0x20, 0xDB, 0x05, 0xD0, + 0x83, 0xD8, 0x10, 0xFD, 0x43, 0x80, 0xB2, 0xB7, 0x23, 0x89, + 0x0A, 0xAE, 0x8F, 0x16, 0xA3, 0xC0, 0x60, 0x07, 0x78, 0x76, + 0x2D, 0x29, 0xFD, 0xE7, 0x39, 0xE8, 0xE4, 0xE1, 0x12, 0x0C, + 0x7F, 0x27, 0x8A, 0x5A, 0x88, 0x01, 0xFA, 0x27, 0x09, 0xC6, + 0x16, 0xBD, 0x5D, 0x73, 0x08, 0x28, 0x3E, 0x1F, 0x4A, 0xA5, + 0x3A, 0x90, 0x0A, 0x09, 0x07, 0x9E, 0x89, 0xCE, 0xB2, 0xDF, + 0xD6, 0x2D, 0xDE, 0x5F, 0xD7, 0x8B, 0xE0, 0x41, 0x08, 0xBF, + 0x9B, 0x4D, 0xEC, 0x82, 0x27, 0x44, 0x78, 0x6E, 0x00, 0x8B, + 0xD9, 0xE3, 0x83, 0xFB, 0xAE, 0xF4, 0x06, 0xD6, 0xCA, 0x5D, + 0xFD, 0x61, 0xC4, 0xB2, 0x2C, 0x11, 0xDA, 0x17, 0xAE, 0x27, + 0x27, 0xD4, 0x4D, 0x90, 0x2E, 0x91, 0xA5, 0x81, 0x48, 0x9E, + 0xAE, 0x36, 0x51, 0x83, 0xD5, 0x89, 0xCF, 0x72, 0x00, 0x7D, + 0x24, 0x9D, 0xE8, 0xF0, 0x26, 0xD8, 0x9F, 0x0C, 0x5F, 0xC7, + 0xF2, 0xE5, 0x90, 0x45, 0x90, 0x7F, 0x60, 0xBA, 0x52, 0xDD, + 0x8F, 0xB2, 0xDE, 0x1A, 0x31, 0x91, 0x2B, 0x40, 0x9D, 0x35, + 0x8A, 0x22, 0xBB, 0x35, 0x65, 0xBF, 0x40, 0x26, 0x9E, 0xF0, + 0xB9, 0x00, 0x4F, 0x54, 0x59, 0x37, 0x53, 0x77, 0xA3, 0x95, + 0x72, 0xA7, 0x50, 0xA3, 0x56, 0x6C, 0x20, 0xF4, 0x1A, 0x31, + 0x4F, 0x4C, 0xD2, 0xD1, 0x18, 0x2E, 0x05, 0x43, 0x68, 0xBC, + 0x49, 0x22, 0x58, 0x39, 0xED, 0x11, 0xC2, 0xDD, 0x08, 0x5F, + 0xDF, 0x1C, 0xC6, 0x45, 0x1F, 0x18, 0xB2, 0xD4, 0xC8, 0xDF, + 0xD8, 0xBB, 0xD8, 0x60, 0xAD, 0xB4, 0x8D, 0xF2, 0xAC, 0xD8, + 0x04, 0xA4, 0x85, 0x29, 0x82, 0x70, 0xA2, 0x36, 0xCB, 0x78, + 0x55, 0x1C, 0xE2, 0x38, 0x00, 0xFA, 0x73, 0xAF, 0xAE, 0x05, + 0xB7, 0xA6, 0xE5, 0xF7, 0x0F, 0xE1, 0x97, 0x7F, 0x5C, 0x6B, + 0x3B, 0xDE, 0xBA, 0x38, 0x34, 0xB0, 0xC1, 0xAE, 0xDF, 0x3F, + 0x0D, 0x38, 0xDA, 0x1D, 0x6B, 0x2E, 0xD3, 0x94, 0xF9, 0x5B, + 0xA4, 0x04, 0x38, 0xAD, 0x27, 0xAE, 0x6C, 0xCC, 0x9C, 0x19, + 0x47, 0xE4, 0x82, 0xE9, 0x73, 0x43, 0x33, 0x65, 0x22, 0x9A, + 0xF7, 0x27, 0xB0, 0x29, 0x4B, 0xE3, 0xCF, 0x88, 0x23, 0xF5, + 0x22, 0x65, 0x42, 0xD2, 0xD3, 0x28, 0xF2, 0xFA, 0xA2, 0xEA, + 0x00, 0x65, 0x50, 0x4C, 0x4A, 0x2E, 0x63, 0xDB, 0xFA, 0xB8, + 0xD1, 0x71, 0x6F, 0x11, 0xB7, 0x5B, 0xE4, 0x32, 0x34, 0x8C, + 0x7F, 0xD1, 0xFA, 0x67, 0xB0, 0x55, 0x05, 0x43, 0xEA, 0xF2, + 0x61, 0xA1, 0x0B, 0x35, 0xBF, 0x76, 0x0F, 0xDE, 0xB4, 0xDD, + 0x0F, 0x1D, 0x41, 0xED, 0x4F, 0xBA, 0x14, 0xCA, 0xD0, 0x4C, + 0xD6, 0x25, 0xD9, 0xF2, 0xA4, 0x0C, 0x8F, 0x7B, 0x88, 0xD9, + 0x79, 0xB7, 0x7A, 0x49, 0xF5, 0xE8, 0x29, 0x6E, 0x6B, 0xC0, + 0x46, 0xEB, 0xCB, 0xE5, 0x86, 0x97, 0xB5, 0xAD, 0x29, 0x3C, + 0x7C, 0x69, 0xAD, 0xD2, 0x14, 0xB1, 0x36, 0x1E, 0x7E, 0xB2, + 0x7F, 0x76, 0xBF, 0xDF, 0x5F, 0xF9, 0xF1, 0x8E, 0xAC, 0x31, + 0xC1, 0xF5, 0x0C, 0xE1, 0x01, 0xB9, 0x45, 0x0E, 0x8E, 0xB8, + 0xF0, 0x52, 0xF4, 0x82, 0xCC, 0x5B, 0x86, 0x32, 0x93, 0x38, + 0x96, 0x67, 0x34, 0xB1, 0xBE, 0x9D, 0x08, 0x2F, 0x18, 0xDC, + 0x7E, 0xB7, 0xE4, 0x55, 0x86, 0x07, 0x49, 0x5D, 0xB8, 0x5B, + 0x4F, 0x63, 0x85, 0xA9, 0x62, 0x88, 0xA5, 0xCB, 0xDC, 0x32, + 0x26, 0xA1, 0x14, 0xCF, 0x29, 0xA4, 0x5F, 0x97, 0x46, 0xA0, + 0x48, 0xFD, 0x00, 0x68, 0xCD, 0xDC, 0x54, 0x13, 0x6B, 0x60, + 0x80, 0xF3, 0x34, 0x9B, 0x74, 0xEE, 0x62, 0x9E, 0x86, 0xF4, + 0x35, 0x48, 0xEA, 0xB1, 0xB8, 0xA3, 0xD5, 0xF8, 0x6D, 0xF1, + 0xFC, 0x95, 0x19, 0xB4, 0xD7, 0x59, 0x1F, 0x9E, 0x2E, 0x77, + 0x37, 0xF6, 0x44, 0x87, 0xAD, 0x06, 0x00, 0xA6, 0x94, 0x43, + 0x9D, 0x34, 0xC9, 0x2E, 0x3D, 0x0E, 0x02, 0x92, 0x79, 0xAC, + 0x85, 0x28, 0xB3, 0xDF, 0xA9, 0x22, 0x71, 0xFA, 0xB7, 0xC5, + 0x93, 0xF5, 0xDB, 0x99, 0xD4, 0x8E, 0xF7, 0x99, 0x15, 0x18, + 0xC9, 0xE7, 0xDC, 0x0C, 0xDA, 0x88, 0x6A, 0xA6, 0x9E, 0xDF, + 0x66, 0x3D, 0xA5, 0x77, 0x7D, 0x59, 0x24, 0x63, 0x40, 0x43, + 0xD4, 0x90, 0x7F, 0xAF, 0x22, 0xB5, 0x63, 0xFF, 0x03, 0x92, + 0xCD, 0x52, 0xA1, 0xFB, 0x22, 0x3B, 0x11, 0xBB, 0xFE, 0xAD, + 0x5D, 0xD4, 0x7E, 0x3A, 0xEC, 0xA4, 0x35, 0x64, 0x54, 0xE3, + 0x64, 0xE8, 0x8B, 0x05, 0x0C, 0x3E, 0xCB, 0x20, 0x6F, 0x90, + 0x76, 0x32, 0x3B, 0xFB, 0xF0, 0xAC, 0x23, 0x61, 0xE3, 0x5C, + 0x62, 0x11, 0x56, 0xF3, 0x2E, 0x43, 0x94, 0x30, 0x84, 0x11, + 0x5E, 0x56, 0x81, 0x5E, 0x07, 0xC9, 0x52, 0xDD, 0xC4, 0x60, + 0x00, 0x11, 0x08, 0x1C, 0x32, 0xDF, 0x27, 0xFB, 0x19, 0x87, + 0x13, 0x45, 0x89, 0x5F, 0xEC, 0x72, 0x98, 0xD9, 0xB9, 0x7C, + 0xFB, 0x1B, 0x21, 0x1B, 0x2E, 0x77, 0x69, 0x49, 0x5E, 0x36, + 0x56, 0x08, 0x2B, 0x94, 0xB3, 0xD1, 0xE2, 0xE3, 0x20, 0xA1, + 0xBA, 0x58, 0xD9, 0xBE, 0xB0, 0xBD, 0x71, 0x08, 0xD1, 0xA7, + 0x6E, 0x4E, 0x72, 0x75, 0x11, 0xE6, 0x70, 0xEF, 0x4A, 0xDD, + 0xAB, 0x7B, 0xFC, 0x81, 0x0B, 0xB2, 0xA0, 0x6D, 0xBC, 0x33, + 0x44, 0x51, 0xDE, 0x48, 0xA6, 0x9B, 0x90, 0xCE, 0x99, 0xEA, + 0x64, 0x96, 0x85, 0x59, 0xFF, 0x27, 0xF5, 0xE6, 0xF5, 0xFD, + 0x06, 0x23, 0xD7, 0x82, 0xEC, 0x3F, 0xD5, 0x14, 0xC4, 0x20, + 0x1C, 0x4E, 0x49, 0xC7, 0x80, 0x57, 0x17, 0xD8, 0x54, 0x43, + 0x19, 0xF8, 0x83, 0x45, 0xE2, 0x39, 0x4D, 0xFB, 0x31, 0x0E, + 0x06, 0x65, 0xE7, 0x3B, 0xEB, 0x17, 0xAC, 0xE8, 0x09, 0xD1, + 0x52, 0xCB, 0x57, 0xC7, 0x97, 0xF7, 0xD2, 0x8A, 0x3C, 0xB8, + 0x13, 0x0F, 0xC4, 0xBD, 0x13, 0xD1, 0xD6, 0xFF, 0xA9, 0xCA, + 0xB0, 0x65, 0xE8, 0x1F, 0xF8, 0xEE, 0xE7, 0x2B, 0xE1, 0xBC, + 0x2E, 0xBD, 0xE0, 0x82, 0x74, 0xC1, 0x77, 0xE8, 0x0B, 0x0A, + 0xC8, 0xDD, 0x0A, 0x6E, 0xFB, 0xB7, 0x6A, 0x00, 0x5F, 0x15, + 0x6C, 0xFE, 0x40, 0x18, 0x59, 0x56, 0x6F, 0x8D, 0xCF, 0x97, + 0xD4, 0xC9, 0x46, 0x03, 0xFE, 0x24, 0x78, 0xDD, 0x53, 0x21, + 0x36, 0x74, 0xD7, 0xFE, 0x13, 0x9F, 0x63, 0xC1, 0x75, 0xEC, + 0xC4, 0xD8, 0xDF, 0xB7, 0xCD, 0x52, 0x4D, 0x6A, 0x66, 0x79, + 0xC4, 0x70, 0xC5, 0xAD, 0x8D, 0x72, 0x13, 0x6F, 0x87, 0x3A, + 0x0E, 0x55, 0xA9, 0x71, 0x0F, 0x93, 0x4E, 0xB1, 0x69, 0xF8, + 0x6B, 0xF5, 0x16, 0xF1, 0xAA, 0x45, 0xCD, 0x1D, 0xD5, 0xF1, + 0xF6, 0x7D, 0xE3, 0x5D, 0x21, 0x28, 0x71, 0xD9, 0x9C, 0x33, + 0xC0, 0x2E, 0x1A, 0x41, 0x3D, 0xCE, 0xBD, 0x59, 0xDF, 0xEB, + 0x2D, 0xC5, 0xC1, 0x22, 0x2F, 0x4A, 0xA9, 0x2C, 0x6C, 0x83, + 0xF7, 0x42, 0x8E, 0xFA, 0x99, 0xE6, 0x22, 0x33, 0xCF, 0xDD, + 0xE1, 0xED, 0x0F, 0xAF, 0x7C, 0x1D, 0x42, 0x36, 0x37, 0xD7, + 0x31, 0x97, 0xD8, 0xDD, 0x52, 0xA9, 0xB7, 0x13, 0x64, 0x86, + 0x88, 0x35, 0x90, 0xA6, 0x02, 0x73, 0xE7, 0x6B, 0xE7, 0x01, + 0x5D, 0x34, 0x03, 0x44, 0xD0, 0xCA, 0xFB, 0xC3, 0x26, 0x32, + 0x31, 0xA0, 0x26, 0xBC, 0x0A, 0x20, 0x35, 0xC1, 0x86, 0x46, + 0xDA, 0x0B, 0xFC, 0x92, 0x9D, 0x87, 0xD4, 0x25, 0x76, 0x3C, + 0x43, 0xA3, 0xA2, 0x07, 0x53, 0xD1, 0x7D, 0x5E, 0x05, 0x22, + 0x27, 0x0D, 0x87, 0x3A, 0x0D, 0x9E, 0x7D, 0xE2, 0xBE, 0x9A, + 0x44, 0xDD, 0xBF, 0xB0, 0x40, 0xC8, 0xD8, 0x48, 0x76, 0x0C, + 0xEE, 0x04, 0x0A, 0x18, 0xFC, 0x1E, 0x44, 0xFE, 0x70, 0xCE, + 0xE0, 0xE5, 0x13, 0xB4, 0xAA, 0x31, 0x9E, 0x19, 0xBC, 0x68, + 0xBA, 0xD2, 0x99, 0xDB, 0xC9, 0x26, 0xA4, 0xB5, 0x62, 0x93, + 0xE7, 0x4D, 0x12, 0xCE, 0x3B, 0x8D, 0xB4, 0xED, 0x00, 0xF4, + 0xD5, 0xF4, 0xA5, 0x99, 0x91, 0x25, 0x59, 0xB8, 0x35, 0x49, + 0x2C, 0x61, 0x5E, 0xE3, 0x7F, 0xD1, 0x2A, 0xDE, 0xFF, 0x5D, + 0x8D, 0xB8, 0xBA, 0xBF, 0xC6, 0x1E, 0x0E, 0x89, 0x12, 0x69, + 0xDD, 0xA1, 0x4B, 0xD7, 0x2F, 0x91, 0x6C, 0x10, 0x60, 0x02, + 0xB2, 0x91, 0xE2, 0xFF, 0x2A, 0xAA, 0xDA, 0xA0, 0xF7, 0x11, + 0x43, 0x93, 0x83, 0xE5, 0xC9, 0xCB, 0x13, 0x0A, 0x89, 0x41, + 0x34, 0x0D, 0x2A, 0x46, 0x06, 0x2F, 0x18, 0xC8, 0x5B, 0xE4, + 0xEB, 0x9A, 0x39, 0xBC, 0x1D, 0x31, 0x7C, 0x5F, 0x2D, 0xDD, + 0xC4, 0x03, 0x49, 0x57, 0x75, 0xF2, 0x65, 0xC2, 0x7C, 0xFD, + 0x6A, 0xB7, 0x2E, 0x22, 0xD2, 0x17, 0x69, 0xB7, 0x78, 0xBA, + 0x8C, 0x00, 0x59, 0x21, 0xE0, 0xC5, 0x9E, 0xE9, 0xBC, 0xDD, + 0xD6, 0x43, 0xD2, 0x5A, 0x8E, 0x74, 0x84, 0xBF, 0x9B, 0xD1, + 0xEC, 0x81, 0x67, 0x12, 0xBD, 0x40, 0x99, 0xE2, 0x15, 0xD7, + 0xA7, 0xAE, 0x20, 0x4C, 0x57, 0x1F, 0xC9, 0x10, 0x39, 0x97, + 0x26, 0x59, 0xAA, 0xE7, 0x1C, 0x0F, 0x2B, 0x29, 0x80, 0x17, + 0xB0, 0x1D, 0x48, 0x37, 0x8C, 0x1F, 0x24, 0xF4, 0xAD, 0xF9, + 0x55, 0x01, 0x1C, 0xD9, 0xE5, 0xD3, 0x0A, 0x20, 0x89, 0x32, + 0x39, 0xE7, 0xC4, 0x15, 0x25, 0x51, 0x6E, 0x4A, 0x6D, 0xB6, + 0xF2, 0x9F, 0x9E, 0xA6, 0x68, 0x3C, 0x6C, 0x67, 0xFB, 0x61, + 0xF7, 0x04, 0x31, 0xE9, 0x38, 0x78, 0x21, 0x23, 0x9B, 0xAE, + 0xBF, 0xDB, 0x46, 0xBB, 0x33, 0x12, 0x16, 0xA8, 0x92, 0xCC, + 0x29, 0x8B, 0x70, 0xB5, 0x2E, 0x0A, 0x1F, 0x6C, 0x25, 0x80, + 0xB3, 0x63, 0x12, 0xD2, 0xFC, 0x34, 0x2B, 0xE4, 0x73, 0x1B, + 0xF9, 0x0C, 0xDA, 0xD0, 0x08, 0x07, 0x3E, 0x24, 0x25, 0xEF, + 0x65, 0x95, 0x64, 0x10, 0x24, 0x5C, 0xD9, 0x1E, 0xD8, 0x51, + 0x26, 0x5F, 0xB1, 0xFD, 0x21, 0xEB, 0xB2, 0x74, 0xF4, 0xDF, + 0x47, 0x99, 0x06, 0x95, 0xF9, 0x0A, 0xEC, 0x1A, 0xC1, 0x12, + 0x2D, 0x96, 0x51, 0x3E, 0xE4, 0xDE, 0xB3, 0xAF, 0xF1, 0xD3, + 0x87, 0x82, 0xC1, 0x5B, 0xC6, 0xCB, 0x18, 0x4C, 0x92, 0x67, + 0x30, 0x4E, 0xE9, 0x34, 0x67, 0xE4, 0xE8, 0xF8, 0x4C, 0x24, + 0xF8, 0xB5, 0x50, 0x86, 0x03, 0xBD, 0x6E, 0x42, 0x46, 0xA7, + 0x25, 0x2D, 0xC2, 0x33, 0x2E, 0x49, 0xAD, 0xBA, 0x28, 0xB0, + 0x5C, 0x78, 0x03, 0xC8, 0x5A, 0x30, 0xB7, 0xC0, 0x3C, 0x29, + 0x66, 0x53, 0x8D, 0xD2, 0x13, 0x90, 0x2B, 0x28, 0x4B, 0x68, + 0xE6, 0xCE, 0xB2, 0x2A, 0x80, 0x20, 0x07, 0xDC, 0x15, 0x1F, + 0xA0, 0x8F, 0xE5, 0x3B, 0x1B, 0xFB, 0xF2, 0x31, 0xBA, 0x6A, + 0x1A, 0x5E, 0x2C, 0x26, 0x10, 0xC2, 0xFF, 0x8A, 0x89, 0xE4, + 0x8C, 0xB2, 0x58, 0x47, 0x47, 0x5B, 0x37, 0x2B, 0xEA, 0x6D, + 0x45, 0xA7, 0x58, 0x8E, 0x5F, 0xDF, 0xDB, 0xFC, 0xE1, 0x0C, + 0xCF, 0x3A, 0xAB, 0xA9, 0x6F, 0x7E, 0x1E, 0x1B, 0x2C, 0x2B, + 0xFE, 0xA4, 0x69, 0x9C, 0x5D, 0xF7, 0x44, 0xD5, 0xE3, 0xC0, + 0x0A, 0x84, 0x37, 0x31, 0xD7, 0x28, 0x2A, 0xD0, 0x8C, 0x93, + 0x54, 0x30, 0xB6, 0x3D, 0xF2, 0x11, 0xAC, 0x8F, 0xBF, 0x9C, + 0x77, 0x3D, 0xC2, 0xD2, 0xAF, 0x8F, 0xBE, 0xB6, 0x6C, 0x94, + 0x5A, 0x0C, 0x10, 0x4C, 0x18, 0x9B, 0x9D, 0x5A, 0x0C, 0x97, + 0x45, 0xF1, 0xBE, 0xA0, 0xA2, 0xFE, 0x49, 0xD6, 0x1E, 0x9C, + 0x83, 0x4E, 0xCF, 0x23, 0x71, 0xC4, 0xC1, 0x42, 0x0F, 0x82, + 0xA9, 0x2F, 0xB3, 0x2F, 0xB9, 0xA1, 0xCF, 0x5A, 0xA7, 0x7A, + 0xB2, 0x3A, 0xAB, 0x28, 0xCB, 0x6B, 0x4E, 0x06, 0x61, 0x9A, + 0x12, 0x3B, 0x39, 0x5A, 0x57, 0xDD, 0x1A, 0x6C, 0x67, 0x59, + 0x0A, 0xFE, 0x56, 0xC7, 0xB6, 0xDE, 0xDC, 0xC7, 0x31, 0xB0, + 0x2B, 0x69, 0x64, 0xFA, 0x4F, 0xA7, 0x74, 0x2E, 0xBF, 0x97, + 0x17, 0x52, 0xF7, 0xC6, 0x7C, 0x5B, 0x3E, 0x78, 0x98, 0xA9, + 0xD0, 0x5A, 0x46, 0x61, 0x02, 0xCD, 0x7C, 0x0D, 0xA4, 0xB5, + 0x4A, 0x8B, 0x4D, 0x76, 0x0E, 0xBF, 0x4E, 0xAC, 0xEB, 0xB0, + 0xB3, 0x16, 0x34, 0x73, 0xB5, 0xCC, 0x69, 0x31, 0x6E, 0x35, + 0xBE, 0xBB, 0x68, 0xF7, 0xF6, 0xF0, 0xBE, 0xE9, 0x4E, 0x13, + 0xE5, 0x38, 0x56, 0x9A, 0xAE, 0x04, 0xC5, 0xA6, 0xB1, 0xA7, + 0xBF, 0x72, 0xE6, 0x02, 0x54, 0x4E, 0xD7, 0xAC, 0x3F, 0x20, + 0x76, 0xD4, 0x7E, 0x33, 0x5E, 0x00, 0xFC, 0x56, 0xEF, 0x97, + 0x18, 0xB2, 0xD7, 0x71, 0x30, 0xFA, 0x57, 0x15, 0x69, 0x16, + 0xF3, 0x0A, 0x6D, 0x9A, 0x25, 0x41, 0x8E, 0xA9, 0x7C, 0xD9, + 0x8D, 0x1D, 0xB2, 0xE7, 0x70, 0x9B, 0x41, 0x2D, 0x57, 0x68, + 0xFF, 0xB6, 0x74, 0x2C, 0x80, 0x4F, 0x01, 0xD9, 0x46, 0x1B, + 0xFD, 0x9F, 0xA9, 0xA2, 0x3E, 0x83, 0xC4, 0xA6, 0xBD, 0xFC, + 0x2B, 0xFF, 0x89, 0x7D, 0x91, 0x6C, 0xEF, 0x19, 0x74, 0xF5, + 0xF9, 0xE6, 0x71, 0x7C, 0x5C, 0x8C, 0xF2, 0x8B, 0x71, 0x53, + 0x5F, 0x08, 0x64, 0xD2, 0x49, 0x6C, 0xB7, 0x6A, 0x8E, 0xC7, + 0xAC, 0xE6, 0xE9, 0x0B, 0x90, 0xEB, 0xF0, 0xB1, 0x37, 0x97, + 0x0F, 0xCF, 0x2C, 0x0E, 0xD5, 0xC4, 0x2C, 0x03, 0x00, 0xD3, + 0x1D, 0xA4, 0x0B, 0x85, 0xD1, 0x70, 0x1B, 0x8E, 0xBA, 0x33, + 0xDF, 0xF7, 0x6C, 0x63, 0x65, 0xC7, 0x3B, 0x7D, 0x3D, 0x1D, + 0x03, 0x55, 0x47, 0x67, 0xAF, 0x20, 0xFA, 0x23, 0xCB, 0xFD, + 0x4E, 0x1D, 0x97, 0xFF, 0x03, 0xC9, 0x59, 0x93, 0xCD, 0x56, + 0x13, 0xC2, 0x9A, 0xEB, 0xDC, 0x6A, 0x72, 0x43, 0xED, 0xCC, + 0xE1, 0xC9, 0x38, 0xA0, 0xD5, 0xB6, 0xD2, 0xA6, 0x4F, 0x83, + 0xAF, 0x84, 0xF9, 0xC6, 0x29, 0xCC, 0xE4, 0x7C, 0x3A, 0x34, + 0x69, 0x15, 0xCB, 0xD8, 0x17, 0x9D, 0xDD, 0x76, 0xB3, 0x77, + 0x59, 0x38, 0x10, 0xAB, 0xA4, 0xDC, 0x13, 0x25, 0x82, 0xDB, + 0x5A, 0x56, 0x7E, 0x79, 0x1A, 0xD4, 0xF3, 0xC4, 0x4F, 0x5A, + 0xF5, 0x6E, 0x66, 0x50, 0x0F, 0xD1, 0x37, 0x7E, 0x60, 0x06, + 0x1D, 0xFF, 0xA5, 0x30, 0x68, 0x68, 0x8E, 0xFC, 0x93, 0xB1, + 0x0F, 0x89, 0x4E, 0x61, 0xC4, 0xA7, 0x1F, 0x8E, 0x49, 0xFC, + 0xD9, 0x49, 0x74, 0xAC, 0xF8, 0x2F, 0x9B, 0x4A, 0xEC, 0xD1, + 0xE2, 0xE2, 0x0F, 0xE3, 0xA4, 0xE3, 0x61, 0x09, 0x70, 0x2D, + 0xC0, 0xED, 0xBD, 0x27, 0x84, 0x69, 0xE3, 0xB7, 0x88, 0x0D, + 0x02, 0x34, 0x96, 0x35, 0xEC, 0xE7, 0x80, 0x18, 0x1D, 0x14, + 0x44, 0x29, 0x33, 0x03, 0x88, 0xE2, 0x5B, 0x6D, 0x03, 0x84, + 0x24, 0x98, 0x93, 0x9B, 0x38, 0x48, 0x6F, 0x19, 0x0F, 0xF0, + 0x49, 0x71, 0x08, 0x2F, 0xC9, 0xA1, 0xA6, 0x90, 0x24, 0x10, + 0x1C, 0x69, 0x88, 0x42, 0x57, 0x16, 0x38, 0x75, 0x38, 0x5B, + 0x42, 0xAD, 0xBE, 0xE8, 0x0F, 0x97, 0xBF, 0x27, 0x5F, 0x67, + 0x29, 0xEC, 0x5E, 0x18, 0x7C, 0xBD, 0x0F, 0xB5, 0x73, 0xCE, + 0x11, 0x13, 0x49, 0x47, 0x4D, 0xC8, 0xEE, 0xC5, 0x27, 0x06, + 0xC6, 0x8E, 0xB8, 0xC5, 0xAC, 0x70, 0x9E, 0x9E, 0x35, 0x4F, + 0x9D, 0x75, 0x18, 0x3E, 0x0E, 0x29, 0x2B, 0x0C, 0x91, 0x16, + 0x76, 0xCE, 0x5B, 0x73, 0x0A, 0xE8, 0xD4, 0x05, 0x46, 0x68, + 0x25, 0x3D, 0xA2, 0xC4, 0xCC, 0x3A, 0x81, 0x39, 0x55, 0x18, + 0xC3, 0xFD, 0xE2, 0xFE, 0xA9, 0xA3, 0xE5, 0x1F, 0x78, 0x3A, + 0xE8, 0xDF, 0x67, 0xD2, 0x59, 0x68, 0x72, 0x62, 0xBD, 0xAD, + 0x76, 0xE1, 0x03, 0x38, 0xFA, 0xAC, 0x96, 0x3F, 0x0E, 0x32, + 0xB8, 0xE8, 0x9F, 0x13, 0x39, 0x79, 0xDD, 0x9D, 0x72, 0x76, + 0xA8, 0xEA, 0x59, 0xF1, 0x2F, 0x0D, 0x9E, 0xA3, 0xD5, 0x10, + 0xA1, 0xB3, 0x5B, 0xA3, 0x70, 0xF3, 0xB6, 0x93, 0x34, 0x0F, + 0xA0, 0x6B, 0xFC, 0x67, 0xF6, 0x0F, 0x3D, 0xCE, 0x5B, 0x20, + 0xD2, 0x83, 0xAC, 0xBA, 0x61, 0x5C, 0x38, 0xB7, 0x84, 0x87, + 0xC4, 0x2F, 0xA4, 0xE6, 0xC6, 0x91, 0x2A, 0xF9, 0x24, 0x1C, + 0x41, 0x5D, 0xFD, 0x08, 0x1B, 0x5F, 0xBE, 0xE9, 0xEF, 0x45, + 0x00, 0x55, 0x11, 0x0F, 0xA9, 0x35, 0xD2, 0x6A, 0xA0, 0x64, + 0xC2, 0x0F, 0x74, 0xD5, 0x89, 0xAB, 0xF5, 0x47, 0x98, 0x0C, + 0xB1, 0xFD, 0x0C, 0xE1, 0x7D, 0xF7, 0x2D, 0xBF, 0x7B, 0xBE, + 0x84, 0x14, 0xD6, 0x41, 0x2F, 0x8B, 0xEB, 0x02, 0x24, 0xDC, + 0x1A, 0x6A, 0x37, 0xFD, 0x56, 0x06, 0x74, 0xE3, 0xBA, 0x5A, + 0x1F, 0x39, 0xC2, 0x37, 0x0A, 0xF5, 0x80, 0x23, 0x79, 0x54, + 0xBE, 0x73, 0xA8, 0x22, 0xFD, 0xF7, 0xF5, 0x31, 0xB3, 0xF9, + 0x18, 0xA2, 0x15, 0x55, 0xE4, 0x32, 0x2B, 0xE9, 0x3F, 0xCD, + 0x72, 0x07, 0xAD, 0xEF, 0x29, 0x0F, 0xB7, 0xDD, 0x7B, 0xB8, + 0xF0, 0xF6, 0xCC, 0x60, 0x4D, 0x44, 0x23, 0x0F, 0x6F, 0x70, + 0x9E, 0x2E, 0x9F, 0x55, 0xDF, 0x6C, 0x58, 0x8E, 0xDB, 0x82, + 0xCE, 0xDD, 0xE9, 0x15, 0x57, 0x28, 0xA5, 0x00, 0xA4, 0x82, + 0xFA, 0xD9, 0x98, 0x10, 0x00, 0xB7, 0x70, 0x34, 0x72, 0xEE, + 0x3C, 0x75, 0x4D, 0x42, 0x7D, 0xCA, 0x9A, 0x6B, 0xC8, 0x51, + 0x7A, 0x6D, 0xBC, 0x5B, 0xD8, 0x70, 0x95, 0x60, 0x11, 0xF8, + 0xC4, 0x3B, 0x66, 0x13, 0x4A, 0xD2, 0x11, 0xC4, 0xBB, 0xCD, + 0x84, 0xE0, 0x7C, 0x87, 0x8B, 0x50, 0x3F, 0x66, 0x6D, 0xC9, + 0x70, 0x5B, 0x92, 0x59, 0xE7, 0x02, 0x49, 0xB0, 0x91, 0x78, + 0x30, 0xF6, 0x5A, 0x93, 0x5E, 0xEE, 0x82, 0x54, 0x9C, 0xC6, + 0x19, 0xC7, 0x15, 0x2D, 0xFE, 0x98, 0x45, 0xF5, 0xA1, 0xC2, + 0xDE, 0xF1, 0x8A, 0x31, 0x71, 0x8F, 0xBF, 0x78, 0x59, 0x1F, + 0xDC, 0xAD, 0x71, 0xF1, 0xDF, 0x55, 0x70, 0x42, 0x95, 0x67, + 0xD5, 0x8A, 0x29, 0x0A, 0x7E, 0x1B, 0x4E, 0x82, 0xA5, 0xEC, + 0x6E, 0x12, 0x96, 0x7B, 0x2E, 0xB4, 0xEE, 0x73, 0x50, 0x4A, + 0xA9, 0x3F, 0x6A, 0x81, 0x6B, 0xC9, 0x7A, 0x6D, 0xD3, 0x7B, + 0xFF, 0x8B, 0xAE, 0x19, 0x7F, 0xB9, 0x91, 0x81, 0x79, 0x6C, + 0x41, 0x5B, 0x70, 0x46, 0x22, 0x70, 0xAC, 0x8E, 0xF2, 0xA8, + 0x0E, 0x6F, 0xB2, 0x9F, 0x7F, 0x8B, 0x7F, 0x5F, 0x2E, 0x6A, + 0x56, 0x78, 0x51, 0x22, 0xAB, 0x2D, 0x34, 0xC6, 0xBE, 0x57, + 0x97, 0x78, 0x72, 0x55, 0x17, 0x88, 0x82, 0xD9, 0x96, 0xF0, + 0x41, 0x64, 0xE3, 0x21, 0xF2, 0xF7, 0x73, 0x9D, 0xC9, 0x90, + 0xF6, 0x11, 0xB8, 0x0F, 0x1B, 0xE4, 0x07, 0x16, 0x50, 0x39, + 0xBC, 0xAE, 0xF4, 0x9A, 0xC7, 0x44, 0x17, 0x5E, 0xB7, 0xE4, + 0x78, 0xB3, 0x9E, 0x97, 0x34, 0x2C, 0x44, 0x24, 0xF0, 0xBB, + 0x2C, 0x81, 0x5E, 0x04, 0x70, 0x3C, 0xC1, 0xE8, 0x65, 0x63, + 0x4F, 0xDE, 0x8C, 0x8D, 0x43, 0x07, 0x5A, 0xDA, 0xB0, 0x9F, + 0x17, 0xA0, 0x10, 0x28, 0x54, 0xFE, 0xA1, 0x31, 0xEA, 0x61, + 0x92, 0xB9, 0x46, 0x5C, 0x96, 0xC6, 0xA0, 0xE3, 0xA4, 0x96, + 0x12, 0xCF, 0x86, 0x88, 0x4C, 0x3E, 0x17, 0x9B, 0x31, 0x74, + 0x77, 0xBD, 0xA8, 0x9A, 0x4C, 0xB3, 0x51, 0x71, 0x96, 0x35, + 0xC3, 0x4C, 0xA2, 0xA1, 0x20, 0x7B, 0x4A, 0xDC, 0xF3, 0x21, + 0xA6, 0x1F, 0xF5, 0x59, 0xA4, 0x9F, 0x87, 0x7E, 0xAA, 0xB8, + 0x18, 0x3A, 0x35, 0xE8, 0x51, 0x33, 0xBF, 0x87, 0x0D, 0xDC, + 0x2E, 0xC6, 0x6D, 0xB0, 0xDC, 0x38, 0x3F, 0x70, 0x83, 0xDC, + 0x52, 0xDB, 0xAF, 0xDE, 0x6A, 0x8A, 0x74, 0x7A, 0x52, 0xB6, + 0x25, 0x92, 0xFB, 0x69, 0x46, 0x5F, 0x84, 0x38, 0x15, 0x11, + 0xB4, 0x70, 0x2E, 0x1F, 0x15, 0xED, 0xEA, 0xDB, 0x67, 0x4B, + 0x12, 0x41, 0x85, 0x6F, 0x6C, 0x02, 0x13, 0x9A, 0x15, 0x14, + 0x85, 0x2E, 0x1B, 0x3E, 0x2D, 0x6F, 0x3D, 0x45, 0x7B, 0x3D, + 0x28, 0x5D, 0x48, 0xD1, 0xB1, 0x3A, 0x76, 0x89, 0x2C, 0x01, + 0xFF, 0xED, 0xB7, 0x5D, 0x63, 0x67, 0xAB, 0xEA, 0x2F, 0x9C, + 0xBA, 0x6A, 0x3B, 0xF4, 0xF7, 0x3E, 0x1A, 0xC2, 0xA8, 0x00, + 0xE5, 0x45, 0x29, 0x66, 0x8D, 0x49, 0x6F, 0xC7, 0x51, 0x43, + 0x1D, 0x0E, 0x64, 0x49, 0xD4, 0x7F, 0x10, 0x18, 0x54, 0x8B, + 0xCB, 0x07, 0xFB, 0xFC, 0xF4, 0x95, 0x94, 0xAD, 0xDB, 0xCD, + 0x74, 0x6E, 0x5F, 0xC4, 0xD9, 0x73, 0xCB, 0x84, 0x78, 0x31, + 0x24, 0x9E, 0x72, 0x4E, 0x3C, 0x98, 0x1E, 0x29, 0x26, 0xB9, + 0x17, 0x6B, 0x1F, 0x49, 0xD5, 0x69, 0x2F, 0xDA, 0x5D, 0x3F, + 0xCB, 0xE4, 0x83, 0x97, 0x66, 0xCD, 0xE8, 0x91, 0x6F, 0x3C, + 0x7E, 0xEB, 0x85, 0xCC, 0x9B, 0xC0, 0x8C, 0xE0, 0xED, 0x6D, + 0x36, 0x09, 0xC6, 0x2D, 0x53, 0x22, 0x6B, 0x67, 0x7E, 0x4E, + 0x41, 0x03, 0x51, 0x4F, 0x73, 0x4B, 0x56, 0x79, 0xBE, 0x26, + 0x84, 0x41, 0x90, 0x80, 0xB8, 0x95, 0xF3, 0x76, 0x2E, 0x97, + 0xDA, 0x0C, 0x6B, 0x03, 0xE4, 0x87, 0xB9, 0x88, 0xEB, 0x93, + 0x28, 0x26, 0xC2, 0x0A, 0x40, 0x70, 0x19, 0x11, 0xC3, 0xC4, + 0x11, 0xFF, 0x27, 0x42, 0x2D, 0xB6, 0x8F, 0x11, 0x22, 0x53, + 0x7E, 0x33, 0xA8, 0xBF, 0x02, 0x51, 0x63, 0x7E, 0x55, 0x27, + 0xD5, 0x4F, 0x25, 0x8A, 0x0F, 0xC5, 0xFA, 0x34, 0x6A, 0x42, + 0x64, 0x27, 0x89, 0xCF, 0x83, 0x3F, 0x7E, 0x68, 0xBA, 0xC3, + 0xCC, 0x0F, 0x41, 0x43, 0xC2, 0xD0, 0xC5, 0xE2, 0x0C, 0x3B, + 0x04, 0x06, 0x76, 0x21, 0x0E, 0x8B, 0x0F, 0x15, 0x33, 0x26, + 0x8D, 0x51, 0x83, 0xE4, 0xB5, 0xCA, 0x7D, 0x80, 0x15, 0x4D, + 0xC2, 0xD6, 0x1C, 0x96, 0xA2, 0x09, 0xDA, 0xD7, 0x40, 0x04, + 0xF9, 0xB0, 0x2E, 0xC1, 0x07, 0xF7, 0xCE, 0x97, 0xF0, 0xB8, + 0x32, 0x8A, 0xFD, 0xC2, 0xF3, 0x53, 0x8B, 0x75, 0xF9, 0x74, + 0x50, 0x65, 0x86, 0x92, 0x2C, 0x73, 0x38, 0xAB, 0x03, 0xDC, + 0xF8, 0xCC, 0xF9, 0x54, 0x05, 0x48, 0x06, 0x94, 0xD7, 0x19, + 0x92, 0x1D, 0x08, 0x5E, 0xE4, 0x08, 0xC5, 0x95, 0x21, 0x29, + 0x1E, 0xE9, 0xD9, 0x21, 0xBC, 0x49, 0x0B, 0xE0, 0x1A, 0x55, + 0x09, 0x21, 0x8E, 0x46, 0xC0, 0x73, 0x01, 0xBA, 0xCA, 0x3C, + 0xC3, 0x2D, 0x26, 0xD3, 0x7E, 0x2B, 0xED, 0x6D, 0x8A, 0xE2, + 0xD6, 0x07, 0x18, 0xE9, 0x16, 0x1E, 0x0D, 0xD6, 0x8A, 0x80, + 0x24, 0x85, 0x5B, 0xE7, 0x76, 0x95, 0xC6, 0x9C, 0x9E, 0x94, + 0x7C, 0xBD, 0x14, 0xA4, 0xC4, 0x55, 0xEB, 0x7A, 0x27, 0xBE, + 0x5C, 0x98, 0x7D, 0xBF, 0x03, 0x95, 0x74, 0xAF, 0x78, 0x72, + 0x7D, 0xB8, 0xFA, 0x4F, 0x92, 0x02, 0x79, 0x88, 0x03, 0xE3, + 0xAF, 0xD1, 0x71, 0x4D, 0x8F, 0x73, 0x89, 0x2F, 0x5E, 0x1E, + 0x5D, 0xEF, 0x07, 0x9C, 0xCD, 0xA5, 0x47, 0x17, 0xAC, 0xB0, + 0x9F, 0xAB, 0xAB, 0x4A, 0xE7, 0x8F, 0x09, 0x07, 0x8A, 0xFB, + 0x4E, 0x8B, 0x0A, 0xA0, 0xDB, 0x2E, 0x78, 0x55, 0x49, 0x0B, + 0xB0, 0xF9, 0xA1, 0xC2, 0xBA, 0x62, 0xDD, 0x40, 0x9E, 0x96, + 0x34, 0x67, 0xF1, 0x78, 0xAC, 0x1F, 0x38, 0x77, 0x30, 0xD6, + 0x7A, 0xEB, 0xDB, 0x21, 0x4B, 0x5F, 0x90, 0x8A, 0x72, 0xB6, + 0x07, 0x67, 0xDD, 0x1A, 0xC4, 0xDC, 0xD1, 0x81, 0x50, 0xA7, + 0xFD, 0xE6, 0x90, 0x78, 0xD3, 0xB8, 0xA9, 0xF0, 0xBA, 0x0C, + 0x3E, 0x0D, 0xAF, 0xA4, 0xFA, 0xA0, 0xC9, 0x02, 0x55, 0xF9, + 0xFD, 0x3A, 0xD7, 0xC5, 0x7F, 0x5C, 0x7A, 0x25, 0xB6, 0x9B, + 0x1F, 0xD0, 0xE8, 0x0F, 0x57, 0xFE, 0x84, 0x09, 0x49, 0x7E, + 0x87, 0x8A, 0x74, 0x9B, 0x5B, 0x56, 0x53, 0xFE, 0x1B, 0x3A, + 0x89, 0x9F, 0x4B, 0x11, 0xFF, 0xB3, 0x8F, 0x3B, 0x14, 0x69, + 0x08, 0xBF, 0x0D, 0x92, 0x8E, 0x99, 0x4E, 0xF7, 0x60, 0xD2, + 0x9D, 0xBB, 0xF5, 0x5D, 0xA4, 0xEC, 0xB5, 0x9E, 0x82, 0xB5, + 0xD8, 0xCA, 0xB8, 0xC7, 0xA2, 0xE6, 0x1D, 0xAC, 0x22, 0x2E, + 0x47, 0xC1, 0x96, 0x3D, 0x67, 0x7A, 0x53, 0x44, 0x96, 0x06, + 0x83, 0x0E, 0x01, 0x3F, 0x19, 0x1B, 0x56, 0xDE, 0x46, 0x95, + 0x16, 0xE8, 0x2C, 0x3A, 0x6A, 0x6A, 0x33, 0xA3, 0x99, 0x0B, + 0x9C, 0x8E, 0x07, 0x55, 0xE2, 0x14, 0x6A, 0xA3, 0x38, 0xE3, + 0xB3, 0x48, 0xC5, 0xEE, 0x08, 0xE2, 0x68, 0xC6, 0xC5, 0x34, + 0xA5, 0xF0, 0xD8, 0x01, 0x70, 0x39, 0x25, 0x7D, 0x1E, 0xB6, + 0x4C, 0x26, 0xC3, 0x0C, 0x72, 0x3A, 0xCE, 0x66, 0x43, 0x4C, + 0xAA, 0xE3, 0x38, 0x7A, 0x89, 0xC5, 0x0D, 0x23, 0x27, 0x53, + 0x7A, 0xE4, 0xA0, 0xDF, 0xC6, 0x75, 0xD4, 0x8F, 0x00, 0x9B, + 0xEC, 0x27, 0x1E, 0x9B, 0x65, 0x07, 0xE5, 0xED, 0xF4, 0xA9, + 0xE8, 0x39, 0xD7, 0x9B, 0x81, 0xCB, 0x06, 0xD0, 0xA7, 0xE5, + 0x7E, 0xCA, 0x67, 0x59, 0xF3, 0x54, 0x44, 0xB8, 0x99, 0xB3, + 0x8B, 0x82, 0xB7, 0x1E, 0x84, 0xC3, 0x20, 0xC5, 0x43, 0xCF, + 0x75, 0xF3, 0x29, 0x0C, 0x46, 0x44, 0x81, 0x2B, 0x93, 0xC7, + 0x68, 0x23, 0x9C, 0xB1, 0xFB, 0x69, 0x47, 0x05, 0x15, 0xD8, + 0x75, 0xC4, 0x5B, 0x80, 0xA4, 0xA9, 0xA2, 0x45, 0x54, 0xFB, + 0x1C, 0x0E, 0x29, 0xE8, 0x63, 0x43, 0xB5, 0xE3, 0x3D, 0x67, + 0x4B, 0x54, 0x37, 0xA3, 0x1D, 0xEE, 0x92, 0x94, 0x20, 0xC9, + 0xC4, 0xAD, 0xC5, 0x38, 0xCD, 0xB0, 0x19, 0xE1, 0x2A, 0x35, + 0x0F, 0xB5, 0x90, 0x33, 0x65, 0x2A, 0x68, 0x19, 0x8F, 0x81, + 0x25, 0xB0, 0xB5, 0xF1, 0x31, 0xAB, 0xD9, 0x30, 0x84, 0x27, + 0xE3, 0xD1, 0x79, 0x0A, 0x15, 0x13, 0xDB, 0xC7, 0x34, 0x27, + 0x07, 0x3F, 0xD7, 0x12, 0x48, 0x05, 0xF3, 0xC7, 0x18, 0x7B, + 0xDC, 0x14, 0xDC, 0xE2, 0xD7, 0x73, 0xAB, 0x9B, 0x54, 0x7B, + 0xEF, 0xA1, 0x93, 0x23, 0xC3, 0x9E, 0x75, 0x0B, 0x97, 0xC9, + 0x3C, 0x4B, 0x66, 0xD8, 0x47, 0x83, 0x2B, 0xA5, 0xA9, 0xD8, + 0x07, 0x7D, 0x89, 0xBA, 0xFC, 0x48, 0x3A, 0xD9, 0x8B, 0x5F, + 0x83, 0xD6, 0x51, 0x65, 0xE6, 0x18, 0x8A, 0x5E, 0xE1, 0x9F, + 0xDB, 0x58, 0x28, 0xDC, 0x0A, 0x98, 0xBB, 0x3F, 0x34, 0xC0, + 0xF3, 0x33, 0x75, 0xA0, 0xF4, 0xCD, 0xA9, 0xCB, 0x6C, 0xCD, + 0x08, 0x2C, 0xBB, 0xA0, 0x73, 0x84, 0xEB, 0xE1, 0x7D, 0x25, + 0x28, 0x21, 0x61, 0x10, 0x4C, 0x96, 0x05, 0xA2, 0x80, 0xB0, + 0xAE, 0x48, 0xC7, 0xFD, 0x51, 0x52, 0x2F, 0x86, 0x3F, 0x8C, + 0x89, 0xFD, 0xB0, 0x0C, 0x61, 0x54, 0xBA, 0x61, 0x7D, 0x13, + 0x9B, 0xB9, 0x20, 0xB4, 0xF0, 0x99, 0x37, 0x35, 0x04, 0xD3, + 0x01, 0xE3, 0x80, 0xC8, 0x5D, 0x17, 0x0B, 0x7E, 0x62, 0x90, + 0xB9, 0x3F, 0xD2, 0x6B, 0xD0, 0xF0, 0xEA, 0x49, 0xDD, 0xC9, + 0xA0, 0x5B, 0xA9, 0x8A, 0xF6, 0x3C, 0x7D, 0x82, 0x88, 0x17, + 0x91, 0xC1, 0xA5, 0x3F, 0xFF, 0x11, 0x87, 0xD2, 0xFA, 0x57, + 0x91, 0x94, 0x44, 0x82, 0x6C, 0x0E, 0x8F, 0x98, 0x31, 0x8A, + 0x47, 0x58, 0xFA, 0x77, 0xBC, 0x12, 0x97, 0x52, 0x04, 0x1B, + 0x5B, 0x0A, 0xA5, 0xB9, 0x07, 0xDE, 0xCA, 0x06, 0xEA, 0x94, + 0x3F, 0xDF, 0x24, 0x08, 0x4A, 0x98, 0xD7, 0x0C, 0x86, 0xF8, + 0xF2, 0x35, 0xD5, 0x6B, 0xF7, 0xE1, 0x63, 0xE0, 0xC7, 0x0A, + 0x35, 0x24, 0x5E, 0x7B, 0x49, 0x8F, 0x46, 0x8E, 0x52, 0x08, + 0x32, 0xD2, 0x35, 0x31, 0xDB, 0xF6, 0x55, 0xD1, 0xEF, 0x74, + 0x85, 0x93, 0x21, 0xC0, 0x1A, 0xE2, 0x1D, 0xB5, 0x84, 0xB3, + 0x33, 0x51, 0x81, 0x33, 0x85, 0x9A, 0x2C, 0xE7, 0x58, 0x91, + 0xAB, 0x8A, 0xDC, 0x89, 0x28, 0x46, 0x66, 0xA2, 0x02, 0x8F, + 0xB3, 0x4E, 0x52, 0xE8, 0xE3, 0x8F, 0x14, 0x71, 0x4F, 0xF9, + 0x48, 0x10, 0xD1, 0x18, 0xEC, 0x42, 0x44, 0x04, 0x62, 0x47, + 0x62, 0x28, 0x5F, 0xD9, 0x01, 0xD6, 0xEE, 0x4C, 0x21, 0xF5, + 0xED, 0x2F, 0x4E, 0x28, 0xD3, 0x8C, 0x7B, 0x79, 0x59, 0x08, + 0xA7, 0xEC, 0x4D, 0x32, 0x52, 0xC3, 0x33, 0x7E, 0xF4, 0x00, + 0xD6, 0x21, 0xFB, 0x45, 0xD6, 0x7B, 0x91, 0x1D, 0x09, 0xEE, + 0x9B, 0xA7, 0x6D, 0x08, 0x76, 0x7E, 0x13, 0xF9, 0x7D, 0x59, + 0xC7, 0xA0, 0x82, 0x57, 0x8B, 0x88, 0xE3, 0x2F, 0xC1, 0x6F, + 0x36, 0x2B, 0xD2, 0x11, 0x77, 0xB0, 0x99, 0x56, 0xBF, 0xBB, + 0x8C, 0x77, 0x06, 0xAD, 0xE9, 0x78, 0xB5, 0x01, 0xDA, 0xC6, + 0x09, 0x33, 0x48, 0xD4, 0x5C, 0xAF, 0xE0, 0x24, 0x43, 0x55, + 0xBA, 0x64, 0x61, 0xB8, 0x50, 0x25, 0xDD, 0x45, 0x9A, 0x48, + 0xB5, 0xC7, 0xAC, 0xC6, 0x31, 0x0F, 0x27, 0x6B, 0x8A, 0x18, + 0x53, 0xDD, 0x67, 0xEF, 0x82, 0xCD, 0x23, 0xB3, 0xF4, 0x38, + 0x40, 0xF8, 0x05, 0xE5, 0xCD, 0x70, 0xD5, 0xFA, 0x04, 0x68, + 0xFF, 0xDC, 0x88, 0x88, 0x11, 0x34, 0xBC, 0x9E, 0x50, 0x64, + 0x2F, 0xAA, 0xE7, 0x64, 0x49, 0xA0, 0xE8, 0x2F, 0xD5, 0xF3, + 0x70, 0x06, 0x0E, 0x82, 0x92, 0x33, 0xBA, 0x69, 0xD5, 0x15, + 0xF2, 0x2F, 0x5A, 0x4C, 0x58, 0xBE, 0x51, 0xFD, 0x69, 0xA5, + 0x93, 0xA0, 0x94, 0x54, 0x1F, 0xC5, 0x60, 0xA7, 0xBA, 0x69, + 0xE8, 0x80, 0x84, 0xA9, 0x1A, 0x5F, 0x02, 0xCB, 0x4A, 0x67, + 0xB5, 0x02, 0xA9, 0x21, 0x76, 0x99, 0x1F, 0xE5, 0x21, 0x2A, + 0xA6, 0xA2, 0x40, 0x02, 0x53, 0x91, 0xAC, 0x2B, 0x19, 0x15, + 0xE4, 0xDB, 0x97, 0x1E, 0xF3, 0x82, 0xBA, 0xF9, 0x56, 0x6D, + 0x94, 0xD0, 0x98, 0xB9, 0x83, 0xBB, 0x98, 0x9B, 0x69, 0xCA, + 0x39, 0xF4, 0x1D, 0x06, 0x1B, 0x7E, 0xF8, 0x3D, 0x21, 0xC6, + 0xCA, 0xAE, 0xA5, 0x94, 0x21, 0xE2, 0xCD, 0x6C, 0xD6, 0x55, + 0xB9, 0x77, 0x2D, 0xA3, 0x79, 0x0C, 0x03, 0x2F, 0x33, 0xCB, + 0x53, 0x90, 0xFE, 0xE3, 0x9C, 0x90, 0xCC, 0x50, 0x86, 0xF4, + 0x87, 0xEE, 0x1C, 0x2C, 0x3D, 0x53, 0xE7, 0xEE, 0xED, 0x73, + 0x73, 0x2E, 0xDD, 0xA9, 0x69, 0xFF, 0x76, 0x35, 0x89, 0x68, + 0xEA, 0x32, 0x4E, 0xC7, 0x03, 0x5A, 0x1E, 0x5E, 0xB8, 0x67, + 0x8A, 0x40, 0xCA, 0x34, 0x7B, 0x52, 0xDC, 0x3F, 0x1E, 0x52, + 0x03, 0xE9, 0xC7, 0x7F, 0x51, 0xAC, 0x01, 0x74, 0x36, 0xEB, + 0xAD, 0xC0, 0x07, 0x4D, 0xD4, 0x0E, 0x39, 0x14, 0x63, 0x09, + 0x7B, 0x7A, 0x04, 0xD5, 0x8A, 0xB8, 0x9C, 0x1F, 0x86, 0xF0, + 0xC3, 0x20, 0xFF, 0x95, 0x80, 0x4A, 0xE9, 0x9D, 0x7B, 0x7A, + 0x30, 0xD1, 0x9B, 0xF7, 0x5A, 0x31, 0x2F, 0xD0, 0xB6, 0xA1, + 0x4D, 0x4F, 0x4F, 0xEC, 0xA3, 0xD2, 0x94, 0x52, 0xAF, 0x2A, + 0xCF, 0xB1, 0x49, 0x45, 0x24, 0xE2, 0x54, 0xD8, 0xE6, 0x65, + 0x76, 0xD5, 0xD0, 0xC3, 0x73, 0xF3, 0x6C, 0x4A, 0xFA, 0x56, + 0x4C, 0x7A, 0x62, 0x80, 0x67, 0xC6, 0xDC, 0xFF, 0xDC, 0xA2, + 0x4B, 0xF7, 0xA8, 0x92, 0xE9, 0x07, 0x70, 0xD6, 0x55, 0x08, + 0xEB, 0x6F, 0x5C, 0xF7, 0x8D, 0xE1, 0xAA, 0xA4, 0xA5, 0x3E, + 0xB5, 0xB8, 0x30, 0x0D, 0x8A, 0x68, 0x06, 0x6B, 0x3F, 0x1E, + 0xEA, 0x1A, 0xF1, 0x6D, 0x97, 0xF5, 0x9D, 0xB2, 0x2A, 0x44, + 0x6D, 0xA3, 0x7D, 0x7A, 0xC6, 0xCD, 0x1F, 0xF3, 0xC3, 0xBE, + 0x53, 0x98, 0xF3, 0xDA, 0x5F, 0xDC, 0xB9, 0xEB, 0x53, 0x8B, + 0x8D, 0x04, 0x1C, 0x91, 0x7B, 0xD5, 0x43, 0x59, 0xB7, 0x5E, + 0x66, 0xF9, 0xB0, 0x8D, 0x53, 0xED, 0x09, 0x0A, 0xD8, 0x5D, + 0xE6, 0x07, 0xC1, 0xAC, 0xB6, 0x44, 0x99, 0xAB, 0xC5, 0xAB, + 0xA1, 0x17, 0xAE, 0x15, 0x2C, 0x33, 0x18, 0x48, 0x4C, 0x74, + 0xB9, 0xDE, 0xCA, 0x14, 0xAB, 0x1F, 0x10, 0x2B, 0x5B, 0x45, + 0x49, 0xF6, 0x6E, 0xFA, 0x01, 0x11, 0xBC, 0xCC, 0x4A, 0xF8, + 0x3E, 0xFA, 0x32, 0x72, 0x70, 0x80, 0x22, 0x88, 0xCD, 0x46, + 0x53, 0x31, 0xD7, 0xEF, 0x92, 0x32, 0x99, 0x7A, 0xF2, 0xA9, + 0xFC, 0x84, 0x91, 0x84, 0xB3, 0x1E, 0x1E, 0xB3, 0x5C, 0x38, + 0x2E, 0x93, 0x2A, 0x52, 0x3A, 0xD1, 0x24, 0x3F, 0xCB, 0x2C, + 0xFE, 0x2D, 0x5E, 0x2D, 0xA7, 0xE0, 0x91, 0x68, 0x3A, 0x99, + 0x4D, 0x91, 0xDB, 0x89, 0xAF, 0xA0, 0x4F, 0x9C, 0x6E, 0x3A, + 0xB8, 0xEB, 0x16, 0x7C, 0xD2, 0xCD, 0xEA, 0x11, 0x2B, 0x50, + 0xFB, 0x42, 0xC4, 0xCE, 0xAA, 0x1E, 0x14, 0xAD, 0x47, 0x70, + 0xA9, 0x9A, 0x9A, 0x7E, 0xE2, 0xED, 0xA5, 0x43, 0x94, 0xE6, + 0xEA, 0x9D, 0x3B, 0xDA, 0x91, 0xA3, 0xC2, 0x72, 0x42, 0xF5, + 0x11, 0x5B, 0x50, 0x2A, 0x95, 0x37, 0xFC, 0x94, 0xF2, 0xCD, + 0xB5, 0x77, 0xBB, 0xB6, 0xAD, 0xA6, 0x0F, 0xFE, 0xAE, 0x6A, + 0x0C, 0xC8, 0x2D, 0x4F, 0x1D, 0xE8, 0x7F, 0x36, 0x88, 0xF9, + 0x36, 0xD6, 0xD1, 0x0D, 0x3C, 0x4E, 0x58, 0x02, 0x75, 0x46, + 0xAB, 0xAB, 0xE8, 0xF8, 0x07, 0x17, 0x35, 0xC1, 0x9C, 0x6F, + 0x24, 0x14, 0xD9, 0xD6, 0x01, 0x4A, 0xF7, 0x38, 0x28, 0xAF, + 0xDF, 0x2A, 0x59, 0x99, 0xC6, 0x56, 0xCD, 0x36, 0xE4, 0x98, + 0x2E, 0x20, 0x6A, 0x75, 0xFD, 0x36, 0xE6, 0xC1, 0xB9, 0x76, + 0x93, 0xCD, 0x2B, 0x57, 0x93, 0x8C, 0xEF, 0xA1, 0x98, 0xFA, + 0x3E, 0x64, 0x76, 0xC6, 0x41, 0x7C, 0x8E, 0x0D, 0x59, 0xAF, + 0xAE, 0x64, 0x8A, 0x8C, 0x6F, 0x0D, 0x68, 0x54, 0x59, 0xFC, + 0x21, 0xA9, 0x51, 0x22, 0x2A, 0x61, 0x92, 0xCD, 0x3E, 0x2F, + 0x2D, 0x52, 0x4D, 0x87, 0x58, 0xDB, 0x61, 0x74, 0x6C, 0xEC, + 0xA7, 0x7B, 0xDE, 0x7F, 0x17, 0x8B, 0x0A, 0xC9, 0xC0, 0xA9, + 0xF3, 0x99, 0x5C, 0x83, 0x57, 0x23, 0xE6, 0xE9, 0xC6, 0x9A, + 0xF9, 0x29, 0x77, 0xF0, 0x7B, 0x73, 0xB4, 0x55, 0xC8, 0xDB, + 0xCF, 0xF0, 0x1A, 0x23, 0xFF, 0xF3, 0x5B, 0xFE, 0xAE, 0xEE, + 0x6D, 0xF9, 0xED, 0x6B, 0x5F, 0x6E, 0x96, 0x0D, 0x33, 0xAD, + 0x92, 0x2D, 0x36, 0x20, 0x21, 0xE1, 0x79, 0xDF, 0x3E, 0x90, + 0xF9, 0x96, 0x1D, 0x89, 0x35, 0xE5, 0xFF, 0xC6, 0xC7, 0x7F, + 0x58, 0xF8, 0x3B, 0xAB, 0x03, 0x84, 0xE3, 0xD7, 0x09, 0xDC, + 0x13, 0xC6, 0xE0, 0xD0, 0x17, 0x9D, 0xA3, 0x6C, 0xF3, 0x02, + 0x23, 0x23, 0x22, 0x29, 0x50, 0xB0, 0x51, 0x76, 0x8F, 0xFE, + 0x1A, 0xEC, 0x6E, 0x66, 0x8F, 0x4F, 0x7C, 0xAE, 0x73, 0xF9, + 0x74, 0x57, 0xDD, 0x65, 0x8B, 0xCE, 0x62, 0x04, 0xBB, 0x4E, + 0x20, 0xC5, 0x56, 0x20, 0x3D, 0x6A, 0xB5, 0xF2, 0xAC, 0x35, + 0x2C, 0x76, 0x33, 0xC0, 0xA6, 0x3F, 0x8C, 0x81, 0x61, 0x8C, + 0x36, 0xAE, 0x0E, 0x90, 0x6F, 0xB8, 0x52, 0x8D, 0x81, 0x83, + 0x76, 0x5F, 0xAD, 0x17, 0xBF, 0x79, 0x3B, 0x3D, 0x1A, 0x4E, + 0x49, 0x48, 0xFF, 0xB0, 0x5F, 0x6C, 0xAB, 0xFA, 0x7C, 0x22, + 0xB5, 0xE4, 0xC2, 0x4C, 0x5C, 0x8B, 0x84, 0x0E, 0x6E, 0x55, + 0x84, 0xBB, 0x71, 0x88, 0x21, 0xDE, 0x68, 0x45, 0xB3, 0x7A, + 0x80, 0xF3, 0x50, 0x8A, 0x3E, 0xB6, 0x23, 0xD5, 0x65, 0x58, + 0xA1, 0xB5, 0xB2, 0x81, 0x0D, 0xCD, 0x40, 0xA6, 0xF0, 0xA9, + 0xA7, 0x76, 0xC8, 0x70, 0x5D, 0x15, 0x7E, 0xBE, 0x56, 0xB3, + 0x0A, 0xF5, 0x1B, 0x19, 0x58, 0x6D, 0x0D, 0xA1, 0x5E, 0xAA, + 0x98, 0x31, 0x9F, 0xC3, 0xFB, 0xFD, 0x67, 0xA2, 0xA8, 0x56, + 0xEC, 0xD6, 0xEA, 0x99, 0x37, 0x0D, 0xB6, 0x87, 0xD8, 0x1E, + 0x0C, 0x5C, 0x9F, 0xD6, 0x28, 0xEB, 0xAF, 0x5A, 0x35, 0x4A, + 0xFA, 0xAC, 0x8C, 0x8B, 0x05, 0x0F, 0x64, 0x7B, 0x1C, 0x32, + 0x0D, 0x3E, 0x8C, 0x7B, 0x41, 0x4B, 0x5C, 0x03, 0x32, 0x30, + 0x07, 0x42, 0xBD, 0x4E, 0x74, 0x36, 0xA8, 0xE5, 0x09, 0xF9, + 0x34, 0xCD, 0xF9, 0x79, 0x8D, 0xB0, 0x48, 0xC6, 0x63, 0x08, + 0x8B, 0x49, 0xAE, 0x8B, 0xBE, 0x94, 0x20, 0x99, 0x22, 0x57, + 0xCE, 0xA9, 0xB0, 0xCC, 0xDA, 0x34, 0x00, 0x31, 0x10, 0xA0, + 0xF6, 0x62, 0xEE, 0x90, 0xF8, 0x6B, 0x03, 0xA9, 0x09, 0x72, + 0x60, 0x81, 0x6B, 0x03, 0x55, 0xEC, 0xC0, 0x69, 0x06, 0x34, + 0xD0, 0x8E, 0x88, 0xD9, 0xAE, 0xA7, 0xDF, 0x10, 0x6E, 0xD0, + 0x77, 0x74, 0x23, 0xE3, 0x14, 0xFC, 0x42, 0x24, 0xD9, 0x4B, + 0x02, 0x9D, 0xE8, 0x03, 0x6E, 0xB6, 0x95, 0xE5, 0x31, 0xE6, + 0x3A, 0x3D, 0x37, 0xE3, 0xC3, 0x6E, 0x8D, 0xFF, 0x8E, 0xC3, + 0x2A, 0x35, 0x57, 0x75, 0x3A, 0x03, 0x92, 0x8C, 0x18, 0xEB, + 0xB9, 0xE6, 0xC7, 0xD5, 0x30, 0xBB, 0x72, 0xC0, 0xC7, 0xE2, + 0xC9, 0x6D, 0x8B, 0x71, 0xCE, 0x47, 0x65, 0x8F, 0x33, 0x7D, + 0x4C, 0x5D, 0x60, 0xD9, 0x2E, 0xD0, 0x6B, 0xBD, 0xD9, 0xAE, + 0xA7, 0x60, 0x04, 0x24, 0x46, 0xCF, 0x23, 0x6B, 0x5E, 0x1E, + 0x29, 0x52, 0x12, 0x05, 0xCC, 0x3D, 0xC2, 0x9F, 0x2F, 0x3B, + 0x85, 0xC7, 0x99, 0xA2, 0x90, 0x7A, 0x49, 0xB4, 0x72, 0x92, + 0xD9, 0xB7, 0x60, 0xEC, 0xF0, 0x9C, 0x3B, 0x52, 0x3D, 0x9E, + 0xD5, 0x79, 0xC6, 0x27, 0xF1, 0x3F, 0xB9, 0x23, 0xBD, 0xFB, + 0x9F, 0x67, 0x2B, 0x87, 0x2C, 0xFE, 0xE6, 0xF5, 0xF9, 0x67, + 0x5C, 0x02, 0xA1, 0xB8, 0x5B, 0x31, 0xEA, 0x05, 0xC5, 0x42, + 0x3D, 0x32, 0x34, 0x66, 0x89, 0xCE, 0x47, 0x5B, 0x0D, 0xC0, + 0x32, 0xF3, 0xFA, 0x82, 0x73, 0xA7, 0x7F, 0x5C, 0x0F, 0x9A, + 0xAF, 0x1B, 0xB6, 0x00, 0x36, 0x36, 0xC2, 0x2B, 0x2A, 0x82, + 0xCB, 0x0D, 0x76, 0xC9, 0x5F, 0xB2, 0xC6, 0xC8, 0x35, 0x13, + 0x07, 0xAD, 0x9A, 0x76, 0x3C, 0x79, 0x58, 0x86, 0xF6, 0xB3, + 0xBA, 0xC0, 0x28, 0x86, 0xCE, 0x83, 0x80, 0x95, 0xB8, 0x11, + 0x7D, 0x4A, 0x27, 0x44, 0x64, 0xEE, 0x32, 0x42, 0xDA, 0x45, + 0x7A, 0xAD, 0x7F, 0x96, 0xCB, 0x93, 0x27, 0x1C, 0x1D, 0x3F, + 0x46, 0xAA, 0x9A, 0x33, 0xF8, 0x06, 0xD6, 0x19, 0x0A, 0x2C, + 0xF8, 0x4E, 0xC7, 0x6F, 0xA6, 0xD5, 0x5F, 0x24, 0x3F, 0xAB, + 0x1C, 0x2D, 0xE5, 0x0F, 0x5E, 0xFF, 0x50, 0x07, 0xF8, 0x27, + 0x7B, 0x47, 0x37, 0x53, 0xC9, 0xBC, 0xF1, 0x42, 0xA7, 0x48, + 0xEE, 0xC5, 0x0F, 0xC2, 0xEB, 0xF5, 0xE9, 0xD6, 0x74, 0xCC, + 0x8E, 0x52, 0x3C, 0x3B, 0xC2, 0xDC, 0x2B, 0xC3, 0x0F, 0x71, + 0x9E, 0x2A, 0xAC, 0xD1, 0x71, 0xF3, 0x7F, 0x70, 0xB0, 0x03, + 0x7F, 0x65, 0xEE, 0x2A, 0xE6, 0xB1, 0xC2, 0x30, 0x85, 0x23, + 0xBE, 0x1F, 0x70, 0xE8, 0xAE, 0x2B, 0x38, 0x69, 0xCF, 0x4A, + 0x0D, 0xAE, 0x54, 0xD0, 0xAC, 0x50, 0x5B, 0x36, 0x2E, 0x3C, + 0x6A, 0xAC, 0x44, 0xE8, 0x21, 0xBC, 0xEC, 0x92, 0xFB, 0xFC, + 0x3C, 0x99, 0x61, 0x2F, 0xEA, 0x5E, 0xBF, 0x9F, 0x9D, 0x3F, + 0xF3, 0x06, 0x95, 0x42, 0x9D, 0x19, 0xA8, 0xC1, 0x50, 0x05, + 0x5F, 0xB8, 0x87, 0xEB, 0xB2, 0xF0, 0xB0, 0x20, 0x30, 0xEB, + 0x21, 0xCC, 0xA4, 0xFE, 0xB5, 0x4F, 0x02, 0x80, 0x72, 0x18, + 0x74, 0x9B, 0x45, 0x3E, 0xC4, 0x0F, 0x3E, 0x12, 0xC4, 0x1F, + 0x6E, 0xA0, 0x62, 0x66, 0xF8, 0x21, 0x54, 0x05, 0xB3, 0xB2, + 0x0B, 0x6D, 0x6B, 0x5C, 0x82, 0x38, 0x4E, 0x8B, 0xBD, 0xB3, + 0xC2, 0x65, 0x5D, 0xCE, 0x15, 0x9D, 0x97, 0x92, 0x6D, 0x60, + 0x2E, 0x81, 0x2F, 0xF2, 0x05, 0xCC, 0xD6, 0xDF, 0x5D, 0x8E, + 0x08, 0x6B, 0xFB, 0x42, 0x34, 0x04, 0x79, 0x25, 0xC1, 0xF5, + 0x50, 0x39, 0x67, 0xBE, 0xF0, 0xD7, 0x79, 0x1B, 0xF7, 0x68, + 0xC9, 0xA3, 0xDC, 0xF1, 0x73, 0x4D, 0xD6, 0xD6, 0x9A, 0x6C, + 0x26, 0x95, 0x5F, 0xAE, 0x47, 0xC3, 0x55, 0x2D, 0xDC, 0x7F, + 0xD5, 0xE5, 0x3C, 0x15, 0x12, 0xF2, 0xDF, 0x2D, 0xB7, 0xD8, + 0x0E, 0x20, 0x9D, 0x84, 0x9C, 0x54, 0x9C, 0xE5, 0x19, 0xF5, + 0x89, 0x16, 0xF1, 0xC5, 0x3F, 0xA7, 0x02, 0x91, 0x7D, 0xAE, + 0x71, 0x36, 0xB6, 0x97, 0x06, 0x29, 0x03, 0x24, 0xF1, 0x44, + 0xF8, 0x9B, 0x20, 0x74, 0x30, 0x3D, 0x16, 0x52, 0x9D, 0x5D, + 0x85, 0x4E, 0xC5, 0x42, 0x20, 0x53, 0xDF, 0x31, 0xAA, 0x09, + 0x1D, 0xF2, 0xEF, 0xE4, 0x4C, 0x10, 0xD1, 0x6A, 0x5E, 0x40, + 0x1E, 0xD0, 0xE7, 0xC2, 0x65, 0x6C, 0xFA, 0xD3, 0x53, 0xBA, + 0xAB, 0x43, 0x39, 0xE1, 0x6F, 0x5C, 0x8B, 0x9F, 0x46, 0xCE, + 0x51, 0x69, 0xF3, 0xDB, 0x72, 0xA1, 0x74, 0x83, 0xEF, 0xE5, + 0x43, 0x1B, 0x90, 0xE7, 0x8F, 0x8E, 0x21, 0xDD, 0xD0, 0x3B, + 0x86, 0xE4, 0x69, 0xB7, 0x3B, 0x6C, 0x8B, 0x84, 0x7D, 0x18, + 0x8C, 0x87, 0xA4, 0xFE, 0xA6, 0x67, 0x1F, 0xFD, 0x77, 0xA8, + 0x4B, 0xC8, 0x77, 0x33, 0x3C, 0xE1, 0x40, 0x2A, 0xB4, 0xA8, + 0x96, 0xE7, 0x57, 0xFE, 0x5C, 0x11, 0x3B, 0xFA, 0xFD, 0x6D, + 0xD2, 0xB8, 0x86, 0xA4, 0xB0, 0xEB, 0xC5, 0x57, 0x0D, 0xCA, + 0x13, 0x85, 0x1C, 0x1B, 0x21, 0x81, 0xCE, 0x5C, 0x96, 0x11, + 0xBE, 0x53, 0xB8, 0xBD, 0x5A, 0xD3, 0x4A, 0x01, 0x21, 0x63, + 0x0A, 0xB1, 0x56, 0xE0, 0x74, 0x9E, 0x17, 0xC2, 0xF3, 0xF6, + 0x9F, 0x7F, 0x6A, 0x2C, 0x18, 0x75, 0xC5, 0xBF, 0x94, 0x4C, + 0xC6, 0x34, 0x7C, 0x5F, 0x47, 0xE9, 0xA5, 0x06, 0xB4, 0x8C, + 0x52, 0x67, 0xC5, 0xED, 0xB4, 0x70, 0x9C, 0x43, 0xE7, 0x00, + 0xD3, 0x34, 0xB9, 0x2B, 0x96, 0x2C, 0x9E, 0xC6, 0x90, 0xEA, + 0x20, 0x10, 0xA8, 0x35, 0xE8, 0xB1, 0xE8, 0xA4, 0x53, 0x1F, + 0xCF, 0xE1, 0x4C, 0x9E, 0xD2, 0x18, 0x0D, 0x5F, 0x07, 0x5E, + 0x9E, 0x69, 0xE9, 0x9D, 0x0E, 0x9A, 0xED, 0x6F, 0xAB, 0xFF, + 0x42, 0x28, 0x12, 0xC1, 0xA7, 0x34, 0x97, 0x6A, 0xED, 0x7B, + 0x31, 0xEB, 0x97, 0xBE, 0x91, 0x64, 0xD3, 0x58, 0xFC, 0x99, + 0x2A, 0xB4, 0x93, 0x12, 0x23, 0xF2, 0x06, 0xE6, 0x79, 0x60, + 0xED, 0xF2, 0x68, 0xF4, 0x61, 0x86, 0x8D, 0x27, 0x82, 0xBE, + 0x1B, 0xB9, 0xF3, 0xF1, 0x1E, 0xE5, 0xB0, 0xE2, 0x15, 0xF1, + 0x28, 0xF8, 0x6F, 0xD9, 0x00, 0x10, 0xC0, 0xF4, 0x40, 0xE8, + 0x58, 0x6F, 0x2C, 0x8C, 0x86, 0xDB, 0x31, 0xBB, 0x73, 0x5D, + 0x7A, 0xD1, 0x82, 0xC7, 0xEE, 0xDB, 0x90, 0xF8, 0x62, 0x5B, + 0x05, 0x1C, 0x8F, 0x18, 0x6A, 0x89, 0x26, 0x4F, 0x4F, 0x24, + 0x93, 0x10, 0xDB, 0x43, 0xB4, 0x89, 0xAA, 0x25, 0x83, 0x73, + 0xD4, 0xBA, 0x0C, 0xA3, 0x90, 0x9A, 0x4F, 0x69, 0xB0, 0x67, + 0xD4, 0xB6, 0x83, 0xF8, 0x4B, 0x62, 0x2F, 0xBF, 0xD8, 0x40, + 0x1C, 0x9E, 0xFC, 0xA6, 0x56, 0x79, 0x9B, 0xEC, 0x96, 0xC6, + 0x01, 0x51, 0xD2, 0x61, 0x39, 0x8D, 0xED, 0x04, 0xEC, 0x54, + 0xE0, 0x30, 0x0B, 0x53, 0x96, 0x88, 0x52, 0x0D, 0x5F, 0x58, + 0x59, 0x05, 0x7A, 0x92, 0x2A, 0x6A, 0xE0, 0x7F, 0x71, 0xA4, + 0x80, 0xA7, 0xA5, 0x76, 0x28, 0x95, 0x1F, 0x67, 0x3D, 0xB1, + 0x38, 0x5B, 0x03, 0xB9, 0x10, 0xA3, 0x4C, 0x5D, 0x39, 0x9C, + 0x02, 0x12, 0x30, 0xE4, 0x2A, 0x27, 0x01, 0x2C, 0xAF, 0xBE, + 0x22, 0xD2, 0x44, 0x5C, 0x1D, 0x7F, 0x00, 0x9C, 0xA7, 0xB2, + 0x48, 0xD1, 0x63, 0xFD, 0x6B, 0x60, 0x4E, 0x70, 0xA4, 0x86, + 0xED, 0xD5, 0xC5, 0x7B, 0xDA, 0x14, 0xFE, 0x37, 0xD5, 0x73, + 0x04, 0x6D, 0x4F, 0xAA, 0xA2, 0x45, 0x2C, 0x1E, 0x01, 0x77, + 0xC4, 0xF6, 0xA8, 0xA9, 0x19, 0x7A, 0x25, 0xFD, 0x1D, 0xAC, + 0x46, 0x18, 0xCB, 0x9C, 0xF6, 0x18, 0xF1, 0x67, 0xDC, 0xDB, + 0xB1, 0xD7, 0x91, 0x64, 0x73, 0x17, 0x84, 0xCF, 0xD2, 0xE0, + 0x4E, 0xEA, 0x8B, 0xCA, 0x9E, 0xE3, 0xA1, 0x8B, 0xD4, 0x18, + 0x2F, 0x85, 0xCF, 0x7D, 0x4F, 0x87, 0xE4, 0x3B, 0x73, 0x71, + 0xE1, 0xEF, 0x3C, 0x6F, 0xD0, 0x31, 0x87, 0x98, 0xEC, 0xCE, + 0x89, 0xE7, 0x08, 0x62, 0xF1, 0x7E, 0xD8, 0xA0, 0xF7, 0xD2, + 0x31, 0xB4, 0x39, 0x57, 0x4E, 0x3B, 0xDE, 0xCC, 0x71, 0xE0, + 0x9E, 0x68, 0x80, 0x28, 0x56, 0xA8, 0xA8, 0x27, 0x75, 0x18, + 0x73, 0xE3, 0xDB, 0x9A, 0x35, 0x63, 0x2E, 0x9A, 0x4C, 0x29, + 0x42, 0x2F, 0xA8, 0xD4, 0x03, 0x6E, 0x58, 0x4E, 0x8C, 0xF8, + 0xEE, 0x59, 0xF3, 0xF5, 0x2F, 0x70, 0x4D, 0x7D, 0x13, 0xAE, + 0x2B, 0xC4, 0xCE, 0x13, 0x73, 0x57, 0xA0, 0xE8, 0x06, 0xA5, + 0x8C, 0xFA, 0xAB, 0x15, 0x51, 0x93, 0xAF, 0x2E, 0x11, 0x75, + 0x2D, 0x6F, 0xD3, 0xC6, 0x04, 0x37, 0xC8, 0x9E, 0x8C, 0xD1, + 0xC7, 0xBE, 0x60, 0x3F, 0x67, 0x8A, 0x44, 0xBC, 0x44, 0x79, + 0xC8, 0x65, 0x8F, 0x50, 0xB6, 0x23, 0x14, 0x93, 0x96, 0x8B, + 0x99, 0xA6, 0x25, 0x10, 0x76, 0x5C, 0x3D, 0x67, 0xD1, 0x10, + 0xBD, 0xC8, 0x72, 0xD5, 0xAC, 0xE4, 0xFD, 0x5C, 0x2C, 0x4E, + 0x3E, 0xB1, 0x74, 0x36, 0x8A, 0x30, 0x28, 0xE1, 0x83, 0x84, + 0xEF, 0x3F, 0x24, 0xC5, 0xC9, 0x92, 0x4D, 0x54, 0x22, 0x42, + 0x7A, 0xF8, 0x8A, 0x74, 0x07, 0x51, 0x52, 0x81, 0x24, 0xFC, + 0xAE, 0xAF, 0x50, 0x86, 0x3C, 0x42, 0x38, 0x88, 0x15, 0x04, + 0xD7, 0xC9, 0x50, 0x5B, 0xB5, 0x1B, 0x13, 0xEB, 0x74, 0x31, + 0x41, 0xCB, 0xE5, 0x29, 0x4C, 0xFA, 0x32, 0x62, 0x6C, 0xB1, + 0xCA, 0x1B, 0x79, 0x9C, 0x89, 0x5B, 0xD5, 0x41, 0x46, 0xFC, + 0x07, 0x41, 0xD7, 0x3C, 0xFA, 0x86, 0xC0, 0xD8, 0x10, 0xFF, + 0x5A, 0x0D, 0x36, 0xFA, 0xE4, 0x97, 0x7F, 0xB8, 0x31, 0x0F, + 0xA3, 0xBB, 0x1F, 0x49, 0x97, 0xBC, 0x26, 0xD8, 0x76, 0xDE, + 0xD0, 0x9B, 0xA5, 0xBD, 0x1E, 0x1A, 0x06, 0x50, 0x4A, 0x44, + 0xB8, 0xB4, 0x9D, 0x53, 0xD5, 0xFD, 0x56, 0x4F, 0x81, 0x0E, + 0x4A, 0x01, 0x7F, 0x9E, 0x4D, 0x7E, 0xD3, 0x3C, 0x8E, 0x95, + 0xED, 0x5F, 0x4C, 0x06, 0x1B, 0x78, 0xE7, 0x3D, 0xF5, 0x28, + 0x78, 0x49, 0x05, 0x0F, 0x48, 0x0D, 0xFA, 0x11, 0x0A, 0x27, + 0x28, 0x3F, 0xB4, 0x42, 0xFD, 0x77, 0x84, 0x0F, 0x74, 0xED, + 0xFB, 0x5C, 0xBF, 0xD1, 0x21, 0x0F, 0x41, 0x81, 0xA2, 0x3D, + 0x6E, 0x8B, 0xF0, 0x9D, 0xEF, 0x27, 0x95, 0x9B, 0x91, 0x11, + 0xBB, 0x69, 0x47, 0xFA, 0x70, 0x04, 0xB2, 0xE9, 0x4C, 0x91, + 0x5B, 0xA7, 0xF9, 0x20, 0x99, 0xC6, 0x69, 0xD7, 0x96, 0x36, + 0x68, 0x15, 0x1A, 0x82, 0x8B, 0x00, 0x9D, 0x00, 0xAC, 0xE9, + 0xB5, 0x64, 0x23, 0xA4, 0x67, 0xFE, 0xD4, 0xC4, 0xB0, 0x6C, + 0xE4, 0x26, 0x05, 0xFE, 0x6C, 0xD6, 0x52, 0xAE, 0x72, 0xE9, + 0x7C, 0xA9, 0x12, 0xFE, 0xD8, 0x0E, 0x09, 0xBC, 0xED, 0x5D, + 0x23, 0xF3, 0xA3, 0x20, 0xEB, 0xD7, 0xB3, 0x35, 0x90, 0x2F, + 0xFB, 0x63, 0x52, 0xBB, 0x43, 0xF3, 0x0F, 0xBD, 0x2F, 0xD7, + 0xEB, 0x4B, 0x31, 0x73, 0x2E, 0x95, 0x20, 0x25, 0xA5, 0x5E, + 0x56, 0x02, 0x38, 0xDD, 0x65, 0xBD, 0xE0, 0x56, 0xE8, 0x06, + 0x3D, 0xCA, 0x6A, 0x23, 0xFE, 0x27, 0x4B, 0x83, 0x5D, 0xA1, + 0xD5, 0xD7, 0x4B, 0xFD, 0x75, 0x5A, 0x7E, 0xB6, 0x3E, 0xA7, + 0xC5, 0x8F, 0x4C, 0xE0, 0xA7, 0xC7, 0x06, 0x75, 0x59, 0x62, + 0x48, 0x9E, 0xDA, 0x94, 0x07, 0xA8, 0x79, 0xCF, 0xF8, 0x31, + 0x36, 0x9C, 0xB8, 0x88, 0x31, 0x5C, 0xCB, 0x42, 0x47, 0x09, + 0xC2, 0x50, 0x59, 0x9A, 0x87, 0xA2, 0x6A, 0x3E, 0xE1, 0x71, + 0x71, 0x0C, 0x45, 0x07, 0xF7, 0xCE, 0xAB, 0x53, 0xA2, 0x14, + 0x11, 0x0E, 0xF5, 0x0F, 0xFD, 0x3D, 0xD2, 0xAE, 0xA7, 0xB4, + 0xD5, 0x3A, 0x03, 0xB3, 0xA7, 0xC5, 0x3D, 0x23, 0x7E, 0x95, + 0xCE, 0xDD, 0x26, 0x00, 0xD8, 0x72, 0x75, 0x7B, 0xB3, 0xE1, + 0x50, 0x92, 0x5F, 0xFE, 0x09, 0x3C, 0xD4, 0xDC, 0x9A, 0x93, + 0x0F, 0xE2, 0x64, 0x81, 0xD4, 0xF7, 0x5A, 0x69, 0x48, 0xB7, + 0xBF, 0x59, 0x18, 0xE1, 0xC7, 0x08, 0xF3, 0x84, 0x08, 0xAB, + 0x92, 0xBC, 0x33, 0x75, 0x44, 0xD4, 0x05, 0x4A, 0x94, 0xC7, + 0x10, 0xAA, 0x18, 0x61, 0xB1, 0x6F, 0x27, 0x39, 0xED, 0x72, + 0x1A, 0x7F, 0xD0, 0x33, 0xFE, 0x83, 0xF6, 0x49, 0x44, 0x44, + 0x46, 0x9D, 0xAE, 0xFA, 0x1E, 0x7E, 0xE5, 0xA0, 0x78, 0x18, + 0x31, 0xFF, 0x54, 0xE7, 0x99, 0x26, 0x9F, 0x51, 0x52, 0xC2, + 0x36, 0x34, 0x33, 0x4A, 0xE8, 0x3D, 0xA5, 0x9C, 0xDD, 0x3D, + 0xFB, 0x19, 0x5D, 0x73, 0x56, 0x58, 0x46, 0xB4, 0x07, 0x9D, + 0xE6, 0xD8, 0x9F, 0x50, 0xA2, 0x70, 0x8C, 0xCD, 0xA3, 0xB8, + 0xA9, 0x94, 0x9D, 0x15, 0xB6, 0xAE, 0xFC, 0xA6, 0x47, 0x1F, + 0x24, 0xF9, 0x4F, 0xFE, 0x5B, 0x1E, 0x55, 0xAA, 0x31, 0x78, + 0x2E, 0x20, 0xD5, 0x13, 0xF3, 0xD4, 0x90, 0x3D, 0x1F, 0x4B, + 0xF4, 0xE8, 0x00, 0x43, 0x66, 0xF4, 0xC5, 0xB3, 0xC4, 0xA8, + 0x65, 0x7D, 0x4F, 0x8E, 0xE5, 0x8C, 0x45, 0xD3, 0x67, 0x26, + 0xB5, 0x5B, 0xE0, 0x0F, 0x41, 0x06, 0x83, 0xE4, 0x34, 0xF9, + 0x87, 0x63, 0x7D, 0x42, 0x45, 0xFE, 0x85, 0xE7, 0x79, 0x04, + 0xD1, 0x9C, 0xD8, 0x85, 0xCB, 0x58, 0x3B, 0xA3, 0x16, 0x78, + 0x80, 0x0C, 0x42, 0x02, 0xB9, 0xB7, 0x0B, 0xE4, 0x19, 0x3D, + 0x37, 0xB3, 0xB5, 0xF9, 0x23, 0x19, 0xBF, 0xA6, 0xC2, 0x7B, + 0x4B, 0xD1, 0x92, 0x3B, 0x55, 0xFE, 0xDE, 0x91, 0x12, 0xBF, + 0x43, 0x46, 0xBA, 0x84, 0x35, 0x89, 0x9B, 0x80, 0x0C, 0x48, + 0x5E, 0xD5, 0x17, 0x29, 0x86, 0x49, 0x51, 0xA0, 0x95, 0x6C, + 0xD0, 0x2E, 0x5E, 0xB3, 0x3C, 0xBA, 0x0A, 0x3D, 0x87, 0x33, + 0x64, 0x2F, 0xEC, 0xA1, 0xAF, 0xDF, 0x42, 0x79, 0x2B, 0xA8, + 0x44, 0xAB, 0xFD, 0xD7, 0x2B, 0x62, 0x0D, 0x88, 0x03, 0xB1, + 0x63, 0xD4, 0xAD, 0x9D, 0x23, 0x88, 0xEA, 0x45, 0x7C, 0x52, + 0xA4, 0x2E, 0xE2, 0x6C, 0x78, 0xD6, 0xFD, 0x1E, 0x85, 0x44, + 0x38, 0xA0, 0xFB, 0x4F, 0x22, 0xA7, 0x6B, 0x5E, 0x1E, 0x9A, + 0x83, 0x1D, 0x3E, 0x0B, 0xEC, 0xAE, 0xDA, 0xDF, 0x63, 0x84, + 0xE5, 0x93, 0xC1, 0x5D, 0x55, 0x7C, 0xCE, 0xA6, 0xBC, 0xA1, + 0x8F, 0x64, 0x5B, 0xA7, 0xD8, 0x28, 0x14, 0x36, 0x98, 0xEA, + 0x98, 0x19, 0xED, 0x21, 0xAC, 0x1D, 0x1E, 0x2C, 0x8D, 0x88, + 0x3B, 0xB0, 0xA9, 0x11, 0x92, 0x3C, 0x03, 0x0B, 0xB4, 0xAB, + 0x07, 0xBC, 0xA2, 0x14, 0x92, 0x5D, 0x14, 0x0D, 0xA5, 0x2E, + 0x8B, 0x67, 0x39, 0xD5, 0xEC, 0xDD, 0x33, 0x69, 0x6C, 0x93, + 0x4B, 0x52, 0x47, 0x40, 0xB1, 0x9D, 0xAD, 0x52, 0x23, 0x79, + 0xBD, 0xD7, 0x7F, 0x63, 0x45, 0xF7, 0x4E, 0xA5, 0xC8, 0x96, + 0x03, 0xE1, 0xA7, 0x1B, 0x27, 0x63, 0x39, 0x08, 0xAD, 0x45, + 0x5D, 0xC2, 0x37, 0x62, 0xAA, 0x92, 0x63, 0xA6, 0x89, 0x5C, + 0xA4, 0x2B, 0xE5, 0x54, 0x88, 0xB4, 0x14, 0x9A, 0x0A, 0x6B, + 0x97, 0xB1, 0x1A, 0x2F, 0x82, 0x03, 0x9A, 0x16, 0xCA, 0x62, + 0x62, 0x61, 0xFB, 0x8A, 0x70, 0xC9, 0xE5, 0x8C, 0x38, 0x74, + 0xF2, 0x74, 0xA3, 0xF0, 0xA7, 0x09, 0xB4, 0xC5, 0xF5, 0xA5, + 0x6A, 0x7D, 0x6E, 0x00, 0x56, 0x39, 0x27, 0x73, 0x97, 0x17, + 0x22, 0xE6, 0x68, 0x2E, 0x6F, 0xEA, 0x0E, 0x86, 0xC8, 0xBA, + 0xC4, 0x5B, 0xEF, 0xB2, 0x40, 0xF1, 0xB8, 0xE4, 0x7B, 0x67, + 0x3D, 0x18, 0x6E, 0x2F, 0x56, 0x1A, 0x36, 0xD4, 0xF7, 0xD3, + 0x90, 0x25, 0x11, 0x10, 0x76, 0x6D, 0x73, 0x86, 0x05, 0x21, + 0x82, 0x49, 0x42, 0xC5, 0x44, 0x8E, 0x9D, 0x98, 0xF9, 0x8D, + 0x74, 0x22, 0x06, 0x69, 0x40, 0x1A, 0xC6, 0x9E, 0x34, 0x75, + 0x81, 0xBA, 0xFE, 0xA5, 0xB4, 0x16, 0x44, 0x0A, 0xE4, 0xE0, + 0xC2, 0xC5, 0xC2, 0x11, 0xD0, 0xE6, 0xA6, 0x21, 0xD5, 0x37, + 0xC3, 0x3A, 0x35, 0x4B, 0x55, 0x84, 0xF1, 0x83, 0xA8, 0x32, + 0x64, 0x16, 0xFD, 0xAA, 0x6F, 0xB7, 0xAD, 0x73, 0x16, 0x6A, + 0x38, 0x45, 0x06, 0x0E, 0x86, 0xDE, 0x8C, 0x1E, 0xC6, 0xCA, + 0xB9, 0x70, 0x14, 0x04, 0x7B, 0xE6, 0xDB, 0xB7, 0xF2, 0x0A, + 0x56, 0x73, 0x5D, 0xAA, 0x4B, 0x1B, 0x99, 0x2C, 0xCC, 0x80, + 0x77, 0x69, 0x6B, 0x71, 0x79, 0xFD, 0xCE, 0xF8, 0xB0, 0x9B, + 0xFA, 0xB0, 0xA7, 0x66, 0x7F, 0x5E, 0xAF, 0x25, 0xAF, 0xC9, + 0x06, 0x35, 0x4F, 0x65, 0xFC, 0x59, 0xBA, 0x97, 0x68, 0x96, + 0xE7, 0x39, 0x47, 0xDE, 0x57, 0x09, 0x98, 0x43, 0xF6, 0x2B, + 0x4A, 0xAD, 0xF1, 0x0D, 0x3A, 0x24, 0x32, 0x41, 0x7A, 0x7E, + 0x73, 0x6C, 0x17, 0xBC, 0x3B, 0xD1, 0x3A, 0x0E, 0xAE, 0x0E, + 0x41, 0x7A, 0x1D, 0x87, 0x0D, 0x53, 0xB2, 0xED, 0xA6, 0x04, + 0x4F, 0x93, 0x62, 0xB9, 0x9D, 0xCB, 0xBE, 0xD3, 0x48, 0x32, + 0x80, 0x6F, 0x1E, 0x39, 0x17, 0x4D, 0x4C, 0x9B, 0x71, 0x69, + 0x6C, 0xA4, 0x41, 0x1D, 0x36, 0xC4, 0xDC, 0x41, 0x48, 0xFD, + 0x19, 0x2B, 0xED, 0x4E, 0x7A, 0x78, 0xC2, 0xD7, 0x1B, 0xF9, + 0xAF, 0xCC, 0xE4, 0xC2, 0xC4, 0xB3, 0x3D, 0xAC, 0x0A, 0xD8, + 0x08, 0x7D, 0xEE, 0xE1, 0x0C, 0xF9, 0x33, 0xA4, 0x90, 0xE0, + 0xA4, 0xEC, 0xFB, 0xA7, 0x31, 0xEF, 0xCE, 0xCB, 0x9D, 0x7D, + 0x57, 0xE0, 0x9F, 0x54, 0x1B, 0x3D, 0x43, 0x99, 0x95, 0x16, + 0x82, 0x46, 0xC4, 0x49, 0x86, 0x5E, 0xA2, 0x8D, 0x60, 0x79, + 0x9A, 0x01, 0x0E, 0xB0, 0xDD, 0x2A, 0x6C, 0xBC, 0x05, 0x83, + 0x6F, 0xFD, 0x94, 0x8A, 0xA0, 0x3B, 0x31, 0xA9, 0xBF, 0x4F, + 0x0D, 0x77, 0xBB, 0x9F, 0x9D, 0xCE, 0xE0, 0x72, 0xBF, 0x74, + 0x2D, 0xC0, 0xF4, 0xA4, 0x7B, 0xBC, 0xA6, 0xD7, 0x1C, 0x7A, + 0x51, 0xFE, 0x4A, 0xA9, 0xF7, 0x48, 0x6D, 0x5F, 0x3B, 0x2B, + 0x1A, 0x90, 0x4E, 0xEB, 0xBC, 0x03, 0xC2, 0xF6, 0xD4, 0x57, + 0xBB, 0x2C, 0x85, 0xB6, 0x54, 0x38, 0x93, 0xBF, 0x11, 0xBD, + 0x57, 0x23, 0x59, 0x15, 0x96, 0xBC, 0x71, 0xB2, 0xDE, 0x8A, + 0x0B, 0xB3, 0xA1, 0x8D, 0x11, 0x37, 0x34, 0x81, 0xB5, 0x65, + 0xD7, 0x43, 0xA9, 0xBF, 0xC9, 0x83, 0x2C, 0x56, 0x24, 0x60, + 0x82, 0x00, 0xEA, 0xB9, 0xB0, 0x0B, 0x3F, 0xD2, 0x3D, 0xC5, + 0xE7, 0xF2, 0xCB, 0x85, 0xCD, 0x4E, 0xD2, 0x4D, 0x2F, 0x8C, + 0xCD, 0x50, 0xC2, 0x93, 0x82, 0x9E, 0xB0, 0xC7, 0x13, 0x78, + 0xEF, 0xC4, 0x01, 0x94, 0xD4, 0x87, 0x16, 0x03, 0x98, 0x00, + 0x96, 0xD1, 0x68, 0x54, 0x65, 0x9F, 0x59, 0xC5, 0x86, 0xDB, + 0x6E, 0x0C, 0x86, 0x80, 0x52, 0x18, 0xBD, 0x27, 0x65, 0x87, + 0x56, 0xE8, 0xF4, 0x24, 0xB9, 0x76, 0x5B, 0x07, 0xEF, 0xD6, + 0x3A, 0xA3, 0x94, 0x54, 0x2A, 0xBD, 0xE9, 0xD3, 0xED, 0x6A, + 0xEE, 0x87, 0x5F, 0xD8, 0x22, 0xBC, 0x47, 0x14, 0xEE, 0xA1, + 0x20, 0xF6, 0xBE, 0xD5, 0xCD, 0xD7, 0x7D, 0x31, 0x36, 0xD0, + 0x34, 0x07, 0xEE, 0x9E, 0x0A, 0x91, 0xE2, 0x01, 0xDD, 0x16, + 0x98, 0x5D, 0x76, 0xFA, 0x42, 0x23, 0xFF, 0x6A, 0xB6, 0xCB, + 0x92, 0xB8, 0xCA, 0x8B, 0x97, 0xF5, 0x83, 0x1A, 0x88, 0x15, + 0xA3, 0xAD, 0x5A, 0xA7, 0xBF, 0xFE, 0x1B, 0x79, 0x59, 0x6E, + 0x8C, 0x3C, 0x48, 0x16, 0x7F, 0x97, 0x49, 0xCA, 0x98, 0xC0, + 0x89, 0xAB, 0x74, 0x15, 0xC8, 0xD0, 0xF3, 0xD0, 0x0B, 0x3D, + 0xD0, 0xC3, 0x73, 0x12, 0x0D, 0x08, 0x73, 0x64, 0xA2, 0x1A, + 0x9F, 0x85, 0x14, 0x26, 0xA5, 0xFF, 0x43, 0x0D, 0xD3, 0x44, + 0xA8, 0x9B, 0xB0, 0x99, 0xA9, 0x38, 0xAD, 0x4D, 0x3C, 0xD2, + 0x53, 0x51, 0x9E, 0xD2, 0x12, 0x68, 0xC1, 0x76, 0xAA, 0x4E, + 0x34, 0x0C, 0x2A, 0x23, 0x18, 0x00, 0x36, 0xB9, 0x39, 0x69, + 0x57, 0x16, 0xDA, 0xF7, 0x6B, 0x63, 0x0C, 0x78, 0xB1, 0xE5, + 0x52, 0x3B, 0x61, 0x29, 0x90, 0x4B, 0xFB, 0x4C, 0xE0, 0x8C, + 0x90, 0x60, 0xC7, 0x83, 0x99, 0x90, 0x55, 0xAD, 0x08, 0x97, + 0x4F, 0xFA, 0x99, 0x9D, 0x8D, 0xC2, 0xB8, 0x7C, 0x49, 0x4A, + 0x97, 0x3F, 0xE3, 0x56, 0x68, 0xB1, 0x67, 0xCC, 0x64, 0x5F, + 0xAF, 0x8A, 0x9D, 0x32, 0x52, 0xCF, 0x9F, 0x84, 0xD7, 0x1D, + 0x64, 0x90, 0x1D, 0x27, 0xC6, 0x8F, 0xA6, 0x10, 0x03, 0x6F, + 0xC8, 0x69, 0x88, 0xAF, 0xCE, 0xDA, 0xA2, 0xC0, 0xD7, 0xF3, + 0x64, 0xD4, 0x5D, 0xED, 0x46, 0x85, 0xB7, 0xA3, 0x7D, 0xAE, + 0xD4, 0xC3, 0x00, 0xFD, 0xA6, 0xF4, 0x7F, 0x56, 0x15, 0xEF, + 0x4D, 0x1B, 0x56, 0x4C, 0x2C, 0x12, 0x8C, 0xF3, 0x7F, 0x9F, + 0x73, 0x66, 0xAC, 0x61, 0xBF, 0xF8, 0x2B, 0xF4, 0x4C, 0x2E, + 0x64, 0x63, 0x86, 0xB5, 0xA1, 0x88, 0x44, 0x6B, 0x22, 0x4D, + 0x02, 0x1A, 0xF5, 0xC3, 0x32, 0x71, 0xC6, 0xF2, 0x72, 0xA5, + 0xF0, 0x41, 0xF4, 0x65, 0x0F, 0xE5, 0x39, 0x91, 0x99, 0xA7, + 0x97, 0xE7, 0x24, 0x04, 0x26, 0x27, 0xC0, 0xAE, 0x6D, 0x37, + 0x0A, 0xD3, 0xF7, 0x37, 0xC5, 0xD7, 0x7F, 0xF6, 0xD8, 0x75, + 0x8E, 0xF9, 0x72, 0xDC, 0x6A, 0x19, 0x86, 0x24, 0xD7, 0x5A, + 0xAE, 0xA7, 0x55, 0xEC, 0x4B, 0xBB, 0x9E, 0xF5, 0xD2, 0xFD, + 0xE7, 0x33, 0x95, 0xEF, 0xF4, 0xDF, 0x50, 0xC1, 0xCC, 0x81, + 0x45, 0x55, 0x3E, 0xF5, 0x48, 0xF4, 0x0E, 0x96, 0xE1, 0x9B, + 0xB6, 0x9F, 0xAC, 0xA7, 0x78, 0x52, 0x84, 0xD1, 0xDE, 0x20, + 0x3A, 0xAC, 0x6B, 0x09, 0xBF, 0x4C, 0x15, 0xBE, 0x8F, 0xB4, + 0xFD, 0xAD, 0x58, 0xD7, 0x93, 0xDF, 0x2E, 0x0E, 0x71, 0x27, + 0x93, 0x40, 0xAB, 0xC3, 0x6B, 0xC1, 0x93, 0xAA, 0x5D, 0x34, + 0xDF, 0x69, 0xA7, 0xA5, 0x1B, 0x2B, 0x93, 0x91, 0x93, 0x91, + 0x10, 0x5B, 0xD6, 0xCB, 0x71, 0x7C, 0x3A, 0x48, 0x2F, 0xD6, + 0xEE, 0x83, 0xC3, 0x56, 0x44, 0x01, 0xA6, 0x3F, 0x27, 0x6E, + 0xA2, 0x04, 0x23, 0x9B, 0x27, 0xE5, 0x5F, 0x4A, 0xD4, 0x12, + 0xC3, 0x82, 0x1A, 0x24, 0x24, 0xEB, 0x98, 0x33, 0xD0, 0x0E, + 0x6F, 0x08, 0x9E, 0xA2, 0x9E, 0x89, 0x2D, 0x42, 0x39, 0x15, + 0x83, 0x5D, 0xDC, 0xA6, 0xCE, 0x5C, 0x64, 0x59, 0x12, 0x21, + 0x03, 0xDF, 0x19, 0x5E, 0x4B, 0x77, 0xF7, 0x1F, 0xC4, 0xED, + 0xA3, 0x81, 0x48, 0x32, 0xC6, 0x86, 0x9A, 0x3B, 0xE6, 0xAB, + 0xE2, 0x04, 0x80, 0xB2, 0x5B, 0xC4, 0xEF, 0xBD, 0x67, 0x8F, + 0x70, 0xE5, 0x49, 0x7E, 0x62, 0xAF, 0xBA, 0x2B, 0x31, 0x18, + 0xBB, 0x02, 0x35, 0xC2, 0x57, 0xA9, 0x69, 0x46, 0xB5, 0xF1, + 0xF1, 0xB6, 0x13, 0x0E, 0x45, 0x90, 0xBB, 0x5A, 0xAA, 0xA5, + 0xD4, 0x6E, 0xA9, 0x27, 0xAC, 0x44, 0x13, 0x73, 0xAE, 0x37, + 0x3C, 0x6C, 0x4B, 0x37, 0x04, 0x47, 0x74, 0x5E, 0x92, 0x5B, + 0x89, 0x7E, 0x95, 0x0C, 0xFB, 0x8A, 0x40, 0xF0, 0x38, 0x68, + 0xAA, 0x0A, 0x7A, 0x91, 0xD6, 0x55, 0x3E, 0xF2, 0x54, 0xFD, + 0x9A, 0xD5, 0x3F, 0x9A, 0xC8, 0xD9, 0x9E, 0x0B, 0x6C, 0x21, + 0x7D, 0x8F, 0x1F, 0xE8, 0x53, 0xF3, 0xCC, 0x3D, 0x96, 0x14, + 0xF2, 0x39, 0xF6, 0x13, 0xE7, 0x4F, 0x14, 0x8B, 0x49, 0x1F, + 0xF5, 0x73, 0x7A, 0x6E, 0xED, 0x48, 0xE7, 0xAF, 0x8F, 0x05, + 0xBE, 0x00, 0xAD, 0xC6, 0x64, 0xA5, 0xBC, 0x81, 0x00, 0x25, + 0xD0, 0x46, 0x1A, 0xCE, 0xE9, 0x1F, 0x8B, 0xD0, 0x1D, 0x13, + 0x2B, 0xF4, 0xA9, 0x98, 0x62, 0xB4, 0xAE, 0x91, 0x9C, 0x47, + 0x84, 0xC1, 0x71, 0x2D, 0xBB, 0x04, 0xB6, 0xFF, 0xC3, 0x85, + 0xCE, 0x27, 0x59, 0xA9, 0x2B, 0xA2, 0x98, 0x9D, 0x9F, 0x2F, + 0x2E, 0x00, 0xD1, 0x0F, 0x07, 0x90, 0x94, 0x5D, 0x33, 0xCF, + 0x85, 0x5B, 0x87, 0x32, 0xF7, 0x37, 0x92, 0x3A, 0x3D, 0xE1, + 0xAF, 0x05, 0x18, 0xB7, 0x49, 0xF6, 0x73, 0x74, 0xCF, 0x50, + 0xA4, 0xE8, 0x15, 0xDE, 0x20, 0xEB, 0xB5, 0xA3, 0x0E, 0x78, + 0x3B, 0x5D, 0xF0, 0xE9, 0x39, 0xA5, 0xAC, 0x41, 0x81, 0x09, + 0x24, 0x94, 0x1F, 0x51, 0x51, 0xBC, 0xD8, 0xB5, 0x55, 0x16, + 0xE7, 0x28, 0x26, 0xF1, 0x8F, 0x8B, 0xF0, 0x19, 0x7E, 0x20, + 0xE6, 0xC9, 0x16, 0x6F, 0xAB, 0xFC, 0x6C, 0x9D, 0xB2, 0xF8, + 0xD0, 0xED, 0x5E, 0xF2, 0x25, 0xAA, 0xDC, 0xF4, 0x0F, 0x70, + 0xB7, 0xA1, 0x5F, 0x7A, 0xBD, 0xD9, 0x9D, 0xB0, 0x46, 0x03, + 0xF2, 0xE9, 0x2F, 0x92, 0x03, 0xA3, 0x6B, 0x5B, 0x8F, 0xEA, + 0x31, 0x65, 0xBF, 0x52, 0x64, 0x62, 0x3F, 0xD3, 0x8D, 0x19, + 0xA7, 0x0C, 0x01, 0x3C, 0x72, 0x9E, 0x87, 0xB8, 0x37, 0xDF, + 0x2F, 0x41, 0xF4, 0xE1, 0xB2, 0x3A, 0xF4, 0x0C, 0xE7, 0xDA, + 0xC8, 0xAB, 0xCF, 0x61, 0x78, 0xB6, 0x7F, 0x06, 0x73, 0xDD, + 0x91, 0x35, 0xD4, 0xFA, 0xCE, 0x8D, 0xDE, 0x11, 0x16, 0x28, + 0xB1, 0xC9, 0x85, 0x6D, 0x9D, 0x60, 0x11, 0x0A, 0xA3, 0x4D, + 0xCC, 0x91, 0xFD, 0x69, 0x47, 0x1B, 0xCD, 0xF9, 0xF4, 0x99, + 0x31, 0xA5, 0x3C, 0x3A, 0xD4, 0xA0, 0x82, 0x54, 0x61, 0x24, + 0xD6, 0xA8, 0xF6, 0x47, 0x97, 0xD2, 0x4E, 0x3A, 0x89, 0xF0, + 0xE9, 0x0C, 0x01, 0xA8, 0x94, 0xE4, 0x01, 0x8E, 0x53, 0xF0, + 0xDD, 0xDF, 0x03, 0x64, 0xFF, 0x4A, 0xB0, 0xE0, 0xAC, 0x5E, + 0x82, 0x04, 0x87, 0x7B, 0xA4, 0x82, 0x3F, 0x83, 0xB6, 0x4C, + 0x3F, 0x26, 0xF4, 0xAE, 0x65, 0x67, 0x25, 0x2F, 0xCC, 0x44, + 0x53, 0x98, 0x8D, 0xBF, 0x54, 0x4B, 0xB4, 0x7A, 0xFA, 0xDC, + 0xF1, 0xA4, 0xED, 0x41, 0x56, 0xB1, 0x3E, 0x32, 0x2F, 0xD5, + 0x0C, 0xD2, 0x3E, 0x42, 0xC0, 0x45, 0x85, 0x33, 0x61, 0x8E, + 0x97, 0xED, 0xA8, 0x07, 0x7B, 0x97, 0x15, 0x79, 0xA6, 0xDB, + 0xB8, 0xF0, 0xFE, 0x6F, 0x36, 0x9D, 0x61, 0x49, 0x0B, 0x89, + 0x4F, 0xF6, 0x08, 0x6A, 0x79, 0x10, 0x38, 0x26, 0xBD, 0x91, + 0xA7, 0x9D, 0x50, 0x64, 0x16, 0x14, 0x08, 0xBE, 0xDB, 0x3E, + 0xD6, 0x53, 0xED, 0x20, 0xE6, 0x05, 0x2E, 0xC6, 0x0E, 0xE9, + 0xAD, 0xFB, 0x5A, 0x5F, 0x58, 0xB7, 0xC7, 0xDA, 0xC2, 0x24, + 0x5F, 0x59, 0xA6, 0x66, 0x17, 0x21, 0x79, 0xF5, 0x9B, 0x85, + 0x45, 0x98, 0x88, 0x41, 0xC0, 0x70, 0x0B, 0x47, 0x77, 0x05, + 0xA3, 0x06, 0x82, 0x2B, 0x6F, 0xBE, 0xC4, 0x52, 0xB7, 0x93, + 0x35, 0x20, 0x19, 0xBD, 0xD8, 0x25, 0x4A, 0x0B, 0x2E, 0xDA, + 0x2F, 0x51, 0xD2, 0x57, 0x6A, 0x96, 0xC9, 0x16, 0x9C, 0xA1, + 0x23, 0xA0, 0x85, 0xB6, 0x4E, 0xC3, 0x8D, 0xB0, 0xBB, 0xAF, + 0xCB, 0x88, 0x99, 0x42, 0x7B, 0x51, 0x93, 0xB0, 0x46, 0x5F, + 0x1D, 0x34, 0x41, 0x39, 0xD9, 0x5E, 0x39, 0x1B, 0x07, 0xD9, + 0x14, 0x63, 0xB7, 0xD4, 0x0D, 0x86, 0x64, 0x5C, 0x62, 0x76, + 0x12, 0x63, 0x59, 0xC4, 0xD6, 0x2A, 0xD2, 0x11, 0x98, 0x92, + 0x23, 0x17, 0xAF, 0xBB, 0x2B, 0x3B, 0xDF, 0x22, 0x26, 0x19, + 0xDA, 0x00, 0xD4, 0x82, 0x97, 0x13, 0x24, 0x17, 0x59, 0xD1, + 0xD1, 0x15, 0x70, 0x18, 0xF0, 0xCF, 0x59, 0x61, 0xC8, 0xF6, + 0x5C, 0x60, 0x17, 0x3C, 0xE4, 0x87, 0x17, 0x96, 0x1F, 0x8D, + 0x6E, 0xB4, 0x5D, 0x75, 0xFB, 0x11, 0x10, 0x3E, 0x19, 0x46, + 0x76, 0xF4, 0x88, 0x77, 0xC1, 0x07, 0x75, 0xE2, 0xA9, 0x91, + 0x43, 0x73, 0xAA, 0x31, 0x27, 0x3C, 0x7F, 0x1A, 0x9E, 0xD1, + 0x8E, 0x88, 0xA5, 0xF5, 0xFC, 0xB6, 0xAC, 0x65, 0x3F, 0x89, + 0x6F, 0xCA, 0xD4, 0xDB, 0xC9, 0x33, 0x66, 0x69, 0xAE, 0x6C, + 0xA9, 0xEC, 0x34, 0x0D, 0xB8, 0x2B, 0xBA, 0x48, 0x79, 0x4C, + 0x54, 0x29, 0xC1, 0xF6, 0x08, 0xB8, 0x48, 0x14, 0x62, 0x94, + 0xDB, 0x0D, 0xC6, 0x4C, 0xE4, 0x66, 0x91, 0xA1, 0xC6, 0x5C, + 0x38, 0x1A, 0x85, 0x01, 0xE9, 0xC3, 0x61, 0x0A, 0x45, 0x9B, + 0xB3, 0x9D, 0x9C, 0x20, 0xE9, 0xE2, 0x8F, 0x04, 0x1A, 0xCC, + 0x84, 0xBE, 0x26, 0x1F, 0xCD, 0xC3, 0x54, 0xC1, 0x1E, 0x20, + 0xAB, 0xAD, 0xB3, 0xB8, 0x7B, 0xCB, 0x3F, 0xF5, 0x46, 0x6F, + 0x48, 0xD7, 0x0C, 0x60, 0x56, 0x95, 0xD0, 0x93, 0x1C, 0x1B, + 0x34, 0x88, 0x87, 0xA0, 0x44, 0x5C, 0xC9, 0x4D, 0xC9, 0x10, + 0x1F, 0x9C, 0xF3, 0xC7, 0x44, 0xD4, 0x60, 0x52, 0x63, 0xA7, + 0x51, 0xE7, 0x7A, 0x34, 0x6F, 0x80, 0xC5, 0xD2, 0xB6, 0x8B, + 0x20, 0x63, 0xF1, 0xDF, 0x3D, 0x49, 0x5E, 0x51, 0xC7, 0xD2, + 0x2F, 0x5F, 0x9E, 0x51, 0xF0, 0xAA, 0x63, 0x79, 0x56, 0x6D, + 0xDD, 0x58, 0xA8, 0xE5, 0xC2, 0x6C, 0xB7, 0xE2, 0x02, 0xDA, + 0xCA, 0x03, 0x68, 0x61, 0xFB, 0xCF, 0x7A, 0xDB, 0xCB, 0xD3, + 0xB3, 0xF2, 0x1B, 0xCF, 0xDF, 0x23, 0x1E, 0xD9, 0x29, 0xE8, + 0xB4, 0x57, 0xA8, 0x02, 0xD3, 0x1B, 0x77, 0x42, 0x1E, 0x98, + 0xEE, 0xD4, 0x21, 0xEB, 0xC5, 0xB1, 0x0A, 0x7A, 0xEC, 0x96, + 0x74, 0xC6, 0x18, 0xA3, 0x14, 0xE7, 0x81, 0x2B, 0xED, 0xBE, + 0xC5, 0xE9, 0x07, 0x29, 0x2F, 0xEF, 0xFD, 0xF4, 0x04, 0x44, + 0x58, 0xD6, 0xA4, 0x19, 0xA6, 0xAD, 0x1E, 0x45, 0x09, 0x0C, + 0xD1, 0x6B, 0x6D, 0x7E, 0xB3, 0x3F, 0x3B, 0xAE, 0x60, 0x63, + 0xB7, 0x82, 0x28, 0xBB, 0xF1, 0x29, 0xCE, 0x28, 0x8D, 0x4C, + 0x0B, 0x05, 0x73, 0x38, 0xFD, 0x33, 0x55, 0xD5, 0x7A, 0x43, + 0xC8, 0x18, 0xE8, 0x18, 0xF2, 0x59, 0x55, 0xFB, 0xDA, 0xC7, + 0x74, 0x0A, 0xC1, 0x48, 0x77, 0x12, 0xF9, 0x7F, 0xE0, 0xBC, + 0xF1, 0x44, 0xC2, 0x06, 0x41, 0x78, 0xDE, 0x25, 0xCC, 0x15, + 0xDC, 0xA5, 0xC6, 0x21, 0x60, 0xBB, 0x3C, 0x29, 0x34, 0xA5, + 0xCB, 0xA6, 0x61, 0x8B, 0xEE, 0x5F, 0x43, 0x01, 0x35, 0x32, + 0xC2, 0x69, 0x7D, 0xBB, 0x8A, 0x67, 0xBD, 0x82, 0x3F, 0x9F, + 0x29, 0x04, 0x6A, 0x48, 0xE5, 0x27, 0xD2, 0x7C, 0x46, 0x49, + 0x75, 0x24, 0x67, 0x81, 0xFB, 0x81, 0x54, 0xE8, 0x65, 0xA8, + 0xC6, 0xA6, 0x5F, 0x73, 0xC8, 0x11, 0x4B, 0x78, 0x76, 0x6B, + 0x7C, 0x5D, 0xE0, 0x7F, 0xCD, 0x9D, 0x6E, 0xB6, 0x5C, 0xF5, + 0xC4, 0xED, 0xCF, 0x66, 0x30, 0x30, 0x0E, 0x73, 0x8A, 0xAF, + 0x40, 0x7E, 0x98, 0x3C, 0x92, 0xCE, 0x1D, 0x91, 0xBD, 0xCC, + 0x69, 0x4E, 0xFE, 0xE4, 0x3A, 0xCF, 0x2C, 0x64, 0x16, 0x7A, + 0xB0, 0x6A, 0x61, 0xC1, 0xD8, 0x50, 0x08, 0xC2, 0x0A, 0x81, + 0x01, 0xF4, 0x7D, 0xE3, 0xB4, 0x72, 0xA5, 0xE4, 0x5A, 0xFC, + 0x69, 0x3F, 0x95, 0x70, 0x90, 0x59, 0x92, 0x39, 0xAD, 0xA2, + 0x6D, 0xCB, 0xDD, 0xDB, 0xF4, 0x0B, 0xFC, 0x22, 0x79, 0x69, + 0xB6, 0xC3, 0xC9, 0x11, 0xCD, 0x9D, 0x62, 0x5E, 0xD8, 0xD2, + 0x4E, 0x95, 0x9D, 0x34, 0xC3, 0x77, 0x58, 0x9A, 0x8E, 0x45, + 0xAC, 0x05, 0x61, 0x82, 0xFB, 0x9F, 0x1D, 0x92, 0x1B, 0xE9, + 0x71, 0x70, 0xFF, 0xC8, 0x08, 0x70, 0xE7, 0x19, 0xF6, 0xFE, + 0x23, 0xCE, 0x4E, 0x66, 0xB8, 0xB8, 0x7B, 0x17, 0x8A, 0xF0, + 0xD8, 0x6F, 0x71, 0x13, 0x96, 0x2D, 0xB8, 0xFC, 0x82, 0x59, + 0xEC, 0x54, 0x23, 0xB1, 0x58, 0xEC, 0x35, 0xE0, 0xE5, 0x1B, + 0x6D, 0x64, 0x96, 0xE1, 0x7E, 0xD5, 0xA2, 0xD1, 0x89, 0xC2, + 0x09, 0x62, 0x9C, 0x3C, 0x7D, 0x44, 0xA3, 0x37, 0xE5, 0x0B, + 0xA8, 0xFF, 0xBD, 0xB8, 0x4F, 0xD4, 0xF5, 0xA9, 0x29, 0xCC, + 0x2C, 0x12, 0xED, 0xFF, 0x32, 0x72, 0xE3, 0x61, 0xB4, 0x78, + 0x5A, 0xE4, 0xFF, 0xA3, 0x5C, 0x48, 0x3F, 0xE7, 0xAF, 0xA6, + 0xC4, 0x26, 0xC9, 0x5C, 0x65, 0xEC, 0x66, 0x0B, 0x8B, 0x58, + 0x68, 0xC2, 0xFE, 0xC2, 0x59, 0x2F, 0x84, 0x03, 0x18, 0x1D, + 0x53, 0x75, 0xF1, 0xBE, 0xD2, 0xC0, 0x98, 0x0B, 0x5F, 0x20, + 0xDA, 0xB8, 0xD2, 0x13, 0x43, 0xCC, 0xCD, 0x23, 0x10, 0xEE, + 0xD7, 0x7E, 0x1A, 0x58, 0xB1, 0x60, 0xD5, 0x05, 0x15, 0xA0, + 0xD1, 0x37, 0x3E, 0x01, 0xEB, 0xF3, 0x4E, 0x04, 0xFB, 0xC9, + 0x88, 0x86, 0x08, 0xEF, 0x7D, 0xF3, 0xB6, 0x8F, 0x9F, 0x21, + 0xE4, 0xC7, 0x46, 0xE8, 0x12, 0xDD, 0x8F, 0x97, 0xE5, 0x6E, + 0xB5, 0x69, 0x88, 0xE7, 0x74, 0x2D, 0xAA, 0x70, 0x94, 0x5F, + 0x4C, 0x4A, 0x4B, 0x94, 0x30, 0xC6, 0xF1, 0xFA, 0x7B, 0x58, + 0x85, 0x93, 0x33, 0x7F, 0x42, 0xDB, 0xE7, 0x6C, 0x9F, 0x77, + 0x12, 0xEA, 0x58, 0xDA, 0x9C, 0xB5, 0x25, 0x4E, 0x2B, 0xB8, + 0xF6, 0xA0, 0xA2, 0xC0, 0x6B, 0x46, 0x31, 0x8C, 0x31, 0xB3, + 0xE4, 0xCA, 0x7F, 0x1B, 0xA5, 0x08, 0x37, 0xDC, 0x58, 0x2B, + 0x17, 0xA8, 0x55, 0x73, 0x24, 0xE8, 0x2B, 0xAF, 0xF0, 0xC0, + 0xB5, 0x68, 0x67, 0x38, 0xEB, 0xE6, 0x0B, 0x06, 0x6D, 0xC7, + 0x8B, 0xB3, 0x34, 0x4E, 0xF8, 0xF4, 0xCB, 0xBD, 0x17, 0xA0, + 0xED, 0x6C, 0xE5, 0xB9, 0x2E, 0xA2, 0xAB, 0x4C, 0xC5, 0xF1, + 0x1D, 0x21, 0xED, 0x6F, 0xC3, 0xE3, 0x7B, 0x78, 0x81, 0x4C, + 0x3F, 0x56, 0x2E, 0xDF, 0x0D, 0x53, 0x39, 0xFC, 0x91, 0x6D, + 0xAF, 0xC3, 0x96, 0xF0, 0xAF, 0x32, 0xE0, 0xDA, 0x0D, 0xFB, + 0x3C, 0x51, 0xEE, 0x42, 0xF7, 0xB0, 0x07, 0x2C, 0xFC, 0x9B, + 0xB7, 0x50, 0x10, 0x91, 0xD5, 0xAC, 0xCC, 0xEB, 0x40, 0xEF, + 0x74, 0x63, 0xB1, 0x95, 0x44, 0xAC, 0x29, 0xE9, 0xCC, 0x26, + 0x21, 0x77, 0x02, 0xC5, 0x48, 0xAB, 0xEF, 0x0B, 0x7E, 0x28, + 0xC6, 0xAE, 0x2D, 0xE0, 0x65, 0xAF, 0xA0, 0xEA, 0x86, 0x02, + 0x20, 0xD3, 0x98, 0x8B, 0xA5, 0x5E, 0x05, 0x91, 0x7C, 0x33, + 0xA5, 0xD9, 0x9C, 0x22, 0xD3, 0x38, 0x99, 0x26, 0x0B, 0x83, + 0x31, 0x2D, 0xC3, 0x2A, 0xF0, 0x39, 0xF8, 0xC3, 0x9B, 0x37, + 0xC9, 0x4B, 0xF7, 0xC5, 0xC3, 0xF1, 0x4E, 0x26, 0x44, 0x17, + 0x42, 0x3E, 0xA4, 0xFE, 0x12, 0x99, 0xC3, 0x11, 0x70, 0xCB, + 0x6E, 0xC5, 0xBF, 0x66, 0x58, 0x69, 0x95, 0x9B, 0xF4, 0xD4, + 0x20, 0xEE, 0x5A, 0x71, 0x33, 0x05, 0x25, 0xDC, 0x72, 0x31, + 0x54, 0xF1, 0x63, 0x81, 0xF9, 0xF8, 0x89, 0x6A, 0x9B, 0x23, + 0xF7, 0x74, 0xA1, 0x97, 0x77, 0x31, 0x92, 0x06, 0xF8, 0xAE, + 0x3C, 0xC4, 0x7C, 0xB9, 0x01, 0x64, 0x09, 0xFE, 0x9E, 0x5F, + 0x9F, 0x56, 0x71, 0x1C, 0x6B, 0x00, 0x4F, 0xCB, 0x82, 0x25, + 0xDD, 0x31, 0xE6, 0x18, 0x05, 0x92, 0xE5, 0x1E, 0x41, 0x22, + 0x48, 0x14, 0x22, 0xE5, 0x0E, 0x0B, 0xF9, 0x7C, 0x48, 0xA5, + 0xE6, 0x01, 0xF7, 0xD8, 0xA3, 0x7F, 0x93, 0xB7, 0x6C, 0xE0, + 0x91, 0xCC, 0x5F, 0x81, 0x11, 0x6B, 0xD8, 0xB4, 0x33, 0xB2, + 0x40, 0xAE, 0x58, 0xFA, 0xCA, 0xAF, 0x97, 0xF4, 0xD5, 0x62, + 0x73, 0xA4, 0xB6, 0xE7, 0xAF, 0xF8, 0xAB, 0x0C, 0xB9, 0x79, + 0x78, 0x9F, 0x93, 0x8A, 0xEF, 0xD0, 0xFA, 0x27, 0x86, 0xA8, + 0x45, 0x21, 0xB9, 0x45, 0xE9, 0x53, 0xDA, 0xB1, 0xC4, 0x56, + 0x66, 0x64, 0x39, 0xDC, 0xF9, 0x0C, 0x55, 0x2A, 0x07, 0x8E, + 0x8C, 0xDE, 0xCC, 0x8A, 0x61, 0x94, 0xA8, 0x0D, 0xD5, 0x6D, + 0x92, 0x9D, 0x65, 0x04, 0x66, 0xC6, 0x14, 0x57, 0x81, 0xD3, + 0x20, 0x60, 0x83, 0x4F, 0x4E, 0x3E, 0x3E, 0x19, 0xEA, 0x2E, + 0x43, 0x09, 0x95, 0x6A, 0xCB, 0x8E, 0x9D, 0x57, 0x33, 0xAF, + 0x3C, 0xEC, 0x02, 0x20, 0x4E, 0x67, 0xAA, 0x41, 0x6A, 0x10, + 0xDD, 0x36, 0x0C, 0x50, 0xD6, 0x20, 0x32, 0x39, 0xE1, 0xC6, + 0x08, 0xBA, 0x5C, 0x5A, 0x90, 0x64, 0xD7, 0x87, 0x11, 0xB8, + 0xA7, 0xC4, 0xB2, 0xF3, 0x2F, 0x14, 0x36, 0xDE, 0xE4, 0x8E, + 0x58, 0xE9, 0x61, 0x61, 0xAC, 0x63, 0x19, 0x71, 0xDB, 0x07, + 0xF5, 0x68, 0x21, 0x4A, 0x56, 0xE7, 0xAF, 0x99, 0x0D, 0x63, + 0x32, 0x41, 0xB5, 0xC7, 0x4C, 0x8E, 0xDF, 0xBF, 0x54, 0x2F, + 0xDD, 0x55, 0x8C, 0x36, 0x87, 0x51, 0xEA, 0xCB, 0x21, 0x9F, + 0x04, 0xB9, 0x1A, 0x5C, 0xF2, 0x81, 0x54, 0x1A, 0xDE, 0x9A, + 0x1D, 0xFB, 0x68, 0x3B, 0xF0, 0x92, 0x57, 0x6D, 0xC1, 0x91, + 0x58, 0xFA, 0x40, 0x39, 0x74, 0x24, 0xB8, 0xD6, 0xAD, 0xB4, + 0xEB, 0xF6, 0x48, 0x70, 0x2E, 0x63, 0x87, 0xF4, 0xB2, 0x99, + 0x79, 0x7F, 0xA1, 0x36, 0xB8, 0xB2, 0x8E, 0x33, 0x89, 0x7F, + 0xCE, 0x12, 0x44, 0x79, 0x87, 0xB2, 0x35, 0x44, 0xFF, 0x3D, + 0x8D, 0x9D, 0x7A, 0x37, 0x62, 0x24, 0x44, 0x90, 0x67, 0xFE, + 0xA8, 0x55, 0x99, 0xB2, 0x50, 0x78, 0x01, 0x5A, 0xA4, 0xEE, + 0x38, 0x5F, 0xF5, 0x65, 0x9B, 0x20, 0x61, 0x1D, 0xF9, 0xFA, + 0x27, 0x80, 0x07, 0xA5, 0x07, 0xD8, 0x0E, 0x23, 0x61, 0x39, + 0xC5, 0x67, 0x1D, 0x98, 0x6E, 0xC0, 0xC6, 0xF3, 0xD3, 0x2D, + 0x14, 0xA0, 0x17, 0x6F, 0xA7, 0x95, 0x2D, 0xD0, 0xC0, 0x7A, + 0x77, 0x03, 0xD6, 0x30, 0xF7, 0xA6, 0x3B, 0xD2, 0xDF, 0xC2, + 0xEE, 0xB2, 0xFC, 0x42, 0x5E, 0x74, 0xFC, 0xCA, 0x85, 0x77, + 0x76, 0x1A, 0xC2, 0xBB, 0xB6, 0x9F, 0x9B, 0x0F, 0x70, 0x6D, + 0x6B, 0x6E, 0x0E, 0x0D, 0x61, 0xDD, 0xC1, 0x69, 0x5D, 0xFF, + 0x90, 0xBE, 0x68, 0x8E, 0xDE, 0x7F, 0xEE, 0x86, 0x98, 0xD4, + 0xF9, 0x66, 0x51, 0xFF, 0x34, 0xFD, 0x67, 0xBC, 0x31, 0x20, + 0xDE, 0xD3, 0x8D, 0x09, 0x37, 0x5F, 0xE0, 0xB3, 0x8F, 0x16, + 0xA1, 0x76, 0xA3, 0x98, 0xF8, 0x98, 0x36, 0x9F, 0xB0, 0xAA, + 0xB8, 0xFF, 0x3B, 0x45, 0x88, 0x5B, 0x9B, 0xCC, 0x6E, 0x4F, + 0x45, 0x29, 0x4B, 0x7A, 0x71, 0xBC, 0xCE, 0xF5, 0xAB, 0x5D, + 0xB0, 0xA2, 0xBA, 0x2D, 0x60, 0xD9, 0x03, 0x3F, 0x3B, 0x61, + 0x4B, 0x74, 0x0B, 0x52, 0x30, 0xBB, 0xBB, 0xC8, 0x92, 0x90, + 0x7F, 0xA9, 0x6D, 0xBF, 0x03, 0x93, 0x49, 0x3E, 0x87, 0x26, + 0x4A, 0x1B, 0xDD, 0xCA, 0xC0, 0xFB, 0x6E, 0x0A, 0x62, 0xAC, + 0x74, 0xB1, 0x33, 0x23, 0x58, 0x97, 0x42, 0x95, 0x62, 0x5F, + 0x7C, 0xF2, 0xFC, 0x3F, 0x2F, 0x91, 0x9D, 0x11, 0x4F, 0x18, + 0xB6, 0x5E, 0xA2, 0x5D, 0xC3, 0xFB, 0x5C, 0x8E, 0xCD, 0xBE, + 0x14, 0x88, 0x42, 0xD6, 0xAA, 0x66, 0x07, 0xBB, 0x06, 0x62, + 0xC8, 0xAD, 0x65, 0x83, 0xD9, 0x1A, 0x8B, 0xA2, 0xF8, 0x9A, + 0x93, 0xE2, 0xAA, 0x15, 0xD7, 0xFC, 0xCB, 0x36, 0x67, 0x9E, + 0xA2, 0x45, 0x13, 0x8E, 0xC7, 0x22, 0x81, 0xBD, 0x2B, 0xB6, + 0x7B, 0x67, 0x1D, 0x77, 0x4E, 0x60, 0xF1, 0x5A, 0x8F, 0xEB, + 0x4E, 0xE3, 0x2A, 0x9F, 0x62, 0xC1, 0xEB, 0xDD, 0xA8, 0x6C, + 0xB1, 0x2C, 0x2D, 0xAE, 0x70, 0xC6, 0xD7, 0x18, 0xD2, 0xBC, + 0x0C, 0x36, 0xC6, 0x34, 0x77, 0x13, 0x62, 0x01, 0x3C, 0xED, + 0xB5, 0x10, 0xD0, 0xB8, 0x04, 0xD6, 0x94, 0xC7, 0xD7, 0xF7, + 0xBB, 0xB7, 0x4C, 0xF6, 0x53, 0x84, 0x6D, 0x5E, 0x05, 0x2D, + 0x05, 0xF9, 0x4A, 0xC8, 0x3C, 0x7B, 0xE2, 0xF3, 0x72, 0xB9, + 0xE0, 0xC0, 0xC6, 0xC3, 0x81, 0x59, 0x05, 0xE2, 0x5F, 0x3B, + 0x61, 0xDB, 0x57, 0x35, 0xD8, 0xD4, 0x4F, 0xAB, 0xF3, 0xFB, + 0xE0, 0x35, 0x5E, 0x6A, 0x22, 0xD0, 0x7E, 0xAF, 0xE2, 0x3F, + 0x99, 0x28, 0xE7, 0x68, 0x38, 0x51, 0x19, 0x59, 0x91, 0x84, + 0x01, 0xDA, 0xA9, 0xEE, 0x6A, 0xA9, 0xB2, 0x10, 0xCC, 0x3A, + 0x01, 0x65, 0x2B, 0x53, 0xFD, 0x93, 0x23, 0x71, 0x73, 0x11, + 0x41, 0x3E, 0x2A, 0xE5, 0xE8, 0xA3, 0x44, 0xF5, 0x87, 0xD2, + 0xB6, 0xA1, 0x34, 0x34, 0x82, 0x90, 0x8F, 0x94, 0x57, 0xDD, + 0x1B, 0xA9, 0xD0, 0x84, 0xF9, 0x2B, 0x0C, 0xE8, 0x39, 0x0B, + 0xB0, 0x7F, 0x66, 0x85, 0x21, 0xD8, 0xD8, 0x5E, 0x73, 0xE8, + 0x15, 0x29, 0xB3, 0x92, 0x96, 0xAA, 0x87, 0xA8, 0xCA, 0xA1, + 0x0E, 0x92, 0x1B, 0xF3, 0xCB, 0x7B, 0xEE, 0xB5, 0x1F, 0x2F, + 0xB4, 0xE9, 0x64, 0x32, 0x89, 0x04, 0x6B, 0x76, 0xF9, 0xF0, + 0x2B, 0x09, 0xAD, 0x6A, 0x4F, 0x6E, 0x7D, 0xA7, 0xF9, 0xA5, + 0x7C, 0x72, 0xDB, 0x94, 0x21, 0x92, 0x57, 0x8E, 0x2F, 0x7F, + 0x9B, 0xE1, 0xEE, 0xE9, 0x28, 0x83, 0x79, 0x99, 0x5C, 0x99, + 0x59, 0x06, 0x91, 0xE5, 0x84, 0x99, 0x2A, 0x6C, 0x5A, 0xB9, + 0x66, 0x8C, 0x18, 0x96, 0xA4, 0xAD, 0x7A, 0xB6, 0x75, 0xF7, + 0xCF, 0x98, 0xE2, 0xF1, 0xF7, 0xEF, 0x65, 0x01, 0xE8, 0x02, + 0x14, 0xB9, 0x21, 0x50, 0x1E, 0xA6, 0x61, 0xF2, 0x86, 0xA1, + 0xC0, 0x41, 0x27, 0x02, 0xC5, 0xB6, 0x32, 0x29, 0x9D, 0x97, + 0x35, 0x6C, 0x44, 0xBB, 0x2D, 0x15, 0x26, 0x17, 0x4A, 0xD4, + 0x90, 0x05, 0xC9, 0x1E, 0x46, 0xC5, 0x0A, 0x57, 0xFC, 0x19, + 0x9E, 0x2D, 0x99, 0x19, 0xCA, 0xFD, 0x1A, 0x65, 0x88, 0xD5, + 0x56, 0x8F, 0x12, 0x2D, 0x73, 0x37, 0xAE, 0x26, 0x66, 0x4C, + 0x8D, 0x31, 0x7E, 0xE8, 0xDE, 0xDA, 0xDD, 0x5D, 0x61, 0xF0, + 0x61, 0x21, 0x4A, 0xD3, 0x3A, 0x7B, 0x58, 0x0E, 0xC1, 0x43, + 0x0D, 0x75, 0xCB, 0x1A, 0x53, 0xF1, 0x14, 0x4A, 0x85, 0x62, + 0xC1, 0xE1, 0xAF, 0xFE, 0x67, 0x53, 0x62, 0x53, 0xB1, 0x26, + 0x8C, 0x96, 0xA4, 0xB3, 0x1D, 0x17, 0x7A, 0x87, 0xFE, 0x6B, + 0x53, 0xC0, 0x5B, 0xC4, 0x9B, 0x68, 0x87, 0xBA, 0x25, 0x71, + 0xB5, 0x8B, 0x42, 0xD3, 0x60, 0x3F, 0xFE, 0x29, 0x20, 0x3F, + 0x1D, 0x8F, 0xCC, 0x6F, 0xEB, 0x9C, 0x0F, 0x78, 0x19, 0x93, + 0x1E, 0xF5, 0xC6, 0x6D, 0x46, 0xE3, 0x3E, 0x27, 0xF0, 0xAD, + 0x3E, 0xB7, 0xA2, 0x35, 0x5C, 0x8A, 0xE5, 0x8F, 0xC8, 0xFA, + 0x9E, 0x22, 0x64, 0x8D, 0x75, 0xAA, 0x2B, 0xD5, 0xB8, 0x32, + 0xB1, 0x76, 0x70, 0x5D, 0xF0, 0x05, 0x5E, 0x15, 0xF0, 0x7C, + 0xF6, 0xDA, 0xE2, 0xDF, 0xE9, 0xB0, 0x08, 0x30, 0x97, 0xD4, + 0x39, 0xA9, 0x74, 0x86, 0x83, 0xAC, 0xC2, 0x36, 0x2A, 0xA4, + 0xBA, 0x1A, 0xEE, 0x0D, 0xAD, 0x51, 0x17, 0x54, 0x8D, 0x1A, + 0x75, 0xAA, 0xD0, 0x74, 0x4B, 0x68, 0xA3, 0x81, 0xC6, 0xFB, + 0x91, 0x87, 0xA6, 0xC4, 0x47, 0xCC, 0xB7, 0x78, 0xD6, 0x6F, + 0xB9, 0x23, 0xEF, 0x85, 0xD8, 0xF6, 0x7C, 0x7D, 0x9F, 0x6F, + 0x69, 0x97, 0x75, 0xC9, 0x81, 0xD9, 0xD7, 0xD6, 0x8B, 0x85, + 0xF4, 0x17, 0x93, 0x4C, 0xF6, 0xF5, 0x0C, 0x50, 0xCB, 0xDE, + 0x36, 0x2B, 0xD6, 0x74, 0x64, 0x65, 0xB9, 0xE9, 0x16, 0x65, + 0x07, 0x26, 0xA3, 0xB2, 0x31, 0xA8, 0xB7, 0x4B, 0x04, 0x3A, + 0x9A, 0x7A, 0xAE, 0x1E, 0xD5, 0xA0, 0x55, 0x9D, 0x3A, 0xDF, + 0x4F, 0xAC, 0x0A, 0xA2, 0xC1, 0x67, 0x57, 0x9C, 0x83, 0x67, + 0xD6, 0x11, 0x38, 0x36, 0x2B, 0x8B, 0x1F, 0x8C, 0xC8, 0xAD, + 0xC5, 0x67, 0x77, 0xF2, 0xB8, 0xA6, 0x07, 0x5D, 0xB8, 0x4F, + 0xDB, 0xFA, 0x4D, 0x3F, 0x21, 0xC1, 0x60, 0x4D, 0xE6, 0xB3, + 0xF8, 0xED, 0xEE, 0x7A, 0xD3, 0xEE, 0x4D, 0x4A, 0xCA, 0x32, + 0xDD, 0x81, 0x24, 0xA5, 0x30, 0x40, 0x80, 0xBA, 0x86, 0xC7, + 0x87, 0x2E, 0x49, 0x9C, 0x34, 0x65, 0xC3, 0x89, 0x2C, 0xDE, + 0x20, 0x4E, 0x36, 0x36, 0x78, 0xB6, 0xEB, 0x08, 0x2B, 0x08, + 0x91, 0x4F, 0x98, 0x48, 0xE7, 0xC3, 0x43, 0x74, 0xEE, 0x9E, + 0x3F, 0x1F, 0xE5, 0x83, 0x30, 0xC4, 0x2C, 0x9F, 0x99, 0x10, + 0xF3, 0x1E, 0xA6, 0x93, 0x16, 0xF4, 0xC5, 0x85, 0x16, 0x8D, + 0x47, 0xAA, 0x3C, 0xCA, 0x6D, 0x49, 0x56, 0xD0, 0xEC, 0x4C, + 0xD1, 0x9C, 0x13, 0xE9, 0xDC, 0x3B, 0x5C, 0x53, 0x4B, 0xDF, + 0xA0, 0x8D, 0x0B, 0x4F, 0x18, 0x10, 0xBC, 0xE3, 0x78, 0xAB, + 0xC6, 0x9D, 0xCB, 0x90, 0xEB, 0x2D, 0xA8, 0xEA, 0x92, 0x60, + 0xCC, 0xDC, 0x5A, 0xEE, 0xAF, 0x44, 0x8A, 0x4C, 0x64, 0xB2, + 0x5A, 0x9E, 0xB5, 0xF6, 0x09, 0x35, 0x29, 0xF7, 0x47, 0x12, + 0x1F, 0xAD, 0x2B, 0x4F, 0xC7, 0xF3, 0xD4, 0xF2, 0x25, 0xA1, + 0xDA, 0x75, 0x40, 0x47, 0x6A, 0x6A, 0x27, 0x0F, 0xF0, 0xA7, + 0x97, 0x50, 0x7A, 0xE4, 0xDF, 0xFF, 0x6A, 0xC6, 0xAC, 0x5B, + 0x3E, 0xE5, 0x54, 0x76, 0x45, 0x90, 0xE6, 0x5D, 0xAB, 0x09, + 0x50, 0x80, 0x95, 0xCD, 0x44, 0x99, 0x55, 0xBB, 0xA5, 0xC8, + 0x33, 0xEE, 0x8F, 0x44, 0xA3, 0xA1, 0xA1, 0xB9, 0x21, 0x20, + 0x25, 0x4F, 0xB8, 0x29, 0x47, 0x49, 0xAE, 0xE4, 0x01, 0x96, + 0x31, 0x44, 0x57, 0x5C, 0x64, 0x57, 0xDD, 0x85, 0x05, 0xE7, + 0xF1, 0x42, 0x87, 0xDF, 0x10, 0x4D, 0x03, 0x53, 0x17, 0xC2, + 0x6D, 0x3A, 0x06, 0x53, 0x4F, 0xE4, 0xDF, 0x9A, 0x38, 0xA3, + 0x38, 0x46, 0x3C, 0x6E, 0xF2, 0x6C, 0x73, 0xA7, 0x8F, 0x4B, + 0xFF, 0xFE, 0xB6, 0x74, 0x3E, 0xEE, 0xD4, 0xC8, 0xC6, 0x8F, + 0xC9, 0x15, 0x17, 0x55, 0x9C, 0x84, 0x31, 0x7F, 0x31, 0xDC, + 0x1F, 0x44, 0x9E, 0xEE, 0xD9, 0xF7, 0xA0, 0x80, 0x05, 0xB9, + 0x2F, 0xDA, 0x99, 0xA7, 0x4C, 0xBA, 0x23, 0x77, 0x5D, 0x12, + 0xFF, 0x27, 0xC1, 0x9B, 0x72, 0xB7, 0x90, 0x9E, 0x82, 0x8A, + 0xFF, 0x1C, 0x41, 0x20, 0xED, 0xC7, 0x68, 0x22, 0xAA, 0x6C, + 0x34, 0x26, 0xDE, 0xB8, 0x6A, 0x41, 0x41, 0xDA, 0x60, 0x67, + 0x5D, 0xCE, 0x58, 0x73, 0x82, 0x7B, 0x46, 0x9F, 0x92, 0x0A, + 0x73, 0x95, 0x30, 0xB5, 0x38, 0x6E, 0x16, 0x77, 0xB0, 0xCC, + 0xDF, 0x3B, 0x6A, 0x4C, 0xC2, 0x59, 0xB1, 0x05, 0x6A, 0x2B, + 0x74, 0xC1, 0xE4, 0xBB, 0x05, 0xB6, 0xA4, 0xD9, 0xBE, 0x79, + 0xDE, 0x4E, 0x3A, 0xA2, 0x8C, 0xBF, 0x51, 0x34, 0x53, 0x65, + 0xBD, 0x27, 0xB2, 0x00, 0xA8, 0x00, 0x16, 0xF3, 0xF5, 0xE9, + 0x97, 0x16, 0xAA, 0xE3, 0x0A, 0xC4, 0xA7, 0xCD, 0x94, 0x49, + 0xF0, 0xD3, 0xCF, 0x4D, 0x61, 0x4E, 0x6D, 0xCB, 0x8A, 0x13, + 0xDD, 0x29, 0x11, 0x0D, 0x63, 0x7B, 0x6B, 0x37, 0x9E, 0x93, + 0x21, 0xA0, 0x65, 0xE5, 0x82, 0xD6, 0xC4, 0xB0, 0x9E, 0xE1, + 0x9B, 0xBC, 0xE6, 0x77, 0x3C, 0xAB, 0xFA, 0xFE, 0xA4, 0xBE, + 0xBE, 0x5B, 0x50, 0xB1, 0xFD, 0x7E, 0x33, 0xAB, 0x79, 0x4D, + 0xEA, 0xF8, 0x4E, 0x7B, 0x59, 0xCD, 0x3D, 0xFF, 0xCF, 0xC2, + 0xA8, 0x1D, 0x8C, 0xED, 0x33, 0x29, 0x75, 0xA0, 0x9F, 0xC0, + 0x6F, 0xDC, 0x30, 0x86, 0xAC, 0x3B, 0x1E, 0x27, 0x47, 0xBF, + 0x6D, 0xBB, 0x5F, 0x27, 0x16, 0xA2, 0xFE, 0x0B, 0x7A, 0x87, + 0x83, 0x68, 0x6F, 0x52, 0x4E, 0x3C, 0x6C, 0xC7, 0x13, 0x80, + 0xF5, 0x73, 0xE7, 0xFE, 0xED, 0x91, 0xBF, 0xD8, 0x95, 0xEC, + 0x96, 0xFC, 0xF1, 0xA8, 0x02, 0x5F, 0xCB, 0x81, 0x89, 0x7A, + 0x22, 0xC8, 0x41, 0x19, 0x2E, 0xFD, 0x5D, 0x07, 0x3C, 0x15, + 0x11, 0x89, 0xD5, 0xB7, 0x6A, 0x79, 0x0B, 0x2D, 0x89, 0x59, + 0x14, 0x23, 0x8B, 0x16, 0xBC, 0x81, 0x7E, 0x27, 0xD8, 0xF1, + 0xB0, 0xA7, 0x1A, 0x06, 0x61, 0xE4, 0xCD, 0x7A, 0x64, 0x03, + 0x4C, 0xC3, 0x9B, 0xC2, 0x64, 0x50, 0x68, 0xB0, 0x9A, 0x9E, + 0x96, 0x28, 0x81, 0xA6, 0x89, 0xEF, 0x1D, 0xC2, 0x6D, 0xA0, + 0x1B, 0x8E, 0x9C, 0x40, 0xCD, 0x30, 0x7F, 0xBF, 0x0A, 0xAB, + 0xD5, 0xB4, 0x63, 0x57, 0x43, 0x2C, 0xC5, 0x91, 0x00, 0xCE, + 0xE1, 0xEF, 0x69, 0xC4, 0xB8, 0x39, 0x0D, 0x57, 0x5F, 0xAF, + 0x8D, 0x42, 0x99, 0xA1, 0x36, 0x0B, 0x51, 0xF3, 0x14, 0xEC, + 0x76, 0xBD, 0x07, 0x97, 0xF8, 0x06, 0xB3, 0x67, 0x1C, 0x08, + 0x59, 0xED, 0xEC, 0x30, 0xB4, 0x2F, 0x9B, 0x9E, 0x44, 0xD4, + 0xF9, 0x97, 0x3A, 0x09, 0x5C, 0xF3, 0xFB, 0x81, 0x20, 0x82, + 0x84, 0x22, 0x6A, 0x30, 0x58, 0x47, 0xE0, 0x2D, 0x32, 0x16, + 0xB0, 0x01, 0xC1, 0xA6, 0xB3, 0x64, 0x73, 0x24, 0xDB, 0xD4, + 0xEC, 0xD5, 0xFF, 0x83, 0xB0, 0xDD, 0xEE, 0x2B, 0x2E, 0x4C, + 0x57, 0x04, 0x8B, 0x89, 0xDE, 0x7C, 0x55, 0x0C, 0x8A, 0xAB, + 0x8D, 0x8E, 0x61, 0x45, 0x57, 0x4A, 0xB2, 0x5D, 0xE4, 0xE8, + 0x45, 0x72, 0x5D, 0x9E, 0xFA, 0xE6, 0xD6, 0xF0, 0x8A, 0x9D, + 0xFD, 0x4A, 0xBA, 0x41, 0xEC, 0x6D, 0x49, 0xC2, 0xDA, 0x2C, + 0x0A, 0x3B, 0xBE, 0x04, 0xAA, 0xF8, 0x37, 0x5B, 0xAE, 0xF4, + 0x82, 0x12, 0x23, 0xE7, 0xC8, 0xCC, 0x11, 0xA2, 0xED, 0xAF, + 0x06, 0x06, 0xD3, 0xA0, 0xA3, 0xD9, 0xEA, 0xA6, 0x77, 0xBC, + 0x79, 0xE4, 0xC7, 0xA1, 0x6A, 0xDE, 0xA4, 0xA2, 0x6D, 0xC5, + 0x14, 0x95, 0xEB, 0x33, 0x36, 0x38, 0xB4, 0x51, 0x4C, 0x55, + 0xA9, 0x56, 0xC1, 0x13, 0x64, 0x20, 0x90, 0x3F, 0xE5, 0xD9, + 0xF4, 0xA4, 0x8F, 0x11, 0xFF, 0x2A, 0x4B, 0x3C, 0xC0, 0x29, + 0x44, 0x34, 0x04, 0xFF, 0xA1, 0xFF, 0x26, 0xF9, 0x72, 0x08, + 0x72, 0x8A, 0x4A, 0x68, 0x9E, 0x64, 0xB3, 0xBF, 0x0A, 0x66, + 0x56, 0x64, 0x6C, 0x08, 0x37, 0xC6, 0x20, 0x72, 0x61, 0x84, + 0x99, 0xCC, 0x38, 0x2B, 0xDF, 0xE6, 0x45, 0x0B, 0x1B, 0xA8, + 0x97, 0x51, 0x0E, 0x08, 0x8A, 0xED, 0x3B, 0xD8, 0x09, 0x21, + 0xFD, 0xF8, 0x24, 0x00, 0xFE, 0xCA, 0xAB, 0xA3, 0x66, 0x41, + 0x3F, 0xBF, 0x38, 0x75, 0x9F, 0xA2, 0x20, 0x51, 0xCA, 0xB5, + 0x33, 0xA7, 0xE2, 0x5B, 0x70, 0x9C, 0x27, 0x44, 0x6E, 0x03, + 0x66, 0xFD, 0x01, 0xA9, 0xCF, 0x30, 0xC6, 0xC6, 0xD9, 0x1C, + 0xA3, 0x9C, 0x8D, 0x69, 0x45, 0x40, 0xEB, 0xD7, 0x05, 0x2E, + 0x6B, 0x19, 0x9A, 0x6C, 0x76, 0x07, 0x2D, 0xFE, 0xC1, 0x05, + 0x2D, 0x88, 0x39, 0x10, 0x83, 0x9E, 0x6A, 0x0B, 0x3D, 0x30, + 0x02, 0xA5, 0xC7, 0x75, 0x4B, 0x2E, 0x35, 0xFD, 0xA9, 0xBE, + 0x05, 0xDF, 0x3C, 0x62, 0x01, 0x91, 0x56, 0x1A, 0x93, 0xB7, + 0xCA, 0x16, 0x13, 0xDA, 0xF9, 0x9D, 0x00, 0xB8, 0x64, 0xA6, + 0x49, 0xB6, 0xAD, 0x05, 0xD6, 0xF1, 0x67, 0x6A, 0x55, 0xE5, + 0x57, 0x17, 0x36, 0xCD, 0xD1, 0x54, 0x4B, 0x8B, 0xA8, 0x39, + 0xEA, 0x25, 0xE6, 0x93, 0xE9, 0x49, 0x1F, 0x48, 0x6E, 0xEA, + 0x3F, 0x8F, 0x54, 0xB0, 0xBD, 0xF6, 0x06, 0xE8, 0x90, 0x68, + 0xF0, 0x0D, 0xC4, 0x63, 0x20, 0x7F, 0x5C, 0xBC, 0xE5, 0x25, + 0x74, 0xDC, 0xF7, 0xEE, 0x59, 0x3C, 0xF4, 0x7E, 0x8F, 0x7D, + 0x51, 0x70, 0x60, 0x37, 0x70, 0x67, 0x35, 0xA3, 0x51, 0x37, + 0xCC, 0x1C, 0x87, 0x20, 0x39, 0x4C, 0x3D, 0x44, 0xE8, 0x9A, + 0x3D, 0x6F, 0x57, 0x88, 0x1F, 0xEA, 0xC0, 0xEA, 0x82, 0x3B, + 0x21, 0xBF, 0x16, 0xAC, 0x7E, 0x5F, 0x95, 0xE6, 0xD2, 0x56, + 0x67, 0x9E, 0x35, 0x95, 0x1C, 0xE1, 0xF1, 0x5C, 0x0B, 0xBA, + 0x8A, 0x3E, 0x6E, 0xEA, 0xE8, 0x26, 0x27, 0xCE, 0x7E, 0xCE, + 0x01, 0x0D, 0x52, 0x8A, 0xF7, 0x2D, 0x99, 0x8C, 0x58, 0xAF, + 0x67, 0x77, 0x06, 0xE8, 0x24, 0x0C, 0x2A, 0xFE, 0x7D, 0x78, + 0xB5, 0x98, 0x2D, 0x88, 0x78, 0xB1, 0x2E, 0x92, 0x72, 0xC2, + 0x63, 0xEA, 0xC9, 0x2D, 0x91, 0x90, 0x22, 0xFC, 0x41, 0xCA, + 0x64, 0x20, 0x84, 0x2D, 0x74, 0xF5, 0x8E, 0x89, 0xB2, 0x94, + 0x27, 0x1C, 0xC6, 0xE0, 0xA7, 0x2D, 0x34, 0x84, 0xE0, 0xCA, + 0xD6, 0xBE, 0x6B, 0x53, 0xAF, 0x92, 0x97, 0x5D, 0x45, 0x74, + 0xF0, 0x98, 0xB8, 0xA1, 0x11, 0x49, 0xCE, 0x4E, 0x26, 0xBB, + 0x8E, 0x48, 0x25, 0x15, 0xF2, 0xFF, 0x4F, 0x7A, 0x73, 0x40, + 0x2C, 0x2E, 0x68, 0xA6, 0x9B, 0x9C, 0x9D, 0x5D, 0x55, 0xEF, + 0xE5, 0x74, 0x22, 0xDF, 0x16, 0x50, 0x77, 0xE9, 0xBF, 0x7E, + 0x4B, 0x77, 0xAB, 0x50, 0x1C, 0x1B, 0xC0, 0x97, 0x91, 0xB5, + 0x11, 0xB3, 0x95, 0x38, 0xF0, 0xAB, 0xF7, 0x49, 0x7B, 0x91, + 0x7E, 0x70, 0x70, 0xA1, 0x30, 0xA4, 0x22, 0x1F, 0x0A, 0xDD, + 0xBF, 0xE4, 0x5E, 0xC4, 0x49, 0x5E, 0xCA, 0xE6, 0x4F, 0xC4, + 0x8B, 0xEA, 0x6C, 0x7D, 0x45, 0x97, 0x76, 0xB3, 0x8F, 0x79, + 0x28, 0xA1, 0xF6, 0xE0, 0x29, 0x73, 0x56, 0xD8, 0xBA, 0xD9, + 0xEE, 0x0E, 0x16, 0x58, 0xF3, 0xC5, 0xB9, 0xAB, 0x7B, 0x94, + 0x11, 0x5B, 0x10, 0x36, 0x1B, 0xCB, 0x1B, 0x61, 0xDB, 0x91, + 0xF7, 0x6F, 0xA1, 0x8D, 0xB1, 0xE1, 0xFB, 0x4A, 0x05, 0x6C, + 0xD9, 0x4B, 0xFB, 0x44, 0xDB, 0xBE, 0x0E, 0x10, 0xCD, 0x8E, + 0x1D, 0x31, 0x6D, 0x9F, 0xB3, 0xE0, 0xDF, 0xDA, 0x25, 0xF7, + 0x59, 0xDD, 0x1A, 0xB2, 0xFD, 0x57, 0x20, 0x65, 0xC8, 0xFC, + 0xA7, 0x65, 0x38, 0x39, 0x81, 0x4D, 0xBF, 0xC3, 0x58, 0x26, + 0x0B, 0x48, 0x17, 0xD2, 0x63, 0x51, 0x21, 0xC6, 0x6E, 0xD8, + 0xD4, 0x1C, 0x4F, 0x72, 0xA7, 0xA6, 0x1E, 0x69, 0x73, 0xA9, + 0x2B, 0xF2, 0x5F, 0xF6, 0x88, 0x9E, 0xCA, 0x61, 0x89, 0xE4, + 0x98, 0x8C, 0xB4, 0xAD, 0x59, 0x5B, 0xDA, 0x37, 0x48, 0x71, + 0xBA, 0x2E, 0x10, 0xC9, 0x55, 0x1E, 0x63, 0xAE, 0xB6, 0xDD, + 0xC6, 0x2A, 0x26, 0x90, 0xBA, 0xB2, 0x95, 0x24, 0x11, 0x34, + 0x61, 0x17, 0x83, 0xA9, 0x7F, 0xB0, 0x9F, 0x6B, 0x2E, 0x40, + 0xD7, 0xF6, 0xCC, 0x9B, 0xD2, 0x46, 0x7F, 0xE4, 0xA2, 0x9F, + 0xA3, 0xD9, 0xAA, 0x73, 0xF9, 0x18, 0x30, 0xA8, 0x77, 0x31, + 0xF6, 0x02, 0x62, 0x4D, 0x0E, 0x51, 0x8C, 0x34, 0x40, 0x77, + 0x6C, 0xF1, 0x68, 0x7F, 0x87, 0xA9, 0xB8, 0x46, 0xE3, 0x17, + 0x5D, 0x7A, 0xED, 0x39, 0x91, 0xB7, 0x88, 0xED, 0xB1, 0xBB, + 0x20, 0x3B, 0xA9, 0x18, 0x6E, 0xCE, 0xDE, 0xDA, 0x07, 0x91, + 0xD5, 0xE8, 0x2D, 0xE1, 0x8B, 0xF8, 0xB3, 0x87, 0xA8, 0xF7, + 0xBE, 0x12, 0x9E, 0x5C, 0xCE, 0xC8, 0xCE, 0x07, 0x4D, 0xCC, + 0x12, 0xE2, 0xBA, 0xDA, 0xE6, 0x4F, 0x49, 0x1D, 0x3C, 0x6F, + 0x42, 0xCD, 0x6A, 0x1E, 0x53, 0x9D, 0x64, 0xD6, 0x3C, 0xCC, + 0x16, 0x97, 0xFE, 0x6A, 0x57, 0xC7, 0x04, 0x3A, 0x5D, 0x89, + 0xAA, 0x57, 0xB7, 0x0E, 0xAE, 0x2D, 0xF4, 0x72, 0x68, 0x83, + 0xBC, 0x15, 0xD0, 0x74, 0xC8, 0x06, 0x93, 0x40, 0xFD, 0xC7, + 0x26, 0x7F, 0x19, 0x92, 0xB5, 0xB2, 0x23, 0x60, 0x60, 0x90, + 0xEB, 0xBE, 0x30, 0x0E, 0xDC, 0xA9, 0x99, 0x4A, 0xAB, 0xB0, + 0x1A, 0xEB, 0xB5, 0x33, 0xD5, 0xE2, 0xFA, 0x49, 0xCF, 0x98, + 0xC9, 0xF8, 0x74, 0xFF, 0x12, 0x7F, 0x1E, 0x98, 0x67, 0xA8, + 0xCF, 0xBB, 0xD0, 0x1F, 0x26, 0xD3, 0x3C, 0xD3, 0xA2, 0xB2, + 0x83, 0xB1, 0x68, 0x57, 0x4E, 0x6F, 0xEF, 0xED, 0x0B, 0xBE, + 0x33, 0x05, 0xB8, 0x7D, 0x75, 0x2C, 0x12, 0xF0, 0x05, 0x40, + 0xD6, 0xA9, 0x43, 0x0D, 0x6A, 0x13, 0x63, 0x93, 0xE8, 0xB2, + 0x0D, 0x7B, 0xC1, 0xB3, 0xB9, 0x51, 0x59, 0x3C, 0xF1, 0x47, + 0x70, 0x68, 0x25, 0x28, 0x70, 0xDE, 0x65, 0x89, 0xDD, 0xFD, + 0x43, 0x23, 0xF0, 0x39, 0x9C, 0x1C, 0x45, 0xD9, 0x77, 0x4B, + 0x9A, 0x58, 0x13, 0x35, 0x37, 0xFE, 0xD8, 0x9C, 0x46, 0xCD, + 0x1C, 0xA4, 0x26, 0xF5, 0x37, 0x9F, 0x14, 0x55, 0xE5, 0x0A, + 0x63, 0xC9, 0xDF, 0x24, 0x44, 0xB2, 0xCD, 0x63, 0xD3, 0x31, + 0xF0, 0x97, 0xF1, 0x62, 0x22, 0x48, 0x8F, 0xFA, 0x27, 0xE6, + 0xAE, 0x19, 0x2B, 0x37, 0xA2, 0x1C, 0xA8, 0x48, 0x1D, 0x13, + 0x5E, 0x5C, 0x1A, 0x48, 0xBB, 0xAD, 0xAB, 0x12, 0x5F, 0xB1, + 0xFC, 0x23, 0x05, 0xE5, 0xDA, 0x70, 0x2D, 0xC8, 0xBB, 0x0A, + 0xFC, 0x2F, 0x7D, 0x4A, 0x48, 0xC6, 0x88, 0x37, 0x51, 0xCE, + 0x64, 0x32, 0x14, 0x9F, 0x53, 0x08, 0xCA, 0xC6, 0xB3, 0x79, + 0x9D, 0x65, 0x01, 0x8F, 0xB9, 0xD6, 0x2B, 0xCA, 0x35, 0x49, + 0xB3, 0x37, 0xDF, 0x22, 0x70, 0xA7, 0xF2, 0xFC, 0x43, 0xE0, + 0x05, 0xE8, 0xF6, 0x7F, 0xDB, 0xB9, 0xFD, 0xB8, 0xF9, 0xAD, + 0x59, 0xAA, 0xD6, 0x7D, 0x71, 0x17, 0x7C, 0xA8, 0x32, 0xBF, + 0x25, 0x87, 0x6C, 0xE1, 0xCA, 0xB4, 0xFD, 0x20, 0xAF, 0x5D, + 0x47, 0x81, 0x07, 0xAF, 0x50, 0x40, 0x2C, 0x63, 0x43, 0xAD, + 0xA6, 0x31, 0x61, 0xD5, 0x8E, 0xFF, 0xC8, 0x8C, 0xC7, 0x30, + 0x1E, 0x1E, 0x06, 0xBD, 0x21, 0x3C, 0xF1, 0xB1, 0x92, 0x8D, + 0xDB, 0x41, 0x89, 0x31, 0x21, 0xCE, 0x9F, 0xAB, 0x9A, 0x4C, + 0x5D, 0xA9, 0xDA, 0x77, 0xE5, 0xE7, 0x11, 0x99, 0xC2, 0xA7, + 0xD5, 0x9B, 0xB8, 0x55, 0x47, 0x45, 0xEC, 0x24, 0xDA, 0xA0, + 0x1F, 0xD6, 0x70, 0x8C, 0x9C, 0xE8, 0x1D, 0x6D, 0x19, 0x75, + 0x99, 0xEF, 0x2E, 0x10, 0xA6, 0xF5, 0x84, 0x9A, 0xEF, 0x33, + 0x50, 0x31, 0x86, 0x0B, 0x08, 0xD5, 0xFD, 0xBC, 0xDA, 0xE0, + 0x60, 0x3C, 0x00, 0xBA, 0x65, 0x79, 0xDB, 0x74, 0x8C, 0x24, + 0x91, 0xF8, 0x7B, 0x38, 0x77, 0xF2, 0x46, 0xB5, 0x13, 0xC5, + 0x22, 0x78, 0x6A, 0xEF, 0x8A, 0x0B, 0x62, 0xB5, 0x37, 0x33, + 0x10, 0xC8, 0x29, 0x68, 0x68, 0x6E, 0x9A, 0x46, 0x3E, 0xE3, + 0x78, 0x1C, 0x4C, 0x3A, 0xA8, 0x1A, 0x7F, 0x12, 0x59, 0x56, + 0xF4, 0xED, 0x3B, 0x12, 0x71, 0x69, 0xCF, 0xE0, 0x38, 0x28, + 0x55, 0xB2, 0x41, 0x6D, 0x96, 0xA5, 0x42, 0x9B, 0xDB, 0x58, + 0x9C, 0x4D, 0x9B, 0x9D, 0x70, 0x1F, 0xEE, 0xB7, 0x46, 0x73, + 0x0F, 0x09, 0x0D, 0x00, 0x11, 0xDE, 0xE5, 0x3C, 0x8D, 0xC3, + 0xCC, 0xC3, 0x86, 0xE7, 0x88, 0x13, 0x02, 0x38, 0x6C, 0x4E, + 0xC7, 0x2D, 0x78, 0x1B, 0xFA, 0x3E, 0x17, 0xCC, 0x6A, 0x14, + 0xB9, 0xFE, 0xE1, 0x01, 0x43, 0x4C, 0x5C, 0x53, 0x7D, 0x82, + 0xEB, 0x4F, 0xEA, 0x15, 0xD3, 0xD7, 0xD2, 0x90, 0x47, 0x95, + 0xE4, 0x77, 0x1C, 0xF6, 0xB4, 0xA1, 0xDB, 0x07, 0x45, 0xF1, + 0xB2, 0xC3, 0x55, 0x77, 0x04, 0xC0, 0x61, 0x9C, 0x20, 0x48, + 0x70, 0x14, 0xE1, 0xF8, 0xC4, 0x0E, 0xFD, 0x04, 0x46, 0x2A, + 0x8C, 0xAA, 0x9E, 0x31, 0x5D, 0xD0, 0xCE, 0x5D, 0xFA, 0x35, + 0x7B, 0xBC, 0x16, 0xC6, 0x55, 0x4E, 0x0B, 0x0E, 0xB4, 0x3D, + 0x24, 0xD2, 0xFE, 0xAB, 0x3C, 0xC7, 0x4C, 0xE1, 0x69, 0xF9, + 0x6E, 0x32, 0x94, 0xD6, 0x78, 0x76, 0x8A, 0x75, 0x01, 0x5D, + 0x7F, 0xE3, 0x3D, 0xCA, 0x68, 0xAE, 0x6B, 0xC8, 0x9B, 0xB8, + 0x6D, 0xC0, 0xB7, 0xC6, 0x1C, 0x67, 0x62, 0x7C, 0xC8, 0xD1, + 0x97, 0x55, 0x3E, 0xA8, 0x79, 0xD1, 0x03, 0x86, 0xE2, 0x84, + 0x74, 0x61, 0x53, 0x50, 0xC6, 0x0A, 0x10, 0x36, 0x81, 0x06, + 0xEB, 0x8F, 0x58, 0x19, 0xA9, 0xD4, 0x4E, 0xF2, 0xED, 0xA3, + 0x63, 0x06, 0xFA, 0x14, 0x3B, 0xA9, 0x97, 0xA2, 0x5D, 0x7B, + 0x4D, 0x88, 0x0F, 0x81, 0x1B, 0x1E, 0xED, 0x94, 0xCE, 0xF0, + 0x5B, 0x2B, 0x13, 0x87, 0x2B, 0x67, 0x4E, 0x27, 0xA0, 0x2E, + 0x2A, 0x85, 0x0C, 0x62, 0x41, 0xE6, 0x05, 0xD6, 0xC8, 0x67, + 0x7A, 0x1F, 0x68, 0x04, 0x5A, 0xB5, 0x50, 0xC0, 0xD4, 0xF6, + 0x86, 0xFA, 0x77, 0x19, 0xD4, 0x0C, 0xCB, 0x95, 0x66, 0x43, + 0xF7, 0xE9, 0x85, 0x24, 0xC9, 0xCC, 0x80, 0x80, 0xE3, 0x5E, + 0xA6, 0x02, 0x33, 0x8E, 0xD2, 0xFF, 0x7E, 0x94, 0x0A, 0xCD, + 0x76, 0xB4, 0x98, 0xCB, 0x89, 0xD4, 0x95, 0xF7, 0x97, 0xC6, + 0x0F, 0x8C, 0x13, 0xD1, 0x9A, 0xC2, 0xB1, 0x87, 0xE0, 0x26, + 0x3A, 0xDC, 0x52, 0xE9, 0x59, 0x52, 0xE7, 0x35, 0xF1, 0x02, + 0xE4, 0xAF, 0xDC, 0x64, 0xF9, 0xA0, 0x2B, 0x28, 0x63, 0xFB, + 0xAB, 0x26, 0x34, 0xAC, 0x24, 0x81, 0xEF, 0xF9, 0x0B, 0xB9, + 0x50, 0x4F, 0xFD, 0x1E, 0x53, 0xE2, 0xAB, 0x59, 0x95, 0x7E, + 0x27, 0x7F, 0xBF, 0xCB, 0xDD, 0xEA, 0x3B, 0x30, 0x7D, 0xD0, + 0xB2, 0x52, 0xD2, 0x24, 0xF0, 0x26, 0xAE, 0x5A, 0xBC, 0x41, + 0xC2, 0xE8, 0x9D, 0x49, 0xA5, 0xCB, 0x91, 0x85, 0x6E, 0xEC, + 0xBE, 0xBA, 0xB7, 0xF0, 0x84, 0x6D, 0x33, 0x08, 0x37, 0x85, + 0x70, 0x36, 0xD8, 0x6D, 0x41, 0x71, 0x56, 0x74, 0x1B, 0xB6, + 0xC4, 0xCB, 0x37, 0x69, 0x03, 0x03, 0x52, 0x63, 0xAA, 0xB8, + 0xC2, 0x73, 0xDB, 0x06, 0x24, 0x29, 0x11, 0x09, 0x82, 0xEB, + 0xE3, 0xEA, 0x51, 0xCF, 0x48, 0xD8, 0xAF, 0x2B, 0xF8, 0x7D, + 0x2B, 0xEF, 0x41, 0x4E, 0x06, 0x5A, 0x17, 0x3E, 0xED, 0xA5, + 0x00, 0x57, 0x85, 0x68, 0x2E, 0xCE, 0xC3, 0x0D, 0x7E, 0x3A, + 0x02, 0x92, 0xB0, 0xA9, 0x6C, 0x95, 0xA2, 0xBE, 0x50, 0xB6, + 0x55, 0xEB, 0xE3, 0xB7, 0xD4, 0x4E, 0x7B, 0xD3, 0xC2, 0x53, + 0x05, 0x29, 0x80, 0xE9, 0x49, 0x34, 0xA2, 0x31, 0x05, 0xB0, + 0x63, 0xDA, 0x13, 0xC4, 0x14, 0x33, 0x79, 0x05, 0xEC, 0x35, + 0xF4, 0xC9, 0xBF, 0xF0, 0xB6, 0xF4, 0xD4, 0xA6, 0xC3, 0xAE, + 0x64, 0xEE, 0x33, 0x85, 0xBB, 0x75, 0x2C, 0x4E, 0xC9, 0x5B, + 0x04, 0x65, 0x26, 0x59, 0x5F, 0x7A, 0x40, 0xDA, 0x2F, 0xC8, + 0x32, 0xB3, 0x08, 0xD4, 0x2B, 0x68, 0x9C, 0x95, 0x65, 0x57, + 0x40, 0xF2, 0x74, 0x20, 0x63, 0xEA, 0x69, 0x1E, 0x12, 0xD0, + 0x73, 0x2D, 0x16, 0x26, 0x05, 0x0E, 0x2F, 0x78, 0xF8, 0xA6, + 0xE9, 0xCA, 0x75, 0xA9, 0x83, 0x14, 0x95, 0xA9, 0x9B, 0xFC, + 0x9F, 0x71, 0xC5, 0x3C, 0x03, 0x1B, 0x87, 0xCF, 0x37, 0xD8, + 0xDC, 0x30, 0xD9, 0x3C, 0x97, 0x77, 0x79, 0xDC, 0x4A, 0x73, + 0xF5, 0x71, 0x95, 0x09, 0x0E, 0xC1, 0x59, 0xD7, 0x8D, 0x4A, + 0xEC, 0x95, 0x13, 0x55, 0x17, 0xEA, 0xB4, 0x4D, 0xC2, 0x89, + 0xEE, 0x35, 0x1B, 0xA9, 0xD4, 0xB9, 0x42, 0xA9, 0x22, 0x5C, + 0x51, 0x95, 0x88, 0xE4, 0xCE, 0xD0, 0xB7, 0xBB, 0x62, 0x13, + 0xCC, 0x62, 0x2D, 0xAB, 0x61, 0x49, 0x7B, 0xDC, 0x05, 0x45, + 0x4D, 0x12, 0x70, 0x64, 0xA5, 0x43, 0xAC, 0x93, 0x21, 0x66, + 0x2D, 0x44, 0x83, 0x1C, 0x32, 0xC2, 0x67, 0x07, 0xC4, 0x92, + 0x82, 0x1E, 0x15, 0x25, 0xDB, 0x9A, 0xBB, 0xA3, 0xAB, 0xF3, + 0xF5, 0x9E, 0x60, 0xA6, 0x2A, 0x13, 0xCC, 0x6D, 0x21, 0xC7, + 0xB7, 0x9A, 0xD6, 0x2B, 0xA6, 0x4A, 0x96, 0x00, 0x71, 0xD2, + 0xAB, 0x90, 0x7B, 0x15, 0x7F, 0xAC, 0x84, 0x40, 0x3E, 0x93, + 0x35, 0x79, 0x6E, 0xE0, 0x23, 0xFF, 0xDC, 0x09, 0x9D, 0x7F, + 0x69, 0xE6, 0x45, 0xDA, 0x35, 0x00, 0xA5, 0x83, 0x88, 0xC9, + 0x43, 0xC7, 0x27, 0xB8, 0xFA, 0x98, 0x65, 0x76, 0x98, 0x7F, + 0x5F, 0x5B, 0xB9, 0xA6, 0xAB, 0x0D, 0x70, 0xD4, 0x10, 0x98, + 0x64, 0x59, 0x94, 0xF2, 0x82, 0x0E, 0xAC, 0xB1, 0xD3, 0x0D, + 0x27, 0x81, 0x39, 0x40, 0xE1, 0xD3, 0x02, 0xE8, 0xC0, 0xC1, + 0xAB, 0x89, 0xA3, 0xDF, 0xAE, 0xDF, 0xDC, 0xA4, 0x6D, 0x27, + 0x9B, 0x20, 0xD3, 0x8E, 0x5A, 0x0B, 0x17, 0x4A, 0xEC, 0x7C, + 0x70, 0xD3, 0x1F, 0x1A, 0xF5, 0xD8, 0x4F, 0xAC, 0x24, 0x80, + 0xCA, 0xC2, 0x50, 0xBF, 0xA0, 0xE0, 0x2B, 0xD4, 0xA2, 0xAC, + 0x3A, 0xF6, 0xC2, 0x9E, 0xC0, 0x43, 0x81, 0x53, 0xEE, 0xB9, + 0xCA, 0xCE, 0x53, 0xF4, 0xED, 0x29, 0x65, 0x58, 0x34, 0x80, + 0x91, 0x81, 0xB6, 0x1B, 0x78, 0xFF, 0xE5, 0x71, 0x41, 0xB8, + 0xB7, 0xB0, 0x49, 0xD1, 0x32, 0x18, 0xA7, 0x35, 0x96, 0x5B, + 0xBE, 0xE4, 0xFD, 0xC4, 0xC0, 0xDE, 0x66, 0x33, 0xF4, 0xF0, + 0x2D, 0x59, 0x72, 0x8E, 0x68, 0x97, 0xC4, 0x0B, 0x35, 0x0D, + 0xFB, 0x84, 0x7F, 0x1F, 0x96, 0xE9, 0x41, 0x4C, 0x2F, 0x85, + 0x3E, 0x80, 0x9D, 0xAF, 0xD9, 0xCB, 0xA1, 0xED, 0x6F, 0x3E, + 0x91, 0x94, 0xDE, 0x7B, 0x4B, 0x66, 0x8B, 0x70, 0xD4, 0xFA, + 0x22, 0x65, 0xF1, 0x03, 0xCF, 0x6D, 0xFB, 0x5F, 0x9D, 0x9E, + 0xF8, 0x61, 0x30, 0x2B, 0xE1, 0x88, 0x3E, 0xF8, 0x41, 0xAB, + 0x18, 0x0D, 0xD4, 0xF4, 0xD4, 0x42, 0x46, 0xEF, 0xB0, 0x35, + 0x8B, 0xE5, 0x65, 0x61, 0x9C, 0x64, 0x0C, 0x49, 0xAE, 0x99, + 0x68, 0xE9, 0x08, 0xF4, 0x26, 0xCA, 0x8F, 0x13, 0xE9, 0x00, + 0xBF, 0x84, 0x71, 0x45, 0x52, 0xA5, 0xD3, 0xAF, 0xC1, 0x6B, + 0xC3, 0x87, 0x44, 0x03, 0x72, 0x95, 0xC3, 0x5F, 0x9C, 0x7C, + 0xA1, 0xC5, 0x12, 0x77, 0x24, 0xED, 0xDA, 0xB5, 0x97, 0xA9, + 0x14, 0xB6, 0x8B, 0xEC, 0x08, 0xBF, 0xEF, 0xEC, 0xC3, 0x55, + 0xE5, 0x96, 0x8B, 0x8E, 0x78, 0x3C, 0x9D, 0x72, 0x60, 0x9C, + 0x5B, 0x6D, 0x90, 0xD6, 0x9F, 0xD5, 0x27, 0x0F, 0x37, 0xBF, + 0x09, 0x38, 0x43, 0xB4, 0x63, 0xAE, 0x0B, 0x34, 0xF4, 0xFC, + 0xCF, 0x3B, 0x27, 0x1D, 0xEB, 0xB8, 0xED, 0x63, 0xF8, 0x15, + 0xAE, 0xE8, 0x83, 0xA5, 0x59, 0xA3, 0xCA, 0x0F, 0x8D, 0xC5, + 0xA5, 0x7B, 0xDD, 0x8C, 0x31, 0x49, 0x5C, 0x7D, 0x39, 0xE4, + 0x82, 0x84, 0x93, 0xFC, 0x7C, 0x5B, 0x1D, 0xC0, 0x08, 0x92, + 0xAE, 0xF8, 0xC8, 0x51, 0x49, 0x26, 0x47, 0x94, 0x39, 0x7C, + 0xF4, 0xC3, 0xDE, 0x76, 0x5C, 0xA8, 0xBE, 0xFB, 0x1F, 0x9D, + 0xE8, 0x82, 0xD5, 0x25, 0xC7, 0xE1, 0x4F, 0x48, 0x6D, 0x69, + 0x77, 0x98, 0xDF, 0x94, 0x2A, 0x40, 0xAF, 0x4F, 0xDB, 0x29, + 0x52, 0xCB, 0xAA, 0x6A, 0xB6, 0x29, 0x45, 0x70, 0xCC, 0xED, + 0x11, 0xB8, 0x3D, 0xFA, 0x2E, 0xF3, 0xEC, 0x82, 0x26, 0x36, + 0x36, 0x05, 0x1A, 0x39, 0x9F, 0xE6, 0x12, 0x29, 0xF5, 0xC2, + 0x65, 0x94, 0xFF, 0x19, 0xB2, 0xFE, 0xCB, 0x66, 0xF9, 0x0B, + 0x3C, 0x36, 0xEE, 0xB1, 0x71, 0x8E, 0x0F, 0x67, 0x32, 0x12, + 0xC3, 0xAC, 0x1C, 0xB1, 0xE7, 0x09, 0xE8, 0x73, 0x39, 0x08, + 0x73, 0x7D, 0xC8, 0xE5, 0xA9, 0x9A, 0x01, 0x46, 0x2E, 0x83, + 0xC3, 0xBE, 0xC0, 0x32, 0x0D, 0x7A, 0x91, 0x86, 0x38, 0x47, + 0x8B, 0xE4, 0x88, 0x66, 0x96, 0x32, 0x7F, 0x8C, 0x6A, 0x90, + 0xA1, 0x62, 0x73, 0xDD, 0x69, 0xBC, 0x81, 0xD6, 0x9E, 0x13, + 0x34, 0xF3, 0xA7, 0x07, 0xC6, 0xD5, 0xC6, 0x12, 0x04, 0xB6, + 0x65, 0x41, 0x01, 0xC3, 0x0C, 0x56, 0x3C, 0x98, 0x5C, 0xA0, + 0xBA, 0x2A, 0xC5, 0xF9, 0xFB, 0x3E, 0xD2, 0x2D, 0xD0, 0x44, + 0xD2, 0xDA, 0x73, 0x45, 0x7A, 0x1C, 0x7C, 0x22, 0x49, 0x5B, + 0xB3, 0x20, 0x94, 0x20, 0x5E, 0xE7, 0x06, 0x33, 0xC7, 0x5A, + 0x4B, 0x71, 0xDE, 0x4A, 0xC3, 0xC2, 0x80, 0xD2, 0x04, 0xF2, + 0xE3, 0x8E, 0x47, 0x52, 0xA5, 0xA1, 0x65, 0xF3, 0x8A, 0x64, + 0xBC, 0xD6, 0x4C, 0xC3, 0x9E, 0xD2, 0x9F, 0x45, 0x09, 0x0E, + 0xE6, 0x69, 0xA2, 0xFA, 0xC2, 0x2A, 0x95, 0xFA, 0xD4, 0x00, + 0x2A, 0x03, 0x7B, 0xE5, 0xCF, 0x2D, 0x20, 0xCF, 0x90, 0x87, + 0x10, 0x75, 0x51, 0x13, 0x12, 0xE1, 0xD7, 0x08, 0x02, 0x2E, + 0x16, 0x3E, 0xF9, 0xAD, 0xDB, 0xA8, 0xC4, 0x7D, 0x05, 0x7A, + 0x45, 0x17, 0x38, 0xF8, 0x84, 0xCF, 0xE2, 0xDC, 0x3A, 0xB4, + 0x12, 0x0A, 0x0B, 0x4F, 0x05, 0x8A, 0x84, 0xF8, 0xCB, 0xBF, + 0xA9, 0xE8, 0xD1, 0x32, 0xE2, 0x6A, 0x3D, 0x9C, 0x26, 0x33, + 0x26, 0xBC, 0x36, 0x23, 0x2D, 0x83, 0x7D, 0x3B, 0x1F, 0x1C, + 0xA6, 0xE9, 0x48, 0xAB, 0xF0, 0xF7, 0x1A, 0xBF, 0x23, 0xF4, + 0xC2, 0x89, 0x95, 0x41, 0xE0, 0x60, 0xAE, 0x05, 0x05, 0xA9, + 0x9F, 0x66, 0xA9, 0xEF, 0x9F, 0x15, 0x48, 0x9C, 0xB1, 0x3D, + 0x33, 0x75, 0x75, 0x82, 0xA3, 0x39, 0x06, 0xD5, 0x35, 0x14, + 0xB1, 0x89, 0xB1, 0x2F, 0x65, 0xB6, 0x42, 0x69, 0x80, 0x09, + 0xC8, 0xBE, 0x3C, 0x6C, 0xED, 0xD7, 0x67, 0x48, 0x84, 0xA3, + 0x07, 0x24, 0x1D, 0xD1, 0xB0, 0xCC, 0xF6, 0x02, 0x27, 0xA8, + 0xF0, 0xFE, 0xF0, 0xF3, 0xE9, 0x56, 0xB2, 0xF2, 0xA3, 0x21, + 0x2C, 0x5B, 0x03, 0x34, 0x71, 0x92, 0x87, 0xDB, 0x53, 0xC5, + 0xFC, 0x9B, 0x21, 0x4D, 0x3A, 0xE3, 0xF0, 0x95, 0x1A, 0x4B, + 0x88, 0x36, 0xFA, 0xEF, 0x63, 0xBF, 0xC4, 0x33, 0x18, 0x42, + 0x5A, 0xB2, 0x4C, 0xA3, 0x3D, 0x7F, 0x80, 0xB2, 0x40, 0x69, + 0x23, 0x07, 0x82, 0x83, 0xA7, 0x10, 0xAF, 0x81, 0xD7, 0x15, + 0xE2, 0xFF, 0xDD, 0xFC, 0x51, 0xC9, 0x4E, 0x11, 0x61, 0xC5, + 0xED, 0x14, 0xE5, 0xAA, 0xD4, 0xBA, 0x1E, 0x57, 0xB3, 0xF4, + 0x48, 0xCB, 0x7D, 0x1C, 0xA4, 0x70, 0x3B, 0xCA, 0xFF, 0xA6, + 0x24, 0x06, 0xB3, 0xBC, 0x3C, 0x9F, 0xB7, 0xD9, 0x31, 0x59, + 0x41, 0x58, 0xA7, 0xDC, 0x69, 0x28, 0xD1, 0x7A, 0x79, 0x8C, + 0x05, 0x18, 0x0E, 0x5E, 0x46, 0xA5, 0x25, 0x35, 0xEC, 0x69, + 0xED, 0x6A, 0x40, 0x7C, 0x9E, 0xDE, 0x75, 0xBD, 0xB2, 0x02, + 0xE1, 0x24, 0x71, 0xC5, 0x70, 0x08, 0x44, 0xB3, 0x02, 0x0E, + 0xB6, 0x59, 0xB9, 0x53, 0xBC, 0xF9, 0x0E, 0xE2, 0x2F, 0x2A, + 0x8B, 0x0D, 0x70, 0x09, 0x84, 0x5A, 0xE4, 0x56, 0x52, 0xCE, + 0x6B, 0xE1, 0x92, 0xC0, 0x6E, 0x56, 0xD4, 0x19, 0x61, 0xDE, + 0xA9, 0x1B, 0x82, 0xAB, 0x70, 0xFA, 0x77, 0xAF, 0xF5, 0xF7, + 0xE0, 0xF8, 0x59, 0x94, 0x65, 0x7F, 0xEC, 0x49, 0x2E, 0x79, + 0x64, 0xA9, 0x27, 0xE0, 0x4F, 0xD0, 0xCA, 0x9C, 0xFB, 0xF9, + 0x81, 0x17, 0xC9, 0x64, 0xDB, 0x07, 0x41, 0x3A, 0xE0, 0x5D, + 0x71, 0x17, 0x86, 0x4E, 0x8C, 0xAD, 0xEE, 0xD1, 0x62, 0xA0, + 0xB6, 0x5B, 0xE1, 0xB5, 0xC1, 0xBF, 0xB2, 0x5E, 0x54, 0xF0, + 0x9F, 0xF6, 0xB8, 0xDB, 0x28, 0x56, 0xDB, 0x7D, 0xFA, 0x39, + 0xB3, 0xC5, 0x25, 0x8D, 0x6F, 0xEE, 0xB6, 0x4E, 0x54, 0x60, + 0xDA, 0xCF, 0x74, 0x81, 0x93, 0x9E, 0xE3, 0xB7, 0x9A, 0x7E, + 0x9B, 0xE5, 0x35, 0xCA, 0xEE, 0x0B, 0x24, 0x27, 0x78, 0xCF, + 0x67, 0x55, 0xAF, 0xAE, 0x9F, 0x5B, 0x4B, 0xE4, 0x03, 0x46, + 0x4A, 0x68, 0x16, 0xF4, 0xC2, 0xC0, 0xE5, 0xF4, 0x90, 0x95, + 0xC2, 0xD3, 0xDB, 0xD3, 0x05, 0x16, 0xD0, 0x70, 0xEF, 0x49, + 0x6C, 0x13, 0xFD, 0x4D, 0x3E, 0xBA, 0x6E, 0x88, 0xA4, 0xC3, + 0x9A, 0x70, 0xE6, 0x41, 0x0C, 0xF4, 0x88, 0x21, 0xFD, 0x60, + 0xA4, 0x7C, 0xF2, 0xD0, 0x4E, 0x11, 0xF2, 0x25, 0xA8, 0xD0, + 0xA6, 0x0C, 0x9F, 0x37, 0xB8, 0x68, 0x2A, 0x66, 0x68, 0x9B, + 0x89, 0xD7, 0xA2, 0x37, 0xD9, 0xC5, 0x5F, 0x10, 0xC2, 0xAA, + 0xFA, 0xC0, 0x9E, 0x4B, 0x5A, 0xDF, 0x41, 0xB8, 0x3E, 0x53, + 0xF2, 0xA4, 0x56, 0xBD, 0xFB, 0x46, 0x68, 0xC3, 0x66, 0x5E, + 0x84, 0xF2, 0xEF, 0xAB, 0xC9, 0x12, 0x2C, 0x2C, 0x93, 0x85, + 0xF5, 0xD9, 0x49, 0xF4, 0x32, 0xCE, 0xD9, 0x25, 0x88, 0xC2, + 0x03, 0x7F, 0x07, 0xB8, 0x6D, 0x39, 0x9A, 0xD1, 0x26, 0x4F, + 0x37, 0x50, 0xB4, 0xA8, 0xCF, 0x83, 0xF6, 0x65, 0x99, 0x27, + 0xC7, 0x25, 0x7D, 0x2F, 0x36, 0xF8, 0x41, 0x60, 0x4C, 0xE4, + 0xD9, 0xBC, 0x94, 0x98, 0x5D, 0xBA, 0x59, 0xCE, 0xD0, 0x10, + 0x40, 0x2D, 0x71, 0xD0, 0x68, 0x33, 0x5C, 0x8A, 0xF0, 0x20, + 0xD5, 0xDD, 0xF1, 0xE6, 0xC6, 0x3E, 0x8A, 0x84, 0xA5, 0xD1, + 0x70, 0x5B, 0xBF, 0x3B, 0x79, 0xD3, 0xAB, 0xB9, 0xFD, 0x62, + 0x53, 0x1C, 0x05, 0x07, 0xE2, 0xED, 0x89, 0xC7, 0x76, 0xD2, + 0xC8, 0xCE, 0x52, 0xE0, 0xAE, 0x9B, 0x30, 0x9B, 0x77, 0x71, + 0xF2, 0xDB, 0x71, 0x93, 0x94, 0x4A, 0xA7, 0xAB, 0x2D, 0xCE, + 0xD8, 0x48, 0x61, 0xAA, 0xD6, 0xFA, 0xC0, 0x36, 0x36, 0xB1, + 0x35, 0x05, 0x2E, 0x75, 0x1D, 0x44, 0x7F, 0x6D, 0xE6, 0xB2, + 0x37, 0xB5, 0x7A, 0x4B, 0x87, 0x36, 0x0A, 0xFE, 0xEF, 0xD0, + 0x9E, 0xDB, 0x7F, 0x81, 0x5D, 0x9B, 0x21, 0x12, 0xAD, 0x17, + 0x33, 0x52, 0x7F, 0xE3, 0xA8, 0x3B, 0x0F, 0x62, 0xB6, 0xD9, + 0x14, 0x71, 0x2B, 0xAC, 0xF5, 0x44, 0x6A, 0x39, 0x75, 0xBC, + 0x60, 0xB7, 0xE7, 0x03, 0x24, 0xAE, 0xE9, 0x15, 0x72, 0x25, + 0xD2, 0x32, 0x8C, 0xB5, 0x66, 0xEE, 0x73, 0x60, 0x28, 0xDC, + 0xA1, 0xD7, 0xED, 0x68, 0xF3, 0x2B, 0x9A, 0x3F, 0x40, 0xC4, + 0x4A, 0xDF, 0x62, 0x97, 0x80, 0xAB, 0xDB, 0x10, 0x8E, 0xD8, + 0x56, 0xA7, 0x96, 0xE8, 0x3F, 0xB2, 0x3C, 0x9D, 0xE3, 0x83, + 0x08, 0x68, 0x2C, 0x7F, 0x66, 0xDF, 0x3D, 0xB5, 0xD2, 0x6F, + 0x7B, 0xD1, 0x65, 0x9D, 0x00, 0xC0, 0xF0, 0x17, 0x45, 0xAD, + 0xDA, 0x0F, 0xCA, 0x5B, 0x65, 0x8B, 0x09, 0x1C, 0xA9, 0xD0, + 0x43, 0x4D, 0x41, 0x57, 0x8F, 0x7E, 0xA7, 0x65, 0x34, 0x8E, + 0x78, 0x4B, 0x1F, 0x85, 0x01, 0xD3, 0xAA, 0x8F, 0xFA, 0xAA, + 0x5C, 0x08, 0x8B, 0x98, 0x1F, 0x78, 0x5B, 0x64, 0x87, 0xB3, + 0x01, 0x84, 0x61, 0xC2, 0x3F, 0x88, 0x4E, 0xAF, 0xED, 0x8A, + 0xB6, 0x5A, 0xB1, 0x79, 0x94, 0x01, 0xFE, 0x70, 0xA7, 0x6C, + 0xD8, 0x9E, 0x7B, 0xCE, 0x80, 0x23, 0x50, 0x95, 0x20, 0xA0, + 0x81, 0x7B, 0x85, 0x84, 0x80, 0x8D, 0xAA, 0x0A, 0xF0, 0x5C, + 0xF5, 0xD9, 0xB8, 0xB3, 0x3F, 0x60, 0xD2, 0xA6, 0x31, 0x77, + 0xC4, 0x80, 0x3C, 0xF6, 0x51, 0x2B, 0x09, 0xC2, 0xB5, 0xC5, + 0x39, 0x22, 0x11, 0x9C, 0x56, 0x50, 0x45, 0x74, 0x1F, 0x03, + 0xA2, 0x3B, 0xE9, 0xBC, 0xC6, 0xEA, 0xC6, 0xEA, 0xFE, 0x5E, + 0x77, 0x88, 0x3F, 0xBA, 0x9C, 0xF6, 0x01, 0x31, 0x7A, 0x10, + 0xF7, 0x42, 0xBA, 0x6A, 0x44, 0x81, 0xC2, 0x08, 0x89, 0x4E, + 0x87, 0x0D, 0xEE, 0xBA, 0x67, 0x91, 0xC6, 0x4F, 0x1B, 0x80, + 0x3C, 0x26, 0xC8, 0xAC, 0xC6, 0xE1, 0x0E, 0x09, 0x7E, 0x82, + 0x29, 0xDB, 0x5F, 0x85, 0x84, 0x90, 0x47, 0xEB, 0xB9, 0xCA, + 0x90, 0x25, 0x09, 0x62, 0x5F, 0xA4, 0xF7, 0xFC, 0x0D, 0x12, + 0xEE, 0x13, 0x7C, 0x4A, 0x53, 0xE0, 0xE6, 0x17, 0xA0, 0x1F, + 0x13, 0xDA, 0xE8, 0x7F, 0xE1, 0x95, 0x83, 0x24, 0x23, 0x4A, + 0x5F, 0xB3, 0x7A, 0x17, 0x36, 0x8D, 0xF0, 0xD2, 0x4B, 0x13, + 0x68, 0x76, 0xA5, 0x11, 0xAC, 0xF2, 0xAC, 0x1E, 0x1D, 0x78, + 0x6A, 0x48, 0x0D, 0x14, 0xD9, 0x12, 0x76, 0x95, 0x52, 0xD2, + 0xE3, 0xD1, 0x30, 0xF9, 0xA2, 0xA5, 0x24, 0x69, 0xC4, 0xE1, + 0x2F, 0xC4, 0xC7, 0x55, 0x49, 0x5B, 0xD5, 0x3C, 0x6C, 0xB9, + 0x19, 0x79, 0x43, 0x8F, 0x23, 0x3F, 0xC3, 0xC1, 0xEA, 0x70, + 0xC1, 0xC6, 0x06, 0x73, 0xEA, 0x65, 0x9D, 0x4C, 0x81, 0xB0, + 0x08, 0xF7, 0x55, 0xC0, 0xF9, 0x32, 0x97, 0xE1, 0x31, 0x42, + 0x96, 0xB8, 0x42, 0xE0, 0x40, 0xDC, 0x15, 0x14, 0x58, 0x34, + 0xE0, 0x28, 0xCB, 0x6E, 0x9D, 0x14, 0xFE, 0xB8, 0x6E, 0x0C, + 0xBF, 0x79, 0xD9, 0x0F, 0xD2, 0x90, 0x4E, 0x7F, 0x87, 0xC1, + 0xAA, 0x79, 0xB5, 0xDC, 0x6E, 0xF0, 0x10, 0x4E, 0x21, 0x21, + 0x7D, 0x84, 0x9F, 0x41, 0xE4, 0x2A, 0x8B, 0x46, 0xA0, 0x86, + 0x62, 0x3C, 0xAA, 0x60, 0xF3, 0x7D, 0x8D, 0x14, 0xC9, 0x06, + 0x64, 0xD7, 0x99, 0x12, 0x3D, 0x92, 0x3B, 0x9E, 0xCB, 0xD9, + 0x36, 0x2C, 0x57, 0x07, 0x27, 0x89, 0x80, 0x62, 0x53, 0x26, + 0x40, 0x02, 0xDB, 0xAF, 0xBB, 0x3B, 0x8D, 0x89, 0x66, 0x6D, + 0xE8, 0xE7, 0x42, 0xA4, 0xD1, 0x13, 0x4F, 0xDD, 0x74, 0x61, + 0x5E, 0x4C, 0xC5, 0x2D, 0xF2, 0xD3, 0x03, 0xB8, 0xA2, 0xEC, + 0xC4, 0x87, 0x3C, 0xCD, 0x26, 0xA0, 0xD5, 0xA6, 0xD6, 0xCF, + 0x41, 0x50, 0x54, 0xA3, 0x43, 0x5E, 0xEB, 0x30, 0xCD, 0xC3, + 0x05, 0x8A, 0x8B, 0xAF, 0x00, 0x87, 0xD9, 0x0C, 0x4C, 0x52, + 0x97, 0x56, 0x35, 0xFB, 0xD8, 0x1E, 0x49, 0xBC, 0x5A, 0x9D, + 0xA7, 0xF5, 0x6F, 0x6C, 0xD6, 0x56, 0x01, 0xED, 0x3C, 0x19, + 0x41, 0x6F, 0x6B, 0xE4, 0xD3, 0x6E, 0x06, 0xFE, 0x61, 0x25, + 0xF5, 0x09, 0xAF, 0x6B, 0x84, 0x63, 0x37, 0xF9, 0xEF, 0xF7, + 0x5E, 0x0C, 0x0D, 0x53, 0x1E, 0x35, 0xCD, 0x68, 0x40, 0x18, + 0x18, 0x38, 0x27, 0xEF, 0x5D, 0xD7, 0xE5, 0xAA, 0x18, 0x78, + 0xE8, 0x35, 0x9D, 0x59, 0xBA, 0x0D, 0x45, 0x7A, 0x9F, 0xE8, + 0x66, 0xEA, 0xBA, 0x7C, 0xE7, 0xFD, 0x0B, 0x92, 0x60, 0x8B, + 0x47, 0x1A, 0x05, 0xC3, 0xB9, 0x89, 0xA2, 0xC2, 0xF5, 0xDE, + 0xC2, 0x57, 0x06, 0x4E, 0x59, 0xA2, 0x3E, 0xC0, 0x0A, 0x63, + 0xED, 0x59, 0x27, 0x6B, 0x47, 0xFB, 0xE2, 0x78, 0xCA, 0xD3, + 0x9E, 0xAE, 0xBA, 0x9E, 0x7A, 0xB9, 0x5B, 0x9C, 0x57, 0x96, + 0xA1, 0x34, 0x5E, 0xC1, 0x20, 0x20, 0x0E, 0xDC, 0xB1, 0xED, + 0x9D, 0x8D, 0x2F, 0x9E, 0xD0, 0x9B, 0x74, 0xA8, 0x9C, 0xCC, + 0x85, 0x74, 0x62, 0x7F, 0x1F, 0xB6, 0x1D, 0xF9, 0x2B, 0x39, + 0x55, 0xAB, 0x53, 0xE1, 0xCF, 0xAC, 0x33, 0xE8, 0x54, 0x6B, + 0xB0, 0x8E, 0xD9, 0x21, 0x26, 0x0C, 0xEF, 0x1E, 0xD6, 0x14, + 0x1B, 0x64, 0x76, 0x00, 0xDD, 0x3F, 0x22, 0x5E, 0x5D, 0x04, + 0x80, 0x99, 0xFB, 0xFE, 0x30, 0x1F, 0xDA, 0xD9, 0x56, 0x5B, + 0x2B, 0x8D, 0xCE, 0xA6, 0x10, 0x47, 0xBF, 0xE6, 0x42, 0x19, + 0x70, 0xE6, 0xBF, 0xEA, 0xD9, 0x9D, 0xB8, 0x5E, 0x68, 0x7B, + 0xE8, 0x41, 0xE1, 0x31, 0x04, 0xFD, 0x0C, 0x15, 0x38, 0xC9, + 0x3A, 0x99, 0xF8, 0x23, 0xF8, 0xDE, 0xBF, 0xFD, 0x07, 0xF5, + 0xD8, 0x94, 0xA4, 0x4F, 0x5D, 0x24, 0xA9, 0x21, 0xF3, 0x13, + 0xE8, 0xB7, 0xB5, 0x25, 0xC1, 0xC1, 0x26, 0xA7, 0x23, 0x0A, + 0xF1, 0x39, 0x98, 0xBE, 0x84, 0xB6, 0xAA, 0xD9, 0x61, 0x09, + 0x23, 0xB9, 0x2F, 0xF0, 0x12, 0xF5, 0xCC, 0x8F, 0x3A, 0xA8, + 0x66, 0x88, 0x7A, 0x74, 0xFE, 0xD9, 0x24, 0xFE, 0x55, 0x6A, + 0x3A, 0x8A, 0x7F, 0xF7, 0xEC, 0x49, 0xE7, 0xB4, 0x65, 0xF1, + 0x18, 0xCE, 0x51, 0xD4, 0xE9, 0x44, 0x85, 0xCC, 0x4D, 0x16, + 0xE8, 0xE2, 0x4F, 0xF2, 0xC9, 0x50, 0xA8, 0x3A, 0x06, 0x69, + 0xAD, 0x0F, 0x43, 0xDF, 0x08, 0x8C, 0xB9, 0x2F, 0x68, 0xFF, + 0xA5, 0x38, 0x7D, 0xE9, 0xB7, 0x9C, 0xCA, 0x98, 0x17, 0x1F, + 0x02, 0x1D, 0xEB, 0x8A, 0x06, 0x7C, 0xFE, 0x72, 0x9F, 0xA9, + 0x37, 0xEA, 0x76, 0x7D, 0x42, 0x04, 0xAF, 0x04, 0x42, 0xB6, + 0xA3, 0x30, 0x8E, 0xDC, 0x44, 0xD2, 0x80, 0x64, 0xB4, 0x9E, + 0x3A, 0xEC, 0x9A, 0xAE, 0x53, 0xC0, 0x4C, 0xAF, 0x1D, 0xAC, + 0x06, 0x46, 0xCD, 0xC4, 0x87, 0x5E, 0x11, 0x57, 0x3E, 0x41, + 0x3C, 0x73, 0x0B, 0x21, 0xA8, 0xFD, 0x63, 0x9C, 0xD9, 0x43, + 0x8B, 0xCA, 0x5E, 0xF9, 0xF4, 0x3F, 0x36, 0x0D, 0x8D, 0xBF, + 0x1D, 0xFF, 0x5E, 0xD4, 0xE3, 0x62, 0xD6, 0x79, 0xB2, 0xFE, + 0xF9, 0x59, 0x83, 0x62, 0x97, 0x1F, 0x48, 0x69, 0xD4, 0xE9, + 0xB2, 0x53, 0x65, 0x05, 0x84, 0x7C, 0x55, 0xE3, 0x4F, 0x0C, + 0x73, 0x85, 0x77, 0x24, 0x04, 0x88, 0x60, 0xC6, 0x72, 0xE5, + 0xCB, 0x68, 0xF0, 0x96, 0x22, 0x7C, 0x10, 0xBE, 0xE1, 0x17, + 0x12, 0x44, 0x8F, 0xE3, 0x9E, 0x2D, 0x78, 0xF9, 0x91, 0x57, + 0xB1, 0xB0, 0xD5, 0xB6, 0x72, 0xD7, 0x35, 0x8D, 0x9C, 0x3F, + 0x60, 0xE1, 0x6B, 0xB5, 0x37, 0x9D, 0x5B, 0x1E, 0xFB, 0xCF, + 0x49, 0xD8, 0x8D, 0x77, 0xBC, 0x9D, 0xFB, 0x5B, 0x87, 0x5B, + 0x9B, 0x4A, 0x67, 0x31, 0x0B, 0x36, 0x42, 0x15, 0x88, 0x38, + 0x96, 0x07, 0x81, 0x12, 0x89, 0x4A, 0xB8, 0x07, 0x5E, 0x3D, + 0x34, 0x1E, 0x7E, 0x1B, 0x38, 0x59, 0xF3, 0x92, 0x07, 0xC3, + 0x7D, 0xF7, 0xFB, 0xC5, 0x90, 0x51, 0x41, 0xB7, 0xEB, 0x2E, + 0xF6, 0x4A, 0x0B, 0xFF, 0x07, 0x98, 0xD2, 0x5A, 0x40, 0x2B, + 0x88, 0xB8, 0x03, 0xBA, 0x71, 0xDB, 0x93, 0x22, 0xA8, 0x37, + 0xBC, 0xE1, 0x13, 0x60, 0x83, 0x9F, 0x5E, 0x95, 0xBC, 0xBD, + 0xD1, 0xB4, 0xB2, 0x15, 0x31, 0x10, 0x00, 0x65, 0xB9, 0x8E, + 0xDB, 0x63, 0x51, 0x65, 0x51, 0x27, 0x4D, 0x28, 0x1B, 0x4F, + 0x0B, 0xA8, 0x22, 0x39, 0xA0, 0xAD, 0x32, 0xDC, 0xE5, 0xA6, + 0xD5, 0xAB, 0xA5, 0x10, 0xA9, 0x48, 0x3F, 0x2F, 0x41, 0xD4, + 0x07, 0x52, 0x36, 0x05, 0xCA, 0x57, 0x11, 0x82, 0x35, 0x11, + 0xDE, 0x03, 0xDF, 0x6B, 0xE2, 0x7C, 0x0C, 0xE8, 0xDF, 0x1A, + 0x2B, 0xC1, 0x24, 0x99, 0xDB, 0x0E, 0x51, 0x67, 0x31, 0xB9, + 0x1C, 0xF9, 0x72, 0xEB, 0x31, 0x25, 0x95, 0x1E, 0xED, 0x05, + 0xD4, 0xC3, 0xB7, 0x0B, 0x56, 0x60, 0x63, 0x12, 0x0E, 0x58, + 0x60, 0x46, 0xB6, 0x72, 0xAC, 0x40, 0xD6, 0xBD, 0xDE, 0x3C, + 0xC4, 0x43, 0x5E, 0x7F, 0x92, 0xC2, 0xA3, 0x07, 0x73, 0x2B, + 0x82, 0x9D, 0x91, 0x81, 0x53, 0xE7, 0xE9, 0xB3, 0x94, 0x90, + 0x7C, 0x80, 0x23, 0xCB, 0x76, 0x49, 0xEB, 0xDD, 0x6A, 0xF3, + 0x67, 0x47, 0x63, 0x6F, 0xE6, 0x9C, 0x22, 0x29, 0xCE, 0xBD, + 0x72, 0x5C, 0x46, 0xC9, 0x54, 0xD3, 0xDB, 0xA0, 0x5A, 0x4E, + 0xA3, 0x11, 0xEF, 0x8E, 0x0B, 0x5A, 0xE8, 0x7E, 0x29, 0xA6, + 0xD2, 0x56, 0xF9, 0x41, 0x85, 0xC1, 0x30, 0xB0, 0x77, 0x4F, + 0xAE, 0xDB, 0x2D, 0x2C, 0x8A, 0xD3, 0x94, 0x90, 0x81, 0x04, + 0xB9, 0x4C, 0x80, 0x88, 0x15, 0x43, 0x0B, 0x3D, 0xD8, 0x01, + 0xDB, 0x2C, 0x7E, 0x2E, 0x49, 0xF8, 0xB7, 0x00, 0x64, 0xAB, + 0x77, 0x39, 0xD1, 0xD9, 0xB2, 0xBA, 0x50, 0xFF, 0xFE, 0x06, + 0xCF, 0xAD, 0x5B, 0xD8, 0xE0, 0x3F, 0xE2, 0x84, 0x01, 0x30, + 0xB2, 0x5B, 0x97, 0x31, 0x56, 0x2B, 0xC6, 0xCA, 0x73, 0x57, + 0xE5, 0xB7, 0x21, 0xA4, 0x99, 0xAC, 0x47, 0xFC, 0x81, 0xBD, + 0x70, 0xF5, 0xD0, 0x1B, 0xB5, 0x67, 0xEC, 0xBE, 0xB1, 0x96, + 0xFB, 0x1A, 0xFC, 0x08, 0x2D, 0xBA, 0x82, 0xA2, 0x03, 0x75, + 0x72, 0x10, 0xD5, 0xA5, 0x54, 0xFE, 0xAD, 0x22, 0x0C, 0x98, + 0x20, 0x93, 0xA4, 0xC2, 0x26, 0xE7, 0x40, 0x64, 0x79, 0x95, + 0xAF, 0x4D, 0x49, 0x8F, 0x07, 0xAB, 0x13, 0x6D, 0x8F, 0xCC, + 0x12, 0x35, 0x41, 0x10, 0x64, 0x0A, 0x71, 0x46, 0x83, 0x05, + 0x35, 0x33, 0x0E, 0xAE, 0xC1, 0x80, 0x61, 0x56, 0x2D, 0xBC, + 0x63, 0xD2, 0xB1, 0x1F, 0xDE, 0x6D, 0xE9, 0x69, 0xCD, 0xD1, + 0x91, 0xDF, 0x65, 0x4F, 0x9D, 0x38, 0xB0, 0x4A, 0xC4, 0x62, + 0xDD, 0xCD, 0x32, 0x37, 0x22, 0x8C, 0xFC, 0xD1, 0xE5, 0xF3, + 0xCC, 0xC8, 0x94, 0x25, 0x06, 0xC9, 0x64, 0xED, 0xD8, 0x5F, + 0x09, 0x3B, 0x26, 0xFD, 0x2F, 0xAD, 0x4F, 0x32, 0x54, 0x7D, + 0xE3, 0x7E, 0x04, 0xD7, 0xF7, 0x03, 0x67, 0x8C, 0x91, 0xF8, + 0x89, 0x15, 0x2E, 0x94, 0xC2, 0xEF, 0xEF, 0x06, 0x6A, 0x30, + 0x0F, 0x34, 0xD7, 0xF8, 0x26, 0x65, 0xE0, 0x39, 0xFE, 0xD9, + 0x8F, 0x88, 0x7D, 0xEF, 0x2B, 0xA8, 0x9A, 0x00, 0x55, 0x7F, + 0x44, 0xDA, 0xE9, 0x22, 0xFE, 0x24, 0xFC, 0xF0, 0xF6, 0x8C, + 0xCB, 0x6A, 0xDB, 0x22, 0x01, 0x66, 0x20, 0x2A, 0x0A, 0x2B, + 0x01, 0x51, 0xEC, 0x6D, 0x7A, 0xBE, 0x5B, 0x96, 0x96, 0xE8, + 0x72, 0xE0, 0xC0, 0xF0, 0xAF, 0xDE, 0x41, 0x8C, 0x00, 0x21, + 0x58, 0xEB, 0x27, 0x0D, 0x9A, 0x84, 0xD1, 0xA0, 0xBB, 0x13, + 0x8F, 0xFE, 0x6C, 0xE3, 0x64, 0x90, 0xA8, 0x62, 0x8E, 0x1B, + 0x23, 0x8D, 0x6D, 0xF7, 0xD6, 0x98, 0xCD, 0xA9, 0xDA, 0x30, + 0xB0, 0x11, 0x63, 0x98, 0xE0, 0x3C, 0x7E, 0xD1, 0x82, 0xEF, + 0x75, 0x49, 0x2F, 0x0B, 0xB7, 0xFF, 0x33, 0x8E, 0x1A, 0x8D, + 0x83, 0x37, 0x59, 0xF6, 0x63, 0xCE, 0x1F, 0xBA, 0x88, 0x29, + 0x0D, 0x06, 0x18, 0xF5, 0xF5, 0x77, 0x6D, 0x92, 0x2F, 0xDD, + 0xD1, 0xE5, 0x53, 0xE7, 0x1D, 0x1B, 0x74, 0x0E, 0x30, 0x6D, + 0xDF, 0x81, 0x51, 0x63, 0xE8, 0xBD, 0x21, 0x7D, 0x52, 0x4A, + 0xC6, 0x0C, 0xF5, 0x86, 0x35, 0xD4, 0x6A, 0x6E, 0x6E, 0xA9, + 0xAB, 0x6E, 0xFF, 0xC6, 0x3F, 0xB4, 0xE6, 0x95, 0xB4, 0xF4, + 0xD0, 0xDE, 0x95, 0xEB, 0x1B, 0x5A, 0xC1, 0xDA, 0x07, 0xF1, + 0xB1, 0x49, 0xEE, 0x5E, 0x32, 0x61, 0x31, 0xBB, 0xB6, 0x62, + 0x5E, 0xD7, 0x36, 0xAC, 0x64, 0x4E, 0x80, 0xA7, 0xE6, 0xCA, + 0xBB, 0x4E, 0xB9, 0x51, 0x54, 0x01, 0xEA, 0xFF, 0x90, 0x76, + 0x83, 0x5C, 0x8E, 0xDC, 0x59, 0x22, 0xE7, 0xF7, 0x03, 0x70, + 0xC5, 0x23, 0x50, 0x76, 0x5C, 0x8A, 0x1C, 0xBD, 0xE4, 0x6F, + 0xF9, 0x3F, 0x02, 0x38, 0xE2, 0x48, 0xCC, 0x3B, 0xD9, 0x00, + 0x92, 0x6A, 0xEE, 0xD3, 0xDD, 0xD9, 0x6C, 0x73, 0x9C, 0x51, + 0xCF, 0xF1, 0xDF, 0x29, 0x65, 0x3A, 0x12, 0xD9, 0x59, 0xC5, + 0xB0, 0x1D, 0xFE, 0x64, 0xEF, 0xE4, 0xFB, 0x11, 0x42, 0x3C, + 0x73, 0x74, 0x65, 0xBF, 0x95, 0xB0, 0xE4, 0x2C, 0x3D, 0x65, + 0xCA, 0xC8, 0xAE, 0xC8, 0x9A, 0xD7, 0x14, 0xCB, 0x4C, 0x22, + 0xA8, 0x55, 0x16, 0xF3, 0xA8, 0x41, 0x2F, 0xFC, 0x48, 0xE4, + 0x39, 0x7C, 0x18, 0x34, 0x0A, 0xDE, 0x45, 0x1D, 0xB0, 0x5E, + 0xE9, 0x4D, 0xA1, 0x20, 0x9A, 0x36, 0xB4, 0xE1, 0x24, 0xA4, + 0xE1, 0x78, 0x33, 0x0E, 0xD8, 0x03, 0xC0, 0x77, 0x2B, 0x24, + 0x17, 0x51, 0x0E, 0x83, 0x0E, 0xF0, 0x0C, 0x52, 0xEC, 0xC2, + 0x9E, 0xDD, 0x93, 0x59, 0x14, 0x07, 0x1F, 0x5C, 0x92, 0xA4, + 0x5F, 0x11, 0x14, 0xF2, 0x51, 0x39, 0xA4, 0xB3, 0xAE, 0x99, + 0x70, 0x82, 0x56, 0xE7, 0x84, 0x6B, 0xCB, 0xFC, 0x73, 0x35, + 0x31, 0xA0, 0xB6, 0x75, 0x0B, 0x14, 0xAD, 0x40, 0x57, 0xF9, + 0x03, 0x5E, 0xB3, 0x08, 0x4D, 0x13, 0x96, 0xF1, 0xBF, 0xA1, + 0x62, 0x96, 0xC2, 0x91, 0x9E, 0xB1, 0x48, 0x7B, 0xF4, 0xA6, + 0xC8, 0xAE, 0x04, 0xC1, 0x27, 0x1F, 0x11, 0x83, 0xB8, 0x1B, + 0xAA, 0x5A, 0xF6, 0x68, 0x61, 0x3A, 0xF6, 0x05, 0x27, 0x94, + 0xC2, 0x64, 0x71, 0x72, 0xD9, 0xE9, 0x4B, 0xAB, 0xF7, 0xB6, + 0xDF, 0x8C, 0x68, 0x8C, 0x36, 0xA9, 0xBF, 0xD6, 0xFA, 0xC8, + 0x10, 0xB3, 0x55, 0x0E, 0xFA, 0x5E, 0xD3, 0x7B, 0x5F, 0x12, + 0xF0, 0xAF, 0x42, 0x7A, 0x22, 0x71, 0xC7, 0xD8, 0xF6, 0x99, + 0xD8, 0x0E, 0x16, 0x96, 0x1E, 0x53, 0xC5, 0x45, 0x6E, 0xE0, + 0x3B, 0xEB, 0x98, 0xBE, 0x35, 0xBA, 0x8A, 0xE4, 0x05, 0x9D, + 0x74, 0xD1, 0xCC, 0xA8, 0xC2, 0xA6, 0x10, 0x6D, 0xB1, 0xF5, + 0x8F, 0x5A, 0x0F, 0x29, 0xAF, 0x95, 0xAD, 0x73, 0x63, 0x83, + 0x60, 0x1D, 0xE4, 0xBE, 0x6F, 0xE0, 0x7B, 0x27, 0x8A, 0x56, + 0x9F, 0x3D, 0x6E, 0xF6, 0x65, 0x19, 0x4E, 0xE5, 0xDB, 0x32, + 0x17, 0x50, 0xED, 0xC0, 0x7D, 0xCF, 0xB4, 0x3F, 0x27, 0xB1, + 0xCA, 0x74, 0x4C, 0x4E, 0x82, 0xD1, 0x83, 0xE1, 0xC5, 0x3B, + 0xCA, 0x35, 0xE3, 0xA8, 0xF3, 0x95, 0xAF, 0xA7, 0x30, 0x87, + 0xAE, 0xD4, 0x73, 0xC7, 0x7C, 0xC1, 0xCF, 0x2D, 0x96, 0x1E, + 0x16, 0x0D, 0xF7, 0x28, 0x5F, 0x16, 0xA2, 0xAF, 0xDE, 0x38, + 0xA2, 0xC7, 0x27, 0x5C, 0xB7, 0x43, 0xAB, 0xCF, 0x76, 0xCF, + 0xE3, 0xB4, 0x86, 0x34, 0x82, 0x0B, 0x47, 0x79, 0x62, 0x02, + 0x3E, 0xBA, 0x29, 0x98, 0x7E, 0x2A, 0xCB, 0xB7, 0xC5, 0xA1, + 0xB7, 0x92, 0x71, 0x13, 0x5E, 0x19, 0xB2, 0x21, 0xAB, 0x8D, + 0x7F, 0x54, 0x4F, 0xCF, 0x64, 0x03, 0x7B, 0x58, 0x69, 0x83, + 0xE3, 0x10, 0xE8, 0xF3, 0xB5, 0x8B, 0x65, 0xD9, 0x04, 0xF7, + 0x7C, 0xB4, 0xBF, 0x79, 0x92, 0xF1, 0x69, 0xF2, 0x16, 0x1C, + 0xBF, 0x55, 0xA0, 0x63, 0x29, 0x9C, 0x5E, 0x53, 0x6A, 0xD9, + 0x0C, 0x3F, 0x98, 0xD8, 0x07, 0x17, 0x4F, 0x76, 0x8D, 0x69, + 0xE0, 0x68, 0x41, 0x0E, 0x29, 0x79, 0x64, 0x2A, 0xFD, 0x20, + 0xFA, 0xDC, 0xB3, 0x39, 0x94, 0x69, 0x94, 0x0F, 0x6F, 0x79, + 0x4C, 0x99, 0x49, 0xDA, 0x19, 0x88, 0x70, 0x61, 0xB4, 0xC2, + 0xDE, 0x60, 0x49, 0x6D, 0xE9, 0xF0, 0xDD, 0x75, 0x29, 0x04, + 0x41, 0x61, 0x28, 0xEE, 0x30, 0xAE, 0xCE, 0x69, 0xBE, 0x83, + 0xE5, 0x44, 0xB0, 0x3E, 0x9D, 0x94, 0xBF, 0x2B, 0xC9, 0xDD, + 0x1C, 0xDD, 0x9F, 0x34, 0xC9, 0xB9, 0xCE, 0xCD, 0x03, 0xD2, + 0x23, 0x0D, 0x09, 0xE1, 0x7A, 0x2F, 0x7C, 0xD0, 0x1E, 0x8D, + 0x2C, 0x5F, 0x93, 0x7D, 0x95, 0x12, 0xBE, 0x2B, 0xB4, 0x21, + 0xDC, 0x87, 0xA1, 0x12, 0x52, 0xA0, 0xEF, 0x11, 0x78, 0xFD, + 0x0F, 0x1E, 0xBE, 0x93, 0x8D, 0x8D, 0x67, 0xCC, 0x67, 0xF2, + 0x11, 0xDC, 0xEF, 0x9D, 0xC3, 0xB1, 0x2F, 0x7C, 0x0A, 0x94, + 0x50, 0x90, 0xAC, 0x16, 0x98, 0xF7, 0x06, 0x56, 0xDA, 0x79, + 0xF2, 0xF4, 0x31, 0xF1, 0x11, 0xDD, 0x51, 0x45, 0xE2, 0xBB, + 0x04, 0xC8, 0x28, 0x71, 0x4F, 0x87, 0x30, 0xD0, 0xE9, 0xDF, + 0xE5, 0xC6, 0xE3, 0x3A, 0x89, 0x33, 0x23, 0x02, 0xEA, 0x42, + 0x7C, 0x67, 0x41, 0x2F, 0xE0, 0xEA, 0xFF, 0x27, 0xBA, 0x5A, + 0xDD, 0x57, 0x41, 0xF6, 0x64, 0x01, 0x76, 0xDE, 0x68, 0xDA, + 0x07, 0x00, 0x12, 0x7B, 0x40, 0x09, 0x9A, 0x17, 0x2C, 0x1B, + 0xA1, 0x9F, 0x98, 0x1A, 0x70, 0x04, 0xF5, 0xAF, 0xBB, 0xFC, + 0xEE, 0xEF, 0x02, 0xE0, 0xD9, 0x03, 0xC1, 0xEB, 0xAF, 0x73, + 0x1E, 0x5B, 0x43, 0x79, 0x2B, 0xCE, 0x71, 0xE2, 0x54, 0x3A, + 0xC9, 0x40, 0x1E, 0xA9, 0xF4, 0x23, 0xD6, 0xB4, 0x4A, 0x3B, + 0xA2, 0x0D, 0xBC, 0x24, 0x92, 0x7D, 0xD2, 0x78, 0x9A, 0x96, + 0x96, 0x13, 0x0A, 0x0D, 0x20, 0x61, 0xEA, 0xF8, 0x26, 0x94, + 0xB7, 0x0D, 0x2E, 0x5C, 0xD5, 0x43, 0x76, 0x9E, 0x5E, 0x60, + 0xD0, 0x96, 0x43, 0x4F, 0x49, 0x2E, 0x83, 0x24, 0xAC, 0xFE, + 0xA0, 0x74, 0xF7, 0xB0, 0xD3, 0x66, 0x05, 0xD3, 0x13, 0x32, + 0x31, 0x0D, 0x16, 0xEE, 0x28, 0xE4, 0x03, 0x47, 0x42, 0x08, + 0xAB, 0x09, 0xA0, 0xB6, 0x9A, 0x9F, 0x2A, 0x8D, 0x53, 0x3C, + 0xDB, 0xA1, 0x3A, 0x2E, 0xC9, 0x39, 0x9B, 0x1E, 0x51, 0x30, + 0x8E, 0x5D, 0x4F, 0x60, 0xBC, 0xF7, 0xC2, 0x46, 0x98, 0xCB, + 0x96, 0x85, 0xCF, 0x00, 0x48, 0xCC, 0x8C, 0x1A, 0x44, 0xE2, + 0xB8, 0xFF, 0x87, 0x33, 0xEB, 0x81, 0x82, 0xD3, 0x54, 0xE4, + 0x4C, 0xC8, 0xEB, 0xBF, 0x10, 0x7A, 0x26, 0x52, 0x08, 0x3C, + 0xE3, 0xEF, 0x68, 0x9C, 0xD1, 0x27, 0x29, 0xEF, 0x40, 0x83, + 0x00, 0xA3, 0x9A, 0x23, 0x3D, 0xEA, 0x63, 0x43, 0xED, 0xAA, + 0x89, 0x86, 0xA8, 0xFD, 0xAA, 0x26, 0xE2, 0xB1, 0x6C, 0x79, + 0x81, 0xED, 0xAD, 0xC9, 0x8F, 0xA1, 0x7B, 0x1D, 0x90, 0x1E, + 0xE7, 0xEE, 0xA0, 0xEB, 0xCE, 0x1C, 0x27, 0xB1, 0xE6, 0x21, + 0xE8, 0x0B, 0x65, 0xBF, 0x1B, 0x1D, 0x06, 0xAD, 0x17, 0xBA, + 0x94, 0xE7, 0xFC, 0x77, 0x87, 0xCE, 0xEC, 0x7E, 0xCD, 0x65, + 0x19, 0xD0, 0x81, 0x44, 0xA0, 0x38, 0xAA, 0x1C, 0x1E, 0x16, + 0xA5, 0x64, 0x94, 0x47, 0xB8, 0x87, 0xB5, 0xDC, 0x2B, 0x88, + 0x40, 0x6E, 0x69, 0xB3, 0x57, 0x93, 0x98, 0xD9, 0xE7, 0xBD, + 0x6B, 0x6E, 0x02, 0x4C, 0xC2, 0x68, 0xEB, 0x15, 0x6B, 0xA1, + 0x62, 0x6C, 0x85, 0x7A, 0xBC, 0x0B, 0x36, 0xC0, 0xFE, 0x5B, + 0x5C, 0x0D, 0x26, 0xD7, 0x0F, 0x88, 0x6E, 0x0E, 0x25, 0x1E, + 0xE5, 0xC6, 0xC7, 0xFD, 0x9F, 0x2E, 0xE8, 0x83, 0x7A, 0x5E, + 0x17, 0x51, 0xDD, 0x97, 0x74, 0xE4, 0xDB, 0x61, 0x99, 0x93, + 0xE7, 0xA4, 0x25, 0xA7, 0x90, 0x2F, 0x5A, 0x07, 0x90, 0x42, + 0xAF, 0x77, 0xF5, 0xF4, 0x0B, 0xE2, 0x5D, 0x1E, 0x07, 0x3B, + 0x21, 0x9E, 0x2B, 0xDE, 0xA2, 0xB0, 0x17, 0x69, 0xE1, 0xE8, + 0x81, 0xF2, 0xFA, 0xD7, 0xA7, 0x39, 0x9A, 0x8C, 0x14, 0x9B, + 0x1F, 0xF1, 0x3B, 0xE5, 0x2D, 0x84, 0xAD, 0x09, 0xA9, 0xB6, + 0xFD, 0x22, 0x67, 0xDD, 0x53, 0x86, 0x4F, 0xAB, 0x51, 0x3C, + 0xDA, 0x11, 0xE3, 0x08, 0xA6, 0xDC, 0xFE, 0x7B, 0x4C, 0xEB, + 0x0F, 0x57, 0x59, 0x92, 0x1D, 0x81, 0xF6, 0x4E, 0x6A, 0xC2, + 0x7E, 0x16, 0xB0, 0xD0, 0x0A, 0x51, 0xAD, 0x0D, 0x35, 0xD8, + 0xF4, 0x7B, 0xA6, 0x34, 0xA9, 0xA1, 0xBD, 0xB0, 0x24, 0xE0, + 0x8D, 0xCA, 0xB1, 0x75, 0xDD, 0x40, 0xAF, 0x1E, 0xD5, 0x8B, + 0x34, 0x19, 0xE1, 0x46, 0xA4, 0x84, 0x4C, 0xAE, 0xCB, 0x68, + 0xC0, 0x3C, 0x08, 0xE7, 0xEE, 0x28, 0x56, 0x19, 0x29, 0x6E, + 0x6D, 0xEA, 0x64, 0x49, 0xE5, 0x25, 0x1B, 0xC7, 0x54, 0x9E, + 0xA0, 0x85, 0x34, 0xF4, 0xC3, 0x86, 0xE0, 0x60, 0x92, 0xD2, + 0xF9, 0xB3, 0x16, 0x58, 0x3C, 0x42, 0x54, 0xF5, 0xC1, 0xD9, + 0x08, 0x04, 0xD2, 0xD4, 0xBE, 0x4C, 0xF0, 0x1C, 0x91, 0x24, + 0x4F, 0x17, 0x1D, 0x24, 0xEB, 0x23, 0xE3, 0xC5, 0x83, 0x09, + 0xFA, 0xF7, 0xD2, 0x56, 0xD9, 0x7C, 0xA8, 0x72, 0x28, 0x80, + 0x35, 0xA0, 0x9F, 0x8B, 0xF3, 0x55, 0xA8, 0xA6, 0x0E, 0xF9, + 0x93, 0xAB, 0xA4, 0x8C, 0x42, 0x62, 0x19, 0x8D, 0xF3, 0x14, + 0x87, 0x36, 0xE4, 0xF5, 0x93, 0xDD, 0x25, 0x59, 0x2A, 0x3A, + 0x38, 0x49, 0x07, 0xCC, 0x89, 0x36, 0xB1, 0xE2, 0x00, 0xCA, + 0x6E, 0x2A, 0xA1, 0x11, 0x3D, 0x24, 0x3B, 0x18, 0xF9, 0x4C, + 0x1F, 0xAB, 0x7D, 0xBE, 0xAE, 0xBB, 0x88, 0x6F, 0xFA, 0xB8, + 0x81, 0x3D, 0x73, 0xAF, 0x01, 0xA5, 0x6C, 0x28, 0xC6, 0x0F, + 0x91, 0x4C, 0xD8, 0xA4, 0x71, 0x4B, 0x4C, 0xD8, 0x90, 0x18, + 0xE0, 0x4E, 0xD2, 0xAF, 0x5E, 0x44, 0x05, 0x6A, 0x00, 0x20, + 0x99, 0x63, 0xC9, 0x23, 0x4B, 0xD5, 0xEC, 0x10, 0x05, 0x88, + 0x42, 0x91, 0x81, 0x76, 0xD1, 0x22, 0xC1, 0x5B, 0xA6, 0x53, + 0x01, 0x74, 0x7C, 0x5A, 0x82, 0xFD, 0xF3, 0x24, 0x6C, 0xE4, + 0x8E, 0x83, 0x8F, 0x68, 0xED, 0xF8, 0x03, 0x3F, 0xC1, 0x02, + 0x8A, 0x05, 0xC0, 0x6D, 0x24, 0xA9, 0x46, 0x2A, 0xB8, 0x36, + 0xC5, 0xF0, 0xCF, 0xBA, 0x67, 0xC9, 0xE3, 0xF8, 0x25, 0xA2, + 0x23, 0x48, 0xB8, 0x6E, 0x86, 0x94, 0x21, 0xF3, 0x9C, 0xC9, + 0xB8, 0x08, 0x74, 0xCA, 0x69, 0x86, 0xE3, 0x48, 0x46, 0xB7, + 0xC6, 0xA4, 0x6C, 0x33, 0x72, 0xAB, 0x49, 0x81, 0x7F, 0x52, + 0xE1, 0x85, 0x28, 0x36, 0x17, 0x98, 0x31, 0x83, 0x80, 0x5A, + 0x29, 0x20, 0xEC, 0xC3, 0xDA, 0xA4, 0xAA, 0xF9, 0x93, 0x32, + 0xBF, 0xF4, 0xD9, 0x1B, 0xB3, 0xDE, 0x73, 0x66, 0x6F, 0xA1, + 0x88, 0x32, 0xA3, 0xB7, 0x80, 0xDF, 0xFB, 0xE8, 0x24, 0x0C, + 0x13, 0xAC, 0x17, 0x77, 0xA0, 0xE2, 0xE7, 0xA8, 0x25, 0x79, + 0x36, 0x85, 0x44, 0x4F, 0x64, 0x89, 0x66, 0x5F, 0x0B, 0x4F, + 0x2F, 0xC3, 0xD7, 0x59, 0x27, 0xAC, 0x51, 0xB3, 0xFB, 0xE5, + 0xDA, 0xAF, 0x2A, 0x5B, 0xB5, 0x5E, 0x4D, 0xE7, 0xB4, 0x5E, + 0x7D, 0x0E, 0x07, 0xEA, 0xD3, 0x98, 0x5A, 0xD1, 0xC9, 0x81, + 0x3C, 0x0D, 0xFC, 0x59, 0x49, 0x15, 0xF6, 0x15, 0xA5, 0x37, + 0x81, 0x0A, 0xD5, 0x9F, 0xD4, 0xAB, 0x8C, 0xB0, 0x8D, 0x87, + 0x69, 0x31, 0x3D, 0x80, 0x98, 0xE0, 0x7A, 0x5E, 0xCE, 0x07, + 0x0A, 0xD5, 0xE4, 0x87, 0x57, 0x61, 0x11, 0x0E, 0xE2, 0x99, + 0xB6, 0x0C, 0xB2, 0xA4, 0x2A, 0x5B, 0x6F, 0xAD, 0xE6, 0x35, + 0x5A, 0x44, 0x63, 0xBA, 0x9F, 0xCC, 0xE7, 0x35, 0x60, 0x45, + 0x71, 0xA4, 0xE5, 0xB9, 0x81, 0x77, 0xEA, 0xF2, 0xFC, 0x07, + 0x8A, 0x94, 0xE7, 0x7C, 0x4B, 0x2B, 0x71, 0xF2, 0x81, 0x82, + 0x93, 0xB6, 0xC5, 0x24, 0xA6, 0x2E, 0xF6, 0xC9, 0x7D, 0x02, + 0x8A, 0x32, 0x84, 0x5E, 0x47, 0x94, 0xB0, 0xFD, 0x81, 0x28, + 0x5F, 0x39, 0xB6, 0xF3, 0xFA, 0xB6, 0xD3, 0xF8, 0x67, 0x5A, + 0x3D, 0xB8, 0xDE, 0x61, 0x08, 0xF7, 0x16, 0x90, 0x6F, 0xD7, + 0x73, 0xC5, 0x63, 0x2A, 0x83, 0x9E, 0x83, 0xB0, 0x59, 0x63, + 0xD0, 0x44, 0xC1, 0x51, 0xD2, 0x4A, 0x4E, 0x31, 0x01, 0x9E, + 0x6D, 0xE7, 0x06, 0x25, 0xE9, 0x9F, 0x25, 0x04, 0xE6, 0x22, + 0x8F, 0x70, 0x21, 0x31, 0x76, 0x2D, 0xF2, 0x93, 0xFA, 0x8C, + 0xD7, 0xA6, 0xE5, 0xBE, 0x82, 0x1F, 0x0A, 0x10, 0xC6, 0x48, + 0xB0, 0x0F, 0xD9, 0xB5, 0xAC, 0x8D, 0xAD, 0x63, 0xB3, 0x73, + 0x18, 0x83, 0x9F, 0xEC, 0xE6, 0x21, 0x9D, 0xD8, 0x3E, 0x1F, + 0x91, 0x23, 0x9B, 0x4D, 0xA4, 0x22, 0x16, 0x1E, 0x37, 0xA3, + 0xD5, 0xB1, 0xA9, 0x18, 0xEE, 0x54, 0xB7, 0x42, 0x99, 0x18, + 0xD0, 0x22, 0x29, 0xDE, 0xEE, 0x5C, 0xF7, 0x0F, 0x68, 0xF8, + 0x8A, 0xC5, 0x01, 0xD2, 0x9F, 0xCF, 0x22, 0x93, 0x7F, 0x32, + 0x91, 0x76, 0x70, 0x23, 0x98, 0xD7, 0x56, 0xF2, 0x45, 0x23, + 0x80, 0xB7, 0xA1, 0x48, 0x85, 0xE1, 0x99, 0x11, 0x63, 0x58, + 0xDC, 0x5C, 0x63, 0x55, 0x9F, 0x98, 0xA6, 0xBE, 0xDC, 0x72, + 0x17, 0x52, 0x4D, 0x88, 0xB1, 0x89, 0x33, 0x98, 0x73, 0x59, + 0x43, 0xB2, 0x2E, 0x97, 0x84, 0xE1, 0x34, 0xF6, 0xB6, 0x9B, + 0x2B, 0xAA, 0xC2, 0xA7, 0xA2, 0x3D, 0x1E, 0x7A, 0xF5, 0xE8, + 0xBE, 0x37, 0x0E, 0xF9, 0x2A, 0x71, 0x65, 0xB7, 0x22, 0x7A, + 0xD7, 0x4A, 0xE4, 0xF5, 0x6E, 0x0F, 0xCB, 0xF4, 0xFB, 0x2F, + 0xC9, 0xDD, 0x4A, 0x53, 0x94, 0xB2, 0x61, 0x7C, 0xD4, 0x7F, + 0x38, 0x83, 0x74, 0x72, 0x72, 0xE9, 0xFA, 0xD1, 0x20, 0x67, + 0x3D, 0x4C, 0x0D, 0xDE, 0x82, 0xB1, 0x68, 0x9C, 0xE5, 0x8A, + 0x66, 0x42, 0x54, 0x76, 0x96, 0xD5, 0x72, 0x19, 0x9E, 0x50, + 0xA0, 0xAF, 0xC7, 0x2C, 0xBE, 0xCC, 0x8F, 0x31, 0xC7, 0xF7, + 0xBF, 0x11, 0xEF, 0x39, 0x74, 0xEF, 0xBC, 0xB7, 0x1F, 0xE4, + 0x58, 0x6C, 0xCB, 0xCC, 0xDA, 0x0D, 0xF0, 0x82, 0x6E, 0xCA, + 0xB1, 0x9D, 0x18, 0x9A, 0x73, 0x45, 0x3A, 0x22, 0xA1, 0x6F, + 0xF4, 0x67, 0x25, 0xDB, 0xCA, 0x0C, 0x06, 0xBD, 0xC2, 0xD0, + 0x5B, 0x0D, 0x9B, 0x7B, 0x7C, 0xFC, 0x46, 0x86, 0x09, 0x6E, + 0xCD, 0xBD, 0x52, 0xA4, 0x3E, 0x68, 0x8D, 0x19, 0xB3, 0x6E, + 0xBC, 0x80, 0xEC, 0x4A, 0xB0, 0xC1, 0x9A, 0x5C, 0xFE, 0xC6, + 0x19, 0xCA, 0xD8, 0xFA, 0x8A, 0xA5, 0x18, 0xD3, 0x4B, 0x13, + 0xE3, 0x4A, 0xBC, 0x1A, 0x7F, 0x82, 0x52, 0xD4, 0x0B, 0x23, + 0x1E, 0x08, 0xAD, 0x75, 0x66, 0xE7, 0x2C, 0xF3, 0x47, 0x52, + 0xB0, 0xC2, 0xB9, 0xED, 0x18, 0xC5, 0x8C, 0x2C, 0x50, 0x6B, + 0x13, 0xB9, 0xAD, 0x17, 0xB4, 0x0A, 0x17, 0x55, 0x1E, 0x0B, + 0x35, 0x41, 0x3E, 0x3C, 0x07, 0xB5, 0x33, 0x0F, 0xAC, 0x83, + 0x5F, 0x18, 0xFA, 0x6B, 0xAD, 0x15, 0xD6, 0x90, 0x2C, 0xCB, + 0xFA, 0xF9, 0xB8, 0xE2, 0x48, 0x7F, 0x45, 0x8A, 0x0A, 0x67, + 0x4B, 0x34, 0xFB, 0xE8, 0x53, 0x83, 0xDF, 0x91, 0xBE, 0xF6, + 0xE3, 0x6E, 0x70, 0x24, 0x19, 0xBE, 0x89, 0x80, 0xD4, 0xB7, + 0xC6, 0x16, 0x93, 0x94, 0x23, 0xE9, 0x95, 0xD2, 0xB0, 0xE4, + 0x0E, 0x56, 0x6D, 0x1F, 0x9D, 0x0D, 0x45, 0x29, 0xE9, 0xB1, + 0x85, 0x8F, 0x4D, 0x30, 0x05, 0x1F, 0x77, 0x11, 0x81, 0xA9, + 0x28, 0xCF, 0x5B, 0x34, 0x11, 0xCB, 0x71, 0x4A, 0xA2, 0xE0, + 0xD9, 0xC5, 0x03, 0x55, 0x34, 0x1A, 0x43, 0x95, 0x05, 0x96, + 0xB5, 0x36, 0x33, 0xE1, 0x54, 0x0D, 0x13, 0x09, 0x3B, 0xB3, + 0x9B, 0xB2, 0x1A, 0x92, 0x5E, 0x33, 0x88, 0x1F, 0x20, 0xE7, + 0x55, 0x4D, 0x4E, 0x32, 0x99, 0x99, 0xEA, 0xE9, 0x54, 0xC3, + 0x7E, 0xA3, 0x49, 0x87, 0x5F, 0x9B, 0x76, 0x3F, 0x84, 0xBD, + 0x57, 0xB6, 0x96, 0xA0, 0xD1, 0xB0, 0xB8, 0xF4, 0xA7, 0xEB, + 0x48, 0x16, 0x0C, 0x3E, 0x63, 0x3F, 0xF3, 0x6F, 0x98, 0xDD, + 0x99, 0xD1, 0x77, 0x4D, 0x3E, 0x7D, 0x5E, 0xA0, 0x9A, 0x7F, + 0x16, 0x6B, 0x59, 0xA9, 0xB6, 0xE2, 0x56, 0x6B, 0x4C, 0xB9, + 0x5A, 0xB2, 0x38, 0x05, 0x7C, 0xBB, 0xCA, 0x68, 0x33, 0x32, + 0x19, 0xD1, 0xE6, 0x81, 0xFB, 0xDD, 0xCC, 0x90, 0xA3, 0xBE, + 0xFE, 0x16, 0xAB, 0x8F, 0x74, 0xFA, 0x22, 0xD2, 0x73, 0x53, + 0xD5, 0xA1, 0xD2, 0x70, 0x9F, 0x7A, 0xED, 0x79, 0xE8, 0x41, + 0x0E, 0xFD, 0xD8, 0x3C, 0xBA, 0x6F, 0x34, 0xFD, 0xF7, 0x55, + 0x7E, 0x7D, 0x96, 0x68, 0x8D, 0x38, 0xAA, 0x90, 0xCC, 0x87, + 0x5D, 0xC1, 0x0E, 0x5B, 0xC3, 0xF8, 0x11, 0xA2, 0x2D, 0x4D, + 0xD1, 0x66, 0x61, 0x40, 0x94, 0xBC, 0xD8, 0x36, 0x2A, 0x19, + 0xE1, 0xAD, 0x1F, 0xB9, 0xEC, 0x68, 0xAA, 0x95, 0x38, 0x9F, + 0x2A, 0xED, 0x0F, 0x12, 0x3A, 0x3B, 0x03, 0x37, 0x72, 0xE5, + 0x9E, 0x1F, 0xD1, 0x1F, 0x9E, 0x6B, 0xFA, 0x7A, 0x18, 0xC7, + 0x74, 0x5B, 0x63, 0xCD, 0x2D, 0xE0, 0xA3, 0x5F, 0x2C, 0x6F, + 0xB5, 0xB9, 0xB9, 0x78, 0xDB, 0xE5, 0xF8, 0xA2, 0x90, 0x24, + 0x96, 0x8D, 0x18, 0x40, 0x0F, 0x7B, 0xD1, 0x48, 0x68, 0x84, + 0x2C, 0xAE, 0xA4, 0x35, 0x3E, 0x15, 0x81, 0x34, 0xEB, 0xD4, + 0x74, 0x04, 0x11, 0x30, 0x24, 0xA0, 0xFF, 0x04, 0x0F, 0x6F, + 0x7F, 0x58, 0x5B, 0x0D, 0x5D, 0x1E, 0x34, 0xE7, 0xAC, 0x67, + 0x49, 0x48, 0x6C, 0x40, 0xD4, 0xD6, 0xB7, 0xB1, 0x63, 0x0B, + 0xA1, 0xBB, 0x70, 0xE3, 0x20, 0x83, 0xFC, 0x2B, 0x43, 0x3B, + 0x3F, 0x59, 0xB3, 0x0C, 0x3C, 0xE5, 0x2F, 0x12, 0x93, 0x1E, + 0x05, 0xEF, 0x3C, 0x0D, 0xD9, 0x23, 0xBF, 0x63, 0x2D, 0x2D, + 0x6F, 0xAC, 0x9C, 0x82, 0x08, 0x73, 0xB9, 0x62, 0xC9, 0x54, + 0x37, 0xB9, 0xAE, 0x04, 0xED, 0x05, 0x64, 0x54, 0xC5, 0xFA, + 0x23, 0xD5, 0x54, 0x52, 0x19, 0x11, 0x16, 0x71, 0xF5, 0x56, + 0xC7, 0xDF, 0x04, 0x0C, 0xB4, 0x9C, 0xE8, 0x90, 0xD4, 0x57, + 0x9A, 0x6F, 0xA6, 0xCE, 0xCF, 0x0E, 0xAC, 0x06, 0x19, 0xE0, + 0x44, 0x22, 0x2F, 0x5E, 0x87, 0x76, 0x23, 0x4A, 0x5F, 0x56, + 0x3B, 0xE2, 0x58, 0xEB, 0x76, 0x28, 0x1E, 0x76, 0xDA, 0xED, + 0x52, 0x27, 0x5E, 0x85, 0x77, 0xD0, 0xD3, 0xC8, 0x7F, 0x4A, + 0x4A, 0x0B, 0x69, 0x96, 0x0E, 0xA9, 0x6F, 0x19, 0x14, 0xCF, + 0xC2, 0xF3, 0x6B, 0xA2, 0xFF, 0x25, 0xEB, 0xDD, 0x8E, 0x35, + 0x8D, 0x01, 0xB1, 0x90, 0x73, 0x18, 0x0C, 0xD5, 0xF0, 0x98, + 0x9B, 0x70, 0xA2, 0xF3, 0x36, 0x29, 0xFE, 0x8E, 0xE3, 0x8F, + 0x06, 0xDC, 0x4F, 0xB1, 0xF4, 0x99, 0x73, 0xBF, 0x08, 0x11, + 0x8C, 0x63, 0x47, 0x3E, 0xE5, 0xC1, 0xFC, 0x1C, 0x68, 0xE9, + 0x0C, 0x29, 0xC4, 0x07, 0x97, 0x09, 0x2A, 0xF6, 0x46, 0xFB, + 0x7E, 0x0C, 0x35, 0x18, 0x1B, 0x12, 0xCB, 0x62, 0x9D, 0xAC, + 0x57, 0x91, 0x97, 0x68, 0x49, 0x2A, 0xAC, 0x77, 0xF0, 0xFA, + 0x39, 0x32, 0xA5, 0x86, 0x8B, 0x82, 0x2C, 0xED, 0x63, 0xD3, + 0xC8, 0x8D, 0xA3, 0x63, 0xF3, 0xB5, 0x68, 0x7D, 0x7B, 0x94, + 0x94, 0x60, 0x42, 0xF8, 0xF8, 0x2F, 0x20, 0xBA, 0xC6, 0x6C, + 0x8B, 0x11, 0x2C, 0xC1, 0x02, 0xB6, 0xDA, 0x5E, 0x7E, 0x2B, + 0x7A, 0xA2, 0xEA, 0xA4, 0x25, 0x94, 0x05, 0x75, 0x74, 0xC2, + 0xF1, 0xE8, 0x5C, 0xBA, 0x5D, 0x6E, 0x82, 0xF0, 0x11, 0x5E, + 0x1D, 0xC9, 0xF7, 0xAE, 0x58, 0x0D, 0x08, 0xC9, 0x0E, 0x28, + 0xF5, 0x98, 0xF2, 0xB1, 0x10, 0xFE, 0x56, 0x4E, 0xF2, 0x17, + 0x54, 0x0B, 0x9D, 0xD3, 0x13, 0x9A, 0x02, 0xF1, 0x69, 0x62, + 0xB3, 0x64, 0xEF, 0x70, 0x53, 0x4F, 0xC5, 0x32, 0xB0, 0xFE, + 0x9E, 0xAF, 0x42, 0xD0, 0xE1, 0x36, 0xA0, 0xD6, 0x22, 0x30, + 0xE9, 0xC8, 0xBD, 0x39, 0xE6, 0x5F, 0x74, 0xE2, 0xAB, 0x65, + 0x80, 0x46, 0xE3, 0x91, 0xC2, 0x3E, 0x14, 0x2B, 0x6F, 0xC4, + 0xF8, 0x81, 0x46, 0x2F, 0x36, 0x1A, 0x2E, 0xB3, 0x3B, 0x52, + 0x9F, 0x2B, 0x78, 0x1A, 0xF5, 0x96, 0xDC, 0x24, 0xF3, 0x09, + 0x72, 0x41, 0x64, 0x35, 0x92, 0x4B, 0xD1, 0x71, 0x83, 0x5D, + 0xBE, 0xD6, 0xFE, 0x41, 0xBB, 0x3B, 0x4D, 0x51, 0xA2, 0xAB, + 0xEE, 0xDC, 0x98, 0xF3, 0x28, 0xB7, 0x42, 0xDC, 0x99, 0xE9, + 0x55, 0x98, 0xE4, 0x43, 0x12, 0x9A, 0x5E, 0x7B, 0x34, 0x5F, + 0x33, 0xD8, 0x3D, 0xB8, 0x0A, 0x8C, 0x0C, 0xEB, 0x94, 0x32, + 0x4D, 0xD1, 0x3D, 0x90, 0x4C, 0xEA, 0xC8, 0xD5, 0x70, 0x11, + 0x56, 0x63, 0xFA, 0xE9, 0x52, 0x39, 0xAB, 0x2C, 0x6F, 0x21, + 0xCA, 0x0E, 0x6A, 0x47, 0xAF, 0x6D, 0x54, 0x50, 0xEE, 0xF0, + 0x48, 0xDF, 0x76, 0xAA, 0x7A, 0x7C, 0x29, 0x84, 0xC7, 0x1E, + 0x92, 0xFD, 0x7F, 0x96, 0x43, 0x85, 0x8F, 0xF9, 0x92, 0x3F, + 0xA2, 0xEE, 0x08, 0x89, 0xE5, 0x3B, 0xFE, 0x5F, 0x37, 0xE1, + 0xD6, 0xDF, 0x36, 0xB0, 0x9A, 0xCB, 0x02, 0xB7, 0x59, 0x05, + 0xE4, 0xBB, 0x7C, 0x58, 0xBE, 0xDF, 0xB0, 0x6B, 0xC3, 0x4E, + 0x2C, 0xFB, 0x36, 0xE7, 0x18, 0x98, 0x93, 0x6A, 0x7A, 0x30, + 0x3E, 0x65, 0x8D, 0x19, 0x10, 0xCF, 0x61, 0xC3, 0xF8, 0x0B, + 0x9C, 0x40, 0x95, 0xA4, 0x55, 0xAF, 0x12, 0x5A, 0xE4, 0x01, + 0x0C, 0x66, 0x6A, 0x44, 0xAA, 0x85, 0x10, 0xF7, 0x68, 0x84, + 0x61, 0x28, 0x41, 0xD4, 0x4E, 0x64, 0x6A, 0xE7, 0x9A, 0x4F, + 0x9F, 0xAA, 0xEA, 0xCE, 0x64, 0x8A, 0xE8, 0xB1, 0x9E, 0x17, + 0x58, 0x7E, 0x66, 0x5B, 0x72, 0x26, 0x24, 0xAB, 0xC2, 0x52, + 0xF2, 0xF4, 0x74, 0xA7, 0x2E, 0x30, 0xAA, 0xB2, 0x88, 0xFD, + 0xA2, 0x38, 0xA4, 0xD1, 0x74, 0x8A, 0x66, 0xF2, 0x19, 0xB8, + 0x93, 0x0D, 0x69, 0x8C, 0x6C, 0xC0, 0xD0, 0x76, 0xA5, 0x34, + 0x39, 0x1A, 0x3B, 0x02, 0x40, 0xC7, 0xAB, 0x4F, 0xB2, 0x2B, + 0x29, 0x1D, 0x17, 0xCE, 0xA2, 0xD3, 0x4B, 0xDB, 0x04, 0x0B, + 0xEC, 0x6D, 0x8B, 0xB2, 0x96, 0x4F, 0x64, 0x4C, 0x32, 0x12, + 0xD0, 0xB3, 0x31, 0xEE, 0x53, 0x3A, 0xD2, 0x01, 0x3C, 0x44, + 0xE4, 0x00, 0x68, 0xB1, 0xED, 0xB6, 0x4A, 0x96, 0xE1, 0x6F, + 0xDE, 0x46, 0x3D, 0x36, 0x8A, 0x0A, 0xCD, 0xB9, 0x13, 0x01, + 0x38, 0xAE, 0xB8, 0xA7, 0xA7, 0x30, 0x51, 0x09, 0x39, 0x9C, + 0x6F, 0xDF, 0x91, 0x6C, 0xA4, 0x2A, 0x67, 0x72, 0x29, 0x32, + 0xA1, 0x7E, 0xCB, 0xCF, 0x4D, 0x99, 0x98, 0x11, 0xEF, 0x37, + 0x0B, 0xB5, 0x30, 0x9F, 0x93, 0x81, 0x01, 0xCA, 0xEE, 0x28, + 0x79, 0x69, 0x51, 0xCD, 0xCF, 0xDC, 0xED, 0x50, 0x01, 0x60, + 0x8D, 0xE2, 0x77, 0x55, 0xAE, 0x84, 0x12, 0x2C, 0x01, 0xE3, + 0xF7, 0xAB, 0x55, 0x3B, 0xDD, 0x7E, 0xEC, 0x97, 0x96, 0xE6, + 0x18, 0x5A, 0xAD, 0x3A, 0x77, 0x7A, 0x77, 0x63, 0xBF, 0x28, + 0x39, 0xA0, 0x32, 0x86, 0x4C, 0xFE, 0x8C, 0xE8, 0x9B, 0x66, + 0x2E, 0x09, 0x5A, 0x48, 0x5D, 0x61, 0x25, 0xA5, 0x48, 0x4A, + 0x54, 0x2C, 0xD0, 0xAC, 0xA2, 0xAD, 0x8F, 0x55, 0xAD, 0x17, + 0x29, 0x72, 0x22, 0xC9, 0x93, 0x36, 0x87, 0xEF, 0x6F, 0xE4, + 0x47, 0xEE, 0x3C, 0x82, 0x08, 0x02, 0x0C, 0x71, 0x9E, 0xDD, + 0xF0, 0xDC, 0x1B, 0x76, 0xB6, 0xC3, 0xEA, 0x6F, 0x6D, 0x5D, + 0x2B, 0xA1, 0x38, 0xAA, 0xDB, 0x97, 0xE4, 0x9A, 0x87, 0x90, + 0x88, 0x62, 0x72, 0x88, 0x09, 0x6C, 0x31, 0x4E, 0xB1, 0x8F, + 0xB1, 0x21, 0x55, 0x2E, 0xC0, 0xEA, 0x56, 0x19, 0xBD, 0x96, + 0x79, 0x9D, 0xEF, 0x32, 0xC3, 0x40, 0x89, 0x12, 0x2D, 0x23, + 0x93, 0x2D, 0xBD, 0x19, 0x36, 0x63, 0x0E, 0x05, 0x92, 0x75, + 0x3D, 0x05, 0x12, 0x14, 0x5F, 0x0D, 0xFB, 0x30, 0x0B, 0x56, + 0x84, 0xC5, 0x01, 0x20, 0x4A, 0x1C, 0xF4, 0x59, 0x53, 0x00, + 0x69, 0x5A, 0xF4, 0xA8, 0x00, 0x03, 0xBF, 0x62, 0xC6, 0x5C, + 0x51, 0x36, 0x73, 0x25, 0x32, 0x77, 0x75, 0x27, 0x47, 0xEF, + 0x56, 0x9F, 0xF6, 0x80, 0x08, 0x71, 0xA5, 0xE4, 0x1A, 0x15, + 0xA6, 0x5B, 0x48, 0x55, 0x50, 0x60, 0x7E, 0xBD, 0x07, 0xC2, + 0xE6, 0x2D, 0x17, 0x59, 0x82, 0xEC, 0x3C, 0x57, 0x1D, 0x32, + 0xE0, 0xFB, 0x12, 0x38, 0xE4, 0xE2, 0x04, 0x86, 0xDF, 0x8C, + 0x68, 0x8C, 0x15, 0xA5, 0x73, 0xD3, 0xE7, 0x51, 0xED, 0xF5, + 0xF3, 0x5E, 0x4D, 0x82, 0x36, 0x0F, 0xAB, 0x2A, 0x89, 0x41, + 0xC4, 0x45, 0x4F, 0xAD, 0x04, 0xD2, 0x5F, 0xDF, 0xF0, 0x8F, + 0x31, 0x80, 0xFF, 0xDC, 0xF5, 0xF1, 0x91, 0xCB, 0x04, 0x20, + 0x13, 0xD0, 0xAE, 0xA1, 0xBC, 0x55, 0x37, 0x58, 0x4A, 0x75, + 0x4E, 0x0C, 0x5B, 0x3C, 0x7C, 0xE1, 0x65, 0xC1, 0x4C, 0x4C, + 0xCD, 0x27, 0x66, 0x88, 0x22, 0x10, 0x28, 0xCC, 0x30, 0xDB, + 0xFD, 0x8D, 0xB0, 0x93, 0x56, 0xE8, 0xD3, 0x13, 0x01, 0xF9, + 0x63, 0xA4, 0xE6, 0xC4, 0xC5, 0x50, 0x5C, 0x71, 0x69, 0x05, + 0x63, 0xD7, 0x65, 0x9B, 0x55, 0x35, 0xAC, 0x1B, 0x78, 0xB0, + 0xCD, 0x0A, 0x1D, 0xCE, 0x82, 0x9E, 0x21, 0xFF, 0xA3, 0x90, + 0x0D, 0x5F, 0x49, 0x95, 0xD1, 0xB6, 0x80, 0xFB, 0x40, 0xC3, + 0x0C, 0x71, 0xE5, 0x47, 0x91, 0x63, 0xD9, 0x3F, 0xCC, 0xA3, + 0x39, 0x60, 0xB0, 0x6F, 0xC3, 0xDE, 0x18, 0x65, 0x2C, 0x94, + 0xB4, 0xFB, 0x6B, 0xA7, 0xF0, 0x0A, 0x0A, 0x31, 0x4A, 0xFA, + 0xFE, 0xF9, 0xA1, 0x26, 0xA6, 0x06, 0xEC, 0x10, 0x67, 0x46, + 0xEE, 0x94, 0x8B, 0x1B, 0xB3, 0x9D, 0xA4, 0xE6, 0x0B, 0xF3, + 0x48, 0x11, 0x77, 0x57, 0xF2, 0x70, 0x99, 0x46, 0x4B, 0xCE, + 0xF4, 0xEB, 0x45, 0x43, 0xC1, 0x36, 0xDE, 0x2A, 0x04, 0xE9, + 0x69, 0x57, 0xFF, 0xFF, 0x1E, 0x73, 0xAD, 0x05, 0x3C, 0x29, + 0xB3, 0x67, 0x36, 0xCF, 0xF4, 0xBE, 0x8B, 0x0D, 0x29, 0xA3, + 0x04, 0xC0, 0x88, 0x49, 0xAB, 0x61, 0xE0, 0xE7, 0xF3, 0x51, + 0xE7, 0x48, 0xA4, 0xF8, 0x45, 0x33, 0xBB, 0x9B, 0x92, 0xEC, + 0xB0, 0xB9, 0x2E, 0xFD, 0x4E, 0xF4, 0x7B, 0x93, 0x5E, 0xC8, + 0x53, 0x4A, 0x44, 0x03, 0x28, 0x00, 0x95, 0x55, 0x78, 0xEE, + 0x1B, 0x0C, 0x90, 0xB3, 0x1E, 0x3D, 0xB2, 0x54, 0x48, 0xAC, + 0xC9, 0x23, 0xFC, 0xC6, 0x74, 0x6E, 0xDF, 0xBB, 0x95, 0xC2, + 0x22, 0x43, 0xDC, 0xE3, 0x6A, 0x84, 0x08, 0x97, 0xC2, 0x5D, + 0x12, 0x8F, 0x17, 0x8C, 0x19, 0x06, 0x52, 0xA8, 0x06, 0xB1, + 0xC7, 0x02, 0xA0, 0x65, 0x52, 0xED, 0x51, 0x2C, 0x1B, 0xDA, + 0x16, 0xB0, 0xDA, 0xFF, 0x13, 0xD3, 0x0F, 0x23, 0x17, 0x05, + 0xCF, 0xBF, 0x39, 0xE9, 0xD9, 0x6A, 0x04, 0x45, 0xF1, 0x13, + 0x09, 0xC3, 0x5D, 0xD1, 0x0A, 0x2D, 0x25, 0xE5, 0xB1, 0x85, + 0x0A, 0xA9, 0xB5, 0xC3, 0x10, 0xEB, 0x30, 0x3C, 0x10, 0x45, + 0x3C, 0x22, 0x0C, 0x2D, 0x52, 0xCB, 0x40, 0xE2, 0x85, 0xD3, + 0xA8, 0x70, 0x0B, 0xBA, 0xBA, 0xD1, 0xF5, 0x5E, 0xCE, 0xE5, + 0x70, 0xF1, 0xE4, 0x73, 0x4B, 0x3D, 0x85, 0xE1, 0xAB, 0xA8, + 0xA9, 0x6B, 0xE8, 0x97, 0x18, 0xEE, 0x6B, 0xB1, 0x18, 0x07, + 0xC1, 0x1E, 0xBB, 0xA5, 0x87, 0xE6, 0x3F, 0x33, 0x71, 0x4A, + 0xCE, 0x5F, 0xBB, 0x5B, 0xEB, 0x02, 0x29, 0xC2, 0xEF, 0xCB, + 0xD1, 0x9D, 0x37, 0x51, 0x87, 0xAC, 0x91, 0x17, 0x7D, 0x71, + 0x90, 0x1F, 0x62, 0x34, 0xBE, 0x7A, 0x6A, 0xA2, 0x39, 0x83, + 0x87, 0x52, 0xA9, 0xE4, 0xC5, 0x29, 0x14, 0x05, 0x60, 0x09, + 0x90, 0x5F, 0x6E, 0x6E, 0x92, 0xA3, 0xB4, 0xAF, 0x7F, 0xEE, + 0x25, 0xDC, 0x13, 0xD3, 0x3C, 0x77, 0xC7, 0xE1, 0x3F, 0x05, + 0xBB, 0x7A, 0xE2, 0x5C, 0xE5, 0x0C, 0xA5, 0x51, 0xD8, 0xC5, + 0x77, 0x01, 0x1E, 0xAA, 0xB7, 0x71, 0x40, 0xF5, 0xE4, 0x7D, + 0x16, 0xBF, 0xD2, 0x2B, 0xC7, 0x1A, 0xAB, 0xCA, 0x1D, 0x00, + 0x44, 0xC4, 0x54, 0x68, 0x2C, 0x4C, 0xA0, 0xFD, 0x3B, 0x98, + 0xBE, 0xD2, 0x09, 0xFA, 0x4A, 0xDE, 0x0A, 0x4B, 0x11, 0xB7, + 0xD4, 0xB7, 0x9C, 0x4D, 0x85, 0x3E, 0x89, 0x96, 0xA6, 0x7D, + 0x6E, 0xD7, 0xDE, 0x55, 0x9E, 0xAA, 0x17, 0x1E, 0x8D, 0x12, + 0xA4, 0x15, 0xD0, 0xDD, 0xA4, 0x5F, 0x97, 0x16, 0x6C, 0xFB, + 0x40, 0x43, 0xB5, 0x37, 0xCE, 0xB7, 0x4A, 0xF4, 0xB7, 0x8C, + 0xA0, 0x87, 0xD3, 0x7D, 0x58, 0xE0, 0x35, 0xD0, 0x8C, 0x4E, + 0x7B, 0xC1, 0x85, 0xB0, 0x80, 0x7E, 0xC4, 0x35, 0x35, 0x87, + 0xDA, 0x53, 0xFE, 0xF1, 0x75, 0x52, 0xE0, 0xE6, 0xA4, 0x8A, + 0x1A, 0x92, 0x3B, 0x4E, 0x0F, 0x4D, 0x3F, 0x48, 0x31, 0xAF, + 0xCA, 0xE8, 0xB1, 0x96, 0x16, 0x24, 0xE6, 0xB0, 0x42, 0x12, + 0x7B, 0xF4, 0xF8, 0xD9, 0xE4, 0x62, 0xFB, 0xD9, 0x05, 0xFF, + 0x39, 0xF5, 0xC6, 0xA6, 0xF3, 0x7B, 0x11, 0x3A, 0x96, 0x72, + 0xA6, 0x78, 0x27, 0x5C, 0xC3, 0x5F, 0x33, 0x54, 0xAB, 0xE2, + 0x94, 0xD9, 0xA3, 0x7F, 0x97, 0x95, 0x3E, 0x9C, 0x71, 0x1E, + 0xB5, 0xCD, 0x8C, 0x66, 0x99, 0x87, 0x6A, 0xE9, 0x31, 0x71, + 0x8A, 0x7E, 0xA5, 0x83, 0xD9, 0xFD, 0x9F, 0x3C, 0x4A, 0x0D, + 0xCC, 0xC9, 0x1E, 0xD7, 0xA9, 0x5A, 0x8C, 0x36, 0x15, 0xA7, + 0x20, 0xA1, 0x25, 0xB9, 0xE0, 0xB7, 0xBF, 0x92, 0x0E, 0x2D, + 0xC7, 0x27, 0x3B, 0xF6, 0x54, 0xD7, 0x67, 0x13, 0xDB, 0xEE, + 0xFC, 0x27, 0xE1, 0xF4, 0x43, 0x5D, 0x51, 0x08, 0x62, 0x7A, + 0x6A, 0xBA, 0x4E, 0x04, 0xEC, 0x7C, 0xA4, 0x10, 0xE6, 0xED, + 0xEE, 0x22, 0x2D, 0xF9, 0xFB, 0x91, 0x67, 0xC1, 0x36, 0x6D, + 0x3B, 0xDC, 0xAE, 0x95, 0x02, 0x42, 0x7C, 0x2F, 0xBD, 0xDA, + 0xF3, 0x22, 0xE5, 0x30, 0x94, 0x51, 0x83, 0x28, 0x48, 0xE1, + 0x34, 0xCB, 0x6D, 0xA2, 0x98, 0x41, 0xCF, 0x5C, 0xC0, 0x11, + 0x34, 0x14, 0x3A, 0x7C, 0xBE, 0xE3, 0xC8, 0x9F, 0x6D, 0x16, + 0xE8, 0x2F, 0x19, 0xDB, 0x25, 0x45, 0x8A, 0x3A, 0xB3, 0xF8, + 0x91, 0xAA, 0x43, 0x9E, 0x43, 0x99, 0x4F, 0x14, 0xCC, 0x18, + 0xE1, 0x0D, 0xB0, 0xCD, 0x26, 0xBD, 0x07, 0xC3, 0x79, 0x9B, + 0xFE, 0xBC, 0xFA, 0x66, 0x0A, 0xA3, 0x20, 0x61, 0x0D, 0x1D, + 0x5F, 0x4A, 0xC0, 0xF1, 0x80, 0xD2, 0x66, 0x9E, 0x60, 0x63, + 0x92, 0x74, 0x56, 0x11, 0xF9, 0x1F, 0x01, 0x49, 0xFA, 0xB5, + 0x2F, 0xE1, 0x77, 0xE7, 0xC3, 0xA3, 0x34, 0xC0, 0x2C, 0xAF, + 0x7C, 0x8B, 0x09, 0xC8, 0xF1, 0x59, 0x06, 0xF7, 0x1C, 0x9C, + 0x4F, 0x5B, 0xF7, 0x0C, 0xEA, 0xC9, 0x67, 0x05, 0xFA, 0x0B, + 0xFC, 0x03, 0x5F, 0x57, 0x50, 0xA0, 0x4B, 0x5E, 0x25, 0x63, + 0x23, 0x6E, 0xDE, 0x7D, 0x94, 0x3D, 0xCB, 0xFC, 0xB4, 0x82, + 0xF0, 0x78, 0x23, 0xA0, 0x4F, 0xE0, 0x45, 0xE0, 0xE8, 0x05, + 0xCD, 0x75, 0xA4, 0xEC, 0x3A, 0x63, 0xFF, 0xB0, 0x08, 0xBA, + 0xEB, 0x35, 0x8B, 0xAF, 0x7C, 0xC4, 0xE8, 0xD0, 0xC9, 0xA1, + 0x56, 0xD6, 0x7A, 0x35, 0x1C, 0x5B, 0xB9, 0xD3, 0xE7, 0x4E, + 0x6B, 0x59, 0x68, 0x89, 0x8E, 0x00, 0xCD, 0x2E, 0x35, 0x78, + 0x2D, 0x2A, 0x1A, 0x1E, 0x1B, 0xFA, 0x24, 0x63, 0x2B, 0x61, + 0x92, 0x94, 0xCF, 0xF1, 0x25, 0x49, 0xED, 0xF1, 0x2D, 0x29, + 0x22, 0xC7, 0xC4, 0x09, 0x77, 0xB0, 0x2A, 0x68, 0x68, 0x13, + 0x01, 0x23, 0x11, 0x1F, 0xD4, 0x86, 0xA4, 0xF9, 0x03, 0xD7, + 0xF3, 0x78, 0x94, 0x43, 0x4E, 0x83, 0x5D, 0xA9, 0xEB, 0x3B, + 0xEE, 0x62, 0x18, 0x04, 0x45, 0x1C, 0x8C, 0x80, 0x57, 0x18, + 0x72, 0x7E, 0x10, 0xA4, 0x73, 0x96, 0x06, 0x33, 0x12, 0x35, + 0x6C, 0xBD, 0xEF, 0xBE, 0x94, 0xCC, 0x27, 0xF2, 0x7C, 0x09, + 0xB9, 0x93, 0xB6, 0xDD, 0x87, 0xBD, 0xCD, 0x95, 0x4B, 0x82, + 0x5B, 0xAD, 0x79, 0x7A, 0xDC, 0xAA, 0xA3, 0x63, 0x71, 0xE3, + 0xAC, 0x6C, 0xEA, 0x1B, 0x11, 0x38, 0x86, 0x74, 0xE9, 0x7F, + 0xAB, 0x3E, 0x87, 0x6B, 0x5C, 0xAB, 0xD6, 0x5C, 0x0E, 0xE1, + 0x17, 0x35, 0xF4, 0x8A, 0x92, 0xC8, 0xF2, 0x26, 0xC7, 0x00, + 0xCA, 0x14, 0x21, 0xAB, 0xBE, 0x74, 0x8D, 0x59, 0x8B, 0x6A, + 0xA1, 0x53, 0x3C, 0x49, 0x87, 0x60, 0xD1, 0xF7, 0xCF, 0x0E, + 0x8F, 0x9C, 0xF2, 0x1C, 0x8F, 0x70, 0x80, 0x17, 0x8B, 0x39, + 0x6D, 0x84, 0x34, 0x25, 0x69, 0xF6, 0xD6, 0xED, 0x4A, 0x2F, + 0x1A, 0xD9, 0x81, 0x59, 0x3F, 0x53, 0x2F, 0xB1, 0xD4, 0x20, + 0x9F, 0x4A, 0x3A, 0x29, 0x92, 0x9E, 0xB9, 0x80, 0x1E, 0xA3, + 0x3E, 0x71, 0x1B, 0x25, 0x7C, 0x16, 0xE2, 0xCC, 0xFC, 0xB8, + 0xAE, 0xBC, 0x03, 0xAA, 0x33, 0x8F, 0x7F, 0xD9, 0xB3, 0x96, + 0x01, 0xBF, 0x12, 0x80, 0x19, 0x28, 0x38, 0xB6, 0x9E, 0x4F, + 0xA8, 0x0F, 0x9C, 0x8D, 0x72, 0xC6, 0x65, 0x2C, 0x83, 0x40, + 0xE4, 0xFD, 0xA6, 0xE5, 0x87, 0xBE, 0x81, 0xD4, 0x76, 0x2D, + 0xCF, 0x84, 0x63, 0x0B, 0x47, 0xFD, 0xF2, 0x9B, 0xDE, 0xFA, + 0xF0, 0x94, 0x04, 0x4B, 0x80, 0xC6, 0xF7, 0x5D, 0xDF, 0x5F, + 0x0E, 0xF2, 0x19, 0x80, 0x0D, 0x36, 0x3F, 0xC3, 0x54, 0x67, + 0xA4, 0xAE, 0x70, 0x88, 0xDC, 0xB0, 0x12, 0xD8, 0xE0, 0xCB, + 0x2F, 0x9E, 0x87, 0x30, 0x85, 0xFA, 0xDB, 0x5F, 0x7D, 0xB5, + 0x87, 0x3E, 0xFB, 0xA7, 0x0C, 0x57, 0x6A, 0x8E, 0x43, 0xFF, + 0x82, 0x53, 0xD2, 0xCE, 0x27, 0xF6, 0x21, 0x20, 0x6D, 0x92, + 0x29, 0xD5, 0x9C, 0x9F, 0x07, 0xCC, 0x42, 0x37, 0x7C, 0x02, + 0x38, 0xE9, 0x89, 0x0E, 0x57, 0x88, 0xA0, 0xEA, 0xD2, 0xAE, + 0xEA, 0x01, 0x4C, 0xF3, 0x7C, 0x18, 0xDB, 0x54, 0x9D, 0x2A, + 0x03, 0x95, 0x12, 0x60, 0x2C, 0xAF, 0x34, 0x55, 0x66, 0xB9, + 0x1B, 0x27, 0x54, 0x9C, 0xB4, 0x38, 0xAE, 0x7A, 0x5D, 0xDA, + 0xC9, 0xC8, 0x5A, 0x81, 0x24, 0xE0, 0x0C, 0xE7, 0x31, 0xE6, + 0x36, 0x26, 0x14, 0x9D, 0xB1, 0x4D, 0xE1, 0xE5, 0x58, 0xC4, + 0x99, 0x03, 0x0A, 0x8D, 0x4E, 0xF9, 0x75, 0xD2, 0xBD, 0xA5, + 0x77, 0x4A, 0x09, 0xC9, 0x9C, 0xB5, 0xA8, 0xED, 0x27, 0xA4, + 0x5E, 0xCF, 0xC1, 0x7E, 0x30, 0xDD, 0x42, 0x0B, 0x0A, 0x90, + 0x85, 0xFD, 0x66, 0x34, 0x98, 0xE3, 0xDF, 0xA7, 0x9A, 0xC1, + 0x58, 0x81, 0xD6, 0x46, 0x42, 0x27, 0x35, 0x50, 0xCE, 0xCE, + 0xD6, 0xCB, 0x91, 0xF2, 0x86, 0x03, 0xA0, 0xF1, 0xC1, 0x85, + 0x01, 0xF8, 0x8C, 0xCE, 0x8E, 0x67, 0xA9, 0x10, 0x08, 0xFC, + 0xE7, 0x26, 0xAA, 0xF0, 0x77, 0x56, 0xCF, 0xFB, 0x01, 0x54, + 0xD3, 0x69, 0x13, 0xDD, 0x21, 0x78, 0x8A, 0x04, 0xFB, 0x54, + 0x7F, 0x1F, 0x34, 0x51, 0x80, 0x28, 0x0F, 0xEB, 0x5E, 0xA1, + 0xA1, 0x0C, 0xCD, 0x82, 0x6F, 0x9F, 0xA5, 0xA6, 0x5E, 0xC4, + 0xCC, 0x64, 0x57, 0x37, 0x7D, 0x9A, 0x23, 0xFB, 0x07, 0x0B, + 0x7D, 0x4F, 0x68, 0xAF, 0xD9, 0x00, 0xA9, 0x07, 0x88, 0xA0, + 0x5F, 0x9D, 0x2F, 0x23, 0x10, 0xA5, 0xD1, 0xBE, 0xAB, 0x69, + 0x4E, 0x1E, 0x88, 0x3F, 0x05, 0xDA, 0x90, 0xA0, 0x80, 0x4B, + 0xD2, 0x10, 0xE6, 0x38, 0x83, 0xC1, 0x65, 0xFB, 0xD4, 0x73, + 0x8B, 0x1A, 0xB6, 0x30, 0x97, 0xAF, 0x9E, 0x90, 0x0A, 0x33, + 0x6A, 0x90, 0x1E, 0x75, 0xD3, 0x17, 0x50, 0xFC, 0xCE, 0x2E, + 0xB3, 0x0E, 0x50, 0xA7, 0xA2, 0xD7, 0xE7, 0xC7, 0xED, 0x24, + 0xBB, 0xA9, 0x76, 0xC0, 0x19, 0x8E, 0x19, 0xE1, 0xAC, 0xF1, + 0x99, 0x5B, 0x6D, 0xF4, 0xCD, 0x31, 0xFD, 0x79, 0x0E, 0xA1, + 0xEB, 0xB0, 0xC7, 0x5D, 0xE8, 0x59, 0x56, 0x5F, 0xF1, 0x66, + 0x9C, 0x11, 0x03, 0x7B, 0xC0, 0x56, 0x25, 0xCD, 0xCC, 0x30, + 0xE6, 0xC1, 0x43, 0x8E, 0x5F, 0x28, 0x70, 0x84, 0xF9, 0xFF, + 0xF5, 0x27, 0x77, 0xC3, 0xA9, 0xB7, 0xB7, 0x2E, 0xF4, 0xAF, + 0xA4, 0xE0, 0x38, 0xFE, 0xFF, 0x0D, 0x5A, 0x5B, 0x2A, 0x86, + 0xD7, 0xE8, 0xC0, 0xC0, 0xAE, 0x06, 0xB3, 0x51, 0x11, 0x6C, + 0x2B, 0x74, 0xA5, 0x0C, 0x6D, 0x29, 0x42, 0x04, 0x1F, 0x59, + 0x31, 0xBE, 0xE0, 0x65, 0x08, 0x05, 0x2A, 0xF1, 0x84, 0xC3, + 0x31, 0x14, 0xF9, 0x3B, 0xB0, 0x5F, 0x9F, 0x8D, 0x40, 0x48, + 0x2F, 0xE4, 0x87, 0x1B, 0x5F, 0xD9, 0xFB, 0x01, 0x18, 0x2D, + 0x63, 0x42, 0x7C, 0x82, 0x17, 0xDA, 0x4D, 0x9E, 0x4B, 0xA1, + 0xEA, 0xD8, 0x65, 0xB3, 0x3F, 0xDC, 0x47, 0x5C, 0xE8, 0xF8, + 0xD3, 0x9F, 0x25, 0x3F, 0xF5, 0x24, 0x63, 0xB1, 0x3B, 0x20, + 0xA9, 0xC6, 0x43, 0x0E, 0x78, 0x86, 0xD6, 0xF3, 0xF5, 0x90, + 0x7F, 0xEB, 0xFF, 0xB3, 0x90, 0xE2, 0x0E, 0x19, 0xF2, 0x6E, + 0x88, 0x32, 0x99, 0xFD, 0xE7, 0xCF, 0x78, 0xDC, 0x55, 0x57, + 0x25, 0x18, 0x73, 0x11, 0x0B, 0xEC, 0x22, 0xE1, 0x9A, 0xD1, + 0xE6, 0x22, 0x6D, 0x09, 0xFB, 0x9E, 0x0F, 0x03, 0x0A, 0xCF, + 0x1B, 0x16, 0x16, 0xFF, 0x86, 0xBE, 0x03, 0xF5, 0xFB, 0xE7, + 0x9D, 0x4C, 0xBE, 0x19, 0x6B, 0x61, 0x59, 0x36, 0x78, 0xDD, + 0x9B, 0x0A, 0x9F, 0x17, 0xBE, 0xD8, 0xF8, 0x21, 0x38, 0x9B, + 0x03, 0x4E, 0x06, 0xB5, 0xDA, 0x81, 0x22, 0x2D, 0xE6, 0x3A, + 0xE4, 0xEA, 0xBB, 0x3E, 0xC2, 0x8B, 0x93, 0x69, 0x4A, 0xC0, + 0x99, 0xC3, 0x93, 0x7A, 0xE5, 0xA3, 0x96, 0x5A, 0xC7, 0xC2, + 0x05, 0xC6, 0x5E, 0xAC, 0xE4, 0x54, 0xC1, 0x6A, 0xFC, 0xEE, + 0xDE, 0x8F, 0xB5, 0xCB, 0x18, 0xDC, 0xD5, 0x0E, 0xAE, 0x05, + 0xC3, 0x99, 0x00, 0x9B, 0x6D, 0x4E, 0x7F, 0x4C, 0x24, 0x51, + 0xA2, 0xB2, 0x0D, 0xD8, 0xB0, 0x6A, 0x40, 0x72, 0x29, 0xBD, + 0x5B, 0x5F, 0xE0, 0x00, 0xBE, 0xE2, 0xBC, 0xD1, 0xB2, 0xF2, + 0x98, 0xB2, 0x13, 0x45, 0x23, 0xDB, 0xBD, 0x0A, 0x76, 0x5A, + 0xC5, 0x9B, 0xD8, 0x3F, 0xE0, 0xC4, 0x34, 0x23, 0xE8, 0xD5, + 0x9D, 0xD2, 0x09, 0xF8, 0x23, 0x7C, 0xE5, 0x54, 0x7D, 0x6B, + 0x40, 0x4C, 0x83, 0x5F, 0xD6, 0xCF, 0xB3, 0x78, 0xD1, 0xF0, + 0x43, 0x10, 0xDD, 0xAD, 0x94, 0x35, 0xF7, 0x2A, 0x59, 0x94, + 0xCC, 0x2E, 0x3A, 0x76, 0xEC, 0x01, 0x99, 0xC2, 0xC2, 0x82, + 0x93, 0x50, 0x72, 0x36, 0xDD, 0x43, 0x2B, 0x31, 0x38, 0xA2, + 0x76, 0x10, 0x81, 0x1F, 0xF7, 0x8F, 0x87, 0x8F, 0xAC, 0x97, + 0x18, 0xA0, 0xCE, 0x1F, 0xE5, 0x6E, 0xC9, 0x68, 0x59, 0x0D, + 0xCF, 0x3B, 0x76, 0xC3, 0xE4, 0xE4, 0x9B, 0xBA, 0x47, 0xEE, + 0xB5, 0x4F, 0xD2, 0x91, 0x92, 0x75, 0x8D, 0xD9, 0x3F, 0x6C, + 0xFE, 0xEB, 0x29, 0x0F, 0xB4, 0x20, 0xA0, 0x87, 0xAC, 0x3C, + 0x10, 0x77, 0xF9, 0xA8, 0xF9, 0xC3, 0x98, 0x81, 0x6C, 0xF0, + 0xC8, 0xE2, 0x52, 0xE2, 0x2A, 0x65, 0x67, 0xC2, 0xFC, 0x77, + 0x54, 0x75, 0x27, 0x8D, 0x7A, 0x2E, 0x0F, 0xDD, 0x5A, 0x3C, + 0x94, 0xCC, 0xBE, 0x0D, 0xA2, 0xD6, 0xFF, 0x12, 0xF4, 0xD6, + 0x43, 0x7E, 0xAB, 0x6F, 0x0E, 0xB2, 0x6A, 0x98, 0xF3, 0xE8, + 0xEA, 0x8F, 0xA3, 0xC8, 0x20, 0xBD, 0x23, 0x0E, 0x68, 0x93, + 0x8F, 0xE5, 0x64, 0xE8, 0xC1, 0x68, 0x55, 0x4D, 0x4D, 0xC1, + 0xCB, 0xC0, 0xFD, 0xB9, 0x5B, 0xE4, 0xC7, 0x69, 0x08, 0xCA, + 0x0A, 0xC9, 0x83, 0xB0, 0xB8, 0xB2, 0x17, 0xDB, 0xD8, 0xA1, + 0xF5, 0xE4, 0x8A, 0x8E, 0xA1, 0x91, 0xE5, 0x2B, 0x08, 0x2A, + 0x61, 0x87, 0x72, 0x62, 0x5C, 0x09, 0x13, 0xD8, 0x1B, 0x14, + 0x3A, 0x10, 0x68, 0x7D, 0x53, 0x8F, 0x6C, 0x07, 0x91, 0x06, + 0x11, 0x8E, 0xBE, 0xF3, 0x70, 0x92, 0xC8, 0x5C, 0x8E, 0x0A, + 0x98, 0x35, 0xD7, 0xE8, 0xA4, 0x57, 0x93, 0x3C, 0xF9, 0x14, + 0xC0, 0x64, 0x79, 0xA3, 0x59, 0xBF, 0xE0, 0x2F, 0x1C, 0xD7, + 0xCD, 0xB6, 0xCB, 0x8C, 0x9C, 0xA3, 0x3D, 0x32, 0x53, 0x62, + 0x6D, 0x49, 0xB0, 0x5B, 0x0F, 0x2D, 0x25, 0xB5, 0xF0, 0x7D, + 0x4E, 0xE0, 0xAF, 0xC7, 0x2D, 0x42, 0x80, 0x2D, 0x4B, 0x5E, + 0xF5, 0xC6, 0x96, 0x0B, 0x40, 0x34, 0x4D, 0x51, 0xD9, 0x05, + 0xE6, 0xC7, 0x6C, 0x3A, 0x65, 0x99, 0xD4, 0x2D, 0x99, 0xCF, + 0x1F, 0x1A, 0x1B, 0x60, 0x20, 0xA4, 0x4F, 0x2D, 0x23, 0x55, + 0x36, 0x6B, 0x96, 0xFF, 0x11, 0xFE, 0x09, 0x77, 0x90, 0xF4, + 0xCB, 0x3B, 0x6E, 0x51, 0xC0, 0x5F, 0x6B, 0x26, 0xF4, 0x5E, + 0x4E, 0xCD, 0xB6, 0xE8, 0x76, 0xFB, 0x93, 0xD6, 0xA0, 0x4D, + 0xA3, 0x2C, 0x52, 0x86, 0xFC, 0xC3, 0x17, 0xF3, 0x36, 0x4D, + 0xDE, 0x74, 0x83, 0x56, 0xE6, 0x9D, 0x48, 0x6D, 0x3D, 0x09, + 0x15, 0xCC, 0xD2, 0x1C, 0x09, 0xF3, 0x16, 0xDE, 0x4B, 0x47, + 0xA7, 0x30, 0x01, 0xC1, 0xBC, 0x53, 0xB8, 0x59, 0x0E, 0xAF, + 0x2B, 0x5D, 0x07, 0x52, 0xE1, 0x8E, 0x12, 0x22, 0x7C, 0x1B, + 0x4E, 0xEB, 0xC7, 0x85, 0x6A, 0xD3, 0xF9, 0x42, 0xCF, 0x2B, + 0x22, 0xD4, 0xFB, 0xE4, 0x15, 0xE8, 0x3F, 0x8F, 0x44, 0xE1, + 0xBF, 0x81, 0x28, 0xB9, 0x78, 0x33, 0xD6, 0x6E, 0xB7, 0xD0, + 0x82, 0x3A, 0x4E, 0x15, 0x4C, 0x3F, 0xD7, 0xEB, 0x8E, 0x3B, + 0xF5, 0xAB, 0x08, 0x53, 0xCE, 0xF5, 0x3F, 0x15, 0xF8, 0x37, + 0x50, 0xDD, 0x6A, 0x68, 0x9D, 0x20, 0xB5, 0x95, 0x4D, 0x85, + 0x6B, 0xD1, 0x9B, 0x61, 0x5F, 0x82, 0x25, 0xB1, 0x61, 0xB2, + 0xE2, 0xC0, 0xA3, 0xDF, 0x3F, 0xC1, 0xFB, 0xE8, 0xA5, 0xDD, + 0x46, 0x84, 0xD1, 0x6C, 0xCE, 0x9C, 0x75, 0x8F, 0x2B, 0xA5, + 0x97, 0xF9, 0xB6, 0x5F, 0x4E, 0x21, 0xBE, 0xB5, 0xD5, 0x9D, + 0x53, 0xC8, 0x5C, 0x4C, 0x86, 0x72, 0x88, 0xDA, 0xCA, 0x27, + 0x20, 0x07, 0x2C, 0x7B, 0xC2, 0x17, 0xB2, 0x1E, 0xED, 0x7B, + 0x5D, 0x84, 0x54, 0x4A, 0x3A, 0xC7, 0x96, 0xCA, 0x20, 0xAF, + 0xAC, 0x71, 0x21, 0x76, 0x2E, 0x27, 0x7B, 0x00, 0xE6, 0xB0, + 0x98, 0x30, 0xEA, 0x9D, 0x3E, 0x1D, 0xC5, 0x39, 0xC7, 0x72, + 0xF2, 0x00, 0x98, 0xC3, 0xE9, 0xC3, 0x87, 0x8F, 0x5E, 0x72, + 0xA8, 0x51, 0x51, 0x15, 0xA9, 0x87, 0x38, 0xFD, 0xEA, 0x1B, + 0xF4, 0x0C, 0x52, 0xEA, 0xA0, 0x70, 0x6D, 0xFE, 0x47, 0x61, + 0x3B, 0x59, 0xF1, 0x22, 0xA6, 0x16, 0x61, 0xB9, 0x2C, 0xE2, + 0x2A, 0x73, 0xD7, 0x8F, 0xBF, 0xA5, 0x1D, 0x16, 0x61, 0x29, + 0xA1, 0xC5, 0x57, 0xB2, 0x4A, 0xEE, 0x28, 0x8D, 0x7C, 0xC3, + 0x73, 0x36, 0x43, 0xCB, 0xC7, 0xB5, 0x8F, 0x02, 0x9C, 0x5F, + 0x0C, 0x22, 0x9E, 0xD7, 0x70, 0x2A, 0x07, 0x6F, 0xA4, 0x03, + 0xB3, 0x81, 0x76, 0x5B, 0x92, 0xED, 0xBE, 0x70, 0x6E, 0x93, + 0x1B, 0x6C, 0xA1, 0x97, 0xA7, 0x42, 0x6F, 0x9D, 0xF0, 0x56, + 0xB5, 0x7C, 0x17, 0x1D, 0x85, 0x2E, 0x07, 0xE1, 0x99, 0x2E, + 0xA4, 0x92, 0x9B, 0x80, 0x2E, 0x5E, 0x85, 0x34, 0xD0, 0xFF, + 0x5B, 0x26, 0xCC, 0xFE, 0xD5, 0xA8, 0x2E, 0x9E, 0xFF, 0xBB, + 0xC4, 0xDD, 0x86, 0x46, 0xC5, 0xE4, 0x93, 0xB4, 0x0E, 0x13, + 0xBB, 0x57, 0x7E, 0x7A, 0x5C, 0xC5, 0x38, 0xBA, 0xDF, 0xB2, + 0x0E, 0x03, 0x36, 0x75, 0xB4, 0x98, 0x61, 0x01, 0x1B, 0x3F, + 0x4C, 0x7B, 0x2E, 0x5C, 0xA3, 0x62, 0x4F, 0x67, 0x86, 0xBA, + 0x6D, 0x51, 0x61, 0x54, 0x5C, 0xE5, 0x8C, 0x3E, 0x9C, 0xE1, + 0x9C, 0x7C, 0xF6, 0x7E, 0x96, 0x8C, 0x42, 0xF2, 0xB5, 0x94, + 0x7D, 0x94, 0xF1, 0x76, 0x97, 0xA9, 0x46, 0x0D, 0x1D, 0x69, + 0x22, 0x33, 0x07, 0xC9, 0x41, 0x8C, 0xE5, 0x26, 0xA2, 0xED, + 0x6B, 0x06, 0x7B, 0x77, 0x14, 0x23, 0x80, 0xDA, 0xC0, 0xE7, + 0xF5, 0x63, 0x95, 0xC9, 0x55, 0x12, 0xAE, 0xCF, 0x17, 0xE5, + 0xC4, 0x06, 0xDF, 0x05, 0xBE, 0x30, 0x63, 0x50, 0x77, 0x95, + 0xDC, 0x07, 0x54, 0x31, 0xDE, 0xCC, 0x03, 0x72, 0xB8, 0x24, + 0xE5, 0x90, 0x46, 0x7E, 0xC2, 0xC3, 0xCB, 0xF0, 0x31, 0xDC, + 0x08, 0x85, 0x8C, 0x88, 0xEA, 0xA2, 0x8E, 0x22, 0xB8, 0x72, + 0x84, 0x4E, 0x54, 0x81, 0x3A, 0x3C, 0xEF, 0x88, 0x2A, 0x2F, + 0x00, 0x32, 0xFB, 0xA1, 0xF7, 0x3A, 0x0D, 0xAF, 0x62, 0xBD, + 0xCC, 0xE1, 0x92, 0xCD, 0x66, 0xE5, 0x2F, 0xC6, 0xCC, 0xDB, + 0x2E, 0x52, 0x19, 0xF0, 0x28, 0x25, 0xBE, 0xD2, 0x7C, 0x47, + 0xBD, 0x59, 0x02, 0xB8, 0x25, 0x63, 0x00, 0xEA, 0x36, 0xB4, + 0xF3, 0x90, 0x4C, 0x7F, 0x6A, 0x53, 0x39, 0xFF, 0x18, 0xD4, + 0x0C, 0x81, 0xCA, 0xCD, 0x6C, 0x30, 0x91, 0xBC, 0x1C, 0xE5, + 0xA1, 0x6F, 0x1F, 0xF1, 0x34, 0x4E, 0xC0, 0x89, 0x69, 0xCA, + 0xEC, 0xDD, 0x14, 0x87, 0x2A, 0x95, 0xFF, 0x28, 0xB6, 0x7B, + 0xCC, 0xDD, 0xD1, 0x55, 0x06, 0xD0, 0x78, 0xA6, 0x58, 0x57, + 0x2A, 0x69, 0x26, 0x11, 0x7B, 0x2D, 0xF3, 0x61, 0x7C, 0x5A, + 0x5B, 0x56, 0x7C, 0x6C, 0xEA, 0xC5, 0xB2, 0x5E, 0x48, 0x4D, + 0xE3, 0x23, 0x19, 0xDF, 0x61, 0x53, 0x17, 0x32, 0x5F, 0xA0, + 0x35, 0xC3, 0x23, 0xBE, 0x85, 0x51, 0xE2, 0x8A, 0x6F, 0x80, + 0x23, 0xA0, 0x55, 0x8B, 0xCE, 0x33, 0x48, 0x86, 0xBD, 0x1B, + 0x81, 0x83, 0x07, 0x0B, 0xFB, 0xD8, 0x70, 0xB7, 0xD0, 0xBD, + 0x03, 0xE4, 0xD1, 0xA7, 0xE4, 0x18, 0xD4, 0x00, 0xC4, 0x13, + 0x1A, 0xE6, 0x30, 0xC3, 0x81, 0xFE, 0xDE, 0x22, 0x7D, 0x9E, + 0xA4, 0x6F, 0x05, 0xE5, 0x6F, 0x0F, 0x45, 0x09, 0xFB, 0x47, + 0x2F, 0x84, 0xEF, 0x0F, 0xBE, 0x56, 0x04, 0x2D, 0xA5, 0x16, + 0xF1, 0x50, 0x1C, 0x73, 0x75, 0xCE, 0xC5, 0xD7, 0x55, 0x74, + 0x3E, 0x8F, 0x2B, 0xB6, 0x2A, 0xD6, 0xD7, 0x2E, 0x25, 0xBB, + 0xED, 0x36, 0x6B, 0xB7, 0xC3, 0x00, 0x59, 0x2D, 0xED, 0xEA, + 0x11, 0xB6, 0xA0, 0xB2, 0x18, 0x4F, 0xF6, 0x96, 0x05, 0xAE, + 0x88, 0x57, 0x26, 0x61, 0x23, 0x1E, 0x6B, 0xD5, 0x9C, 0xD6, + 0x03, 0x05, 0xDD, 0x23, 0xBB, 0xA5, 0xED, 0x00, 0x0D, 0x63, + 0x4B, 0xBC, 0x2F, 0x85, 0x6E, 0x81, 0xE1, 0xE2, 0xB8, 0x27, + 0xA3, 0xCA, 0xB3, 0x96, 0x78, 0xAF, 0xDC, 0x2C, 0xF3, 0xDF, + 0xB6, 0xF1, 0x7B, 0xC8, 0xC9, 0xC0, 0xCC, 0xE7, 0x6E, 0x7E, + 0x91, 0xED, 0x4C, 0x65, 0xBF, 0x67, 0xF6, 0x8C, 0xB3, 0xC7, + 0x34, 0x25, 0xFC, 0x6E, 0x78, 0x1C, 0x4F, 0x41, 0x0B, 0x8B, + 0x45, 0x76, 0xDF, 0xA7, 0x3B, 0xF3, 0x3B, 0xD6, 0xB1, 0x55, + 0x78, 0x1F, 0x12, 0x7A, 0xEB, 0x1C, 0x94, 0x8B, 0xA8, 0x19, + 0x4C, 0x85, 0x52, 0xA8, 0x66, 0x3F, 0x64, 0xC4, 0xB5, 0x7A, + 0x6F, 0x4B, 0xD1, 0xE6, 0x03, 0x96, 0x33, 0xAA, 0xAA, 0x6B, + 0x55, 0x50, 0x75, 0x96, 0xEB, 0xE5, 0x92, 0x9F, 0xAF, 0xD8, + 0x26, 0xFE, 0x17, 0xDA, 0x58, 0x61, 0x9C, 0xE2, 0x4B, 0x90, + 0xB9, 0xCF, 0x78, 0x8A, 0x78, 0x9B, 0x8E, 0x8F, 0x7C, 0x21, + 0xD5, 0x60, 0x9E, 0xFE, 0x87, 0x52, 0x6E, 0x3C, 0x47, 0xCC, + 0xB8, 0x51, 0x2B, 0x68, 0x55, 0x09, 0xB5, 0xAB, 0xE9, 0xFB, + 0xC6, 0x8E, 0x1E, 0x59, 0x51, 0x2E, 0xCF, 0xAB, 0x1F, 0x1F, + 0xED, 0x2D, 0x29, 0xD4, 0xCD, 0xC7, 0x11, 0x9B, 0x4A, 0x2D, + 0xF9, 0x95, 0x6C, 0x4C, 0xBF, 0xAA, 0x92, 0xCE, 0x3D, 0xB5, + 0x1C, 0xB8, 0x03, 0xC1, 0xC2, 0xE8, 0x6D, 0xD6, 0x56, 0x00, + 0x66, 0xD6, 0x4E, 0x76, 0xB6, 0xC5, 0x68, 0x2C, 0x94, 0x10, + 0x75, 0xD4, 0x3A, 0x40, 0x0F, 0x87, 0xB2, 0xAA, 0x0D, 0xF3, + 0x30, 0x82, 0x7D, 0x8A, 0x2A, 0xC2, 0x45, 0xF8, 0x96, 0x11, + 0xC6, 0xB9, 0xDC, 0x44, 0xCE, 0x74, 0xE7, 0xEC, 0x3D, 0x99, + 0xA8, 0x4F, 0xE1, 0xB2, 0xEB, 0xFA, 0x93, 0x7F, 0x75, 0x73, + 0xE3, 0xEC, 0x06, 0x6A, 0x23, 0x29, 0x6B, 0x66, 0x33, 0x4F, + 0x7A, 0x3D, 0x99, 0x21, 0x85, 0x19, 0x21, 0x6F, 0xD7, 0x5D, + 0xD4, 0x14, 0xE2, 0x9F, 0x47, 0x9C, 0x81, 0x77, 0x2E, 0x47, + 0x0C, 0xBB, 0xB4, 0xBC, 0x7B, 0x31, 0x43, 0x4F, 0xFD, 0x3F, + 0x63, 0xB1, 0xEE, 0x4C, 0xF4, 0xA1, 0xA4, 0x50, 0x5D, 0x87, + 0x84, 0x13, 0xAE, 0x98, 0x9D, 0x96, 0x22, 0x26, 0xC3, 0x14, + 0xA1, 0xB2, 0x51, 0xD6, 0xB9, 0x8E, 0xC0, 0xEF, 0xCD, 0x2D, + 0xDE, 0xB0, 0x99, 0xAC, 0x37, 0xE6, 0x91, 0x48, 0x2B, 0x86, + 0xD7, 0x14, 0x7D, 0xCD, 0x40, 0x94, 0x9F, 0x85, 0x8E, 0xDE, + 0x90, 0xFC, 0x73, 0xAC, 0x71, 0x20, 0xAF, 0x41, 0xBE, 0x9D, + 0x62, 0x39, 0xC9, 0x19, 0xE5, 0x29, 0x06, 0x38, 0xF4, 0xF6, + 0xBC, 0x63, 0x51, 0x29, 0x24, 0x06, 0xA2, 0x5B, 0x7D, 0x2A, + 0x3D, 0xFC, 0x86, 0xA8, 0xB3, 0x55, 0xC2, 0x8B, 0x2E, 0x17, + 0x5A, 0x45, 0x03, 0x8F, 0x40, 0xC9, 0x2A, 0xAB, 0x63, 0xFA, + 0xCF, 0xB5, 0xEF, 0xFD, 0xC9, 0x44, 0xB5, 0x3E, 0x67, 0xDF, + 0x4F, 0x1A, 0x3F, 0xE9, 0xC0, 0x09, 0x6B, 0x97, 0x81, 0x16, + 0x6B, 0xA2, 0x29, 0x8F, 0x3C, 0x69, 0xDC, 0x1B, 0x69, 0x35, + 0x2E, 0x1E, 0x51, 0x49, 0x4D, 0x03, 0x12, 0x16, 0xE1, 0xB5, + 0xCE, 0x78, 0xF6, 0x1C, 0xF4, 0x38, 0x28, 0x27, 0xEE, 0xFC, + 0xCC, 0x09, 0xFB, 0x7D, 0x48, 0x6A, 0xC3, 0x29, 0xDA, 0xA9, + 0x7E, 0x86, 0x75, 0x4A, 0x3C, 0x1D, 0xE7, 0x06, 0xA3, 0x4E, + 0x6F, 0x33, 0x3C, 0x2D, 0x37, 0x59, 0x0B, 0x14, 0xCA, 0xA6, + 0x9B, 0x5A, 0x07, 0x8F, 0xEB, 0xED, 0x20, 0xD2, 0xE9, 0x77, + 0x24, 0x18, 0x95, 0x26, 0xDD, 0xA2, 0xC8, 0x75, 0x5A, 0x8B, + 0x10, 0xF5, 0xFA, 0x95, 0xA9, 0xCB, 0x21, 0xD9, 0x1D, 0x16, + 0x25, 0x6D, 0x07, 0xB4, 0xB9, 0x48, 0xE8, 0xEB, 0xAC, 0xD4, + 0x62, 0xF4, 0xA8, 0xBD, 0xCE, 0xEE, 0x2E, 0x6F, 0x7E, 0xAD, + 0xD3, 0xBD, 0x08, 0x74, 0x1F, 0x97, 0x69, 0xC7, 0x4F, 0x5D, + 0xF0, 0xBC, 0x1B, 0x39, 0xD7, 0xED, 0xB2, 0x7D, 0x7B, 0x0C, + 0xFE, 0x35, 0x95, 0x4B, 0x96, 0x51, 0x6F, 0xC0, 0x2A, 0x18, + 0x6C, 0xB5, 0x1E, 0x64, 0xEE, 0xDA, 0xD9, 0x00, 0xC9, 0x21, + 0x54, 0x30, 0xDE, 0x83, 0x46, 0xED, 0x1C, 0x4A, 0x17, 0xFA, + 0x0A, 0x99, 0x0A, 0x9C, 0x05, 0x8F, 0xE3, 0x97, 0x84, 0x4E, + 0xB2, 0x9A, 0x70, 0xCA, 0xD4, 0xB6, 0xAE, 0x1E, 0x42, 0xD4, + 0x99, 0xC2, 0xCE, 0xB0, 0x54, 0x6B, 0x0B, 0x26, 0xCF, 0xCB, + 0xA4, 0x8C, 0x3E, 0x45, 0xD8, 0xBF, 0x86, 0x0D, 0xEF, 0xBB, + 0x91, 0x6D, 0x66, 0x42, 0x0A, 0xEB, 0x6E, 0x40, 0x82, 0x20, + 0xF0, 0x4F, 0x3A, 0xAB, 0x14, 0x55, 0x84, 0xBD, 0xB9, 0x6C, + 0xB0, 0x36, 0x3F, 0x95, 0xB9, 0x63, 0x82, 0x63, 0x15, 0xAC, + 0x0C, 0x3D, 0xDE, 0xF6, 0x77, 0x7F, 0xD9, 0xB6, 0x1F, 0x62, + 0x9C, 0x5E, 0x27, 0xE9, 0xA9, 0x3E, 0x41, 0xBD, 0x47, 0x37, + 0x59, 0x54, 0x2D, 0xF2, 0xD2, 0xBB, 0x49, 0x08, 0xE8, 0xD6, + 0x4D, 0xCC, 0x24, 0xFF, 0xAE, 0xE6, 0x1D, 0x84, 0x5B, 0x0A, + 0x29, 0x0F, 0x04, 0xAA, 0x6B, 0xE7, 0xE3, 0x3F, 0x73, 0x83, + 0xF8, 0xF7, 0xDC, 0xF3, 0x74, 0x54, 0xEF, 0xD5, 0xC6, 0xAB, + 0x48, 0xDD, 0xCF, 0x24, 0xF6, 0x0E, 0xE4, 0xAA, 0x46, 0x7F, + 0x26, 0x3B, 0x3D, 0x55, 0xC4, 0xE3, 0xDB, 0x68, 0x80, 0x01, + 0x26, 0x25, 0xEF, 0x13, 0xC3, 0x43, 0x53, 0x08, 0xDB, 0x09, + 0xBF, 0x37, 0x4A, 0xA3, 0x4D, 0x58, 0xE3, 0x47, 0xDC, 0x3E, + 0x4D, 0xCA, 0x9E, 0x49, 0xE4, 0x97, 0x91, 0xA3, 0xBD, 0xDF, + 0x16, 0x39, 0xCC, 0x4A, 0x93, 0xA8, 0x5E, 0x5A, 0xEB, 0x1B, + 0x7F, 0x6D, 0xEC, 0xCD, 0x79, 0x7C, 0x02, 0xBB, 0x02, 0xA8, + 0x88, 0x79, 0x2B, 0xF2, 0xA7, 0x82, 0xD1, 0x78, 0xDB, 0x4A, + 0x53, 0x46, 0x17, 0x12, 0x68, 0x55, 0x93, 0x56, 0x9E, 0x51, + 0x88, 0x96, 0x2A, 0xD2, 0x1A, 0x1A, 0x3E, 0xE7, 0x2A, 0xD2, + 0xBA, 0x8E, 0xB7, 0x9E, 0xAA, 0xE4, 0x47, 0xB2, 0x0F, 0x91, + 0x15, 0x60, 0x8C, 0xD8, 0x0B, 0xC9, 0x95, 0x6C, 0xB5, 0x8A, + 0x83, 0xC1, 0xAF, 0x9C, 0x62, 0x8B, 0x55, 0xE8, 0xDC, 0x95, + 0xC7, 0x86, 0xDC, 0x8C, 0xCD, 0x7A, 0x5D, 0xFA, 0x08, 0x81, + 0x43, 0x4E, 0xBD, 0x14, 0xFA, 0x29, 0x18, 0x7A, 0x6A, 0x21, + 0x83, 0x35, 0x81, 0x3A, 0x9D, 0xEF, 0xD2, 0x7F, 0x40, 0x0B, + 0xB3, 0x99, 0xD8, 0x84, 0x41, 0xC0, 0x85, 0x84, 0x64, 0x0D, + 0x31, 0xAC, 0xB2, 0x61, 0x87, 0x90, 0x42, 0x7F, 0xBF, 0x7D, + 0x05, 0xE4, 0xBA, 0x90, 0x1A, 0x0B, 0x9D, 0x7F, 0xE2, 0x2C, + 0x91, 0x63, 0x78, 0x04, 0xCA, 0x51, 0xEA, 0x95, 0xBA, 0xC3, + 0x14, 0xF7, 0xC5, 0xEF, 0xA1, 0xA1, 0xC4, 0x91, 0x1F, 0x3B, + 0xD6, 0xEE, 0xDB, 0x47, 0x27, 0x10, 0x65, 0x8B, 0x46, 0x0B, + 0xA6, 0x1C, 0xBE, 0x19, 0xF0, 0x5C, 0xDD, 0xAA, 0x47, 0x55, + 0x0B, 0xF9, 0x29, 0x94, 0xE6, 0x6B, 0xD3, 0x23, 0xA6, 0x19, + 0x95, 0xDD, 0xA9, 0xB4, 0xBC, 0xB6, 0xDD, 0xD1, 0x58, 0x15, + 0x7C, 0x40, 0xBF, 0xB8, 0xF9, 0x7C, 0x11, 0x8C, 0x96, 0xDE, + 0xE5, 0xB0, 0xA7, 0x99, 0x72, 0x14, 0x85, 0xF0, 0x24, 0x60, + 0xE6, 0xBA, 0xFC, 0x98, 0x6E, 0xF7, 0x83, 0x3E, 0x96, 0x29, + 0x75, 0xA6, 0x75, 0x58, 0xA4, 0xAC, 0x76, 0x1B, 0x28, 0xB8, + 0x3C, 0xA6, 0x24, 0x43, 0xB2, 0x3A, 0xC1, 0x0D, 0x3F, 0xD6, + 0x20, 0x15, 0x6D, 0x6D, 0x81, 0x2B, 0xCF, 0x59, 0x8B, 0xF7, + 0x21, 0xD9, 0xDE, 0xD6, 0x09, 0x12, 0x12, 0xC5, 0xC7, 0xF0, + 0xDC, 0x76, 0xA5, 0xE8, 0x76, 0x9B, 0x26, 0xF8, 0xB7, 0xA5, + 0x17, 0xFC, 0x03, 0x51, 0x4E, 0x05, 0x4F, 0xFB, 0x1C, 0x07, + 0x8C, 0xEF, 0x85, 0x23, 0x9A, 0x73, 0xE9, 0xC6, 0xAD, 0xEE, + 0xE2, 0x57, 0x63, 0x3A, 0x9A, 0x85, 0x3B, 0x69, 0x67, 0x96, + 0xA1, 0x04, 0x4F, 0x66, 0x8D, 0x45, 0xC7, 0x23, 0xB6, 0xFC, + 0x35, 0xA1, 0x9B, 0x85, 0xF3, 0x0E, 0x1D, 0x0E, 0x42, 0xD3, + 0x2E, 0xA2, 0x9D, 0x32, 0xFD, 0xD0, 0x1D, 0x85, 0x23, 0x9E, + 0xC7, 0xA9, 0x74, 0xAB, 0xB0, 0x0F, 0x8B, 0x9C, 0xF0, 0xE1, + 0x97, 0x95, 0x94, 0x37, 0x91, 0x46, 0xE5, 0x4C, 0xCE, 0x68, + 0xE4, 0x3F, 0xDB, 0xA0, 0xDF, 0xC8, 0x58, 0xE6, 0xD3, 0x7A, + 0x41, 0xEC, 0x2E, 0x70, 0x6C, 0x0B, 0x40, 0xCA, 0x31, 0x39, + 0x1D, 0x76, 0x34, 0x11, 0x30, 0xEF, 0xF5, 0x6C, 0xE9, 0x5E, + 0xDA, 0x48, 0xAE, 0xB1, 0x22, 0xA3, 0x19, 0xC9, 0xF5, 0x74, + 0x58, 0xB5, 0x7F, 0x3F, 0x3D, 0x64, 0x24, 0xC0, 0x04, 0xF6, + 0x4A, 0x75, 0x81, 0x39, 0x39, 0x47, 0xC5, 0xF5, 0x17, 0xE2, + 0x12, 0x74, 0x35, 0x1A, 0x3C, 0xC3, 0x53, 0x0D, 0x60, 0x85, + 0x42, 0xEE, 0x65, 0x2B, 0x1A, 0x70, 0x90, 0x22, 0x29, 0xCF, + 0xC5, 0x56, 0x8F, 0xC4, 0x46, 0x19, 0xCC, 0xC5, 0xD1, 0x28, + 0xEE, 0xFE, 0x78, 0x39, 0xB2, 0xAB, 0xF8, 0x6F, 0x4C, 0xB0, + 0x87, 0x36, 0x40, 0xBC, 0xEB, 0x97, 0x19, 0x6D, 0x50, 0x39, + 0x24, 0x7F, 0xCD, 0x46, 0xF4, 0xAA, 0x2B, 0x38, 0x92, 0x02, + 0x98, 0xD4, 0x40, 0x2A, 0x3E, 0xBC, 0x24, 0xC7, 0x86, 0xBD, + 0x0C, 0x44, 0x7B, 0xA6, 0x64, 0xFA, 0x28, 0x26, 0x4C, 0x8E, + 0xB6, 0xA0, 0x5A, 0x15, 0xDC, 0xFB, 0x30, 0x8C, 0xB9, 0xDD, + 0xD2, 0x51, 0x0E, 0x4C, 0xED, 0x84, 0xA1, 0x01, 0xCC, 0x04, + 0x72, 0xD5, 0x30, 0x16, 0x98, 0xB2, 0xCC, 0xE5, 0xFD, 0x60, + 0xF5, 0x1C, 0x28, 0x72, 0x0B, 0x37, 0xD4, 0x09, 0x58, 0x8D, + 0x81, 0xCE, 0x7D, 0xAF, 0x97, 0xA2, 0xC6, 0x10, 0x9C, 0x19, + 0x0C, 0x8E, 0x94, 0x3D, 0x94, 0x7A, 0x0D, 0xCB, 0xA2, 0xC2, + 0x0F, 0x60, 0x57, 0x8F, 0x3B, 0x6A, 0x59, 0xBB, 0x4C, 0xAB, + 0xBF, 0x2B, 0xC7, 0x67, 0xF2, 0x14, 0xBE, 0x19, 0xA9, 0xA3, + 0xBE, 0x38, 0xB3, 0x8E, 0xFB, 0x63, 0x4C, 0x13, 0x57, 0xD2, + 0x24, 0x66, 0x3D, 0xF2, 0x19, 0x1A, 0xD5, 0x51, 0xDB, 0x6F, + 0xB2, 0x95, 0xA7, 0x65, 0x10, 0x24, 0xB7, 0x5C, 0x1C, 0x44, + 0x17, 0x5D, 0x35, 0x5F, 0x73, 0x61, 0x4C, 0x9C, 0xC8, 0xF9, + 0xF5, 0x4D, 0xC2, 0x0D, 0x82, 0xCC, 0x86, 0x0C, 0x87, 0x1D, + 0xFC, 0x2A, 0x8E, 0x27, 0x28, 0x5C, 0x21, 0xED, 0x52, 0xC3, + 0x20, 0xBB, 0x57, 0x4C, 0x94, 0x26, 0x40, 0x5E, 0xEB, 0x27, + 0x33, 0xA7, 0x93, 0x07, 0x61, 0xF2, 0x57, 0x4E, 0xAF, 0xBC, + 0x86, 0xDB, 0xFC, 0xC0, 0x7B, 0x71, 0xE7, 0xB8, 0x08, 0xFA, + 0xE0, 0xC2, 0xF6, 0xC2, 0x6E, 0x96, 0x50, 0xAD, 0x11, 0xC3, + 0x42, 0x70, 0xB2, 0xA8, 0x8B, 0xAF, 0xBA, 0xE9, 0x17, 0x75, + 0x01, 0xA2, 0x3B, 0xE4, 0x82, 0xBD, 0x54, 0x8F, 0x07, 0xBD, + 0xD4, 0x07, 0x87, 0x44, 0x6E, 0xCE, 0xD6, 0x6D, 0x8C, 0xE7, + 0x9C, 0x27, 0x81, 0x9D, 0xF1, 0x07, 0xA8, 0xE2, 0xF7, 0x70, + 0x6E, 0x0B, 0x32, 0xBF, 0xF9, 0x36, 0xF6, 0x68, 0xB0, 0x43, + 0x4E, 0xCC, 0x7A, 0xAF, 0x38, 0x39, 0x59, 0x6B, 0x6B, 0x30, + 0x9C, 0xD5, 0xF8, 0xB9, 0xA1, 0xEE, 0xB0, 0xCF, 0x32, 0xBC, + 0x32, 0xFA, 0x68, 0x1B, 0xCA, 0xA0, 0x29, 0x6E, 0x69, 0xAA, + 0xE4, 0x06, 0x63, 0x56, 0xF9, 0x2C, 0xDB, 0x0D, 0xC3, 0xFC, + 0xB2, 0x37, 0xDC, 0x70, 0x6C, 0xFA, 0xA9, 0x20, 0x79, 0xE7, + 0x78, 0x3C, 0xA2, 0x1E, 0x4F, 0x6D, 0x5E, 0xD4, 0x7B, 0xD6, + 0x88, 0x42, 0xAB, 0x92, 0x96, 0x97, 0x56, 0x41, 0x45, 0x35, + 0xF0, 0x16, 0xB6, 0xFD, 0xEE, 0xEB, 0xDC, 0x6E, 0xD0, 0x05, + 0x80, 0xC1, 0xA2, 0xF6, 0xAD, 0x33, 0xF1, 0xAD, 0x35, 0x8C, + 0x90, 0x18, 0x44, 0xED, 0x4D, 0x09, 0x17, 0x6F, 0xA4, 0xF4, + 0x60, 0xFD, 0xD5, 0xA2, 0xC8, 0x0F, 0xAA, 0xE0, 0xD9, 0x97, + 0x6F, 0x7B, 0x44, 0xB2, 0x9E, 0xE9, 0x48, 0x49, 0x86, 0xB5, + 0xB9, 0x2F, 0xA2, 0x48, 0x64, 0x35, 0xEA, 0x31, 0xB9, 0xFB, + 0x18, 0x8D, 0xC4, 0x70, 0x8B, 0x93, 0xBF, 0xC7, 0x6E, 0x05, + 0x0E, 0x21, 0xA0, 0x73, 0xD0, 0x71, 0x00, 0xF9, 0x53, 0xA4, + 0x0B, 0x34, 0xD8, 0x20, 0x5A, 0x08, 0xE4, 0x2D, 0x5E, 0xA6, + 0xBF, 0xB5, 0x33, 0xFA, 0x02, 0x7D, 0xD7, 0x37, 0x94, 0xA7, + 0x3E, 0x59, 0x2C, 0x1C, 0x91, 0x51, 0x8A, 0x77, 0xA6, 0xE0, + 0x1D, 0xED, 0x2B, 0x2E, 0xFF, 0x16, 0x00, 0x2B, 0x38, 0xC7, + 0x9A, 0xCA, 0x8B, 0xCB, 0xAA, 0x0B, 0xB2, 0xD8, 0x0B, 0x3A, + 0xE7, 0x36, 0x80, 0x72, 0xE9, 0x93, 0x39, 0x3E, 0xB7, 0x2F, + 0x66, 0x6F, 0x65, 0xC4, 0x0D, 0x28, 0x5A, 0x96, 0x4F, 0x2F, + 0xBF, 0x93, 0x2F, 0x32, 0xD4, 0xD2, 0x7B, 0xAE, 0x74, 0x09, + 0xE1, 0x33, 0x63, 0x32, 0x3F, 0x1F, 0x78, 0x46, 0x65, 0x66, + 0x38, 0x19, 0xB9, 0xE6, 0xF7, 0xD6, 0xCB, 0x8B, 0xA4, 0xCE, + 0x46, 0x0E, 0xF9, 0x26, 0x18, 0x12, 0xC6, 0xDE, 0x69, 0xD0, + 0x75, 0xBC, 0x63, 0x68, 0x05, 0x72, 0x38, 0xEA, 0xE9, 0xFD, + 0xE0, 0x81, 0x00, 0xA2, 0x55, 0xB9, 0x0E, 0xD6, 0xFE, 0xEB, + 0x40, 0xDD, 0x05, 0x8A, 0x35, 0x2D, 0x27, 0xA6, 0x05, 0x6F, + 0x92, 0x73, 0x80, 0x73, 0xA8, 0x25, 0xF6, 0xB6, 0x16, 0x1C, + 0x58, 0xEE, 0x69, 0xC0, 0xE2, 0x7C, 0xA5, 0xF2, 0x45, 0x10, + 0xAC, 0x3D, 0x26, 0xD2, 0x94, 0xE8, 0x2B, 0x1E, 0x55, 0xF7, + 0x1C, 0xDA, 0x62, 0x39, 0x1E, 0x37, 0xF1, 0xF5, 0xFF, 0x56, + 0x97, 0x23, 0x4C, 0x33, 0x48, 0x25, 0x64, 0x2C, 0xF7, 0x88, + 0x20, 0x88, 0xC5, 0x35, 0xBE, 0x3F, 0x54, 0x81, 0x83, 0xCD, + 0x12, 0x8A, 0xED, 0xD7, 0x2C, 0x66, 0x16, 0x62, 0x6C, 0x27, + 0x9C, 0x7E, 0x5D, 0xCD, 0xBF, 0x7D, 0xDE, 0x20, 0xE3, 0xD1, + 0x99, 0xEE, 0xEC, 0x67, 0x8E, 0xAB, 0xC2, 0x93, 0xFA, 0xBB, + 0x1E, 0x0C, 0xA1, 0xD8, 0x16, 0x9B, 0x36, 0xD7, 0x98, 0x81, + 0x77, 0x62, 0x9B, 0x76, 0xC9, 0x0C, 0x93, 0xAC, 0x99, 0x70, + 0x23, 0x22, 0x45, 0x44, 0x7C, 0x5F, 0x46, 0x42, 0x4F, 0x40, + 0xDE, 0x4F, 0xEA, 0xB4, 0x37, 0x88, 0x9B, 0x69, 0x5B, 0x42, + 0x66, 0x78, 0xA4, 0x81, 0x43, 0x48, 0x03, 0xD4, 0x83, 0xF3, + 0x59, 0x85, 0x44, 0x77, 0x69, 0x1E, 0xA0, 0xF5, 0x52, 0x9F, + 0x72, 0x15, 0xE9, 0x35, 0x53, 0xCC, 0xB8, 0xFA, 0xBB, 0xE2, + 0xEB, 0x95, 0x48, 0x3D, 0x08, 0x1E, 0x91, 0x80, 0x8E, 0x1B, + 0xB8, 0x69, 0x52, 0xD9, 0x95, 0x67, 0x2F, 0xAA, 0x4C, 0x37, + 0x90, 0x19, 0xD9, 0x1D, 0x0E, 0x3B, 0xBD, 0x51, 0x17, 0xB0, + 0x5E, 0x77, 0x64, 0xBB, 0xF6, 0x12, 0xCC, 0x04, 0x5F, 0x65, + 0x58, 0xEB, 0xCD, 0xCC, 0x8F, 0x9F, 0xF3, 0xD7, 0x68, 0x2E, + 0xF8, 0xE3, 0xA1, 0x4D, 0xA2, 0x03, 0x32, 0x68, 0x48, 0xE9, + 0xA9, 0xD6, 0x34, 0x5B, 0xCB, 0x18, 0x2D, 0x57, 0x56, 0xC4, + 0x38, 0x28, 0x99, 0xB0, 0x35, 0xFB, 0x0F, 0xDA, 0xD2, 0x9F, + 0xED, 0x3A, 0xBA, 0x57, 0x94, 0x7A, 0x3A, 0xE5, 0x43, 0xE1, + 0x71, 0xDA, 0xCE, 0x7E, 0xB8, 0x49, 0x93, 0x54, 0x9F, 0x63, + 0x08, 0xE8, 0x49, 0x1B, 0xA6, 0xA6, 0x45, 0x12, 0xFE, 0x19, + 0x11, 0xA2, 0x0C, 0x08, 0xA3, 0x28, 0x95, 0x23, 0xB3, 0x38, + 0xE7, 0x39, 0x40, 0x10, 0xF5, 0x07, 0x5E, 0x22, 0x5F, 0xAF, + 0x7E, 0x86, 0x23, 0xA2, 0x6C, 0x80, 0x92, 0x8C, 0xF1, 0xDD, + 0x09, 0x09, 0xC9, 0xEA, 0x91, 0xFF, 0x30, 0xE6, 0x65, 0x70, + 0x37, 0x23, 0x2E, 0x35, 0x3D, 0xB0, 0x87, 0x7D, 0x96, 0xAB, + 0x43, 0x83, 0xB2, 0x2F, 0xF1, 0x15, 0x4E, 0xDF, 0x8D, 0x9A, + 0x20, 0xA1, 0x91, 0x4C, 0x78, 0x8F, 0x14, 0xB8, 0x96, 0x58, + 0xE0, 0x6F, 0x5D, 0x1D, 0x44, 0x42, 0x26, 0xA8, 0x59, 0xAF, + 0xD4, 0x2F, 0x77, 0x45, 0x88, 0x50, 0x66, 0xB6, 0xB8, 0x08, + 0x53, 0x17, 0x8E, 0x40, 0x2A, 0x04, 0x65, 0x79, 0x59, 0x88, + 0xF1, 0xAE, 0xE6, 0xB1, 0xAC, 0xAA, 0xD7, 0x79, 0x2C, 0xDF, + 0xC6, 0xE3, 0x78, 0x93, 0x8A, 0x03, 0x5F, 0xF9, 0x9C, 0xCD, + 0x84, 0xDA, 0x17, 0x71, 0x4C, 0x62, 0xB3, 0xE7, 0xA7, 0xA9, + 0xE3, 0x5E, 0x13, 0xE3, 0xD3, 0xB8, 0x07, 0x07, 0x85, 0x2F, + 0xEC, 0x96, 0xBF, 0x05, 0x94, 0x33, 0x3D, 0x5D, 0x40, 0x57, + 0xDA, 0x97, 0xDE, 0x6C, 0x4B, 0xFB, 0xB8, 0x34, 0xBD, 0x35, + 0x5F, 0xB9, 0x4E, 0x7F, 0x4A, 0x73, 0x79, 0x3E, 0xF3, 0x7C, + 0x21, 0x04, 0x33, 0xAF, 0x14, 0x96, 0x68, 0xCE, 0x99, 0x52, + 0x07, 0x9B, 0x0D, 0xB3, 0x5B, 0x12, 0x18, 0xAE, 0xAB, 0x36, + 0xD7, 0x00, 0x28, 0x3E, 0x4F, 0x32, 0xCE, 0xB9, 0x7C, 0xA6, + 0xB5, 0x83, 0x54, 0x4D, 0xFE, 0x9F, 0x20, 0xC8, 0xEF, 0x32, + 0x2F, 0x88, 0xC6, 0xA3, 0xB4, 0x31, 0x37, 0x2C, 0x22, 0x86, + 0xF2, 0x36, 0xD1, 0x6D, 0x68, 0x51, 0xA8, 0x69, 0x18, 0xC4, + 0x3A, 0xC6, 0xEB, 0x59, 0xCB, 0x62, 0x8E, 0x26, 0x5A, 0x55, + 0xCA, 0x4F, 0xB9, 0x2C, 0x25, 0xE9, 0x85, 0xB9, 0x8C, 0x84, + 0x65, 0xEC, 0xCD, 0x28, 0x6F, 0x4C, 0xC8, 0xE5, 0xA1, 0x62, + 0x0D, 0x3E, 0xAA, 0xFD, 0xC9, 0x58, 0x8E, 0x75, 0x61, 0x30, + 0x15, 0xB3, 0x0D, 0x4B, 0x5B, 0x85, 0x7E, 0xC5, 0x87, 0xC3, + 0xED, 0x5B, 0xDB, 0xD4, 0x00, 0x91, 0xF7, 0xD2, 0xD6, 0x76, + 0xB3, 0x90, 0x98, 0x6D, 0x8E, 0xE5, 0x64, 0xCD, 0x79, 0x3E, + 0xFF, 0x93, 0xA5, 0x3F, 0xFE, 0x9F, 0xD3, 0x8E, 0x28, 0xDD, + 0x77, 0x91, 0x63, 0xC2, 0x6E, 0x6D, 0x45, 0x6D, 0x1A, 0xD3, + 0x47, 0x92, 0x1C, 0x3F, 0xDF, 0x3C, 0xA7, 0x17, 0x6A, 0x0E, + 0x70, 0xE9, 0xD6, 0xEE, 0xF1, 0x8C, 0x2C, 0xEB, 0x38, 0x6F, + 0x90, 0x60, 0x49, 0xA0, 0xAF, 0xAF, 0x02, 0xBE, 0x29, 0x9F, + 0x19, 0x59, 0xB4, 0xE9, 0xAB, 0xC3, 0x9D, 0x2F, 0x15, 0x62, + 0xFE, 0x8D, 0xE9, 0xED, 0x49, 0xA6, 0x83, 0xB9, 0x08, 0x63, + 0x80, 0xFA, 0x29, 0x6B, 0x9C, 0x69, 0x87, 0x0C, 0xAE, 0x9E, + 0x00, 0x2D, 0x3F, 0x29, 0x54, 0xD7, 0x86, 0xA2, 0x59, 0x8F, + 0x91, 0xBF, 0xDF, 0xAE, 0x70, 0xD9, 0xFA, 0xA6, 0x99, 0x36, + 0x49, 0x16, 0x37, 0xF5, 0xB4, 0x5D, 0xC1, 0x1D, 0xA1, 0x4D, + 0x32, 0xDF, 0x49, 0x62, 0xD4, 0xA4, 0x40, 0xDB, 0x6C, 0xBB, + 0x01, 0x1B, 0xA9, 0x87, 0x40, 0xCC, 0x76, 0xA2, 0x61, 0xA0, + 0x3C, 0x15, 0x51, 0x67, 0x50, 0xBF, 0x6D, 0x2B, 0x71, 0x17, + 0x92, 0x22, 0xC8, 0x02, 0x65, 0x8C, 0xF1, 0x9C, 0x0B, 0xEE, + 0x93, 0xFB, 0x3E, 0x17, 0x40, 0x04, 0x3E, 0x79, 0x83, 0xF1, + 0xAA, 0x40, 0xA9, 0xAB, 0x2C, 0x98, 0xCB, 0x49, 0xEA, 0x67, + 0x1C, 0x1B, 0xF7, 0xF9, 0xA9, 0xCA, 0x98, 0x35, 0x0E, 0x94, + 0x3B, 0x5D, 0x9A, 0x9B, 0x1E, 0xDF, 0xF9, 0xB3, 0xF6, 0x3B, + 0xCA, 0x69, 0x2D, 0x7B, 0x8C, 0xBF, 0x20, 0x0C, 0x90, 0x26, + 0x89, 0xA8, 0x39, 0x5F, 0x19, 0x84, 0xB3, 0x29, 0x54, 0xBA, + 0x64, 0x3A, 0x76, 0x4B, 0x9A, 0x42, 0xA0, 0x8F, 0x4C, 0x0C, + 0xBE, 0xED, 0x27, 0xAB, 0x09, 0x2F, 0xF2, 0x02, 0x37, 0x4E, + 0x8D, 0x98, 0x28, 0x27, 0x44, 0xC1, 0x9E, 0xBA, 0xDB, 0xD0, + 0x31, 0x68, 0xE7, 0x28, 0x91, 0xAF, 0x5A, 0x5A, 0xA8, 0xCD, + 0x1E, 0xF8, 0x22, 0xCC, 0xF2, 0x3B, 0x59, 0xF2, 0xEB, 0x6F, + 0x40, 0xD8, 0xE9, 0xFF, 0x3C, 0x0A, 0x80, 0x20, 0x65, 0x92, + 0x41, 0xDC, 0xDD, 0x24, 0x8E, 0x8D, 0x0E, 0x5B, 0xC7, 0xEB, + 0x12, 0x9E, 0x5C, 0x9D, 0x49, 0x22, 0xA2, 0x00, 0x56, 0xEC, + 0xF2, 0x1B, 0xA9, 0x3A, 0xD5, 0xA4, 0xBD, 0xB8, 0xF6, 0x8D, + 0x2F, 0x1E, 0xE8, 0xC3, 0x6A, 0x63, 0xA5, 0x31, 0x03, 0x68, + 0xA9, 0xEF, 0x04, 0xD2, 0xAD, 0x8B, 0x1A, 0x56, 0x7F, 0x12, + 0xEC, 0xC6, 0xA1, 0x9F, 0x59, 0x8A, 0x16, 0xC8, 0xE6, 0x96, + 0xA2, 0x3E, 0x93, 0xD2, 0x8C, 0x6E, 0x24, 0xF3, 0x6D, 0xD1, + 0xB3, 0xB5, 0x97, 0xBD, 0x92, 0x82, 0xE4, 0xBE, 0x0E, 0x78, + 0x80, 0x93, 0x40, 0xEA, 0xC6, 0x2A, 0x52, 0x59, 0xD0, 0xAF, + 0x71, 0x4E, 0x23, 0x4F, 0xC8, 0x69, 0x8D, 0xB5, 0xFF, 0x27, + 0x99, 0x57, 0xAA, 0x05, 0x93, 0xE6, 0x3A, 0x47, 0x12, 0x27, + 0x76, 0x7D, 0xF4, 0xE1, 0xF1, 0xB0, 0x22, 0xF3, 0xD8, 0xA8, + 0x60, 0x4C, 0x58, 0x83, 0xEB, 0x93, 0xD6, 0x26, 0xD2, 0x2E, + 0x5A, 0x39, 0xE6, 0xAD, 0xE6, 0x75, 0x5F, 0xF7, 0x86, 0xC5, + 0xD7, 0x03, 0x2F, 0xA0, 0xFD, 0x1B, 0xF9, 0x5D, 0xAF, 0x7E, + 0x7E, 0x7C, 0xC3, 0x01, 0xC5, 0x6A, 0x82, 0xA6, 0xE2, 0x56, + 0xF6, 0x67, 0xE0, 0x55, 0xC6, 0x9C, 0x33, 0x41, 0xFC, 0x14, + 0xCE, 0x77, 0xBE, 0x21, 0xCD, 0x13, 0x09, 0xF0, 0x79, 0xB1, + 0xC2, 0xB6, 0x01, 0x87, 0x4F, 0x22, 0x95, 0x76, 0xC9, 0x9B, + 0xD9, 0x0F, 0x6C, 0xD8, 0x47, 0x61, 0xFF, 0xA9, 0x14, 0x18, + 0x0E, 0x46, 0xCB, 0x58, 0xAB, 0x85, 0x64, 0x5D, 0x88, 0x94, + 0xD1, 0x19, 0x62, 0xB0, 0x69, 0xA7, 0x29, 0xAF, 0xD0, 0x9D, + 0xAB, 0x11, 0x00, 0xDE, 0xA7, 0x2A, 0x6D, 0xFA, 0xA6, 0x1C, + 0x85, 0xCF, 0x2B, 0x4C, 0x16, 0x78, 0xAC, 0x8F, 0xA9, 0x93, + 0x8E, 0x63, 0x76, 0x42, 0x44, 0xBC, 0xFC, 0xEB, 0xA9, 0x4E, + 0x1B, 0x2F, 0xA2, 0x66, 0xF8, 0xAE, 0xC1, 0xDF, 0xEE, 0x24, + 0xFE, 0x2B, 0x15, 0x7C, 0x9C, 0xFD, 0xFF, 0xFC, 0xB0, 0x9D, + 0xC4, 0x7A, 0x8D, 0xAB, 0x10, 0xA4, 0x6A, 0x48, 0xBD, 0x65, + 0x03, 0xD4, 0xBD, 0xCB, 0x3B, 0x3F, 0x58, 0xD3, 0x48, 0x30, + 0xFB, 0xBE, 0x69, 0xA0, 0x2C, 0x30, 0x00, 0x80, 0x81, 0x6C, + 0x28, 0x65, 0x98, 0xED, 0xFD, 0x02, 0x13, 0x1E, 0x9D, 0x1E, + 0xC9, 0xB5, 0x29, 0x37, 0xEB, 0xD2, 0x0B, 0x7D, 0xE2, 0x0C, + 0x9E, 0x89, 0xF6, 0x82, 0xD3, 0x7E, 0x5F, 0x70, 0xBA, 0x6D, + 0xCA, 0xAA, 0xFF, 0x1B, 0x0D, 0x60, 0xBD, 0xBA, 0xD6, 0x7F, + 0x45, 0x18, 0xDA, 0xF8, 0x4A, 0x72, 0x32, 0xA9, 0x58, 0x94, + 0x7E, 0xE6, 0x17, 0x88, 0xAC, 0x53, 0xDA, 0xC6, 0x2C, 0xCB, + 0x47, 0x1E, 0x79, 0xB8, 0x53, 0xBD, 0x5A, 0xE7, 0x70, 0xD6, + 0x94, 0x36, 0x1C, 0x8B, 0x97, 0x22, 0x41, 0x01, 0x1A, 0xFB, + 0xBE, 0x2B, 0x24, 0x26, 0x7E, 0x01, 0xCE, 0x4F, 0x32, 0xC6, + 0x59, 0xA8, 0x32, 0xE0, 0xCE, 0x49, 0x68, 0xCD, 0x03, 0x0A, + 0xB9, 0x6E, 0x55, 0x41, 0x1A, 0x4D, 0xDE, 0xE8, 0xDC, 0x7B, + 0x4D, 0x83, 0x93, 0x67, 0x0F, 0x0A, 0xAB, 0x22, 0xD6, 0xF9, + 0x64, 0xE2, 0x92, 0xA7, 0x57, 0xE6, 0xC3, 0xF0, 0xB6, 0xB5, + 0xBE, 0xE8, 0x96, 0x11, 0x66, 0xE4, 0xA7, 0x75, 0x66, 0x56, + 0xD8, 0x94, 0xDF, 0x5C, 0x5D, 0x57, 0x56, 0x06, 0xA7, 0x60, + 0xB3, 0xFC, 0x9F, 0xB9, 0x5F, 0x96, 0x80, 0xBB, 0x31, 0xA5, + 0x34, 0xD8, 0x3B, 0x7F, 0xBA, 0x9F, 0x33, 0xEB, 0xAB, 0x2E, + 0x90, 0x9C, 0xD2, 0x37, 0xC0, 0x3B, 0x8A, 0x1B, 0x43, 0x40, + 0x1E, 0xEE, 0xA9, 0x01, 0x2A, 0x2A, 0xB7, 0xDA, 0xB1, 0x84, + 0x49, 0x98, 0xA9, 0xA9, 0xA0, 0xD3, 0x55, 0xAD, 0xB7, 0x6B, + 0x12, 0x68, 0x06, 0x5B, 0x85, 0xC9, 0xB7, 0xDC, 0xC7, 0x7B, + 0x06, 0xA4, 0x42, 0x7F, 0xD5, 0x47, 0x0D, 0x77, 0x05, 0xAB, + 0x88, 0x8C, 0x3E, 0x17, 0x10, 0x12, 0x04, 0x05, 0xA1, 0x9C, + 0x68, 0xD2, 0x6F, 0x77, 0xCF, 0x37, 0x61, 0xD4, 0xAD, 0x1C, + 0x91, 0x16, 0x6E, 0x83, 0xD4, 0xAA, 0x7C, 0xAC, 0x08, 0xD1, + 0xC5, 0x21, 0x91, 0x1E, 0x5B, 0x86, 0xB7, 0x83, 0x7D, 0x15, + 0xC7, 0xD2, 0xAA, 0x08, 0xC9, 0xFE, 0x11, 0x9C, 0x15, 0xBF, + 0xB4, 0x65, 0x5F, 0xE0, 0xFB, 0xC1, 0xC2, 0xE6, 0x2C, 0xE1, + 0xDB, 0x79, 0xDA, 0x63, 0x5F, 0x79, 0x55, 0x3D, 0x0B, 0xE8, + 0xAD, 0x40, 0xBA, 0xC8, 0x3F, 0xA0, 0xBC, 0x4A, 0x69, 0x9D, + 0xF2, 0x10, 0xAF, 0xB0, 0x19, 0x6E, 0x7C, 0x01, 0x54, 0x6D, + 0x5E, 0x1D, 0xAB, 0x18, 0x59, 0xFD, 0x42, 0xF0, 0x8B, 0x17, + 0xB3, 0x49, 0x2D, 0xAA, 0x65, 0x68, 0x97, 0xF0, 0x05, 0xBB, + 0xAB, 0x02, 0xDF, 0xEB, 0x2F, 0x7D, 0x0A, 0xC7, 0x6B, 0xE3, + 0x16, 0x09, 0xBD, 0x8D, 0x08, 0x0F, 0xE4, 0xDD, 0x1B, 0x8C, + 0x28, 0x11, 0x71, 0xC8, 0x35, 0x1E, 0x8D, 0xDE, 0x98, 0x25, + 0x6A, 0xF7, 0xE5, 0x1C, 0xDC, 0xA8, 0x36, 0x9D, 0xEE, 0x60, + 0xCA, 0x1E, 0x61, 0xC2, 0xA9, 0x8E, 0xC3, 0xE7, 0xDC, 0xBF, + 0xEC, 0xD7, 0x07, 0xBB, 0xA8, 0x46, 0xE2, 0x97, 0x7D, 0xEE, + 0xB5, 0x2E, 0x63, 0xE7, 0xE9, 0xDA, 0x51, 0x83, 0x7E, 0x1C, + 0x5C, 0x8B, 0xB8, 0xD0, 0xF7, 0xDE, 0x9B, 0xEB, 0xB3, 0xE0, + 0x66, 0xA2, 0xA7, 0xC7, 0x2D, 0xC8, 0x8C, 0xB8, 0x28, 0xB5, + 0xED, 0x77, 0x19, 0xB2, 0xA7, 0x36, 0x70, 0x70, 0x0E, 0x44, + 0x8C, 0xD9, 0xF3, 0x74, 0x4B, 0xCD, 0x85, 0xD7, 0x4C, 0xEB, + 0xDA, 0xE5, 0x4C, 0x6D, 0x68, 0x27, 0x13, 0x62, 0x59, 0xE6, + 0x7A, 0xB5, 0x65, 0x77, 0xC7, 0x56, 0xBF, 0x1D, 0x4F, 0x5B, + 0x92, 0xC9, 0x83, 0x93, 0x22, 0xDA, 0xC6, 0x9E, 0xC2, 0xB8, + 0x27, 0x88, 0x6F, 0x00, 0xF8, 0x13, 0xBE, 0x1F, 0x99, 0x9A, + 0x34, 0x89, 0xCD, 0x43, 0xAD, 0x18, 0xFF, 0x50, 0x98, 0x71, + 0x8E, 0x75, 0x60, 0x4D, 0xD8, 0x82, 0x96, 0xB5, 0x38, 0x54, + 0xF0, 0x3B, 0x77, 0x4B, 0xC2, 0xCA, 0x34, 0x8D, 0xE6, 0x38, + 0xE1, 0x4B, 0x81, 0x91, 0xAA, 0x1D, 0x93, 0x2C, 0x62, 0xBF, + 0x73, 0x33, 0xE2, 0xC9, 0xF7, 0x0E, 0x33, 0x6C, 0xEB, 0x8B, + 0xF4, 0xEC, 0x80, 0xAD, 0xA9, 0xA4, 0xA1, 0x24, 0x60, 0x4D, + 0xF7, 0xBA, 0x92, 0xE2, 0xDD, 0xE4, 0x20, 0x17, 0x9A, 0x54, + 0x35, 0x08, 0x05, 0xD7, 0xFE, 0xD8, 0xBA, 0x92, 0x99, 0x1A, + 0x30, 0x95, 0x91, 0x3F, 0x0D, 0xF6, 0x03, 0x03, 0x0D, 0x15, + 0x9C, 0xBD, 0xD7, 0x07, 0xA4, 0x26, 0xD9, 0x4F, 0x86, 0x08, + 0xFD, 0x61, 0x67, 0x56, 0x85, 0x4E, 0xA5, 0x37, 0xBF, 0x20, + 0xA9, 0xA4, 0x15, 0x9A, 0x11, 0x57, 0xAB, 0xB4, 0x7B, 0x3F, + 0x95, 0x57, 0x86, 0xCB, 0x84, 0xF6, 0xCB, 0x23, 0x47, 0xB5, + 0xDE, 0xDE, 0x3D, 0xF2, 0x09, 0xBE, 0x79, 0xF5, 0xB6, 0x1E, + 0x46, 0x9A, 0x75, 0x8B, 0x1F, 0x89, 0x15, 0xD5, 0xCC, 0x41, + 0x9A, 0xD3, 0x9E, 0xB1, 0xF6, 0xD5, 0x5D, 0x12, 0xBD, 0x33, + 0xC8, 0x92, 0x73, 0xC2, 0x6B, 0x03, 0xC9, 0xF9, 0x8F, 0xE8, + 0xD5, 0x0A, 0x51, 0x00, 0x48, 0x81, 0xD9, 0x93, 0xAB, 0x45, + 0x34, 0x94, 0x17, 0x2A, 0x32, 0xEF, 0x42, 0xD0, 0x5B, 0xE8, + 0x8D, 0xDB, 0x98, 0xB9, 0x23, 0xE5, 0xC7, 0xF9, 0x37, 0xA4, + 0x22, 0x4A, 0x12, 0x7E, 0x1F, 0xAA, 0x46, 0x47, 0x3A, 0xFE, + 0xA7, 0x8A, 0xB4, 0xCB, 0x42, 0x38, 0x65, 0x7E, 0x00, 0x62, + 0xE4, 0x5D, 0x71, 0xBC, 0x07, 0x13, 0x42, 0x37, 0x52, 0x33, + 0xB7, 0x11, 0xD4, 0x03, 0xA8, 0x49, 0x4E, 0xDF, 0xE2, 0xEC, + 0x30, 0x7B, 0x62, 0x4F, 0xB6, 0xD8, 0x64, 0xF9, 0x0C, 0xD4, + 0x16, 0x44, 0x59, 0x25, 0xFC, 0x35, 0x0F, 0x2D, 0x55, 0xCC, + 0xD9, 0x03, 0x98, 0x04, 0x5C, 0x20, 0x19, 0xDD, 0x60, 0xA2, + 0xBB, 0xAA, 0xA5, 0xEE, 0xBE, 0x02, 0xB3, 0x5B, 0x27, 0xC6, + 0xC1, 0x64, 0xFA, 0x8C, 0x0F, 0xC3, 0xBC, 0x1B, 0xCB, 0xF1, + 0xC1, 0x8F, 0xE5, 0x79, 0xE8, 0x6D, 0xC5, 0xE5, 0x03, 0x64, + 0x03, 0xA2, 0x0C, 0x40, 0x02, 0xC9, 0x38, 0x03, 0x17, 0x77, + 0x12, 0x66, 0xFF, 0x81, 0xFA, 0x7B, 0xEC, 0x54, 0xA3, 0x6D, + 0x2A, 0xB7, 0xD0, 0xB0, 0xB2, 0x01, 0x73, 0x92, 0xB0, 0x27, + 0xBC, 0xAD, 0xE4, 0x0E, 0xB6, 0x6B, 0x15, 0xE4, 0xDD, 0x3D, + 0x20, 0x64, 0x49, 0x77, 0xF2, 0x25, 0xB1, 0x94, 0x74, 0xEF, + 0xDB, 0xEF, 0x80, 0xEA, 0x5F, 0x09, 0x27, 0x28, 0x33, 0xAC, + 0xEF, 0x61, 0x2A, 0x57, 0x3A, 0x07, 0x3A, 0x81, 0xAA, 0x4B, + 0xB3, 0xB8, 0xF2, 0xFB, 0xA3, 0x87, 0x9F, 0x93, 0x10, 0x0A, + 0x58, 0x16, 0xAD, 0x22, 0x72, 0x33, 0x41, 0x0C, 0x0E, 0x46, + 0xA7, 0xD0, 0x4A, 0x38, 0x4B, 0xC8, 0x40, 0x05, 0xBC, 0xEE, + 0x1C, 0x0D, 0x2C, 0xC0, 0xBF, 0x0B, 0x6A, 0x4A, 0x79, 0x79, + 0xD9, 0xC5, 0x4A, 0xF2, 0x20, 0xC9, 0x20, 0xAC, 0x5B, 0x9D, + 0xC7, 0x38, 0xA2, 0x27, 0x51, 0x46, 0x79, 0x4C, 0x62, 0x97, + 0xB9, 0x9B, 0x92, 0x9A, 0xC0, 0xF9, 0x5B, 0xE5, 0xB6, 0xD0, + 0xCC, 0x7A, 0x14, 0x3B, 0x74, 0xC2, 0x76, 0x70, 0xBF, 0x6D, + 0x2C, 0x0C, 0x3D, 0xCE, 0x46, 0x3A, 0x89, 0x82, 0xB6, 0x4B, + 0x13, 0x6A, 0x37, 0x29, 0x20, 0x7D, 0xFA, 0x26, 0xD7, 0x02, + 0x8C, 0x4B, 0x60, 0x79, 0x5B, 0x2D, 0x1C, 0x55, 0xF0, 0x91, + 0x2A, 0x4A, 0xAD, 0xAE, 0xF4, 0xB3, 0x36, 0xC6, 0x2D, 0x1A, + 0x32, 0x13, 0xF0, 0x46, 0x1A, 0x56, 0x7F, 0xCA, 0x00, 0xD8, + 0x5A, 0x2A, 0x51, 0x79, 0x37, 0x6E, 0xAD, 0x9F, 0x6B, 0x42, + 0x76, 0xF6, 0x7B, 0xC3, 0x8C, 0x62, 0x04, 0x96, 0x98, 0xA6, + 0xDF, 0x08, 0x16, 0xC1, 0xBC, 0xA1, 0x4B, 0x20, 0xB6, 0x5B, + 0xFA, 0x1F, 0xF0, 0x5A, 0xFE, 0x5C, 0xD6, 0x00, 0xE2, 0xBD, + 0xEA, 0xF5, 0xEF, 0x0B, 0x67, 0x24, 0x9A, 0x33, 0xEB, 0x4A, + 0x11, 0x44, 0x18, 0x90, 0x5C, 0x4B, 0xC2, 0x3F, 0xC3, 0x3C, + 0x55, 0x60, 0x19, 0x7A, 0x23, 0x87, 0xA7, 0x21, 0x72, 0x8D, + 0x50, 0x43, 0x37, 0xDE, 0xFE, 0xF7, 0xA6, 0xB1, 0x2B, 0xA5, + 0x32, 0x21, 0xB6, 0x58, 0x5F, 0x24, 0x8D, 0xF2, 0x17, 0x1D, + 0x71, 0x39, 0x9B, 0x2D, 0x86, 0x81, 0x86, 0xC2, 0x60, 0x72, + 0xAA, 0x7F, 0x75, 0xFF, 0x9C, 0xCB, 0xCE, 0xF3, 0x60, 0x2B, + 0xBE, 0xD4, 0x3E, 0xA7, 0xB9, 0xFF, 0x6D, 0x8A, 0x1F, 0x4D, + 0xEC, 0x18, 0x75, 0xA9, 0xC2, 0x6A, 0xC3, 0xFA, 0x8F, 0x14, + 0xC5, 0x8F, 0xDF, 0xD6, 0xE0, 0xD4, 0x56, 0x16, 0xBC, 0xEF, + 0xA5, 0xDB, 0xC8, 0x3C, 0x25, 0x7F, 0x2F, 0xFC, 0x9C, 0xF3, + 0xFA, 0x11, 0xF9, 0x3B, 0x6B, 0x64, 0x43, 0xCF, 0xF7, 0xD5, + 0x25, 0x13, 0xAC, 0xFE, 0x5B, 0x7F, 0xB4, 0x2C, 0xCF, 0x43, + 0xBF, 0x06, 0x11, 0x26, 0xA6, 0x11, 0xB2, 0x70, 0x1F, 0xD2, + 0x63, 0x09, 0x98, 0xDF, 0xEF, 0xBA, 0x71, 0x2B, 0xFE, 0xB2, + 0x67, 0xDF, 0xF3, 0xC0, 0xA2, 0x35, 0xCE, 0x6C, 0x78, 0x6E, + 0x26, 0x5E, 0x7F, 0xC1, 0x0E, 0x78, 0xEA, 0x5D, 0x86, 0x1F, + 0x1F, 0x5C, 0xE6, 0x71, 0xC5, 0x5A, 0x54, 0xFC, 0xC7, 0xCC, + 0xC2, 0xAA, 0x81, 0x62, 0xD9, 0x37, 0x5A, 0x49, 0x95, 0x44, + 0xF9, 0x1B, 0x74, 0x0F, 0x7F, 0x2A, 0x92, 0x13, 0xEE, 0xBE, + 0xEF, 0x96, 0x07, 0x9A, 0x1D, 0xFE, 0x32, 0xA8, 0xC2, 0xB0, + 0xA0, 0xAC, 0x2E, 0x0C, 0x65, 0x80, 0xF9, 0x50, 0x51, 0xFE, + 0xA8, 0x7B, 0x25, 0xB0, 0xA5, 0x05, 0x2E, 0x5A, 0x57, 0xA1, + 0xFE, 0xB5, 0x17, 0x87, 0x14, 0x5A, 0xE8, 0x50, 0x5A, 0x30, + 0xBA, 0x11, 0x11, 0x58, 0x8E, 0x29, 0xDA, 0x77, 0x58, 0x52, + 0x5A, 0x3A, 0x14, 0xE0, 0xCF, 0x6C, 0x9A, 0xE5, 0x78, 0xE3, + 0x5E, 0xC9, 0xEA, 0xC4, 0x30, 0xB4, 0xD2, 0xAE, 0xA5, 0x2E, + 0x65, 0x7F, 0xD3, 0x56, 0x5A, 0xF7, 0x1F, 0x92, 0xEC, 0x28, + 0x4C, 0xEC, 0xB2, 0x15, 0x2F, 0x5F, 0x54, 0xBC, 0xA2, 0x3D, + 0x96, 0x38, 0xC4, 0x75, 0x4E, 0x96, 0x9F, 0xDA, 0x76, 0x20, + 0x22, 0xB6, 0xA0, 0x4D, 0x40, 0xE8, 0xE3, 0x48, 0xC5, 0x07, + 0xE4, 0xD0, 0x16, 0x6A, 0x31, 0xB9, 0x5E, 0xBB, 0x54, 0x51, + 0x65, 0x6E, 0x21, 0x05, 0xFA, 0xA1, 0x8C, 0xF3, 0xDC, 0x4A, + 0x3C, 0x1E, 0xE9, 0xE7, 0x80, 0x3E, 0xBE, 0xF0, 0x19, 0x8F, + 0x33, 0x7E, 0xAA, 0x03, 0x2A, 0x26, 0x1B, 0x59, 0xC3, 0x24, + 0x83, 0xA2, 0x06, 0xF4, 0x79, 0x00, 0x9C, 0x01, 0x87, 0x4B, + 0x22, 0xEE, 0x4B, 0xDE, 0x3A, 0x6D, 0x0D, 0x53, 0x35, 0x30, + 0xBF, 0x8A, 0xAA, 0xA2, 0xAF, 0x2D, 0x08, 0x8B, 0x18, 0xDA, + 0x78, 0x27, 0x38, 0x62, 0xAE, 0x6A, 0x53, 0x7C, 0x3E, 0xED, + 0x2B, 0x3B, 0xF8, 0xF7, 0xD2, 0x09, 0xF8, 0x8F, 0x23, 0x4C, + 0xEE, 0x16, 0x19, 0x9A, 0x39, 0x7C, 0xAE, 0x53, 0x7B, 0x65, + 0xF2, 0xD5, 0xB8, 0x48, 0x34, 0x0B, 0x9C, 0x6C, 0xEF, 0x92, + 0x58, 0xF2, 0x5E, 0xCA, 0x18, 0x49, 0x1D, 0x19, 0x8E, 0xCE, + 0xB0, 0xE5, 0x4B, 0x87, 0xAF, 0x82, 0x76, 0xE6, 0x50, 0xAF, + 0xBE, 0x37, 0x2E, 0x4B, 0x11, 0xF7, 0xFD, 0x6E, 0xFF, 0xFB, + 0x26, 0x1F, 0xDF, 0x32, 0x0E, 0x63, 0x68, 0x60, 0x8F, 0xA1, + 0x3C, 0x38, 0xF2, 0xA9, 0x4A, 0xD7, 0xAE, 0x0B, 0xC2, 0xAB, + 0x1D, 0x73, 0x4D, 0xD6, 0xD5, 0x98, 0x2B, 0x34, 0x6D, 0xFC, + 0x38, 0xE8, 0xFF, 0x98, 0xE9, 0x69, 0x5C, 0x5B, 0xB7, 0x45, + 0xAD, 0xEF, 0x74, 0x0A, 0xC9, 0xAC, 0xC1, 0x46, 0xCE, 0x11, + 0x17, 0xD4, 0x0B, 0xE0, 0x4F, 0x3B, 0x84, 0xBE, 0x98, 0xD4, + 0xBE, 0x65, 0x37, 0x4A, 0x07, 0x70, 0x0B, 0x57, 0xAE, 0x84, + 0x0E, 0xFA, 0x81, 0xFA, 0x13, 0xB3, 0xB2, 0x6A, 0x1F, 0xB5, + 0xF0, 0x00, 0xDD, 0x55, 0xD2, 0x91, 0xF3, 0xFD, 0x15, 0x1D, + 0x01, 0xF6, 0xC3, 0x7B, 0xCB, 0x4A, 0x13, 0x10, 0x07, 0x52, + 0x13, 0x48, 0x2F, 0x09, 0x2B, 0x37, 0xBC, 0x38, 0x1E, 0x4B, + 0x38, 0xEE, 0x15, 0xDC, 0x81, 0x57, 0xD5, 0x57, 0xD5, 0x2F, + 0x68, 0xF6, 0xA1, 0xB5, 0x3A, 0x92, 0xC2, 0x73, 0x61, 0xF5, + 0xA5, 0xAC, 0x53, 0x96, 0x7A, 0xEA, 0x4C, 0xE5, 0x76, 0x3D, + 0x82, 0x2D, 0x5E, 0xDA, 0xB0, 0x08, 0x97, 0x91, 0xE5, 0x86, + 0xE8, 0x07, 0x72, 0xF0, 0x1C, 0x00, 0x1B, 0x05, 0x8C, 0x29, + 0x8C, 0x67, 0x52, 0x3C, 0x30, 0x0E, 0x73, 0x61, 0xDC, 0x8C, + 0x86, 0x74, 0x4F, 0x24, 0xEF, 0x50, 0x01, 0x3B, 0x75, 0x92, + 0x3B, 0xBC, 0x11, 0xB0, 0x77, 0xE9, 0x04, 0x0D, 0x92, 0x2A, + 0xCA, 0x31, 0x7A, 0x80, 0x0B, 0xE2, 0x3B, 0x41, 0x03, 0x6F, + 0x0E, 0x12, 0x8E, 0x51, 0x65, 0xB7, 0xD3, 0xF1, 0x97, 0x7A, + 0x71, 0x84, 0x7F, 0xEB, 0x29, 0xA7, 0x81, 0x54, 0x60, 0x17, + 0x17, 0xAC, 0xB9, 0xFC, 0x6B, 0x15, 0x77, 0x9B, 0x3D, 0x6C, + 0x83, 0x91, 0xC0, 0x8B, 0x31, 0xDA, 0x1A, 0xDA, 0x2F, 0x5B, + 0x96, 0x19, 0xC9, 0x30, 0x18, 0xC8, 0x13, 0x9E, 0x4C, 0x8E, + 0xF8, 0x2C, 0x78, 0x39, 0xAD, 0xD2, 0x08, 0x97, 0xE1, 0xF3, + 0xBD, 0x91, 0x69, 0x3D, 0x90, 0xC1, 0x01, 0x20, 0xC0, 0xBE, + 0x2A, 0xB0, 0x30, 0xB5, 0x85, 0xB8, 0xA9, 0x2C, 0x25, 0x65, + 0x94, 0x5F, 0x01, 0x4C, 0x7A, 0x37, 0xCD, 0x2D, 0x29, 0x85, + 0x1C, 0x97, 0x4D, 0x42, 0xD7, 0x90, 0xBE, 0x1D, 0xA7, 0x17, + 0x70, 0x6A, 0x07, 0xA5, 0x8C, 0xA1, 0xE7, 0x1D, 0x8D, 0xBF, + 0xDF, 0x82, 0x94, 0xC0, 0x50, 0x9B, 0x8B, 0xED, 0x5B, 0x55, + 0x48, 0xDD, 0x4F, 0x0C, 0x48, 0x91, 0xC8, 0x6E, 0xFB, 0xC4, + 0x4B, 0xE8, 0x8F, 0x4A, 0x8F, 0xD4, 0x95, 0xBE, 0x30, 0x15, + 0x67, 0xB6, 0xC2, 0x03, 0xF0, 0xA0, 0x8F, 0x9B, 0x45, 0xB8, + 0x2C, 0x77, 0xD8, 0x84, 0x1D, 0xDD, 0x2B, 0x2E, 0x9B, 0x46, + 0x35, 0xEF, 0x91, 0x2C, 0x05, 0x25, 0xF0, 0xE8, 0xE9, 0xBB, + 0x2E, 0x2B, 0x33, 0xE3, 0x0B, 0x46, 0x89, 0xD6, 0x99, 0x38, + 0x3A, 0xD9, 0x73, 0x7C, 0xD7, 0x1A, 0x0B, 0x24, 0xD6, 0x7A, + 0xA5, 0x8B, 0xE9, 0x01, 0xD7, 0x4C, 0xD6, 0x29, 0xAF, 0x98, + 0x78, 0xBC, 0xD2, 0xB5, 0x84, 0x8E, 0x51, 0x4C, 0x12, 0xEB, + 0x3A, 0x28, 0xF9, 0x38, 0xA0, 0x0E, 0x3B, 0x23, 0x1B, 0x04, + 0x97, 0xE7, 0x46, 0x3E, 0x4D, 0xA8, 0xF7, 0x81, 0x4A, 0x8D, + 0x57, 0x50, 0xBA, 0x8C, 0xD8, 0x49, 0xC1, 0x34, 0x31, 0xFE, + 0xEF, 0x09, 0xF4, 0xC2, 0xBA, 0xE6, 0x88, 0xD5, 0xED, 0x14, + 0x80, 0x20, 0x0F, 0x47, 0x39, 0x4E, 0xED, 0x77, 0x89, 0x12, + 0x59, 0x06, 0xC6, 0xF2, 0x55, 0x69, 0x0F, 0x70, 0x19, 0x91, + 0xA9, 0x9E, 0x3B, 0xDB, 0xBD, 0x07, 0x61, 0x48, 0x85, 0x75, + 0x4D, 0x4F, 0xFA, 0xA8, 0x8B, 0xD0, 0xA4, 0x18, 0x31, 0x01, + 0x65, 0xA5, 0x9D, 0x6C, 0xBC, 0x0A, 0xC6, 0x30, 0xEC, 0xEA, + 0x22, 0xDA, 0x65, 0xBE, 0xE3, 0xBA, 0xA6, 0x5C, 0xDF, 0x25, + 0x1E, 0xE1, 0xF0, 0x2E, 0x2F, 0x9C, 0xF5, 0x0A, 0xBD, 0xC9, + 0x59, 0xF2, 0x2E, 0x5E, 0xA0, 0xD9, 0x63, 0x6B, 0x6E, 0x61, + 0xF9, 0x8F, 0x79, 0x89, 0xAB, 0xFA, 0xB6, 0xFB, 0xDB, 0x24, + 0x78, 0x10, 0x87, 0xFC, 0xFF, 0x74, 0x1D, 0xDA, 0x2A, 0x6D, + 0x9E, 0xBD, 0x7A, 0x12, 0x95, 0x00, 0x91, 0x06, 0x8D, 0x41, + 0x63, 0xF2, 0xF0, 0xA9, 0x60, 0x0D, 0x3B, 0xE0, 0x4E, 0xC0, + 0x30, 0xE3, 0x57, 0xAB, 0xD0, 0xBD, 0xE2, 0x03, 0xDF, 0xDF, + 0x7D, 0xE2, 0x9B, 0xBB, 0xCC, 0x82, 0x1E, 0x59, 0x40, 0xF2, + 0x06, 0xFE, 0x2B, 0x06, 0x59, 0xD4, 0x6F, 0x62, 0x06, 0x49, + 0x77, 0xDE, 0x86, 0x79, 0x61, 0x92, 0x20, 0x00, 0xCA, 0x89, + 0x9A, 0x9A, 0x29, 0x02, 0x2C, 0x63, 0x03, 0x94, 0x34, 0xD3, + 0xBB, 0x8B, 0xE9, 0x5F, 0x50, 0x56, 0x22, 0xE7, 0x64, 0xE5, + 0x05, 0x05, 0x40, 0x4D, 0xBA, 0x6D, 0x12, 0x94, 0x0E, 0xF8, + 0x38, 0xD0, 0x3C, 0xAE, 0x8C, 0xF3, 0xC6, 0x41, 0x44, 0x37, + 0x6D, 0x5D, 0x9C, 0x73, 0xF5, 0xD9, 0x99, 0xB3, 0x20, 0x60, + 0xE4, 0x0B, 0xA3, 0x36, 0x27, 0x23, 0x2D, 0xFB, 0x66, 0x6E, + 0x31, 0xBD, 0xC2, 0x88, 0x2D, 0xEA, 0x4C, 0xB1, 0xC0, 0x86, + 0x5D, 0x6A, 0x01, 0x55, 0x47, 0x37, 0x1A, 0x62, 0xF1, 0x44, + 0x98, 0x71, 0x64, 0x5F, 0x23, 0x02, 0x68, 0x75, 0x1A, 0x18, + 0x0C, 0xC2, 0x26, 0xF2, 0xE5, 0x9B, 0x3E, 0x3F, 0x13, 0x37, + 0x16, 0xD8, 0x2B, 0x15, 0xE8, 0xFF, 0xE0, 0x8B, 0xEE, 0x07, + 0xB5, 0x6B, 0xB9, 0xE7, 0x15, 0xDF, 0x59, 0xFC, 0x7F, 0x71, + 0x9E, 0x07, 0x9A, 0xE5, 0x97, 0xD0, 0xD8, 0x65, 0x44, 0x74, + 0x75, 0x0F, 0x99, 0x8C, 0x5C, 0xA7, 0xEB, 0x24, 0x16, 0x5F, + 0x08, 0xF1, 0xAC, 0x9C, 0xAC, 0xC7, 0x92, 0x44, 0x21, 0xA8, + 0x5F, 0x69, 0xB3, 0x07, 0x8E, 0xE2, 0x35, 0x7C, 0x4C, 0xF1, + 0xF4, 0x5A, 0x8C, 0xB4, 0x63, 0xDA, 0x93, 0xC5, 0x64, 0x89, + 0x11, 0x53, 0xAA, 0x67, 0xED, 0xCC, 0x4F, 0x2B, 0xCC, 0x9E, + 0xC9, 0x0A, 0x4F, 0xB4, 0x98, 0x11, 0xFE, 0x9E, 0x99, 0x19, + 0x48, 0xDE, 0x46, 0x4F, 0x2A, 0x76, 0x36, 0xA0, 0x5D, 0x6F, + 0xAC, 0xC7, 0x47, 0x24, 0xCB, 0x7A, 0xEC, 0x5B, 0x5C, 0x09, + 0xA0, 0xD1, 0x02, 0x92, 0x85, 0xB4, 0xAA, 0xEE, 0x83, 0xC5, + 0x5D, 0xC6, 0x7C, 0x61, 0xBD, 0x4E, 0x26, 0xDD, 0x64, 0xC4, + 0x0F, 0x6E, 0x6B, 0xA5, 0x52, 0x08, 0xC0, 0x6B, 0xE0, 0x43, + 0x51, 0x51, 0x6B, 0x9C, 0xD6, 0xD3, 0xD9, 0x07, 0xC0, 0x84, + 0xEC, 0x31, 0x7B, 0x5F, 0x32, 0xD1, 0x46, 0x79, 0x93, 0x99, + 0x50, 0x6B, 0x1E, 0x03, 0x4B, 0xF8, 0x21, 0x28, 0x70, 0x30, + 0xA1, 0xFF, 0x46, 0x7F, 0x36, 0x36, 0x39, 0xFA, 0x64, 0xC8, + 0x5A, 0xC8, 0x39, 0x4B, 0x0E, 0xEE, 0x93, 0x45, 0x3F, 0x00, + 0x6C, 0xE7, 0x9A, 0xC4, 0x1B, 0x8F, 0x5C, 0xCC, 0xAF, 0xB8, + 0x42, 0x05, 0x8E, 0x66, 0x67, 0x66, 0xCD, 0x7F, 0xA6, 0x19, + 0xCE, 0x8E, 0xB8, 0xA4, 0xFE, 0x3D, 0xF5, 0xD3, 0xBC, 0xDF, + 0x9A, 0xFE, 0x4A, 0x3E, 0x09, 0xC4, 0xEC, 0x2F, 0xD4, 0x24, + 0x71, 0xD1, 0xA0, 0xAD, 0x8A, 0x0E, 0xEB, 0x8B, 0x0D, 0xE8, + 0x88, 0x46, 0x5C, 0x3B, 0x72, 0x4B, 0x15, 0xCA, 0x49, 0x12, + 0xB7, 0x54, 0x4B, 0xC6, 0x6D, 0x5E, 0x08, 0x54, 0x34, 0x75, + 0xE3, 0xA6, 0x4A, 0x00, 0xF3, 0x75, 0x55, 0xF7, 0x5A, 0x6B, + 0x57, 0x80, 0x11, 0xF5, 0x2D, 0x7E, 0x9D, 0xB1, 0x67, 0xED, + 0xAA, 0xF7, 0x16, 0x24, 0xEB, 0x9F, 0x9F, 0xAE, 0x6F, 0xEE, + 0xBA, 0x1A, 0x24, 0xD7, 0x01, 0x1D, 0xC5, 0xAE, 0xB9, 0xE8, + 0x41, 0xE7, 0x91, 0xA5, 0x8F, 0xB7, 0xD0, 0xB4, 0x43, 0x5E, + 0x8F, 0x12, 0x9F, 0x03, 0x9D, 0xA7, 0xC4, 0x05, 0xE3, 0x47, + 0xED, 0x20, 0x85, 0xC8, 0x79, 0x55, 0x51, 0xE4, 0xF9, 0x88, + 0xC2, 0xE0, 0x1E, 0x07, 0x1F, 0x76, 0x46, 0xB9, 0xB3, 0x9B, + 0xCD, 0xEF, 0x5E, 0x7B, 0x37, 0xD1, 0xEB, 0x97, 0xF4, 0x28, + 0xFE, 0x22, 0x07, 0xCD, 0x9B, 0x65, 0xE4, 0x3D, 0x3F, 0xF5, + 0xF7, 0x19, 0x85, 0x2F, 0xD8, 0x0C, 0xC4, 0x6D, 0xED, 0x34, + 0xDF, 0x7B, 0xA7, 0x19, 0x62, 0xA3, 0xCC, 0x60, 0xFA, 0x01, + 0xF2, 0x91, 0x7B, 0xD0, 0x1D, 0xF1, 0x30, 0x01, 0x9D, 0xC3, + 0x3B, 0x41, 0xFF, 0x33, 0x2E, 0x80, 0x55, 0xB0, 0x77, 0x37, + 0xBA, 0x18, 0x4C, 0x89, 0x06, 0x81, 0x67, 0xEB, 0x33, 0xF7, + 0xEB, 0x33, 0xD4, 0x74, 0xF4, 0xAE, 0x00, 0xD9, 0xCB, 0xA2, + 0xCD, 0xC3, 0x1B, 0xCA, 0x61, 0x07, 0x04, 0x69, 0x45, 0x45, + 0x8B, 0xCA, 0x23, 0xD8, 0x3F, 0x4F, 0x18, 0xD1, 0x76, 0xFB, + 0xB1, 0xA4, 0x64, 0x5B, 0x54, 0x37, 0xEE, 0x15, 0x98, 0xD0, + 0x10, 0x2E, 0xA9, 0x69, 0x5D, 0x0C, 0xB5, 0x6B, 0x07, 0x38, + 0x3F, 0x62, 0x36, 0x1A, 0xE7, 0xE0, 0x91, 0x99, 0x83, 0xC5, + 0x80, 0x3A, 0xF5, 0xBD, 0x7F, 0x28, 0xE9, 0x76, 0xAF, 0x1C, + 0x78, 0xE2, 0xB8, 0x17, 0x5D, 0x4B, 0x55, 0xBF, 0xF8, 0x7B, + 0xF1, 0x81, 0x4C, 0x9C, 0xF7, 0x5E, 0x85, 0x51, 0xD6, 0x97, + 0x70, 0x71, 0x99, 0x4F, 0x85, 0x65, 0xEB, 0x0E, 0x91, 0x7E, + 0x7A, 0xD0, 0x77, 0x8C, 0xF5, 0x9F, 0xA2, 0x2D, 0xB7, 0xBF, + 0xEE, 0xC8, 0x4C, 0x8E, 0x75, 0xFB, 0x0A, 0xD7, 0x90, 0x91, + 0x6F, 0xFF, 0xF0, 0x5D, 0x9C, 0x45, 0x2A, 0xEA, 0x5E, 0x98, + 0x7C, 0xFB, 0x36, 0x80, 0x93, 0xF7, 0xF5, 0xBF, 0x1A, 0xA8, + 0x97, 0xF2, 0x53, 0xCE, 0xC5, 0xCC, 0xE2, 0xAD, 0xD0, 0x9B, + 0xE4, 0x48, 0x87, 0x68, 0xDE, 0x56, 0xB7, 0xAC, 0xB3, 0xA6, + 0x4D, 0xBE, 0x18, 0x92, 0x53, 0x0B, 0xB9, 0x54, 0x85, 0xDC, + 0x5D, 0x50, 0x90, 0x74, 0xB8, 0x5B, 0x5C, 0x0A, 0x18, 0x9C, + 0x95, 0x1A, 0x57, 0xD2, 0x89, 0x13, 0xA5, 0x24, 0x64, 0x38, + 0x3F, 0x85, 0x71, 0xB0, 0x28, 0x99, 0x68, 0xF6, 0x27, 0xE2, + 0x45, 0x9C, 0x60, 0xD8, 0x21, 0x5B, 0xC7, 0x13, 0x7F, 0xA0, + 0xA4, 0xCD, 0x71, 0x05, 0x38, 0x01, 0x90, 0xCA, 0x34, 0xC6, + 0x34, 0x32, 0xF3, 0x33, 0xB5, 0x74, 0x1D, 0xD0, 0xC6, 0x43, + 0x38, 0x76, 0x0E, 0x16, 0xDA, 0xCF, 0xB8, 0x05, 0xC4, 0xF1, + 0x41, 0x68, 0x00, 0x93, 0xF5, 0x2A, 0x2A, 0xEE, 0xBD, 0x5F, + 0x70, 0x49, 0xE9, 0x3E, 0xEB, 0xE9, 0x30, 0x0D, 0x48, 0xD2, + 0x7C, 0xF7, 0xDE, 0xD0, 0x21, 0x78, 0x7E, 0x1C, 0xE3, 0xA0, + 0xAC, 0xEB, 0xEF, 0x34, 0x41, 0xEB, 0xDC, 0x7F, 0xF6, 0xC6, + 0xA6, 0x4A, 0xC2, 0x32, 0xDA, 0x71, 0x73, 0x09, 0x31, 0xF6, + 0xE3, 0x15, 0xC6, 0x5E, 0x64, 0x15, 0x43, 0xEE, 0x93, 0x98, + 0xA8, 0xC9, 0x27, 0xF2, 0xB3, 0x7A, 0xC0, 0xC6, 0x46, 0xAE, + 0xFF, 0xB2, 0xBF, 0xAF, 0x77, 0x89, 0x7F, 0x40, 0x35, 0xD1, + 0x5B, 0xF3, 0x9D, 0x72, 0xA8, 0x17, 0xB6, 0xC0, 0x52, 0xF0, + 0x24, 0x24, 0x66, 0x77, 0xC3, 0xD5, 0x30, 0x04, 0x4C, 0xBE, + 0x3F, 0x47, 0x06, 0xE1, 0x56, 0xA5, 0x35, 0xFE, 0x04, 0x5C, + 0x04, 0x6E, 0x41, 0x24, 0x66, 0x34, 0x12, 0x6F, 0xCF, 0x08, + 0xEC, 0xE8, 0x48, 0xC1, 0x1B, 0x1F, 0x86, 0xAA, 0x21, 0x32, + 0x78, 0x9D, 0x93, 0xB1, 0x1D, 0xF0, 0xD6, 0x65, 0xC4, 0x27, + 0x75, 0xE6, 0x01, 0xB0, 0xF8, 0x56, 0x1F, 0x13, 0xDD, 0x51, + 0x83, 0x45, 0xBF, 0xDD, 0xB7, 0x06, 0xF0, 0x1F, 0x84, 0xDD, + 0x91, 0xEC, 0x47, 0xDB, 0x6C, 0x2A, 0xD9, 0x3C, 0xFD, 0xDF, + 0x25, 0x8B, 0x95, 0x39, 0xC5, 0x70, 0x78, 0xFF, 0xC0, 0xAD, + 0x80, 0xEC, 0x7C, 0xEF, 0x1C, 0xF0, 0x14, 0x1E, 0x64, 0x6A, + 0xF6, 0x26, 0x7B, 0x65, 0xE5, 0x53, 0xD5, 0xA2, 0x3B, 0xDD, + 0xC4, 0xF5, 0xCD, 0x53, 0x93, 0x1F, 0x68, 0x84, 0x61, 0x75, + 0xEE, 0xD9, 0x85, 0x84, 0xBE, 0x2E, 0x8B, 0x95, 0x91, 0xD1, + 0xD7, 0x54, 0xCB, 0x41, 0x08, 0x0E, 0x8A, 0x31, 0x83, 0x17, + 0xF3, 0x6C, 0x5C, 0xFC, 0x05, 0xD8, 0x2E, 0xE7, 0xCE, 0xAE, + 0x2D, 0xF4, 0xD8, 0x15, 0x57, 0x19, 0x7B, 0xE3, 0x89, 0x24, + 0xF6, 0x6F, 0x01, 0x0B, 0x6B, 0x1C, 0x57, 0x6B, 0x3F, 0x24, + 0x2B, 0x3E, 0x79, 0x45, 0x13, 0xAE, 0xE6, 0xF0, 0x68, 0xFC, + 0xB7, 0x1D, 0x6B, 0xD7, 0xFD, 0x8B, 0xAE, 0x91, 0x21, 0x75, + 0x04, 0x35, 0x10, 0x86, 0xF9, 0x4D, 0x48, 0xE1, 0xA0, 0x28, + 0x45, 0x80, 0x6E, 0x6D, 0x1D, 0x40, 0xB3, 0x87, 0x74, 0x23, + 0x8C, 0x27, 0xFE, 0xCD, 0xB3, 0x02, 0xEC, 0x15, 0x91, 0x88, + 0xB2, 0x35, 0x81, 0xA8, 0xDB, 0xD7, 0xDC, 0xB2, 0x52, 0x7F, + 0x53, 0x42, 0x64, 0xF4, 0x66, 0x62, 0x2E, 0xC0, 0x73, 0x77, + 0x79, 0xDF, 0x6E, 0x94, 0x21, 0xC7, 0x3D, 0xDF, 0x26, 0x61, + 0xD2, 0xC8, 0xDD, 0xD2, 0x7D, 0xAB, 0xE4, 0x6E, 0x6B, 0x7D, + 0x71, 0xF2, 0xD9, 0x0A, 0x4E, 0x18, 0x5B, 0x12, 0x1C, 0xBE, + 0x7B, 0x08, 0x29, 0x95, 0x82, 0x90, 0x7D, 0xFE, 0x60, 0xC5, + 0x18, 0x9E, 0x75, 0x10, 0xC5, 0xAB, 0xB0, 0xEB, 0x65, 0xA3, + 0x28, 0x07, 0x02, 0x9F, 0x05, 0xC2, 0x03, 0x8C, 0x98, 0x27, + 0x6A, 0x36, 0xFC, 0x55, 0x4D, 0xAA, 0xE6, 0x98, 0x03, 0x40, + 0x01, 0x45, 0xB5, 0x59, 0xC4, 0x99, 0xE3, 0x44, 0x0A, 0x85, + 0x4C, 0x5D, 0x16, 0x95, 0xF1, 0x5F, 0x81, 0x90, 0x1A, 0xA9, + 0x50, 0x67, 0xB4, 0x94, 0xA3, 0x76, 0x08, 0x76, 0x72, 0xFD, + 0x3C, 0xA4, 0xC6, 0x1C, 0xD8, 0x3B, 0x3D, 0x03, 0x92, 0x6B, + 0x94, 0xB9, 0xD5, 0xCD, 0x3D, 0x7A, 0x33, 0x01, 0x7F, 0x7C, + 0x4A, 0x20, 0xA0, 0x48, 0xFD, 0x4F, 0xF4, 0xA4, 0xF0, 0x3D, + 0xE9, 0xAF, 0xAA, 0x32, 0x3E, 0xE9, 0x63, 0x7A, 0x33, 0x95, + 0x25, 0x18, 0xE4, 0x57, 0x10, 0x6C, 0x9C, 0x16, 0xED, 0x21, + 0x56, 0xD5, 0xC8, 0xFC, 0x86, 0xAE, 0xAB, 0x20, 0xD7, 0x96, + 0x2B, 0x5E, 0x48, 0x53, 0x26, 0x56, 0x0E, 0xBD, 0x23, 0x79, + 0x0D, 0x8F, 0xE5, 0x74, 0x2F, 0x2E, 0xE9, 0x6B, 0xEE, 0x89, + 0x51, 0xDD, 0x3C, 0x1A, 0x72, 0x3B, 0x5C, 0xE5, 0xA4, 0x69, + 0xDA, 0x91, 0x1F, 0xE5, 0xB4, 0xCC, 0x6D, 0x36, 0x1B, 0x94, + 0x5D, 0xC4, 0x62, 0x11, 0x4B, 0xF1, 0x32, 0x40, 0x7D, 0x82, + 0x11, 0x65, 0xFB, 0x19, 0x46, 0x0A, 0x6A, 0xD6, 0x8D, 0xA0, + 0x43, 0xE1, 0xFD, 0x3A, 0x3E, 0x4F, 0xB3, 0xDA, 0xFE, 0x54, + 0xCC, 0xC9, 0x1C, 0xE4, 0x64, 0x8F, 0xED, 0x18, 0xB3, 0xA5, + 0x41, 0xB7, 0x6A, 0xE1, 0x30, 0xA5, 0x84, 0x04, 0x3D, 0xF8, + 0x01, 0x0C, 0x5C, 0xAD, 0xAD, 0xB3, 0xFC, 0x86, 0xCA, 0x0A, + 0x72, 0x91, 0x00, 0xBC, 0x3D, 0xEE, 0x90, 0x46, 0xCC, 0x71, + 0x69, 0x6A, 0x3F, 0xAD, 0xA8, 0xD3, 0x04, 0x7E, 0xE3, 0x9E, + 0x08, 0x5F, 0x6E, 0xA0, 0x03, 0x18, 0x7E, 0x8D, 0xA2, 0x87, + 0xA7, 0x74, 0x5F, 0x2F, 0x4C, 0x66, 0xC9, 0x0D, 0x91, 0xA2, + 0x30, 0xFF, 0x2D, 0xAC, 0xF8, 0x49, 0x2D, 0x63, 0x4A, 0x4D, + 0x10, 0xFF, 0x84, 0x36, 0x45, 0x1C, 0xF3, 0xC7, 0x18, 0xF6, + 0x2A, 0x8F, 0x1F, 0x55, 0x95, 0xE4, 0xC9, 0x6B, 0x38, 0xE4, + 0x1D, 0x31, 0x50, 0x24, 0xF9, 0xA0, 0x9B, 0xF3, 0xBF, 0x3A, + 0xAB, 0x4D, 0xC0, 0x20, 0x34, 0x6C, 0x20, 0x59, 0xF7, 0xD9, + 0x45, 0x93, 0xF4, 0x1E, 0x99, 0xBF, 0xE4, 0xE5, 0x09, 0x5D, + 0x1E, 0xF9, 0x5F, 0x35, 0x75, 0xEA, 0xFB, 0x8E, 0xF6, 0x45, + 0x7E, 0xA5, 0xD2, 0xF4, 0xA4, 0xC7, 0x34, 0xCB, 0xD3, 0x12, + 0xFA, 0x37, 0xFE, 0x2F, 0x3A, 0x66, 0x7F, 0x27, 0x46, 0x19, + 0xDB, 0x5A, 0xDD, 0xCD, 0xA2, 0xA2, 0x49, 0x25, 0x4F, 0x3F, + 0x25, 0xB6, 0xD2, 0xE4, 0x1A, 0x1D, 0x75, 0x53, 0x76, 0x1E, + 0xA1, 0x86, 0xB0, 0xC7, 0xE3, 0xCE, 0xA0, 0x53, 0xDB, 0x67, + 0xC4, 0x5D, 0x8B, 0x1C, 0xF5, 0xAB, 0xE8, 0x32, 0xB4, 0x84, + 0xC4, 0x30, 0x1D, 0xD8, 0x0D, 0x01, 0xB1, 0x88, 0x4A, 0xEA, + 0xF4, 0xA3, 0x9A, 0xD9, 0xED, 0x34, 0x43, 0x01, 0x13, 0x38, + 0xD1, 0x2C, 0xB5, 0x69, 0xDD, 0x9B, 0x0B, 0xA2, 0xA5, 0xB8, + 0x96, 0x05, 0x0E, 0x88, 0x01, 0x30, 0xB9, 0xCC, 0x2E, 0x26, + 0xE5, 0xBB, 0xE2, 0xEA, 0xFE, 0x2A, 0xB1, 0x51, 0x6A, 0xE3, + 0x1E, 0xD6, 0x98, 0x7A, 0xDF, 0x73, 0xD3, 0x56, 0x01, 0xDB, + 0x35, 0xF0, 0xE2, 0xF8, 0xB7, 0x9B, 0x96, 0xDD, 0x81, 0xC2, + 0xAF, 0xA0, 0xD6, 0xAB, 0x27, 0xB5, 0x0E, 0x65, 0x68, 0x20, + 0x1F, 0xFD, 0x6A, 0x3E, 0x42, 0xC1, 0x46, 0xF2, 0xA9, 0xDC, + 0xC9, 0x85, 0x1E, 0xC1, 0x29, 0x8D, 0x19, 0xF9, 0xDA, 0xFC, + 0xCE, 0x9D, 0x2C, 0x3A, 0xFC, 0xA5, 0xFC, 0x13, 0x10, 0xAA, + 0x06, 0x07, 0xD6, 0xE8, 0x8E, 0x9B, 0xDB, 0x1C, 0x58, 0x5B, + 0xD5, 0xE7, 0x81, 0x99, 0xFD, 0x51, 0xD1, 0xD4, 0xDC, 0x46, + 0x6D, 0xBC, 0x9A, 0x1F, 0x00, 0x47, 0xEE, 0xDD, 0xA4, 0x54, + 0x60, 0x8A, 0x6E, 0xB2, 0x5C, 0xC3, 0x4B, 0xE9, 0xEC, 0xD8, + 0xCF, 0xCC, 0x3F, 0x34, 0xE4, 0x91, 0x16, 0x1F, 0xFA, 0xAE, + 0x03, 0x72, 0x70, 0xD3, 0x6F, 0x6A, 0x84, 0x51, 0x75, 0x8C, + 0x22, 0x21, 0x9A, 0x15, 0xCE, 0x41, 0xD9, 0x63, 0x88, 0x9D, + 0xDC, 0x5F, 0xBF, 0xA1, 0x8E, 0xE5, 0x7B, 0xC7, 0xB8, 0x89, + 0x62, 0xBA, 0x1A, 0x87, 0x94, 0x53, 0x13, 0xC9, 0xFB, 0x6B, + 0x64, 0x3D, 0xE0, 0x5F, 0xC4, 0x7D, 0xD4, 0xD4, 0x17, 0x95, + 0x11, 0xFC, 0x5C, 0x65, 0x81, 0x9A, 0xC0, 0x2E, 0xE8, 0xD2, + 0x31, 0xE9, 0xC9, 0x7E, 0x3C, 0x8E, 0xD8, 0xCD, 0x87, 0xE5, + 0xAA, 0xC5, 0x84, 0xA5, 0x4B, 0x37, 0x67, 0x49, 0xD8, 0x99, + 0xBB, 0xAF, 0xCD, 0x6F, 0xAE, 0xDE, 0x81, 0x0D, 0xD0, 0x33, + 0x1D, 0xF9, 0xFC, 0x50, 0x36, 0x6F, 0x8B, 0x42, 0xF0, 0xA8, + 0x85, 0xBF, 0x4A, 0xDD, 0x74, 0x9B, 0x54, 0xBF, 0x1F, 0x23, + 0x31, 0x13, 0xB6, 0xE7, 0xEB, 0x78, 0x5C, 0xD1, 0xA6, 0x55, + 0x2D, 0x19, 0x7B, 0x3C, 0x54, 0x60, 0x06, 0x79, 0x69, 0xB8, + 0xA6, 0x5C, 0x60, 0x22, 0x05, 0xCC, 0xBB, 0x74, 0x94, 0x54, + 0x0F, 0x89, 0xAB, 0xE2, 0x37, 0xF9, 0xBF, 0x5F, 0xB0, 0x32, + 0x69, 0x47, 0x20, 0x2E, 0xBC, 0x85, 0x8A, 0x93, 0x12, 0x16, + 0xAE, 0x00, 0xCC, 0x32, 0x85, 0xAC, 0x21, 0x33, 0xA9, 0x33, + 0x45, 0xB6, 0xE3, 0x75, 0x43, 0x54, 0xC0, 0xC4, 0x19, 0x1A, + 0x29, 0xDB, 0xCB, 0xE9, 0xB8, 0x09, 0x0E, 0x27, 0xF2, 0x2D, + 0xA4, 0x23, 0x40, 0x0C, 0x0C, 0xDD, 0x47, 0x97, 0x3A, 0xBE, + 0x5A, 0x8A, 0x66, 0x1F, 0x14, 0x4B, 0x50, 0x05, 0x5A, 0x1A, + 0x48, 0x70, 0xA9, 0x5F, 0xA2, 0x64, 0x75, 0xDD, 0xEF, 0x5C, + 0x8C, 0x1C, 0xA6, 0x54, 0x0F, 0x73, 0xB3, 0xFE, 0x02, 0xE4, + 0x07, 0x27, 0x9E, 0xD6, 0xD5, 0xD7, 0x2F, 0x42, 0x2E, 0xD8, + 0x6A, 0xCE, 0x6E, 0x2A, 0x9F, 0x79, 0xB5, 0xCF, 0xF9, 0xF7, + 0x9C, 0xD6, 0xC6, 0xF0, 0x58, 0x74, 0x66, 0x09, 0x77, 0x4C, + 0x5B, 0x4C, 0x5B, 0x21, 0xE7, 0x2D, 0x1E, 0xD3, 0x7B, 0x56, + 0xEA, 0xCE, 0x8D, 0x85, 0xB1, 0x44, 0xB8, 0x09, 0x15, 0xAB, + 0xCD, 0x97, 0x28, 0xB6, 0xD7, 0xDC, 0x7C, 0xDE, 0x8B, 0xC9, + 0x6D, 0x3F, 0xE2, 0x02, 0x58, 0x64, 0x85, 0x57, 0x71, 0x99, + 0x16, 0xB9, 0x3D, 0xBF, 0x36, 0x10, 0xA5, 0xD0, 0x4A, 0x8B, + 0x90, 0xF4, 0x40, 0xE1, 0x60, 0x12, 0x1D, 0xB1, 0xBC, 0x72, + 0xDC, 0xF5, 0xEE, 0xE6, 0x5C, 0x84, 0x73, 0x56, 0xF2, 0x9C, + 0x54, 0x78, 0x0D, 0x85, 0xA9, 0x5C, 0xC1, 0x79, 0x57, 0xA1, + 0x3C, 0x15, 0x1B, 0x61, 0x84, 0xA6, 0x59, 0xCA, 0x41, 0x18, + 0x49, 0xB5, 0x6E, 0x26, 0x4B, 0x10, 0x13, 0xA3, 0x61, 0xA3, + 0x4C, 0x97, 0xBE, 0x5A, 0x98, 0x2B, 0x30, 0xE7, 0xE6, 0x92, + 0x92, 0x67, 0x84, 0x63, 0x77, 0xA9, 0x8F, 0x2C, 0x7C, 0xD0, + 0xD4, 0x7E, 0xA6, 0xE3, 0xCA, 0xF6, 0xBF, 0x4A, 0x73, 0x3C, + 0x6B, 0xFB, 0x48, 0x07, 0x22, 0x5E, 0x57, 0x60, 0x75, 0x98, + 0x1A, 0xE7, 0x0B, 0x8F, 0x68, 0x34, 0xF9, 0xBF, 0x98, 0xD8, + 0x66, 0x8B, 0xA5, 0xE4, 0x2E, 0x23, 0x20, 0x28, 0xDD, 0xB6, + 0xB7, 0xE4, 0xA0, 0xAF, 0x06, 0x66, 0x07, 0xC5, 0x8A, 0xE5, + 0xC1, 0x40, 0x8D, 0xF2, 0x66, 0x90, 0xF3, 0xF4, 0x3C, 0x92, + 0xA5, 0x3D, 0x9D, 0x71, 0x17, 0xC9, 0xC5, 0xDD, 0x73, 0x93, + 0xE0, 0x13, 0x1F, 0x9A, 0x84, 0xF6, 0x2B, 0x71, 0xD8, 0x47, + 0x2B, 0xA9, 0xD2, 0xF9, 0xD9, 0x98, 0x82, 0xDD, 0x20, 0x78, + 0x4E, 0x70, 0x79, 0xE6, 0x87, 0x20, 0xAB, 0x0A, 0xFA, 0x15, + 0x69, 0xCF, 0xEC, 0x35, 0x2A, 0x12, 0x13, 0x8F, 0x32, 0x91, + 0xE1, 0x9C, 0x91, 0x2D, 0x98, 0xDC, 0xDF, 0x94, 0x9B, 0x6D, + 0x29, 0x23, 0x4E, 0x5F, 0x8E, 0xCF, 0xC8, 0xAE, 0xE4, 0x7D, + 0xC5, 0x6F, 0x05, 0xE0, 0x78, 0x80, 0x04, 0xCD, 0x68, 0xAE, + 0xD2, 0xDE, 0xFA, 0x7B, 0x6E, 0xC1, 0xD2, 0x8E, 0xDC, 0xFB, + 0xA8, 0x9A, 0x44, 0x8C, 0x06, 0x1B, 0xC8, 0x9B, 0x23, 0xE3, + 0x9B, 0xCF, 0xEA, 0x20, 0xAF, 0x39, 0x96, 0xDB, 0x1C, 0x28, + 0x63, 0x74, 0xAF, 0x3D, 0x16, 0xEC, 0xD1, 0x05, 0x04, 0xD4, + 0xA9, 0x43, 0x41, 0xA0, 0xDB, 0x21, 0xF6, 0xD3, 0xF2, 0xC5, + 0xDB, 0xB8, 0xC6, 0xC0, 0x0C, 0x14, 0xB5, 0x40, 0x44, 0x65, + 0x8F, 0x5B, 0x15, 0xCD, 0x26, 0x45, 0x73, 0x47, 0x41, 0x4B, + 0xC4, 0x70, 0x31, 0xA4, 0xE8, 0x5F, 0x3A, 0x78, 0xE5, 0x36, + 0xCB, 0x79, 0x58, 0x7E, 0x9A, 0x9E, 0x16, 0x46, 0x09, 0xD7, + 0xDA, 0xA6, 0xAF, 0x91, 0xC0, 0x06, 0xC0, 0x4B, 0xC9, 0xF0, + 0x4A, 0xD1, 0x01, 0x1B, 0x89, 0x16, 0xBA, 0xE5, 0x02, 0xDD, + 0x58, 0x2F, 0x19, 0x28, 0xC9, 0xEA, 0xCD, 0x60, 0xA6, 0xC5, + 0x82, 0x12, 0x68, 0x36, 0x37, 0x32, 0xFA, 0xD8, 0x1B, 0xAC, + 0xD2, 0xE9, 0x57, 0xE0, 0x6D, 0x96, 0xCE, 0xF4, 0x5B, 0xD9, + 0xD3, 0xE6, 0x7A, 0x3C, 0x1B, 0x22, 0x11, 0xDA, 0xB4, 0x6E, + 0xD2, 0x1F, 0x1C, 0x62, 0x83, 0x53, 0x22, 0xAF, 0x06, 0xA7, + 0x36, 0xB0, 0x34, 0xD4, 0xDF, 0xFE, 0x8A, 0x20, 0xDF, 0x10, + 0xB9, 0xDF, 0x59, 0x21, 0x25, 0xB1, 0x5D, 0x2C, 0x65, 0x46, + 0x01, 0x89, 0x4D, 0x2A, 0xCD, 0x1A, 0x0B, 0xE3, 0xA3, 0x5E, + 0x24, 0x7C, 0x59, 0x4F, 0xBA, 0xBD, 0x85, 0xFE, 0xBD, 0xCA, + 0x71, 0x9E, 0x87, 0x62, 0xE3, 0x5D, 0xC0, 0x99, 0x65, 0x3F, + 0x8E, 0x64, 0xFC, 0x27, 0xDE, 0x24, 0x23, 0x0D, 0x35, 0xA2, + 0xB9, 0xBF, 0x8F, 0x7E, 0x30, 0xD8, 0x90, 0x34, 0x7B, 0xA3, + 0x11, 0x82, 0x97, 0xA1, 0x0F, 0x1B, 0x86, 0xF9, 0xF3, 0x43, + 0xA9, 0x6D, 0x27, 0x71, 0x79, 0xCD, 0x2C, 0xF1, 0x33, 0xF1, + 0x9F, 0x33, 0x4B, 0x12, 0x1C, 0x2C, 0xA8, 0x4F, 0x00, 0x66, + 0x46, 0xC3, 0x8C, 0x94, 0x39, 0xAD, 0x08, 0xBC, 0x78, 0xF5, + 0x0A, 0x67, 0xA1, 0x9A, 0xB8, 0xC1, 0xFB, 0x40, 0x12, 0x99, + 0x6A, 0x20, 0x48, 0x16, 0x52, 0x8A, 0xFD, 0xC1, 0x49, 0x9C, + 0x70, 0x78, 0x75, 0xED, 0xC6, 0xBF, 0x93, 0xDB, 0x93, 0x94, + 0x8D, 0x9F, 0x8A, 0x84, 0x7F, 0xF3, 0x17, 0xE9, 0x95, 0xBB, + 0xBB, 0x1A, 0xAE, 0x61, 0xB9, 0x74, 0x6C, 0x76, 0xA2, 0xE6, + 0x5F, 0xFD, 0xE5, 0xC3, 0xBD, 0xDB, 0x7F, 0x9F, 0x08, 0xA2, + 0x83, 0xDD, 0x2E, 0xBF, 0xB5, 0x6E, 0x92, 0xAA, 0xB5, 0x12, + 0x6F, 0x6E, 0x12, 0xF9, 0x91, 0x9E, 0x43, 0x45, 0x89, 0xE5, + 0xA4, 0x11, 0x97, 0xD8, 0xF3, 0x21, 0x1E, 0x32, 0x81, 0xAB, + 0x46, 0xE8, 0xBE, 0x30, 0x7C, 0x4A, 0xF4, 0xB7, 0x3B, 0xDF, + 0xC2, 0x74, 0x11, 0x56, 0xC0, 0x15, 0x95, 0xE2, 0x16, 0x31, + 0xB0, 0x04, 0xEE, 0xB7, 0x7B, 0x14, 0x21, 0x80, 0x92, 0x4B, + 0xA7, 0xA7, 0x71, 0x28, 0x05, 0xFA, 0xE4, 0xD2, 0x40, 0x00, + 0x9F, 0x3E, 0x1F, 0xC6, 0x6B, 0xE6, 0x4A, 0x9A, 0x2E, 0x87, + 0xD7, 0xC9, 0x84, 0xA2, 0xFF, 0x9D, 0xCB, 0x17, 0x45, 0x1E, + 0x88, 0x42, 0xB9, 0x95, 0x9E, 0xF6, 0xC2, 0xE3, 0xA4, 0xCE, + 0x82, 0xC1, 0x6F, 0xAB, 0x65, 0xAB, 0xB9, 0x93, 0xC0, 0x86, + 0xED, 0x6E, 0x5D, 0x06, 0x97, 0xBE, 0xC0, 0x06, 0x72, 0x7F, + 0x58, 0xD8, 0xC3, 0x34, 0x17, 0x37, 0x3E, 0xF0, 0xFD, 0x84, + 0x4F, 0x27, 0xA1, 0xD4, 0x7E, 0xCD, 0x0D, 0xFE, 0x66, 0x08, + 0x4E, 0xA4, 0x97, 0x8E, 0xC9, 0x98, 0x71, 0xFA, 0x44, 0xC7, + 0xA4, 0xFF, 0x30, 0x27, 0xB7, 0x16, 0x7B, 0x26, 0x03, 0x83, + 0x45, 0x42, 0x9A, 0x97, 0x4F, 0x88, 0x85, 0xF5, 0x00, 0x66, + 0xE1, 0xE3, 0x51, 0x80, 0x17, 0xFD, 0x7F, 0xA1, 0xC9, 0x56, + 0xB2, 0x27, 0x05, 0x8D, 0x44, 0x3F, 0x97, 0x7E, 0x62, 0x6B, + 0xBD, 0xCA, 0xE3, 0x61, 0x5D, 0x7A, 0x83, 0x72, 0x16, 0x70, + 0xBC, 0xC6, 0x50, 0x7B, 0xDD, 0x12, 0x06, 0x96, 0xDC, 0x6C, + 0x0A, 0xE9, 0x13, 0x0F, 0x63, 0x42, 0xD7, 0xC6, 0xA6, 0xDA, + 0x2E, 0x99, 0x84, 0x29, 0x1B, 0x70, 0x80, 0xAB, 0xB7, 0x7D, + 0x65, 0x8F, 0x28, 0x5F, 0x74, 0xF2, 0xCD, 0x88, 0xB2, 0xEE, + 0x6C, 0xD3, 0x5E, 0x83, 0x32, 0x20, 0x57, 0xBF, 0xD6, 0x37, + 0xFD, 0x83, 0x2E, 0x2C, 0x15, 0xBA, 0xCE, 0xEE, 0xCD, 0xAF, + 0x84, 0xC2, 0xA6, 0xC6, 0xF3, 0x4D, 0xF5, 0x54, 0x4F, 0x44, + 0x23, 0x5E, 0xA0, 0x66, 0x0B, 0x96, 0x6B, 0xF8, 0xA5, 0x3D, + 0x9D, 0xA2, 0x18, 0x71, 0x04, 0x0F, 0xFB, 0xF5, 0x75, 0x8C, + 0x01, 0xDD, 0x81, 0x4B, 0x09, 0x57, 0xA1, 0x61, 0x1B, 0x54, + 0x1C, 0xAE, 0x2C, 0x0E, 0x4E, 0xB1, 0x87, 0xCE, 0x2D, 0x60, + 0xD3, 0x27, 0x01, 0xCE, 0x5F, 0x62, 0x52, 0xCA, 0x1E, 0x07, + 0x6E, 0x0E, 0x73, 0xFD, 0xE7, 0x7F, 0x2C, 0xE4, 0x61, 0x41, + 0x1E, 0x5F, 0x57, 0x29, 0x8D, 0x53, 0x9E, 0x07, 0x9C, 0x9E, + 0xCA, 0xDB, 0x12, 0x63, 0x51, 0x88, 0xC9, 0x36, 0x98, 0xD2, + 0x96, 0xAC, 0x32, 0xEE, 0xD8, 0xBD, 0xA9, 0x76, 0x2D, 0xDC, + 0x85, 0x41, 0xFE, 0x54, 0xFB, 0x4C, 0xF4, 0x2E, 0x09, 0x64, + 0xF5, 0xEB, 0x4F, 0xB3, 0x0A, 0x54, 0x77, 0xB7, 0x05, 0xD8, + 0xD3, 0xF0, 0x7D, 0xA0, 0xD8, 0x22, 0x1C, 0x94, 0x85, 0x6D, + 0xCA, 0x43, 0x5A, 0x32, 0x3E, 0xDC, 0x20, 0x33, 0x81, 0xCD, + 0xFF, 0x6A, 0xBB, 0xD7, 0x00, 0xDB, 0x2E, 0x9D, 0xC5, 0x3F, + 0x5A, 0xDC, 0x75, 0x93, 0x2C, 0x5B, 0x8B, 0xCC, 0x29, 0x2D, + 0x29, 0x73, 0x82, 0x1A, 0xA2, 0x6B, 0x58, 0x04, 0x74, 0x3A, + 0x88, 0xC2, 0xE7, 0x47, 0x1F, 0xF4, 0xC9, 0x32, 0xF9, 0x52, + 0xF1, 0x57, 0x75, 0x71, 0x26, 0x56, 0xFB, 0xD8, 0x8B, 0xEA, + 0xE3, 0x01, 0x77, 0x2C, 0x1A, 0xD6, 0xBC, 0x2E, 0xAC, 0xD1, + 0x91, 0x8B, 0xEE, 0xB7, 0x11, 0xE1, 0x05, 0x38, 0x30, 0xED, + 0xFB, 0x4B, 0x4E, 0x76, 0x78, 0xA3, 0xBE, 0x3D, 0x3A, 0xC0, + 0x99, 0x0D, 0x0B, 0xF8, 0xB9, 0x02, 0x2A, 0x49, 0x4F, 0x1F, + 0x05, 0xEA, 0xFE, 0xAB, 0xF9, 0x14, 0xC4, 0x47, 0xFD, 0x42, + 0x3E, 0x01, 0x5A, 0x8E, 0xE4, 0xE0, 0x4B, 0xD0, 0x9D, 0x1D, + 0xC2, 0xB7, 0x81, 0x81, 0x25, 0x29, 0xAD, 0x58, 0x16, 0xAE, + 0x23, 0xFB, 0xE6, 0x9C, 0xE5, 0xDA, 0x71, 0xB4, 0x22, 0x08, + 0x2E, 0xEF, 0x9A, 0x91, 0x56, 0xAA, 0x9E, 0xD0, 0xC4, 0x4C, + 0x2E, 0xFD, 0x98, 0xF0, 0xE5, 0x23, 0x99, 0xA2, 0x4A, 0x88, + 0x24, 0x64, 0x79, 0x8B, 0x2A, 0x6E, 0x4A, 0x00, 0x65, 0x0A, + 0x74, 0xC1, 0x8A, 0xFF, 0xB6, 0x43, 0xA9, 0x61, 0xE8, 0xD0, + 0x2F, 0x1C, 0x97, 0xB6, 0xC0, 0xD8, 0x12, 0x2C, 0x11, 0x50, + 0xA5, 0xCF, 0x83, 0xAB, 0xC6, 0xDE, 0xB0, 0x3F, 0x14, 0x7B, + 0xEC, 0xAC, 0x37, 0x4C, 0x3F, 0xCE, 0xC4, 0x39, 0xC6, 0x1F, + 0x1A, 0x1E, 0x7B, 0xF9, 0xA3, 0x8F, 0x2F, 0xE0, 0x48, 0x22, + 0x97, 0x49, 0x37, 0xA8, 0xC7, 0x3E, 0x92, 0xB0, 0x65, 0x28, + 0xED, 0xF3, 0xAD, 0x58, 0xD4, 0xC4, 0xCC, 0x28, 0xD0, 0x47, + 0x72, 0x3D, 0xC9, 0xF7, 0xA6, 0x20, 0xD8, 0x8D, 0xCD, 0xA5, + 0x52, 0x45, 0x85, 0x29, 0x6F, 0x50, 0xA2, 0xBC, 0x66, 0xC9, + 0x7C, 0x70, 0x37, 0xC4, 0x65, 0x07, 0x15, 0x9F, 0x75, 0x3D, + 0x16, 0x80, 0x38, 0xB9, 0x40, 0xC4, 0xA5, 0xAF, 0x8F, 0x6D, + 0x9A, 0x6A, 0xDF, 0x12, 0xD2, 0x01, 0xFE, 0x63, 0x64, 0x21, + 0x28, 0x8D, 0x55, 0x65, 0x35, 0x08, 0x26, 0x53, 0xCD, 0xF6, + 0x1B, 0x50, 0xAA, 0xE3, 0x2C, 0x58, 0x14, 0x0C, 0xD7, 0x01, + 0xDB, 0xBA, 0x44, 0x15, 0x2B, 0xA5, 0x5C, 0x4C, 0xD6, 0xB8, + 0x82, 0x7C, 0xCE, 0x84, 0x0D, 0xE1, 0x39, 0x35, 0xC3, 0x48, + 0x9F, 0xA9, 0x01, 0x26, 0x53, 0xD7, 0x08, 0xD7, 0xDE, 0x69, + 0x0A, 0xD9, 0x83, 0x34, 0xF5, 0xBA, 0x46, 0x4E, 0x87, 0x8D, + 0xF8, 0x8F, 0xCC, 0x6B, 0x97, 0xC6, 0xDA, 0x8E, 0x55, 0xD5, + 0x78, 0x06, 0x0B, 0x1E, 0x98, 0xA2, 0x6A, 0xA7, 0x0D, 0xCD, + 0xC3, 0x70, 0x06, 0xDE, 0x77, 0xDA, 0x03, 0x93, 0x01, 0xAC, + 0xFA, 0x68, 0x63, 0x50, 0x8E, 0xD5, 0xEC, 0x3F, 0x66, 0x67, + 0xE6, 0x1B, 0x59, 0x98, 0x85, 0x3A, 0x56, 0x9E, 0xD9, 0x05, + 0x5E, 0x4A, 0x92, 0xE3, 0x7E, 0x98, 0xC7, 0xD9, 0xF0, 0xA3, + 0x4A, 0x92, 0x6F, 0x46, 0xB5, 0x38, 0xEE, 0x9B, 0x4A, 0xE0, + 0x53, 0x07, 0x0D, 0xA1, 0x76, 0xE8, 0xD1, 0x73, 0x8C, 0x9A, + 0x7C, 0xFC, 0x87, 0xC3, 0xD3, 0x3F, 0x89, 0x94, 0xA6, 0x23, + 0x8E, 0xE9, 0x1A, 0xE7, 0xBF, 0x9D, 0xE8, 0xB6, 0x46, 0x9B, + 0x9B, 0xB6, 0x8D, 0x99, 0xF2, 0xE4, 0x3C, 0xD3, 0x32, 0xA4, + 0x14, 0x95, 0x58, 0xE8, 0x5F, 0x4E, 0xEB, 0x38, 0x24, 0x5D, + 0x8B, 0x14, 0x23, 0x9A, 0xEF, 0x63, 0x27, 0xAE, 0xA5, 0xE3, + 0x4B, 0x56, 0x8B, 0x9D, 0x13, 0xAA, 0x5E, 0xA0, 0x51, 0xFA, + 0x53, 0xA0, 0x9F, 0x56, 0x72, 0x36, 0x91, 0x3B, 0xB4, 0xCB, + 0x68, 0x13, 0xCE, 0x77, 0x67, 0x8E, 0x28, 0xFE, 0x43, 0x6E, + 0x67, 0x28, 0xB1, 0xAF, 0x6A, 0xC2, 0x88, 0x2E, 0xC6, 0xEA, + 0x19, 0xEA, 0xF9, 0x18, 0xEA, 0x89, 0x73, 0x73, 0xBF, 0x1A, + 0x4B, 0xFC, 0x7A, 0x3B, 0x6F, 0x2D, 0x8E, 0xEA, 0x1F, 0x92, + 0x5F, 0xFE, 0xB6, 0x7E, 0x82, 0x2F, 0xD0, 0xB9, 0x47, 0x63, + 0x45, 0xB5, 0x78, 0x15, 0x64, 0x4B, 0x70, 0x62, 0xAD, 0xF1, + 0xD9, 0x95, 0x1C, 0x9F, 0x75, 0x11, 0xF1, 0x33, 0xC2, 0x19, + 0x2F, 0x1D, 0x7F, 0x87, 0x7B, 0xA5, 0xAA, 0xE0, 0xB7, 0xC8, + 0x5B, 0xD7, 0x04, 0x6C, 0x52, 0xB0, 0xB3, 0x31, 0xB4, 0xF8, + 0xC3, 0x57, 0x68, 0xF2, 0x7E, 0x81, 0xBE, 0x64, 0x93, 0x69, + 0x83, 0x91, 0xC8, 0x61, 0x25, 0x12, 0x00, 0x7A, 0xD5, 0xE4, + 0xC2, 0x9D, 0x55, 0xCB, 0x03, 0x6D, 0x51, 0xAE, 0xCE, 0xA1, + 0xC6, 0x2D, 0x4D, 0x76, 0x97, 0x2A, 0x33, 0x8E, 0xF9, 0x6A, + 0xED, 0x5F, 0x6F, 0xBB, 0x9B, 0x51, 0xE4, 0x51, 0x18, 0xD6, + 0xC6, 0x2C, 0x8E, 0x3C, 0xC0, 0x17, 0x00, 0xBF, 0xFF, 0xA0, + 0x9C, 0x26, 0x3A, 0x75, 0x45, 0x55, 0x40, 0xF0, 0x8A, 0xC0, + 0x6D, 0xFD, 0x36, 0x27, 0x89, 0x7A, 0x59, 0xFB, 0x77, 0xD0, + 0x03, 0xFE, 0x88, 0xB6, 0xB2, 0xBF, 0xE0, 0x7E, 0xDC, 0x43, + 0x8B, 0x3F, 0x6B, 0x72, 0xEE, 0x40, 0x32, 0x5F, 0x23, 0x29, + 0xF2, 0xBD, 0x15, 0x28, 0x15, 0x5B, 0x06, 0xA6, 0x0B, 0xB5, + 0x2A, 0xCA, 0xB8, 0xB4, 0xBF, 0xD7, 0xE4, 0x78, 0x1D, 0x1F, + 0xF7, 0x7E, 0xE0, 0x40, 0xB0, 0x5B, 0xE4, 0x76, 0x59, 0x1D, + 0xDA, 0xB7, 0x83, 0xD1, 0x66, 0x85, 0xBB, 0x13, 0xB8, 0xF8, + 0x72, 0x16, 0xA3, 0x29, 0x97, 0xF0, 0xA0, 0x9D, 0x19, 0x39, + 0x7E, 0x7D, 0x78, 0xAA, 0xE2, 0xEC, 0xC4, 0xC0, 0xA7, 0xCF, + 0xDD, 0x13, 0xD0, 0xA9, 0x91, 0xB6, 0x1C, 0x68, 0x86, 0x5A, + 0x9D, 0xF1, 0xA3, 0x60, 0x8C, 0x91, 0xA6, 0x1A, 0xB2, 0xF2, + 0x24, 0xB4, 0xA4, 0xAE, 0x17, 0x24, 0xB3, 0xD9, 0x9B, 0x65, + 0x03, 0xC5, 0xA8, 0x1A, 0x51, 0xE2, 0xCF, 0x89, 0x9D, 0xC3, + 0xF5, 0x8A, 0xDC, 0x95, 0xB5, 0x14, 0xB0, 0x1A, 0x48, 0x7D, + 0x7E, 0xDE, 0x1E, 0x03, 0xEA, 0x8D, 0xDD, 0xEB, 0x02, 0x3F, + 0xB6, 0x18, 0x4D, 0x68, 0xB8, 0xF7, 0x58, 0x97, 0x3A, 0x81, + 0x4F, 0x05, 0xDE, 0xD2, 0xBD, 0xBB, 0xDC, 0x46, 0x6E, 0x90, + 0x73, 0xB2, 0x89, 0xD5, 0xF8, 0xDD, 0x58, 0xE6, 0x34, 0xB1, + 0xF8, 0x6F, 0xFE, 0xD3, 0x37, 0x65, 0x97, 0x0E, 0x0B, 0x08, + 0x0A, 0x47, 0x73, 0xD8, 0x71, 0xAC, 0x0C, 0xF7, 0x72, 0x1C, + 0xD0, 0x3E, 0x45, 0x1E, 0xD4, 0xA8, 0x7C, 0x43, 0x59, 0xFD, + 0x80, 0xAF, 0x60, 0xB0, 0x57, 0xA6, 0x63, 0x89, 0x33, 0x9D, + 0xD9, 0x1A, 0xD6, 0x80, 0xC0, 0xEC, 0x55, 0x47, 0xDF, 0x81, + 0xAB, 0x66, 0xB7, 0xD6, 0x5D, 0x3F, 0x3E, 0xA8, 0x0A, 0xFA, + 0x75, 0x53, 0xB4, 0xDA, 0xD2, 0x92, 0xF5, 0xA3, 0x9F, 0x16, + 0xA6, 0xE8, 0xC7, 0xDB, 0x0A, 0x45, 0xA4, 0x72, 0x3E, 0xD4, + 0xFA, 0x23, 0x28, 0xE7, 0x68, 0x98, 0x90, 0x15, 0x7A, 0xDC, + 0x1D, 0x31, 0x23, 0xC7, 0x0E, 0xCB, 0xB3, 0x02, 0x34, 0x53, + 0x62, 0x11, 0x55, 0x23, 0x6A, 0x96, 0x73, 0x0B, 0xD6, 0x00, + 0x7D, 0x23, 0x75, 0x8B, 0x5B, 0xFA, 0x86, 0xF1, 0xAD, 0x32, + 0xE5, 0x3A, 0x60, 0x32, 0x9C, 0x20, 0x0E, 0x73, 0x45, 0xCB, + 0x8E, 0xDE, 0x38, 0x2D, 0x8F, 0x39, 0x44, 0x9D, 0x83, 0x10, + 0x6C, 0xEC, 0xD4, 0xB7, 0x22, 0x3C, 0x62, 0x18, 0x5B, 0x45, + 0x19, 0xED, 0xB2, 0x53, 0x34, 0x7C, 0x7D, 0x2F, 0xE6, 0x16, + 0xB9, 0xE5, 0x59, 0x86, 0x82, 0x61, 0xA4, 0x8C, 0x66, 0x61, + 0x56, 0xCF, 0x50, 0x21, 0xF6, 0x36, 0x2D, 0x02, 0x5A, 0xB3, + 0x65, 0x15, 0xFB, 0xDE, 0x40, 0x5C, 0xB6, 0x6B, 0xDE, 0x07, + 0xE8, 0x01, 0x9E, 0xC5, 0xD9, 0x7A, 0x59, 0xC3, 0x6C, 0xDB, + 0xA3, 0x6F, 0x3E, 0xCA, 0x55, 0x90, 0x44, 0x6E, 0x69, 0x2D, + 0x27, 0x2B, 0xF6, 0xD6, 0xF1, 0xB5, 0x05, 0x31, 0x21, 0x46, + 0x25, 0xEB, 0xAC, 0x87, 0x08, 0xF8, 0xD6, 0x5D, 0x86, 0xFF, + 0x6C, 0x4F, 0xE5, 0xA9, 0x06, 0xA8, 0x1C, 0x0C, 0x0E, 0x6E, + 0x18, 0x4E, 0xFB, 0xE6, 0x67, 0x1C, 0xF4, 0x28, 0x73, 0x69, + 0xA6, 0x39, 0xAF, 0x30, 0x37, 0xB0, 0xF8, 0x17, 0xAA, 0x9B, + 0x1D, 0xFD, 0x62, 0x9B, 0xDC, 0x76, 0x0D, 0x7F, 0x30, 0x1A, + 0xBB, 0x59, 0x7D, 0x01, 0xBC, 0xB0, 0x24, 0x72, 0xED, 0x44, + 0x25, 0xEB, 0xD2, 0xCE, 0x74, 0xA1, 0x5E, 0xB6, 0x02, 0x17, + 0x8E, 0x8D, 0x30, 0x89, 0xC3, 0xD2, 0x5E, 0xF5, 0x0F, 0xB5, + 0x6B, 0xA3, 0x0E, 0x7A, 0xC2, 0x1A, 0x70, 0x2D, 0xBC, 0xD6, + 0x48, 0x55, 0x4F, 0x7C, 0xCE, 0x96, 0xC9, 0xEE, 0x62, 0x42, + 0xB0, 0xB8, 0x3C, 0x89, 0x38, 0xCF, 0x51, 0x3F, 0x3D, 0xFB, + 0x02, 0x60, 0xFA, 0x38, 0xEE, 0x55, 0x1F, 0x6D, 0x97, 0xA1, + 0x7B, 0xA1, 0x01, 0x44, 0xEE, 0xD0, 0x5E, 0x06, 0x61, 0x50, + 0xA9, 0x4D, 0xE1, 0xF7, 0xAA, 0x83, 0x99, 0x84, 0xF6, 0xF8, + 0x2E, 0xA0, 0x2F, 0x19, 0xC2, 0x91, 0x74, 0x98, 0xBE, 0x04, + 0xCE, 0x97, 0xA0, 0x9A, 0x76, 0x64, 0x0A, 0x40, 0x7D, 0x9F, + 0x5F, 0x7E, 0xF9, 0xA3, 0x3E, 0x4F, 0xBE, 0xBB, 0x2A, 0x06, + 0xD0, 0xFC, 0x36, 0xBB, 0xEE, 0x21, 0x09, 0x07, 0xF6, 0xCA, + 0x8F, 0x01, 0xD4, 0xB3, 0x51, 0xE5, 0xEF, 0x6D, 0x1A, 0x1C, + 0x9D, 0x79, 0x37, 0xC6, 0x42, 0xDF, 0x57, 0xB0, 0x81, 0x6C, + 0x11, 0xBD, 0x71, 0x34, 0xE7, 0xA4, 0xCF, 0x56, 0xE7, 0x36, + 0x6E, 0x6D, 0xF1, 0xCC, 0x17, 0x2C, 0xD8, 0x2D, 0x8F, 0xC3, + 0x29, 0xDF, 0x1A, 0x5B, 0xE1, 0x4A, 0xC2, 0x43, 0xBD, 0x66, + 0x73, 0x4F, 0xB5, 0x55, 0x18, 0xA1, 0x42, 0xFE, 0x93, 0x72, + 0x76, 0x35, 0x4F, 0x78, 0x64, 0xBB, 0x00, 0xF8, 0x95, 0x72, + 0xD8, 0xC0, 0x23, 0x2F, 0xC8, 0x88, 0x58, 0xC7, 0x02, 0x3D, + 0x1D, 0xC3, 0xFB, 0xFB, 0x20, 0x46, 0x73, 0x59, 0xA6, 0x46, + 0xB3, 0x6D, 0x5C, 0x5B, 0x7F, 0xF8, 0x4C, 0x6B, 0x05, 0xE5, + 0x18, 0x6B, 0x05, 0xEE, 0x24, 0x18, 0x39, 0xD9, 0xC3, 0xE1, + 0xBB, 0xAA, 0x4F, 0x52, 0x63, 0x09, 0xD2, 0x79, 0x91, 0xE1, + 0xE5, 0x14, 0x6D, 0x4F, 0x07, 0xCE, 0xCE, 0xBD, 0x57, 0xC8, + 0x24, 0xB0, 0x58, 0x4E, 0x42, 0xC3, 0x78, 0xCC, 0x94, 0xDB, + 0x8D, 0xB8, 0x9E, 0x14, 0x50, 0x09, 0xBB, 0x28, 0xC1, 0x9C, + 0x78, 0xE2, 0x1E, 0xDB, 0xB3, 0xB4, 0xCA, 0xD2, 0xB3, 0xFF, + 0xEA, 0x36, 0xE8, 0xF2, 0x39, 0x86, 0x2C, 0xB6, 0xA1, 0x37, + 0x9C, 0x7D, 0xC7, 0x72, 0x99, 0x7E, 0xDE, 0xE3, 0x63, 0x46, + 0x35, 0x8A, 0x24, 0x1E, 0x90, 0xAD, 0xEB, 0x36, 0x65, 0x2B, + 0x00, 0x8E, 0x2A, 0xDC, 0x0D, 0x01, 0x3A, 0x8D, 0x54, 0x19, + 0x91, 0x8F, 0x72, 0xEF, 0x3A, 0x3A, 0x94, 0x40, 0xD5, 0x85, + 0x85, 0x89, 0xF6, 0x08, 0x83, 0xFF, 0x3F, 0x9B, 0x8C, 0x9E, + 0x4A, 0x34, 0xF7, 0xAB, 0x71, 0x48, 0x49, 0x8F, 0x6F, 0x8E, + 0x9C, 0x28, 0xA8, 0xE5, 0x38, 0x4E, 0xDC, 0x45, 0x21, 0xD7, + 0x61, 0x4C, 0x5F, 0x89, 0x03, 0x09, 0xCD, 0x5F, 0x93, 0xEA, + 0xDB, 0x31, 0xB9, 0x57, 0x0E, 0x97, 0xC2, 0x53, 0x73, 0x60, + 0xD2, 0xB9, 0x0C, 0x86, 0x55, 0xDF, 0x25, 0x59, 0xEC, 0xF8, + 0xC8, 0xFA, 0xEE, 0xDF, 0x23, 0x77, 0xDF, 0x49, 0xF9, 0x01, + 0xC6, 0xA4, 0xAD, 0x2F, 0xC8, 0xCF, 0x67, 0x26, 0xA6, 0xD8, + 0x74, 0x31, 0x42, 0x44, 0x32, 0x57, 0x1B, 0x26, 0xF2, 0xA9, + 0x23, 0x62, 0x3B, 0x23, 0x8E, 0xBD, 0x9D, 0x96, 0x9C, 0x82, + 0xEB, 0x63, 0x0C, 0x32, 0x67, 0xCC, 0x5B, 0x55, 0xF2, 0xFD, + 0x7F, 0x40, 0xB0, 0xBC, 0x7D, 0xE1, 0x34, 0x54, 0x81, 0x21, + 0xCC, 0xB8, 0x43, 0x8D, 0xCD, 0x14, 0x81, 0x1E, 0xE5, 0xE1, + 0xEA, 0xFB, 0x69, 0x50, 0x20, 0x60, 0xE0, 0xDC, 0x39, 0x12, + 0x6E, 0xF5, 0xCE, 0x9A, 0x17, 0x11, 0x67, 0xB8, 0xA7, 0xE5, + 0x02, 0x90, 0x85, 0xED, 0x7D, 0x67, 0x01, 0x6C, 0x71, 0xA3, + 0x4B, 0xD8, 0xBB, 0x71, 0x30, 0x11, 0xFA, 0xE3, 0x7E, 0xEC, + 0x72, 0xE5, 0xD0, 0x80, 0x0B, 0xB3, 0x05, 0xD4, 0xB4, 0x22, + 0x9D, 0x9C, 0x56, 0x09, 0x55, 0x90, 0x82, 0xEB, 0x70, 0x46, + 0x91, 0x69, 0x39, 0xEE, 0x12, 0x7F, 0x41, 0x85, 0xFE, 0x9E, + 0xDC, 0xD9, 0xF0, 0x5F, 0x4A, 0x66, 0xFE, 0x3D, 0xBD, 0x75, + 0x0D, 0xDB, 0x5A, 0x4C, 0xE3, 0x4B, 0x6F, 0x2C, 0xEB, 0x5F, + 0x92, 0x62, 0x3B, 0x17, 0xF9, 0x99, 0xB8, 0xAC, 0xC1, 0x5A, + 0x10, 0xC2, 0x3B, 0x36, 0xF8, 0x03, 0xF5, 0xC0, 0xDA, 0x7B, + 0x0B, 0x9D, 0xCD, 0xF3, 0x63, 0xB3, 0xB0, 0xB6, 0x0A, 0x4E, + 0x29, 0xCF, 0xD9, 0x09, 0xC2, 0x14, 0x1F, 0x03, 0xA6, 0xC0, + 0x3A, 0xA9, 0xE3, 0x24, 0xDA, 0x89, 0xF4, 0x1D, 0x0B, 0x0E, + 0x28, 0x31, 0xA2, 0x52, 0x48, 0x3E, 0x0F, 0x7A, 0x96, 0xD4, + 0x09, 0xF5, 0x87, 0xE7, 0x59, 0xF6, 0xC9, 0x61, 0xAD, 0xA8, + 0x9B, 0xBC, 0xA4, 0xD6, 0x39, 0xF4, 0xAB, 0x32, 0xF6, 0x0F, + 0x07, 0xC3, 0x1E, 0xD1, 0xF8, 0x24, 0x4F, 0x53, 0x30, 0xB1, + 0x3C, 0x87, 0x08, 0x25, 0xD7, 0x97, 0x42, 0x13, 0x25, 0x18, + 0x48, 0xFE, 0x90, 0x2F, 0xEC, 0x9A, 0xAF, 0x2B, 0xB1, 0x90, + 0xAD, 0x8C, 0x76, 0x3B, 0x9F, 0xD1, 0xEF, 0x2C, 0x1A, 0xAF, + 0xA7, 0x35, 0xF4, 0xD0, 0x11, 0x11, 0x4B, 0x37, 0xBA, 0x54, + 0x02, 0xB1, 0x1E, 0x44, 0xC1, 0xEF, 0x44, 0x5C, 0x06, 0x55, + 0x0A, 0xFE, 0x1E, 0x92, 0x2A, 0xC3, 0xE2, 0xA1, 0x70, 0x38, + 0x44, 0x91, 0x9E, 0xBC, 0x73, 0xF6, 0x24, 0x62, 0xDA, 0x2E, + 0xA3, 0x6E, 0x94, 0xE0, 0x17, 0x6A, 0x3F, 0x3C, 0x87, 0xEC, + 0x89, 0xFB, 0xA1, 0xDF, 0x1C, 0x81, 0x39, 0xB2, 0xAF, 0x8C, + 0x69, 0x28, 0x7D, 0xEB, 0xC5, 0x05, 0x70, 0xAE, 0x06, 0x38, + 0x45, 0xB5, 0xB2, 0xD9, 0x9D, 0x97, 0x65, 0xFD, 0xEB, 0x83, + 0x1E, 0x5A, 0x49, 0x3B, 0x7D, 0xA6, 0x1B, 0x98, 0xD7, 0xC7, + 0x71, 0x70, 0xF3, 0x5F, 0x05, 0x67, 0xBE, 0x59, 0xC1, 0xCF, + 0xC8, 0xA0, 0xF0, 0x8C, 0xE5, 0x51, 0x35, 0x97, 0xAA, 0x95, + 0x2B, 0x1D, 0xA3, 0x80, 0x04, 0xD9, 0x6E, 0x00, 0x33, 0x6D, + 0xEA, 0xF4, 0xD7, 0x7C, 0x73, 0x67, 0xB1, 0xB7, 0x18, 0x7C, + 0x5D, 0xE3, 0x0E, 0x0C, 0x70, 0x13, 0x38, 0xB9, 0x45, 0xE0, + 0x53, 0xA1, 0x08, 0xA7, 0x5E, 0x63, 0x49, 0x72, 0x77, 0x48, + 0x0D, 0x9E, 0x59, 0xD7, 0xDF, 0x21, 0x6A, 0xF3, 0xAF, 0xE8, + 0xEC, 0x6B, 0xC7, 0xDA, 0xF8, 0x4D, 0x2E, 0xC1, 0xA8, 0x0D, + 0x09, 0x12, 0x22, 0x34, 0xAD, 0x0C, 0xD3, 0x16, 0x36, 0x22, + 0x44, 0x3E, 0x45, 0x4B, 0xFD, 0x25, 0x36, 0x49, 0x07, 0x3B, + 0x87, 0x26, 0x92, 0xCD, 0xC1, 0xAA, 0xED, 0x47, 0xA2, 0x70, + 0xA1, 0x27, 0xD5, 0x36, 0xE8, 0xE9, 0x1B, 0xE9, 0xC9, 0x42, + 0x6D, 0x9F, 0x39, 0x3C, 0x9D, 0x55, 0x89, 0x0D, 0x81, 0xE3, + 0x78, 0x4E, 0x4D, 0x5F, 0x1B, 0x24, 0xF1, 0xB9, 0x40, 0xDF, + 0xF2, 0x62, 0xDB, 0x71, 0xD8, 0x0B, 0xD5, 0x20, 0xA2, 0x33, + 0x16, 0x8F, 0x7B, 0x2C, 0x1B, 0x2C, 0xFD, 0x4F, 0x18, 0x92, + 0xD4, 0x73, 0x53, 0x44, 0x6A, 0x6F, 0xDA, 0xC2, 0x4F, 0x2C, + 0xA1, 0xCB, 0xF9, 0xAD, 0x4B, 0x03, 0x43, 0x91, 0x4D, 0x01, + 0xF4, 0x48, 0x90, 0x08, 0x6E, 0x73, 0x41, 0x7D, 0x59, 0xAD, + 0x52, 0xB3, 0xEC, 0x62, 0x37, 0x94, 0x6E, 0xBB, 0x56, 0x2F, + 0xFE, 0x01, 0xE8, 0x9E, 0x81, 0x91, 0xE0, 0x2A, 0xCB, 0x9D, + 0xBB, 0xD5, 0xB1, 0xAB, 0xF2, 0xF9, 0x15, 0xE9, 0xA5, 0x72, + 0xDD, 0xBE, 0xF5, 0x5D, 0x37, 0xC9, 0x09, 0x61, 0x92, 0x03, + 0xAB, 0x1F, 0x7B, 0x22, 0xBD, 0x5A, 0x24, 0x46, 0x90, 0xAC, + 0x8C, 0xF6, 0x08, 0xA9, 0x0F, 0x93, 0xC2, 0xA8, 0x23, 0x35, + 0xC9, 0x4B, 0x7A, 0xDA, 0xE4, 0xB5, 0x5C, 0xAF, 0xAA, 0x1F, + 0x4F, 0x8D, 0x5A, 0x98, 0x6E, 0x60, 0x42, 0x9A, 0x78, 0x02, + 0x7F, 0x03, 0xFC, 0x31, 0x75, 0x97, 0x20, 0xE7, 0xDB, 0xA8, + 0x4F, 0x35, 0xC1, 0xCD, 0x76, 0xE0, 0x57, 0xD2, 0x43, 0x6A, + 0xA8, 0x65, 0xD8, 0xA2, 0x72, 0x99, 0xD8, 0x43, 0xE5, 0x78, + 0x99, 0x6F, 0xDF, 0xAA, 0x4E, 0xFE, 0xF5, 0x3F, 0x77, 0x65, + 0x9C, 0x90, 0x9A, 0x68, 0x98, 0x3D, 0xE5, 0x6E, 0xF8, 0xE9, + 0x6B, 0x58, 0xF9, 0xBF, 0x59, 0x26, 0xA2, 0x71, 0x94, 0x9B, + 0xC4, 0x81, 0x96, 0xBB, 0xBA, 0x9F, 0x9A, 0xF8, 0x28, 0x0A, + 0x48, 0x69, 0x1A, 0xC8, 0x94, 0xBD, 0x28, 0x11, 0xAD, 0x73, + 0x88, 0x85, 0xCF, 0x18, 0xBB, 0xFE, 0x3D, 0x75, 0xDC, 0x4D, + 0xD7, 0xEE, 0xAD, 0x66, 0x4A, 0x65, 0x3A, 0x30, 0x63, 0xA5, + 0x63, 0x24, 0xA7, 0x45, 0xEF, 0x64, 0x49, 0xF1, 0x49, 0x66, + 0x26, 0x85, 0xC5, 0xE0, 0xAE, 0x3D, 0x4C, 0x2F, 0xF7, 0x1D, + 0x80, 0x3B, 0xAE, 0x5A, 0xC9, 0xC3, 0xB4, 0x49, 0xD6, 0x18, + 0x44, 0xFD, 0x41, 0x91, 0x3E, 0x0B, 0xA4, 0x1C, 0xE3, 0x53, + 0xBA, 0x9C, 0x1C, 0xAE, 0xAF, 0xED, 0x75, 0xED, 0x16, 0x70, + 0xC3, 0x87, 0x00, 0xC3, 0xA4, 0xD3, 0xD9, 0xF1, 0x7C, 0x1D, + 0x69, 0x87, 0x55, 0x5D, 0x60, 0x74, 0xB1, 0x9E, 0x83, 0x9A, + 0xAC, 0x05, 0x6E, 0x5E, 0x54, 0x49, 0x2B, 0xD7, 0xD7, 0xAF, + 0xAF, 0xC1, 0x9B, 0x2A, 0xC0, 0xE7, 0x25, 0x99, 0xAB, 0xA7, + 0xE8, 0x51, 0x4C, 0x81, 0xE5, 0x52, 0x9F, 0x8D, 0x9C, 0xFA, + 0x67, 0x5C, 0x33, 0x84, 0x8E, 0x55, 0x88, 0x9A, 0xC5, 0x6E, + 0x8B, 0x7A, 0xDB, 0xEB, 0x4A, 0xC5, 0x23, 0x3F, 0xDC, 0xF5, + 0x5F, 0x6B, 0x02, 0x1F, 0x34, 0xDB, 0x85, 0x90, 0x17, 0x17, + 0x06, 0xE0, 0x81, 0xCA, 0x19, 0x0E, 0xF7, 0xE2, 0xDE, 0x65, + 0xC8, 0x38, 0x15, 0xE1, 0x13, 0xD3, 0x84, 0x2D, 0x31, 0xFF, + 0xFC, 0x7E, 0x8F, 0x45, 0x6A, 0x53, 0xE8, 0x6A, 0xE2, 0x84, + 0xB0, 0x46, 0x7A, 0xF7, 0xA6, 0x98, 0xBA, 0xD7, 0x61, 0xC6, + 0xB5, 0xA1, 0x40, 0x2C, 0xC0, 0x28, 0xF0, 0x47, 0x6A, 0xE9, + 0x84, 0x84, 0xE3, 0x4D, 0xB3, 0xF5, 0xA9, 0xC3, 0x19, 0xB5, + 0xEA, 0xD7, 0x04, 0xF2, 0xC0, 0x78, 0x86, 0xF7, 0x42, 0xA2, + 0x47, 0xD4, 0x89, 0x11, 0x82, 0x83, 0xDB, 0x10, 0x6B, 0x5D, + 0xBA, 0x1F, 0xCE, 0x79, 0xFB, 0xAA, 0xE2, 0x52, 0xCB, 0x8F, + 0x9E, 0x33, 0xC0, 0x70, 0xFC, 0xA1, 0xB4, 0xFF, 0xC3, 0xF5, + 0xCE, 0xF5, 0x00, 0x34, 0x22, 0xFC, 0x77, 0x97, 0x67, 0x99, + 0xA2, 0xD7, 0x91, 0xDD, 0x54, 0x64, 0x3C, 0x1A, 0x41, 0x07, + 0xB6, 0xB5, 0x41, 0x2F, 0xEA, 0xDA, 0x49, 0xBC, 0x2D, 0xF5, + 0xCD, 0xD8, 0xD1, 0x78, 0xEB, 0x15, 0x94, 0x19, 0xF0, 0x40, + 0x1F, 0xC2, 0x38, 0xF0, 0x7D, 0x5B, 0x42, 0x1C, 0xB4, 0xE0, + 0xC6, 0x28, 0xF9, 0x9B, 0xBF, 0x92, 0xED, 0xEC, 0xAC, 0xEF, + 0x0F, 0xB6, 0x3E, 0x1E, 0x31, 0x61, 0x7E, 0x67, 0xD4, 0xC5, + 0xFD, 0x34, 0x97, 0xC1, 0x8C, 0xD6, 0x0D, 0x93, 0xD7, 0x9B, + 0x80, 0xE9, 0x54, 0x4F, 0x45, 0x6E, 0x5E, 0x3D, 0xB7, 0x54, + 0x36, 0x38, 0xFE, 0x24, 0xD1, 0x7E, 0xA7, 0x37, 0x07, 0x03, + 0xD8, 0x1E, 0x4F, 0xC2, 0x66, 0x90, 0x1E, 0xC4, 0x00, 0xAE, + 0xB0, 0x93, 0xCD, 0x08, 0x6B, 0x1D, 0x01, 0x7D, 0x3E, 0x47, + 0x08, 0xE6, 0xAB, 0x87, 0x63, 0xAF, 0x29, 0x8A, 0x58, 0x2A, + 0xEA, 0x2E, 0xAA, 0xCB, 0xC3, 0x13, 0x1D, 0xDD, 0x31, 0xEC, + 0xF1, 0x31, 0xB8, 0xB3, 0xF1, 0xCA, 0x44, 0xB7, 0xF3, 0xEE, + 0x58, 0x03, 0xDF, 0xE2, 0x4D, 0x99, 0x98, 0x62, 0x92, 0xF1, + 0x9A, 0x07, 0x0F, 0x8C, 0x49, 0xFF, 0x93, 0x71, 0x96, 0xF3, + 0x52, 0xD7, 0x6C, 0xA0, 0xA1, 0xB4, 0x68, 0x7B, 0x81, 0x9A, + 0xB2, 0x4F, 0xD7, 0xD6, 0xFA, 0x18, 0x4F, 0xD4, 0x58, 0xF8, + 0x6A, 0x50, 0xC5, 0x4C, 0xEC, 0x3E, 0xA1, 0x14, 0x1C, 0x3E, + 0x59, 0x5F, 0x26, 0x46, 0x47, 0x17, 0x47, 0x87, 0x26, 0x31, + 0x91, 0x2E, 0x84, 0x71, 0xD2, 0x0D, 0xC8, 0x7C, 0xBF, 0xEB, + 0x2A, 0x1E, 0x96, 0xDE, 0xDB, 0x0A, 0x2A, 0x3F, 0xB3, 0x35, + 0x07, 0xB8, 0xA2, 0x48, 0x62, 0xEB, 0x6B, 0xA8, 0x66, 0xB3, + 0xE0, 0x38, 0x75, 0xCB, 0xDA, 0x9C, 0x8D, 0x7C, 0x5E, 0x3E, + 0x89, 0xA8, 0x99, 0x8F, 0x4F, 0x72, 0x25, 0x07, 0x2B, 0xBE, + 0xE3, 0x4E, 0x4A, 0x19, 0x46, 0x72, 0xF2, 0x47, 0x51, 0x16, + 0xDA, 0x42, 0x87, 0xB2, 0x9F, 0xC1, 0x2A, 0x65, 0x4F, 0x38, + 0xBA, 0xB1, 0x3C, 0x62, 0xBF, 0x4A, 0x7D, 0x44, 0x69, 0x9A, + 0x8A, 0x8E, 0x30, 0x8C, 0x53, 0xDD, 0x0E, 0x99, 0x30, 0x60, + 0x7F, 0xB7, 0x9A, 0x72, 0xB3, 0x08, 0x34, 0x47, 0x4C, 0x55, + 0xD6, 0x47, 0xD0, 0xC3, 0x70, 0xF4, 0x8A, 0xAE, 0xAF, 0x92, + 0x43, 0xEE, 0x42, 0xBF, 0xB2, 0x5A, 0x61, 0xF8, 0x08, 0xFA, + 0xC8, 0x95, 0xC2, 0x95, 0x79, 0x68, 0xDC, 0x2C, 0x00, 0xF9, + 0x6E, 0x35, 0x8E, 0x5A, 0x8F, 0x54, 0xA3, 0x95, 0x3E, 0x65, + 0xF4, 0xE9, 0x54, 0xB7, 0x64, 0xBB, 0xCE, 0xF6, 0xE5, 0x5A, + 0x34, 0xD1, 0x96, 0x31, 0x96, 0xCB, 0xEA, 0x2A, 0xDD, 0xCE, + 0xC6, 0x62, 0xF0, 0x90, 0xE5, 0x05, 0xF1, 0x38, 0x97, 0x31, + 0x57, 0xB9, 0x6A, 0x4D, 0x5E, 0x81, 0xAD, 0xDA, 0xB0, 0x4E, + 0x6C, 0xD3, 0xD0, 0x17, 0xDF, 0x74, 0xB5, 0xAC, 0x3E, 0x8E, + 0xFB, 0x78, 0xB6, 0x93, 0x81, 0xD3, 0xD5, 0x5F, 0x56, 0x72, + 0xF2, 0xCD, 0x41, 0x22, 0xCE, 0xB9, 0x11, 0x60, 0xCF, 0x21, + 0xCE, 0x82, 0xD8, 0x1E, 0xD7, 0x12, 0xF4, 0xD4, 0xFA, 0xD8, + 0x4E, 0x98, 0xAF, 0x33, 0xC2, 0x6E, 0xA6, 0x87, 0xDF, 0xC9, + 0x68, 0x1E, 0x5A, 0x45, 0x8B, 0xC0, 0xE6, 0x94, 0xEC, 0xD1, + 0x16, 0x75, 0x72, 0x54, 0x60, 0x3C, 0xDD, 0xDD, 0x5A, 0xE8, + 0xCD, 0xDC, 0x02, 0x6C, 0x58, 0xCE, 0xE9, 0x32, 0xF2, 0xEE, + 0x77, 0xEB, 0x36, 0x46, 0xD8, 0xFB, 0xB7, 0x1B, 0x32, 0xD4, + 0x50, 0xC1, 0xA5, 0xED, 0x29, 0x80, 0x18, 0x8C, 0x8D, 0x1D, + 0x45, 0x28, 0x85, 0x67, 0x60, 0xB7, 0x5E, 0xBD, 0xC4, 0x96, + 0xD0, 0xD5, 0xB9, 0x37, 0xD4, 0x90, 0xEC, 0x2A, 0xC6, 0x3F, + 0x92, 0xF3, 0x8B, 0x0D, 0x0C, 0x10, 0x30, 0xF1, 0x80, 0xE7, + 0x61, 0x88, 0x32, 0x92, 0x47, 0xA9, 0x2C, 0x49, 0x79, 0xCC, + 0x67, 0xE8, 0x44, 0x38, 0x17, 0x22, 0x69, 0xD5, 0x8A, 0xC1, + 0x99, 0xF5, 0xC6, 0x1C, 0x5B, 0x33, 0xFC, 0x98, 0x48, 0x9C, + 0x52, 0x7F, 0x97, 0x8D, 0x4D, 0x6A, 0xFD, 0xFB, 0xC0, 0x84, + 0x12, 0x98, 0xB2, 0x3B, 0x30, 0x34, 0x79, 0x3E, 0x59, 0x16, + 0x99, 0xC5, 0x89, 0xC5, 0x45, 0xE4, 0xF6, 0x01, 0x13, 0xC2, + 0x3D, 0x9D, 0x55, 0xA0, 0x78, 0x19, 0x38, 0xA5, 0xAB, 0x43, + 0x22, 0x94, 0x9A, 0x02, 0xB0, 0xFF, 0x9A, 0x84, 0x67, 0xD4, + 0x92, 0x40, 0xC1, 0xDB, 0x2D, 0x10, 0x57, 0xAD, 0xC8, 0xF5, + 0x11, 0xD2, 0xD9, 0x65, 0x9A, 0xC8, 0xCD, 0x62, 0xBD, 0x65, + 0x6B, 0xF3, 0xAF, 0x6A, 0x69, 0x61, 0xD1, 0x21, 0x5A, 0x69, + 0x03, 0xCC, 0xAC, 0x44, 0xBB, 0xDC, 0xCA, 0x06, 0x4A, 0x0C, + 0xE1, 0x27, 0xFC, 0xA5, 0x3E, 0xA8, 0xC7, 0xC8, 0x71, 0x82, + 0x22, 0xE4, 0x4E, 0x10, 0x3D, 0x03, 0x7B, 0xDF, 0xE9, 0x7E, + 0x80, 0x23, 0x0B, 0x6D, 0x49, 0x7B, 0x24, 0xC1, 0x28, 0x21, + 0x35, 0xA0, 0x6C, 0x63, 0x6B, 0x91, 0x7D, 0x23, 0xCD, 0x79, + 0x30, 0x07, 0x53, 0x72, 0x36, 0x4E, 0x6D, 0xB6, 0x24, 0xDB, + 0x79, 0xE9, 0x96, 0x1A, 0xDE, 0x03, 0x60, 0x73, 0x01, 0x98, + 0xCE, 0xB6, 0xCF, 0xD5, 0x19, 0x93, 0xF9, 0xA6, 0x27, 0x46, + 0xCB, 0x65, 0xCD, 0x62, 0xDF, 0x9C, 0x07, 0x8D, 0x90, 0x33, + 0x26, 0x18, 0xCC, 0xAE, 0xC2, 0x6F, 0x04, 0xB2, 0xC5, 0x81, + 0xE2, 0xD6, 0xD9, 0xE0, 0x92, 0x46, 0xC7, 0x4C, 0x90, 0x34, + 0x30, 0xE4, 0x12, 0xB1, 0xD3, 0x8B, 0x1A, 0x8C, 0x33, 0x1E, + 0x9A, 0xCB, 0xE6, 0x98, 0x82, 0x21, 0x45, 0xFA, 0xFC, 0xB3, + 0xB1, 0x18, 0x22, 0x73, 0x05, 0xEC, 0xD8, 0x53, 0x40, 0x26, + 0x68, 0xD5, 0x55, 0xD7, 0x60, 0xF0, 0xD5, 0x5A, 0xEE, 0x98, + 0x86, 0x36, 0x9B, 0x41, 0x22, 0x9A, 0x66, 0xCC, 0x44, 0x93, + 0x72, 0x5B, 0xB7, 0x6A, 0x45, 0x8F, 0x9F, 0xCB, 0x13, 0x92, + 0x64, 0x70, 0x07, 0xFD, 0x36, 0xAB, 0xDC, 0x70, 0x5C, 0x0C, + 0xEE, 0xAB, 0x17, 0xF2, 0xCC, 0x9A, 0xA7, 0xD3, 0x2E, 0xEE, + 0xDD, 0xCA, 0x53, 0x0A, 0x81, 0x0C, 0x8C, 0xD7, 0x8F, 0x26, + 0xD6, 0x18, 0xA5, 0x40, 0xE2, 0x66, 0x2B, 0x02, 0xC4, 0xD0, + 0x7D, 0xE3, 0x5C, 0x60, 0x8A, 0xDB, 0xE6, 0xD7, 0xA7, 0x96, + 0x49, 0xB7, 0x98, 0x74, 0xA0, 0x56, 0xE7, 0xAC, 0xCE, 0xD1, + 0xB0, 0x85, 0xB7, 0x6F, 0x6B, 0xED, 0x98, 0x09, 0x2D, 0xD7, + 0x78, 0xBC, 0x74, 0x7B, 0xAE, 0xCB, 0x0F, 0x35, 0x03, 0x0E, + 0x7F, 0xE5, 0x79, 0x5A, 0x9C, 0xE3, 0x73, 0xF4, 0xBA, 0x3E, + 0x5F, 0x3A, 0x55, 0xB7, 0x3C, 0x35, 0x1B, 0xC4, 0xFF, 0x5F, + 0xFD, 0x5D, 0x6C, 0xF9, 0x91, 0x66, 0x2C, 0x25, 0xBA, 0x0B, + 0x54, 0xE6, 0xA8, 0xCC, 0x62, 0x57, 0xF0, 0x0C, 0xA0, 0x8C, + 0x58, 0xFC, 0xE0, 0xCC, 0xA3, 0x91, 0xF2, 0x52, 0x34, 0xB9, + 0x93, 0x69, 0x1E, 0x70, 0x42, 0x00, 0x84, 0x4E, 0x89, 0x42, + 0x1A, 0x30, 0x95, 0x95, 0x31, 0x44, 0xB6, 0x1A, 0x13, 0x4E, + 0xF3, 0x4F, 0x43, 0x7D, 0xA7, 0xB6, 0x6A, 0x63, 0x2C, 0xA7, + 0x0E, 0x9E, 0x6C, 0x09, 0x3E, 0xA2, 0x02, 0x14, 0x2D, 0x13, + 0xBB, 0xB1, 0xD4, 0xE8, 0x1F, 0xB4, 0x8B, 0xFE, 0x9C, 0x06, + 0x88, 0x61, 0x78, 0x47, 0x82, 0x24, 0x6B, 0xFA, 0xE7, 0xB2, + 0xCA, 0x0E, 0x5C, 0x76, 0xBB, 0x77, 0x00, 0xDA, 0x8A, 0xF1, + 0x17, 0x7C, 0xE4, 0x7E, 0x24, 0x2C, 0x7F, 0xCA, 0x25, 0x14, + 0x1C, 0x42, 0x66, 0xFF, 0x87, 0xBE, 0x5E, 0xAC, 0x52, 0x3C, + 0x2C, 0x31, 0x54, 0x1B, 0x17, 0xDC, 0x2B, 0xAC, 0x5C, 0x38, + 0xFE, 0x1A, 0x39, 0xE4, 0xEC, 0x67, 0xF8, 0xD1, 0xA2, 0x4E, + 0xFF, 0xD8, 0xA3, 0x88, 0x2E, 0x70, 0x68, 0x58, 0xB0, 0xFB, + 0x72, 0x1D, 0x2F, 0x12, 0x88, 0x0B, 0xCE, 0x4B, 0xEC, 0x62, + 0xEA, 0x22, 0xE6, 0x71, 0xA9, 0xEB, 0x64, 0x39, 0x36, 0x9F, + 0x4E, 0x45, 0x98, 0xB2, 0x15, 0x01, 0xDC, 0xB9, 0x01, 0xD7, + 0x9C, 0x6C, 0x17, 0x23, 0xA5, 0x65, 0x93, 0x6B, 0x3D, 0xE3, + 0x1B, 0xAC, 0xB4, 0xCB, 0xDF, 0xCF, 0x54, 0x58, 0xBE, 0x6A, + 0xEC, 0x22, 0x6D, 0xF7, 0x6E, 0x0F, 0xAE, 0x76, 0x43, 0x58, + 0x06, 0xA1, 0x54, 0x4D, 0xA3, 0xDE, 0x08, 0x80, 0xF2, 0x2D, + 0xB8, 0xC8, 0x18, 0x2B, 0x02, 0x8C, 0xBE, 0xED, 0x13, 0x8A, + 0x6D, 0x7C, 0x8B, 0x70, 0x0C, 0xDA, 0xF4, 0x94, 0xB6, 0xFF, + 0x00, 0x4A, 0x86, 0x4F, 0x93, 0xE3, 0x8B, 0xA3, 0x44, 0xF9, + 0x36, 0xDE, 0xED, 0xF1, 0xEA, 0x2B, 0xBC, 0xCE, 0xF4, 0xB4, + 0x93, 0xCD, 0x66, 0x95, 0x4E, 0xE1, 0x84, 0x09, 0x4F, 0x4E, + 0x16, 0x56, 0x12, 0x6C, 0xF3, 0x09, 0x2D, 0x2E, 0x87, 0x8C, + 0x76, 0x5C, 0x18, 0xB5, 0xA3, 0xFE, 0x59, 0x27, 0x9D, 0x13, + 0x77, 0x6D, 0x3D, 0x9B, 0x0B, 0x83, 0x84, 0xB3, 0x2B, 0x60, + 0x80, 0xC4, 0x5A, 0x84, 0xAE, 0x19, 0x44, 0x54, 0xC2, 0xDD, + 0x52, 0xE4, 0x4B, 0xB1, 0xCB, 0x35, 0xB7, 0xFC, 0xF9, 0x4A, + 0x0C, 0xD3, 0x48, 0x14, 0x1E, 0x76, 0xBA, 0xA1, 0xB4, 0x99, + 0xF4, 0x26, 0xCC, 0xFD, 0xE6, 0x5C, 0x2E, 0x4C, 0xB7, 0x64, + 0xBE, 0xC2, 0x46, 0xD2, 0xED, 0xD0, 0x64, 0xD6, 0xE9, 0x7B, + 0x73, 0xEB, 0x3B, 0x24, 0xE7, 0xAD, 0x71, 0xB6, 0x72, 0x9D, + 0xE9, 0xF8, 0x3A, 0xEA, 0xC4, 0x65, 0x5D, 0xF1, 0xA6, 0x24, + 0x74, 0xF5, 0xCC, 0x47, 0xDC, 0x2E, 0x1A, 0xDC, 0xD4, 0xA7, + 0x73, 0x7E, 0x77, 0x0A, 0xED, 0x08, 0xBA, 0x88, 0x98, 0xBE, + 0xD9, 0xF9, 0x35, 0x18, 0x35, 0xF3, 0x44, 0xE7, 0x96, 0x32, + 0xC8, 0x13, 0xFD, 0xB2, 0x2D, 0xF2, 0x9F, 0x2B, 0xE7, 0xE8, + 0x33, 0x76, 0x8E, 0x2D, 0xB4, 0x2C, 0x5C, 0x72, 0x36, 0xCA, + 0x25, 0x19, 0x4C, 0x0C, 0xA7, 0xEF, 0x3D, 0x3C, 0x14, 0x9D, + 0x20, 0xE7, 0xBD, 0x22, 0xFA, 0x8B, 0x2A, 0x42, 0x07, 0xEF, + 0xD7, 0x57, 0xFC, 0x44, 0x11, 0xAA, 0x7F, 0x2B, 0xE3, 0x6A, + 0x81, 0xC5, 0x15, 0x69, 0x3D, 0x91, 0x2C, 0x95, 0x3D, 0xF0, + 0x1D, 0x9B, 0xE5, 0x99, 0x4A, 0xE4, 0x59, 0x28, 0x0E, 0xF7, + 0xBB, 0x4F, 0x33, 0xD9, 0x9C, 0xB3, 0x63, 0x5C, 0x96, 0x9C, + 0x2E, 0x91, 0x16, 0xE2, 0x67, 0x79, 0xF0, 0x10, 0x3E, 0xB4, + 0xE3, 0x5E, 0xE6, 0x92, 0x5F, 0xE3, 0xBE, 0x44, 0x24, 0xA5, + 0x31, 0x0C, 0x5D, 0x3E, 0xF0, 0x0F, 0xC7, 0x32, 0x23, 0x9E, + 0xDC, 0xC4, 0x29, 0xD1, 0x42, 0xDB, 0xC9, 0x3B, 0x24, 0x3D, + 0x9E, 0x5A, 0x7B, 0x9F, 0x29, 0xCC, 0xDD, 0xB7, 0xFB, 0x09, + 0xD9, 0x4B, 0xC2, 0xE5, 0x1D, 0x41, 0xED, 0x04, 0x22, 0x6D, + 0xB9, 0x41, 0x54, 0xC0, 0x89, 0xF1, 0x09, 0xA4, 0x23, 0xF1, + 0x8B, 0x00, 0xB4, 0x77, 0xBD, 0xFD, 0x80, 0x76, 0x48, 0x17, + 0x9B, 0xD9, 0x93, 0xC8, 0x16, 0xCB, 0x10, 0xF8, 0x84, 0x57, + 0x57, 0x41, 0x00, 0x5E, 0xFC, 0x3E, 0xEE, 0x05, 0xC9, 0xFA, + 0x82, 0xCB, 0x58, 0x67, 0x8A, 0x50, 0xE6, 0x16, 0xBB, 0xEA, + 0xDA, 0x2E, 0x3C, 0x1C, 0x28, 0x0E, 0x0B, 0x8B, 0x59, 0x72, + 0x02, 0x2C, 0xCB, 0xF8, 0x0D, 0x63, 0xCC, 0xCA, 0x91, 0x20, + 0x5F, 0xAD, 0x54, 0x1E, 0x5E, 0x7F, 0x04, 0x2C, 0x87, 0x91, + 0xD8, 0xC7, 0x63, 0x17, 0x1B, 0x8F, 0xFD, 0x86, 0xD3, 0xA7, + 0xEA, 0x85, 0x8F, 0x0F, 0x9C, 0x51, 0xCB, 0xAC, 0xAE, 0xE9, + 0xF2, 0x73, 0x93, 0x04, 0x0F, 0x46, 0x5D, 0xC6, 0xE8, 0xD1, + 0x35, 0xE5, 0xE7, 0xFC, 0xF9, 0x0A, 0x9B, 0xEC, 0xA4, 0xDC, + 0x96, 0xB1, 0xF9, 0x03, 0x27, 0x11, 0x1F, 0x4F, 0x9D, 0x06, + 0x4F, 0x81, 0x57, 0x88, 0x91, 0xD5, 0xC9, 0x3B, 0xE4, 0x18, + 0xC8, 0x6D, 0xF0, 0xEF, 0x40, 0x2B, 0xCA, 0x8E, 0x8D, 0xC8, + 0x92, 0x9E, 0x12, 0xE2, 0xA7, 0x9A, 0x86, 0x19, 0xB9, 0x1F, + 0xD5, 0xE1, 0x95, 0xDD, 0x6D, 0x2A, 0x7F, 0x26, 0x7E, 0x8D, + 0xF3, 0xDE, 0xFB, 0xBA, 0xC8, 0xEF, 0xAE, 0x31, 0xF1, 0x0F, + 0x41, 0xAC, 0x8A, 0x5B, 0x01, 0x0D, 0x14, 0x3B, 0x00, 0x80, + 0xC5, 0xD4, 0x3E, 0xE8, 0x6E, 0x69, 0xE6, 0x31, 0x7A, 0x32, + 0x2B, 0x7F, 0x05, 0x3A, 0xA2, 0x58, 0x7D, 0xE7, 0xA7, 0x21, + 0xB7, 0x0F, 0xB5, 0x8B, 0x6E, 0x55, 0xD7, 0x8F, 0xCE, 0xBD, + 0x82, 0x49, 0xC9, 0xA8, 0x1A, 0x2D, 0x68, 0xCC, 0xC6, 0xA2, + 0x5A, 0x7C, 0x98, 0xEE, 0x8B, 0x64, 0xB7, 0x1B, 0x14, 0xC4, + 0x92, 0x9E, 0x36, 0xAF, 0x14, 0xD9, 0xB5, 0xEF, 0x76, 0xE5, + 0xAA, 0x5F, 0x77, 0xCB, 0x75, 0x46, 0xC2, 0x7D, 0x42, 0xE6, + 0x9A, 0x60, 0xF7, 0x80, 0xC9, 0x49, 0x77, 0xB5, 0x0F, 0xE0, + 0xBF, 0x4B, 0x2C, 0xDA, 0xE2, 0xAA, 0xFA, 0x02, 0x93, 0x09, + 0x2E, 0x48, 0x2A, 0xF0, 0x05, 0xD2, 0x2E, 0xE4, 0x89, 0xD3, + 0x15, 0x2E, 0x5D, 0x80, 0xEB, 0x7A, 0xA5, 0x35, 0x0D, 0xE6, + 0x9D, 0xC8, 0x33, 0x0A, 0x63, 0x52, 0xA1, 0x97, 0xFD, 0xB0, + 0xE7, 0x71, 0x55, 0x07, 0xA4, 0xA3, 0x5F, 0xDC, 0xBD, 0x90, + 0x6A, 0xB0, 0xB5, 0x0D, 0x2B, 0xE1, 0xB3, 0x0F, 0xA6, 0x28, + 0xA7, 0xF7, 0x9E, 0x67, 0xEF, 0x2A, 0x6F, 0x86, 0x82, 0x47, + 0x9B, 0xEB, 0x42, 0xCB, 0x00, 0x4D, 0xC5, 0x9A, 0xB7, 0x56, + 0xAB, 0x80, 0x8B, 0x7F, 0x00, 0x1A, 0x4B, 0xBF, 0x28, 0x3E, + 0x61, 0xC4, 0xD3, 0x4D, 0x04, 0x88, 0x50, 0x8A, 0x62, 0xAE, + 0xDD, 0xA6, 0xA2, 0x43, 0x19, 0xD6, 0xAB, 0x6F, 0xB6, 0xB1, + 0x07, 0x67, 0x19, 0x30, 0x4A, 0x92, 0x52, 0x94, 0x92, 0x48, + 0x6A, 0x8C, 0xDE, 0x76, 0x40, 0x06, 0x85, 0xE7, 0x0E, 0x6A, + 0x2B, 0xFB, 0x02, 0x0D, 0xFE, 0x62, 0x5F, 0x72, 0x9D, 0x49, + 0x0C, 0x89, 0x29, 0x22, 0xC5, 0x36, 0xC1, 0x72, 0x4C, 0xE5, + 0x29, 0xFF, 0x9C, 0x05, 0x18, 0xE7, 0xF1, 0x41, 0x04, 0x66, + 0x23, 0x14, 0xB8, 0x95, 0xD9, 0xB4, 0xA2, 0x3B, 0x7C, 0xDB, + 0x27, 0x5E, 0xC7, 0x0B, 0x57, 0x55, 0x17, 0xF4, 0x97, 0xE8, + 0x92, 0x51, 0xC7, 0x05, 0x0C, 0x23, 0xE8, 0x83, 0x5F, 0x0E, + 0x2D, 0xA9, 0x14, 0xEF, 0x14, 0x15, 0xC0, 0x28, 0x3C, 0x30, + 0x63, 0x98, 0x27, 0x3F, 0x90, 0xEE, 0xAF, 0xC1, 0xBD, 0x66, + 0x26, 0xFC, 0xF1, 0x6B, 0xBB, 0x3A, 0xF2, 0x86, 0x3D, 0xD5, + 0x9F, 0x9C, 0x3A, 0xC2, 0x2A, 0xB6, 0x43, 0x0D, 0x43, 0x90, + 0xA2, 0xB2, 0xE0, 0xA9, 0x79, 0x61, 0xBD, 0xE5, 0x1D, 0x3F, + 0xCD, 0x0F, 0xC2, 0x95, 0xC6, 0xF9, 0x5E, 0x53, 0x94, 0xD2, + 0x62, 0xAE, 0x2A, 0x63, 0x4D, 0x9D, 0x74, 0x25, 0xEB, 0xD5, + 0xFC, 0xFF, 0x86, 0x88, 0xAD, 0x04, 0xE4, 0x59, 0x69, 0xB1, + 0x9F, 0x5E, 0xE2, 0x3A, 0x73, 0x76, 0xF6, 0xA6, 0xF6, 0x03, + 0x92, 0xF4, 0xC9, 0x50, 0x9D, 0x0A, 0x78, 0xD7, 0x43, 0xBC, + 0xD4, 0x8A, 0x25, 0x5E, 0x60, 0x70, 0x08, 0x98, 0x40, 0x63, + 0x8D, 0xE7, 0x10, 0x3E, 0x7D, 0xF4, 0xCE, 0xCE, 0xE9, 0x78, + 0xA4, 0x4E, 0xAB, 0xC5, 0x18, 0x47, 0x11, 0xED, 0x71, 0xA0, + 0x83, 0xF2, 0x20, 0xE3, 0x9B, 0x23, 0xD2, 0x00, 0xCA, 0x16, + 0xDE, 0x73, 0x48, 0xD1, 0x16, 0xA9, 0x9D, 0x53, 0x07, 0x9E, + 0x73, 0x9C, 0xFC, 0x4E, 0x5A, 0xDB, 0xE2, 0x16, 0xF8, 0xF9, + 0x7F, 0x68, 0x23, 0x4B, 0x2D, 0x25, 0xB1, 0xFC, 0x57, 0x10, + 0x20, 0x5F, 0x6C, 0xC4, 0x4F, 0x44, 0xC2, 0x1F, 0x15, 0xCE, + 0x83, 0x4F, 0xB9, 0xEF, 0x4E, 0x5F, 0x06, 0x76, 0x6E, 0x58, + 0x96, 0x6F, 0xBD, 0x3E, 0xE1, 0x93, 0xE6, 0x70, 0x98, 0x1A, + 0x79, 0x7D, 0x31, 0xAF, 0x4E, 0x92, 0xE3, 0x27, 0xF1, 0x05, + 0xFB, 0xF3, 0x9D, 0x15, 0x26, 0x94, 0x63, 0xB6, 0x26, 0x6D, + 0x1A, 0x35, 0x1E, 0x96, 0x53, 0xA9, 0xD7, 0xBF, 0x19, 0x06, + 0x0E, 0x2E, 0x67, 0x7F, 0xED, 0xF7, 0xE2, 0x85, 0xE4, 0x7E, + 0xE9, 0x15, 0xB4, 0xFB, 0xC6, 0x10, 0xDA, 0x75, 0x18, 0xC7, + 0xC6, 0x75, 0x0B, 0x67, 0x04, 0x7F, 0x1F, 0x4E, 0x45, 0x9F, + 0x49, 0x04, 0x2C, 0x9B, 0xD3, 0xD3, 0x03, 0x18, 0x37, 0xB4, + 0x4F, 0xA2, 0x26, 0xE2, 0x31, 0x22, 0x8E, 0x59, 0xE6, 0xE1, + 0x13, 0x17, 0x46, 0x4B, 0xC0, 0xC2, 0x65, 0x66, 0x6B, 0x3B, + 0xCC, 0xCC, 0xC9, 0x62, 0xA2, 0x54, 0xF5, 0xE3, 0x65, 0x8A, + 0x52, 0x6D, 0xF8, 0x02, 0x6D, 0x88, 0x77, 0x12, 0x57, 0x80, + 0x50, 0xF1, 0xFA, 0xF8, 0x06, 0xD1, 0xCD, 0x06, 0xEB, 0x43, + 0x98, 0x1D, 0xCB, 0x34, 0x8D, 0xB8, 0x40, 0x01, 0xE8, 0x0F, + 0x9F, 0x27, 0xCB, 0x10, 0xE2, 0x68, 0x88, 0x15, 0xAB, 0x2E, + 0x80, 0x19, 0x98, 0xA9, 0x57, 0xF0, 0x84, 0x81, 0xB8, 0xBA, + 0x46, 0x47, 0xEF, 0x3F, 0x16, 0x0F, 0x4F, 0x6F, 0xEA, 0xE8, + 0x95, 0x8F, 0x82, 0x81, 0x7D, 0x00, 0x38, 0x34, 0x02, 0x00, + 0x3E, 0x6F, 0x18, 0x14, 0xB4, 0x46, 0xFC, 0xE2, 0xED, 0xD5, + 0x90, 0x19, 0x4D, 0xE4, 0xEE, 0x5A, 0xD0, 0x49, 0xD3, 0x6F, + 0xD4, 0xAC, 0xB0, 0x02, 0x11, 0xA7, 0xE6, 0xF1, 0xA8, 0xEF, + 0x81, 0x95, 0x91, 0xE9, 0xE0, 0xED, 0x85, 0x8D, 0x9F, 0xEE, + 0x1A, 0x33, 0xB1, 0x55, 0xCB, 0x54, 0xCA, 0xED, 0x19, 0xAB, + 0x71, 0x2C, 0xE2, 0xC9, 0xA1, 0x64, 0xB8, 0x1E, 0xF2, 0xB0, + 0x7E, 0x5D, 0x39, 0x66, 0x32, 0x9D, 0x2A, 0xD8, 0xAD, 0x98, + 0xED, 0x38, 0xBD, 0xEC, 0x74, 0xE8, 0x4C, 0xD2, 0x94, 0x68, + 0x56, 0xCC, 0xAC, 0xE5, 0x99, 0x76, 0x3A, 0x97, 0xDB, 0x76, + 0xF2, 0x06, 0xB7, 0x56, 0xAD, 0x76, 0x55, 0x35, 0x97, 0x1D, + 0xFF, 0xFB, 0x9F, 0xD5, 0x5B, 0x07, 0x0F, 0x1B, 0x5E, 0x6F, + 0x32, 0xFC, 0x4A, 0xF7, 0x97, 0xA6, 0x30, 0x97, 0xEC, 0x83, + 0x91, 0xEA, 0xDC, 0x90, 0x21, 0x84, 0xE6, 0x83, 0x39, 0x61, + 0x98, 0xD0, 0x02, 0x35, 0x48, 0x14, 0xE7, 0x16, 0x87, 0xB3, + 0xB0, 0x90, 0x8D, 0x2F, 0x18, 0x35, 0x13, 0x47, 0x3B, 0x2A, + 0x00, 0x44, 0x66, 0x2E, 0x8F, 0x42, 0x8C, 0x40, 0x71, 0xA4, + 0xE2, 0xCF, 0x27, 0x3D, 0xA8, 0xFA, 0x69, 0x29, 0x36, 0xF5, + 0xE4, 0xEE, 0xF2, 0x0B, 0x91, 0xE8, 0x68, 0x33, 0x04, 0x8D, + 0x9A, 0xC3, 0x7E, 0x1F, 0x44, 0x1E, 0x98, 0xEB, 0xFD, 0x15, + 0xE4, 0x79, 0x97, 0x04, 0xB3, 0x3D, 0x63, 0xEA, 0x3B, 0x3B, + 0x51, 0x5C, 0x9D, 0x9E, 0xB5, 0x33, 0xB7, 0xB3, 0xD8, 0x85, + 0xFE, 0x0D, 0xF6, 0x69, 0xA4, 0x63, 0x90, 0x25, 0x8C, 0xC0, + 0xE9, 0x51, 0xA1, 0xF8, 0xB0, 0x77, 0x55, 0x51, 0xAF, 0xD8, + 0x80, 0x32, 0x83, 0xB4, 0xC3, 0xF3, 0xC8, 0xF8, 0xAD, 0xF2, + 0x74, 0xC6, 0x32, 0xA0, 0x7A, 0x57, 0x03, 0x10, 0xF1, 0x9D, + 0x1D, 0xC3, 0x7B, 0xE5, 0x42, 0x5A, 0x03, 0x7E, 0xF0, 0x71, + 0x17, 0xCC, 0x54, 0x93, 0x66, 0x06, 0xBA, 0x5C, 0xAA, 0xCC, + 0x90, 0x1F, 0xA7, 0x15, 0xBE, 0x7D, 0x4B, 0x0B, 0x32, 0x51, + 0xAF, 0xF5, 0x04, 0xDC, 0x23, 0x82, 0x36, 0xED, 0x8D, 0xCE, + 0x38, 0x44, 0xA6, 0x0F, 0x3A, 0x81, 0xCE, 0x42, 0x07, 0x38, + 0xCD, 0x51, 0xC1, 0x30, 0xC5, 0x2B, 0xA1, 0x2D, 0x3E, 0xFE, + 0x8F, 0xC6, 0xA7, 0xF2, 0x5A, 0x8A, 0x7F, 0x1C, 0xE1, 0x71, + 0x78, 0xAF, 0x61, 0xB3, 0x72, 0x41, 0x94, 0xBA, 0xAA, 0x3B, + 0x45, 0x60, 0xAC, 0x85, 0xC7, 0xDE, 0x6D, 0x0E, 0x01, 0xAD, + 0x91, 0x14, 0x1C, 0xA4, 0xF4, 0xDF, 0x87, 0xD2, 0xF8, 0x4D, + 0x9D, 0xE4, 0x4B, 0x76, 0x2D, 0x89, 0xA8, 0xE7, 0xF8, 0x32, + 0xCA, 0xFF, 0x7B, 0xF6, 0xBF, 0x4D, 0xB9, 0x80, 0xD2, 0x5D, + 0x75, 0xB4, 0x5D, 0xBD, 0x28, 0xAD, 0x59, 0x73, 0xE2, 0xEF, + 0xF4, 0x8D, 0x7F, 0xE4, 0x2A, 0xD0, 0x75, 0xD8, 0xA3, 0x2B, + 0xFB, 0x2C, 0x05, 0x54, 0xAC, 0x58, 0xBC, 0xD5, 0x3E, 0xA3, + 0x76, 0x56, 0x84, 0x5F, 0x92, 0x73, 0xC5, 0x21, 0xC2, 0x6D, + 0xB4, 0xB1, 0xFF, 0xCC, 0xD5, 0x7A, 0xD3, 0x74, 0x06, 0x78, + 0x8F, 0xCA, 0x6D, 0x53, 0xFF, 0xF4, 0xA6, 0xB8, 0xD1, 0x91, + 0xDC, 0xA1, 0xFA, 0x7B, 0xC0, 0x6C, 0xEB, 0x80, 0x86, 0xC2, + 0x8B, 0x26, 0x74, 0x15, 0x88, 0xE3, 0x72, 0xBC, 0x7C, 0x6D, + 0x77, 0xF8, 0x33, 0x4A, 0x3D, 0x5C, 0x7B, 0xA1, 0x3D, 0x89, + 0xAE, 0xB5, 0x2D, 0x5E, 0x8B, 0xBA, 0x6B, 0x72, 0x14, 0x47, + 0xFF, 0xF9, 0x17, 0x9E, 0xCA, 0x56, 0x7F, 0x2B, 0xD4, 0xD5, + 0x90, 0x10, 0x87, 0x77, 0xD2, 0x20, 0x03, 0xB5, 0xE0, 0xF1, + 0x9A, 0x50, 0xA5, 0xB8, 0x8D, 0xB8, 0xB8, 0x61, 0xBB, 0x75, + 0x58, 0xCC, 0xE3, 0xEE, 0x8E, 0x12, 0xE9, 0xD7, 0x79, 0x43, + 0x22, 0x65, 0x33, 0xF0, 0xFE, 0x33, 0x96, 0x8C, 0x00, 0x04, + 0xE6, 0x2C, 0xA3, 0x7C, 0xE4, 0xCD, 0x6A, 0xDC, 0xF0, 0x41, + 0x45, 0x6D, 0xD4, 0xCB, 0x88, 0x94, 0x35, 0xAA, 0xC2, 0xB1, + 0x68, 0xB5, 0x93, 0x49, 0x62, 0xF3, 0x15, 0xE0, 0x3D, 0x6F, + 0xAB, 0x40, 0x47, 0x84, 0x72, 0x07, 0xB9, 0xF4, 0x62, 0xE6, + 0x0B, 0x22, 0xA7, 0x82, 0x2F, 0xF9, 0x2A, 0x42, 0x66, 0x41, + 0x25, 0x53, 0x23, 0xB0, 0x07, 0xD3, 0x1D, 0x3D, 0xC2, 0x01, + 0x50, 0xB5, 0x01, 0xDB, 0x60, 0x85, 0xF1, 0x2F, 0x34, 0x66, + 0xC7, 0xCA, 0x12, 0x4A, 0x1F, 0xF5, 0xC5, 0x33, 0x86, 0x87, + 0xAB, 0xD7, 0xD8, 0xA4, 0x70, 0x1A, 0xA7, 0xDA, 0xEF, 0x12, + 0xD4, 0x5A, 0x72, 0xF2, 0xB7, 0x63, 0xC6, 0xC0, 0xD4, 0x4F, + 0x32, 0xE0, 0xA6, 0xB2, 0x8C, 0x58, 0xDF, 0xD2, 0x6C, 0x93, + 0xAC, 0xC4, 0x82, 0xCC, 0x8A, 0x75, 0x07, 0x8F, 0x39, 0x4B, + 0x5F, 0x33, 0x98, 0x0B, 0x5F, 0x11, 0x92, 0xB6, 0x38, 0x51, + 0x95, 0x1A, 0xC2, 0xBB, 0x26, 0xC0, 0x0B, 0x42, 0xE8, 0x7B, + 0x82, 0xE3, 0x54, 0x8F, 0xAF, 0x29, 0xEA, 0xEE, 0xEB, 0x55, + 0x2E, 0x38, 0x71, 0x39, 0x71, 0xD6, 0x91, 0x16, 0x07, 0x4D, + 0x4C, 0xEF, 0xD5, 0xC2, 0x7F, 0x4B, 0x26, 0xA1, 0x4D, 0xF7, + 0x03, 0x40, 0x38, 0x55, 0x78, 0xBC, 0x0A, 0x6D, 0x46, 0xEA, + 0xC3, 0x0C, 0x60, 0x10, 0xE2, 0x8A, 0x5E, 0x0F, 0xE8, 0x39, + 0x8B, 0xA8, 0x28, 0x1E, 0x82, 0x6B, 0x6E, 0x8A, 0xFB, 0xAD, + 0x84, 0x15, 0x45, 0xB4, 0xA3, 0xEE, 0x3B, 0x50, 0x7F, 0x85, + 0xF3, 0x37, 0x1D, 0xFB, 0x24, 0x47, 0xCF, 0xA4, 0xAD, 0xCB, + 0xD1, 0xBA, 0x9A, 0x36, 0xF1, 0x5F, 0x2B, 0xD8, 0x10, 0x0A, + 0xF0, 0xDC, 0xD7, 0xFC, 0x26, 0x4F, 0x61, 0x4A, 0xAA, 0xD2, + 0x5B, 0x28, 0x74, 0x45, 0xB1, 0x92, 0xAB, 0x4C, 0x3B, 0x73, + 0x3E, 0x11, 0x59, 0xE9, 0x3E, 0x1D, 0xBD, 0x36, 0x0C, 0x53, + 0x0A, 0x73, 0xB9, 0xB0, 0xDE, 0x5E, 0xD2, 0x08, 0xE9, 0x16, + 0xA0, 0x4C, 0xC6, 0xF3, 0x7A, 0xE2, 0xE0, 0x1D, 0x3F, 0x14, + 0x1C, 0x5A, 0x7B, 0x88, 0x06, 0xA4, 0x2A, 0x02, 0x0C, 0xE5, + 0x73, 0xC8, 0xBB, 0x41, 0x4B, 0xE6, 0xCB, 0x3C, 0x95, 0x65, + 0xE0, 0xE5, 0x50, 0x30, 0xF8, 0xB1, 0xB9, 0x27, 0x87, 0x90, + 0x82, 0x08, 0x01, 0x02, 0x3C, 0x74, 0x5F, 0x89, 0x70, 0x98, + 0xD7, 0x16, 0xFC, 0x66, 0x6B, 0x24, 0x78, 0xF4, 0xFA, 0x28, + 0x81, 0xB8, 0x93, 0xCA, 0xFC, 0xB1, 0x27, 0xFC, 0xEA, 0x97, + 0x69, 0x42, 0xE9, 0xB2, 0x9B, 0x7C, 0x13, 0xA8, 0x04, 0x21, + 0xF3, 0xAD, 0x29, 0x8A, 0x8F, 0x46, 0x4F, 0xE2, 0xA5, 0x52, + 0x24, 0xB1, 0x27, 0x70, 0x20, 0xE5, 0xB9, 0xA3, 0x60, 0xC4, + 0x62, 0x77, 0x87, 0x0D, 0xC5, 0x91, 0x56, 0x34, 0xC5, 0xA6, + 0x4B, 0xEA, 0x3F, 0xC1, 0xB2, 0xFC, 0x5F, 0x03, 0xAC, 0xBF, + 0x50, 0x4E, 0x53, 0x5F, 0x17, 0xB4, 0xB9, 0x5F, 0x0A, 0x7D, + 0xA4, 0xB8, 0x44, 0xDE, 0x80, 0xAB, 0x19, 0x14, 0x4B, 0xE8, + 0xC3, 0x01, 0x96, 0xAA, 0x0D, 0xA9, 0x45, 0x30, 0xE1, 0x3B, + 0x74, 0x5F, 0x9A, 0xF2, 0x0E, 0xCC, 0xE4, 0xD5, 0x08, 0xAE, + 0x35, 0xD3, 0x43, 0x80, 0x5B, 0xA6, 0x91, 0x8C, 0x48, 0xD8, + 0x16, 0x2E, 0x5D, 0x97, 0x0A, 0x16, 0x23, 0x6E, 0xF7, 0x81, + 0xAB, 0xA9, 0x8D, 0xB2, 0x17, 0x0D, 0x7A, 0x55, 0x46, 0x35, + 0xC5, 0xAF, 0x6C, 0x5F, 0xD0, 0xFD, 0x36, 0x31, 0x4E, 0x3E, + 0xE1, 0x0E, 0x76, 0xCD, 0x0F, 0x3D, 0x8D, 0x23, 0x7A, 0x9E, + 0x6C, 0xB2, 0x2D, 0xB9, 0xFA, 0xD9, 0xA2, 0x20, 0xE0, 0x57, + 0x61, 0x44, 0x47, 0xE5, 0xEF, 0x56, 0x32, 0x42, 0x91, 0x77, + 0x7C, 0x24, 0x9A, 0x23, 0x9C, 0xB5, 0x84, 0xB3, 0xFC, 0xEE, + 0x5F, 0x66, 0x90, 0xE4, 0x99, 0xE9, 0x9E, 0x5A, 0xBD, 0x3E, + 0xAD, 0xFE, 0xEB, 0xA3, 0x2A, 0xED, 0x99, 0x73, 0x70, 0x70, + 0x1D, 0x49, 0xB8, 0x63, 0xC5, 0x7C, 0x88, 0x77, 0xF7, 0x08, + 0x3A, 0x48, 0x72, 0xCE, 0x9A, 0xCF, 0xB8, 0x41, 0x14, 0x7C, + 0x85, 0x03, 0x88, 0x9E, 0xA1, 0xB3, 0x77, 0x16, 0xB7, 0x09, + 0x05, 0x52, 0x75, 0x9A, 0x21, 0xF4, 0x5A, 0x1F, 0x41, 0x29, + 0xCA, 0x5E, 0x98, 0x30, 0x0B, 0xB5, 0xA1, 0x0C, 0x69, 0x1E, + 0xAE, 0xFF, 0x9D, 0xB6, 0xD6, 0xFE, 0x04, 0x70, 0xC1, 0x5E, + 0xD7, 0xF4, 0xC5, 0x40, 0x0D, 0x92, 0xB5, 0xA2, 0x62, 0xB1, + 0x6C, 0x6C, 0xDA, 0xF4, 0xF6, 0xEF, 0x6F, 0x70, 0x17, 0x2B, + 0x36, 0x1E, 0x63, 0xDC, 0x98, 0xA9, 0xF3, 0x1C, 0x55, 0xF8, + 0x58, 0xFC, 0xFE, 0xEE, 0x19, 0x3E, 0x61, 0xE6, 0x4D, 0x52, + 0x25, 0x76, 0x4C, 0x51, 0x4C, 0x29, 0xD8, 0xA1, 0x1E, 0xB0, + 0xC2, 0x3B, 0x40, 0x13, 0x04, 0x49, 0x3B, 0xAE, 0x15, 0xFA, + 0x52, 0xD3, 0x9B, 0xD3, 0x8C, 0x9F, 0x40, 0xDB, 0x90, 0x16, + 0x10, 0x50, 0x13, 0x32, 0x84, 0x6E, 0x47, 0x3C, 0x41, 0xD9, + 0xA3, 0x45, 0x72, 0x1F, 0x15, 0x76, 0xA3, 0xA3, 0xB4, 0xC3, + 0x26, 0x5A, 0x6F, 0x2D, 0x5B, 0x96, 0xBF, 0xF8, 0x65, 0x8F, + 0x4E, 0x6B, 0x80, 0xDD, 0xD9, 0xA4, 0x52, 0x0A, 0xFA, 0x3B, + 0x91, 0xE0, 0xDD, 0x84, 0x15, 0xB7, 0xAC, 0x82, 0xCB, 0x18, + 0x52, 0xBC, 0x79, 0x42, 0x2C, 0x91, 0x05, 0x94, 0xCE, 0x76, + 0xF1, 0xBD, 0x73, 0xFF, 0xDD, 0xDA, 0x1D, 0x3C, 0xD7, 0x02, + 0x96, 0xBE, 0xE3, 0x7F, 0x7A, 0x5A, 0x89, 0x15, 0xF4, 0xA7, + 0x4F, 0x82, 0xE7, 0xA2, 0x25, 0xA9, 0x77, 0xCA, 0x80, 0xF2, + 0xE5, 0x98, 0x2A, 0xFC, 0x78, 0x04, 0x42, 0x2B, 0xF5, 0xE8, + 0xA3, 0x29, 0xBC, 0x3A, 0x87, 0x38, 0x0F, 0x6D, 0x47, 0x6E, + 0xB0, 0xC9, 0x7C, 0x41, 0xA0, 0xCF, 0x1A, 0x53, 0x9C, 0x9E, + 0x8C, 0x6D, 0x4A, 0x0C, 0x78, 0xDC, 0x36, 0x5E, 0x62, 0x5B, + 0xE0, 0x1A, 0xD0, 0xD1, 0x29, 0xF8, 0x62, 0x79, 0x10, 0xF1, + 0x2D, 0x71, 0x5F, 0xD2, 0x2B, 0xE7, 0xC0, 0x11, 0xD6, 0xB5, + 0xAF, 0xD2, 0xDB, 0xE8, 0x4C, 0x8A, 0x2F, 0xDD, 0x73, 0x56, + 0x7F, 0xD7, 0xE0, 0xBF, 0xDB, 0xA4, 0x27, 0xE0, 0x4C, 0x63, + 0x90, 0x7D, 0x5A, 0x39, 0xB9, 0x91, 0x80, 0x70, 0x67, 0x4F, + 0xCA, 0x3C, 0x97, 0xFE, 0x15, 0x7C, 0x6C, 0x85, 0x33, 0x6D, + 0xA2, 0x6E, 0xFB, 0xD2, 0xAF, 0xEF, 0xA5, 0xB6, 0x92, 0xFF, + 0x02, 0x84, 0xA6, 0x6E, 0x9E, 0xAE, 0xD9, 0x82, 0xFE, 0xFC, + 0x91, 0x47, 0x16, 0xB6, 0x21, 0xE1, 0xEC, 0x95, 0x23, 0x48, + 0xF5, 0xCD, 0xB6, 0xDD, 0xF8, 0xD1, 0x9C, 0xD3, 0xEA, 0x5E, + 0x8E, 0xA5, 0x68, 0x21, 0x41, 0x87, 0x81, 0x07, 0x39, 0xAB, + 0x5D, 0x4F, 0x38, 0x73, 0x20, 0xAB, 0xC3, 0x99, 0x51, 0x9F, + 0x84, 0x1A, 0x41, 0xA8, 0x59, 0xB9, 0xB9, 0x97, 0x93, 0x71, + 0x13, 0x4E, 0xB7, 0x27, 0xB2, 0x59, 0xC9, 0x53, 0xE3, 0xAC, + 0xB7, 0x02, 0xB2, 0x8C, 0x82, 0xEF, 0xBF, 0x08, 0x4D, 0x9D, + 0x64, 0x44, 0x4C, 0xBD, 0x41, 0xAD, 0x41, 0x3C, 0x8A, 0xAA, + 0x89, 0xDA, 0x8B, 0x20, 0x95, 0x43, 0x8A, 0x16, 0x2A, 0x45, + 0x2D, 0x91, 0xD0, 0x4A, 0x3C, 0xD9, 0xD1, 0x2E, 0x93, 0xCE, + 0x34, 0x13, 0xAC, 0x58, 0x7E, 0xBF, 0xAF, 0xB9, 0x86, 0x35, + 0xCA, 0x43, 0x8A, 0xD6, 0x98, 0x59, 0xDC, 0x13, 0xF5, 0xC5, + 0x6B, 0x19, 0x70, 0x7A, 0xEC, 0x13, 0xB1, 0x83, 0xC9, 0x95, + 0xEC, 0x86, 0x4F, 0x6E, 0x91, 0x70, 0x44, 0xC9, 0x8A, 0xBE, + 0x89, 0x70, 0xFE, 0x8E, 0x1D, 0x2D, 0x89, 0x26, 0xA1, 0x1E, + 0x9F, 0x43, 0xB1, 0x57, 0x20, 0xD8, 0x61, 0x4E, 0x3D, 0x57, + 0xFD, 0xC3, 0x98, 0x17, 0x63, 0xDB, 0x74, 0x42, 0xA8, 0x77, + 0x69, 0xFA, 0x58, 0x5D, 0xCC, 0xC0, 0x05, 0x6C, 0x26, 0x3C, + 0xC7, 0x5E, 0xE9, 0xE6, 0xEC, 0x84, 0xE1, 0xB8, 0x17, 0x1C, + 0xA7, 0x8A, 0x0D, 0x96, 0xAA, 0x9B, 0xC4, 0x03, 0xE7, 0xAA, + 0x8F, 0x85, 0x22, 0x9C, 0xF8, 0xC9, 0x2B, 0x96, 0x01, 0xAD, + 0xF5, 0x69, 0x3E, 0x4F, 0xB7, 0x95, 0x3A, 0x22, 0x55, 0xCA, + 0xFE, 0x0C, 0x29, 0xDB, 0xEC, 0x15, 0xD0, 0x8B, 0xCE, 0xC1, + 0x5B, 0xC7, 0x49, 0x00, 0xC2, 0xE6, 0x5A, 0x54, 0x9F, 0xDC, + 0xB1, 0x72, 0x16, 0x1C, 0xCC, 0x33, 0x3E, 0x4C, 0x57, 0x49, + 0xF5, 0x74, 0x33, 0x7A, 0xB3, 0xD1, 0xFA, 0x1F, 0x9A, 0xDE, + 0x77, 0x53, 0x48, 0xAB, 0xAB, 0x7B, 0xB6, 0x18, 0x64, 0x8C, + 0x51, 0xBD, 0xFD, 0x79, 0x46, 0x6E, 0xE4, 0x4E, 0x2C, 0xC2, + 0xC6, 0x3C, 0xC4, 0x3B, 0x7B, 0x92, 0x94, 0x2D, 0xC7, 0xAB, + 0x80, 0x25, 0x91, 0x5F, 0x64, 0x67, 0x2E, 0xFE, 0xC1, 0xCD, + 0xFD, 0xA1, 0x86, 0x56, 0x98, 0xE8, 0x9E, 0xF6, 0x01, 0xB6, + 0xF0, 0xCE, 0xCA, 0x9C, 0xE8, 0x9D, 0x51, 0xA4, 0x69, 0x4E, + 0x48, 0x9E, 0x3A, 0x07, 0x06, 0xB7, 0x12, 0x5B, 0x15, 0x57, + 0x9B, 0x81, 0xF6, 0x6C, 0x15, 0xEE, 0x73, 0x60, 0x10, 0xFE, + 0x87, 0x49, 0x79, 0xCF, 0xAB, 0x0C, 0xA1, 0x66, 0x63, 0x60, + 0x80, 0x4E, 0x94, 0x60, 0x41, 0x80, 0x74, 0xE0, 0xAE, 0x66, + 0x2C, 0x7C, 0x29, 0x0B, 0x51, 0xAC, 0x98, 0xD6, 0x27, 0xF1, + 0xCC, 0xE6, 0x6C, 0xC7, 0xD2, 0x7E, 0xB7, 0xB7, 0x5B, 0x44, + 0xCC, 0x47, 0xB0, 0x02, 0x50, 0x7B, 0x84, 0xD3, 0x74, 0xD0, + 0xD2, 0x26, 0xD2, 0x90, 0x70, 0x21, 0xC1, 0x88, 0x62, 0x03, + 0xE0, 0xCF, 0x9C, 0xCD, 0x7A, 0xC5, 0x2A, 0x06, 0x96, 0xF1, + 0xC6, 0x97, 0x95, 0xC5, 0xB0, 0x8A, 0xF3, 0x91, 0x44, 0x58, + 0x43, 0x4C, 0x57, 0x3C, 0x94, 0x29, 0xF3, 0x8E, 0x12, 0x2A, + 0x4A, 0x32, 0xB4, 0x01, 0x56, 0x70, 0x82, 0x8C, 0x2E, 0x75, + 0x4A, 0xB3, 0xC2, 0xAC, 0xFA, 0x3E, 0x8F, 0xB0, 0xFA, 0xA1, + 0x30, 0xF0, 0x75, 0x37, 0xFD, 0x2A, 0xAE, 0x8F, 0x51, 0xA0, + 0xFF, 0x5F, 0x48, 0x55, 0xD0, 0xA0, 0x8D, 0xFC, 0xB8, 0xFD, + 0xDD, 0xCE, 0x80, 0x15, 0x90, 0xF1, 0x4C, 0x73, 0xEA, 0x4E, + 0xEF, 0x4B, 0x09, 0x1D, 0x89, 0x19, 0xA4, 0xE6, 0xB9, 0xAB, + 0x22, 0x14, 0x73, 0x3D, 0x7E, 0x33, 0x99, 0x9A, 0xD9, 0x80, + 0xF7, 0x88, 0x77, 0x90, 0xE5, 0x4E, 0x37, 0x56, 0x06, 0xEA, + 0x94, 0x63, 0xB5, 0x44, 0xB4, 0xF4, 0xCF, 0x1F, 0x2C, 0x95, + 0x07, 0xBF, 0x1C, 0x72, 0x0C, 0x44, 0x51, 0xF3, 0x47, 0x9A, + 0xCC, 0x27, 0xE0, 0x76, 0xA8, 0x2C, 0xE5, 0x81, 0xAD, 0x78, + 0xEF, 0x73, 0x09, 0xE4, 0x70, 0xDC, 0x67, 0x55, 0x73, 0xA3, + 0x34, 0x92, 0x0E, 0xD1, 0xD2, 0x7D, 0x2D, 0x25, 0x5C, 0x93, + 0xAE, 0xB4, 0x0E, 0xF4, 0x38, 0x74, 0xB4, 0x47, 0x3D, 0xF8, + 0x9D, 0xE5, 0xE1, 0x37, 0x6F, 0xA8, 0x43, 0xDE, 0x6D, 0x24, + 0x8F, 0xD9, 0xF6, 0x91, 0xCF, 0xAD, 0x39, 0xE0, 0x39, 0x36, + 0x34, 0x05, 0x06, 0x0C, 0x7B, 0x2B, 0xC6, 0x97, 0xD6, 0x87, + 0x34, 0xF9, 0x95, 0x91, 0x93, 0x5A, 0x4F, 0xFD, 0x69, 0x30, + 0x65, 0xEF, 0xCB, 0x08, 0xFF, 0x33, 0xE9, 0x8C, 0xD6, 0x3F, + 0xB4, 0x6A, 0xE1, 0xB1, 0xF6, 0x49, 0xE2, 0x2F, 0x95, 0xAF, + 0x0C, 0xF9, 0xB5, 0xE3, 0xF0, 0xFB, 0x41, 0x57, 0x74, 0xA1, + 0x24, 0x59, 0x99, 0x6B, 0x3D, 0xB3, 0xD0, 0x12, 0x17, 0x33, + 0xC1, 0x1E, 0x7E, 0x07, 0xFA, 0xD7, 0x09, 0x82, 0xE0, 0x91, + 0xD7, 0x60, 0x4B, 0xCE, 0xB1, 0xC5, 0xD3, 0x98, 0x5B, 0x97, + 0xBB, 0x7F, 0x83, 0xC8, 0x12, 0x48, 0x44, 0x68, 0xF9, 0xA4, + 0xE9, 0xBB, 0x25, 0x46, 0xA8, 0x2F, 0x28, 0x92, 0x94, 0xBA, + 0x74, 0xC4, 0x7A, 0xDA, 0xBD, 0xFB, 0x62, 0xD8, 0x8F, 0x01, + 0x14, 0x6C, 0x7C, 0x1C, 0x21, 0x9A, 0xFD, 0x4F, 0x91, 0x71, + 0x99, 0xEA, 0x39, 0xB5, 0xB8, 0x26, 0xA2, 0xEC, 0x06, 0x18, + 0x50, 0xE5, 0x13, 0xD1, 0x7D, 0x56, 0x6B, 0x3D, 0x90, 0x97, + 0x0A, 0x0C, 0x9B, 0xEF, 0xFA, 0x4D, 0xA4, 0x07, 0xF0, 0x9A, + 0x8A, 0xAE, 0x7C, 0x30, 0x46, 0x49, 0xE0, 0x93, 0xFD, 0x4D, + 0xB3, 0xAA, 0xF5, 0x72, 0x05, 0xE8, 0xBA, 0x39, 0x3F, 0x9C, + 0xCB, 0x0C, 0x0A, 0x44, 0x07, 0xA8, 0x32, 0x32, 0xBC, 0xF2, + 0x88, 0xB8, 0x1A, 0x3C, 0xC1, 0x84, 0x47, 0x3F, 0xE9, 0xBF, + 0x32, 0x7A, 0x01, 0xEF, 0x46, 0xF5, 0x0D, 0x7A, 0x91, 0x12, + 0x66, 0x5B, 0x0B, 0xEC, 0x48, 0xE3, 0xC5, 0x42, 0x78, 0xA9, + 0x85, 0x8C, 0x43, 0x03, 0x05, 0x8D, 0xC7, 0x7E, 0xCC, 0x14, + 0xEF, 0xC8, 0x36, 0xEA, 0x04, 0x39, 0x17, 0x1C, 0x67, 0x9E, + 0x78, 0x84, 0x8C, 0xA3, 0x00, 0x00, 0x6D, 0xB5, 0x44, 0x7C, + 0xFE, 0xFC, 0x22, 0x0F, 0x0D, 0x23, 0x0E, 0x41, 0x4B, 0xEB, + 0x76, 0xDB, 0x66, 0x54, 0x7C, 0x73, 0x79, 0x52, 0x47, 0x4A, + 0xC9, 0x03, 0xC5, 0xFA, 0x56, 0xE5, 0x28, 0x63, 0x1B, 0xC6, + 0x74, 0x60, 0x84, 0x4E, 0x3F, 0x85, 0x1A, 0x76, 0x84, 0xAF, + 0xEB, 0x54, 0x28, 0xAD, 0x99, 0xFE, 0xC8, 0x7C, 0x4A, 0x3D, + 0x3E, 0x8C, 0xDE, 0xD5, 0xFA, 0x46, 0x9C, 0x9A, 0x10, 0xC2, + 0x68, 0x74, 0x74, 0x4C, 0x26, 0x21, 0xE6, 0xDA, 0xEE, 0x8D, + 0xD3, 0x0F, 0x6A, 0x4B, 0xF9, 0x64, 0xE9, 0x80, 0x29, 0xA6, + 0xB5, 0xC7, 0xD4, 0x3F, 0x59, 0xC1, 0x4F, 0x76, 0x22, 0xF1, + 0x5B, 0x37, 0x80, 0xF8, 0x56, 0x2E, 0x8C, 0x7A, 0xA2, 0xC7, + 0xF8, 0xB1, 0x37, 0xF6, 0x44, 0x9A, 0xC6, 0x46, 0xD4, 0xA9, + 0x17, 0xC3, 0xD6, 0xCB, 0x5D, 0xBA, 0x29, 0x41, 0xDF, 0xCD, + 0x00, 0x0D, 0xCE, 0x67, 0xD6, 0x33, 0x31, 0x90, 0xEC, 0xAE, + 0x45, 0x01, 0x14, 0x0D, 0xAB, 0x21, 0x59, 0x1D, 0xD5, 0xD6, + 0xF7, 0x5A, 0x80, 0xDC, 0x16, 0x57, 0xBC, 0x28, 0xBB, 0x40, + 0x16, 0x81, 0xD4, 0xBF, 0x88, 0xAD, 0x04, 0x8F, 0x87, 0x4A, + 0xE5, 0xA1, 0xBE, 0x0F, 0x99, 0xE5, 0xD3, 0xCA, 0x6D, 0xD6, + 0x71, 0xFF, 0x33, 0xB0, 0x2E, 0x89, 0x51, 0xD4, 0x3D, 0x03, + 0x10, 0x78, 0x4E, 0x94, 0x22, 0x86, 0x5E, 0x6E, 0xB6, 0xCB, + 0x1B, 0x38, 0x56, 0x84, 0xBA, 0xFA, 0x19, 0x90, 0x74, 0x7A, + 0x93, 0xC2, 0x3C, 0xDA, 0x3B, 0x81, 0xA8, 0x5E, 0x23, 0x25, + 0xBE, 0x05, 0xC4, 0x06, 0xB7, 0x90, 0xF1, 0xE2, 0x8E, 0x3C, + 0x21, 0x18, 0xFE, 0xE5, 0x57, 0x3F, 0x26, 0x6F, 0x82, 0x8E, + 0xAF, 0x5D, 0x0D, 0xE4, 0xB7, 0xE8, 0x27, 0xD4, 0xEB, 0x42, + 0xD3, 0x59, 0xBF, 0xAF, 0xCB, 0x10, 0xE3, 0x17, 0x80, 0x03, + 0x30, 0x80, 0x5A, 0x10, 0x58, 0xBB, 0xCB, 0x93, 0x0E, 0x67, + 0x2B, 0x3E, 0x3E, 0x87, 0x13, 0xD4, 0x32, 0xF5, 0x7A, 0xD4, + 0x98, 0xB2, 0xA3, 0xAC, 0x64, 0x93, 0x3B, 0x3D, 0xCA, 0x7F, + 0x2B, 0x6E, 0x7A, 0xA1, 0xA1, 0xF8, 0x96, 0x23, 0x8E, 0x81, + 0x39, 0x25, 0x4C, 0xE0, 0x45, 0x65, 0x37, 0x2F, 0x8D, 0x4A, + 0x80, 0xEB, 0xB0, 0x90, 0xB4, 0xBF, 0xE7, 0x4B, 0x0E, 0x36, + 0xC3, 0x1E, 0x65, 0xA9, 0x47, 0xBB, 0x2F, 0x95, 0x20, 0xCC, + 0x88, 0x9F, 0x0E, 0x65, 0x45, 0xA0, 0x13, 0x28, 0xE0, 0x5E, + 0x7E, 0x7E, 0x86, 0x4A, 0x8D, 0x33, 0xDB, 0xB2, 0xF2, 0x0F, + 0x86, 0xCB, 0x24, 0xD0, 0x04, 0xFA, 0x6E, 0xBE, 0x92, 0xEC, + 0x36, 0x3E, 0xA2, 0x35, 0x42, 0x57, 0x9A, 0xAE, 0x8A, 0xE5, + 0x98, 0xAF, 0x24, 0x9C, 0xFF, 0x79, 0x9A, 0x98, 0xD6, 0xDF, + 0xDA, 0x56, 0x5C, 0x4B, 0xC7, 0x74, 0xA8, 0x15, 0x06, 0xAF, + 0xAB, 0x00, 0x52, 0x85, 0x91, 0xDE, 0xE0, 0x48, 0x43, 0x82, + 0xFF, 0xD9, 0xD9, 0x3D, 0x18, 0x89, 0x85, 0xAA, 0xED, 0xBF, + 0xD6, 0x2B, 0xB4, 0xC0, 0x31, 0xA4, 0x85, 0x56, 0x26, 0x56, + 0x3E, 0x69, 0x50, 0x37, 0x27, 0x7C, 0xF3, 0x6B, 0x3C, 0xC6, + 0xBD, 0x26, 0xF9, 0xDE, 0x56, 0xE5, 0x3A, 0x26, 0xAE, 0xA4, + 0xE7, 0x39, 0xAD, 0xDB, 0x4C, 0x67, 0x49, 0x92, 0x09, 0x23, + 0x5E, 0xAF, 0x81, 0x4E, 0x59, 0xB2, 0xA8, 0x8E, 0x1E, 0xCE, + 0x3F, 0x28, 0x4F, 0x92, 0x8B, 0xFC, 0x62, 0xDE, 0xCF, 0x9D, + 0x2B, 0x32, 0x61, 0x6C, 0x46, 0x14, 0x8C, 0xA7, 0xB2, 0xF0, + 0xF3, 0x35, 0x4F, 0xBC, 0x1B, 0x8F, 0xE0, 0x60, 0xF2, 0x25, + 0x32, 0x61, 0x75, 0xBC, 0xBB, 0xE1, 0x58, 0x5F, 0x5F, 0xBA, + 0x43, 0x9D, 0xC4, 0x7D, 0xCD, 0xD9, 0xBD, 0x75, 0x02, 0x8D, + 0x0F, 0x6F, 0xEA, 0x5A, 0x76, 0x0D, 0xFC, 0xA3, 0xE0, 0xF4, + 0x7E, 0x50, 0x60, 0xAC, 0x7C, 0xED, 0x77, 0x51, 0x94, 0xCA, + 0xAB, 0xA0, 0x8E, 0xB2, 0x27, 0xFB, 0x31, 0x8A, 0x03, 0x85, + 0x8C, 0x0F, 0xC7, 0x99, 0xC6, 0xCB, 0x56, 0xCF, 0xAD, 0xBD, + 0xBE, 0xEE, 0xF1, 0xB0, 0xA4, 0x15, 0x14, 0x24, 0x68, 0xAC, + 0x10, 0x11, 0xD9, 0xF5, 0x39, 0xA9, 0x85, 0x21, 0x94, 0x5E, + 0x22, 0x04, 0x0D, 0x2C, 0xB5, 0x44, 0x56, 0x6B, 0x12, 0xDB, + 0xBB, 0x64, 0x2E, 0xAD, 0xB9, 0x6E, 0x45, 0xE1, 0xE6, 0x4D, + 0xE3, 0x7B, 0x39, 0x51, 0xAE, 0xCE, 0xB7, 0x75, 0x84, 0x46, + 0xB8, 0x54, 0xFB, 0xDA, 0x28, 0x04, 0xEE, 0xF3, 0x51, 0x54, + 0x2D, 0xC1, 0x84, 0x0C, 0xEB, 0xC1, 0x21, 0xAE, 0xA8, 0xAB, + 0xFE, 0x2A, 0x05, 0x18, 0x63, 0x27, 0xFB, 0x7B, 0xF7, 0x91, + 0xF9, 0x99, 0xA2, 0xC3, 0x19, 0x9E, 0xF3, 0xE8, 0x5C, 0xBA, + 0xB8, 0xA1, 0x4E, 0x2F, 0xD3, 0x6C, 0x17, 0x4B, 0x3B, 0xFD, + 0xEF, 0x76, 0x34, 0x3C, 0x27, 0x37, 0x06, 0x49, 0x6E, 0xC3, + 0x67, 0x91, 0xEC, 0x48, 0x35, 0x1C, 0xC3, 0x95, 0xF7, 0x2B, + 0xA5, 0x06, 0xDE, 0x88, 0x7A, 0x48, 0x72, 0xD3, 0xF7, 0x5D, + 0x7F, 0x44, 0x57, 0x04, 0x6A, 0x22, 0x75, 0xCD, 0xDF, 0x6A, + 0x99, 0xF5, 0xD1, 0xBB, 0xD5, 0x74, 0x30, 0xDB, 0x34, 0x18, + 0x49, 0xB1, 0xA0, 0x15, 0xB4, 0xE0, 0x39, 0x3B, 0x7A, 0x47, + 0xF6, 0xAC, 0xA6, 0x63, 0x34, 0x3A, 0x43, 0xAC, 0xE2, 0xF2, + 0xAE, 0xF6, 0xB3, 0xE5, 0x7F, 0x58, 0x3F, 0x36, 0x44, 0x6D, + 0xD2, 0xC9, 0xE3, 0x87, 0x86, 0x90, 0xB0, 0xEA, 0x01, 0x3D, + 0x4F, 0x1A, 0xCE, 0x5D, 0x00, 0x3A, 0xFE, 0xB5, 0xEF, 0x99, + 0x83, 0xFB, 0x87, 0xA5, 0x0E, 0x52, 0x8C, 0xBF, 0x6E, 0x76, + 0x65, 0xB6, 0xF4, 0xCD, 0x89, 0x29, 0x6C, 0x84, 0x05, 0x4D, + 0x38, 0xD4, 0xBB, 0x17, 0x6F, 0x27, 0x32, 0x96, 0x95, 0x30, + 0xDA, 0x7A, 0xE2, 0x26, 0x38, 0x27, 0x1E, 0x5B, 0xB8, 0xF6, + 0xA9, 0x53, 0x9D, 0xA6, 0x66, 0x13, 0x34, 0x79, 0xD5, 0xF4, + 0xBB, 0x01, 0xBB, 0x60, 0x8C, 0x73, 0xE7, 0x20, 0xCA, 0xFC, + 0x59, 0xCC, 0x16, 0x51, 0x41, 0x33, 0xB7, 0x95, 0x0E, 0xA2, + 0xA6, 0xE0, 0x02, 0x7F, 0x54, 0x6B, 0xDC, 0x50, 0x62, 0xAF, + 0x73, 0x38, 0x4B, 0xD5, 0xE8, 0xC6, 0xB6, 0x28, 0x2A, 0x4B, + 0x9C, 0x29, 0x11, 0xDF, 0xE9, 0x58, 0x2C, 0xE7, 0x4C, 0x0C, + 0x12, 0xC6, 0x03, 0xAA, 0x77, 0xF0, 0xF6, 0xFF, 0x39, 0xE4, + 0x1A, 0x13, 0x60, 0x0C, 0x7F, 0x8F, 0xF5, 0xA1, 0x6B, 0x37, + 0x64, 0xE5, 0x01, 0x01, 0x7B, 0x2C, 0x77, 0x9B, 0xA3, 0x52, + 0xF3, 0xC0, 0x25, 0xBD, 0x06, 0xDE, 0xA1, 0x5D, 0xA9, 0x88, + 0xC2, 0xF8, 0x32, 0x2B, 0x42, 0x01, 0xD5, 0x45, 0xE1, 0x16, + 0xD3, 0x7A, 0x35, 0x5F, 0x6F, 0xC5, 0x89, 0x52, 0x19, 0xE4, + 0xEC, 0x87, 0x75, 0x6D, 0x38, 0xA6, 0x96, 0xE7, 0xB9, 0x1F, + 0x3B, 0x93, 0x06, 0x0A, 0x9C, 0x16, 0xFA, 0x36, 0xDA, 0x09, + 0x7C, 0x1E, 0x1B, 0x67, 0xB9, 0xD2, 0xA6, 0x3D, 0x0A, 0xF7, + 0xE7, 0x77, 0x69, 0x87, 0x29, 0x7B, 0xDA, 0xD1, 0x4F, 0x4A, + 0x62, 0x64, 0xBE, 0x1D, 0xFE, 0xF4, 0x75, 0xBE, 0x03, 0xCF, + 0x2D, 0xF2, 0x85, 0x11, 0x66, 0xD3, 0xEC, 0x62, 0x42, 0x4D, + 0x10, 0x9D, 0x9B, 0x79, 0x50, 0xCD, 0x52, 0x5F, 0xBB, 0x5D, + 0xD2, 0xB8, 0xB6, 0xDE, 0x33, 0xEA, 0x77, 0x70, 0xE5, 0x20, + 0x13, 0xEE, 0x96, 0xAA, 0xA9, 0x73, 0xB3, 0x16, 0x71, 0xF5, + 0xB9, 0xE4, 0xEE, 0x8B, 0x19, 0x6F, 0xC0, 0x46, 0xF7, 0x24, + 0xBD, 0x84, 0xE3, 0x67, 0x1A, 0x33, 0xB3, 0x61, 0x61, 0x28, + 0x15, 0xAE, 0x6B, 0x39, 0x31, 0x87, 0xCA, 0x52, 0xE3, 0x04, + 0x4A, 0xD8, 0x9A, 0xCF, 0x25, 0xF5, 0xDF, 0xA2, 0xF0, 0x28, + 0x15, 0x6F, 0x6E, 0x8D, 0x7D, 0x90, 0x4B, 0x81, 0x0B, 0xB1, + 0x8D, 0x0E, 0xC7, 0xA8, 0xF0, 0xEA, 0xE0, 0x33, 0x25, 0x3D, + 0x0B, 0xAC, 0xB3, 0x04, 0x40, 0xFF, 0x74, 0x70, 0xCC, 0x69, + 0x92, 0xB1, 0x01, 0xEC, 0x2B, 0xCA, 0x4B, 0x60, 0x8F, 0x20, + 0x6C, 0xAB, 0xF0, 0x05, 0x47, 0x68, 0xF4, 0xCA, 0x1D, 0xFF, + 0x66, 0x4C, 0xE4, 0xDC, 0x7F, 0xFB, 0xE5, 0xAB, 0x2E, 0x1A, + 0xB9, 0x40, 0xC5, 0x45, 0xB5, 0x68, 0xC2, 0x3A, 0x16, 0x89, + 0xD3, 0x12, 0xB3, 0x96, 0xFE, 0x92, 0x4D, 0x2B, 0x4B, 0x4D, + 0x6C, 0x12, 0xC7, 0x15, 0xA2, 0x22, 0x61, 0xEF, 0x16, 0x7A, + 0x5A, 0x6C, 0x44, 0xAF, 0x08, 0x7B, 0xCD, 0xBD, 0xA6, 0x83, + 0x7D, 0x98, 0xA6, 0x79, 0x55, 0x9A, 0x05, 0xC3, 0x4B, 0x4F, + 0x93, 0x90, 0x1E, 0x2C, 0x9E, 0x91, 0x8A, 0xAA, 0xD4, 0x41, + 0x8C, 0x2A, 0x54, 0x0F, 0x28, 0x09, 0x2A, 0xE9, 0xBC, 0x60, + 0x5A, 0x5E, 0x09, 0xBA, 0x8E, 0x26, 0xBA, 0x52, 0x84, 0xFD, + 0x33, 0x96, 0x65, 0xF3, 0x0B, 0xCF, 0x01, 0xE7, 0xFE, 0x00, + 0x48, 0xE5, 0x52, 0x69, 0x31, 0xF5, 0xC7, 0x62, 0x4D, 0xE2, + 0x28, 0x54, 0x7B, 0x1E, 0x5D, 0xD2, 0x32, 0x41, 0xB2, 0xC8, + 0x33, 0xF9, 0x5D, 0xE5, 0xCE, 0xA0, 0xD5, 0x81, 0xE9, 0xCC, + 0xB1, 0x32, 0x68, 0x79, 0x7A, 0xA8, 0xD7, 0xDB, 0x4F, 0xE8, + 0x91, 0x4C, 0x81, 0x4D, 0xE3, 0xDD, 0x11, 0x5B, 0x0F, 0x24, + 0xD7, 0x1A, 0xCB, 0xAC, 0xDF, 0x75, 0x7F, 0x16, 0xE4, 0xDA, + 0x64, 0x5C, 0x4F, 0xE8, 0xA2, 0x38, 0x6D, 0xF7, 0xB9, 0xA8, + 0xFC, 0xE9, 0xB7, 0x63, 0x90, 0xB3, 0x21, 0x65, 0x63, 0x08, + 0xA4, 0x5E, 0x06, 0xD2, 0xFE, 0x84, 0x0C, 0xDA, 0xCE, 0x4F, + 0x57, 0x17, 0x85, 0x5C, 0x3F, 0x16, 0x05, 0x2B, 0x66, 0x1A, + 0x5F, 0xFB, 0x33, 0x23, 0xC4, 0x3B, 0x67, 0x8C, 0x44, 0x76, + 0x98, 0x92, 0x24, 0xBC, 0xE8, 0x57, 0x0C, 0x6F, 0x50, 0x4B, + 0xCE, 0x97, 0x6A, 0x18, 0x71, 0x52, 0x71, 0xF4, 0x5A, 0x11, + 0x39, 0x5D, 0x61, 0xA6, 0x0D, 0xB8, 0xDC, 0xEC, 0x7A, 0x1B, + 0x7E, 0xDB, 0x7C, 0xEF, 0xAF, 0xD6, 0x2C, 0xCF, 0x6E, 0xE3, + 0x23, 0xE3, 0x6A, 0xB2, 0xA7, 0xD0, 0x2B, 0x56, 0xFC, 0x0A, + 0xE0, 0xE0, 0xA5, 0x34, 0x15, 0xA2, 0xA1, 0x13, 0xFD, 0xDA, + 0x6D, 0xBC, 0x6B, 0xD4, 0xBE, 0x45, 0xC3, 0xFA, 0x28, 0x4C, + 0xFF, 0xB7, 0xA6, 0xD7, 0x7A, 0xAB, 0x09, 0xA5, 0x4A, 0x19, + 0x67, 0xA0, 0x82, 0x25, 0x6A, 0x63, 0x1B, 0x53, 0x2D, 0x7D, + 0x11, 0x7C, 0xCE, 0x45, 0xFF, 0xAD, 0x1F, 0x11, 0x78, 0x8C, + 0xBC, 0x2F, 0x44, 0x7F, 0x86, 0x18, 0xF5, 0x11, 0x8D, 0x1A, + 0x51, 0xC3, 0xDA, 0x80, 0xCB, 0x8D, 0x27, 0x79, 0xDD, 0x13, + 0x79, 0xFD, 0x66, 0x5A, 0x4A, 0x77, 0x18, 0xF6, 0x08, 0xC0, + 0xFC, 0x50, 0xE3, 0x8A, 0x0E, 0xC6, 0x83, 0x02, 0x75, 0x89, + 0x6C, 0xAB, 0x02, 0xA1, 0x27, 0x45, 0xA1, 0xBA, 0xCD, 0xF8, + 0x75, 0xBD, 0xC0, 0x33, 0x5A, 0x9A, 0xE4, 0x2F, 0xC3, 0xA1, + 0xAE, 0x88, 0x1E, 0xF1, 0x1B, 0xD2, 0x2D, 0xB3, 0x96, 0x85, + 0x54, 0xAD, 0x3B, 0x72, 0x44, 0x12, 0x0A, 0xA8, 0x16, 0xE9, + 0xD5, 0x71, 0xEE, 0x45, 0x1D, 0x8C, 0xC7, 0x27, 0xE5, 0x96, + 0x0E, 0x48, 0x71, 0x09, 0x38, 0xE9, 0xAE, 0x57, 0x58, 0x05, + 0x53, 0x35, 0xB5, 0xA8, 0xBF, 0xAD, 0x91, 0xFA, 0x6D, 0xBE, + 0x7F, 0x6A, 0xAE, 0xFF, 0x35, 0xF7, 0xB6, 0x64, 0x54, 0x59, + 0x5C, 0xC4, 0xEC, 0x3C, 0x46, 0x82, 0xB0, 0x37, 0xA7, 0x5A, + 0x95, 0x4C, 0x22, 0x84, 0xF6, 0xD3, 0x08, 0x41, 0x31, 0xB9, + 0xCD, 0xFB, 0x3F, 0x42, 0x01, 0xFB, 0x97, 0xF0, 0x4D, 0xE5, + 0x8D, 0x15, 0x20, 0xE6, 0x6E, 0xC8, 0xB0, 0x5D, 0xD6, 0xCF, + 0xAB, 0x26, 0x46, 0xB4, 0x86, 0xEF, 0xEF, 0xC1, 0xC0, 0x70, + 0x3E, 0xED, 0x04, 0xBC, 0x89, 0xFF, 0xF3, 0x6E, 0x17, 0x1C, + 0x54, 0x01, 0x6C, 0xB9, 0xC2, 0x73, 0xCC, 0x40, 0xB2, 0x95, + 0xAF, 0xBB, 0xD8, 0xB8, 0x50, 0xAC, 0x7F, 0xB9, 0xEA, 0xF1, + 0x97, 0xE0, 0x75, 0x63, 0x71, 0x6E, 0x63, 0xA8, 0x65, 0xC1, + 0x7D, 0xE0, 0x81, 0x46, 0xE4, 0xF8, 0xD0, 0x55, 0xD7, 0xA8, + 0xAA, 0x07, 0x6E, 0xF9, 0xF8, 0x0D, 0x78, 0xF9, 0x4B, 0x7B, + 0x18, 0x66, 0xE0, 0x81, 0xE7, 0xCB, 0xAC, 0x1E, 0x85, 0x5A, + 0xE9, 0xDB, 0x96, 0xFE, 0xF3, 0x49, 0x62, 0xDE, 0xBF, 0x96, + 0x13, 0xE4, 0xF0, 0x4A, 0x51, 0x7A, 0xA5, 0xE0, 0x5F, 0x5B, + 0x26, 0x13, 0x56, 0xC9, 0x39, 0x08, 0x10, 0x72, 0x82, 0xF1, + 0xA0, 0xED, 0x91, 0x81, 0xA8, 0x5B, 0xE6, 0x54, 0xF5, 0x54, + 0x7F, 0xCE, 0x75, 0x90, 0xEA, 0x7B, 0xF3, 0xEC, 0x3A, 0xF3, + 0x38, 0x59, 0x95, 0x0F, 0x53, 0x36, 0x74, 0x8B, 0x82, 0xA0, + 0x5B, 0xED, 0x2E, 0xE0, 0x75, 0x0E, 0x94, 0x96, 0x5B, 0xD0, + 0x39, 0x5A, 0x0F, 0x65, 0x83, 0x44, 0x52, 0xC9, 0x95, 0x5F, + 0xBD, 0x08, 0xE4, 0x61, 0x0B, 0x28, 0xE0, 0x70, 0xAF, 0xD1, + 0x22, 0xA6, 0xEE, 0x24, 0x33, 0xCA, 0x76, 0xEB, 0x99, 0xF7, + 0x51, 0x32, 0xB5, 0x18, 0xE0, 0x5C, 0x7A, 0xEA, 0xB0, 0xD2, + 0x7B, 0x3D, 0x1A, 0x61, 0x95, 0xDB, 0x0F, 0x9E, 0x7A, 0x14, + 0x45, 0xD8, 0xF1, 0x0D, 0xA7, 0x24, 0xF0, 0xB8, 0x09, 0x82, + 0x8D, 0x39, 0xFE, 0xDA, 0x4A, 0x8F, 0x12, 0xC3, 0xD3, 0x71, + 0xC9, 0x2E, 0x22, 0x6E, 0x79, 0x39, 0x70, 0x29, 0x00, 0x2E, + 0x48, 0x49, 0xD7, 0x90, 0xD2, 0x02, 0x5D, 0xF9, 0x6E, 0x47, + 0x3A, 0xC6, 0x37, 0x66, 0x82, 0xFE, 0xFA, 0xC2, 0x0C, 0xD4, + 0x24, 0x1E, 0x52, 0x95, 0x4D, 0x7F, 0xE3, 0xBB, 0xC4, 0x16, + 0xA3, 0x7D, 0x8B, 0x67, 0xC0, 0x2E, 0xF1, 0xF2, 0x61, 0x48, + 0x9B, 0x4A, 0x52, 0xE0, 0xE8, 0x04, 0x74, 0x44, 0xDC, 0xEA, + 0xA5, 0x0F, 0x73, 0x7A, 0x26, 0xCF, 0xE7, 0x91, 0x39, 0xCC, + 0x66, 0x06, 0xD9, 0x91, 0xCA, 0xC4, 0x5E, 0x1E, 0x88, 0x3A, + 0x93, 0x98, 0xDF, 0x47, 0x1E, 0x32, 0xC7, 0x99, 0x9D, 0x57, + 0x23, 0xAC, 0x28, 0x84, 0xA7, 0x78, 0x4D, 0xC1, 0x8F, 0x15, + 0x87, 0x21, 0xF1, 0x4C, 0xE3, 0x8B, 0xA0, 0xA5, 0x0E, 0xDD, + 0x93, 0x9E, 0x62, 0x96, 0x2C, 0xC4, 0x8B, 0x52, 0xFB, 0x9B, + 0xD7, 0xCE, 0xE0, 0x92, 0x78, 0x7C, 0xF6, 0x72, 0x46, 0xE6, + 0xD9, 0x6F, 0x92, 0x36, 0x33, 0xC7, 0x3B, 0x5E, 0x2C, 0x01, + 0x60, 0x58, 0x28, 0x1E, 0x54, 0x2E, 0xD1, 0xE8, 0x6C, 0x94, + 0x9F, 0xC6, 0xF9, 0x5C, 0x1C, 0x8B, 0x7F, 0x77, 0x85, 0x77, + 0x11, 0x7A, 0x4B, 0x53, 0x93, 0x95, 0x70, 0xF2, 0x67, 0xB6, + 0x4C, 0x5F, 0xA4, 0xFC, 0x7D, 0xFF, 0x27, 0xF5, 0x16, 0x8C, + 0x9D, 0x28, 0xDA, 0x09, 0x89, 0xC9, 0xA0, 0xE9, 0xD4, 0xF5, + 0x40, 0x99, 0x36, 0x13, 0x4C, 0x89, 0xD3, 0xF2, 0x42, 0xAC, + 0xEF, 0x5F, 0xEF, 0xBC, 0x0D, 0x53, 0xB1, 0xE2, 0xC9, 0x6E, + 0xB3, 0x71, 0xDE, 0x97, 0x6B, 0xBF, 0xAE, 0x96, 0x72, 0xC0, + 0xBF, 0x3A, 0xE7, 0xB8, 0x1F, 0xCF, 0x40, 0x69, 0xE1, 0xD6, + 0x4E, 0xFF, 0x4E, 0xE6, 0xE7, 0xAB, 0x77, 0x81, 0x75, 0x69, + 0x9D, 0xE8, 0xD3, 0x0B, 0xD4, 0x50, 0x8A, 0xFD, 0xB7, 0x1E, + 0xB6, 0x19, 0x5A, 0xE2, 0x4F, 0xD0, 0x44, 0x8A, 0xAE, 0xD4, + 0x82, 0x80, 0xCA, 0x89, 0xEA, 0x4E, 0x9B, 0x70, 0x41, 0xCD, + 0x8E, 0xA8, 0x1E, 0xBB, 0x61, 0x6A, 0xCB, 0xE3, 0xD6, 0xFC, + 0x8C, 0x8A, 0x4E, 0xED, 0x98, 0x8A, 0xED, 0x3D, 0xF9, 0x02, + 0x16, 0x93, 0x65, 0x77, 0xE3, 0x06, 0x33, 0x28, 0x8E, 0x4F, + 0x5A, 0xD9, 0xE2, 0x07, 0xEC, 0x29, 0x08, 0x53, 0x4A, 0x11, + 0xF4, 0xEB, 0x3D, 0xBC, 0x95, 0x6C, 0x6D, 0xA6, 0xD9, 0x57, + 0xA8, 0x5F, 0x9F, 0x58, 0xC7, 0x9F, 0x38, 0x18, 0x24, 0xE2, + 0x9B, 0xC8, 0x9B, 0x43, 0x94, 0x16, 0x42, 0xA4, 0x32, 0x84, + 0xD6, 0xCD, 0x1A, 0x06, 0x9B, 0xF4, 0x88, 0xBB, 0x5C, 0x11, + 0x06, 0x00, 0x1E, 0xB0, 0x0C, 0x98, 0x6E, 0xE6, 0xBD, 0xCB, + 0xF5, 0x93, 0x08, 0x1C, 0x43, 0xC9, 0xA1, 0xC9, 0x71, 0x79, + 0x29, 0x69, 0x4B, 0xE8, 0xE7, 0x9B, 0xCD, 0x62, 0x68, 0x45, + 0x24, 0xFB, 0x0E, 0x7E, 0x83, 0xA5, 0x86, 0xBB, 0xE8, 0x2D, + 0x66, 0xEB, 0x2D, 0x70, 0xF1, 0x39, 0xC9, 0x73, 0xC1, 0x01, + 0xA1, 0x68, 0x6C, 0xBE, 0x19, 0x0F, 0x47, 0xE7, 0xDB, 0x84, + 0xD7, 0x31, 0x58, 0x71, 0x21, 0x82, 0xCB, 0xE5, 0x6C, 0x52, + 0x94, 0x54, 0x0C, 0xE7, 0xF0, 0x1A, 0x3C, 0xE5, 0x83, 0xD4, + 0x4D, 0x09, 0x5B, 0x3F, 0x84, 0x19, 0xD5, 0xBB, 0xC8, 0x56, + 0xFF, 0xFB, 0xED, 0x86, 0x56, 0x79, 0x1B, 0x15, 0xE3, 0x0E, + 0x72, 0xB1, 0x93, 0xC6, 0xE5, 0x4A, 0xB7, 0x27, 0x9E, 0xC3, + 0xDE, 0x14, 0x1D, 0xAF, 0xE8, 0x3C, 0xDC, 0x52, 0xC4, 0x75, + 0xF6, 0x4E, 0xFA, 0x13, 0xAB, 0x65, 0xB6, 0x66, 0x6A, 0x5A, + 0x0D, 0x02, 0x5F, 0x0F, 0x85, 0xD7, 0x99, 0x4F, 0x3E, 0x4C, + 0xD4, 0x6D, 0xF2, 0x9D, 0x2C, 0x3B, 0xEF, 0x87, 0x1D, 0xD4, + 0x4D, 0x03, 0x08, 0x23, 0xC2, 0xBC, 0x8B, 0x74, 0x87, 0x8F, + 0x61, 0x01, 0xED, 0x98, 0x3A, 0xF0, 0x1F, 0x2A, 0x66, 0x4C, + 0x88, 0xF3, 0x57, 0x3A, 0x20, 0xB4, 0xC6, 0x6C, 0x7A, 0x1F, + 0xEF, 0x84, 0x2D, 0x11, 0xD4, 0x49, 0x4E, 0x98, 0xE1, 0xD5, + 0x4C, 0xAF, 0x17, 0x86, 0xC8, 0x64, 0x32, 0x1A, 0x4C, 0xB3, + 0x72, 0x25, 0xDD, 0x13, 0x61, 0xE9, 0x28, 0x43, 0x4D, 0x31, + 0xB9, 0x28, 0xC0, 0x53, 0x26, 0xBD, 0xA1, 0x18, 0xDC, 0x3C, + 0x8E, 0x1B, 0x9B, 0x58, 0x01, 0x1C, 0x36, 0x98, 0x50, 0x69, + 0x97, 0x1A, 0x8D, 0x56, 0xC4, 0x95, 0x2C, 0x92, 0xBB, 0x0E, + 0x72, 0xAC, 0xE8, 0xFC, 0xC2, 0x7E, 0x3C, 0x84, 0xD2, 0x28, + 0xAD, 0xDE, 0x24, 0x04, 0x22, 0x77, 0x2F, 0xE6, 0x00, 0xC6, + 0x38, 0x27, 0x08, 0x30, 0x65, 0x0A, 0xDA, 0xF6, 0xE1, 0xAC, + 0xEC, 0x45, 0x5F, 0x91, 0xE0, 0xAF, 0x0A, 0x96, 0xBA, 0x6B, + 0xF8, 0x7C, 0xF9, 0x1B, 0xBC, 0x38, 0xAB, 0x47, 0xE2, 0xA1, + 0xCA, 0x4C, 0x17, 0xEC, 0xDB, 0x86, 0x93, 0x4E, 0xE8, 0xB3, + 0x0F, 0xF6, 0xBD, 0xAA, 0xFA, 0xD6, 0x0F, 0x3E, 0xF2, 0xA8, + 0xBF, 0xCE, 0x88, 0x92, 0xEC, 0x1A, 0xCF, 0x42, 0xC6, 0x0B, + 0xCE, 0xDD, 0x37, 0x0E, 0x1B, 0x00, 0xFA, 0xFC, 0x39, 0x5A, + 0x91, 0xD2, 0x92, 0x9C, 0x63, 0xDD, 0xBB, 0x03, 0xC3, 0xC4, + 0x6D, 0x08, 0xEB, 0xC0, 0xF0, 0x1E, 0xE2, 0xBA, 0xA2, 0xB6, + 0x10, 0x02, 0x78, 0x21, 0x80, 0x56, 0xE3, 0xAC, 0xC6, 0xF0, + 0x43, 0xA8, 0x38, 0x85, 0x27, 0x63, 0x3F, 0x0C, 0x38, 0xFA, + 0x12, 0x46, 0x00, 0x74, 0xD5, 0x5E, 0xA9, 0xBD, 0xD7, 0x2E, + 0xF0, 0x7B, 0x1B, 0xEE, 0xEE, 0x5E, 0x8B, 0x08, 0xE8, 0xB5, + 0xAF, 0xB1, 0xFB, 0xA3, 0xBA, 0xAC, 0xD2, 0xFF, 0xBC, 0x12, + 0x01, 0x45, 0xE3, 0xFA, 0x7E, 0x39, 0x75, 0x3B, 0x4F, 0x1B, + 0x7A, 0x25, 0xFE, 0x52, 0x5A, 0x06, 0xBB, 0x42, 0x38, 0x34, + 0x91, 0xF6, 0xE0, 0x37, 0x97, 0xB5, 0xB1, 0x1B, 0xF4, 0xE5, + 0x6E, 0x26, 0x18, 0xE3, 0xAD, 0xAB, 0xF0, 0xD9, 0xF9, 0x86, + 0xFB, 0x73, 0x90, 0x2D, 0x43, 0x8E, 0xBA, 0xB5, 0x83, 0x6B, + 0xA6, 0xB8, 0x10, 0xCB, 0x41, 0x87, 0x8A, 0x8E, 0x67, 0xBB, + 0xA8, 0x73, 0xF6, 0xBE, 0x66, 0x13, 0x98, 0x18, 0xB5, 0x52, + 0xE2, 0x24, 0x15, 0x2E, 0xB3, 0x63, 0xFD, 0x03, 0x3B, 0x2A, + 0xDE, 0xD3, 0x1A, 0x7B, 0x90, 0x7B, 0x92, 0x9B, 0xFC, 0x1C, + 0x21, 0xB6, 0x07, 0x57, 0xBA, 0xAC, 0x43, 0xD5, 0xE5, 0x2B, + 0x64, 0x5D, 0x1A, 0xDF, 0x02, 0x52, 0x3B, 0x1B, 0x74, 0xB5, + 0xD3, 0xD8, 0xD6, 0xC7, 0xD9, 0x20, 0xD4, 0x10, 0xA5, 0xB4, + 0x2B, 0x61, 0x5E, 0xF4, 0xAF, 0x77, 0xBA, 0x34, 0x83, 0xA3, + 0x73, 0x5D, 0xFD, 0x61, 0xCD, 0x47, 0xCB, 0x8D, 0xDA, 0xF1, + 0x78, 0x6F, 0x47, 0x0C, 0x5B, 0x6C, 0x0F, 0x0D, 0x1F, 0x1E, + 0xCB, 0x27, 0x2E, 0x4F, 0x94, 0xFF, 0x51, 0x0E, 0xF0, 0x18, + 0xF3, 0x2E, 0x0B, 0x1C, 0xB8, 0x19, 0xCF, 0x7B, 0xDA, 0x59, + 0xA5, 0xAE, 0xE9, 0x38, 0x20, 0x6E, 0xDA, 0xB6, 0x04, 0x77, + 0x96, 0x38, 0x1C, 0x3B, 0x2E, 0x01, 0x28, 0x0A, 0x07, 0x4C, + 0x1E, 0x1C, 0x8A, 0x77, 0xBE, 0x3E, 0x28, 0xFB, 0xC2, 0xAE, + 0x73, 0x73, 0xC8, 0x04, 0x63, 0xE7, 0xCB, 0x73, 0x48, 0x1D, + 0x0C, 0x46, 0x04, 0x53, 0xC9, 0x84, 0xE7, 0xD4, 0x45, 0x2A, + 0x97, 0xF2, 0xC4, 0xE0, 0xB5, 0x0C, 0x17, 0x30, 0x8A, 0x33, + 0x9B, 0x07, 0xE3, 0xAB, 0xB9, 0x41, 0xAC, 0x31, 0x3C, 0xE4, + 0x4D, 0xCE, 0x07, 0xED, 0x19, 0x65, 0x9F, 0x3F, 0xC2, 0x37, + 0xA4, 0x64, 0xF0, 0xF4, 0x80, 0xDF, 0x9C, 0xCA, 0x1C, 0x5A, + 0xBA, 0xF0, 0xC1, 0x1E, 0xE1, 0xD3, 0x68, 0xE5, 0x2F, 0xE0, + 0x59, 0x68, 0xFF, 0xEC, 0x01, 0x0D, 0x5F, 0x2D, 0xAF, 0x4C, + 0x08, 0xE7, 0x69, 0x62, 0x2C, 0x62, 0x9E, 0x63, 0xAC, 0x93, + 0xDC, 0xAE, 0x93, 0x8D, 0x4B, 0x57, 0xC9, 0x35, 0x30, 0x32, + 0xD0, 0x56, 0xCB, 0x3A, 0xDB, 0x2A, 0x8E, 0x9D, 0xA2, 0xAC, + 0x84, 0x24, 0x21, 0x2F, 0x40, 0x3D, 0x4F, 0x66, 0x9F, 0x5F, + 0x83, 0x8C, 0xC6, 0x82, 0xAE, 0xE8, 0xEF, 0xAD, 0x10, 0x1C, + 0x1A, 0xA9, 0x21, 0xC9, 0x9A, 0x78, 0x49, 0x70, 0x46, 0x23, + 0x90, 0xB0, 0x6F, 0x09, 0x7C, 0xB6, 0x72, 0x8C, 0x1F, 0xC5, + 0x0F, 0x79, 0xD6, 0x96, 0x95, 0x4C, 0x7D, 0x3B, 0x91, 0xF0, + 0xA8, 0x16, 0xDF, 0x30, 0x84, 0x55, 0x65, 0xED, 0x67, 0x11, + 0x4A, 0x6B, 0x4C, 0x4F, 0x0F, 0x8C, 0x45, 0x68, 0x21, 0x34, + 0x92, 0x5E, 0xFA, 0x73, 0xC0, 0x22, 0xF5, 0x81, 0x87, 0xB7, + 0x36, 0x10, 0xF2, 0xF1, 0xCD, 0xC1, 0x76, 0xF0, 0xF2, 0x0E, + 0x9D, 0xAE, 0xA4, 0x48, 0x24, 0x1B, 0x15, 0x1E, 0x35, 0x65, + 0xDC, 0xB9, 0xBA, 0xFC, 0xA1, 0x4D, 0xBD, 0x33, 0x21, 0x1A, + 0x95, 0x5A, 0xFE, 0x04, 0x21, 0xA3, 0xF5, 0xBE, 0x2D, 0x55, + 0x39, 0x7A, 0xFF, 0x7D, 0xC2, 0xCD, 0xF0, 0x2F, 0xE8, 0x10, + 0x29, 0x76, 0xCA, 0xF5, 0xC2, 0xCA, 0xDF, 0x2B, 0x69, 0xFE, + 0xE5, 0xA8, 0x9B, 0x5B, 0xE9, 0xA7, 0xBC, 0xD7, 0x4D, 0x9B, + 0xC0, 0x46, 0x1D, 0x0B, 0x22, 0xA8, 0x96, 0x73, 0x0B, 0x5E, + 0x1A, 0x99, 0xC5, 0xB9, 0x73, 0x98, 0xB2, 0x5A, 0x71, 0xE4, + 0x32, 0x42, 0xF2, 0x52, 0x29, 0x1B, 0xA0, 0x19, 0xD4, 0x54, + 0x8A, 0x52, 0x7A, 0xE8, 0x0C, 0xA0, 0xE4, 0x3F, 0x39, 0xBB, + 0x95, 0xF5, 0xFD, 0xED, 0x5B, 0x4C, 0x11, 0xD3, 0x71, 0x9E, + 0xCE, 0x45, 0xAC, 0x18, 0xB3, 0x4C, 0x31, 0x9C, 0x1E, 0x46, + 0x90, 0xA4, 0x9F, 0x4B, 0x11, 0x0A, 0x99, 0x30, 0x4C, 0x92, + 0x65, 0x10, 0x11, 0x34, 0x41, 0xAC, 0x0E, 0x36, 0x59, 0x9C, + 0xF5, 0x75, 0x30, 0x0C, 0xD2, 0x4F, 0xE2, 0xB6, 0x1E, 0x61, + 0x39, 0xA2, 0xBC, 0x6D, 0x59, 0xC8, 0xD9, 0x2E, 0x5D, 0x93, + 0x36, 0xD2, 0xE2, 0xC5, 0x5E, 0x03, 0xCC, 0xB8, 0x9D, 0x4C, + 0x14, 0x7B, 0x21, 0xB7, 0x6B, 0xC8, 0x10, 0x23, 0x3E, 0xB3, + 0x0C, 0xE8, 0xE6, 0x39, 0x43, 0xC5, 0x22, 0x88, 0xDE, 0xB0, + 0x48, 0x46, 0x5F, 0x95, 0x6D, 0x50, 0xF6, 0x83, 0x93, 0x12, + 0xE7, 0x85, 0x3F, 0x29, 0x92, 0x54, 0x0B, 0x53, 0x41, 0xEC, + 0xB2, 0x05, 0xED, 0x75, 0x8D, 0xCA, 0x1A, 0x75, 0xF1, 0x94, + 0x61, 0x6A, 0x68, 0xAE, 0xBA, 0x56, 0x81, 0x24, 0x6C, 0xAB, + 0x72, 0x26, 0x53, 0xF0, 0x17, 0xC8, 0x7D, 0x7A, 0xAF, 0x56, + 0xD4, 0x76, 0xD0, 0x3F, 0x21, 0x1E, 0x21, 0x24, 0x15, 0x6F, + 0x78, 0x80, 0x25, 0x81, 0xB5, 0x6F, 0x70, 0xBC, 0xBF, 0x2F, + 0xF2, 0x4C, 0x04, 0xC0, 0xD1, 0xF0, 0x8A, 0x1B, 0xCC, 0xF4, + 0xF2, 0x68, 0x9A, 0x65, 0xAA, 0x1B, 0x1D, 0xF8, 0x5E, 0xC8, + 0x95, 0x21, 0x58, 0xC1, 0x30, 0xE4, 0xB5, 0xB1, 0x55, 0x42, + 0x3E, 0xD6, 0x86, 0xC8, 0xFE, 0x6E, 0x21, 0xD0, 0x8B, 0xDD, + 0x6C, 0xFB, 0x3D, 0x43, 0x10, 0x03, 0x3C, 0x41, 0xA7, 0x55, + 0xFE, 0x99, 0x4F, 0x3E, 0x70, 0xF4, 0xE7, 0xEE, 0x8A, 0xE9, + 0x0C, 0xC9, 0xEB, 0x33, 0x58, 0xF9, 0x70, 0xCA, 0x8A, 0xBD, + 0x46, 0x51, 0x3C, 0x45, 0x3B, 0x5A, 0x3C, 0xC3, 0xC6, 0xED, + 0x1E, 0x38, 0x5B, 0x07, 0xE8, 0xBE, 0x00, 0x1B, 0x7F, 0xBA, + 0xF8, 0x4E, 0x6D, 0xAB, 0x8E, 0xDC, 0x7A, 0x0F, 0x9B, 0x47, + 0x92, 0x63, 0xC4, 0x36, 0x8F, 0xD0, 0x63, 0x00, 0xB5, 0xE2, + 0xA3, 0x1B, 0xF5, 0x7A, 0xF4, 0xC2, 0x11, 0xA5, 0x75, 0x85, + 0xD4, 0x47, 0x24, 0xC7, 0x4F, 0x33, 0x51, 0x5D, 0xC9, 0xEA, + 0x3E, 0xF0, 0x0C, 0x90, 0x4B, 0x5D, 0x40, 0x7B, 0x7B, 0xF9, + 0xAE, 0x24, 0xA0, 0x79, 0xA7, 0x0A, 0x2F, 0xB8, 0x92, 0xE6, + 0x89, 0x98, 0x91, 0xB3, 0x2F, 0x11, 0x63, 0x9B, 0x1E, 0x74, + 0x62, 0x32, 0xBF, 0xB5, 0xF0, 0x0E, 0x90, 0xAC, 0x81, 0x74, + 0x89, 0xCC, 0xFF, 0xFE, 0xAA, 0x50, 0xA5, 0xDD, 0x35, 0xB0, + 0xED, 0x43, 0xC8, 0xE0, 0x20, 0x64, 0x54, 0x46, 0x54, 0x9B, + 0xCF, 0x74, 0x04, 0x97, 0x63, 0xAE, 0x8D, 0x18, 0xB1, 0xA8, + 0xB9, 0x92, 0xE2, 0xC9, 0xF2, 0x1C, 0xBA, 0x80, 0x80, 0x94, + 0xBA, 0x37, 0x6B, 0x08, 0xFB, 0x31, 0x18, 0xDD, 0x80, 0xE0, + 0xD4, 0x3D, 0x92, 0x3B, 0x6F, 0x45, 0xE8, 0x19, 0x3E, 0x2D, + 0x91, 0x32, 0x07, 0xE3, 0xBA, 0x0F, 0x72, 0x75, 0x52, 0x33, + 0x5B, 0xF5, 0x83, 0x22, 0xB9, 0xFA, 0xBC, 0x96, 0x85, 0x7F, + 0xD5, 0x3A, 0x41, 0x55, 0x75, 0xC8, 0x21, 0x95, 0x43, 0xD4, + 0xA2, 0x1F, 0xF5, 0x1D, 0x86, 0x12, 0xD0, 0xB4, 0xBA, 0x47, + 0x97, 0x32, 0x98, 0x41, 0x87, 0xA9, 0xE3, 0xE3, 0xFC, 0x63, + 0x8E, 0x52, 0x1C, 0x6E, 0x5B, 0x4A, 0x62, 0x70, 0x33, 0x62, + 0xD8, 0xA2, 0xBE, 0xD1, 0x53, 0x33, 0xFC, 0x72, 0xD3, 0x4B, + 0xE1, 0x70, 0x3B, 0xE7, 0xAE, 0x56, 0xE6, 0xDD, 0x52, 0x47, + 0xB4, 0xFC, 0x96, 0xBD, 0x44, 0x08, 0x96, 0x51, 0xB9, 0x05, + 0xBF, 0xA9, 0xB3, 0x0F, 0x5B, 0xD9, 0xE4, 0xBA, 0xF2, 0xC5, + 0x62, 0x0D, 0x2D, 0x11, 0xD4, 0xEC, 0x3F, 0x7E, 0xC9, 0x5F, + 0xB7, 0x11, 0x0A, 0xA4, 0x08, 0x96, 0x9E, 0x62, 0x43, 0xF9, + 0x01, 0x83, 0xB3, 0x09, 0x96, 0x07, 0x16, 0x1D, 0x64, 0x48, + 0xB6, 0x9E, 0x3F, 0xD6, 0x44, 0xDC, 0xC4, 0x29, 0x34, 0xBE, + 0x27, 0x89, 0x79, 0xFD, 0x8C, 0x78, 0xCD, 0x0B, 0x51, 0x8D, + 0x85, 0xB9, 0x06, 0x62, 0xAA, 0xFA, 0x9C, 0x8E, 0x53, 0x85, + 0xDA, 0xA8, 0xBA, 0xDE, 0xB7, 0x53, 0xC1, 0xAC, 0x7A, 0x29, + 0xEC, 0x0C, 0x00, 0xC0, 0x54, 0x5A, 0x3F, 0x56, 0x6C, 0x85, + 0x75, 0xA2, 0xD6, 0x24, 0xDB, 0x3C, 0x2F, 0xEB, 0x44, 0x29, + 0x2B, 0x7C, 0x31, 0x90, 0x81, 0x2E, 0xC7, 0x6C, 0xFC, 0x51, + 0x6A, 0xDA, 0xA8, 0x50, 0x89, 0x84, 0xBF, 0xBF, 0x8A, 0xD5, + 0x7C, 0x2F, 0x4D, 0x72, 0x89, 0x6D, 0x9C, 0xCB, 0x14, 0xF8, + 0x06, 0x2C, 0x2B, 0x51, 0x56, 0x50, 0x67, 0x84, 0x36, 0x00, + 0x0F, 0xD5, 0x59, 0xAC, 0xBA, 0x59, 0xD5, 0x40, 0xE7, 0xAA, + 0x3C, 0xB3, 0x0D, 0x75, 0x47, 0x74, 0x08, 0x0A, 0x46, 0x13, + 0x4E, 0xD5, 0xC8, 0x23, 0x7C, 0x1A, 0x83, 0xB3, 0xC8, 0x86, + 0x24, 0xE8, 0x10, 0xEB, 0x24, 0x03, 0x34, 0xD7, 0x5B, 0xCB, + 0xF6, 0xBC, 0x4C, 0x6E, 0x2C, 0x1E, 0x15, 0x3B, 0x9A, 0x35, + 0x15, 0x8A, 0xF6, 0x53, 0x29, 0xB9, 0xC8, 0x37, 0x18, 0xED, + 0x3B, 0x2B, 0x67, 0xC6, 0x6C, 0xC3, 0xA8, 0xC0, 0xDA, 0x27, + 0xAF, 0x0A, 0x98, 0x7A, 0x68, 0x4D, 0x0A, 0x41, 0xE7, 0xF8, + 0x40, 0xBF, 0xA7, 0x45, 0xA4, 0x8B, 0x9B, 0x3C, 0x92, 0xA7, + 0x9A, 0x76, 0xD4, 0xC3, 0xC4, 0x05, 0x1D, 0xC6, 0x79, 0x35, + 0x6C, 0x7F, 0x41, 0xC9, 0xAD, 0x97, 0x6A, 0x62, 0x21, 0xD4, + 0x2C, 0xE3, 0xBD, 0x03, 0x9D, 0x5F, 0x25, 0x9D, 0x4F, 0x60, + 0xC3, 0xE8, 0x32, 0x71, 0xFC, 0x9F, 0x20, 0x4B, 0x61, 0x91, + 0xB8, 0x25, 0xD2, 0x6E, 0x60, 0xA4, 0xDE, 0xCC, 0x8E, 0xAE, + 0x7A, 0x3C, 0xCF, 0xCB, 0x13, 0xF5, 0x38, 0x0C, 0xC1, 0xB6, + 0x91, 0x40, 0x97, 0x4B, 0x37, 0x2C, 0x16, 0xB9, 0xA1, 0xC4, + 0xFD, 0xF0, 0xF0, 0x94, 0x20, 0xFF, 0x53, 0x51, 0x06, 0x6F, + 0xBA, 0x69, 0x8E, 0x0C, 0x7C, 0x13, 0x5B, 0xCE, 0x23, 0x82, + 0x6E, 0x61, 0xEF, 0x8A, 0xB9, 0x7B, 0x17, 0x8B, 0x86, 0x91, + 0x59, 0xEB, 0xAB, 0xAC, 0x83, 0x0E, 0x8A, 0x79, 0x37, 0x5F, + 0x7D, 0x54, 0x82, 0x4F, 0x6C, 0xB2, 0xC4, 0x9C, 0x21, 0x48, + 0x62, 0x57, 0x15, 0xC2, 0x03, 0x09, 0x93, 0x96, 0xAD, 0xF0, + 0xC8, 0x60, 0xBD, 0x84, 0x2A, 0xAD, 0x1D, 0x73, 0x2A, 0x78, + 0xC3, 0x07, 0xD7, 0x3E, 0xEE, 0xB6, 0x1B, 0xF6, 0x7B, 0xA0, + 0x95, 0xAE, 0x9C, 0xAF, 0x6E, 0x1C, 0x53, 0x9C, 0x09, 0x45, + 0xE2, 0x41, 0x9A, 0x85, 0x45, 0xC1, 0xC8, 0xAE, 0x5D, 0xAB, + 0xA8, 0x57, 0x3E, 0x4A, 0xEA, 0xC8, 0x3A, 0xFE, 0x3C, 0xFA, + 0x5A, 0x80, 0x9D, 0xD1, 0xCA, 0xEF, 0xC2, 0x35, 0xF7, 0xF8, + 0x5A, 0xA0, 0xBA, 0x5A, 0xA4, 0x86, 0x3A, 0x63, 0xC5, 0xCA, + 0x56, 0xFD, 0x61, 0x10, 0xE6, 0xF1, 0xBE, 0x00, 0x83, 0x7F, + 0xA5, 0xB7, 0xC8, 0x82, 0x79, 0x2E, 0xA7, 0xE3, 0x5A, 0xFA, + 0xF4, 0x92, 0x83, 0x2F, 0x22, 0x4B, 0xC7, 0x85, 0x16, 0x37, + 0x13, 0xFC, 0xEF, 0x34, 0x7D, 0x37, 0xDD, 0xDA, 0xCD, 0x39, + 0x50, 0x41, 0x0A, 0x6B, 0xE7, 0x5C, 0xD4, 0xA3, 0x62, 0x29, + 0x99, 0xE2, 0x07, 0x04, 0xBA, 0x50, 0x4E, 0xDD, 0x60, 0x3B, + 0xF2, 0x9C, 0x3C, 0xA2, 0x59, 0x9A, 0xA0, 0xDF, 0x83, 0x1E, + 0xA2, 0x91, 0xC7, 0x4A, 0xC5, 0x04, 0xF6, 0xA5, 0x86, 0xD9, + 0x7F, 0x1F, 0x1B, 0x6F, 0x32, 0x32, 0x25, 0x1E, 0xF6, 0xF9, + 0x7D, 0x45, 0xF0, 0xAA, 0xC3, 0xB4, 0x92, 0x0C, 0xA4, 0x03, + 0xAE, 0xF5, 0x7D, 0xC9, 0xD9, 0xB4, 0x72, 0x43, 0xBA, 0x32, + 0x5C, 0xC9, 0xD3, 0x8F, 0x43, 0x74, 0x2C, 0x4C, 0x08, 0x88, + 0x4D, 0x4A, 0x79, 0x83, 0x2F, 0xDA, 0xA8, 0x84, 0xE4, 0xC9, + 0xA7, 0x19, 0x9C, 0x0A, 0x77, 0xDA, 0x1D, 0x09, 0xD3, 0x25, + 0x6A, 0x45, 0x68, 0xD1, 0xB0, 0x20, 0x77, 0x7B, 0xBC, 0xBA, + 0x6F, 0xAB, 0x70, 0x1B, 0xF4, 0x6F, 0x0A, 0x04, 0x6B, 0xD9, + 0xCE, 0xA6, 0x42, 0x61, 0x32, 0xA8, 0xD1, 0xA0, 0xE5, 0xF4, + 0xA3, 0xD7, 0x4E, 0xF7, 0x6B, 0x45, 0xE9, 0xC3, 0x60, 0x62, + 0x97, 0x81, 0x05, 0x2E, 0x18, 0xD0, 0x1D, 0xBA, 0xD6, 0x67, + 0x4D, 0x43, 0x87, 0xDE, 0xF6, 0x81, 0x89, 0xCD, 0xF3, 0x14, + 0x14, 0xA9, 0xA6, 0x0C, 0x9D, 0x46, 0x90, 0x19, 0x5D, 0x35, + 0x7E, 0x3B, 0x3D, 0x4A, 0xD1, 0x3B, 0xA0, 0x10, 0xE9, 0xE3, + 0x83, 0x99, 0x38, 0x63, 0x1F, 0x35, 0x19, 0x23, 0x73, 0xF0, + 0x12, 0x83, 0x54, 0xE3, 0xFE, 0xD4, 0x0C, 0x68, 0x8A, 0x3E, + 0xC3, 0x95, 0x37, 0x4E, 0xBF, 0xEC, 0xA5, 0xF4, 0x69, 0x58, + 0xB3, 0x58, 0x70, 0xDE, 0x27, 0x79, 0xA3, 0xBC, 0xD7, 0x07, + 0x2E, 0x7E, 0x37, 0x65, 0x88, 0x31, 0x90, 0x35, 0xDE, 0xB9, + 0xF4, 0xDA, 0x84, 0xD8, 0x1D, 0xD4, 0x67, 0x6D, 0x0B, 0xF1, + 0x63, 0x05, 0x3B, 0xC6, 0xB5, 0xF3, 0x5F, 0xB6, 0xDC, 0xB4, + 0x6F, 0x7A, 0x4B, 0x63, 0xB0, 0x0D, 0x9E, 0xC0, 0x1B, 0x02, + 0xCD, 0x2F, 0xE7, 0x75, 0x12, 0x4B, 0x0E, 0xB4, 0xFA, 0xAE, + 0x6F, 0xC2, 0x7E, 0xEE, 0xFF, 0x6D, 0x67, 0x1F, 0xFE, 0xD0, + 0x25, 0x67, 0x0E, 0x6D, 0xF0, 0xA8, 0x8B, 0x52, 0xE0, 0x4E, + 0xEB, 0x0C, 0x41, 0x4B, 0xC7, 0xC9, 0x11, 0x46, 0xED, 0xC0, + 0xFE, 0x33, 0x88, 0x81, 0x3C, 0xBE, 0x92, 0x89, 0x03, 0x18, + 0xB8, 0x0E, 0x84, 0xCE, 0x30, 0x99, 0x74, 0xF1, 0x0A, 0x22, + 0x27, 0x54, 0xCD, 0xAB, 0x45, 0x77, 0x36, 0x1D, 0x38, 0x98, + 0x05, 0x28, 0x9B, 0x56, 0xF0, 0x61, 0xEB, 0xFB, 0xD2, 0x97, + 0xD5, 0xEA, 0xBA, 0xF7, 0x2E, 0x43, 0x1E, 0x07, 0xD2, 0xA3, + 0xA3, 0xB1, 0xDA, 0xCC, 0x02, 0xFB, 0xD5, 0x36, 0xD6, 0x44, + 0xEE, 0x45, 0x86, 0x7E, 0xE2, 0xA7, 0xA7, 0x51, 0x4A, 0xF8, + 0x2D, 0xCB, 0x2D, 0x48, 0x7F, 0xC1, 0x14, 0x3B, 0x48, 0xE1, + 0xA0, 0xE4, 0xEE, 0xBC, 0x8C, 0x74, 0xB2, 0x5B, 0x29, 0x22, + 0xAF, 0x0F, 0xA0, 0x9B, 0x04, 0xB7, 0xD5, 0xFE, 0x8C, 0xB5, + 0xF7, 0xC7, 0x02, 0x3B, 0xB7, 0xAD, 0xFC, 0xBD, 0x63, 0xB9, + 0x42, 0x60, 0xB3, 0x1E, 0x84, 0xC5, 0x82, 0x65, 0xFD, 0x13, + 0x87, 0x43, 0x00, 0x7F, 0xD2, 0x29, 0x4A, 0xD6, 0x74, 0xFA, + 0x71, 0x8B, 0x86, 0x2D, 0x15, 0x5A, 0x9C, 0xC8, 0xA2, 0x27, + 0x64, 0x22, 0x0B, 0x76, 0xFE, 0x84, 0x41, 0xA2, 0x2C, 0xB4, + 0x0D, 0x35, 0x7A, 0x22, 0xD5, 0x43, 0xA9, 0x19, 0x6A, 0x2F, + 0xDB, 0x9B, 0x35, 0xE8, 0x6D, 0x80, 0x47, 0x82, 0x59, 0x0D, + 0x17, 0xC3, 0xB9, 0x41, 0xEF, 0xFA, 0x64, 0xF4, 0xC8, 0xF0, + 0x82, 0xBA, 0x8D, 0x55, 0x79, 0x9A, 0x28, 0x4A, 0x0B, 0x84, + 0x23, 0xF3, 0x8A, 0xF9, 0x42, 0xCA, 0xF1, 0x6E, 0x5B, 0xFD, + 0x4B, 0xD1, 0xB2, 0xDC, 0xDD, 0x44, 0x13, 0x1B, 0x5C, 0xF3, + 0x0A, 0x57, 0x5C, 0xC7, 0x0C, 0x11, 0x5D, 0x9B, 0x21, 0xBF, + 0x19, 0x1A, 0x9A, 0x2E, 0x95, 0x2E, 0xCC, 0x3A, 0x32, 0x00, + 0x05, 0x6F, 0xDD, 0x91, 0x02, 0x83, 0xC9, 0x88, 0x7F, 0x2E, + 0x77, 0x3C, 0x4C, 0xBE, 0xAB, 0x26, 0x0F, 0xC4, 0x1E, 0xA4, + 0x8D, 0x06, 0x8C, 0x9C, 0xA8, 0xD9, 0x75, 0xFB, 0x47, 0x75, + 0xED, 0xD1, 0xBE, 0xF4, 0xD0, 0x18, 0x92, 0xD2, 0x3E, 0x69, + 0xAC, 0xE6, 0x54, 0xD6, 0x45, 0xEA, 0xDB, 0x4D, 0x50, 0xF1, + 0x22, 0x4F, 0xCA, 0x80, 0xDB, 0x26, 0xAF, 0x87, 0x61, 0x63, + 0x29, 0x73, 0x17, 0x3D, 0x25, 0x09, 0x90, 0x9C, 0x5F, 0xDF, + 0x39, 0x02, 0x47, 0x65, 0xBA, 0xB4, 0xFD, 0xEC, 0x47, 0xCC, + 0x03, 0x42, 0xBA, 0x01, 0x91, 0xE9, 0xCE, 0x06, 0x56, 0x4D, + 0x34, 0xB0, 0x9E, 0xC1, 0x1F, 0x1E, 0xE3, 0x40, 0x6F, 0xE6, + 0x70, 0x31, 0x8A, 0x88, 0x40, 0xB4, 0xE3, 0x77, 0x37, 0x13, + 0xA8, 0x6A, 0x9A, 0x2C, 0xBF, 0xBC, 0x3D, 0x20, 0xDE, 0x6F, + 0x0E, 0x36, 0xDA, 0xBB, 0x02, 0x15, 0x26, 0xA8, 0xB8, 0x62, + 0x2B, 0xFC, 0x29, 0xF2, 0x0E, 0x15, 0xAA, 0x8A, 0x42, 0x85, + 0x6F, 0xEB, 0x95, 0xB9, 0xD6, 0x47, 0x0F, 0x41, 0x28, 0x0E, + 0x2C, 0x32, 0xB2, 0xBA, 0xB1, 0x05, 0xBE, 0x1D, 0xA7, 0xD3, + 0x2E, 0xD0, 0x9B, 0x97, 0x21, 0xF0, 0x2D, 0x94, 0x80, 0x17, + 0xA2, 0x57, 0xCF, 0x87, 0xEE, 0xE7, 0x1B, 0x3E, 0x20, 0xB3, + 0xF4, 0xEE, 0x23, 0xE1, 0xDD, 0xFD, 0x98, 0x71, 0xD9, 0x83, + 0x55, 0x9B, 0xE2, 0xCC, 0xC2, 0xF0, 0xD6, 0xCD, 0x01, 0x1E, + 0xCA, 0x88, 0xF2, 0x41, 0xE5, 0xD1, 0xD7, 0xAF, 0x55, 0xB4, + 0xC7, 0x77, 0x52, 0x4D, 0x07, 0xF4, 0x5D, 0xCE, 0x33, 0x58, + 0x63, 0xEC, 0xAC, 0xA1, 0x70, 0x8A, 0xD8, 0xAA, 0x15, 0x35, + 0x04, 0xA3, 0xD0, 0xE8, 0xBC, 0x5E, 0xF0, 0x76, 0xD3, 0x6B, + 0x30, 0x00, 0xEA, 0xF2, 0x53, 0x17, 0x59, 0xFE, 0x6E, 0x8E, + 0xA8, 0x9B, 0x4A, 0xDD, 0x4D, 0xD9, 0x69, 0x20, 0x86, 0x6F, + 0xAF, 0xC5, 0x97, 0x8D, 0xD4, 0xF0, 0xD7, 0x46, 0x2F, 0x5D, + 0x63, 0xCB, 0x82, 0x68, 0x13, 0x87, 0x40, 0x83, 0xD5, 0x1D, + 0x3F, 0x8C, 0x4F, 0x93, 0x03, 0xC5, 0x61, 0xA4, 0x1A, 0xBE, + 0x95, 0x51, 0x95, 0x06, 0xB6, 0x52, 0x2B, 0xB5, 0x20, 0xDC, + 0x44, 0x4D, 0x7A, 0x1A, 0xB2, 0xF0, 0x8A, 0x5C, 0x45, 0xE6, + 0xD8, 0x5E, 0x36, 0x33, 0x59, 0xCD, 0x8B, 0xF0, 0xA1, 0xC0, + 0xD5, 0x83, 0x84, 0xB6, 0x3E, 0x69, 0x8A, 0x2C, 0xF1, 0xF3, + 0xF6, 0xB9, 0x03, 0xB4, 0xDA, 0x52, 0x2B, 0x36, 0xEC, 0x5B, + 0x8A, 0x43, 0xAA, 0x70, 0x5B, 0x7E, 0x1A, 0x10, 0xE2, 0x5F, + 0x7D, 0x6B, 0xE2, 0xB1, 0xD5, 0xB3, 0x2F, 0x29, 0x8B, 0x7C, + 0xCE, 0xCF, 0xAE, 0x98, 0x15, 0xCC, 0x87, 0xCD, 0x28, 0x56, + 0x79, 0x24, 0xD1, 0x5B, 0xB9, 0xDF, 0xBE, 0xEE, 0x7A, 0x67, + 0x1D, 0x00, 0xED, 0xF8, 0x84, 0xE7, 0xA2, 0x3A, 0xBE, 0xB1, + 0x97, 0x79, 0xEC, 0xEA, 0x7E, 0xBF, 0x1A, 0xA2, 0x61, 0x1C, + 0x59, 0x1A, 0xCA, 0xA1, 0xAD, 0x2E, 0x36, 0x51, 0xB6, 0x7D, + 0x57, 0x05, 0x40, 0xF8, 0x86, 0x23, 0x18, 0x25, 0x65, 0x95, + 0x7D, 0x31, 0xD8, 0xD1, 0x37, 0xD7, 0x3D, 0xB7, 0x5F, 0x00, + 0xF3, 0x96, 0xF4, 0x58, 0x7B, 0x07, 0xCB, 0xA8, 0x63, 0x7B, + 0x1A, 0x84, 0xCA, 0xF4, 0x2C, 0x7E, 0x54, 0x9B, 0xF0, 0x68, + 0x1E, 0xC1, 0xE7, 0x54, 0xC8, 0x0F, 0x09, 0x88, 0xB5, 0xEF, + 0x9B, 0xF4, 0x63, 0xF6, 0x57, 0x37, 0xC8, 0xA2, 0x3C, 0x8D, + 0x8A, 0xEC, 0xCA, 0xAF, 0xA6, 0x59, 0x96, 0x00, 0xCD, 0x6A, + 0x66, 0xE9, 0x57, 0xE6, 0x0E, 0x7D, 0xA4, 0x45, 0x0A, 0x1E, + 0x66, 0xB5, 0x0E, 0x7E, 0x83, 0xFB, 0x68, 0xA0, 0x04, 0x6D, + 0xC3, 0xBA, 0xFD, 0xDB, 0x13, 0x45, 0x79, 0xFB, 0x32, 0x19, + 0x80, 0x9F, 0x79, 0xA0, 0xF3, 0x7A, 0x60, 0x89, 0xB7, 0x19, + 0x78, 0xFD, 0x23, 0x2B, 0x1B, 0x5B, 0x67, 0x6E, 0x1F, 0x32, + 0x1C, 0x16, 0x08, 0xC5, 0xB4, 0x7F, 0xB8, 0x95, 0x5B, 0x2F, + 0xDE, 0x9D, 0xFC, 0x79, 0x9B, 0x8E, 0xE8, 0x55, 0xEB, 0x94, + 0x89, 0x91, 0x58, 0xDF, 0xF3, 0x5A, 0xBE, 0x57, 0xF6, 0xFE, + 0xB7, 0xB8, 0x66, 0x99, 0x9D, 0xA9, 0x5E, 0x28, 0x37, 0xBE, + 0xA3, 0x91, 0x92, 0xE2, 0xCC, 0xF1, 0xEB, 0xCE, 0x67, 0xA3, + 0xA5, 0x37, 0xD3, 0x26, 0xD9, 0x26, 0x4B, 0xF7, 0x60, 0x0E, + 0xDD, 0x60, 0x2C, 0x9B, 0x5A, 0xBB, 0x53, 0x29, 0xBC, 0xA3, + 0x37, 0x3E, 0x62, 0xAA, 0x80, 0x3B, 0x53, 0xA1, 0x49, 0xBF, + 0x67, 0x60, 0x05, 0x95, 0x1A, 0x5C, 0xC1, 0xFB, 0xF2, 0x0C, + 0xF6, 0x35, 0x9A, 0x23, 0x8B, 0x04, 0xB2, 0x19, 0x02, 0xB0, + 0xA5, 0x27, 0xEA, 0xD4, 0xA4, 0x9E, 0x13, 0xD4, 0x6A, 0xFA, + 0x0D, 0x35, 0xC2, 0x1B, 0xD1, 0x91, 0x6E, 0xFA, 0xF2, 0x9C, + 0x80, 0x41, 0x7A, 0x16, 0x23, 0x32, 0x00, 0x4C, 0x80, 0x09, + 0x5E, 0x65, 0x5E, 0x53, 0x02, 0x7B, 0xDD, 0x84, 0x5E, 0x74, + 0xC5, 0x65, 0x79, 0x9C, 0x85, 0x57, 0x20, 0x01, 0x09, 0x24, + 0xC6, 0x80, 0x18, 0xBF, 0x6D, 0xDB, 0x30, 0x4C, 0x8B, 0xC6, + 0x10, 0xAE, 0xD5, 0x75, 0x44, 0xD8, 0x07, 0x67, 0xB4, 0xEA, + 0x99, 0x2F, 0xF7, 0xC1, 0x2E, 0x9D, 0x84, 0x1A, 0xC7, 0xF1, + 0x8C, 0x39, 0x46, 0x86, 0xC4, 0x2E, 0x72, 0x06, 0x5A, 0x87, + 0xFA, 0x05, 0xBA, 0x6D, 0x5C, 0xDF, 0x74, 0x36, 0x5D, 0xA7, + 0xC9, 0x5D, 0xD7, 0xEE, 0xDF, 0x25, 0x31, 0xD1, 0x3D, 0xFA, + 0xCD, 0xEA, 0xDD, 0xFF, 0x8A, 0x35, 0x33, 0x3D, 0x69, 0xD0, + 0x09, 0x55, 0xD9, 0xEA, 0x00, 0x58, 0x19, 0x04, 0xCC, 0x38, + 0xF5, 0x94, 0x13, 0x1F, 0x41, 0x77, 0xF4, 0x0C, 0x0B, 0xE4, + 0x12, 0xF3, 0xDF, 0xD0, 0xC8, 0xD8, 0x92, 0x30, 0x8E, 0xAA, + 0x3D, 0xF6, 0xE0, 0x77, 0xAE, 0x52, 0x53, 0x2F, 0x38, 0x92, + 0x71, 0x8C, 0x2F, 0x11, 0x10, 0x08, 0xDB, 0x8C, 0x53, 0xD1, + 0x58, 0xC5, 0xF6, 0x44, 0xD3, 0x2D, 0x59, 0x3A, 0x97, 0x2D, + 0xDE, 0x12, 0x87, 0xEF, 0xD6, 0x0B, 0x21, 0xFE, 0x7D, 0x1F, + 0x7C, 0x33, 0x94, 0x9A, 0xA0, 0x46, 0x95, 0x6D, 0xEE, 0x22, + 0xD3, 0x25, 0x57, 0x13, 0x88, 0x04, 0x5F, 0x76, 0x24, 0xBC, + 0x1E, 0x4B, 0xB5, 0x7C, 0xD4, 0xFF, 0x1B, 0x6E, 0x99, 0x9C, + 0x40, 0x49, 0x90, 0x6A, 0x6B, 0x52, 0x8F, 0x79, 0x2B, 0xB5, + 0xA0, 0x51, 0x14, 0x29, 0xC8, 0xFD, 0xCF, 0xFF, 0x15, 0xE7, + 0xC2, 0xD3, 0xB3, 0x37, 0xBA, 0x30, 0xC4, 0x3E, 0x32, 0xEB, + 0xE5, 0x85, 0x4B, 0x25, 0xBC, 0x76, 0x3D, 0xD8, 0x53, 0x7C, + 0x71, 0x1C, 0xDE, 0x6A, 0xD6, 0x2D, 0x32, 0x21, 0x1E, 0xAB, + 0x48, 0xA8, 0x29, 0x68, 0x58, 0xF4, 0x34, 0x8B, 0x32, 0xBE, + 0xAD, 0x40, 0x72, 0x1D, 0xD1, 0xF9, 0xE4, 0xCC, 0xF8, 0x10, + 0xFF, 0x77, 0x22, 0x48, 0x3D, 0xB7, 0x34, 0x6A, 0x4A, 0x22, + 0x75, 0x38, 0xD1, 0xB4, 0xF9, 0x09, 0xDB, 0x31, 0x48, 0x39, + 0x1E, 0x13, 0xB5, 0xF1, 0x6C, 0x44, 0x2B, 0x22, 0x51, 0xB7, + 0x4C, 0xEA, 0xD1, 0x71, 0x4D, 0x96, 0x96, 0x6C, 0x62, 0x11, + 0x78, 0x0F, 0xC9, 0xB5, 0xED, 0x4D, 0xF0, 0x6B, 0x67, 0xBD, + 0x71, 0x65, 0x66, 0x20, 0x0B, 0x92, 0xCC, 0x1E, 0x9C, 0x55, + 0xEA, 0x28, 0x7A, 0x8F, 0x51, 0x9E, 0x94, 0x59, 0x9A, 0x00, + 0x92, 0x0B, 0xB4, 0x23, 0x77, 0xC7, 0xC1, 0x43, 0x9F, 0x40, + 0x96, 0x06, 0x43, 0x59, 0xCD, 0xDD, 0x04, 0x26, 0xFD, 0xBC, + 0x96, 0x15, 0x5A, 0xE3, 0x95, 0xFB, 0xB7, 0x6D, 0x53, 0xAB, + 0xFE, 0x38, 0xA0, 0x54, 0xFE, 0x9F, 0x8C, 0x45, 0x9D, 0xEE, + 0x36, 0xB6, 0x22, 0xCF, 0x34, 0xEF, 0xED, 0xC5, 0xC1, 0x8C, + 0x5C, 0xB7, 0x78, 0xE7, 0x63, 0xDD, 0x10, 0x08, 0xC7, 0xCB, + 0xD2, 0x6C, 0xB3, 0xE5, 0xD0, 0x79, 0x6D, 0x32, 0xAD, 0xC5, + 0xF8, 0x38, 0xB2, 0x44, 0xE1, 0xAB, 0xB1, 0x82, 0xE8, 0x18, + 0xD4, 0x44, 0x63, 0xC2, 0xCD, 0x82, 0xD4, 0xB8, 0xDA, 0x3B, + 0x69, 0x36, 0x0D, 0x8B, 0x2F, 0x53, 0x9E, 0x65, 0x80, 0xBF, + 0xA2, 0x8A, 0x3B, 0x29, 0x26, 0x14, 0xC4, 0x80, 0x91, 0x97, + 0x2E, 0x13, 0x8B, 0x13, 0xAF, 0x32, 0xA5, 0x50, 0x46, 0x8D, + 0x6F, 0xCD, 0xCE, 0x30, 0x62, 0x1A, 0x17, 0xFB, 0xC9, 0x12, + 0x5E, 0x7A, 0x69, 0xE6, 0x94, 0xB1, 0x6D, 0x4F, 0xFC, 0xDD, + 0x40, 0x77, 0x20, 0x9E, 0x77, 0xFD, 0x45, 0x74, 0x91, 0x00, + 0x49, 0xFC, 0x29, 0x63, 0x68, 0x45, 0xAB, 0x33, 0x04, 0x83, + 0x85, 0xC3, 0x7D, 0x1D, 0x76, 0x77, 0xF8, 0xA7, 0x9C, 0x95, + 0x9D, 0x60, 0x04, 0x21, 0x43, 0xE9, 0x78, 0xAE, 0x94, 0xB8, + 0x7C, 0x0F, 0xB8, 0x16, 0x8F, 0x73, 0x1C, 0xF8, 0x96, 0x64, + 0xDE, 0xDA, 0x99, 0x1E, 0xF3, 0x9C, 0xC5, 0xFE, 0xB5, 0x66, + 0xCF, 0x87, 0xB6, 0x42, 0x7A, 0x1B, 0xE1, 0x51, 0xAA, 0xDC, + 0xDE, 0x1C, 0x17, 0x57, 0xB3, 0xBA, 0xCC, 0x0A, 0x20, 0x67, + 0x49, 0x8A, 0xF5, 0x09, 0x74, 0x5A, 0xAD, 0x16, 0x1B, 0xF0, + 0x40, 0x20, 0x57, 0x58, 0xE4, 0x44, 0x06, 0x66, 0x55, 0x72, + 0xFC, 0x8C, 0x36, 0x5D, 0x94, 0xEB, 0x79, 0xFD, 0x12, 0x9F, + 0x8B, 0xF2, 0xEC, 0xE4, 0xBB, 0xAE, 0x91, 0x0D, 0x78, 0x20, + 0x8C, 0xBF, 0xBC, 0x46, 0xFE, 0x36, 0x34, 0x32, 0x2A, 0x92, + 0x74, 0x9F, 0x97, 0x4B, 0x4A, 0xF6, 0xDD, 0x42, 0x21, 0xD1, + 0x75, 0xA1, 0x70, 0xF3, 0xB8, 0xCA, 0x67, 0x71, 0xCD, 0xFC, + 0xE4, 0x31, 0x7D, 0x53, 0xBD, 0xE5, 0x6F, 0xBF, 0xDB, 0xD7, + 0xBB, 0x7E, 0xE7, 0x51, 0xFE, 0x53, 0xC8, 0x66, 0xF8, 0x94, + 0xCB, 0xEE, 0x05, 0x63, 0x33, 0x18, 0x8C, 0x98, 0x09, 0x66, + 0xE1, 0x2C, 0x22, 0x09, 0x59, 0xB4, 0x9E, 0xDB, 0xD3, 0xA9, + 0x99, 0x1F, 0x53, 0x38, 0x8B, 0x2A, 0x69, 0xF9, 0xD6, 0x4E, + 0x24, 0xC8, 0x22, 0xB7, 0x4B, 0xAE, 0xCC, 0xC3, 0x69, 0x07, + 0x76, 0x31, 0x4D, 0x96, 0x10, 0x26, 0xC6, 0xF5, 0x79, 0x47, + 0xAD, 0x8E, 0xAC, 0xD0, 0x1A, 0x81, 0xC2, 0x0A, 0x4D, 0x22, + 0xF2, 0x24, 0x68, 0x3B, 0x02, 0xDF, 0x7A, 0x52, 0xEF, 0x42, + 0x7A, 0x98, 0x4B, 0x10, 0x60, 0xC7, 0xB5, 0xB6, 0x03, 0x86, + 0x71, 0x6A, 0x92, 0x25, 0x9E, 0xC5, 0x05, 0x60, 0x85, 0x2D, + 0x96, 0xA1, 0x39, 0xAF, 0x39, 0x63, 0x3A, 0xB3, 0x4F, 0x6E, + 0x5E, 0x31, 0x92, 0xDC, 0xE7, 0xE2, 0x2C, 0x1A, 0x29, 0x35, + 0x70, 0xA5, 0x13, 0x98, 0x80, 0xCE, 0x1B, 0x80, 0xCE, 0x8A, + 0xC0, 0x8D, 0xE2, 0xB1, 0x64, 0x2A, 0x30, 0x58, 0x3E, 0x64, + 0xBC, 0xE9, 0x5F, 0x3D, 0x2F, 0x9C, 0xBF, 0x74, 0x6C, 0x27, + 0x6F, 0x23, 0x8D, 0x65, 0x12, 0x9F, 0xD1, 0x8C, 0x02, 0xC5, + 0x2F, 0xFA, 0xA4, 0x2D, 0xD9, 0x41, 0xA6, 0xA4, 0x03, 0xD3, + 0x4B, 0x6E, 0xEB, 0x20, 0x90, 0x82, 0xAC, 0x5E, 0x90, 0x83, + 0x1F, 0x1F, 0x98, 0xB1, 0xC1, 0xBC, 0x6D, 0xB8, 0x83, 0x56, + 0xB7, 0x98, 0x84, 0x95, 0x76, 0x9B, 0x82, 0xED, 0x58, 0x19, + 0x7C, 0x64, 0x64, 0x78, 0x3E, 0x22, 0x61, 0xC6, 0x6C, 0x9B, + 0xB1, 0x74, 0x3C, 0xFE, 0xF7, 0xF5, 0x27, 0xE2, 0x75, 0xEB, + 0x2F, 0x10, 0x9F, 0xDC, 0x5F, 0x21, 0x2A, 0xB0, 0x5E, 0xDE, + 0xA5, 0xFF, 0x3C, 0xF4, 0x4E, 0xE8, 0xC3, 0x43, 0xF4, 0xE3, + 0x48, 0xCA, 0x76, 0x41, 0xFE, 0x5D, 0x45, 0x2A, 0x49, 0x85, + 0xEA, 0x2D, 0x38, 0x6D, 0x5E, 0x0B, 0x53, 0x6A, 0xDD, 0x40, + 0xD0, 0x51, 0xCC, 0x5C, 0xB0, 0xE6, 0xCE, 0x63, 0xB0, 0xE7, + 0x13, 0xB9, 0x8C, 0xB8, 0xF7, 0x0F, 0x4B, 0x98, 0x51, 0x40, + 0x1D, 0xCC, 0x77, 0x11, 0xE1, 0xF2, 0x39, 0x64, 0xA2, 0x26, + 0x53, 0x78, 0x31, 0x5A, 0x0A, 0xD3, 0x60, 0x6E, 0xB0, 0x47, + 0x8D, 0xD3, 0xD3, 0x38, 0x59, 0x86, 0x02, 0x3E, 0xF7, 0xD5, + 0xDF, 0x16, 0xBF, 0xFF, 0x2C, 0x79, 0xF8, 0x38, 0x5F, 0xE9, + 0x2D, 0x4E, 0xCB, 0x88, 0x62, 0x08, 0x94, 0x62, 0xD7, 0x6E, + 0x48, 0x18, 0xCF, 0x91, 0x6F, 0xBD, 0x6A, 0x64, 0x0D, 0xC0, + 0x9F, 0x11, 0xF7, 0x7E, 0x38, 0xE2, 0x5E, 0xF2, 0x32, 0xA3, + 0x7E, 0x2F, 0x10, 0xFC, 0xB7, 0xAE, 0xE4, 0xA0, 0x9D, 0xBD, + 0x54, 0x97, 0x8D, 0xD9, 0x7C, 0x99, 0x6E, 0x78, 0x75, 0x17, + 0x6E, 0x88, 0xC3, 0x48, 0x56, 0xDF, 0xD5, 0x38, 0x08, 0x40, + 0x50, 0x75, 0x39, 0xD5, 0xB1, 0x79, 0x87, 0x20, 0xB9, 0x81, + 0x27, 0xDC, 0x6F, 0xE0, 0xE7, 0x30, 0xCF, 0x72, 0x08, 0xC0, + 0x09, 0x72, 0x83, 0x49, 0x4C, 0x16, 0x3F, 0x1A, 0x90, 0x5D, + 0xC0, 0x66, 0x99, 0xA8, 0x57, 0x0E, 0x61, 0xE1, 0x0E, 0xE5, + 0xAB, 0xC1, 0xD0, 0x67, 0x01, 0xD4, 0x86, 0xE8, 0xA9, 0x08, + 0x19, 0xA7, 0x71, 0xEF, 0xA5, 0x6A, 0x80, 0xF3, 0x54, 0x6B, + 0xA1, 0x7E, 0x81, 0x54, 0xCB, 0x13, 0xF3, 0xDB, 0x30, 0xA7, + 0xF7, 0x15, 0x8F, 0xCF, 0xC6, 0x2B, 0x10, 0x96, 0x6C, 0xFF, + 0x27, 0x8D, 0x48, 0x66, 0xE3, 0x99, 0x0E, 0xE2, 0x52, 0xF8, + 0xA1, 0x64, 0xB0, 0x58, 0x7E, 0x20, 0x5B, 0xD3, 0x99, 0x82, + 0xBD, 0xCB, 0x56, 0xE7, 0x16, 0x72, 0x46, 0xA9, 0x41, 0xF9, + 0x44, 0xAD, 0x37, 0x54, 0x54, 0xFE, 0x03, 0x70, 0x71, 0x7F, + 0x61, 0x06, 0x40, 0x60, 0xF5, 0x85, 0xD8, 0xC8, 0xAD, 0x0D, + 0x9D, 0x6A, 0xB1, 0x21, 0x30, 0x88, 0xBD, 0xA4, 0xCC, 0x5A, + 0xAB, 0xAF, 0x1E, 0x44, 0xF2, 0x7A, 0xE4, 0x67, 0xD1, 0x96, + 0xE6, 0x76, 0x73, 0xC3, 0xBF, 0x86, 0x5C, 0x3A, 0x93, 0xBC, + 0x42, 0x63, 0x7C, 0x9C, 0x3C, 0xEC, 0x29, 0x61, 0xD2, 0x94, + 0xB4, 0x1A, 0xCD, 0xB8, 0x0D, 0x3F, 0x44, 0x82, 0xAC, 0xD0, + 0x78, 0xB5, 0x22, 0xDD, 0x6B, 0xB8, 0x83, 0x1A, 0x09, 0xB9, + 0x8E, 0x2A, 0xFD, 0xB4, 0x97, 0x39, 0x4C, 0xDA, 0x44, 0xE3, + 0x3A, 0x9C, 0x8D, 0x11, 0x15, 0x80, 0x9E, 0x3B, 0xBF, 0x08, + 0xCF, 0x9D, 0x01, 0x3C, 0xE3, 0xA2, 0xE5, 0x88, 0xD2, 0xF8, + 0x6B, 0xF1, 0xAC, 0x36, 0xBF, 0xF0, 0xC5, 0x6A, 0x27, 0xDD, + 0x88, 0x48, 0xD1, 0x99, 0xED, 0xC3, 0x95, 0xEC, 0x82, 0xB1, + 0x8E, 0x3D, 0x26, 0x52, 0xE0, 0xE2, 0x07, 0x83, 0x30, 0x06, + 0xC1, 0x12, 0x4E, 0xBD, 0x7B, 0xF6, 0x7A, 0x8E, 0xC8, 0xCB, + 0x13, 0x5C, 0xB4, 0x03, 0x25, 0xC4, 0xAD, 0x32, 0xE6, 0xB7, + 0x5F, 0x95, 0xB8, 0x2A, 0xE1, 0x0B, 0x38, 0x8F, 0x5F, 0x76, + 0xEA, 0x9A, 0xAF, 0x3D, 0x00, 0x91, 0xE4, 0x23, 0xD8, 0x38, + 0xE0, 0xBC, 0xB0, 0x4E, 0x10, 0xFE, 0x08, 0x56, 0x76, 0x18, + 0xB1, 0xEB, 0xE1, 0x1F, 0x33, 0x73, 0x0B, 0x77, 0xF1, 0xD7, + 0xC9, 0x03, 0x1A, 0x57, 0x14, 0x65, 0x4A, 0x5C, 0xAE, 0x3D, + 0x5A, 0x35, 0x8C, 0x9F, 0x95, 0x4F, 0x7F, 0x2D, 0x5E, 0xBA, + 0x65, 0xC3, 0xCB, 0xA3, 0xB2, 0xEB, 0x74, 0x1C, 0xD0, 0x7E, + 0xEA, 0x25, 0x56, 0x46, 0xBD, 0xA1, 0xC0, 0x39, 0x7D, 0xE1, + 0xA2, 0x56, 0xA3, 0x88, 0x22, 0xAF, 0xBB, 0x2D, 0x82, 0x63, + 0x9F, 0x5D, 0x2E, 0x0B, 0xF9, 0x0F, 0xDA, 0x33, 0x7B, 0xE4, + 0xAB, 0x05, 0x05, 0xE8, 0x9F, 0x95, 0xF0, 0x61, 0x16, 0x67, + 0x0C, 0x68, 0x4C, 0x8A, 0xA6, 0x8C, 0x29, 0x24, 0x7D, 0xDE, + 0x3D, 0xF9, 0x2C, 0x03, 0x49, 0xD6, 0x7F, 0x75, 0x47, 0x21, + 0xA1, 0xC9, 0x9A, 0xF4, 0xA5, 0x6B, 0xA2, 0xC6, 0xDE, 0x53, + 0x8E, 0x3B, 0x40, 0xE0, 0xCC, 0xBD, 0xD6, 0x49, 0xE9, 0x3D, + 0x80, 0x9B, 0x2A, 0x00, 0x02, 0x04, 0xF3, 0xE2, 0x06, 0x07, + 0x22, 0x6C, 0xB6, 0x5C, 0x0E, 0x12, 0xF3, 0x90, 0x63, 0xA0, + 0x11, 0xFD, 0xF3, 0x96, 0x76, 0x60, 0xE6, 0x89, 0xDC, 0x3E, + 0xDD, 0x0B, 0x25, 0xB1, 0xEF, 0x93, 0xA3, 0x65, 0x3B, 0x1B, + 0xC1, 0x8C, 0x83, 0xBC, 0x0A, 0x4C, 0x7D, 0x1F, 0xED, 0x05, + 0x0E, 0x93, 0xC6, 0x68, 0xB0, 0xFF, 0xF6, 0x4E, 0xDB, 0xCA, + 0xAE, 0x4B, 0xBD, 0x83, 0x5D, 0x35, 0x5A, 0x7F, 0x47, 0xB8, + 0x5D, 0xAD, 0x59, 0x04, 0x0A, 0xEC, 0x44, 0x1E, 0x4C, 0x4E, + 0xE8, 0xED, 0xBC, 0xD7, 0x56, 0x8B, 0x2F, 0x8A, 0x3C, 0xD6, + 0x03, 0xAB, 0x68, 0x1D, 0x4F, 0x52, 0x13, 0x3E, 0x02, 0x15, + 0xAA, 0xDC, 0xE1, 0xD9, 0xE7, 0x17, 0x46, 0x41, 0x4D, 0x34, + 0x59, 0xB1, 0xFF, 0x87, 0x02, 0x99, 0x78, 0x29, 0xF7, 0xCA, + 0x48, 0x59, 0xF9, 0x73, 0x8C, 0xE6, 0x27, 0xA4, 0xCB, 0x89, + 0x0B, 0x89, 0x57, 0xEF, 0x29, 0xF3, 0x53, 0x89, 0x22, 0x56, + 0x68, 0x6E, 0x5E, 0xB0, 0x99, 0x90, 0xED, 0x2C, 0x5C, 0x69, + 0xFA, 0xF5, 0x22, 0xF4, 0x62, 0xD3, 0x6F, 0x74, 0xB0, 0x25, + 0xCA, 0xF4, 0x18, 0xE3, 0xFD, 0xF1, 0xF5, 0x96, 0xEA, 0x21, + 0xC4, 0xAE, 0x34, 0x1C, 0xED, 0x4A, 0x2D, 0xBC, 0x63, 0x91, + 0xCA, 0x4D, 0x3F, 0x87, 0x9E, 0x48, 0xB3, 0x4B, 0xEA, 0x1D, + 0xCA, 0x79, 0x69, 0xA4, 0x51, 0xA7, 0xC1, 0x5B, 0x14, 0xD8, + 0x2A, 0x7C, 0x8B, 0xBD, 0xE5, 0x8D, 0xD0, 0x5C, 0x3C, 0x12, + 0x8E, 0x5D, 0x65, 0x64, 0x5D, 0x0B, 0x50, 0xEA, 0xB0, 0x86, + 0x27, 0xD6, 0xC3, 0x19, 0x79, 0x1F, 0xFC, 0x95, 0xD1, 0x0B, + 0xE6, 0xAB, 0xB8, 0x3D, 0x0C, 0xA9, 0x76, 0xF9, 0xAA, 0x1B, + 0x7C, 0xC4, 0x3A, 0xD1, 0x43, 0x5E, 0x7F, 0xA0, 0xCA, 0x50, + 0x2D, 0xC9, 0x05, 0x5A, 0x8D, 0xED, 0x55, 0x99, 0xC6, 0xB0, + 0x38, 0x56, 0xB2, 0xE9, 0x83, 0x47, 0xBB, 0x6D, 0x4B, 0x8B, + 0xD7, 0x27, 0x71, 0xA2, 0xB3, 0xA3, 0x9B, 0xBE, 0x9D, 0xEF, + 0x70, 0x8E, 0x04, 0x2F, 0x64, 0x9B, 0xB9, 0xA9, 0xAF, 0x4A, + 0xA4, 0xCA, 0x2F, 0x46, 0xEC, 0xD4, 0xE4, 0x8D, 0x55, 0x2F, + 0xA0, 0x77, 0x4D, 0x35, 0x95, 0x75, 0xDF, 0x74, 0x6B, 0xE7, + 0xDC, 0x21, 0xC6, 0x62, 0x9C, 0xB4, 0x64, 0x4F, 0x62, 0x64, + 0xF8, 0x41, 0x99, 0x69, 0x26, 0x82, 0xBE, 0x42, 0xDD, 0x8C, + 0xDE, 0x5C, 0xB1, 0x1F, 0x93, 0x3C, 0x0A, 0x4B, 0xCA, 0xCE, + 0x8C, 0xA7, 0xFE, 0x05, 0xDD, 0x1B, 0x9C, 0x59, 0x18, 0x9B, + 0xAE, 0xB7, 0xFC, 0x31, 0x6F, 0xFF, 0x49, 0x99, 0x4C, 0x85, + 0x6E, 0xD4, 0x91, 0x01, 0xA7, 0x14, 0xFD, 0x98, 0xAE, 0x0E, + 0xA3, 0x11, 0xCC, 0x50, 0x99, 0x79, 0x02, 0xED, 0x21, 0xD2, + 0x1F, 0x86, 0xEA, 0x10, 0x29, 0x41, 0xDD, 0xCC, 0xFB, 0x6A, + 0x89, 0x8D, 0xED, 0x62, 0xB7, 0x9C, 0x82, 0x01, 0xE6, 0x8F, + 0x4C, 0xAD, 0x01, 0x6C, 0x68, 0xEB, 0x1B, 0x5A, 0xE2, 0x0B, + 0xD9, 0xB7, 0x6D, 0xB9, 0x1D, 0x93, 0x88, 0xF7, 0xE6, 0x4D, + 0xB3, 0x18, 0xB9, 0x81, 0xA0, 0x5E, 0xFA, 0xCE, 0x0A, 0xBA, + 0x4D, 0x86, 0xED, 0x11, 0x2C, 0x57, 0x23, 0x54, 0x73, 0xD9, + 0xC1, 0x67, 0x41, 0xC9, 0x4C, 0x08, 0x51, 0x99, 0xAD, 0xE0, + 0x48, 0x19, 0x27, 0x25, 0x92, 0x69, 0x38, 0x14, 0xEC, 0x02, + 0xC0, 0x28, 0x2C, 0x85, 0x6A, 0xC2, 0x10, 0x1D, 0x61, 0xA6, + 0xBB, 0x6B, 0x3F, 0x45, 0x88, 0xD1, 0xCB, 0x8A, 0x9A, 0xD4, + 0x07, 0x62, 0x7C, 0x6F, 0xA0, 0x4B, 0xFC, 0x1D, 0x98, 0x6D, + 0xCD, 0x65, 0x7A, 0x87, 0x54, 0x45, 0x4A, 0xA8, 0x0A, 0x44, + 0x44, 0xCF, 0x00, 0xFE, 0xDE, 0x78, 0x03, 0x69, 0x99, 0xA9, + 0x1F, 0xF8, 0xAE, 0xDB, 0xF2, 0xFE, 0x78, 0x08, 0x68, 0x7C, + 0x8C, 0x31, 0x31, 0x50, 0x31, 0xEB, 0x68, 0xD8, 0x15, 0xBA, + 0x23, 0x57, 0x50, 0x49, 0xFE, 0x29, 0x96, 0x53, 0x44, 0x84, + 0xE2, 0xBF, 0x0B, 0x69, 0x0B, 0xDE, 0x04, 0xC8, 0x54, 0x75, + 0x24, 0xD4, 0x9C, 0xC6, 0x66, 0xF4, 0x92, 0x5B, 0x40, 0x06, + 0x89, 0x82, 0x2B, 0x7E, 0xA4, 0x18, 0xDD, 0x25, 0x7D, 0x12, + 0x90, 0x69, 0xF0, 0x93, 0xAE, 0xD4, 0x5C, 0x23, 0xE5, 0x43, + 0xE9, 0x50, 0xCE, 0x47, 0x9E, 0xF1, 0x70, 0x92, 0xBA, 0x7E, + 0x47, 0x07, 0x44, 0x34, 0x96, 0xD2, 0x7C, 0x49, 0xE1, 0x18, + 0x77, 0x11, 0xAE, 0xBE, 0x29, 0xF0, 0xAF, 0x19, 0x25, 0xB7, + 0x10, 0x94, 0xBE, 0xA2, 0x15, 0xE1, 0xAD, 0xA8, 0x31, 0x28, + 0xA2, 0xD9, 0x41, 0xA3, 0x75, 0x4D, 0x8B, 0xCB, 0xD7, 0xA6, + 0x9B, 0x85, 0xE1, 0x16, 0xCC, 0x90, 0x6E, 0x1D, 0x9B, 0xBE, + 0x81, 0xCD, 0x4D, 0xEC, 0x94, 0x0D, 0x88, 0x7D, 0xB4, 0x5F, + 0x23, 0xDD, 0xAF, 0x28, 0xCC, 0x8F, 0x16, 0xEA, 0x5B, 0x52, + 0x73, 0x1B, 0x94, 0xF9, 0xE9, 0xAC, 0x66, 0x05, 0xC0, 0xDF, + 0x9B, 0xCF, 0x42, 0x39, 0xAD, 0xF9, 0x33, 0x7D, 0xD8, 0x53, + 0x42, 0xEC, 0xA1, 0x29, 0xA7, 0xFF, 0xAA, 0x42, 0xCB, 0xD4, + 0x74, 0x41, 0xB7, 0x6A, 0x4B, 0xCA, 0x24, 0xB2, 0x11, 0xCF, + 0x2D, 0x75, 0xA6, 0x08, 0x95, 0x3B, 0x74, 0x16, 0x69, 0x80, + 0xE2, 0xF1, 0x45, 0xDD, 0xFC, 0x7E, 0x0E, 0x12, 0x63, 0xFB, + 0x6D, 0xB4, 0xC9, 0x91, 0xD0, 0x72, 0x6F, 0x13, 0xD7, 0xCA, + 0x91, 0x70, 0x11, 0xC5, 0x17, 0x7C, 0x4C, 0xA0, 0x52, 0xF3, + 0x72, 0xDA, 0xF8, 0x8C, 0x8C, 0x02, 0x09, 0x9B, 0x93, 0xCF, + 0xB9, 0xFB, 0x8F, 0x46, 0xB1, 0xBE, 0xFA, 0xEF, 0x9D, 0x0D, + 0x2C, 0x3D, 0x5C, 0x01, 0xA5, 0x01, 0x0A, 0x96, 0x64, 0xC0, + 0xEA, 0x95, 0xE4, 0x4A, 0x26, 0x7B, 0xF2, 0x29, 0xF6, 0xC1, + 0xCA, 0xF0, 0xCA, 0x76, 0xF7, 0x4F, 0xFC, 0x36, 0xAD, 0x17, + 0x64, 0xF9, 0x87, 0x9D, 0xA6, 0x14, 0xFB, 0x6F, 0xE7, 0xDE, + 0xFC, 0x6E, 0x62, 0x14, 0x4E, 0xB2, 0x43, 0x38, 0xDD, 0xD3, + 0x62, 0x08, 0xEC, 0x69, 0xAB, 0xEA, 0x94, 0x64, 0x4E, 0xFA, + 0xD7, 0x90, 0xB8, 0x86, 0x73, 0xB0, 0x38, 0x72, 0xFF, 0x23, + 0x10, 0xCD, 0xE6, 0x4A, 0x7F, 0xDA, 0x40, 0x8D, 0x51, 0x26, + 0x02, 0x1B, 0xDD, 0x6A, 0x94, 0xA3, 0xDA, 0xBE, 0x94, 0xB5, + 0x8A, 0x7C, 0x22, 0xDA, 0x53, 0xDD, 0xC8, 0x26, 0xA9, 0x34, + 0x4A, 0x33, 0xB4, 0x68, 0x6F, 0x14, 0x53, 0xAE, 0x37, 0x3C, + 0xE4, 0xD7, 0x00, 0xA3, 0xCC, 0x48, 0xFA, 0x22, 0x89, 0x9C, + 0xDC, 0xE4, 0x33, 0x7D, 0xC4, 0xAB, 0x54, 0xB8, 0xD1, 0x39, + 0xCD, 0x08, 0xE2, 0xB2, 0xAD, 0x88, 0x7D, 0xE9, 0x6F, 0x17, + 0x61, 0x28, 0x25, 0x99, 0xAE, 0x52, 0xBC, 0x46, 0x58, 0x48, + 0xF8, 0x02, 0xDF, 0x63, 0x1B, 0x51, 0x48, 0xFA, 0x88, 0x60, + 0xE4, 0x5D, 0x84, 0x7E, 0x05, 0x8A, 0x2B, 0x0E, 0x72, 0xED, + 0x24, 0x9D, 0x8A, 0x60, 0xC8, 0x9C, 0xD9, 0xCD, 0xB3, 0xE3, + 0xC5, 0xF2, 0xC9, 0x77, 0x27, 0xE2, 0xF5, 0xBD, 0x59, 0xE7, + 0x77, 0x4D, 0x80, 0x65, 0x07, 0xF0, 0xB5, 0x1F, 0xE7, 0x2E, + 0xD3, 0x36, 0xF5, 0x28, 0xC2, 0xBB, 0x4F, 0x8B, 0x6D, 0xE6, + 0xB0, 0xDB, 0x4F, 0xEC, 0x60, 0x40, 0x39, 0xB2, 0x6D, 0x6C, + 0x4E, 0x25, 0xBE, 0x9D, 0x57, 0x63, 0x85, 0x98, 0x65, 0x8C, + 0x20, 0xBA, 0xA0, 0xCC, 0x0E, 0xEE, 0x7F, 0xCD, 0x77, 0xE5, + 0xDC, 0x58, 0xA9, 0x4C, 0xC7, 0x0E, 0x40, 0x5F, 0xDA, 0x01, + 0xD0, 0x49, 0x40, 0xCE, 0xC0, 0xAB, 0xFC, 0x11, 0xD0, 0xB5, + 0x3F, 0x0F, 0xDF, 0x2F, 0x5E, 0x8B, 0x16, 0x78, 0x4E, 0xA0, + 0x62, 0x16, 0x50, 0x9B, 0x85, 0x00, 0x71, 0x77, 0x77, 0x7B, + 0x8B, 0x15, 0xA2, 0xA9, 0x28, 0x10, 0x7D, 0x8E, 0xF1, 0x96, + 0x82, 0x43, 0xA3, 0xE8, 0x55, 0x01, 0x7C, 0x13, 0x7D, 0xFE, + 0x76, 0xA3, 0x08, 0xFF, 0x30, 0x15, 0xE4, 0xCD, 0xCD, 0x3C, + 0x14, 0x0B, 0xF4, 0x25, 0x69, 0x9D, 0x5B, 0xE0, 0x99, 0x6B, + 0xE1, 0xFA, 0x68, 0x58, 0xF7, 0x84, 0xC0, 0x2B, 0x04, 0x1F, + 0x9C, 0x95, 0x4E, 0xD2, 0xCF, 0x72, 0x16, 0x88, 0x38, 0x41, + 0x61, 0xCF, 0x3E, 0xE8, 0x42, 0x58, 0x15, 0x16, 0x0A, 0x5B, + 0x41, 0x0A, 0xC1, 0xAD, 0xA8, 0xE8, 0x6B, 0xDE, 0xFC, 0x93, + 0xF8, 0x01, 0xEC, 0x7D, 0x9A, 0x91, 0x98, 0xD1, 0x0A, 0x13, + 0xA6, 0x01, 0x34, 0xCA, 0xA9, 0x75, 0x34, 0x01, 0x5E, 0x7F, + 0xC4, 0x1F, 0xBB, 0x80, 0xBB, 0xDE, 0xF0, 0x8C, 0x60, 0xC1, + 0x1D, 0x9A, 0x51, 0xDD, 0x0B, 0xF0, 0x12, 0xBC, 0x59, 0xFC, + 0x5C, 0xC2, 0x1E, 0xA7, 0x99, 0x5C, 0xEE, 0x5D, 0xA8, 0x3F, + 0xE9, 0x93, 0x63, 0x0A, 0xBA, 0x42, 0xB1, 0xB8, 0xBC, 0x3A, + 0x03, 0xD9, 0xF6, 0xEB, 0x1A, 0x9D, 0x27, 0xFD, 0x30, 0x90, + 0x62, 0xAD, 0x9E, 0xDD, 0xB3, 0xB9, 0x02, 0x0A, 0x6B, 0x40, + 0x3E, 0x49, 0xE2, 0x75, 0xEF, 0xEE, 0x7F, 0x4E, 0xB9, 0xF0, + 0xF9, 0x7E, 0x6D, 0x41, 0xF9, 0x6E, 0x5F, 0x47, 0xBE, 0xD5, + 0xBD, 0xD8, 0x2C, 0xB5, 0x24, 0xC8, 0x20, 0x5B, 0xDF, 0x26, + 0xAC, 0x55, 0xA7, 0x00, 0x44, 0x62, 0xD6, 0x46, 0x0C, 0xE1, + 0x55, 0xB9, 0xB7, 0xDB, 0xB9, 0x31, 0x3C, 0x69, 0x75, 0x38, + 0xC4, 0xC6, 0x34, 0xFD, 0x2D, 0xE6, 0xBB, 0x5E, 0x58, 0xFE, + 0x82, 0x4B, 0x9F, 0x5D, 0xC2, 0x09, 0xEE, 0x02, 0xC0, 0x56, + 0xFB, 0x61, 0x7B, 0xAE, 0x5C, 0x5C, 0x47, 0x98, 0xCF, 0xC6, + 0xD3, 0x73, 0x4B, 0xAA, 0x8E, 0xF8, 0xEC, 0x07, 0x17, 0xBF, + 0x5D, 0xD2, 0x57, 0x82, 0x67, 0xB1, 0xDD, 0x16, 0x96, 0x5F, + 0x0B, 0xD5, 0xCB, 0x6B, 0xC8, 0x71, 0x4F, 0xBF, 0xFB, 0xFE, + 0x3A, 0xEA, 0xCF, 0xD5, 0xAA, 0xE2, 0x80, 0xD4, 0x6E, 0xD7, + 0xD1, 0x2D, 0x6C, 0x6B, 0x36, 0x6E, 0x68, 0xC9, 0x9F, 0x5D, + 0x99, 0xD8, 0x78, 0x1D, 0x2B, 0xE1, 0xE4, 0xD3, 0x40, 0xFF, + 0x9D, 0x19, 0x88, 0x19, 0x4D, 0xC7, 0x51, 0xA9, 0x83, 0x62, + 0xB5, 0x0D, 0x73, 0x28, 0xC1, 0xB8, 0xB7, 0xBC, 0xBA, 0xCD, + 0xE9, 0xA8, 0x7E, 0x81, 0x12, 0x58, 0x23, 0x3B, 0xA6, 0x16, + 0x10, 0x2E, 0x84, 0x51, 0x88, 0x80, 0xF7, 0xEF, 0xD8, 0x4B, + 0x0B, 0x2E, 0xD9, 0x3D, 0xF7, 0x7E, 0x11, 0x5F, 0xA7, 0x55, + 0xCB, 0x1A, 0xC3, 0x2A, 0x2B, 0xF6, 0xE1, 0x0F, 0x45, 0xD3, + 0xEA, 0x86, 0x39, 0x20, 0x3E, 0xF1, 0xE9, 0x55, 0xD3, 0x00, + 0xB5, 0x67, 0x7F, 0xC1, 0x3A, 0xF3, 0x83, 0xEB, 0x44, 0xD9, + 0xC5, 0x14, 0x11, 0x58, 0x0A, 0x7F, 0x6B, 0x9C, 0xC3, 0xB2, + 0xBE, 0x38, 0xD0, 0x79, 0xEA, 0x2F, 0xD6, 0x8D, 0x00, 0x58, + 0x06, 0x60, 0x14, 0xC0, 0xA5, 0x26, 0xC8, 0x50, 0x72, 0xFF, + 0x69, 0x6D, 0xE2, 0x67, 0xD1, 0xDB, 0x9E, 0x97, 0x7E, 0x5D, + 0xE5, 0x5B, 0xE3, 0x74, 0x56, 0xB1, 0x76, 0xDC, 0x88, 0xB8, + 0xF1, 0x3F, 0x22, 0xBA, 0x2C, 0x0C, 0xF9, 0xD0, 0xC8, 0x26, + 0x78, 0x7D, 0xC5, 0xDB, 0x8D, 0x55, 0x7A, 0x13, 0x4C, 0x6F, + 0x01, 0x6D, 0x06, 0x7D, 0xE3, 0x3B, 0x40, 0x45, 0x62, 0xE8, + 0x79, 0x2C, 0x71, 0xBE, 0x7C, 0x93, 0x40, 0x1A, 0x73, 0x02, + 0x31, 0x48, 0xA7, 0x1C, 0xB9, 0xBD, 0xA2, 0xCA, 0x24, 0x44, + 0x1D, 0x91, 0x40, 0x0C, 0x94, 0x7B, 0xD6, 0x6B, 0xF6, 0xA2, + 0xF1, 0x35, 0xC1, 0xB9, 0x4E, 0xF4, 0x59, 0x8E, 0xFD, 0x76, + 0xAF, 0x5D, 0x19, 0x0F, 0xBE, 0x66, 0xC7, 0xD6, 0xD1, 0xE3, + 0x5F, 0xBB, 0x04, 0x55, 0x01, 0x2E, 0x85, 0x8B, 0x15, 0x63, + 0xDD, 0x20, 0xCD, 0xB2, 0x82, 0x01, 0x4A, 0xBF, 0x72, 0x31, + 0xC5, 0xE4, 0x7F, 0x66, 0x6B, 0xDA, 0x78, 0xA5, 0xDF, 0xB2, + 0x1E, 0x87, 0x4D, 0x13, 0xD8, 0x67, 0x4F, 0x75, 0x2B, 0x10, + 0x75, 0x4E, 0xDC, 0x99, 0xCF, 0xDC, 0x8A, 0xA2, 0x94, 0xFC, + 0xB0, 0x9F, 0xCA, 0x8F, 0x20, 0x70, 0xCA, 0xD7, 0xFA, 0xF4, + 0x62, 0x54, 0x2A, 0x4F, 0xD1, 0xA3, 0xD4, 0x1F, 0xDC, 0x33, + 0x14, 0x1C, 0x9F, 0xCC, 0xD6, 0xEB, 0xA5, 0xD3, 0x98, 0x56, + 0xF1, 0xB2, 0x7A, 0xA2, 0x7F, 0xA3, 0x17, 0xB8, 0xFB, 0xC6, + 0xFA, 0x36, 0x77, 0x37, 0x29, 0xFD, 0xD2, 0xDA, 0xE6, 0xF8, + 0xCB, 0x47, 0x73, 0x31, 0xC0, 0xF4, 0x4C, 0x38, 0x29, 0xC2, + 0x49, 0x5A, 0xDF, 0x5D, 0x72, 0x76, 0xB4, 0xB6, 0xEC, 0x63, + 0x1D, 0x82, 0x3E, 0xCC, 0x99, 0x7A, 0xC5, 0xF1, 0xEA, 0x8E, + 0xB3, 0x63, 0x7A, 0xAE, 0x6B, 0x0D, 0x53, 0xD8, 0x19, 0x3C, + 0x11, 0x84, 0xCB, 0x79, 0xDF, 0xAB, 0x5B, 0xEB, 0xF1, 0x59, + 0x7A, 0x7B, 0x8D, 0x45, 0xD9, 0xE5, 0x78, 0xC4, 0x45, 0x19, + 0xB9, 0x57, 0x0A, 0x46, 0x8B, 0xC1, 0x87, 0x46, 0x39, 0x55, + 0x9A, 0x1E, 0x00, 0xD2, 0x89, 0x4F, 0xBA, 0x3C, 0x96, 0x9F, + 0x69, 0x5D, 0x35, 0xBB, 0x86, 0xC5, 0xBA, 0x57, 0xD8, 0x38, + 0x97, 0x86, 0x1E, 0x42, 0xB7, 0xD2, 0x40, 0x8C, 0x69, 0x68, + 0xA0, 0x4E, 0xD4, 0xB7, 0x2D, 0x62, 0x4B, 0x37, 0x3F, 0x97, + 0x8F, 0xA7, 0xED, 0xBC, 0xF0, 0x43, 0x89, 0xBF, 0x63, 0x20, + 0x68, 0xB2, 0xB0, 0xF2, 0x51, 0x09, 0x00, 0x50, 0x17, 0x29, + 0x78, 0x43, 0x70, 0xF6, 0x67, 0x76, 0x05, 0x59, 0x6F, 0x75, + 0x2A, 0x0E, 0xEB, 0xA7, 0xF8, 0x6E, 0x37, 0x5F, 0xA7, 0x73, + 0x33, 0x54, 0x3F, 0x05, 0x13, 0x13, 0x9E, 0x21, 0xEB, 0xB2, + 0x0C, 0x87, 0x9D, 0x86, 0xAA, 0x38, 0x28, 0xA9, 0x96, 0x44, + 0x1D, 0x65, 0x3A, 0x70, 0xFB, 0x86, 0x14, 0x5F, 0xBE, 0xD5, + 0x92, 0x9A, 0xBD, 0x83, 0x3C, 0x08, 0x5F, 0x85, 0xFA, 0x45, + 0x33, 0x56, 0x95, 0x2D, 0xAA, 0x67, 0x9B, 0x5B, 0xB2, 0x9D, + 0xEA, 0x22, 0xC5, 0x0F, 0xEC, 0x95, 0x39, 0xC2, 0xF3, 0xA2, + 0xC2, 0x64, 0x69, 0x2D, 0x03, 0x0B, 0xDE, 0x86, 0x05, 0x99, + 0x95, 0x0B, 0x2D, 0xA3, 0x77, 0x31, 0x76, 0x6C, 0x8F, 0x0A, + 0x4F, 0xF4, 0xBE, 0x8D, 0x00, 0x3B, 0x6F, 0x6B, 0xC1, 0x8C, + 0xD7, 0x1C, 0x0A, 0x75, 0x07, 0x92, 0xE7, 0xDD, 0xD0, 0xD8, + 0x71, 0x01, 0x57, 0x3E, 0x39, 0x33, 0xDF, 0x85, 0x4D, 0xEC, + 0x09, 0x05, 0xBE, 0x6A, 0x63, 0xE5, 0x66, 0xB2, 0x71, 0x0C, + 0xAD, 0xFF, 0x6F, 0xDB, 0xF5, 0xF3, 0x88, 0xE4, 0x46, 0x06, + 0x66, 0x66, 0xD0, 0x00, 0xBA, 0x9C, 0x0A, 0x47, 0x2B, 0xC5, + 0x7D, 0xD8, 0x39, 0x10, 0x59, 0x8C, 0xBB, 0xDF, 0x5B, 0x42, + 0xDA, 0xE5, 0xA4, 0xC3, 0x41, 0x77, 0xA3, 0x23, 0x86, 0xE1, + 0xB4, 0x19, 0x2F, 0x09, 0x74, 0xC9, 0x82, 0xE8, 0x85, 0xF8, + 0xDB, 0x2C, 0x64, 0xD5, 0xA9, 0x6F, 0x66, 0x02, 0x27, 0x2D, + 0x20, 0xAD, 0x8C, 0xCF, 0xA8, 0xBD, 0x97, 0x07, 0x86, 0x71, + 0xA3, 0xC4, 0x3A, 0x4B, 0xEB, 0x29, 0xD0, 0xBC, 0x8E, 0x01, + 0x75, 0xE6, 0x16, 0xF4, 0x28, 0x42, 0xFE, 0xD7, 0x2A, 0x97, + 0xE1, 0xBF, 0xD3, 0xE5, 0x24, 0x9A, 0x73, 0x27, 0xD1, 0x68, + 0x18, 0x39, 0xAC, 0xAB, 0xE0, 0x17, 0xE7, 0x8E, 0x4D, 0x5D, + 0x3A, 0x79, 0x39, 0x04, 0xDF, 0x3B, 0xC7, 0x09, 0x07, 0xDE, + 0x64, 0x9E, 0x22, 0xCD, 0x20, 0x1B, 0xC1, 0x74, 0x1A, 0x28, + 0x84, 0x95, 0x1B, 0x75, 0xCB, 0xEF, 0x0F, 0xC7, 0xCC, 0xAF, + 0x45, 0xA3, 0xF3, 0x0B, 0x58, 0x31, 0x0E, 0x68, 0x7E, 0xA5, + 0xFD, 0xD7, 0x4B, 0xFC, 0xE0, 0xDB, 0x0C, 0x0D, 0x13, 0x07, + 0x65, 0x95, 0xB7, 0xD9, 0x55, 0xFC, 0x9A, 0xFC, 0x53, 0x82, + 0x01, 0x47, 0xB9, 0xFA, 0x0C, 0x3A, 0x3D, 0x36, 0xA5, 0x56, + 0x87, 0xA9, 0x1E, 0xAB, 0x08, 0x61, 0x8A, 0xD0, 0x31, 0x2B, + 0x28, 0x31, 0xFB, 0xD1, 0x39, 0x2F, 0x00, 0x82, 0x6C, 0x24, + 0x54, 0xD1, 0x9E, 0x8F, 0x25, 0x6B, 0x5D, 0x07, 0xA4, 0x8D, + 0x0B, 0x32, 0x81, 0x3B, 0x2C, 0xFC, 0x0D, 0xC4, 0xC9, 0xFB, + 0x15, 0xD8, 0xAA, 0x40, 0x36, 0xEE, 0x69, 0xDF, 0x2D, 0x2A, + 0xAD, 0xE1, 0x0D, 0xE2, 0xDC, 0xF1, 0x0F, 0xAA, 0xEA, 0x04, + 0xCE, 0x93, 0x6B, 0x6E, 0x6D, 0xF0, 0x7A, 0x3A, 0x8C, 0x92, + 0x73, 0xCB, 0x60, 0xE9, 0xAC, 0x4C, 0xD0, 0x10, 0x1D, 0x07, + 0x76, 0xFB, 0x97, 0x0D, 0xD9, 0xEE, 0xA3, 0x50, 0x78, 0xB9, + 0xC9, 0xF6, 0x1B, 0x82, 0x82, 0x8C, 0x87, 0xAE, 0x3F, 0x65, + 0xBA, 0xD8, 0x72, 0x27, 0x3D, 0xD7, 0x73, 0xAC, 0x99, 0xCE, + 0x93, 0xAE, 0xA8, 0xEC, 0xEC, 0xB6, 0x8F, 0x4F, 0xEE, 0x90, + 0x09, 0x35, 0x72, 0x68, 0x24, 0xEA, 0x68, 0xC9, 0xC4, 0x66, + 0x9E, 0x39, 0xBD, 0xF6, 0xF2, 0x93, 0xC9, 0xE8, 0x98, 0x61, + 0x8C, 0x89, 0x29, 0x95, 0x90, 0x2C, 0x0C, 0x7F, 0x1E, 0xF9, + 0x85, 0xDB, 0x64, 0x39, 0xC0, 0x43, 0x85, 0x70, 0x0C, 0x18, + 0x0A, 0x3D, 0xE5, 0x66, 0xE5, 0x5E, 0xB7, 0xA3, 0xD0, 0x17, + 0x60, 0x25, 0x19, 0x6C, 0x4B, 0xBD, 0x8F, 0x78, 0x85, 0xFE, + 0xB9, 0x43, 0xE5, 0x69, 0x1A, 0x7F, 0x4A, 0xDF, 0xD4, 0x44, + 0x37, 0x42, 0x3E, 0xBC, 0xD3, 0x7E, 0x12, 0xEF, 0x46, 0x22, + 0xD9, 0x53, 0x80, 0xA6, 0x77, 0x8F, 0x60, 0x15, 0xE7, 0x46, + 0xA2, 0x14, 0x5C, 0xBA, 0xF3, 0xBD, 0x87, 0x3D, 0x8F, 0x23, + 0xF3, 0xD5, 0x56, 0x6D, 0x26, 0xCD, 0x83, 0x90, 0x62, 0x13, + 0x97, 0xE6, 0x7F, 0x18, 0xFC, 0x94, 0x54, 0x70, 0x56, 0x00, + 0xD0, 0x5C, 0x25, 0x76, 0x4A, 0xA9, 0xBD, 0xA4, 0x98, 0x45, + 0x57, 0xDD, 0x66, 0x0D, 0x51, 0xDC, 0xC3, 0xEE, 0xD2, 0x94, + 0x74, 0xBE, 0x26, 0xF0, 0x08, 0x73, 0x1D, 0x59, 0x34, 0x2E, + 0x33, 0x6B, 0x62, 0xEC, 0x14, 0x70, 0x93, 0xC3, 0xC8, 0x9E, + 0x3A, 0x3C, 0x4A, 0x52, 0x0F, 0xE8, 0xA8, 0x37, 0x2A, 0x22, + 0x7C, 0x69, 0xF1, 0xA2, 0xBF, 0x2F, 0xF0, 0x08, 0x35, 0x2E, + 0x6F, 0x5D, 0x2F, 0x89, 0xED, 0x9F, 0x23, 0x13, 0x96, 0x11, + 0xA3, 0x1D, 0x77, 0x98, 0xBE, 0xE7, 0x1F, 0x21, 0xA6, 0x8A, + 0xD4, 0x41, 0x49, 0x92, 0x25, 0xA2, 0x38, 0x32, 0xED, 0x7D, + 0xA8, 0x45, 0x41, 0x2F, 0x9F, 0x4D, 0xA8, 0xBA, 0xAA, 0x79, + 0x3F, 0xDD, 0x9A, 0x75, 0x30, 0x1C, 0x85, 0x1A, 0x31, 0x55, + 0x76, 0xE4, 0xB4, 0xF9, 0x2F, 0x76, 0x35, 0xC2, 0xC3, 0xE8, + 0xAF, 0xAD, 0xB6, 0x0C, 0x19, 0xA2, 0xA8, 0xC2, 0x61, 0x3A, + 0x25, 0x31, 0xF1, 0xFB, 0x12, 0xA0, 0x09, 0x86, 0xB5, 0x48, + 0x02, 0x03, 0xE8, 0x94, 0xA6, 0xAE, 0x1F, 0x4F, 0x1C, 0xD6, + 0x68, 0xCF, 0x87, 0xAC, 0xC3, 0xF4, 0x08, 0x19, 0xC3, 0x6E, + 0x46, 0x4A, 0x04, 0x4C, 0xBB, 0x6F, 0x9B, 0xED, 0xF4, 0xE1, + 0x01, 0x5A, 0x17, 0xA4, 0xBE, 0x9C, 0xFC, 0xB4, 0x55, 0x66, + 0x13, 0x57, 0x2A, 0xCE, 0x9D, 0xCB, 0xC2, 0x97, 0xA1, 0x26, + 0xA5, 0x2B, 0x08, 0x46, 0x78, 0xAF, 0x16, 0xA0, 0xF1, 0xC1, + 0x1C, 0x61, 0x88, 0x6B, 0x19, 0xF5, 0x01, 0xA9, 0x4B, 0x17, + 0x6E, 0xFE, 0x5A, 0x3B, 0x3A, 0xFF, 0x8D, 0x42, 0xC4, 0xC7, + 0xEE, 0xF8, 0x22, 0x61, 0x3D, 0xDB, 0xCB, 0xE8, 0x9F, 0xDF, + 0x3D, 0x3E, 0x17, 0x51, 0x61, 0x5B, 0x38, 0xED, 0x38, 0x46, + 0xF4, 0x84, 0x77, 0x53, 0x3D, 0xB9, 0x2C, 0xD1, 0x7B, 0xF4, + 0xA0, 0xEF, 0xD1, 0x73, 0x7E, 0x38, 0x89, 0xEB, 0xE2, 0xD9, + 0xDD, 0x8A, 0x6F, 0x37, 0xC4, 0xB8, 0x46, 0xD7, 0x85, 0xAA, + 0x0E, 0x98, 0xCC, 0xA4, 0x96, 0xF8, 0xD8, 0x76, 0x48, 0x25, + 0xDC, 0x33, 0xF5, 0x95, 0x8B, 0x45, 0xC6, 0x43, 0x6E, 0xF6, + 0x6C, 0x3C, 0xA0, 0xD4, 0xB4, 0x4F, 0x92, 0x8B, 0xE4, 0xFC, + 0x29, 0x82, 0x95, 0x56, 0x3C, 0x2A, 0x2A, 0x9F, 0x5A, 0x02, + 0x1F, 0x12, 0xFD, 0x20, 0x07, 0x75, 0xD6, 0xC7, 0x40, 0x12, + 0xC5, 0x7C, 0xBA, 0xD2, 0x16, 0xEE, 0xD4, 0x95, 0x42, 0x45, + 0xE9, 0xB0, 0x0B, 0x93, 0x41, 0x97, 0x64, 0x8B, 0x91, 0x09, + 0xDC, 0xD9, 0xD8, 0x8E, 0xF2, 0x54, 0xC7, 0x55, 0x0F, 0x94, + 0x3D, 0xCE, 0x41, 0x57, 0x33, 0x25, 0x41, 0x3C, 0x71, 0x86, + 0x6D, 0x90, 0x79, 0x5E, 0x10, 0x4C, 0x19, 0x47, 0xB3, 0xA3, + 0xA0, 0x5C, 0xD3, 0xFA, 0x4C, 0x42, 0x5E, 0x90, 0xD2, 0xDD, + 0x7E, 0x16, 0x5E, 0x13, 0xF8, 0xAB, 0x3D, 0xDD, 0x61, 0x10, + 0x84, 0x69, 0x92, 0xC1, 0x16, 0x38, 0xFD, 0x8C, 0xFB, 0x4A, + 0x6F, 0x07, 0xCB, 0x4A, 0x58, 0x53, 0xBD, 0x14, 0x8B, 0x88, + 0x6E, 0x72, 0xD7, 0x6D, 0x03, 0xB4, 0x9E, 0x5B, 0xF4, 0xFF, + 0x63, 0x46, 0x79, 0xAF, 0xDC, 0x50, 0xE6, 0x3F, 0x4E, 0x72, + 0xCC, 0x64, 0x32, 0x55, 0xBE, 0x4E, 0xFC, 0xC2, 0x28, 0x53, + 0xD0, 0x0C, 0xF5, 0x2B, 0x7A, 0x48, 0xEF, 0x1A, 0x1E, 0xA2, + 0x52, 0xC9, 0x3E, 0x74, 0x37, 0xB2, 0x78, 0xA7, 0xDB, 0xEF, + 0x4C, 0x9E, 0xE6, 0x57, 0xFB, 0x1E, 0x14, 0x78, 0x90, 0x7E, + 0x79, 0x69, 0x13, 0xB9, 0xD2, 0xCC, 0x3B, 0x48, 0xAF, 0x6F, + 0x6E, 0xD2, 0x14, 0x4F, 0xC7, 0xEB, 0x38, 0x9D, 0x29, 0x0F, + 0xEB, 0x2A, 0xC3, 0x2A, 0xBF, 0x40, 0x85, 0x48, 0x90, 0xBF, + 0xF7, 0xBF, 0xD3, 0x59, 0x72, 0x3E, 0x42, 0x43, 0x01, 0x5A, + 0x19, 0xE8, 0xFF, 0xE9, 0x97, 0x05, 0x63, 0x05, 0x19, 0xEF, + 0x85, 0xCB, 0x53, 0x6B, 0xD4, 0x0B, 0xD8, 0xD3, 0x78, 0x48, + 0xCF, 0x57, 0xE1, 0x4A, 0xA0, 0x88, 0xAA, 0xA8, 0x77, 0x16, + 0xD5, 0x4F, 0x44, 0x6B, 0xAC, 0xEB, 0xBA, 0xA9, 0x84, 0xB5, + 0x4E, 0xAB, 0x23, 0xAA, 0xB0, 0xB1, 0xB5, 0xA2, 0x83, 0x99, + 0x92, 0x8E, 0x22, 0x51, 0x97, 0xC8, 0xDA, 0xBB, 0xB9, 0xF0, + 0xBD, 0x32, 0x60, 0x14, 0xF4, 0xED, 0x34, 0x1C, 0x90, 0x67, + 0x94, 0x61, 0x7E, 0xB5, 0xA6, 0x42, 0x4C, 0x49, 0x99, 0x6F, + 0x4B, 0x29, 0xA4, 0xA2, 0x71, 0xC6, 0xB2, 0x9C, 0xFB, 0xA0, + 0x77, 0xA1, 0x7E, 0xBF, 0xDA, 0xC1, 0xED, 0x5D, 0x26, 0x5F, + 0x55, 0xC8, 0x98, 0x16, 0xD1, 0xC2, 0x1C, 0x50, 0x69, 0x2C, + 0x62, 0xF5, 0x9A, 0x32, 0x9F, 0x62, 0xC2, 0xE8, 0x55, 0x1B, + 0x52, 0xB6, 0x8D, 0x72, 0xDC, 0x3F, 0x9E, 0xB1, 0xD6, 0x7B, + 0xC3, 0x67, 0xC6, 0xF3, 0x2F, 0xC0, 0x93, 0xDD, 0x5E, 0xE0, + 0x9B, 0xAF, 0x71, 0x98, 0x8D, 0xF1, 0xF8, 0x92, 0xAE, 0xDA, + 0xDD, 0xC3, 0x45, 0x2E, 0xEA, 0x43, 0x90, 0x9C, 0xBF, 0x57, + 0x48, 0xC7, 0x20, 0x6D, 0xDA, 0xFF, 0xE1, 0xDC, 0x88, 0x76, + 0xAE, 0x1C, 0xB8, 0xF6, 0xFE, 0xD0, 0xCA, 0xF4, 0x2C, 0xC0, + 0xF5, 0xE5, 0xF3, 0x1C, 0x57, 0x97, 0xDD, 0x35, 0x9C, 0xCB, + 0xCC, 0x45, 0x60, 0xDE, 0xD2, 0xD3, 0xA4, 0x2A, 0x22, 0x8E, + 0xFD, 0xAB, 0x5E, 0x6E, 0x9A, 0x47, 0x78, 0xEB, 0xFC, 0x44, + 0x15, 0x90, 0x9F, 0xEA, 0x8E, 0x8E, 0x8E, 0xC8, 0x5E, 0x85, + 0x48, 0xB7, 0x79, 0x38, 0x41, 0x10, 0x39, 0x45, 0x0C, 0x7E, + 0xBD, 0x7A, 0xC0, 0x35, 0x62, 0x1A, 0x2E, 0x44, 0x5E, 0x15, + 0x0E, 0x85, 0x0F, 0xCF, 0x5F, 0x32, 0xFC, 0xA7, 0x40, 0x83, + 0xB5, 0x1C, 0x73, 0x79, 0xE6, 0xCC, 0x5D, 0x87, 0x83, 0x14, + 0x5C, 0xC8, 0x49, 0x06, 0x13, 0x02, 0x8A, 0xC1, 0x99, 0x82, + 0x18, 0x1C, 0xA1, 0x66, 0xF0, 0x37, 0xF4, 0xDE, 0x15, 0x9D, + 0x6C, 0x38, 0x10, 0x9B, 0xF6, 0x72, 0x59, 0x04, 0xDE, 0x2C, + 0x8B, 0xC8, 0x68, 0xF5, 0x84, 0xD6, 0x40, 0xA2, 0xF9, 0x0D, + 0x3E, 0xC3, 0xBA, 0x9A, 0xC3, 0x70, 0xF3, 0x19, 0x4B, 0x3D, + 0x76, 0xFE, 0xDB, 0xBB, 0xC2, 0xA8, 0x61, 0xE5, 0x78, 0x0F, + 0x7D, 0xEE, 0x1E, 0x04, 0x5C, 0x40, 0x48, 0xDD, 0x20, 0xB1, + 0xB0, 0xE0, 0x43, 0x3D, 0x24, 0x8B, 0x44, 0x6D, 0xC9, 0x73, + 0x78, 0x76, 0x21, 0xAC, 0xA9, 0xF2, 0x46, 0x99, 0x0C, 0x8A, + 0xE0, 0xDE, 0x24, 0xBE, 0x29, 0x8B, 0x3E, 0x11, 0xBE, 0x2D, + 0xC6, 0xD1, 0x48, 0x57, 0x2A, 0xD1, 0xCC, 0x53, 0x23, 0x70, + 0x58, 0x47, 0x66, 0xC6, 0xEB, 0x82, 0x50, 0xAA, 0xE2, 0xEF, + 0xC2, 0x73, 0xD3, 0x7D, 0xC0, 0x3C, 0x07, 0x50, 0x53, 0x06, + 0xFB, 0x55, 0x8F, 0x0A, 0x97, 0x3E, 0xD1, 0xE5, 0x18, 0x5A, + 0x9A, 0x3B, 0xBC, 0x7B, 0x3E, 0xF6, 0x94, 0xF8, 0x1D, 0x03, + 0x13, 0x14, 0x17, 0x30, 0x02, 0x98, 0x7F, 0xDB, 0x33, 0x20, + 0x7F, 0x7F, 0x4A, 0xDF, 0x6A, 0x10, 0x94, 0x09, 0x5D, 0x30, + 0x75, 0x70, 0x45, 0xCE, 0x17, 0x01, 0x62, 0x45, 0xFF, 0x0A, + 0xF1, 0x4A, 0xDB, 0x46, 0x11, 0x5C, 0xDF, 0xDD, 0x02, 0xB0, + 0xF2, 0x28, 0xD0, 0x4E, 0x74, 0xAA, 0xC7, 0x79, 0x6B, 0xBB, + 0x9F, 0xAD, 0x2D, 0xA9, 0x20, 0x76, 0x06, 0xA9, 0xA9, 0xB1, + 0x66, 0xFE, 0xC1, 0x91, 0xDF, 0xD9, 0x19, 0xF0, 0x01, 0x0B, + 0x00, 0xF2, 0x14, 0x63, 0x7B, 0x27, 0xC5, 0x52, 0x66, 0xED, + 0xC9, 0x39, 0x3A, 0xCF, 0x52, 0xB5, 0x68, 0x6E, 0x00, 0xAC, + 0x32, 0xD0, 0x1F, 0xD5, 0x57, 0xE2, 0xD2, 0x83, 0x21, 0x69, + 0x55, 0x9D, 0xA7, 0x22, 0x7A, 0x26, 0xAF, 0x6F, 0xFA, 0xDE, + 0x8F, 0x5E, 0xE6, 0x1F, 0xA4, 0x68, 0x13, 0xF4, 0x24, 0xDD, + 0x58, 0xA7, 0x72, 0xD1, 0x14, 0x48, 0x6C, 0x7D, 0x58, 0x64, + 0x8A, 0xFE, 0x4B, 0xAD, 0x20, 0x51, 0x54, 0xB0, 0xA9, 0xCC, + 0xEA, 0xE0, 0x0E, 0x95, 0x49, 0xF6, 0x57, 0x7B, 0x65, 0xD1, + 0x1E, 0x3D, 0xB5, 0xC2, 0xDC, 0xDE, 0x72, 0x94, 0x26, 0xEB, + 0x83, 0xCD, 0xF5, 0xCD, 0x98, 0x49, 0xE2, 0x6E, 0xD0, 0x2E, + 0xA4, 0x84, 0x42, 0x86, 0xEE, 0x93, 0x48, 0x63, 0x60, 0x1E, + 0x31, 0x9B, 0x02, 0x4F, 0x13, 0x43, 0xC4, 0x5A, 0x9F, 0x58, + 0xBE, 0x9B, 0x0B, 0x27, 0xCC, 0x49, 0x19, 0x5F, 0xBF, 0x30, + 0x62, 0x8A, 0xD6, 0xCA, 0x14, 0xC7, 0x79, 0x96, 0xD1, 0x25, + 0x2B, 0x5A, 0xA3, 0x21, 0x93, 0xB6, 0xD6, 0xA2, 0xA5, 0xDF, + 0xBE, 0xB7, 0x9B, 0xBC, 0xE0, 0x68, 0x5B, 0x6B, 0xE7, 0x78, + 0x25, 0x23, 0x89, 0x97, 0x1A, 0x50, 0x7E, 0x14, 0xF0, 0x8E, + 0xBC, 0x20, 0xB4, 0xBC, 0xCB, 0x65, 0x91, 0xA7, 0xF5, 0x2B, + 0x3E, 0xCC, 0xF6, 0x80, 0xD0, 0x5D, 0xF8, 0x6F, 0xD7, 0x0E, + 0xE0, 0x4B, 0xFA, 0xE4, 0x48, 0x48, 0x54, 0xE0, 0x42, 0xD7, + 0xCD, 0x1D, 0x34, 0x45, 0x4B, 0x21, 0xD8, 0x7D, 0xE6, 0x62, + 0x29, 0x22, 0x5A, 0x40, 0x48, 0x61, 0xDC, 0x6C, 0x29, 0x16, + 0x20, 0x8B, 0xBC, 0x3E, 0x9E, 0x6A, 0x17, 0x77, 0x82, 0x6E, + 0x32, 0xD8, 0x55, 0x18, 0x12, 0x3B, 0xC1, 0x0C, 0x67, 0x7D, + 0x8A, 0xE4, 0x68, 0x2E, 0x30, 0x94, 0xC6, 0xDC, 0xF8, 0x20, + 0x98, 0x87, 0xA3, 0xC2, 0x45, 0x16, 0x40, 0x79, 0x97, 0xEB, + 0xA3, 0xE6, 0xD6, 0xA7, 0xD2, 0x2C, 0x7A, 0x42, 0xBF, 0x77, + 0x6E, 0x34, 0xDD, 0x73, 0xAF, 0x81, 0x7F, 0xAD, 0xB6, 0x58, + 0x71, 0x98, 0xB1, 0x6F, 0xE3, 0x7D, 0x2F, 0x89, 0xDB, 0x34, + 0x6F, 0x99, 0x44, 0x54, 0xC1, 0x74, 0x72, 0x3E, 0x96, 0x5A, + 0x57, 0x7C, 0xDE, 0x89, 0x56, 0x5D, 0x46, 0xBF, 0x32, 0x03, + 0x4E, 0x82, 0xCF, 0x2F, 0x30, 0xF3, 0x0B, 0xAA, 0x56, 0xAC, + 0x12, 0xBD, 0xA9, 0x5E, 0x0D, 0x4D, 0x77, 0x87, 0xBF, 0xC2, + 0x8B, 0x57, 0x97, 0x51, 0xBF, 0xE6, 0xC6, 0xD8, 0x2E, 0x7F, + 0x86, 0x4F, 0xD8, 0xE7, 0x0E, 0x26, 0x2D, 0x24, 0xFE, 0x80, + 0x9B, 0x22, 0xCB, 0xB6, 0x2D, 0xD7, 0x06, 0x08, 0x8B, 0x10, + 0x42, 0x6B, 0x64, 0x14, 0x00, 0x15, 0x02, 0xA2, 0x44, 0xA5, + 0xCA, 0x84, 0x28, 0x80, 0x88, 0xE1, 0x66, 0xC5, 0x7E, 0x4D, + 0xE1, 0x9E, 0xFB, 0x52, 0x98, 0x37, 0x6B, 0x1C, 0x38, 0xDF, + 0x9D, 0x3A, 0xD7, 0xF2, 0xE7, 0x38, 0x2D, 0x49, 0x7F, 0x7F, + 0x20, 0x9B, 0x83, 0x58, 0x04, 0x1C, 0x23, 0x4F, 0x07, 0xF1, + 0x33, 0xE9, 0x14, 0xC8, 0x83, 0xD5, 0x48, 0xBC, 0x64, 0xF5, + 0x92, 0x91, 0x7F, 0x97, 0xDF, 0xCF, 0x7C, 0x19, 0xA1, 0x1A, + 0xB0, 0x91, 0x12, 0xBD, 0xAE, 0x2D, 0x9E, 0xFF, 0x81, 0xEB, + 0x5C, 0xB9, 0xF8, 0x4E, 0x89, 0xBA, 0xA9, 0x0F, 0xA1, 0x8B, + 0x39, 0x61, 0x69, 0x58, 0x07, 0x52, 0xE0, 0x39, 0x5E, 0xB8, + 0x61, 0x95, 0x67, 0x95, 0x79, 0x91, 0x0C, 0x2B, 0xF3, 0x15, + 0xC9, 0xE8, 0xBC, 0x8A, 0x55, 0xCD, 0x5A, 0x06, 0x3A, 0xD6, + 0xA4, 0xC9, 0xFF, 0xD3, 0x96, 0x0C, 0x47, 0xB0, 0xC8, 0x8E, + 0x07, 0x8F, 0x92, 0xF4, 0x2B, 0x80, 0xB7, 0x4D, 0x72, 0x61, + 0xB2, 0x37, 0x24, 0xEC, 0x35, 0x5F, 0xC9, 0xA2, 0x48, 0xE1, + 0x47, 0xFB, 0x74, 0x4B, 0x33, 0x4D, 0xA8, 0x3F, 0x52, 0x1B, + 0xEE, 0x49, 0x72, 0x18, 0xA6, 0x43, 0x18, 0xDA, 0x70, 0xF2, + 0x54, 0x4A, 0xC5, 0x95, 0x74, 0xE6, 0x5E, 0xB4, 0xBC, 0x99, + 0x07, 0xF9, 0x91, 0x8F, 0xF6, 0xB4, 0xB0, 0x21, 0xD8, 0x8E, + 0xE6, 0x87, 0x5F, 0x90, 0x99, 0x2B, 0xF2, 0xA2, 0x1C, 0xA9, + 0x64, 0x08, 0x10, 0xA9, 0xA3, 0xA9, 0x93, 0x1F, 0x31, 0xF0, + 0xE5, 0x50, 0x30, 0xB8, 0xBC, 0x8C, 0xD9, 0x41, 0x77, 0xD3, + 0xC8, 0xF3, 0x39, 0x65, 0xB4, 0x5B, 0xCB, 0xD7, 0xC0, 0xD9, + 0xBA, 0xBB, 0xDE, 0x35, 0x85, 0x67, 0xEA, 0x39, 0xB8, 0xCA, + 0xDD, 0xDA, 0xDA, 0x09, 0x49, 0x9D, 0x44, 0x55, 0x8A, 0x48, + 0xA6, 0x77, 0x7A, 0xD9, 0x25, 0x0C, 0x4B, 0xE9, 0x9B, 0x7A, + 0x25, 0x9D, 0x63, 0xD8, 0x9E, 0xF4, 0x10, 0xD9, 0x4D, 0x95, + 0x3D, 0x00, 0xE6, 0x43, 0xCD, 0x89, 0x7F, 0x0D, 0x99, 0x79, + 0x26, 0x18, 0x37, 0x92, 0xB9, 0x4B, 0xFB, 0x99, 0xE5, 0x23, + 0x3F, 0x5C, 0xAB, 0x2A, 0xDE, 0x6A, 0x9E, 0x11, 0x8C, 0xF7, + 0x2B, 0xFA, 0x27, 0xF4, 0xE6, 0x5B, 0x5D, 0xB7, 0xE7, 0x1A, + 0xBD, 0x2F, 0x9A, 0x62, 0x6A, 0x2A, 0x9C, 0xA9, 0xEE, 0x8F, + 0x87, 0x0A, 0xD0, 0x83, 0xBF, 0xC2, 0x23, 0x6A, 0x0A, 0x98, + 0x6F, 0x29, 0x36, 0x56, 0xD8, 0x5B, 0xF2, 0xB4, 0x8A, 0xBC, + 0xED, 0xF0, 0x05, 0x56, 0xD8, 0x96, 0xC0, 0xCE, 0x5F, 0x54, + 0x50, 0x97, 0xCE, 0x99, 0x26, 0x98, 0xC7, 0x0A, 0xD7, 0x76, + 0x06, 0x80, 0xCF, 0x93, 0x82, 0xAD, 0x1E, 0xAE, 0x86, 0xD0, + 0x39, 0x77, 0xBC, 0x25, 0x1C, 0x57, 0x2F, 0xD4, 0x3C, 0x30, + 0xB5, 0xFB, 0x5B, 0x61, 0x22, 0x38, 0xE4, 0xD9, 0x1A, 0xDB, + 0x41, 0xEE, 0x18, 0xC0, 0xA4, 0x10, 0x3D, 0x2B, 0x53, 0x79, + 0x5E, 0x0C, 0x16, 0xBF, 0x4A, 0x8D, 0x95, 0x87, 0xFD, 0x42, + 0x59, 0xE9, 0x41, 0xEB, 0x3C, 0x67, 0x4F, 0x68, 0x3F, 0x78, + 0x4E, 0xD1, 0x38, 0x9B, 0x77, 0x3D, 0xF2, 0x40, 0x3C, 0xC4, + 0xEF, 0x48, 0x85, 0x4E, 0xC8, 0xBF, 0x15, 0x25, 0xB7, 0x33, + 0x9B, 0xF7, 0x77, 0x09, 0x29, 0xB0, 0xA8, 0x27, 0x0E, 0x01, + 0xC3, 0x0B, 0x5F, 0xA9, 0x50, 0x11, 0x98, 0x7A, 0x45, 0x24, + 0x00, 0x3D, 0xC0, 0x83, 0xF5, 0x39, 0x3D, 0x77, 0xE8, 0x73, + 0x78, 0xB2, 0xF7, 0xF5, 0xD2, 0xA2, 0x70, 0xED, 0x62, 0x18, + 0x22, 0xAD, 0xC5, 0x35, 0xA7, 0x02, 0x72, 0x30, 0xD3, 0xD4, + 0x2C, 0x1E, 0x9D, 0x74, 0xA0, 0xF2, 0x15, 0x29, 0x6D, 0x10, + 0xE7, 0x76, 0xE2, 0xEC, 0x8D, 0x04, 0x82, 0x28, 0xBD, 0x25, + 0xA1, 0xDB, 0xE1, 0x99, 0x3C, 0x23, 0x61, 0x3B, 0x92, 0x87, + 0x07, 0x99, 0x9F, 0x6C, 0x7F, 0xF8, 0x6E, 0x7D, 0x04, 0xBF, + 0x23, 0x01, 0x19, 0xDE, 0x01, 0xC1, 0xBD, 0xDC, 0xF1, 0x6B, + 0xE5, 0x21, 0xFF, 0x67, 0x15, 0xD0, 0x1F, 0xAD, 0xC3, 0x36, + 0xD0, 0x69, 0x90, 0xE2, 0xC4, 0xCB, 0xB5, 0x8A, 0x66, 0x26, + 0xDE, 0xAC, 0xB7, 0x84, 0xB6, 0xA3, 0x6B, 0x90, 0x7A, 0x19, + 0xF8, 0xEF, 0x2E, 0xC4, 0xC6, 0x04, 0xD2, 0x3B, 0x23, 0x13, + 0x04, 0x71, 0x1F, 0x7B, 0xAE, 0x8B, 0x09, 0x85, 0x29, 0x7C, + 0xDE, 0xDD, 0x07, 0x4D, 0x84, 0x2C, 0x70, 0xE6, 0xAD, 0xC0, + 0xFB, 0x64, 0x27, 0x38, 0xFA, 0xED, 0x4B, 0x81, 0xBC, 0x65, + 0xB1, 0x18, 0xEC, 0xAD, 0xF7, 0xCC, 0x97, 0xAE, 0x2D, 0x5E, + 0x6F, 0xBC, 0x0B, 0x6C, 0xD9, 0xB5, 0xE3, 0x36, 0xFD, 0xC8, + 0x28, 0x69, 0x09, 0x70, 0xB0, 0x21, 0x7B, 0x9B, 0x5B, 0x2D, + 0x2E, 0xC8, 0x0B, 0x20, 0xDF, 0xFE, 0x71, 0x9E, 0x26, 0x00, + 0x3C, 0x42, 0x21, 0x83, 0xEA, 0x8C, 0xBB, 0xDE, 0xCE, 0x85, + 0x06, 0x4A, 0xED, 0xC6, 0xE3, 0x4C, 0x9E, 0xCC, 0xDA, 0x0E, + 0x4E, 0xE1, 0x9D, 0x99, 0x79, 0x3E, 0x13, 0x60, 0x6C, 0xD3, + 0x92, 0x1D, 0x4F, 0xA8, 0x7A, 0x6F, 0x65, 0xE4, 0xFA, 0x13, + 0xEF, 0x29, 0x85, 0x3E, 0xE0, 0x10, 0x02, 0x11, 0xEF, 0xD1, + 0x33, 0x68, 0x18, 0x07, 0x31, 0x2E, 0xC8, 0x4F, 0x4B, 0xD0, + 0x03, 0x68, 0x39, 0xEB, 0xB5, 0x90, 0x4A, 0x70, 0x15, 0xC6, + 0xD5, 0x59, 0x6D, 0x98, 0x5A, 0xA9, 0xFD, 0x9B, 0x58, 0xE5, + 0x95, 0x52, 0x27, 0x62, 0xF0, 0xD5, 0x24, 0x9C, 0xC5, 0xA9, + 0x86, 0x93, 0x3C, 0x26, 0x29, 0x16, 0x10, 0x5C, 0x48, 0xD2, + 0xBD, 0x1C, 0x42, 0x49, 0x2B, 0xEC, 0x57, 0x2A, 0x4D, 0x8F, + 0xCD, 0x48, 0x91, 0x33, 0xFB, 0xEC, 0x61, 0x5E, 0x9B, 0xA7, + 0x70, 0xAC, 0x3F, 0xD2, 0x8D, 0x34, 0xAE, 0xC3, 0xD2, 0xDC, + 0xF6, 0xF6, 0x3E, 0x3F, 0xB8, 0x3D, 0x5F, 0x13, 0x0A, 0x64, + 0x94, 0xB6, 0xC5, 0x2E, 0xE4, 0xFE, 0x34, 0x41, 0xC4, 0xC3, + 0x9F, 0xB9, 0x76, 0xFE, 0xE5, 0xDA, 0x04, 0xBD, 0x81, 0xE1, + 0xE4, 0xA4, 0x18, 0x45, 0x12, 0x01, 0x3B, 0x09, 0x40, 0xC7, + 0x8E, 0xB7, 0x4E, 0x77, 0xAC, 0xD8, 0x2B, 0x9B, 0x8E, 0x57, + 0x67, 0x98, 0xE3, 0x89, 0xEB, 0x2D, 0x8C, 0xA5, 0xAF, 0x8C, + 0x6A, 0x4F, 0x3E, 0x66, 0x3C, 0x69, 0x40, 0xB6, 0x72, 0x12, + 0x11, 0x0A, 0x71, 0x81, 0x56, 0x63, 0xD9, 0x3F, 0x2B, 0x3A, + 0x95, 0xBC, 0x94, 0x0C, 0xF8, 0xC1, 0x1F, 0x72, 0x9E, 0xC1, + 0x4F, 0x3E, 0x77, 0x33, 0xF9, 0x21, 0xCE, 0x4A, 0x22, 0x12, + 0xC5, 0x7C, 0xDD, 0x19, 0x55, 0x67, 0xA3, 0x57, 0xC1, 0x76, + 0xF0, 0xE0, 0xD5, 0x74, 0xCC, 0x72, 0x9F, 0x5D, 0x0F, 0xC2, + 0xC7, 0x9A, 0x37, 0xE2, 0x95, 0x13, 0xFE, 0xD9, 0xEF, 0x3F, + 0x7B, 0xE2, 0x5B, 0xEA, 0x65, 0x74, 0x22, 0x50, 0x2D, 0x62, + 0x4B, 0xA0, 0xE4, 0x6C, 0xE6, 0xC0, 0x3E, 0x61, 0x51, 0x2B, + 0xA2, 0x68, 0x51, 0xF0, 0xD8, 0xC7, 0xE9, 0x6C, 0x39, 0x1C, + 0x11, 0xB2, 0x6E, 0xC2, 0x8A, 0xF1, 0xDC, 0x42, 0xEC, 0x05, + 0x1C, 0x8F, 0xE2, 0xFE, 0x17, 0x62, 0xD5, 0xA4, 0x6B, 0x22, + 0xDF, 0x75, 0xE7, 0x7F, 0xC7, 0x38, 0xBE, 0x42, 0xD8, 0x1B, + 0x80, 0x73, 0xA6, 0x0A, 0x85, 0xD4, 0x50, 0x88, 0xA2, 0xBA, + 0x96, 0x88, 0x3E, 0x14, 0x9F, 0x48, 0xF0, 0xC2, 0x80, 0x93, + 0xD4, 0x77, 0xD0, 0x51, 0xCF, 0x9B, 0xCA, 0xCD, 0xF8, 0x62, + 0x15, 0x41, 0x4E, 0x46, 0xF6, 0xFD, 0x64, 0xA3, 0x00, 0xBD, + 0x5E, 0x3E, 0x21, 0x38, 0x89, 0x71, 0x37, 0xA4, 0x0E, 0x6B, + 0x9F, 0xA1, 0x93, 0x41, 0x96, 0x55, 0x05, 0xEB, 0x6D, 0xC0, + 0xF4, 0x20, 0x1B, 0x47, 0x5D, 0xB5, 0xC9, 0x5D, 0x67, 0xBD, + 0xC8, 0x2F, 0xEB, 0x9E, 0xC8, 0xCA, 0x16, 0xB5, 0x39, 0x7A, + 0x3E, 0xB6, 0x8F, 0xF4, 0x92, 0xBD, 0xC4, 0x8E, 0xF9, 0x65, + 0x97, 0x69, 0xBB, 0x04, 0x40, 0xB8, 0x0A, 0xBD, 0x4A, 0xB2, + 0x4C, 0x54, 0x0D, 0x40, 0x76, 0xAD, 0xAC, 0x0B, 0x80, 0x94, + 0x59, 0xEF, 0x87, 0xE5, 0x7C, 0x94, 0x68, 0xFD, 0xC4, 0xB8, + 0xD2, 0xE5, 0xF5, 0x67, 0x6C, 0xE6, 0xB5, 0xED, 0x50, 0x44, + 0x3A, 0x35, 0xFC, 0xE8, 0x0B, 0x23, 0x25, 0x42, 0x01, 0xEB, + 0x8C, 0x38, 0x94, 0x7A, 0x7F, 0x02, 0xCA, 0x5D, 0x41, 0x20, + 0x5D, 0xBA, 0x61, 0xCC, 0x43, 0xE9, 0xBF, 0x30, 0xC8, 0xEF, + 0xD4, 0x62, 0x11, 0xF6, 0xA8, 0x65, 0x42, 0x1D, 0x87, 0xC4, + 0xC0, 0xC2, 0xE8, 0xDD, 0x06, 0x00, 0x4D, 0xF0, 0xE2, 0xCD, + 0x26, 0x95, 0x54, 0xFE, 0x0D, 0xB9, 0x90, 0x63, 0xD2, 0x87, + 0x0D, 0x62, 0xD3, 0xF9, 0xA9, 0x2D, 0xF4, 0xB8, 0xBC, 0x70, + 0x89, 0xF5, 0x2E, 0x90, 0x0B, 0x58, 0x86, 0xB6, 0x3D, 0x43, + 0x88, 0xF4, 0x98, 0x00, 0xC5, 0x9E, 0x2A, 0x8C, 0x98, 0x8C, + 0x01, 0x04, 0x12, 0xBA, 0xF7, 0x12, 0xCC, 0x3E, 0x9A, 0x40, + 0x99, 0xD4, 0x53, 0xA6, 0xF2, 0x26, 0xF4, 0x33, 0x85, 0x44, + 0x10, 0xD7, 0xD6, 0x8F, 0x46, 0xBB, 0x8B, 0xCD, 0x7D, 0xDC, + 0x8A, 0x0D, 0x93, 0x27, 0xC0, 0x57, 0x10, 0x81, 0x4E, 0xB6, + 0xBB, 0x47, 0xEA, 0x9C, 0x75, 0x30, 0xD1, 0x4A, 0xC5, 0x37, + 0x8C, 0xAB, 0x64, 0x12, 0x2F, 0xEE, 0x48, 0xFD, 0x23, 0x8A, + 0x45, 0x5A, 0x1F, 0x50, 0x0E, 0x02, 0x5C, 0x40, 0xDC, 0x76, + 0x07, 0x83, 0x49, 0x47, 0xF8, 0x60, 0x26, 0xF4, 0xD7, 0x3A, + 0x08, 0xAC, 0x21, 0xDE, 0x29, 0xA9, 0x69, 0x74, 0x72, 0xB7, + 0x8A, 0xF0, 0xC2, 0x95, 0xB3, 0x2E, 0x9D, 0xB8, 0x48, 0xD2, + 0x67, 0xDE, 0xA1, 0xE1, 0x1B, 0x1F, 0xA5, 0x96, 0xDD, 0x5C, + 0x68, 0x91, 0x3D, 0xD8, 0xE4, 0x3C, 0x3C, 0xB0, 0xF6, 0xF5, + 0xE7, 0x8C, 0xAF, 0x0E, 0x81, 0x6B, 0x1A, 0x42, 0x2F, 0x6D, + 0x44, 0xF8, 0x39, 0x3B, 0x0A, 0x6D, 0xC4, 0x59, 0x28, 0x1D, + 0xA4, 0x15, 0xB2, 0xF3, 0x98, 0x90, 0xE6, 0xE2, 0x75, 0xAD, + 0xFE, 0xBE, 0x93, 0xA5, 0x47, 0x64, 0x69, 0xB7, 0xB6, 0x53, + 0xEB, 0x6C, 0x2C, 0x7A, 0xC1, 0x5F, 0xEC, 0x3E, 0xF8, 0x9A, + 0x86, 0x2B, 0xB5, 0xE2, 0x9C, 0x48, 0x82, 0xBE, 0x7A, 0x61, + 0x15, 0xDC, 0x5B, 0x7A, 0xC3, 0x03, 0xBF, 0x5A, 0xE4, 0x95, + 0x9E, 0xB8, 0xD5, 0xB5, 0xB3, 0xB0, 0xE3, 0x8B, 0x18, 0x28, + 0x3E, 0x77, 0xE7, 0xC3, 0xF7, 0x87, 0x60, 0x36, 0xBE, 0x9C, + 0xE6, 0x97, 0x9A, 0xC0, 0x19, 0x9E, 0xF1, 0xCA, 0x4D, 0xBB, + 0xF5, 0x00, 0x80, 0x2D, 0xFB, 0xD4, 0x73, 0x82, 0xB4, 0x82, + 0x41, 0x79, 0x57, 0x98, 0x90, 0x6E, 0xD3, 0xA6, 0xBD, 0xCB, + 0xDF, 0xCD, 0x3B, 0x29, 0xAF, 0xB2, 0xED, 0xBA, 0x9E, 0xCA, + 0x7A, 0x2C, 0xB6, 0xEA, 0x5D, 0x4B, 0x1D, 0xCE, 0x10, 0x08, + 0x31, 0xF7, 0x5A, 0xC8, 0x7F, 0x4F, 0x12, 0x3C, 0xCB, 0xD9, + 0x26, 0xCB, 0x6E, 0xF9, 0xE0, 0xF4, 0xF4, 0xC6, 0x8C, 0x3C, + 0x95, 0x03, 0x1B, 0x46, 0x0A, 0xE0, 0x92, 0x31, 0x8B, 0x09, + 0x26, 0xB3, 0xB4, 0xEE, 0x65, 0xC9, 0x48, 0x89, 0xBA, 0xE8, + 0xA6, 0xC4, 0xD1, 0xB2, 0x16, 0x3E, 0xA0, 0x32, 0xA8, 0xBE, + 0x4B, 0x3F, 0xA0, 0xB5, 0xCB, 0x1A, 0xF9, 0x4B, 0xC8, 0xF2, + 0x46, 0xA6, 0x0E, 0x4D, 0x14, 0xE0, 0x1F, 0xB7, 0x19, 0xCE, + 0xA6, 0xEC, 0x5E, 0xB9, 0x8D, 0xA8, 0xB8, 0x3A, 0xD7, 0x49, + 0x1E, 0x9E, 0x0F, 0xFB, 0x4A, 0x53, 0x47, 0x4E, 0x5F, 0x85, + 0xDF, 0x17, 0x1E, 0xF5, 0x25, 0x98, 0x0C, 0xB9, 0xE3, 0x63, + 0x66, 0x8F, 0xD3, 0xEC, 0xD6, 0x87, 0x57, 0xDC, 0xA0, 0xB3, + 0x8F, 0x93, 0x39, 0x8D, 0x68, 0x1F, 0xD2, 0x9F, 0x08, 0xCD, + 0x62, 0xBA, 0xC7, 0x7C, 0x83, 0x2D, 0xF2, 0xCA, 0x5B, 0x86, + 0x1B, 0x98, 0xD9, 0x8F, 0x66, 0xFC, 0x23, 0x23, 0x40, 0xC0, + 0x76, 0x07, 0xCF, 0x27, 0xC7, 0x8C, 0xEB, 0x03, 0xEB, 0xF4, + 0x10, 0xDB, 0xD9, 0xC2, 0x53, 0x05, 0x78, 0x6F, 0xFE, 0xDE, + 0x47, 0x65, 0xF7, 0x18, 0x22, 0x0C, 0x1A, 0x0A, 0xE3, 0x04, + 0x74, 0x1C, 0x83, 0xBB, 0xE8, 0xDB, 0xC8, 0xCA, 0xBC, 0xB1, + 0x29, 0x00, 0x63, 0xE4, 0x7D, 0x4A, 0x9B, 0x34, 0xB6, 0x44, + 0x89, 0x33, 0x40, 0xBF, 0xA7, 0x2B, 0xEC, 0xC3, 0xB3, 0x83, + 0xFF, 0xD0, 0x8C, 0x5C, 0x9B, 0x92, 0x79, 0xBB, 0x3A, 0x9B, + 0xC7, 0xE5, 0x1C, 0x35, 0xD2, 0x0A, 0x1C, 0x63, 0x7D, 0xEE, + 0x5D, 0x6E, 0xA7, 0x2E, 0x76, 0x8B, 0x8B, 0x3E, 0x3B, 0xD2, + 0x16, 0x2F, 0x50, 0xF2, 0xE2, 0x54, 0x81, 0xDB, 0x3C, 0x88, + 0x5F, 0x8C, 0x7D, 0xC8, 0x00, 0x96, 0xB8, 0x03, 0x7A, 0xBC, + 0x6E, 0xA6, 0x44, 0x85, 0x1C, 0x1E, 0x2A, 0xE5, 0x01, 0x71, + 0xB9, 0xBF, 0x4C, 0xF8, 0xEA, 0xC3, 0xD5, 0x0A, 0x53, 0x01, + 0xF9, 0xD1, 0x29, 0x7C, 0x96, 0xE7, 0x53, 0xEA, 0x88, 0xDC, + 0x7E, 0x9E, 0xE7, 0xBA, 0xD7, 0x53, 0x66, 0x32, 0xAD, 0xCF, + 0xC8, 0xB0, 0x67, 0xF4, 0x5D, 0xE6, 0x9D, 0x3D, 0x5D, 0x33, + 0x6A, 0xF1, 0xAC, 0x1F, 0x09, 0x23, 0x2B, 0x8B, 0xE7, 0xCC, + 0x94, 0x7D, 0xA4, 0xC1, 0xE7, 0xF3, 0x97, 0xB3, 0xA7, 0x3F, + 0xFD, 0x65, 0x27, 0x90, 0x73, 0xA0, 0x40, 0xB7, 0xF1, 0xFD, + 0x47, 0xF7, 0x50, 0xC0, 0xD8, 0x61, 0xFC, 0xE8, 0x18, 0x20, + 0x93, 0x67, 0x9C, 0x2A, 0x9B, 0xFA, 0xDB, 0x14, 0xDA, 0x97, + 0xE1, 0x54, 0x97, 0xC3, 0x05, 0x4E, 0x84, 0x1E, 0x45, 0x38, + 0xCF, 0x35, 0x91, 0x0C, 0x79, 0xD4, 0x6C, 0x12, 0xA4, 0x60, + 0x27, 0x0E, 0xF7, 0x0F, 0x8E, 0x70, 0x8C, 0xA0, 0x56, 0x7A, + 0xAE, 0xC6, 0xBF, 0x9E, 0x49, 0xB4, 0x57, 0xDC, 0x0B, 0x84, + 0x52, 0x8D, 0x5D, 0xB7, 0x5A, 0xC0, 0x27, 0x89, 0x5F, 0x8B, + 0x1F, 0x48, 0x58, 0xC9, 0x34, 0xD4, 0xBD, 0x32, 0xE4, 0x76, + 0x25, 0x71, 0x28, 0xAC, 0xB1, 0x2A, 0xC1, 0x07, 0x09, 0xA1, + 0x71, 0x99, 0xD7, 0x53, 0x65, 0x27, 0xC0, 0x1E, 0x82, 0x2F, + 0xC0, 0x15, 0x4C, 0x5E, 0x06, 0x29, 0xDD, 0x9A, 0x0B, 0x0B, + 0x2A, 0x28, 0x48, 0xC7, 0xD7, 0x9F, 0x56, 0x45, 0x71, 0x8F, + 0x83, 0x48, 0xE8, 0xA4, 0xB9, 0x4D, 0x66, 0x02, 0x8B, 0x6C, + 0x12, 0xEF, 0x30, 0x96, 0x8F, 0x21, 0x5E, 0x96, 0xDE, 0x0E, + 0x31, 0x9D, 0xE2, 0x7B, 0x7E, 0xBC, 0x10, 0x1D, 0xA1, 0x97, + 0x96, 0xA9, 0x6C, 0xE1, 0x5B, 0x06, 0xA4, 0xE8, 0x77, 0xBA, + 0xB6, 0x42, 0xB7, 0xA5, 0x04, 0xE0, 0x28, 0x28, 0x3C, 0xE3, + 0xC0, 0x57, 0x6E, 0x06, 0x6A, 0x98, 0x78, 0xC2, 0xEE, 0xE6, + 0x32, 0x95, 0xBA, 0xCC, 0xC7, 0x60, 0x9A, 0x76, 0xBD, 0xCF, + 0x6B, 0xD7, 0x30, 0xC5, 0xCD, 0x96, 0xEB, 0xB8, 0x95, 0xDB, + 0x82, 0xDC, 0x29, 0x28, 0x0C, 0xED, 0x07, 0xB0, 0x95, 0xEB, + 0x55, 0xCD, 0xBD, 0xAE, 0xF1, 0x54, 0xA8, 0xD6, 0x7C, 0x42, + 0x8D, 0x44, 0xC5, 0x06, 0x7D, 0x23, 0xF3, 0x7B, 0xC9, 0xA3, + 0x1A, 0x3B, 0x4B, 0x0E, 0xCC, 0xB5, 0x8A, 0x7D, 0x9F, 0x64, + 0x29, 0x09, 0xBC, 0x47, 0x3A, 0xAD, 0xF7, 0xA1, 0xCD, 0x2C, + 0x0D, 0xA5, 0xD6, 0xEE, 0xD1, 0x3C, 0xA4, 0x63, 0x6A, 0xDB, + 0x67, 0x65, 0xF9, 0xE7, 0xF6, 0x1D, 0xDB, 0x7E, 0xF8, 0x8B, + 0x37, 0x4F, 0x6F, 0x36, 0x81, 0xCB, 0x12, 0x30, 0x99, 0x4E, + 0xB4, 0x59, 0x3F, 0x15, 0x32, 0xC6, 0x5D, 0x6F, 0xA5, 0x5B, + 0x2B, 0x66, 0x54, 0x59, 0x29, 0x01, 0x64, 0x88, 0xF5, 0xFF, + 0x4B, 0x4D, 0x5B, 0xEF, 0x71, 0x32, 0x77, 0xE4, 0xE7, 0xFE, + 0xEE, 0xAA, 0x45, 0x41, 0xF3, 0x34, 0x9B, 0x6A, 0xAA, 0x11, + 0xF1, 0x3E, 0x98, 0x4A, 0x2F, 0xF1, 0xE8, 0xB1, 0x6F, 0x60, + 0x24, 0x3E, 0x42, 0xAA, 0x2D, 0xBD, 0xAB, 0xA0, 0x45, 0x5F, + 0xE1, 0x81, 0x4F, 0xDD, 0x4C, 0x19, 0xD9, 0x52, 0x90, 0xAF, + 0xBB, 0x10, 0x48, 0x2F, 0xE9, 0x72, 0x0B, 0x4A, 0x0D, 0x96, + 0xA4, 0xBA, 0x66, 0xBC, 0x57, 0xA2, 0x79, 0x94, 0xA1, 0x00, + 0xE5, 0xF4, 0x58, 0xC3, 0x41, 0xAD, 0xA6, 0x1B, 0xFD, 0x80, + 0x91, 0x7F, 0x65, 0xB2, 0xC7, 0xF7, 0x7F, 0xAA, 0x69, 0x53, + 0x3B, 0xC8, 0x0F, 0x24, 0x6D, 0x93, 0xE2, 0x9D, 0x71, 0x6F, + 0xE2, 0xAF, 0x70, 0xA7, 0x5B, 0xD9, 0xD4, 0xFC, 0x3B, 0xB3, + 0xBF, 0xF7, 0x5F, 0xDF, 0x9B, 0x7B, 0x1D, 0xF5, 0xCD, 0x10, + 0xE7, 0xDE, 0x08, 0x0E, 0x0D, 0x3A, 0x82, 0x19, 0x1C, 0x19, + 0x75, 0x7F, 0x2F, 0x1C, 0x59, 0xEC, 0x5A, 0x7B, 0xC5, 0xB3, + 0x3F, 0x78, 0x9A, 0xE6, 0xA5, 0x82, 0x9E, 0x46, 0x17, 0xC0, + 0x93, 0xD5, 0x2F, 0xEA, 0x09, 0xB8, 0x19, 0x33, 0x4D, 0x34, + 0xCB, 0xDE, 0x7A, 0x3B, 0x7B, 0x23, 0x5F, 0x95, 0x8C, 0x62, + 0x01, 0x92, 0x55, 0xF6, 0xB1, 0x93, 0x03, 0x76, 0x33, 0x9C, + 0x89, 0x40, 0x6A, 0xD8, 0x46, 0xF4, 0xE5, 0x30, 0xC4, 0x7D, + 0x8D, 0xD9, 0x8B, 0x03, 0xE1, 0xF1, 0x0A, 0xB3, 0x49, 0x01, + 0xF1, 0x63, 0xA3, 0xF7, 0x3D, 0x07, 0x31, 0x5C, 0x2F, 0x3F, + 0xE8, 0x2C, 0xA8, 0xF3, 0xAC, 0xE7, 0xBA, 0xB1, 0xCF, 0xBA, + 0xF2, 0x65, 0x77, 0x6A, 0x80, 0x67, 0x11, 0x07, 0x10, 0x54, + 0x06, 0x77, 0x85, 0x42, 0x81, 0xF2, 0x83, 0xDB, 0x76, 0xF2, + 0xDA, 0x7E, 0x90, 0x8A, 0x56, 0x1A, 0xB6, 0x2A, 0xA1, 0x48, + 0x24, 0x95, 0x6A, 0xA9, 0xF3, 0xE9, 0xFC, 0x57, 0x03, 0x6C, + 0x76, 0xC3, 0x81, 0xC8, 0x4D, 0x54, 0x02, 0x58, 0xD8, 0x61, + 0xB0, 0x5E, 0x47, 0x2A, 0xEB, 0x79, 0xCE, 0x07, 0xE8, 0x8F, + 0xC4, 0x42, 0x46, 0xCD, 0x88, 0xC7, 0x2F, 0x73, 0x1D, 0x5B, + 0x8F, 0x42, 0xB8, 0x3A, 0x65, 0xEF, 0xAF, 0x6F, 0xD1, 0x04, + 0x90, 0x51, 0x92, 0xAD, 0xA7, 0x74, 0x46, 0x0D, 0x2B, 0xA9, + 0x58, 0xCB, 0xB4, 0x5A, 0xB3, 0xE8, 0xF1, 0xA0, 0x0B, 0xE8, + 0x50, 0x03, 0xED, 0x16, 0x42, 0x2F, 0x7D, 0x23, 0xF7, 0xF4, + 0xE7, 0xBB, 0x17, 0xB1, 0xD7, 0xAB, 0xDA, 0x37, 0xC4, 0xC5, + 0x53, 0xCD, 0x4B, 0x41, 0x89, 0x48, 0x4E, 0x3A, 0x04, 0x53, + 0xC3, 0x5D, 0x07, 0x80, 0xEB, 0x1E, 0x39, 0x34, 0xFE, 0x5A, + 0x32, 0x5B, 0x5B, 0x6B, 0xC3, 0xB4, 0xCA, 0x73, 0x48, 0xFE, + 0xE7, 0x17, 0x33, 0x77, 0xF6, 0xB7, 0x68, 0x8F, 0xE7, 0xDB, + 0xAC, 0x9F, 0x8B, 0x36, 0x8D, 0xB7, 0x8D, 0x61, 0x79, 0x8D, + 0x5F, 0xEA, 0xD2, 0x16, 0x5E, 0x5A, 0x31, 0x08, 0x06, 0x8B, + 0x0C, 0x49, 0x61, 0x9A, 0x09, 0xA6, 0x81, 0xBE, 0x14, 0xD6, + 0x1C, 0x96, 0x50, 0xD2, 0xD5, 0x15, 0x5B, 0x89, 0x11, 0xCC, + 0x3C, 0x43, 0xB5, 0xB2, 0xED, 0xE1, 0x89, 0x34, 0xFE, 0xDF, + 0xA1, 0xC1, 0x32, 0x4F, 0xD3, 0x64, 0xA2, 0x7C, 0x7F, 0x44, + 0x06, 0xF9, 0x76, 0xFE, 0x6F, 0xB3, 0x2E, 0x80, 0x1C, 0xCD, + 0x65, 0xAF, 0x25, 0xC1, 0xEE, 0xE9, 0x44, 0x92, 0x4F, 0x88, + 0x96, 0x9A, 0xF4, 0xB0, 0x4E, 0xB8, 0xF6, 0xB1, 0xBC, 0x28, + 0x89, 0x55, 0xD3, 0x84, 0xD5, 0x74, 0x96, 0x34, 0xC9, 0x8C, + 0x3D, 0x22, 0x52, 0x36, 0xD4, 0xF0, 0xDB, 0x07, 0x2A, 0xE6, + 0xC6, 0x45, 0xB9, 0x6F, 0xE8, 0xDC, 0x11, 0x46, 0x3A, 0x8D, + 0x9E, 0xE1, 0xC3, 0x33, 0xD0, 0xB4, 0x52, 0x69, 0x8A, 0xFA, + 0xBD, 0xA8, 0x0A, 0xE7, 0xE8, 0x18, 0x32, 0xB2, 0x4D, 0xEE, + 0x49, 0x4E, 0x79, 0xD7, 0xE3, 0xAB, 0xE1, 0x1C, 0x75, 0x7C, + 0xC2, 0x9E, 0xF5, 0x15, 0x2F, 0xFD, 0x11, 0xEB, 0xB8, 0xB8, + 0x3A, 0x6D, 0x42, 0xDF, 0x4F, 0xE4, 0xA3, 0x62, 0xC7, 0xB8, + 0xA7, 0x1F, 0x92, 0xFC, 0x59, 0x7D, 0x73, 0xAD, 0x8D, 0x5C, + 0x3B, 0xE5, 0x92, 0xA9, 0x28, 0x5B, 0xBF, 0xD9, 0x85, 0x08, + 0xE3, 0x8D, 0x1B, 0xBC, 0x01, 0xCB, 0x04, 0xF1, 0xC6, 0xD9, + 0xB9, 0x83, 0xD2, 0xAC, 0x70, 0x81, 0x4F, 0x37, 0x7C, 0xB8, + 0xCB, 0x73, 0x3E, 0x89, 0xCF, 0x75, 0xAD, 0xED, 0x64, 0x82, + 0x07, 0x0B, 0x89, 0x37, 0x27, 0x26, 0x5E, 0x51, 0x79, 0x6F, + 0x69, 0x18, 0x7E, 0xE0, 0x7B, 0xD6, 0x85, 0x15, 0xE9, 0x60, + 0xA6, 0xF9, 0xC5, 0xBE, 0x7C, 0xC4, 0xAE, 0x86, 0x1C, 0xCA, + 0xA7, 0x94, 0x1A, 0x20, 0xB2, 0x92, 0xB1, 0x02, 0x22, 0x03, + 0xED, 0xF8, 0x74, 0xBF, 0x63, 0x20, 0x52, 0x37, 0xEF, 0xF0, + 0x4C, 0x62, 0x80, 0x48, 0xD9, 0x65, 0x0C, 0xDB, 0xFE, 0x55, + 0x37, 0x77, 0x18, 0x99, 0x9B, 0x60, 0xA3, 0x42, 0x0F, 0xD9, + 0x3B, 0x98, 0xC4, 0xEA, 0x12, 0x1A, 0xCC, 0x3B, 0x8E, 0x02, + 0x5A, 0x44, 0x31, 0x98, 0xA9, 0x1B, 0x05, 0xC8, 0x95, 0xBC, + 0xD4, 0xD3, 0x2E, 0x0D, 0x6B, 0xA1, 0xE2, 0xB4, 0x6F, 0x02, + 0x14, 0x89, 0xBC, 0x4C, 0x72, 0x8E, 0x20, 0xED, 0x51, 0x94, + 0xD5, 0x66, 0xF4, 0x3B, 0x4D, 0xBB, 0x34, 0xA7, 0x6D, 0x79, + 0x19, 0xED, 0x7A, 0xBE, 0xED, 0x31, 0x69, 0x93, 0xAD, 0x9E, + 0x60, 0x01, 0xEC, 0x45, 0x34, 0x17, 0x44, 0xB5, 0xE0, 0xF1, + 0xD0, 0xA7, 0xA1, 0xD3, 0x69, 0x7D, 0xA9, 0x31, 0xCC, 0xF6, + 0x23, 0xC6, 0x10, 0x5A, 0xCC, 0x4F, 0xE6, 0xB7, 0xF3, 0x13, + 0x94, 0x67, 0xE9, 0xE1, 0x0A, 0x3E, 0x41, 0xD5, 0x36, 0x9F, + 0x4E, 0x76, 0x62, 0xD5, 0x7C, 0x83, 0x63, 0x52, 0x30, 0xDA, + 0xBE, 0x11, 0x70, 0x44, 0x68, 0x92, 0x4E, 0xFB, 0x5C, 0x68, + 0x57, 0xE3, 0xE0, 0x71, 0xFC, 0xFA, 0x40, 0x18, 0x68, 0xB5, + 0x7C, 0xDE, 0xD1, 0xF9, 0xBE, 0x9C, 0x2A, 0x96, 0x52, 0x7A, + 0xD3, 0xEE, 0x17, 0x32, 0xDB, 0x65, 0xFC, 0x75, 0x66, 0x49, + 0x6F, 0x65, 0xF1, 0xBB, 0xE1, 0x08, 0xED, 0xD7, 0x53, 0xD4, + 0x24, 0x3F, 0xF4, 0x5D, 0xC1, 0x87, 0x10, 0x12, 0x78, 0xEC, + 0x8B, 0xBB, 0x17, 0x8C, 0xDA, 0xED, 0xD9, 0x12, 0x4D, 0x4B, + 0x27, 0x88, 0xF3, 0x43, 0xA3, 0xB6, 0x9B, 0x51, 0x89, 0x60, + 0x53, 0x09, 0xB9, 0xA0, 0xA6, 0x90, 0x57, 0xB4, 0x87, 0xA1, + 0x13, 0xA4, 0x2E, 0xC4, 0xD7, 0x05, 0x51, 0xEF, 0xAC, 0xC1, + 0xDF, 0xBC, 0x00, 0x6C, 0xB0, 0x8F, 0xA8, 0x76, 0x1D, 0xD7, + 0x80, 0xD7, 0x50, 0xA7, 0x85, 0x8D, 0x31, 0x06, 0x30, 0x78, + 0x95, 0x96, 0x88, 0x85, 0x35, 0x29, 0x07, 0xBC, 0xDD, 0x3B, + 0x2B, 0x28, 0x36, 0x9F, 0x9D, 0xEC, 0xA1, 0x37, 0x07, 0xA3, + 0xAB, 0x03, 0xF8, 0x9A, 0x86, 0x06, 0x7F, 0x62, 0xD8, 0x01, + 0xFA, 0x6A, 0x76, 0x98, 0x40, 0xFE, 0x96, 0xC6, 0x45, 0x38, + 0xB4, 0x84, 0x54, 0x94, 0x9F, 0x6E, 0x1C, 0x1E, 0xC3, 0xCA, + 0xA2, 0xA6, 0x53, 0x99, 0x40, 0x6C, 0x84, 0x46, 0x83, 0x43, + 0xEC, 0x6A, 0x3A, 0x1D, 0xE1, 0xB9, 0x5A, 0x9B, 0xE9, 0xD5, + 0x09, 0x34, 0x1E, 0x44, 0xAB, 0x4A, 0x4C, 0x31, 0x43, 0x2B, + 0x37, 0x11, 0x0B, 0x55, 0xE9, 0xFC, 0xD7, 0x74, 0xAA, 0x1E, + 0xC3, 0x94, 0xC7, 0x32, 0xDF, 0x36, 0xDD, 0x00, 0x07, 0xBD, + 0xF1, 0xF1, 0x32, 0xB3, 0x44, 0x96, 0x30, 0x61, 0xE8, 0x86, + 0x1F, 0xBD, 0xA0, 0x48, 0x5B, 0x0A, 0xD8, 0x9C, 0xA9, 0x18, + 0x45, 0x5D, 0x3C, 0x17, 0xBF, 0xA9, 0xFB, 0xC7, 0xAA, 0x97, + 0x18, 0x34, 0x2A, 0x35, 0xB1, 0x7E, 0xC1, 0xA0, 0xE8, 0xF5, + 0xEF, 0xFB, 0x26, 0x34, 0xC4, 0x4B, 0xE0, 0x74, 0xDC, 0x6C, + 0x02, 0x62, 0x59, 0x53, 0xAD, 0x11, 0x87, 0x41, 0x6F, 0x84, + 0x9B, 0x02, 0x31, 0xF6, 0xAF, 0xC9, 0xFF, 0x5E, 0x45, 0xA5, + 0xDA, 0x22, 0xEA, 0xB2, 0xB8, 0xE7, 0x83, 0xB4, 0x4A, 0xD5, + 0x93, 0x17, 0x3A, 0x01, 0x99, 0x40, 0xAC, 0xC7, 0xEE, 0xB9, + 0xE8, 0x6D, 0x9E, 0x3C, 0x6C, 0x2B, 0x70, 0xAD, 0xD7, 0xCF, + 0xC0, 0xA4, 0xEE, 0x60, 0xA0, 0xB3, 0xF8, 0x19, 0x83, 0x8D, + 0x47, 0x38, 0xDE, 0x1C, 0x4D, 0xF6, 0x35, 0x0B, 0x02, 0x6A, + 0x90, 0xE5, 0x39, 0x62, 0x57, 0xEA, 0xE3, 0x73, 0x16, 0x61, + 0x70, 0x4B, 0x61, 0xB4, 0x1A, 0xEE, 0xE5, 0xF1, 0x86, 0x26, + 0xB0, 0x3C, 0x2E, 0xA5, 0x2F, 0xA6, 0x1A, 0xEB, 0x1F, 0x71, + 0xE5, 0xF0, 0x03, 0xE7, 0x5F, 0x52, 0x7B, 0x18, 0xAD, 0xE6, + 0xA3, 0x59, 0xE6, 0x81, 0xDA, 0x0E, 0x0A, 0x1E, 0x32, 0xFE, + 0x20, 0x7F, 0xDB, 0x48, 0xB6, 0x3B, 0x99, 0x06, 0xAE, 0x0D, + 0xE0, 0xEC, 0x58, 0xC7, 0xF6, 0x39, 0xA1, 0xFB, 0x8A, 0x78, + 0x2D, 0x29, 0xF3, 0xBB, 0xE0, 0xA5, 0x93, 0xEB, 0x6A, 0xD9, + 0x14, 0xA9, 0x4C, 0xB5, 0x25, 0x0D, 0xC7, 0xFF, 0x58, 0xC3, + 0xDF, 0x7C, 0xCC, 0x8F, 0x9A, 0xA0, 0xDD, 0x2B, 0x4D, 0x7D, + 0x93, 0xB5, 0x42, 0x2A, 0x04, 0x31, 0xC0, 0xBE, 0xE6, 0x9C, + 0x35, 0x48, 0x8F, 0x15, 0x5A, 0x46, 0x09, 0xA7, 0x6E, 0x53, + 0x6F, 0xF3, 0xE8, 0x83, 0x37, 0x62, 0x8D, 0xDE, 0x2A, 0x49, + 0xA5, 0x3C, 0x01, 0x39, 0x7D, 0x67, 0x41, 0x76, 0x46, 0xD6, + 0xB6, 0x2C, 0x0D, 0xCA, 0x87, 0x2B, 0x9F, 0xCF, 0xD6, 0x99, + 0x9C, 0x50, 0x97, 0x36, 0xA4, 0xC8, 0xA7, 0xAB, 0x46, 0xA9, + 0xE7, 0x3A, 0x4B, 0x27, 0xDD, 0xD9, 0x3F, 0xE3, 0x65, 0xDB, + 0x50, 0x6E, 0xE2, 0xF5, 0x1D, 0xE7, 0x8E, 0x48, 0xBD, 0x17, + 0xBD, 0x66, 0x8C, 0xAA, 0xC0, 0x5F, 0x8C, 0x7D, 0xB4, 0xFF, + 0xBD, 0xCA, 0x7E, 0x99, 0x0E, 0xB9, 0x7F, 0x55, 0x58, 0xF1, + 0xA8, 0x6E, 0x51, 0xEE, 0x61, 0xEA, 0xDD, 0x0C, 0x72, 0x43, + 0x4A, 0x90, 0x6B, 0xC7, 0x98, 0x8D, 0x12, 0xB9, 0xD8, 0x1D, + 0x80, 0xCD, 0x7E, 0xE5, 0x6E, 0x68, 0x1C, 0x5E, 0x5F, 0xED, + 0xFA, 0xF5, 0x30, 0x43, 0x63, 0x07, 0xD5, 0xC9, 0x40, 0xD2, + 0xFE, 0xAC, 0x00, 0x97, 0xDC, 0x27, 0x63, 0x5A, 0xFA, 0x53, + 0xA6, 0x5F, 0xA8, 0x34, 0x10, 0xEE, 0x9F, 0x42, 0xF0, 0xC4, + 0x75, 0x17, 0xFD, 0xB8, 0x59, 0x8D, 0x57, 0x94, 0x4F, 0xE2, + 0xED, 0x97, 0x91, 0x2D, 0xD3, 0xCD, 0xF9, 0xFB, 0x06, 0x65, + 0xD5, 0xA5, 0x87, 0xF8, 0xC3, 0x77, 0x5B, 0xD8, 0x0D, 0x9D, + 0x72, 0x84, 0x9C, 0x3B, 0x7E, 0x4E, 0x8A, 0x9D, 0xF5, 0x7F, + 0x34, 0x9B, 0xCC, 0x92, 0x6D, 0x9A, 0x38, 0x44, 0x0C, 0xF6, + 0xA4, 0x0C, 0x0A, 0xA5, 0x46, 0x81, 0x81, 0x8A, 0xC2, 0x23, + 0x1E, 0xFD, 0x4E, 0x60, 0x9F, 0x64, 0xA2, 0x9C, 0xBF, 0xAB, + 0xC0, 0x91, 0x2C, 0xC6, 0xF2, 0x0B, 0x6C, 0x11, 0xFE, 0x7C, + 0x2F, 0x54, 0xB8, 0x33, 0xED, 0x9B, 0x7E, 0x10, 0x98, 0xCC, + 0x33, 0xEE, 0x6C, 0x66, 0x2F, 0xFE, 0xB9, 0xB8, 0xCC, 0x84, + 0xBE, 0xEF, 0xFC, 0x86, 0x68, 0x25, 0xE2, 0x00, 0x03, 0x91, + 0x5E, 0x5B, 0x61, 0x58, 0xB2, 0x56, 0x6F, 0x5B, 0xD9, 0xAF, + 0xFB, 0xE2, 0xBE, 0xB9, 0xB7, 0xF9, 0x08, 0x6E, 0x3A, 0xCB, + 0xA1, 0x12, 0xEC, 0xDE, 0x5D, 0xA2, 0x92, 0x08, 0xC8, 0x4D, + 0x6F, 0x5E, 0xD9, 0x0C, 0xEB, 0x96, 0xCA, 0xF8, 0x90, 0x67, + 0x8D, 0x4C, 0xF0, 0xEC, 0x42, 0x94, 0x8D, 0x8E, 0xB5, 0xDD, + 0x6D, 0x73, 0x5F, 0x28, 0xED, 0xD4, 0x0B, 0x87, 0x90, 0xD6, + 0x0F, 0x62, 0x41, 0xB1, 0xA2, 0xB7, 0x88, 0xB1, 0xC2, 0x38, + 0x6A, 0x64, 0xC9, 0xCE, 0x4E, 0x20, 0x00, 0xE4, 0x36, 0x07, + 0x4F, 0xD4, 0xB3, 0xD0, 0xBE, 0x27, 0x1D, 0xB0, 0x81, 0x87, + 0xF9, 0xED, 0xD7, 0xD3, 0xB3, 0xE9, 0xD1, 0x9A, 0xD3, 0x2C, + 0x15, 0x7E, 0x03, 0x82, 0x11, 0x91, 0x9E, 0x82, 0x8A, 0x5E, + 0x5A, 0x80, 0xDE, 0x36, 0xE8, 0x8D, 0x58, 0xFF, 0x96, 0x7E, + 0xDF, 0x6E, 0x66, 0xEB, 0x76, 0xDE, 0xB1, 0x2F, 0x2A, 0xFD, + 0x4C, 0x12, 0xDE, 0x48, 0x44, 0xD7, 0x64, 0x26, 0x42, 0x3F, + 0xB2, 0x10, 0x49, 0xB3, 0xAB, 0x58, 0x1B, 0xE2, 0xE6, 0xD6, + 0xED, 0x2B, 0x7B, 0xE9, 0x0A, 0xDB, 0xE1, 0xC1, 0x2C, 0xDB, + 0x8B, 0x04, 0x9D, 0xED, 0xDC, 0xCE, 0x8B, 0xB0, 0x43, 0x0F, + 0x3C, 0x74, 0x47, 0xBA, 0x0B, 0x9E, 0x7C, 0x16, 0xCB, 0xD6, + 0x58, 0xE7, 0x92, 0x1F, 0xE4, 0x63, 0x45, 0x80, 0x6C, 0x99, + 0x16, 0xC1, 0x2B, 0x76, 0xA4, 0xEE, 0x51, 0x9E, 0xD4, 0x7F, + 0xD3, 0xC1, 0x7A, 0x42, 0xCA, 0xCE, 0x50, 0x05, 0x99, 0x99, + 0x9A, 0x8C, 0xE9, 0x8A, 0xEB, 0x86, 0x14, 0xBB, 0x1F, 0x52, + 0x03, 0x8F, 0xC2, 0xDF, 0x3D, 0x2C, 0xE4, 0xB1, 0x0C, 0x7E, + 0xA3, 0x07, 0xDD, 0xB1, 0xFB, 0x82, 0x63, 0x67, 0x0C, 0x73, + 0x5E, 0x14, 0x3B, 0x1C, 0x9B, 0x65, 0x6B, 0x4A, 0x93, 0x73, + 0xF1, 0x45, 0xCA, 0x4D, 0xC1, 0x2B, 0xD6, 0x99, 0x64, 0x91, + 0x83, 0x60, 0x3D, 0x4E, 0x2F, 0x2B, 0x7B, 0x97, 0x1E, 0x41, + 0xDD, 0xA8, 0x31, 0xB8, 0xB3, 0x53, 0x2F, 0x9E, 0x4C, 0x69, + 0xCE, 0x54, 0x84, 0x4D, 0x77, 0xC3, 0x12, 0xE8, 0x14, 0xC8, + 0x52, 0x30, 0x6F, 0x20, 0x4E, 0x4C, 0xB6, 0x74, 0x10, 0x09, + 0x14, 0x9A, 0x6E, 0x1D, 0xDC, 0x72, 0xAA, 0xD4, 0x3A, 0xB0, + 0x38, 0x9B, 0x92, 0xE5, 0x5A, 0xAE, 0x44, 0xFA, 0x82, 0x05, + 0x81, 0x2C, 0x4F, 0x64, 0x88, 0x0B, 0x87, 0xD8, 0x95, 0xB9, + 0x21, 0xC1, 0xAA, 0x53, 0xB2, 0x9E, 0xCA, 0x4F, 0x16, 0x81, + 0x6F, 0xDB, 0xFA, 0x31, 0x8C, 0xE8, 0x08, 0xAF, 0xA6, 0xA6, + 0x92, 0x0C, 0x25, 0x0D, 0xA2, 0x39, 0x1A, 0xFB, 0x25, 0xFF, + 0x40, 0x76, 0x57, 0x01, 0x90, 0x7B, 0x06, 0x3C, 0x61, 0xBE, + 0xC2, 0xD5, 0x52, 0x02, 0xB7, 0xFF, 0xE4, 0x35, 0x35, 0xA2, + 0x38, 0x75, 0x53, 0x51, 0xB5, 0x94, 0x01, 0x50, 0xEF, 0xF9, + 0xA9, 0xDD, 0x7B, 0x0E, 0x12, 0x4A, 0x02, 0x13, 0x77, 0x7D, + 0xF2, 0x58, 0x8F, 0xFE, 0x63, 0x72, 0xAE, 0x0B, 0x21, 0x94, + 0x64, 0x01, 0x5D, 0x06, 0x43, 0x92, 0x63, 0xCA, 0xF1, 0x4B, + 0x12, 0xE9, 0xA5, 0x25, 0x62, 0x18, 0x7A, 0x14, 0x33, 0xF8, + 0xB5, 0x46, 0x02, 0x0B, 0xB9, 0xD2, 0xDC, 0xAF, 0x8F, 0x3A, + 0xDE, 0x9A, 0x8F, 0xB9, 0x0B, 0x6E, 0x5E, 0x90, 0xED, 0x8A, + 0x28, 0x57, 0xFB, 0x10, 0x16, 0x8D, 0xBB, 0x4E, 0xEF, 0xB6, + 0x8F, 0x17, 0x48, 0x55, 0xE6, 0x94, 0xDF, 0x7D, 0x77, 0x2E, + 0x7B, 0x88, 0xFD, 0x26, 0x53, 0x1A, 0xBB, 0xF7, 0x86, 0x08, + 0x5A, 0x30, 0x79, 0x98, 0x7B, 0xA6, 0xA5, 0xA5, 0x9F, 0x56, + 0xA3, 0x8C, 0x15, 0x3E, 0x11, 0x16, 0x10, 0x81, 0x05, 0xEA, + 0xAF, 0xF5, 0x8E, 0x1A, 0x09, 0xE6, 0xC5, 0x72, 0x78, 0xB2, + 0x9D, 0x1F, 0xEA, 0xF9, 0x2D, 0xA7, 0x83, 0x22, 0x82, 0xC4, + 0xFA, 0xED, 0xD5, 0xB9, 0x0F, 0xE3, 0x51, 0x51, 0xC0, 0xEB, + 0xE9, 0x51, 0xE1, 0x29, 0x8E, 0x83, 0x89, 0x3C, 0xB0, 0x0F, + 0xB5, 0xCC, 0x19, 0x06, 0xF8, 0xCE, 0x68, 0xB6, 0x14, 0x3E, + 0x6C, 0x27, 0x65, 0x61, 0xF6, 0x40, 0x9B, 0xCF, 0xA0, 0x73, + 0x62, 0xFB, 0x25, 0x53, 0x25, 0x6D, 0xE9, 0x2E, 0x12, 0x86, + 0x8E, 0x40, 0x98, 0x2D, 0x88, 0xEC, 0x00, 0x40, 0xE3, 0x2E, + 0xAC, 0x66, 0x5F, 0xD5, 0x91, 0xA5, 0xB0, 0xE9, 0xBD, 0x25, + 0xFA, 0x37, 0xF5, 0x41, 0x70, 0x60, 0x6B, 0x99, 0xBF, 0x4D, + 0xB3, 0x82, 0x29, 0xC7, 0x8F, 0x1C, 0x15, 0xCE, 0x5A, 0xE2, + 0xB0, 0xE8, 0x6B, 0x84, 0x94, 0x05, 0xBB, 0x79, 0xF6, 0xEB, + 0x98, 0x54, 0x51, 0xBA, 0xCB, 0xA4, 0x10, 0x4D, 0x79, 0x73, + 0x85, 0xEE, 0xDA, 0x31, 0xCC, 0xCE, 0xC4, 0x27, 0x69, 0x70, + 0xD8, 0x09, 0x8F, 0x72, 0x75, 0x20, 0x0E, 0x6B, 0x8D, 0xD1, + 0x47, 0x3C, 0x23, 0x67, 0x73, 0x42, 0x28, 0xB8, 0x1E, 0x76, + 0xA5, 0xE4, 0x71, 0x56, 0x0D, 0x82, 0x3A, 0x3A, 0x10, 0x0C, + 0x7B, 0x28, 0x58, 0xDB, 0xF8, 0xEC, 0x1E, 0xCE, 0x07, 0x8A, + 0xAF, 0xD3, 0x11, 0xAB, 0x57, 0x2D, 0xC1, 0xB0, 0xCA, 0x8B, + 0xDD, 0xBC, 0xB9, 0xD2, 0xBC, 0x64, 0x82, 0x74, 0x19, 0x54, + 0x55, 0x75, 0xD8, 0xDB, 0xC6, 0x33, 0xAC, 0xCC, 0x59, 0xB7, + 0xFE, 0x04, 0x58, 0x05, 0x3D, 0x6C, 0x82, 0x9A, 0xB7, 0x18, + 0x3A, 0xBC, 0x50, 0xAB, 0xF4, 0x01, 0xF2, 0xCA, 0xBC, 0xDE, + 0x41, 0x5B, 0x7C, 0x5B, 0xBC, 0x61, 0x15, 0x44, 0x21, 0x51, + 0x3B, 0x02, 0x3E, 0x28, 0x39, 0xB8, 0xBB, 0xD2, 0x1E, 0x88, + 0x14, 0x92, 0x0E, 0xBB, 0x19, 0x7C, 0xE0, 0x8F, 0x84, 0x4C, + 0x78, 0x6A, 0xCD, 0xF2, 0x16, 0xF2, 0xE5, 0x85, 0xDA, 0x0F, + 0xD1, 0xB3, 0xEB, 0xB6, 0xB6, 0xEB, 0x80, 0x41, 0xFA, 0x56, + 0xA5, 0x01, 0x4E, 0xB3, 0x11, 0x1C, 0x35, 0x35, 0x8C, 0x00, + 0x3F, 0xDB, 0xAD, 0xA1, 0x30, 0x4B, 0xCB, 0xEA, 0x20, 0xE9, + 0x07, 0x08, 0x3D, 0xD2, 0x92, 0x6B, 0x8B, 0x6D, 0x9B, 0x97, + 0xF1, 0x60, 0xEB, 0x89, 0xF6, 0x46, 0xC1, 0x7A, 0x7A, 0x32, + 0x15, 0x97, 0x70, 0x0D, 0x7C, 0x02, 0x07, 0x2F, 0x60, 0x3E, + 0x2B, 0xF2, 0x0F, 0x1D, 0xDA, 0x4C, 0xA5, 0x01, 0x48, 0x18, + 0x3C, 0xAD, 0x60, 0x0D, 0x71, 0x6F, 0x20, 0xC7, 0x06, 0xBF, + 0x9A, 0x99, 0x9F, 0xB5, 0xF5, 0x9E, 0xA4, 0x40, 0xF0, 0xDD, + 0x54, 0x1D, 0xCC, 0x07, 0x83, 0x9D, 0x18, 0x3E, 0x0E, 0xD6, + 0x4E, 0xB3, 0x0A, 0x89, 0x43, 0xF8, 0xFA, 0x53, 0xFF, 0xC2, + 0x9C, 0xBB, 0x3C, 0x02, 0x3C, 0x7A, 0x04, 0x04, 0x7B, 0x9D, + 0xC8, 0x9D, 0x69, 0x83, 0x26, 0xC7, 0x86, 0x9B, 0x49, 0xA7, + 0x67, 0x45, 0xED, 0x1D, 0x3B, 0xAD, 0x1A, 0xFC, 0x50, 0x38, + 0xEC, 0xCC, 0x15, 0xF6, 0xB1, 0xF4, 0xFD, 0x77, 0x6B, 0xCA, + 0x99, 0xE3, 0x48, 0xF7, 0x82, 0xC0, 0x37, 0xA9, 0xE6, 0x70, + 0xF1, 0x6F, 0x35, 0xAB, 0x5F, 0x64, 0x61, 0x50, 0xC3, 0x6C, + 0xE2, 0x44, 0xFD, 0xE5, 0x22, 0x4C, 0x0D, 0x5F, 0xF9, 0x0F, + 0x6A, 0xCE, 0x7F, 0xB0, 0x19, 0xAF, 0x51, 0xA8, 0xAD, 0xDE, + 0x31, 0x2E, 0xC3, 0x64, 0x73, 0xEC, 0x90, 0x67, 0x14, 0xE0, + 0xC9, 0x69, 0xB0, 0xAB, 0xA6, 0xED, 0x91, 0x55, 0x0B, 0x8B, + 0xE5, 0x72, 0x1E, 0x85, 0xBD, 0x44, 0xE2, 0x8F, 0x62, 0xAC, + 0x8C, 0x46, 0xAA, 0x8C, 0xC1, 0xF1, 0x12, 0x8C, 0x5B, 0x5F, + 0x23, 0xC0, 0x32, 0x16, 0x4B, 0x66, 0x82, 0xB4, 0xE9, 0x81, + 0xC4, 0xF7, 0xB0, 0x24, 0x69, 0x48, 0x53, 0x4D, 0xE6, 0x26, + 0x19, 0x17, 0x75, 0xD3, 0x01, 0x02, 0x5B, 0x15, 0x1A, 0x7A, + 0x67, 0x0C, 0xCD, 0xC5, 0x45, 0x13, 0xDC, 0x70, 0x5B, 0x6D, + 0x2B, 0xE6, 0x5E, 0x13, 0x8D, 0xB4, 0xBD, 0x38, 0x48, 0x73, + 0x2A, 0x7D, 0x8A, 0x72, 0xBF, 0x5D, 0x05, 0x29, 0x75, 0xA2, + 0xA4, 0x18, 0xE9, 0xE7, 0x9D, 0x96, 0x9B, 0x37, 0x80, 0xEB, + 0x4D, 0x13, 0x87, 0x6B, 0x17, 0x58, 0x4E, 0x35, 0xCF, 0xEC, + 0x0A, 0xD0, 0xAC, 0xB2, 0x99, 0xBE, 0xB2, 0x07, 0xC1, 0x04, + 0x6F, 0xF6, 0xA0, 0x0D, 0x63, 0x05, 0x76, 0xED, 0x18, 0x71, + 0xEE, 0xCB, 0xFB, 0x90, 0x42, 0xE2, 0x24, 0x48, 0xE2, 0x3A, + 0x1D, 0x3E, 0x63, 0xE0, 0x0D, 0xDF, 0xB0, 0x71, 0x97, 0x5A, + 0x54, 0x0B, 0x32, 0x9E, 0xB5, 0xD7, 0x32, 0x62, 0x8F, 0xAE, + 0x10, 0x4E, 0xFE, 0x3C, 0x04, 0x94, 0x95, 0x61, 0x16, 0xB9, + 0xA6, 0xEB, 0xB8, 0x2E, 0x24, 0x10, 0xEA, 0xB1, 0xE1, 0x95, + 0x08, 0xE4, 0xBF, 0x7F, 0x52, 0xFA, 0x9C, 0x53, 0x29, 0x7A, + 0xFC, 0x18, 0x85, 0x02, 0xA6, 0x88, 0x94, 0x0C, 0x2C, 0x50, + 0x96, 0x7F, 0xE7, 0xA3, 0x68, 0xE8, 0xF2, 0xE4, 0x70, 0xBF, + 0x8A, 0x21, 0x03, 0x5F, 0x80, 0xDB, 0x61, 0x5F, 0x37, 0x18, + 0xBE, 0x9C, 0x4F, 0xB4, 0xAE, 0x8F, 0xB2, 0x7F, 0x92, 0x04, + 0xCE, 0x4E, 0xB5, 0x86, 0x0A, 0x57, 0x6C, 0x38, 0x31, 0x7A, + 0xD3, 0xC0, 0x35, 0x24, 0x3C, 0x61, 0xB7, 0x25, 0xF7, 0x01, + 0x3E, 0xBD, 0x0B, 0x2A, 0x8C, 0xF4, 0xF5, 0x7D, 0x54, 0x60, + 0x12, 0xED, 0xA7, 0x72, 0x59, 0x5A, 0xDB, 0x0F, 0xFB, 0x66, + 0x41, 0x6E, 0x07, 0x3A, 0x92, 0x02, 0xC5, 0xDE, 0x82, 0x4B, + 0xD9, 0xA4, 0x73, 0x37, 0xDD, 0x0C, 0xCD, 0x7E, 0xAB, 0x4D, + 0x1C, 0x06, 0xA9, 0x42, 0xBB, 0x4A, 0x2C, 0x44, 0xA3, 0xE3, + 0x10, 0x25, 0x49, 0xF2, 0x6E, 0x00, 0x3B, 0x95, 0x42, 0xEA, + 0x21, 0xD0, 0x00, 0x4D, 0xF7, 0x77, 0x37, 0x16, 0x67, 0x27, + 0xE3, 0xB6, 0x74, 0xA1, 0xAF, 0xF9, 0x66, 0x9E, 0xC9, 0xFC, + 0xBC, 0x8D, 0x7A, 0x73, 0x39, 0xBE, 0xBC, 0x11, 0x43, 0xB9, + 0x40, 0xAF, 0x07, 0xB8, 0xC2, 0x43, 0xD8, 0xB9, 0x61, 0x01, + 0x07, 0xAF, 0x90, 0xE7, 0x28, 0xCE, 0xDF, 0xBC, 0x2F, 0xE5, + 0x57, 0x75, 0xAC, 0xF2, 0x8A, 0xCE, 0x08, 0xEE, 0x32, 0x3D, + 0xA9, 0x54, 0x19, 0xB5, 0xE4, 0x12, 0x84, 0x85, 0x8C, 0x70, + 0x2E, 0x63, 0x84, 0x56, 0x27, 0xBD, 0x6C, 0x85, 0xBF, 0x1E, + 0x1A, 0x53, 0x55, 0x6D, 0x37, 0xE1, 0x71, 0xD0, 0xC1, 0xEB, + 0xC6, 0xA1, 0x19, 0x0F, 0xE4, 0xCA, 0x59, 0xAC, 0x98, 0x5E, + 0xA4, 0xE8, 0x16, 0x6A, 0xBC, 0xE3, 0xD3, 0x5C, 0x68, 0xCB, + 0xFF, 0x0F, 0x41, 0x3B, 0xBB, 0x76, 0x6A, 0xEA, 0x61, 0x59, + 0x19, 0x86, 0x8B, 0xCC, 0x73, 0x0B, 0xBC, 0x33, 0x12, 0x11, + 0x0B, 0xE8, 0xBF, 0xF5, 0x79, 0x39, 0xD5, 0x93, 0xC4, 0x8D, + 0x8C, 0x20, 0x30, 0xF4, 0x29, 0xF6, 0x93, 0xED, 0xC8, 0x8B, + 0x90, 0xA5, 0x9B, 0x47, 0x2B, 0x3F, 0xC6, 0x3F, 0xA0, 0x2A, + 0x4E, 0xB4, 0x25, 0x9E, 0xA5, 0x74, 0x01, 0x02, 0xD2, 0xEC, + 0xB9, 0x81, 0x5E, 0xCC, 0x04, 0xDD, 0xE9, 0x32, 0x0C, 0xEF, + 0x03, 0x66, 0x56, 0xF5, 0x73, 0x42, 0x98, 0x1B, 0x43, 0x6D, + 0xCC, 0xAA, 0xE8, 0xC4, 0x50, 0x37, 0x09, 0x72, 0x08, 0x84, + 0x03, 0x45, 0xA8, 0x93, 0xC8, 0xB9, 0xB6, 0xEB, 0x7F, 0x7D, + 0x6D, 0x9B, 0x5B, 0x27, 0x5B, 0x8B, 0xAC, 0xD9, 0x4A, 0x9F, + 0x04, 0x3F, 0x1C, 0x65, 0xB0, 0x3E, 0x1C, 0x3F, 0x05, 0x57, + 0x63, 0xFF, 0xF2, 0xA2, 0x96, 0xEA, 0x16, 0x03, 0xBA, 0x52, + 0x66, 0x53, 0xF1, 0x9F, 0x0B, 0xCD, 0x80, 0x01, 0x8F, 0x15, + 0x80, 0xB3, 0x31, 0xEC, 0xF9, 0x6D, 0xE7, 0x7E, 0x76, 0xA4, + 0xC1, 0xF6, 0x6F, 0x32, 0x58, 0xEF, 0x7B, 0x60, 0xFE, 0x32, + 0x1E, 0xC8, 0x48, 0xA9, 0x75, 0xEA, 0x7C, 0xD1, 0xEE, 0x6C, + 0xE7, 0xEE, 0x23, 0x2D, 0x13, 0xC0, 0x7E, 0x5D, 0xDA, 0xF1, + 0x50, 0xD2, 0x30, 0xF9, 0x9E, 0xF0, 0x95, 0xA6, 0x18, 0x09, + 0x6B, 0x0B, 0x6B, 0x6B, 0x5C, 0x83, 0xEE, 0x44, 0xB1, 0x3A, + 0xF8, 0x9A, 0xCB, 0xEC, 0x11, 0x19, 0x27, 0x11, 0x70, 0xAF, + 0x71, 0xF8, 0xE5, 0xE6, 0x2C, 0x81, 0x07, 0x59, 0x3B, 0xCB, + 0xDC, 0x2C, 0xE8, 0xE2, 0x3A, 0xBD, 0x0C, 0x45, 0x8A, 0xE7, + 0x10, 0xEF, 0x32, 0xED, 0xC2, 0xF2, 0x63, 0x57, 0x44, 0xFC, + 0x54, 0x89, 0x9D, 0xD8, 0x5F, 0xE2, 0x3C, 0xBB, 0x92, 0x98, + 0x4D, 0x71, 0x7B, 0x0C, 0x11, 0x77, 0x1E, 0x73, 0x2A, 0xBD, + 0x2A, 0xBF, 0x96, 0xF4, 0x58, 0x8E, 0x57, 0x7E, 0x52, 0xEB, + 0x6B, 0x91, 0x03, 0xA8, 0xD3, 0xEF, 0xAC, 0xBE, 0x1C, 0x23, + 0x56, 0x65, 0x08, 0x4E, 0xF4, 0x4B, 0x5F, 0x63, 0x05, 0x49, + 0x22, 0xB5, 0x2B, 0xF2, 0x0D, 0x7E, 0xE7, 0x69, 0x10, 0x82, + 0x90, 0x2B, 0x3F, 0x1E, 0x5F, 0x14, 0x31, 0x89, 0x7B, 0x00, + 0x1C, 0x78, 0x3E, 0x22, 0x21, 0x83, 0xCB, 0x24, 0xAE, 0x75, + 0x6D, 0x46, 0xF1, 0xD9, 0x35, 0x77, 0x53, 0xB8, 0xDF, 0xAD, + 0x52, 0x0C, 0x9E, 0xCC, 0x58, 0x8B, 0xE7, 0x28, 0x41, 0xB5, + 0x0A, 0xED, 0xF2, 0xE7, 0xAA, 0xAE, 0x2A, 0x3B, 0x51, 0xC6, + 0x11, 0x2B, 0x2D, 0x8E, 0x18, 0xD8, 0xAD, 0xE4, 0x34, 0x6B, + 0xFD, 0x69, 0x25, 0xBB, 0x18, 0xF1, 0x08, 0x7A, 0xB1, 0xA6, + 0x54, 0xFD, 0xA8, 0xA6, 0xF9, 0xCB, 0xEC, 0xFC, 0x4F, 0xF6, + 0x08, 0x20, 0x83, 0x08, 0x27, 0x9F, 0xB0, 0x16, 0x0A, 0xE3, + 0xBA, 0x7E, 0x1F, 0x0A, 0x57, 0x9E, 0xDF, 0x70, 0x46, 0x03, + 0x95, 0x49, 0xDE, 0xBE, 0x9F, 0x29, 0x8C, 0x5D, 0x5B, 0x37, + 0xA0, 0xF5, 0xA2, 0xF7, 0xE7, 0x1F, 0xFA, 0x4C, 0x9E, 0x11, + 0xB8, 0x9A, 0x54, 0x81, 0xF5, 0xF7, 0xCB, 0xE3, 0x0E, 0x43, + 0x87, 0x11, 0xA3, 0x25, 0x3E, 0x16, 0xBF, 0x32, 0xC0, 0x72, + 0x16, 0xDC, 0x77, 0xCE, 0x07, 0x1F, 0x18, 0xC0, 0xAA, 0x55, + 0xB7, 0x64, 0xB2, 0x92, 0x80, 0x13, 0x3B, 0x3A, 0x1D, 0xBE, + 0xF5, 0x05, 0xE2, 0xE9, 0x00, 0xE4, 0xB9, 0x15, 0x8F, 0x27, + 0x84, 0x07, 0xDA, 0x35, 0xFD, 0x1F, 0x43, 0x8E, 0x34, 0xB1, + 0x36, 0xD2, 0x32, 0xD7, 0xFD, 0xED, 0x4F, 0x56, 0x51, 0xB0, + 0x63, 0xA6, 0x3E, 0x99, 0x54, 0xCD, 0x30, 0xAD, 0x25, 0x12, + 0x18, 0xEB, 0x26, 0xBF, 0xBF, 0x49, 0x99, 0xE3, 0xD3, 0xA4, + 0x29, 0xBD, 0x72, 0x83, 0xDA, 0x27, 0x80, 0x0E, 0x4E, 0xFE, + 0x08, 0x66, 0xCF, 0x63, 0x20, 0x2D, 0x90, 0xA9, 0x4C, 0x35, + 0xC0, 0xB9, 0x08, 0x27, 0x67, 0x11, 0x72, 0x5D, 0x4D, 0x25, + 0xAE, 0x58, 0x34, 0xE6, 0xD8, 0x2D, 0xBC, 0x33, 0x37, 0x46, + 0x0D, 0x76, 0x87, 0x69, 0x14, 0x6D, 0x5B, 0x9F, 0x3B, 0x3C, + 0x1E, 0x74, 0x90, 0x2B, 0x4A, 0xF5, 0x4D, 0xD5, 0x9E, 0x12, + 0x1E, 0x72, 0x06, 0xE7, 0x80, 0xE0, 0xA6, 0x5E, 0x6A, 0x14, + 0x86, 0xB6, 0x4E, 0x5A, 0xB6, 0x28, 0xBA, 0xCF, 0x26, 0x10, + 0x66, 0xDD, 0x40, 0x46, 0x1C, 0x02, 0x18, 0xC0, 0x2F, 0xC7, + 0x8F, 0xA7, 0x6E, 0xB8, 0xB8, 0xD9, 0x82, 0xAF, 0x16, 0x17, + 0x90, 0xD0, 0xCF, 0xEF, 0xA7, 0x43, 0xC1, 0x9E, 0x66, 0x5B, + 0xB8, 0x7D, 0x7A, 0xE5, 0x21, 0xA3, 0x82, 0x13, 0xD0, 0xC4, + 0x5F, 0x3F, 0x12, 0x32, 0x59, 0xA0, 0x0A, 0x59, 0xA6, 0x33, + 0xAA, 0x78, 0x8D, 0xBE, 0xFB, 0x7B, 0xEE, 0xCF, 0x91, 0xB2, + 0x95, 0x16, 0x24, 0xDE, 0x2C, 0x7A, 0xBC, 0xB2, 0xCC, 0x5E, + 0x1A, 0x50, 0xD7, 0x2D, 0x10, 0x84, 0x49, 0xD7, 0x77, 0xF9, + 0x22, 0x65, 0xEC, 0x4E, 0x2C, 0x20, 0x61, 0x0C, 0xDD, 0x4B, + 0xC7, 0x71, 0xB7, 0xCF, 0xB9, 0x86, 0x84, 0x31, 0x50, 0xF4, + 0x7D, 0x9B, 0x73, 0x07, 0x32, 0x2A, 0xDC, 0x40, 0xC1, 0xA2, + 0x6A, 0x56, 0xAE, 0xA8, 0xA1, 0x2F, 0xF1, 0x27, 0x37, 0xB8, + 0x1A, 0x83, 0x75, 0x5F, 0xB7, 0xFA, 0x2E, 0x23, 0x9D, 0xA6, + 0xF0, 0x1C, 0xF4, 0xF6, 0x7C, 0xDA, 0xAE, 0x8E, 0xB3, 0x16, + 0xB6, 0x3B, 0xA6, 0xB0, 0x4C, 0x74, 0xBC, 0x17, 0x07, 0xEF, + 0xB4, 0x61, 0xB7, 0x42, 0xCC, 0xA4, 0x3B, 0x65, 0x5A, 0xF2, + 0x98, 0x01, 0xBD, 0x46, 0xCD, 0x2F, 0xAB, 0x04, 0x3F, 0xD8, + 0x58, 0xB7, 0xA1, 0xE4, 0xCE, 0x6B, 0xD1, 0x33, 0x17, 0x5B, + 0x84, 0x7D, 0x85, 0x88, 0x6A, 0x50, 0x4D, 0x11, 0xE5, 0x5F, + 0x06, 0xF7, 0x59, 0x55, 0x16, 0xA0, 0x74, 0x53, 0xC9, 0x2A, + 0x26, 0xF2, 0x4F, 0x6F, 0x25, 0xFB, 0x09, 0x34, 0x28, 0x16, + 0x14, 0xD2, 0x95, 0xF3, 0xB3, 0xC8, 0x6C, 0x19, 0xC5, 0xED, + 0x4A, 0x38, 0x03, 0x89, 0x68, 0x14, 0x00, 0xB0, 0xAD, 0x9F, + 0xBE, 0xCD, 0x16, 0x9E, 0x68, 0xBC, 0x17, 0xBB, 0xF8, 0x42, + 0x9A, 0x8E, 0x3D, 0x7C, 0x1A, 0x32, 0x0E, 0x82, 0x91, 0x9C, + 0xB8, 0xD9, 0x85, 0xF1, 0x17, 0x68, 0xE8, 0x3E, 0x00, 0x21, + 0xAC, 0x05, 0x1F, 0x2F, 0x47, 0xC6, 0x2D, 0x88, 0x2F, 0x31, + 0x13, 0x15, 0x25, 0x77, 0x8C, 0x5C, 0x8B, 0x3F, 0x32, 0xBB, + 0xA0, 0xAE, 0x44, 0x2D, 0x17, 0x92, 0xD1, 0xB3, 0x29, 0xA4, + 0x73, 0x7C, 0x26, 0x5C, 0xE6, 0x1C, 0x0D, 0x7D, 0xFA, 0xF2, + 0x8A, 0xAD, 0x27, 0x6A, 0x9F, 0x7E, 0x35, 0x7F, 0x77, 0x46, + 0x42, 0x39, 0xE3, 0x5E, 0x6A, 0xFA, 0x93, 0x9C, 0x2C, 0xA0, + 0x2A, 0x48, 0x4D, 0xF4, 0xAE, 0x56, 0x07, 0x37, 0x1C, 0x94, + 0x0B, 0x74, 0xEA, 0x91, 0xF2, 0x09, 0x66, 0x89, 0xFC, 0x27, + 0xA3, 0x3D, 0x7C, 0x91, 0xB2, 0xD2, 0x94, 0x68, 0x2B, 0xC3, + 0x55, 0x59, 0x6D, 0xC8, 0x56, 0xF2, 0x11, 0x94, 0x56, 0x88, + 0x72, 0x9D, 0x62, 0xCB, 0x52, 0x48, 0x1C, 0x54, 0x6F, 0xF1, + 0x48, 0xB0, 0x42, 0xA7, 0xDD, 0xFA, 0x05, 0x79, 0x11, 0x36, + 0x3F, 0x91, 0xBB, 0x4A, 0x68, 0x23, 0xE1, 0x8B, 0x92, 0xD8, + 0x0F, 0x25, 0x44, 0xFB, 0x1E, 0xD8, 0xBC, 0xB7, 0x6F, 0xF5, + 0xA6, 0x77, 0xE9, 0xBD, 0x24, 0x46, 0xFE, 0x69, 0x1B, 0xB3, + 0x95, 0xDF, 0xAD, 0xE1, 0xEC, 0xBF, 0xB9, 0x88, 0xB7, 0x16, + 0x65, 0x26, 0x5F, 0xE5, 0xCA, 0x38, 0x87, 0x3D, 0xDD, 0x03, + 0xE1, 0xB4, 0x80, 0xE6, 0x16, 0x4E, 0xBA, 0xA7, 0x5E, 0x2A, + 0xA9, 0xA3, 0xF5, 0x58, 0xCB, 0x96, 0xA1, 0xAD, 0x60, 0xC8, + 0xB9, 0x7E, 0xC4, 0x24, 0x7A, 0xE5, 0xAB, 0x45, 0xF5, 0x4F, + 0x0F, 0xDC, 0xF0, 0x9D, 0xF1, 0xAC, 0x64, 0x78, 0x63, 0xEC, + 0xCA, 0x84, 0x81, 0x47, 0xC2, 0xDF, 0xA7, 0xE5, 0x90, 0x3A, + 0x35, 0x2F, 0x08, 0xD6, 0xBE, 0x91, 0x1C, 0x9A, 0xBE, 0x2F, + 0x4F, 0xE7, 0xD0, 0xDA, 0xDF, 0x1F, 0x5B, 0x89, 0xC6, 0xF0, + 0xB5, 0xA9, 0x28, 0x27, 0xF9, 0x32, 0x0B, 0xE1, 0x58, 0x86, + 0x1C, 0x57, 0x68, 0xD9, 0x1F, 0x5F, 0x16, 0x6F, 0x35, 0x99, + 0x5F, 0xF7, 0xBA, 0xB7, 0x1E, 0xDD, 0x42, 0xFC, 0xC9, 0xEF, + 0x54, 0xE4, 0x48, 0x9D, 0x33, 0x82, 0x45, 0x63, 0x55, 0x1A, + 0x3B, 0x1D, 0x72, 0x59, 0x97, 0x80, 0x97, 0xB5, 0x98, 0x79, + 0x6E, 0x31, 0x20, 0x0A, 0x27, 0x72, 0x39, 0x75, 0x53, 0xDC, + 0x54, 0xD6, 0xDB, 0xF9, 0xE0, 0x23, 0x4D, 0x14, 0xAE, 0xF0, + 0xB9, 0xAE, 0x1B, 0xBD, 0x78, 0x86, 0x07, 0x63, 0xC8, 0x39, + 0x72, 0x3B, 0xC5, 0xED, 0xED, 0xAA, 0x17, 0x81, 0x3A, 0x4A, + 0x0D, 0x1D, 0xEB, 0xAC, 0x29, 0x93, 0x37, 0x9D, 0x87, 0xF5, + 0xE2, 0x5E, 0x0B, 0xDC, 0x47, 0x06, 0x8A, 0x20, 0xE1, 0x5E, + 0x41, 0xC5, 0x29, 0x88, 0xA2, 0x14, 0xCE, 0xE5, 0x9E, 0xFE, + 0xF2, 0x0F, 0x64, 0xC2, 0x8D, 0x5C, 0x42, 0xC4, 0x8E, 0x55, + 0x73, 0x95, 0xE2, 0xAA, 0x19, 0x97, 0x14, 0x89, 0x5C, 0x7B, + 0xA0, 0x52, 0xBD, 0x6E, 0xF0, 0xD3, 0xBE, 0x07, 0xD6, 0x12, + 0x8A, 0x50, 0x69, 0x4B, 0x85, 0x4B, 0x3B, 0xE5, 0xF7, 0x92, + 0x73, 0xD7, 0xE8, 0xD6, 0xD5, 0x39, 0x45, 0xCC, 0x38, 0x29, + 0xDC, 0x09, 0x1E, 0x93, 0x9F, 0x4D, 0xB7, 0x8E, 0x73, 0xAA, + 0xEF, 0x66, 0x0C, 0x16, 0x25, 0x9E, 0x36, 0xC7, 0x6F, 0x4F, + 0xD0, 0x79, 0xD7, 0x24, 0xED, 0xD4, 0xED, 0x61, 0x2A, 0x85, + 0x0A, 0xB3, 0x6A, 0xF4, 0x5A, 0x25, 0x92, 0x25, 0x2F, 0x5F, + 0xBC, 0xF2, 0x10, 0xD8, 0x5E, 0xF5, 0x37, 0xFB, 0xAF, 0xBA, + 0x5B, 0x7A, 0xB7, 0x3F, 0xF4, 0x2C, 0xD7, 0x9C, 0x33, 0xDD, + 0x3A, 0xAD, 0x87, 0x8E, 0x07, 0x36, 0xD5, 0xD7, 0xD7, 0xFF, + 0x3E, 0x9B, 0x4C, 0x10, 0x35, 0xBB, 0x3A, 0x4A, 0xD3, 0xE0, + 0xB8, 0xC1, 0x3A, 0x35, 0x03, 0xE7, 0x2C, 0x9E, 0xB7, 0xCF, + 0x07, 0xD4, 0xD4, 0xC4, 0xF3, 0x69, 0x79, 0x70, 0x46, 0x53, + 0x95, 0x5C, 0x6C, 0x8D, 0xA9, 0xBD, 0xEF, 0x1B, 0xA0, 0x03, + 0x58, 0x01, 0x66, 0x31, 0x03, 0x8E, 0x48, 0x82, 0x34, 0x6A, + 0x87, 0xAE, 0x26, 0x1E, 0x21, 0x56, 0xF4, 0x3D, 0x33, 0xF7, + 0x73, 0x72, 0x39, 0x56, 0x42, 0x91, 0xDF, 0x47, 0x37, 0x5B, + 0xBD, 0x6B, 0xAC, 0xD8, 0xB6, 0x03, 0x11, 0xC3, 0xA0, 0xF1, + 0xE7, 0x7A, 0xAE, 0xCC, 0xDE, 0xAF, 0xE5, 0x77, 0xF8, 0xAE, + 0xB2, 0x92, 0x0B, 0x6D, 0x9D, 0xDC, 0x52, 0x68, 0x2A, 0xD3, + 0xA4, 0x22, 0x71, 0x78, 0x30, 0x4B, 0xD0, 0x0E, 0xB9, 0x27, + 0x52, 0x78, 0x80, 0x82, 0x1E, 0xA3, 0x2E, 0x4E, 0x74, 0x9B, + 0xB4, 0x38, 0xBC, 0x2E, 0x0D, 0x5C, 0x6B, 0x8D, 0x61, 0xE0, + 0xAD, 0xDC, 0x81, 0xBC, 0x63, 0x31, 0x77, 0x88, 0xAF, 0xED, + 0x77, 0x7A, 0x05, 0xE8, 0x1B, 0x93, 0x84, 0xB8, 0x81, 0xEC, + 0xB7, 0xFE, 0x8D, 0x67, 0x26, 0x18, 0x2D, 0x3A, 0x2B, 0x59, + 0xA2, 0x5A, 0x14, 0x98, 0x1E, 0xDF, 0x95, 0xDC, 0x9B, 0x87, + 0xD8, 0x3A, 0x29, 0xCB, 0x7E, 0xB4, 0xA7, 0x7C, 0xFC, 0x3D, + 0x0E, 0xDB, 0xB3, 0x1A, 0xC0, 0xD6, 0x18, 0x52, 0x7B, 0xF9, + 0x5E, 0x5B, 0xBA, 0x80, 0xAB, 0xCD, 0x3C, 0x65, 0xA5, 0xA9, + 0x9C, 0x19, 0xE5, 0xA6, 0x55, 0x61, 0xA9, 0xCF, 0xFB, 0xF4, + 0xF1, 0xC5, 0xB7, 0x1C, 0x24, 0x1C, 0x5B, 0x34, 0x8E, 0x5E, + 0x5A, 0x98, 0x0F, 0x31, 0x9E, 0x51, 0x92, 0x93, 0x20, 0xE8, + 0x14, 0x48, 0x50, 0x0E, 0x02, 0x40, 0x2C, 0x26, 0x4B, 0x23, + 0x59, 0x28, 0xE4, 0x5C, 0x32, 0x5B, 0x38, 0xAD, 0x73, 0x1E, + 0x20, 0xCD, 0x8C, 0x09, 0xAB, 0x31, 0x52, 0x62, 0x12, 0x5D, + 0x71, 0x9A, 0x96, 0x20, 0x00, 0x2A, 0x1C, 0x28, 0x3A, 0x27, + 0x59, 0x91, 0x23, 0x63, 0x45, 0x43, 0xA6, 0x2C, 0x43, 0x87, + 0x9B, 0x6B, 0xF6, 0x77, 0xBD, 0x58, 0x53, 0xC4, 0x1B, 0x3F, + 0x2E, 0x8D, 0xB2, 0x05, 0x5D, 0xB8, 0x60, 0xEB, 0x38, 0xC0, + 0x41, 0xFF, 0xE7, 0xE8, 0x98, 0xEB, 0x72, 0x6C, 0x48, 0xBE, + 0x07, 0x6C, 0x7A, 0x0D, 0x74, 0x6A, 0x61, 0x9B, 0x37, 0x59, + 0xC3, 0x4B, 0x12, 0xE7, 0xD7, 0xB2, 0x9C, 0x05, 0x90, 0xA8, + 0x0E, 0xBD, 0xA8, 0x65, 0x81, 0xC9, 0x89, 0x02, 0xC4, 0x2E, + 0xC8, 0x7E, 0x65, 0xF3, 0xA0, 0x1F, 0xD5, 0xF5, 0x6A, 0x70, + 0xE7, 0x83, 0x59, 0xE3, 0x76, 0xC5, 0x63, 0x4A, 0xE9, 0xB6, + 0x9C, 0x80, 0x1D, 0xCD, 0x8E, 0x35, 0x61, 0xC7, 0x4B, 0x33, + 0x79, 0x7E, 0x5C, 0x7F, 0x9C, 0x64, 0x02, 0x32, 0x23, 0x7E, + 0xB6, 0xE2, 0x4A, 0x1A, 0x03, 0x48, 0x2C, 0x6C, 0x05, 0xE6, + 0xD9, 0x7D, 0x5E, 0x5F, 0xBF, 0x20, 0x66, 0x41, 0xA7, 0x75, + 0x32, 0xF7, 0x3A, 0xC0, 0x42, 0x3E, 0xF8, 0xBE, 0x6F, 0xF1, + 0x0A, 0x23, 0xB1, 0x60, 0x13, 0x4C, 0x2F, 0x67, 0xE6, 0x3A, + 0x06, 0xD2, 0xBA, 0x20, 0xDB, 0x2B, 0x45, 0x14, 0xB2, 0x4C, + 0xC1, 0x1A, 0xA7, 0xEE, 0x90, 0xF0, 0x7D, 0xD7, 0x76, 0x71, + 0x5D, 0xFA, 0xBB, 0x2B, 0xB9, 0x40, 0xD6, 0xC9, 0xBB, 0x7D, + 0x63, 0xFD, 0x7C, 0xB2, 0xBE, 0x59, 0x7D, 0x73, 0x36, 0x8D, + 0xAA, 0xB5, 0x2F, 0x86, 0x4F, 0xEB, 0xA0, 0x6F, 0xB0, 0xF7, + 0x96, 0xE4, 0xDE, 0x3E, 0x06, 0xE6, 0x96, 0x76, 0x87, 0xAC, + 0x2A, 0xA8, 0x21, 0x05, 0x47, 0xEA, 0xEC, 0x79, 0xC9, 0x73, + 0xFF, 0xB8, 0x5E, 0xCB, 0x10, 0x41, 0x5C, 0xDF, 0x61, 0x04, + 0xEA, 0x37, 0x1A, 0x5B, 0xAF, 0xEF, 0x14, 0xEB, 0x90, 0x3D, + 0xCD, 0x1A, 0xB0, 0x25, 0xC8, 0x6C, 0x71, 0x72, 0x31, 0xB1, + 0xDA, 0xD4, 0x9A, 0x8D, 0x18, 0xEA, 0xA4, 0xD8, 0x84, 0x77, + 0x33, 0xAA, 0xB5, 0x46, 0x9A, 0xA6, 0x44, 0x68, 0xE1, 0xC0, + 0xBF, 0xA8, 0x77, 0xF2, 0xF6, 0x6B, 0xAE, 0x46, 0x4F, 0x1A, + 0x64, 0x24, 0x2E, 0x02, 0x50, 0x57, 0x06, 0x1E, 0x0A, 0x78, + 0xB1, 0xB7, 0x92, 0x5C, 0x62, 0x9C, 0x26, 0x66, 0xA0, 0xD0, + 0x70, 0xC6, 0x0C, 0xFE, 0x7C, 0x28, 0xFC, 0x45, 0xEE, 0x51, + 0x47, 0x90, 0xBC, 0x1E, 0x42, 0x89, 0x1F, 0x39, 0xDA, 0xAB, + 0x4D, 0x06, 0xBE, 0xC1, 0x5F, 0x59, 0x8C, 0x28, 0x41, 0xF5, + 0x13, 0xB5, 0x99, 0x12, 0x71, 0x4B, 0xBF, 0xE9, 0x39, 0xD5, + 0x56, 0x02, 0x53, 0x24, 0x99, 0xAC, 0xD2, 0x22, 0x90, 0x0C, + 0x2D, 0xC8, 0xAA, 0x84, 0x7F, 0x8B, 0xD8, 0x40, 0xEB, 0x93, + 0x4D, 0x08, 0x8F, 0xE5, 0x2C, 0xE6, 0x1F, 0x65, 0xDD, 0x1A, + 0xD0, 0x1C, 0xE3, 0x8F, 0xCA, 0x84, 0x8F, 0x85, 0x98, 0xD1, + 0x87, 0x09, 0xC9, 0xFF, 0xBC, 0x0E, 0xDE, 0x67, 0x35, 0x75, + 0x99, 0x51, 0xD4, 0x89, 0x1E, 0xED, 0xA6, 0xA4, 0x6D, 0x01, + 0xFB, 0x61, 0xCF, 0xA2, 0xC2, 0x9A, 0x7B, 0xE6, 0xE7, 0xFF, + 0xA1, 0x5A, 0x18, 0x9D, 0x3A, 0x77, 0x62, 0x75, 0xE4, 0x53, + 0x92, 0x35, 0xD1, 0x66, 0x40, 0x96, 0x53, 0x80, 0x12, 0x9C, + 0x7B, 0x6E, 0xF8, 0xEC, 0x3B, 0x90, 0xB9, 0x32, 0xB0, 0x90, + 0xA6, 0x8C, 0x9A, 0xDD, 0xF7, 0xA5, 0x5A, 0xF9, 0xFD, 0x9D, + 0x08, 0x1C, 0xB9, 0x71, 0x82, 0x90, 0x00, 0x42, 0xBE, 0x2B, + 0xA3, 0x44, 0xD4, 0xED, 0x5E, 0xBE, 0x55, 0x1C, 0xD4, 0x84, + 0x99, 0x56, 0x9D, 0x1D, 0xDB, 0x74, 0x70, 0xEF, 0x48, 0xA8, + 0x8D, 0xC3, 0x40, 0xD9, 0xE3, 0xAC, 0x7C, 0x43, 0xC5, 0xFF, + 0x03, 0x15, 0x61, 0x4A, 0xB3, 0x96, 0x35, 0x93, 0x5B, 0x3C, + 0xBE, 0x16, 0x1F, 0x10, 0xC1, 0xC0, 0x04, 0x67, 0x7C, 0x0D, + 0xE4, 0x78, 0x53, 0x48, 0x90, 0x28, 0xF6, 0x2F, 0xB0, 0xE8, + 0x24, 0xB5, 0x3F, 0x92, 0xF6, 0xBF, 0xD0, 0xCC, 0x9B, 0x76, + 0x72, 0xC5, 0xFE, 0xAB, 0x82, 0x8E, 0x2D, 0x64, 0x5A, 0x93, + 0xAE, 0xFA, 0x30, 0x7E, 0x9E, 0x27, 0x89, 0x03, 0x77, 0x81, + 0x53, 0x13, 0xD8, 0x9B, 0x3D, 0x97, 0x36, 0x1B, 0xAE, 0x3D, + 0xDC, 0xEF, 0x6D, 0xCA, 0xC1, 0x22, 0x11, 0x9C, 0xB3, 0xBD, + 0x31, 0x31, 0xDB, 0x29, 0x3D, 0x3A, 0xFF, 0x2A, 0x99, 0x5D, + 0x40, 0x29, 0xB8, 0x3D, 0x17, 0x2F, 0xA6, 0xDC, 0x2D, 0xD7, + 0x21, 0x75, 0x44, 0x16, 0x74, 0xAB, 0x7E, 0xE4, 0x2A, 0x4A, + 0x26, 0xB3, 0x7F, 0xDC, 0x9D, 0x4B, 0x1A, 0xF7, 0xD5, 0xF3, + 0x91, 0x96, 0x62, 0xB4, 0xF6, 0x38, 0x5E, 0x92, 0x52, 0xB5, + 0x62, 0x21, 0x62, 0x7E, 0xF1, 0xB3, 0x6E, 0xD3, 0x46, 0x3F, + 0xC6, 0xD0, 0x31, 0xD9, 0x44, 0xE6, 0x6C, 0xA1, 0xAF, 0x6C, + 0x0C, 0x74, 0xA2, 0x57, 0x08, 0x80, 0x64, 0xBD, 0x3D, 0x6C, + 0xFA, 0xFD, 0x5C, 0xFD, 0xBC, 0x41, 0x4A, 0x38, 0xBC, 0xCD, + 0x30, 0xC2, 0x44, 0x58, 0xFE, 0x77, 0x89, 0xC8, 0x1F, 0x23, + 0xFD, 0xA3, 0x1C, 0xE5, 0x04, 0x59, 0x7D, 0x84, 0x55, 0x54, + 0x60, 0x7C, 0x65, 0x2D, 0xFF, 0x26, 0xD1, 0x59, 0xBF, 0x35, + 0xBB, 0xD1, 0x2E, 0x94, 0x1B, 0x3E, 0x8F, 0x03, 0x3B, 0x1D, + 0xA7, 0x36, 0x39, 0xFD, 0xAC, 0x64, 0xCE, 0x5C, 0xB9, 0xC6, + 0xDE, 0x5F, 0x3D, 0xF5, 0xBE, 0xD3, 0xE5, 0x7F, 0x4F, 0x71, + 0xCE, 0x09, 0x8D, 0xA2, 0x4C, 0x32, 0x50, 0xE4, 0xA9, 0xFE, + 0x84, 0xD9, 0xD5, 0x7F, 0xE7, 0x83, 0x73, 0xFD, 0x97, 0x01, + 0xBD, 0xBB, 0x33, 0xBD, 0xDA, 0xD3, 0x78, 0x7D, 0x8C, 0x9E, + 0xF2, 0xE1, 0xD4, 0x4C, 0xCD, 0xB3, 0x2C, 0x9A, 0x29, 0x97, + 0x63, 0x54, 0x69, 0x2A, 0x01, 0xC5, 0xA8, 0x12, 0xD4, 0x4D, + 0x4C, 0xB2, 0xD6, 0x96, 0xC0, 0x23, 0x7A, 0x9B, 0x1E, 0xDE, + 0xD4, 0x3D, 0x71, 0x21, 0x21, 0x79, 0x70, 0x09, 0x3F, 0xCA, + 0x26, 0xA9, 0xC9, 0x6B, 0x72, 0xFE, 0xFD, 0x69, 0xA6, 0x21, + 0x57, 0x64, 0xF2, 0x8D, 0xB7, 0x24, 0xFD, 0x04, 0x34, 0xBF, + 0x6E, 0x0B, 0x15, 0x6D, 0x09, 0x21, 0x58, 0xDD, 0xB2, 0xE4, + 0xCB, 0x98, 0x2F, 0x75, 0x86, 0xAE, 0x6F, 0x72, 0x56, 0x0C, + 0x7D, 0x45, 0x48, 0xB0, 0xC5, 0x2C, 0xAD, 0x6E, 0xA5, 0xE1, + 0x0D, 0x61, 0x71, 0xFB, 0x6D, 0x44, 0x5D, 0x2E, 0x32, 0x07, + 0xD2, 0xB8, 0x08, 0x19, 0x01, 0x92, 0xCA, 0x4C, 0x33, 0xD2, + 0x5D, 0x44, 0xDC, 0xF6, 0x1F, 0xDC, 0x13, 0xEF, 0x0E, 0xE5, + 0x83, 0x3E, 0xA8, 0x0B, 0xB7, 0x70, 0x25, 0x7E, 0x4E, 0x93, + 0xC2, 0x64, 0x79, 0xC4, 0x2A, 0x0F, 0xFB, 0xBE, 0xD6, 0x4F, + 0xB5, 0x58, 0xA5, 0x22, 0x0F, 0xBE, 0x53, 0x41, 0x2E, 0x12, + 0x1C, 0x29, 0xF5, 0xD9, 0x51, 0x76, 0xBD, 0x06, 0x9C, 0x96, + 0x9F, 0x26, 0x1F, 0x81, 0xF5, 0xEC, 0x83, 0xA2, 0xD1, 0x04, + 0x18, 0x38, 0xAD, 0x4A, 0x91, 0xAE, 0xB3, 0xA9, 0x54, 0x95, + 0xE6, 0xBF, 0x35, 0x44, 0xAF, 0x6E, 0xC4, 0x57, 0x3F, 0x51, + 0x32, 0x96, 0x15, 0xB9, 0xD2, 0x28, 0x4F, 0xBA, 0xFB, 0xA8, + 0x0E, 0xA9, 0x61, 0xD8, 0xB0, 0x97, 0x83, 0x72, 0xDE, 0x7A, + 0x22, 0xCD, 0xE6, 0xA6, 0x6B, 0xCD, 0x12, 0x41, 0xAC, 0x1B, + 0xCD, 0x82, 0x88, 0x58, 0x32, 0x09, 0x93, 0xFB, 0x38, 0xDC, + 0xCB, 0x91, 0x5F, 0xF0, 0xB1, 0x53, 0x5A, 0xB3, 0x79, 0x50, + 0xEF, 0x02, 0xAA, 0xEC, 0xD4, 0xD2, 0x73, 0xF2, 0x49, 0xAA, + 0x02, 0x65, 0x0D, 0x13, 0xE9, 0xAB, 0xEF, 0xF8, 0xE6, 0xC3, + 0xA3, 0xAA, 0xE2, 0x37, 0xD9, 0xBF, 0x44, 0xEA, 0x44, 0xA7, + 0x0C, 0x90, 0x8A, 0x0E, 0xC4, 0x4E, 0x11, 0xB5, 0xF1, 0xF1, + 0x3C, 0xD7, 0x9D, 0x95, 0xE7, 0xC6, 0x53, 0x05, 0x9A, 0x14, + 0x49, 0x1B, 0xB8, 0xCA, 0xCD, 0xE8, 0xFA, 0x95, 0xA5, 0xC8, + 0xBB, 0xC3, 0xE0, 0xB8, 0xF1, 0x78, 0xE5, 0x8E, 0xBE, 0x0F, + 0xC9, 0x25, 0x79, 0x44, 0x89, 0xFC, 0x3D, 0x9F, 0x87, 0x57, + 0x24, 0x46, 0x7B, 0x1D, 0x4E, 0xB6, 0xEC, 0xD7, 0x8F, 0xF3, + 0x8E, 0x17, 0xEF, 0x02, 0x59, 0x4E, 0x79, 0x06, 0x1D, 0x28, + 0x3D, 0x70, 0x43, 0x21, 0x27, 0xDB, 0x22, 0x6A, 0x48, 0x1B, + 0x6C, 0xDE, 0xF8, 0x65, 0x5E, 0x16, 0x83, 0x51, 0xC6, 0x94, + 0xC3, 0xEC, 0x51, 0xAB, 0x2A, 0x1B, 0x44, 0xB6, 0xC5, 0x76, + 0x0C, 0x8A, 0xDE, 0x0F, 0x24, 0xEF, 0x40, 0x43, 0x79, 0x5A, + 0x11, 0x68, 0x03, 0xD4, 0x97, 0xF8, 0x97, 0xA9, 0xBE, 0x86, + 0x1C, 0x57, 0xEC, 0xD4, 0xC5, 0xFB, 0x22, 0x8D, 0x7D, 0xA7, + 0xD9, 0x06, 0x49, 0x03, 0xB3, 0xD8, 0x81, 0x9B, 0x70, 0x17, + 0xB4, 0x79, 0x6E, 0x2E, 0xDB, 0x82, 0x6A, 0x97, 0xBE, 0x14, + 0x1A, 0xD4, 0xC9, 0x98, 0x32, 0xB3, 0xC7, 0x04, 0x8F, 0x7F, + 0xBF, 0x3E, 0x6F, 0x4C, 0x87, 0xDA, 0xD7, 0xF2, 0xF1, 0x66, + 0x8F, 0xF5, 0x67, 0xBD, 0xCD, 0xEF, 0x93, 0xB2, 0xE6, 0xB5, + 0x39, 0x75, 0xC3, 0xDD, 0xCC, 0x0F, 0xA4, 0x47, 0x5A, 0xCE, + 0xD4, 0xD0, 0xA0, 0xF8, 0x05, 0x05, 0x8B, 0x70, 0xC3, 0x25, + 0x5B, 0x8E, 0x90, 0x9B, 0xF1, 0x17, 0x0F, 0xF8, 0x3B, 0x54, + 0xF8, 0x4E, 0xE0, 0x86, 0x95, 0x94, 0x38, 0x1C, 0x12, 0x28, + 0x2B, 0xB1, 0x5C, 0xE0, 0x5E, 0x09, 0xA2, 0xD8, 0x87, 0x8D, + 0x34, 0x4A, 0x32, 0x8B, 0x8A, 0x5C, 0x5C, 0x67, 0x34, 0x24, + 0x60, 0xD6, 0x57, 0xB4, 0x7C, 0x26, 0x3F, 0x01, 0x73, 0x08, + 0xF4, 0x6A, 0x2B, 0x96, 0x26, 0x90, 0x55, 0x76, 0x2C, 0xE8, + 0xA8, 0xE3, 0x67, 0x5B, 0x61, 0x19, 0x2E, 0x9E, 0x03, 0x3B, + 0xF4, 0x57, 0xC1, 0xE0, 0xFB, 0x88, 0x6F, 0xDB, 0x47, 0x7A, + 0x50, 0x1A, 0xBB, 0xFB, 0x69, 0xCC, 0xEA, 0xE8, 0xA2, 0xB2, + 0x8C, 0x74, 0xF2, 0xE4, 0x96, 0xFE, 0x2B, 0xE1, 0xD1, 0x1F, + 0xC1, 0x63, 0xDB, 0x1B, 0x7A, 0xEE, 0xE1, 0xAB, 0x50, 0xA2, + 0x73, 0x60, 0x93, 0xB4, 0x73, 0x3E, 0x3E, 0x44, 0x6C, 0x0E, + 0x6F, 0x11, 0x08, 0x1E, 0x8B, 0x16, 0x9E, 0xB1, 0xD4, 0xA9, + 0x73, 0x61, 0x63, 0x79, 0x4F, 0x28, 0xE9, 0x00, 0xAB, 0x72, + 0x0C, 0xF8, 0x39, 0xC2, 0xA4, 0x9F, 0x74, 0x5C, 0x61, 0x13, + 0xFA, 0x14, 0x8E, 0x9D, 0x26, 0x69, 0xF5, 0x55, 0x4B, 0x99, + 0x6B, 0xD0, 0xCA, 0x08, 0xF9, 0xD2, 0xF0, 0xB5, 0xE3, 0xCC, + 0x2A, 0x39, 0x62, 0xCB, 0x30, 0xBB, 0x08, 0xA2, 0x05, 0x7A, + 0x46, 0x72, 0xD9, 0x58, 0x6E, 0x48, 0x7E, 0x7B, 0x5D, 0xF8, + 0x85, 0x49, 0x5F, 0xF0, 0x3E, 0x94, 0xB5, 0x85, 0x71, 0xCD, + 0xB6, 0xAF, 0xEC, 0x03, 0xF1, 0x42, 0x7E, 0xC3, 0x2C, 0x41, + 0x10, 0x0F, 0x24, 0x4D, 0xB5, 0x22, 0xB2, 0x65, 0x11, 0xEA, + 0x9C, 0x06, 0xED, 0x71, 0x29, 0xC9, 0x6A, 0xA9, 0x50, 0xF6, + 0xB8, 0xB4, 0x87, 0xAB, 0x0A, 0x9B, 0x7B, 0x3F, 0x83, 0xFB, + 0x1F, 0x97, 0x58, 0x24, 0xAE, 0xE9, 0x8B, 0xB4, 0xDF, 0xF6, + 0x12, 0x4F, 0x5B, 0x54, 0x1E, 0xF5, 0x7A, 0x14, 0xE0, 0xAF, + 0xA2, 0x26, 0xC6, 0xB8, 0x8C, 0xE5, 0xFA, 0x25, 0x7A, 0xD4, + 0x91, 0x0D, 0xDE, 0x84, 0x3F, 0xC5, 0x9D, 0x53, 0xEC, 0x9E, + 0x85, 0x68, 0x5D, 0x25, 0xAA, 0x0F, 0x0B, 0xB9, 0x8A, 0x5F, + 0x74, 0xBA, 0x78, 0xC9, 0x7F, 0x5A, 0x70, 0x5D, 0x97, 0x9A, + 0x77, 0x4F, 0x72, 0x77, 0x91, 0x5D, 0x38, 0xAB, 0xC6, 0x40, + 0x54, 0x76, 0x43, 0xC4, 0xA8, 0xE9, 0xD1, 0xDF, 0x3F, 0xC2, + 0xF0, 0xAE, 0x8C, 0x52, 0x19, 0xCC, 0xEE, 0x43, 0x26, 0x71, + 0xEE, 0x03, 0x38, 0x0C, 0x9C, 0xB0, 0x04, 0x57, 0x6B, 0xDA, + 0x09, 0xD1, 0x9C, 0x2D, 0x97, 0xF2, 0xFE, 0x4C, 0x45, 0x15, + 0x70, 0x44, 0x12, 0x56, 0x2E, 0x48, 0x50, 0x72, 0x0B, 0x07, + 0x5E, 0xB5, 0xC0, 0x44, 0xC0, 0x7A, 0xDA, 0x2E, 0xCF, 0x13, + 0x4E, 0x29, 0xCA, 0x02, 0xB0, 0x12, 0x52, 0xE6, 0x24, 0xA9, + 0x07, 0x9B, 0x54, 0x56, 0x0D, 0x09, 0xD2, 0x97, 0xF8, 0xE7, + 0x13, 0xAA, 0x33, 0xCE, 0xF9, 0x3E, 0x0E, 0xFE, 0x9D, 0x4E, + 0x2D, 0x93, 0x03, 0x9E, 0xF7, 0x2E, 0x0E, 0x09, 0x13, 0xC8, + 0x2E, 0xC0, 0xF9, 0x43, 0xE1, 0x31, 0xC1, 0x74, 0xA2, 0x17, + 0xFA, 0xCD, 0x4B, 0x07, 0x10, 0xE8, 0x77, 0x9D, 0x14, 0x9C, + 0xAC, 0x06, 0x00, 0x09, 0x8A, 0x61, 0x7D, 0x9C, 0x45, 0xE1, + 0x78, 0x6D, 0x46, 0x1B, 0x47, 0x8E, 0xB7, 0x82, 0x8D, 0xE1, + 0xE9, 0xF6, 0x4A, 0x69, 0xC6, 0xCF, 0x75, 0x1D, 0xC1, 0x6C, + 0xA2, 0x06, 0xDC, 0x28, 0x5F, 0xF3, 0x19, 0xE9, 0xB6, 0x09, + 0x57, 0x2E, 0x3E, 0xA3, 0xF7, 0xC2, 0x79, 0x8A, 0x17, 0x16, + 0xB6, 0x76, 0x39, 0xA0, 0xD1, 0x38, 0xF2, 0x63, 0xAA, 0xBB, + 0xCC, 0x0C, 0x59, 0x86, 0x6A, 0xC8, 0xC4, 0x93, 0xD1, 0x83, + 0x63, 0x5A, 0xD4, 0xAA, 0x41, 0xE7, 0x90, 0xA7, 0x79, 0xC3, + 0xDE, 0x1C, 0x04, 0x78, 0x17, 0x87, 0x93, 0xA4, 0x0A, 0x88, + 0x29, 0xE7, 0xB6, 0x4C, 0xD0, 0x74, 0x5A, 0x7F, 0xC7, 0xC9, + 0xFD, 0x89, 0x4E, 0xAF, 0x36, 0x85, 0x8D, 0x7D, 0x50, 0xC5, + 0x82, 0x7D, 0x03, 0xC6, 0x70, 0x33, 0x09, 0x8C, 0xA3, 0x3B, + 0x60, 0x74, 0x8F, 0xEA, 0xEB, 0xF0, 0x90, 0x12, 0xA4, 0xD5, + 0xCE, 0x48, 0xDA, 0x61, 0x9E, 0xB8, 0x86, 0x90, 0x66, 0x5B, + 0x5B, 0x1B, 0xB1, 0x7C, 0x0F, 0x2C, 0x99, 0x88, 0x1E, 0x3D, + 0x26, 0xF9, 0x24, 0xBC, 0x54, 0x11, 0xEB, 0x90, 0xCA, 0x1A, + 0x11, 0xCA, 0x71, 0x2B, 0x2B, 0x22, 0xF1, 0x5C, 0x56, 0xFD, + 0x7B, 0xB3, 0x57, 0x76, 0x68, 0x2E, 0x9C, 0x68, 0xB8, 0xA3, + 0x01, 0x31, 0x4F, 0xF9, 0xCB, 0xB3, 0x2D, 0x95, 0x21, 0xC3, + 0x9C, 0xDE, 0xE3, 0x57, 0xC2, 0x0F, 0xBE, 0x20, 0xBD, 0xEE, + 0x6D, 0xA4, 0x27, 0x6E, 0x5B, 0x65, 0x76, 0xF1, 0x30, 0xB4, + 0x0D, 0x0D, 0x95, 0xC8, 0x83, 0x13, 0x23, 0xA0, 0xAD, 0xAD, + 0x7D, 0xF7, 0x53, 0xFD, 0x40, 0x25, 0x1A, 0xF9, 0xF9, 0xA5, + 0xB3, 0xB8, 0xCF, 0x76, 0xDD, 0x86, 0x7B, 0xDF, 0x2F, 0xA6, + 0xA4, 0x6C, 0xBD, 0x51, 0x5E, 0x20, 0x5B, 0x5B, 0xD5, 0x99, + 0xB7, 0x1E, 0x9D, 0x2E, 0xB4, 0x0E, 0xD6, 0x50, 0xB1, 0x02, + 0x57, 0xCC, 0xB2, 0x85, 0x72, 0x47, 0x66, 0xD0, 0xC3, 0xA9, + 0x68, 0xE1, 0x58, 0x37, 0xD8, 0xAA, 0x18, 0x34, 0x40, 0xF5, + 0x49, 0xBA, 0xFC, 0x31, 0x85, 0xE3, 0x61, 0x42, 0x10, 0x1D, + 0x16, 0x1E, 0x20, 0xCE, 0x65, 0xE1, 0xD5, 0xF1, 0x03, 0x3C, + 0xB7, 0xD4, 0x42, 0x9E, 0x49, 0x9C, 0x53, 0xA4, 0x99, 0xE7, + 0x25, 0xFB, 0x64, 0x57, 0x69, 0x87, 0xEC, 0x05, 0x03, 0x79, + 0x9F, 0xAB, 0x45, 0xB8, 0x87, 0x60, 0xBC, 0xEB, 0x83, 0x76, + 0x28, 0xD1, 0xCC, 0x67, 0x24, 0x64, 0x99, 0x88, 0xB2, 0x7C, + 0xBA, 0x01, 0x06, 0x8C, 0x77, 0x69, 0xD7, 0x4A, 0x04, 0xB7, + 0x6F, 0x5E, 0xD5, 0x5D, 0x8D, 0xC1, 0x12, 0xD0, 0x2A, 0x90, + 0x6C, 0xAE, 0x2E, 0xE3, 0xA9, 0xCC, 0xFA, 0x53, 0x6A, 0x24, + 0xDC, 0xBA, 0xA3, 0x17, 0x37, 0x3D, 0x92, 0xD7, 0x83, 0xCC, + 0x51, 0x16, 0xF2, 0xCA, 0xAB, 0xFE, 0xA0, 0xB6, 0x7F, 0x5F, + 0x4F, 0x96, 0xFB, 0x96, 0xA4, 0x36, 0xF0, 0xB9, 0x9E, 0x75, + 0x7F, 0x78, 0x38, 0xC8, 0x58, 0x17, 0x96, 0x3C, 0xE3, 0x59, + 0x5B, 0x5F, 0xCE, 0xFA, 0xEA, 0xA0, 0x03, 0x53, 0x21, 0x32, + 0x1D, 0xD1, 0x17, 0x3C, 0x29, 0xD3, 0x73, 0xA3, 0xC6, 0x27, + 0xD4, 0x31, 0xB2, 0xE9, 0xFC, 0x97, 0xB4, 0x6B, 0x89, 0x30, + 0x9C, 0x45, 0xE3, 0x54, 0x35, 0xB7, 0xBB, 0xC9, 0x3E, 0x7A, + 0x26, 0xF9, 0xFB, 0xB1, 0xF8, 0x29, 0xEF, 0x19, 0x49, 0x25, + 0x99, 0x43, 0x50, 0x12, 0xC6, 0xE6, 0x58, 0xCF, 0x33, 0x90, + 0x38, 0xA2, 0x94, 0x81, 0x77, 0x66, 0x79, 0x0D, 0xA6, 0x08, + 0x9B, 0x5E, 0xE0, 0x34, 0x1E, 0xF5, 0x4E, 0x78, 0xA4, 0x35, + 0xBC, 0x78, 0xB1, 0x17, 0xE0, 0xE7, 0x90, 0x10, 0xAE, 0x7D, + 0x31, 0x63, 0x4D, 0x41, 0x50, 0x46, 0xB8, 0xB4, 0xA9, 0x65, + 0x52, 0x3E, 0x1F, 0x6F, 0x29, 0xDC, 0x78, 0x75, 0x05, 0x69, + 0xC3, 0x5A, 0x8E, 0x72, 0x64, 0x1B, 0xF1, 0xEB, 0xA4, 0x49, + 0xA3, 0xDF, 0x38, 0xDC, 0x7E, 0x31, 0x79, 0xC8, 0x25, 0xBE, + 0x4F, 0x58, 0xBE, 0x2C, 0x0F, 0xC7, 0x2D, 0x31, 0x48, 0xD7, + 0x3E, 0xF4, 0xDD, 0x7A, 0x25, 0x83, 0xAF, 0x22, 0xE3, 0xFD, + 0x37, 0x6E, 0xAE, 0x29, 0x57, 0xE4, 0xFE, 0xCD, 0x6E, 0x37, + 0xA0, 0x2B, 0x45, 0xA9, 0x5F, 0x23, 0x4B, 0xC4, 0x84, 0xCC, + 0xEA, 0x1D, 0xB5, 0xF1, 0xBF, 0x21, 0x20, 0x14, 0xA0, 0x84, + 0xF6, 0x2D, 0x6A, 0x3B, 0x26, 0xE2, 0xBC, 0x3B, 0xD0, 0x4E, + 0xBF, 0x63, 0x57, 0x79, 0x4B, 0x7C, 0xF7, 0xCC, 0x00, 0x09, + 0x16, 0xE0, 0xD8, 0x48, 0xDF, 0x6B, 0x09, 0x8B, 0x30, 0xC4, + 0xC4, 0xBD, 0xB2, 0x58, 0x39, 0x33, 0x6D, 0x54, 0x84, 0x66, + 0x4E, 0x52, 0x43, 0xB7, 0x2B, 0x50, 0xEB, 0x58, 0xF2, 0x9E, + 0x2D, 0x7C, 0x53, 0xC4, 0x2A, 0x44, 0x01, 0x7E, 0x59, 0x9C, + 0x4C, 0xFB, 0x51, 0xED, 0xCA, 0x71, 0x59, 0xEF, 0xED, 0xB1, + 0x12, 0x37, 0x18, 0xE6, 0xCD, 0xCF, 0xDC, 0xC1, 0xAD, 0x8C, + 0x76, 0x25, 0x92, 0xD4, 0xC8, 0x39, 0xF8, 0xA2, 0x57, 0x19, + 0xB6, 0x72, 0x63, 0x87, 0xBC, 0x47, 0x9F, 0x3D, 0x68, 0x25, + 0x05, 0x73, 0x1F, 0xB6, 0x9C, 0xD3, 0x33, 0x5E, 0x0C, 0xAB, + 0x86, 0x01, 0x0C, 0x7D, 0xE7, 0xFF, 0x93, 0xDC, 0x30, 0x49, + 0xDC, 0x5E, 0xE6, 0xD4, 0x56, 0x4E, 0x8C, 0xAA, 0x80, 0xDC, + 0xB7, 0xA1, 0x89, 0x25, 0x8D, 0x24, 0xFB, 0x17, 0x48, 0x2B, + 0x89, 0x8C, 0x3D, 0x61, 0xD9, 0x49, 0xE2, 0x0E, 0x39, 0x6D, + 0xB7, 0xB0, 0xFD, 0x30, 0x2F, 0x27, 0x9F, 0x0F, 0x39, 0x31, + 0x40, 0x41, 0x56, 0x60, 0xC0, 0xA1, 0xCD, 0x3E, 0x15, 0xF2, + 0x94, 0x50, 0xC3, 0x8E, 0x91, 0xA9, 0xBA, 0x98, 0x64, 0x4F, + 0x14, 0xBD, 0x57, 0xD3, 0x15, 0x3F, 0xEB, 0x1E, 0x4B, 0x2F, + 0x92, 0x9D, 0x6A, 0x2E, 0x23, 0x6C, 0xA8, 0x82, 0x7A, 0x9F, + 0xFD, 0x29, 0x4B, 0x10, 0xEC, 0xA3, 0xD0, 0x80, 0xEF, 0x1B, + 0x11, 0x5E, 0x56, 0x3F, 0xE7, 0x45, 0xDD, 0x41, 0xC8, 0x41, + 0x61, 0x4F, 0x8F, 0x2B, 0x3C, 0x99, 0x4D, 0xFA, 0x8A, 0x86, + 0x54, 0xF9, 0x21, 0xB2, 0x1C, 0x75, 0x87, 0xDB, 0x58, 0x52, + 0x71, 0xF2, 0xED, 0xD6, 0x70, 0xCE, 0x24, 0x13, 0x36, 0xEE, + 0x2F, 0x5E, 0x1B, 0xA6, 0x03, 0xD8, 0x9A, 0xB8, 0x6C, 0xF0, + 0x9B, 0xF4, 0x0B, 0x98, 0x83, 0xA9, 0x23, 0xCC, 0x4F, 0x3E, + 0x26, 0x87, 0x48, 0xED, 0xA1, 0xD2, 0x53, 0x23, 0x20, 0x5D, + 0x64, 0xDB, 0xE2, 0xA2, 0xF9, 0x72, 0x97, 0x7D, 0x5F, 0x3A, + 0xEE, 0x6A, 0xA4, 0xC2, 0x79, 0x55, 0xDC, 0x99, 0x58, 0x26, + 0x53, 0xE6, 0x46, 0x30, 0xB7, 0xC3, 0xAA, 0xBF, 0x46, 0x80, + 0xC1, 0xE2, 0xEC, 0x6D, 0xD6, 0xFA, 0x6E, 0x80, 0xF3, 0x2B, + 0xD9, 0xD1, 0x4C, 0x2F, 0x86, 0xDD, 0xB1, 0xFD, 0xD4, 0xFE, + 0x3F, 0xB8, 0x49, 0xF9, 0x80, 0x27, 0xCF, 0x63, 0x1E, 0xD9, + 0x21, 0x81, 0xF3, 0x65, 0xF7, 0xC0, 0x7A, 0x43, 0x99, 0x79, + 0x50, 0x0F, 0xF3, 0x75, 0xC5, 0xB6, 0x63, 0xD0, 0x73, 0x18, + 0xB2, 0xB2, 0x6F, 0x2C, 0xA9, 0xBA, 0x7A, 0xF1, 0x86, 0xF6, + 0x5B, 0x60, 0xDD, 0x4B, 0xF3, 0xA0, 0xA4, 0x11, 0x1E, 0xCC, + 0xA9, 0xD3, 0x57, 0xED, 0x9A, 0x2D, 0x7E, 0x95, 0x1D, 0xE2, + 0x01, 0x38, 0xE7, 0x36, 0x62, 0xD2, 0x19, 0xD4, 0x80, 0x16, + 0xBC, 0x9C, 0xC2, 0x3F, 0x54, 0xE0, 0xE1, 0x17, 0xE5, 0x42, + 0xF6, 0x83, 0x56, 0x28, 0xFD, 0xD7, 0xCB, 0xE9, 0x07, 0x26, + 0xDE, 0xF5, 0x5F, 0xE0, 0x21, 0xA4, 0x80, 0xD8, 0x38, 0xCC, + 0x48, 0x75, 0xC9, 0xE6, 0xF2, 0x7A, 0x12, 0x06, 0x27, 0x37, + 0x86, 0xFF, 0xDB, 0xF5, 0x57, 0x84, 0xCA, 0x2B, 0x6E, 0x5C, + 0xB9, 0x5A, 0x37, 0x12, 0xE1, 0x31, 0x1B, 0x16, 0x50, 0xDA, + 0x4C, 0x5F, 0x2B, 0x85, 0x55, 0x0C, 0xE2, 0x7F, 0xFC, 0x22, + 0xB2, 0x02, 0x29, 0xF0, 0x43, 0x93, 0x2F, 0x4A, 0x71, 0xEF, + 0x01, 0x18, 0x0D, 0x12, 0x59, 0x1D, 0x04, 0x27, 0x6D, 0xDA, + 0x4C, 0x74, 0x53, 0x9B, 0x92, 0xB8, 0x88, 0x4B, 0xAB, 0x02, + 0x9A, 0xE1, 0xE3, 0xC2, 0xE9, 0x76, 0x49, 0x74, 0xAE, 0xDB, + 0x21, 0x4F, 0x54, 0x5E, 0xE2, 0x05, 0xB9, 0xE1, 0x6E, 0x76, + 0xD2, 0x10, 0x62, 0x61, 0xBF, 0xDC, 0x6B, 0xD2, 0x2D, 0x32, + 0xB7, 0x80, 0xC0, 0x86, 0x3F, 0xD5, 0x35, 0xE9, 0xFA, 0x15, + 0xBE, 0xB1, 0x46, 0xDE, 0x64, 0x66, 0xCE, 0xE4, 0x47, 0x91, + 0x51, 0xBE, 0x6B, 0x35, 0x4A, 0x41, 0x5D, 0x24, 0x88, 0x16, + 0x33, 0xE5, 0x4F, 0xB5, 0x40, 0xCE, 0x11, 0x4B, 0x08, 0xD2, + 0x53, 0x19, 0x8B, 0x6C, 0xD8, 0x29, 0x7A, 0x71, 0x7A, 0x9B, + 0x74, 0x37, 0x01, 0x59, 0xDE, 0x8F, 0x2C, 0xA4, 0x35, 0xE1, + 0xE6, 0x70, 0x59, 0x73, 0x18, 0xF0, 0x7E, 0x6A, 0xE4, 0xBC, + 0x89, 0x71, 0x77, 0x11, 0x82, 0x34, 0x00, 0x12, 0xDC, 0x35, + 0xB5, 0xEF, 0x83, 0x24, 0x53, 0x2B, 0xAD, 0x3E, 0xBF, 0x7D, + 0xAB, 0xE2, 0xCE, 0xD2, 0xF5, 0xF8, 0xCD, 0xDD, 0xF0, 0x27, + 0x71, 0x8E, 0x8A, 0xF1, 0x51, 0xB1, 0x06, 0x27, 0xFB, 0x96, + 0x29, 0xDF, 0x23, 0xEA, 0x39, 0x1F, 0x4F, 0x4B, 0x13, 0xE5, + 0xF5, 0x0F, 0x73, 0x44, 0xC9, 0xC8, 0xFA, 0x40, 0x7A, 0x29, + 0x58, 0x65, 0x9D, 0x14, 0x4B, 0x14, 0xC6, 0xAA, 0x31, 0x9B, + 0xFF, 0x70, 0x06, 0x5A, 0x58, 0x68, 0x69, 0x0D, 0xD9, 0x1E, + 0x83, 0x66, 0xE8, 0xBF, 0xEC, 0xBF, 0x5D, 0x83, 0xD9, 0x50, + 0x29, 0xAF, 0x59, 0xB8, 0x00, 0xDF, 0x5C, 0x66, 0x06, 0xCB, + 0xDA, 0x03, 0x62, 0x1F, 0xCA, 0x49, 0xEE, 0x32, 0xB1, 0x5D, + 0x83, 0x9E, 0x43, 0x41, 0x15, 0x14, 0xD2, 0x8E, 0x7B, 0xFA, + 0xC8, 0xA4, 0x2B, 0xA2, 0x0E, 0xD5, 0x28, 0x32, 0xA1, 0xF2, + 0x37, 0xD3, 0x85, 0xB5, 0xCF, 0x8A, 0x99, 0xBB, 0x43, 0xC0, + 0x41, 0xF8, 0x79, 0xCE, 0x8D, 0xD7, 0x18, 0x90, 0x66, 0x66, + 0xEC, 0x17, 0x39, 0x05, 0x0A, 0x4C, 0x81, 0xC0, 0x8E, 0x55, + 0x29, 0x32, 0x10, 0x1A, 0xAB, 0x40, 0xA6, 0xF2, 0xD5, 0x9C, + 0xD4, 0x40, 0x5F, 0x56, 0xCF, 0x8B, 0x63, 0x1D, 0xEC, 0x82, + 0x64, 0x2C, 0x85, 0x5D, 0x2B, 0x82, 0x78, 0x4F, 0x59, 0xA8, + 0xCF, 0x61, 0x90, 0x0F, 0x41, 0x34, 0x89, 0x17, 0x18, 0x8E, + 0x3D, 0x38, 0x50, 0xDD, 0xE9, 0xC0, 0xB0, 0x64, 0xDA, 0x91, + 0x3F, 0x7C, 0x4F, 0xBE, 0x2A, 0xCA, 0xE0, 0x6E, 0x79, 0x27, + 0xB3, 0x3E, 0x1D, 0x43, 0xF5, 0xF4, 0x64, 0x54, 0x24, 0x4B, + 0x2E, 0x73, 0xE8, 0x2D, 0x03, 0x0B, 0x0B, 0xB3, 0xD7, 0xE3, + 0x8C, 0x76, 0x59, 0xAD, 0xD3, 0x1F, 0x75, 0x25, 0xC6, 0x8F, + 0xA0, 0x3C, 0xEA, 0xE1, 0xD7, 0xD7, 0x37, 0xAD, 0xFE, 0xD5, + 0xEF, 0xAB, 0x00, 0x36, 0xC5, 0x2A, 0xC8, 0x74, 0x43, 0x94, + 0xA6, 0x72, 0x03, 0xED, 0x11, 0xCF, 0x27, 0x1C, 0xED, 0x01, + 0x06, 0x3B, 0xFF, 0xE5, 0x71, 0x32, 0xFA, 0x00, 0x8B, 0x33, + 0x00, 0xA8, 0x6D, 0x74, 0x6D, 0xC1, 0xBE, 0x3B, 0x15, 0xDD, + 0xA0, 0xE6, 0x53, 0x1B, 0x12, 0xAC, 0x23, 0x77, 0x51, 0xC7, + 0xB4, 0x9E, 0x38, 0xC4, 0x55, 0xD7, 0x7B, 0xE4, 0x81, 0x41, + 0x98, 0x81, 0x7F, 0x31, 0x27, 0x9F, 0xC9, 0xC8, 0x83, 0xDB, + 0x14, 0x7F, 0x71, 0xDD, 0xC7, 0x67, 0xE0, 0xAB, 0xDC, 0x06, + 0xDA, 0xEB, 0x98, 0xA6, 0x7E, 0xCB, 0x9D, 0x6D, 0xE2, 0x32, + 0x33, 0xC6, 0x46, 0x51, 0xBD, 0xFE, 0x3C, 0x8C, 0x84, 0xE4, + 0x3D, 0xEA, 0x7A, 0xD9, 0x97, 0xAB, 0x56, 0x4D, 0xC4, 0xEE, + 0xB6, 0xD4, 0x17, 0x72, 0x4D, 0x03, 0x1B, 0xDE, 0xBA, 0x02, + 0xDD, 0xC1, 0x16, 0x5F, 0x0D, 0xCE, 0xD5, 0x6F, 0x96, 0x8D, + 0xE5, 0xD5, 0xDA, 0x96, 0x11, 0x03, 0xE9, 0x43, 0x8C, 0x7A, + 0x44, 0xFF, 0x33, 0x2E, 0xA3, 0x87, 0x03, 0xFB, 0x56, 0x4D, + 0x37, 0x63, 0xD1, 0xDC, 0x88, 0x9A, 0xC4, 0x5C, 0x23, 0xFD, + 0x1E, 0xFC, 0x59, 0x04, 0x02, 0xD9, 0x8A, 0x89, 0xAC, 0xD7, + 0xC4, 0x83, 0x92, 0x40, 0xBF, 0x66, 0x56, 0x63, 0x62, 0xAC, + 0x81, 0x18, 0x46, 0x1D, 0x59, 0x90, 0x8B, 0x70, 0xCC, 0xE1, + 0xAB, 0x81, 0x57, 0x45, 0x4E, 0x55, 0xCE, 0x4A, 0x31, 0x03, + 0xBF, 0x44, 0x27, 0x73, 0xDC, 0x54, 0xF8, 0x0F, 0x67, 0x87, + 0x6B, 0x5D, 0xDC, 0x17, 0x4F, 0xE4, 0x0E, 0xBF, 0x6E, 0x95, + 0x70, 0xC4, 0x40, 0x4E, 0x57, 0x44, 0x73, 0x13, 0x7A, 0x73, + 0x52, 0xFA, 0xAB, 0x34, 0x3C, 0x54, 0xC3, 0x89, 0x87, 0xB9, + 0x97, 0x44, 0xA0, 0x23, 0x03, 0x61, 0xCC, 0x09, 0x25, 0xAC, + 0x72, 0xA7, 0x15, 0x6C, 0xE9, 0x3F, 0x1B, 0xCF, 0x8C, 0x9E, + 0x2D, 0x8B, 0xD8, 0x21, 0x2F, 0x9F, 0x52, 0xD6, 0x4D, 0x0F, + 0x17, 0x4D, 0x1D, 0x3E, 0x05, 0x7B, 0xD3, 0x10, 0x21, 0xC9, + 0xE0, 0x78, 0x01, 0x1A, 0x4E, 0x4E, 0xA5, 0xDE, 0xF7, 0x63, + 0x35, 0x1F, 0x4F, 0x68, 0xFA, 0xFD, 0xAF, 0xC5, 0xA1, 0xE3, + 0x3A, 0xA8, 0x59, 0x72, 0x45, 0xA2, 0xCB, 0x6B, 0xC8, 0xDB, + 0xA2, 0xF3, 0xEA, 0x9B, 0x84, 0x9C, 0xB1, 0x8F, 0x37, 0xB0, + 0x68, 0xDE, 0xAE, 0x21, 0xD1, 0x0C, 0x0E, 0x36, 0x85, 0xEF, + 0xD1, 0xF4, 0x45, 0x63, 0xA5, 0xC4, 0x99, 0x56, 0x98, 0xAC, + 0xE1, 0xE2, 0x9C, 0xCA, 0x88, 0x15, 0x31, 0x5A, 0xCA, 0xDD, + 0xCC, 0x3D, 0x11, 0x19, 0x65, 0x05, 0x22, 0x96, 0xC7, 0x41, + 0x32, 0x44, 0x90, 0x1B, 0x25, 0xB5, 0x23, 0x88, 0x03, 0xFC, + 0x99, 0x49, 0xEF, 0xFA, 0xA1, 0xE2, 0x95, 0xB3, 0x40, 0xE4, + 0xC1, 0xF3, 0x13, 0xA8, 0x0E, 0xB7, 0x98, 0x55, 0x5A, 0x8B, + 0x7D, 0xD6, 0x72, 0x82, 0xFE, 0xB4, 0xE6, 0x9B, 0x2F, 0xCE, + 0xD9, 0x24, 0xAC, 0xA5, 0x90, 0x9C, 0x48, 0x93, 0x60, 0x04, + 0x55, 0x0C, 0xF1, 0xE1, 0x22, 0xDB, 0xA3, 0x6E, 0xD0, 0x72, + 0xC0, 0x99, 0xC7, 0x5A, 0xCC, 0x1F, 0xE4, 0x4E, 0xD9, 0x8C, + 0xC7, 0x1B, 0xF1, 0x83, 0xA0, 0xBB, 0xFF, 0xB3, 0x99, 0x01, + 0x01, 0x30, 0x90, 0x30, 0x4E, 0x8F, 0x3A, 0x28, 0x56, 0x43, + 0xF7, 0xA6, 0xCD, 0xF0, 0x2E, 0xB0, 0xAB, 0xE8, 0xE4, 0x2B, + 0xFF, 0x79, 0xDB, 0x47, 0xD3, 0xC2, 0xDD, 0xD0, 0xEC, 0x32, + 0x91, 0x27, 0xB0, 0x7A, 0xC6, 0x8B, 0xD1, 0x9A, 0x14, 0xAF, + 0x40, 0x65, 0xBC, 0x57, 0x53, 0x2C, 0xF5, 0xE6, 0xC9, 0x82, + 0x86, 0x0F, 0x4D, 0xF3, 0x8D, 0xFE, 0x2A, 0xB3, 0xBA, 0x80, + 0x62, 0x48, 0x27, 0x60, 0xE7, 0x1E, 0xBA, 0x58, 0xF9, 0x6B, + 0x88, 0xA7, 0xCA, 0x95, 0x84, 0x29, 0x39, 0x2F, 0xBA, 0xBC, + 0x9B, 0xBB, 0x16, 0xC9, 0xC6, 0x8C, 0x03, 0xD0, 0x1E, 0xF3, + 0x3F, 0x21, 0x72, 0x8A, 0xE7, 0x08, 0x22, 0x56, 0xDE, 0xF5, + 0xFE, 0x53, 0x59, 0x6E, 0xCC, 0xC6, 0xA3, 0xE9, 0xAC, 0x13, + 0x91, 0x17, 0xA3, 0xB9, 0x96, 0xAB, 0xD8, 0x63, 0xAA, 0x73, + 0x5B, 0x4C, 0x33, 0xEA, 0xF0, 0x34, 0xAD, 0x9D, 0xD2, 0x5B, + 0x1F, 0x38, 0xE2, 0xFB, 0x35, 0xF4, 0xA3, 0x44, 0x8F, 0x92, + 0xC3, 0x95, 0x3A, 0xBC, 0x74, 0xC9, 0x6D, 0x70, 0x8D, 0x16, + 0xBD, 0x12, 0x1D, 0xE2, 0xC1, 0x96, 0x9C, 0xA8, 0xE1, 0xE8, + 0xAF, 0x37, 0x98, 0x0A, 0x03, 0xD2, 0x30, 0xC3, 0x77, 0x98, + 0x5B, 0x64, 0x61, 0xF7, 0x16, 0x22, 0x5B, 0xAF, 0x2E, 0x63, + 0xA2, 0xEF, 0x6E, 0xF0, 0x73, 0x16, 0xB8, 0xC9, 0xC6, 0xF7, + 0x2F, 0x39, 0x34, 0xB6, 0xFA, 0x63, 0xED, 0x39, 0x99, 0xA0, + 0x68, 0xC7, 0x44, 0x8A, 0x70, 0xE4, 0x8E, 0x43, 0x5B, 0xF5, + 0xC4, 0xC8, 0x3B, 0x17, 0xD1, 0x29, 0x74, 0x45, 0x09, 0x27, + 0x48, 0x96, 0x9E, 0xFC, 0xC5, 0x16, 0xEF, 0x11, 0x38, 0xBE, + 0x6C, 0x74, 0x67, 0xE1, 0x40, 0x2F, 0xE0, 0x18, 0x8C, 0x12, + 0xD6, 0xBD, 0xB4, 0x57, 0xDA, 0xF2, 0x9E, 0x8B, 0xC9, 0x84, + 0xE4, 0x34, 0x9A, 0xAF, 0x1E, 0x17, 0x54, 0xF8, 0xF7, 0x9F, + 0x72, 0xD0, 0xF0, 0x34, 0x45, 0x29, 0x6F, 0x60, 0xA9, 0xEA, + 0x1C, 0xAA, 0x26, 0x35, 0x72, 0x8B, 0x3A, 0xD4, 0x9C, 0x24, + 0xF7, 0x6B, 0x15, 0xDB, 0x7A, 0xC7, 0x45, 0x76, 0x39, 0xFB, + 0x4F, 0x40, 0xB1, 0xB0, 0x0F, 0x1D, 0x72, 0x32, 0x26, 0xB7, + 0x50, 0x92, 0x72, 0x34, 0xEC, 0xC1, 0xB8, 0x5F, 0x18, 0xAA, + 0xCC, 0xB7, 0xAC, 0xC0, 0x78, 0xB4, 0xB2, 0x99, 0xBB, 0xB5, + 0x0B, 0x26, 0x10, 0x23, 0x5A, 0x97, 0xB4, 0xA9, 0xFC, 0xDC, + 0xCF, 0x52, 0x2F, 0xB4, 0x4C, 0x74, 0x5D, 0x99, 0xFC, 0x16, + 0x58, 0xD3, 0xD1, 0xD6, 0x3A, 0xFC, 0x97, 0xB4, 0xC3, 0xEF, + 0x5D, 0x89, 0x5B, 0x74, 0x00, 0x02, 0x6A, 0xA7, 0x0C, 0x6C, + 0x56, 0x2D, 0x2A, 0x9A, 0xD3, 0x82, 0x32, 0x61, 0xF1, 0x3F, + 0x4E, 0xE5, 0xF7, 0x48, 0x7B, 0xBA, 0xBF, 0xF1, 0xA8, 0x93, + 0x65, 0x8E, 0xCA, 0x66, 0xDD, 0xAA, 0x6C, 0x11, 0xD4, 0xF2, + 0x48, 0xD6, 0x7A, 0xDA, 0x25, 0x53, 0xE7, 0x9E, 0x3F, 0x2B, + 0xD0, 0xD6, 0xDC, 0xF4, 0xC7, 0xBC, 0x3F, 0x36, 0xAE, 0xB6, + 0x8D, 0x24, 0xD6, 0x27, 0x7F, 0x01, 0x86, 0xB7, 0x48, 0x02, + 0x26, 0xD2, 0x32, 0xCB, 0x96, 0x6C, 0xC2, 0x57, 0x44, 0x27, + 0x40, 0xDD, 0xF4, 0xB4, 0x30, 0xC1, 0xE2, 0x5C, 0x35, 0xB7, + 0xC1, 0x53, 0x0F, 0x09, 0x2D, 0x2E, 0x71, 0xDA, 0x9F, 0x45, + 0x79, 0x06, 0x0F, 0x19, 0xC6, 0x98, 0x09, 0xFF, 0x69, 0x46, + 0xF8, 0x76, 0x59, 0x40, 0xC8, 0x7E, 0x0B, 0x7D, 0x89, 0x6F, + 0x2D, 0x05, 0x5B, 0x74, 0xB2, 0x50, 0xFC, 0x75, 0xF8, 0x7B, + 0x5D, 0x3A, 0x2A, 0x3D, 0xE5, 0x8D, 0x26, 0x9D, 0x66, 0x31, + 0xE0, 0x63, 0xBC, 0xD0, 0xE7, 0x0C, 0xF0, 0x2A, 0x9F, 0xCE, + 0xEB, 0x00, 0x07, 0xB6, 0x75, 0xF7, 0x9B, 0x9C, 0xF5, 0x3E, + 0xEE, 0x39, 0xE1, 0xD6, 0x9A, 0x02, 0x93, 0x25, 0x63, 0xB8, + 0x86, 0xF5, 0x5A, 0xAB, 0xF8, 0x12, 0xFD, 0xBF, 0x32, 0x5B, + 0xFD, 0x61, 0x97, 0xD1, 0x6B, 0x2C, 0x9F, 0x73, 0x86, 0x12, + 0x6C, 0x25, 0xE5, 0x8F, 0x90, 0x7D, 0xD1, 0xFD, 0x42, 0xD8, + 0x8D, 0xF4, 0xAB, 0x72, 0xBF, 0xF3, 0xB4, 0x63, 0xD1, 0x0F, + 0xFB, 0x6A, 0x6F, 0xE9, 0x2E, 0xFE, 0xCC, 0x82, 0xA1, 0x86, + 0xDF, 0xAE, 0x8A, 0x75, 0xC2, 0x4D, 0xEC, 0x88, 0xE9, 0x14, + 0x79, 0xC1, 0xA0, 0x1E, 0x8F, 0x87, 0x5C, 0x58, 0x6B, 0x62, + 0x39, 0xAA, 0x1F, 0x31, 0x1C, 0xBA, 0x53, 0xD5, 0x3F, 0x66, + 0xB3, 0x39, 0x60, 0x75, 0xEB, 0x53, 0x44, 0x7E, 0x74, 0xE7, + 0x0D, 0xD2, 0xAB, 0x2B, 0xA4, 0x01, 0x9F, 0xDF, 0x39, 0xB2, + 0x0B, 0xB3, 0xBC, 0x8A, 0xD9, 0x0D, 0x0D, 0xAC, 0x37, 0xFE, + 0xCD, 0x62, 0xBB, 0xD6, 0x59, 0x33, 0x63, 0xC5, 0x66, 0x65, + 0x9B, 0xB5, 0x22, 0x0D, 0xAF, 0x02, 0xC3, 0xE4, 0x8A, 0x75, + 0xFF, 0xAA, 0xA1, 0xD7, 0x9C, 0x1C, 0x3F, 0x62, 0x91, 0x2F, + 0xD4, 0x85, 0x37, 0x66, 0xE5, 0xEA, 0x60, 0x83, 0xDE, 0x24, + 0xA6, 0x15, 0xC7, 0xEB, 0xB9, 0x77, 0x8E, 0x09, 0x75, 0x39, + 0x3E, 0x24, 0x68, 0x78, 0xCE, 0x92, 0xF5, 0xDF, 0x25, 0x85, + 0xF6, 0x3C, 0x22, 0xAC, 0x86, 0xCF, 0x56, 0x50, 0x05, 0x2A, + 0x57, 0x8F, 0x5F, 0x0B, 0xDD, 0x53, 0xBC, 0xB4, 0x48, 0xA4, + 0x65, 0x19, 0xBB, 0x47, 0x34, 0x56, 0xD3, 0x68, 0x42, 0x5D, + 0xCC, 0x58, 0xD7, 0xBE, 0x3F, 0x8D, 0xFB, 0xEC, 0x51, 0xBB, + 0x7C, 0x74, 0x9A, 0x65, 0x60, 0xBC, 0x11, 0x7C, 0x0E, 0x61, + 0xAF, 0xDC, 0x6F, 0x9A, 0xE0, 0xE5, 0x46, 0xF3, 0x36, 0xEB, + 0x37, 0x73, 0xA2, 0x08, 0x4A, 0x3D, 0xF8, 0x98, 0xC0, 0x4E, + 0xF3, 0xB2, 0x27, 0xE0, 0x1A, 0x00, 0x6E, 0x0C, 0x19, 0x7F, + 0xF3, 0x74, 0x73, 0xF7, 0x94, 0x7A, 0xD1, 0xFA, 0x21, 0x89, + 0x9C, 0xEA, 0x07, 0x40, 0x78, 0x33, 0x5E, 0x7B, 0xB4, 0xC8, + 0x54, 0xF0, 0xCA, 0x52, 0x5A, 0x37, 0xC3, 0x20, 0x66, 0x88, + 0x4D, 0xA7, 0xA1, 0xBA, 0xE7, 0x09, 0xA7, 0x8A, 0x31, 0xBA, + 0xC5, 0x01, 0x30, 0xF1, 0x45, 0xD4, 0x01, 0xFA, 0xE3, 0x9C, + 0xC2, 0x29, 0x9F, 0x2C, 0x15, 0x39, 0x04, 0xF9, 0x4B, 0xB5, + 0x52, 0x33, 0x61, 0x54, 0x63, 0xEF, 0x0F, 0x75, 0xE2, 0x01, + 0x7F, 0xBD, 0xEE, 0x37, 0x9E, 0xDD, 0xBC, 0xAA, 0xBB, 0xC7, + 0x05, 0xAF, 0x35, 0x6C, 0x72, 0x22, 0x20, 0xD5, 0x97, 0xFD, + 0x44, 0x4D, 0xC9, 0x04, 0x03, 0xA1, 0x47, 0xA5, 0x2A, 0x88, + 0x1C, 0xE3, 0x48, 0x0D, 0xA9, 0x9A, 0xA2, 0x54, 0x4B, 0x63, + 0xBE, 0x90, 0xF2, 0x57, 0x31, 0x49, 0x6F, 0xCD, 0xD9, 0x54, + 0x83, 0xCF, 0x4B, 0xD6, 0xF2, 0x26, 0x73, 0x14, 0x24, 0xE8, + 0x51, 0x66, 0xE8, 0xF2, 0x5F, 0x9A, 0xD1, 0x56, 0xED, 0x5D, + 0x43, 0xC8, 0xDA, 0x32, 0xC2, 0xBD, 0x01, 0xA7, 0xDB, 0xEE, + 0x43, 0x5F, 0xF4, 0xF4, 0x0B, 0x94, 0xA5, 0x40, 0x42, 0xDA, + 0x5A, 0x81, 0x3B, 0xB2, 0x21, 0x00, 0xA4, 0x53, 0x62, 0x67, + 0x62, 0xCE, 0xAE, 0x98, 0xB7, 0x03, 0xDC, 0x73, 0x8B, 0xEC, + 0x2D, 0x92, 0xB0, 0x17, 0x4A, 0x5B, 0xA8, 0x01, 0x32, 0x93, + 0xC0, 0x62, 0x7F, 0x4D, 0xDA, 0xC9, 0x82, 0xD0, 0xB4, 0xC2, + 0xAA, 0xC3, 0x10, 0xCA, 0x0C, 0xBB, 0x05, 0x5D, 0x21, 0x6D, + 0x4C, 0xC3, 0xBD, 0x02, 0xAD, 0x23, 0xC4, 0x60, 0xC6, 0x53, + 0x4C, 0x83, 0x54, 0x51, 0xF2, 0x08, 0x4C, 0x08, 0xBD, 0x65, + 0xC0, 0xD2, 0x84, 0x77, 0x6D, 0x6F, 0x9C, 0x83, 0xE2, 0xA0, + 0xDC, 0x05, 0xE5, 0x26, 0x1E, 0x34, 0x64, 0x8C, 0x70, 0x6C, + 0xAD, 0xA6, 0x2F, 0x4F, 0x20, 0x19, 0x6A, 0x1E, 0x15, 0x28, + 0x91, 0x6B, 0x2A, 0x79, 0x93, 0x22, 0x24, 0x0A, 0x51, 0xF2, + 0x06, 0xB6, 0x9E, 0xE4, 0x9A, 0xC8, 0x57, 0xE1, 0x8A, 0xA1, + 0xE4, 0x9F, 0xDA, 0x18, 0xD4, 0x5E, 0x8B, 0x66, 0xEC, 0xD7, + 0xB8, 0x31, 0x4B, 0xC8, 0xF9, 0x05, 0x6A, 0x8E, 0x76, 0x3B, + 0x26, 0x0B, 0x9D, 0xBD, 0x82, 0xF7, 0x61, 0xAD, 0xD5, 0x50, + 0x55, 0x78, 0x54, 0x9B, 0x81, 0x1E, 0x36, 0x62, 0x0A, 0xAD, + 0x9E, 0x03, 0x9B, 0xDB, 0xE9, 0xC0, 0x2E, 0x18, 0x19, 0xE1, + 0x00, 0x44, 0x1F, 0x61, 0xC5, 0x9A, 0xA9, 0xE6, 0x1A, 0xF0, + 0x9A, 0xA4, 0x2C, 0x86, 0x26, 0x33, 0x39, 0x70, 0x5F, 0x49, + 0x66, 0x2E, 0xBF, 0x4A, 0xB0, 0x3B, 0x1B, 0x08, 0x32, 0x4E, + 0x5E, 0xA9, 0x8D, 0xD6, 0xBE, 0x5A, 0xEE, 0x1E, 0xF5, 0x97, + 0xA9, 0x11, 0x3B, 0x3C, 0x74, 0xF5, 0x2D, 0x69, 0xD3, 0x07, + 0x44, 0xA2, 0x71, 0x2C, 0xF3, 0x03, 0x17, 0xDA, 0xCE, 0xF9, + 0x21, 0x80, 0xB6, 0x5D, 0xA2, 0xB9, 0x90, 0xCB, 0x27, 0x4D, + 0x4B, 0xD8, 0xF0, 0xC3, 0x5D, 0x04, 0xF2, 0xDE, 0x47, 0x2A, + 0x75, 0x7E, 0xA0, 0x23, 0xB2, 0x19, 0x0F, 0xE2, 0x62, 0x97, + 0x94, 0x11, 0x83, 0xE8, 0xE7, 0x38, 0x0F, 0x00, 0x2B, 0x58, + 0x78, 0x35, 0xD3, 0xDA, 0xA1, 0x4D, 0x9A, 0x45, 0x37, 0x7D, + 0x54, 0x6F, 0x65, 0xF3, 0x35, 0x44, 0x2A, 0x76, 0x20, 0x67, + 0x40, 0x0A, 0xCF, 0xAA, 0xEB, 0x66, 0x82, 0xD2, 0x58, 0x51, + 0xD7, 0xC0, 0xE1, 0x6C, 0xB1, 0x2D, 0xD1, 0x24, 0x8E, 0xAE, + 0x15, 0xEC, 0x4E, 0x7F, 0x27, 0xBF, 0xA8, 0x3E, 0x5A, 0xF7, + 0x8A, 0xEA, 0x12, 0x5A, 0x91, 0xBE, 0x0B, 0x80, 0x01, 0xBE, + 0xAD, 0x94, 0x0C, 0xC8, 0xD3, 0x53, 0x02, 0xDF, 0x07, 0x1D, + 0x64, 0x33, 0xC2, 0xD6, 0xDC, 0x96, 0x1E, 0xF6, 0x76, 0x16, + 0xE6, 0x80, 0x70, 0xE8, 0x46, 0x2D, 0x20, 0xDB, 0x0F, 0x22, + 0xD2, 0x09, 0xD8, 0x61, 0x71, 0xEA, 0xFD, 0x93, 0x96, 0x22, + 0xC2, 0xCD, 0x02, 0x05, 0x37, 0xBF, 0xC3, 0xC4, 0x0A, 0x39, + 0xB5, 0x32, 0xC8, 0x06, 0xFE, 0x95, 0x08, 0x68, 0x43, 0xE3, + 0xCC, 0xCA, 0xA7, 0x3C, 0x67, 0x58, 0x26, 0x9C, 0xA0, 0xBA, + 0x66, 0xDD, 0x03, 0x07, 0xE8, 0x27, 0xF6, 0xBC, 0x9B, 0x21, + 0xF2, 0x0E, 0x73, 0xC6, 0xC0, 0xBB, 0xEA, 0x65, 0x5F, 0x27, + 0xBF, 0x92, 0xA3, 0x3A, 0x3A, 0x6B, 0xF8, 0xFE, 0xCD, 0x99, + 0x51, 0xB5, 0x37, 0xD6, 0xFE, 0xEE, 0xEF, 0x74, 0xF8, 0xD2, + 0xE1, 0x9C, 0x25, 0xBF, 0xC5, 0x2E, 0x36, 0x4C, 0x70, 0xD9, + 0x8F, 0x8D, 0xF1, 0xD7, 0x80, 0xB9, 0xAF, 0x1B, 0x06, 0x91, + 0x93, 0xC8, 0xCF, 0xAB, 0x0D, 0xB5, 0xA0, 0x48, 0x1C, 0x34, + 0xC8, 0x36, 0xE5, 0xAD, 0x20, 0x6C, 0xDB, 0x4A, 0x01, 0x29, + 0x00, 0xCB, 0xC0, 0x00, 0x8F, 0x4D, 0x27, 0x93, 0xF5, 0x04, + 0x95, 0xA1, 0x21, 0x50, 0x5E, 0xF8, 0x46, 0x63, 0xD8, 0x49, + 0x4B, 0xDC, 0xFF, 0xCB, 0x58, 0x67, 0x05, 0x28, 0x20, 0x19, + 0xBF, 0xBF, 0xBB, 0x26, 0xF6, 0xA7, 0xDA, 0xBC, 0x35, 0xCC, + 0x6E, 0x2B, 0xF5, 0xC2, 0x8F, 0x33, 0x35, 0x91, 0x16, 0xB4, + 0x82, 0xF6, 0x49, 0x8A, 0xEB, 0x46, 0xEA, 0xB4, 0x2D, 0x45, + 0x21, 0xA8, 0x0A, 0xEB, 0x6D, 0x74, 0x62, 0xD2, 0x18, 0x72, + 0x83, 0x14, 0x69, 0xFB, 0x14, 0x69, 0x3A, 0xC0, 0x5C, 0x7B, + 0xE4, 0x78, 0x60, 0xBB, 0x65, 0x59, 0xD5, 0x1E, 0xD3, 0xA3, + 0xA5, 0x2F, 0xD9, 0x54, 0x76, 0x7F, 0x36, 0xAD, 0x91, 0xDD, + 0x2F, 0x22, 0x15, 0x1E, 0x64, 0x8F, 0xBC, 0x8A, 0x9E, 0xC1, + 0x88, 0x35, 0xCD, 0x4B, 0x18, 0x23, 0x80, 0x14, 0x6B, 0x91, + 0x7D, 0xF1, 0xB6, 0xDF, 0xD2, 0x5F, 0xE4, 0x44, 0xF2, 0xC8, + 0xE4, 0xD4, 0x09, 0xBD, 0x3D, 0x4E, 0xB2, 0xD1, 0x5A, 0xE4, + 0x7E, 0x46, 0x85, 0x5B, 0xC3, 0xA7, 0xC9, 0x8F, 0x7E, 0x01, + 0x73, 0xB6, 0xE0, 0x96, 0x5D, 0x78, 0xA7, 0x03, 0xF5, 0x72, + 0xA4, 0x77, 0xF4, 0x1D, 0x8D, 0xA9, 0xA8, 0xFB, 0xA4, 0xA9, + 0xEF, 0xEB, 0x52, 0x68, 0xDA, 0x42, 0x2F, 0x3B, 0xD6, 0x7D, + 0x7B, 0x5D, 0x49, 0x63, 0x79, 0xD5, 0x53, 0xC8, 0x7D, 0x66, + 0x9A, 0x95, 0x03, 0x62, 0x41, 0x8D, 0x89, 0x03, 0xFE, 0x54, + 0x05, 0x72, 0x6A, 0xCD, 0x9B, 0x05, 0x27, 0x45, 0x81, 0x52, + 0x3B, 0x0D, 0xA8, 0xDB, 0x8C, 0x7A, 0x09, 0x5C, 0x8E, 0x64, + 0xB5, 0xFE, 0x70, 0x69, 0x3A, 0x44, 0xDE, 0x66, 0x9B, 0x75, + 0xC1, 0x13, 0x17, 0x4D, 0x5E, 0x51, 0x0B, 0x7A, 0xFE, 0xCE, + 0x6B, 0x1C, 0xCE, 0x2B, 0x67, 0xC3, 0xBB, 0xC9, 0x4D, 0xDD, + 0xD8, 0xE5, 0xD8, 0x69, 0xDB, 0xD3, 0xF7, 0xFA, 0xB1, 0x02, + 0x7A, 0x2A, 0xE3, 0xEA, 0x0A, 0x1C, 0x16, 0xE4, 0x90, 0x6B, + 0xF0, 0x4E, 0x6E, 0x3E, 0xEC, 0x01, 0x6A, 0x04, 0x6D, 0x0A, + 0x4E, 0xB3, 0xFA, 0x39, 0x97, 0x06, 0x55, 0xFB, 0xAC, 0xB5, + 0x28, 0x55, 0x99, 0x15, 0xE9, 0x62, 0x3B, 0x24, 0xBB, 0xA1, + 0xFC, 0xB3, 0x2C, 0x75, 0x29, 0xA4, 0x70, 0xD1, 0x19, 0x46, + 0xC5, 0x0B, 0xD1, 0x2B, 0x5E, 0x60, 0xA1, 0x08, 0x6C, 0xDE, + 0x48, 0x6D, 0xAB, 0x8A, 0x41, 0xE9, 0xB0, 0x4D, 0x4B, 0x76, + 0xCC, 0x7E, 0xFA, 0xF5, 0xCD, 0x24, 0xB9, 0x68, 0xB6, 0xF6, + 0x79, 0x9C, 0xD5, 0x85, 0x8F, 0x4B, 0x88, 0xE7, 0x43, 0x3F, + 0xF5, 0x6A, 0x2A, 0x29, 0xB8, 0xEB, 0x5F, 0x5B, 0x17, 0x06, + 0x35, 0xC0, 0x49, 0x0A, 0x74, 0x99, 0x97, 0x5D, 0x64, 0x73, + 0xA4, 0xF8, 0x95, 0x4C, 0x4C, 0x8C, 0xB0, 0x90, 0x44, 0x85, + 0x82, 0x6B, 0xB4, 0x67, 0x2D, 0x2C, 0x26, 0xE2, 0x1A, 0x8F, + 0xAB, 0xFB, 0x0B, 0xE9, 0x09, 0x88, 0xD4, 0x5E, 0x91, 0xD5, + 0xB6, 0xF1, 0x4B, 0x51, 0xB5, 0xCD, 0xA9, 0x4A, 0x1F, 0x1F, + 0x4E, 0x70, 0xF3, 0xEF, 0x44, 0xE9, 0xA3, 0x0B, 0x4C, 0x5C, + 0x15, 0x9A, 0x98, 0x97, 0x98, 0xB4, 0xA6, 0x17, 0x13, 0x68, + 0x92, 0xD7, 0xB1, 0x1B, 0xBA, 0xF4, 0x11, 0xBB, 0xF4, 0xD1, + 0x0A, 0x73, 0x5B, 0x24, 0xCE, 0x0F, 0x28, 0x51, 0xD8, 0x8A, + 0x09, 0xA5, 0x0C, 0x0A, 0x68, 0x52, 0x25, 0x3B, 0xC4, 0x17, + 0xBA, 0x65, 0xD3, 0x80, 0x26, 0x05, 0xC1, 0x72, 0xF3, 0xFD, + 0x5E, 0x46, 0xA7, 0x2B, 0x7E, 0x6D, 0xF8, 0xEA, 0x37, 0x77, + 0x33, 0x05, 0xD3, 0xC9, 0x27, 0x22, 0xDF, 0x4F, 0x3A, 0xAD, + 0xA3, 0x69, 0xA0, 0xC7, 0xD5, 0x27, 0x76, 0x19, 0xCC, 0x3E, + 0xD1, 0x7B, 0x44, 0xED, 0x8C, 0xBC, 0x45, 0xF5, 0x4D, 0x14, + 0x58, 0xAA, 0x5A, 0x0F, 0x2B, 0xD9, 0x51, 0x09, 0x79, 0x04, + 0x21, 0xBD, 0xCE, 0x41, 0xB9, 0x9A, 0x8E, 0xC2, 0xE0, 0x19, + 0xB5, 0x7B, 0x5E, 0xEB, 0xFA, 0xBB, 0x30, 0xA1, 0x8E, 0x7B, + 0xD3, 0x64, 0xDA, 0x1B, 0x08, 0x41, 0xED, 0x72, 0x52, 0xB9, + 0x7A, 0xDA, 0x2B, 0xA4, 0xDF, 0x9F, 0xF4, 0xEE, 0xDA, 0xDD, + 0xEF, 0xDD, 0xB3, 0x75, 0x45, 0xC2, 0x5C, 0xF2, 0xB4, 0xF9, + 0xEA, 0x2C, 0x9D, 0x3E, 0xDB, 0x28, 0x65, 0x55, 0x5B, 0xBA, + 0x11, 0xEE, 0xDF, 0xDF, 0x69, 0x32, 0x71, 0x46, 0x3D, 0x67, + 0x5F, 0x44, 0xAC, 0x34, 0x45, 0x3F, 0xDA, 0x35, 0xD3, 0x86, + 0x01, 0xEC, 0xA8, 0x4B, 0xFE, 0x70, 0xBB, 0x84, 0xE0, 0x74, + 0xCF, 0xC2, 0x3E, 0xD7, 0x84, 0xFC, 0x99, 0xA9, 0xE3, 0xC6, + 0x0D, 0xAF, 0xEB, 0x3E, 0x89, 0xBF, 0xCC, 0x17, 0x2C, 0xE3, + 0xB8, 0xF4, 0xB3, 0x8D, 0x41, 0x43, 0x5F, 0x04, 0xBD, 0x07, + 0xBA, 0x85, 0xAD, 0x20, 0xF1, 0xB7, 0xFC, 0xCF, 0x32, 0xB6, + 0xD4, 0xFD, 0x7E, 0x47, 0x32, 0x9B, 0xD2, 0xEE, 0x20, 0x77, + 0x15, 0x21, 0x9A, 0xE1, 0x70, 0x29, 0xF9, 0x9C, 0x53, 0x40, + 0xD8, 0xE0, 0xA9, 0x22, 0xAD, 0xBB, 0x70, 0xF9, 0x44, 0x46, + 0x39, 0x6B, 0x84, 0x29, 0x45, 0x73, 0xB8, 0xE2, 0x2E, 0x8F, + 0x1B, 0x9F, 0x7A, 0x92, 0x29, 0x11, 0xF9, 0x8B, 0xA2, 0x00, + 0xB1, 0xCF, 0x29, 0xCC, 0x03, 0x40, 0x97, 0x96, 0xCF, 0x7A, + 0x08, 0xCE, 0xE7, 0x28, 0xBE, 0x0F, 0x54, 0x39, 0xA9, 0x71, + 0x03, 0x7E, 0x29, 0x3F, 0x8D, 0x9B, 0xDB, 0x68, 0xFE, 0x54, + 0x91, 0x04, 0x5D, 0x8C, 0xFA, 0x9A, 0xF7, 0x8E, 0x10, 0x18, + 0x9C, 0x48, 0x64, 0xB2, 0xD0, 0xDC, 0xE2, 0x8A, 0xAA, 0xA6, + 0x77, 0x67, 0x91, 0xC2, 0xFA, 0x76, 0xE0, 0x14, 0x4B, 0x8E, + 0xB3, 0x14, 0x9A, 0xC1, 0x87, 0x63, 0x3F, 0x09, 0x2D, 0x1C, + 0xA0, 0xC8, 0xB0, 0xE2, 0x55, 0xE8, 0x76, 0xBD, 0xFF, 0xC9, + 0x44, 0xD9, 0x3A, 0xB1, 0x98, 0xF5, 0x15, 0x96, 0x83, 0xAA, + 0x57, 0xBB, 0xC0, 0x0D, 0xBA, 0xF9, 0x3A, 0xD5, 0x37, 0x10, + 0xE7, 0x7A, 0xBB, 0x7B, 0xF9, 0x1E, 0xA3, 0x82, 0x0E, 0x7E, + 0x02, 0x97, 0x02, 0x27, 0x5E, 0x65, 0x5E, 0x57, 0x18, 0x52, + 0x20, 0xD8, 0xE8, 0x26, 0xAD, 0xCD, 0x83, 0x5F, 0x82, 0x95, + 0x16, 0x33, 0x18, 0x32, 0x45, 0x38, 0xC3, 0x93, 0xC3, 0xA5, + 0x4A, 0xCD, 0xC3, 0x02, 0xB2, 0xDA, 0xF9, 0x26, 0x00, 0xFC, + 0xA6, 0xCA, 0x0C, 0xAF, 0xCD, 0xD8, 0xE3, 0x0B, 0xBC, 0xFD, + 0x8D, 0xC3, 0xD8, 0x88, 0x0A, 0x90, 0x54, 0xE5, 0x6C, 0xEB, + 0x6C, 0x5F, 0xB4, 0xB1, 0x65, 0x10, 0x66, 0x0E, 0x5E, 0xAB, + 0x1C, 0x78, 0x66, 0x12, 0xE3, 0x5F, 0x43, 0x2B, 0x30, 0x48, + 0x34, 0x8B, 0x28, 0x20, 0x0C, 0x1C, 0xE7, 0x8C, 0xA0, 0xFF, + 0x9E, 0x3F, 0xDE, 0x91, 0xA4, 0x58, 0x42, 0xEB, 0xB1, 0xA4, + 0xD1, 0x11, 0x41, 0x3A, 0x43, 0xA7, 0x58, 0x0A, 0xC9, 0x4E, + 0xEB, 0xFB, 0x90, 0x3E, 0x1F, 0x3C, 0x9F, 0x0E, 0xE8, 0x8C, + 0x3F, 0x03, 0x29, 0xE5, 0xB1, 0x71, 0x61, 0xB7, 0x09, 0xFF, + 0x0A, 0xBD, 0x4D, 0xD1, 0x82, 0x5B, 0x6A, 0x3A, 0x4D, 0x49, + 0xFD, 0x10, 0xA0, 0x2C, 0xD7, 0x24, 0xF7, 0x71, 0xAD, 0xA8, + 0x35, 0x29, 0xA2, 0x8D, 0x65, 0xA7, 0x59, 0xCE, 0xB0, 0x2D, + 0x06, 0x37, 0x78, 0xDA, 0x89, 0x8F, 0xCB, 0x06, 0x2A, 0x51, + 0x06, 0x23, 0x04, 0x65, 0x9E, 0x98, 0x2E, 0x39, 0x9E, 0xCF, + 0x19, 0x00, 0x2B, 0xE8, 0x4F, 0x9C, 0x8F, 0xF0, 0x19, 0xA0, + 0xB2, 0x55, 0x21, 0x20, 0x94, 0x21, 0x1A, 0x04, 0x2B, 0x43, + 0xF2, 0xAA, 0xDC, 0x7A, 0x6A, 0xB5, 0xFB, 0xDF, 0xC0, 0xC9, + 0xF5, 0x65, 0x01, 0xD0, 0x74, 0xF6, 0xFF, 0xA9, 0x06, 0x5E, + 0x7A, 0xE5, 0xA8, 0x73, 0x12, 0xA4, 0x76, 0xD8, 0xF8, 0x21, + 0x89, 0x07, 0x88, 0xDA, 0xF8, 0x8D, 0xD8, 0x29, 0xB3, 0x83, + 0x01, 0xD1, 0x36, 0x32, 0x7D, 0x33, 0x60, 0x31, 0xFD, 0x77, + 0xD5, 0x74, 0xAA, 0x20, 0xC3, 0xDF, 0x16, 0x8F, 0xAF, 0x71, + 0xD7, 0x4D, 0xAA, 0xC6, 0xDB, 0x98, 0x8B, 0x15, 0xFE, 0x3E, + 0x47, 0x9A, 0x16, 0x30, 0x76, 0xF8, 0x01, 0xA3, 0xF9, 0x83, + 0xC2, 0xAF, 0x91, 0x4C, 0x8E, 0x58, 0x9A, 0x91, 0x70, 0xA2, + 0xDE, 0x17, 0x84, 0xD2, 0x31, 0xBF, 0x06, 0x78, 0x35, 0xB7, + 0x80, 0x8B, 0xC4, 0x8D, 0xCF, 0xB5, 0xEB, 0x75, 0xE5, 0x66, + 0x5E, 0x95, 0xB6, 0xA4, 0x76, 0x9B, 0x21, 0x7B, 0xE9, 0x62, + 0x2D, 0xAD, 0x0A, 0xA2, 0x32, 0x25, 0xCA, 0x5A, 0xC4, 0x29, + 0x98, 0x8E, 0xDF, 0x8B, 0x80, 0x6C, 0xA9, 0x04, 0x8E, 0xDD, + 0x8F, 0xEA, 0xD6, 0xA7, 0xEC, 0x6E, 0xD3, 0x1B, 0xD4, 0x03, + 0x73, 0x47, 0x92, 0x12, 0xD9, 0xD0, 0xE5, 0xFB, 0x1D, 0x89, + 0x4D, 0xB7, 0x08, 0xE1, 0xED, 0x19, 0x42, 0xD7, 0xB3, 0xFC, + 0xED, 0x8E, 0x3A, 0x7A, 0xD5, 0xAF, 0xA7, 0x54, 0xDB, 0xAC, + 0xB8, 0x4D, 0xD2, 0x97, 0x26, 0x07, 0xE9, 0x1A, 0xB4, 0xB8, + 0x04, 0xC9, 0xAE, 0xD2, 0x69, 0xA3, 0xA8, 0x3E, 0xBD, 0x58, + 0xC0, 0x9B, 0x00, 0x9E, 0x0C, 0xF8, 0xBA, 0xF7, 0x76, 0x22, + 0x96, 0xBF, 0xEE, 0x67, 0xE9, 0x78, 0xF8, 0xFB, 0xC1, 0x76, + 0x26, 0x93, 0xDC, 0xD4, 0xF1, 0x3A, 0x9D, 0x50, 0x1D, 0x19, + 0xB8, 0x84, 0x83, 0xA2, 0xF4, 0x39, 0x1C, 0x75, 0x3D, 0xBB, + 0x4E, 0x7A, 0xE7, 0x17, 0xF3, 0x65, 0x8A, 0x3A, 0xE3, 0xB9, + 0x3B, 0xA2, 0x2A, 0x2A, 0x31, 0x68, 0x84, 0x95, 0x92, 0xB0, + 0x3E, 0x62, 0xC8, 0xCC, 0x2A, 0xE8, 0xC8, 0xAE, 0x22, 0x25, + 0xBF, 0x68, 0xDD, 0x12, 0xA3, 0xC5, 0x07, 0xF2, 0x66, 0xBC, + 0x3A, 0xF6, 0xDD, 0xF2, 0x6D, 0x32, 0xDD, 0x6F, 0x9A, 0x0D, + 0x62, 0x5E, 0xAE, 0x6E, 0xE0, 0x12, 0x57, 0x3A, 0x22, 0x73, + 0xB3, 0x52, 0xD5, 0x7D, 0xFD, 0xCB, 0x96, 0x1E, 0x17, 0x0F, + 0x3F, 0xED, 0x5F, 0xF4, 0x0A, 0x62, 0xC4, 0x49, 0xFB, 0x28, + 0x3C, 0x29, 0x35, 0x78, 0xE0, 0x06, 0x76, 0x2E, 0x6C, 0x4C, + 0xAB, 0x53, 0xA5, 0xE3, 0x80, 0x62, 0x97, 0x93, 0x19, 0x4E, + 0x5D, 0x1D, 0xE5, 0x06, 0x22, 0x0A, 0xA0, 0xA1, 0x27, 0x49, + 0x4E, 0xD0, 0x12, 0x01, 0xCA, 0x94, 0xBC, 0xC1, 0xE2, 0x5D, + 0x5D, 0x77, 0x86, 0x50, 0xF5, 0xB5, 0x42, 0xC3, 0x6C, 0xED, + 0x9D, 0x61, 0x94, 0xDB, 0x5A, 0x4D, 0x24, 0x32, 0xD9, 0x51, + 0x96, 0x91, 0xEF, 0x03, 0xF1, 0xE9, 0xBD, 0xB1, 0x11, 0xFE, + 0x83, 0x5C, 0x90, 0xB2, 0x2A, 0x42, 0x52, 0x81, 0x6E, 0x00, + 0xCB, 0x34, 0x1B, 0xE6, 0xEB, 0x8B, 0x00, 0x22, 0x7B, 0xD5, + 0x3D, 0xE0, 0x19, 0x75, 0x85, 0x0A, 0xFE, 0x54, 0x3C, 0x7B, + 0xF5, 0x56, 0x94, 0xDF, 0x24, 0xF0, 0xC0, 0x0C, 0x1A, 0x53, + 0x1C, 0x1D, 0x26, 0x04, 0xA6, 0xBB, 0xC6, 0x4D, 0x24, 0xC0, + 0xF2, 0x00, 0x14, 0xFB, 0x19, 0x7B, 0x50, 0xCA, 0xF4, 0xCE, + 0x08, 0x27, 0x4B, 0xE6, 0xB8, 0xA2, 0xC4, 0xA9, 0x57, 0xBA, + 0xE5, 0xC2, 0xAF, 0xBF, 0xFB, 0x44, 0x1B, 0xA7, 0x75, 0xBA, + 0xC7, 0xB9, 0x0D, 0x09, 0x26, 0x81, 0x24, 0xB2, 0xC9, 0x2B, + 0x04, 0x46, 0x8C, 0x6B, 0x02, 0xA4, 0x35, 0xB1, 0x77, 0xFB, + 0xC5, 0x1D, 0x9F, 0xC7, 0x94, 0xD2, 0x00, 0xF2, 0x56, 0x86, + 0xA5, 0xDA, 0x12, 0xA6, 0x7E, 0xFE, 0xE3, 0xF4, 0x49, 0x4F, + 0x02, 0xAD, 0x30, 0x16, 0xC6, 0x3C, 0x2A, 0xBF, 0xF9, 0x8D, + 0x47, 0xC7, 0x88, 0xA7, 0x51, 0x6C, 0x53, 0xC3, 0x67, 0x8A, + 0x2A, 0xF3, 0x14, 0x9D, 0x75, 0x1A, 0x9D, 0x67, 0x54, 0xEE, + 0x60, 0xE0, 0x10, 0xD3, 0xDA, 0x36, 0xF2, 0x5C, 0xB9, 0xAA, + 0x7D, 0xFD, 0x2C, 0xA6, 0x51, 0x38, 0x7E, 0xFD, 0xDA, 0x4E, + 0x97, 0xE5, 0xF3, 0x4A, 0x44, 0x04, 0xB3, 0x6A, 0xDB, 0xD7, + 0xCF, 0x4F, 0x64, 0x23, 0x8A, 0x81, 0x10, 0xF9, 0x99, 0x26, + 0x58, 0x0A, 0x1B, 0x24, 0x41, 0xD3, 0xF2, 0x35, 0x33, 0xAD, + 0xF5, 0xBE, 0x0A, 0xCF, 0xF1, 0x02, 0x3C, 0xD6, 0xA2, 0xCC, + 0xC8, 0x28, 0x82, 0x5B, 0x72, 0x91, 0x0B, 0x54, 0xD4, 0xDC, + 0x8D, 0xD7, 0xCB, 0x16, 0x6B, 0xD3, 0x5A, 0xEA, 0x41, 0xB4, + 0x2F, 0x4F, 0x66, 0x6C, 0x9A, 0xA2, 0x11, 0x91, 0x74, 0xCF, + 0xE9, 0x3E, 0x44, 0x14, 0x73, 0xEC, 0x80, 0x68, 0xD3, 0x50, + 0x37, 0xF9, 0x70, 0x98, 0x66, 0x9D, 0xE0, 0xA2, 0xFE, 0x0B, + 0x49, 0x61, 0x6F, 0x9D, 0xF8, 0x91, 0x2C, 0x84, 0xFB, 0x03, + 0x48, 0x2A, 0x6B, 0xB4, 0xBA, 0xE1, 0xF3, 0xA6, 0x4D, 0x3F, + 0x71, 0xED, 0x87, 0xB6, 0x8F, 0x2B, 0x33, 0xCF, 0xE4, 0x6B, + 0xBE, 0xEC, 0x69, 0xDB, 0x7C, 0x5F, 0x7A, 0xB9, 0x14, 0x07, + 0x74, 0xEC, 0x63, 0x76, 0xF5, 0xB8, 0x48, 0xA5, 0x82, 0x96, + 0x77, 0x1D, 0x4A, 0x36, 0x75, 0x99, 0xB5, 0xEF, 0x3C, 0xCC, + 0xEF, 0xB0, 0x97, 0x46, 0x9D, 0x84, 0x7B, 0xAC, 0x81, 0x2B, + 0x3D, 0x35, 0xA2, 0x83, 0x57, 0x99, 0x0B, 0x61, 0xAF, 0x96, + 0x9B, 0x73, 0x0D, 0xBA, 0xC4, 0xF1, 0xCB, 0xC2, 0x6F, 0x1A, + 0x1A, 0x2A, 0xA1, 0x81, 0x20, 0xB7, 0xA4, 0xC8, 0x2B, 0x23, + 0x19, 0x9C, 0x79, 0x7E, 0x41, 0xC3, 0xE3, 0xF0, 0x38, 0x44, + 0x02, 0x5F, 0x02, 0x0C, 0x6D, 0x74, 0xC3, 0xBF, 0x55, 0x49, + 0xA6, 0xD7, 0x18, 0x87, 0xD0, 0x2C, 0xD3, 0x9D, 0x2B, 0xBE, + 0xD4, 0x6D, 0xAE, 0x4B, 0x42, 0x73, 0x92, 0xFF, 0x88, 0xE1, + 0x55, 0xC7, 0xFE, 0x6B, 0xE2, 0x0F, 0xEA, 0x68, 0x2E, 0xCF, + 0xD6, 0x6E, 0x06, 0x88, 0x68, 0xE0, 0xA9, 0x8C, 0x86, 0x5B, + 0xF0, 0xB6, 0xB9, 0x49, 0x11, 0xB1, 0xCB, 0x5F, 0xD2, 0xB3, + 0xEF, 0x24, 0x1A, 0xF3, 0xC8, 0xEB, 0xE1, 0xCC, 0x58, 0x40, + 0xF1, 0xA5, 0xD6, 0xEA, 0x77, 0x1F, 0xBA, 0xF4, 0x23, 0xD9, + 0x9F, 0x38, 0x22, 0xEB, 0xC6, 0x67, 0xED, 0x34, 0x2A, 0x59, + 0x6F, 0x68, 0x46, 0xC1, 0xDD, 0xFF, 0xC7, 0x45, 0xA0, 0x91, + 0x62, 0xD4, 0x39, 0xBE, 0x4A, 0x73, 0x08, 0xD3, 0x24, 0x52, + 0xC1, 0xD9, 0xFA, 0xFE, 0xD9, 0x4A, 0x26, 0x85, 0xE7, 0xDF, + 0x72, 0x2E, 0x45, 0x5D, 0x01, 0x08, 0x16, 0xAF, 0x16, 0x96, + 0x85, 0x6F, 0x85, 0x8D, 0x35, 0x51, 0x6A, 0xDB, 0xF0, 0xEA, + 0xCA, 0xF8, 0xC2, 0x02, 0xCD, 0x93, 0xEF, 0x34, 0x99, 0xED, + 0x1E, 0xC9, 0x87, 0xB9, 0x8F, 0x79, 0xCE, 0x6F, 0x3E, 0x2F, + 0x9A, 0xB3, 0xDD, 0x08, 0x4D, 0x52, 0x85, 0x4F, 0xE2, 0x26, + 0x39, 0x8F, 0x98, 0x84, 0x73, 0x49, 0x2F, 0xB2, 0xC4, 0x48, + 0xBE, 0x74, 0x3E, 0x42, 0x4B, 0x0E, 0x34, 0x1C, 0x4F, 0x33, + 0xF9, 0x51, 0xFC, 0xCB, 0xD3, 0xD6, 0xF1, 0x61, 0xF1, 0x19, + 0xCF, 0x42, 0xEE, 0xB3, 0x85, 0xBB, 0x47, 0x56, 0x71, 0x36, + 0x87, 0x0A, 0x29, 0x0F, 0xFD, 0x8A, 0x24, 0xC1, 0x06, 0x3B, + 0x73, 0xD5, 0x8D, 0x79, 0x72, 0xAC, 0x44, 0xE0, 0x45, 0x71, + 0x61, 0xBC, 0x2B, 0xE6, 0x5F, 0x81, 0x5D, 0x4A, 0xD8, 0x11, + 0x8F, 0x0F, 0x20, 0xD9, 0x6E, 0x51, 0xB0, 0x65, 0x70, 0xAD, + 0xBE, 0x1E, 0xDC, 0xD6, 0xC2, 0xCE, 0x44, 0x94, 0xA9, 0x98, + 0x6E, 0x5F, 0x90, 0x21, 0x02, 0xE8, 0x3A, 0xE8, 0x79, 0xE3, + 0x17, 0x35, 0x7E, 0xC8, 0x0A, 0x00, 0xDB, 0x35, 0x6F, 0x51, + 0x7C, 0x36, 0x9A, 0xD2, 0xEA, 0x6F, 0x1E, 0x38, 0x0F, 0x50, + 0xA0, 0xA2, 0xEC, 0xB2, 0x19, 0x13, 0x33, 0xD0, 0x4F, 0x9B, + 0xD0, 0xF0, 0x9C, 0x8F, 0xC5, 0xA7, 0x77, 0xEA, 0x0F, 0x82, + 0x7F, 0x20, 0xBC, 0x37, 0x17, 0x41, 0x8D, 0x04, 0x63, 0xD5, + 0x12, 0x55, 0x00, 0xE6, 0x34, 0x35, 0x5F, 0x03, 0x04, 0xE7, + 0xBC, 0x31, 0x1C, 0xE9, 0x31, 0x1A, 0x32, 0xFB, 0xE2, 0xE7, + 0x79, 0xA3, 0xC5, 0x0B, 0xD1, 0x84, 0xB0, 0x36, 0xA0, 0xBD, + 0x85, 0x82, 0x5B, 0x62, 0x1D, 0x08, 0x31, 0xB2, 0x54, 0x52, + 0x49, 0xA9, 0x28, 0x4D, 0x57, 0x23, 0x56, 0xF7, 0xAC, 0x6B, + 0xF6, 0xDD, 0x27, 0x23, 0xDD, 0x58, 0xC4, 0x1B, 0x28, 0xD9, + 0xE9, 0x91, 0xCE, 0xCA, 0x57, 0x1D, 0x3E, 0x65, 0x6C, 0xFC, + 0x5F, 0x93, 0x9A, 0x0F, 0x65, 0xCF, 0xB0, 0xBD, 0xBC, 0x03, + 0x62, 0xD3, 0xAE, 0x5B, 0x60, 0xF7, 0x4D, 0x04, 0xE6, 0x96, + 0x12, 0x0F, 0x1C, 0x8A, 0xA7, 0x80, 0x7E, 0xBB, 0x2D, 0x5D, + 0x91, 0x55, 0xD8, 0xC7, 0x20, 0xAE, 0x59, 0x6B, 0xF0, 0x0E, + 0xE4, 0x25, 0xC1, 0xC3, 0x4E, 0x95, 0xF2, 0x00, 0x58, 0x75, + 0xCE, 0x52, 0x3B, 0xC2, 0x4C, 0xD5, 0xC7, 0x90, 0x11, 0x06, + 0x86, 0xD6, 0x32, 0xF8, 0xC6, 0x08, 0xBC, 0x05, 0x13, 0x4D, + 0x3E, 0xC6, 0x4D, 0x60, 0x17, 0xE7, 0x3A, 0xAB, 0xE8, 0x41, + 0xA2, 0x2E, 0x89, 0xA5, 0xC4, 0x9A, 0xB3, 0x60, 0xA0, 0xB5, + 0x5F, 0xCD, 0x8C, 0x33, 0x55, 0x9B, 0x40, 0x12, 0x95, 0x4B, + 0x14, 0xB0, 0x68, 0x56, 0xB2, 0xEF, 0xED, 0xEF, 0xB9, 0x25, + 0x0F, 0xC2, 0xC0, 0xC1, 0x0E, 0x80, 0x08, 0x9A, 0xFA, 0xCD, + 0x78, 0x22, 0xD2, 0x7F, 0x45, 0xD8, 0xFC, 0xD7, 0x1E, 0x9F, + 0xCC, 0xA3, 0x23, 0x91, 0x9B, 0x76, 0xFC, 0x6D, 0xB0, 0xC6, + 0x58, 0xDB, 0x75, 0x7E, 0x80, 0xED, 0x56, 0xA2, 0x9E, 0xD8, + 0x5D, 0xAA, 0x95, 0x4A, 0x87, 0x05, 0xBE, 0xEA, 0x9F, 0xED, + 0x4B, 0x7A, 0x16, 0x61, 0xA2, 0xED, 0x87, 0x2E, 0x05, 0x06, + 0x95, 0x44, 0xB4, 0x6D, 0xB1, 0x7D, 0x61, 0xE9, 0x03, 0x37, + 0xF8, 0x5A, 0xEB, 0x54, 0x61, 0x46, 0x72, 0x3F, 0x60, 0xA4, + 0x5B, 0xDE, 0xDE, 0x6E, 0x9B, 0x86, 0x99, 0x80, 0xE4, 0x8C, + 0x44, 0x92, 0x56, 0x04, 0x67, 0xF4, 0x7F, 0x6F, 0xDE, 0xB7, + 0xE7, 0x1F, 0x3F, 0xCE, 0x4F, 0x63, 0xC5, 0xFB, 0x99, 0xC7, + 0x3F, 0x75, 0x67, 0x22, 0x76, 0x19, 0x79, 0x31, 0xF9, 0x25, + 0xC1, 0x48, 0xB6, 0xE0, 0x78, 0xB7, 0x05, 0x4A, 0x23, 0x1C, + 0x81, 0x7F, 0x31, 0xEE, 0xC4, 0xBC, 0x51, 0xF9, 0x0C, 0x2D, + 0x5E, 0x82, 0x76, 0xEF, 0x8F, 0xB6, 0x45, 0x0C, 0xE5, 0x80, + 0xD8, 0x29, 0x7A, 0xF6, 0x3E, 0xE8, 0xE6, 0xFF, 0x7F, 0xAB, + 0x21, 0x37, 0x1B, 0x1E, 0xE6, 0x88, 0xAA, 0x9A, 0x24, 0xA4, + 0x63, 0x6A, 0x9E, 0xD0, 0x73, 0x85, 0x8C, 0x9B, 0x6B, 0x77, + 0x09, 0x24, 0xC5, 0x49, 0x6F, 0x51, 0xA3, 0x55, 0xEF, 0x5B, + 0xEE, 0x84, 0x9B, 0x0A, 0x83, 0xB6, 0x16, 0xBB, 0xB6, 0x74, + 0x5F, 0x45, 0x00, 0x39, 0x3D, 0x0E, 0x9D, 0xFD, 0x4F, 0x68, + 0x82, 0x1E, 0xDA, 0xFF, 0x78, 0x67, 0x1F, 0x62, 0xF5, 0x1C, + 0xAE, 0xD1, 0xAC, 0x3E, 0x22, 0xE0, 0x97, 0xDA, 0x0A, 0x33, + 0x64, 0x32, 0x50, 0x5A, 0x8D, 0x2E, 0xBC, 0x0D, 0x00, 0x73, + 0x03, 0xE4, 0x5A, 0xEC, 0xF0, 0xA3, 0x7F, 0x18, 0x67, 0x20, + 0x61, 0x6D, 0xCC, 0xC3, 0x09, 0xBB, 0x0F, 0x84, 0xF0, 0x96, + 0xAE, 0x25, 0xDD, 0x63, 0x41, 0x61, 0x52, 0xAB, 0xD1, 0x0D, + 0x7E, 0x5C, 0x89, 0x64, 0xB5, 0x97, 0x7C, 0xD6, 0x51, 0xA4, + 0x04, 0x98, 0x31, 0xBB, 0x06, 0xFB, 0xFB, 0xF3, 0x53, 0x3A, + 0x40, 0xAF, 0x0E, 0xD5, 0x4D, 0xB3, 0x08, 0x74, 0xBC, 0x21, + 0x45, 0x21, 0x59, 0xDF, 0x41, 0xCE, 0x33, 0xDB, 0x16, 0x5D, + 0xEB, 0xFD, 0x6C, 0x17, 0x8C, 0xD1, 0x03, 0xCA, 0x8E, 0x4F, + 0x38, 0x3C, 0xD5, 0x7C, 0x48, 0x82, 0xDB, 0x65, 0xC1, 0x0C, + 0x54, 0xD9, 0x5F, 0xAF, 0x12, 0x65, 0x2E, 0xBE, 0xCA, 0xDE, + 0x90, 0x5A, 0x57, 0x51, 0x13, 0x0B, 0x12, 0x87, 0x48, 0x77, + 0x30, 0x4D, 0x79, 0x67, 0xB9, 0xBE, 0xAA, 0x6A, 0x80, 0x49, + 0x8F, 0x9F, 0xEE, 0xAE, 0x5D, 0x24, 0xBC, 0x74, 0xCF, 0x5E, + 0x02, 0x07, 0xAC, 0x8F, 0x39, 0xFF, 0x8C, 0x3E, 0xDA, 0xE0, + 0x0A, 0x58, 0xB1, 0x86, 0x1C, 0x82, 0xA4, 0xBE, 0x1E, 0x91, + 0x8C, 0x9C, 0x1A, 0xF5, 0x50, 0xFA, 0xE3, 0xD7, 0x21, 0x29, + 0x3E, 0x94, 0x74, 0x6D, 0xD0, 0x89, 0x73, 0xE3, 0x4F, 0xD6, + 0xA5, 0x7D, 0x92, 0xDC, 0xC6, 0xFF, 0x7F, 0x82, 0x7A, 0xAC, + 0x5B, 0x04, 0x3D, 0x9A, 0xFC, 0x88, 0x50, 0xA3, 0xCD, 0x41, + 0xFD, 0x85, 0xDA, 0x33, 0x6C, 0x6A, 0x25, 0x6D, 0x2B, 0x6C, + 0x1B, 0x5F, 0x32, 0xF3, 0xA7, 0x43, 0x3A, 0x58, 0x89, 0xD5, + 0xCF, 0xA6, 0xE7, 0x3C, 0x55, 0x84, 0x87, 0x66, 0x71, 0x1E, + 0xC5, 0xB0, 0x72, 0xA8, 0xB0, 0x07, 0x56, 0x9A, 0x2A, 0x8E, + 0xD2, 0xBD, 0x78, 0xB6, 0x33, 0x2D, 0xE2, 0xDD, 0x84, 0x78, + 0x50, 0x44, 0xB6, 0x8A, 0x29, 0x82, 0x0D, 0x14, 0x50, 0x5D, + 0x2C, 0x7C, 0x8A, 0x39, 0x42, 0x44, 0xAB, 0x0C, 0x31, 0x44, + 0x15, 0x87, 0xE0, 0x70, 0x14, 0xA9, 0xA7, 0x12, 0x6E, 0xF5, + 0xBE, 0xC3, 0x45, 0x1B, 0xE7, 0x4A, 0xDC, 0x9A, 0x2D, 0x24, + 0x22, 0xF8, 0x65, 0x26, 0xAB, 0x96, 0x8D, 0xB3, 0x14, 0x73, + 0x54, 0x71, 0x95, 0xCC, 0x11, 0xB2, 0x76, 0xCC, 0xA2, 0x2E, + 0x14, 0x13, 0xEE, 0x67, 0xB2, 0x25, 0x63, 0x6C, 0xE6, 0x49, + 0xEF, 0xC4, 0x32, 0x53, 0xAA, 0xBF, 0x6D, 0xFF, 0xE6, 0x74, + 0x80, 0x1A, 0x46, 0x71, 0x1C, 0xAF, 0x8A, 0xFA, 0x7E, 0x6D, + 0xA3, 0x47, 0x25, 0x3D, 0x38, 0x78, 0x6D, 0xCB, 0xB5, 0x24, + 0xE8, 0xB8, 0x56, 0xE5, 0xE2, 0xAD, 0xB0, 0x24, 0xEC, 0x6C, + 0xC5, 0x24, 0xEC, 0x72, 0x18, 0x28, 0x6F, 0x20, 0x62, 0x5F, + 0x2D, 0x53, 0xCD, 0x8E, 0xFE, 0xDF, 0xFC, 0xD5, 0x22, 0x67, + 0x73, 0x0C, 0x41, 0xCF, 0x4B, 0x22, 0xD8, 0xA5, 0xC5, 0x95, + 0xA7, 0x59, 0x43, 0x3E, 0x13, 0x3A, 0x90, 0xE5, 0xBD, 0x3E, + 0xB3, 0xBE, 0x7C, 0x13, 0xF5, 0xC2, 0x4B, 0x57, 0xF4, 0x00, + 0x27, 0xF9, 0xDF, 0x5C, 0xF8, 0xC5, 0x4C, 0xED, 0x0F, 0x81, + 0xC4, 0xA5, 0xA1, 0x21, 0xCF, 0xDA, 0x65, 0xD9, 0x1F, 0xFD, + 0x5E, 0x9F, 0xCA, 0x60, 0xB0, 0x21, 0x87, 0xD6, 0x66, 0x62, + 0xE1, 0xBE, 0x36, 0x44, 0xA6, 0xF5, 0x1E, 0x0C, 0x57, 0x64, + 0xEC, 0x93, 0xEC, 0x51, 0x6E, 0xEE, 0xAB, 0x89, 0x3C, 0xD7, + 0xF7, 0x2B, 0x38, 0x77, 0xDF, 0x87, 0x26, 0x64, 0x22, 0xBE, + 0x2A, 0xF3, 0x30, 0xB1, 0xD8, 0x04, 0xD4, 0xF9, 0xAE, 0x1D, + 0x33, 0x39, 0xBA, 0x29, 0x7F, 0xA5, 0x53, 0xF9, 0x6C, 0xF2, + 0xEA, 0x4C, 0x7B, 0xAE, 0x4C, 0xBE, 0x71, 0xC5, 0x14, 0x79, + 0xC6, 0xAD, 0x5F, 0x3A, 0xB4, 0x21, 0xB3, 0xBF, 0x0E, 0xEB, + 0x98, 0x6A, 0x7D, 0xD0, 0x79, 0xDA, 0x65, 0xA9, 0x04, 0xB5, + 0xF3, 0x2B, 0x1F, 0x82, 0x9E, 0x82, 0xEC, 0xB5, 0x58, 0xBC, + 0xFB, 0x78, 0x89, 0xD3, 0x57, 0xDD, 0x38, 0x85, 0xEA, 0x0D, + 0xF9, 0x5E, 0x7C, 0xF6, 0x81, 0x30, 0xEB, 0xC6, 0x35, 0xCE, + 0x4C, 0x08, 0x04, 0xB0, 0x77, 0x07, 0x04, 0x03, 0xB8, 0xBD, + 0x17, 0xDC, 0x28, 0x86, 0x59, 0xEE, 0xCD, 0xA0, 0x8A, 0x46, + 0x81, 0x0E, 0x70, 0x19, 0xAA, 0x14, 0x12, 0xA1, 0xF8, 0x1A, + 0xBB, 0x86, 0x5D, 0x41, 0x6D, 0x48, 0x54, 0x3C, 0x9E, 0xE3, + 0x88, 0x41, 0x42, 0x71, 0x52, 0x75, 0x91, 0xB1, 0x1E, 0x2C, + 0x12, 0xDC, 0xF2, 0xD1, 0xB4, 0xDC, 0x94, 0xEA, 0x63, 0x89, + 0xD9, 0x2D, 0x3D, 0x63, 0x28, 0x07, 0x67, 0xB9, 0x2D, 0xD9, + 0x93, 0x0C, 0x8E, 0x88, 0xCE, 0xFD, 0xA4, 0x09, 0x40, 0x3C, + 0xA8, 0x88, 0x5C, 0xC7, 0xEA, 0xB5, 0xFE, 0x44, 0x77, 0xCC, + 0x08, 0xE5, 0x8C, 0x80, 0x17, 0xA4, 0x34, 0xFF, 0x08, 0x0C, + 0xE7, 0x52, 0x08, 0x89, 0xBF, 0x1D, 0xB2, 0xEB, 0xD5, 0x59, + 0xA8, 0xC8, 0xDD, 0x17, 0x42, 0x99, 0x76, 0x52, 0x66, 0xAA, + 0x0B, 0x5F, 0xA7, 0xCB, 0xDF, 0x11, 0x2A, 0x06, 0xA4, 0xE8, + 0xB6, 0x1B, 0xF9, 0x74, 0x82, 0xEE, 0xA1, 0x03, 0x4F, 0x2E, + 0x88, 0x0E, 0x23, 0x8C, 0x4F, 0xDC, 0x2C, 0x24, 0x5F, 0xAE, + 0x1F, 0xD3, 0x5C, 0x3B, 0xC3, 0x87, 0x56, 0xB2, 0xC0, 0xA4, + 0xE0, 0xFB, 0x30, 0xB1, 0x91, 0x91, 0x00, 0xED, 0x4C, 0xE9, + 0xAC, 0xE4, 0xE9, 0x2E, 0xF0, 0x2D, 0x00, 0x8D, 0x05, 0xA3, + 0xD0, 0x6B, 0x73, 0x6A, 0xEC, 0x5A, 0xF2, 0xB0, 0x94, 0x05, + 0x14, 0x91, 0xB5, 0xDF, 0xAF, 0x7A, 0x85, 0xC6, 0x4C, 0x4E, + 0xA7, 0x70, 0x1B, 0x61, 0x30, 0xE0, 0x8A, 0x18, 0x33, 0x86, + 0x19, 0x9B, 0x09, 0x84, 0x42, 0x4E, 0x78, 0x65, 0x11, 0x00, + 0x93, 0x7A, 0x75, 0x45, 0x93, 0x5A, 0xB7, 0x82, 0x65, 0xF3, + 0x6A, 0x4F, 0x4B, 0xC4, 0x83, 0x9F, 0x6D, 0x2D, 0x5C, 0xF5, + 0x58, 0x7B, 0x42, 0xBE, 0x9D, 0xC3, 0x95, 0xDF, 0xB4, 0xF2, + 0x99, 0x1C, 0x22, 0x6B, 0x15, 0x15, 0x94, 0x46, 0xB3, 0x8B, + 0xD9, 0x8C, 0x12, 0x17, 0x87, 0xB4, 0xB0, 0x17, 0xA9, 0xF8, + 0x66, 0x82, 0x87, 0x23, 0x44, 0x10, 0xFC, 0xF8, 0x1B, 0xFF, + 0xB4, 0x74, 0x4E, 0x01, 0x52, 0x74, 0x25, 0x9B, 0x1B, 0x8C, + 0x43, 0x10, 0xDD, 0xF3, 0xB8, 0x62, 0x96, 0x87, 0xFA, 0xAB, + 0x75, 0x59, 0xD3, 0x96, 0xF3, 0x4B, 0x8A, 0x85, 0xAD, 0xED, + 0x3B, 0xB8, 0x87, 0xDD, 0xA4, 0x19, 0x92, 0x18, 0x8D, 0x5C, + 0x9D, 0x21, 0x68, 0x24, 0xAB, 0x89, 0x00, 0xBB, 0xD3, 0x86, + 0xD7, 0x57, 0x35, 0x9E, 0x78, 0x05, 0xF6, 0x45, 0x39, 0x0F, + 0x4A, 0x79, 0xD2, 0xA7, 0x27, 0x7C, 0x8F, 0x2F, 0x94, 0x10, + 0x59, 0xFC, 0x85, 0x0C, 0x5E, 0x04, 0xB6, 0xB0, 0x18, 0x88, + 0xAE, 0x0E, 0x01, 0x16, 0xB8, 0x7A, 0x2C, 0x5F, 0xF9, 0xBC, + 0x99, 0xCD, 0xA4, 0xAA, 0xE4, 0x53, 0xEC, 0xD7, 0xC5, 0x44, + 0x06, 0xC9, 0x20, 0x01, 0xEF, 0xE6, 0x13, 0x1C, 0x41, 0x29, + 0x28, 0xF1, 0xEA, 0x30, 0xD9, 0x6E, 0xE6, 0x1B, 0x4F, 0xEE, + 0x0E, 0x87, 0xEF, 0x38, 0xDE, 0xE3, 0x47, 0xFA, 0x05, 0x3D, + 0x06, 0xD5, 0xB6, 0x28, 0x63, 0x75, 0x88, 0xFA, 0x2D, 0x15, + 0x98, 0x60, 0x1E, 0x8A, 0xC0, 0x20, 0xF2, 0x4A, 0xDA, 0x9F, + 0x8C, 0xBB, 0x78, 0x78, 0x8F, 0xAD, 0xBB, 0x1C, 0xBB, 0x55, + 0xED, 0xF3, 0x88, 0xF0, 0x9A, 0x83, 0xFC, 0x86, 0xFE, 0x8D, + 0x85, 0x8B, 0x43, 0x54, 0xF8, 0x75, 0x18, 0x16, 0xE5, 0xCF, + 0xC9, 0x93, 0x1D, 0xE7, 0x44, 0xEE, 0x16, 0xE4, 0xF2, 0xBE, + 0x60, 0xEA, 0x88, 0xE3, 0x66, 0x5B, 0xF8, 0x0F, 0x83, 0x66, + 0x65, 0x60, 0xCB, 0x12, 0x10, 0x50, 0x95, 0xE9, 0x9F, 0x2D, + 0x2E, 0x4F, 0xC6, 0xEA, 0x59, 0x03, 0xF9, 0x4D, 0x4A, 0x7F, + 0xE3, 0x35, 0x03, 0x4F, 0x0E, 0x60, 0xF3, 0x75, 0xFF, 0x9F, + 0x1A, 0xD3, 0x0B, 0xC1, 0x46, 0xEA, 0x39, 0x57, 0x38, 0x93, + 0x22, 0x51, 0xB9, 0xB5, 0x15, 0x61, 0xAA, 0x05, 0x1E, 0x6B, + 0xEC, 0xC6, 0x28, 0x36, 0x7F, 0x7E, 0x68, 0xE1, 0xE3, 0xAC, + 0xDB, 0x55, 0x63, 0xED, 0xCD, 0xB4, 0x3C, 0xC3, 0xB1, 0xB7, + 0x01, 0xE5, 0x30, 0xE1, 0x09, 0xBE, 0xC9, 0x3C, 0x5B, 0xA1, + 0x26, 0x57, 0xCE, 0x38, 0x64, 0x42, 0x51, 0x75, 0x28, 0x10, + 0xAF, 0xE8, 0xD1, 0xDE, 0x1B, 0xC4, 0x4C, 0xB3, 0xA1, 0x87, + 0x39, 0x92, 0xD0, 0x04, 0x24, 0xDB, 0x9A, 0x29, 0x51, 0xC9, + 0xA9, 0x8D, 0xEE, 0xCC, 0xD3, 0x62, 0x23, 0x56, 0x0D, 0xCF, + 0x28, 0x6C, 0x11, 0xDC, 0x2C, 0x88, 0x6A, 0xBC, 0xAC, 0x3B, + 0x27, 0x31, 0x3C, 0x70, 0x79, 0x55, 0x56, 0x45, 0x2B, 0x73, + 0x89, 0x6E, 0x67, 0x83, 0x7A, 0x4D, 0x1E, 0x3E, 0x55, 0xC4, + 0x4B, 0x17, 0xDA, 0x71, 0x20, 0x81, 0xFF, 0xD2, 0x3C, 0xDD, + 0xD0, 0x75, 0x98, 0xA9, 0xCC, 0x90, 0x1D, 0x76, 0x74, 0x01, + 0xFA, 0x2E, 0xA8, 0x02, 0x1C, 0xB7, 0xAC, 0x59, 0x93, 0xA3, + 0x10, 0x78, 0x33, 0x41, 0xD3, 0xD8, 0xD3, 0xDB, 0x86, 0x49, + 0x32, 0x8E, 0x21, 0x3F, 0xD7, 0x4F, 0xBE, 0x75, 0x53, 0x99, + 0x8E, 0x6B, 0x37, 0xE1, 0x57, 0xFA, 0x24, 0x88, 0xE3, 0xC7, + 0x72, 0xA6, 0x31, 0xF3, 0x8B, 0xFF, 0x05, 0x27, 0xDE, 0xE2, + 0x25, 0x71, 0x70, 0xBF, 0x39, 0x37, 0x1B, 0x84, 0x84, 0x39, + 0x07, 0xA5, 0x3D, 0x67, 0xC0, 0xC7, 0x41, 0x9E, 0x56, 0x41, + 0x46, 0x2D, 0x65, 0x53, 0xE1, 0xCB, 0x8E, 0x66, 0x05, 0xAC, + 0xB2, 0x36, 0xB9, 0x40, 0x1B, 0xC6, 0xBF, 0x77, 0x73, 0x76, + 0x0E, 0xF3, 0x90, 0x0A, 0xB1, 0xC6, 0xFF, 0xF6, 0x1E, 0xB1, + 0xE9, 0x2B, 0x42, 0xE5, 0xDF, 0x67, 0x30, 0xB1, 0x47, 0x76, + 0x52, 0x28, 0xDF, 0x53, 0x86, 0x0F, 0x9D, 0x5E, 0x3D, 0xA2, + 0x01, 0x4B, 0x20, 0xA7, 0x92, 0xE9, 0x41, 0x0C, 0x16, 0x4B, + 0xE7, 0x07, 0x4D, 0x77, 0x43, 0x70, 0x74, 0x5B, 0xDD, 0x81, + 0xC5, 0x8F, 0xD5, 0x8D, 0xF8, 0xD6, 0xBE, 0xF6, 0xD6, 0x25, + 0x17, 0x17, 0x20, 0x04, 0xC2, 0x8B, 0xEF, 0xF5, 0xF6, 0x80, + 0xF9, 0x06, 0x83, 0xCE, 0xD2, 0x2B, 0x9B, 0xAF, 0x1A, 0x7A, + 0x65, 0x84, 0x12, 0x99, 0xF7, 0x0E, 0x42, 0xCF, 0x25, 0x9F, + 0x15, 0xF2, 0x40, 0x26, 0x15, 0x2A, 0x34, 0x63, 0xFF, 0xB1, + 0xED, 0xA8, 0xB4, 0x21, 0x03, 0x27, 0x3B, 0xEE, 0x7D, 0x40, + 0xD5, 0x71, 0x49, 0xA2, 0xA0, 0xB7, 0x34, 0x29, 0x8B, 0x06, + 0x32, 0x58, 0x5D, 0xE7, 0x57, 0xC9, 0x6C, 0x94, 0x27, 0x00, + 0xC1, 0xF4, 0x7F, 0x16, 0xFA, 0x34, 0x55, 0x11, 0x04, 0x71, + 0x62, 0x66, 0xC8, 0x6A, 0xCD, 0xD4, 0x9E, 0x72, 0xE2, 0x6E, + 0xD1, 0xA4, 0x05, 0xD7, 0x69, 0x6F, 0x0E, 0xA0, 0xAD, 0xD3, + 0x48, 0x25, 0x23, 0x74, 0x35, 0xA6, 0x74, 0x89, 0xC2, 0x60, + 0xB6, 0x46, 0x59, 0xC6, 0x46, 0x64, 0x64, 0x69, 0x47, 0xAF, + 0x2C, 0xBE, 0xBA, 0x32, 0xA2, 0xAA, 0x1C, 0x52, 0xDD, 0xC4, + 0xA9, 0x47, 0xE9, 0x74, 0xD2, 0xDB, 0xA0, 0xF5, 0x25, 0x7D, + 0x0A, 0xA9, 0x88, 0x43, 0x50, 0x71, 0x99, 0x3B, 0x62, 0xA2, + 0xCB, 0x31, 0xDD, 0x08, 0x60, 0x19, 0x79, 0xB3, 0xCF, 0x0B, + 0xDB, 0x08, 0xD4, 0xE4, 0xA8, 0xB0, 0x29, 0xB1, 0x94, 0xFE, + 0xBE, 0xA7, 0x56, 0x2B, 0xD6, 0xFF, 0x6D, 0x9C, 0xEB, 0x24, + 0x35, 0xB7, 0x8E, 0x65, 0x55, 0x7D, 0x0B, 0x30, 0x16, 0xEB, + 0xE2, 0x93, 0x13, 0x46, 0x5E, 0xAC, 0x17, 0x19, 0x54, 0x3E, + 0xEA, 0x95, 0xDA, 0x99, 0xDE, 0x72, 0x24, 0x2B, 0x31, 0x8D, + 0x5C, 0x27, 0x73, 0x3F, 0x11, 0x7D, 0xBD, 0x0A, 0x59, 0xBF, + 0xAE, 0x95, 0xC0, 0x58, 0xC3, 0x80, 0x1A, 0x7F, 0xA5, 0xC8, + 0xAA, 0x54, 0x5B, 0x20, 0x8B, 0x4F, 0x1B, 0x92, 0x34, 0xF2, + 0x67, 0xEF, 0x30, 0x1D, 0x22, 0x12, 0x3C, 0x94, 0x66, 0xF7, + 0x01, 0xA7, 0x2B, 0xC7, 0x32, 0xB6, 0x9D, 0x14, 0x1C, 0x9E, + 0xF3, 0x5E, 0x16, 0x0E, 0x68, 0x98, 0x1B, 0x0E, 0xA3, 0x58, + 0x40, 0x49, 0x3A, 0x4E, 0xAA, 0x41, 0xF5, 0x52, 0x4E, 0x68, + 0x6E, 0x5D, 0x31, 0x71, 0x2F, 0x45, 0x9A, 0x88, 0xD6, 0x8A, + 0xAE, 0xA7, 0x69, 0xB6, 0xC0, 0x7F, 0xF9, 0xC2, 0xEA, 0x5E, + 0xBA, 0xC3, 0xA1, 0x97, 0xE0, 0xC5, 0x4F, 0x1E, 0x90, 0xD6, + 0x7E, 0x34, 0x4C, 0x9D, 0x7A, 0xE9, 0xF9, 0xF0, 0x18, 0x56, + 0x73, 0xC7, 0x21, 0xE4, 0x3C, 0x50, 0xA0, 0xE3, 0xD4, 0xBE, + 0xB8, 0x58, 0xD9, 0xAB, 0xB8, 0x4E, 0xD1, 0x35, 0xF6, 0x8F, + 0x1B, 0x3A, 0x7F, 0xA3, 0x7F, 0x9E, 0xD1, 0x76, 0x4D, 0x49, + 0xD9, 0xFB, 0x80, 0x84, 0xA9, 0xC6, 0xE3, 0xD8, 0xA8, 0x51, + 0x93, 0xAE, 0xBB, 0xD5, 0x8F, 0x27, 0x98, 0x37, 0x51, 0x6A, + 0x98, 0x33, 0xD5, 0xE5, 0x44, 0x15, 0x58, 0x3A, 0xD5, 0xF1, + 0xA8, 0xA5, 0x50, 0xF9, 0xFA, 0x55, 0xD8, 0x23, 0xF6, 0xE6, + 0xCC, 0x05, 0xDC, 0x60, 0x6C, 0xA9, 0x47, 0x53, 0x30, 0xFA, + 0x4F, 0xFF, 0xAD, 0xEE, 0x1B, 0x11, 0x4E, 0x35, 0x6D, 0xA0, + 0x8D, 0x83, 0x8E, 0xBC, 0x78, 0xE1, 0x93, 0x65, 0x39, 0xA8, + 0xC9, 0x85, 0xDD, 0xBA, 0xA0, 0x07, 0x3A, 0x0B, 0xE8, 0x3D, + 0xDB, 0x84, 0xCA, 0x71, 0xEE, 0x18, 0xDF, 0x9F, 0xF4, 0xAA, + 0xF2, 0x82, 0x30, 0xA5, 0x76, 0x68, 0x8D, 0x81, 0xD1, 0x2C, + 0xEA, 0x43, 0x00, 0x66, 0xCD, 0xE3, 0xA6, 0x90, 0x1E, 0x99, + 0x01, 0x9D, 0xAF, 0x6E, 0xCF, 0x9B, 0x8E, 0xE0, 0x4B, 0xB7, + 0xE2, 0x8F, 0xDC, 0x8C, 0xD5, 0x9E, 0x1C, 0x7B, 0xB5, 0x93, + 0x86, 0xDD, 0x59, 0x36, 0x83, 0x2B, 0x8C, 0xBE, 0x21, 0x50, + 0xB5, 0xA2, 0xF9, 0xAD, 0xA3, 0xCC, 0x3A, 0x59, 0x47, 0x9E, + 0xE0, 0xFA, 0x44, 0x96, 0xBC, 0x22, 0x11, 0xF6, 0xA2, 0x93, + 0x79, 0x40, 0xA0, 0xF8, 0x35, 0x20, 0x10, 0x91, 0x3A, 0x64, + 0x44, 0x3E, 0x87, 0xA5, 0xFC, 0x34, 0xA5, 0x02, 0x74, 0xDA, + 0x46, 0xA0, 0xC8, 0x5B, 0x49, 0xAF, 0xC9, 0xCA, 0xAF, 0x10, + 0x25, 0xCB, 0x0D, 0x35, 0xE3, 0xEB, 0x64, 0xB2, 0x40, 0xC0, + 0x70, 0x46, 0xD4, 0x46, 0x42, 0x65, 0x1C, 0x70, 0xB9, 0xBA, + 0x72, 0xF8, 0x60, 0x62, 0x81, 0xFC, 0x13, 0xC7, 0x21, 0xE5, + 0x64, 0x4D, 0x65, 0x07, 0xE2, 0xE1, 0x57, 0x39, 0x76, 0xA8, + 0xB2, 0x2A, 0x63, 0xBD, 0xD5, 0xDA, 0x39, 0xAB, 0x99, 0xB2, + 0x26, 0xA0, 0x57, 0xE0, 0xD8, 0x6F, 0xCF, 0xED, 0x74, 0xB8, + 0xA4, 0x1D, 0xF8, 0x17, 0x32, 0x61, 0x41, 0x96, 0xA2, 0x6B, + 0xF7, 0x77, 0xA7, 0xFD, 0xB5, 0x3A, 0x80, 0x57, 0x2F, 0xB3, + 0x26, 0x38, 0x9D, 0x8B, 0xD7, 0xED, 0xC1, 0xCD, 0xE9, 0x68, + 0x45, 0xA7, 0x6A, 0x68, 0xFD, 0x93, 0xE1, 0xA9, 0xE4, 0x7D, + 0xA0, 0x7B, 0x60, 0x30, 0x7A, 0xF3, 0x11, 0x19, 0xEF, 0xD8, + 0x8D, 0x01, 0x13, 0xF6, 0x81, 0x6E, 0x16, 0x55, 0x99, 0x65, + 0xFD, 0xC3, 0xDB, 0x67, 0x09, 0x01, 0x69, 0x00, 0x8F, 0xC1, + 0xF8, 0x95, 0xDD, 0x91, 0x5C, 0x62, 0x54, 0x6F, 0xA3, 0x52, + 0x43, 0x68, 0xF8, 0x0E, 0x9E, 0x99, 0x92, 0x1B, 0xAB, 0x6B, + 0x6F, 0xDE, 0x83, 0x03, 0x0B, 0x7F, 0xF3, 0xE5, 0xD7, 0x02, + 0x63, 0xDD, 0xC2, 0xF3, 0xE8, 0x77, 0xB5, 0xC4, 0x8F, 0xD3, + 0xAF, 0x0C, 0x74, 0x21, 0x77, 0x02, 0x87, 0xE4, 0x95, 0xC4, + 0x8D, 0x6E, 0x67, 0xB1, 0xB2, 0x9A, 0x2A, 0x72, 0x36, 0xAE, + 0xAD, 0xB8, 0xAA, 0x6C, 0x0D, 0xB5, 0xFB, 0xB7, 0xA9, 0xBC, + 0x8C, 0x88, 0x3F, 0x67, 0x5E, 0xAD, 0x23, 0xAF, 0xC6, 0x20, + 0x21, 0x33, 0x02, 0xE1, 0x8F, 0xEB, 0xD1, 0x70, 0xB3, 0xDB, + 0x9A, 0x10, 0x93, 0x31, 0xF7, 0x3A, 0xE0, 0xBF, 0x70, 0x5F, + 0x86, 0xF8, 0x58, 0x9D, 0x52, 0x2A, 0xF6, 0x68, 0xB7, 0x07, + 0xB4, 0x36, 0x0F, 0xD6, 0x88, 0x2D, 0x50, 0x68, 0x14, 0x24, + 0xC7, 0xF3, 0xDC, 0xDD, 0x99, 0x11, 0x1F, 0xA1, 0x6D, 0x31, + 0x20, 0xEB, 0xA4, 0x57, 0x69, 0x42, 0x0E, 0x30, 0xC9, 0x60, + 0x1E, 0x59, 0x8C, 0x34, 0xD0, 0xF9, 0xEE, 0x63, 0x83, 0x19, + 0x42, 0x32, 0x40, 0x91, 0x4D, 0x92, 0xCC, 0xC6, 0x76, 0x33, + 0xCF, 0x52, 0x56, 0x96, 0x60, 0xBF, 0xD1, 0x3A, 0x51, 0xEB, + 0xC8, 0x99, 0x5F, 0x33, 0xCA, 0xB4, 0x0A, 0x39, 0x36, 0xA0, + 0x87, 0x85, 0xFF, 0x8A, 0x1E, 0x13, 0xFC, 0x9E, 0x42, 0xB7, + 0xB1, 0x6A, 0x3A, 0x88, 0x40, 0x4B, 0xBE, 0x1B, 0x49, 0x01, + 0x95, 0x79, 0xED, 0x48, 0xDD, 0xDC, 0xC0, 0x39, 0x9D, 0x2E, + 0x9C, 0xDC, 0xCF, 0x2B, 0x48, 0x2B, 0x4D, 0xC8, 0x42, 0x1F, + 0xF8, 0xBE, 0xA3, 0xB7, 0x54, 0xD1, 0x72, 0x5B, 0x5E, 0xDE, + 0x5F, 0xAE, 0x7E, 0x24, 0xE4, 0x4A, 0xED, 0xD9, 0x28, 0x1E, + 0xFF, 0xCD, 0x95, 0xC2, 0xEA, 0x2A, 0xCC, 0x50, 0xA6, 0x09, + 0x7C, 0x33, 0x99, 0x2D, 0xDB, 0xA7, 0x4D, 0x3C, 0x8B, 0x8F, + 0x07, 0x3A, 0x42, 0xE7, 0xF6, 0x4F, 0xD9, 0xAC, 0x31, 0x7F, + 0x50, 0x0E, 0x42, 0x93, 0x1D, 0x14, 0xB0, 0x09, 0xC5, 0x76, + 0x3F, 0xF0, 0x2C, 0xD8, 0x72, 0x9D, 0x93, 0x22, 0x9C, 0xD0, + 0x12, 0x21, 0xE3, 0xC9, 0x41, 0x2C, 0xBE, 0x37, 0xB4, 0xD3, + 0xB6, 0x12, 0x37, 0xE5, 0x4D, 0xB7, 0x35, 0x29, 0xA7, 0xD2, + 0xE7, 0x6B, 0x25, 0x42, 0x09, 0xDB, 0x59, 0xF1, 0x2B, 0x69, + 0x07, 0x82, 0x7E, 0xBA, 0xE4, 0xD3, 0x02, 0xBA, 0xAE, 0x34, + 0x3C, 0x56, 0x84, 0x30, 0xF9, 0x4F, 0xE7, 0x59, 0xC2, 0x11, + 0x58, 0xB3, 0xD0, 0x31, 0x2B, 0xDA, 0x24, 0xA1, 0xB0, 0xE0, + 0xDD, 0xD6, 0x32, 0x78, 0xDD, 0xB6, 0xE4, 0x15, 0x70, 0x42, + 0xB5, 0xE0, 0x58, 0xC9, 0x79, 0x4D, 0xD3, 0x20, 0x81, 0x9E, + 0xBF, 0x5A, 0x7D, 0x8B, 0x0C, 0xAA, 0x66, 0xCE, 0xF1, 0xC5, + 0x03, 0x45, 0x43, 0xAF, 0xAE, 0x8C, 0xF6, 0xDD, 0xCF, 0x78, + 0xEF, 0x98, 0xA7, 0x75, 0x77, 0x82, 0xFA, 0xB5, 0x15, 0xDE, + 0x86, 0x95, 0xD9, 0xEC, 0x16, 0xA4, 0x4A, 0x5D, 0x12, 0x73, + 0x48, 0x4A, 0x81, 0xC5, 0xED, 0x9F, 0x5F, 0xD5, 0x90, 0x97, + 0xA7, 0x36, 0xEF, 0x40, 0xC8, 0x7C, 0xC4, 0x9D, 0xFD, 0x2C, + 0x43, 0xF7, 0xAC, 0x20, 0xAB, 0x83, 0x05, 0x21, 0x14, 0x9B, + 0xC8, 0x46, 0xA8, 0x89, 0x99, 0x6E, 0x35, 0x04, 0x74, 0x5B, + 0xCE, 0x2E, 0x05, 0x66, 0x5B, 0xC3, 0x23, 0xBD, 0x50, 0x63, + 0x4C, 0xBC, 0xBE, 0x08, 0xF4, 0x3F, 0x2B, 0x94, 0x51, 0x55, + 0xBA, 0x4E, 0x12, 0xE7, 0x48, 0xE2, 0x99, 0x7C, 0xDD, 0x06, + 0xA5, 0xD7, 0x83, 0xD0, 0xE0, 0x5E, 0xCF, 0x8A, 0x21, 0x60, + 0xC5, 0xF9, 0xD1, 0x0E, 0xE5, 0x4F, 0xBF, 0xC1, 0x61, 0x00, + 0x3D, 0x03, 0x4C, 0x43, 0x38, 0x9F, 0x66, 0x31, 0xA8, 0xD0, + 0x84, 0xBC, 0xF1, 0xEC, 0xAF, 0xF2, 0x06, 0x7D, 0xE9, 0xDF, + 0xFB, 0xC1, 0xA1, 0x15, 0x2A, 0x03, 0x09, 0xAD, 0xCB, 0x62, + 0xA1, 0x3F, 0xDD, 0x67, 0xF5, 0xDC, 0x70, 0x33, 0x64, 0x3E, + 0x89, 0x03, 0xC9, 0xFC, 0x0E, 0x02, 0x43, 0xE1, 0xD7, 0x01, + 0x73, 0x58, 0x06, 0x4F, 0x03, 0x3E, 0xE7, 0x87, 0x0B, 0x45, + 0x35, 0x76, 0x78, 0x37, 0x13, 0x9F, 0x81, 0x47, 0x1E, 0xD0, + 0xA4, 0x44, 0x35, 0x87, 0x4E, 0x68, 0x68, 0x64, 0x74, 0xDB, + 0x0D, 0x9B, 0xB2, 0xA0, 0xA6, 0x58, 0x77, 0x91, 0x2A, 0x1A, + 0xCD, 0x6C, 0x81, 0xB5, 0x59, 0x4F, 0xC9, 0x9E, 0x95, 0x2A, + 0x00, 0xBA, 0xC9, 0x0C, 0x59, 0xEF, 0x2D, 0x4F, 0xF5, 0x20, + 0x86, 0xF5, 0x57, 0x75, 0xE2, 0x88, 0x26, 0x5A, 0x05, 0x7C, + 0x0B, 0xCF, 0x75, 0x6E, 0x81, 0x17, 0xB3, 0xBB, 0x2C, 0xAF, + 0x4A, 0x77, 0x6C, 0xE9, 0xF6, 0x3A, 0x05, 0x38, 0x9B, 0x52, + 0xD6, 0x38, 0x59, 0x7E, 0xC3, 0x2C, 0xCD, 0x33, 0x3F, 0x3E, + 0x92, 0x0B, 0x5D, 0xC4, 0x35, 0x14, 0x5D, 0x1E, 0xDC, 0x84, + 0x5F, 0xFF, 0xBB, 0xAC, 0xFF, 0x3B, 0xCD, 0xBF, 0x78, 0xC8, + 0x7A, 0x1B, 0xA9, 0xAB, 0x15, 0x26, 0x7F, 0xDC, 0x6C, 0x4C, + 0x23, 0xC0, 0x4A, 0xFD, 0x10, 0xBE, 0xFA, 0xD6, 0x5F, 0xFE, + 0x51, 0x06, 0xB9, 0xE1, 0xA5, 0xC8, 0x31, 0x83, 0x46, 0x86, + 0xD6, 0x3F, 0x0B, 0xD9, 0x33, 0xEC, 0x5F, 0xA6, 0x3D, 0x37, + 0x03, 0x07, 0x50, 0x4C, 0xE8, 0x79, 0x02, 0xA8, 0x9C, 0x92, + 0xCE, 0x8B, 0xA5, 0x0F, 0x0B, 0xFB, 0x6D, 0xD2, 0xD2, 0x12, + 0xC8, 0xB3, 0x51, 0xF3, 0x1C, 0x27, 0x69, 0x49, 0x52, 0x5F, + 0x73, 0x42, 0xFA, 0xE8, 0x64, 0xA9, 0x26, 0xBA, 0xF7, 0xEF, + 0x35, 0x83, 0x4D, 0xF3, 0xEC, 0x86, 0x2D, 0x6D, 0x63, 0x11, + 0x7B, 0x61, 0xE3, 0x02, 0x66, 0xF5, 0x0A, 0xFA, 0x18, 0x7B, + 0xA4, 0x15, 0x28, 0x89, 0x21, 0xB3, 0x02, 0xCD, 0x6A, 0x6A, + 0x98, 0xE9, 0x01, 0xE3, 0x4A, 0xEC, 0xB0, 0xA8, 0x6F, 0xE6, + 0x92, 0x2D, 0x85, 0x28, 0x3F, 0x0B, 0x72, 0xE2, 0x1D, 0x9B, + 0x23, 0x10, 0x98, 0xEB, 0xBF, 0x6D, 0x82, 0xB7, 0x3A, 0x41, + 0x81, 0xC5, 0x4A, 0xA6, 0x97, 0xD6, 0x8B, 0xEB, 0x1C, 0xFB, + 0xEC, 0xB9, 0xBC, 0xBE, 0xEA, 0xC6, 0xEB, 0x1B, 0x8B, 0xEE, + 0x4A, 0x6C, 0x49, 0x9A, 0xBB, 0x8F, 0x22, 0xD5, 0xB8, 0x57, + 0x35, 0x62, 0xAB, 0xA6, 0xA7, 0x6F, 0xB9, 0x90, 0xA7, 0xC6, + 0xAE, 0x50, 0x7B, 0xE1, 0xEC, 0xB9, 0xD1, 0xAE, 0xF8, 0xC9, + 0x74, 0x15, 0xAB, 0x56, 0x9E, 0x42, 0x86, 0xC6, 0x26, 0xFF, + 0xD4, 0x2E, 0x61, 0x24, 0x07, 0x0B, 0xB0, 0xF8, 0xB3, 0xBB, + 0x9F, 0xCD, 0x50, 0xEF, 0x27, 0x6B, 0xE1, 0x88, 0x9D, 0x86, + 0x96, 0x1E, 0x0B, 0x70, 0xF5, 0x0F, 0xB6, 0xC5, 0xB4, 0xD3, + 0x6C, 0x11, 0xBB, 0xB5, 0xC8, 0x55, 0xBF, 0xA5, 0x48, 0xA6, + 0xA3, 0x3B, 0xF1, 0x46, 0xE0, 0x66, 0x47, 0x86, 0x68, 0x42, + 0x6D, 0xF8, 0x14, 0x4C, 0x95, 0xCA, 0xFE, 0x6E, 0x97, 0xCC, + 0xCC, 0xBF, 0x15, 0x24, 0x1B, 0x6B, 0x58, 0x8F, 0x32, 0xB0, + 0x74, 0x5D, 0xB5, 0x1F, 0xEA, 0xF4, 0x43, 0x9B, 0xCF, 0xCD, + 0xBB, 0x6C, 0x10, 0xFF, 0x87, 0xBF, 0xA6, 0x7D, 0xA1, 0x20, + 0xB0, 0x31, 0xCD, 0xB3, 0xE5, 0xB7, 0x13, 0x91, 0xD9, 0xCD, + 0x59, 0xA0, 0x4C, 0xDE, 0x30, 0x22, 0x8A, 0xE5, 0xCC, 0xE1, + 0x56, 0x72, 0x10, 0x22, 0x98, 0xA1, 0x33, 0x35, 0x63, 0x2D, + 0x47, 0xC5, 0x51, 0xF8, 0x89, 0x54, 0x0B, 0x73, 0x03, 0xD2, + 0x6E, 0x08, 0x10, 0xC0, 0xC1, 0x05, 0x25, 0x40, 0x5C, 0x0D, + 0xC5, 0x74, 0x9E, 0x1A, 0x69, 0x5A, 0x09, 0x90, 0xD8, 0xC9, + 0xFB, 0x7F, 0xF8, 0x4F, 0x6C, 0x8E, 0x05, 0x22, 0x6E, 0xFB, + 0x99, 0x84, 0x8F, 0x65, 0x1E, 0x82, 0xE9, 0x7D, 0xCA, 0x1C, + 0x23, 0x62, 0xBE, 0xC4, 0x85, 0x1B, 0x4B, 0x2E, 0x95, 0x81, + 0x28, 0x54, 0x66, 0xD7, 0x93, 0xC6, 0x54, 0xF2, 0xBB, 0xDE, + 0x4B, 0x98, 0x4C, 0x1E, 0xEC, 0xF2, 0xBA, 0x95, 0x7B, 0x6E, + 0x67, 0x94, 0xB5, 0xD2, 0x6E, 0x87, 0x72, 0x24, 0x6C, 0xBE, + 0xB6, 0x35, 0x2E, 0x7F, 0x92, 0xB3, 0xC6, 0x4E, 0xE9, 0xBE, + 0xEF, 0x9A, 0x7A, 0x42, 0x36, 0x54, 0x4F, 0x38, 0xE3, 0x44, + 0x6C, 0x00, 0xD8, 0x82, 0xF5, 0xD1, 0x4A, 0xE6, 0x55, 0x22, + 0xB6, 0x75, 0xEE, 0x6F, 0x85, 0x1E, 0x6C, 0x95, 0x04, 0xCE, + 0x39, 0x66, 0xF5, 0xD8, 0x3D, 0xE1, 0x0D, 0x17, 0x88, 0x43, + 0xD7, 0xFF, 0x2B, 0x4F, 0xD2, 0x7F, 0xC8, 0xE7, 0x7A, 0x2D, + 0xD0, 0xAC, 0xD2, 0xB7, 0x58, 0x1D, 0xF8, 0x7E, 0x5C, 0x25, + 0xAD, 0x8E, 0x65, 0x60, 0x35, 0x34, 0xA2, 0x28, 0xDA, 0x7B, + 0x2D, 0x4D, 0xE1, 0x02, 0x25, 0x4F, 0xB7, 0xF6, 0xA4, 0xEB, + 0xB6, 0xA8, 0x88, 0x7E, 0x33, 0x58, 0x5E, 0x97, 0x94, 0x41, + 0xAB, 0x8F, 0x61, 0xD9, 0xE1, 0x24, 0x34, 0xE4, 0x35, 0xB4, + 0x82, 0x0E, 0xBE, 0xD5, 0xB8, 0xF6, 0xFD, 0xB4, 0xD1, 0xD7, + 0xCD, 0x16, 0xF8, 0x73, 0xD3, 0xF8, 0x0D, 0xB1, 0x71, 0x95, + 0x60, 0x69, 0x85, 0xAA, 0xC2, 0x67, 0x07, 0x65, 0x9F, 0x78, + 0x57, 0xED, 0x81, 0xAB, 0xFC, 0x1B, 0x57, 0xD7, 0xF8, 0x43, + 0xAF, 0xDD, 0xD6, 0x5A, 0x79, 0x91, 0x77, 0xE7, 0x2F, 0x06, + 0x7E, 0x7F, 0x81, 0x42, 0x94, 0xCD, 0xD2, 0xD3, 0xAF, 0xC4, + 0x9B, 0x1B, 0x30, 0x4C, 0xEF, 0x7A, 0x1C, 0xBC, 0x13, 0x60, + 0x86, 0x52, 0x58, 0x08, 0x6D, 0xD0, 0x66, 0xC0, 0x0E, 0xC8, + 0x16, 0x61, 0xB8, 0x8F, 0xD9, 0x1E, 0xFE, 0xBB, 0x94, 0xCC, + 0x21, 0x5B, 0x49, 0x5B, 0x6E, 0x7F, 0x36, 0x8C, 0x29, 0xDA, + 0x03, 0x2E, 0xC0, 0xDE, 0xA5, 0x73, 0x3B, 0xED, 0x99, 0x0F, + 0xE0, 0xEE, 0x48, 0xBC, 0x1F, 0x8D, 0x04, 0x94, 0xED, 0xCB, + 0x41, 0x05, 0x60, 0x50, 0x68, 0xD7, 0xAB, 0xF2, 0x2C, 0x02, + 0x14, 0x83, 0xDB, 0xF9, 0xF1, 0x28, 0xF4, 0x2E, 0x48, 0x84, + 0x39, 0x5E, 0xD7, 0x59, 0x94, 0x7A, 0x03, 0xFD, 0xD3, 0xDE, + 0x39, 0xDF, 0xE0, 0xD2, 0x8D, 0xF3, 0xCC, 0xC5, 0xD6, 0x69, + 0xF2, 0x5C, 0x52, 0x0E, 0x80, 0x18, 0x3C, 0x57, 0xED, 0x3E, + 0xB0, 0x46, 0xC8, 0xF0, 0x42, 0x83, 0x80, 0x6C, 0x29, 0x00, + 0xF1, 0x15, 0xD6, 0x17, 0xFB, 0xF7, 0xC2, 0x3B, 0x5A, 0xAC, + 0x4E, 0xDE, 0x50, 0x25, 0x89, 0x1F, 0x91, 0xEF, 0x80, 0xB0, + 0x33, 0x5F, 0x9E, 0x79, 0xD2, 0xF0, 0x75, 0xB7, 0xBC, 0xDC, + 0x17, 0xBD, 0x05, 0x9B, 0x95, 0x81, 0xC4, 0xAD, 0x2E, 0xE2, + 0x84, 0x2B, 0x98, 0x81, 0x48, 0x58, 0x37, 0xD8, 0xB3, 0x07, + 0xD5, 0xF1, 0xA8, 0x7C, 0x16, 0x03, 0xB4, 0x04, 0x57, 0xE5, + 0xBA, 0x1F, 0xC1, 0xA2, 0x29, 0x76, 0xD9, 0x39, 0x18, 0x4A, + 0x30, 0x13, 0x44, 0xFE, 0x74, 0x93, 0x7D, 0xA7, 0x2C, 0xC5, + 0x2E, 0xCD, 0xEE, 0x4F, 0x1B, 0x2D, 0x2B, 0x88, 0xEA, 0xBD, + 0xE5, 0xDB, 0x74, 0x35, 0x87, 0x61, 0x55, 0xA1, 0xAB, 0xC7, + 0x37, 0xDC, 0xE8, 0x93, 0x3A, 0x69, 0xB0, 0xC6, 0x42, 0x9B, + 0x6B, 0xEC, 0xD1, 0xDA, 0xCC, 0x40, 0x64, 0xC5, 0xCB, 0x16, + 0x7E, 0x41, 0x67, 0xFF, 0x75, 0x3A, 0x8E, 0xF9, 0xA8, 0xBC, + 0xF8, 0x39, 0x32, 0x93, 0xA0, 0xC3, 0x7C, 0x8F, 0x1B, 0xF7, + 0xA9, 0x7F, 0x3A, 0x84, 0xF9, 0xCD, 0xFC, 0x66, 0x60, 0x9B, + 0x4D, 0xD6, 0xC5, 0x9F, 0x64, 0xFB, 0x45, 0xE7, 0xFB, 0xCF, + 0x33, 0x23, 0x66, 0xD8, 0x16, 0x1B, 0xB1, 0x1B, 0xD6, 0xFB, + 0xD1, 0xE1, 0x7A, 0x24, 0x7D, 0xCD, 0x3E, 0x80, 0x9A, 0xBD, + 0x4A, 0x95, 0x84, 0xFD, 0x1C, 0x99, 0x35, 0x44, 0x9E, 0x58, + 0x06, 0x6F, 0xCF, 0x21, 0x57, 0xD3, 0xDD, 0x8B, 0x9A, 0x25, + 0x7F, 0x53, 0xCD, 0x9D, 0x20, 0xD8, 0x80, 0x86, 0xE9, 0x62, + 0x13, 0x48, 0x80, 0xB1, 0x04, 0x6F, 0x6C, 0x60, 0x66, 0x2A, + 0xD2, 0x05, 0x3E, 0x16, 0x75, 0xBF, 0xCD, 0xB6, 0xF2, 0x45, + 0x6B, 0xEE, 0xE9, 0x91, 0x2C, 0x89, 0x82, 0x7A, 0x8D, 0x50, + 0x84, 0x90, 0x8A, 0x82, 0x91, 0x51, 0xD4, 0xFA, 0x7C, 0x02, + 0x08, 0xFE, 0x51, 0x09, 0x0B, 0xF9, 0x89, 0x60, 0x53, 0xF0, + 0xF2, 0x8A, 0x25, 0xF9, 0x0B, 0xF4, 0x16, 0x64, 0x37, 0x6C, + 0xC8, 0x48, 0x87, 0x56, 0x74, 0x79, 0xB4, 0x0B, 0x8C, 0x20, + 0x97, 0xF9, 0xBA, 0xDB, 0x57, 0x8D, 0xDE, 0x13, 0x22, 0xBA, + 0x98, 0x14, 0x42, 0x54, 0xEE, 0xA7, 0xD1, 0x55, 0xBB, 0xC2, + 0x9D, 0xF6, 0x11, 0x65, 0xE2, 0xA1, 0x0F, 0xE7, 0x4F, 0xFE, + 0xF1, 0xD1, 0x80, 0xCA, 0x36, 0xA0, 0x0F, 0xB0, 0xD0, 0x4F, + 0xF5, 0xE7, 0x55, 0xD1, 0xE2, 0x0C, 0x03, 0x1F, 0x29, 0x58, + 0x0D, 0x88, 0x12, 0x64, 0x81, 0x7C, 0x57, 0x12, 0x5B, 0x66, + 0x38, 0x46, 0x4D, 0x40, 0x41, 0xED, 0x68, 0xBB, 0x17, 0xDD, + 0x8D, 0x20, 0x71, 0x6F, 0xBD, 0x15, 0x43, 0x46, 0xAE, 0x61, + 0x7B, 0x1C, 0xFB, 0x56, 0x05, 0xD6, 0x4A, 0xD6, 0x80, 0xA2, + 0x0B, 0x38, 0x4D, 0xFE, 0xF5, 0x60, 0x83, 0x9D, 0x21, 0xE2, + 0xC2, 0xBA, 0x2B, 0x7B, 0x6C, 0x7B, 0xB8, 0x7A, 0xC0, 0x7E, + 0x5D, 0x2E, 0x74, 0x5C, 0x4B, 0x7E, 0xC9, 0x71, 0xDF, 0x2F, + 0xAA, 0x05, 0xE7, 0x67, 0x7E, 0x9C, 0x8C, 0x45, 0x9D, 0xEE, + 0xD0, 0x8A, 0x66, 0x78, 0x64, 0xED, 0x06, 0x5F, 0xEC, 0x48, + 0xA8, 0x97, 0xBA, 0xCD, 0x10, 0x7E, 0x8A, 0x3D, 0x6D, 0x62, + 0x73, 0x71, 0x02, 0x8B, 0x63, 0xFF, 0xAA, 0xC5, 0x52, 0x4F, + 0xC6, 0x74, 0x87, 0x35, 0xF1, 0x1B, 0x67, 0xA4, 0xFB, 0x1C, + 0x57, 0xFD, 0xA6, 0xB9, 0x56, 0x6D, 0xE1, 0xFB, 0x72, 0x32, + 0x57, 0x95, 0x99, 0x22, 0xB1, 0x2B, 0x93, 0x58, 0x60, 0xA9, + 0x40, 0xDE, 0x80, 0x68, 0xA7, 0xCF, 0x34, 0xB6, 0x2C, 0x01, + 0x4F, 0x5E, 0x7D, 0x49, 0xA3, 0x8E, 0x24, 0xCB, 0xE8, 0x56, + 0x52, 0x51, 0x83, 0xAD, 0x58, 0x0B, 0xC5, 0x46, 0x96, 0x9E, + 0x2D, 0xEC, 0xCB, 0xD1, 0x8B, 0xB5, 0x3F, 0x98, 0x35, 0x4D, + 0x92, 0x31, 0xC1, 0x1D, 0x74, 0x9E, 0x8F, 0xAF, 0xDD, 0x4B, + 0xC4, 0x5B, 0x7B, 0xF6, 0xAC, 0x56, 0x90, 0xA3, 0xA2, 0x24, + 0x15, 0x8D, 0x98, 0x14, 0x44, 0x07, 0x2A, 0x6D, 0xCA, 0x59, + 0x94, 0x18, 0xD4, 0x4F, 0x83, 0xBB, 0xC9, 0x47, 0x36, 0xE7, + 0xC2, 0xF7, 0x67, 0xF1, 0xE4, 0x92, 0x89, 0xB4, 0xDA, 0x73, + 0xA4, 0x05, 0xBB, 0xBC, 0xF6, 0x8E, 0x07, 0x91, 0x6E, 0xDC, + 0xBC, 0x44, 0x10, 0xE5, 0x03, 0x18, 0x0E, 0xE6, 0xC7, 0x61, + 0x10, 0xA1, 0xDA, 0x8E, 0xB8, 0x02, 0x07, 0x95, 0x39, 0x0C, + 0xA0, 0x4E, 0xDC, 0xBF, 0xAB, 0x73, 0xFE, 0xEE, 0x06, 0x24, + 0x83, 0x5B, 0x3F, 0x0D, 0x47, 0x3C, 0xC2, 0xE7, 0x89, 0x26, + 0x3B, 0x70, 0x76, 0x8F, 0x7D, 0xA3, 0x33, 0x5C, 0x22, 0x3B, + 0x11, 0x60, 0xDB, 0xB3, 0x2E, 0xAA, 0xA5, 0x44, 0x0F, 0x59, + 0xF0, 0x49, 0xB4, 0xB9, 0xB8, 0xD1, 0x1F, 0x18, 0xC0, 0x15, + 0xF1, 0xF8, 0x21, 0x73, 0xA0, 0xC4, 0xD9, 0x30, 0x9B, 0x72, + 0x54, 0x04, 0x28, 0x4B, 0x1F, 0xE1, 0xC6, 0x6C, 0x7F, 0xC2, + 0x11, 0x5A, 0x36, 0x48, 0xC5, 0xB7, 0xEF, 0x2C, 0x11, 0x18, + 0x4A, 0xC2, 0x87, 0xF9, 0x88, 0x2E, 0xD4, 0x91, 0xE5, 0xF3, + 0xCC, 0xDB, 0x31, 0x41, 0xC6, 0x3B, 0x8F, 0xDC, 0xB9, 0xBA, + 0xA9, 0xF3, 0x87, 0x89, 0x76, 0xC6, 0x5B, 0xD1, 0x42, 0x99, + 0x85, 0x57, 0x9B, 0x99, 0x55, 0x4F, 0x60, 0x71, 0xD8, 0xB4, + 0x11, 0xBE, 0xA4, 0x31, 0x43, 0x17, 0x47, 0x42, 0x4B, 0x25, + 0x9B, 0x32, 0x3B, 0x48, 0x02, 0x67, 0x86, 0x8D, 0xF1, 0x5F, + 0x0D, 0xDD, 0xE9, 0x5B, 0x96, 0x82, 0x83, 0x3C, 0xF5, 0x00, + 0xF2, 0xEB, 0x1B, 0x0B, 0xA3, 0xBA, 0xF9, 0x9A, 0x1E, 0x7F, + 0x09, 0x53, 0x87, 0x3F, 0xB9, 0x59, 0x41, 0xDA, 0xD6, 0x1A, + 0x71, 0x25, 0x9D, 0xF9, 0x22, 0x17, 0x74, 0x10, 0x82, 0xAE, + 0x14, 0x68, 0xF5, 0x45, 0xD9, 0x3C, 0x37, 0x9A, 0x84, 0x94, + 0x3B, 0xA3, 0x34, 0x58, 0x1D, 0x77, 0x11, 0x5B, 0x68, 0xDA, + 0x10, 0x9E, 0x17, 0x58, 0xDD, 0x8F, 0xCF, 0xF2, 0x2E, 0xEA, + 0x23, 0x15, 0x24, 0xEF, 0xA1, 0xFA, 0x0C, 0xD6, 0x09, 0xC2, + 0x31, 0x5A, 0xA7, 0x88, 0xD5, 0x7C, 0x09, 0x97, 0x82, 0xDD, + 0x12, 0x25, 0x6C, 0x5C, 0xDD, 0xCA, 0xAE, 0xF1, 0xDD, 0x6D, + 0x04, 0xC4, 0xB6, 0x3B, 0x3C, 0x25, 0x50, 0xCA, 0xC6, 0x64, + 0x43, 0xAF, 0xDB, 0x99, 0x1B, 0xD7, 0xD1, 0x05, 0x06, 0xE8, + 0x80, 0x12, 0x92, 0x85, 0x90, 0x22, 0xC8, 0xED, 0x29, 0x96, + 0x1A, 0xCE, 0xD8, 0x36, 0xA0, 0xC8, 0xCE, 0xDE, 0x2D, 0x54, + 0x85, 0xFD, 0x7F, 0xA2, 0x0A, 0x1A, 0x48, 0x07, 0xC0, 0x99, + 0x56, 0x67, 0x5A, 0xDA, 0xD2, 0x30, 0x8C, 0x60, 0xB9, 0x77, + 0xB6, 0x8A, 0xEC, 0xD9, 0x6D, 0xAA, 0x63, 0x35, 0x5B, 0x7F, + 0x4D, 0x45, 0x4C, 0xFE, 0x8B, 0x0E, 0x87, 0xAF, 0xF0, 0xA5, + 0xB5, 0xC5, 0x83, 0xF9, 0x7E, 0x52, 0xBF, 0x15, 0x72, 0x3A, + 0x56, 0x56, 0xDE, 0x2F, 0xED, 0xE0, 0xBD, 0x8A, 0xF1, 0xC7, + 0x77, 0x60, 0x70, 0x6B, 0xBB, 0x75, 0xAB, 0x4D, 0x98, 0x4B, + 0x74, 0x4A, 0xAD, 0x87, 0x81, 0x4B, 0x5C, 0x76, 0xCE, 0x0D, + 0x43, 0x3B, 0x62, 0xBC, 0xCE, 0x29, 0xEC, 0x84, 0xC5, 0x0D, + 0x95, 0x47, 0x34, 0xC4, 0x66, 0x1D, 0x17, 0x7A, 0xF6, 0x79, + 0x80, 0x3F, 0x11, 0x16, 0x07, 0x26, 0xA2, 0xCC, 0xBA, 0xD6, + 0x16, 0xA7, 0xA3, 0x0E, 0x16, 0xE7, 0xB5, 0x5C, 0x85, 0x98, + 0x53, 0x62, 0x8F, 0xBE, 0xF0, 0x62, 0x96, 0xB4, 0xF2, 0x88, + 0xBB, 0x2A, 0x13, 0xFE, 0xD1, 0xFB, 0x28, 0x5D, 0xF5, 0x6E, + 0xC9, 0xD9, 0xDE, 0x50, 0xC0, 0x2D, 0xB7, 0x86, 0x4F, 0xBA, + 0xDA, 0x02, 0x73, 0xFD, 0xDB, 0x1F, 0x04, 0xA2, 0x93, 0x7B, + 0xBB, 0xD5, 0x86, 0x05, 0xFF, 0xB0, 0xBA, 0xC6, 0x6B, 0xBA, + 0xB8, 0xBA, 0x9F, 0x32, 0xC9, 0x56, 0x8F, 0x87, 0x04, 0x4F, + 0xBC, 0x92, 0x95, 0x1F, 0x9B, 0x29, 0x98, 0x1B, 0x1A, 0x11, + 0xE1, 0x55, 0x14, 0x2A, 0x15, 0x87, 0x3E, 0xA7, 0xF3, 0xA0, + 0x50, 0xC2, 0x22, 0x05, 0xF2, 0x87, 0x0C, 0x8C, 0xC3, 0xAC, + 0x82, 0x2E, 0x8E, 0x73, 0xA8, 0x4C, 0x27, 0x0C, 0xED, 0xEC, + 0xE1, 0xFA, 0x18, 0x89, 0x44, 0xF1, 0x63, 0xEA, 0x53, 0xF8, + 0xBD, 0x96, 0x07, 0x9D, 0x85, 0x6A, 0xCB, 0x46, 0x2E, 0x97, + 0x92, 0x00, 0x06, 0xC3, 0x56, 0xA4, 0x3A, 0x04, 0x65, 0x12, + 0x51, 0x49, 0xB2, 0x53, 0x3E, 0x06, 0xC4, 0xB7, 0x39, 0x62, + 0x60, 0xF4, 0xEF, 0x27, 0x97, 0xA8, 0xCA, 0x9A, 0x81, 0x7C, + 0xEC, 0x99, 0xFA, 0xE2, 0xA2, 0xC3, 0x9D, 0x34, 0x46, 0xBA, + 0xD3, 0x80, 0x45, 0xAB, 0x28, 0x68, 0x5D, 0x50, 0xBA, 0x02, + 0x5F, 0x69, 0x21, 0x57, 0xA0, 0x2E, 0x3A, 0xB3, 0x0A, 0x6E, + 0x76, 0xC5, 0x39, 0x7F, 0x99, 0x9B, 0x0B, 0xB5, 0x2D, 0xC2, + 0xCF, 0xBB, 0xEC, 0x27, 0x88, 0x9A, 0x5B, 0x0A, 0xD4, 0xF3, + 0xCE, 0xD1, 0xC1, 0x0F, 0xE4, 0x29, 0x3A, 0xDF, 0x30, 0x1C, + 0x09, 0xF9, 0x49, 0x8D, 0xC1, 0x42, 0x65, 0xC8, 0x7E, 0x7F, + 0x85, 0xF2, 0x4D, 0x1E, 0xA8, 0x39, 0x96, 0xC4, 0x15, 0xBA, + 0x5E, 0xD3, 0xB6, 0xB9, 0xF0, 0x37, 0x57, 0xFC, 0x6E, 0xF7, + 0x68, 0xE9, 0x40, 0x19, 0x5A, 0x7A, 0x33, 0x72, 0x1A, 0xB0, + 0x10, 0xD4, 0x0F, 0x9C, 0xAF, 0x2D, 0x21, 0xD0, 0xAC, 0x77, + 0x70, 0x48, 0x54, 0x4F, 0x30, 0xF1, 0x0C, 0x7D, 0xA0, 0x47, + 0xFE, 0xBA, 0x4D, 0xCB, 0x43, 0xDB, 0x7B, 0x62, 0x40, 0xD2, + 0xE9, 0x8A, 0x81, 0x11, 0x93, 0xA0, 0x39, 0x41, 0x71, 0x29, + 0x50, 0xEF, 0x7A, 0x1E, 0x6B, 0xBF, 0x3D, 0xCF, 0xA0, 0xBC, + 0xDA, 0xAC, 0xBD, 0xB7, 0x32, 0x30, 0x86, 0x53, 0x5F, 0x1D, + 0xE2, 0xF4, 0xC8, 0xFE, 0xE0, 0x82, 0x51, 0xB8, 0x52, 0x99, + 0x54, 0xE2, 0xC7, 0x0B, 0xD2, 0x72, 0x34, 0x34, 0x4D, 0x7A, + 0x45, 0xCE, 0x9F, 0x34, 0x02, 0x24, 0x91, 0x3A, 0x1A, 0x63, + 0xD4, 0x33, 0xAA, 0xD5, 0xDE, 0x50, 0x48, 0x9E, 0xA4, 0x9B, + 0x62, 0x5C, 0xA8, 0x81, 0xAB, 0xCF, 0x76, 0x7C, 0xCF, 0x8E, + 0x56, 0x4B, 0xBD, 0xBB, 0xE8, 0xDA, 0x85, 0x72, 0xFA, 0x6F, + 0xEE, 0x66, 0xA5, 0x9E, 0x32, 0x10, 0x67, 0xF6, 0xF9, 0x4A, + 0xBD, 0x02, 0xC6, 0x3C, 0x81, 0xB6, 0x71, 0x57, 0xF5, 0x69, + 0xFB, 0xB7, 0xD7, 0x22, 0x0E, 0xAE, 0xCA, 0x2E, 0x8C, 0xDB, + 0x4E, 0xBE, 0xD7, 0x23, 0x16, 0x16, 0x85, 0x5C, 0x25, 0xDA, + 0x60, 0x94, 0x5F, 0x6A, 0xE6, 0x72, 0x6C, 0xFF, 0xB9, 0x4A, + 0xE1, 0xCD, 0xEA, 0x58, 0xA1, 0x57, 0x4D, 0x06, 0xBB, 0xFB, + 0x63, 0xE3, 0xC4, 0x38, 0x61, 0x24, 0xDC, 0x90, 0xBE, 0x15, + 0x16, 0x27, 0x51, 0x0C, 0x28, 0xBC, 0xF5, 0x5E, 0x41, 0xF9, + 0x03, 0xC2, 0x77, 0x8E, 0x67, 0x60, 0xDE, 0x7D, 0x0B, 0x89, + 0x30, 0x88, 0xF4, 0x33, 0xBE, 0x8B, 0xDA, 0x22, 0x6C, 0xAA, + 0xE6, 0x69, 0xA2, 0xEC, 0x63, 0x48, 0x2F, 0xE2, 0xD6, 0xE4, + 0x61, 0x4B, 0xE1, 0x60, 0x89, 0x77, 0xA4, 0xB0, 0x34, 0xD1, + 0x62, 0xE4, 0x06, 0xC8, 0xD1, 0x16, 0x3C, 0x6D, 0x6B, 0xDF, + 0x76, 0xCE, 0x87, 0xEF, 0xB0, 0x7E, 0x66, 0xB5, 0x42, 0xAF, + 0x86, 0x0A, 0xF3, 0x64, 0x2F, 0xC6, 0x7C, 0x44, 0x58, 0xF0, + 0xF4, 0xF1, 0x24, 0x5B, 0xDC, 0x53, 0xE5, 0xEC, 0x85, 0xB6, + 0xF9, 0xBF, 0x03, 0x8F, 0x7D, 0xC2, 0x38, 0x2A, 0xB5, 0x9A, + 0x00, 0xB9, 0xC9, 0x20, 0xB8, 0x5D, 0x4D, 0xC5, 0x0D, 0xE2, + 0x8F, 0x35, 0x22, 0xF0, 0x78, 0xC1, 0x1B, 0xC0, 0x90, 0x31, + 0x5F, 0x88, 0xF0, 0x97, 0xE3, 0x76, 0x74, 0xC3, 0x43, 0x52, + 0x89, 0x9D, 0x00, 0x53, 0x9D, 0xAF, 0x11, 0xE5, 0xA6, 0x2C, + 0x89, 0x5D, 0x9B, 0x42, 0xA5, 0xD8, 0x4E, 0x40, 0x79, 0xF1, + 0x00, 0x8A, 0x9E, 0x83, 0x80, 0x79, 0xE9, 0x43, 0x8F, 0xF5, + 0xA0, 0xC7, 0xC6, 0x4D, 0xF9, 0x62, 0x6F, 0xF3, 0x6B, 0x3D, + 0xAE, 0xF0, 0x2B, 0xB7, 0xDA, 0x36, 0x4D, 0x12, 0x4F, 0xC9, + 0x39, 0xD4, 0x7F, 0x6D, 0x60, 0x18, 0xC2, 0x3A, 0x61, 0x97, + 0xB3, 0x03, 0x07, 0xEA, 0xF0, 0x71, 0x72, 0x07, 0xEC, 0xBC, + 0x0F, 0xC4, 0x5A, 0xBE, 0x02, 0x90, 0xD2, 0x89, 0x29, 0x2F, + 0xA6, 0xD8, 0xE6, 0x13, 0x7D, 0x2B, 0xA2, 0x86, 0xE5, 0x3E, + 0x9A, 0x57, 0xCC, 0x99, 0x50, 0x38, 0x86, 0xC1, 0x40, 0xFB, + 0x96, 0x1A, 0xF3, 0x70, 0x1D, 0x2F, 0x36, 0xAC, 0xEB, 0x80, + 0x39, 0x64, 0x64, 0xCD, 0xED, 0xFA, 0x37, 0x00, 0x56, 0x5E, + 0xB5, 0x0B, 0xE9, 0x3F, 0x65, 0xDD, 0x7B, 0x8C, 0xF8, 0xAE, + 0xEA, 0xA2, 0xDE, 0xCC, 0x88, 0xAD, 0xEF, 0x63, 0x75, 0xED, + 0x2B, 0xD0, 0x50, 0x00, 0xD0, 0x32, 0x5F, 0x52, 0xB4, 0xD4, + 0x22, 0x79, 0x9A, 0xEA, 0xC3, 0x7E, 0x13, 0x54, 0xA1, 0x5B, + 0xE0, 0xB2, 0xF3, 0xAC, 0xF1, 0xD9, 0xC9, 0x3C, 0xB7, 0xDA, + 0xF6, 0x37, 0x3C, 0xB6, 0x72, 0x44, 0x91, 0xE9, 0x38, 0x41, + 0x66, 0x10, 0xB6, 0xCF, 0x7E, 0x0A, 0x86, 0x10, 0x71, 0x07, + 0x26, 0xB0, 0x7B, 0x2D, 0xC7, 0x35, 0x74, 0x54, 0xFE, 0xD6, + 0xF8, 0x03, 0xB6, 0x70, 0x22, 0x1E, 0xF5, 0x7E, 0x26, 0x28, + 0xD7, 0x00, 0xA2, 0x21, 0x57, 0xCB, 0xC2, 0x90, 0x35, 0x90, + 0xF5, 0x7F, 0x8A, 0xF1, 0x45, 0x97, 0x38, 0x2E, 0x88, 0xE7, + 0x00, 0x5E, 0x57, 0x38, 0x3F, 0x34, 0x65, 0x9F, 0x55, 0xAD, + 0xE8, 0x89, 0xA3, 0xBE, 0x69, 0xF4, 0x52, 0x4E, 0x52, 0xE4, + 0x22, 0x80, 0x30, 0x06, 0xD0, 0x59, 0x75, 0xDC, 0x24, 0xAD, + 0x85, 0xF1, 0x67, 0x5E, 0xF4, 0x61, 0xD4, 0x65, 0xF5, 0x7E, + 0xB9, 0xD3, 0x93, 0x6A, 0x1E, 0xBE, 0x55, 0x09, 0x24, 0xE4, + 0x9E, 0xC7, 0x23, 0xF8, 0xFA, 0xAC, 0xE0, 0x81, 0xC4, 0xD6, + 0x27, 0xBD, 0x67, 0xA2, 0x07, 0x69, 0x9E, 0x9B, 0x5D, 0xE8, + 0x24, 0x4D, 0xCF, 0xC0, 0xEA, 0x97, 0x11, 0x7F, 0xA3, 0x1E, + 0x80, 0x12, 0x5A, 0x18, 0xE1, 0xB0, 0x1F, 0x8B, 0x92, 0xE6, + 0xBC, 0x5B, 0x53, 0x83, 0x7F, 0x32, 0x09, 0xE6, 0x2D, 0x85, + 0xB3, 0x91, 0x0C, 0xEA, 0xA6, 0x8E, 0x5D, 0xE7, 0xDC, 0xB8, + 0xEA, 0xC2, 0x02, 0x90, 0x13, 0x86, 0x1E, 0x52, 0x35, 0xD7, + 0x3E, 0xA1, 0x5C, 0x27, 0x77, 0x82, 0xEF, 0x39, 0xD1, 0x73, + 0xD1, 0xD9, 0x5B, 0x5A, 0x56, 0x1A, 0x92, 0x02, 0xE2, 0xDD, + 0xFF, 0xC1, 0xDB, 0xBE, 0x3D, 0x05, 0x86, 0xF4, 0xC1, 0xF8, + 0x70, 0xFB, 0x51, 0x45, 0xC7, 0x2F, 0xE0, 0xBA, 0xDB, 0xE6, + 0x5F, 0x0F, 0x1E, 0x07, 0x1F, 0xF4, 0x78, 0xBD, 0x0B, 0xFF, + 0x16, 0x3D, 0x84, 0xE2, 0xDC, 0x6A, 0xE9, 0xAB, 0x32, 0x4B, + 0xF8, 0x3E, 0x08, 0x16, 0xE1, 0x46, 0x54, 0xB9, 0x42, 0x15, + 0xF4, 0x31, 0x00, 0x35, 0xAA, 0x8E, 0x45, 0xEE, 0xFE, 0x4F, + 0x2F, 0x60, 0x5F, 0xB9, 0xB1, 0x70, 0x50, 0x1C, 0x60, 0x2D, + 0xFB, 0x24, 0x8C, 0x79, 0x40, 0xE4, 0xB4, 0x08, 0xB6, 0xDF, + 0x36, 0x56, 0x31, 0xCD, 0x52, 0x5F, 0x40, 0x89, 0x9F, 0xA0, + 0xF1, 0xDA, 0xE8, 0x07, 0x76, 0x78, 0xF0, 0xE9, 0x7C, 0xBF, + 0x19, 0x6D, 0x65, 0x7F, 0x9F, 0xE0, 0x3C, 0xA8, 0x5C, 0x69, + 0xB3, 0x58, 0xE7, 0xBA, 0xE4, 0xA6, 0x33, 0x24, 0x66, 0xA2, + 0xF6, 0xCF, 0x9E, 0xD4, 0xE1, 0x95, 0xE2, 0xE4, 0x1A, 0xCF, + 0x1A, 0xF8, 0x8F, 0x52, 0xED, 0x78, 0x5D, 0xCB, 0x1F, 0xD7, + 0xED, 0xBD, 0xFD, 0x8F, 0x53, 0x33, 0x44, 0xDC, 0x4D, 0x83, + 0xFA, 0x42, 0xCB, 0x05, 0x97, 0x96, 0x27, 0x72, 0xD5, 0xA2, + 0xD8, 0x38, 0x43, 0x02, 0xAD, 0x26, 0x8A, 0xE1, 0x68, 0x35, + 0x37, 0xC6, 0x2D, 0xF2, 0x34, 0x49, 0xEB, 0x92, 0xAA, 0xF7, + 0xEB, 0xCB, 0xF7, 0x40, 0x17, 0x66, 0xEC, 0x7B, 0x32, 0xCA, + 0x05, 0xB8, 0x23, 0x73, 0xCD, 0xBF, 0xC2, 0xDD, 0x44, 0xD2, + 0x49, 0x59, 0xD5, 0x5A, 0x3B, 0x56, 0x3D, 0x89, 0x91, 0x3C, + 0xB5, 0xA9, 0x7B, 0x2D, 0x9D, 0xF2, 0xB4, 0x23, 0x50, 0xDE, + 0x2A, 0xD2, 0x7B, 0xD5, 0x54, 0x8E, 0x77, 0x6B, 0x65, 0xE8, + 0xCE, 0xAE, 0xAC, 0xDC, 0xB3, 0xD5, 0x73, 0xE2, 0xDD, 0xA6, + 0xE7, 0x4D, 0x4E, 0x3B, 0xFE, 0xD7, 0xDA, 0xB2, 0x00, 0x63, + 0xAA, 0x40, 0xDB, 0xBB, 0x86, 0x73, 0xCF, 0x59, 0x9E, 0x55, + 0xF7, 0xF1, 0x17, 0xE3, 0x94, 0xF6, 0x90, 0xA0, 0x4E, 0xA5, + 0xE9, 0xBC, 0x81, 0xC9, 0xFE, 0x3B, 0x7D, 0x21, 0xA9, 0x0B, + 0x5B, 0x72, 0xAB, 0x06, 0x33, 0x22, 0x18, 0xC5, 0x1B, 0x1A, + 0xBB, 0x3A, 0x81, 0xBE, 0x37, 0x15, 0x73, 0x79, 0xD7, 0xCB, + 0xDC, 0xDB, 0xDF, 0x2D, 0x67, 0x11, 0xC9, 0x73, 0x28, 0xEE, + 0x89, 0x6D, 0x27, 0xBD, 0x67, 0xB2, 0x5D, 0x70, 0x42, 0x68, + 0x43, 0x59, 0x75, 0x08, 0xA4, 0xAD, 0xE2, 0x4E, 0x51, 0xAF, + 0xFF, 0xE5, 0x2E, 0x8A, 0xB4, 0x04, 0x08, 0x96, 0x24, 0x6D, + 0x71, 0xB5, 0x45, 0x36, 0x6A, 0x4E, 0x83, 0xAD, 0x6F, 0xF3, + 0x4D, 0x98, 0xB9, 0x40, 0xBF, 0x8E, 0xEA, 0x61, 0x40, 0xDF, + 0x9D, 0x5F, 0xA6, 0xA5, 0x21, 0x42, 0x4C, 0xE7, 0x99, 0x09, + 0xE9, 0x35, 0xDA, 0x81, 0xE4, 0xCF, 0x4F, 0xA6, 0x55, 0x02, + 0xA0, 0xBF, 0x3C, 0xBC, 0x8D, 0x59, 0xA0, 0xF0, 0x77, 0xAF, + 0x81, 0xD2, 0x3E, 0x29, 0x08, 0xC2, 0x14, 0x6F, 0xA7, 0xA3, + 0x7D, 0xE7, 0x80, 0xA4, 0x52, 0x71, 0xBA, 0xD9, 0x9F, 0x26, + 0xBB, 0xEB, 0x0C, 0x28, 0x1B, 0x39, 0x65, 0x8D, 0xD3, 0x2F, + 0x04, 0x75, 0xCD, 0xA0, 0x39, 0x17, 0x52, 0x4A, 0xEF, 0xE3, + 0xE4, 0xA5, 0xD2, 0x31, 0x98, 0x52, 0x90, 0xB5, 0xE4, 0x16, + 0x90, 0x29, 0xA8, 0x54, 0x05, 0x10, 0x29, 0x92, 0x75, 0xAB, + 0x14, 0x59, 0xAE, 0xA1, 0x87, 0xD1, 0xC2, 0xE3, 0x58, 0xAF, + 0xA3, 0x7D, 0xFA, 0x08, 0x2C, 0xB9, 0x11, 0xE3, 0xF2, 0xA5, + 0x07, 0x1F, 0x8E, 0xE2, 0xEF, 0xB1, 0x29, 0xD4, 0x61, 0x50, + 0x08, 0xA6, 0xBC, 0x0B, 0xEB, 0x03, 0x10, 0x3D, 0x56, 0x27, + 0xB6, 0x8C, 0x79, 0xD1, 0x20, 0x3C, 0x6D, 0x7C, 0x4C, 0x7D, + 0xC1, 0x64, 0x41, 0x72, 0x3B, 0x79, 0xF9, 0x44, 0xAD, 0x67, + 0xF4, 0xF0, 0x79, 0x8A, 0x4B, 0xC9, 0x5C, 0x5A, 0xAF, 0x77, + 0x51, 0x19, 0xBE, 0x74, 0x7D, 0x4A, 0x06, 0xE6, 0xD6, 0xEE, + 0xB2, 0x79, 0x81, 0x32, 0xB9, 0x9C, 0x56, 0x17, 0xD4, 0x2F, + 0x1F, 0x33, 0xC7, 0xF9, 0x0A, 0xCF, 0x06, 0xE9, 0x22, 0xE9, + 0x97, 0x73, 0x1E, 0x16, 0xFB, 0xF6, 0x91, 0x42, 0x78, 0x50, + 0x02, 0x91, 0x6D, 0xE4, 0xA9, 0xB8, 0x0E, 0xB5, 0x3F, 0x66, + 0xE7, 0xE6, 0xAF, 0x96, 0x45, 0x06, 0x1C, 0xDE, 0x21, 0x32, + 0x1A, 0x9D, 0xE9, 0x43, 0xA1, 0xBE, 0x9E, 0x09, 0x8A, 0x8D, + 0x2D, 0xC6, 0x53, 0x65, 0xF0, 0x85, 0x77, 0xE4, 0x3E, 0xA7, + 0x7A, 0xE7, 0x89, 0xCD, 0x6C, 0x18, 0x8A, 0x82, 0x80, 0xF8, + 0x40, 0xA7, 0xB3, 0x9C, 0x61, 0x1E, 0xCE, 0xD5, 0xAF, 0x78, + 0xB9, 0xC4, 0xDB, 0xF9, 0xAC, 0xEE, 0x3D, 0x37, 0xB8, 0xA0, + 0x6B, 0x9C, 0x05, 0x54, 0x68, 0x93, 0xD9, 0xB7, 0xBC, 0x37, + 0x0B, 0x36, 0xF2, 0x3F, 0x88, 0x28, 0x32, 0xE3, 0x11, 0xA9, + 0x4A, 0xB1, 0x12, 0xC4, 0x33, 0xF6, 0xA3, 0xCB, 0xF5, 0xEB, + 0x3B, 0xF7, 0x2E, 0xC8, 0x56, 0xE2, 0xC9, 0xBB, 0x82, 0xEB, + 0x69, 0xAA, 0x81, 0x81, 0x2C, 0x89, 0xA6, 0xB8, 0x39, 0xE0, + 0x3E, 0xCE, 0x3F, 0x3A, 0x58, 0xC7, 0x35, 0x1A, 0x16, 0xE2, + 0x9A, 0x16, 0x98, 0x3D, 0xA3, 0x91, 0x60, 0x25, 0x60, 0x19, + 0xAE, 0xD6, 0x20, 0x26, 0x4E, 0x0C, 0x0F, 0x9C, 0xD4, 0xD7, + 0xC8, 0x1E, 0x51, 0xAC, 0xCE, 0x41, 0xF7, 0x8B, 0x58, 0x96, + 0xF2, 0xDA, 0x59, 0x01, 0xCF, 0x53, 0xD8, 0xB8, 0xBC, 0x04, + 0xFF, 0x99, 0x41, 0x5B, 0x77, 0x58, 0x30, 0x68, 0x7F, 0x2B, + 0x20, 0x9E, 0xBE, 0x89, 0x66, 0x3C, 0x35, 0x97, 0x2E, 0x30, + 0xE4, 0x9F, 0x3B, 0x42, 0xF7, 0x87, 0xE4, 0x3E, 0x77, 0x80, + 0x2A, 0xB4, 0x66, 0xE0, 0xD6, 0x19, 0xB3, 0x67, 0x23, 0xD6, + 0xF2, 0x64, 0x9A, 0x25, 0x10, 0x64, 0x5D, 0xC2, 0x78, 0x1D, + 0xA1, 0x40, 0x5B, 0xAF, 0x87, 0x0B, 0x96, 0xBD, 0x19, 0xA8, + 0x0B, 0x98, 0xB7, 0x1F, 0xB0, 0x15, 0x77, 0x5B, 0xD9, 0x37, + 0xE9, 0x4C, 0x88, 0x4E, 0xE8, 0x47, 0x30, 0x31, 0xF0, 0xB2, + 0x65, 0xDF, 0x78, 0xFD, 0x81, 0x08, 0xD7, 0x2D, 0x68, 0x13, + 0xFE, 0xDF, 0x9D, 0xBD, 0x1F, 0xF1, 0xAC, 0xE9, 0x9D, 0xA7, + 0x46, 0xD1, 0x44, 0x36, 0x19, 0x5F, 0x43, 0x4F, 0xEA, 0x72, + 0x46, 0x66, 0x3C, 0xE6, 0x96, 0x4A, 0x88, 0xA1, 0x2D, 0x19, + 0xFF, 0xA4, 0xF3, 0xFC, 0xD9, 0x3C, 0xC1, 0xBA, 0xC8, 0x02, + 0xA0, 0xF1, 0x55, 0xFA, 0x5E, 0xBD, 0x14, 0x08, 0x77, 0x87, + 0x03, 0x10, 0x2D, 0xBA, 0x12, 0x87, 0x0C, 0x39, 0x92, 0xE3, + 0x66, 0x98, 0xC2, 0x2E, 0x86, 0xEB, 0x27, 0xCA, 0xE8, 0xD9, + 0xB6, 0xA8, 0xA7, 0xF6, 0x4B, 0xD3, 0x09, 0x64, 0x4F, 0x4E, + 0x0F, 0xD0, 0xA7, 0x0B, 0x82, 0x4A, 0xA9, 0xBF, 0x39, 0xBA, + 0x9C, 0xE1, 0xC6, 0xAD, 0x88, 0xC6, 0x24, 0xC3, 0x5B, 0x36, + 0x57, 0x88, 0xBE, 0x0F, 0x9B, 0x41, 0x46, 0x56, 0x72, 0x8F, + 0x18, 0x3C, 0x54, 0xEE, 0x29, 0x2C, 0x67, 0x82, 0xF4, 0xA5, + 0x12, 0xBF, 0xC6, 0x1C, 0xB4, 0xBB, 0x7B, 0xAF, 0x92, 0x81, + 0x18, 0x01, 0x07, 0x3F, 0x5F, 0xE0, 0xD8, 0x74, 0xBB, 0xCF, + 0x04, 0x3D, 0xCF, 0x70, 0x5D, 0x23, 0x1E, 0x98, 0x49, 0xA6, + 0x0C, 0xCC, 0x1E, 0x82, 0x11, 0xE1, 0x58, 0xD3, 0x32, 0xA5, + 0x8A, 0x67, 0x7F, 0x23, 0x2A, 0x75, 0x6A, 0xFB, 0xFC, 0xC6, + 0x3B, 0xA0, 0xD5, 0x4B, 0xAC, 0xFB, 0x48, 0x35, 0xB7, 0xCE, + 0xE8, 0x82, 0x05, 0x8D, 0x04, 0x0F, 0x28, 0xAF, 0xB4, 0x79, + 0x44, 0x2D, 0x31, 0xE0, 0xB1, 0xC4, 0x08, 0xC3, 0x40, 0xDC, + 0xF0, 0x82, 0x4E, 0x14, 0x1F, 0xF1, 0xF0, 0x99, 0x14, 0x7C, + 0x79, 0x03, 0xAB, 0x45, 0x9D, 0x5C, 0x25, 0x88, 0xF1, 0x4B, + 0x8E, 0xE4, 0xAC, 0x8E, 0x62, 0xA3, 0x22, 0x3A, 0x57, 0x50, + 0x80, 0x3A, 0xF9, 0xC1, 0x56, 0x68, 0xC6, 0x50, 0xF6, 0xE4, + 0xB2, 0xC0, 0x2C, 0xE9, 0xA4, 0xFC, 0x6E, 0xE2, 0xE2, 0x43, + 0xF5, 0x0B, 0xC1, 0x47, 0x84, 0x0B, 0xF5, 0x4F, 0x0B, 0xC7, + 0x97, 0xF0, 0x89, 0x49, 0x7C, 0xC0, 0xCC, 0xD1, 0x39, 0x53, + 0x6F, 0x10, 0x9C, 0x43, 0xE0, 0xEA, 0x47, 0xFA, 0xB4, 0xE2, + 0x02, 0x83, 0x90, 0xBF, 0xCA, 0x26, 0xA0, 0xB3, 0x5A, 0xDC, + 0x06, 0x6A, 0x6A, 0xC3, 0xD4, 0x67, 0xC2, 0x3B, 0x8F, 0x97, + 0x7B, 0x6E, 0xEF, 0xDA, 0x5C, 0x6A, 0x15, 0x6B, 0x78, 0xCB, + 0x62, 0x22, 0xB5, 0x85, 0xBC, 0xE6, 0xA7, 0x50, 0x3E, 0x50, + 0x70, 0x4A, 0x69, 0xB8, 0x3F, 0x74, 0x46, 0x42, 0x4E, 0x59, + 0x18, 0xF6, 0xFD, 0x47, 0x81, 0x73, 0xE3, 0xB1, 0xDE, 0xF8, + 0xA9, 0x93, 0x87, 0xDF, 0x81, 0x4E, 0xAD, 0x38, 0xF8, 0xFE, + 0xA7, 0xDD, 0xB7, 0xF5, 0xFF, 0xBF, 0xE3, 0x1F, 0x30, 0xC3, + 0x58, 0x85, 0xC9, 0x94, 0xD3, 0xAA, 0x6E, 0xBE, 0x9D, 0x12, + 0x1B, 0x5B, 0x02, 0x75, 0x2F, 0xAD, 0x87, 0xE0, 0xCC, 0x18, + 0x3E, 0x67, 0x65, 0xAB, 0x25, 0x3F, 0xB2, 0x70, 0xC1, 0x08, + 0x0D, 0x51, 0x33, 0x91, 0xB1, 0x0A, 0x08, 0x34, 0x1F, 0xD0, + 0xC4, 0x2F, 0xA7, 0x19, 0x64, 0xC9, 0xA2, 0xD2, 0x8F, 0x26, + 0xF7, 0x78, 0x3D, 0x17, 0xB9, 0x8E, 0x12, 0x8A, 0x4D, 0x34, + 0xC1, 0xDA, 0xBF, 0x01, 0x7C, 0x86, 0xA0, 0xCC, 0x87, 0xC1, + 0x63, 0x23, 0x19, 0x58, 0xB2, 0xEF, 0xA4, 0xDE, 0xE3, 0xE7, + 0xF9, 0x5F, 0x40, 0x9E, 0x92, 0x9C, 0x8B, 0x41, 0x57, 0x7F, + 0xC7, 0x54, 0x47, 0x4A, 0x3A, 0x8F, 0x0F, 0x0B, 0x45, 0x3D, + 0x0A, 0xB6, 0xDC, 0x3C, 0x75, 0x40, 0x55, 0x01, 0xAE, 0x41, + 0xFD, 0x2D, 0x5C, 0x3D, 0x0B, 0xD4, 0x71, 0x00, 0x6B, 0xB5, + 0x2A, 0x62, 0xC3, 0xA3, 0xE8, 0x50, 0xB7, 0x93, 0x96, 0x3A, + 0xFF, 0x74, 0xB3, 0xBB, 0x64, 0xD9, 0x59, 0xA4, 0xFF, 0x21, + 0xDB, 0x54, 0xB3, 0xAC, 0x07, 0x6D, 0xE4, 0xD8, 0x9A, 0x95, + 0xC7, 0x12, 0xD7, 0x68, 0x49, 0x26, 0x08, 0x5A, 0x58, 0x3D, + 0xF5, 0xCE, 0xFA, 0x47, 0xF3, 0x6D, 0xEB, 0xC8, 0xFB, 0x07, + 0xF8, 0xFB, 0x89, 0xDA, 0xEB, 0x53, 0xBF, 0xDC, 0xF3, 0xFC, + 0x5D, 0xA6, 0xA5, 0xB7, 0xBE, 0xD3, 0x35, 0xAA, 0xBD, 0x27, + 0xD3, 0xF5, 0x41, 0x37, 0x90, 0xAC, 0xCD, 0xD0, 0x9F, 0x6C, + 0x4A, 0x98, 0x50, 0x96, 0xF3, 0x03, 0xFC, 0xB9, 0x83, 0x25, + 0x5B, 0xC5, 0x63, 0xF2, 0xB4, 0xB6, 0xCA, 0xA2, 0x3B, 0xAC, + 0x66, 0x32, 0x5F, 0x31, 0x3B, 0xB9, 0x74, 0x52, 0x14, 0xB8, + 0xCA, 0xB9, 0x6B, 0x2F, 0x1E, 0xAD, 0x98, 0x3B, 0x6C, 0x7B, + 0xC6, 0x92, 0xD6, 0x02, 0xDC, 0x57, 0x22, 0x5F, 0xCB, 0x81, + 0x46, 0x4D, 0xAB, 0x2D, 0xC7, 0x51, 0x49, 0xAA, 0x85, 0x2E, + 0x3B, 0x24, 0x19, 0xE5, 0x63, 0x6C, 0xC4, 0x0F, 0x83, 0x17, + 0x47, 0xD2, 0xC3, 0x74, 0xD2, 0x4C, 0x6A, 0xD5, 0xA1, 0x77, + 0xA4, 0x4A, 0xC3, 0x62, 0x31, 0xA2, 0x2D, 0xD9, 0x6C, 0xCA, + 0xFA, 0x9D, 0xEA, 0x2A, 0xEE, 0x21, 0xAE, 0x3A, 0x64, 0x1C, + 0xE3, 0xBF, 0x0C, 0xE2, 0x4A, 0xD7, 0x60, 0xAE, 0x2F, 0xA0, + 0x93, 0xFF, 0x07, 0xC9, 0x21, 0xB2, 0xDD, 0xD6, 0xD4, 0x01, + 0x20, 0xDA, 0x77, 0x9B, 0xA8, 0xD7, 0xF1, 0xFC, 0x73, 0x1F, + 0x88, 0x1F, 0xDF, 0x32, 0x05, 0xFE, 0xB2, 0x67, 0xBD, 0x0D, + 0x6F, 0x69, 0xF8, 0xD9, 0xFB, 0x4D, 0xEE, 0xC9, 0x02, 0x7A, + 0x96, 0x26, 0x57, 0x9F, 0x22, 0x08, 0x88, 0x53, 0x9F, 0xE7, + 0x58, 0x55, 0x10, 0xC7, 0x6D, 0x5E, 0xF9, 0x8D, 0x3B, 0x8D, + 0xE4, 0x10, 0xE5, 0xFD, 0xCA, 0xC9, 0x7B, 0xC8, 0x7E, 0x84, + 0x73, 0xBA, 0x30, 0x59, 0x8A, 0xB7, 0x36, 0xEB, 0x64, 0x94, + 0x3D, 0xF1, 0x40, 0xE2, 0xE4, 0x90, 0xB2, 0x9F, 0x13, 0xD9, + 0xD4, 0x4B, 0x01, 0xBC, 0xBA, 0x01, 0x1D, 0x36, 0xA3, 0xC4, + 0xF8, 0xC5, 0x89, 0xA7, 0x3A, 0xDC, 0x00, 0x04, 0x22, 0x12, + 0x26, 0x95, 0xD5, 0x6E, 0xEC, 0x6E, 0xFE, 0x92, 0x68, 0x5F, + 0x5C, 0x74, 0xFA, 0x38, 0x4C, 0x41, 0x80, 0xB5, 0x4A, 0xB5, + 0xA1, 0xB9, 0x62, 0xB5, 0xF4, 0x7C, 0x47, 0x72, 0xE6, 0x45, + 0x98, 0x4B, 0xC7, 0xB9, 0x53, 0x6E, 0xEB, 0x2F, 0x0C, 0xD7, + 0x49, 0x16, 0x45, 0xB6, 0x42, 0xE7, 0xBC, 0x40, 0xBF, 0xB1, + 0x6A, 0xBF, 0x93, 0x50, 0x69, 0xF6, 0x2B, 0x96, 0x8E, 0xD9, + 0xD7, 0xBD, 0x3D, 0xB0, 0x77, 0x06, 0x69, 0xB9, 0xDF, 0x23, + 0xE9, 0x99, 0x90, 0x25, 0x78, 0x70, 0xA2, 0xD3, 0x20, 0x7B, + 0xD6, 0xB3, 0x9A, 0x7D, 0xDB, 0x50, 0xBE, 0x16, 0x38, 0x77, + 0x1E, 0x02, 0x9C, 0x08, 0x03, 0xD4, 0x0E, 0x13, 0x84, 0x8D, + 0xCC, 0x8A, 0xAC, 0xDF, 0x87, 0xC3, 0xC6, 0x33, 0x36, 0x70, + 0x66, 0xE4, 0xC5, 0x61, 0x01, 0xFE, 0xF7, 0x3D, 0xFF, 0x5F, + 0x0E, 0x27, 0x07, 0x88, 0x93, 0x36, 0x61, 0x61, 0x43, 0x39, + 0x52, 0x6E, 0xFA, 0x90, 0x99, 0x00, 0xB8, 0xCA, 0x5C, 0xAC, + 0x76, 0xD8, 0x92, 0x20, 0x1B, 0x1F, 0x2B, 0x42, 0x1D, 0x77, + 0x29, 0x6C, 0xB4, 0x0B, 0xFA, 0x7A, 0x75, 0xEA, 0x7D, 0xE9, + 0xD5, 0xBB, 0xCD, 0xE9, 0x1F, 0xE8, 0xF6, 0xCE, 0xCA, 0x30, + 0x82, 0x5E, 0x76, 0xC7, 0x2A, 0xC8, 0xD3, 0x6E, 0xCB, 0xA7, + 0xF2, 0xD2, 0x1A, 0xEF, 0xD6, 0xE5, 0x63, 0x65, 0xED, 0x02, + 0xFE, 0x2C, 0x3A, 0xBE, 0xA6, 0xB2, 0x76, 0xD0, 0x09, 0x1C, + 0x71, 0x7B, 0x9D, 0x59, 0x9D, 0xFE, 0x5C, 0x98, 0x54, 0x90, + 0x7F, 0x3A, 0x82, 0x4F, 0x82, 0xAD, 0x78, 0x24, 0xD0, 0x37, + 0x81, 0x01, 0x28, 0xFA, 0xC0, 0x0D, 0x11, 0x41, 0xF0, 0x6A, + 0x20, 0x6A, 0xF9, 0xFD, 0x92, 0x2E, 0x42, 0x25, 0x5D, 0xD1, + 0x3F, 0x05, 0x6D, 0x45, 0x6D, 0x1E, 0xBB, 0x30, 0xA2, 0xBC, + 0xC5, 0x3D, 0xEF, 0xD4, 0x26, 0x6B, 0x01, 0x1A, 0x85, 0x21, + 0x99, 0x6F, 0x8A, 0x76, 0x70, 0x1A, 0x76, 0x53, 0x58, 0x5D, + 0x23, 0xE3, 0x9A, 0x62, 0xE2, 0x1A, 0x01, 0x86, 0x4D, 0x06, + 0x6E, 0xF9, 0x1E, 0x23, 0x01, 0x9A, 0x98, 0xBD, 0xA1, 0xA5, + 0x7F, 0x3E, 0x24, 0x5B, 0x38, 0x3B, 0xA5, 0xD1, 0x98, 0xAD, + 0x3E, 0x3D, 0x77, 0xAF, 0x41, 0xD9, 0xC6, 0xAC, 0x48, 0x20, + 0xCB, 0xC9, 0x67, 0xAC, 0x68, 0xF8, 0x91, 0x0E, 0x00, 0x53, + 0x13, 0x17, 0x9A, 0x12, 0x1F, 0x43, 0xD0, 0x5D, 0x5C, 0xA5, + 0x6A, 0xC2, 0xA7, 0xF7, 0xD5, 0xF4, 0x93, 0xA1, 0xC8, 0x47, + 0xAA, 0x33, 0xA4, 0x80, 0x06, 0xC7, 0xFE, 0xCD, 0x2B, 0xA1, + 0x40, 0x97, 0x9E, 0x5D, 0xA4, 0x2D, 0x22, 0x6D, 0x8B, 0x7A, + 0xDE, 0xA1, 0x8E, 0x3C, 0x10, 0xB1, 0xDD, 0x98, 0x15, 0xE9, + 0x3C, 0xA3, 0x79, 0xD5, 0xB8, 0xE7, 0x25, 0x5C, 0x02, 0x20, + 0x1A, 0x44, 0xEE, 0x22, 0x04, 0xC9, 0xCD, 0xEA, 0xFE, 0x1E, + 0x17, 0xD2, 0xA3, 0xBD, 0xED, 0x3E, 0x6A, 0xF4, 0xAC, 0x84, + 0xE0, 0x57, 0x74, 0x15, 0xF8, 0x05, 0x70, 0xD5, 0x19, 0x29, + 0xF6, 0x5A, 0x0D, 0xA4, 0xD6, 0x00, 0xD1, 0x48, 0xBD, 0x71, + 0xD1, 0xB1, 0x6E, 0x93, 0x34, 0xD1, 0x3C, 0x0D, 0x00, 0xA0, + 0xC4, 0x18, 0x4B, 0x0D, 0x3C, 0x16, 0x1E, 0x8D, 0x33, 0x70, + 0x6B, 0x30, 0x3B, 0x8E, 0xE5, 0x4C, 0x06, 0x7E, 0x84, 0xFF, + 0xAF, 0x18, 0xAE, 0x39, 0xFE, 0x91, 0xAB, 0x52, 0x16, 0x8E, + 0xFB, 0x0C, 0xF8, 0x14, 0x21, 0x3A, 0xF8, 0xF8, 0x15, 0x23, + 0xCE, 0x58, 0x9C, 0xCA, 0x95, 0x55, 0xFB, 0x24, 0xA6, 0xF7, + 0x38, 0x7C, 0xE1, 0x2C, 0x1A, 0x91, 0x96, 0xBA, 0x66, 0x12, + 0xCE, 0x95, 0xB6, 0xB3, 0xFF, 0x54, 0x95, 0xF6, 0x48, 0x12, + 0x1E, 0x85, 0x99, 0xC5, 0x0E, 0x7C, 0xFD, 0xE2, 0x42, 0x6F, + 0xC0, 0xD5, 0xD1, 0x55, 0xD0, 0xED, 0x6B, 0x64, 0xBC, 0x94, + 0x15, 0x94, 0x33, 0xB7, 0xA7, 0x84, 0x74, 0x4C, 0x28, 0xDF, + 0x31, 0xA3, 0xA2, 0xE5, 0x86, 0x57, 0x5D, 0xA1, 0x43, 0x2A, + 0x6B, 0xA5, 0xC7, 0x0A, 0x2C, 0xAF, 0x5A, 0xBB, 0x5F, 0x94, + 0x60, 0xBE, 0x0D, 0x54, 0xF8, 0x03, 0x2F, 0xB1, 0xFD, 0x3D, + 0x93, 0x16, 0xDA, 0x61, 0xA0, 0x4B, 0x4E, 0xA1, 0x96, 0xCA, + 0x2B, 0x5A, 0x87, 0xEA, 0x76, 0x06, 0xB5, 0xF9, 0x10, 0x69, + 0x46, 0xB8, 0xFB, 0xA6, 0x54, 0x4F, 0xEA, 0x01, 0x03, 0xAE, + 0xDB, 0x50, 0x3A, 0x91, 0x70, 0x26, 0x88, 0xBB, 0x0F, 0xB7, + 0x93, 0x5E, 0x6C, 0x19, 0x9F, 0x8E, 0x20, 0x21, 0x2B, 0x2A, + 0xCB, 0x74, 0x0E, 0xF8, 0xBF, 0xCD, 0x6B, 0xF0, 0x29, 0xDE, + 0x25, 0x4C, 0x18, 0xB8, 0x18, 0xC1, 0x0C, 0x84, 0x7A, 0x8E, + 0x10, 0xD7, 0x59, 0x9D, 0x02, 0xAA, 0x94, 0xD5, 0x38, 0x92, + 0xB0, 0xA3, 0x41, 0x17, 0x7E, 0x1D, 0x71, 0x00, 0x75, 0x62, + 0xA3, 0x81, 0x13, 0x7B, 0x49, 0x51, 0x64, 0xA5, 0x5C, 0x05, + 0x6C, 0x53, 0x24, 0x3F, 0xF3, 0xCB, 0x49, 0x4C, 0x80, 0x99, + 0x85, 0x73, 0xAF, 0x71, 0x89, 0x5A, 0x3A, 0xAB, 0x0B, 0x86, + 0xF8, 0x7B, 0x56, 0x68, 0x25, 0x32, 0x4F, 0x88, 0x8D, 0xBC, + 0x50, 0xD3, 0xC2, 0x71, 0x0E, 0xEF, 0xCB, 0xF3, 0x45, 0x56, + 0xF1, 0x98, 0x9F, 0x77, 0x3C, 0xDD, 0x21, 0x39, 0x7F, 0xE5, + 0xA3, 0x67, 0x0A, 0x46, 0x56, 0x69, 0x7F, 0x5F, 0x88, 0xB6, + 0x59, 0xF4, 0xB2, 0xCD, 0x7F, 0x20, 0x9B, 0xD7, 0x57, 0x99, + 0xF4, 0x9C, 0x1C, 0x6A, 0x87, 0x45, 0xC3, 0x91, 0xD6, 0x2C, + 0xED, 0x8E, 0xFE, 0x2C, 0xD4, 0x3A, 0x1A, 0xB8, 0xA9, 0xB6, + 0xD5, 0xE5, 0xE7, 0xDD, 0x99, 0x06, 0x95, 0xF3, 0x54, 0xF7, + 0xCF, 0x03, 0x99, 0x9F, 0x0A, 0x87, 0x0C, 0x46, 0xBA, 0x32, + 0x36, 0x5C, 0xFC, 0x70, 0xE1, 0x53, 0x64, 0xB9, 0x93, 0xA0, + 0x1B, 0x11, 0x88, 0xAB, 0xF7, 0xA1, 0x97, 0x29, 0x44, 0x49, + 0xD5, 0xCB, 0x1E, 0x5B, 0xB2, 0x1B, 0x32, 0x69, 0xB6, 0x4E, + 0x11, 0x12, 0xB9, 0x53, 0xE3, 0x93, 0xD4, 0x4F, 0x7F, 0xCB, + 0x61, 0x23, 0x10, 0xE4, 0x2A, 0x63, 0xCC, 0xD9, 0x60, 0x18, + 0xE3, 0xC4, 0x0B, 0xD0, 0x95, 0x2A, 0x89, 0x45, 0x06, 0x2C, + 0x52, 0x87, 0xA0, 0x9A, 0xD9, 0x30, 0x87, 0x44, 0x78, 0xF2, + 0x71, 0x5E, 0xC1, 0x82, 0xE7, 0x27, 0x48, 0x4D, 0x59, 0xE8, + 0xCD, 0x06, 0xC9, 0x4B, 0x91, 0x36, 0x35, 0x02, 0xD2, 0x70, + 0xD1, 0xB8, 0x4A, 0xE1, 0x99, 0xA3, 0xB5, 0x36, 0x1B, 0xC3, + 0xBF, 0x20, 0xBA, 0x27, 0x83, 0x34, 0xC9, 0xD2, 0x44, 0x2F, + 0x33, 0x83, 0xDA, 0x22, 0xC2, 0x78, 0x57, 0x99, 0xBB, 0x05, + 0xBE, 0x8E, 0x3C, 0xB6, 0x17, 0x10, 0xDF, 0x91, 0x85, 0x98, + 0xF2, 0xB9, 0x4A, 0x62, 0x99, 0x07, 0x2C, 0xAD, 0x03, 0xF5, + 0x58, 0xBE, 0x3B, 0x26, 0x84, 0xC8, 0xCC, 0xEB, 0x58, 0xE5, + 0xD0, 0xDE, 0xE7, 0x4E, 0x63, 0xA7, 0x2F, 0x00, 0x19, 0x58, + 0xA1, 0x39, 0x51, 0xDE, 0xA3, 0x4A, 0x94, 0xC0, 0x96, 0xDA, + 0xAA, 0x81, 0x17, 0xDC, 0xAC, 0x54, 0xF7, 0xE1, 0x14, 0x2F, + 0x8D, 0xD7, 0x68, 0x48, 0xAB, 0x92, 0x6C, 0xB5, 0x0C, 0xDA, + 0x3C, 0x10, 0x78, 0xD6, 0xE5, 0xAE, 0xD2, 0xE9, 0x60, 0xA1, + 0x44, 0xB8, 0x21, 0xFA, 0x23, 0x26, 0xD5, 0x80, 0x79, 0xF0, + 0xA2, 0xF3, 0x21, 0x1C, 0x35, 0xA0, 0xDA, 0x22, 0x23, 0x22, + 0xBA, 0x4A, 0x1F, 0x3D, 0xBC, 0xA7, 0xCC, 0xE3, 0xD5, 0xF8, + 0x48, 0x8E, 0x66, 0x1A, 0x2E, 0x91, 0x56, 0x71, 0x60, 0x6D, + 0x1C, 0x5F, 0x54, 0xC6, 0x32, 0x67, 0xC8, 0x45, 0x22, 0x30, + 0x4F, 0xA6, 0x26, 0xF6, 0xDA, 0x69, 0xDE, 0x7D, 0x26, 0x36, + 0xB5, 0x85, 0x61, 0x9A, 0xAE, 0x10, 0x7F, 0x59, 0x32, 0xB2, + 0xBF, 0x7C, 0x76, 0x61, 0x0C, 0x6C, 0x2E, 0x91, 0x2A, 0x64, + 0x92, 0xD5, 0xDC, 0x4C, 0xCF, 0x79, 0x32, 0xA6, 0xB5, 0xCB, + 0x1D, 0x9C, 0x9B, 0x0C, 0xAC, 0x27, 0xFC, 0xB5, 0x46, 0x97, + 0x31, 0x7A, 0xD1, 0xB0, 0xD7, 0xB1, 0xDE, 0x65, 0xF6, 0x0B, + 0x0E, 0xBD, 0x53, 0x5D, 0xE3, 0xA6, 0xB8, 0x67, 0x26, 0x65, + 0x95, 0x8D, 0x34, 0x65, 0x73, 0x38, 0x74, 0x24, 0xE3, 0x1C, + 0x67, 0xB9, 0x97, 0x21, 0x24, 0x67, 0xCD, 0x48, 0x85, 0xA8, + 0x9C, 0x73, 0x08, 0xB3, 0x07, 0xD2, 0xF8, 0x87, 0x48, 0xA8, + 0xEB, 0x98, 0x7B, 0x10, 0xDF, 0x23, 0xCC, 0xD5, 0xB6, 0xBF, + 0x09, 0xAA, 0x81, 0xE4, 0xB6, 0x6C, 0xFC, 0xBA, 0x40, 0xD1, + 0x2E, 0x78, 0x7E, 0x4C, 0xE3, 0x68, 0x80, 0x3E, 0xE7, 0xBE, + 0x26, 0xA4, 0x54, 0xE9, 0xFA, 0xFE, 0x9C, 0xDE, 0x63, 0x4E, + 0xD2, 0x7A, 0xB1, 0x28, 0x70, 0x89, 0x2B, 0x7D, 0x5D, 0xE6, + 0x7A, 0xA5, 0x6C, 0xF1, 0xA3, 0x81, 0xC2, 0xB9, 0x76, 0x12, + 0xF4, 0xDE, 0x83, 0xA4, 0xBA, 0xE0, 0x7B, 0xFA, 0xE9, 0xAE, + 0xF8, 0x46, 0x0E, 0xCD, 0xCC, 0x16, 0xB5, 0xF8, 0x6D, 0xF6, + 0xC2, 0x88, 0xB8, 0x00, 0xD8, 0x6F, 0x2C, 0xB4, 0x72, 0xDA, + 0xDA, 0xF4, 0x0A, 0xF9, 0x30, 0x4A, 0xE3, 0xF2, 0x41, 0xA5, + 0x4A, 0xBE, 0x8D, 0x21, 0xBB, 0x97, 0x89, 0x96, 0xD8, 0xB4, + 0x87, 0x1C, 0x83, 0xE2, 0xE9, 0x7A, 0x32, 0xAD, 0xE1, 0x5A, + 0x97, 0x9E, 0xBB, 0x17, 0xCC, 0xD1, 0xBE, 0xD9, 0xF6, 0x6E, + 0x09, 0xEA, 0x69, 0x7C, 0x17, 0x5F, 0xD5, 0x5A, 0xFF, 0xED, + 0xE2, 0x9B, 0xA5, 0xAF, 0xCA, 0x8A, 0x03, 0x08, 0x44, 0xEA, + 0xB0, 0x63, 0x20, 0xAF, 0x9D, 0xF6, 0x23, 0xBE, 0x34, 0xBF, + 0x3A, 0x3C, 0x18, 0xAD, 0x97, 0x78, 0x04, 0xA7, 0xAC, 0xCF, + 0x96, 0x86, 0xE9, 0xB4, 0xF1, 0x17, 0xFA, 0x09, 0x2F, 0x30, + 0xEA, 0xBA, 0x19, 0xFC, 0xFD, 0xD1, 0x9D, 0x2F, 0x68, 0x74, + 0x0E, 0x8D, 0x25, 0xF5, 0xAA, 0xC6, 0xF5, 0xE5, 0xA8, 0x38, + 0xEF, 0x13, 0x2B, 0x66, 0x22, 0x1B, 0x8A, 0x34, 0xC5, 0xB2, + 0x49, 0xD1, 0x30, 0xDE, 0x04, 0x9C, 0x53, 0x9A, 0x6B, 0xDD, + 0xA1, 0x56, 0x8C, 0x89, 0xF5, 0x17, 0xBC, 0xE1, 0x3A, 0xF4, + 0x71, 0xBA, 0x7C, 0xDC, 0xF8, 0x30, 0xE4, 0x24, 0x57, 0x87, + 0xAB, 0xE3, 0x28, 0x3C, 0x2C, 0x07, 0xFE, 0x2A, 0xC7, 0x21, + 0xE6, 0x97, 0x70, 0x5A, 0x01, 0x2D, 0x95, 0xF6, 0x52, 0xDE, + 0x61, 0xA4, 0xEB, 0xFD, 0xEA, 0x96, 0xEC, 0x15, 0xA6, 0xE9, + 0xB8, 0x41, 0xB8, 0x27, 0xF6, 0xFC, 0x51, 0x5A, 0xFF, 0x59, + 0xCC, 0xFA, 0xFE, 0x02, 0x4E, 0x1A, 0x89, 0x7F, 0xC8, 0xDE, + 0x4E, 0x4D, 0x14, 0xC7, 0x35, 0xAC, 0x21, 0x25, 0x43, 0x2E, + 0xC7, 0x96, 0x5C, 0x91, 0xE5, 0x03, 0xC9, 0x61, 0x60, 0xBA, + 0x9F, 0xE0, 0x51, 0x38, 0xE3, 0xB4, 0xD0, 0xC0, 0xA7, 0x27, + 0xB8, 0x09, 0x0F, 0x37, 0x25, 0x19, 0xE0, 0x93, 0x14, 0xF2, + 0x54, 0x94, 0x92, 0xE7, 0x37, 0xD2, 0x7D, 0xF2, 0x3E, 0x11, + 0xCC, 0x4C, 0xA2, 0x19, 0x75, 0xCA, 0x43, 0x72, 0x1D, 0x69, + 0xD6, 0xDA, 0xCA, 0x5B, 0x13, 0x7F, 0xEB, 0xB1, 0xBB, 0xF1, + 0x4E, 0x77, 0xD8, 0x14, 0xC2, 0x9F, 0x9A, 0xBF, 0x4F, 0x2E, + 0xDD, 0x7B, 0x61, 0x49, 0xFE, 0xB0, 0xE1, 0x47, 0x05, 0x16, + 0xE1, 0xD4, 0x60, 0x6E, 0xE6, 0x1E, 0x23, 0xE9, 0x86, 0xD6, + 0xB1, 0xEF, 0x7F, 0xDC, 0xDF, 0x6E, 0xCB, 0xE6, 0x59, 0xC3, + 0x82, 0xD4, 0xBF, 0x36, 0x34, 0x33, 0x7C, 0x53, 0xE2, 0x24, + 0xA6, 0xB1, 0xFA, 0x17, 0xEB, 0x0D, 0xB7, 0x18, 0x53, 0x18, + 0x51, 0x48, 0x00, 0x8D, 0x04, 0x71, 0xC2, 0x70, 0x9D, 0x4C, + 0x67, 0xFA, 0x07, 0xEE, 0xCE, 0x55, 0xA4, 0xB3, 0x31, 0x22, + 0xAA, 0xF1, 0xB3, 0x04, 0xBE, 0xFE, 0x81, 0xAF, 0x03, 0x7D, + 0x52, 0x5C, 0x30, 0x6D, 0x73, 0xA4, 0x0A, 0xF0, 0x12, 0xA5, + 0x6E, 0x4B, 0xBC, 0x24, 0x2A, 0xAB, 0xC5, 0x85, 0x57, 0x48, + 0x19, 0xE0, 0x6F, 0x04, 0xCB, 0x41, 0x37, 0x41, 0xF8, 0x61, + 0x7B, 0x77, 0xFA, 0x26, 0x07, 0x6A, 0x63, 0x0E, 0x03, 0x08, + 0xF0, 0x6F, 0x83, 0x07, 0xC3, 0x36, 0x50, 0xAB, 0x3C, 0x84, + 0x6F, 0xF6, 0x75, 0x2C, 0x52, 0x52, 0x65, 0xB1, 0xF9, 0x80, + 0xBC, 0x4F, 0xD8, 0xDD, 0x0B, 0x67, 0xCB, 0xB5, 0x10, 0x76, + 0x5B, 0xA1, 0x17, 0x80, 0x13, 0x61, 0x8B, 0x4C, 0xCC, 0xD0, + 0x51, 0x81, 0x6B, 0xBB, 0xAE, 0xDC, 0x0E, 0x66, 0x9C, 0x9E, + 0x11, 0x80, 0x80, 0x98, 0x8E, 0x56, 0x0D, 0xCF, 0x26, 0xFF, + 0x7B, 0xA2, 0xE3, 0x80, 0x72, 0x8B, 0x18, 0x34, 0x52, 0x5F, + 0xB5, 0xDB, 0x1D, 0x4E, 0x47, 0x0E, 0xA5, 0x59, 0x26, 0xD2, + 0xFB, 0x77, 0xD1, 0xAB, 0xEA, 0x51, 0x77, 0x56, 0x16, 0x72, + 0xD9, 0x83, 0x8E, 0x1C, 0xAD, 0xD8, 0x40, 0x34, 0xB8, 0x97, + 0x77, 0x61, 0xA3, 0xD3, 0xB8, 0x63, 0xC2, 0x8A, 0x64, 0x94, + 0xB9, 0x2E, 0xA6, 0xDF, 0xDB, 0xAC, 0xE9, 0xD4, 0x88, 0xA4, + 0x43, 0x84, 0xF7, 0x34, 0x3E, 0x67, 0xAF, 0x68, 0x0F, 0xFB, + 0x76, 0x34, 0xE9, 0xFE, 0x40, 0x43, 0x1A, 0x52, 0x4C, 0x40, + 0x21, 0x4C, 0xD7, 0xF2, 0xE6, 0x69, 0x72, 0xA6, 0x36, 0x1F, + 0x39, 0xBB, 0x3F, 0xDE, 0x80, 0x77, 0x48, 0xE9, 0x66, 0x34, + 0x4C, 0xAD, 0xF0, 0x50, 0x0B, 0x16, 0xD1, 0xFB, 0xD5, 0x2A, + 0x12, 0x4D, 0x06, 0x6E, 0x83, 0xD6, 0x69, 0xA1, 0x94, 0x52, + 0xA5, 0x49, 0xFE, 0x38, 0xCC, 0x29, 0x83, 0x99, 0xFE, 0xDC, + 0xEE, 0xB3, 0x71, 0xDE, 0x55, 0xDF, 0xA2, 0x2A, 0xD2, 0x63, + 0x54, 0x77, 0xEF, 0xF9, 0x3A, 0xE2, 0xD7, 0xC1, 0x50, 0x7D, + 0x5B, 0x1E, 0x6E, 0x4D, 0x51, 0x26, 0x7B, 0x02, 0x78, 0xF2, + 0x75, 0x53, 0xCA, 0xB9, 0x17, 0x63, 0x4E, 0x1D, 0xF6, 0x3A, + 0x3E, 0x16, 0xD1, 0xA7, 0xA9, 0x05, 0x98, 0x4C, 0xC2, 0x71, + 0xDE, 0x98, 0x80, 0x0F, 0xC4, 0x73, 0xAB, 0x4F, 0x51, 0x81, + 0x99, 0x9E, 0x33, 0xFF, 0x14, 0xDA, 0x65, 0x0C, 0xCE, 0x8B, + 0xB8, 0x27, 0x1E, 0x17, 0xD0, 0xEB, 0x98, 0x35, 0xC0, 0xA8, + 0x3B, 0x10, 0x4C, 0x6F, 0x12, 0xF7, 0x9A, 0x95, 0x2A, 0x77, + 0x5B, 0xF9, 0x68, 0xA4, 0x63, 0x9A, 0xFD, 0x7A, 0xFB, 0xFF, + 0xEB, 0x36, 0x5C, 0xF3, 0xBB, 0x93, 0x18, 0xD8, 0xC1, 0x36, + 0xC8, 0x72, 0xC2, 0x83, 0x5E, 0xA8, 0x9B, 0xF4, 0x34, 0x2C, + 0x5A, 0x9A, 0xD3, 0x81, 0x4C, 0x40, 0xF9, 0x9F, 0xA9, 0x06, + 0xE5, 0x4A, 0xF1, 0xA5, 0x79, 0x12, 0x72, 0x22, 0xE7, 0xBB, + 0xBB, 0x4A, 0xEF, 0xB0, 0x6E, 0xBE, 0x66, 0x62, 0xB2, 0xA7, + 0x23, 0x9C, 0x4D, 0x44, 0x56, 0x12, 0x73, 0x39, 0x5D, 0x7B, + 0x4C, 0xBA, 0x52, 0x64, 0x8A, 0xBA, 0x93, 0xFB, 0x0D, 0x33, + 0xBC, 0xE2, 0x70, 0xD0, 0x5E, 0x5F, 0xA6, 0x40, 0x0C, 0x6B, + 0x4C, 0x5F, 0x2E, 0x05, 0x91, 0xF9, 0x4C, 0x6D, 0xF8, 0x9D, + 0x2E, 0xFB, 0xA4, 0x1A, 0x01, 0xA9, 0xC0, 0x73, 0xF6, 0xA4, + 0x09, 0x64, 0x69, 0x60, 0xEA, 0x44, 0x12, 0x41, 0x18, 0x83, + 0x71, 0x72, 0xC7, 0x05, 0x73, 0x6C, 0x62, 0x39, 0x42, 0xF9, + 0x40, 0xED, 0x7C, 0xA8, 0x04, 0x9C, 0x38, 0xA4, 0x95, 0x36, + 0x05, 0xD4, 0x4E, 0xA2, 0x08, 0x0D, 0x41, 0xC5, 0x03, 0x17, + 0xE1, 0x92, 0x1B, 0xCB, 0xE8, 0x83, 0xAA, 0xF7, 0xBF, 0x7A, + 0x92, 0x36, 0xC5, 0x38, 0x41, 0xA1, 0x7E, 0x44, 0x69, 0x65, + 0x48, 0xE1, 0xDC, 0xE9, 0x0D, 0x89, 0xD3, 0x6B, 0xFE, 0x56, + 0x60, 0x35, 0xEA, 0x93, 0x36, 0xE5, 0xDD, 0x92, 0xDA, 0xAA, + 0x1B, 0x0D, 0xBE, 0xA3, 0x91, 0xD6, 0x37, 0xE7, 0x66, 0xD4, + 0xA3, 0xBB, 0xF9, 0x5B, 0xDA, 0xB2, 0x00, 0xF0, 0xED, 0x2E, + 0x35, 0x79, 0x97, 0xFF, 0x99, 0xF9, 0x4E, 0xE6, 0x39, 0xE8, + 0xD2, 0xF3, 0x2A, 0x22, 0x4D, 0x5B, 0x9C, 0x5E, 0x71, 0x60, + 0x62, 0x58, 0x04, 0x9F, 0x77, 0xFD, 0xD5, 0xA7, 0x9F, 0x1A, + 0xC2, 0xD8, 0x37, 0x4F, 0x35, 0x39, 0xCC, 0xF2, 0x6B, 0x77, + 0x29, 0xF8, 0x51, 0x95, 0xAA, 0x36, 0xBF, 0xA5, 0x7A, 0x37, + 0xF7, 0xF0, 0xA2, 0xB9, 0xF1, 0x6D, 0xED, 0xE2, 0xEC, 0x5B, + 0x9D, 0xF0, 0x82, 0xB2, 0xC0, 0xEE, 0x2B, 0x5C, 0xDF, 0x07, + 0x42, 0xCA, 0x31, 0xA8, 0xB7, 0x62, 0x2E, 0xAB, 0x2A, 0xF0, + 0x9E, 0xD5, 0x02, 0x9D, 0x54, 0x4C, 0x82, 0x3D, 0x5A, 0x26, + 0x9F, 0xCA, 0x0A, 0x11, 0x67, 0x1F, 0x72, 0xC7, 0xA9, 0xC6, + 0x39, 0x89, 0x28, 0x21, 0x58, 0xFA, 0x8E, 0xFE, 0x03, 0x0D, + 0x19, 0x7A, 0x77, 0x07, 0xFF, 0x8B, 0xF0, 0x00, 0x51, 0xE4, + 0xD3, 0x9E, 0x90, 0xC0, 0xE9, 0xBE, 0xD4, 0x13, 0x3F, 0xCA, + 0xB4, 0x41, 0xB3, 0x70, 0x33, 0x38, 0x7E, 0xA4, 0xDE, 0x79, + 0x9A, 0x49, 0x96, 0x42, 0x4B, 0x3A, 0x32, 0xA6, 0xA9, 0x7C, + 0x74, 0xEE, 0x39, 0xD1, 0x08, 0x23, 0x42, 0xCD, 0x2F, 0x78, + 0xE1, 0xC1, 0x72, 0x14, 0xDC, 0xF7, 0xF3, 0x9B, 0x38, 0x4C, + 0x0A, 0x01, 0x50, 0x9B, 0x94, 0xD6, 0xF6, 0x3E, 0x9C, 0x33, + 0xF0, 0x87, 0x43, 0x1A, 0xF6, 0xBD, 0xD8, 0x71, 0xBB, 0xA7, + 0x11, 0xA0, 0x2E, 0x6C, 0x34, 0xEF, 0x51, 0x9A, 0x40, 0xD3, + 0x47, 0xD2, 0x44, 0xFE, 0x4C, 0x90, 0xFD, 0xEF, 0x6A, 0xE6, + 0x79, 0x48, 0x65, 0xEE, 0x6D, 0x31, 0xED, 0x71, 0x0B, 0x2D, + 0xED, 0x37, 0xB0, 0x0E, 0x50, 0x67, 0x65, 0x66, 0xEC, 0xD6, + 0x8E, 0x15, 0x46, 0xD5, 0x8B, 0xBD, 0x98, 0x06, 0xA6, 0x94, + 0x46, 0x54, 0xA6, 0xC3, 0x8F, 0xB5, 0x29, 0x67, 0x5E, 0xF3, + 0x5B, 0x6A, 0x0E, 0x93, 0xEF, 0x0A, 0x3B, 0xB4, 0x23, 0x8E, + 0xB5, 0xD9, 0x10, 0x5A, 0xE6, 0x34, 0x4E, 0x29, 0xAE, 0x28, + 0xD0, 0xE7, 0x89, 0x46, 0x4F, 0x5E, 0xD5, 0x4A, 0x16, 0x6F, + 0xA0, 0xDA, 0x81, 0x15, 0x23, 0x04, 0x9C, 0x7B, 0xDC, 0xF0, + 0xD7, 0x84, 0xEF, 0xF4, 0x76, 0xC5, 0xAD, 0xC3, 0xA9, 0xB3, + 0x76, 0x4C, 0x11, 0x1F, 0xF8, 0x75, 0xC3, 0x7C, 0x84, 0x0F, + 0x88, 0x56, 0x9F, 0x98, 0xE2, 0xCD, 0x48, 0xFD, 0x7F, 0x25, + 0x28, 0x7D, 0xDA, 0x35, 0xA0, 0x60, 0xD5, 0x94, 0x76, 0xB0, + 0xA7, 0x85, 0x04, 0xC8, 0x85, 0x35, 0x7A, 0x0C, 0xDF, 0x3E, + 0x44, 0xBE, 0x5D, 0x91, 0x5A, 0x3A, 0x82, 0x75, 0xC2, 0x52, + 0x12, 0xB1, 0x8D, 0x94, 0xB7, 0x1F, 0x30, 0xD4, 0xA7, 0x15, + 0x2F, 0xDF, 0x23, 0xDD, 0x96, 0xF3, 0x2D, 0xDE, 0x2E, 0xC5, + 0x60, 0x2A, 0x9F, 0x5F, 0x48, 0xA8, 0x69, 0x32, 0x33, 0x64, + 0x95, 0x51, 0x76, 0x4D, 0x92, 0x6B, 0x0B, 0xAF, 0xF0, 0x02, + 0xA9, 0x89, 0x69, 0x84, 0x22, 0x11, 0x17, 0x01, 0x11, 0xBD, + 0x85, 0x03, 0x61, 0x82, 0xA4, 0xF2, 0x04, 0xE4, 0xEE, 0xC9, + 0xF7, 0xAE, 0x2C, 0x93, 0x94, 0xAF, 0xDD, 0xCA, 0x89, 0xAD, + 0x0C, 0xF2, 0xFF, 0x69, 0x9B, 0x7C, 0x52, 0xF5, 0xF9, 0x7D, + 0xE3, 0xAE, 0x6B, 0xC5, 0x81, 0x18, 0x34, 0xCB, 0x42, 0x11, + 0x71, 0x9B, 0xAE, 0x3E, 0x1D, 0x53, 0xE0, 0x07, 0x9D, 0x42, + 0xC0, 0x28, 0x4C, 0x04, 0x93, 0xE9, 0x43, 0xF0, 0xDE, 0x2F, + 0xBD, 0xD8, 0xC2, 0x26, 0x49, 0x65, 0x3C, 0x2D, 0xA8, 0x09, + 0xAF, 0x00, 0xCD, 0x07, 0x68, 0x64, 0x21, 0xFE, 0xA3, 0xBF, + 0xA1, 0x0F, 0x7A, 0x16, 0xA6, 0x36, 0x37, 0xA1, 0x81, 0x66, + 0x02, 0x91, 0x18, 0xEB, 0xA4, 0x09, 0x2C, 0x1A, 0x6C, 0x8D, + 0xF5, 0xA1, 0xB6, 0x55, 0x04, 0xBE, 0xD2, 0x91, 0xF3, 0x0B, + 0x6B, 0x7E, 0x4D, 0x1B, 0xFA, 0x69, 0x09, 0x5C, 0xC2, 0x63, + 0xDA, 0x9E, 0xA8, 0x72, 0xD9, 0x15, 0x60, 0xF6, 0x2D, 0x18, + 0xF3, 0x70, 0x31, 0xB5, 0x9C, 0xDA, 0x67, 0x9C, 0x23, 0xF2, + 0xED, 0x63, 0x3A, 0x94, 0xC1, 0x62, 0xC5, 0x98, 0xF4, 0x50, + 0x7F, 0x93, 0x30, 0x65, 0x81, 0xD2, 0x91, 0x38, 0x06, 0x88, + 0x18, 0x16, 0x1B, 0x81, 0x22, 0xD4, 0xDA, 0x10, 0xBF, 0x35, + 0x4E, 0xCC, 0x72, 0xE2, 0xB3, 0x16, 0x52, 0x3A, 0x5C, 0x9F, + 0xC5, 0x0D, 0xFB, 0xA5, 0x09, 0xDB, 0x32, 0xBE, 0xE4, 0x66, + 0x1D, 0xA2, 0x49, 0x9D, 0x2C, 0x95, 0xE0, 0xD5, 0x8F, 0xE5, + 0x88, 0x7D, 0x5B, 0x80, 0x6D, 0x53, 0x14, 0x94, 0x9D, 0x78, + 0x9A, 0x85, 0x0B, 0xFA, 0x7E, 0x81, 0xA8, 0x99, 0x40, 0x0F, + 0x85, 0x0E, 0x9E, 0xD5, 0x71, 0xCC, 0x1F, 0x54, 0xE9, 0x9C, + 0x87, 0x39, 0x7D, 0xF2, 0x09, 0x88, 0xB4, 0x00, 0xAA, 0x81, + 0x96, 0xC9, 0x39, 0xF1, 0xF0, 0x31, 0x47, 0x42, 0x0A, 0xCC, + 0x4D, 0xDB, 0xF7, 0x9F, 0x8A, 0x78, 0x6E, 0xFE, 0x61, 0x2A, + 0x7A, 0xE5, 0xA0, 0xC5, 0xBE, 0xA4, 0x26, 0x06, 0x0E, 0x61, + 0x53, 0xA6, 0x05, 0xD8, 0x6C, 0xA0, 0x53, 0xF8, 0x7E, 0x3D, + 0xA8, 0x3F, 0x49, 0x40, 0xCD, 0x3B, 0x1B, 0x26, 0x71, 0x3E, + 0x8C, 0x15, 0xAC, 0x33, 0xB8, 0x17, 0xB1, 0x79, 0xEC, 0xE1, + 0x82, 0x1B, 0x03, 0x01, 0x71, 0xAC, 0x6B, 0x41, 0x06, 0x40, + 0x35, 0xB2, 0x67, 0x84, 0xAB, 0xCF, 0x9C, 0xB8, 0x21, 0xEE, + 0x19, 0x59, 0x24, 0x36, 0x30, 0x5C, 0x03, 0xFA, 0xB2, 0x23, + 0xCE, 0xF1, 0x9C, 0x53, 0xD1, 0xF1, 0x59, 0xC3, 0x72, 0xD8, + 0x9D, 0x10, 0x61, 0x0A, 0xC8, 0x59, 0x2D, 0x05, 0xFD, 0x5A, + 0x26, 0x70, 0xAC, 0x7E, 0x7F, 0x69, 0x6F, 0x73, 0x86, 0x9F, + 0x46, 0x7F, 0xB6, 0x31, 0x54, 0x5F, 0xDC, 0xB3, 0xC7, 0xC1, + 0xB2, 0xD0, 0x3B, 0x04, 0xE7, 0xF7, 0xFB, 0x46, 0xF5, 0xF0, + 0x60, 0xE5, 0x08, 0x27, 0x31, 0x94, 0x9E, 0x1B, 0xC4, 0xFB, + 0xEE, 0xC7, 0xDF, 0x41, 0xAF, 0xC4, 0x87, 0x02, 0x27, 0x98, + 0x76, 0x39, 0x5D, 0x02, 0x92, 0xE1, 0x5B, 0x55, 0x8B, 0x4D, + 0x11, 0xF6, 0x90, 0xDA, 0xCE, 0x7D, 0xFF, 0x60, 0x2E, 0xC7, + 0x81, 0xAE, 0xC8, 0x25, 0xCE, 0xF5, 0xE5, 0x75, 0x2D, 0xBE, + 0x59, 0x0B, 0x09, 0x67, 0xF7, 0x58, 0x8F, 0x8D, 0xB8, 0x08, + 0xA7, 0xA4, 0xA4, 0xB9, 0xAC, 0x40, 0xFD, 0x68, 0x1F, 0xCF, + 0x98, 0x2A, 0x76, 0xCF, 0x4E, 0x08, 0x7F, 0x62, 0xEF, 0xE9, + 0xD4, 0xDC, 0x52, 0x79, 0xBB, 0x23, 0xBD, 0x0A, 0x42, 0x37, + 0x87, 0xAF, 0x11, 0x8C, 0x24, 0x38, 0x2B, 0x2E, 0xE2, 0x0A, + 0x5C, 0xB1, 0x72, 0x5D, 0x9E, 0x6E, 0x6A, 0x2E, 0xEF, 0x86, + 0xC8, 0xCF, 0x52, 0x8F, 0x85, 0x78, 0x2E, 0xCC, 0x9C, 0xBF, + 0xFE, 0x1C, 0x99, 0x4C, 0x5D, 0x3E, 0xF0, 0xBA, 0x84, 0xF7, + 0x41, 0x04, 0x61, 0xD8, 0x16, 0x9A, 0x39, 0xD0, 0x67, 0xEE, + 0x2B, 0xC0, 0xC0, 0xDB, 0x8E, 0x69, 0xCC, 0xDB, 0xA1, 0xBE, + 0x0B, 0x36, 0x1E, 0xD1, 0xF1, 0x89, 0xC2, 0x5A, 0x5D, 0xFA, + 0xC9, 0xB2, 0x4C, 0x5A, 0x94, 0x64, 0x89, 0x9C, 0x8D, 0x4B, + 0x2F, 0x1D, 0xC1, 0x17, 0x2A, 0xCB, 0xA6, 0xF2, 0xDE, 0x27, + 0x1D, 0x86, 0x7E, 0x87, 0x08, 0x7D, 0xD3, 0xE1, 0x26, 0xF1, + 0xF7, 0x1B, 0xDD, 0x3B, 0x9B, 0xCC, 0xE7, 0xFA, 0x2F, 0xBF, + 0x21, 0xEE, 0x78, 0xBC, 0x38, 0xE1, 0x6F, 0x76, 0x2F, 0xA4, + 0x7F, 0x8D, 0x7C, 0x2E, 0xF3, 0x3A, 0x50, 0xA5, 0x15, 0x09, + 0xFF, 0x29, 0xC4, 0x54, 0x1C, 0xB3, 0xE7, 0x88, 0xD8, 0xD7, + 0x3F, 0xE7, 0xFB, 0xEC, 0xB6, 0xAE, 0xC8, 0xDB, 0xFA, 0xBF, + 0x3E, 0x2F, 0x80, 0x4D, 0xED, 0x42, 0x1E, 0x0E, 0xE6, 0xC5, + 0x12, 0xE7, 0x70, 0x10, 0xA8, 0xE3, 0x1C, 0x92, 0x0E, 0x0E, + 0x73, 0xB8, 0xDF, 0x07, 0x8F, 0xCB, 0xFD, 0x73, 0x3E, 0x6A, + 0x30, 0xE7, 0x68, 0xE5, 0xC6, 0x53, 0xF9, 0xE9, 0xF1, 0xDA, + 0xCA, 0xC1, 0x56, 0x71, 0x61, 0x18, 0x6A, 0x4E, 0x0B, 0x66, + 0xEC, 0x43, 0x6F, 0x16, 0x73, 0x46, 0x26, 0x3F, 0x6B, 0x01, + 0xA1, 0x10, 0xFC, 0xD1, 0x64, 0x1A, 0x00, 0x2F, 0x12, 0xD8, + 0xCC, 0x05, 0x28, 0x81, 0x40, 0x1B, 0xCE, 0x13, 0x9B, 0xF5, + 0x05, 0x39, 0xE4, 0xBD, 0x33, 0xF6, 0x4E, 0x9E, 0xE6, 0x7B, + 0x5F, 0x43, 0x7F, 0x22, 0x41, 0x93, 0x41, 0x48, 0x84, 0x41, + 0x80, 0xC3, 0x61, 0x18, 0x16, 0x5C, 0x04, 0x7B, 0xCD, 0x57, + 0x8D, 0x6A, 0xD8, 0x37, 0x55, 0x2E, 0x7D, 0x78, 0xD8, 0x5E, + 0xC4, 0x32, 0x0A, 0x29, 0x4C, 0xB8, 0x6C, 0x56, 0x75, 0x58, + 0xEC, 0x25, 0x0F, 0x1A, 0x6F, 0x43, 0xBB, 0xB7, 0x77, 0x2C, + 0x5E, 0xFF, 0x67, 0x9E, 0x5C, 0x03, 0x2B, 0x1B, 0x8A, 0xAC, + 0xF3, 0x35, 0x14, 0x97, 0x13, 0x91, 0x96, 0xF4, 0x07, 0x6B, + 0x1C, 0x31, 0x12, 0x11, 0x72, 0x02, 0x7D, 0x3B, 0x8C, 0x52, + 0x55, 0x0D, 0xC3, 0x30, 0x77, 0x0D, 0x4D, 0x1B, 0x37, 0x83, + 0xF6, 0xFB, 0xF4, 0x2C, 0x36, 0x30, 0x7B, 0x69, 0x76, 0xEC, + 0xAC, 0x9D, 0x7B, 0xBA, 0x58, 0xB8, 0xE9, 0x26, 0xD7, 0x32, + 0xBF, 0x57, 0xF2, 0xA7, 0x61, 0xC6, 0x9A, 0xEF, 0xAB, 0xA1, + 0x35, 0xD8, 0x4A, 0xDB, 0x05, 0x08, 0x38, 0x1D, 0x55, 0x8B, + 0xF3, 0x4D, 0xDB, 0xA1, 0x1B, 0x3F, 0x5B, 0xF5, 0x59, 0xFE, + 0x17, 0xBF, 0x8B, 0xDE, 0xAB, 0xED, 0xC6, 0xA4, 0xED, 0x4A, + 0xCE, 0x7D, 0x0B, 0xB1, 0xBB, 0x68, 0x97, 0x83, 0x33, 0x1E, + 0x91, 0xE7, 0x99, 0x86, 0x5A, 0xB0, 0xF1, 0xDE, 0xB1, 0xAE, + 0x57, 0x2F, 0x3A, 0x25, 0xDF, 0x67, 0x03, 0xB7, 0xE4, 0x1D, + 0xB5, 0x93, 0x5E, 0xF5, 0xA7, 0xE5, 0x14, 0xFB, 0xE8, 0x72, + 0xC2, 0xF9, 0x7B, 0xE6, 0x8A, 0xEC, 0xD1, 0x9D, 0x37, 0x08, + 0x03, 0x11, 0x00, 0xF6, 0xA1, 0x8C, 0x36, 0x33, 0xE1, 0xF2, + 0x9E, 0x98, 0x50, 0x9A, 0x78, 0xE9, 0x18, 0xE0, 0xB1, 0xB7, + 0x43, 0x9F, 0x66, 0x0A, 0xAB, 0x4D, 0x18, 0xA1, 0xB4, 0x90, + 0xB8, 0x0B, 0x59, 0xA0, 0x56, 0x2A, 0xA0, 0xEB, 0xE0, 0xDC, + 0x9B, 0xB0, 0x98, 0xB9, 0x66, 0x49, 0xE1, 0xDB, 0xEE, 0x03, + 0xE9, 0x44, 0x90, 0xA8, 0x9C, 0xD1, 0xEA, 0xA7, 0xAC, 0x9A, + 0x9F, 0x32, 0xD7, 0x43, 0x48, 0x26, 0xA8, 0x9E, 0xD0, 0x39, + 0xA7, 0xDC, 0x89, 0x16, 0x48, 0x0B, 0x67, 0x50, 0x4B, 0xFC, + 0xD6, 0x01, 0xB9, 0xA3, 0xF7, 0xA4, 0x4A, 0x10, 0x99, 0x38, + 0x77, 0xD2, 0xE2, 0xAD, 0xD3, 0x82, 0x78, 0x58, 0xE0, 0x73, + 0x0A, 0x73, 0x46, 0xDF, 0x34, 0xD5, 0xC7, 0x8A, 0xA3, 0x39, + 0x89, 0xC2, 0x41, 0x16, 0xEF, 0xDA, 0x92, 0xF8, 0x52, 0x1C, + 0x2B, 0x2B, 0x72, 0x39, 0x05, 0xD4, 0x2A, 0x0A, 0x86, 0xEC, + 0xB0, 0x2A, 0x14, 0xE5, 0x79, 0xCD, 0x99, 0xEA, 0x7F, 0xC0, + 0xB0, 0xDE, 0x7F, 0x6A, 0xB1, 0x9D, 0x13, 0x13, 0x1D, 0x61, + 0xD1, 0xE5, 0xAA, 0xF5, 0xFC, 0x71, 0xCB, 0xA4, 0x58, 0x02, + 0x67, 0xD7, 0x75, 0x82, 0xBD, 0xC9, 0xB8, 0x58, 0x1B, 0x0F, + 0x32, 0x02, 0xB3, 0x3A, 0xED, 0x85, 0x8A, 0xB8, 0xA0, 0x84, + 0xF0, 0x12, 0x41, 0x87, 0x12, 0xCA, 0x40, 0x07, 0x9A, 0x1B, + 0x6D, 0x19, 0x8D, 0x30, 0x91, 0x9F, 0xE7, 0xDA, 0x18, 0x13, + 0x65, 0xF1, 0x30, 0xBF, 0xD0, 0xCD, 0xFC, 0x57, 0x43, 0xA0, + 0xA6, 0xDC, 0x3B, 0x65, 0x43, 0x29, 0x26, 0x5B, 0x89, 0x13, + 0x72, 0x3B, 0x9B, 0xA5, 0xA7, 0x7E, 0xD2, 0x09, 0xEE, 0x53, + 0x8E, 0xFB, 0x2F, 0x38, 0xE4, 0xBA, 0xDA, 0x4E, 0xB0, 0x81, + 0xDF, 0x59, 0x4D, 0xCE, 0x00, 0x18, 0x78, 0x14, 0x0A, 0x83, + 0xD2, 0xD6, 0xC2, 0x81, 0x76, 0xD8, 0x71, 0x9D, 0x22, 0x5C, + 0xEA, 0x66, 0xDB, 0x1F, 0xB0, 0x9A, 0xF0, 0x82, 0x01, 0x2C, + 0x29, 0x1F, 0xCD, 0x4A, 0x15, 0x0A, 0x65, 0x9B, 0xA2, 0x6C, + 0x81, 0x8D, 0xF2, 0x68, 0x4E, 0x56, 0xE3, 0x65, 0xCA, 0x2F, + 0x0F, 0x5B, 0x5B, 0x9E, 0x3A, 0xAA, 0x1C, 0x34, 0x3C, 0x9A, + 0xB5, 0x5E, 0xCC, 0x14, 0xB1, 0xA8, 0x6F, 0x11, 0x5A, 0x70, + 0xCC, 0x44, 0xAA, 0x24, 0xFB, 0xE7, 0xA7, 0x3F, 0xCE, 0xA7, + 0x80, 0x55, 0x11, 0x50, 0x48, 0x21, 0xE8, 0x5C, 0x66, 0x3C, + 0x3F, 0x94, 0x80, 0xFE, 0x41, 0x48, 0x1E, 0x37, 0x08, 0xA1, + 0x3F, 0x4F, 0x3E, 0x87, 0x6C, 0x95, 0x33, 0x9C, 0x35, 0x2B, + 0x75, 0xE0, 0xC0, 0x16, 0x4A, 0xFF, 0x67, 0xAE, 0x9D, 0x99, + 0xFC, 0xBD, 0x84, 0x69, 0x42, 0xE6, 0x10, 0xD2, 0x6A, 0x32, + 0xFE, 0xBE, 0xE8, 0xAE, 0x2C, 0x19, 0x5E, 0x3B, 0x96, 0xD9, + 0x9F, 0x4B, 0x38, 0x44, 0xAB, 0x46, 0xDB, 0xEC, 0xD2, 0xC5, + 0xF5, 0x82, 0xE6, 0xAA, 0x8D, 0xCD, 0x15, 0xC0, 0x67, 0x7C, + 0x96, 0xE4, 0x45, 0xA7, 0x6E, 0x21, 0x09, 0x6B, 0x0F, 0xB5, + 0xAE, 0x33, 0x46, 0x20, 0x59, 0x14, 0x3E, 0x9A, 0xE1, 0x6D, + 0x20, 0x70, 0x81, 0x52, 0x5B, 0x2A, 0x8C, 0x5C, 0x65, 0x8C, + 0x16, 0xB1, 0x50, 0xE1, 0x03, 0xC6, 0xD2, 0x3A, 0x43, 0xA9, + 0x7C, 0xAD, 0xCB, 0x77, 0x7A, 0xC9, 0x9E, 0xD5, 0x0F, 0xCE, + 0xD4, 0x57, 0xCD, 0xF6, 0xED, 0x99, 0xB0, 0x87, 0xCF, 0x9C, + 0x08, 0x62, 0xCD, 0x97, 0x1B, 0xA5, 0xAD, 0x4E, 0x3A, 0x2E, + 0xCD, 0x2C, 0x4C, 0x63, 0x6A, 0x32, 0xFF, 0x8B, 0xF2, 0xE0, + 0xA1, 0x05, 0xB3, 0xFE, 0xEC, 0x43, 0x02, 0xDC, 0x4D, 0x7C, + 0xC8, 0x4C, 0xD2, 0xCC, 0x63, 0x84, 0x79, 0x7C, 0x73, 0xDC, + 0x2B, 0x1E, 0x66, 0x5B, 0xF2, 0xC4, 0xF9, 0x5B, 0x04, 0x42, + 0xE5, 0x9E, 0x89, 0x66, 0xEE, 0x6D, 0xE9, 0x96, 0xD2, 0x97, + 0xBC, 0x78, 0xEC, 0x58, 0xC2, 0xC2, 0xD2, 0x3F, 0xF5, 0x97, + 0x85, 0x07, 0xC9, 0x83, 0x74, 0x6C, 0x04, 0xFA, 0x15, 0xF3, + 0x4C, 0x88, 0xD3, 0x24, 0xE3, 0xB8, 0xDD, 0xCE, 0xF9, 0x51, + 0xB8, 0xC2, 0x4B, 0xB2, 0xDD, 0xE5, 0xFB, 0x4A, 0x83, 0x1C, + 0x00, 0xD9, 0x22, 0x42, 0x9A, 0xAF, 0x82, 0x91, 0xF8, 0x4C, + 0x66, 0x5E, 0x22, 0x65, 0xEB, 0x3A, 0xA5, 0xEF, 0xF9, 0xB2, + 0xF9, 0xB7, 0xAC, 0x27, 0x12, 0x8F, 0x9C, 0x5A, 0x80, 0x32, + 0x8B, 0x95, 0xB0, 0xBD, 0xCB, 0x33, 0xCB, 0x60, 0x72, 0xDF, + 0x87, 0xBB, 0xC7, 0x29, 0xF8, 0xE6, 0x9E, 0x87, 0x6E, 0xA6, + 0x30, 0xFF, 0x7E, 0xA3, 0x90, 0x7D, 0x0D, 0xB7, 0x23, 0x30, + 0xBC, 0xEF, 0xB3, 0x02, 0x50, 0x3D, 0xC7, 0x93, 0x9A, 0x20, + 0xB7, 0x83, 0x9A, 0x9B, 0x48, 0xF3, 0x38, 0x21, 0xDD, 0x36, + 0x42, 0x84, 0x9F, 0x34, 0xA5, 0x4D, 0x1C, 0xBA, 0x31, 0xE4, + 0x99, 0x4F, 0x48, 0xD8, 0x5F, 0x35, 0x67, 0xE3, 0x91, 0x45, + 0x61, 0x3D, 0x2B, 0x00, 0x66, 0x2C, 0xDB, 0x28, 0x22, 0xFE, + 0x6C, 0x9F, 0xC7, 0x7B, 0x90, 0x5D, 0x9F, 0x6F, 0x0C, 0x0D, + 0x7B, 0xC2, 0xAE, 0x86, 0xE3, 0xD4, 0xC1, 0x27, 0x8A, 0x3C, + 0x4E, 0xAC, 0x76, 0xB3, 0x8B, 0xA8, 0x82, 0x77, 0xFA, 0xB0, + 0xE2, 0x47, 0x52, 0xA3, 0x74, 0xFC, 0xBA, 0x89, 0xA9, 0x35, + 0x23, 0x11, 0xAB, 0xD5, 0x0F, 0x02, 0xF7, 0x33, 0x71, 0x5E, + 0xD6, 0x87, 0x1F, 0x1A, 0x6B, 0x09, 0x04, 0x3D, 0x79, 0x11, + 0xAB, 0x45, 0x3A, 0xB5, 0xB4, 0x5A, 0x28, 0xD9, 0x4F, 0x70, + 0x46, 0x18, 0x28, 0x07, 0xF6, 0xE7, 0x2B, 0xA8, 0x25, 0x34, + 0x56, 0xA6, 0x02, 0x78, 0x88, 0x5E, 0x56, 0xBF, 0xD1, 0x5A, + 0xAC, 0x4E, 0xBF, 0x21, 0x4B, 0x5C, 0x3A, 0xCC, 0x98, 0xD5, + 0x43, 0x52, 0x08, 0x33, 0x47, 0xAE, 0x9B, 0xB0, 0x4D, 0xD2, + 0x6A, 0x6A, 0x09, 0x6C, 0xEB, 0xBF, 0xC6, 0x5C, 0xFE, 0x49, + 0xCC, 0xF4, 0x1E, 0x26, 0x15, 0xA5, 0x84, 0x85, 0x6D, 0x1E, + 0x69, 0x5C, 0x8B, 0xFC, 0x93, 0xDC, 0x5F, 0x51, 0x3C, 0x50, + 0x8C, 0xB8, 0x41, 0x84, 0x41, 0x46, 0x02, 0xBC, 0x93, 0xEF, + 0x12, 0x5D, 0xB0, 0x0B, 0x8A, 0x92, 0xCE, 0x55, 0x8F, 0x65, + 0x23, 0x89, 0x32, 0x59, 0xC3, 0xC8, 0xB7, 0xE5, 0x86, 0x0E, + 0xE6, 0xF6, 0x33, 0xF6, 0x95, 0xFD, 0xBE, 0x5E, 0x32, 0xBA, + 0xE9, 0xC7, 0xFF, 0xB0, 0xF7, 0xAC, 0x2D, 0x4D, 0xC1, 0xB6, + 0xE4, 0xE2, 0x63, 0xAE, 0xCB, 0xC4, 0x3A, 0xE0, 0xB6, 0xF1, + 0x42, 0x9C, 0x82, 0x8B, 0xBB, 0xBC, 0x2C, 0x1F, 0x6D, 0x8D, + 0x8A, 0x1C, 0x31, 0x82, 0xDF, 0xEC, 0x57, 0x40, 0xA6, 0x4F, + 0x2A, 0x58, 0xDD, 0x9C, 0x79, 0xBD, 0x9D, 0xFE, 0xDD, 0xF7, + 0x48, 0x2C, 0xA5, 0x19, 0xB0, 0x5D, 0x19, 0x95, 0x42, 0x2B, + 0x37, 0xF5, 0xF8, 0xCB, 0x78, 0x40, 0x64, 0xB1, 0x83, 0xB2, + 0xAC, 0xE4, 0xBB, 0xA5, 0xBD, 0x9F, 0xB7, 0x89, 0x13, 0x55, + 0xC1, 0x16, 0xAC, 0xCC, 0xCB, 0xAB, 0x77, 0x67, 0x60, 0xF7, + 0xE1, 0x78, 0xA7, 0xEB, 0x61, 0x65, 0x9D, 0x8C, 0x23, 0x9F, + 0x3F, 0xBE, 0x29, 0xFD, 0xBB, 0x4F, 0xDE, 0x56, 0x1D, 0x8C, + 0x4B, 0x9A, 0x3D, 0x2B, 0x7E, 0xA2, 0xB8, 0x8D, 0xBE, 0xF4, + 0x4B, 0xB2, 0x11, 0x3D, 0x36, 0x0B, 0x9F, 0x1B, 0xE4, 0xA3, + 0x2E, 0x9C, 0xB1, 0x30, 0x05, 0x10, 0x6E, 0x57, 0x8A, 0x07, + 0xEA, 0xE2, 0x69, 0x09, 0xF0, 0xD5, 0x96, 0x97, 0xAA, 0x51, + 0x3E, 0x43, 0xFB, 0xC2, 0x1A, 0x37, 0x4D, 0x02, 0x0B, 0x31, + 0xEC, 0x09, 0x44, 0x3A, 0x98, 0xC7, 0xC1, 0x72, 0x57, 0x80, + 0xD5, 0x1D, 0x8B, 0x53, 0x8B, 0xC9, 0x9A, 0x45, 0xFE, 0xB9, + 0x40, 0x6A, 0x39, 0xE8, 0x64, 0xFB, 0x29, 0x4B, 0x75, 0x65, + 0x9F, 0x71, 0xEE, 0xDC, 0x96, 0xB4, 0x65, 0x20, 0x1B, 0x0C, + 0x7C, 0xCB, 0xB8, 0x2D, 0xE4, 0xFB, 0x39, 0xB7, 0x24, 0xBE, + 0x24, 0xBC, 0xF2, 0x53, 0x76, 0x3B, 0x36, 0x44, 0x54, 0x46, + 0xA1, 0xD0, 0x53, 0x69, 0xB6, 0x65, 0xDD, 0xDF, 0xA4, 0xA6, + 0x3A, 0x97, 0xA5, 0xAE, 0x0D, 0xE5, 0xAF, 0x18, 0xA1, 0x99, + 0xAC, 0x10, 0x97, 0x0A, 0xAB, 0x7F, 0xD8, 0x97, 0x06, 0x86, + 0xA2, 0x1A, 0x8C, 0x7E, 0xAB, 0xE8, 0xAE, 0xFD, 0x36, 0xFF, + 0xC2, 0x68, 0x98, 0xC9, 0x0C, 0x20, 0x4C, 0x3F, 0x3B, 0x26, + 0x3A, 0x3B, 0xB9, 0xF9, 0x9A, 0x19, 0xDA, 0x78, 0x6C, 0xB1, + 0xBE, 0x8D, 0x6C, 0x06, 0xDC, 0x9E, 0xA0, 0x31, 0x39, 0xF3, + 0x60, 0x69, 0xC6, 0xC6, 0xE9, 0x15, 0xED, 0xFF, 0x6A, 0x13, + 0xCD, 0x17, 0x2B, 0x16, 0x4F, 0xF9, 0x0F, 0x06, 0xE9, 0xBD, + 0xDD, 0x0F, 0x58, 0x61, 0xE9, 0x53, 0xED, 0x35, 0xEE, 0x07, + 0x45, 0x21, 0x92, 0x8E, 0x76, 0xBA, 0x7C, 0x43, 0x6D, 0x1B, + 0xCD, 0x9D, 0xE1, 0x0E, 0x7E, 0xE3, 0xB0, 0xD6, 0xEB, 0x6F, + 0xC7, 0xD6, 0x77, 0x12, 0x26, 0x23, 0x15, 0xE5, 0xCB, 0x4B, + 0x04, 0xC5, 0x65, 0xD9, 0x88, 0x93, 0x78, 0x7F, 0xE1, 0x81, + 0x1F, 0xFC, 0x8A, 0xB6, 0x38, 0x06, 0x6B, 0x58, 0xEE, 0xE0, + 0x5E, 0x84, 0xCA, 0x5D, 0xE0, 0x41, 0xE5, 0x6E, 0x8D, 0x1C, + 0xB0, 0xA8, 0x68, 0x57, 0x3C, 0xD4, 0x42, 0xB6, 0xE4, 0x41, + 0x4C, 0x2C, 0x2A, 0x5E, 0x79, 0xB6, 0x63, 0xDB, 0xFB, 0x1B, + 0x27, 0x16, 0x25, 0x16, 0x32, 0x4D, 0x61, 0x01, 0xAB, 0x60, + 0x38, 0xA1, 0x63, 0x74, 0xE2, 0x96, 0xBF, 0x15, 0xF3, 0x19, + 0x8E, 0xDC, 0xF0, 0x19, 0x53, 0xAF, 0xCF, 0x1B, 0x9B, 0x31, + 0xAB, 0x47, 0x5C, 0xA0, 0x09, 0xFF, 0x47, 0x18, 0xDB, 0xCA, + 0x34, 0x82, 0x04, 0xF3, 0x41, 0x05, 0x6C, 0xB5, 0xD3, 0x09, + 0x0F, 0xCF, 0x4C, 0xA0, 0xBE, 0x41, 0x29, 0xBC, 0xA6, 0xAC, + 0xCC, 0xFB, 0x19, 0xBC, 0x2A, 0x04, 0x28, 0xEB, 0xD7, 0x8C, + 0xC6, 0x48, 0x1B, 0xBE, 0xF1, 0x83, 0x71, 0x81, 0xB4, 0xFB, + 0x35, 0xD1, 0x5B, 0x00, 0xE4, 0x3A, 0x37, 0xA0, 0xD2, 0xEE, + 0xA7, 0xF1, 0x7B, 0xB3, 0xF1, 0x91, 0x7C, 0xEB, 0xC0, 0xB0, + 0x12, 0xD6, 0x1D, 0x84, 0x27, 0x74, 0x9F, 0x4F, 0x32, 0x07, + 0xDE, 0x6C, 0xB1, 0x3E, 0xFF, 0x0A, 0x7F, 0x88, 0x48, 0xDD, + 0xFE, 0x73, 0x70, 0x24, 0xBF, 0x1A, 0x2E, 0x95, 0x47, 0xE8, + 0xFB, 0x5A, 0x4E, 0x12, 0x55, 0x4A, 0xD7, 0x65, 0x33, 0x4B, + 0x87, 0xB0, 0x8C, 0x0A, 0xCE, 0x61, 0x2A, 0x31, 0xC6, 0x14, + 0x11, 0xD0, 0x4A, 0xAC, 0x06, 0x61, 0xC0, 0x33, 0x2D, 0xA3, + 0x8C, 0x55, 0xBF, 0x94, 0x45, 0x82, 0xB2, 0x9E, 0x47, 0xB7, + 0x1D, 0x76, 0x14, 0xD5, 0xC6, 0x7C, 0xF8, 0x3B, 0x27, 0x1B, + 0x70, 0x3F, 0xCD, 0x61, 0xD4, 0xB1, 0x80, 0x6A, 0x35, 0x9D, + 0xC6, 0x37, 0x53, 0x7A, 0x5B, 0x07, 0x0D, 0x14, 0x85, 0xBB, + 0x67, 0xFA, 0x50, 0xDE, 0x8E, 0xA9, 0x27, 0x74, 0x0E, 0x19, + 0x2F, 0xC8, 0x04, 0x6C, 0xAF, 0x44, 0x8B, 0xE3, 0xEB, 0xD5, + 0x59, 0x7F, 0xA8, 0x0C, 0x35, 0xDD, 0x28, 0x4B, 0x24, 0x56, + 0x23, 0xA1, 0x18, 0xA9, 0xA1, 0xB6, 0xC4, 0x6D, 0xFE, 0x67, + 0xC0, 0x03, 0xDE, 0x51, 0x9E, 0xB2, 0xD8, 0x03, 0xE5, 0xAF, + 0xF0, 0x94, 0x64, 0x6A, 0xAC, 0xF7, 0xB8, 0x50, 0x01, 0x05, + 0x24, 0x89, 0x1C, 0xB5, 0x22, 0xC3, 0x94, 0xE9, 0x8A, 0x07, + 0xA9, 0x2D, 0x40, 0x8D, 0x58, 0x70, 0x11, 0x5C, 0x1C, 0xBB, + 0x83, 0xC8, 0xE1, 0xC0, 0x61, 0x9C, 0xA5, 0xCC, 0x5A, 0x55, + 0x07, 0x7F, 0x2A, 0xCF, 0x26, 0x63, 0xF8, 0x49, 0x92, 0x60, + 0x6A, 0xA6, 0x70, 0xB4, 0x2A, 0x26, 0xB0, 0xE4, 0x64, 0x48, + 0xA7, 0xD3, 0xCD, 0xD2, 0xB6, 0xB9, 0x10, 0x9C, 0x50, 0x43, + 0xD4, 0x78, 0xAC, 0xB1, 0xB8, 0xE0, 0xD2, 0xEB, 0xB7, 0x0C, + 0xEE, 0x3C, 0x97, 0xB9, 0x14, 0xDD, 0xDA, 0xF4, 0x26, 0x19, + 0x39, 0x5E, 0xB2, 0xF6, 0x1E, 0x38, 0x54, 0xA7, 0x46, 0xA9, + 0xAD, 0x88, 0xF5, 0xB3, 0xB9, 0x27, 0x24, 0x25, 0x91, 0x68, + 0x2F, 0xB6, 0x92, 0x59, 0xCF, 0x09, 0xF4, 0x20, 0xD5, 0xA0, + 0x9E, 0xA7, 0x07, 0x67, 0x96, 0xCE, 0x9F, 0xA2, 0xAA, 0x8C, + 0x40, 0xD3, 0x69, 0x0A, 0x6D, 0x3F, 0x22, 0x85, 0x70, 0x8C, + 0x4E, 0x58, 0x9B, 0xD7, 0x8C, 0xFA, 0x16, 0xCF, 0x83, 0x52, + 0x1B, 0xD1, 0x90, 0xE1, 0xEF, 0x69, 0x74, 0xD7, 0x72, 0xCA, + 0x00, 0xA3, 0xC9, 0xC3, 0x85, 0x6D, 0x0A, 0x98, 0xDA, 0xE3, + 0x9D, 0x2C, 0x1D, 0x1A, 0xD8, 0x3A, 0xED, 0xD5, 0xDE, 0x83, + 0x1B, 0x57, 0x08, 0x8B, 0x69, 0x7B, 0x1A, 0x02, 0xEA, 0xAC, + 0xF1, 0xA2, 0xAD, 0x69, 0xA5, 0x79, 0x50, 0x01, 0xD5, 0xEF, + 0xE5, 0x08, 0x64, 0x9D, 0xBD, 0x8C, 0xDF, 0x97, 0xE4, 0x1F, + 0x90, 0xB1, 0xB2, 0x25, 0x8F, 0x61, 0x73, 0xB6, 0x52, 0x4B, + 0xFA, 0xD2, 0x37, 0xDD, 0x65, 0xB0, 0x26, 0x32, 0x23, 0x4D, + 0x27, 0x26, 0x54, 0x50, 0x40, 0x20, 0xAB, 0xF3, 0xA3, 0xC7, + 0xAD, 0xE7, 0xA6, 0x3B, 0x6D, 0x22, 0x08, 0xCC, 0xD7, 0x42, + 0x26, 0x04, 0x58, 0x8A, 0x42, 0x0A, 0x3E, 0x02, 0x89, 0x3A, + 0x89, 0x56, 0x79, 0xAA, 0x3B, 0x1F, 0x41, 0xAC, 0xB9, 0xFB, + 0x15, 0xC9, 0x1D, 0x3C, 0x99, 0xAF, 0x8C, 0x06, 0xDA, 0x3A, + 0xEF, 0xF7, 0x32, 0xFD, 0x36, 0x93, 0xEE, 0x0C, 0xE0, 0x21, + 0xA5, 0x70, 0xA2, 0xD1, 0x48, 0x52, 0x01, 0x9F, 0xEF, 0x88, + 0x09, 0xC8, 0xB0, 0x5D, 0xDF, 0xD4, 0x10, 0x9A, 0x91, 0xC0, + 0x82, 0xAA, 0xF4, 0x95, 0x8B, 0xD7, 0x0C, 0x3A, 0xE3, 0x6E, + 0xD0, 0x71, 0xED, 0xA0, 0xC3, 0x99, 0xB0, 0x70, 0x8E, 0x3D, + 0x29, 0xD0, 0x7F, 0x74, 0x82, 0x21, 0x52, 0xE6, 0x83, 0x99, + 0xA9, 0xDA, 0xB6, 0x88, 0x7D, 0x6C, 0x42, 0xF6, 0x56, 0x11, + 0xF2, 0x62, 0x72, 0x99, 0xA8, 0x6D, 0x81, 0x62, 0xA7, 0x16, + 0x96, 0xC0, 0x27, 0x6E, 0x82, 0x99, 0x10, 0x7B, 0xA4, 0x74, + 0x38, 0x28, 0x03, 0x90, 0xD4, 0xC1, 0x05, 0xF3, 0x3D, 0x41, + 0x88, 0x11, 0x5B, 0x5C, 0xF1, 0xF5, 0x09, 0xC3, 0x8B, 0x28, + 0x91, 0x91, 0x3B, 0x97, 0xC2, 0x1A, 0x16, 0xD3, 0xA1, 0x57, + 0xBC, 0x06, 0xE1, 0x9D, 0x5D, 0xC9, 0xDE, 0xD9, 0x24, 0xE1, + 0x3D, 0x8A, 0xC9, 0x8F, 0x73, 0xF2, 0xBC, 0x7C, 0x6E, 0x39, + 0x1B, 0xE0, 0x7F, 0x62, 0xDF, 0xEE, 0xF1, 0xBD, 0x43, 0xA8, + 0x83, 0xF7, 0x9A, 0x02, 0x78, 0xCB, 0x1F, 0x11, 0xFB, 0x44, + 0x08, 0x2D, 0x83, 0x5E, 0x0C, 0x73, 0x80, 0xC5, 0xD7, 0x7E, + 0x17, 0x64, 0x75, 0x1A, 0xFD, 0x6D, 0xC1, 0x1B, 0x9A, 0xC5, + 0x1E, 0xA1, 0xD6, 0xBA, 0x6A, 0x9A, 0x8E, 0x57, 0xF7, 0x81, + 0x1F, 0xAD, 0x4E, 0x42, 0x5E, 0x84, 0x35, 0x3A, 0xD2, 0x27, + 0x92, 0xD8, 0x7C, 0x3C, 0xA5, 0x79, 0x97, 0x76, 0x20, 0x7E, + 0xF4, 0xCA, 0x8B, 0xC1, 0xF1, 0xBF, 0xCD, 0x31, 0x02, 0x65, + 0x8D, 0xA2, 0x7B, 0x1C, 0x33, 0x50, 0x91, 0x41, 0x19, 0xD8, + 0xF4, 0x85, 0x0E, 0x7F, 0x7D, 0x7A, 0xD2, 0x40, 0x19, 0x40, + 0xBA, 0xAB, 0x35, 0x37, 0x56, 0x47, 0xC4, 0xD5, 0x64, 0xE8, + 0xA5, 0x01, 0x6E, 0x99, 0x42, 0xD8, 0x26, 0x99, 0xF5, 0x32, + 0xD5, 0x98, 0x2B, 0x9B, 0x94, 0xA2, 0x43, 0x3A, 0xFE, 0xE8, + 0x27, 0xB9, 0xB8, 0x32, 0x55, 0x6A, 0x0F, 0x1F, 0x68, 0xED, + 0x5D, 0x6A, 0x0C, 0x22, 0x5D, 0xD3, 0xEC, 0x6E, 0xFC, 0x92, + 0x45, 0xA0, 0x97, 0x8C, 0xD0, 0x15, 0x74, 0x96, 0x8F, 0xBB, + 0x4C, 0x47, 0xE8, 0x0E, 0xC8, 0xA1, 0x40, 0x83, 0xE9, 0xE0, + 0x1D, 0x9B, 0x0D, 0x40, 0x7C, 0xEC, 0x20, 0x1E, 0xF0, 0xE2, + 0xFC, 0xA5, 0x47, 0x80, 0x4B, 0xA6, 0xE0, 0x14, 0x2F, 0x36, + 0x98, 0xC6, 0xD0, 0x20, 0x42, 0x09, 0x00, 0x40, 0xF7, 0x8F, + 0x1E, 0x6D, 0x50, 0x1F, 0x9C, 0xBB, 0x9E, 0x85, 0xE6, 0x31, + 0x1E, 0xD3, 0x66, 0x19, 0x34, 0x19, 0xC7, 0x3D, 0x01, 0x0D, + 0xDB, 0x12, 0x07, 0x68, 0xC6, 0x49, 0x99, 0x46, 0x9E, 0xD7, + 0x77, 0x83, 0x78, 0x11, 0xE0, 0xE9, 0x47, 0xB6, 0xBA, 0x51, + 0x65, 0x66, 0xDB, 0x83, 0x84, 0x82, 0x91, 0xC2, 0x09, 0x42, + 0xC2, 0x95, 0x45, 0xA3, 0x19, 0xBE, 0xED, 0x75, 0xE5, 0xA8, + 0xE7, 0xB0, 0x3B, 0x1A, 0xD3, 0xA5, 0x6D, 0x5A, 0x87, 0x17, + 0x6F, 0x5B, 0xBA, 0xC5, 0x91, 0xB5, 0xB9, 0xAB, 0x17, 0xEE, + 0xFD, 0xE6, 0xF3, 0x9F, 0xBF, 0x60, 0xB4, 0xC4, 0x9A, 0x04, + 0xE5, 0x02, 0x63, 0x6E, 0x10, 0x73, 0xCD, 0xB3, 0x15, 0x5D, + 0x39, 0x54, 0x5E, 0xEC, 0x2D, 0xDC, 0x3D, 0x00, 0xCD, 0x87, + 0x9A, 0xB4, 0xBF, 0x49, 0xAB, 0xE7, 0xAC, 0xAD, 0xBA, 0xC3, + 0x4F, 0x60, 0xAF, 0xC7, 0x87, 0xD1, 0x98, 0x93, 0x86, 0x3D, + 0xBE, 0x6F, 0x2E, 0x12, 0x8D, 0x3A, 0x53, 0x80, 0xB4, 0xA6, + 0x3C, 0x39, 0xEB, 0xE3, 0x64, 0x33, 0xBE, 0x71, 0xED, 0xD2, + 0xE7, 0x79, 0x26, 0x05, 0x85, 0x41, 0xE7, 0x65, 0xAB, 0x9B, + 0x21, 0x49, 0xD6, 0x63, 0x4F, 0x4F, 0xBF, 0x10, 0x36, 0x13, + 0xE4, 0xA5, 0xD3, 0xCE, 0xDB, 0x73, 0x32, 0xA3, 0x6D, 0xC3, + 0x72, 0x7E, 0xB8, 0xAB, 0x83, 0x07, 0xEB, 0x7B, 0x76, 0x27, + 0x16, 0x65, 0x23, 0x6A, 0x75, 0x14, 0x42, 0x95, 0xC1, 0x96, + 0xD6, 0x3E, 0x4A, 0xA8, 0x08, 0x04, 0xF6, 0xBA, 0xE4, 0xAA, + 0x0F, 0x26, 0x05, 0x6C, 0x0B, 0x38, 0x38, 0xA0, 0x87, 0x94, + 0xAB, 0x9D, 0x86, 0xD1, 0xC3, 0x36, 0x9E, 0x72, 0x18, 0xE4, + 0x04, 0xE9, 0xD2, 0x73, 0x3E, 0x2C, 0xA0, 0x0E, 0x47, 0x44, + 0xD7, 0xC1, 0xED, 0x6D, 0x47, 0xE3, 0x57, 0x3B, 0x51, 0xAF, + 0x30, 0x89, 0x9E, 0x1F, 0x6F, 0x11, 0xA8, 0x0F, 0x54, 0x9A, + 0x64, 0x00, 0xEB, 0x60, 0x0E, 0xB8, 0x83, 0x00, 0x31, 0x16, + 0x73, 0x5A, 0xBB, 0x8C, 0x81, 0xD3, 0x26, 0x6B, 0x96, 0xDB, + 0xC2, 0x58, 0x2E, 0x8C, 0x54, 0x12, 0xA8, 0x44, 0x42, 0x12, + 0x95, 0x3E, 0x39, 0x64, 0x47, 0xB1, 0xDC, 0xF0, 0x8D, 0xCA, + 0x4F, 0xD9, 0xE5, 0xE9, 0x1A, 0x8A, 0xBF, 0xAF, 0x2B, 0x09, + 0x3D, 0x1C, 0xD9, 0x9B, 0x64, 0x44, 0x8E, 0xC0, 0x70, 0x04, + 0x35, 0x52, 0x1C, 0x8B, 0x4E, 0x6C, 0x05, 0xA9, 0xA3, 0xA7, + 0x42, 0xEB, 0xA2, 0x39, 0xB7, 0xAB, 0xD8, 0x93, 0xE9, 0xA6, + 0x50, 0x3E, 0x0A, 0xA5, 0x89, 0x17, 0x5B, 0x93, 0x91, 0x3B, + 0x25, 0x20, 0xFF, 0x94, 0xC4, 0xC2, 0x4F, 0x8A, 0x29, 0xF9, + 0xA2, 0xAD, 0x17, 0x9E, 0x61, 0xB2, 0xB5, 0x6A, 0x55, 0x12, + 0x02, 0x50, 0xB7, 0x82, 0xAB, 0xC7, 0x9C, 0xEA, 0xC5, 0x71, + 0x85, 0xE7, 0x16, 0x1F, 0xD8, 0x4B, 0xEF, 0x02, 0x9D, 0x2C, + 0xB8, 0x06, 0xF5, 0x52, 0x09, 0xAC, 0x61, 0x14, 0xC1, 0xF0, + 0xA0, 0xD4, 0x42, 0xBE, 0xAE, 0x6B, 0x57, 0x17, 0x15, 0x96, + 0xC0, 0x4C, 0x03, 0x56, 0x93, 0x6E, 0xEE, 0x41, 0xF0, 0xC7, + 0x6B, 0x1A, 0xA4, 0x6D, 0x50, 0x8B, 0x4F, 0xEB, 0xE2, 0xBF, + 0x3B, 0xBD, 0xA4, 0xC5, 0x7E, 0x9A, 0x5D, 0x6B, 0x37, 0x1C, + 0xDA, 0xFD, 0x70, 0x75, 0xBA, 0xB6, 0xA2, 0x71, 0x8F, 0x7B, + 0x5E, 0xF4, 0x68, 0x67, 0x95, 0x94, 0x67, 0x6E, 0x7E, 0x66, + 0x34, 0x6E, 0x57, 0x6C, 0x02, 0x67, 0x05, 0x41, 0xB6, 0xA7, + 0xE2, 0x78, 0xA5, 0x3C, 0xE1, 0x74, 0x6C, 0x20, 0x82, 0xC6, + 0xD1, 0x0B, 0x50, 0x36, 0x1D, 0x4A, 0xBD, 0x01, 0x41, 0x81, + 0xDB, 0x87, 0xB9, 0xDC, 0x1E, 0xDE, 0x14, 0x0B, 0x1E, 0x5C, + 0x72, 0xEB, 0x0E, 0x7E, 0x8C, 0xB6, 0xA3, 0x74, 0xA7, 0x00, + 0xE1, 0x7F, 0x6E, 0x3A, 0x68, 0x02, 0x6C, 0x65, 0x66, 0x78, + 0x9D, 0x63, 0xEB, 0xF0, 0xE3, 0x55, 0x9F, 0xEA, 0x24, 0xBA, + 0x34, 0x98, 0x56, 0x6B, 0xA8, 0x1E, 0xFA, 0x83, 0xC1, 0x62, + 0x4F, 0x78, 0xE0, 0x36, 0xA1, 0x61, 0x8C, 0xC6, 0xF6, 0xC3, + 0xE1, 0xEB, 0x93, 0xC1, 0x4D, 0x81, 0xB9, 0xF0, 0xE9, 0x2C, + 0x8C, 0x07, 0x47, 0xBC, 0xC5, 0x81, 0x5C, 0xD2, 0x1B, 0x24, + 0xFD, 0x10, 0x7D, 0xA6, 0xDF, 0x0D, 0x3F, 0x43, 0xB8, 0x1D, + 0x86, 0xFD, 0x5A, 0x79, 0x1D, 0xFA, 0xD7, 0x51, 0xBE, 0xA6, + 0x55, 0xAC, 0x32, 0xB0, 0xF7, 0x08, 0x22, 0x8B, 0x88, 0x8B, + 0xA8, 0xC3, 0xA0, 0xDE, 0xAB, 0xC5, 0x47, 0x84, 0x0D, 0xAB, + 0x86, 0xBB, 0x9D, 0x59, 0x07, 0x30, 0x61, 0xEA, 0x59, 0xDC, + 0x85, 0x9D, 0x81, 0xAF, 0x40, 0x8E, 0x60, 0xD3, 0x0D, 0x95, + 0x8A, 0xA3, 0xD1, 0x15, 0x02, 0x59, 0x61, 0x05, 0xA7, 0xE3, + 0x10, 0x3B, 0xDD, 0x7C, 0x9D, 0x8C, 0x76, 0x3A, 0x9F, 0x24, + 0xE5, 0x07, 0x5B, 0x3B, 0xCB, 0xAF, 0x81, 0x02, 0x44, 0x62, + 0x02, 0x3C, 0x90, 0x44, 0x20, 0xAD, 0x57, 0x80, 0x0A, 0xD8, + 0x44, 0x9A, 0x9F, 0xEA, 0x0D, 0x72, 0x81, 0xD5, 0x58, 0x36, + 0x2D, 0xCE, 0x3E, 0xB1, 0x65, 0x2B, 0xCC, 0x2C, 0x2B, 0x72, + 0x7E, 0x0E, 0xC5, 0xE8, 0x05, 0x6D, 0x6C, 0x85, 0x59, 0xB7, + 0x84, 0xE3, 0x75, 0x26, 0x19, 0xB4, 0x62, 0x1B, 0x4E, 0x2A, + 0x58, 0xD1, 0xB3, 0x49, 0xDC, 0xC5, 0xC9, 0xE6, 0xBB, 0x8E, + 0x21, 0x87, 0x95, 0xCF, 0x30, 0x06, 0x66, 0xA9, 0x29, 0xCC, + 0x37, 0x07, 0xDF, 0xB7, 0x5C, 0x40, 0xAC, 0x93, 0x29, 0x12, + 0x45, 0x30, 0xF9, 0x33, 0x4D, 0x7E, 0x55, 0x3F, 0x0F, 0x75, + 0x31, 0x9B, 0x81, 0xC5, 0x26, 0x87, 0x38, 0xB3, 0x3B, 0xB9, + 0xAD, 0xA5, 0x45, 0x74, 0x1D, 0x00, 0x0F, 0x26, 0x40, 0x2C, + 0xB5, 0xF2, 0x34, 0xC1, 0x3B, 0x3E, 0x24, 0x30, 0xCA, 0x4B, + 0xB3, 0x86, 0xD5, 0x15, 0x58, 0x82, 0x42, 0xD4, 0x62, 0xF1, + 0xE3, 0x34, 0xB8, 0xB2, 0x2B, 0x21, 0x9F, 0x96, 0x26, 0x0D, + 0x20, 0xF1, 0x6D, 0x61, 0xBB, 0xD3, 0x07, 0x1F, 0x09, 0xF6, + 0xBD, 0x2D, 0x9E, 0x89, 0xF1, 0xD1, 0x11, 0x88, 0x32, 0x10, + 0xD6, 0xB6, 0x1F, 0xC8, 0x14, 0x86, 0xE6, 0xC6, 0x0C, 0x9B, + 0x02, 0x36, 0x1F, 0xAD, 0xA1, 0x66, 0x62, 0x88, 0x58, 0x59, + 0xAF, 0x86, 0x0E, 0xA5, 0x9F, 0xAF, 0x6E, 0x57, 0xD6, 0xAA, + 0xB5, 0xD5, 0xC5, 0x20, 0x1B, 0x8C, 0x55, 0xEB, 0x69, 0x9E, + 0x24, 0x22, 0x98, 0x66, 0x66, 0x16, 0x29, 0x95, 0x4D, 0xAB, + 0x30, 0xFB, 0xD9, 0x73, 0x64, 0xA0, 0xF7, 0x05, 0xD9, 0x4C, + 0x4E, 0x0A, 0xE6, 0x14, 0xC3, 0xE0, 0x50, 0x1F, 0x12, 0xB5, + 0xF7, 0x81, 0xC3, 0xFB, 0xDC, 0x1A, 0x45, 0x99, 0xFD, 0xBF, + 0x9F, 0x20, 0x8C, 0x60, 0x90, 0x57, 0xE2, 0x12, 0xE0, 0xA6, + 0xDE, 0x0E, 0xB2, 0xF5, 0x8F, 0x15, 0x64, 0x72, 0xC0, 0xCC, + 0x6D, 0x2B, 0xD9, 0xDE, 0xC0, 0xE6, 0xFD, 0x53, 0x94, 0x7D, + 0x47, 0x26, 0x08, 0x82, 0x2D, 0xE3, 0x49, 0x0B, 0x70, 0x46, + 0x15, 0x63, 0xD0, 0x54, 0x2B, 0x15, 0xF4, 0x6B, 0x67, 0x28, + 0x0A, 0xC9, 0xCE, 0xAE, 0x4C, 0x53, 0x67, 0x4F, 0x6E, 0x3B, + 0xD5, 0xC8, 0xCA, 0xB9, 0xFC, 0xEC, 0x11, 0x2E, 0x56, 0xBD, + 0xEB, 0x22, 0x2B, 0xD3, 0xA7, 0xD1, 0x16, 0xF4, 0xF9, 0xD9, + 0xAD, 0x83, 0xC6, 0x24, 0x9F, 0x3D, 0x6E, 0xBA, 0x1E, 0x4F, + 0x4E, 0x18, 0xDB, 0xB8, 0xFB, 0x3D, 0x71, 0x4B, 0xDE, 0x3F, + 0x28, 0x71, 0x97, 0xD7, 0x6C, 0x78, 0x48, 0x0C, 0x6A, 0xEC, + 0xF0, 0x26, 0xFC, 0x87, 0xCC, 0xE9, 0x0D, 0xFA, 0xDE, 0xEB, + 0x64, 0x34, 0xFA, 0x7D, 0x6F, 0xE2, 0x7D, 0xE2, 0x32, 0xEF, + 0xAC, 0xCE, 0x86, 0xB7, 0x1C, 0x31, 0x13, 0xF2, 0x15, 0x0C, + 0x99, 0x6C, 0x6B, 0x9E, 0x18, 0x14, 0x63, 0x63, 0xDC, 0x62, + 0xB1, 0x3F, 0xBC, 0x86, 0xB8, 0x47, 0x89, 0x8F, 0xFA, 0xE4, + 0xF5, 0x7B, 0x7B, 0xBE, 0x37, 0xA2, 0xF3, 0xC5, 0x40, 0x5A, + 0x4C, 0x84, 0x72, 0xC4, 0xC4, 0x11, 0x82, 0xDF, 0x2F, 0x05, + 0xF7, 0x0C, 0xC4, 0x66, 0x90, 0xB4, 0x11, 0xE0, 0xA4, 0x08, + 0x43, 0x99, 0x2A, 0x51, 0xCE, 0xA7, 0xAD, 0x00, 0x30, 0x1A, + 0x69, 0x89, 0x2B, 0xA8, 0x22, 0xD4, 0xD1, 0xF0, 0x06, 0xAB, + 0x3E, 0x2E, 0x00, 0xE6, 0x65, 0xC2, 0x25, 0x66, 0xCD, 0x95, + 0xFB, 0x34, 0x2E, 0xC7, 0x64, 0xFB, 0x3C, 0x9D, 0x42, 0x74, + 0xBF, 0xE9, 0xE5, 0xC9, 0x68, 0x67, 0xF3, 0x2E, 0x4B, 0x3E, + 0x6E, 0x0C, 0x24, 0x0F, 0xCA, 0x80, 0x0D, 0x15, 0xF9, 0x66, + 0x42, 0x3B, 0x2A, 0x82, 0xB3, 0xA6, 0x09, 0x1B, 0xCD, 0x32, + 0x74, 0xC1, 0x37, 0xB4, 0x78, 0x93, 0x62, 0x4A, 0xF7, 0x12, + 0x85, 0xDA, 0xA0, 0x49, 0x26, 0x12, 0xD4, 0xEC, 0xDF, 0x4B, + 0x20, 0xB0, 0xB6, 0x99, 0x8B, 0x1C, 0x9C, 0x4D, 0x71, 0xA4, + 0xAB, 0xAE, 0xE6, 0x07, 0xE9, 0x64, 0x60, 0x9C, 0x03, 0x14, + 0x8E, 0x97, 0xFB, 0x60, 0x94, 0x69, 0x4E, 0xB2, 0x8F, 0x0B, + 0xC7, 0x63, 0xD4, 0xB1, 0x1B, 0x59, 0xC3, 0x5A, 0xB7, 0xD3, + 0x39, 0x0B, 0xE5, 0x52, 0xA1, 0x71, 0x0E, 0xAD, 0x41, 0xF9, + 0x3F, 0xDD, 0x10, 0xF2, 0x47, 0x1E, 0xC0, 0x9F, 0x27, 0x19, + 0x87, 0x85, 0x4C, 0xD5, 0x4A, 0xDF, 0x70, 0x9B, 0x13, 0x10, + 0xE7, 0x6E, 0x06, 0x01, 0xF1, 0xF4, 0x13, 0xB1, 0x37, 0x87, + 0xD5, 0x2B, 0x8D, 0x6C, 0x23, 0xB4, 0x7A, 0x44, 0xF7, 0xE4, + 0xF5, 0xAD, 0xF6, 0x0C, 0x8C, 0x98, 0xFD, 0xB7, 0x55, 0x34, + 0xA4, 0x83, 0x30, 0x25, 0xFD, 0xD4, 0x9B, 0x31, 0x75, 0x7F, + 0xB6, 0x92, 0x54, 0x90, 0xA4, 0xC0, 0x66, 0x45, 0xD5, 0x54, + 0x8C, 0xA5, 0xC7, 0x7A, 0x48, 0x8A, 0x43, 0x6B, 0x93, 0x14, + 0x1D, 0xC4, 0x77, 0x52, 0xCC, 0x61, 0xD3, 0xC7, 0xDE, 0x18, + 0x8A, 0x08, 0x02, 0x3B, 0xAA, 0xD6, 0xBD, 0xB9, 0xD6, 0x4A, + 0xEC, 0x77, 0x2B, 0x2E, 0x68, 0x46, 0x3A, 0xF5, 0x14, 0x75, + 0x05, 0x8B, 0xFD, 0x45, 0xF9, 0xDF, 0x5A, 0x69, 0x03, 0x7F, + 0x99, 0x82, 0x2F, 0x38, 0xB0, 0xC9, 0x30, 0x50, 0x18, 0x10, + 0x80, 0x16, 0x9D, 0xF8, 0x46, 0xE6, 0x5D, 0xD4, 0xA3, 0xFC, + 0xEA, 0x5D, 0xF0, 0x52, 0x49, 0xE4, 0x14, 0x23, 0x58, 0x45, + 0xB0, 0xE1, 0x8E, 0xE1, 0x2B, 0x98, 0x94, 0x54, 0x2E, 0xF5, + 0xC6, 0x27, 0x0E, 0x1B, 0x81, 0x70, 0xF5, 0x92, 0x98, 0x1E, + 0xB3, 0x6E, 0x21, 0x7A, 0xF6, 0xCA, 0x0D, 0x7D, 0xFA, 0xF8, + 0x8A, 0xCB, 0xA0, 0x4A, 0xFC, 0xED, 0xCC, 0xD1, 0x1C, 0x8C, + 0xC4, 0xC8, 0x4F, 0x1D, 0x06, 0x3C, 0x57, 0x77, 0xD7, 0x2F, + 0x2A, 0xA0, 0x95, 0x3E, 0x0C, 0x4A, 0xEE, 0x2F, 0xAA, 0xF3, + 0xCB, 0xE1, 0xEE, 0x54, 0x25, 0x99, 0x9F, 0xF1, 0x3E, 0xBB, + 0x9A, 0x61, 0x34, 0x46, 0xA9, 0x3B, 0x99, 0x1E, 0xAE, 0x5F, + 0x20, 0xBA, 0x7B, 0xB5, 0x53, 0xE1, 0xCC, 0x6A, 0x33, 0xF1, + 0xF9, 0xB4, 0x96, 0x20, 0x9B, 0xB8, 0xFB, 0x83, 0xBF, 0x86, + 0x6B, 0xB7, 0x7C, 0x55, 0x5F, 0x51, 0x15, 0xFE, 0x57, 0x05, + 0xAF, 0xC2, 0x8E, 0xBC, 0xB2, 0x15, 0x51, 0x95, 0x21, 0x38, + 0xB5, 0x3B, 0x9D, 0x7A, 0xEC, 0x08, 0x7A, 0x18, 0x1E, 0x80, + 0xBB, 0x0B, 0x6E, 0x0C, 0x1B, 0x23, 0x42, 0x0E, 0x66, 0xA1, + 0x0F, 0xBE, 0xF8, 0x78, 0x8C, 0xAD, 0xA7, 0xA0, 0xB9, 0x46, + 0xE6, 0x5E, 0x2A, 0x8B, 0xA0, 0x90, 0x0E, 0x45, 0x6E, 0x6C, + 0x7D, 0x9B, 0x47, 0xD4, 0x1B, 0x47, 0x2B, 0x26, 0x62, 0x6F, + 0xB2, 0xCE, 0xC5, 0x73, 0xD6, 0xF7, 0xF5, 0xEA, 0x0B, 0xF7, + 0xBA, 0xE1, 0x77, 0x01, 0x31, 0x68, 0x58, 0xDF, 0x4B, 0x04, + 0x66, 0x6B, 0x7F, 0x30, 0x60, 0xBE, 0x40, 0x3C, 0xF7, 0xE4, + 0x2D, 0xFB, 0x52, 0xC6, 0x86, 0xB1, 0xB6, 0xF8, 0x51, 0x26, + 0x87, 0xBD, 0x54, 0x6D, 0xC1, 0x79, 0xF8, 0x2C, 0xC1, 0x43, + 0x62, 0x04, 0x43, 0xFA, 0xC0, 0xD0, 0xDF, 0xCA, 0x29, 0xB6, + 0xF8, 0xFC, 0xBD, 0x54, 0x63, 0x53, 0xD2, 0xBC, 0x30, 0x2A, + 0xBB, 0x67, 0x6B, 0xA9, 0x01, 0x73, 0x1F, 0x29, 0x68, 0x91, + 0xBD, 0xF1, 0xEB, 0xFB, 0x4E, 0xD0, 0xCD, 0xD3, 0x90, 0xA5, + 0x1B, 0x80, 0xD6, 0xE9, 0x71, 0x68, 0x99, 0x28, 0xB5, 0x0E, + 0x00, 0x62, 0x86, 0xF9, 0xE3, 0x11, 0xB5, 0x02, 0x93, 0x0A, + 0x1E, 0x9A, 0x33, 0x1D, 0x65, 0x59, 0x37, 0xD7, 0x4A, 0x4C, + 0xC4, 0xF8, 0xC1, 0x6B, 0xE0, 0x11, 0x78, 0x43, 0x43, 0x0D, + 0x0E, 0x90, 0x0D, 0x0D, 0x6E, 0x83, 0xBB, 0x56, 0xEE, 0xF8, + 0xDA, 0x1A, 0xB0, 0x52, 0xF2, 0xDF, 0x8C, 0xB7, 0xFD, 0xBA, + 0x90, 0xE1, 0x06, 0xDF, 0x93, 0x40, 0x00, 0x81, 0x0B, 0xAA, + 0x3B, 0x7C, 0x27, 0xAA, 0x81, 0x95, 0x4A, 0x7E, 0x44, 0x31, + 0x89, 0xF8, 0x2F, 0xF8, 0xA5, 0x27, 0x3D, 0xB2, 0x69, 0xB5, + 0xEC, 0xFD, 0x4F, 0xD6, 0x47, 0x9C, 0xBA, 0xD6, 0x67, 0x78, + 0x8A, 0x38, 0xD6, 0xAA, 0x63, 0x89, 0x58, 0xD7, 0x77, 0x5F, + 0xCE, 0xF7, 0x72, 0xE9, 0x9A, 0xAE, 0x6A, 0x73, 0x2F, 0x4E, + 0xCE, 0x81, 0xB5, 0x57, 0x2B, 0x39, 0x6E, 0x71, 0x9D, 0x8F, + 0x6B, 0x91, 0xF8, 0xE5, 0x31, 0xA9, 0xF5, 0x62, 0xAC, 0xF2, + 0x73, 0x73, 0xB4, 0xDF, 0xC3, 0x21, 0xE7, 0xAD, 0x74, 0x69, + 0x0F, 0x08, 0xCB, 0x83, 0x42, 0x9C, 0x86, 0xA3, 0xF1, 0x2F, + 0x80, 0xD3, 0xBE, 0x2B, 0xF3, 0x81, 0xB7, 0xE9, 0x0B, 0x8A, + 0x14, 0x1E, 0x55, 0x60, 0xC6, 0x36, 0x99, 0xCA, 0xB2, 0xAB, + 0xD9, 0xC2, 0x7C, 0x42, 0x01, 0xF5, 0x67, 0x71, 0x94, 0x51, + 0xD4, 0xAD, 0x3C, 0xAE, 0x4D, 0x0C, 0xB5, 0xA1, 0x03, 0xA0, + 0xD4, 0x41, 0xCF, 0x12, 0x5E, 0xA6, 0x1C, 0xCC, 0xFE, 0xD1, + 0x78, 0x28, 0xEC, 0xC2, 0x30, 0x01, 0x40, 0x21, 0xFD, 0x0C, + 0x17, 0xCE, 0xEB, 0x77, 0x41, 0xCD, 0xE7, 0xCC, 0x5E, 0x62, + 0x7C, 0x26, 0x1D, 0x08, 0x11, 0x29, 0xA8, 0x78, 0xF9, 0xE3, + 0xF3, 0x53, 0xDC, 0x79, 0xF3, 0x42, 0x8D, 0x9D, 0xEF, 0xC6, + 0x65, 0x94, 0x99, 0xCF, 0xD2, 0x3B, 0xC5, 0xFD, 0x05, 0xE2, + 0x47, 0x65, 0x17, 0xD0, 0xC7, 0xA0, 0xE0, 0xCA, 0xCF, 0x72, + 0x1E, 0xAD, 0x2E, 0x36, 0x6F, 0x29, 0x16, 0xE4, 0x2B, 0x71, + 0x46, 0xCC, 0x56, 0x74, 0x18, 0x5F, 0x34, 0xDF, 0x4C, 0xF0, + 0x77, 0x70, 0x38, 0xC9, 0xAB, 0xBD, 0x15, 0x53, 0x65, 0x88, + 0xE4, 0x26, 0xAA, 0x16, 0xA9, 0x0B, 0x36, 0x68, 0x48, 0x1E, + 0xE2, 0x55, 0xBA, 0x66, 0x9C, 0x7E, 0x71, 0x7E, 0x19, 0x6D, + 0x06, 0x8E, 0x49, 0xFA, 0x97, 0x10, 0xCE, 0xE4, 0x1A, 0x66, + 0x16, 0x98, 0xFF, 0x15, 0xB2, 0x5A, 0x9D, 0xB9, 0xE7, 0xAB, + 0xF3, 0x10, 0xCA, 0xA0, 0xB4, 0x99, 0x7F, 0x28, 0x94, 0x8A, + 0xD4, 0x8C, 0xE7, 0xCD, 0xBE, 0x9F, 0x0C, 0xFB, 0xF5, 0xDD, + 0x17, 0xD6, 0xC9, 0x05, 0xEF, 0xAB, 0x55, 0x9E, 0xC3, 0x5E, + 0x6D, 0x51, 0xCB, 0x1F, 0x45, 0x5E, 0x3E, 0x04, 0xBF, 0xBB, + 0xD1, 0x6B, 0x14, 0xAE, 0xF4, 0xCE, 0x17, 0xCC, 0xA6, 0xB8, + 0xFC, 0xE9, 0xE8, 0x9D, 0x04, 0xC4, 0x09, 0x3A, 0xDC, 0xB7, + 0x7F, 0xDA, 0xD7, 0x75, 0x34, 0x68, 0x42, 0xBE, 0x64, 0x43, + 0x66, 0x00, 0x34, 0x57, 0xF9, 0x93, 0xB0, 0x84, 0x52, 0xC9, + 0x6E, 0xF3, 0x1C, 0xBA, 0x2E, 0x3A, 0x0B, 0xED, 0x61, 0xEB, + 0x9E, 0x8F, 0x69, 0xA7, 0x54, 0x57, 0x86, 0x4C, 0xBF, 0x20, + 0x9D, 0x8B, 0x0F, 0xBF, 0x4C, 0xD4, 0xDF, 0x07, 0x4B, 0x6F, + 0xB9, 0x9B, 0x05, 0xD8, 0x17, 0x9C, 0x66, 0x58, 0xEE, 0xAC, + 0xED, 0xF6, 0x69, 0xFC, 0x42, 0x85, 0x3E, 0xA0, 0x6D, 0x1E, + 0x4D, 0x4B, 0x95, 0xC6, 0xF9, 0x22, 0x69, 0x97, 0xE8, 0xA1, + 0xDB, 0xE7, 0xDC, 0xC5, 0x16, 0x48, 0x57, 0x4D, 0x34, 0xF6, + 0x69, 0xC8, 0xED, 0xFE, 0xFD, 0x50, 0xFF, 0x81, 0x97, 0xE3, + 0x1B, 0xD9, 0xF4, 0x10, 0x10, 0xFB, 0x33, 0x2F, 0x8B, 0x43, + 0xA5, 0x69, 0x40, 0x5A, 0xE8, 0xC5, 0xF2, 0x70, 0xAD, 0x4D, + 0x68, 0xF1, 0xC3, 0x8D, 0x74, 0x9A, 0x0B, 0xD0, 0x91, 0xE1, + 0x8E, 0xA6, 0xD4, 0x77, 0xA8, 0x17, 0x48, 0xE7, 0x8F, 0xF7, + 0x26, 0xF5, 0xE0, 0xC9, 0xDE, 0x91, 0x48, 0xC6, 0x96, 0x1B, + 0xDD, 0x68, 0xE6, 0x4F, 0x83, 0x6A, 0x79, 0x2B, 0xC8, 0x2D, + 0x85, 0x61, 0xB8, 0xE9, 0x85, 0xAB, 0xC7, 0xAD, 0x40, 0xB9, + 0x58, 0x3C, 0x52, 0xB0, 0x01, 0x44, 0xF1, 0x63, 0x83, 0xF2, + 0x9E, 0x8F, 0x7A, 0x69, 0xC6, 0xEB, 0x4D, 0x38, 0x7F, 0x1A, + 0x72, 0x9F, 0x79, 0xAA, 0xBC, 0x56, 0x2B, 0xE8, 0x69, 0x04, + 0xE4, 0x72, 0x34, 0xD5, 0xFD, 0x25, 0x3E, 0xA6, 0xE0, 0xED, + 0xAB, 0x83, 0xB2, 0x67, 0xFB, 0x19, 0x05, 0x5A, 0x0B, 0x18, + 0x62, 0xA8, 0x0E, 0x5C, 0xDD, 0x23, 0xE7, 0xC1, 0x35, 0xA6, + 0xAC, 0xEF, 0x5B, 0x5C, 0x69, 0xB0, 0x48, 0xBC, 0xC5, 0x0D, + 0xE8, 0x0B, 0xAB, 0x9F, 0xA0, 0x47, 0x31, 0x23, 0xA8, 0xB2, + 0x34, 0xA9, 0xF6, 0xE0, 0x69, 0x85, 0xDE, 0x03, 0x69, 0xAF, + 0x69, 0x8C, 0x7B, 0x9D, 0x9A, 0x15, 0xC1, 0xBA, 0xFA, 0x67, + 0xF1, 0x16, 0x14, 0xD6, 0x5E, 0x70, 0x01, 0x67, 0x55, 0x6A, + 0xDC, 0xC0, 0x9A, 0x6E, 0x3A, 0x92, 0xE2, 0xDE, 0xF0, 0x7A, + 0x33, 0x8F, 0xA2, 0xE5, 0x62, 0xF8, 0x6D, 0xD3, 0x9B, 0xC8, + 0xE5, 0x3C, 0xDE, 0x37, 0x3C, 0x09, 0xB0, 0xBC, 0x27, 0xF6, + 0x6E, 0x9F, 0xE5, 0x01, 0xA4, 0x5B, 0x5F, 0x69, 0x1B, 0x2F, + 0xDC, 0x59, 0x16, 0x4D, 0x5A, 0x1A, 0xB2, 0xAD, 0x5C, 0xEE, + 0xBE, 0xA6, 0x0A, 0xCD, 0x0C, 0x10, 0x57, 0x3D, 0xA9, 0x19, + 0x3E, 0x14, 0x8C, 0xE3, 0x1B, 0xA5, 0x44, 0xBB, 0x6B, 0x4D, + 0xF0, 0xAF, 0xCF, 0x0C, 0x5B, 0xCD, 0x4C, 0x66, 0x65, 0xD2, + 0x65, 0xC9, 0x88, 0xAD, 0x11, 0xC4, 0x25, 0x2A, 0xE4, 0x11, + 0x2B, 0x65, 0xF5, 0x9A, 0xB9, 0xE5, 0xD8, 0x60, 0xBF, 0x10, + 0x77, 0xDD, 0x59, 0xCE, 0xAE, 0x7F, 0x75, 0x08, 0x9A, 0x87, + 0x09, 0xF9, 0x77, 0x87, 0xBD, 0x30, 0x29, 0x3B, 0x76, 0x96, + 0xDB, 0x70, 0x99, 0xED, 0xDB, 0xD3, 0xA3, 0x79, 0xFB, 0xFD, + 0xBB, 0x4D, 0xB7, 0x6A, 0xF1, 0x4D, 0x80, 0x5F, 0x81, 0xEF, + 0xE3, 0x6C, 0xBD, 0x09, 0x50, 0x08, 0x94, 0xF0, 0x67, 0x25, + 0xDE, 0x1B, 0x2D, 0xBA, 0x2D, 0x6A, 0x9F, 0xCD, 0x40, 0xCB, + 0xED, 0x6E, 0xF9, 0x33, 0x1F, 0x7A, 0xE4, 0x3D, 0xF3, 0x1A, + 0xBE, 0xD5, 0xEF, 0x8F, 0x85, 0xD0, 0xFA, 0xB2, 0x1A, 0x20, + 0x30, 0x3D, 0xAD, 0x3B, 0x7C, 0x34, 0xA0, 0x31, 0x21, 0xFB, + 0x37, 0x03, 0x15, 0x60, 0xDE, 0x08, 0xCF, 0x40, 0xC4, 0x72, + 0x62, 0x9D, 0x9D, 0xE2, 0x87, 0x6A, 0x20, 0x93, 0x10, 0x71, + 0x3C, 0x63, 0x24, 0x49, 0x24, 0x54, 0x16, 0x8B, 0x7B, 0x57, + 0x2B, 0x07, 0x04, 0xE5, 0x6B, 0xAD, 0x10, 0x56, 0xD6, 0xB9, + 0x05, 0xD2, 0xEC, 0x11, 0x6D, 0x3F, 0x22, 0xD9, 0x3E, 0x86, + 0xF9, 0x33, 0x60, 0xAF, 0xBF, 0xA7, 0xBE, 0x2E, 0xE5, 0x67, + 0x31, 0x07, 0x34, 0xA8, 0x89, 0x65, 0x9E, 0x16, 0x32, 0x95, + 0x7F, 0x7F, 0x1B, 0x04, 0xD8, 0x9E, 0xC5, 0xA4, 0xD5, 0x2D, + 0x33, 0xAD, 0x2A, 0x57, 0x26, 0x43, 0x79, 0xA1, 0x93, 0x4B, + 0xD7, 0xC0, 0x02, 0xB1, 0x36, 0x17, 0x8E, 0x7A, 0xAB, 0xE2, + 0xD1, 0xD1, 0x9F, 0xD5, 0x23, 0x44, 0x1F, 0x12, 0x16, 0xBE, + 0xAD, 0x4B, 0x66, 0x21, 0x4E, 0xFB, 0x12, 0x68, 0xF3, 0x8C, + 0xDF, 0x6F, 0xAF, 0x2E, 0x24, 0xB1, 0x70, 0x41, 0x11, 0xDE, + 0x12, 0x03, 0x49, 0xFB, 0xF6, 0x5C, 0x04, 0x37, 0x0B, 0x8A, + 0x9C, 0x46, 0x94, 0xE0, 0x83, 0x7C, 0xDA, 0x91, 0x31, 0xEC, + 0xA3, 0x09, 0x43, 0x24, 0x44, 0x49, 0x36, 0x86, 0xC4, 0x38, + 0xEB, 0x03, 0xE5, 0x8F, 0x4C, 0xC5, 0x39, 0xE8, 0xE3, 0xD7, + 0xBD, 0x1D, 0x3F, 0xD8, 0x5F, 0x44, 0x8C, 0xB3, 0x7F, 0xC4, + 0x14, 0xEE, 0xD6, 0xD9, 0x23, 0x21, 0x70, 0x21, 0x92, 0xAE, + 0x7E, 0x30, 0x22, 0xA5, 0x9D, 0x91, 0x4D, 0x3B, 0xFD, 0x6F, + 0x4F, 0x50, 0x30, 0x22, 0x5D, 0xEC, 0xCB, 0x83, 0xAE, 0x5B, + 0x47, 0x91, 0xC8, 0x65, 0x21, 0x4A, 0x9D, 0xDA, 0xD2, 0xCE, + 0x9E, 0x67, 0x3A, 0xD0, 0x71, 0x8C, 0xB9, 0x2C, 0xAF, 0x72, + 0x6E, 0x9D, 0xF1, 0x5F, 0x04, 0x97, 0xA3, 0x2F, 0x33, 0xE9, + 0x9A, 0xD7, 0x29, 0xA6, 0xA6, 0xB7, 0xF5, 0x47, 0xF7, 0x75, + 0xB9, 0x63, 0xC1, 0x3B, 0xBC, 0x0A, 0x25, 0xBB, 0xF5, 0x8D, + 0x5A, 0x14, 0xF8, 0x64, 0x24, 0xF1, 0x5D, 0x4E, 0x24, 0xA0, + 0x25, 0xBA, 0x92, 0x1C, 0xA9, 0x24, 0x5A, 0xEF, 0xBF, 0x16, + 0x6D, 0xDA, 0xAC, 0x74, 0x08, 0x9D, 0x52, 0x6A, 0xDD, 0xCD, + 0x1B, 0xCD, 0xBC, 0xB0, 0x8F, 0x31, 0x8D, 0x66, 0x4F, 0x56, + 0x28, 0xD0, 0xE7, 0x88, 0x70, 0xCA, 0x97, 0x3C, 0xCF, 0x75, + 0x63, 0xE1, 0xD5, 0xF0, 0xB0, 0xFC, 0x85, 0xBA, 0x27, 0x96, + 0x6F, 0x41, 0x69, 0xBE, 0x78, 0x44, 0x70, 0x23, 0xC4, 0x30, + 0xAF, 0xC5, 0xBF, 0x4A, 0xFB, 0x70, 0x73, 0x25, 0xE6, 0xFA, + 0xB1, 0x6A, 0xFB, 0xA7, 0x4C, 0xA5, 0x64, 0x51, 0xD4, 0x93, + 0x1E, 0xA7, 0x8B, 0xBA, 0x84, 0x6E, 0x9E, 0xC3, 0x87, 0xAE, + 0x18, 0x28, 0x6B, 0x11, 0x61, 0xED, 0xBF, 0xBE, 0x41, 0x40, + 0x20, 0x9E, 0x7B, 0xF1, 0x6F, 0x86, 0xEB, 0xB8, 0x90, 0x96, + 0x3E, 0x2E, 0xCE, 0x86, 0x07, 0xD3, 0x46, 0x11, 0x62, 0x9F, + 0xD3, 0xE8, 0xB0, 0x74, 0x7A, 0xD4, 0xB4, 0x0F, 0xE0, 0xBA, + 0x19, 0x17, 0x88, 0xDE, 0xDB, 0x95, 0x6D, 0x8B, 0xA4, 0x51, + 0x97, 0x46, 0x47, 0x2F, 0x3E, 0x08, 0x19, 0x13, 0x6E, 0x5E, + 0x76, 0xF0, 0xA5, 0xB3, 0x06, 0x7E, 0x4C, 0xC5, 0xC9, 0x0D, + 0x14, 0x89, 0x12, 0xEE, 0xE2, 0x28, 0xB1, 0x9F, 0x27, 0x5A, + 0x37, 0x29, 0xDF, 0xF1, 0xAB, 0x17, 0x55, 0x62, 0x06, 0xA7, + 0x57, 0x4F, 0x04, 0x1A, 0xA5, 0x08, 0xFC, 0x6F, 0xC8, 0xCF, + 0xC7, 0x5E, 0x9B, 0xEC, 0x6F, 0x7B, 0x3A, 0x80, 0x59, 0xAB, + 0xA8, 0x62, 0x63, 0x88, 0xA1, 0x09, 0x2A, 0x47, 0xC3, 0xC1, + 0x0F, 0x49, 0x36, 0x6E, 0xE8, 0x3F, 0x3D, 0x1D, 0xB0, 0x23, + 0x3E, 0x58, 0x19, 0xA7, 0x61, 0x04, 0x2C, 0x34, 0x73, 0xD4, + 0x00, 0x7A, 0xBB, 0x32, 0x90, 0x44, 0x17, 0xBA, 0xF4, 0xAE, + 0x47, 0xBE, 0xD6, 0xCB, 0x4F, 0xE9, 0xFE, 0x5F, 0x63, 0x35, + 0x70, 0xD2, 0xAB, 0x69, 0x30, 0x12, 0x72, 0xC1, 0xDF, 0xDC, + 0xEF, 0xBF, 0x14, 0xA4, 0xFD, 0x01, 0x9B, 0x8F, 0x98, 0xAF, + 0xA9, 0x4C, 0x10, 0x1F, 0xBD, 0x8E, 0xF6, 0xEF, 0x0D, 0xDC, + 0x6B, 0x26, 0x5F, 0xB6, 0xB3, 0x71, 0x28, 0x69, 0x10, 0xB3, + 0x70, 0x9B, 0x68, 0x6B, 0x5B, 0x9D, 0xEF, 0x23, 0xED, 0x20, + 0xCE, 0x0F, 0xF1, 0x7E, 0xAE, 0xDE, 0x0F, 0x1B, 0xFB, 0x5B, + 0x5E, 0x91, 0xDC, 0xA0, 0xF9, 0xB1, 0x2B, 0x57, 0xCA, 0x18, + 0x24, 0x84, 0xF1, 0xDC, 0x93, 0x62, 0xDD, 0x60, 0xDD, 0x24, + 0xF9, 0xC7, 0xEC, 0xB1, 0x4F, 0xEA, 0x5C, 0x73, 0x7B, 0x2B, + 0x07, 0xE4, 0x75, 0x73, 0x21, 0x8E, 0x45, 0x3B, 0xED, 0xBF, + 0xBE, 0x76, 0xE9, 0xC1, 0xC2, 0xA6, 0xEF, 0xDB, 0x20, 0x09, + 0x27, 0x95, 0x25, 0x8F, 0x9C, 0x1B, 0x62, 0xF3, 0x9D, 0x04, + 0xA2, 0xE6, 0xE0, 0xAD, 0xAF, 0x5E, 0x57, 0x0B, 0xE5, 0x7F, + 0xD1, 0x26, 0xAC, 0x4C, 0x68, 0xFF, 0xD0, 0x3E, 0x13, 0x52, + 0xD5, 0x00, 0x0B, 0x49, 0xC0, 0x11, 0x99, 0xD5, 0xA7, 0xE0, + 0x8E, 0xB2, 0x91, 0xA4, 0x13, 0x16, 0x10, 0xF1, 0x70, 0xB3, + 0x0B, 0x3D, 0x49, 0x68, 0x44, 0x64, 0x77, 0xBE, 0xAA, 0x02, + 0x5D, 0x43, 0xE5, 0xA1, 0x19, 0x33, 0x23, 0x5C, 0xF9, 0x1D, + 0xAA, 0xB6, 0xED, 0x00, 0x31, 0xDB, 0xDF, 0x1C, 0xDF, 0x53, + 0x3B, 0xBD, 0xDE, 0xDC, 0x57, 0x7D, 0xD1, 0x99, 0x4F, 0xAA, + 0xA4, 0xB5, 0x70, 0x77, 0x4B, 0x56, 0xE4, 0x40, 0x7F, 0x50, + 0x72, 0xE6, 0xF8, 0x40, 0x75, 0x8F, 0xA1, 0x48, 0x50, 0x5E, + 0x87, 0x69, 0xF8, 0xDA, 0x66, 0xCA, 0x7B, 0xD8, 0x4D, 0x5F, + 0x73, 0xE0, 0x62, 0x93, 0x21, 0xE3, 0xCD, 0xCB, 0xEF, 0x2F, + 0xF6, 0x71, 0xAF, 0x6B, 0x8A, 0xBA, 0x13, 0x6E, 0xCC, 0x60, + 0x42, 0x6F, 0xA3, 0x05, 0x51, 0x94, 0xE0, 0x9E, 0x68, 0x15, + 0x68, 0xA6, 0x48, 0xF0, 0x68, 0xE2, 0xBB, 0xCE, 0xE3, 0x59, + 0x70, 0x52, 0x11, 0x96, 0x75, 0xCC, 0x9D, 0x7A, 0xA3, 0x94, + 0xAB, 0x0E, 0xEE, 0xDB, 0xCB, 0x7A, 0x61, 0xBF, 0x8F, 0x0F, + 0xD5, 0x85, 0x34, 0x35, 0x87, 0xB4, 0xDD, 0xB0, 0x25, 0x12, + 0x0B, 0xDD, 0x0C, 0x76, 0x1A, 0x53, 0x1F, 0x70, 0x3B, 0x78, + 0x68, 0x73, 0x0A, 0x80, 0x7C, 0xAC, 0xC1, 0x94, 0x19, 0x3B, + 0x76, 0xF7, 0x1B, 0x21, 0xA5, 0x0F, 0x2C, 0x68, 0x48, 0x09, + 0x33, 0x2B, 0x0E, 0xB3, 0x0A, 0x51, 0x44, 0xBF, 0x8B, 0x13, + 0x81, 0xC7, 0x70, 0xA8, 0xDD, 0x20, 0xC9, 0x24, 0xD3, 0x83, + 0x19, 0xC9, 0x5C, 0x80, 0x01, 0x32, 0x38, 0x8B, 0xD6, 0xE3, + 0xDE, 0xA8, 0x25, 0x43, 0xB1, 0xC0, 0x6E, 0xC6, 0x78, 0xE5, + 0xDF, 0x74, 0x85, 0x01, 0x1C, 0x6D, 0x86, 0x2B, 0x86, 0xCD, + 0x89, 0xFB, 0x2E, 0xE1, 0xF5, 0x48, 0xF8, 0x08, 0x87, 0x7B, + 0xBC, 0xCA, 0xD2, 0x53, 0xAF, 0x7E, 0x2D, 0x7F, 0xEC, 0x4D, + 0x1D, 0x31, 0xC9, 0x7C, 0x3C, 0x73, 0xF7, 0xD7, 0x64, 0xEE, + 0xB2, 0x16, 0xAF, 0x9A, 0xAB, 0x98, 0x21, 0x22, 0x5F, 0x49, + 0x08, 0x22, 0x5F, 0x7E, 0xA5, 0x65, 0xBA, 0x12, 0xDE, 0x67, + 0x21, 0x53, 0x42, 0x15, 0x54, 0xB1, 0xFF, 0x86, 0xD6, 0x11, + 0x96, 0xF8, 0x04, 0xAA, 0x67, 0x8E, 0xEC, 0x48, 0x32, 0xA7, + 0xC9, 0x00, 0xA5, 0xEE, 0xBB, 0xA7, 0xB4, 0x66, 0x89, 0x4B, + 0x8B, 0x75, 0xAE, 0x85, 0x3E, 0x39, 0x59, 0x89, 0x0D, 0x3E, + 0xA1, 0xD9, 0xA9, 0xD4, 0xD8, 0x31, 0xAB, 0x87, 0x42, 0x43, + 0xC9, 0xEE, 0x94, 0x37, 0x8E, 0x59, 0x95, 0x7F, 0xA7, 0x96, + 0x42, 0xB9, 0x1C, 0x58, 0xB8, 0x90, 0x44, 0x5D, 0x68, 0x84, + 0xC9, 0xA7, 0x03, 0x94, 0x10, 0x97, 0x3A, 0xCE, 0x7D, 0xFE, + 0x6B, 0x8B, 0xC0, 0xA6, 0xAD, 0x3F, 0x22, 0x59, 0x64, 0x64, + 0x97, 0xBA, 0x76, 0x2E, 0x99, 0x98, 0x76, 0xE3, 0x21, 0x5E, + 0xBC, 0x6E, 0xE7, 0x00, 0x2A, 0x13, 0xF1, 0x4D, 0x1A, 0x89, + 0xF9, 0x8E, 0xCF, 0x6E, 0xDA, 0x82, 0xB7, 0x65, 0x74, 0x46, + 0xD6, 0xE9, 0x51, 0xC3, 0xCD, 0xCA, 0xDB, 0xF2, 0xD6, 0xF1, + 0x91, 0xD9, 0x6A, 0xAE, 0xC6, 0x17, 0xCD, 0x43, 0x01, 0x55, + 0x6C, 0x79, 0xC7, 0x77, 0x84, 0x46, 0xEC, 0xE6, 0x3C, 0x78, + 0xB4, 0x89, 0xDC, 0x55, 0x4F, 0x6A, 0x7C, 0x4E, 0xCC, 0xD2, + 0x0E, 0x71, 0xA0, 0x22, 0xC8, 0x5C, 0xF6, 0xBB, 0x30, 0x13, + 0x61, 0x8E, 0x57, 0xF6, 0xBB, 0x45, 0xAE, 0x13, 0xFA, 0xAD, + 0xAE, 0x46, 0x9B, 0xD6, 0xA8, 0xE3, 0x11, 0x54, 0xA0, 0x38, + 0xFC, 0x59, 0x92, 0xDE, 0xBC, 0x6D, 0x77, 0x89, 0xB8, 0xDE, + 0x89, 0x28, 0xA9, 0xC8, 0x81, 0x86, 0x41, 0x2A, 0x69, 0xA9, + 0x03, 0x54, 0x7D, 0x9E, 0xEE, 0x80, 0x63, 0x2F, 0x49, 0x1A, + 0xDB, 0x82, 0xCD, 0x9E, 0xEA, 0x9C, 0x36, 0x20, 0xD2, 0x63, + 0x1E, 0x0C, 0xA8, 0xE1, 0xBA, 0xA4, 0xEA, 0x95, 0x4B, 0x75, + 0x7E, 0x2E, 0x32, 0x50, 0xBF, 0xF1, 0xBC, 0x81, 0x5A, 0x50, + 0x40, 0x3C, 0xE2, 0x3A, 0x33, 0xB9, 0x18, 0x27, 0xE2, 0x1A, + 0x45, 0xA4, 0xEE, 0x6B, 0x9D, 0xE2, 0x8A, 0x10, 0x3F, 0x0A, + 0x79, 0xFC, 0x3A, 0xC7, 0x4D, 0x75, 0xAA, 0x55, 0xBB, 0x9E, + 0xE1, 0x73, 0x3E, 0x7F, 0x6E, 0x3C, 0x05, 0xFB, 0xB9, 0xA3, + 0x87, 0xCF, 0x24, 0x71, 0x8C, 0xC2, 0x22, 0x8F, 0x25, 0x79, + 0xFE, 0x21, 0x4F, 0x9D, 0x61, 0x19, 0x29, 0xF9, 0x50, 0x7E, + 0xF6, 0x7F, 0x6C, 0x83, 0xB3, 0x3E, 0x91, 0xC0, 0x67, 0xA6, + 0x1E, 0x5B, 0x36, 0x5B, 0x83, 0x97, 0x06, 0x00, 0x46, 0xE9, + 0x56, 0x75, 0x7F, 0x9A, 0xC6, 0x9E, 0x3C, 0xE2, 0x0A, 0x55, + 0x5D, 0x96, 0x02, 0x5B, 0x66, 0x6B, 0x2A, 0xDD, 0x13, 0x6D, + 0xD1, 0xAF, 0xA5, 0x90, 0xFA, 0xAB, 0xA7, 0x43, 0x32, 0xC5, + 0x8D, 0x07, 0x96, 0xB3, 0x12, 0x49, 0xC9, 0x4C, 0x74, 0x6E, + 0x7B, 0x28, 0xEF, 0xE1, 0x1F, 0x15, 0xB5, 0xBE, 0x13, 0x8C, + 0x43, 0x5A, 0xC9, 0xAB, 0xC1, 0xE5, 0xD2, 0xCD, 0x5E, 0xF4, + 0x14, 0x38, 0x6C, 0x13, 0x99, 0xAD, 0x40, 0x94, 0xFE, 0xB3, + 0xEF, 0x47, 0xFD, 0x10, 0xBF, 0x1A, 0xC4, 0x0A, 0x81, 0xBC, + 0xD5, 0x31, 0xD1, 0x47, 0x22, 0x97, 0x42, 0x68, 0x9B, 0x37, + 0x09, 0xE3, 0xFA, 0x81, 0xA4, 0xB0, 0xED, 0x58, 0xD2, 0x36, + 0x31, 0x9A, 0x09, 0xC3, 0xDA, 0x2D, 0x4B, 0x1C, 0xA7, 0x4D, + 0x9F, 0x4E, 0x6A, 0x29, 0xDF, 0xF2, 0x5F, 0x02, 0x0E, 0xE9, + 0xDC, 0x4C, 0x2E, 0x25, 0x28, 0x2D, 0xEB, 0x81, 0x7F, 0xB8, + 0xAA, 0x76, 0xBE, 0xCC, 0xE5, 0xE2, 0x49, 0x5B, 0x7D, 0xD3, + 0x3C, 0x44, 0x3D, 0xDD, 0x5A, 0xEB, 0xB9, 0x98, 0xD0, 0x9C, + 0x3B, 0x1E, 0x32, 0xE8, 0x1E, 0xDA, 0xCB, 0x24, 0x83, 0xA0, + 0x85, 0xDD, 0x73, 0xF6, 0x95, 0x5D, 0x33, 0x7D, 0x21, 0x81, + 0x4D, 0x8C, 0x69, 0x25, 0x9B, 0xDF, 0x8D, 0x91, 0xED, 0x69, + 0x8F, 0xBE, 0xCA, 0x87, 0x21, 0xA5, 0xDB, 0xCD, 0xC5, 0x76, + 0xC0, 0x64, 0x84, 0xC2, 0x35, 0x7C, 0xC1, 0x41, 0x4E, 0x50, + 0x42, 0x63, 0x2F, 0x5A, 0x39, 0x34, 0xDB, 0x2F, 0x47, 0x2E, + 0x1E, 0xF4, 0x28, 0x8C, 0x09, 0x17, 0x39, 0x88, 0x2D, 0x62, + 0x18, 0x0E, 0xE0, 0xF7, 0x7F, 0x61, 0x6D, 0x90, 0xE7, 0xFD, + 0xED, 0x83, 0xA0, 0xEB, 0xB5, 0x40, 0x5B, 0xBC, 0x64, 0xD6, + 0x97, 0x5D, 0x4A, 0xD2, 0x92, 0xC2, 0x53, 0xC5, 0xFC, 0xBF, + 0x8F, 0xB6, 0xDA, 0x44, 0x4E, 0x12, 0x16, 0xCE, 0x1A, 0xAC, + 0x80, 0x09, 0x78, 0x4A, 0xC4, 0x71, 0xD3, 0x6B, 0xF6, 0x7A, + 0xB2, 0x7E, 0x31, 0x46, 0x2E, 0xF7, 0x6F, 0x84, 0x3E, 0xCA, + 0xFD, 0xAE, 0x90, 0x6C, 0x05, 0x00, 0xC9, 0x06, 0xF3, 0x76, + 0x5F, 0x94, 0xE8, 0x6C, 0x99, 0x23, 0xCA, 0xD4, 0x9B, 0xE9, + 0xE1, 0xDC, 0x50, 0x05, 0x06, 0xC5, 0x82, 0x99, 0x5F, 0xAD, + 0x07, 0x50, 0x42, 0x01, 0xA4, 0x79, 0xFC, 0xD4, 0xB6, 0x47, + 0xEB, 0x05, 0xE5, 0x4E, 0x24, 0x51, 0x13, 0x84, 0x2D, 0xDB, + 0xC7, 0xB3, 0x89, 0xF5, 0x84, 0xBD, 0x1E, 0x54, 0x75, 0x18, + 0x84, 0xEC, 0xA4, 0xBE, 0xB8, 0xD3, 0x70, 0xB8, 0xA8, 0x4A, + 0xFB, 0xA6, 0xC1, 0xAA, 0xEA, 0xE8, 0x9F, 0x72, 0x73, 0x5F, + 0x1C, 0xD0, 0x01, 0x0F, 0x9A, 0x12, 0x4C, 0xDB, 0x3F, 0xE5, + 0xB9, 0x80, 0x8D, 0xDE, 0x9A, 0xB9, 0x75, 0x26, 0x20, 0xDA, + 0x32, 0x4A, 0x89, 0x61, 0xF5, 0x84, 0xB6, 0x5C, 0xE7, 0xCA, + 0xBE, 0x95, 0x44, 0x20, 0x99, 0x56, 0xB4, 0xBB, 0xBE, 0x4D, + 0xA1, 0x10, 0x71, 0x38, 0xCB, 0x91, 0x9D, 0x41, 0x17, 0x59, + 0x9F, 0x5F, 0xEA, 0x30, 0xA0, 0x86, 0x64, 0x67, 0x0B, 0xA1, + 0xEE, 0x2E, 0xC7, 0xBE, 0xC3, 0x77, 0xD1, 0x18, 0xA6, 0x6B, + 0xBA, 0x9C, 0x8E, 0x61, 0x11, 0xBD, 0x82, 0x8D, 0x63, 0x97, + 0xA9, 0xCB, 0x8C, 0x4E, 0xED, 0x20, 0x9F, 0xB5, 0x27, 0xE0, + 0xB3, 0x42, 0xFC, 0x2B, 0xAF, 0x72, 0x3A, 0x2C, 0xFE, 0x2C, + 0xF0, 0x60, 0x6A, 0x13, 0x67, 0x1D, 0xF3, 0x80, 0xC1, 0x83, + 0xFE, 0xEE, 0x17, 0x69, 0x09, 0xA2, 0xA4, 0xF3, 0x9A, 0x05, + 0x7B, 0xA1, 0xAE, 0x84, 0x45, 0x2F, 0x8C, 0x4C, 0xDC, 0xB8, + 0x84, 0xF9, 0x43, 0x7F, 0x4B, 0x85, 0x41, 0x3F, 0x29, 0x90, + 0x74, 0x45, 0x57, 0x30, 0x69, 0x8C, 0x2A, 0x05, 0xE3, 0x33, + 0x02, 0xB0, 0xD3, 0x9D, 0x50, 0x67, 0x8C, 0x20, 0xE2, 0xC1, + 0xCF, 0xD3, 0xB3, 0xD3, 0xE1, 0xE4, 0x3C, 0xAD, 0xA6, 0x04, + 0x40, 0xE3, 0x0C, 0xA2, 0xDB, 0x33, 0x3B, 0x0C, 0xD8, 0xAC, + 0x62, 0xCA, 0x0E, 0xCC, 0x60, 0x63, 0x87, 0x36, 0x23, 0x70, + 0x47, 0x7A, 0xEF, 0xBB, 0x2C, 0x8C, 0xE3, 0xDF, 0xBB, 0x61, + 0xD8, 0x4D, 0x22, 0x1B, 0x3E, 0xFE, 0x21, 0x3F, 0xC3, 0xC0, + 0x75, 0xAE, 0xEB, 0x61, 0xD3, 0xA2, 0x2F, 0x4C, 0xA6, 0x4D, + 0x37, 0x5A, 0x89, 0xC1, 0x50, 0xC9, 0xF7, 0x83, 0xA2, 0xAB, + 0x3F, 0x00, 0xBA, 0xDE, 0xB8, 0x03, 0xEC, 0x9C, 0x31, 0xB3, + 0x5E, 0x63, 0xC3, 0x12, 0x4A, 0x43, 0xB7, 0x3B, 0x21, 0x4F, + 0x28, 0x1F, 0x06, 0xF8, 0xA7, 0x2B, 0x18, 0xC6, 0xE9, 0x46, + 0xCA, 0x53, 0x9A, 0x79, 0x42, 0xA6, 0x7E, 0xA8, 0x50, 0xBC, + 0x7B, 0x27, 0xC8, 0x15, 0xAD, 0x16, 0x31, 0x24, 0x7B, 0x7B, + 0xB4, 0x38, 0x50, 0xFD, 0xEA, 0x97, 0xF5, 0x1B, 0x72, 0x28, + 0x47, 0x3A, 0xC4, 0xE2, 0x7E, 0xF6, 0xBD, 0x68, 0x54, 0x9F, + 0x31, 0x70, 0x94, 0x4B, 0x57, 0x85, 0xFB, 0x3E, 0x9C, 0xAE, + 0x36, 0x42, 0x98, 0x53, 0x02, 0xFD, 0x5F, 0x6D, 0xC2, 0xA5, + 0x24, 0x29, 0x1B, 0xAE, 0xCD, 0x22, 0x7D, 0xFF, 0x9A, 0xDF, + 0x0A, 0x7A, 0x59, 0x9B, 0xD6, 0xCC, 0x58, 0xD3, 0x74, 0x44, + 0x35, 0x7F, 0xFE, 0x35, 0x4B, 0x43, 0xDD, 0x4A, 0x7A, 0xFA, + 0x0E, 0x7E, 0xA3, 0x36, 0x6D, 0x6B, 0xCA, 0x96, 0xB0, 0xB3, + 0x62, 0xFA, 0xB1, 0xB6, 0xEA, 0xD2, 0x92, 0x67, 0x45, 0xF1, + 0x78, 0xCA, 0x99, 0xCC, 0x9F, 0xBA, 0xB4, 0x48, 0x74, 0xB9, + 0x1D, 0xB5, 0x68, 0x0B, 0x8E, 0x92, 0x16, 0x51, 0x29, 0xDD, + 0x9F, 0xA9, 0x3C, 0xBC, 0xF0, 0x43, 0x7C, 0x3B, 0x36, 0x3B, + 0x95, 0x38, 0xF5, 0x5C, 0xC3, 0xF9, 0x98, 0x51, 0x7F, 0x1E, + 0x9C, 0xE0, 0x8D, 0x7B, 0x07, 0x1B, 0x7B, 0xEF, 0x62, 0xCA, + 0x0D, 0x12, 0xE7, 0x23, 0x2B, 0x43, 0x9F, 0xBE, 0x8D, 0xD9, + 0xF7, 0xCD, 0xBC, 0x66, 0x5B, 0x86, 0x22, 0xD3, 0x0B, 0x32, + 0xDA, 0x59, 0x1A, 0x69, 0xC0, 0xC8, 0x99, 0xF4, 0xEB, 0xC7, + 0x36, 0xA1, 0xD8, 0x0D, 0x58, 0xF2, 0xD5, 0x50, 0x72, 0xD5, + 0x88, 0x98, 0x3E, 0x72, 0x52, 0xE2, 0xD8, 0x6A, 0xE7, 0xBF, + 0xC2, 0xD8, 0xCD, 0x0A, 0xB0, 0xA4, 0x6D, 0x37, 0x60, 0xF6, + 0x43, 0xA2, 0xCE, 0xEF, 0xE7, 0x54, 0x00, 0x7A, 0x8B, 0x2C, + 0x06, 0x82, 0x93, 0xA7, 0x63, 0x7C, 0x41, 0xB5, 0xB9, 0x07, + 0xFB, 0x93, 0x50, 0xFB, 0xB6, 0xBD, 0x0A, 0x5E, 0xB2, 0x35, + 0xD6, 0xB5, 0x68, 0xBA, 0x5B, 0xD9, 0x2A, 0x1B, 0x76, 0x33, + 0xC7, 0x28, 0xD4, 0x68, 0xF4, 0x99, 0xA2, 0xDD, 0x67, 0xC9, + 0xE4, 0xBA, 0x73, 0x95, 0xA0, 0xEB, 0xAB, 0x39, 0x02, 0x93, + 0x99, 0x6C, 0x7C, 0x41, 0x86, 0x41, 0x3F, 0x39, 0x5F, 0x25, + 0x90, 0xD8, 0x23, 0x15, 0xA3, 0xC1, 0x8E, 0xB4, 0xD4, 0xA2, + 0xC2, 0xBB, 0xB1, 0x24, 0xE7, 0x36, 0x4C, 0x40, 0x55, 0x64, + 0x45, 0xC8, 0x7C, 0x2E, 0xC9, 0xB3, 0x54, 0x4F, 0x3C, 0xBE, + 0xA6, 0x89, 0x9B, 0xFC, 0x31, 0xED, 0x7C, 0xF5, 0x30, 0x1E, + 0x0F, 0xA4, 0xBB, 0x85, 0xBD, 0x3B, 0x4B, 0x39, 0x31, 0xC6, + 0x5C, 0x18, 0xFD, 0x6A, 0x1E, 0xB0, 0x56, 0x63, 0xFC, 0x5B, + 0x7D, 0x42, 0x64, 0xCA, 0x96, 0x26, 0x51, 0x96, 0x4E, 0x23, + 0x90, 0x3D, 0x1E, 0x81, 0x18, 0x28, 0x88, 0xE5, 0x98, 0xAF, + 0x12, 0x0D, 0x3D, 0x78, 0xB2, 0xAA, 0xFA, 0x7F, 0x28, 0xE1, + 0x7A, 0xD4, 0x0D, 0x49, 0xFA, 0x16, 0xBC, 0xA0, 0xC2, 0xFA, + 0x1D, 0xC4, 0x6A, 0x91, 0x4B, 0xF8, 0x65, 0xB7, 0xEF, 0x38, + 0xFD, 0x7C, 0xDA, 0x4D, 0xBC, 0x98, 0xE0, 0xA6, 0x2E, 0x3C, + 0x6C, 0x65, 0x38, 0x72, 0xD8, 0xB9, 0x76, 0x23, 0xCE, 0xD8, + 0x03, 0x73, 0x51, 0xB9, 0x94, 0x86, 0x84, 0xE8, 0x46, 0x7C, + 0x84, 0xBE, 0x90, 0x80, 0x58, 0x50, 0xB6, 0xE6, 0xFD, 0x87, + 0x44, 0xEC, 0x8F, 0x5A, 0x18, 0xD8, 0x9C, 0xDE, 0xAC, 0xB5, + 0x23, 0x62, 0x86, 0x2D, 0x4D, 0x34, 0x46, 0x4F, 0xE9, 0xD4, + 0x01, 0x69, 0x89, 0x79, 0x16, 0xDD, 0xCB, 0x6F, 0x66, 0xC6, + 0xF9, 0x38, 0x88, 0xE5, 0x37, 0x7C, 0x60, 0xD4, 0x17, 0x5F, + 0x7D, 0x00, 0xCF, 0xF1, 0x66, 0x5C, 0xFB, 0x73, 0xC2, 0x56, + 0x75, 0xD1, 0xA7, 0x40, 0x50, 0xF6, 0x98, 0xE1, 0x25, 0x2A, + 0x95, 0x11, 0x5E, 0xC1, 0x2C, 0x0E, 0xF6, 0x08, 0x3F, 0xAC, + 0x6A, 0x00, 0x53, 0xE7, 0x4B, 0xCB, 0xDA, 0x19, 0x74, 0x25, + 0x05, 0x30, 0xEF, 0x20, 0x3D, 0x02, 0x39, 0x21, 0x55, 0x23, + 0x4B, 0x1C, 0x9D, 0xA7, 0xCB, 0x1E, 0x88, 0x1E, 0x6D, 0x46, + 0x54, 0x56, 0xF4, 0xE5, 0x23, 0x49, 0xDA, 0xA7, 0x90, 0xB2, + 0x1A, 0x68, 0x9F, 0xE6, 0x12, 0x22, 0x2B, 0x70, 0xAB, 0x2A, + 0xF4, 0xCD, 0xA6, 0x1F, 0x37, 0x0C, 0x29, 0xDD, 0x62, 0x9C, + 0x43, 0xAC, 0x56, 0x73, 0xBA, 0x8D, 0xB7, 0xE1, 0x92, 0xBB, + 0x3D, 0xCA, 0xA9, 0xEF, 0xBF, 0x00, 0xA9, 0x58, 0xB7, 0x2D, + 0x68, 0xC4, 0x6D, 0xAF, 0x86, 0xCC, 0xA1, 0x4F, 0xC6, 0xE6, + 0x67, 0xA3, 0xF5, 0xD9, 0x6C, 0xE1, 0x1D, 0x07, 0x90, 0x28, + 0x84, 0x53, 0x10, 0xE1, 0xE0, 0x53, 0x6D, 0x26, 0xD9, 0xB3, + 0xF3, 0xF1, 0x52, 0x55, 0x03, 0x71, 0x7B, 0x22, 0xF6, 0x82, + 0x8A, 0xBA, 0xE7, 0x8A, 0xF8, 0x04, 0x5E, 0x86, 0xF0, 0x78, + 0xF8, 0x94, 0x16, 0xDA, 0xB7, 0xAE, 0xCB, 0x53, 0x3A, 0xBD, + 0xB0, 0x65, 0x2C, 0x00, 0x8A, 0xA1, 0xE7, 0x29, 0x07, 0xE6, + 0x84, 0x1B, 0x76, 0x0E, 0x47, 0xE2, 0x9A, 0x06, 0x1E, 0xBB, + 0x3E, 0x13, 0xA6, 0x8D, 0x09, 0x52, 0xB7, 0xD4, 0xF8, 0xE1, + 0x0B, 0x06, 0x29, 0xFC, 0x1E, 0x00, 0x66, 0xE1, 0x9C, 0xF4, + 0x5D, 0x9B, 0x36, 0x96, 0x2B, 0x98, 0x5C, 0x40, 0x99, 0xC0, + 0x89, 0x02, 0x1F, 0x9B, 0x65, 0x62, 0x42, 0xA2, 0x06, 0x16, + 0x30, 0x19, 0x33, 0x17, 0xED, 0xBB, 0x2F, 0xBC, 0x9F, 0x75, + 0xB1, 0x67, 0x45, 0x54, 0xDA, 0x5F, 0xD5, 0x8B, 0x34, 0x3D, + 0x69, 0x85, 0xEF, 0x18, 0x6B, 0x14, 0xD6, 0x13, 0x56, 0x00, + 0x31, 0x8E, 0x48, 0xDA, 0x81, 0x0F, 0x69, 0xB6, 0xED, 0x25, + 0x38, 0xDB, 0x87, 0x88, 0x09, 0xA6, 0xE5, 0x0C, 0xBB, 0xD5, + 0x53, 0x7B, 0x35, 0x9A, 0x0F, 0x36, 0xD6, 0x4B, 0x2F, 0xBE, + 0x0A, 0xD2, 0x85, 0x9D, 0x7E, 0x3E, 0xF5, 0x17, 0x80, 0x4F, + 0x29, 0x20, 0x63, 0xB8, 0x1B, 0x55, 0x92, 0xB7, 0x88, 0x5F, + 0x0E, 0x6F, 0x6C, 0x21, 0x08, 0x1D, 0x22, 0x68, 0x49, 0x40, + 0x08, 0xDF, 0x1F, 0x54, 0x18, 0x85, 0xE7, 0x45, 0x90, 0xA9, + 0xDC, 0xBC, 0x56, 0x46, 0xE2, 0xBC, 0x08, 0x24, 0x19, 0xC9, + 0x1E, 0x2A, 0x70, 0x33, 0xEE, 0xA7, 0xFE, 0x01, 0x7D, 0x75, + 0x5E, 0x31, 0xC5, 0x67, 0x97, 0xC9, 0xDD, 0xF7, 0x6B, 0xCA, + 0xAD, 0xC7, 0xA4, 0x1F, 0x02, 0xB7, 0x4A, 0x20, 0x06, 0x00, + 0x8F, 0x4B, 0x0F, 0xA9, 0x4E, 0x50, 0x24, 0x43, 0x3B, 0xC0, + 0x2E, 0x05, 0x55, 0xA5, 0x83, 0x27, 0xA1, 0x45, 0x81, 0x01, + 0xA5, 0xEB, 0xB8, 0x4D, 0x07, 0x0A, 0x9A, 0x02, 0xA2, 0x06, + 0xDB, 0xC3, 0x8E, 0x4E, 0x2B, 0xF2, 0x47, 0xD3, 0x58, 0x47, + 0x6E, 0x78, 0xE8, 0xFD, 0x30, 0xB2, 0x3C, 0x6F, 0x88, 0xEF, + 0x53, 0x73, 0x01, 0x81, 0x29, 0x67, 0x06, 0x62, 0x31, 0x99, + 0x7A, 0xE4, 0xF0, 0x3C, 0x82, 0x5B, 0xF0, 0xF8, 0xAF, 0x25, + 0x9B, 0x3A, 0x2C, 0x28, 0x5B, 0xEE, 0x29, 0x6B, 0x0F, 0x6E, + 0x07, 0x8D, 0x09, 0x14, 0x7A, 0x8C, 0xFB, 0x6D, 0x65, 0x1B, + 0x32, 0x21, 0x8E, 0x3A, 0x50, 0xB4, 0xC3, 0x6F, 0xCE, 0xCE, + 0xDD, 0x9B, 0x3B, 0x8F, 0x6D, 0x2B, 0xAE, 0x86, 0xFE, 0x94, + 0xF3, 0x82, 0x1F, 0x4F, 0xFC, 0x17, 0x79, 0x42, 0x26, 0x9B, + 0x38, 0x72, 0x77, 0x6F, 0xB1, 0x20, 0xAD, 0xDE, 0x6D, 0x1C, + 0xF1, 0x83, 0xD3, 0x1F, 0x8D, 0x04, 0xBD, 0x3F, 0xFD, 0xBE, + 0xFB, 0x80, 0x91, 0x97, 0xC2, 0x2F, 0x05, 0x80, 0xB4, 0x3E, + 0x5A, 0x7C, 0xB9, 0x90, 0xBC, 0x0E, 0x7C, 0x46, 0x1C, 0xE8, + 0x33, 0x0F, 0xCB, 0x4D, 0xC1, 0xB5, 0xF4, 0xCD, 0xAB, 0x93, + 0xBF, 0xD8, 0x3A, 0x88, 0x33, 0xB5, 0x43, 0xCC, 0x22, 0x36, + 0x9A, 0x34, 0xAE, 0x2D, 0x06, 0xF0, 0x32, 0x0E, 0x69, 0x6E, + 0xB8, 0xCB, 0xA2, 0xF1, 0x21, 0x78, 0xC4, 0xDA, 0x2C, 0x13, + 0x31, 0x39, 0x2D, 0x30, 0x75, 0xAB, 0xFB, 0xB8, 0x16, 0x55, + 0x63, 0xA8, 0x73, 0xE8, 0xFC, 0x5A, 0xAB, 0xF6, 0xED, 0xE6, + 0x3B, 0xB4, 0xF3, 0xD1, 0xA3, 0x81, 0x63, 0xED, 0x5D, 0x73, + 0x20, 0xD0, 0xB8, 0x40, 0x99, 0x26, 0x05, 0x51, 0xA3, 0x29, + 0xD0, 0xB0, 0xA4, 0x56, 0x90, 0x20, 0x6F, 0x9F, 0x5C, 0xF1, + 0xBC, 0xEE, 0x42, 0xBA, 0xCE, 0xB0, 0xA5, 0x79, 0x55, 0x9C, + 0xF0, 0x16, 0x61, 0x2B, 0x46, 0x29, 0x2B, 0x27, 0x87, 0x7C, + 0x1A, 0x81, 0x70, 0x91, 0x52, 0xAE, 0xE9, 0xAF, 0x92, 0x54, + 0x7A, 0x98, 0xB2, 0x55, 0x5E, 0x3F, 0x80, 0xF3, 0xC4, 0x35, + 0x79, 0x78, 0x0B, 0xFA, 0xE6, 0x92, 0xBF, 0x61, 0x88, 0x9E, + 0xF1, 0x97, 0xEB, 0x7D, 0xE5, 0x37, 0x3C, 0x3A, 0xF5, 0xC4, + 0x69, 0x9C, 0x49, 0x98, 0xFB, 0x7F, 0x0F, 0x96, 0xB7, 0xF6, + 0x1C, 0xC6, 0xE7, 0x97, 0xE3, 0xBF, 0x83, 0x23, 0x8B, 0xF7, + 0x59, 0x5D, 0x54, 0xAA, 0x62, 0x5E, 0xD7, 0xD2, 0xD6, 0x78, + 0xD4, 0xD9, 0x9F, 0xE2, 0x1A, 0xB9, 0xBB, 0xFD, 0x3C, 0x61, + 0x7E, 0x46, 0xBE, 0xE7, 0x1D, 0x76, 0x5A, 0xF0, 0xE6, 0x9F, + 0xDF, 0x45, 0xFB, 0x24, 0xF9, 0x58, 0x73, 0x36, 0x1E, 0x5F, + 0xC2, 0xB5, 0x49, 0x94, 0x2E, 0x2E, 0xB6, 0xA1, 0x1E, 0x1E, + 0x60, 0xE0, 0x14, 0x53, 0x0D, 0xC0, 0xFE, 0x59, 0x5D, 0x5A, + 0x85, 0x2D, 0x71, 0xCC, 0xA1, 0x9F, 0xDF, 0x07, 0xF1, 0xE7, + 0x41, 0xB7, 0xB9, 0x28, 0x0E, 0xB2, 0xFA, 0x32, 0x5E, 0xAC, + 0xB4, 0x1E, 0x78, 0xF7, 0xD3, 0xAE, 0x19, 0x43, 0x33, 0xA0, + 0x02, 0xC4, 0xCC, 0x9F, 0x09, 0x65, 0x54, 0xFD, 0xFF, 0xCC, + 0xAA, 0x10, 0xF7, 0x73, 0x1E, 0xD1, 0x6D, 0x40, 0xA4, 0xEC, + 0x58, 0xC5, 0xC6, 0x6B, 0xE2, 0xA4, 0x7D, 0x62, 0xD3, 0x26, + 0x69, 0xA9, 0x94, 0x58, 0x36, 0xF6, 0x73, 0x33, 0x1D, 0xD0, + 0x87, 0x1D, 0x77, 0x9E, 0xFB, 0x0C, 0x10, 0x22, 0x7F, 0xF1, + 0x44, 0xC0, 0x57, 0x2F, 0xF1, 0xCB, 0xBE, 0x8F, 0x66, 0x5B, + 0x41, 0x32, 0xD7, 0xC3, 0xF1, 0x5A, 0xC8, 0x0D, 0x8E, 0x4D, + 0xA5, 0x26, 0xC6, 0x7F, 0xF9, 0x91, 0x4A, 0x64, 0x0B, 0x03, + 0xF6, 0x32, 0xE6, 0x29, 0x69, 0x7B, 0x88, 0x74, 0x54, 0xC5, + 0xEF, 0xFF, 0xFD, 0x53, 0xD7, 0x31, 0x13, 0x42, 0xBD, 0x48, + 0xA7, 0x7C, 0x63, 0x10, 0x0A, 0x64, 0xC1, 0x32, 0x6E, 0xCD, + 0x72, 0xE2, 0x41, 0xA4, 0x17, 0x61, 0xC6, 0x2E, 0xCD, 0x8E, + 0x75, 0x66, 0x07, 0x9F, 0x4F, 0xE7, 0x53, 0x84, 0x1C, 0xB5, + 0x3F, 0xBB, 0xEB, 0x55, 0x9F, 0xF8, 0x54, 0x5B, 0x34, 0x44, + 0xFB, 0xF6, 0x95, 0xAB, 0x4E, 0x5D, 0x5A, 0xF5, 0x8B, 0x45, + 0x4D, 0x0F, 0xF5, 0x89, 0xAA, 0x5B, 0xB5, 0xFF, 0x4D, 0xD8, + 0xBA, 0x50, 0x26, 0x3E, 0xBE, 0x20, 0x93, 0x22, 0x9C, 0x75, + 0xBC, 0xCD, 0x57, 0xD3, 0xB9, 0x33, 0x77, 0x2C, 0xA5, 0x44, + 0x1E, 0x00, 0x1C, 0x8F, 0x71, 0x67, 0xD4, 0xF9, 0x8E, 0x0A, + 0x2A, 0xEC, 0x9F, 0x90, 0xFF, 0xC9, 0x01, 0xB0, 0x40, 0xA9, + 0x73, 0x76, 0x77, 0x45, 0x2F, 0xF9, 0x8A, 0x50, 0x9D, 0xEC, + 0xEE, 0xB7, 0x65, 0x77, 0x8E, 0xA9, 0x9D, 0x30, 0x53, 0x97, + 0x8A, 0x18, 0xC9, 0x34, 0xB5, 0xFF, 0x5E, 0xBF, 0x9A, 0x5C, + 0x4F, 0x67, 0xD7, 0xE5, 0xF5, 0xD6, 0x06, 0x90, 0xB2, 0xF4, + 0xEF, 0xD8, 0xB6, 0x49, 0x0C, 0xB4, 0xFF, 0x1A, 0x38, 0x1B, + 0x34, 0x7B, 0xC2, 0x41, 0xF6, 0xE8, 0xCF, 0x6E, 0x67, 0xDA, + 0xCF, 0x5B, 0x62, 0x2C, 0x67, 0x93, 0x2C, 0x8B, 0xB0, 0x6B, + 0x48, 0xD9, 0xA2, 0x0B, 0x67, 0xDF, 0x4A, 0x93, 0x2D, 0x68, + 0x65, 0x29, 0x69, 0x43, 0x07, 0x4A, 0x68, 0xA2, 0xAF, 0x26, + 0xA2, 0xC4, 0x37, 0x19, 0xC8, 0x97, 0x35, 0x13, 0x04, 0x26, + 0xE4, 0xDA, 0xF3, 0x27, 0xDD, 0x56, 0x00, 0x8A, 0x0B, 0x73, + 0x6F, 0xFC, 0x0B, 0x12, 0xB1, 0x1C, 0xE0, 0x90, 0xC4, 0x79, + 0x44, 0x82, 0x0E, 0xA7, 0xA9, 0x98, 0xAD, 0xDA, 0xC8, 0x6E, + 0x54, 0x49, 0xAD, 0xD5, 0x9C, 0x63, 0x28, 0xA2, 0xDF, 0xB9, + 0xFB, 0x9C, 0x1B, 0x1F, 0xB1, 0xE5, 0x38, 0x8F, 0xB5, 0x5C, + 0x38, 0x9F, 0x75, 0x94, 0xB7, 0xFF, 0x29, 0x68, 0xFC, 0xD6, + 0x56, 0x59, 0xD5, 0x34, 0xBE, 0xC2, 0xAD, 0xD6, 0xBD, 0xE0, + 0xDA, 0xC6, 0x87, 0x6B, 0xC6, 0x33, 0x5C, 0x03, 0xCB, 0x76, + 0xB1, 0x21, 0x85, 0x01, 0x9C, 0xC1, 0x89, 0x0F, 0xD1, 0x21, + 0x72, 0x10, 0x76, 0xBE, 0x44, 0x59, 0xAA, 0x42, 0x35, 0x2B, + 0x9B, 0x7C, 0x6E, 0x24, 0x88, 0x8D, 0xA6, 0x3E, 0xEC, 0x64, + 0x5A, 0x8F, 0xF8, 0x78, 0x93, 0xD3, 0x5C, 0x0C, 0x93, 0x39, + 0x4E, 0xE5, 0x63, 0x4D, 0x6C, 0x5B, 0xE3, 0x71, 0x16, 0x90, + 0xE3, 0xB2, 0x02, 0xD9, 0x47, 0xE7, 0x92, 0xC3, 0xDE, 0xCA, + 0xD0, 0x5B, 0x14, 0x29, 0x04, 0x57, 0xFB, 0x9A, 0xC8, 0x17, + 0x8C, 0xDC, 0xFE, 0xD7, 0x42, 0xAA, 0x4F, 0x18, 0x2E, 0xC7, + 0xF2, 0xA8, 0x80, 0xDC, 0x6E, 0x71, 0xE1, 0x4A, 0xC9, 0x77, + 0x1B, 0xB0, 0x8D, 0x93, 0x0E, 0x22, 0x88, 0x85, 0x90, 0x79, + 0x89, 0x9D, 0x88, 0xDD, 0xEF, 0xE4, 0x79, 0x7A, 0x10, 0x57, + 0xA6, 0xFC, 0xB8, 0x1D, 0x76, 0x80, 0x88, 0xF0, 0x33, 0xD5, + 0x06, 0x3E, 0xF5, 0x36, 0xC7, 0xF0, 0x0D, 0x5E, 0xA0, 0x2C, + 0xCF, 0xE3, 0xDE, 0x2F, 0x12, 0x2B, 0x4D, 0xA0, 0xF3, 0x05, + 0x33, 0x8E, 0xFE, 0x1B, 0xFA, 0x6A, 0x3B, 0x07, 0x96, 0x9B, + 0x41, 0x9F, 0x7E, 0x42, 0x7F, 0x11, 0xA0, 0xA8, 0xC3, 0x75, + 0xBB, 0x5A, 0x02, 0x1E, 0xC6, 0x21, 0x6B, 0x7A, 0x46, 0xF2, + 0x28, 0x65, 0x40, 0x9D, 0xF9, 0x68, 0x83, 0xC4, 0x0D, 0xA4, + 0xA4, 0x80, 0x7C, 0xC7, 0xC0, 0x3B, 0xBF, 0xEF, 0xDD, 0xF9, + 0x36, 0x4F, 0xFC, 0x70, 0x64, 0x1E, 0x82, 0x0F, 0xF9, 0xD8, + 0x82, 0x7A, 0x3B, 0x7D, 0xA8, 0xEB, 0x39, 0xC3, 0xAC, 0xE9, + 0xD7, 0x6F, 0xFE, 0xE5, 0xBA, 0x89, 0x5D, 0x0A, 0x46, 0x61, + 0x3D, 0xB7, 0x6C, 0x9B, 0xBE, 0x4F, 0x9E, 0x7B, 0xA9, 0x27, + 0x9E, 0xCA, 0xEF, 0x74, 0xD6, 0xFB, 0x8D, 0xD8, 0xF5, 0x9A, + 0x02, 0x11, 0x4D, 0x57, 0x87, 0x19, 0x38, 0xFD, 0x3A, 0x26, + 0xBF, 0xD3, 0xEE, 0x66, 0x8A, 0x1F, 0x33, 0x29, 0x05, 0x94, + 0xB8, 0xD6, 0x6B, 0x93, 0x52, 0x0D, 0xAB, 0xBE, 0x20, 0x08, + 0xBB, 0x8F, 0xC1, 0xB0, 0xA1, 0x8C, 0x76, 0x0B, 0xE7, 0x98, + 0x9B, 0xBD, 0x1E, 0x94, 0x9E, 0xB2, 0x5B, 0x84, 0xB9, 0x14, + 0x14, 0x18, 0x2E, 0xDC, 0xBB, 0x54, 0x1E, 0xA5, 0xC0, 0x3C, + 0x7C, 0x7C, 0x3E, 0x1B, 0xAC, 0x30, 0x4A, 0xEF, 0x64, 0x66, + 0xA7, 0x24, 0x04, 0xCC, 0x91, 0xD2, 0x1A, 0x40, 0x24, 0xF1, + 0x7D, 0xA6, 0xB7, 0xA1, 0x5D, 0xEF, 0x7B, 0x60, 0x47, 0xBF, + 0xF7, 0x1C, 0x92, 0xF8, 0x71, 0xB5, 0xF5, 0x95, 0x95, 0xC6, + 0xDC, 0x14, 0x41, 0xAB, 0x0E, 0xC3, 0x19, 0x2F, 0xA7, 0x85, + 0xE7, 0xE7, 0x0E, 0xD5, 0xF1, 0x38, 0xF0, 0x94, 0xE2, 0xAB, + 0x3F, 0x47, 0xBA, 0x77, 0x3F, 0xD7, 0x5E, 0xC6, 0x3F, 0x89, + 0xEC, 0xE6, 0x52, 0x2E, 0xF6, 0x97, 0x65, 0x63, 0xE4, 0x07, + 0xD7, 0xB4, 0x98, 0x55, 0xF8, 0xA3, 0x70, 0x02, 0x35, 0x53, + 0x47, 0x76, 0x00, 0xBD, 0xD3, 0x7F, 0x7B, 0x2B, 0x11, 0x6E, + 0xB5, 0xDC, 0x5D, 0xF5, 0x1B, 0x21, 0x54, 0xE5, 0x63, 0x7D, + 0xCC, 0x05, 0xD3, 0xE0, 0x8B, 0x72, 0x93, 0x28, 0x90, 0x97, + 0x80, 0x82, 0x80, 0x5E, 0x54, 0xB2, 0x55, 0x49, 0x3D, 0xA0, + 0x49, 0xC4, 0x1F, 0xC5, 0x23, 0xDE, 0x2A, 0x7E, 0x50, 0xD8, + 0x4D, 0xA9, 0x97, 0x41, 0xC3, 0x9C, 0x01, 0xD7, 0xDD, 0xF7, + 0x45, 0x6A, 0xE9, 0x3B, 0x58, 0x2C, 0xE2, 0x15, 0x57, 0xEF, + 0x48, 0x17, 0x1C, 0x09, 0x95, 0x7F, 0x89, 0x21, 0xAC, 0x41, + 0xAA, 0xA5, 0xB7, 0x96, 0x0D, 0x82, 0x0A, 0x8D, 0xBC, 0xEF, + 0xF3, 0xAC, 0xA0, 0xAC, 0x1B, 0xB9, 0xBF, 0xE8, 0xF9, 0x64, + 0x47, 0x7E, 0xBD, 0xD2, 0x6D, 0x74, 0x78, 0x60, 0x7F, 0x0B, + 0xA6, 0x58, 0x42, 0x50, 0xE5, 0xC7, 0x1B, 0x0B, 0xB0, 0x5A, + 0x90, 0xC9, 0xBB, 0xDE, 0xA6, 0xAA, 0x73, 0x02, 0x0F, 0x1E, + 0x47, 0xE6, 0x75, 0x25, 0x79, 0x8E, 0x66, 0x71, 0x64, 0x0B, + 0x86, 0x26, 0x0C, 0x1B, 0x98, 0xDB, 0x0A, 0x85, 0x55, 0x38, + 0x85, 0x22, 0x10, 0x82, 0xFB, 0x0D, 0xD7, 0x1D, 0xFB, 0xD0, + 0x5C, 0x9F, 0xB8, 0xFA, 0x40, 0xDA, 0x79, 0xD7, 0xF7, 0xDD, + 0xB1, 0x87, 0xEB, 0xDA, 0x9D, 0x98, 0xF9, 0xC0, 0x0D, 0xEA, + 0x94, 0x4A, 0x3D, 0xC1, 0x0B, 0x8E, 0xEF, 0xEB, 0x55, 0xC2, + 0x3E, 0xA0, 0xE7, 0x85, 0x9D, 0xA0, 0x2C, 0xE9, 0xF3, 0xF2, + 0x11, 0x5E, 0x8A, 0xCB, 0x0C, 0x7C, 0x67, 0x33, 0x5B, 0xF4, + 0xC8, 0xEC, 0xCF, 0x08, 0xA8, 0xF6, 0xCD, 0x3B, 0x7E, 0x42, + 0xBE, 0x52, 0x3C, 0x11, 0xD3, 0x3A, 0x73, 0xA5, 0x77, 0xAF, + 0x5E, 0x47, 0x12, 0x4D, 0xE6, 0x54, 0x5A, 0x24, 0xD9, 0x05, + 0xC7, 0x09, 0xD6, 0xD8, 0x0B, 0xDE, 0x65, 0xC5, 0x79, 0xA7, + 0xFB, 0x59, 0x2C, 0x7C, 0xFC, 0x14, 0x95, 0x1B, 0x63, 0xDE, + 0xCC, 0x28, 0x1F, 0xA2, 0x4B, 0x48, 0x09, 0x7E, 0x64, 0x37, + 0x5C, 0xFB, 0xC7, 0x12, 0x90, 0xA9, 0x3B, 0x27, 0x4D, 0x62, + 0x5C, 0xA9, 0x99, 0x87, 0xF8, 0x50, 0x6E, 0xCF, 0xAD, 0x7E, + 0x2C, 0x3F, 0xB1, 0x66, 0xFB, 0xCD, 0x13, 0xBC, 0x5A, 0x08, + 0x8D, 0xA4, 0x65, 0xB4, 0xFC, 0xF9, 0xA9, 0x50, 0x95, 0x59, + 0x9C, 0x39, 0x2B, 0x58, 0xD2, 0x6D, 0xAD, 0x1B, 0x7D, 0xA8, + 0x1E, 0x82, 0x3A, 0x1C, 0x22, 0x3A, 0x22, 0x79, 0x41, 0x4A, + 0x8A, 0x54, 0xF1, 0xBA, 0x87, 0xE2, 0xC5, 0x40, 0x0D, 0xFF, + 0x80, 0x57, 0xE5, 0xB3, 0x53, 0xDE, 0x04, 0x60, 0x0C, 0xFF, + 0x1C, 0x98, 0x33, 0xE9, 0xAD, 0x22, 0xCD, 0x3C, 0x1E, 0xB4, + 0x8B, 0x98, 0x94, 0xA2, 0x62, 0xDE, 0x69, 0x2B, 0x09, 0xE0, + 0x4F, 0x4A, 0x4A, 0x42, 0xF7, 0xC2, 0xFC, 0x8C, 0x28, 0x3D, + 0xD7, 0x04, 0x7F, 0x3B, 0x51, 0xA4, 0xF6, 0x7D, 0x0D, 0xC4, + 0x6B, 0xAB, 0x62, 0xFB, 0x88, 0x13, 0x5E, 0xF5, 0x37, 0x41, + 0xB1, 0xDB, 0xF6, 0x9D, 0xCE, 0xD6, 0xA3, 0x95, 0x05, 0x13, + 0xB8, 0x10, 0xDE, 0x55, 0xB6, 0x56, 0xB4, 0x54, 0x9F, 0x5B, + 0x7A, 0x42, 0x2D, 0x27, 0xDB, 0xAB, 0x70, 0x1E, 0x65, 0x76, + 0x40, 0xA1, 0x06, 0x98, 0xA6, 0x7C, 0xD3, 0x0A, 0x9F, 0xE4, + 0x31, 0xEF, 0x97, 0xBB, 0xE6, 0x70, 0xDA, 0x0A, 0x12, 0x35, + 0xD9, 0x98, 0xF6, 0x2F, 0xD3, 0x2B, 0x95, 0xB0, 0x1C, 0xA1, + 0x30, 0x69, 0x14, 0x27, 0xCB, 0x9F, 0xEB, 0x9E, 0xDF, 0x15, + 0x04, 0xF5, 0x93, 0xA7, 0x8D, 0x65, 0x6A, 0x4A, 0xA4, 0x1C, + 0x17, 0x0C, 0x09, 0x6B, 0xFE, 0x2A, 0x66, 0xD9, 0x0A, 0xFA, + 0xAE, 0x44, 0x5C, 0xB7, 0x90, 0x30, 0xB8, 0xBC, 0xCE, 0xC5, + 0x00, 0x47, 0x09, 0xE3, 0x8C, 0xF6, 0x5E, 0x41, 0x62, 0x10, + 0xAB, 0x18, 0xA6, 0xB9, 0x88, 0x6A, 0xD6, 0x8F, 0xF1, 0x17, + 0xDF, 0x68, 0xB1, 0xE5, 0x5F, 0x53, 0x17, 0xAC, 0x07, 0x9B, + 0x65, 0x96, 0xAE, 0x0B, 0x3F, 0x5A, 0x20, 0x83, 0xC4, 0xAB, + 0x83, 0x3B, 0xEF, 0x90, 0x9A, 0x27, 0x4D, 0x83, 0x77, 0xE9, + 0x4A, 0x98, 0xE9, 0x9D, 0x9C, 0xAA, 0x15, 0xCE, 0xDB, 0xA8, + 0x88, 0x44, 0xAF, 0xA0, 0x6E, 0x2F, 0x5D, 0x90, 0x0F, 0x74, + 0x43, 0xE0, 0x83, 0x3D, 0xD3, 0xB2, 0x99, 0x24, 0x43, 0x76, + 0x21, 0x93, 0x1B, 0x2E, 0x10, 0xF5, 0x64, 0x2E, 0x76, 0x33, + 0x6A, 0xF1, 0xF9, 0x85, 0x3B, 0xC2, 0x42, 0x0F, 0x35, 0x66, + 0x87, 0x8B, 0x9A, 0x34, 0x0E, 0xF0, 0xA7, 0xCE, 0x0C, 0x04, + 0x67, 0x64, 0xA5, 0xFC, 0x29, 0x9F, 0xE6, 0x50, 0x97, 0xA8, + 0x28, 0xF5, 0x90, 0xFC, 0xD0, 0x7C, 0xBC, 0x4D, 0x1F, 0x67, + 0x04, 0xFB, 0x7F, 0x5C, 0x13, 0x4E, 0xF8, 0x7F, 0x75, 0xC7, + 0x6F, 0x82, 0xD9, 0xA6, 0x63, 0xF6, 0xAA, 0x57, 0xDD, 0xF1, + 0xDE, 0x11, 0x09, 0x9C, 0xF5, 0x93, 0xDA, 0x7C, 0x1C, 0xCD, + 0xCE, 0x89, 0xDB, 0x23, 0xCE, 0x7D, 0x8E, 0x7A, 0xED, 0xB7, + 0x11, 0x4B, 0x75, 0x32, 0xDA, 0x9A, 0x18, 0xFB, 0xF0, 0x3C, + 0x51, 0xCA, 0x46, 0x16, 0x05, 0x56, 0xE9, 0x4B, 0x96, 0x30, + 0xDB, 0x20, 0xF6, 0xD9, 0x4E, 0x28, 0x6D, 0x4E, 0x41, 0x3D, + 0x4A, 0xA6, 0x94, 0x21, 0xC7, 0xB8, 0xB2, 0x9E, 0xE6, 0x58, + 0x43, 0x2D, 0xBC, 0xC9, 0x7A, 0x2A, 0xF9, 0xAA, 0xFF, 0xDA, + 0x80, 0xA5, 0x0A, 0x9F, 0xFB, 0x04, 0xB7, 0x34, 0x9E, 0xAC, + 0xAC, 0x05, 0x5E, 0xB4, 0xDD, 0xBB, 0xA7, 0xF3, 0x04, 0x7A, + 0xD6, 0x6A, 0xC6, 0x9E, 0x34, 0xB1, 0x5E, 0xAD, 0x76, 0x3E, + 0x41, 0x8D, 0xEE, 0xE5, 0x31, 0x59, 0xA0, 0xB9, 0x80, 0x6B, + 0xFC, 0x79, 0x93, 0xB7, 0x03, 0xED, 0xF7, 0x2A, 0x7F, 0xFC, + 0xC1, 0xC7, 0x6B, 0x4B, 0xA2, 0x35, 0x6D, 0xC2, 0xB5, 0x47, + 0x2E, 0x4E, 0x0F, 0x6B, 0xD1, 0x3F, 0xAF, 0x21, 0x5E, 0x6B, + 0x9A, 0x8D, 0x82, 0xD3, 0x2D, 0xD4, 0xF2, 0x95, 0xE4, 0xB3, + 0x09, 0x6B, 0x60, 0x86, 0x27, 0x45, 0x86, 0x19, 0x41, 0x2E, + 0x7A, 0x11, 0xF1, 0x6C, 0x7D, 0x6D, 0x26, 0x5B, 0x08, 0x2D, + 0xC0, 0xBE, 0x27, 0xC5, 0x8F, 0x53, 0xB4, 0x15, 0x74, 0x4B, + 0x3A, 0x29, 0x5D, 0xCD, 0xBC, 0x28, 0x0A, 0xC4, 0xC3, 0x12, + 0x22, 0x72, 0xA4, 0x7D, 0xA7, 0x19, 0xC2, 0xAB, 0xA9, 0x80, + 0xEC, 0x3C, 0x9F, 0x84, 0xB4, 0xE1, 0xD1, 0x41, 0x40, 0xC9, + 0x65, 0x66, 0x87, 0x49, 0x1F, 0xAD, 0x8D, 0xAD, 0xE4, 0x78, + 0xEA, 0x80, 0x2C, 0x8D, 0xC8, 0x0B, 0x4D, 0x7E, 0x2A, 0x15, + 0x85, 0x4B, 0xF6, 0xC4, 0x08, 0x9A, 0xC1, 0xC5, 0x4B, 0x30, + 0x50, 0xB5, 0x0D, 0xEA, 0x3A, 0xD6, 0x3C, 0xF9, 0x68, 0xC5, + 0x36, 0x52, 0xCB, 0x5A, 0x34, 0xD3, 0x6A, 0x88, 0x2E, 0x1A, + 0x25, 0x7A, 0x51, 0x8B, 0xC4, 0x2D, 0x7F, 0x92, 0x95, 0xB1, + 0x36, 0xE6, 0x57, 0xDC, 0xCF, 0xFA, 0x32, 0xD1, 0x26, 0x57, + 0x7C, 0xB6, 0x0A, 0x19, 0x88, 0xD9, 0x3D, 0x4D, 0x8D, 0x82, + 0x6B, 0xDE, 0xC8, 0x98, 0xB8, 0xAC, 0xC9, 0xF8, 0xAC, 0x44, + 0x4A, 0x8F, 0x72, 0x22, 0xB3, 0x90, 0x9A, 0x94, 0x09, 0x11, + 0xAA, 0x12, 0x85, 0x43, 0xBD, 0x37, 0x1E, 0x1A, 0x2C, 0x8D, + 0x8E, 0xB1, 0x55, 0xB7, 0x3A, 0xD5, 0x3D, 0xD8, 0xC0, 0xDB, + 0xEC, 0xAA, 0xD1, 0x46, 0xED, 0xBB, 0xC7, 0x29, 0x77, 0xF0, + 0x01, 0x20, 0xCA, 0xC7, 0x60, 0x10, 0x52, 0x7C, 0x02, 0x92, + 0x6D, 0x2F, 0xDE, 0x9E, 0xA2, 0x51, 0xF5, 0x19, 0x9A, 0x96, + 0x7E, 0x7B, 0xB5, 0x1F, 0x74, 0x98, 0xAB, 0x13, 0xDD, 0xD7, + 0x57, 0xAE, 0x7E, 0x7A, 0x27, 0x12, 0x53, 0x80, 0x64, 0xB8, + 0xED, 0x6D, 0x5C, 0x36, 0xBC, 0xBE, 0x9F, 0x5C, 0x98, 0xB1, + 0x1B, 0xAA, 0xE7, 0xC1, 0x9B, 0x13, 0x8D, 0x8C, 0x97, 0xCB, + 0xE9, 0x7E, 0x45, 0x23, 0x3C, 0xDA, 0x72, 0x91, 0x89, 0x97, + 0xBE, 0x40, 0x69, 0x5E, 0x13, 0xEC, 0x11, 0xA6, 0x1C, 0x31, + 0x37, 0x00, 0xAB, 0x47, 0x27, 0x6F, 0xC0, 0xF3, 0xF6, 0xF7, + 0xF6, 0x53, 0x80, 0x03, 0x08, 0x43, 0xC8, 0x1C, 0x7C, 0x69, + 0xF9, 0xE8, 0xE0, 0x41, 0x6C, 0x83, 0x5E, 0xAE, 0xFA, 0x1D, + 0x7B, 0xE8, 0x0F, 0x37, 0x5D, 0x72, 0x70, 0x27, 0x43, 0x1D, + 0x03, 0x47, 0xC9, 0xC4, 0xE6, 0xFA, 0xAA, 0x82, 0x52, 0x31, + 0xD6, 0xCD, 0x46, 0xFA, 0x6A, 0x0A, 0x8D, 0xC5, 0x1A, 0x56, + 0xDB, 0xBA, 0x6E, 0x53, 0xF4, 0x0F, 0xA7, 0x12, 0x47, 0x2C, + 0xBE, 0x02, 0xD8, 0xE0, 0xB5, 0x7C, 0xE7, 0xCA, 0x22, 0x1E, + 0x9F, 0x79, 0xA7, 0x10, 0x3B, 0x6B, 0x00, 0x71, 0xE6, 0xBC, + 0x52, 0x9F, 0xD9, 0x20, 0xE8, 0x96, 0xB1, 0xE6, 0x1A, 0x36, + 0x83, 0x62, 0x01, 0x2E, 0xB4, 0xA9, 0xB5, 0x62, 0xDA, 0xA5, + 0x57, 0x21, 0xBA, 0x6A, 0xB0, 0x80, 0x3F, 0x78, 0xFD, 0x50, + 0x22, 0x20, 0x4C, 0x78, 0xB4, 0x02, 0x9E, 0x22, 0x18, 0x3D, + 0x65, 0xB9, 0x4B, 0x4A, 0x73, 0x3F, 0xBA, 0x77, 0x30, 0xFB, + 0x11, 0x0A, 0xD0, 0x8A, 0xF2, 0xD6, 0x12, 0x0F, 0x4E, 0x7D, + 0x21, 0x16, 0xC4, 0x10, 0xE3, 0xA9, 0xCB, 0x2D, 0xE7, 0xD4, + 0x8F, 0x01, 0xA2, 0x27, 0xA5, 0xA1, 0xBC, 0x48, 0x26, 0x16, + 0x9A, 0x20, 0xF5, 0x20, 0x62, 0xA9, 0xDE, 0x63, 0x21, 0x62, + 0xE4, 0x6D, 0xE4, 0xE7, 0x20, 0xA4, 0xC1, 0x3D, 0xEB, 0x38, + 0xF5, 0x4B, 0x86, 0xEA, 0xEE, 0xDF, 0x5C, 0xE8, 0x94, 0x0C, + 0x59, 0xEA, 0x7E, 0x72, 0xC9, 0xB9, 0xB7, 0x9A, 0xFB, 0x19, + 0x0B, 0x54, 0x65, 0xAC, 0x0A, 0xBE, 0x79, 0xE1, 0x39, 0x74, + 0x26, 0x13, 0x13, 0x5F, 0x78, 0x97, 0x1E, 0x3F, 0x3A, 0x50, + 0x5D, 0x00, 0x68, 0xD2, 0x6D, 0x19, 0x5F, 0xD0, 0xEC, 0x67, + 0x0E, 0x60, 0x07, 0x4B, 0x4D, 0xDE, 0x21, 0x5F, 0x7F, 0x07, + 0xCB, 0x76, 0xE9, 0xD4, 0x19, 0x7C, 0x12, 0x9E, 0x21, 0xA4, + 0x23, 0xAE, 0xB2, 0x0A, 0xE0, 0x59, 0xF1, 0xAF, 0xE2, 0x80, + 0x41, 0x83, 0x8C, 0x64, 0xB3, 0xD0, 0x76, 0xF4, 0xA5, 0x5D, + 0xC0, 0x0D, 0x14, 0x44, 0xD7, 0xB8, 0x82, 0xA2, 0x90, 0x41, + 0x16, 0x96, 0xA9, 0x8B, 0x86, 0x72, 0xB5, 0xB0, 0x62, 0x25, + 0x00, 0x03, 0x95, 0xD4, 0x8B, 0xBC, 0x7E, 0x06, 0x68, 0x2D, + 0x68, 0xD2, 0xE4, 0xA1, 0x85, 0x96, 0xB6, 0xB5, 0x13, 0xA0, + 0x1F, 0xBE, 0xC6, 0x76, 0xC8, 0x51, 0x73, 0x0A, 0x02, 0x9D, + 0xDC, 0x76, 0x98, 0xF2, 0x1A, 0x9F, 0x98, 0xE1, 0x3E, 0x49, + 0x62, 0xBA, 0x64, 0xF8, 0x6D, 0x76, 0xD9, 0x3A, 0x06, 0x2E, + 0x91, 0xDA, 0x86, 0xBC, 0x39, 0xA1, 0xD1, 0xA2, 0xC6, 0xA4, + 0x50, 0x99, 0x5F, 0x89, 0x16, 0x2E, 0x2C, 0x86, 0x8F, 0x97, + 0x0D, 0x93, 0xF8, 0xF1, 0xB3, 0xD2, 0x10, 0x9D, 0x77, 0xF9, + 0x3C, 0xAF, 0x49, 0x03, 0xBE, 0xCF, 0x2B, 0x23, 0x5E, 0x77, + 0x42, 0xFB, 0xA4, 0xE7, 0x52, 0x37, 0x8A, 0x4B, 0xC4, 0x62, + 0x28, 0x5B, 0x0F, 0xD3, 0x14, 0x21, 0xBE, 0xD3, 0x5B, 0x10, + 0x1D, 0x42, 0x95, 0x4F, 0xB8, 0x82, 0xC0, 0xDE, 0xD7, 0xF5, + 0xD2, 0x6E, 0x86, 0x44, 0x61, 0xA7, 0xF2, 0x17, 0x42, 0xB2, + 0xEC, 0x04, 0x1D, 0x38, 0x08, 0x37, 0xD5, 0x98, 0xBC, 0xB8, + 0x4B, 0xCF, 0x17, 0xB2, 0x73, 0xB3, 0x52, 0xCF, 0x70, 0x2E, + 0xAA, 0xF0, 0x85, 0xFD, 0x9C, 0x67, 0x19, 0x87, 0x88, 0x0C, + 0xA6, 0x7D, 0x96, 0x31, 0x56, 0xE6, 0x8B, 0x2B, 0xC4, 0x6C, + 0x04, 0x85, 0xD2, 0xC3, 0x28, 0x1A, 0xDB, 0x91, 0x12, 0xE0, + 0xE5, 0x88, 0x72, 0x67, 0xF2, 0x58, 0xFC, 0x81, 0xA6, 0x19, + 0x0F, 0xC7, 0xD5, 0x6E, 0xA2, 0x9D, 0xBF, 0x56, 0xAC, 0x47, + 0xD0, 0xEE, 0x5D, 0xE4, 0x8B, 0xEB, 0x78, 0x36, 0x85, 0x86, + 0x71, 0x28, 0xA3, 0x9F, 0xD0, 0x67, 0x87, 0x0B, 0xF5, 0xC3, + 0x26, 0x67, 0xE9, 0xCA, 0xA8, 0xCF, 0x70, 0xF5, 0x45, 0x37, + 0x4D, 0x4A, 0x76, 0xE4, 0x95, 0xAA, 0x62, 0xF8, 0x02, 0x49, + 0xD8, 0x81, 0xA6, 0x7C, 0x02, 0xC1, 0x66, 0xAE, 0xC5, 0x27, + 0x2D, 0x1E, 0x42, 0x51, 0xA9, 0x0B, 0xC0, 0xFD, 0x13, 0xE0, + 0x12, 0x54, 0x33, 0xBC, 0x26, 0xE4, 0xF7, 0x9A, 0xB7, 0xEE, + 0x52, 0x08, 0xF8, 0x58, 0x7B, 0xE8, 0xA0, 0x70, 0x87, 0x96, + 0x42, 0x12, 0xF6, 0x92, 0x2B, 0x48, 0x1E, 0x8E, 0x1A, 0x4E, + 0x04, 0x0C, 0xA6, 0x79, 0x67, 0x22, 0x23, 0xDB, 0x87, 0xE7, + 0x97, 0x87, 0xEE, 0x2C, 0xC6, 0x2B, 0x1D, 0x89, 0xB1, 0xC2, + 0x77, 0x10, 0x79, 0x43, 0x61, 0x27, 0xB1, 0x05, 0x08, 0xA2, + 0xCD, 0x1D, 0x89, 0x60, 0x3B, 0x36, 0x4D, 0xED, 0x44, 0x63, + 0x8F, 0x6A, 0xDA, 0x31, 0xF3, 0x05, 0x7F, 0xC6, 0xDD, 0x85, + 0x22, 0xEB, 0x2F, 0x25, 0x6D, 0x41, 0xCE, 0x28, 0xBC, 0x64, + 0x88, 0x0D, 0xD2, 0x2F, 0xC8, 0x93, 0x40, 0xAB, 0xAC, 0x81, + 0x5E, 0xCA, 0xD7, 0x2E, 0x37, 0xBF, 0x60, 0xC1, 0xDF, 0x85, + 0xA8, 0x09, 0x2D, 0xE0, 0x21, 0x23, 0xBC, 0xD4, 0x2B, 0x3F, + 0xD3, 0x42, 0x4E, 0xAC, 0xA8, 0x22, 0x32, 0x6E, 0x08, 0x9F, + 0x91, 0xF3, 0x25, 0x1C, 0x41, 0x34, 0x43, 0x17, 0x50, 0xF5, + 0x34, 0xA5, 0x26, 0x84, 0x94, 0x53, 0x16, 0xF4, 0x36, 0xA9, + 0xAE, 0xD9, 0x70, 0x7F, 0xDD, 0xBA, 0x01, 0x74, 0xE5, 0x2F, + 0x7F, 0x75, 0x17, 0x7C, 0x2D, 0x02, 0x0A, 0x3B, 0x60, 0xFF, + 0x3C, 0xB0, 0x4C, 0x7D, 0x76, 0x7A, 0xE9, 0xE6, 0x10, 0xFE, + 0x3B, 0xAE, 0xA8, 0x21, 0x9B, 0x4C, 0x5D, 0xE5, 0xE2, 0xC9, + 0x2B, 0xAE, 0x6F, 0x41, 0xBC, 0xB2, 0xAE, 0xC5, 0x2B, 0xC9, + 0xC1, 0x62, 0xA9, 0x9E, 0xAA, 0x2B, 0xC5, 0x07, 0x76, 0xEC, + 0x68, 0xC6, 0x91, 0x7E, 0xCC, 0x56, 0x4A, 0x43, 0x1B, 0xC4, + 0xC3, 0xAC, 0xF1, 0x48, 0xB7, 0x04, 0xFF, 0xD5, 0x32, 0x9C, + 0x07, 0x2D, 0x4A, 0x82, 0x16, 0xA5, 0xE6, 0x0A, 0x0A, 0x36, + 0xB2, 0xE9, 0x50, 0x6A, 0x80, 0x4D, 0xF7, 0x45, 0xBC, 0x0A, + 0x5D, 0x97, 0xA2, 0x6B, 0x22, 0x07, 0x9E, 0xA9, 0x01, 0x05, + 0xA4, 0x58, 0x0C, 0x93, 0xF8, 0xE1, 0xC8, 0x09, 0xED, 0xEA, + 0x67, 0x99, 0x48, 0x9E, 0xEA, 0xE5, 0xB1, 0x4B, 0xCD, 0x82, + 0x84, 0x4E, 0xDC, 0xF5, 0xB7, 0xE1, 0xF8, 0x3A, 0x39, 0xD4, + 0x0E, 0xBF, 0x36, 0xBE, 0xE9, 0x0B, 0x6C, 0x4F, 0x3C, 0x68, + 0x2F, 0x6B, 0x54, 0x1B, 0x9A, 0x5C, 0x1F, 0x85, 0x99, 0x12, + 0x9E, 0x4C, 0x74, 0xA9, 0x58, 0x69, 0x23, 0xC3, 0xB9, 0x2A, + 0x37, 0xE0, 0x16, 0xBE, 0x2B, 0xB0, 0xFD, 0x79, 0x2D, 0xBC, + 0xFF, 0xFD, 0xDD, 0xEF, 0x13, 0x8A, 0xAB, 0x68, 0xDB, 0x42, + 0x69, 0x9D, 0x10, 0x7C, 0x5C, 0x17, 0x3A, 0x1B, 0x59, 0x66, + 0xEF, 0x2E, 0xBD, 0x2F, 0xAB, 0x0D, 0xBB, 0x6E, 0xB7, 0x44, + 0xE2, 0x09, 0x38, 0x80, 0x92, 0x64, 0x9D, 0x1B, 0xC0, 0xE3, + 0x12, 0xDB, 0x58, 0x17, 0xC5, 0x42, 0x7C, 0x3B, 0x38, 0x2C, + 0x9F, 0xC0, 0xA0, 0x04, 0x60, 0x45, 0xAD, 0x2E, 0xC7, 0xE0, + 0xA9, 0xFF, 0xE5, 0x4A, 0xA8, 0x7E, 0x0F, 0xF0, 0x34, 0x72, + 0xB4, 0xD1, 0x9F, 0x3E, 0xE4, 0x63, 0xC2, 0x4B, 0xEA, 0x88, + 0x75, 0xA3, 0xD1, 0xD1, 0x7E, 0x53, 0x2A, 0xCC, 0x2E, 0x66, + 0x56, 0x31, 0x3E, 0xF9, 0xC9, 0x6C, 0x23, 0x67, 0x1E, 0x06, + 0xEB, 0xB7, 0x69, 0xDB, 0x38, 0xBB, 0xEB, 0xD3, 0x0B, 0x03, + 0x9C, 0x0F, 0x1A, 0x93, 0x56, 0x2A, 0x31, 0xF5, 0xB8, 0x0E, + 0xD4, 0xA0, 0x2D, 0xCF, 0xC1, 0x30, 0xAA, 0x80, 0xA5, 0xD3, + 0x17, 0x1A, 0xA0, 0x78, 0xA8, 0x9C, 0x65, 0xB0, 0xF1, 0xE0, + 0xF7, 0xD8, 0xB6, 0x01, 0xC4, 0x06, 0xAC, 0x7E, 0x0C, 0xFF, + 0x96, 0xE9, 0xC2, 0x11, 0xD6, 0xCB, 0x1C, 0x7E, 0xCF, 0xC1, + 0x42, 0xEA, 0xE6, 0xB8, 0xF7, 0x21, 0x09, 0x4E, 0xD4, 0x6F, + 0xDA, 0xA7, 0xF4, 0xCD, 0x37, 0xC2, 0x7F, 0x44, 0x9B, 0xDC, + 0xE4, 0x0D, 0xD3, 0x25, 0x9C, 0x68, 0x73, 0x66, 0x53, 0x69, + 0xD8, 0xC8, 0x80, 0xAF, 0x49, 0xFB, 0x11, 0x8C, 0x27, 0xDE, + 0xAC, 0xFB, 0x26, 0x9D, 0x68, 0xB3, 0x71, 0xBD, 0xD4, 0x0F, + 0xE3, 0xAE, 0x65, 0x9A, 0x24, 0x87, 0xC7, 0x8A, 0xA3, 0x6E, + 0x78, 0x92, 0x22, 0x10, 0xA5, 0xD3, 0xE7, 0x4A, 0x92, 0x71, + 0xFA, 0xA8, 0x7F, 0x5A, 0xFD, 0xB4, 0x8D, 0x7C, 0x72, 0xE4, + 0xF9, 0x7C, 0x87, 0x5D, 0x93, 0xD3, 0x59, 0xAD, 0xC8, 0x3A, + 0xF5, 0x9E, 0x5D, 0x8C, 0x5F, 0xC9, 0xF2, 0x42, 0xA4, 0x00, + 0x76, 0x66, 0xB5, 0xF0, 0x8A, 0xD5, 0x70, 0xC8, 0xB6, 0x95, + 0x27, 0x6C, 0x6F, 0xA9, 0x6C, 0xEC, 0xDF, 0x7D, 0x7A, 0x43, + 0x65, 0x99, 0xA3, 0xED, 0x9F, 0x06, 0xB1, 0x3F, 0x76, 0x99, + 0x0F, 0xFD, 0x24, 0x06, 0x08, 0xF2, 0x1F, 0x21, 0xD1, 0x2C, + 0x2F, 0xBF, 0x6D, 0x3C, 0xEB, 0x95, 0x88, 0xFC, 0x58, 0x1C, + 0x57, 0x1C, 0x57, 0xD4, 0x64, 0x87, 0xBF, 0x1F, 0xF7, 0x30, + 0x66, 0x97, 0x72, 0x8B, 0xA2, 0x57, 0x46, 0x06, 0x10, 0xA6, + 0x53, 0xF8, 0x35, 0x43, 0x9C, 0xD9, 0xBA, 0x86, 0x04, 0xFA, + 0x3C, 0x5B, 0xBF, 0x8F, 0x6C, 0x90, 0xC3, 0xE9, 0xC8, 0x9D, + 0xE7, 0x56, 0x0C, 0xED, 0x63, 0x41, 0xA2, 0xFB, 0x50, 0xF4, + 0x05, 0xC4, 0xFC, 0xA4, 0x02, 0x3E, 0xC3, 0x49, 0x49, 0xDA, + 0x09, 0xA2, 0xDA, 0xCA, 0x48, 0x2C, 0x00, 0x73, 0x3E, 0x69, + 0x94, 0x04, 0xF9, 0x10, 0x57, 0x69, 0xC7, 0xFF, 0x6F, 0xBB, + 0x5E, 0x83, 0xA4, 0xA2, 0xB8, 0x18, 0x14, 0xA5, 0x12, 0x70, + 0x4A, 0x4A, 0x4D, 0x76, 0xC2, 0xF9, 0xE7, 0x8A, 0xD8, 0x2F, + 0xB2, 0xDD, 0x96, 0xE6, 0x5A, 0x95, 0x0D, 0x6B, 0x97, 0xF9, + 0xF0, 0xDB, 0xDE, 0x5C, 0x41, 0x89, 0x64, 0x07, 0xCA, 0x81, + 0x58, 0x47, 0x65, 0xBE, 0x2C, 0x88, 0x62, 0x56, 0x93, 0xDD, + 0xE9, 0xC3, 0x4C, 0xDE, 0x7B, 0x6A, 0x05, 0xAD, 0x4D, 0x71, + 0xAF, 0x4F, 0xF0, 0x3B, 0xD4, 0x12, 0x03, 0x12, 0x95, 0x6E, + 0xB5, 0x03, 0xBF, 0xAC, 0x62, 0x6F, 0xC7, 0xA1, 0x42, 0xDD, + 0xC7, 0x5E, 0xE8, 0xAB, 0x5A, 0x29, 0x1A, 0xA9, 0xFA, 0x8A, + 0x8C, 0xFA, 0x8D, 0x84, 0x96, 0xEC, 0xDD, 0x10, 0xAC, 0x71, + 0x5B, 0xBC, 0x96, 0x36, 0x08, 0x4E, 0xA4, 0xC8, 0x99, 0xAA, + 0x29, 0x87, 0x30, 0xC1, 0x9A, 0xD8, 0x8E, 0xF1, 0xDF, 0x78, + 0x08, 0x95, 0xFE, 0x75, 0x80, 0x77, 0xE7, 0x52, 0xE3, 0xC8, + 0x31, 0xC6, 0xAC, 0x3A, 0x19, 0xB5, 0x34, 0xEF, 0x34, 0x9C, + 0x1F, 0x5D, 0xFE, 0x65, 0x32, 0x46, 0xFC, 0xD8, 0x2D, 0x26, + 0x0D, 0x04, 0x5B, 0x4D, 0x90, 0x17, 0x8D, 0x4E, 0xBB, 0x25, + 0x69, 0x00, 0x6C, 0xD1, 0xC9, 0xB7, 0x97, 0x32, 0xB4, 0xED, + 0x87, 0x92, 0xDB, 0x63, 0x42, 0x63, 0xED, 0xF9, 0x83, 0x1B, + 0x2B, 0x58, 0xA8, 0x0F, 0x2A, 0x76, 0x9C, 0x5A, 0x2C, 0x80, + 0x02, 0x32, 0x66, 0xD0, 0x6D, 0xBF, 0x07, 0x72, 0x82, 0xB5, + 0x57, 0x13, 0x97, 0xCB, 0xD6, 0xF8, 0xF8, 0xCF, 0x7C, 0xCC, + 0xF7, 0x6C, 0xC2, 0xFA, 0xD7, 0x3B, 0xBD, 0xB3, 0x47, 0x9B, + 0x04, 0x49, 0x7F, 0x8A, 0x60, 0x94, 0x02, 0x65, 0xF4, 0x48, + 0xE1, 0xAE, 0x38, 0x5F, 0xB0, 0xA4, 0x33, 0x10, 0x32, 0x8F, + 0xD8, 0x12, 0xCF, 0x59, 0x24, 0x32, 0xAB, 0x29, 0x4B, 0x73, + 0x99, 0x63, 0x05, 0xF3, 0x50, 0x8D, 0xC3, 0x9D, 0x85, 0x41, + 0x46, 0x9E, 0x7E, 0xEA, 0x2B, 0x61, 0x7C, 0x15, 0x62, 0xE1, + 0x3C, 0xA4, 0x9E, 0x03, 0xD2, 0x33, 0xC0, 0xEE, 0x76, 0x84, + 0xC7, 0x57, 0x33, 0xBE, 0x7A, 0x6C, 0x30, 0x97, 0x51, 0x14, + 0xA7, 0xED, 0xE6, 0x14, 0xD9, 0x00, 0x51, 0x8A, 0xBC, 0x9E, + 0xC0, 0x82, 0x14, 0xC2, 0x8C, 0x98, 0xC2, 0xE7, 0x5E, 0x81, + 0xF8, 0x3B, 0x77, 0x2B, 0x96, 0x82, 0xF7, 0xC3, 0x90, 0x9C, + 0x5E, 0xBF, 0xD6, 0xAE, 0x9E, 0xE2, 0x3A, 0x2C, 0x16, 0x2F, + 0xBC, 0x82, 0x43, 0x2A, 0x5C, 0xD6, 0x6F, 0xB8, 0xDE, 0xEB, + 0x37, 0x3F, 0x0E, 0x77, 0x72, 0x2C, 0x89, 0x96, 0x86, 0x21, + 0xDA, 0xD0, 0x21, 0x9A, 0x38, 0x52, 0xD6, 0x42, 0xA1, 0x64, + 0xC7, 0xA0, 0x4A, 0xBD, 0xF6, 0xC7, 0xCE, 0x97, 0xFE, 0xC4, + 0x7A, 0xAA, 0x02, 0xFD, 0x2E, 0x7D, 0x99, 0x12, 0x8C, 0x1E, + 0x0B, 0x88, 0x71, 0xC7, 0x3D, 0x1C, 0xCD, 0x51, 0x86, 0x90, + 0x9F, 0x92, 0x76, 0xB3, 0x20, 0xED, 0x32, 0x5E, 0x04, 0xB7, + 0xAE, 0x93, 0x30, 0x0C, 0x02, 0xE8, 0x05, 0x58, 0xB0, 0x52, + 0xD0, 0x1B, 0xE4, 0x11, 0x9B, 0x4D, 0x94, 0x47, 0xDE, 0x00, + 0xAA, 0x04, 0x6A, 0xCD, 0xB3, 0x97, 0xDA, 0xFE, 0xDC, 0xDA, + 0xA8, 0xD8, 0xF4, 0xCB, 0x80, 0x5F, 0xE8, 0x36, 0x0D, 0x60, + 0x3C, 0xFF, 0xA7, 0x92, 0x6F, 0x12, 0x8E, 0x01, 0x26, 0x58, + 0x72, 0x2E, 0x7E, 0xDD, 0x8C, 0xDF, 0x4E, 0xC8, 0xE7, 0x7C, + 0xA7, 0xBE, 0x2F, 0x44, 0x16, 0x13, 0xB9, 0x2C, 0x91, 0x3B, + 0x4D, 0xD2, 0x0C, 0x19, 0x92, 0x37, 0x33, 0xE1, 0x0A, 0x4B, + 0xC3, 0x41, 0x1A, 0xCF, 0xB1, 0x68, 0x98, 0xEC, 0x11, 0x29, + 0x00, 0x89, 0x82, 0xAC, 0x48, 0xA9, 0x38, 0x37, 0x04, 0x84, + 0x9E, 0x42, 0xB5, 0xBD, 0x4B, 0x30, 0xCB, 0x21, 0x72, 0xBF, + 0xA3, 0x0B, 0x24, 0x27, 0xBE, 0xCD, 0xD1, 0xD0, 0x73, 0x42, + 0x3A, 0x08, 0x70, 0x51, 0xE1, 0x01, 0x72, 0x49, 0xFC, 0xCF, + 0x6A, 0x08, 0x68, 0xE4, 0xA7, 0x72, 0x1B, 0x08, 0xED, 0x31, + 0xEB, 0x75, 0xB6, 0xF7, 0x36, 0x2C, 0x3B, 0xEB, 0x33, 0xFB, + 0x1F, 0x9E, 0xF5, 0x6E, 0xAD, 0x02, 0xF1, 0xFC, 0x04, 0xF8, + 0x0A, 0x4D, 0x5B, 0xFA, 0x6C, 0x30, 0x47, 0x4E, 0x82, 0x45, + 0xC2, 0x05, 0x30, 0x4A, 0xC2, 0xF0, 0x57, 0x12, 0xEB, 0x91, + 0xE8, 0x82, 0xCA, 0xF3, 0x00, 0x16, 0x90, 0x9E, 0x6B, 0xFA, + 0x0F, 0x93, 0x6D, 0x30, 0x52, 0xB2, 0xFB, 0x42, 0x73, 0x28, + 0xFD, 0x27, 0x5B, 0x95, 0x4C, 0x41, 0x62, 0xED, 0x6E, 0x24, + 0xCC, 0xA8, 0xCD, 0x4A, 0xA7, 0x18, 0x37, 0xEF, 0x11, 0xB6, + 0xA9, 0x3F, 0x9B, 0x28, 0xBE, 0xBF, 0x37, 0x20, 0x66, 0x2E, + 0xE0, 0x4F, 0x5E, 0x47, 0xAF, 0xB7, 0x4D, 0xED, 0x05, 0x61, + 0x46, 0x29, 0x2B, 0x1F, 0x83, 0x6C, 0x95, 0xE2, 0x43, 0x72, + 0x91, 0x9C, 0x20, 0xF1, 0xC2, 0x63, 0xA5, 0x4C, 0xF8, 0x7E, + 0xC3, 0x36, 0xE2, 0xCD, 0x20, 0xCF, 0xD5, 0xB7, 0x0D, 0xF9, + 0x42, 0xDA, 0xFA, 0x27, 0x63, 0x77, 0xDD, 0x65, 0x81, 0xB5, + 0xDD, 0x57, 0x77, 0xF2, 0x27, 0x51, 0x52, 0x61, 0x8A, 0x8C, + 0x51, 0x38, 0xBC, 0x68, 0x9C, 0x30, 0x1C, 0x26, 0x9B, 0xF7, + 0x40, 0x93, 0x31, 0xD4, 0xE3, 0x6B, 0x07, 0xAA, 0xA7, 0x17, + 0x02, 0x13, 0x02, 0xCE, 0xCD, 0x39, 0xBD, 0x9D, 0x29, 0xA9, + 0xB7, 0x18, 0xD4, 0x9B, 0x34, 0x64, 0x90, 0x92, 0x5D, 0x56, + 0xDD, 0x29, 0x50, 0x43, 0x55, 0xA7, 0x59, 0x01, 0xC7, 0x11, + 0x84, 0xC4, 0x9F, 0xC3, 0xEF, 0x51, 0x71, 0x7F, 0xB6, 0x1D, + 0x72, 0x4E, 0x10, 0xE3, 0x18, 0x2F, 0xA8, 0xA5, 0x10, 0x33, + 0xEB, 0x2C, 0x62, 0x5D, 0x0E, 0x94, 0x3F, 0x4A, 0xBA, 0x32, + 0x90, 0x37, 0x58, 0x9A, 0x21, 0xE3, 0x08, 0x47, 0x85, 0x1D, + 0xD6, 0x1E, 0xB0, 0x21, 0x87, 0x30, 0xB4, 0x9C, 0xD0, 0x7E, + 0xCD, 0xFE, 0x36, 0x77, 0x32, 0x5D, 0xC1, 0x31, 0x85, 0xE0, + 0xD2, 0x5E, 0x24, 0xB8, 0x0D, 0xFF, 0x18, 0xF2, 0xB7, 0x3E, + 0xB0, 0x29, 0x41, 0x8D, 0x70, 0x06, 0xDC, 0xBC, 0x64, 0x45, + 0x85, 0xBE, 0x7A, 0x84, 0x5A, 0xA5, 0xA2, 0x61, 0xF1, 0x97, + 0x6B, 0xD7, 0x45, 0x9B, 0x50, 0x0C, 0x8C, 0xC5, 0x61, 0x3E, + 0xA8, 0x66, 0x52, 0xD3, 0xF1, 0x57, 0x68, 0x6B, 0xDC, 0x78, + 0x06, 0x81, 0xBE, 0x0E, 0x3B, 0xAA, 0x5D, 0x29, 0x63, 0x1A, + 0xFD, 0x8A, 0xEB, 0xE2, 0x71, 0x1E, 0x2E, 0x17, 0x29, 0x70, + 0xF8, 0x7B, 0xAA, 0x3C, 0xC8, 0x79, 0xA9, 0x9E, 0x86, 0x9A, + 0x29, 0xA1, 0x05, 0xE0, 0x0C, 0x78, 0x47, 0x95, 0xDB, 0x19, + 0x59, 0xFA, 0x05, 0x9A, 0x3F, 0xC4, 0x02, 0xBE, 0x63, 0xD5, + 0x29, 0xED, 0xDF, 0x74, 0x0B, 0xA3, 0x63, 0x4C, 0xBD, 0x87, + 0x83, 0x4D, 0xAF, 0x83, 0x97, 0x80, 0x74, 0xED, 0x4D, 0x55, + 0xEF, 0xE6, 0xD5, 0x41, 0x6B, 0xDF, 0xEB, 0x9B, 0x8F, 0xDA, + 0x5B, 0xD7, 0x52, 0x06, 0x45, 0xF1, 0x0C, 0xC4, 0xDF, 0x42, + 0x8F, 0x50, 0x4A, 0xAC, 0x90, 0xC4, 0xE5, 0x03, 0x7B, 0x46, + 0x96, 0xD8, 0x86, 0x92, 0x0B, 0x00, 0x82, 0x5E, 0x7E, 0x3B, + 0x93, 0xE9, 0xC6, 0x9C, 0xD0, 0x10, 0xBE, 0xBA, 0xB0, 0xFE, + 0xAB, 0x3A, 0xC3, 0x12, 0x97, 0x9D, 0xEC, 0x6B, 0x21, 0x19, + 0x62, 0x19, 0x5B, 0xAC, 0x10, 0x58, 0xD8, 0xC5, 0xBA, 0x11, + 0x87, 0x21, 0xD4, 0x1A, 0xFA, 0xAE, 0x2C, 0x9D, 0xDA, 0xC6, + 0x94, 0x3A, 0xDE, 0xB9, 0xD1, 0x5B, 0xAF, 0x75, 0x9E, 0xE5, + 0x76, 0x73, 0xEB, 0x3D, 0x41, 0x76, 0x6D, 0x86, 0x1A, 0x49, + 0xCD, 0x4D, 0xA4, 0x4E, 0x17, 0xCD, 0xBB, 0x9D, 0x9E, 0x02, + 0xDA, 0x1E, 0xDD, 0x3D, 0xA7, 0xF5, 0x09, 0x3E, 0xD8, 0x63, + 0x0C, 0xD2, 0xE3, 0xEE, 0x73, 0xBD, 0x3F, 0x38, 0x3C, 0xC9, + 0x6F, 0x46, 0xDF, 0x72, 0x78, 0x27, 0x1F, 0x13, 0x37, 0xDF, + 0x07, 0xAF, 0x15, 0xD8, 0x2D, 0x02, 0xD8, 0xC8, 0x93, 0xA1, + 0x43, 0xE1, 0x98, 0xB4, 0xB5, 0x32, 0xA0, 0xBD, 0x57, 0xD6, + 0x7F, 0x0F, 0x32, 0x8E, 0xFD, 0x55, 0xDF, 0x2D, 0x7F, 0xF6, + 0xC0, 0x93, 0x47, 0x1E, 0x30, 0x78, 0x95, 0x26, 0x40, 0xFE, + 0xC2, 0x8A, 0xC5, 0x4F, 0x8F, 0xF3, 0x32, 0xB2, 0x1F, 0xF0, + 0xE5, 0xDA, 0x6C, 0xD0, 0x7A, 0x75, 0x6D, 0x0C, 0xC5, 0xBF, + 0x24, 0x4A, 0xF0, 0x50, 0x34, 0xB5, 0xCD, 0x34, 0x14, 0x38, + 0x7A, 0xDD, 0x56, 0x89, 0x25, 0x9B, 0x6C, 0x90, 0x68, 0x0D, + 0xED, 0x39, 0xDF, 0x23, 0x90, 0xE7, 0x71, 0x20, 0x6F, 0x8B, + 0x83, 0x60, 0xD8, 0x7E, 0x35, 0x30, 0xF5, 0x4F, 0x14, 0x1B, + 0x9A, 0xE7, 0x60, 0x22, 0xB7, 0x42, 0x14, 0x64, 0x98, 0x38, + 0xEC, 0x45, 0xE9, 0x1E, 0xAA, 0x2C, 0xE1, 0x75, 0x13, 0x64, + 0x1E, 0x2E, 0x85, 0x94, 0xA1, 0xC8, 0x82, 0x9F, 0x03, 0xA5, + 0x93, 0x02, 0x4B, 0x7E, 0xD9, 0xEE, 0x9C, 0x68, 0x62, 0x70, + 0x59, 0x65, 0x68, 0x5E, 0xD3, 0x28, 0xDE, 0x50, 0x55, 0xAA, + 0xB8, 0x7B, 0x25, 0x82, 0x79, 0x3E, 0x65, 0xE6, 0x94, 0x59, + 0x88, 0xBE, 0xFC, 0x73, 0xF1, 0x65, 0x4C, 0xB0, 0x18, 0x98, + 0xD9, 0x8F, 0xCE, 0x2F, 0x59, 0xB4, 0x08, 0x65, 0x8D, 0x31, + 0xE0, 0xE6, 0xBE, 0x06, 0x87, 0xD9, 0x7C, 0xCC, 0xEE, 0x13, + 0xD0, 0xA7, 0x05, 0xAC, 0xA7, 0x94, 0xBC, 0xDB, 0x93, 0x6D, + 0x82, 0xA5, 0x76, 0x10, 0x71, 0x1E, 0xB7, 0xE1, 0x45, 0xCB, + 0xD2, 0x04, 0x35, 0x00, 0xD6, 0x4E, 0x24, 0x89, 0x42, 0x8D, + 0x81, 0xD1, 0x92, 0x75, 0xA4, 0x09, 0xFA, 0x66, 0x16, 0xF8, + 0x75, 0x60, 0x8D, 0xF6, 0xDB, 0xF5, 0x6D, 0x67, 0x9E, 0x59, + 0xAB, 0x7A, 0x0A, 0x4D, 0x24, 0xB0, 0xE1, 0x3A, 0x2C, 0x60, + 0x7C, 0xAA, 0xA7, 0x33, 0xF9, 0x8C, 0xFE, 0xBF, 0x0C, 0x39, + 0x26, 0xEB, 0xA3, 0x7A, 0x44, 0xDF, 0x63, 0x0D, 0xDF, 0xBA, + 0x36, 0xE1, 0xB7, 0x08, 0x06, 0xA4, 0x5A, 0xA9, 0x60, 0x84, + 0xA4, 0x17, 0x2B, 0x56, 0x90, 0xCC, 0x16, 0x0A, 0x26, 0xE1, + 0x42, 0xA6, 0x7E, 0x94, 0x2D, 0xC9, 0x94, 0x7A, 0x47, 0xDD, + 0x56, 0x1A, 0x4A, 0x78, 0xF4, 0x62, 0x7D, 0x0D, 0x28, 0x9B, + 0x90, 0x8F, 0x28, 0x57, 0x2A, 0xA0, 0xB8, 0x20, 0xA1, 0xE3, + 0x69, 0x8C, 0x7E, 0xA4, 0xBA, 0x26, 0xF9, 0x01, 0xE0, 0x36, + 0x75, 0x0A, 0x7E, 0x65, 0xA0, 0xB2, 0x1E, 0x62, 0xE9, 0x71, + 0x08, 0x1A, 0x3A, 0xF6, 0xF9, 0xCD, 0x9A, 0xF8, 0xEA, 0x46, + 0x1F, 0x6C, 0xAF, 0xD1, 0x42, 0x57, 0xEF, 0x35, 0x18, 0x90, + 0xB5, 0x7E, 0x9B, 0xFB, 0x5F, 0x08, 0x98, 0x04, 0x86, 0x6F, + 0x3F, 0xC8, 0x75, 0xA8, 0x1A, 0x2C, 0xB2, 0x74, 0x82, 0x2B, + 0x1C, 0x8B, 0x0A, 0x53, 0x0E, 0xCE, 0xDA, 0x02, 0xEF, 0x7E, + 0x25, 0xA7, 0x49, 0x7E, 0xAC, 0xB4, 0xB7, 0xE1, 0xD5, 0xB9, + 0xA2, 0x21, 0x68, 0x67, 0xC2, 0x14, 0xCF, 0x6C, 0x92, 0x7C, + 0x96, 0x9B, 0x7A, 0xCE, 0xE8, 0xC2, 0x9F, 0xA4, 0x73, 0x3C, + 0x7F, 0xBD, 0x5E, 0xBD, 0x38, 0x1F, 0x7D, 0xC3, 0x6C, 0x9C, + 0xF0, 0x96, 0x00, 0xB2, 0xD2, 0x85, 0x36, 0x35, 0xB4, 0x62, + 0x40, 0xA9, 0x1E, 0x7C, 0xBC, 0xE2, 0xA7, 0x55, 0x50, 0xF6, + 0x39, 0x41, 0xFF, 0x31, 0xC2, 0x9B, 0xFA, 0xE5, 0x36, 0x82, + 0xEE, 0x77, 0xCF, 0x2C, 0x18, 0xCF, 0xDA, 0x22, 0x4D, 0x97, + 0xA3, 0x3C, 0x9B, 0xFF, 0x7D, 0x44, 0x55, 0xD2, 0x59, 0x76, + 0xFE, 0x37, 0xF5, 0xF3, 0xD7, 0xED, 0x13, 0x0B, 0x83, 0x70, + 0xC7, 0xDD, 0x9B, 0xF9, 0x8C, 0x2A, 0xA9, 0x4B, 0xD6, 0x31, + 0x47, 0xD3, 0x29, 0x5F, 0x42, 0xF5, 0x26, 0x36, 0x90, 0x9C, + 0xF5, 0xC3, 0x8C, 0x2C, 0x9C, 0x98, 0xBD, 0x2D, 0x4D, 0x2D, + 0x16, 0x2E, 0x10, 0xA4, 0xF2, 0x64, 0xA3, 0xDC, 0x21, 0xC3, + 0x47, 0xAB, 0x86, 0xAC, 0x35, 0x4D, 0x06, 0x0C, 0x3C, 0xB4, + 0xB9, 0xDB, 0x91, 0x0E, 0x63, 0xA5, 0xD0, 0xA6, 0x10, 0x8B, + 0xCE, 0xB9, 0x0C, 0x69, 0xA7, 0x7E, 0x18, 0x1D, 0xAB, 0x3A, + 0x09, 0x60, 0xC2, 0x92, 0x74, 0x7D, 0x3F, 0x68, 0xD9, 0x0D, + 0x68, 0xD1, 0x1A, 0x77, 0xB1, 0x4F, 0xED, 0x04, 0xB9, 0xBF, + 0x58, 0xEF, 0x11, 0xC6, 0xB9, 0x86, 0x60, 0x22, 0xBF, 0x93, + 0xC5, 0xC2, 0x6F, 0x66, 0xB6, 0x84, 0x45, 0xD1, 0x7B, 0x7D, + 0xB4, 0x0E, 0xC3, 0x9D, 0x9B, 0x8D, 0xD0, 0x02, 0xE9, 0x5C, + 0xBE, 0xC1, 0xA1, 0xF6, 0xE1, 0xED, 0xCF, 0xD5, 0x50, 0x85, + 0x05, 0xC7, 0xCE, 0x8B, 0xD3, 0xDC, 0xA6, 0x2D, 0xE2, 0x5E, + 0x66, 0x52, 0x58, 0x6D, 0xCB, 0xE0, 0x58, 0x42, 0x10, 0x0D, + 0x27, 0x25, 0x9D, 0xAB, 0x7D, 0x93, 0xEC, 0x6B, 0xAF, 0x9F, + 0xDA, 0x08, 0x29, 0x6C, 0x8C, 0x45, 0x03, 0x70, 0xB7, 0x6A, + 0xB0, 0xA7, 0xED, 0x18, 0xE3, 0x4C, 0xAD, 0x6E, 0x75, 0x89, + 0x21, 0xD8, 0xDB, 0x46, 0xBA, 0x65, 0x32, 0x8E, 0xA4, 0x04, + 0x77, 0x61, 0x2E, 0x8C, 0xE2, 0x3C, 0x9B, 0xD4, 0x35, 0x7E, + 0x8F, 0x3E, 0x0C, 0x70, 0x82, 0x87, 0xB3, 0xA2, 0xAF, 0x2F, + 0xC5, 0x82, 0x5F, 0x0E, 0xB2, 0x53, 0x9E, 0x30, 0x8B, 0x57, + 0xEF, 0xBD, 0xB5, 0xFD, 0xF9, 0x2C, 0x9A, 0x74, 0xEA, 0xCF, + 0x80, 0x3A, 0x8D, 0x7B, 0xB0, 0xD1, 0x6A, 0x76, 0xA1, 0xCF, + 0x97, 0xA5, 0x61, 0xE4, 0xB2, 0x09, 0x97, 0xF3, 0x07, 0x8A, + 0xC4, 0x91, 0x39, 0xFA, 0x03, 0xED, 0x8A, 0x2F, 0xAC, 0x34, + 0x2D, 0x4E, 0xAD, 0x33, 0x95, 0xA1, 0xEB, 0xE5, 0x60, 0x4B, + 0x13, 0x6F, 0x7E, 0x28, 0x7D, 0xFC, 0x78, 0x05, 0x1C, 0xB5, + 0x5C, 0x58, 0x84, 0x5D, 0xF6, 0x54, 0xC7, 0xD0, 0xDD, 0xBA, + 0x41, 0xF9, 0x3B, 0x92, 0x9F, 0xDA, 0x5F, 0xF6, 0xD1, 0x29, + 0x8B, 0xD5, 0xE0, 0xFD, 0x4E, 0x15, 0xD5, 0xC9, 0x99, 0x85, + 0xFB, 0x3E, 0x0D, 0x77, 0x8B, 0x1A, 0x00, 0x57, 0x8C, 0x66, + 0xC4, 0xFF, 0x98, 0x1B, 0x13, 0x61, 0xFB, 0xCC, 0xDA, 0x1E, + 0x75, 0x0F, 0x6D, 0xAE, 0xD6, 0xDE, 0x22, 0x43, 0xDF, 0xC9, + 0xD0, 0x2D, 0xEE, 0x4A, 0x0B, 0xAF, 0x7C, 0x69, 0xA7, 0x15, + 0x64, 0xB1, 0xB0, 0x00, 0x99, 0x48, 0x20, 0x3D, 0x93, 0xEF, + 0xE6, 0xAA, 0x57, 0x45, 0x65, 0x24, 0xA9, 0xA0, 0xBE, 0xCD, + 0xCC, 0x1A, 0xF6, 0xA1, 0xA6, 0x2C, 0x40, 0x35, 0x17, 0x31, + 0xD8, 0xF9, 0x03, 0x8B, 0x2D, 0x8A, 0x9F, 0x27, 0x13, 0xD3, + 0x03, 0xC1, 0x9A, 0xD4, 0xF7, 0xA8, 0xBE, 0x54, 0x91, 0x24, + 0xE6, 0x8E, 0xE1, 0x10, 0x44, 0x0A, 0x75, 0x54, 0x5C, 0x44, + 0x5D, 0x79, 0x82, 0x59, 0x80, 0x79, 0x2F, 0x85, 0xF9, 0x7F, + 0x24, 0x58, 0xBD, 0x5E, 0x2F, 0x65, 0x08, 0x7C, 0xF3, 0x48, + 0x01, 0x9F, 0x83, 0x93, 0xB1, 0x9D, 0xFE, 0x17, 0xE5, 0x4A, + 0xE1, 0x32, 0x2E, 0xEA, 0x71, 0x30, 0x9A, 0x09, 0xFA, 0x4D, + 0xD1, 0xFD, 0x09, 0x0B, 0x36, 0xBD, 0x13, 0xEB, 0x9D, 0xF3, + 0x01, 0x4C, 0x64, 0xFC, 0x50, 0xBF, 0x4C, 0x24, 0xDE, 0xC9, + 0x50, 0x56, 0xBF, 0x61, 0xA9, 0x04, 0xCE, 0x71, 0x54, 0xCC, + 0x6B, 0xB2, 0x1C, 0xDA, 0x38, 0x1A, 0xE3, 0xA2, 0xE3, 0x55, + 0x93, 0x71, 0x79, 0xE3, 0xFB, 0xC3, 0xE5, 0xFD, 0x75, 0x57, + 0x1E, 0x3D, 0x21, 0x09, 0x84, 0x21, 0xB7, 0x97, 0xBF, 0x8A, + 0x77, 0x21, 0xA6, 0x8D, 0xA7, 0x46, 0x8E, 0x19, 0x7B, 0x08, + 0xB5, 0x5C, 0x11, 0x48, 0xFF, 0xD1, 0x99, 0x2A, 0xEC, 0x81, + 0x2C, 0x63, 0x46, 0x1A, 0x9A, 0xA8, 0x0A, 0x7E, 0xF9, 0x62, + 0x13, 0x20, 0x1B, 0x63, 0x6E, 0x0D, 0x30, 0xDB, 0x80, 0xCE, + 0x6C, 0x30, 0x74, 0x9A, 0x61, 0x29, 0x38, 0x34, 0xE0, 0xF1, + 0xD7, 0x8A, 0x91, 0x77, 0x50, 0x92, 0x13, 0xAC, 0x77, 0x95, + 0x3B, 0x9A, 0xCD, 0xDA, 0x69, 0x6F, 0x18, 0xCB, 0x0E, 0x3A, + 0x06, 0x38, 0x6A, 0x4E, 0xF2, 0xFA, 0x92, 0xB0, 0x9A, 0x18, + 0x95, 0xF6, 0x9F, 0xF2, 0xCA, 0xF7, 0x47, 0x10, 0xD5, 0x09, + 0xC8, 0x75, 0x6D, 0x21, 0xCC, 0x57, 0xD5, 0x28, 0x93, 0xE3, + 0xB1, 0x26, 0x5F, 0xAE, 0x8E, 0x6A, 0x01, 0x07, 0x35, 0xD2, + 0x11, 0x7F, 0xC6, 0xC4, 0xD1, 0x64, 0x66, 0xD9, 0xDD, 0xE2, + 0xF6, 0x01, 0x49, 0xB8, 0x92, 0xDF, 0x25, 0x41, 0x25, 0x1C, + 0x35, 0x3F, 0x5E, 0x3D, 0x34, 0xEA, 0x72, 0x74, 0xB9, 0x10, + 0x3A, 0x60, 0x7B, 0xBC, 0xD4, 0xB1, 0xDF, 0xB9, 0x9F, 0x32, + 0x37, 0x2F, 0xC0, 0xE0, 0xBF, 0x62, 0xDD, 0x7C, 0xE0, 0x5E, + 0xE3, 0xD8, 0xA8, 0x93, 0xF9, 0xA9, 0x5F, 0xE8, 0x4D, 0x9B, + 0x89, 0x3A, 0x03, 0xDD, 0xB1, 0xDC, 0x91, 0xF0, 0x58, 0x55, + 0xA1, 0x04, 0x45, 0xB6, 0xEB, 0x35, 0x2B, 0x0C, 0xB2, 0x81, + 0xD4, 0x8E, 0x20, 0x67, 0x0B, 0x79, 0x20, 0xBD, 0x8B, 0xC9, + 0xF2, 0x5F, 0xA4, 0x4C, 0xA5, 0xD9, 0x4F, 0xB1, 0x9A, 0x12, + 0xA3, 0x2E, 0xF9, 0x5D, 0x25, 0xA4, 0xA0, 0xAA, 0x83, 0xD4, + 0x79, 0x26, 0x8E, 0xCE, 0x5F, 0x62, 0xBA, 0x82, 0x02, 0x84, + 0x4E, 0x9B, 0xCD, 0x5F, 0x2F, 0x34, 0x68, 0xBD, 0x32, 0x5A, + 0x1A, 0x7C, 0xAE, 0xB9, 0x07, 0xB8, 0x50, 0x84, 0x6F, 0xB3, + 0x92, 0x9D, 0x2C, 0xEC, 0xDE, 0xD1, 0x8C, 0x2E, 0x6A, 0x69, + 0x7C, 0x3B, 0x1D, 0x1A, 0x62, 0xB3, 0xE2, 0x1D, 0xD3, 0xE0, + 0x20, 0x88, 0x79, 0x0E, 0x1B, 0xC4, 0x08, 0x90, 0x93, 0xEE, + 0x7D, 0x41, 0x33, 0x9F, 0x35, 0x80, 0x9F, 0xD8, 0xDE, 0xA1, + 0xB3, 0x79, 0x77, 0x9C, 0xF7, 0x7D, 0x1D, 0x2A, 0xE1, 0x2E, + 0xE8, 0xBD, 0xE8, 0x32, 0xBD, 0xDA, 0xD1, 0x40, 0x16, 0xB2, + 0x2C, 0x7B, 0x09, 0x47, 0x32, 0x95, 0x3C, 0xD3, 0x62, 0x14, + 0x6B, 0xA8, 0xD9, 0x46, 0x11, 0x2A, 0x27, 0x13, 0x51, 0xCB, + 0x08, 0xF2, 0xB5, 0xD9, 0x48, 0x23, 0xFD, 0xB6, 0x8B, 0xAE, + 0x6F, 0xAE, 0xBF, 0x8F, 0xD5, 0x4F, 0x57, 0xDF, 0xAF, 0xA4, + 0xEA, 0x4C, 0x7E, 0x3F, 0x41, 0x71, 0x76, 0xA2, 0x09, 0x60, + 0x1F, 0x29, 0x1A, 0x9C, 0x47, 0x7C, 0x1A, 0xBB, 0x71, 0x73, + 0xBF, 0xA9, 0xB7, 0x31, 0x39, 0x27, 0x4F, 0x7F, 0x6F, 0xCE, + 0xCF, 0x98, 0x57, 0xCC, 0xA1, 0xDE, 0x5E, 0xDE, 0xB3, 0xDF, + 0x58, 0x2E, 0x7D, 0xFA, 0x52, 0x6A, 0x56, 0x8E, 0xE1, 0x78, + 0x22, 0x2E, 0xAC, 0xE2, 0xA3, 0xDB, 0xFF, 0xC5, 0x68, 0x1F, + 0x82, 0xB0, 0x99, 0x25, 0x54, 0xE5, 0x90, 0x43, 0x71, 0x2E, + 0x8D, 0x8B, 0x88, 0x75, 0xE4, 0x6C, 0x59, 0x56, 0x1D, 0x10, + 0x1A, 0x66, 0x7D, 0x22, 0x93, 0x19, 0x31, 0xB3, 0x15, 0xA3, + 0xD6, 0xA8, 0xDD, 0x7C, 0xE7, 0x7D, 0x55, 0xBC, 0x72, 0x5E, + 0x83, 0x8D, 0xEB, 0x3D, 0x35, 0xA2, 0x58, 0x1B, 0xB6, 0x92, + 0xB4, 0x70, 0x26, 0x0B, 0x75, 0x08, 0xE1, 0x9F, 0xB9, 0xA6, + 0xC7, 0x6F, 0xA1, 0xFC, 0x6E, 0x4E, 0xB7, 0x06, 0xD3, 0x56, + 0x88, 0x17, 0xF8, 0xD5, 0x97, 0xF1, 0x4A, 0x2F, 0x22, 0xB9, + 0xE3, 0xDA, 0x64, 0xD7, 0xC3, 0xDD, 0x22, 0xFD, 0xAE, 0x10, + 0x32, 0x09, 0xBA, 0x58, 0x9F, 0x6E, 0xE3, 0x6F, 0x1E, 0x3B, + 0x34, 0x69, 0xDF, 0xCD, 0x8B, 0xD9, 0x06, 0x3D, 0x95, 0xB4, + 0x49, 0x47, 0x73, 0xCF, 0xFA, 0xEB, 0xC4, 0xB3, 0xD8, 0x18, + 0xD8, 0xFE, 0x83, 0x32, 0x6B, 0xC3, 0x01, 0x25, 0x78, 0x46, + 0x9B, 0x12, 0xD6, 0x5D, 0x86, 0x4D, 0x53, 0x3C, 0xEC, 0x9C, + 0xCC, 0xD7, 0x9A, 0xBD, 0x92, 0x3A, 0x77, 0x91, 0x3C, 0x24, + 0xA6, 0xE3, 0x5F, 0xFC, 0x6B, 0x9B, 0x53, 0x9C, 0xC4, 0x95, + 0xE1, 0xAF, 0x6A, 0xB6, 0xB0, 0x15, 0x85, 0x11, 0x06, 0x25, + 0xA2, 0xCB, 0x98, 0x07, 0x7A, 0x73, 0x6D, 0x73, 0x62, 0xCD, + 0x7F, 0x9C, 0xB8, 0x72, 0xCB, 0xF2, 0xA7, 0xD3, 0xC3, 0x89, + 0xCC, 0x1A, 0x23, 0x5A, 0xCD, 0x0D, 0x67, 0xE0, 0xF0, 0xA5, + 0x59, 0x86, 0x00, 0x24, 0xD5, 0x36, 0x3B, 0xFA, 0x9D, 0xDE, + 0x08, 0x40, 0x3A, 0x80, 0x4A, 0x93, 0x90, 0xF2, 0xDD, 0x72, + 0x69, 0x4A, 0x0B, 0x5B, 0xB0, 0xFF, 0x4B, 0x1F, 0xD1, 0x5D, + 0x7D, 0xF1, 0x93, 0xA7, 0x24, 0x8A, 0xBE, 0x8A, 0xE6, 0xD9, + 0xFE, 0x14, 0xDA, 0x42, 0x92, 0xED, 0x5E, 0x27, 0xDD, 0x86, + 0x7E, 0x65, 0x68, 0x09, 0x05, 0x72, 0x8C, 0x6C, 0x43, 0x6B, + 0xA8, 0x02, 0x56, 0xD5, 0x14, 0x1B, 0x74, 0xAF, 0xCA, 0x36, + 0x32, 0xA8, 0x6E, 0xDA, 0x3E, 0x30, 0xA7, 0x4F, 0x02, 0x5F, + 0x65, 0x96, 0x41, 0xEC, 0x1C, 0x6F, 0x7B, 0xBD, 0x3D, 0xF8, + 0x2D, 0xE2, 0xE3, 0x12, 0xCC, 0xE0, 0x03, 0xBF, 0x08, 0x90, + 0xB7, 0xE0, 0xBA, 0xE9, 0x9E, 0xFC, 0xCC, 0x3D, 0x2B, 0x4C, + 0x82, 0x3D, 0x27, 0x15, 0xF0, 0x9F, 0x02, 0x01, 0x0B, 0xC1, + 0xCC, 0xE8, 0x2A, 0x7F, 0x34, 0xB7, 0x8B, 0xDA, 0x3C, 0x61, + 0x5C, 0x63, 0xBF, 0x26, 0xCB, 0x4B, 0xB5, 0xCB, 0x5E, 0x0D, + 0x02, 0x1E, 0x8A, 0x03, 0xF7, 0xF9, 0x0C, 0x17, 0x9F, 0xF4, + 0x56, 0xB7, 0x13, 0x35, 0x85, 0xDC, 0xF1, 0x2F, 0x99, 0x5F, + 0xF7, 0x2A, 0x6D, 0x23, 0x95, 0xA5, 0xB1, 0xBD, 0x9B, 0xD3, + 0xA2, 0xDB, 0x89, 0x5E, 0xDC, 0xDF, 0xE8, 0x22, 0xF2, 0x4A, + 0x93, 0xB6, 0x16, 0x6F, 0x39, 0x7F, 0x02, 0x6E, 0xB7, 0x64, + 0xCF, 0xBE, 0x07, 0xD3, 0x0F, 0xFA, 0xC6, 0xD7, 0xD4, 0x90, + 0x39, 0x8A, 0x6B, 0x77, 0xCB, 0x5D, 0xC6, 0x51, 0xC5, 0xFE, + 0x49, 0x41, 0x49, 0xD1, 0xB4, 0xDF, 0xE0, 0xC5, 0xA3, 0x38, + 0x04, 0xAA, 0x54, 0x99, 0xC9, 0xD7, 0x85, 0x7B, 0xAB, 0xB3, + 0x9F, 0xD8, 0x30, 0x83, 0xF5, 0x90, 0x25, 0x46, 0xD6, 0x49, + 0x35, 0x74, 0xCE, 0x8D, 0x77, 0xBE, 0x6E, 0x07, 0xDB, 0xE6, + 0x6E, 0x21, 0xC7, 0xE5, 0xC0, 0x3F, 0x74, 0xAC, 0xFD, 0xFC, + 0x18, 0x1B, 0x73, 0x7B, 0x59, 0x94, 0xDC, 0xAD, 0x67, 0x36, + 0xB6, 0xEF, 0xA1, 0x14, 0xF8, 0x27, 0xEC, 0x1A, 0x0D, 0xD5, + 0x49, 0x14, 0x81, 0x1B, 0xAA, 0x73, 0xB6, 0xD8, 0x9A, 0x64, + 0x4F, 0x8A, 0x27, 0xC0, 0x1A, 0x2D, 0x63, 0x12, 0x53, 0xC3, + 0xCB, 0x7C, 0x10, 0x4A, 0xD1, 0x17, 0x2E, 0x2E, 0x80, 0x84, + 0x82, 0xC5, 0x22, 0xB3, 0x27, 0x2A, 0x49, 0xA2, 0xF1, 0xCE, + 0x47, 0x13, 0x98, 0xC2, 0x74, 0xF6, 0x90, 0x25, 0x8A, 0xB4, + 0x13, 0xE6, 0xC7, 0x40, 0x22, 0xC7, 0xF4, 0x53, 0x0D, 0x70, + 0x05, 0x10, 0x82, 0x97, 0x12, 0xB9, 0xC3, 0x17, 0x89, 0x8E, + 0x81, 0xD7, 0xC4, 0x41, 0xD4, 0x1D, 0xD8, 0x03, 0x52, 0x27, + 0x9A, 0xC4, 0x02, 0x29, 0xBC, 0xD8, 0xCB, 0xBB, 0x45, 0x86, + 0x05, 0x14, 0xD3, 0xCC, 0xD8, 0x12, 0x6B, 0x37, 0xF6, 0xA3, + 0xF7, 0x85, 0x5B, 0x5E, 0x04, 0x13, 0xFC, 0xAD, 0x23, 0x91, + 0x00, 0x43, 0x90, 0x11, 0x68, 0xFC, 0xF1, 0xDE, 0x94, 0x73, + 0x0C, 0x75, 0x4D, 0x5C, 0x24, 0xC8, 0x0D, 0xFB, 0xF1, 0x5A, + 0xC0, 0xC5, 0x2A, 0x7D, 0xDE, 0xAF, 0xC0, 0x5A, 0x20, 0x27, + 0x89, 0x58, 0x69, 0x64, 0xC2, 0xA5, 0x15, 0xE7, 0x90, 0x8B, + 0x66, 0x92, 0xE9, 0x1C, 0xDF, 0xCC, 0x5A, 0x74, 0x43, 0xC9, + 0x62, 0x22, 0x2B, 0x6C, 0xD0, 0xA5, 0x09, 0x20, 0x15, 0x2B, + 0x77, 0xDA, 0x30, 0xC0, 0xC0, 0xB4, 0x6D, 0xCE, 0x51, 0x5D, + 0x97, 0x83, 0x39, 0x37, 0xD4, 0x02, 0x29, 0xBD, 0x8E, 0x6F, + 0x4B, 0x1D, 0xCD, 0xD8, 0xA0, 0xF8, 0x08, 0x0A, 0x69, 0x85, + 0x2F, 0xAF, 0xE1, 0x18, 0xE5, 0x0F, 0xE1, 0xC6, 0x9D, 0xDC, + 0xEE, 0xC7, 0x2A, 0x9F, 0xAF, 0x31, 0x6B, 0xDF, 0x14, 0x8F, + 0xF5, 0xAF, 0x77, 0x24, 0xF0, 0x74, 0xC5, 0xDD, 0xE6, 0x5D, + 0x6A, 0x7E, 0xE7, 0x8D, 0x3F, 0x4F, 0xA0, 0x90, 0x4D, 0xAD, + 0xE5, 0xFE, 0x7D, 0xA5, 0xED, 0x5C, 0x11, 0x0D, 0xCC, 0x8B, + 0xE3, 0xE0, 0xD7, 0x82, 0xE9, 0x4A, 0xA2, 0xA4, 0xDA, 0xF4, + 0x3F, 0xE9, 0xC5, 0xB0, 0x00, 0x8F, 0x67, 0xE5, 0x58, 0xFA, + 0xC0, 0x91, 0x3C, 0x02, 0x27, 0x36, 0x00, 0x94, 0xCF, 0x59, + 0x15, 0xB4, 0xBB, 0xA1, 0xEC, 0xD7, 0x5F, 0x63, 0x52, 0x6C, + 0x71, 0x8F, 0x92, 0xCE, 0x5E, 0x14, 0x4C, 0xA1, 0xE7, 0x74, + 0x38, 0xE5, 0xD2, 0x14, 0xCD, 0x8B, 0xB9, 0x2C, 0xB8, 0x14, + 0x78, 0x4A, 0x95, 0x6A, 0x15, 0x3C, 0x7A, 0x14, 0x76, 0x1E, + 0xBB, 0xB4, 0xD4, 0x8E, 0x8B, 0x19, 0xED, 0x43, 0x46, 0xD5, + 0xA0, 0xF6, 0x11, 0x84, 0x22, 0xBA, 0x36, 0xEB, 0x29, 0x86, + 0xB8, 0xF3, 0x38, 0x3E, 0x27, 0xE9, 0x4C, 0xD6, 0xAC, 0x68, + 0x65, 0x18, 0x2F, 0xE9, 0x09, 0xF1, 0x1E, 0xD3, 0x3B, 0x3E, + 0x52, 0x18, 0x06, 0x65, 0xC8, 0x59, 0x09, 0x03, 0x34, 0x77, + 0x40, 0x4D, 0x31, 0xAC, 0x47, 0x17, 0x5F, 0xE5, 0x0C, 0x5A, + 0xB9, 0x66, 0x36, 0x86, 0x71, 0x8A, 0x92, 0x24, 0xE7, 0xC6, + 0xED, 0x0B, 0x11, 0x42, 0x66, 0x4E, 0x25, 0x7C, 0x1D, 0xD9, + 0xE0, 0x0D, 0x07, 0x1C, 0x74, 0x8B, 0x60, 0x14, 0x85, 0xCD, + 0x74, 0x4F, 0xA7, 0xF8, 0x2E, 0x26, 0xAF, 0xF2, 0xFB, 0x51, + 0x6D, 0x8C, 0x3E, 0x75, 0x90, 0xC0, 0x5B, 0x4A, 0x25, 0x11, + 0x1C, 0x61, 0x65, 0x1C, 0xA1, 0x04, 0x5A, 0xBA, 0x7D, 0xA1, + 0xA4, 0xB4, 0x30, 0x09, 0xDC, 0xE2, 0x00, 0xF9, 0xB3, 0x26, + 0xCC, 0xA4, 0x36, 0x89, 0x8B, 0xD7, 0xCA, 0x63, 0xF1, 0x1C, + 0xF5, 0x4A, 0xF0, 0xEC, 0x5F, 0x10, 0x14, 0x61, 0xE7, 0xE5, + 0xCF, 0x26, 0x00, 0x8C, 0x38, 0x10, 0xFC, 0x67, 0x72, 0x8B, + 0x80, 0xE4, 0x31, 0x93, 0x04, 0x3A, 0xDF, 0xB5, 0xB3, 0x45, + 0x62, 0x78, 0x40, 0xDF, 0x53, 0xDD, 0x46, 0x1C, 0x34, 0xE6, + 0xAB, 0x05, 0xBF, 0x34, 0x77, 0x57, 0x1F, 0xDE, 0xA7, 0x8D, + 0x44, 0x9E, 0xD4, 0x45, 0x26, 0x97, 0xED, 0xC2, 0x6C, 0xE5, + 0x09, 0xC3, 0x53, 0xD5, 0x40, 0x8B, 0x46, 0x6D, 0x35, 0x33, + 0xA8, 0x24, 0xD0, 0xA0, 0x61, 0xC2, 0xA8, 0x9C, 0xDB, 0x33, + 0x70, 0x14, 0x47, 0x9A, 0x6F, 0xD5, 0x14, 0x1D, 0x3E, 0x12, + 0x72, 0x23, 0x55, 0xF4, 0x82, 0xB6, 0x50, 0xAA, 0x28, 0x28, + 0x12, 0x3F, 0x0E, 0xF1, 0x6C, 0x1A, 0x3F, 0xA8, 0x0E, 0x47, + 0x47, 0x27, 0x3E, 0xAA, 0x27, 0xE0, 0x18, 0xD2, 0x3B, 0xDE, + 0xFD, 0x4B, 0x9C, 0x24, 0x0A, 0x5A, 0x02, 0xA4, 0x7F, 0x8B, + 0x72, 0x13, 0xE8, 0x75, 0x90, 0x80, 0xDB, 0x49, 0xD8, 0xF1, + 0x22, 0xEB, 0x90, 0xFB, 0x63, 0x7F, 0x12, 0xD3, 0xEE, 0xD8, + 0x4F, 0x53, 0xEF, 0x01, 0x7A, 0x7F, 0x22, 0x4B, 0x20, 0xCB, + 0x88, 0x31, 0x57, 0x06, 0x92, 0x0D, 0x45, 0x55, 0xA0, 0xF5, + 0xA7, 0x86, 0xF6, 0x31, 0x47, 0x93, 0xB0, 0xC0, 0x04, 0x92, + 0x08, 0xD4, 0xCE, 0x75, 0x81, 0x11, 0xF7, 0xF2, 0x47, 0x31, + 0x87, 0x74, 0x37, 0x6D, 0x32, 0xBC, 0x8D, 0x86, 0xB7, 0x09, + 0x40, 0x81, 0xDD, 0x01, 0x93, 0x78, 0x15, 0xC5, 0xD3, 0x87, + 0x05, 0x6D, 0xA4, 0x2E, 0x76, 0xEE, 0x36, 0x72, 0xB1, 0xB6, + 0x7C, 0x26, 0xCB, 0x50, 0x7A, 0xE6, 0xB2, 0x86, 0xB3, 0x22, + 0x6F, 0xA7, 0xC5, 0x04, 0xAD, 0xB9, 0x62, 0xB4, 0xF2, 0xE0, + 0x49, 0x59, 0x6F, 0xFD, 0x30, 0xF6, 0xB7, 0xF4, 0xA1, 0x0C, + 0x16, 0x8F, 0xCD, 0xE5, 0x0F, 0x90, 0x0A, 0x10, 0x9D, 0x96, + 0xD3, 0x53, 0x75, 0xA1, 0xCE, 0xDB, 0x7A, 0xDE, 0xA5, 0x62, + 0x9D, 0xF4, 0xE4, 0x64, 0xB7, 0xBC, 0xEE, 0xE8, 0xAB, 0xBA, + 0xD2, 0x1C, 0x29, 0x1C, 0x42, 0x9C, 0xBB, 0x8E, 0x66, 0x84, + 0x4F, 0x2E, 0x80, 0x93, 0x34, 0xE8, 0xC0, 0xA9, 0x32, 0xFA, + 0xDB, 0x55, 0xE3, 0xF2, 0x6C, 0x8A, 0x8E, 0x1F, 0x50, 0x13, + 0x73, 0x47, 0xBA, 0xF9, 0xF4, 0x7A, 0x5C, 0x2F, 0x17, 0x4D, + 0x9E, 0xAC, 0x91, 0x2C, 0xAC, 0xD9, 0xC4, 0xBE, 0x9A, 0x17, + 0xD7, 0xF8, 0xDA, 0x74, 0x2B, 0x16, 0x73, 0x43, 0x0C, 0xF6, + 0x19, 0xED, 0x8E, 0x71, 0x71, 0xDE, 0x1C, 0x0C, 0xB3, 0xFE, + 0x15, 0x86, 0xCB, 0xEF, 0x7C, 0xCE, 0xCA, 0x05, 0x0E, 0x26, + 0x83, 0x6B, 0x3A, 0x8A, 0x63, 0xE3, 0x10, 0x39, 0x6B, 0xA8, + 0x2D, 0xD4, 0x96, 0x7D, 0xF9, 0xD2, 0x03, 0x53, 0xC9, 0xBA, + 0x93, 0x0E, 0x68, 0x45, 0x3B, 0x2B, 0x41, 0x46, 0x4D, 0x77, + 0x9B, 0xC7, 0x42, 0x29, 0xA7, 0x03, 0x4F, 0xEA, 0x3D, 0x39, + 0x4B, 0xAF, 0xBC, 0x19, 0x4D, 0xF3, 0x36, 0x06, 0xD7, 0x7A, + 0x54, 0xB9, 0x27, 0xAD, 0xFB, 0x90, 0xC0, 0x94, 0x75, 0x8F, + 0xAC, 0x37, 0x97, 0x95, 0xE1, 0xA7, 0xC9, 0x7F, 0x11, 0x82, + 0x7E, 0x59, 0xC0, 0x42, 0x18, 0x9E, 0xC8, 0xC7, 0xD1, 0x19, + 0xDC, 0xCA, 0xEC, 0x27, 0x62, 0x3E, 0xBF, 0x53, 0x92, 0x6D, + 0x6A, 0x02, 0x3E, 0x4F, 0xB1, 0x52, 0x60, 0x39, 0x26, 0x84, + 0x79, 0x72, 0x42, 0xDE, 0xFE, 0xF2, 0x96, 0x65, 0xE2, 0xF8, + 0xEF, 0x73, 0x60, 0xB5, 0x55, 0x21, 0xA6, 0xAF, 0xEA, 0x29, + 0x76, 0x8B, 0xCC, 0xB3, 0xC6, 0x4E, 0xE6, 0x36, 0xB6, 0x06, + 0xDF, 0x0F, 0x29, 0xB1, 0x68, 0xDF, 0xBC, 0x67, 0xDB, 0x75, + 0x57, 0x6D, 0x22, 0x12, 0xC0, 0x34, 0xF1, 0xC8, 0x27, 0xA2, + 0x03, 0x1A, 0x82, 0x5D, 0xB1, 0xF7, 0x0A, 0xF9, 0xEA, 0xED, + 0x7E, 0x79, 0x88, 0xFF, 0xE1, 0xEC, 0x7D, 0xF6, 0x90, 0x2C, + 0x2A, 0x94, 0xA9, 0x3F, 0xC3, 0xC9, 0xBC, 0x38, 0xAB, 0x28, + 0xBD, 0x95, 0x02, 0xEF, 0x90, 0x82, 0xB1, 0x77, 0x4B, 0x89, + 0xD7, 0x26, 0xC1, 0xA5, 0xF5, 0xAD, 0x72, 0x04, 0x41, 0x71, + 0xC2, 0x19, 0x2E, 0x36, 0x45, 0xE8, 0xC1, 0x88, 0x53, 0x1D, + 0xB8, 0x00, 0x4E, 0x21, 0x43, 0x43, 0x6E, 0x58, 0x45, 0x71, + 0xAA, 0xEB, 0x0E, 0xE0, 0x2C, 0x4D, 0x98, 0x5F, 0xD6, 0x2B, + 0x56, 0x0C, 0x5A, 0x2F, 0xA4, 0x10, 0x59, 0x26, 0xB9, 0x9F, + 0x08, 0xF1, 0x46, 0x56, 0x07, 0x9B, 0x55, 0x99, 0x5F, 0x98, + 0x52, 0x83, 0xCB, 0x98, 0x30, 0x26, 0x48, 0xE4, 0xF3, 0x13, + 0xC3, 0x3E, 0xFA, 0xDB, 0x9D, 0x79, 0x79, 0x81, 0x7B, 0x13, + 0x13, 0xB0, 0xA2, 0x57, 0x5F, 0x97, 0xCE, 0x9C, 0x39, 0x22, + 0x31, 0xB8, 0x94, 0x17, 0xEA, 0x7E, 0x08, 0xC0, 0x1D, 0x69, + 0x7E, 0xD6, 0xDF, 0x02, 0x39, 0x94, 0x58, 0x2A, 0x75, 0xB9, + 0x1A, 0x35, 0x44, 0x70, 0x6D, 0x50, 0x56, 0x0C, 0x5A, 0x8E, + 0xCA, 0x0F, 0x80, 0x13, 0x6C, 0xFF, 0x07, 0xFD, 0x35, 0xE6, + 0xAA, 0xEC, 0x6F, 0xF7, 0x4D, 0x87, 0x7A, 0xD6, 0xA4, 0x5A, + 0xB7, 0xBB, 0x25, 0x59, 0x19, 0x8C, 0x47, 0x83, 0x5A, 0x41, + 0xFD, 0xFD, 0x24, 0x28, 0xD0, 0x4E, 0x68, 0x33, 0xB4, 0xB6, + 0xA3, 0x31, 0xC2, 0x94, 0x5B, 0xAB, 0x0D, 0xCB, 0x39, 0x0A, + 0x8A, 0xD2, 0x17, 0x82, 0x08, 0xD4, 0xDD, 0x7E, 0xB3, 0xDC, + 0x7E, 0xF6, 0x41, 0x51, 0xA2, 0x9A, 0x57, 0x6F, 0x55, 0x21, + 0xB2, 0xB4, 0xA0, 0xB4, 0x58, 0x9A, 0x90, 0xB3, 0x63, 0x63, + 0x4F, 0x2F, 0xE3, 0xBF, 0x93, 0x23, 0xF7, 0x9D, 0xC7, 0x11, + 0xB1, 0xB9, 0xED, 0xE9, 0x3C, 0x85, 0x6A, 0x07, 0x51, 0x45, + 0xD2, 0xEF, 0x85, 0x9B, 0x4B, 0x59, 0x12, 0x6D, 0xE6, 0x9B, + 0x50, 0x31, 0xC6, 0x82, 0xB0, 0x99, 0x6C, 0xEE, 0x36, 0x0C, + 0x6E, 0xD2, 0x9B, 0x39, 0xD2, 0x47, 0xEA, 0xB9, 0x0D, 0x92, + 0xF8, 0xD9, 0x51, 0x67, 0xCC, 0x98, 0xC9, 0x31, 0x88, 0xE6, + 0xDF, 0x67, 0xE1, 0xF0, 0xA5, 0x6E, 0xC3, 0x25, 0x35, 0x91, + 0x4C, 0x0D, 0xF7, 0xCF, 0xC7, 0xC8, 0x18, 0xF2, 0x56, 0xD9, + 0x02, 0x17, 0x21, 0xB0, 0x73, 0x91, 0xAA, 0xF1, 0xA0, 0x0E, + 0xA7, 0x43, 0x8E, 0x2F, 0x57, 0xC5, 0xCB, 0xCA, 0x65, 0x61, + 0x8F, 0x24, 0xA7, 0xAF, 0x2B, 0xB2, 0xDC, 0xCB, 0xA3, 0xB1, + 0x89, 0xE2, 0x80, 0x37, 0xEA, 0xE7, 0x00, 0x8E, 0x4B, 0x2C, + 0x93, 0xD4, 0x89, 0x7B, 0x64, 0x51, 0x8C, 0x4D, 0x47, 0x75, + 0x97, 0x17, 0x0A, 0x74, 0x6E, 0x61, 0xE9, 0x57, 0x7B, 0x68, + 0x4A, 0xD3, 0xB8, 0x15, 0x01, 0x4A, 0x68, 0x1E, 0x8E, 0x53, + 0x99, 0x72, 0xCF, 0xE5, 0xF5, 0xC6, 0x80, 0x45, 0xD6, 0xFD, + 0xF7, 0xFD, 0x8D, 0x97, 0xD9, 0xC4, 0xD2, 0x05, 0x01, 0xD2, + 0xEE, 0x4F, 0x95, 0x40, 0x8A, 0xDB, 0x2F, 0xED, 0x2D, 0x70, + 0xCB, 0xBA, 0xBB, 0x0F, 0xA5, 0xEE, 0xE3, 0x46, 0xB2, 0x03, + 0x39, 0xD7, 0xF3, 0xC4, 0x5B, 0x03, 0xC3, 0x93, 0x7F, 0xBB, + 0xC4, 0x5A, 0x8A, 0x5A, 0x1B, 0xD0, 0x55, 0x58, 0x3F, 0xC6, + 0xC2, 0xDA, 0xD7, 0x33, 0x37, 0xF3, 0x6F, 0xD3, 0x01, 0xD7, + 0x9A, 0x36, 0x8F, 0x79, 0x20, 0x5F, 0x18, 0x07, 0xBF, 0x46, + 0x82, 0x6E, 0x3E, 0x92, 0x32, 0x74, 0xA5, 0x2C, 0x57, 0x53, + 0x6B, 0x43, 0x2A, 0x14, 0xF5, 0x50, 0x62, 0x4F, 0xA9, 0x49, + 0x3B, 0xB4, 0xFD, 0xCF, 0xF6, 0x8A, 0x3C, 0xAA, 0x1D, 0xCE, + 0xB2, 0xD4, 0xE5, 0xE2, 0x35, 0x6D, 0x04, 0x1C, 0x2E, 0xAE, + 0x62, 0x10, 0x27, 0x21, 0x81, 0xC7, 0x1D, 0x57, 0x06, 0xCC, + 0xB1, 0xE1, 0x88, 0x12, 0xF0, 0x02, 0xB4, 0x89, 0xAB, 0xBA, + 0x14, 0xD8, 0xA5, 0xFA, 0x2A, 0xC4, 0xC8, 0xDB, 0x84, 0x0A, + 0x6A, 0xBB, 0xF8, 0xFA, 0x59, 0x45, 0x31, 0x9C, 0x24, 0xC1, + 0x22, 0xDD, 0x2F, 0x76, 0xD3, 0xA4, 0xCD, 0x19, 0x6F, 0x1E, + 0x29, 0xD6, 0xCD, 0xFA, 0xB5, 0xE9, 0x3B, 0x86, 0x95, 0x2A, + 0xF8, 0xE5, 0xCC, 0xBA, 0xC0, 0x58, 0x86, 0xF8, 0xE0, 0xA3, + 0x0B, 0x8A, 0x51, 0x8B, 0x67, 0x0A, 0x5A, 0x53, 0x30, 0xCB, + 0x64, 0xFC, 0x38, 0xF7, 0x65, 0x72, 0xE1, 0xC4, 0xA4, 0x89, + 0xE9, 0x51, 0x51, 0x79, 0xCC, 0x79, 0x13, 0xF4, 0xA8, 0x21, + 0x5F, 0xFA, 0xF2, 0x24, 0x2F, 0x45, 0x95, 0x1F, 0xB5, 0x6E, + 0xD9, 0xB1, 0xB5, 0x86, 0xC3, 0x91, 0xEE, 0x7B, 0x26, 0x3F, + 0x1D, 0xE8, 0x23, 0x48, 0x98, 0xC2, 0x2F, 0x9B, 0xF2, 0xDF, + 0x28, 0xB5, 0x32, 0x6C, 0xDE, 0xDB, 0x8E, 0xE2, 0xAB, 0x78, + 0xE3, 0x02, 0x8D, 0x18, 0xBD, 0x48, 0xDF, 0x83, 0x3C, 0x8F, + 0xED, 0xCC, 0xC9, 0x4A, 0xDD, 0xE3, 0xE8, 0xEB, 0xAB, 0xEF, + 0xF1, 0xC1, 0x16, 0xAB, 0x34, 0x01, 0xAB, 0x7F, 0x3F, 0xBB, + 0x17, 0xAD, 0xC7, 0xAB, 0xFE, 0x99, 0x44, 0x7D, 0xF2, 0x64, + 0xCD, 0x8B, 0x97, 0x9C, 0x94, 0x19, 0xD7, 0x31, 0xE6, 0x8B, + 0xD8, 0xF9, 0x4A, 0xB9, 0xCF, 0xED, 0x37, 0x76, 0xDA, 0xDB, + 0x13, 0x7C, 0x7E, 0x4C, 0xB6, 0x62, 0x79, 0xF7, 0xC1, 0x91, + 0x17, 0x5D, 0x07, 0x34, 0x72, 0x2C, 0x08, 0xFC, 0x5F, 0xA8, + 0x47, 0x65, 0xE0, 0x62, 0x7B, 0xD8, 0xD7, 0xD3, 0x64, 0x9E, + 0xEB, 0xD0, 0xE2, 0x95, 0x97, 0x05, 0xB6, 0x45, 0x5D, 0x1F, + 0xAB, 0x72, 0x9D, 0x9A, 0x47, 0xFF, 0x16, 0x5B, 0x3C, 0x44, + 0x46, 0x13, 0xDC, 0xD1, 0xDE, 0x41, 0x86, 0x63, 0x67, 0xA3, + 0x96, 0x6D, 0x56, 0xCC, 0x10, 0xE1, 0x7C, 0x4B, 0x2E, 0x55, + 0x42, 0xC2, 0x41, 0xA6, 0x99, 0x16, 0x73, 0xE7, 0xA9, 0xE9, + 0xA1, 0xBD, 0xF7, 0xB6, 0x2F, 0x1A, 0x55, 0x9A, 0xAA, 0xF5, + 0xE1, 0x33, 0xCE, 0x86, 0x36, 0x3F, 0xFE, 0xA5, 0x80, 0x55, + 0x3B, 0x27, 0xB5, 0x99, 0xB1, 0xB1, 0x42, 0x8B, 0x93, 0x0E, + 0x62, 0x02, 0x8D, 0x9A, 0x3A, 0x07, 0x66, 0x21, 0xBB, 0x45, + 0xA4, 0x98, 0xAF, 0x5D, 0xBC, 0xD4, 0x74, 0xD4, 0x44, 0x24, + 0x5E, 0x0B, 0xAF, 0xA6, 0xC8, 0x14, 0xD0, 0x0A, 0xE8, 0xE0, + 0xD4, 0xD2, 0x2F, 0xAC, 0x67, 0xFC, 0xB1, 0x84, 0x7E, 0xAE, + 0x62, 0x69, 0xB4, 0xE1, 0x0E, 0x9A, 0x06, 0xDA, 0xD1, 0x53, + 0xB0, 0xE2, 0x16, 0x04, 0x08, 0xCB, 0x96, 0xE4, 0xF5, 0xB6, + 0x67, 0x63, 0xB9, 0x06, 0x02, 0xF7, 0xFC, 0x93, 0x9F, 0x89, + 0x2F, 0xFC, 0x53, 0xE8, 0x6B, 0xAE, 0x3D, 0x0E, 0x15, 0xE6, + 0xA6, 0x47, 0xF2, 0xD0, 0x8F, 0x16, 0xE0, 0x9B, 0x19, 0xF3, + 0xD7, 0xDE, 0xEE, 0x69, 0x3C, 0xDD, 0xAF, 0xEA, 0xC9, 0x4C, + 0xB0, 0x2F, 0x5E, 0x17, 0x6F, 0xEB, 0x46, 0xA6, 0x27, 0x1E, + 0xAA, 0xF7, 0xF4, 0xF7, 0x8A, 0x19, 0xFE, 0x40, 0x1E, 0xB6, + 0xF5, 0x7F, 0xC3, 0x74, 0x70, 0x9A, 0x32, 0xAA, 0x49, 0x5D, + 0x3E, 0x82, 0x94, 0x07, 0xB3, 0xB5, 0x83, 0xAC, 0x1B, 0xB1, + 0x56, 0x9B, 0x73, 0x64, 0x6A, 0xFE, 0x0D, 0xBF, 0x38, 0xA5, + 0x30, 0x1D, 0x39, 0xA1, 0x97, 0x66, 0xD6, 0x65, 0x9A, 0xEF, + 0xA2, 0xD7, 0x83, 0x12, 0x62, 0x5C, 0xD4, 0x34, 0x3B, 0xD1, + 0x70, 0x1C, 0xFF, 0x54, 0x07, 0x58, 0xB0, 0xFA, 0x46, 0x02, + 0x08, 0x36, 0x0B, 0x31, 0x2A, 0x25, 0xF7, 0x72, 0xEA, 0xB4, + 0xE4, 0x5D, 0x9E, 0x0E, 0x1A, 0x2C, 0x1B, 0x45, 0x3B, 0x76, + 0x24, 0xB8, 0x5F, 0x2A, 0x25, 0x68, 0x63, 0xE4, 0xA9, 0xE6, + 0xD6, 0x5C, 0x3E, 0xD0, 0xFA, 0x97, 0xC2, 0x75, 0xF1, 0x17, + 0xEC, 0xAB, 0x63, 0x0E, 0x95, 0xD5, 0xC6, 0x19, 0xC4, 0x03, + 0xA2, 0x15, 0xAC, 0x67, 0xD3, 0x16, 0x92, 0xE7, 0x25, 0x1C, + 0xDC, 0x4D, 0x20, 0x4C, 0x41, 0xB2, 0x8B, 0x3D, 0x4B, 0xFB, + 0x95, 0xC5, 0xEF, 0x01, 0x7A, 0x8C, 0x40, 0x20, 0x79, 0x3C, + 0xB2, 0x18, 0x69, 0x2F, 0x4E, 0xDD, 0x41, 0x62, 0x40, 0x79, + 0x64, 0xF0, 0xE4, 0x71, 0x28, 0xFF, 0x1D, 0x5B, 0x4A, 0xD7, + 0x4F, 0x53, 0xCD, 0x51, 0x2E, 0xCB, 0x2A, 0xC7, 0x26, 0x93, + 0x38, 0x16, 0x68, 0xA8, 0x4E, 0x5C, 0x8F, 0xF5, 0x3F, 0x2E, + 0x60, 0xAB, 0x92, 0x7B, 0x87, 0x05, 0x2C, 0xE4, 0xE0, 0x97, + 0xFF, 0xC0, 0xB4, 0x68, 0x3A, 0x66, 0x3D, 0x83, 0x65, 0xD3, + 0xF6, 0x0F, 0x0E, 0x1F, 0x8D, 0xA0, 0x35, 0x8C, 0xFD, 0x43, + 0x08, 0xF7, 0x71, 0x3D, 0x17, 0x95, 0xBE, 0xFA, 0x13, 0x0E, + 0xAD, 0xB3, 0x90, 0x5D, 0x53, 0xDB, 0x91, 0xC9, 0x29, 0x2C, + 0x74, 0xAF, 0xDF, 0x4F, 0x3A, 0xDA, 0x6C, 0x3D, 0xB4, 0xEA, + 0xD1, 0x0B, 0x9E, 0xCF, 0xC7, 0x53, 0x3C, 0x32, 0xF1, 0x98, + 0xFB, 0x8C, 0x92, 0x93, 0x1E, 0xCD, 0x6D, 0x70, 0x4D, 0x1F, + 0x8E, 0x5C, 0xA1, 0xDB, 0x2D, 0x19, 0x47, 0x11, 0x9E, 0xBB, + 0xD6, 0x93, 0xA8, 0x49, 0x78, 0x70, 0x0E, 0x5F, 0xAA, 0x37, + 0x4F, 0x47, 0xE0, 0x02, 0xA9, 0xEE, 0xF8, 0x42, 0x32, 0x80, + 0xBD, 0x5F, 0xD5, 0x87, 0x22, 0xF6, 0x66, 0x86, 0xE3, 0x55, + 0x71, 0xBB, 0xB9, 0x68, 0xBA, 0x16, 0xC7, 0x3A, 0xA0, 0xEA, + 0xCB, 0x74, 0xEE, 0x07, 0x6B, 0x6E, 0x03, 0x3B, 0xA0, 0x09, + 0xFA, 0x6F, 0x3F, 0x99, 0x97, 0x5A, 0x4E, 0x97, 0x74, 0xA2, + 0x8D, 0x55, 0x33, 0x92, 0xCE, 0xD3, 0x7B, 0x31, 0x9D, 0x38, + 0xBE, 0x09, 0x01, 0xCE, 0x10, 0x7C, 0x06, 0xEE, 0xE4, 0x23, + 0xCA, 0x98, 0x34, 0xEB, 0xE7, 0xE2, 0x76, 0xB3, 0xA6, 0x44, + 0x56, 0x17, 0x54, 0x9D, 0x19, 0x61, 0x1D, 0x82, 0xFE, 0xF9, + 0x34, 0x38, 0xCD, 0x51, 0x1F, 0x63, 0x02, 0xFD, 0x69, 0xF2, + 0x26, 0x12, 0x17, 0xE6, 0x4C, 0x8C, 0xA9, 0x30, 0x14, 0xDC, + 0x1F, 0x22, 0xEA, 0xF9, 0xB8, 0x77, 0x86, 0x8D, 0xAF, 0xBE, + 0xB4, 0x14, 0xD6, 0xAF, 0xDC, 0xEA, 0xC9, 0x47, 0x2E, 0xD4, + 0xE7, 0x6B, 0x2F, 0xAA, 0xB9, 0x60, 0x67, 0x3D, 0x0C, 0x14, + 0x7C, 0x81, 0xF3, 0x8F, 0x51, 0xB4, 0x7A, 0x7D, 0x09, 0x39, + 0x4E, 0x28, 0xCF, 0x5D, 0x93, 0x89, 0x84, 0x6A, 0x9B, 0x08, + 0x70, 0x2D, 0x4F, 0x5E, 0xF0, 0x3E, 0x18, 0x56, 0xAF, 0x61, + 0x56, 0x72, 0x0D, 0x26, 0x53, 0x88, 0x9B, 0x1F, 0xE1, 0x62, + 0x85, 0xEB, 0x82, 0x8D, 0x1F, 0xA5, 0xC6, 0x97, 0x55, 0x4E, + 0x77, 0x67, 0x7F, 0x5C, 0x09, 0x66, 0x68, 0x49, 0xC1, 0xB0, + 0x97, 0xC5, 0x3A, 0xED, 0x05, 0x53, 0x14, 0x61, 0x34, 0x84, + 0x2B, 0xF8, 0xF0, 0xC5, 0x57, 0xEE, 0xE4, 0x9B, 0xDB, 0xBA, + 0xCC, 0x50, 0x9A, 0x67, 0x8A, 0x89, 0x07, 0xF7, 0xF8, 0x86, + 0x81, 0x51, 0x30, 0x8B, 0x33, 0x93, 0x34, 0x10, 0xA0, 0xFB, + 0xF8, 0x0C, 0x97, 0x2B, 0x31, 0xD2, 0x2F, 0x80, 0x86, 0x06, + 0x45, 0xFB, 0x11, 0x00, 0x71, 0xB0, 0x3E, 0xC5, 0x7B, 0x68, + 0x59, 0x9C, 0x9B, 0x7B, 0xB0, 0x98, 0x44, 0x2D, 0x77, 0x4B, + 0x78, 0x81, 0x47, 0x5D, 0x53, 0x43, 0x5F, 0xB9, 0xDD, 0xC0, + 0x3F, 0x50, 0xEC, 0x35, 0xEA, 0x65, 0x2D, 0xDC, 0x57, 0x40, + 0x91, 0x3C, 0xD2, 0x4B, 0x0F, 0xF8, 0x97, 0x0E, 0x5D, 0xF9, + 0xEF, 0x2D, 0xF2, 0xC4, 0xDE, 0x99, 0x4E, 0xE9, 0x58, 0x15, + 0xE2, 0xC4, 0xF6, 0xE6, 0x5D, 0x44, 0x86, 0xB9, 0x2A, 0x03, + 0x13, 0x61, 0xAE, 0x12, 0xF0, 0xF4, 0x5B, 0x66, 0x76, 0x1D, + 0x04, 0x52, 0x7F, 0x89, 0x66, 0xD7, 0x2F, 0xFC, 0x77, 0x48, + 0x5E, 0x84, 0x08, 0x70, 0x22, 0xC4, 0x0F, 0x20, 0x35, 0xE6, + 0x6B, 0xAA, 0xFB, 0x3C, 0xAD, 0x2C, 0x79, 0x81, 0x76, 0x4B, + 0x48, 0x02, 0xC7, 0xBF, 0x8E, 0x21, 0xC6, 0x89, 0xDF, 0xD2, + 0x7F, 0x5D, 0x4B, 0xE6, 0x5B, 0x7E, 0xFB, 0xAF, 0xED, 0x4B, + 0xB6, 0x6E, 0x37, 0x44, 0x08, 0xB3, 0x36, 0xC1, 0x52, 0xAF, + 0xC0, 0x07, 0x89, 0xD6, 0x79, 0xD9, 0x4A, 0x3D, 0xA8, 0xAE, + 0x10, 0xBC, 0xC2, 0x1A, 0xB0, 0xC5, 0x8F, 0xED, 0x93, 0xDF, + 0xB1, 0x8D, 0xD9, 0xA2, 0xD6, 0xB6, 0x8A, 0xE0, 0x8E, 0xAD, + 0xB6, 0x3B, 0x34, 0x51, 0xFA, 0xC3, 0xFB, 0x91, 0xB1, 0x32, + 0x13, 0x6A, 0xF6, 0xE8, 0x33, 0x67, 0x7A, 0xFC, 0x7E, 0x58, + 0x37, 0x1E, 0x0D, 0x9F, 0x11, 0xAD, 0xAA, 0x14, 0x54, 0x73, + 0x24, 0x6F, 0xC3, 0xA4, 0x60, 0x23, 0x95, 0x71, 0x27, 0x30, + 0x6C, 0x2F, 0xD6, 0x87, 0xEE, 0xFD, 0xF3, 0xA4, 0x84, 0x60, + 0xE3, 0x05, 0xB0, 0x79, 0xCA, 0xF8, 0x3F, 0x79, 0x06, 0x0B, + 0xE1, 0x58, 0x4D, 0x81, 0x8B, 0xB7, 0xFE, 0x7C, 0xD2, 0x2D, + 0x07, 0x4C, 0x59, 0x46, 0xE0, 0x9C, 0xEF, 0xC0, 0xDB, 0xF4, + 0x35, 0x57, 0x26, 0x05, 0xC7, 0x0D, 0x2E, 0x2E, 0xFC, 0xF0, + 0xA0, 0x80, 0xDD, 0x8F, 0xF9, 0xCF, 0x64, 0xDA, 0x89, 0xAA, + 0xE3, 0x02, 0x5C, 0x41, 0x82, 0x10, 0x37, 0x30, 0x2B, 0x25, + 0x65, 0x08, 0x8D, 0xB0, 0x8C, 0x98, 0xBA, 0x26, 0xA5, 0x78, + 0xC3, 0x15, 0xD9, 0x4F, 0x2F, 0xEA, 0x4C, 0xC4, 0x3C, 0xBD, + 0x9B, 0x48, 0xDF, 0xC4, 0xC3, 0x06, 0xA0, 0xE8, 0x0D, 0x2F, + 0x5B, 0xE7, 0x78, 0xC3, 0x4A, 0x4C, 0x65, 0x5F, 0x92, 0x2A, + 0xFE, 0x93, 0xFD, 0x42, 0x69, 0x8B, 0xE8, 0x86, 0xD8, 0xDB, + 0xD0, 0xE0, 0xA4, 0xAD, 0x30, 0x0D, 0xB4, 0x2A, 0x4B, 0x84, + 0xFC, 0x98, 0x27, 0x61, 0x40, 0x5A, 0x54, 0xF5, 0x80, 0x8E, + 0x43, 0x5F, 0x72, 0x4D, 0x6D, 0xC0, 0xE5, 0x29, 0x7A, 0x62, + 0x0A, 0x72, 0x68, 0x11, 0x83, 0x1A, 0x00, 0x39, 0x24, 0x7A, + 0x49, 0xE5, 0xDC, 0x3A, 0xAD, 0xFB, 0x1F, 0xE4, 0x73, 0xC7, + 0x2F, 0x44, 0x83, 0x0C, 0xE4, 0x47, 0xAF, 0x91, 0x85, 0xCA, + 0xE0, 0x4F, 0x2A, 0x46, 0x69, 0xFF, 0xB2, 0x52, 0x7E, 0xCE, + 0xD6, 0xBD, 0xC9, 0x59, 0x7B, 0x72, 0x0A, 0x45, 0x11, 0x23, + 0xF9, 0xF1, 0xA1, 0x04, 0x2E, 0x8F, 0x8F, 0xA6, 0x44, 0x72, + 0xA6, 0xE9, 0xBC, 0xB8, 0x58, 0x82, 0xA1, 0x0F, 0x20, 0xC1, + 0x3D, 0xD4, 0x2B, 0xFB, 0x63, 0xDF, 0xCE, 0x12, 0xD4, 0x72, + 0x37, 0x72, 0x71, 0xE9, 0x5F, 0xFE, 0x51, 0x20, 0xA6, 0x28, + 0xB9, 0xF6, 0x96, 0xF7, 0x01, 0xFF, 0xA8, 0xAE, 0x3F, 0x18, + 0xE8, 0xD6, 0x54, 0x90, 0x08, 0xAE, 0x16, 0xDD, 0x1A, 0xB3, + 0xFF, 0x99, 0xCC, 0xBD, 0xA1, 0x7C, 0xCC, 0x2E, 0x60, 0x8E, + 0xDE, 0x67, 0xBE, 0x8D, 0x88, 0x8E, 0x89, 0x59, 0xDB, 0x67, + 0xBC, 0xD2, 0xD1, 0xB4, 0x98, 0xB0, 0x57, 0xAA, 0x8F, 0x65, + 0x3A, 0xFD, 0xE0, 0xF3, 0xE1, 0xCD, 0x00, 0xA3, 0x0F, 0x0A, + 0x62, 0xEC, 0xBA, 0xF4, 0xDC, 0xC8, 0x33, 0xE0, 0xAB, 0x50, + 0x53, 0x39, 0x6C, 0x13, 0x37, 0x86, 0xF2, 0xC6, 0x78, 0x0C, + 0xBD, 0xA5, 0x3F, 0x00, 0x17, 0x7B, 0xF4, 0xC4, 0xE2, 0x9D, + 0x26, 0x0D, 0x55, 0x28, 0x8D, 0xC3, 0x47, 0x70, 0x36, 0xE4, + 0xC6, 0xF7, 0xFF, 0x20, 0xB6, 0xFB, 0x57, 0x2E, 0x21, 0x12, + 0xE3, 0x01, 0xA3, 0xBB, 0xA0, 0x0F, 0xF5, 0xF3, 0x65, 0xA3, + 0x22, 0xC3, 0xC5, 0x88, 0x20, 0x72, 0x35, 0xAA, 0x94, 0xEB, + 0xC4, 0x43, 0x48, 0xAB, 0xA0, 0x57, 0xBB, 0xCF, 0xBF, 0xCB, + 0xCB, 0xF6, 0xEA, 0x55, 0x4E, 0x72, 0xC7, 0x04, 0x73, 0x83, + 0x57, 0x1F, 0xB9, 0xD6, 0xAA, 0x64, 0x14, 0xA0, 0xD1, 0xD3, + 0x7F, 0x45, 0x7A, 0xCC, 0xFC, 0xCD, 0xF6, 0x15, 0xE0, 0x3B, + 0xB3, 0x76, 0xF5, 0x63, 0x47, 0x18, 0x2D, 0x07, 0xDC, 0x98, + 0xE6, 0x06, 0x72, 0x3C, 0xF1, 0x57, 0xF0, 0x40, 0x90, 0xE9, + 0x9D, 0x65, 0x4F, 0xA0, 0x5B, 0x2F, 0x1E, 0x44, 0x0E, 0xFE, + 0xDB, 0xA4, 0xC6, 0x94, 0x86, 0x73, 0xE6, 0x54, 0x66, 0x5E, + 0xAA, 0x80, 0x54, 0xE3, 0x96, 0x03, 0x48, 0xDD, 0xA3, 0x22, + 0x00, 0x87, 0xF6, 0x71, 0xE9, 0xF9, 0xF6, 0xD4, 0x0A, 0x99, + 0x80, 0xD0, 0x88, 0x91, 0x87, 0x79, 0xF7, 0x3D, 0xDE, 0x6A, + 0x9F, 0x19, 0x0C, 0xFE, 0x8D, 0xF1, 0x65, 0x54, 0x31, 0xA2, + 0x45, 0x8C, 0x46, 0x3B, 0xEE, 0xC4, 0x09, 0x7C, 0xF4, 0x3A, + 0x2F, 0xFD, 0x88, 0x4E, 0xD0, 0xF5, 0xF2, 0xEF, 0xF0, 0x5F, + 0x10, 0xD0, 0x03, 0x72, 0xB7, 0x42, 0xBB, 0xFE, 0x06, 0xAB, + 0x21, 0xD6, 0xBB, 0x7E, 0xEC, 0x02, 0x1B, 0x66, 0x89, 0xF8, + 0xBD, 0x87, 0xB7, 0x04, 0x1D, 0x42, 0x94, 0x65, 0x54, 0x96, + 0x65, 0x25, 0xB8, 0xF6, 0xC7, 0x2A, 0x69, 0x37, 0xA7, 0x8C, + 0xD6, 0xCF, 0x79, 0x95, 0x3A, 0x78, 0x8B, 0x51, 0x92, 0x3F, + 0x62, 0x9E, 0x35, 0xF3, 0x0B, 0xD7, 0x4B, 0xD0, 0xAD, 0x16, + 0xE6, 0x7B, 0x6F, 0xF7, 0xA7, 0x4A, 0xF6, 0x5C, 0x0A, 0x02, + 0x26, 0x6B, 0x58, 0x8F, 0x8F, 0xDA, 0x11, 0x46, 0x23, 0x0F, + 0x63, 0x1C, 0x1C, 0xDA, 0x2F, 0xAE, 0xFE, 0x60, 0xFB, 0xD8, + 0xFA, 0xC5, 0xF1, 0xDE, 0x38, 0x72, 0x38, 0xBA, 0x83, 0xEF, + 0x80, 0x7B, 0xE3, 0x8A, 0xBB, 0x36, 0x8A, 0x8E, 0x32, 0x75, + 0x74, 0x1E, 0xA2, 0x59, 0x75, 0xA4, 0x8F, 0x0A, 0x52, 0x0F, + 0x29, 0x96, 0x3C, 0xA5, 0x1D, 0x43, 0x72, 0x62, 0x04, 0x9F, + 0x61, 0x9B, 0x42, 0xC1, 0xAE, 0x66, 0x10, 0x8C, 0x4D, 0x3F, + 0x6D, 0x21, 0xCE, 0x25, 0x88, 0x4F, 0x46, 0x5D, 0x5C, 0xF5, + 0x06, 0x6B, 0xFB, 0x6A, 0xA6, 0x08, 0x08, 0x81, 0x5F, 0xB8, + 0x1B, 0x7D, 0x5C, 0xEA, 0x45, 0xC4, 0x40, 0xA7, 0xFE, 0xD4, + 0xC0, 0xB3, 0x74, 0xCC, 0x31, 0xCF, 0x9C, 0xC0, 0x28, 0x7F, + 0xE7, 0xDC, 0x73, 0xB8, 0x1E, 0xAB, 0x85, 0x3F, 0x77, 0x62, + 0x3E, 0x0B, 0x7A, 0x47, 0x35, 0x09, 0x64, 0xE8, 0x17, 0xB1, + 0xBB, 0x37, 0xD5, 0x9E, 0x4B, 0x17, 0xB0, 0x4B, 0x2B, 0x2A, + 0xFC, 0x02, 0xEE, 0x5C, 0x2B, 0x06, 0xAD, 0x8A, 0x53, 0x84, + 0x3B, 0xA5, 0xF6, 0x03, 0x08, 0x85, 0xEA, 0x97, 0x2E, 0x35, + 0xEA, 0x41, 0xB9, 0xFD, 0x2F, 0xCC, 0x03, 0xA0, 0x9F, 0x87, + 0x12, 0x9A, 0xB7, 0x44, 0x02, 0x40, 0x38, 0x79, 0x6A, 0x00, + 0xE9, 0x38, 0x2B, 0xD3, 0x3E, 0xEB, 0x9C, 0x13, 0x51, 0xF5, + 0x9A, 0x79, 0x25, 0x12, 0xF9, 0x58, 0xC0, 0x6D, 0x74, 0x34, + 0x02, 0x88, 0xF5, 0xD1, 0x55, 0xD2, 0x19, 0xF2, 0x65, 0x3E, + 0x06, 0x90, 0xC2, 0x6E, 0x52, 0xD0, 0x33, 0x90, 0xF8, 0x5F, + 0x91, 0xA4, 0xAC, 0xBA, 0x73, 0x7F, 0x4D, 0x86, 0xFC, 0xCB, + 0x22, 0x50, 0x82, 0xA7, 0xB6, 0xCB, 0x0A, 0x40, 0xA2, 0x38, + 0xB1, 0xCF, 0xFA, 0x54, 0xDF, 0x21, 0x11, 0x6D, 0xB7, 0x92, + 0x98, 0xF9, 0xEB, 0xCD, 0x4D, 0x04, 0x97, 0x91, 0x23, 0xFE, + 0xD0, 0x9F, 0xA6, 0xEA, 0x27, 0x49, 0x4C, 0x86, 0x1F, 0x8D, + 0x2F, 0x2A, 0x08, 0x49, 0xAD, 0x59, 0xE7, 0x10, 0x6A, 0xDD, + 0xF6, 0xE2, 0x65, 0xA6, 0x08, 0xC9, 0x77, 0x46, 0x26, 0xE0, + 0xF7, 0xDB, 0x76, 0x99, 0x6D, 0xD7, 0x45, 0x0A, 0x87, 0xBD, + 0x96, 0x2D, 0x71, 0x11, 0xBB, 0x4E, 0x6B, 0xC1, 0x43, 0x8E, + 0x1B, 0x36, 0x03, 0x6A, 0x0C, 0xBF, 0x62, 0x1E, 0xE4, 0x27, + 0xD1, 0xD0, 0xF0, 0xA6, 0xE6, 0xF5, 0x11, 0xA6, 0x11, 0xDB, + 0x46, 0xA8, 0xBC, 0xEF, 0x75, 0x58, 0xC0, 0x0C, 0x11, 0xA0, + 0xB2, 0x59, 0x1D, 0x4D, 0x28, 0x7F, 0xF8, 0xEC, 0xBA, 0x82, + 0x1D, 0xC6, 0xFE, 0x10, 0xC3, 0x34, 0xA7, 0x66, 0x4E, 0x91, + 0x70, 0xA5, 0x56, 0x36, 0xC4, 0x45, 0x34, 0x1F, 0x4A, 0x7E, + 0x77, 0xDD, 0x17, 0x76, 0x89, 0xED, 0x98, 0x8B, 0xF8, 0xD1, + 0x23, 0x30, 0x9B, 0xB2, 0xB8, 0xB1, 0x57, 0xDC, 0x67, 0x11, + 0x3D, 0x37, 0xDD, 0xC5, 0x8B, 0x51, 0xB0, 0x0C, 0x11, 0x01, + 0x9E, 0x36, 0x1C, 0x0B, 0xC6, 0x06, 0x26, 0x41, 0xB1, 0xE5, + 0x6A, 0xA4, 0x10, 0xA9, 0xE5, 0x67, 0xDE, 0xB7, 0x19, 0x56, + 0xFF, 0xE6, 0xB0, 0x5D, 0x72, 0x78, 0x98, 0xC0, 0x23, 0xEA, + 0x52, 0x5B, 0xBF, 0x76, 0xE3, 0x68, 0xA1, 0x58, 0x56, 0xEE, + 0x63, 0x5E, 0x3F, 0xFA, 0x80, 0x16, 0x85, 0x75, 0x07, 0x67, + 0x7F, 0x37, 0x57, 0xC9, 0xB1, 0x1F, 0xAC, 0xBB, 0x1F, 0x42, + 0xD3, 0x93, 0xBE, 0x49, 0x01, 0x90, 0x8B, 0xA9, 0xEF, 0x7C, + 0xF8, 0x72, 0xA5, 0xE8, 0x5E, 0x4C, 0x90, 0x07, 0xDA, 0xF1, + 0x8E, 0x53, 0x31, 0x74, 0x5C, 0x48, 0xB9, 0xCA, 0xE6, 0xF3, + 0xEB, 0xD1, 0x26, 0x14, 0xC6, 0x3D, 0x69, 0x84, 0x51, 0xA3, + 0x91, 0xFA, 0x89, 0x83, 0xC3, 0x67, 0xA3, 0x6C, 0x3D, 0x79, + 0x63, 0x26, 0x64, 0xC4, 0x34, 0xBE, 0xDE, 0xFD, 0x57, 0x7D, + 0x22, 0x29, 0xF2, 0xB8, 0x66, 0xF3, 0x3B, 0x56, 0x6F, 0x52, + 0x69, 0x85, 0xBD, 0x86, 0xD3, 0x25, 0xAC, 0x88, 0x23, 0xCD, + 0x6A, 0x33, 0x26, 0x35, 0x29, 0x7A, 0x5A, 0x95, 0xB3, 0xF4, + 0xD4, 0x1E, 0xDC, 0xBC, 0x38, 0xA1, 0xB7, 0x79, 0x21, 0x8D, + 0x0D, 0x69, 0x1C, 0x58, 0x20, 0x86, 0x51, 0x39, 0xB3, 0x32, + 0xBB, 0x10, 0x76, 0xBB, 0xB2, 0x76, 0x22, 0x29, 0x02, 0x50, + 0x7C, 0x85, 0x99, 0x9D, 0x14, 0xE7, 0x64, 0x63, 0x84, 0x6E, + 0xD6, 0x11, 0xF9, 0x23, 0xD9, 0x03, 0x2D, 0x1E, 0x0D, 0x02, + 0xA7, 0xA7, 0x5E, 0x36, 0x16, 0x4F, 0x02, 0x6A, 0x43, 0xB1, + 0x87, 0xF6, 0xD2, 0x85, 0x6F, 0x4A, 0xB6, 0xED, 0x32, 0xAB, + 0x76, 0x33, 0x3C, 0xBD, 0xA8, 0xDF, 0x6F, 0x3D, 0xE7, 0x37, + 0x75, 0x0F, 0x7A, 0x8A, 0xDC, 0xF1, 0xD2, 0x16, 0x91, 0xFD, + 0x77, 0x81, 0x7B, 0xF7, 0x9A, 0xCF, 0x17, 0xFD, 0x27, 0x45, + 0x86, 0xB6, 0xB5, 0x5C, 0xC2, 0x3F, 0x65, 0xF0, 0x55, 0xC1, + 0xAC, 0xA7, 0x73, 0x03, 0x3D, 0x6A, 0x3B, 0x17, 0xE8, 0x26, + 0x0A, 0xCD, 0x7C, 0x78, 0x0B, 0xA0, 0xB3, 0x77, 0xA7, 0xF1, + 0x98, 0xA5, 0x0E, 0x7E, 0xC6, 0x85, 0x37, 0xCB, 0xA5, 0xF9, + 0x2A, 0x63, 0xE7, 0xDE, 0x4B, 0x28, 0x92, 0x08, 0x8A, 0xC6, + 0x3C, 0x6C, 0x08, 0xEA, 0xDB, 0x2C, 0xC8, 0x45, 0x22, 0x4F, + 0x4D, 0x44, 0x5E, 0x59, 0x6E, 0xC9, 0xFB, 0x83, 0xB3, 0xE3, + 0x06, 0x31, 0xBC, 0xAE, 0x4D, 0x3C, 0x56, 0xA5, 0x49, 0x43, + 0xA2, 0xDA, 0x78, 0x21, 0x06, 0x92, 0x14, 0x51, 0x57, 0xB4, + 0x88, 0xE1, 0xF8, 0xD5, 0x0D, 0x8B, 0xC2, 0x17, 0x44, 0x5B, + 0xC7, 0xD9, 0x9B, 0x10, 0xB8, 0x56, 0x89, 0xAE, 0x94, 0x2C, + 0x40, 0xEA, 0x0D, 0xD8, 0x4E, 0x25, 0x91, 0x88, 0x19, 0x92, + 0x0F, 0xF5, 0xBE, 0xF5, 0x7C, 0x9F, 0xC8, 0xEB, 0xED, 0x90, + 0x37, 0xDF, 0x8F, 0x78, 0x82, 0xA6, 0x4A, 0xC1, 0x43, 0x65, + 0x7A, 0x98, 0x18, 0x04, 0x16, 0x76, 0xDB, 0x73, 0xBB, 0xA3, + 0x27, 0xF8, 0xC0, 0x87, 0x0B, 0x86, 0x53, 0xA4, 0x4A, 0x0C, + 0xAF, 0x10, 0xFB, 0x34, 0x63, 0x83, 0xE8, 0x28, 0x3C, 0x74, + 0x49, 0x81, 0x90, 0x24, 0x88, 0xB1, 0xE6, 0x69, 0x12, 0x91, + 0xA6, 0x05, 0x38, 0x46, 0x1C, 0x31, 0x04, 0x44, 0x1B, 0x3A, + 0x06, 0xAC, 0xCD, 0xD4, 0xE3, 0x4F, 0x65, 0x33, 0x5D, 0xC0, + 0x5B, 0x94, 0x7B, 0x27, 0xB0, 0xE6, 0xB8, 0x08, 0x00, 0x46, + 0x38, 0x93, 0x36, 0xF6, 0x89, 0x90, 0xBC, 0xDD, 0x07, 0xF5, + 0x20, 0x84, 0x8B, 0x9D, 0xB0, 0x33, 0x86, 0x0C, 0x49, 0x66, + 0x9C, 0x01, 0x46, 0x4B, 0x5C, 0xC2, 0x16, 0xE7, 0x6B, 0xD3, + 0x07, 0xB5, 0xD3, 0x24, 0xF9, 0x7A, 0x87, 0xBC, 0xCE, 0x21, + 0xBB, 0x21, 0x67, 0x75, 0x86, 0xC6, 0x13, 0x8B, 0x77, 0xC7, + 0xBC, 0x7C, 0x97, 0x13, 0xBF, 0xA4, 0x9C, 0x45, 0x8F, 0xE0, + 0xB2, 0x20, 0x48, 0x79, 0x4A, 0xEB, 0xA2, 0xC3, 0x21, 0x69, + 0x6D, 0x98, 0xC3, 0x88, 0xA0, 0xF4, 0xD5, 0x62, 0xBE, 0x80, + 0xBB, 0x54, 0x2E, 0x8C, 0xDC, 0xF6, 0x32, 0x03, 0xF5, 0xD8, + 0x67, 0xA0, 0x8C, 0x8E, 0xFB, 0x08, 0xE4, 0xDA, 0x15, 0xA5, + 0xA5, 0x7C, 0x6E, 0x33, 0xCB, 0x95, 0x94, 0xEE, 0x72, 0x6B, + 0x8A, 0xDD, 0xF1, 0xEA, 0xAA, 0xD2, 0x0F, 0x37, 0xA3, 0xA7, + 0xD3, 0xE0, 0x2F, 0x72, 0x1B, 0x2C, 0x13, 0xD5, 0x7A, 0x4C, + 0x15, 0x8A, 0x62, 0x2B, 0xEF, 0x68, 0xB9, 0xEB, 0x9F, 0xDA, + 0x94, 0x2F, 0xD3, 0x4F, 0xE0, 0x08, 0x71, 0x81, 0x64, 0x2E, + 0x63, 0x99, 0x5A, 0xAF, 0x2B, 0x55, 0x6C, 0xD4, 0x5E, 0xE4, + 0xAE, 0xBD, 0xE4, 0xCD, 0xB6, 0xC7, 0x17, 0x1F, 0xD4, 0xFF, + 0x2E, 0x07, 0x52, 0x6C, 0xB7, 0xF0, 0xEF, 0x18, 0x49, 0x90, + 0xAE, 0xD8, 0xCF, 0xDA, 0x86, 0xC8, 0xA5, 0x7C, 0x42, 0xD6, + 0x5F, 0xB0, 0x32, 0x40, 0xE2, 0xB7, 0x6D, 0x07, 0x19, 0x77, + 0xB2, 0xE8, 0x2D, 0xED, 0xF7, 0x71, 0xC4, 0x78, 0xD1, 0xBC, + 0xC6, 0xE8, 0x2B, 0x91, 0x09, 0x58, 0xCF, 0x19, 0x03, 0x0B, + 0x74, 0x1E, 0x50, 0x95, 0xFC, 0x01, 0x0E, 0xB5, 0x63, 0xB6, + 0x79, 0xE6, 0x9E, 0xB4, 0xEE, 0x9D, 0x72, 0xA3, 0x55, 0xAF, + 0xB2, 0x34, 0xD1, 0x77, 0x5B, 0x68, 0x04, 0xE3, 0x9D, 0xC6, + 0x69, 0xF7, 0xA0, 0x31, 0x2C, 0xF6, 0x97, 0x34, 0xD5, 0xCD, + 0x7E, 0xAA, 0x21, 0x30, 0x50, 0x1D, 0xE1, 0xA9, 0xCD, 0x57, + 0x78, 0xE7, 0x95, 0xB7, 0xBA, 0x94, 0x3E, 0x16, 0x4C, 0x16, + 0xD0, 0xF8, 0x2A, 0xFF, 0xD7, 0x5A, 0x07, 0x39, 0x2C, 0x1B, + 0xF0, 0xAC, 0xB9, 0xAD, 0x07, 0x6F, 0xE3, 0xC9, 0xDE, 0x1F, + 0xEE, 0x31, 0x22, 0x46, 0x61, 0x9F, 0xA3, 0xD6, 0xE6, 0x01, + 0x70, 0x3A, 0xB1, 0x12, 0x72, 0x39, 0xA8, 0x60, 0x82, 0x80, + 0xBD, 0x60, 0xE8, 0x8D, 0xF5, 0xB3, 0x65, 0xC4, 0x04, 0xB5, + 0x9E, 0xFB, 0xA5, 0x4D, 0xD0, 0x32, 0x1B, 0xA0, 0x52, 0xA5, + 0x14, 0x43, 0x7D, 0x98, 0xEA, 0x38, 0x89, 0x20, 0x02, 0xAF, + 0x2A, 0x94, 0xDE, 0xF6, 0x94, 0x4D, 0x73, 0xDF, 0x0C, 0x51, + 0x2E, 0x51, 0x92, 0x4C, 0x28, 0x4D, 0x24, 0xCC, 0x4A, 0x5B, + 0x23, 0x4B, 0xB2, 0xB9, 0xF8, 0x08, 0xBB, 0x64, 0x6E, 0x64, + 0xAF, 0x3F, 0x35, 0xCD, 0x9D, 0xBE, 0x26, 0xAF, 0x1F, 0x53, + 0x75, 0x92, 0xC3, 0x5A, 0x9E, 0xA6, 0xF0, 0xCA, 0xA4, 0x06, + 0x1F, 0x04, 0x08, 0x11, 0x16, 0xEF, 0xDE, 0x14, 0x1C, 0x5A, + 0x7E, 0xC1, 0x7E, 0x87, 0x30, 0xE2, 0xE6, 0x05, 0x84, 0x33, + 0x64, 0xAF, 0xC5, 0x69, 0x6F, 0x1C, 0x3D, 0x1B, 0x3F, 0x62, + 0x2D, 0x56, 0x9E, 0x08, 0x07, 0x27, 0x18, 0xAE, 0x3F, 0x3F, + 0xEB, 0xFA, 0x45, 0xFA, 0x05, 0x1A, 0xED, 0x3E, 0xB1, 0x62, + 0xA7, 0x1D, 0x74, 0x63, 0xCA, 0xC8, 0x22, 0x5F, 0xEC, 0x07, + 0x3D, 0xAD, 0x80, 0x9C, 0x8D, 0x3D, 0xCE, 0xD3, 0x4C, 0x30, + 0xB9, 0xF5, 0x38, 0x37, 0x4C, 0x99, 0xE0, 0xE8, 0x5F, 0x31, + 0xC4, 0x3A, 0x15, 0xCD, 0x42, 0x70, 0x48, 0xB2, 0x51, 0xF6, + 0x5A, 0xB1, 0xE7, 0x72, 0x66, 0x10, 0x6A, 0x5E, 0xE3, 0xAD, + 0x13, 0xB7, 0x04, 0x13, 0x22, 0xB7, 0xFC, 0x3F, 0xCE, 0xE7, + 0x0D, 0x1A, 0x8E, 0x77, 0xDC, 0x93, 0xBC, 0x7C, 0x01, 0x71, + 0x20, 0x36, 0x30, 0xF0, 0x27, 0xE4, 0xA1, 0x6D, 0xF6, 0x6C, + 0x7A, 0x6B, 0x45, 0x42, 0x1E, 0x80, 0xF6, 0x85, 0xB6, 0xA7, + 0x38, 0x74, 0x36, 0xDB, 0x36, 0x8C, 0x0C, 0x7A, 0x5A, 0x9E, + 0x9D, 0xF0, 0x32, 0x4B, 0x86, 0x92, 0x24, 0x30, 0xDC, 0xE1, + 0x4E, 0xDF, 0x12, 0x9C, 0x11, 0x56, 0xAD, 0x8F, 0xB1, 0x4E, + 0x46, 0x51, 0x95, 0x55, 0x9C, 0x2E, 0x21, 0x87, 0xEF, 0x53, + 0x5A, 0x35, 0x18, 0x8B, 0xE6, 0x23, 0x7C, 0x75, 0xD6, 0x8C, + 0x42, 0x90, 0x92, 0xD0, 0xF3, 0x9D, 0xCE, 0x83, 0xBC, 0xC1, + 0x5B, 0xCF, 0x9E, 0x63, 0xEB, 0xAE, 0xB4, 0xC3, 0x11, 0xA9, + 0x05, 0x5D, 0x9A, 0x39, 0x9E, 0x8D, 0x98, 0x5B, 0x24, 0x10, + 0xBA, 0x27, 0xE3, 0xBF, 0x55, 0x79, 0xA1, 0x34, 0x7A, 0x3B, + 0x21, 0x45, 0x6C, 0x84, 0xCB, 0xE1, 0x17, 0xF5, 0x4C, 0x7C, + 0x96, 0x93, 0xD9, 0x23, 0xCB, 0x79, 0x52, 0x30, 0xA7, 0x97, + 0x0E, 0x09, 0x3B, 0xE4, 0xC3, 0x6F, 0xB5, 0xFC, 0x0E, 0x10, + 0x6A, 0x62, 0x1F, 0xBD, 0x51, 0xC1, 0x82, 0x54, 0xDB, 0x4F, + 0x46, 0x29, 0x6B, 0xB9, 0x44, 0xBA, 0x41, 0x34, 0x4B, 0xAC, + 0x2B, 0xBE, 0x3A, 0xB5, 0x0D, 0xD1, 0xB0, 0x63, 0x42, 0x07, + 0xAC, 0xBA, 0x85, 0x25, 0x5E, 0x57, 0x0A, 0xAE, 0x4D, 0xCF, + 0x00, 0xA7, 0x9C, 0xD9, 0x4F, 0x87, 0x9B, 0xDE, 0x92, 0xAA, + 0x40, 0xBD, 0x08, 0xC3, 0x78, 0xDD, 0xB1, 0xD3, 0x67, 0x85, + 0xED, 0x5B, 0xC0, 0x71, 0x15, 0xD8, 0x24, 0x13, 0x88, 0x95, + 0x65, 0x03, 0x48, 0x3A, 0x0E, 0x65, 0xC9, 0x6E, 0xB0, 0xFA, + 0xC6, 0xE4, 0xAD, 0xD4, 0xED, 0xEF, 0xAB, 0x8B, 0x7B, 0x18, + 0x3E, 0x28, 0x5D, 0xE7, 0x9F, 0x04, 0x43, 0xA0, 0x25, 0xBF, + 0x8D, 0xF9, 0xBC, 0x16, 0x2D, 0xC8, 0x4A, 0x3B, 0x60, 0x34, + 0x07, 0x3E, 0xA1, 0xFD, 0x08, 0xC4, 0xF9, 0x2A, 0x56, 0x33, + 0xDD, 0xAE, 0x73, 0xDF, 0xB7, 0xB2, 0x8C, 0x5B, 0x43, 0x3C, + 0x00, 0xFF, 0xC7, 0x7B, 0xC4, 0xC0, 0x23, 0x0C, 0x45, 0x3C, + 0x51, 0xA3, 0xA8, 0xF7, 0x88, 0x2D, 0x67, 0xCD, 0xD9, 0x94, + 0x61, 0x0C, 0xC8, 0xC7, 0xF3, 0xAA, 0x77, 0xE4, 0xEE, 0xFD, + 0x70, 0xF2, 0x0F, 0x89, 0x49, 0xE6, 0x93, 0x5C, 0x6E, 0x51, + 0x95, 0x12, 0x80, 0xB6, 0x55, 0x20, 0x4D, 0x54, 0xE8, 0x65, + 0xA4, 0xE7, 0xBF, 0xC8, 0xF8, 0x0C, 0x60, 0x0A, 0xBD, 0xD0, + 0x10, 0x48, 0xD9, 0x2B, 0xCB, 0x62, 0x4B, 0xAF, 0xAE, 0x08, + 0x1A, 0x1D, 0xC6, 0x7A, 0xF7, 0xC6, 0xBE, 0xE2, 0x50, 0x73, + 0x97, 0xE5, 0x25, 0xFA, 0xB4, 0xBF, 0x4C, 0xA7, 0x46, 0x44, + 0xE3, 0x6A, 0x47, 0xEC, 0x16, 0xA3, 0xC1, 0xFD, 0xC3, 0x1F, + 0xDF, 0x60, 0x2C, 0x86, 0x4A, 0xF1, 0x50, 0x09, 0x49, 0xDF, + 0xB4, 0x9D, 0xF4, 0x5A, 0x11, 0x9B, 0x30, 0xEF, 0x3C, 0xB0, + 0x47, 0x82, 0xE9, 0x49, 0xA3, 0x4D, 0x33, 0xDA, 0xAB, 0xA9, + 0xFA, 0x80, 0x7C, 0x19, 0x43, 0x9E, 0xF6, 0xE2, 0x3B, 0xA6, + 0xF8, 0x6D, 0xB6, 0xA8, 0xFA, 0x62, 0xFE, 0x58, 0x2D, 0x77, + 0x45, 0x29, 0x79, 0x90, 0x0C, 0x7D, 0x0D, 0x81, 0xB0, 0x0A, + 0x82, 0x7B, 0xE1, 0x4E, 0xBB, 0xB0, 0x95, 0xC8, 0xF4, 0xB8, + 0x42, 0xF8, 0x95, 0x97, 0x1B, 0x7C, 0x7E, 0x86, 0x66, 0x88, + 0x66, 0xC2, 0x45, 0x83, 0x4C, 0x83, 0x33, 0x85, 0xF4, 0x4F, + 0x83, 0x43, 0x89, 0xDC, 0x34, 0x88, 0x47, 0xDC, 0x37, 0xCE, + 0xB4, 0x21, 0xCC, 0xD0, 0x78, 0x84, 0x67, 0x12, 0xFE, 0x45, + 0xEC, 0x22, 0x4C, 0xE1, 0x5B, 0x1E, 0x03, 0x97, 0x56, 0x9F, + 0x50, 0x2D, 0x63, 0x35, 0x01, 0x5B, 0xAE, 0xFF, 0x68, 0x91, + 0xF6, 0x62, 0x66, 0x92, 0xA9, 0xE4, 0x1B, 0x80, 0x09, 0x5E, + 0xC1, 0x9A, 0xB9, 0x6A, 0x37, 0xB5, 0xAC, 0x52, 0xCD, 0x6E, + 0x6F, 0xCE, 0x60, 0x56, 0x39, 0x11, 0x5F, 0xF3, 0xD8, 0xF5, + 0x46, 0x75, 0xFA, 0x70, 0x0C, 0xC8, 0x59, 0x93, 0x30, 0x7A, + 0x52, 0xA0, 0x0B, 0xEA, 0x49, 0x69, 0x6A, 0x4D, 0x25, 0x4F, + 0x85, 0x31, 0x4A, 0x45, 0x1F, 0x02, 0x00, 0x65, 0x17, 0x1E, + 0xF2, 0x0E, 0x8E, 0x10, 0x46, 0xE3, 0xAF, 0x15, 0x95, 0x34, + 0x82, 0x68, 0x27, 0x09, 0xE3, 0xCC, 0x84, 0x29, 0xA1, 0xE2, + 0xCC, 0x02, 0x49, 0x3E, 0x77, 0x87, 0xBD, 0xF4, 0x1E, 0xB5, + 0x2E, 0x34, 0x93, 0x0C, 0x51, 0xB3, 0x4E, 0xB0, 0x36, 0xA4, + 0x2C, 0xB3, 0x3D, 0x0D, 0x74, 0xA4, 0x8E, 0x5E, 0xFA, 0x0A, + 0xC4, 0xF2, 0x86, 0x73, 0xF3, 0x59, 0x9C, 0x8D, 0x80, 0x04, + 0x3D, 0xA4, 0x73, 0xF5, 0xA4, 0x59, 0x5C, 0x60, 0xE0, 0xA3, + 0x2F, 0xD2, 0xEE, 0x80, 0x52, 0x15, 0x63, 0xFF, 0x35, 0x45, + 0x5C, 0x3D, 0x14, 0x7B, 0xCA, 0x85, 0x1B, 0x05, 0xB4, 0x4E, + 0xFD, 0x58, 0x57, 0xA3, 0xC9, 0x4A, 0x7D, 0x9D, 0xAF, 0xC4, + 0x7D, 0xBC, 0xFE, 0x1D, 0x16, 0x94, 0x49, 0x52, 0x42, 0x62, + 0x3D, 0xB0, 0x50, 0x7D, 0xE2, 0xB7, 0x27, 0x30, 0x39, 0x7A, + 0xB5, 0x81, 0x9F, 0xA8, 0x98, 0xE8, 0xB0, 0xD3, 0x9F, 0x96, + 0x70, 0x56, 0xE3, 0xE9, 0x12, 0x3F, 0xA4, 0x35, 0x2F, 0x4D, + 0x72, 0x6F, 0xF9, 0x58, 0xBE, 0xCF, 0xA5, 0x11, 0xA0, 0x19, + 0x74, 0x87, 0x6F, 0xD0, 0xC9, 0xA4, 0x80, 0x1A, 0x5B, 0x08, + 0x3F, 0x54, 0x9D, 0x9E, 0xF7, 0xA7, 0x1E, 0x67, 0x1D, 0xB2, + 0x8A, 0xC2, 0x0A, 0x57, 0x2B, 0x08, 0x5C, 0x01, 0xCF, 0x91, + 0x1A, 0xA2, 0xF2, 0x1F, 0xD5, 0xF4, 0x9F, 0x59, 0x5D, 0xCA, + 0xB8, 0x69, 0x9A, 0xB0, 0x0C, 0x95, 0x8F, 0xD6, 0x96, 0x5F, + 0x81, 0x8B, 0xFB, 0x79, 0x7B, 0xFF, 0xD7, 0xF5, 0xDE, 0xF7, + 0xB5, 0x6B, 0x97, 0xCE, 0x6F, 0xE6, 0xEE, 0xA4, 0x67, 0xC5, + 0xF6, 0x6C, 0x1F, 0xE5, 0xDC, 0x8D, 0xF7, 0x02, 0x4D, 0xE3, + 0xCA, 0xDA, 0xCA, 0x9E, 0x6C, 0x86, 0x96, 0xD1, 0x21, 0x18, + 0xA2, 0x6B, 0xA3, 0xE2, 0xD2, 0x85, 0x04, 0xC8, 0xB4, 0x5D, + 0x7D, 0x70, 0x0F, 0xFE, 0xEC, 0xFF, 0xC6, 0x30, 0x3D, 0x1F, + 0x66, 0x23, 0xF1, 0x68, 0x7C, 0xFD, 0x2B, 0xED, 0x54, 0xE7, + 0xDE, 0xAD, 0x5C, 0xD8, 0x36, 0x1A, 0xC3, 0xD6, 0x41, 0x11, + 0x40, 0x79, 0xCE, 0x76, 0x4C, 0xF0, 0xEA, 0x12, 0xC2, 0xF8, + 0xBA, 0x9E, 0xA0, 0x60, 0x33, 0x96, 0x2A, 0xE9, 0xD5, 0x50, + 0xB8, 0xD8, 0xCC, 0xE1, 0x3F, 0x92, 0x0B, 0x46, 0xBB, 0x04, + 0x4E, 0x17, 0xF3, 0xF7, 0x00, 0x5C, 0x07, 0xBF, 0x67, 0x0D, + 0x42, 0x63, 0x9C, 0xC4, 0x6C, 0x30, 0x07, 0x72, 0x66, 0xC8, + 0x10, 0xF3, 0x89, 0x94, 0x17, 0x20, 0x70, 0x5B, 0xD8, 0x53, + 0xCF, 0x67, 0xD5, 0x55, 0x7F, 0x9E, 0x8C, 0x2E, 0xD1, 0x6D, + 0xDD, 0xCD, 0xE6, 0x92, 0x48, 0x14, 0x11, 0xE0, 0x58, 0x1F, + 0xAA, 0x9D, 0x43, 0xBD, 0x3C, 0xAF, 0x96, 0x5A, 0x41, 0x11, + 0x7F, 0xF8, 0x2F, 0x36, 0x05, 0xC4, 0xAD, 0x7F, 0x1C, 0x04, + 0x72, 0xE0, 0x44, 0x6F, 0x49, 0x13, 0xB6, 0xBE, 0x4F, 0xFA, + 0x41, 0x41, 0xDD, 0x11, 0x77, 0x10, 0x52, 0x13, 0xE1, 0x88, + 0xA9, 0x6D, 0x79, 0x2C, 0xDF, 0x9D, 0x3D, 0xBF, 0xED, 0xD4, + 0xEB, 0x93, 0x0F, 0xC3, 0xE9, 0x87, 0x83, 0x98, 0x23, 0x1B, + 0xC0, 0x5D, 0x1E, 0xAD, 0xC4, 0xF5, 0x5D, 0x34, 0x2A, 0x60, + 0x23, 0x5E, 0x38, 0x4E, 0xB1, 0x08, 0x91, 0x4E, 0xCA, 0x16, + 0xC5, 0x65, 0xC1, 0x56, 0x6C, 0xCB, 0x4C, 0xDF, 0x6D, 0x7F, + 0xBF, 0xF8, 0xF9, 0x04, 0xE3, 0x9A, 0xAB, 0x8D, 0x44, 0x5D, + 0xAA, 0x0D, 0x5A, 0x8B, 0x9B, 0xF5, 0x6A, 0x4A, 0x27, 0x8D, + 0x0A, 0xCF, 0x41, 0xC3, 0x41, 0x29, 0x92, 0xA2, 0x45, 0x3B, + 0xD0, 0xCB, 0xCF, 0x82, 0xE1, 0x7C, 0x82, 0xCD, 0x83, 0xBA, + 0x99, 0xDA, 0x73, 0xCF, 0x26, 0xE6, 0x3D, 0xF4, 0x8B, 0x06, + 0xD3, 0x25, 0x67, 0x27, 0x07, 0x1D, 0x88, 0xD5, 0xF5, 0xCB, + 0x58, 0x59, 0x9A, 0x0E, 0x56, 0x5D, 0xCD, 0x7F, 0x89, 0xD1, + 0x06, 0x9C, 0xFA, 0x0A, 0xEB, 0xE5, 0x31, 0x4D, 0x30, 0x18, + 0x9A, 0x54, 0x94, 0x3D, 0x4C, 0x12, 0x7B, 0xCD, 0x01, 0x12, + 0x9D, 0x34, 0x70, 0xC7, 0x3A, 0x7C, 0x57, 0x37, 0x3A, 0x8B, + 0xC3, 0xC9, 0x68, 0x5D, 0x8F, 0xBB, 0x22, 0xCD, 0x2A, 0x3A, + 0x4E, 0xE0, 0x71, 0xE9, 0xB1, 0x67, 0xFA, 0x07, 0x5F, 0x8B, + 0xBD, 0x81, 0x41, 0x63, 0xBA, 0x3D, 0x41, 0xB5, 0xA4, 0xD8, + 0x12, 0xC4, 0xD3, 0x00, 0x05, 0xFC, 0x06, 0x9B, 0x02, 0x73, + 0x7A, 0x4D, 0x6D, 0xE8, 0x41, 0x11, 0x18, 0x95, 0xD4, 0x79, + 0xE1, 0xDC, 0x35, 0x28, 0x14, 0x88, 0xC3, 0xA2, 0x5E, 0x6C, + 0x5E, 0x42, 0x40, 0x78, 0xB2, 0xA2, 0x35, 0xE6, 0x71, 0x67, + 0x5C, 0x83, 0x2E, 0x94, 0xC8, 0x59, 0x1D, 0x3B, 0xD8, 0x6A, + 0xFA, 0xCD, 0x84, 0x81, 0xD6, 0xCE, 0x4D, 0xE4, 0x3E, 0x00, + 0x06, 0x6C, 0x26, 0x3E, 0xB8, 0x5D, 0x35, 0x23, 0x99, 0xFD, + 0x0B, 0xC9, 0x82, 0x10, 0xA7, 0x3C, 0x13, 0x16, 0xA6, 0x55, + 0x5C, 0x8D, 0x9D, 0x47, 0x17, 0x98, 0xDC, 0xC8, 0xB3, 0xA1, + 0xFB, 0x98, 0xAC, 0x61, 0x3B, 0xB2, 0x6F, 0x91, 0x35, 0x5F, + 0x5C, 0xF8, 0x0A, 0x28, 0xBB, 0x4B, 0xF7, 0xEA, 0x26, 0x68, + 0x69, 0x27, 0x13, 0xF2, 0x15, 0xE4, 0xD1, 0x77, 0x27, 0x65, + 0xB5, 0xD7, 0x47, 0x86, 0xB8, 0x01, 0x8E, 0x4A, 0x4D, 0xB2, + 0xF0, 0x70, 0xEA, 0xE9, 0x97, 0xDC, 0x9A, 0x23, 0x03, 0xFC, + 0x4C, 0xB4, 0x63, 0xAB, 0x01, 0xD8, 0xF3, 0x06, 0x11, 0xC8, + 0x8F, 0x38, 0x39, 0x53, 0xCB, 0xFE, 0xD2, 0xE7, 0xAC, 0x82, + 0xBE, 0xE0, 0x88, 0x07, 0x75, 0x2D, 0x2B, 0xBB, 0x11, 0xED, + 0x9F, 0x9F, 0xC2, 0x3E, 0x15, 0x84, 0x8B, 0xDE, 0x50, 0xA8, + 0x4D, 0x9D, 0x00, 0xF0, 0x9B, 0xE4, 0xD1, 0x13, 0x40, 0xB6, + 0x74, 0x1A, 0xBB, 0x37, 0x41, 0x1C, 0x4C, 0x37, 0xC5, 0x40, + 0x76, 0xA8, 0xCF, 0x4F, 0x43, 0x52, 0x35, 0xAF, 0x73, 0x27, + 0x82, 0x11, 0x1A, 0x3D, 0x51, 0x59, 0x5C, 0xD6, 0xA2, 0x9C, + 0x0C, 0xB1, 0x97, 0xE6, 0x8E, 0x5B, 0xC8, 0x01, 0x24, 0x4E, + 0xDB, 0x77, 0x09, 0xDB, 0x8F, 0x8D, 0x34, 0x34, 0x49, 0x45, + 0x76, 0x24, 0x52, 0xBE, 0x00, 0xB6, 0x31, 0x14, 0x1E, 0x8D, + 0x9E, 0x6D, 0xBE, 0x47, 0xA0, 0x59, 0x45, 0x90, 0xDE, 0xBB, + 0x9C, 0xF5, 0x2E, 0x04, 0xEC, 0xBA, 0x60, 0x51, 0x89, 0x12, + 0xF6, 0x9B, 0xB3, 0x82, 0x5E, 0x79, 0xBC, 0xC0, 0x2B, 0xD9, + 0x3C, 0xEC, 0x59, 0x9A, 0x91, 0xAE, 0x77, 0x8C, 0x41, 0xF5, + 0x47, 0x15, 0x79, 0xCD, 0xB0, 0xEB, 0xFC, 0xCB, 0x3E, 0x77, + 0x2F, 0xB6, 0x07, 0xD6, 0xA4, 0xF7, 0xDF, 0x04, 0xF1, 0xE5, + 0xD2, 0xE2, 0x63, 0xB5, 0xD6, 0xF8, 0xCA, 0xC3, 0x64, 0x05, + 0x63, 0xC5, 0x41, 0x63, 0xFA, 0x3E, 0xFE, 0x80, 0x4C, 0x97, + 0xCF, 0x9C, 0x9F, 0x40, 0x11, 0x9D, 0xD6, 0xF5, 0x67, 0xAE, + 0x36, 0xE0, 0xB8, 0x6B, 0xE7, 0x22, 0x10, 0x1A, 0x60, 0xD3, + 0x6F, 0x82, 0xF3, 0xCD, 0xD2, 0x9A, 0x8A, 0x87, 0x1E, 0x1F, + 0x8E, 0xBB, 0xF9, 0x64, 0x3A, 0x65, 0x5F, 0x55, 0x59, 0x59, + 0x26, 0x43, 0xDA, 0x4C, 0x0F, 0x05, 0xDA, 0x2C, 0x88, 0x10, + 0x75, 0x8E, 0x8E, 0xA8, 0x4E, 0x4B, 0x6B, 0x8C, 0x47, 0x28, + 0x4A, 0xAC, 0x4C, 0xA8, 0xC2, 0xA9, 0xF5, 0x5C, 0xAA, 0x32, + 0xE4, 0x64, 0xA6, 0xE5, 0x35, 0x1D, 0xD0, 0x97, 0x03, 0xFD, + 0x54, 0x81, 0x9E, 0x2A, 0x80, 0x3D, 0x8F, 0xC0, 0xCC, 0x61, + 0xAC, 0x77, 0x15, 0x25, 0x31, 0xD8, 0xB1, 0x96, 0x1F, 0xA4, + 0x8C, 0x81, 0x89, 0x24, 0xFA, 0x68, 0x4D, 0x87, 0x68, 0xB0, + 0x7B, 0x7F, 0x01, 0xB4, 0xE9, 0x4F, 0x7F, 0xBB, 0x56, 0x7E, + 0x53, 0xD0, 0x73, 0x45, 0x12, 0x88, 0x4B, 0x38, 0x79, 0x47, + 0x82, 0xE8, 0x98, 0xDF, 0xFD, 0x1E, 0x62, 0x0F, 0x79, 0x2D, + 0xD3, 0xBD, 0xD0, 0xC3, 0xC7, 0xD5, 0x68, 0x3E, 0x93, 0xD3, + 0xD3, 0x1E, 0x5B, 0x64, 0x95, 0x2A, 0xDB, 0x34, 0x55, 0xA8, + 0x9C, 0x77, 0xD4, 0x48, 0x57, 0xD5, 0xF9, 0xE5, 0x07, 0x22, + 0xF1, 0xBE, 0x49, 0x39, 0xB9, 0xD3, 0x6C, 0x7B, 0xD4, 0x9D, + 0x59, 0x9F, 0xFD, 0x22, 0x71, 0x23, 0x98, 0xC4, 0x89, 0x10, + 0xB1, 0x65, 0x3C, 0xAD, 0x8D, 0xB9, 0x72, 0x0F, 0x3A, 0xA4, + 0xF1, 0xAA, 0x9F, 0x1A, 0xE7, 0x48, 0x79, 0xAD, 0x10, 0x09, + 0x5A, 0xCD, 0xCF, 0x6F, 0x4E, 0xF2, 0x3B, 0xFF, 0xC3, 0x79, + 0x0A, 0x35, 0xF4, 0x11, 0x2E, 0xB1, 0xFE, 0xA5, 0x0A, 0x91, + 0xD9, 0xFB, 0x7E, 0xD5, 0x51, 0xE8, 0xB2, 0xF6, 0xE0, 0xE1, + 0x4A, 0xB2, 0x60, 0xEA, 0x03, 0x11, 0xB1, 0x08, 0x3F, 0x55, + 0x3F, 0xF1, 0xB8, 0xDE, 0xB1, 0x76, 0xE6, 0x89, 0xB9, 0xAA, + 0xEE, 0x93, 0x68, 0x02, 0x6A, 0x0F, 0xC1, 0xED, 0x4D, 0x59, + 0x70, 0x32, 0x6C, 0x5C, 0xF7, 0x04, 0x03, 0x76, 0x11, 0x86, + 0xAD, 0x47, 0x0C, 0xDD, 0x36, 0x5E, 0xDD, 0x76, 0xFD, 0x45, + 0x5D, 0xB9, 0xF3, 0x77, 0xC8, 0xC2, 0x74, 0xD6, 0xF7, 0xC2, + 0xD4, 0xE5, 0x96, 0xAC, 0x83, 0x54, 0x3B, 0x73, 0xFA, 0x98, + 0x4C, 0xC5, 0x94, 0x95, 0x84, 0x13, 0x66, 0x00, 0xC3, 0x18, + 0xFB, 0xDD, 0xE0, 0xCB, 0x43, 0x8C, 0xFB, 0x0D, 0x66, 0xF4, + 0x64, 0xEB, 0x0F, 0xBB, 0x0C, 0x89, 0xB5, 0x76, 0x0F, 0xF5, + 0xDF, 0x0C, 0xBA, 0x36, 0x6D, 0xFE, 0x48, 0x71, 0xBC, 0x8C, + 0x9B, 0x0A, 0x32, 0x27, 0xE1, 0xE9, 0x51, 0xA5, 0xD6, 0xB4, + 0x35, 0x3C, 0x9E, 0x55, 0x1B, 0x22, 0xF4, 0xC9, 0x17, 0xFD, + 0xD4, 0xC0, 0x21, 0x15, 0xE9, 0xC3, 0x14, 0x8A, 0x60, 0x21, + 0xDD, 0x3B, 0x56, 0x67, 0x21, 0xE9, 0x9D, 0xEE, 0xE5, 0xAD, + 0xA0, 0xB4, 0x82, 0x0C, 0x64, 0x9D, 0x71, 0x25, 0xCC, 0x3F, + 0x27, 0xDE, 0xE7, 0x75, 0x60, 0xBE, 0xE9, 0xA8, 0x22, 0x2B, + 0xCB, 0x0B, 0xCE, 0xE4, 0x42, 0x57, 0x7B, 0xCD, 0xA2, 0x71, + 0x74, 0xE6, 0xB3, 0x2F, 0xCA, 0xC8, 0xED, 0x1F, 0x24, 0x85, + 0x5A, 0xCF, 0x32, 0x26, 0x20, 0x54, 0xD6, 0x63, 0xFF, 0x1A, + 0xD4, 0xF5, 0x14, 0x9E, 0x14, 0x1B, 0xA7, 0x64, 0x9F, 0x40, + 0x02, 0xC5, 0xE2, 0x95, 0x4E, 0xC7, 0x48, 0xC1, 0x20, 0x4B, + 0x30, 0x03, 0x7A, 0x4A, 0x82, 0x9A, 0x4C, 0xF0, 0xAB, 0x6B, + 0x46, 0xDD, 0xFB, 0x89, 0x73, 0x4D, 0xC0, 0x9D, 0xF8, 0xF2, + 0x05, 0x99, 0x3B, 0xE1, 0xB0, 0xE5, 0x2D, 0xFC, 0x78, 0x07, + 0xB2, 0x87, 0x61, 0x66, 0x2D, 0xE9, 0xE0, 0xEE, 0x1E, 0x9F, + 0x3C, 0x72, 0x69, 0x9E, 0x56, 0xB9, 0x70, 0x04, 0x7F, 0xBC, + 0xF6, 0x09, 0x2A, 0x91, 0x4A, 0x69, 0xA6, 0x11, 0x7A, 0xA1, + 0x43, 0x67, 0x4D, 0x73, 0x6E, 0xEF, 0xB5, 0x37, 0x1B, 0x83, + 0x04, 0x57, 0xA6, 0x6E, 0x77, 0xA0, 0x85, 0xEA, 0xB9, 0x2E, + 0xF9, 0x78, 0x41, 0x2C, 0xD5, 0xD4, 0x08, 0x21, 0xF1, 0xB4, + 0xD8, 0x04, 0x11, 0x92, 0x7A, 0xF9, 0xA0, 0x4A, 0x16, 0x79, + 0x0A, 0x62, 0x42, 0x3C, 0xFA, 0x4B, 0xDC, 0xB8, 0x4C, 0x94, + 0x8A, 0xB1, 0x3D, 0x9D, 0x92, 0x80, 0x64, 0x33, 0x70, 0x03, + 0xDE, 0x2C, 0xF6, 0xAA, 0x71, 0xAA, 0x6A, 0x65, 0x2E, 0x2A, + 0xCF, 0x5B, 0xDC, 0xD6, 0xAC, 0x1A, 0xB1, 0x1A, 0x41, 0xC2, + 0x05, 0x6C, 0x3B, 0x49, 0x88, 0xF9, 0x4F, 0x4B, 0xBE, 0x7C, + 0x7A, 0x48, 0x59, 0x3B, 0x88, 0xA4, 0x45, 0x20, 0x89, 0xC5, + 0xBA, 0x73, 0xCD, 0xCE, 0xED, 0x3F, 0xCE, 0xF3, 0x90, 0x97, + 0x78, 0x3A, 0x57, 0x58, 0x36, 0x2C, 0xD1, 0x43, 0x25, 0x0E, + 0xF3, 0x19, 0xB4, 0x23, 0x45, 0x8A, 0xD8, 0x84, 0x6C, 0x85, + 0x8A, 0xA9, 0x28, 0x1C, 0xE1, 0xD1, 0x2D, 0x68, 0xAF, 0x29, + 0xB2, 0x6E, 0x62, 0xF4, 0x41, 0xF4, 0x5F, 0xD5, 0xC9, 0xD5, + 0x5F, 0x92, 0x91, 0xB4, 0xE1, 0x28, 0x63, 0xC3, 0x68, 0x69, + 0xD8, 0x9B, 0x2A, 0x1D, 0xD5, 0x1D, 0x4D, 0x76, 0x7B, 0x71, + 0x10, 0x51, 0x08, 0x78, 0x92, 0xC2, 0x2C, 0x60, 0x8F, 0xE8, + 0x3C, 0xF9, 0x7D, 0x5A, 0xB0, 0xB5, 0x2E, 0x12, 0xF7, 0x9B, + 0xFD, 0x6E, 0xBC, 0x88, 0x81, 0x94, 0x91, 0x2A, 0x46, 0xD4, + 0x7A, 0xBC, 0xBC, 0x81, 0xCB, 0x51, 0x99, 0xF3, 0x9B, 0xBA, + 0xD0, 0xA2, 0x3D, 0x20, 0x3B, 0x15, 0xDF, 0x91, 0x33, 0x67, + 0x0E, 0x47, 0x6B, 0xAD, 0x2C, 0x2D, 0x63, 0x3B, 0xB8, 0x48, + 0x31, 0xE4, 0xEF, 0x92, 0xA3, 0x91, 0xEA, 0x91, 0x75, 0xF7, + 0x92, 0xF2, 0xBD, 0x92, 0x52, 0xE4, 0xFB, 0x85, 0x0A, 0xA5, + 0xAD, 0x38, 0x0C, 0x84, 0x79, 0x72, 0x72, 0x86, 0xE6, 0x04, + 0x07, 0x73, 0x0E, 0xF6, 0x8A, 0x32, 0x46, 0x1A, 0x1A, 0xA5, + 0xD6, 0x90, 0x53, 0x1F, 0xD2, 0xFF, 0x34, 0xD2, 0xE2, 0xF8, + 0xAE, 0x47, 0x99, 0x9E, 0x4E, 0xE4, 0x68, 0x44, 0x63, 0xEE, + 0xB8, 0x6E, 0xCF, 0x3E, 0x45, 0x65, 0x5E, 0x6B, 0x11, 0x3D, + 0xFC, 0xCF, 0x41, 0x24, 0x1E, 0x40, 0xD5, 0xB2, 0xA6, 0x84, + 0x2C, 0x16, 0x48, 0xDE, 0xFE, 0xD6, 0xE8, 0x61, 0x28, 0x86, + 0x3E, 0xB1, 0xBF, 0xE1, 0x45, 0x0E, 0x71, 0xF6, 0x0D, 0xF5, + 0x6F, 0xA6, 0x14, 0x94, 0xD8, 0x13, 0x79, 0xF1, 0x7A, 0x83, + 0xB9, 0x6D, 0x56, 0x5B, 0xE5, 0xE6, 0x9F, 0xA6, 0xEC, 0x84, + 0x7D, 0x9C, 0xB2, 0x86, 0xF6, 0xFE, 0xFB, 0x7A, 0x64, 0x68, + 0xA9, 0x9B, 0xF6, 0x08, 0x3B, 0x6A, 0x07, 0xCE, 0x34, 0xB1, + 0xF4, 0xCE, 0xC0, 0xFC, 0xAF, 0x31, 0xA8, 0xC6, 0x74, 0x76, + 0x61, 0xCE, 0x02, 0x91, 0xC3, 0x67, 0x2C, 0x3E, 0x75, 0x84, + 0xA1, 0x5E, 0x90, 0xD3, 0x1D, 0xB3, 0x60, 0xF2, 0x10, 0x47, + 0x90, 0x77, 0x8E, 0x82, 0x9C, 0x96, 0xA9, 0x9E, 0x7B, 0x29, + 0x4E, 0xD8, 0xD7, 0x11, 0x7B, 0x8C, 0x45, 0xDE, 0x27, 0x5C, + 0x1D, 0xC9, 0xDA, 0x47, 0x55, 0x8C, 0x41, 0x0D, 0x09, 0x70, + 0x1E, 0x23, 0x38, 0x39, 0xDC, 0xF5, 0xC4, 0xAD, 0x6A, 0xAF, + 0xD2, 0x3F, 0xA7, 0x3D, 0x08, 0x24, 0x45, 0xBC, 0xBB, 0xDD, + 0xB6, 0xDC, 0x24, 0xF9, 0xC8, 0x0A, 0x86, 0xB5, 0xB8, 0x8A, + 0x5D, 0x5C, 0x12, 0x2B, 0x76, 0x5C, 0x41, 0x43, 0x23, 0xE4, + 0xE5, 0x1A, 0xDE, 0xC3, 0x27, 0x08, 0xFB, 0x22, 0xFE, 0x1D, + 0x3D, 0xD1, 0xB0, 0xFC, 0x8D, 0xE3, 0x25, 0xA0, 0x4E, 0xA0, + 0x5D, 0xE9, 0x17, 0xDE, 0x6D, 0x55, 0x7E, 0x60, 0xF0, 0x69, + 0x99, 0xCE, 0x7C, 0xCE, 0xC7, 0x76, 0xAE, 0x08, 0x00, 0x44, + 0x4B, 0xF2, 0x0A, 0xCB, 0x1B, 0x52, 0xF4, 0x52, 0xEB, 0xD3, + 0x99, 0x8A, 0xDA, 0x1F, 0x56, 0xE4, 0x8B, 0xBA, 0x2D, 0x61, + 0x0B, 0x17, 0xE5, 0xCF, 0x3C, 0x12, 0x5A, 0x3E, 0xAA, 0xAC, + 0xAD, 0x39, 0xC8, 0x56, 0xC7, 0x4B, 0x71, 0x33, 0x90, 0x95, + 0x5A, 0x7E, 0x9D, 0xDA, 0x0D, 0x9D, 0x0F, 0x76, 0x54, 0xAA, + 0x87, 0xD6, 0x90, 0x5D, 0xF1, 0xC0, 0x23, 0x67, 0x41, 0x70, + 0x03, 0x0B, 0xEF, 0x78, 0x48, 0x66, 0x86, 0x3D, 0xEB, 0x8B, + 0x7E, 0xA6, 0x07, 0xBA, 0xBB, 0x88, 0xCF, 0x1F, 0x88, 0xAE, + 0x9A, 0xE1, 0x2B, 0xD2, 0x25, 0x66, 0xB0, 0x05, 0xB1, 0x27, + 0x82, 0x30, 0xF3, 0xAE, 0x37, 0x66, 0xE4, 0xA6, 0xC8, 0xA3, + 0x6B, 0x02, 0x4C, 0x54, 0xA7, 0xEC, 0x9E, 0x61, 0x25, 0xAF, + 0x86, 0x83, 0x9A, 0xAF, 0x7E, 0xB9, 0x85, 0x7F, 0xBB, 0xEE, + 0x6E, 0x3F, 0x52, 0xCD, 0x8E, 0xB6, 0xFA, 0xB2, 0x61, 0x7D, + 0xF5, 0x82, 0x02, 0x80, 0x4A, 0xE3, 0xFC, 0x39, 0xBB, 0x35, + 0x77, 0xFE, 0xD9, 0x49, 0xBC, 0x05, 0x15, 0xA2, 0xAF, 0x37, + 0x9F, 0xEC, 0x0F, 0xB8, 0xB8, 0x7E, 0xDD, 0x71, 0xF1, 0xA0, + 0xE1, 0x57, 0x74, 0xFB, 0xDE, 0xEC, 0x32, 0x80, 0xFD, 0x1E, + 0xDF, 0x2F, 0xB6, 0x47, 0xA0, 0x87, 0xFF, 0xA4, 0xC7, 0xD8, + 0x34, 0x13, 0x6B, 0x78, 0x1C, 0x9C, 0x64, 0x41, 0x3E, 0x67, + 0x02, 0x55, 0xDA, 0x7A, 0x04, 0x36, 0x14, 0x06, 0x47, 0x22, + 0x17, 0x70, 0xF7, 0x77, 0x55, 0x42, 0xDB, 0x54, 0x43, 0x19, + 0x82, 0x49, 0x2F, 0x36, 0x30, 0x16, 0x48, 0x0C, 0x7C, 0x60, + 0xC9, 0xFE, 0xB5, 0x99, 0x62, 0x51, 0xA4, 0xC9, 0x22, 0xF1, + 0x2A, 0x05, 0x46, 0x0E, 0xDC, 0xC4, 0x51, 0xAB, 0x4C, 0x9A, + 0x09, 0x5A, 0x1B, 0xF8, 0xEF, 0x29, 0x5D, 0xD5, 0x3C, 0xB7, + 0x73, 0xC6, 0x43, 0xD7, 0x92, 0xC0, 0xA2, 0x42, 0x7B, 0x19, + 0x2D, 0x2C, 0x53, 0xAE, 0x8A, 0x3F, 0xDB, 0x9E, 0xAD, 0xE1, + 0x35, 0xD2, 0xC2, 0x82, 0x9B, 0x2F, 0xC9, 0xA8, 0x2C, 0x15, + 0x80, 0x1C, 0x8D, 0x2B, 0x15, 0x1D, 0xC8, 0x9B, 0x11, 0xD4, + 0xED, 0xFA, 0x82, 0x15, 0xC6, 0xF2, 0xD2, 0xC5, 0x2E, 0xB2, + 0x24, 0xF7, 0x6A, 0x47, 0x02, 0x68, 0xB5, 0xC3, 0x0F, 0x4A, + 0x09, 0x80, 0xC6, 0x0C, 0xD1, 0x20, 0xA0, 0x43, 0xE5, 0x59, + 0xA6, 0xA6, 0xA2, 0x62, 0x00, 0xCC, 0x50, 0xF7, 0xEF, 0x81, + 0x1F, 0xF9, 0xF9, 0x81, 0xAB, 0xC1, 0x3E, 0x61, 0x3D, 0x2C, + 0xCF, 0x51, 0x61, 0xFD, 0xB8, 0xE8, 0xF0, 0xBE, 0xB6, 0xFC, + 0xFF, 0xDC, 0xD3, 0x29, 0xD7, 0x47, 0x29, 0x90, 0x95, 0xCE, + 0xC5, 0xD7, 0xB8, 0x9F, 0xEF, 0xDA, 0x78, 0x81, 0xA7, 0xE2, + 0x4C, 0xE4, 0xF1, 0x8F, 0xC3, 0x87, 0x8D, 0x80, 0x7E, 0xBD, + 0xD6, 0xF3, 0x22, 0x85, 0x37, 0x35, 0x9A, 0xCE, 0x46, 0x0E, + 0xD6, 0xFB, 0xCE, 0xA4, 0xB5, 0xA7, 0x51, 0x0A, 0xE2, 0x22, + 0x3A, 0x38, 0x55, 0xF4, 0xD9, 0x13, 0x6F, 0x09, 0x86, 0x26, + 0x2F, 0x1B, 0x44, 0xE5, 0x29, 0x03, 0x25, 0x42, 0x63, 0x0E, + 0x0E, 0xB1, 0x72, 0xB7, 0x98, 0xAD, 0xB4, 0xE3, 0xEE, 0xE0, + 0xE3, 0xF9, 0xD4, 0xC1, 0x20, 0xB0, 0xFF, 0xBA, 0x14, 0x9B, + 0xB1, 0x39, 0x1D, 0x88, 0xAE, 0x1D, 0xA8, 0xFB, 0xD7, 0xD3, + 0x7D, 0x27, 0x06, 0x64, 0xCD, 0x2C, 0x0C, 0xC1, 0x56, 0x16, + 0xBC, 0x7A, 0xA5, 0xEF, 0x76, 0xA4, 0xAF, 0x9B, 0x0E, 0x53, + 0xD2, 0xA2, 0x70, 0xC0, 0x27, 0x5A, 0xE7, 0xAB, 0xEB, 0x3E, + 0xEF, 0xB3, 0xBC, 0x3D, 0x50, 0x86, 0xF3, 0x8B, 0x9D, 0x13, + 0x33, 0x67, 0x97, 0x06, 0xC6, 0x7A, 0xF1, 0x2B, 0x4F, 0x99, + 0x4A, 0x45, 0x17, 0xDC, 0x99, 0xDA, 0xCE, 0x42, 0x4F, 0xFE, + 0x46, 0x3D, 0x17, 0x3D, 0xA8, 0xE9, 0x93, 0x1C, 0xCD, 0x03, + 0xFD, 0x9A, 0x92, 0x42, 0xB5, 0xC5, 0xFD, 0x9E, 0xF4, 0x80, + 0xD8, 0x77, 0xC9, 0xC6, 0x66, 0x43, 0x58, 0xFE, 0xA9, 0xA5, + 0x91, 0x28, 0x17, 0x52, 0xBF, 0x6B, 0xFB, 0x65, 0x14, 0x81, + 0x2B, 0xE4, 0xAF, 0xAC, 0x7E, 0xEE, 0x5A, 0x5F, 0xC4, 0xE4, + 0x53, 0x83, 0x64, 0x3D, 0xB1, 0xDE, 0xF3, 0xCB, 0xCD, 0xC9, + 0xBB, 0xFA, 0xBA, 0xE3, 0xA6, 0xAD, 0x77, 0x4F, 0xE7, 0x79, + 0x63, 0xCF, 0x67, 0x40, 0x9F, 0x87, 0x47, 0x04, 0xFA, 0xC4, + 0xB8, 0x89, 0xCE, 0xAD, 0x20, 0x1A, 0x63, 0x4B, 0x4B, 0x15, + 0xA6, 0xA7, 0xBF, 0xD7, 0xAB, 0x81, 0x55, 0xC1, 0xAC, 0x03, + 0xA4, 0xE0, 0x00, 0x63, 0xC4, 0xBF, 0x7E, 0x2E, 0x31, 0x39, + 0x9A, 0xD1, 0x72, 0xDF, 0xC4, 0x61, 0x9F, 0xFD, 0xB2, 0x22, + 0xE3, 0x1D, 0x96, 0x6F, 0x60, 0x7B, 0x8A, 0x3D, 0x76, 0x03, + 0x19, 0x5E, 0x14, 0xBF, 0x2F, 0x7E, 0x52, 0xBB, 0x5B, 0xE0, + 0x56, 0xD2, 0xD7, 0xFD, 0xE6, 0x89, 0x76, 0x02, 0x76, 0x73, + 0x7B, 0x23, 0xD3, 0x0E, 0xC3, 0x83, 0x84, 0x8F, 0x57, 0x54, + 0x89, 0xFC, 0x6F, 0x86, 0x5E, 0x44, 0x64, 0xBD, 0x7F, 0x13, + 0x69, 0x3D, 0x00, 0x75, 0xC6, 0xD7, 0x66, 0xFB, 0x76, 0x64, + 0x7B, 0xBC, 0x2B, 0x5C, 0x55, 0x4B, 0xE5, 0x8F, 0x8B, 0x50, + 0xE2, 0x16, 0x5D, 0xAC, 0x2C, 0x4C, 0x0E, 0x63, 0xE5, 0xC3, + 0xF1, 0xA6, 0x58, 0xFE, 0xE2, 0x2C, 0xE6, 0x4E, 0xE4, 0x11, + 0xB7, 0x3A, 0x34, 0x82, 0xA6, 0xC7, 0x14, 0xC8, 0xD3, 0x10, + 0x66, 0x64, 0xBF, 0x20, 0x30, 0x5E, 0x9C, 0x72, 0xED, 0x35, + 0xD7, 0xC9, 0xED, 0x4C, 0xD6, 0x01, 0xCD, 0x3A, 0x0F, 0xA8, + 0x2C, 0x30, 0x74, 0xC3, 0x82, 0xED, 0x46, 0xCD, 0xEC, 0x1B, + 0x22, 0x00, 0x1C, 0xB0, 0xE8, 0x02, 0xB6, 0x65, 0x4E, 0x6E, + 0x1F, 0x71, 0xBD, 0xCF, 0xCD, 0xBC, 0x7D, 0x13, 0x87, 0x73, + 0x35, 0x24, 0x95, 0xA1, 0x98, 0xF6, 0xA8, 0xBD, 0xEF, 0xF2, + 0x22, 0xA2, 0x74, 0xA4, 0x67, 0xED, 0xAB, 0xA4, 0xD6, 0x91, + 0xF7, 0x6C, 0x79, 0xE0, 0xC6, 0x24, 0xAE, 0xB4, 0x44, 0xEF, + 0x66, 0x30, 0xA6, 0x20, 0x07, 0x0F, 0x9D, 0x40, 0xF2, 0x7A, + 0xA0, 0x0E, 0xF8, 0x77, 0x6D, 0xF8, 0xDD, 0x9C, 0xDB, 0xA9, + 0xAA, 0x55, 0x3F, 0x63, 0x5D, 0x7B, 0x79, 0x53, 0xBF, 0xE0, + 0x24, 0x52, 0xA1, 0xA2, 0xFB, 0x0B, 0xC5, 0x97, 0xE6, 0xF3, + 0x89, 0x6F, 0x93, 0xF3, 0x89, 0xDD, 0x1B, 0xB5, 0x56, 0x12, + 0x48, 0x78, 0x5D, 0xA9, 0x47, 0x73, 0x6F, 0xE3, 0x58, 0x39, + 0xAB, 0x9C, 0x60, 0x0F, 0x48, 0x2F, 0x3F, 0x97, 0xEA, 0xB4, + 0x72, 0x5D, 0xAA, 0x49, 0xF1, 0xFA, 0xEB, 0x63, 0x46, 0x0A, + 0x24, 0x7B, 0x83, 0x56, 0x96, 0xA7, 0x19, 0x4D, 0x29, 0x8D, + 0xDC, 0x30, 0x77, 0xF7, 0xDD, 0x05, 0xB9, 0x9F, 0x06, 0xF0, + 0x0F, 0xEB, 0x71, 0x83, 0x9A, 0x53, 0xF4, 0xF9, 0xC8, 0x67, + 0xC5, 0xE2, 0x95, 0xE2, 0x5A, 0x1F, 0xFF, 0x07, 0x1E, 0x4C, + 0xB1, 0x54, 0x27, 0x78, 0x66, 0xE8, 0x91, 0x58, 0x1D, 0xB9, + 0xD7, 0x5D, 0x4B, 0x60, 0xC5, 0xC8, 0xC7, 0x69, 0xD9, 0x74, + 0x7C, 0x33, 0xA2, 0x0F, 0x29, 0x98, 0xC7, 0x5A, 0x24, 0xA5, + 0x90, 0xA1, 0x9A, 0xB8, 0xEA, 0xA1, 0x00, 0xE1, 0xB2, 0x14, + 0x60, 0xFA, 0xEB, 0xB3, 0x00, 0xA6, 0x13, 0x1C, 0xA7, 0xF4, + 0x8B, 0x87, 0x15, 0xA5, 0xC6, 0xEF, 0x35, 0x5E, 0xD4, 0xE2, + 0x8D, 0x6D, 0x5E, 0xA2, 0xD0, 0xB0, 0x3A, 0x06, 0x06, 0x83, + 0xAA, 0x67, 0x39, 0x0F, 0xD5, 0x3B, 0xDD, 0xB8, 0x11, 0xE4, + 0x9D, 0x6D, 0x30, 0x29, 0xC5, 0xE2, 0xBA, 0xF8, 0xE4, 0x57, + 0x8D, 0x01, 0xE6, 0xB6, 0x70, 0xA5, 0x69, 0x74, 0x45, 0x0A, + 0x2F, 0xAA, 0xC7, 0x80, 0x6C, 0x8F, 0x77, 0xEB, 0x92, 0x0B, + 0xA6, 0xB3, 0x58, 0x71, 0x9F, 0xC8, 0x5C, 0x26, 0x5D, 0x55, + 0x62, 0xE9, 0xC0, 0x69, 0xE9, 0x84, 0x1B, 0xDF, 0x19, 0x03, + 0x1E, 0x53, 0xEC, 0x38, 0x5A, 0x33, 0xCF, 0x2E, 0x57, 0x0A, + 0x4E, 0x87, 0x60, 0x72, 0x10, 0x7D, 0xFD, 0x7C, 0xF8, 0x40, + 0x29, 0x39, 0x06, 0xD4, 0xE7, 0xB3, 0x7B, 0x92, 0xC7, 0xA5, + 0x88, 0x61, 0x65, 0x99, 0x25, 0x5D, 0xA2, 0xAB, 0xD3, 0x1C, + 0xFF, 0xDD, 0x17, 0x43, 0x46, 0xE6, 0x6B, 0x93, 0x79, 0xE4, + 0x21, 0xC0, 0x92, 0x55, 0xA7, 0x96, 0x7C, 0x5F, 0xC3, 0x31, + 0x07, 0xC6, 0x8F, 0xEA, 0x3C, 0x88, 0xFD, 0xAB, 0xD7, 0x35, + 0x9D, 0xA4, 0x07, 0xFA, 0xBE, 0x20, 0x64, 0xA6, 0xCB, 0xDE, + 0x1B, 0xEF, 0xED, 0xCB, 0x9A, 0x7A, 0xBC, 0xC3, 0x82, 0x42, + 0xAA, 0x41, 0x05, 0x22, 0x79, 0xD9, 0x7D, 0xFF, 0x50, 0x90, + 0x16, 0x3F, 0xBF, 0xD3, 0x38, 0x4D, 0x10, 0x19, 0x91, 0x67, + 0xC6, 0x7F, 0x76, 0x16, 0x32, 0x19, 0x56, 0x7C, 0xC9, 0xC9, + 0xAE, 0x31, 0x2B, 0x12, 0x5F, 0xAC, 0x3B, 0x87, 0xEA, 0xBE, + 0x79, 0x0F, 0x3C, 0x24, 0x35, 0xED, 0xB6, 0x65, 0x56, 0x94, + 0x96, 0x16, 0x4C, 0xBA, 0xAE, 0x09, 0x84, 0x0D, 0x8E, 0x2D, + 0xB7, 0xAE, 0x86, 0x9D, 0x77, 0xD8, 0x23, 0x2F, 0x76, 0x55, + 0x3E, 0xD6, 0xF5, 0xAE, 0xCE, 0x41, 0x17, 0x68, 0x06, 0xD5, + 0x7F, 0x2F, 0x3D, 0xAA, 0x14, 0xA2, 0xDD, 0x37, 0x70, 0xF9, + 0xFD, 0xE2, 0x0C, 0xE6, 0x83, 0x75, 0x7A, 0x94, 0x5C, 0xEA, + 0x67, 0xE0, 0x72, 0xC5, 0xD2, 0x3D, 0x40, 0x2E, 0x74, 0xE2, + 0x39, 0x5D, 0xC3, 0x7E, 0x0F, 0xA6, 0xC2, 0x2F, 0x3A, 0xF4, + 0xC4, 0xCF, 0xA8, 0xE1, 0xAD, 0x34, 0xB6, 0xC8, 0xC8, 0xE2, + 0xF5, 0xC2, 0x66, 0xFF, 0x2F, 0x4F, 0x67, 0x08, 0xB1, 0x58, + 0xE9, 0xA9, 0x7C, 0xE6, 0x72, 0x6C, 0x6E, 0x3F, 0x5D, 0x89, + 0x62, 0x80, 0x4E, 0x1D, 0xF2, 0xF2, 0xF1, 0xBC, 0x83, 0x19, + 0x97, 0x31, 0x35, 0x41, 0xCF, 0xCB, 0x88, 0xEE, 0x51, 0x3A, + 0xE8, 0x91, 0x15, 0x6E, 0xEB, 0x5B, 0x06, 0x54, 0x25, 0xE1, + 0x37, 0x31, 0xF4, 0xD0, 0x3C, 0xF0, 0x62, 0xE9, 0xC3, 0x2B, + 0xC9, 0x54, 0xA4, 0xB4, 0x49, 0x35, 0x5A, 0x5D, 0x0B, 0xB8, + 0x9C, 0xEE, 0x41, 0x57, 0x5C, 0x5F, 0x64, 0xC3, 0x2C, 0x1E, + 0xC8, 0x46, 0x69, 0xE8, 0x61, 0x1E, 0x62, 0xD3, 0x20, 0x66, + 0x71, 0xDE, 0x24, 0x27, 0x81, 0x03, 0xB1, 0xFB, 0x28, 0x7B, + 0xEA, 0x8C, 0xDB, 0x39, 0x6A, 0xD6, 0x08, 0xCE, 0x21, 0xA1, + 0x57, 0x1B, 0x91, 0x58, 0x86, 0x66, 0x26, 0x76, 0x77, 0x56, + 0x87, 0x6C, 0x7D, 0xE0, 0x5C, 0xAE, 0xF0, 0xAC, 0xEE, 0x49, + 0xD8, 0x7F, 0xE1, 0xF2, 0xC5, 0x6B, 0x56, 0x25, 0x31, 0xEB, + 0x28, 0xA2, 0x90, 0x67, 0xAE, 0x46, 0xEE, 0x55, 0xFE, 0xE2, + 0x1B, 0x71, 0x19, 0x92, 0xCC, 0xD2, 0x7A, 0x75, 0x05, 0x47, + 0xF7, 0x3E, 0x72, 0x49, 0xB0, 0x70, 0x88, 0x72, 0x8F, 0x3F, + 0x63, 0xB3, 0xB1, 0x91, 0xCC, 0xD8, 0x18, 0x34, 0x8D, 0x34, + 0x48, 0x0A, 0x14, 0xAA, 0x6A, 0x28, 0x89, 0x1A, 0xED, 0x96, + 0x5B, 0x47, 0xC5, 0x16, 0xFD, 0x89, 0xEC, 0x41, 0xBC, 0x8B, + 0x89, 0xB8, 0x86, 0x06, 0x7C, 0x6A, 0x8B, 0xEE, 0xD4, 0xAA, + 0xF4, 0x46, 0x4A, 0x79, 0x8A, 0x94, 0x10, 0x8E, 0x30, 0x0A, + 0x8F, 0x34, 0xE3, 0x99, 0x54, 0x56, 0xDA, 0x77, 0xDF, 0x7D, + 0x4D, 0x3E, 0xEC, 0x2A, 0x6B, 0x4F, 0x82, 0xE4, 0x32, 0x52, + 0x1C, 0xE7, 0x7D, 0x63, 0x92, 0x45, 0xA6, 0x84, 0xCC, 0x08, + 0x95, 0x92, 0xED, 0x02, 0xAD, 0x44, 0xBD, 0xFA, 0x70, 0xED, + 0xFB, 0x20, 0xCF, 0x95, 0xB8, 0x99, 0x6A, 0xF6, 0x7A, 0xD4, + 0x1B, 0x2D, 0x64, 0x87, 0x39, 0xFF, 0x5E, 0x78, 0x43, 0x93, + 0x2F, 0xCD, 0x8F, 0x33, 0x88, 0xCC, 0xA2, 0x41, 0xF6, 0xF2, + 0x7D, 0xD3, 0x66, 0x77, 0x21, 0x75, 0xB5, 0xFA, 0x8F, 0x1C, + 0x7C, 0x6C, 0xD9, 0xF0, 0xEA, 0xCB, 0x1D, 0x3F, 0xBE, 0xE1, + 0xD9, 0xCD, 0xBF, 0xFD, 0x7B, 0x3F, 0x31, 0x0D, 0x50, 0x2A, + 0x04, 0x8C, 0xD4, 0xD2, 0x78, 0x9F, 0x81, 0xBD, 0x6E, 0x9C, + 0x00, 0xEB, 0x00, 0xBA, 0xC8, 0x24, 0x54, 0x44, 0xF0, 0xBF, + 0x6B, 0x22, 0x03, 0x2E, 0x50, 0xF6, 0xEE, 0x32, 0xEA, 0x3E, + 0x32, 0xDE, 0x3A, 0xFD, 0x45, 0x00, 0x97, 0x77, 0xDC, 0xAD, + 0x0B, 0x26, 0x60, 0xEC, 0xD7, 0xBB, 0x59, 0xFB, 0x7B, 0x62, + 0xD9, 0x2A, 0x57, 0xFD, 0xC9, 0xED, 0x6E, 0x7D, 0xAF, 0xBA, + 0x7D, 0xF3, 0x95, 0xF0, 0x14, 0xA0, 0x74, 0x14, 0x42, 0x27, + 0x41, 0xEB, 0xFA, 0xC4, 0xCE, 0xA6, 0xC4, 0xEC, 0x5A, 0x4B, + 0xBF, 0xB8, 0x0D, 0xA5, 0x6F, 0x3E, 0x76, 0x99, 0x07, 0x38, + 0xED, 0xFA, 0x3B, 0x88, 0x34, 0x8B, 0x65, 0x32, 0x37, 0x5E, + 0x62, 0x94, 0x59, 0x03, 0xFF, 0x83, 0xBE, 0xA1, 0x1F, 0x8C, + 0x0B, 0xF5, 0x92, 0xA9, 0x36, 0x4C, 0x10, 0x76, 0x11, 0x44, + 0xBD, 0x53, 0x94, 0xAA, 0x77, 0x89, 0xAD, 0x2F, 0x4F, 0x86, + 0x54, 0xDB, 0x96, 0xD8, 0xE3, 0xA7, 0x90, 0x59, 0x96, 0x4C, + 0x22, 0xB5, 0xA8, 0x73, 0x3E, 0x69, 0x00, 0x4B, 0x66, 0xC8, + 0x73, 0x6D, 0x7C, 0xC8, 0x6B, 0x32, 0x47, 0xEC, 0x1D, 0x42, + 0x42, 0xE5, 0x7B, 0xBB, 0x5F, 0x35, 0x79, 0xE5, 0xEC, 0xA2, + 0xC9, 0xC6, 0x7D, 0x49, 0xAB, 0x8F, 0x79, 0xAD, 0x09, 0xAB, + 0xF1, 0xEA, 0x4D, 0x65, 0x0E, 0x2E, 0x3D, 0x47, 0x4B, 0x42, + 0xAA, 0x8E, 0x94, 0x48, 0xC8, 0xEC, 0x1D, 0x25, 0x7D, 0xF4, + 0x0E, 0xAA, 0x71, 0x16, 0xE6, 0xEA, 0xE4, 0x64, 0xAA, 0xF8, + 0x5B, 0xD9, 0xA6, 0x35, 0x12, 0x0F, 0xC6, 0x57, 0x44, 0xFC, + 0x90, 0xAF, 0x65, 0x65, 0xFB, 0x33, 0x7F, 0xB7, 0xAE, 0x73, + 0x19, 0x7A, 0xB3, 0x11, 0x87, 0x26, 0xFA, 0xEE, 0x81, 0x9F, + 0x4C, 0x98, 0xBC, 0x01, 0x76, 0x1A, 0x54, 0x36, 0xC6, 0x0E, + 0x00, 0x0A, 0xFC, 0xDE, 0xD4, 0xAF, 0x24, 0x94, 0x42, 0x57, + 0xA5, 0xB4, 0xAF, 0x05, 0x75, 0xA2, 0x55, 0xF7, 0x12, 0xBD, + 0xE1, 0x41, 0xD9, 0x96, 0x11, 0xE0, 0x27, 0x11, 0x79, 0x11, + 0x4E, 0xA8, 0xEC, 0xD9, 0x2E, 0xCB, 0xA6, 0xAE, 0x6F, 0xD2, + 0x59, 0x9E, 0xED, 0x2F, 0x8F, 0xB0, 0xB0, 0xC5, 0x0B, 0xA3, + 0x09, 0xEF, 0xB9, 0x27, 0xAD, 0xED, 0xF8, 0xC3, 0x2A, 0x47, + 0x0D, 0x8A, 0xD1, 0xF7, 0x8C, 0xD2, 0x6A, 0x65, 0x47, 0x35, + 0x98, 0xE8, 0x4A, 0x09, 0x4C, 0x7A, 0x90, 0x9D, 0x70, 0x1F, + 0x96, 0x39, 0x64, 0x02, 0x83, 0x9D, 0xE4, 0xFA, 0x5C, 0x33, + 0xC2, 0xA0, 0x68, 0x33, 0xB6, 0xFB, 0x7E, 0x4F, 0xF7, 0xD6, + 0x1E, 0x0B, 0x38, 0xF9, 0x85, 0x7F, 0xF6, 0x69, 0x9C, 0x5B, + 0x71, 0xF3, 0x01, 0xC9, 0x4D, 0x70, 0xFB, 0x15, 0x58, 0x1B, + 0x7C, 0x06, 0xB8, 0xD9, 0x21, 0xF5, 0xE1, 0x11, 0x4A, 0xA3, + 0x75, 0x4D, 0xD1, 0x00, 0xD9, 0x82, 0x71, 0x3E, 0x81, 0xDE, + 0x4B, 0xB6, 0x04, 0x0A, 0x5E, 0x47, 0x45, 0x1A, 0xE3, 0xCD, + 0xEC, 0x5A, 0x7D, 0x14, 0x57, 0xC3, 0x44, 0xF2, 0xA2, 0x4F, + 0xF7, 0xD1, 0x2D, 0x4A, 0x65, 0xC6, 0x0E, 0x83, 0xD5, 0x0A, + 0x79, 0x75, 0xB8, 0xBA, 0x34, 0xF1, 0x65, 0xFB, 0x4A, 0x30, + 0x55, 0x0C, 0x41, 0xAA, 0x8B, 0x87, 0xBB, 0x6E, 0x10, 0xAD, + 0x91, 0x9A, 0xFE, 0xB6, 0x58, 0xD0, 0x3A, 0x4F, 0xE9, 0x62, + 0x25, 0x83, 0xEB, 0x30, 0x6B, 0x52, 0x6D, 0x2E, 0x14, 0x54, + 0x75, 0x0F, 0x45, 0x80, 0xA5, 0x2D, 0x90, 0x17, 0x1D, 0x59, + 0x56, 0x3A, 0xE5, 0xE8, 0x63, 0xAB, 0xB4, 0x8D, 0xAA, 0x68, + 0x63, 0xC6, 0xA0, 0xAF, 0x66, 0xAB, 0x03, 0xF3, 0xF6, 0xF2, + 0xAF, 0x9B, 0x03, 0x2E, 0x70, 0x13, 0x0B, 0xF4, 0x9F, 0x05, + 0x54, 0x04, 0x56, 0x89, 0xE0, 0xA7, 0x09, 0x78, 0xEB, 0x47, + 0x76, 0x82, 0xA4, 0xAF, 0x67, 0xE1, 0xA9, 0xEB, 0x5E, 0x07, + 0x2F, 0x7B, 0xA1, 0x86, 0x34, 0x51, 0x29, 0xFA, 0x0E, 0x29, + 0xD6, 0xC3, 0xEB, 0x96, 0xD4, 0x72, 0x9B, 0xE6, 0x0E, 0x06, + 0x7B, 0x7F, 0xC3, 0x7D, 0x5A, 0xB8, 0xB7, 0x0E, 0x44, 0xB8, + 0xB6, 0x38, 0x1C, 0xB4, 0xF1, 0xCF, 0x38, 0xF5, 0x00, 0x3F, + 0x66, 0x1C, 0x07, 0x75, 0x6E, 0x9D, 0x73, 0x3E, 0xB1, 0x50, + 0x2B, 0xEA, 0x58, 0x02, 0xC8, 0x38, 0x3A, 0xDD, 0x8B, 0xA3, + 0x0A, 0x1B, 0x2A, 0xB1, 0x89, 0xDE, 0x16, 0x43, 0x54, 0x15, + 0x81, 0xDB, 0xCB, 0xE5, 0x82, 0x25, 0xFD, 0x9C, 0x70, 0x0E, + 0xA2, 0x6C, 0x81, 0xCD, 0x8F, 0x38, 0x20, 0x85, 0xDF, 0xBE, + 0x90, 0x00, 0xC9, 0x1B, 0x3D, 0xEF, 0x7E, 0x94, 0x95, 0x3B, + 0x8A, 0x93, 0x34, 0x67, 0x47, 0x03, 0x91, 0x11, 0x43, 0x9A, + 0x09, 0xDC, 0xA4, 0x68, 0x02, 0xB1, 0x50, 0x1D, 0xFF, 0xA0, + 0x67, 0xE6, 0x0F, 0x50, 0x57, 0x3D, 0x59, 0x26, 0x99, 0x2F, + 0xDA, 0x71, 0x28, 0xCD, 0x9E, 0x60, 0x38, 0x8E, 0xCC, 0xFB, + 0x64, 0x93, 0xDA, 0xFD, 0x20, 0x60, 0x1B, 0xB9, 0x63, 0x8D, + 0x36, 0x62, 0x80, 0xBB, 0xDC, 0x20, 0x6D, 0x08, 0xAA, 0xEE, + 0x43, 0xEE, 0x4A, 0x48, 0x7A, 0xEF, 0xEE, 0xC6, 0xE1, 0xDD, + 0x76, 0x3F, 0xD1, 0x3B, 0x6E, 0xC5, 0xB8, 0xB4, 0x9A, 0xE1, + 0xDA, 0x09, 0x18, 0xFF, 0x5D, 0xC4, 0x1B, 0xE8, 0x27, 0x64, + 0x6D, 0xFF, 0x2C, 0x38, 0x12, 0xDB, 0xAC, 0x04, 0x0E, 0x00, + 0xBE, 0x23, 0xF4, 0xA0, 0x1F, 0x42, 0xFE, 0x55, 0x5D, 0x1D, + 0x14, 0x7B, 0x0B, 0x72, 0x24, 0x76, 0xBC, 0xA4, 0xA9, 0x6E, + 0x1D, 0xB7, 0xFF, 0x15, 0xFF, 0x73, 0x88, 0xE1, 0xFE, 0x74, + 0x1C, 0x9D, 0x0B, 0x52, 0x2A, 0xBF, 0x5F, 0x15, 0x92, 0x8C, + 0x92, 0xF9, 0xD5, 0x2A, 0x37, 0xD1, 0xEA, 0x2F, 0xD0, 0x9F, + 0x91, 0xAF, 0x50, 0xDB, 0xE4, 0x46, 0x74, 0x97, 0xBD, 0x96, + 0x38, 0x1D, 0xCA, 0xEC, 0x2E, 0xEE, 0xB8, 0x00, 0x91, 0xA6, + 0x64, 0x09, 0xE2, 0x8D, 0x12, 0xAC, 0x19, 0xBE, 0xEB, 0x04, + 0xD5, 0xC2, 0x2B, 0x79, 0x0F, 0xF2, 0x68, 0x31, 0xF9, 0xBD, + 0xDB, 0x31, 0xD2, 0x1C, 0x40, 0xB2, 0xD0, 0x9E, 0x10, 0xF2, + 0x28, 0x9B, 0xDD, 0x65, 0xBA, 0x18, 0x89, 0x9B, 0x1A, 0x8F, + 0x06, 0x40, 0x57, 0x6F, 0xD5, 0xC0, 0x24, 0xCF, 0x1E, 0xED, + 0xF0, 0x05, 0x57, 0xB9, 0x88, 0x05, 0x09, 0x05, 0x11, 0x23, + 0xFE, 0x79, 0x47, 0x6A, 0x47, 0x48, 0xD8, 0x4F, 0xAD, 0x0F, + 0xEB, 0x08, 0x20, 0x69, 0x60, 0x58, 0xF0, 0x33, 0x48, 0x78, + 0xB1, 0xE6, 0x44, 0xCE, 0x25, 0xDD, 0xF3, 0x7E, 0xD9, 0x2F, + 0xE0, 0xA5, 0xC9, 0xA4, 0x42, 0x22, 0xBB, 0xC7, 0x45, 0x7B, + 0x0E, 0x67, 0x41, 0x3C, 0x70, 0x0D, 0xD9, 0xAD, 0x84, 0xE9, + 0xF2, 0xE9, 0xF8, 0x81, 0xB4, 0x67, 0x3F, 0x8A, 0xFF, 0x5D, + 0x5C, 0x7C, 0x86, 0x4C, 0x6E, 0xD5, 0xBD, 0x93, 0x78, 0x10, + 0x8E, 0x92, 0x99, 0x10, 0x73, 0x31, 0x21, 0x01, 0x32, 0xF2, + 0xAF, 0x45, 0x6B, 0x56, 0x1A, 0xC9, 0x37, 0x57, 0x34, 0x97, + 0xA2, 0x75, 0x24, 0x6B, 0xEA, 0xC4, 0xF8, 0x99, 0x74, 0xDB, + 0xA7, 0x7B, 0x4A, 0xA4, 0xDA, 0xDD, 0x0A, 0x67, 0x05, 0x2C, + 0x3E, 0x44, 0x76, 0xA4, 0x1A, 0xFD, 0x08, 0x2B, 0x62, 0x35, + 0x73, 0xFF, 0x5E, 0x8F, 0xAF, 0x41, 0x29, 0x64, 0xD0, 0xCA, + 0x78, 0xC8, 0x9B, 0x9C, 0x54, 0x82, 0x04, 0x28, 0x7D, 0xA9, + 0xE0, 0x15, 0xFF, 0x44, 0xFF, 0x45, 0x58, 0xE1, 0x89, 0xEC, + 0x27, 0x53, 0xA6, 0x02, 0x0D, 0x04, 0x34, 0x37, 0x6D, 0x1B, + 0x88, 0xA8, 0x6D, 0x57, 0xB4, 0xDA, 0xEA, 0x90, 0x3B, 0xE2, + 0x85, 0x3D, 0x14, 0x92, 0x9E, 0x12, 0x13, 0x1B, 0xBB, 0x6B, + 0xE3, 0x5D, 0x9B, 0xBF, 0xBA, 0xB4, 0x00, 0x43, 0x53, 0xDD, + 0x60, 0x40, 0xAF, 0x1B, 0xC8, 0x82, 0x51, 0x07, 0x99, 0xD6, + 0x5C, 0xBB, 0x90, 0x46, 0x9E, 0x64, 0xCC, 0xEC, 0x7C, 0x5B, + 0xF8, 0xDB, 0x85, 0x26, 0xB3, 0xBD, 0x11, 0x13, 0x05, 0x9B, + 0x55, 0x03, 0x2D, 0x7C, 0xB0, 0x35, 0x2E, 0x99, 0xD2, 0x12, + 0x04, 0x2A, 0x34, 0x5B, 0x8A, 0xB0, 0xBA, 0xB8, 0xFE, 0x28, + 0x65, 0x42, 0x48, 0xA8, 0x69, 0xAD, 0x42, 0x72, 0x72, 0x30, + 0x21, 0xE0, 0x12, 0xDF, 0x85, 0x7F, 0xA9, 0xEF, 0xC7, 0x4B, + 0xD8, 0x35, 0x84, 0xBB, 0xA0, 0x9C, 0x09, 0x8D, 0x64, 0x69, + 0xFB, 0x26, 0x71, 0x83, 0x97, 0x94, 0x7C, 0x39, 0x41, 0x53, + 0x4D, 0x5E, 0xF2, 0x1F, 0x91, 0xF0, 0xF2, 0x44, 0xDF, 0x98, + 0x26, 0x46, 0x59, 0xA3, 0x21, 0xB8, 0x88, 0xAB, 0xC1, 0x2D, + 0x24, 0x2D, 0x9C, 0xFC, 0x6D, 0x92, 0x16, 0x83, 0xF7, 0xC8, + 0xCC, 0x78, 0x6D, 0x5F, 0x23, 0x73, 0xCB, 0xF0, 0x36, 0xA7, + 0xA4, 0x19, 0x89, 0x7D, 0xB2, 0x05, 0x9F, 0xC7, 0xA6, 0x9C, + 0x24, 0xA7, 0x93, 0x02, 0x5C, 0x27, 0xC6, 0x42, 0x4B, 0x61, + 0xF4, 0x3D, 0x52, 0x14, 0x94, 0x46, 0xE2, 0x4D, 0x79, 0xB7, + 0x12, 0x08, 0xE6, 0xD8, 0xCE, 0xE8, 0x10, 0xEA, 0x9B, 0xA3, + 0xBA, 0x5F, 0x94, 0x41, 0x29, 0x20, 0xD5, 0x74, 0xF6, 0xA0, + 0xCE, 0xD8, 0x0C, 0x07, 0x51, 0xDB, 0xBC, 0x91, 0xD7, 0x27, + 0x6E, 0x22, 0x14, 0xA6, 0x0E, 0x4D, 0x16, 0xB0, 0x1C, 0xB6, + 0x3E, 0xD9, 0x70, 0x55, 0xE3, 0xF0, 0xA5, 0x76, 0xFA, 0xAC, + 0x75, 0x0F, 0xEC, 0x82, 0xA9, 0x7E, 0xD7, 0x43, 0xF3, 0x14, + 0x12, 0x90, 0x9A, 0xF1, 0xA1, 0xA1, 0xFB, 0x9C, 0xCD, 0x21, + 0xFE, 0x63, 0xC9, 0xA4, 0xB4, 0x09, 0xE3, 0x70, 0x40, 0xA6, + 0x68, 0xBF, 0x9C, 0x70, 0xCA, 0x1B, 0xFA, 0xD2, 0xCD, 0x00, + 0xB3, 0xE8, 0x53, 0xB4, 0x75, 0x7D, 0x43, 0xEE, 0x69, 0x81, + 0x34, 0x57, 0x21, 0xC4, 0x19, 0xFA, 0x66, 0x02, 0xDC, 0x68, + 0x11, 0x92, 0xA9, 0x28, 0xD2, 0x4C, 0x81, 0xEC, 0x05, 0x99, + 0x30, 0xA7, 0x1F, 0xCE, 0xF2, 0xB4, 0x79, 0x9F, 0x98, 0x97, + 0xE3, 0x05, 0x88, 0x77, 0x93, 0xBA, 0x6D, 0x1C, 0x00, 0x96, + 0x8E, 0x32, 0x06, 0x8A, 0xF5, 0xEF, 0xB3, 0xA2, 0x68, 0x61, + 0x1E, 0x12, 0xF1, 0xA4, 0x5C, 0x43, 0xD8, 0x7F, 0x66, 0x74, + 0xFA, 0x58, 0xB6, 0x3F, 0x81, 0xE6, 0x15, 0xA0, 0x32, 0xD0, + 0x9D, 0xCB, 0xB4, 0xB3, 0xD4, 0x88, 0xA2, 0x7C, 0x81, 0xFD, + 0x9E, 0x6D, 0xC3, 0xB4, 0xFE, 0xB9, 0x0B, 0x78, 0x0C, 0x02, + 0x89, 0x05, 0x57, 0x92, 0x37, 0xFF, 0x00, 0x4C, 0x65, 0x2B, + 0xA6, 0xB4, 0x2B, 0xD7, 0x52, 0xAC, 0x15, 0xAE, 0x64, 0x3D, + 0x76, 0x51, 0x07, 0x4B, 0x38, 0xB8, 0xF1, 0x26, 0x08, 0xDE, + 0x88, 0xDF, 0xF4, 0xA8, 0xBD, 0xD6, 0x27, 0xDB, 0x89, 0x28, + 0xF4, 0xCC, 0x14, 0xF4, 0xCA, 0x79, 0x17, 0xB5, 0x26, 0x71, + 0xB7, 0x68, 0x84, 0x17, 0x73, 0x73, 0xC5, 0x06, 0xB9, 0xA8, + 0x03, 0x2B, 0xA6, 0xEF, 0x89, 0x99, 0x55, 0x61, 0x4E, 0x40, + 0x9B, 0xEE, 0x7E, 0xA5, 0x6B, 0xDB, 0xD4, 0xFE, 0x90, 0x92, + 0x94, 0xFE, 0x0C, 0x3B, 0xF7, 0xCE, 0x67, 0xFC, 0x71, 0x0C, + 0xB1, 0x53, 0x07, 0xAC, 0xF7, 0xF6, 0xC6, 0x50, 0x12, 0xB0, + 0xDE, 0x51, 0xE2, 0xF5, 0xE6, 0x15, 0xB9, 0xAB, 0xF4, 0x3C, + 0xCB, 0xDC, 0xAD, 0x76, 0x36, 0x80, 0xE2, 0xBB, 0xF8, 0x2E, + 0x5A, 0xE6, 0x55, 0xD6, 0x2A, 0x22, 0xBF, 0x4A, 0xB6, 0x71, + 0xF4, 0xDE, 0x0F, 0x37, 0x55, 0x6F, 0x8C, 0x63, 0x65, 0x42, + 0x02, 0xEF, 0xF4, 0x76, 0x65, 0x3A, 0x04, 0xF0, 0xA5, 0x5C, + 0x42, 0x66, 0xFE, 0x23, 0x30, 0xE7, 0x93, 0x73, 0x0A, 0x30, + 0xDF, 0x65, 0xDA, 0xA4, 0x9D, 0xA9, 0xEF, 0xD7, 0x3D, 0x05, + 0x7B, 0x77, 0x78, 0x20, 0xF6, 0x49, 0xA5, 0xDD, 0x83, 0x9B, + 0x65, 0x3B, 0x1E, 0x27, 0xA7, 0xD8, 0xED, 0x37, 0x12, 0x78, + 0xB8, 0xCB, 0x1F, 0x00, 0xD1, 0xDF, 0x1C, 0x73, 0x3F, 0x6F, + 0x97, 0xE9, 0xB5, 0xE2, 0xE2, 0x79, 0xBB, 0x3D, 0xCC, 0x1F, + 0x29, 0xDD, 0xB6, 0x06, 0x10, 0x5F, 0xD5, 0x7F, 0x8A, 0x96, + 0x26, 0x53, 0xEA, 0x4E, 0x4E, 0x46, 0x73, 0x7E, 0xFA, 0x7E, + 0x6E, 0x66, 0x27, 0x12, 0x75, 0x78, 0x28, 0x45, 0xF6, 0x80, + 0x78, 0xFE, 0x20, 0x25, 0x5C, 0xD2, 0xCB, 0x07, 0x36, 0x67, + 0x4E, 0xC7, 0xBE, 0x33, 0xA6, 0xFB, 0x9E, 0xE0, 0xD6, 0x1E, + 0x32, 0x99, 0xE5, 0xA3, 0xD0, 0x16, 0xD4, 0x07, 0x2A, 0xAE, + 0x9D, 0x56, 0xE9, 0x20, 0x40, 0x0D, 0x9D, 0x72, 0x4F, 0xE8, + 0x1D, 0xC0, 0xC9, 0x21, 0xED, 0xCD, 0xFD, 0x2A, 0x09, 0x59, + 0x3F, 0xEB, 0xE1, 0xBB, 0x92, 0xDA, 0x26, 0xF0, 0x4E, 0x1E, + 0xF7, 0x3D, 0xE2, 0x97, 0x7D, 0x1D, 0x91, 0x82, 0x15, 0xD9, + 0x68, 0x33, 0x9D, 0x14, 0x29, 0x9D, 0x8F, 0x08, 0x18, 0x12, + 0x17, 0x0A, 0x57, 0x11, 0xB7, 0x20, 0x30, 0x85, 0xC5, 0xF1, + 0xB2, 0x49, 0xEA, 0xD7, 0xC5, 0x4E, 0xE2, 0x0D, 0xA6, 0x2A, + 0xD0, 0xE9, 0x46, 0x8E, 0xA1, 0xF0, 0xD6, 0xEA, 0xE7, 0x41, + 0xDD, 0xEE, 0x76, 0x22, 0x2F, 0x12, 0x1B, 0x13, 0x28, 0x78, + 0x7A, 0x5A, 0xC1, 0x8E, 0xFA, 0xE1, 0x0F, 0x6D, 0xDC, 0x7F, + 0x9A, 0x71, 0xEC, 0xDF, 0xB9, 0xE9, 0xF5, 0x9D, 0x95, 0xAC, + 0x50, 0xA7, 0x8C, 0x0E, 0x20, 0x7F, 0x8D, 0x95, 0x4C, 0x7B, + 0x4E, 0xB5, 0x3E, 0x20, 0x3B, 0x78, 0xF7, 0x74, 0x48, 0x34, + 0xBB, 0x9C, 0xA0, 0xE8, 0x7B, 0x30, 0x2E, 0x66, 0xC2, 0x63, + 0xB9, 0x39, 0xB8, 0x76, 0x64, 0x71, 0xEC, 0x93, 0xD9, 0xDB, + 0x88, 0x75, 0xB3, 0x4F, 0x52, 0x9F, 0xC8, 0x09, 0x87, 0x56, + 0x94, 0x00, 0x27, 0xA8, 0x7D, 0xED, 0xB9, 0xDD, 0xB7, 0x35, + 0x39, 0x58, 0x0C, 0x33, 0x29, 0xDB, 0x0F, 0xC1, 0x95, 0x89, + 0x4E, 0xBA, 0x6D, 0x33, 0x68, 0x61, 0x1C, 0xE5, 0xAE, 0x9C, + 0x26, 0x35, 0x81, 0x87, 0xD0, 0x25, 0xEE, 0xD4, 0xC4, 0x05, + 0x9D, 0x17, 0x6A, 0x7A, 0xB9, 0x37, 0xF4, 0xC3, 0x32, 0x9A, + 0xE3, 0x6B, 0x0B, 0x65, 0xF8, 0x43, 0x1C, 0xEE, 0x44, 0xF3, + 0xE6, 0x15, 0xB7, 0x20, 0x84, 0xF1, 0x51, 0x57, 0xE5, 0x52, + 0x66, 0x3F, 0x3D, 0x80, 0x71, 0x1B, 0x96, 0x47, 0x70, 0xE7, + 0x7D, 0x4B, 0x39, 0xCF, 0x10, 0xF6, 0x45, 0xC0, 0xE9, 0x77, + 0x88, 0x28, 0xB2, 0x24, 0x2B, 0x7D, 0xCD, 0x9D, 0xFC, 0x8C, + 0x98, 0xB1, 0x73, 0x6F, 0xD6, 0x23, 0xC9, 0xB4, 0x43, 0x89, + 0x9C, 0x46, 0x17, 0x7A, 0x3F, 0xFB, 0x59, 0xE1, 0x2F, 0x53, + 0xEB, 0x46, 0x51, 0x82, 0xC0, 0x4A, 0xCF, 0x33, 0xD0, 0x25, + 0x6F, 0x5A, 0x43, 0xCE, 0xAD, 0x76, 0xEA, 0xD8, 0xB0, 0x35, + 0x77, 0x85, 0x43, 0x62, 0x42, 0x67, 0x4A, 0xF7, 0xDA, 0x6C, + 0xB7, 0x0C, 0x5E, 0xA3, 0x8B, 0x94, 0x49, 0x5A, 0x75, 0x3B, + 0xCD, 0x10, 0xB2, 0xBC, 0xA7, 0xD2, 0x19, 0x5E, 0xA2, 0xC6, + 0x46, 0xFF, 0xA6, 0x54, 0xE2, 0x00, 0x74, 0xF6, 0x31, 0xB6, + 0x61, 0x76, 0x9B, 0xE5, 0x94, 0x74, 0x5E, 0x48, 0xF5, 0xF3, + 0xAE, 0xEA, 0x5D, 0x2A, 0x59, 0x09, 0x4A, 0x20, 0x92, 0xBB, + 0x5A, 0x45, 0xC9, 0xE9, 0x0B, 0x1A, 0xD4, 0xFE, 0xD5, 0x54, + 0x14, 0x7D, 0xDD, 0xE7, 0x8E, 0xAE, 0x1F, 0xA4, 0xCF, 0x33, + 0xAA, 0x1D, 0xD5, 0x66, 0x3A, 0x23, 0xB5, 0x41, 0x9C, 0x5F, + 0x75, 0xDB, 0x46, 0x98, 0x07, 0x76, 0x60, 0x1A, 0x5A, 0x31, + 0xA6, 0x57, 0x2D, 0xCE, 0xD2, 0xA6, 0x7D, 0x3C, 0x27, 0x36, + 0x44, 0xF0, 0xFC, 0xD2, 0xA6, 0xB8, 0xA3, 0xBB, 0xBB, 0xE5, + 0x07, 0x94, 0xEA, 0x4A, 0x06, 0xFF, 0x5E, 0xF5, 0xF7, 0xDC, + 0xF7, 0x25, 0x52, 0xA8, 0x1E, 0xB0, 0x63, 0xD9, 0x5D, 0x26, + 0x1F, 0xC2, 0x06, 0x05, 0xF6, 0x29, 0x4A, 0x4D, 0xBF, 0xB9, + 0x22, 0x97, 0x8D, 0xDD, 0xE8, 0x50, 0x07, 0x88, 0x5F, 0x49, + 0x53, 0x34, 0x28, 0x43, 0xAE, 0x6B, 0xAD, 0x8B, 0x21, 0xCA, + 0xB9, 0x64, 0xD5, 0x70, 0x47, 0x03, 0x55, 0x66, 0xD3, 0x25, + 0xDE, 0x4F, 0xAD, 0xAC, 0x26, 0x01, 0x3B, 0xA3, 0x57, 0x14, + 0xA4, 0x67, 0x19, 0x6D, 0x50, 0x63, 0xA9, 0xD2, 0xCB, 0x55, + 0x98, 0xD9, 0x0E, 0x77, 0x6E, 0x84, 0x92, 0xBE, 0xC0, 0xB7, + 0x0B, 0x22, 0xB8, 0xDB, 0x21, 0x8F, 0x28, 0x76, 0x2E, 0x17, + 0x7E, 0xD8, 0xB4, 0xA5, 0x4A, 0xA1, 0xBF, 0xC4, 0xDC, 0x3E, + 0x79, 0x04, 0x95, 0x76, 0x2C, 0x5E, 0xFD, 0x94, 0x44, 0x41, + 0x6A, 0x13, 0x7B, 0x44, 0x07, 0x86, 0x20, 0x16, 0x4A, 0x25, + 0x9A, 0x3E, 0x8E, 0xE7, 0xA4, 0xF0, 0x29, 0x1D, 0x33, 0xEC, + 0xEB, 0x99, 0x37, 0xCB, 0x1B, 0x1F, 0x79, 0xC5, 0x6A, 0xA3, + 0xB0, 0x68, 0xC5, 0xE3, 0xE4, 0xC6, 0xD6, 0x8E, 0xCF, 0x50, + 0x45, 0xBB, 0xE6, 0xB7, 0xB5, 0x9F, 0x67, 0x3F, 0x33, 0xE4, + 0xB8, 0x03, 0xEC, 0x2A, 0x47, 0xA4, 0x71, 0xD5, 0x4B, 0x1F, + 0xAA, 0x03, 0x1F, 0x87, 0x13, 0x5F, 0x3C, 0x45, 0x3B, 0x07, + 0x0C, 0xC7, 0xEC, 0x7E, 0xA8, 0xFE, 0x3C, 0x6D, 0xA5, 0x3E, + 0x06, 0x31, 0xE9, 0x82, 0x8E, 0x3F, 0xB5, 0x70, 0x4C, 0xB3, + 0xE5, 0xE9, 0xF4, 0xB3, 0x06, 0x3A, 0xF3, 0x01, 0xD7, 0x59, + 0x9E, 0x9C, 0x74, 0xEC, 0xF0, 0x9A, 0x23, 0xF6, 0x75, 0x33, + 0x87, 0x8F, 0x61, 0x45, 0xED, 0x48, 0x10, 0xDA, 0xDF, 0x52, + 0x72, 0x05, 0x3B, 0x1C, 0x0E, 0x1E, 0x57, 0x8D, 0x56, 0xE5, + 0x26, 0x4F, 0x69, 0x16, 0xB4, 0x7A, 0x32, 0xED, 0x8F, 0x2F, + 0xC9, 0xE7, 0x21, 0xCD, 0x24, 0x14, 0x83, 0xC3, 0x80, 0xED, + 0x1D, 0xF6, 0x87, 0x53, 0xA3, 0xF3, 0x14, 0x19, 0x94, 0x14, + 0x1B, 0x8C, 0xFF, 0xE2, 0xB5, 0x1D, 0xB2, 0x80, 0xCF, 0x0D, + 0xCE, 0xCB, 0xA6, 0x3F, 0x1A, 0x0E, 0x0E, 0x86, 0x88, 0xA5, + 0xAA, 0x1D, 0xCB, 0xE5, 0xAF, 0xA3, 0x33, 0x82, 0xA2, 0x07, + 0x84, 0x0A, 0x87, 0xE5, 0x1C, 0xED, 0x92, 0x9A, 0x90, 0x7D, + 0xE3, 0x76, 0xE6, 0x33, 0xC2, 0x5C, 0x61, 0xAD, 0xB5, 0xAE, + 0x2A, 0x51, 0x69, 0xB0, 0xC3, 0x78, 0x61, 0x5E, 0xB1, 0x74, + 0x79, 0x10, 0xDE, 0xC8, 0x6A, 0x43, 0x82, 0x0B, 0xC9, 0x53, + 0x39, 0xF8, 0x80, 0x37, 0xF8, 0x7E, 0x88, 0xD1, 0x56, 0xC2, + 0x5E, 0x2C, 0x54, 0x0F, 0x06, 0xC4, 0x13, 0xFC, 0x8C, 0x3F, + 0x0F, 0xDF, 0x33, 0xD6, 0xC6, 0xD5, 0xE2, 0xE5, 0xF3, 0x24, + 0x80, 0xA7, 0xD4, 0x0B, 0xDC, 0x9B, 0x65, 0x39, 0x8A, 0x2F, + 0x8A, 0xD4, 0x8D, 0x5A, 0xCF, 0x50, 0xA4, 0x46, 0xA0, 0x2A, + 0xF4, 0xCA, 0xD8, 0xDB, 0xC0, 0x6D, 0x64, 0xA0, 0x27, 0x08, + 0xC0, 0x72, 0x98, 0xA9, 0x41, 0x16, 0x09, 0x91, 0x7E, 0xA2, + 0x00, 0x86, 0xCC, 0x0A, 0xDA, 0x75, 0xF5, 0x6B, 0xED, 0xFB, + 0xCD, 0x49, 0x71, 0x0C, 0xA6, 0xE6, 0x9C, 0x87, 0x5F, 0x22, + 0x8C, 0xEF, 0xA7, 0x57, 0xB0, 0x71, 0x93, 0x6A, 0xE9, 0xEC, + 0xFE, 0xF3, 0x58, 0xA1, 0xF7, 0x4B, 0x8A, 0xF1, 0x5F, 0xF1, + 0x49, 0x8C, 0x29, 0xA8, 0x7E, 0x48, 0xDF, 0x82, 0x8B, 0x12, + 0xC3, 0xC1, 0xBA, 0x58, 0xF7, 0x71, 0x08, 0x48, 0xAC, 0x0F, + 0x29, 0x18, 0xF2, 0x5F, 0xB9, 0xC2, 0x6A, 0x72, 0x73, 0x9F, + 0x7A, 0xC4, 0xE5, 0x16, 0xD8, 0x64, 0xF3, 0xAE, 0x13, 0xA2, + 0x14, 0x15, 0x97, 0xB6, 0x8E, 0xDD, 0x30, 0x2E, 0xE5, 0xFD, + 0x15, 0x01, 0x2C, 0x0A, 0x06, 0x20, 0x37, 0xC9, 0x4F, 0x80, + 0x45, 0x2A, 0xF4, 0x48, 0x94, 0x98, 0xC2, 0x43, 0x97, 0x60, + 0x2E, 0x9D, 0x6D, 0xF3, 0xBE, 0xF5, 0xA3, 0x6B, 0x36, 0x07, + 0x94, 0x13, 0x47, 0xD5, 0x35, 0x3E, 0xDE, 0x39, 0x4D, 0xDD, + 0xD1, 0xAE, 0xA5, 0x81, 0x8B, 0xA5, 0xD0, 0xED, 0x48, 0xFA, + 0xCF, 0xB4, 0xF4, 0x43, 0xF5, 0x21, 0xF9, 0xFF, 0x03, 0x0A, + 0xB7, 0x20, 0xB4, 0x57, 0xB9, 0xBD, 0xDC, 0x1B, 0x17, 0x8E, + 0xA1, 0xAF, 0x17, 0xDB, 0x09, 0x5A, 0x8C, 0x91, 0xFC, 0x3A, + 0xED, 0x62, 0x8A, 0x54, 0x3E, 0xE5, 0xAB, 0x01, 0x0C, 0xE8, + 0x9C, 0x50, 0x19, 0xE1, 0xE4, 0x9C, 0x01, 0xE5, 0xB4, 0x30, + 0x5F, 0x78, 0x9F, 0x5B, 0x80, 0xC0, 0x48, 0x11, 0x3A, 0x70, + 0xD9, 0x72, 0xB8, 0xCD, 0x86, 0xB9, 0xBA, 0xD1, 0x98, 0x7F, + 0x20, 0xD6, 0xF2, 0x8A, 0x23, 0xA6, 0x00, 0x17, 0x25, 0xFF, + 0x61, 0x32, 0x9D, 0x98, 0xFC, 0x84, 0x42, 0x92, 0xE1, 0x1D, + 0xBD, 0x05, 0xF5, 0x74, 0x20, 0x6D, 0xB7, 0x8F, 0x28, 0x7B, + 0x75, 0xDF, 0x85, 0xE8, 0x4C, 0x14, 0x06, 0xB8, 0x61, 0xB3, + 0xE9, 0x80, 0x0A, 0x84, 0x9E, 0xC3, 0x1B, 0xF8, 0xCD, 0x73, + 0x11, 0x96, 0xB5, 0x0E, 0xF0, 0x66, 0x87, 0x51, 0x76, 0xA9, + 0x6B, 0x31, 0xC5, 0xEA, 0x63, 0xB2, 0xAE, 0xC5, 0xD7, 0x11, + 0x51, 0x20, 0x3A, 0xF7, 0xE5, 0x37, 0xF3, 0x5D, 0x6B, 0xD6, + 0x04, 0x28, 0x7F, 0xB6, 0xA5, 0x20, 0xC9, 0xDB, 0xF4, 0x0B, + 0xD8, 0x9D, 0x2C, 0xD7, 0x4A, 0x72, 0x3D, 0x49, 0x8D, 0xB1, + 0xF3, 0x2F, 0xD0, 0x52, 0x11, 0xF9, 0xEB, 0x7B, 0xD6, 0x44, + 0x71, 0x15, 0x73, 0x32, 0x79, 0xF6, 0x89, 0x55, 0x75, 0xA8, + 0x02, 0x91, 0x27, 0x67, 0x7A, 0x5E, 0x1E, 0x36, 0x6E, 0x63, + 0x27, 0xAE, 0x15, 0xAA, 0xDB, 0xF0, 0x6C, 0x13, 0xAC, 0x1C, + 0x1A, 0x4F, 0x55, 0x8C, 0x40, 0x01, 0xF4, 0x61, 0x60, 0x4A, + 0xFF, 0xD8, 0x8B, 0x1C, 0x20, 0xE4, 0xB5, 0x3A, 0x80, 0x5C, + 0x46, 0x01, 0x9A, 0xE1, 0xD7, 0x6B, 0xE5, 0xE3, 0x09, 0x4A, + 0xA7, 0xCE, 0x01, 0xD8, 0xF1, 0xAF, 0xB7, 0xA3, 0xDD, 0x95, + 0xCF, 0x39, 0x5D, 0x9E, 0xB3, 0x16, 0x8F, 0x75, 0x83, 0x99, + 0xB2, 0x55, 0x63, 0x51, 0x3A, 0x19, 0xB4, 0x60, 0x3A, 0x43, + 0x89, 0x77, 0x97, 0x01, 0xF9, 0x3E, 0xFA, 0xA6, 0x45, 0x2E, + 0x98, 0x23, 0x98, 0x59, 0x09, 0x6A, 0xA4, 0x1E, 0x99, 0x50, + 0xE3, 0x76, 0x9E, 0x0D, 0xB9, 0x16, 0xFD, 0x74, 0x60, 0x84, + 0xE5, 0xC6, 0x16, 0xF0, 0x18, 0xC9, 0x6F, 0x7A, 0x51, 0xB8, + 0x67, 0xAE, 0xDA, 0xDD, 0xC2, 0x3E, 0x3E, 0x35, 0x08, 0x7A, + 0x27, 0x82, 0x8F, 0x91, 0x0D, 0x81, 0x1A, 0x3F, 0x81, 0x23, + 0x8E, 0x81, 0x79, 0xA4, 0x88, 0x92, 0x1F, 0xEE, 0x96, 0x9A, + 0x99, 0x18, 0x31, 0xDB, 0xE0, 0xC5, 0xB9, 0x0B, 0x78, 0x54, + 0x0A, 0xF8, 0x7A, 0xF2, 0xEC, 0x86, 0x15, 0x9F, 0x45, 0x43, + 0x6D, 0xB1, 0x72, 0xC0, 0x4E, 0x46, 0x41, 0x57, 0xE0, 0xEC, + 0x4F, 0x56, 0xB8, 0x68, 0x10, 0x1D, 0x26, 0x90, 0xF8, 0x74, + 0xFB, 0xAC, 0x13, 0x7C, 0x8B, 0x51, 0xAA, 0x1C, 0x64, 0xB2, + 0xFB, 0x50, 0x29, 0x4F, 0xC6, 0xD2, 0x93, 0xFF, 0x08, 0x76, + 0x0C, 0x8D, 0x6D, 0x55, 0x3C, 0x7F, 0xF5, 0x68, 0x61, 0x25, + 0x2C, 0xA6, 0xE0, 0xC2, 0xBA, 0xDC, 0x32, 0x14, 0xAF, 0xA4, + 0x4A, 0xB7, 0x10, 0x83, 0x4D, 0x0E, 0xCF, 0xA5, 0xDE, 0x62, + 0x9F, 0x49, 0x82, 0x35, 0x2D, 0x03, 0x39, 0x0B, 0xF2, 0xEE, + 0x95, 0xA3, 0x95, 0x61, 0x3B, 0x53, 0x86, 0x82, 0x9C, 0x99, + 0x2D, 0x80, 0x18, 0xBE, 0x87, 0x7B, 0x20, 0xE1, 0xCF, 0xAF, + 0xDA, 0xFA, 0x3D, 0x74, 0x59, 0xBE, 0x0F, 0x8D, 0x38, 0xBE, + 0x6C, 0xDE, 0xC8, 0xE4, 0xC3, 0xD6, 0x05, 0x87, 0x34, 0x7B, + 0xB1, 0x47, 0xDE, 0x42, 0xE0, 0x17, 0xBB, 0xFD, 0xCB, 0x3D, + 0x15, 0x07, 0x5E, 0x03, 0x81, 0x1B, 0x16, 0xE2, 0x0E, 0xDD, + 0xB0, 0x8D, 0xA1, 0xD8, 0x84, 0x93, 0xA7, 0xEB, 0xBF, 0x11, + 0xD6, 0x98, 0xB8, 0x31, 0xB4, 0xC8, 0x10, 0x7F, 0x1C, 0xCE, + 0xA5, 0xB4, 0x41, 0xD8, 0xCC, 0xFE, 0x0D, 0x56, 0x5C, 0xEB, + 0x43, 0x0C, 0x27, 0x07, 0xF9, 0x03, 0x09, 0x3D, 0xC3, 0x5C, + 0x2C, 0x05, 0xBC, 0x40, 0x0B, 0x99, 0x8B, 0x5C, 0x7E, 0xFE, + 0x48, 0xD6, 0x34, 0xBC, 0x45, 0x94, 0xAC, 0x10, 0xAA, 0x0B, + 0x27, 0xE8, 0x00, 0xC4, 0x52, 0x94, 0x5E, 0x72, 0x7E, 0x8B, + 0x96, 0xCF, 0x47, 0xE9, 0xBA, 0xE9, 0xAD, 0x8F, 0xE1, 0x6C, + 0x94, 0x19, 0x94, 0xCD, 0x19, 0xDE, 0xF4, 0x42, 0x37, 0x94, + 0x8C, 0x48, 0x07, 0x5E, 0xC4, 0x46, 0x8B, 0xE7, 0xAC, 0x18, + 0xE8, 0x61, 0xAD, 0x93, 0x90, 0x97, 0x8A, 0x2F, 0xE0, 0x3C, + 0x78, 0xCC, 0x18, 0xC4, 0x59, 0xD1, 0xD4, 0xDD, 0x1B, 0xAD, + 0x87, 0x99, 0x59, 0x56, 0xD4, 0xEB, 0x88, 0x63, 0x6D, 0x95, + 0xB0, 0x57, 0xD6, 0x52, 0x83, 0xC3, 0xF0, 0x8A, 0xC0, 0x59, + 0xD6, 0x71, 0x2B, 0x0E, 0x75, 0xD2, 0x97, 0x5B, 0xAB, 0x4D, + 0xB2, 0xFC, 0xAB, 0x6B, 0xC4, 0x6E, 0xD5, 0x13, 0x1B, 0xA6, + 0xC6, 0xD0, 0x3B, 0x91, 0xB0, 0xEC, 0x5A, 0xF8, 0x4E, 0x5A, + 0x8B, 0x71, 0x0B, 0xEB, 0xE5, 0x6B, 0xCF, 0x2B, 0x83, 0x98, + 0x92, 0x23, 0x54, 0xF7, 0x3B, 0x4F, 0x9F, 0x53, 0x7B, 0x2F, + 0xE4, 0xDB, 0xFE, 0xA6, 0x79, 0xE8, 0x3C, 0x8F, 0x80, 0x1A, + 0x7D, 0x79, 0x3A, 0x2E, 0x26, 0x2C, 0xCF, 0x9F, 0xBC, 0xF2, + 0x99, 0x65, 0xAA, 0xA9, 0xB3, 0x1E, 0x04, 0x05, 0xF2, 0x06, + 0x6E, 0x97, 0x40, 0xAF, 0xC2, 0x1F, 0xE1, 0x40, 0x94, 0xAD, + 0xF6, 0x3C, 0xE2, 0xB8, 0x69, 0x39, 0x5E, 0xBB, 0x39, 0xD7, + 0x99, 0x3D, 0xD5, 0x02, 0x8A, 0x99, 0x44, 0x69, 0x60, 0xD6, + 0x72, 0x7F, 0x06, 0x36, 0x0A, 0x2D, 0xC4, 0xAD, 0x5A, 0x86, + 0x5F, 0x1D, 0x1B, 0x3C, 0x01, 0xA3, 0x31, 0xE6, 0x8D, 0xAD, + 0x69, 0xD5, 0x90, 0x84, 0xD9, 0x5B, 0x39, 0xB4, 0xE3, 0x0D, + 0x40, 0xF4, 0x0C, 0xC0, 0x08, 0x16, 0x16, 0x39, 0xD7, 0xCB, + 0x6B, 0x1E, 0x8B, 0xDE, 0x14, 0xCC, 0x72, 0xC7, 0xBA, 0xF2, + 0x84, 0xB2, 0x68, 0x83, 0xEC, 0xD1, 0xCF, 0xA9, 0xA4, 0x57, + 0xF8, 0x58, 0x16, 0x8F, 0x6C, 0xE4, 0x24, 0x1E, 0x2B, 0x90, + 0x12, 0x52, 0x85, 0x2D, 0x41, 0xDE, 0x46, 0x53, 0xD4, 0x66, + 0x2E, 0xE9, 0x3A, 0x36, 0x54, 0xBC, 0xDB, 0x9B, 0x65, 0x7D, + 0xFE, 0xE7, 0xE7, 0xB2, 0x1B, 0xCD, 0x55, 0x20, 0x13, 0x6A, + 0x5C, 0xD5, 0x59, 0xEB, 0x79, 0xA2, 0xBA, 0x29, 0xDA, 0x66, + 0x6B, 0x59, 0xBA, 0x91, 0xCF, 0x38, 0xE6, 0xF7, 0x27, 0x1E, + 0x2E, 0x69, 0xA3, 0x93, 0xEC, 0x39, 0x4D, 0xB0, 0xB2, 0xA1, + 0x48, 0x35, 0x44, 0x8E, 0x54, 0x95, 0x11, 0x71, 0x6F, 0x27, + 0xD8, 0xDD, 0x94, 0x8B, 0x42, 0x31, 0x09, 0x34, 0x93, 0x0D, + 0x3B, 0x51, 0xE2, 0xE0, 0xBD, 0x2D, 0x11, 0x3A, 0xD2, 0x2D, + 0xDC, 0x42, 0x95, 0xD3, 0x4D, 0x93, 0x87, 0xF3, 0x7B, 0x88, + 0x85, 0x20, 0x22, 0x12, 0xF6, 0x9B, 0x71, 0xF4, 0x79, 0x1F, + 0x4A, 0x2C, 0x6A, 0xC6, 0x3F, 0x1E, 0x8A, 0x8A, 0xA1, 0x07, + 0x22, 0xF5, 0x70, 0x9B, 0xE7, 0x78, 0x87, 0x2B, 0x60, 0xDC, + 0xDF, 0xB7, 0x1C, 0x37, 0x31, 0xEC, 0x3E, 0x1E, 0xDC, 0xB7, + 0x0B, 0x77, 0x5A, 0x60, 0x0A, 0xB2, 0xA4, 0x54, 0x15, 0x60, + 0x14, 0x74, 0x61, 0x49, 0x98, 0x50, 0x3E, 0x55, 0x07, 0x57, + 0x71, 0x23, 0x87, 0x0C, 0xD1, 0x34, 0x25, 0x2E, 0x52, 0x20, + 0xB7, 0xBE, 0x47, 0x82, 0x9B, 0x39, 0xE7, 0x6B, 0x2B, 0xC9, + 0x49, 0x23, 0x6C, 0x3E, 0xC0, 0xF3, 0xB2, 0x1E, 0x06, 0xB6, + 0xD1, 0xF0, 0x21, 0x8D, 0x17, 0x5E, 0xB6, 0xAA, 0xDA, 0x0C, + 0x82, 0xA0, 0x09, 0x22, 0x27, 0x93, 0xD7, 0x05, 0xBC, 0xCA, + 0xAD, 0xC0, 0xD4, 0x04, 0x8D, 0x96, 0xB8, 0xD1, 0x21, 0xC4, + 0xF1, 0x89, 0xBB, 0x12, 0xE5, 0xC9, 0x7F, 0x05, 0x27, 0xB7, + 0x10, 0x92, 0xA6, 0xB8, 0x4D, 0x46, 0x00, 0x0F, 0x56, 0x1A, + 0x25, 0xDC, 0xF7, 0x06, 0xFC, 0xFA, 0xF2, 0x82, 0xEF, 0x04, + 0xD6, 0x30, 0xC8, 0x88, 0xAF, 0x9F, 0xE7, 0x49, 0x3D, 0x86, + 0x74, 0xBA, 0xE0, 0xFC, 0x65, 0xB0, 0x28, 0xC2, 0x1A, 0xB3, + 0x08, 0x33, 0xF2, 0x28, 0x5C, 0x2C, 0x0A, 0x21, 0x25, 0x34, + 0xDF, 0xB8, 0xE2, 0x24, 0x96, 0x82, 0x6D, 0xF9, 0x06, 0xA3, + 0x8E, 0x8F, 0x34, 0xE5, 0x0E, 0xCE, 0x35, 0xB3, 0xEF, 0xB6, + 0xB1, 0xF2, 0x37, 0xE8, 0x8B, 0x1D, 0x36, 0x87, 0x92, 0xDB, + 0xF8, 0x41, 0xA3, 0x81, 0x09, 0x82, 0x3F, 0x58, 0x45, 0x10, + 0xF9, 0xC2, 0x71, 0xC5, 0x95, 0x85, 0x82, 0xC0, 0xE7, 0xF2, + 0xFA, 0xD0, 0x1A, 0x96, 0x20, 0x4D, 0xB7, 0x43, 0xC4, 0x2B, + 0xFE, 0xFB, 0x3C, 0xBF, 0x48, 0x06, 0xD9, 0x0E, 0x76, 0x18, + 0x06, 0x5E, 0x28, 0xF6, 0xB4, 0x50, 0xC6, 0xEE, 0x62, 0xD6, + 0xF3, 0x2D, 0x3C, 0x30, 0x92, 0xA1, 0x22, 0x15, 0x31, 0xB8, + 0x61, 0xBB, 0x15, 0x90, 0x5F, 0xBF, 0xCF, 0x25, 0x99, 0xAB, + 0xBC, 0x76, 0x21, 0xEA, 0xD9, 0x8B, 0xE3, 0xF8, 0x31, 0x57, + 0xBF, 0xE0, 0x30, 0x80, 0x1C, 0x8D, 0xBD, 0x56, 0xDB, 0x82, + 0xAD, 0x36, 0xFB, 0xB0, 0xE9, 0x3A, 0x25, 0x48, 0xBE, 0x27, + 0xF1, 0x3C, 0x94, 0xC1, 0xFB, 0xAA, 0x12, 0xE8, 0x06, 0xB2, + 0xCE, 0x90, 0x76, 0x47, 0x21, 0xE1, 0x22, 0xE5, 0x46, 0x52, + 0x50, 0xDD, 0x53, 0xF9, 0x06, 0xB3, 0xF0, 0x6D, 0x6B, 0xDC, + 0x6B, 0x78, 0xC9, 0xA3, 0x4B, 0x9E, 0xC7, 0xEC, 0xF0, 0x05, + 0x6E, 0x25, 0x15, 0x06, 0xDE, 0x08, 0x0E, 0x94, 0xC6, 0x12, + 0x45, 0x5A, 0xF6, 0xE4, 0x38, 0xBD, 0x52, 0xE9, 0x1C, 0xBA, + 0xB7, 0x3C, 0xEA, 0x84, 0xA7, 0xC9, 0xD8, 0x4F, 0x43, 0xE8, + 0x8E, 0xE6, 0x5C, 0x87, 0xDC, 0x5E, 0x31, 0x44, 0x55, 0xCF, + 0xC4, 0x2D, 0xA1, 0x0A, 0x50, 0x1F, 0x03, 0x60, 0xAC, 0x27, + 0x15, 0x1E, 0x42, 0x95, 0xCD, 0x4F, 0x93, 0x51, 0x38, 0xB6, + 0x0C, 0x78, 0x3F, 0x8F, 0x28, 0xDE, 0x65, 0x66, 0x90, 0x30, + 0x32, 0x8D, 0x81, 0xDC, 0x22, 0x94, 0xEF, 0xF1, 0xD3, 0x37, + 0x6F, 0xD7, 0x79, 0x45, 0x99, 0x9D, 0x96, 0x78, 0x36, 0x37, + 0x41, 0x57, 0x53, 0xA5, 0x8C, 0x87, 0x78, 0x42, 0x38, 0xD8, + 0x93, 0xAC, 0x55, 0x28, 0x6D, 0xF3, 0x96, 0x1D, 0x8E, 0x7E, + 0xE2, 0xCA, 0x7F, 0xF9, 0xCD, 0xB0, 0xED, 0x7F, 0xEF, 0x06, + 0x32, 0xB6, 0xFE, 0xD2, 0x89, 0x6A, 0x94, 0xB7, 0x7C, 0x43, + 0x1E, 0x05, 0xDB, 0x86, 0x63, 0xBB, 0x38, 0xE8, 0x83, 0x33, + 0x98, 0xCB, 0x70, 0xBC, 0xB2, 0xE5, 0xC8, 0x7F, 0x10, 0xDC, + 0xFA, 0x8F, 0x3F, 0xAC, 0x12, 0xB4, 0xB9, 0xD9, 0xC2, 0x99, + 0x5B, 0x2E, 0x5E, 0x55, 0x0D, 0xB7, 0xB0, 0x1F, 0x0F, 0x57, + 0x01, 0x11, 0x28, 0xBD, 0x8A, 0x63, 0x2E, 0xA6, 0x1A, 0xE7, + 0x21, 0x63, 0x37, 0x47, 0x2C, 0x9A, 0xFC, 0xEC, 0x32, 0xDC, + 0x4F, 0xB7, 0x77, 0x45, 0xD0, 0xDB, 0x25, 0x0F, 0x2A, 0x36, + 0xE0, 0x0B, 0xD0, 0x67, 0x88, 0xAE, 0xA4, 0xE5, 0x58, 0x4F, + 0x1F, 0x62, 0xB6, 0xF5, 0x01, 0xFB, 0x9E, 0xF1, 0xDD, 0x73, + 0x16, 0x6E, 0x98, 0xB2, 0x25, 0xFA, 0x55, 0xC9, 0xE5, 0x11, + 0x06, 0xAE, 0x9B, 0xBE, 0xA0, 0x9A, 0xF0, 0x99, 0x34, 0xC5, + 0x96, 0xEC, 0xBB, 0xAD, 0x9E, 0x36, 0xDC, 0xC6, 0x70, 0xEE, + 0x57, 0x6E, 0x18, 0x15, 0x90, 0x80, 0x90, 0xD2, 0x35, 0xCE, + 0xE3, 0x67, 0x2A, 0xC4, 0x57, 0xF3, 0xB6, 0xF4, 0xEA, 0xCA, + 0xE2, 0x59, 0xE0, 0x06, 0x7B, 0xA2, 0x2C, 0xCB, 0x60, 0x95, + 0x1B, 0x29, 0x60, 0x72, 0x03, 0x9C, 0x05, 0x2D, 0xBA, 0xEE, + 0xB5, 0x64, 0x6E, 0xA6, 0xA7, 0xC6, 0x51, 0xF4, 0xB0, 0xBF, + 0x51, 0xC5, 0x0E, 0x6F, 0x02, 0xF7, 0xA5, 0x69, 0x63, 0xC6, + 0x52, 0x29, 0x28, 0xA9, 0xC8, 0xB2, 0x1B, 0x06, 0xFE, 0x2B, + 0x0C, 0x6C, 0x07, 0xAC, 0x56, 0xD7, 0xB2, 0xC6, 0x21, 0x45, + 0x29, 0x48, 0x26, 0xF7, 0x13, 0xB3, 0x43, 0x41, 0xB5, 0xDC, + 0xCF, 0x17, 0x89, 0x1A, 0x6B, 0x26, 0x9C, 0xFC, 0x43, 0xC1, + 0x6D, 0xC6, 0x40, 0x91, 0x58, 0x97, 0x31, 0x9E, 0x06, 0x7F, + 0x22, 0xE2, 0x88, 0x71, 0x17, 0xCA, 0x83, 0xA4, 0x93, 0x92, + 0x6B, 0x5B, 0x97, 0x38, 0xB2, 0x52, 0x95, 0x70, 0x51, 0xEB, + 0x96, 0xBB, 0x32, 0xBD, 0x72, 0x8A, 0x4C, 0x56, 0xE9, 0x96, + 0xA0, 0x05, 0xBD, 0xB2, 0x3E, 0xFC, 0x59, 0xBA, 0x8D, 0xC3, + 0x1C, 0x1E, 0xE0, 0xE1, 0xCE, 0x9B, 0x5A, 0x40, 0xB3, 0xA9, + 0xF6, 0xE6, 0x95, 0xB0, 0x75, 0xEC, 0x95, 0x53, 0xDC, 0x55, + 0x08, 0x43, 0xDC, 0xE0, 0x32, 0xBD, 0x32, 0x9D, 0x43, 0xE1, + 0xC4, 0x74, 0x43, 0x91, 0x97, 0xB5, 0x41, 0x5D, 0xCF, 0x4D, + 0x62, 0x87, 0xD9, 0x39, 0xF8, 0x2C, 0x94, 0xB3, 0x8C, 0xB3, + 0xA2, 0x2F, 0xD6, 0x84, 0x65, 0x34, 0x64, 0xFC, 0x13, 0xC1, + 0x91, 0x0C, 0x1C, 0x65, 0x79, 0x81, 0x0B, 0x5D, 0x12, 0x3F, + 0x47, 0x8E, 0x4F, 0x79, 0x8F, 0x6A, 0x93, 0x62, 0xED, 0x47, + 0x7A, 0x87, 0x51, 0x12, 0x50, 0xAE, 0xA7, 0x54, 0x43, 0x5A, + 0xA1, 0x3F, 0x8E, 0x6B, 0x06, 0x5D, 0x73, 0xBD, 0x05, 0xC2, + 0x99, 0xEC, 0x22, 0xD7, 0x34, 0x72, 0xBC, 0x39, 0xE3, 0xA7, + 0x4E, 0xEE, 0xAF, 0x85, 0x10, 0xAD, 0xB7, 0xE6, 0x7D, 0xFC, + 0xF5, 0xA6, 0xC4, 0x37, 0xC1, 0xA0, 0x71, 0x24, 0xBA, 0xD3, + 0xB1, 0xCD, 0x26, 0xDA, 0xD3, 0x5F, 0x24, 0x1A, 0x87, 0xA7, + 0xCA, 0xF9, 0xF7, 0x4F, 0x41, 0x96, 0x85, 0x9A, 0xCB, 0xCD, + 0xC9, 0xC3, 0x1C, 0x07, 0x0F, 0x09, 0x63, 0xC9, 0xD8, 0x52, + 0x4A, 0x85, 0x5C, 0x47, 0xC2, 0xC9, 0xAF, 0x0A, 0xBA, 0x95, + 0x8E, 0x0D, 0x28, 0x64, 0x2A, 0xB4, 0x8F, 0x77, 0xA6, 0xFF, + 0xEF, 0x7C, 0x50, 0xE7, 0x26, 0x31, 0x84, 0x70, 0xD3, 0x45, + 0x54, 0xA6, 0xD3, 0x4A, 0x05, 0x20, 0x26, 0xC1, 0x7D, 0xFE, + 0xEF, 0xFE, 0xE9, 0x14, 0x6F, 0x25, 0xE7, 0x5D, 0x1A, 0x2E, + 0x3F, 0xEA, 0x75, 0x72, 0x99, 0x94, 0x9E, 0x7E, 0xB0, 0xA7, + 0xD0, 0x0B, 0xF9, 0xD7, 0x2C, 0xAA, 0x55, 0x38, 0x65, 0xA1, + 0xBF, 0x5D, 0xC3, 0xE5, 0xA9, 0xB3, 0xA8, 0x02, 0x77, 0x8B, + 0xD5, 0x49, 0xD1, 0xC8, 0xF0, 0x4F, 0x32, 0x94, 0x1C, 0xC0, + 0xCD, 0x52, 0xC0, 0x99, 0xA1, 0x54, 0x53, 0x66, 0x4D, 0x62, + 0x83, 0xA9, 0x1E, 0xDB, 0x47, 0xF6, 0xCE, 0x40, 0x75, 0x2F, + 0x45, 0x65, 0x07, 0x71, 0xFC, 0x33, 0x60, 0xC5, 0x9F, 0x3D, + 0xE9, 0xD7, 0xF0, 0x17, 0xAC, 0xF5, 0x21, 0x73, 0x7C, 0xFE, + 0x31, 0x25, 0x54, 0xE7, 0xD7, 0xF1, 0x11, 0x52, 0xEC, 0x40, + 0x36, 0xAA, 0x05, 0xDC, 0x01, 0x57, 0x8E, 0xC5, 0x20, 0x21, + 0xF8, 0xF7, 0x18, 0x1C, 0xFB, 0xA7, 0x4A, 0x14, 0xE9, 0x02, + 0x72, 0x87, 0xEA, 0x8C, 0x68, 0xCE, 0xFA, 0xC8, 0xFF, 0xDE, + 0x34, 0x8B, 0x35, 0xBE, 0x01, 0x37, 0x89, 0x7D, 0x10, 0x1D, + 0x0A, 0x70, 0x7E, 0xB6, 0x7A, 0xF7, 0x00, 0x07, 0xC6, 0x50, + 0xF6, 0x21, 0x55, 0x0F, 0xEB, 0x77, 0x89, 0xEE, 0x7C, 0x1C, + 0xA9, 0x48, 0x3C, 0x4A, 0x65, 0xD3, 0x2A, 0xED, 0x8C, 0x9C, + 0xAE, 0x42, 0xD2, 0xF5, 0xCE, 0x6B, 0x86, 0x75, 0x71, 0xC3, + 0xE6, 0x0C, 0x03, 0x71, 0xFB, 0x31, 0xE5, 0x32, 0xEB, 0x05, + 0xB5, 0x6B, 0xBB, 0x3C, 0x9A, 0x0F, 0xC3, 0x45, 0xC5, 0x35, + 0xFB, 0x11, 0x6C, 0xDF, 0xB8, 0x85, 0x29, 0x00, 0xB9, 0xF0, + 0x63, 0xCF, 0x47, 0xA9, 0x68, 0xDE, 0x95, 0x04, 0x71, 0x48, + 0xAD, 0xA4, 0xEA, 0xBB, 0x13, 0x7D, 0x43, 0xE5, 0xE8, 0x48, + 0x27, 0xA2, 0x51, 0x61, 0x80, 0x77, 0x47, 0x50, 0x77, 0xC6, + 0x22, 0x36, 0x76, 0x1D, 0x89, 0x6A, 0xC7, 0xA5, 0xDB, 0x8C, + 0x75, 0x35, 0xE9, 0xB4, 0x83, 0xAE, 0xF5, 0xBA, 0xF0, 0x5B, + 0x93, 0xEB, 0xC7, 0xA8, 0x60, 0xFC, 0xAA, 0xC0, 0xAC, 0x66, + 0x04, 0x41, 0xE1, 0x4D, 0xBA, 0xD2, 0xC9, 0x8F, 0x4B, 0x4C, + 0x81, 0xE2, 0x6B, 0x59, 0xC9, 0x7C, 0x3E, 0x9D, 0xE8, 0xAD, + 0x58, 0xD1, 0xBB, 0x83, 0xF9, 0x6C, 0xF3, 0xC8, 0xA0, 0x2F, + 0x2B, 0x61, 0x03, 0xE1, 0x62, 0xD4, 0x3F, 0xD0, 0x31, 0x63, + 0x82, 0xDE, 0x32, 0xE3, 0xB8, 0xBE, 0x02, 0x64, 0xB2, 0x94, + 0x29, 0x95, 0x2E, 0x29, 0x03, 0xA9, 0x2A, 0x23, 0xFD, 0x68, + 0xAD, 0x41, 0xB2, 0xFC, 0x06, 0x0D, 0x11, 0xBB, 0x19, 0x46, + 0x51, 0x7A, 0xC0, 0x6A, 0x16, 0xE0, 0x14, 0x6C, 0x5D, 0xD2, + 0x2A, 0xE4, 0xE0, 0x85, 0x1A, 0x80, 0x1F, 0x43, 0xFA, 0xAE, + 0xD5, 0xC1, 0xDD, 0xC4, 0x0D, 0xD0, 0xB7, 0x9D, 0x0A, 0x5D, + 0xF1, 0x8B, 0xF9, 0x78, 0xBD, 0x64, 0xBE, 0x1B, 0xFE, 0x7C, + 0x79, 0xB6, 0x60, 0x35, 0xAF, 0xDC, 0x47, 0xFC, 0x8F, 0xA9, + 0xAA, 0xE6, 0x65, 0xD4, 0x9D, 0xDB, 0x20, 0xF6, 0x9F, 0x90, + 0x9A, 0xC3, 0x7B, 0xB0, 0x99, 0xE9, 0x00, 0xFD, 0x07, 0x9F, + 0x29, 0x01, 0x9C, 0x0E, 0xB7, 0xBF, 0xD2, 0xD6, 0x70, 0xC4, + 0xDE, 0xEE, 0xBA, 0xC5, 0x2C, 0xFF, 0xD8, 0x92, 0x13, 0x2A, + 0xAC, 0x51, 0xE8, 0xDE, 0x6E, 0xF1, 0x81, 0x8C, 0x48, 0xCF, + 0xC3, 0xDA, 0x26, 0x16, 0xE5, 0x6B, 0x16, 0x52, 0x52, 0x21, + 0x61, 0x71, 0x6C, 0x6B, 0xAE, 0x23, 0xFE, 0xB3, 0x78, 0x39, + 0xCA, 0xB0, 0x35, 0x0B, 0x82, 0x68, 0x96, 0x7E, 0x29, 0x02, + 0x5E, 0x7F, 0xE4, 0xB2, 0x21, 0x76, 0xD0, 0x98, 0xB0, 0x85, + 0x84, 0xC4, 0x60, 0x07, 0x1C, 0xB3, 0x67, 0x60, 0x7A, 0x75, + 0x14, 0x81, 0xDC, 0xC0, 0x4E, 0xE0, 0x1C, 0x26, 0xBC, 0xC7, + 0xD4, 0xCC, 0xF9, 0x61, 0xA0, 0x36, 0x67, 0x07, 0x9B, 0x4C, + 0xA0, 0xBD, 0x99, 0x66, 0x48, 0x04, 0x25, 0xEE, 0xB6, 0x51, + 0xB4, 0x0C, 0x5A, 0x48, 0x0E, 0xCA, 0x3D, 0xE7, 0x17, 0x4B, + 0xAE, 0x54, 0xCF, 0x6D, 0x0C, 0xAD, 0x83, 0x1F, 0xF4, 0x9F, + 0xC1, 0x8E, 0x7F, 0x00, 0x87, 0x2A, 0x81, 0x10, 0x15, 0x60, + 0x01, 0x1D, 0x34, 0xAA, 0x20, 0x3D, 0x91, 0xCA, 0xF8, 0xCD, + 0x42, 0x08, 0xEE, 0x61, 0xAE, 0x38, 0x90, 0x12, 0xDA, 0x3D, + 0xDD, 0x58, 0x49, 0x33, 0xDF, 0x2C, 0xD8, 0x7E, 0x40, 0xB0, + 0x8D, 0x1D, 0xC5, 0x9C, 0x4F, 0xE8, 0x77, 0xCE, 0xE3, 0x2A, + 0xF5, 0x85, 0x5F, 0x60, 0x41, 0x42, 0x1F, 0xF3, 0x15, 0x22, + 0xA1, 0xC2, 0xCE, 0x20, 0x3B, 0x88, 0x49, 0x07, 0x21, 0xB1, + 0x15, 0xE3, 0xFD, 0x8D, 0x65, 0xC0, 0xAC, 0xED, 0xB7, 0x00, + 0x69, 0xF0, 0x78, 0x79, 0x8F, 0x51, 0x1E, 0x99, 0x85, 0x9F, + 0x49, 0x18, 0x7C, 0xFE, 0x66, 0x13, 0xF2, 0x82, 0x33, 0x22, + 0xA2, 0x1D, 0x7E, 0x30, 0xB2, 0x2C, 0x5B, 0x86, 0x5E, 0x92, + 0xFB, 0xB0, 0x0E, 0xA9, 0xEF, 0xE3, 0x92, 0x53, 0x94, 0xE8, + 0x7E, 0x37, 0x54, 0xD5, 0xA5, 0x35, 0xAC, 0x3C, 0xA4, 0xAF, + 0x00, 0x87, 0xDF, 0xC6, 0xA9, 0xCE, 0xE0, 0x9F, 0x61, 0xCA, + 0x52, 0xB4, 0x8B, 0x38, 0xE8, 0x8A, 0x59, 0xBF, 0x31, 0x60, + 0xEE, 0xDD, 0xE3, 0x75, 0x47, 0x1B, 0xFA, 0x8F, 0xA1, 0x61, + 0x3F, 0x08, 0x2F, 0xAD, 0xB9, 0xAF, 0x12, 0x77, 0x5D, 0xF9, + 0xB4, 0x2C, 0xF4, 0x21, 0xA4, 0xD9, 0x84, 0x5D, 0xAD, 0xDF, + 0x76, 0x84, 0x8C, 0x01, 0xE8, 0x25, 0xB2, 0xC9, 0x27, 0xF6, + 0xF2, 0xB3, 0x43, 0xD9, 0x66, 0xF3, 0x61, 0xE6, 0x90, 0x23, + 0x1A, 0x90, 0x93, 0x6F, 0xAA, 0xA6, 0x63, 0xBC, 0x3A, 0x66, + 0x5D, 0x16, 0xCE, 0x78, 0x34, 0x85, 0x70, 0xC7, 0x22, 0x45, + 0xD2, 0xB9, 0x17, 0xB4, 0x37, 0x17, 0xE6, 0x47, 0x40, 0x9D, + 0xD6, 0x36, 0x4D, 0x61, 0xCC, 0xF7, 0xB4, 0x20, 0x6F, 0xB9, + 0x2E, 0x0D, 0xC8, 0xA8, 0x90, 0x2E, 0x5E, 0x6A, 0xD4, 0x29, + 0xFC, 0x14, 0x52, 0xA7, 0xFD, 0x61, 0x91, 0xDC, 0x64, 0xBB, + 0xC9, 0xD4, 0x6B, 0x27, 0x4B, 0x07, 0x36, 0xFB, 0x3E, 0x99, + 0x94, 0x71, 0x51, 0x24, 0x2A, 0x14, 0xA3, 0xFE, 0x53, 0xD9, + 0x17, 0x32, 0x0C, 0x02, 0xFC, 0x92, 0x43, 0xF1, 0xF3, 0xD3, + 0xF3, 0x1F, 0x6C, 0x6F, 0xCD, 0xCD, 0xBE, 0x93, 0x07, 0xA0, + 0x95, 0x2F, 0xCE, 0xD6, 0x7C, 0x1C, 0x13, 0xBA, 0xDE, 0xFD, + 0xA5, 0x20, 0xC1, 0x72, 0x25, 0x18, 0xC7, 0x60, 0x19, 0xFE, + 0x1B, 0x64, 0xFD, 0x6F, 0xF9, 0xFB, 0x1E, 0xFB, 0x15, 0xDC, + 0x80, 0x8F, 0xE6, 0x2D, 0xFE, 0x38, 0x61, 0xA6, 0x1F, 0xCF, + 0x78, 0x6E, 0x87, 0x74, 0xBA, 0x45, 0x54, 0x43, 0xF4, 0xF5, + 0xFA, 0x15, 0x4C, 0x96, 0xFE, 0x2E, 0xEE, 0x6A, 0xED, 0x4C, + 0x93, 0xA7, 0xC9, 0x90, 0x97, 0x65, 0xEC, 0x80, 0x58, 0x18, + 0xA2, 0xC5, 0x01, 0x65, 0x33, 0x54, 0x28, 0x73, 0xA4, 0x02, + 0x7A, 0x7C, 0xCB, 0xAC, 0xB9, 0x26, 0x0B, 0x1A, 0xFB, 0x4F, + 0x3E, 0x1C, 0x3D, 0x59, 0x63, 0x73, 0xFA, 0xA6, 0x34, 0xE5, + 0x83, 0x6D, 0x1E, 0x3D, 0x0B, 0xFA, 0x3F, 0x85, 0x7B, 0xDC, + 0x7D, 0xF3, 0xEF, 0x45, 0x0F, 0xD6, 0xC7, 0x36, 0x20, 0x07, + 0x12, 0x8F, 0xF7, 0x52, 0x32, 0x73, 0xB3, 0x00, 0x40, 0xEF, + 0x46, 0xFB, 0xC4, 0x6B, 0x08, 0x6C, 0x61, 0x72, 0xA0, 0x0E, + 0x37, 0x78, 0xA0, 0x44, 0x06, 0xF7, 0x07, 0xDE, 0xBA, 0x76, + 0x66, 0x28, 0x48, 0x47, 0x31, 0x4C, 0xDE, 0xE7, 0xB4, 0xE8, + 0x86, 0x06, 0x0A, 0x23, 0x8A, 0x00, 0xA7, 0x57, 0x0E, 0x2B, + 0x05, 0x57, 0x47, 0xE5, 0x0F, 0xB7, 0xCD, 0x0B, 0x5F, 0xFB, + 0x04, 0x97, 0x6F, 0x51, 0x99, 0x60, 0x5C, 0x74, 0x53, 0xE0, + 0xFB, 0x85, 0x6C, 0x5D, 0x82, 0x14, 0xD3, 0xAE, 0x7A, 0x31, + 0x2E, 0x0D, 0xF4, 0xD1, 0x09, 0x9F, 0xE8, 0xE3, 0x9B, 0x3E, + 0x8C, 0x1A, 0xCB, 0xCA, 0x06, 0x8D, 0xD3, 0x90, 0x6E, 0x13, + 0xBA, 0x01, 0xCB, 0xD2, 0xCB, 0xEA, 0x57, 0xDD, 0xCD, 0x59, + 0x2E, 0x05, 0x71, 0xFF, 0x6B, 0x34, 0x07, 0x65, 0x74, 0xA0, + 0xAD, 0x39, 0x4D, 0x11, 0xEB, 0x08, 0x43, 0x69, 0x6A, 0x2E, + 0x50, 0x8F, 0x5B, 0x14, 0x84, 0x9E, 0xB3, 0x99, 0xEF, 0x66, + 0xFA, 0x4C, 0xFB, 0x9B, 0x0E, 0xE8, 0xBA, 0x25, 0x87, 0xB6, + 0x89, 0x37, 0x00, 0x10, 0xD2, 0xB2, 0x0E, 0x06, 0x3C, 0x08, + 0x44, 0x65, 0x4A, 0x78, 0x46, 0x58, 0x27, 0x58, 0x75, 0x75, + 0x84, 0x62, 0xB5, 0xB3, 0x8E, 0x73, 0xDF, 0x3D, 0xCC, 0x5B, + 0xC4, 0x25, 0xF0, 0xF5, 0x3A, 0x09, 0x27, 0xD5, 0x0A, 0x75, + 0x5D, 0x9B, 0xFB, 0x32, 0x1C, 0xA2, 0x2A, 0x20, 0x94, 0x14, + 0xD2, 0x2B, 0x1F, 0xBD, 0xF7, 0x8F, 0x2A, 0x94, 0x6C, 0x4A, + 0x7F, 0x35, 0xEE, 0xFE, 0xAC, 0x1D, 0x95, 0x66, 0xC7, 0xB2, + 0x49, 0xD5, 0x9D, 0xB5, 0x80, 0xEB, 0xE4, 0x07, 0xEE, 0x9E, + 0x76, 0xAA, 0xA4, 0x3B, 0x14, 0x55, 0x0A, 0x70, 0x91, 0x56, + 0x5D, 0xC1, 0x53, 0xA2, 0x01, 0xE7, 0xA9, 0xD4, 0xFF, 0x7E, + 0x42, 0x88, 0x6D, 0x8C, 0xDB, 0x60, 0x31, 0xA1, 0x98, 0x80, + 0xEF, 0x0E, 0x37, 0x81, 0x5B, 0x19, 0xE0, 0xF6, 0x21, 0x19, + 0xE4, 0xFA, 0xD3, 0x37, 0xDF, 0x8B, 0xB1, 0x05, 0x86, 0xCB, + 0xD8, 0xBC, 0x4F, 0x66, 0xEC, 0xA8, 0x2E, 0xC1, 0x63, 0x46, + 0xF0, 0x1E, 0x08, 0x88, 0x2A, 0xF8, 0x48, 0x39, 0x68, 0x39, + 0xE5, 0x61, 0xF6, 0x99, 0x08, 0xD5, 0x7A, 0xE8, 0x46, 0x79, + 0x7B, 0x69, 0x02, 0x19, 0x88, 0xE6, 0xEE, 0x78, 0xD9, 0x56, + 0xCC, 0x12, 0x23, 0x04, 0x78, 0x32, 0x91, 0xC3, 0x64, 0x42, + 0x52, 0x2D, 0x3C, 0x85, 0x4F, 0x70, 0xF7, 0xAE, 0x8A, 0x4C, + 0xBB, 0xB9, 0x0B, 0x2B, 0x23, 0x12, 0xBF, 0xB8, 0xAD, 0x59, + 0xBC, 0xCF, 0xE8, 0xD9, 0x33, 0xD2, 0xDD, 0x3F, 0x2A, 0x82, + 0x41, 0xB7, 0x24, 0x03, 0xA1, 0xF9, 0x23, 0xD7, 0x06, 0x7B, + 0x4E, 0x8A, 0x02, 0xD9, 0xEE, 0x89, 0x4C, 0xB7, 0xF9, 0xAF, + 0x8C, 0x91, 0x64, 0x9E, 0xCD, 0x54, 0x43, 0xE7, 0xE4, 0x09, + 0x5A, 0xA9, 0x9F, 0x5D, 0xDD, 0x2E, 0xB7, 0xAA, 0x94, 0x79, + 0xC6, 0x7B, 0x05, 0x7B, 0xD9, 0xE0, 0xCC, 0x18, 0x72, 0x0C, + 0x8A, 0x7C, 0xCD, 0xC0, 0x3E, 0x0C, 0xC6, 0xAC, 0x2F, 0xBA, + 0xC7, 0x13, 0xAB, 0xDB, 0x76, 0xCF, 0x82, 0x93, 0x16, 0x34, + 0x7E, 0x02, 0x4A, 0xA3, 0xD9, 0xED, 0x14, 0x15, 0x32, 0xA7, + 0xD9, 0x44, 0xCC, 0x1C, 0xB3, 0xF5, 0xEB, 0x5E, 0xE8, 0x08, + 0x8A, 0x2C, 0xB6, 0x3F, 0x96, 0xF3, 0xFF, 0xE0, 0xD6, 0x12, + 0x4D, 0x72, 0xD8, 0x1C, 0x8F, 0x5D, 0x95, 0x5D, 0x83, 0x52, + 0x41, 0xAB, 0xF1, 0x74, 0xA5, 0xC9, 0xD7, 0x17, 0x7C, 0x07, + 0x14, 0x5A, 0x36, 0xE1, 0xB6, 0x81, 0xA1, 0xC8, 0x0C, 0xD4, + 0x7A, 0x25, 0x68, 0xB4, 0x78, 0x94, 0x23, 0xE7, 0x44, 0x8F, + 0x8A, 0x26, 0xE7, 0x0F, 0xB8, 0xB0, 0x78, 0xA9, 0x5A, 0x4C, + 0x18, 0x15, 0xFC, 0xE8, 0x8C, 0x48, 0x39, 0x1C, 0x7B, 0xDA, + 0xE8, 0x55, 0x08, 0x07, 0x36, 0x71, 0x39, 0x25, 0xEA, 0xBB, + 0x1B, 0x6F, 0x52, 0xC7, 0xB2, 0xCD, 0x47, 0xAB, 0xF1, 0x95, + 0x59, 0x51, 0x3A, 0x90, 0x16, 0x6F, 0x31, 0x48, 0x7F, 0x0D, + 0x5F, 0x78, 0x60, 0x9D, 0x92, 0xE7, 0x6C, 0xBE, 0x66, 0x2F, + 0xFB, 0x24, 0xF8, 0xAE, 0xBC, 0x8D, 0x1B, 0x54, 0xF5, 0xF3, + 0x2E, 0x67, 0x15, 0x1D, 0x08, 0x3B, 0x38, 0xB0, 0x43, 0x71, + 0xEF, 0xB4, 0xE6, 0x44, 0x0F, 0x0A, 0xA0, 0xAD, 0x42, 0xCD, + 0xC0, 0xB3, 0x84, 0x71, 0x1D, 0xD3, 0x51, 0xE2, 0x27, 0xD3, + 0x32, 0x1B, 0x74, 0x22, 0x32, 0xF9, 0x37, 0x0B, 0x1E, 0xBF, + 0xF5, 0x0B, 0xA6, 0x65, 0x00, 0x1E, 0xDE, 0x79, 0x0A, 0x9E, + 0x3D, 0xB4, 0x0D, 0x05, 0x70, 0xE9, 0x11, 0x95, 0xF9, 0x72, + 0x29, 0x71, 0x78, 0xD9, 0x32, 0x17, 0xE9, 0xBE, 0x1B, 0x4C, + 0xB8, 0xA0, 0x67, 0xFD, 0x13, 0x5E, 0xB8, 0x1E, 0x81, 0x54, + 0xD2, 0x33, 0x6B, 0x69, 0x2A, 0x01, 0x0C, 0x6D, 0x84, 0xFA, + 0x50, 0xFA, 0xCF, 0x37, 0x5B, 0x8A, 0xA7, 0xF0, 0x4B, 0x33, + 0x55, 0x19, 0xF0, 0x1A, 0x0D, 0x65, 0xC5, 0xC8, 0x40, 0x0D, + 0x39, 0x28, 0x0F, 0x55, 0x65, 0x49, 0x3C, 0xAD, 0xC0, 0xA6, + 0xBA, 0x64, 0xFA, 0x66, 0x63, 0xC1, 0x38, 0x3F, 0x94, 0x9C, + 0x71, 0x4F, 0x67, 0xCC, 0xC1, 0x03, 0xC3, 0xA1, 0x8B, 0xEF, + 0xA8, 0x6D, 0x70, 0x3F, 0x62, 0xF5, 0xE7, 0xF9, 0xC7, 0x90, + 0xE5, 0xBB, 0xD8, 0x87, 0xE5, 0x7D, 0xB2, 0x4A, 0xEB, 0x47, + 0x32, 0x74, 0x6E, 0xC2, 0x40, 0x1B, 0x18, 0x3F, 0x58, 0x05, + 0xC9, 0x83, 0x60, 0x93, 0x6C, 0x9F, 0xD1, 0x51, 0xD0, 0x07, + 0x3F, 0xA7, 0x0E, 0x4C, 0x2B, 0x7C, 0x04, 0x7C, 0x8C, 0xC3, + 0xE0, 0xF6, 0x40, 0x56, 0x0C, 0x0B, 0xAA, 0x58, 0x05, 0x11, + 0x48, 0xD8, 0xD0, 0xE7, 0xC6, 0xCC, 0xDB, 0x83, 0xC4, 0xA4, + 0x3C, 0xA2, 0xDD, 0xBE, 0xA8, 0x2A, 0xC4, 0xA0, 0x4C, 0x92, + 0xA7, 0x1B, 0xF4, 0xEF, 0xE5, 0x33, 0x8A, 0x49, 0xCA, 0x1A, + 0xDF, 0x82, 0xE6, 0x4D, 0x89, 0xD9, 0x52, 0xE2, 0x8F, 0xB0, + 0x9E, 0x80, 0xC9, 0x88, 0xB9, 0x67, 0x23, 0x90, 0xD6, 0xA6, + 0x8F, 0xF8, 0x0B, 0x4E, 0x53, 0x41, 0x85, 0x7D, 0xC3, 0x08, + 0x6B, 0xB7, 0xEF, 0xFE, 0x3F, 0x57, 0x6D, 0xCA, 0x1D, 0x58, + 0xE0, 0x9C, 0xA7, 0xDE, 0x95, 0x1C, 0x73, 0xDF, 0x5A, 0xF1, + 0xB6, 0x87, 0x7A, 0x7D, 0x2C, 0xE6, 0x3B, 0x12, 0xF4, 0x44, + 0xFD, 0xEF, 0x22, 0xC7, 0x98, 0xE1, 0x30, 0x8B, 0x58, 0x80, + 0x12, 0x47, 0xC1, 0x56, 0x8D, 0x0B, 0x2E, 0x5C, 0x3A, 0x2D, + 0xCD, 0xBC, 0x1D, 0xAF, 0x8F, 0x6C, 0x71, 0x56, 0x25, 0xA2, + 0x25, 0x2E, 0xC8, 0x11, 0x46, 0x64, 0x32, 0xEC, 0x29, 0xC6, + 0x3C, 0x63, 0x14, 0x35, 0x9D, 0xCB, 0xC9, 0x51, 0x83, 0x4F, + 0xE9, 0x6F, 0x58, 0x45, 0x12, 0xAB, 0xB1, 0xF6, 0x44, 0x14, + 0xBC, 0x5C, 0x02, 0xF8, 0x2B, 0xAD, 0xB7, 0xFD, 0x66, 0x02, + 0xDA, 0x62, 0xED, 0x95, 0x7A, 0x87, 0xB5, 0x36, 0xC2, 0xE7, + 0xFA, 0x5D, 0x02, 0x12, 0x5B, 0xD0, 0xC8, 0x98, 0x6C, 0x48, + 0xF2, 0x82, 0x57, 0x65, 0xCB, 0xBB, 0x08, 0x3B, 0x8D, 0x34, + 0xB4, 0x76, 0xA4, 0xA2, 0x70, 0xA2, 0x83, 0xFA, 0xBB, 0x08, + 0x22, 0x6E, 0x67, 0x81, 0x22, 0x83, 0x61, 0x23, 0x40, 0xB2, + 0x3B, 0xD2, 0x50, 0xDB, 0xC7, 0x8A, 0x65, 0x1F, 0xE0, 0x44, + 0x18, 0xD9, 0xF7, 0x62, 0x9C, 0x45, 0xAA, 0x0C, 0x97, 0x4B, + 0x29, 0x24, 0x0D, 0x82, 0x22, 0x55, 0xF8, 0xE3, 0xED, 0x38, + 0x8F, 0x14, 0x8B, 0x16, 0xA8, 0x12, 0x1A, 0xDB, 0x5E, 0xD8, + 0x3C, 0x77, 0xF6, 0x61, 0x82, 0x9B, 0x8C, 0xA1, 0xD4, 0xF7, + 0xC7, 0xE3, 0x9E, 0x62, 0x81, 0x86, 0x8B, 0xFD, 0x4B, 0xF4, + 0x05, 0xCA, 0xDF, 0x24, 0xD1, 0x56, 0xBF, 0x2A, 0x3C, 0xFC, + 0xB8, 0x34, 0x23, 0x5B, 0xE1, 0xE8, 0x8A, 0xAD, 0xBB, 0x58, + 0x6D, 0xA2, 0xCB, 0x5B, 0xC4, 0x7F, 0xEA, 0x8B, 0xC0, 0x98, + 0x0C, 0xCB, 0x07, 0x68, 0x37, 0x89, 0xD5, 0x41, 0x89, 0x47, + 0xD7, 0xDC, 0x38, 0x86, 0x68, 0xF5, 0x0F, 0x28, 0x25, 0x68, + 0xEF, 0x0D, 0xE7, 0x7B, 0x9F, 0x92, 0x7E, 0x49, 0x93, 0x16, + 0xF2, 0xE2, 0x60, 0x55, 0x4B, 0x11, 0x37, 0x23, 0xD5, 0x60, + 0xFD, 0x41, 0x9E, 0x97, 0xAE, 0xAF, 0x9E, 0x7F, 0x37, 0xF6, + 0xEE, 0xDF, 0x5E, 0xC6, 0xC2, 0xEE, 0x9D, 0x5E, 0xB3, 0x2E, + 0xC1, 0xEF, 0xB4, 0x41, 0x8C, 0x95, 0x65, 0x09, 0x46, 0x3D, + 0xFE, 0xDF, 0xC5, 0x09, 0xCB, 0xA5, 0xCF, 0x33, 0x6A, 0xD9, + 0x26, 0x5B, 0x35, 0xB3, 0x2A, 0x36, 0xF5, 0x74, 0xBE, 0x99, + 0xE7, 0xC1, 0xE0, 0x10, 0xC4, 0x69, 0x9A, 0xBD, 0x90, 0x3C, + 0x27, 0x2D, 0x3E, 0xD3, 0x8A, 0x30, 0x32, 0x9B, 0x82, 0xAE, + 0x9E, 0x3A, 0x92, 0x1D, 0xA2, 0xD4, 0xF2, 0x16, 0x11, 0xD0, + 0xA4, 0xF8, 0x57, 0x05, 0x29, 0x8F, 0x7D, 0xBE, 0xBF, 0x33, + 0xCF, 0x67, 0x6E, 0x26, 0x87, 0xA7, 0x87, 0x2A, 0xE8, 0x4E, + 0x2A, 0xBD, 0xB5, 0xC6, 0x89, 0x26, 0x32, 0x7C, 0xD2, 0xFD, + 0xE3, 0xAD, 0xB4, 0xE5, 0xFB, 0x4F, 0xFD, 0xED, 0x19, 0x35, + 0xDD, 0x1A, 0x70, 0x77, 0x5F, 0xC3, 0x32, 0xBE, 0xC3, 0xFA, + 0xC1, 0xA9, 0x02, 0x33, 0x91, 0xBE, 0x6A, 0x91, 0x77, 0x0D, + 0x79, 0x99, 0xB6, 0x9F, 0xA6, 0xE3, 0x96, 0x12, 0x7B, 0x60, + 0x35, 0xE8, 0xF4, 0x94, 0x1E, 0x87, 0x89, 0x66, 0xDE, 0x21, + 0xB2, 0x88, 0x70, 0xEB, 0x72, 0x03, 0x27, 0xE2, 0x53, 0xE6, + 0xDE, 0xE0, 0xEE, 0x32, 0xC3, 0x98, 0x39, 0x1A, 0x72, 0x5D, + 0xE4, 0x88, 0x9F, 0x2D, 0x0D, 0x4E, 0x97, 0xE2, 0x91, 0x9E, + 0x7F, 0xBE, 0xC2, 0x5B, 0x42, 0x63, 0x10, 0x95, 0x93, 0x21, + 0x1B, 0x12, 0xCE, 0x29, 0xA7, 0xE2, 0xC5, 0x81, 0x4B, 0x32, + 0xEF, 0xDA, 0x6C, 0x51, 0x11, 0xF6, 0x99, 0x63, 0xC8, 0xC7, + 0xD9, 0x4E, 0x36, 0xA0, 0xC3, 0xC8, 0xB6, 0x32, 0x61, 0x85, + 0xEA, 0x4B, 0x89, 0x49, 0xA8, 0xBF, 0xC7, 0x36, 0x90, 0x02, + 0xCC, 0x8A, 0xA0, 0x91, 0x2C, 0x04, 0x22, 0xBF, 0x48, 0xB6, + 0xB7, 0x5D, 0x35, 0x47, 0x29, 0x2F, 0x05, 0x6A, 0x0E, 0xD4, + 0x6B, 0x7E, 0x5C, 0x88, 0xEE, 0x36, 0xC5, 0x48, 0x55, 0xD3, + 0xD0, 0x64, 0x94, 0xDE, 0x9F, 0xC0, 0x24, 0x6F, 0xA6, 0x47, + 0x34, 0x1F, 0xAE, 0x1A, 0x5D, 0x7C, 0xA5, 0xE7, 0xFE, 0xBA, + 0xA1, 0x6B, 0xDD, 0x23, 0x77, 0x39, 0xF5, 0x6C, 0x05, 0x38, + 0x7F, 0x3C, 0xFC, 0xC5, 0xAC, 0x79, 0x4F, 0xEB, 0xB1, 0x01, + 0xCD, 0xFD, 0x46, 0x8E, 0x0E, 0x28, 0x82, 0xEB, 0x00, 0x95, + 0xC2, 0xD7, 0x01, 0xD9, 0xBB, 0x6C, 0xE9, 0xB1, 0x90, 0xF4, + 0x14, 0xB0, 0x1C, 0x16, 0x4C, 0xAD, 0x0F, 0x53, 0x00, 0x36, + 0x6E, 0x00, 0xBA, 0xB9, 0xDE, 0xFA, 0x73, 0x77, 0x47, 0xAA, + 0xB5, 0x34, 0xD7, 0x0D, 0x46, 0xB7, 0x60, 0x73, 0xA9, 0x8A, + 0x21, 0xB4, 0x2D, 0x21, 0x83, 0xDE, 0xE7, 0xA3, 0x07, 0xCC, + 0x45, 0x86, 0x75, 0x0B, 0xDB, 0x42, 0x01, 0x9B, 0x82, 0x78, + 0x06, 0x02, 0x74, 0xA2, 0x16, 0x6E, 0xDF, 0xBE, 0x41, 0xD6, + 0x14, 0x49, 0xC3, 0x59, 0x0B, 0xDE, 0x58, 0xB3, 0x63, 0x1F, + 0x5E, 0x42, 0x4F, 0x4A, 0xCC, 0xAB, 0xB8, 0x65, 0xF5, 0x52, + 0xE4, 0x6F, 0xF3, 0x22, 0x70, 0xF6, 0x69, 0x5D, 0xF0, 0x5C, + 0xF3, 0x90, 0x0D, 0x8B, 0x00, 0x32, 0xAD, 0x72, 0x1C, 0xFD, + 0x64, 0xC9, 0x84, 0xD8, 0xCF, 0xCE, 0x69, 0xEF, 0x47, 0xD8, + 0x14, 0xE7, 0x35, 0x5A, 0xE9, 0x45, 0x07, 0xDD, 0x22, 0x57, + 0xC8, 0x25, 0x0D, 0x13, 0x67, 0xDC, 0x87, 0xFA, 0x2F, 0x04, + 0xD9, 0x60, 0xBD, 0x03, 0xFC, 0x43, 0x03, 0x25, 0x9F, 0x7E, + 0x6D, 0xB0, 0x25, 0x32, 0xC3, 0x59, 0x06, 0x46, 0xF3, 0xCA, + 0x86, 0xB5, 0x6B, 0x7A, 0xCA, 0x5E, 0x98, 0xC8, 0x88, 0x2B, + 0xD5, 0xC4, 0x3A, 0x3B, 0xE5, 0xEF, 0x45, 0x7C, 0xB5, 0xAC, + 0x1E, 0x2D, 0x22, 0xB1, 0x07, 0xE3, 0x41, 0x6F, 0x9C, 0x2D, + 0x03, 0xD2, 0x48, 0x0F, 0x13, 0xF8, 0xAD, 0xBB, 0x34, 0x0B, + 0xD1, 0x3B, 0x61, 0x41, 0x16, 0x7F, 0x34, 0xD8, 0x09, 0xC2, + 0xD9, 0xAD, 0xA0, 0x9A, 0xEC, 0x11, 0x79, 0x50, 0xDE, 0x34, + 0x30, 0xCC, 0xC4, 0x62, 0x55, 0xF0, 0x66, 0x7E, 0x78, 0xCF, + 0xEB, 0x17, 0x01, 0x27, 0xBB, 0x07, 0x08, 0x03, 0x54, 0x42, + 0xD8, 0x87, 0xC4, 0xCA, 0xEA, 0x82, 0xF2, 0xC8, 0xFF, 0x64, + 0x40, 0xD0, 0x0B, 0x45, 0xF5, 0x79, 0x8A, 0x1B, 0xE1, 0x17, + 0x9F, 0x0C, 0xE1, 0xE6, 0xB8, 0xB7, 0xC5, 0x37, 0x96, 0x4F, + 0x09, 0x73, 0x44, 0xB0, 0x6B, 0xE5, 0xB4, 0x67, 0x17, 0x96, + 0xB3, 0x41, 0x92, 0x2E, 0xDF, 0xFD, 0xC9, 0x40, 0xB2, 0xE3, + 0x75, 0xAD, 0x8B, 0x78, 0xB2, 0x38, 0x29, 0x48, 0x0E, 0x11, + 0xA9, 0x23, 0x25, 0x82, 0x4B, 0xDD, 0x11, 0x1A, 0x29, 0x1E, + 0xCF, 0x57, 0xC9, 0xAC, 0x84, 0x8A, 0x45, 0xAD, 0x40, 0x4D, + 0xE9, 0x97, 0xFF, 0xE9, 0x6B, 0x10, 0x7F, 0x51, 0x40, 0xE6, + 0xC7, 0xEB, 0x58, 0x22, 0xA2, 0x51, 0xDF, 0xB2, 0xB6, 0x46, + 0xEA, 0x2E, 0x71, 0xA2, 0x85, 0xD4, 0xFC, 0x0E, 0x9F, 0xD4, + 0x34, 0x0B, 0x62, 0x90, 0x24, 0xD0, 0xDD, 0xFE, 0x9D, 0xC9, + 0x97, 0x59, 0x28, 0xA7, 0x2D, 0x5B, 0x67, 0xBF, 0x26, 0x10, + 0x3E, 0xA5, 0xFF, 0x04, 0x5C, 0xBF, 0x75, 0x35, 0x3A, 0x80, + 0x7E, 0xE0, 0x25, 0x4E, 0x30, 0xFB, 0x16, 0xFD, 0x45, 0xA8, + 0xBC, 0x79, 0xF1, 0x10, 0xD4, 0xCF, 0x3B, 0x39, 0x20, 0x1E, + 0xF5, 0x26, 0x22, 0x83, 0xC8, 0x70, 0x95, 0xCC, 0x58, 0x78, + 0xF2, 0x7D, 0x04, 0x29, 0xD8, 0x79, 0x78, 0xC9, 0x12, 0x70, + 0xE2, 0xD2, 0xE5, 0x5A, 0x8B, 0x64, 0x0D, 0x7E, 0xD5, 0x56, + 0x37, 0x87, 0x2C, 0x7F, 0x62, 0x1B, 0xCE, 0x58, 0xBD, 0xF9, + 0x4D, 0x1E, 0xA3, 0xA3, 0x6E, 0x58, 0x84, 0x18, 0x56, 0xF8, + 0x5F, 0xEC, 0xE3, 0xAF, 0xA1, 0xA7, 0x87, 0xD8, 0xEE, 0xE8, + 0x6E, 0x5E, 0x4F, 0x73, 0x7E, 0xF8, 0xC8, 0x73, 0xF0, 0x1C, + 0x17, 0xC0, 0x63, 0x4B, 0x15, 0x43, 0xD4, 0x32, 0xD2, 0xFE, + 0xBE, 0x44, 0x61, 0x4F, 0xB0, 0x01, 0x8D, 0x81, 0x60, 0x3B, + 0xD4, 0xBA, 0x55, 0x3A, 0x5A, 0x0C, 0xEE, 0x14, 0xCC, 0xBB, + 0xC7, 0x14, 0x7E, 0x88, 0x6E, 0x0F, 0x2C, 0x43, 0xDE, 0x9D, + 0x3F, 0xAD, 0x3E, 0x85, 0x9E, 0x12, 0xD1, 0x05, 0x9B, 0xA5, + 0x85, 0x42, 0x46, 0xB0, 0xE4, 0x44, 0x80, 0x0D, 0x11, 0xA8, + 0xD4, 0xCE, 0xEF, 0xDC, 0x2D, 0xFF, 0x8C, 0x02, 0x91, 0x2A, + 0xD8, 0x33, 0xB9, 0x6D, 0x25, 0x40, 0x8E, 0x17, 0xCD, 0x72, + 0x1A, 0x05, 0xBB, 0x2E, 0xEB, 0x0D, 0x46, 0x30, 0x58, 0x79, + 0x3B, 0xE7, 0x63, 0x17, 0xE0, 0xDE, 0x24, 0xC1, 0xF1, 0xB7, + 0xB8, 0xAC, 0x13, 0xF8, 0x27, 0xA0, 0x1E, 0x99, 0x06, 0x02, + 0x34, 0x03, 0xFD, 0x84, 0xA7, 0x18, 0x4D, 0x56, 0xD8, 0xDB, + 0x16, 0x55, 0xD3, 0xEF, 0x6F, 0xF3, 0x79, 0x5E, 0xAF, 0x9E, + 0x3A, 0x42, 0x36, 0x2A, 0x8B, 0x77, 0xAA, 0x65, 0xA5, 0x1D, + 0x30, 0x39, 0x4A, 0x2E, 0x7E, 0xC4, 0x25, 0xB3, 0x8E, 0xCC, + 0xCE, 0x5B, 0xC2, 0xB5, 0xED, 0x91, 0x97, 0xC9, 0x9D, 0x04, + 0x76, 0x66, 0x97, 0x57, 0x7F, 0x3A, 0x92, 0x7B, 0xA9, 0xD1, + 0x47, 0x27, 0x29, 0xBB, 0x9C, 0xB1, 0x2E, 0x6B, 0x40, 0x22, + 0x7D, 0xEC, 0xFE, 0x1D, 0x98, 0xA0, 0x5E, 0x92, 0xC5, 0x7D, + 0x05, 0xD8, 0x7D, 0x15, 0x1D, 0x0B, 0x55, 0x16, 0xD7, 0xE7, + 0x2A, 0xE0, 0x23, 0x9C, 0x6E, 0x0C, 0xF0, 0x37, 0xB9, 0x21, + 0x4B, 0x48, 0x2C, 0x36, 0x60, 0x74, 0x5B, 0xC0, 0x1C, 0x6F, + 0x0D, 0x74, 0xBC, 0x55, 0xA7, 0x79, 0x68, 0xDB, 0x82, 0x1F, + 0xE0, 0xA0, 0x12, 0x6E, 0xA7, 0xB7, 0x97, 0x12, 0x2F, 0xA2, + 0xB4, 0x76, 0x60, 0x62, 0x89, 0x4A, 0xC6, 0x7A, 0x55, 0x49, + 0xFB, 0xAA, 0x4B, 0xEB, 0xAA, 0x4F, 0xB9, 0x9D, 0xD7, 0x54, + 0x6E, 0xC5, 0xFA, 0xFC, 0x22, 0xB4, 0xAD, 0x05, 0xC7, 0xB0, + 0xD6, 0x7C, 0xF4, 0xE5, 0x99, 0x84, 0x95, 0x3D, 0x91, 0x0D, + 0x06, 0x15, 0xE9, 0x08, 0xF8, 0x32, 0x75, 0xF7, 0x50, 0x0A, + 0x28, 0x5F, 0x22, 0x98, 0xE5, 0x85, 0xC7, 0xB0, 0xD3, 0xF8, + 0x68, 0xB4, 0x6A, 0xF8, 0x86, 0x6A, 0x47, 0xC5, 0x31, 0x6E, + 0xB0, 0x39, 0x7D, 0xF1, 0xE1, 0x56, 0xBA, 0xA3, 0x5A, 0x37, + 0xB6, 0x69, 0xF8, 0xF2, 0x64, 0x46, 0xDF, 0xFD, 0x89, 0x99, + 0xA7, 0x1A, 0x7A, 0x7E, 0x50, 0x7F, 0xAB, 0x8B, 0x27, 0xE5, + 0x81, 0x7B, 0xCA, 0x1D, 0x2D, 0xF4, 0x4A, 0x58, 0xC4, 0x8A, + 0x16, 0xBB, 0x9D, 0xBF, 0x5E, 0xF4, 0xC7, 0x79, 0xA7, 0x88, + 0x8F, 0x01, 0x93, 0xEA, 0x7F, 0x0F, 0x71, 0x01, 0xEF, 0xCD, + 0xDC, 0x81, 0x1F, 0x8B, 0x48, 0x99, 0xE0, 0x6A, 0x5F, 0xC2, + 0x62, 0x83, 0xAB, 0xE7, 0x99, 0x6E, 0x1C, 0x20, 0x77, 0xE2, + 0x88, 0xD3, 0x76, 0x62, 0x42, 0xF9, 0x2B, 0x94, 0xE7, 0x66, + 0x47, 0x41, 0x72, 0xA7, 0x2A, 0x7E, 0x53, 0x84, 0x92, 0x1B, + 0xE4, 0x41, 0x96, 0xA0, 0x0B, 0xFC, 0xD6, 0x0E, 0xED, 0x77, + 0x1E, 0x17, 0xEE, 0x06, 0x58, 0xCD, 0x7D, 0x70, 0x96, 0xFA, + 0x24, 0x59, 0x26, 0x38, 0x57, 0x08, 0xC8, 0x85, 0xBB, 0xB6, + 0x10, 0x9F, 0x71, 0xC5, 0x21, 0x6E, 0xA6, 0x99, 0x4A, 0x8B, + 0x93, 0x50, 0x1E, 0xA9, 0xAB, 0x35, 0x42, 0x58, 0xF9, 0xCF, + 0x4A, 0x5B, 0x6C, 0x7C, 0x03, 0x10, 0x99, 0xD7, 0x5E, 0xDE, + 0x48, 0xEB, 0xC6, 0x87, 0x4C, 0x6A, 0x2A, 0x07, 0x4C, 0xF1, + 0x4A, 0xE9, 0x6A, 0x06, 0x3D, 0x55, 0x22, 0xE1, 0x6B, 0x6E, + 0x7C, 0xB5, 0xBF, 0xCE, 0xCE, 0x4B, 0x03, 0xEF, 0x3C, 0x1F, + 0x67, 0xFE, 0x04, 0xBE, 0xAB, 0x77, 0x62, 0x04, 0xBB, 0x26, + 0x8F, 0xAA, 0xB0, 0xC0, 0x75, 0x83, 0xA7, 0xFC, 0x2C, 0xA8, + 0xDB, 0xBB, 0x8A, 0x8A, 0xA9, 0xC4, 0x4E, 0x29, 0x05, 0x3E, + 0x23, 0x15, 0xBC, 0x32, 0xCC, 0x4B, 0xE7, 0x7E, 0xBC, 0xBF, + 0xBA, 0x2E, 0x5F, 0xEB, 0x7A, 0x09, 0xF9, 0xDB, 0x40, 0xF8, + 0x93, 0xCE, 0x77, 0x52, 0x2D, 0xD4, 0xF1, 0x22, 0xCC, 0x55, + 0x31, 0xFB, 0x26, 0x51, 0x0A, 0x6C, 0x8A, 0xB6, 0xE1, 0xB7, + 0x83, 0x9C, 0x2E, 0x2E, 0x5F, 0xBF, 0xB2, 0x96, 0xDC, 0xD3, + 0xF1, 0xC6, 0xE2, 0x9A, 0xC1, 0xBF, 0x51, 0x6D, 0xCD, 0xC5, + 0xEA, 0x20, 0x96, 0x99, 0x87, 0x03, 0x8E, 0xFA, 0x9B, 0xC5, + 0xB3, 0xE6, 0x7A, 0xCE, 0xBC, 0x0D, 0x9F, 0x95, 0xC6, 0xE5, + 0x68, 0x0E, 0x68, 0xDC, 0x2B, 0x15, 0x35, 0xD4, 0x5A, 0x30, + 0x79, 0x77, 0xF5, 0x6C, 0x19, 0xC8, 0x4F, 0x03, 0xC8, 0xFC, + 0x31, 0x11, 0x51, 0x42, 0x86, 0x26, 0xE5, 0x43, 0x48, 0x3B, + 0x85, 0x4D, 0xD9, 0xF6, 0x25, 0xE5, 0x9F, 0xBA, 0x75, 0x7F, + 0xA9, 0x04, 0xA2, 0x60, 0x35, 0x00, 0xFE, 0xF4, 0x97, 0xBB, + 0x99, 0x11, 0x2B, 0xA6, 0x89, 0x3C, 0xCA, 0xB9, 0x44, 0x52, + 0x15, 0x1B, 0xCB, 0x2B, 0x73, 0x4A, 0x04, 0x3D, 0xF5, 0xCE, + 0x7F, 0x50, 0xB9, 0xAB, 0xF8, 0xE8, 0x2D, 0x9F, 0x6C, 0x55, + 0xFF, 0xA3, 0xBA, 0x1D, 0xE8, 0x14, 0x19, 0x4C, 0x17, 0xCB, + 0xCB, 0xA9, 0x8C, 0x41, 0xA4, 0x81, 0x03, 0xCE, 0x53, 0x45, + 0xC4, 0xDB, 0x25, 0xB0, 0x37, 0x4B, 0xC2, 0x8D, 0x52, 0x0B, + 0xCA, 0x57, 0x02, 0x91, 0x7A, 0x8D, 0x24, 0x10, 0xB4, 0x26, + 0xAF, 0x65, 0xA7, 0x65, 0x68, 0x86, 0xC5, 0x31, 0xC5, 0x2A, + 0xCF, 0x98, 0x78, 0x15, 0x0B, 0x91, 0x0B, 0xB3, 0x01, 0xCF, + 0xF0, 0xFB, 0x61, 0x7D, 0x3D, 0x81, 0xA6, 0x4A, 0x96, 0x5E, + 0x22, 0x7E, 0x66, 0x73, 0xCB, 0x7B, 0x5E, 0x2B, 0x47, 0x4D, + 0x06, 0x38, 0x40, 0xEE, 0x2E, 0x4B, 0xB0, 0x3B, 0xF5, 0xF7, + 0xF3, 0x42, 0x6D, 0x68, 0xF6, 0x0E, 0x11, 0x91, 0x5A, 0x97, + 0xEC, 0x93, 0x34, 0x50, 0x98, 0x80, 0xA5, 0xBA, 0x67, 0xAB, + 0x7E, 0xB7, 0xD3, 0xDD, 0xB7, 0xC3, 0xAE, 0x3D, 0x54, 0x28, + 0x60, 0x66, 0xD3, 0x3B, 0x32, 0xE6, 0xFA, 0x8D, 0xDB, 0x32, + 0xDB, 0xA1, 0xD3, 0x47, 0xFC, 0x37, 0x45, 0x3B, 0x16, 0x5C, + 0xCE, 0xF8, 0x4E, 0x8C, 0x8A, 0xED, 0x0A, 0x1E, 0xA7, 0x14, + 0x96, 0xC5, 0x37, 0x05, 0x1A, 0xB1, 0x02, 0x6D, 0xBF, 0xD2, + 0xC7, 0x2C, 0xEA, 0x24, 0x7B, 0x42, 0x87, 0x48, 0xA0, 0x62, + 0x8B, 0x1E, 0xB4, 0x50, 0x4B, 0xC3, 0xEC, 0x8D, 0xBD, 0x51, + 0x68, 0x1F, 0xE8, 0x74, 0x67, 0x86, 0xA6, 0x73, 0x88, 0xD8, + 0xBB, 0x9B, 0x5F, 0x3B, 0x96, 0x4C, 0xF6, 0x7C, 0x4D, 0x0F, + 0xD6, 0x31, 0xD4, 0x90, 0xD8, 0xB8, 0xFC, 0x4A, 0xAD, 0x04, + 0x3B, 0x32, 0x3A, 0x5C, 0xC7, 0xF3, 0x1C, 0x42, 0x0C, 0x74, + 0x52, 0xFB, 0x1D, 0xD2, 0x26, 0x5D, 0x17, 0x5A, 0xCE, 0x2A, + 0xE0, 0x4B, 0x6A, 0x7F, 0x74, 0x06, 0x27, 0x76, 0xE2, 0x95, + 0xD5, 0x32, 0x80, 0x5B, 0xC8, 0xA1, 0xE8, 0x88, 0x95, 0x05, + 0xD5, 0xE9, 0x69, 0xF9, 0x45, 0xAE, 0x5C, 0x75, 0x4E, 0x31, + 0x0F, 0x9E, 0xB5, 0xB4, 0x95, 0x72, 0xF3, 0x3F, 0xD2, 0xDE, + 0x6B, 0xD5, 0xF3, 0x4A, 0x9F, 0x0C, 0x49, 0x6F, 0x32, 0xC7, + 0x95, 0xA6, 0xBD, 0xD9, 0xB4, 0x63, 0x10, 0x24, 0xAA, 0xE4, + 0xD6, 0x4B, 0x92, 0x9D, 0x3E, 0xC3, 0xE9, 0x02, 0x0F, 0xB7, + 0xDE, 0xD5, 0x0E, 0x87, 0x74, 0x9A, 0xB4, 0x6B, 0x00, 0xD7, + 0x2D, 0x33, 0x29, 0x97, 0x17, 0xE3, 0x2C, 0xAF, 0xBC, 0x6D, + 0x8E, 0x6D, 0x4A, 0x20, 0xD8, 0x12, 0x0A, 0x94, 0x7D, 0x82, + 0x42, 0x53, 0x69, 0x73, 0xFE, 0x60, 0xA9, 0x4F, 0xFC, 0x3D, + 0x63, 0x7A, 0x10, 0x8A, 0x5C, 0xBF, 0x9B, 0x5A, 0xAF, 0xD7, + 0xA4, 0xAD, 0x05, 0x5F, 0x3E, 0x23, 0x20, 0xAE, 0xD9, 0xB7, + 0x23, 0x03, 0x85, 0xAE, 0xDA, 0x14, 0xB9, 0x93, 0x02, 0xDB, + 0x68, 0x6D, 0x17, 0xEB, 0xE3, 0x33, 0x55, 0xA3, 0xCA, 0xC0, + 0xBD, 0x6C, 0x60, 0x0C, 0x4B, 0x75, 0xB4, 0xA1, 0x26, 0xAA, + 0xA6, 0x92, 0x92, 0x4A, 0x87, 0xA5, 0x95, 0xF9, 0xEB, 0x37, + 0x32, 0x1D, 0xFA, 0xA1, 0x4A, 0xA4, 0x17, 0xD1, 0xE9, 0x7E, + 0x96, 0xA1, 0x65, 0xC5, 0x1E, 0x96, 0x75, 0xAD, 0x49, 0x97, + 0x8B, 0x1A, 0x63, 0xFB, 0x9F, 0xF9, 0xEE, 0xFB, 0xDD, 0xF7, + 0x0B, 0xDA, 0xAA, 0x77, 0x50, 0x4C, 0x39, 0x9B, 0x17, 0xAF, + 0xB0, 0xEE, 0x0B, 0x5E, 0x8A, 0xC5, 0xAB, 0x1E, 0xB1, 0x3F, + 0x55, 0x87, 0x31, 0x7F, 0xF8, 0x09, 0x1A, 0x06, 0x1A, 0x58, + 0x68, 0x9D, 0xDA, 0x88, 0x56, 0x30, 0x7C, 0x30, 0x14, 0x5C, + 0x3C, 0x85, 0x3C, 0xF5, 0x2A, 0x06, 0xD7, 0x03, 0x92, 0x29, + 0xDD, 0xFE, 0x17, 0xA2, 0x67, 0xAC, 0xFB, 0x10, 0xE5, 0x4E, + 0x5F, 0xCF, 0xD2, 0xA6, 0xE7, 0xDE, 0xB2, 0x13, 0x88, 0x8B, + 0xC4, 0xFA, 0x0E, 0x57, 0xE1, 0xF0, 0x87, 0xE8, 0x43, 0xAD, + 0x46, 0xA8, 0xBE, 0xB4, 0x36, 0xE7, 0x57, 0xF7, 0x74, 0x1E, + 0x67, 0x85, 0x06, 0xE4, 0x22, 0x12, 0x85, 0x0A, 0x94, 0xF8, + 0x54, 0x7A, 0xE9, 0x8E, 0x08, 0x38, 0x9F, 0xCE, 0x7C, 0x96, + 0x13, 0xFD, 0xD3, 0xB6, 0x69, 0xEF, 0x5E, 0xAF, 0xB9, 0x96, + 0xCB, 0x4D, 0xB1, 0xBB, 0x83, 0xB7, 0x57, 0x14, 0xCF, 0x39, + 0x64, 0xD4, 0x48, 0x13, 0xBF, 0x80, 0x5C, 0xC5, 0xA0, 0xEB, + 0xAD, 0x62, 0xBE, 0xBE, 0x92, 0x36, 0x7C, 0x5C, 0xFB, 0x30, + 0x77, 0xE7, 0xFA, 0x65, 0xBE, 0xC1, 0x47, 0x28, 0xF4, 0xBB, + 0xA1, 0x2D, 0x3B, 0x98, 0xDA, 0xB4, 0xBA, 0x6F, 0x1F, 0x43, + 0x3C, 0x49, 0x98, 0x6D, 0x73, 0xAB, 0x08, 0x3E, 0x20, 0xB8, + 0x18, 0xB7, 0xAE, 0xE9, 0xC2, 0x6D, 0xA0, 0xF5, 0xC9, 0x93, + 0x25, 0x9D, 0x7C, 0xBD, 0xDE, 0xEC, 0x4C, 0xC1, 0x58, 0xCA, + 0x53, 0x0D, 0xA4, 0x64, 0xC4, 0xC4, 0x45, 0xC5, 0xCE, 0xD7, + 0x02, 0x4D, 0xB6, 0x6C, 0x70, 0xFC, 0x9D, 0xCF, 0xCF, 0x25, + 0x9A, 0x4F, 0x1C, 0xFC, 0x0B, 0x6F, 0x0A, 0xF8, 0x85, 0x1C, + 0x21, 0x1D, 0xA9, 0x7E, 0xA4, 0xF7, 0xC4, 0xA1, 0xC8, 0x7B, + 0x2B, 0xBB, 0xCA, 0x6F, 0x8E, 0xD7, 0x79, 0x52, 0x63, 0x3D, + 0x32, 0xE4, 0x49, 0x81, 0x15, 0x70, 0xBD, 0xDD, 0x7F, 0x31, + 0x18, 0xDF, 0x89, 0xF3, 0x0C, 0x86, 0x03, 0xFC, 0x66, 0x78, + 0x36, 0x97, 0xDC, 0xD8, 0x3A, 0xAE, 0x18, 0xDC, 0x82, 0x4A, + 0xAC, 0x55, 0x2A, 0x0C, 0x84, 0x53, 0xD8, 0x27, 0x8C, 0x70, + 0x23, 0x38, 0x9E, 0x0F, 0x40, 0x9B, 0x7D, 0x0B, 0x4A, 0x21, + 0x57, 0xA6, 0x15, 0x07, 0xFD, 0x5F, 0x13, 0x8F, 0xBA, 0x09, + 0x19, 0x80, 0xFF, 0x28, 0xB9, 0xE5, 0x9B, 0x0A, 0x43, 0xD7, + 0x5C, 0xE3, 0xDB, 0x2F, 0x86, 0x49, 0x40, 0x81, 0xAB, 0xDC, + 0x21, 0x3E, 0xF2, 0x9C, 0xA6, 0xEE, 0xAB, 0xDF, 0xDA, 0xD3, + 0xDD, 0xFD, 0xA8, 0x97, 0x8A, 0x7B, 0xB0, 0xF3, 0x60, 0x67, + 0x62, 0xC2, 0xB6, 0xCA, 0x13, 0x31, 0x5B, 0x82, 0x62, 0x18, + 0x5A, 0x04, 0x56, 0x06, 0x86, 0x24, 0x9A, 0x58, 0x8C, 0xB2, + 0x3A, 0x00, 0xEA, 0x70, 0x56, 0x8D, 0x9C, 0xD5, 0x9F, 0x68, + 0x89, 0xED, 0x85, 0x81, 0x0E, 0xB1, 0x43, 0x04, 0x4D, 0x8B, + 0xDA, 0xB4, 0x33, 0x35, 0x45, 0x39, 0xB0, 0x9C, 0xF5, 0x82, + 0x07, 0x85, 0xA1, 0x6A, 0xC3, 0x1D, 0x34, 0x04, 0x2A, 0x46, + 0x46, 0x75, 0x1B, 0x44, 0xB5, 0x00, 0xCF, 0xD5, 0xB6, 0x4E, + 0xC1, 0xAF, 0xB0, 0xD2, 0x9F, 0xF8, 0xCB, 0x03, 0x17, 0x6F, + 0xD4, 0xB2, 0xFF, 0xFD, 0xB8, 0x0C, 0x64, 0xC9, 0xB2, 0x54, + 0x85, 0x8D, 0xD2, 0x1A, 0x01, 0xC5, 0x00, 0x32, 0x4D, 0xE8, + 0x97, 0xA5, 0x38, 0x61, 0x66, 0x93, 0x63, 0x87, 0xD6, 0xC4, + 0x0A, 0xCB, 0x8E, 0xA8, 0x36, 0x2D, 0x44, 0x06, 0xA1, 0x08, + 0x03, 0xF4, 0x79, 0xBF, 0x07, 0x08, 0x29, 0x07, 0x60, 0x92, + 0x60, 0x47, 0x0D, 0xA2, 0x6B, 0xAB, 0x55, 0xFC, 0x67, 0xF6, + 0xF1, 0x7C, 0x00, 0x51, 0x90, 0x5C, 0x28, 0x5B, 0x73, 0xAD, + 0x41, 0x15, 0x9A, 0x1C, 0xBE, 0xEB, 0xF7, 0xD8, 0x8C, 0x41, + 0x03, 0x60, 0x84, 0x99, 0x18, 0xF4, 0xEA, 0x3D, 0x95, 0x3A, + 0xFC, 0xD1, 0x24, 0xDF, 0xB2, 0xC6, 0x77, 0xB6, 0xF5, 0x79, + 0xC7, 0xA6, 0x75, 0xA0, 0x82, 0x11, 0x3E, 0x1C, 0x9C, 0x88, + 0x7F, 0x17, 0xFF, 0xBD, 0x6A, 0x56, 0x91, 0x10, 0x4C, 0xE2, + 0x3F, 0x7A, 0xA5, 0x11, 0xC2, 0xE1, 0x24, 0x5D, 0x39, 0x1A, + 0x6D, 0xDF, 0x88, 0xF6, 0xC5, 0x89, 0xF2, 0x4F, 0xC9, 0x6C, + 0x83, 0x7F, 0xFA, 0x54, 0xE3, 0x9E, 0x8C, 0x54, 0x86, 0xC7, + 0xA3, 0x7D, 0x11, 0x86, 0xA4, 0xFF, 0xBA, 0xE3, 0xDA, 0x94, + 0xA8, 0x0D, 0x2D, 0xE5, 0x1F, 0x0E, 0xE8, 0xC9, 0x32, 0x22, + 0xA5, 0x9C, 0x49, 0xB7, 0xBE, 0x35, 0xB7, 0xAB, 0x27, 0xE6, + 0x7D, 0x48, 0xE5, 0x2E, 0xC9, 0x9A, 0xED, 0xDE, 0x90, 0x5B, + 0xCC, 0x94, 0xCF, 0xF6, 0x62, 0x6C, 0x61, 0xFA, 0xF5, 0x27, + 0x22, 0x8B, 0x2C, 0x74, 0x50, 0xAD, 0x43, 0x3B, 0xA2, 0xA0, + 0xEE, 0x19, 0xF0, 0xBA, 0xCB, 0x02, 0x2C, 0xFF, 0x5C, 0x20, + 0x1F, 0xBA, 0x3B, 0xAA, 0x36, 0x01, 0x78, 0x18, 0xD0, 0xB7, + 0xBE, 0x2C, 0x3A, 0xEB, 0x6B, 0xE7, 0x09, 0xDE, 0x11, 0x93, + 0xD6, 0x3F, 0x99, 0xC4, 0x4D, 0xBF, 0x66, 0xDF, 0xC2, 0x34, + 0x63, 0xC7, 0x99, 0x18, 0x17, 0xC1, 0xDA, 0x7B, 0xBA, 0x60, + 0xD0, 0x48, 0x17, 0xE2, 0x1D, 0xC1, 0xA7, 0x6E, 0x25, 0x53, + 0x1B, 0xF1, 0x7D, 0xC4, 0x2F, 0xA5, 0x62, 0xF2, 0x84, 0x36, + 0x20, 0xF2, 0x4E, 0x7A, 0xF0, 0xDA, 0xAA, 0x59, 0x5E, 0xC7, + 0x39, 0x7F, 0x15, 0x11, 0xEF, 0x73, 0x4C, 0x45, 0x92, 0x80, + 0xE9, 0xE1, 0xF0, 0x8B, 0x40, 0x93, 0xDD, 0x0F, 0x48, 0x0E, + 0x0A, 0x8C, 0x0B, 0xE5, 0xAA, 0x84, 0x4A, 0x7C, 0xA8, 0xF6, + 0x8B, 0x6E, 0xCB, 0xBD, 0x82, 0x2C, 0x53, 0x92, 0x08, 0x98, + 0xC3, 0x45, 0x0D, 0xBE, 0x9C, 0x01, 0x95, 0x7E, 0x66, 0x9F, + 0x29, 0xD6, 0x58, 0xBD, 0x0C, 0x87, 0x9D, 0x77, 0x22, 0x53, + 0xAE, 0x9E, 0xEE, 0x5E, 0x4E, 0x85, 0xA1, 0x09, 0x49, 0xBD, + 0x53, 0x7B, 0x27, 0xF4, 0xE1, 0xA3, 0x0A, 0xEC, 0xA3, 0xA5, + 0x14, 0x57, 0x8B, 0x5E, 0xEC, 0x43, 0x40, 0x9D, 0x39, 0xA3, + 0x95, 0xCD, 0x44, 0x66, 0xED, 0x65, 0xD0, 0xA2, 0xC8, 0x59, + 0x59, 0x7A, 0x24, 0x95, 0x3A, 0x8B, 0x86, 0xB7, 0x8F, 0x81, + 0x4E, 0xA7, 0x66, 0x5D, 0x31, 0xCF, 0xBD, 0xD9, 0x58, 0x32, + 0x76, 0xC3, 0xFB, 0x8C, 0x80, 0x94, 0xC8, 0xAF, 0x04, 0x31, + 0x9C, 0xD6, 0x66, 0xE6, 0x71, 0x60, 0x45, 0xDB, 0x7E, 0x60, + 0xD1, 0xFF, 0x5C, 0x66, 0x31, 0x98, 0x23, 0x74, 0x16, 0x7A, + 0x1E, 0x70, 0x30, 0x07, 0x12, 0x8F, 0x25, 0xDF, 0x5B, 0x8A, + 0x3B, 0xA9, 0xDA, 0x56, 0xBE, 0xA1, 0x2E, 0xD3, 0xAC, 0x8F, + 0x19, 0xD6, 0x8A, 0x1E, 0x1E, 0x8A, 0xB4, 0xC0, 0xA9, 0x46, + 0x25, 0xBD, 0x80, 0xA3, 0xC0, 0xF3, 0x37, 0xC0, 0xC7, 0xC7, + 0xBF, 0x6D, 0x4B, 0xA7, 0x43, 0xD9, 0x57, 0x53, 0x0D, 0xA1, + 0x39, 0x36, 0xE8, 0xB9, 0xA5, 0x59, 0xF0, 0xC8, 0x4A, 0x87, + 0x26, 0xED, 0xEE, 0xB9, 0xE4, 0xFD, 0x67, 0x5D, 0x8B, 0xE4, + 0x03, 0x62, 0xD9, 0x5E, 0xD3, 0xB5, 0x30, 0xA2, 0x95, 0xCB, + 0xF5, 0xC8, 0xC4, 0x30, 0xCF, 0xCA, 0x8B, 0x76, 0x08, 0x47, + 0x07, 0x47, 0x70, 0x0D, 0x5A, 0x45, 0xA8, 0xBB, 0x39, 0xCE, + 0x31, 0xAC, 0x37, 0x6F, 0x0D, 0x2D, 0x22, 0x3A, 0x60, 0xC7, + 0x14, 0x9F, 0x44, 0xC4, 0xE3, 0x96, 0xA7, 0xB4, 0x9A, 0x03, + 0x13, 0xE7, 0x4D, 0x9C, 0xD4, 0x5C, 0xAD, 0xD5, 0x8B, 0xFD, + 0x25, 0x04, 0x4A, 0x92, 0x56, 0xE6, 0x2C, 0x7E, 0xE7, 0x1F, + 0xEA, 0x2E, 0x00, 0xC3, 0x0A, 0x9E, 0xEE, 0xA9, 0x30, 0x8E, + 0xA9, 0xAE, 0xC1, 0x5B, 0xBF, 0x5C, 0x2B, 0x07, 0x04, 0xAC, + 0x31, 0x12, 0x74, 0x55, 0x17, 0xB4, 0xC3, 0xE8, 0x33, 0x19, + 0x9A, 0x37, 0xB4, 0x42, 0xF9, 0xD2, 0x7D, 0x43, 0xD1, 0xE5, + 0x5E, 0x0A, 0xA0, 0x89, 0x49, 0xAB, 0xE2, 0x4C, 0xC7, 0x7B, + 0xEA, 0x0B, 0x64, 0xEA, 0xEE, 0x31, 0x96, 0x63, 0x41, 0xD7, + 0x33, 0xD3, 0x37, 0xF9, 0x15, 0x1D, 0x1A, 0x4E, 0xCB, 0x78, + 0xD6, 0x45, 0x7D, 0xCC, 0x0E, 0xE7, 0x7A, 0x66, 0xC7, 0x0C, + 0x46, 0x14, 0x75, 0x38, 0xC6, 0xCA, 0xF3, 0x4A, 0x6A, 0x56, + 0x6B, 0x98, 0xFB, 0xEA, 0xC2, 0x92, 0x40, 0xEB, 0x1A, 0xD6, + 0x5F, 0xCB, 0x09, 0x22, 0x8D, 0x31, 0x06, 0x0F, 0xB7, 0xFD, + 0x0B, 0xB7, 0xEA, 0x0E, 0x00, 0x8F, 0x7F, 0x66, 0xD0, 0x19, + 0xFF, 0x5A, 0x77, 0x08, 0x2E, 0x10, 0x89, 0x2B, 0x51, 0x37, + 0xEA, 0x70, 0xFB, 0x66, 0xF2, 0xF7, 0x93, 0x6D, 0xC8, 0x6F, + 0x1D, 0xC4, 0x8D, 0x5A, 0x94, 0x26, 0x5B, 0xC7, 0x0F, 0xF0, + 0x7E, 0x9E, 0x9D, 0xD2, 0x8A, 0x5C, 0x06, 0xBC, 0xA3, 0xD4, + 0x35, 0xA6, 0x9C, 0x5E, 0xC1, 0x34, 0xE9, 0x4E, 0xFA, 0x98, + 0xA8, 0x8C, 0xE2, 0x6A, 0x5C, 0xBB, 0xB8, 0xE3, 0xEB, 0x0E, + 0x9E, 0xF8, 0xCB, 0xD1, 0x82, 0x1C, 0xCF, 0x1D, 0x89, 0x24, + 0xE8, 0x5A, 0xEF, 0x61, 0x08, 0x72, 0x31, 0x42, 0x25, 0x97, + 0x58, 0x99, 0xF0, 0x75, 0x0D, 0xDE, 0xCD, 0x44, 0x43, 0xE8, + 0xEF, 0x00, 0xEE, 0x82, 0x79, 0xDF, 0x64, 0x6C, 0xEC, 0x76, + 0x3D, 0x58, 0xAE, 0x43, 0x2B, 0xD5, 0x63, 0xF1, 0xBA, 0x82, + 0xC3, 0xF4, 0x8D, 0x6D, 0x4E, 0xEB, 0xAD, 0xC5, 0x6D, 0x1A, + 0xF7, 0xC0, 0x50, 0x31, 0x62, 0x76, 0xCF, 0x08, 0x0B, 0xCC, + 0x13, 0xD7, 0xD2, 0xC9, 0x1F, 0x0A, 0xA2, 0x3F, 0xD7, 0x39, + 0x87, 0xF5, 0x33, 0x25, 0x2A, 0xED, 0x77, 0xA6, 0x65, 0x83, + 0x2F, 0x71, 0xBE, 0x46, 0xD3, 0x70, 0x24, 0x61, 0x25, 0xB6, + 0x4E, 0xDE, 0xBA, 0xF5, 0x8C, 0x2C, 0x05, 0xFA, 0x8F, 0x11, + 0x8C, 0x3F, 0x3C, 0x31, 0x64, 0xA3, 0xDC, 0x9B, 0x5A, 0x84, + 0xB8, 0x7F, 0x3D, 0x74, 0x7E, 0x5B, 0x05, 0x16, 0x47, 0xAD, + 0x92, 0x46, 0x81, 0xC9, 0x46, 0x86, 0x10, 0xAF, 0xA1, 0x87, + 0x9B, 0xA7, 0xC6, 0x15, 0x36, 0xD9, 0x4A, 0x7B, 0xA4, 0x5C, + 0xCC, 0x72, 0x61, 0x3F, 0xB9, 0xD6, 0x30, 0xCA, 0xA4, 0x48, + 0x31, 0xBA, 0xE1, 0x0B, 0xC3, 0xF0, 0x1A, 0x81, 0x4D, 0xBA, + 0x21, 0x87, 0x5C, 0xA5, 0x43, 0x6F, 0x03, 0x90, 0xA0, 0x84, + 0xB9, 0x8E, 0x13, 0xC1, 0xF3, 0xDC, 0x68, 0xA7, 0x47, 0xCA, + 0x09, 0x34, 0xE1, 0xB8, 0x12, 0x90, 0xEB, 0xFE, 0x3C, 0xF8, + 0xDA, 0x13, 0xEF, 0x53, 0x4A, 0xBD, 0x58, 0x19, 0x9B, 0xD5, + 0x1F, 0x78, 0x0C, 0xAD, 0xAA, 0x79, 0x91, 0xE6, 0x29, 0xED, + 0xDE, 0x16, 0x92, 0x89, 0x44, 0x23, 0xDD, 0xB5, 0xDB, 0xA5, + 0x8B, 0x16, 0x48, 0x58, 0x61, 0x5C, 0x90, 0xEA, 0xF1, 0x1B, + 0x67, 0x3C, 0x38, 0x37, 0xE4, 0xE2, 0x41, 0xC7, 0xD5, 0x10, + 0x68, 0x78, 0x8D, 0xCE, 0xAA, 0x5B, 0x9F, 0x78, 0x31, 0x79, + 0xE7, 0x32, 0xD6, 0x0E, 0x6F, 0xC4, 0x43, 0xBD, 0x9B, 0x20, + 0xC7, 0x06, 0x93, 0x7F, 0x89, 0x0F, 0x94, 0x29, 0x18, 0xD5, + 0x1B, 0x8C, 0xD5, 0xA8, 0x5C, 0x6C, 0xD4, 0x4C, 0xB2, 0x9D, + 0x6E, 0x8D, 0x90, 0x99, 0xF5, 0x8B, 0x86, 0x91, 0x5F, 0x31, + 0xDB, 0xD0, 0xA2, 0x85, 0xDB, 0xBF, 0x3E, 0x5F, 0x46, 0x87, + 0x4F, 0xF4, 0x75, 0xDA, 0x87, 0x0E, 0xBC, 0x26, 0x2E, 0xDD, + 0xDC, 0xEC, 0x46, 0x67, 0xC2, 0xAF, 0xA4, 0x37, 0x77, 0xBF, + 0x72, 0x47, 0xDD, 0x3D, 0x39, 0xA7, 0xD0, 0x8C, 0x19, 0xE3, + 0x80, 0x9D, 0x93, 0xC6, 0x29, 0xBD, 0xEA, 0xA6, 0x94, 0x9C, + 0x06, 0x39, 0x47, 0x62, 0x4B, 0x6D, 0x9E, 0xF2, 0x8B, 0x7E, + 0xC1, 0xA9, 0x9A, 0x96, 0x3F, 0x7D, 0x6D, 0xFC, 0xEE, 0x0D, + 0xAA, 0x23, 0x49, 0x82, 0xEA, 0xC1, 0x54, 0x2D, 0x7B, 0x80, + 0xFA, 0x47, 0x35, 0x65, 0x47, 0x5E, 0x25, 0x15, 0xCF, 0xC1, + 0x7E, 0x77, 0x45, 0x8C, 0xB2, 0x5C, 0x87, 0xA8, 0x16, 0x9D, + 0x71, 0x49, 0x2C, 0x6A, 0x2A, 0x62, 0xDC, 0x4D, 0xAF, 0x74, + 0x69, 0xD7, 0x6E, 0xAD, 0x75, 0xD0, 0x28, 0x52, 0x3B, 0x93, + 0x36, 0xB5, 0xBA, 0x7F, 0xB8, 0x7A, 0x42, 0x94, 0xBC, 0xEC, + 0x00, 0x31, 0x45, 0x59, 0xDE, 0xC0, 0x88, 0x2A, 0xD7, 0xAF, + 0x55, 0xF8, 0xAC, 0xBE, 0xEE, 0x18, 0xA3, 0x5A, 0xD5, 0x02, + 0x63, 0x6D, 0x3C, 0xF4, 0x00, 0xC3, 0xA0, 0x9E, 0x37, 0x1F, + 0xE4, 0x7B, 0x41, 0x61, 0xC2, 0xA4, 0x0E, 0xD1, 0x3C, 0x81, + 0x87, 0x18, 0x9C, 0x75, 0x5A, 0xCB, 0x06, 0x4F, 0x5D, 0x73, + 0xAF, 0xAD, 0x21, 0xE1, 0x1D, 0xC2, 0xCE, 0xAD, 0x13, 0x11, + 0x16, 0xB8, 0x22, 0x38, 0x8F, 0xA4, 0x77, 0x21, 0x6C, 0xE2, + 0x7B, 0x80, 0x92, 0x37, 0x8C, 0x32, 0x0E, 0xEF, 0xB8, 0x90, + 0x69, 0x52, 0xBB, 0xAB, 0x02, 0xC9, 0xD8, 0x6D, 0x8E, 0x91, + 0x83, 0x3E, 0xF1, 0xF8, 0x52, 0x45, 0x36, 0x99, 0xDE, 0x40, + 0x41, 0xD0, 0x37, 0xA2, 0xFE, 0x73, 0xA4, 0x9C, 0x04, 0xE2, + 0x58, 0x6B, 0x8E, 0x9C, 0xAE, 0x0C, 0x03, 0x44, 0xFF, 0xF4, + 0x92, 0x57, 0x86, 0xAD, 0x63, 0x4A, 0xCE, 0x75, 0x59, 0x68, + 0x93, 0x3F, 0x2C, 0x89, 0xDF, 0xA4, 0xFE, 0x33, 0x55, 0x00, + 0x2F, 0x34, 0x34, 0x5E, 0xB0, 0xD0, 0x0E, 0xD4, 0x3E, 0xC9, + 0x75, 0xE8, 0x07, 0xB9, 0x8A, 0x09, 0x62, 0x33, 0xD7, 0xE1, + 0x6B, 0xAC, 0x28, 0xD1, 0x67, 0x0A, 0x97, 0xC4, 0xF1, 0x04, + 0x7A, 0x27, 0x4A, 0xA6, 0xC9, 0xEF, 0xA4, 0xAB, 0x71, 0xB5, + 0x20, 0xA8, 0x90, 0x89, 0x72, 0x79, 0xBB, 0x1E, 0x24, 0xB8, + 0xF9, 0x84, 0xA5, 0x88, 0xFF, 0xDC, 0xE7, 0x38, 0x93, 0xA8, + 0x2C, 0xA8, 0xFA, 0xD6, 0xB6, 0xDB, 0xE1, 0xF7, 0xFD, 0x65, + 0xB9, 0x9A, 0x7D, 0xF3, 0x3E, 0x31, 0x90, 0x7C, 0x69, 0x85, + 0x14, 0x50, 0xB2, 0x1C, 0xF8, 0x7A, 0xB1, 0x19, 0x82, 0x11, + 0x8F, 0xFE, 0x63, 0xCB, 0x22, 0x7C, 0x6C, 0x98, 0xD4, 0x9C, + 0x21, 0x0A, 0xD3, 0xB0, 0x9B, 0x45, 0xCE, 0x7F, 0xDC, 0x7D, + 0x34, 0xA9, 0xDB, 0xF3, 0xA0, 0x71, 0x63, 0xFC, 0x8A, 0x10, + 0x71, 0x39, 0x5A, 0x66, 0x99, 0xB4, 0x46, 0xB8, 0x03, 0x8F, + 0x9C, 0xC1, 0x13, 0xAF, 0x88, 0xD4, 0xE9, 0xCD, 0x1A, 0xD1, + 0xCF, 0x6D, 0xEE, 0x71, 0x3C, 0xCC, 0x3C, 0xFF, 0x6B, 0x71, + 0xC6, 0xF6, 0xCB, 0xFB, 0xE3, 0x27, 0x32, 0xDB, 0x0F, 0x30, + 0x75, 0xF3, 0x85, 0x66, 0xE8, 0x82, 0x86, 0x4A, 0xBD, 0x67, + 0x24, 0x5D, 0x79, 0x76, 0x73, 0x24, 0xBB, 0x0E, 0x32, 0xE0, + 0x18, 0x98, 0xE5, 0xE0, 0x1D, 0x20, 0x35, 0xBC, 0xFD, 0xE7, + 0xDC, 0x2E, 0x06, 0xF4, 0x85, 0x6C, 0xDD, 0xAA, 0x97, 0x7B, + 0xA0, 0x20, 0x31, 0x3D, 0xA6, 0x84, 0x56, 0xA6, 0x91, 0x7E, + 0xC7, 0xD4, 0x95, 0x60, 0xEE, 0x11, 0xEB, 0x58, 0xE7, 0x5F, + 0x43, 0xD6, 0xF4, 0x25, 0xCC, 0x40, 0x91, 0x10, 0xFD, 0x4C, + 0x82, 0x94, 0x29, 0x3D, 0x88, 0x43, 0x97, 0xCF, 0x37, 0x3C, + 0x76, 0x03, 0xFD, 0x88, 0xA0, 0xB7, 0xD8, 0x72, 0xA4, 0xCF, + 0x35, 0x30, 0x2D, 0x73, 0xC5, 0xF6, 0xD0, 0x94, 0x05, 0xA7, + 0xAF, 0xEA, 0x53, 0x8E, 0x56, 0x4F, 0xAF, 0x3E, 0x2F, 0x54, + 0x53, 0x0D, 0xC8, 0x6F, 0xA2, 0x4C, 0xC6, 0xC0, 0x46, 0xC8, + 0x49, 0xC2, 0xFF, 0x25, 0x82, 0xA1, 0x59, 0x1D, 0x49, 0x5A, + 0xC1, 0x64, 0x08, 0xC1, 0xB5, 0x99 +}; + +static const uint8_t alice[] = { + 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, + 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x27, 0x73, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x27, 0x73, 0x20, 0x41, 0x64, + 0x76, 0x65, 0x6E, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x69, + 0x6E, 0x20, 0x57, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x6C, 0x61, + 0x6E, 0x64, 0x2C, 0x20, 0x62, 0x79, 0x20, 0x4C, 0x65, 0x77, + 0x69, 0x73, 0x20, 0x43, 0x61, 0x72, 0x72, 0x6F, 0x6C, 0x6C, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, + 0x42, 0x6F, 0x6F, 0x6B, 0x20, 0x69, 0x73, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x6F, 0x6E, 0x65, 0x20, + 0x61, 0x6E, 0x79, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x61, + 0x74, 0x20, 0x6E, 0x6F, 0x20, 0x63, 0x6F, 0x73, 0x74, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, + 0x61, 0x6C, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6E, 0x6F, 0x20, + 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6F, + 0x6E, 0x73, 0x20, 0x77, 0x68, 0x61, 0x74, 0x73, 0x6F, 0x65, + 0x76, 0x65, 0x72, 0x2E, 0x20, 0x20, 0x59, 0x6F, 0x75, 0x20, + 0x6D, 0x61, 0x79, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x20, 0x69, + 0x74, 0x2C, 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, 0x69, 0x74, + 0x20, 0x61, 0x77, 0x61, 0x79, 0x20, 0x6F, 0x72, 0x0D, 0x0A, + 0x72, 0x65, 0x2D, 0x75, 0x73, 0x65, 0x20, 0x69, 0x74, 0x20, + 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x20, 0x4C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x20, 0x69, + 0x6E, 0x63, 0x6C, 0x75, 0x64, 0x65, 0x64, 0x0D, 0x0A, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, + 0x42, 0x6F, 0x6F, 0x6B, 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x6E, + 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x61, 0x74, 0x20, 0x77, 0x77, + 0x77, 0x2E, 0x67, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2E, 0x6F, 0x72, 0x67, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x69, 0x74, 0x6C, 0x65, 0x3A, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x27, 0x73, 0x20, 0x41, 0x64, 0x76, 0x65, + 0x6E, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x69, 0x6E, 0x20, + 0x57, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x6C, 0x61, 0x6E, 0x64, + 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, + 0x3A, 0x20, 0x4C, 0x65, 0x77, 0x69, 0x73, 0x20, 0x43, 0x61, + 0x72, 0x72, 0x6F, 0x6C, 0x6C, 0x0D, 0x0A, 0x0D, 0x0A, 0x50, + 0x6F, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x44, 0x61, 0x74, + 0x65, 0x3A, 0x20, 0x4A, 0x75, 0x6E, 0x65, 0x20, 0x32, 0x35, + 0x2C, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x5B, 0x45, 0x42, + 0x6F, 0x6F, 0x6B, 0x20, 0x23, 0x31, 0x31, 0x5D, 0x0D, 0x0A, + 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x44, 0x61, + 0x74, 0x65, 0x3A, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x2C, + 0x20, 0x31, 0x39, 0x39, 0x34, 0x0D, 0x0A, 0x5B, 0x4C, 0x61, + 0x73, 0x74, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x3A, 0x20, 0x44, 0x65, 0x63, 0x65, 0x6D, 0x62, 0x65, 0x72, + 0x20, 0x32, 0x30, 0x2C, 0x20, 0x32, 0x30, 0x31, 0x31, 0x5D, + 0x0D, 0x0A, 0x0D, 0x0A, 0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x3A, 0x20, 0x45, 0x6E, 0x67, 0x6C, 0x69, 0x73, + 0x68, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, 0x68, 0x61, 0x72, 0x61, + 0x63, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x74, 0x20, 0x65, + 0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x41, + 0x53, 0x43, 0x49, 0x49, 0x0D, 0x0A, 0x0D, 0x0A, 0x2A, 0x2A, + 0x2A, 0x20, 0x53, 0x54, 0x41, 0x52, 0x54, 0x20, 0x4F, 0x46, + 0x20, 0x54, 0x48, 0x49, 0x53, 0x20, 0x50, 0x52, 0x4F, 0x4A, + 0x45, 0x43, 0x54, 0x20, 0x47, 0x55, 0x54, 0x45, 0x4E, 0x42, + 0x45, 0x52, 0x47, 0x20, 0x45, 0x42, 0x4F, 0x4F, 0x4B, 0x20, + 0x41, 0x4C, 0x49, 0x43, 0x45, 0x27, 0x53, 0x20, 0x41, 0x44, + 0x56, 0x45, 0x4E, 0x54, 0x55, 0x52, 0x45, 0x53, 0x20, 0x49, + 0x4E, 0x20, 0x57, 0x4F, 0x4E, 0x44, 0x45, 0x52, 0x4C, 0x41, + 0x4E, 0x44, 0x20, 0x2A, 0x2A, 0x2A, 0x0D, 0x0A, 0x0D, 0x0A, + 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, + 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x4C, + 0x49, 0x43, 0x45, 0x27, 0x53, 0x20, 0x41, 0x44, 0x56, 0x45, + 0x4E, 0x54, 0x55, 0x52, 0x45, 0x53, 0x20, 0x49, 0x4E, 0x20, + 0x57, 0x4F, 0x4E, 0x44, 0x45, 0x52, 0x4C, 0x41, 0x4E, 0x44, + 0x0D, 0x0A, 0x0D, 0x0A, 0x4C, 0x65, 0x77, 0x69, 0x73, 0x20, + 0x43, 0x61, 0x72, 0x72, 0x6F, 0x6C, 0x6C, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x48, 0x45, 0x20, 0x4D, 0x49, 0x4C, 0x4C, 0x45, + 0x4E, 0x4E, 0x49, 0x55, 0x4D, 0x20, 0x46, 0x55, 0x4C, 0x43, + 0x52, 0x55, 0x4D, 0x20, 0x45, 0x44, 0x49, 0x54, 0x49, 0x4F, + 0x4E, 0x20, 0x33, 0x2E, 0x30, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, 0x48, 0x41, 0x50, 0x54, + 0x45, 0x52, 0x20, 0x49, 0x2E, 0x20, 0x44, 0x6F, 0x77, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, + 0x74, 0x2D, 0x48, 0x6F, 0x6C, 0x65, 0x0D, 0x0A, 0x0D, 0x0A, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x62, 0x65, 0x67, 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x74, 0x69, 0x72, 0x65, 0x64, 0x20, 0x6F, 0x66, + 0x20, 0x73, 0x69, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x62, + 0x79, 0x20, 0x68, 0x65, 0x72, 0x20, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x62, 0x61, 0x6E, 0x6B, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6F, 0x66, 0x20, 0x68, 0x61, 0x76, 0x69, 0x6E, 0x67, + 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x20, 0x64, 0x6F, 0x3A, 0x20, 0x6F, 0x6E, 0x63, 0x65, + 0x20, 0x6F, 0x72, 0x20, 0x74, 0x77, 0x69, 0x63, 0x65, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x70, 0x65, + 0x65, 0x70, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x62, 0x6F, 0x6F, 0x6B, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x73, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x69, + 0x6E, 0x67, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x74, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x20, 0x70, 0x69, + 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x6F, 0x72, 0x20, + 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x69, 0x74, + 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x62, 0x6F, + 0x6F, 0x6B, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x27, + 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x70, 0x69, + 0x63, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x6F, 0x72, 0x0D, + 0x0A, 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x53, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x69, 0x64, 0x65, 0x72, 0x69, + 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x6F, 0x77, 0x6E, 0x20, 0x6D, 0x69, 0x6E, 0x64, 0x20, 0x28, + 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, + 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x68, 0x6F, 0x74, 0x20, 0x64, 0x61, 0x79, 0x20, 0x6D, + 0x61, 0x64, 0x65, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x65, + 0x65, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, 0x6C, + 0x65, 0x65, 0x70, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, + 0x74, 0x75, 0x70, 0x69, 0x64, 0x29, 0x2C, 0x20, 0x77, 0x68, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x70, 0x6C, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x0D, 0x0A, + 0x6F, 0x66, 0x20, 0x6D, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x20, 0x64, 0x61, 0x69, 0x73, 0x79, 0x2D, 0x63, 0x68, + 0x61, 0x69, 0x6E, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x62, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x74, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x72, 0x6F, 0x75, 0x62, 0x6C, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, + 0x70, 0x69, 0x63, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x64, 0x61, 0x69, 0x73, 0x69, 0x65, 0x73, 0x2C, + 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x75, 0x64, 0x64, + 0x65, 0x6E, 0x6C, 0x79, 0x20, 0x61, 0x20, 0x57, 0x68, 0x69, + 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x70, 0x69, 0x6E, 0x6B, 0x20, + 0x65, 0x79, 0x65, 0x73, 0x20, 0x72, 0x61, 0x6E, 0x0D, 0x0A, + 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x20, 0x62, 0x79, 0x20, 0x68, + 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x6F, 0x20, 0x56, 0x45, + 0x52, 0x59, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x61, + 0x62, 0x6C, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x3B, 0x20, 0x6E, 0x6F, 0x72, 0x20, 0x64, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x6B, 0x20, 0x69, 0x74, 0x20, 0x73, 0x6F, 0x0D, 0x0A, + 0x56, 0x45, 0x52, 0x59, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x61, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x20, 0x73, 0x61, 0x79, 0x20, 0x74, 0x6F, + 0x20, 0x69, 0x74, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, + 0x4F, 0x68, 0x20, 0x64, 0x65, 0x61, 0x72, 0x21, 0x0D, 0x0A, + 0x4F, 0x68, 0x20, 0x64, 0x65, 0x61, 0x72, 0x21, 0x20, 0x49, + 0x20, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x20, + 0x6C, 0x61, 0x74, 0x65, 0x21, 0x27, 0x20, 0x28, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6F, 0x76, + 0x65, 0x72, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x73, 0x2C, 0x20, 0x69, 0x74, 0x0D, 0x0A, 0x6F, + 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x77, 0x6F, + 0x6E, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, + 0x65, 0x0D, 0x0A, 0x69, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, + 0x74, 0x65, 0x20, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x61, 0x6C, + 0x29, 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x77, 0x68, 0x65, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, + 0x69, 0x74, 0x20, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6C, 0x6C, + 0x79, 0x20, 0x54, 0x4F, 0x4F, 0x4B, 0x20, 0x41, 0x20, 0x57, + 0x41, 0x54, 0x43, 0x48, 0x0D, 0x0A, 0x4F, 0x55, 0x54, 0x20, + 0x4F, 0x46, 0x20, 0x49, 0x54, 0x53, 0x20, 0x57, 0x41, 0x49, + 0x53, 0x54, 0x43, 0x4F, 0x41, 0x54, 0x2D, 0x50, 0x4F, 0x43, + 0x4B, 0x45, 0x54, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x69, + 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x6E, 0x20, 0x68, 0x75, 0x72, 0x72, 0x69, 0x65, 0x64, 0x20, + 0x6F, 0x6E, 0x2C, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x65, 0x65, 0x74, + 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x69, 0x74, 0x20, 0x66, + 0x6C, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, 0x61, 0x63, 0x72, + 0x6F, 0x73, 0x73, 0x20, 0x68, 0x65, 0x72, 0x20, 0x6D, 0x69, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x0D, 0x0A, 0x6E, 0x65, 0x76, + 0x65, 0x72, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, + 0x73, 0x65, 0x65, 0x6E, 0x20, 0x61, 0x20, 0x72, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x65, + 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x20, 0x77, 0x61, + 0x69, 0x73, 0x74, 0x63, 0x6F, 0x61, 0x74, 0x2D, 0x70, 0x6F, + 0x63, 0x6B, 0x65, 0x74, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x61, + 0x20, 0x77, 0x61, 0x74, 0x63, 0x68, 0x0D, 0x0A, 0x74, 0x6F, + 0x20, 0x74, 0x61, 0x6B, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x62, 0x75, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x73, + 0x69, 0x74, 0x79, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x72, + 0x61, 0x6E, 0x20, 0x61, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x0D, + 0x0A, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x69, 0x74, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x75, + 0x6E, 0x61, 0x74, 0x65, 0x6C, 0x79, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, + 0x69, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, + 0x20, 0x69, 0x74, 0x20, 0x70, 0x6F, 0x70, 0x20, 0x64, 0x6F, + 0x77, 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x0D, 0x0A, 0x72, 0x61, 0x62, 0x62, 0x69, 0x74, 0x2D, 0x68, + 0x6F, 0x6C, 0x65, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x64, 0x67, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x49, 0x6E, 0x20, 0x61, 0x6E, 0x6F, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, + 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x6E, 0x65, + 0x76, 0x65, 0x72, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x63, + 0x6F, 0x6E, 0x73, 0x69, 0x64, 0x65, 0x72, 0x69, 0x6E, 0x67, + 0x20, 0x68, 0x6F, 0x77, 0x0D, 0x0A, 0x69, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x6F, 0x20, + 0x67, 0x65, 0x74, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x65, 0x20, 0x72, 0x61, 0x62, 0x62, 0x69, 0x74, 0x2D, 0x68, + 0x6F, 0x6C, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x73, + 0x74, 0x72, 0x61, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6F, 0x6E, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x61, 0x20, 0x74, 0x75, + 0x6E, 0x6E, 0x65, 0x6C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x77, 0x61, 0x79, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x0D, 0x0A, 0x64, + 0x69, 0x70, 0x70, 0x65, 0x64, 0x20, 0x73, 0x75, 0x64, 0x64, + 0x65, 0x6E, 0x6C, 0x79, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x2C, + 0x20, 0x73, 0x6F, 0x20, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, + 0x6C, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x61, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x0D, + 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x73, 0x74, 0x6F, + 0x70, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x66, + 0x61, 0x6C, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x64, 0x6F, 0x77, + 0x6E, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x64, + 0x65, 0x65, 0x70, 0x0D, 0x0A, 0x77, 0x65, 0x6C, 0x6C, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x45, 0x69, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x64, + 0x65, 0x65, 0x70, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x66, 0x65, 0x6C, 0x6C, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x73, 0x6C, 0x6F, 0x77, 0x6C, 0x79, 0x2C, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, + 0x64, 0x0D, 0x0A, 0x70, 0x6C, 0x65, 0x6E, 0x74, 0x79, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, 0x67, 0x6F, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x61, 0x70, 0x70, + 0x65, 0x6E, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x2E, 0x20, 0x46, + 0x69, 0x72, 0x73, 0x74, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x77, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x73, 0x68, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x2C, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x6F, + 0x6F, 0x20, 0x64, 0x61, 0x72, 0x6B, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x65, 0x65, 0x20, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x3B, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x73, + 0x68, 0x65, 0x0D, 0x0A, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, + 0x64, 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x64, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x66, 0x69, 0x6C, 0x6C, 0x65, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x63, 0x75, 0x70, + 0x62, 0x6F, 0x61, 0x72, 0x64, 0x73, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x62, 0x6F, 0x6F, 0x6B, 0x2D, 0x73, 0x68, 0x65, 0x6C, + 0x76, 0x65, 0x73, 0x3B, 0x20, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x77, 0x20, 0x6D, 0x61, + 0x70, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x70, 0x69, 0x63, + 0x74, 0x75, 0x72, 0x65, 0x73, 0x0D, 0x0A, 0x68, 0x75, 0x6E, + 0x67, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x70, 0x65, 0x67, + 0x73, 0x2E, 0x20, 0x53, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x6F, + 0x6B, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x20, 0x6A, + 0x61, 0x72, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x68, 0x65, 0x6C, 0x76, 0x65, 0x73, 0x20, 0x61, 0x73, 0x0D, + 0x0A, 0x73, 0x68, 0x65, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, + 0x64, 0x3B, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x27, + 0x4F, 0x52, 0x41, 0x4E, 0x47, 0x45, 0x20, 0x4D, 0x41, 0x52, + 0x4D, 0x41, 0x4C, 0x41, 0x44, 0x45, 0x27, 0x2C, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x67, 0x72, 0x65, 0x61, 0x74, 0x0D, 0x0A, 0x64, 0x69, 0x73, + 0x61, 0x70, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x6D, 0x65, 0x6E, + 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x65, + 0x6D, 0x70, 0x74, 0x79, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6C, 0x69, + 0x6B, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x72, 0x6F, 0x70, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, 0x61, 0x72, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x66, 0x65, 0x61, 0x72, 0x0D, 0x0A, 0x6F, + 0x66, 0x20, 0x6B, 0x69, 0x6C, 0x6C, 0x69, 0x6E, 0x67, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x62, 0x6F, 0x64, 0x79, 0x2C, 0x20, + 0x73, 0x6F, 0x20, 0x6D, 0x61, 0x6E, 0x61, 0x67, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x70, 0x75, 0x74, 0x20, 0x69, 0x74, + 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x6F, 0x6E, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x70, + 0x62, 0x6F, 0x61, 0x72, 0x64, 0x73, 0x20, 0x61, 0x73, 0x0D, + 0x0A, 0x73, 0x68, 0x65, 0x20, 0x66, 0x65, 0x6C, 0x6C, 0x20, + 0x70, 0x61, 0x73, 0x74, 0x20, 0x69, 0x74, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x6C, 0x6C, 0x21, 0x27, 0x20, + 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, 0x61, 0x66, 0x74, + 0x65, 0x72, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x20, + 0x66, 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2C, 0x20, 0x49, 0x20, 0x73, 0x68, 0x61, 0x6C, + 0x6C, 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x6E, + 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x75, 0x6D, 0x62, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x73, 0x74, 0x61, 0x69, 0x72, 0x73, + 0x21, 0x20, 0x48, 0x6F, 0x77, 0x20, 0x62, 0x72, 0x61, 0x76, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x79, 0x27, 0x6C, 0x6C, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, + 0x6D, 0x65, 0x20, 0x61, 0x74, 0x0D, 0x0A, 0x68, 0x6F, 0x6D, + 0x65, 0x21, 0x20, 0x57, 0x68, 0x79, 0x2C, 0x20, 0x49, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x73, + 0x61, 0x79, 0x20, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, + 0x2C, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x69, 0x66, 0x20, + 0x49, 0x20, 0x66, 0x65, 0x6C, 0x6C, 0x20, 0x6F, 0x66, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x70, 0x0D, 0x0A, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6F, 0x75, + 0x73, 0x65, 0x21, 0x27, 0x20, 0x28, 0x57, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x77, 0x61, 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x6C, 0x79, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x2E, 0x29, 0x0D, 0x0A, 0x0D, 0x0A, 0x44, 0x6F, + 0x77, 0x6E, 0x2C, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x2C, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x2E, 0x20, 0x57, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x6C, 0x6C, + 0x20, 0x4E, 0x45, 0x56, 0x45, 0x52, 0x20, 0x63, 0x6F, 0x6D, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x6E, 0x20, 0x65, 0x6E, + 0x64, 0x21, 0x20, 0x27, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x68, 0x6F, 0x77, 0x0D, 0x0A, 0x6D, 0x61, + 0x6E, 0x79, 0x20, 0x6D, 0x69, 0x6C, 0x65, 0x73, 0x20, 0x49, + 0x27, 0x76, 0x65, 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x65, 0x6E, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, + 0x69, 0x6D, 0x65, 0x3F, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x61, 0x6C, 0x6F, 0x75, 0x64, + 0x2E, 0x20, 0x27, 0x49, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, + 0x62, 0x65, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x73, 0x6F, 0x6D, 0x65, 0x77, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x6E, 0x65, 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x65, 0x6E, 0x74, 0x72, 0x65, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x61, 0x72, 0x74, 0x68, + 0x2E, 0x20, 0x4C, 0x65, 0x74, 0x20, 0x6D, 0x65, 0x20, 0x73, + 0x65, 0x65, 0x3A, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6F, + 0x75, 0x72, 0x0D, 0x0A, 0x74, 0x68, 0x6F, 0x75, 0x73, 0x61, + 0x6E, 0x64, 0x20, 0x6D, 0x69, 0x6C, 0x65, 0x73, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x2C, 0x20, 0x49, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x6B, 0x2D, 0x2D, 0x27, 0x20, 0x28, 0x66, 0x6F, 0x72, + 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x73, 0x65, 0x65, 0x2C, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x6C, 0x65, 0x61, 0x72, 0x6E, 0x74, 0x20, 0x73, 0x65, + 0x76, 0x65, 0x72, 0x61, 0x6C, 0x0D, 0x0A, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x20, 0x69, 0x6E, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x6C, 0x65, 0x73, 0x73, 0x6F, 0x6E, + 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x63, 0x68, 0x6F, 0x6F, 0x6C, 0x72, 0x6F, 0x6F, 0x6D, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x77, 0x61, + 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x56, 0x45, + 0x52, 0x59, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x6F, 0x70, + 0x70, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x69, 0x74, 0x79, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, 0x6F, 0x77, 0x69, 0x6E, + 0x67, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x2C, + 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x0D, + 0x0A, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x65, + 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x2C, 0x20, + 0x73, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x70, 0x72, + 0x61, 0x63, 0x74, 0x69, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x61, 0x79, 0x20, 0x69, 0x74, 0x20, 0x6F, 0x76, 0x65, + 0x72, 0x29, 0x0D, 0x0A, 0x27, 0x2D, 0x2D, 0x79, 0x65, 0x73, + 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, + 0x6E, 0x63, 0x65, 0x2D, 0x2D, 0x62, 0x75, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x6E, 0x20, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x4C, 0x61, + 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x0D, 0x0A, 0x6F, 0x72, + 0x20, 0x4C, 0x6F, 0x6E, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, + 0x20, 0x49, 0x27, 0x76, 0x65, 0x20, 0x67, 0x6F, 0x74, 0x20, + 0x74, 0x6F, 0x3F, 0x27, 0x20, 0x28, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x20, 0x69, + 0x64, 0x65, 0x61, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x4C, + 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x2C, 0x20, 0x6F, 0x72, 0x0D, 0x0A, 0x4C, 0x6F, 0x6E, + 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x20, 0x65, 0x69, 0x74, + 0x68, 0x65, 0x72, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, + 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x79, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x6E, 0x69, 0x63, + 0x65, 0x20, 0x67, 0x72, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x6F, + 0x72, 0x64, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, + 0x2E, 0x29, 0x0D, 0x0A, 0x0D, 0x0A, 0x50, 0x72, 0x65, 0x73, + 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6E, 0x2E, 0x20, 0x27, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x49, 0x20, 0x73, 0x68, + 0x61, 0x6C, 0x6C, 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x20, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x54, 0x48, 0x52, 0x4F, 0x55, + 0x47, 0x48, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x65, 0x61, + 0x72, 0x74, 0x68, 0x21, 0x20, 0x48, 0x6F, 0x77, 0x20, 0x66, + 0x75, 0x6E, 0x6E, 0x79, 0x20, 0x69, 0x74, 0x27, 0x6C, 0x6C, + 0x20, 0x73, 0x65, 0x65, 0x6D, 0x20, 0x74, 0x6F, 0x20, 0x63, + 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x6D, + 0x6F, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, + 0x6F, 0x70, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x77, 0x61, 0x6C, 0x6B, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, + 0x0A, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x77, 0x61, 0x72, + 0x64, 0x21, 0x20, 0x54, 0x68, 0x65, 0x20, 0x41, 0x6E, 0x74, + 0x69, 0x70, 0x61, 0x74, 0x68, 0x69, 0x65, 0x73, 0x2C, 0x20, + 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x2D, 0x2D, 0x27, + 0x20, 0x28, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x67, 0x6C, 0x61, + 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x57, + 0x41, 0x53, 0x20, 0x6E, 0x6F, 0x20, 0x6F, 0x6E, 0x65, 0x20, + 0x6C, 0x69, 0x73, 0x74, 0x65, 0x6E, 0x69, 0x6E, 0x67, 0x2C, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x69, 0x6D, 0x65, + 0x2C, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, 0x64, 0x69, + 0x64, 0x6E, 0x27, 0x74, 0x20, 0x73, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x77, + 0x6F, 0x72, 0x64, 0x29, 0x20, 0x27, 0x2D, 0x2D, 0x62, 0x75, + 0x74, 0x20, 0x49, 0x20, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, + 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x73, + 0x6B, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x61, 0x6D, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x75, 0x6E, 0x74, 0x72, 0x79, 0x0D, 0x0A, 0x69, 0x73, 0x2C, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2E, + 0x20, 0x50, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x2C, 0x20, 0x4D, + 0x61, 0x27, 0x61, 0x6D, 0x2C, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x4E, 0x65, 0x77, 0x20, 0x5A, 0x65, + 0x61, 0x6C, 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x72, 0x20, 0x41, + 0x75, 0x73, 0x74, 0x72, 0x61, 0x6C, 0x69, 0x61, 0x3F, 0x27, + 0x20, 0x28, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x73, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x63, 0x75, 0x72, 0x74, 0x73, 0x65, 0x79, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6B, 0x65, + 0x2D, 0x2D, 0x66, 0x61, 0x6E, 0x63, 0x79, 0x20, 0x43, 0x55, + 0x52, 0x54, 0x53, 0x45, 0x59, 0x49, 0x4E, 0x47, 0x20, 0x61, + 0x73, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x66, + 0x61, 0x6C, 0x6C, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x74, 0x68, + 0x72, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x61, 0x69, 0x72, 0x21, 0x20, 0x44, 0x6F, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6D, 0x61, + 0x6E, 0x61, 0x67, 0x65, 0x20, 0x69, 0x74, 0x3F, 0x29, 0x20, + 0x27, 0x41, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, + 0x61, 0x6E, 0x0D, 0x0A, 0x69, 0x67, 0x6E, 0x6F, 0x72, 0x61, + 0x6E, 0x74, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, + 0x67, 0x69, 0x72, 0x6C, 0x20, 0x73, 0x68, 0x65, 0x27, 0x6C, + 0x6C, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x6D, 0x65, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x73, 0x6B, 0x69, 0x6E, + 0x67, 0x21, 0x20, 0x4E, 0x6F, 0x2C, 0x20, 0x69, 0x74, 0x27, + 0x6C, 0x6C, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x64, + 0x6F, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x61, 0x73, 0x6B, 0x3A, + 0x20, 0x70, 0x65, 0x72, 0x68, 0x61, 0x70, 0x73, 0x20, 0x49, + 0x20, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x65, 0x65, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6E, 0x20, 0x75, 0x70, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x77, + 0x68, 0x65, 0x72, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x44, 0x6F, 0x77, 0x6E, 0x2C, 0x20, 0x64, 0x6F, 0x77, 0x6E, + 0x2C, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x2E, 0x20, 0x54, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x6C, 0x73, 0x65, + 0x20, 0x74, 0x6F, 0x20, 0x64, 0x6F, 0x2C, 0x20, 0x73, 0x6F, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x73, 0x6F, 0x6F, + 0x6E, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x0D, 0x0A, 0x74, + 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x2E, 0x20, 0x27, 0x44, 0x69, 0x6E, 0x61, 0x68, + 0x27, 0x6C, 0x6C, 0x20, 0x6D, 0x69, 0x73, 0x73, 0x20, 0x6D, + 0x65, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x20, 0x74, 0x6F, 0x2D, 0x6E, 0x69, 0x67, 0x68, 0x74, + 0x2C, 0x20, 0x49, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x21, 0x27, 0x0D, 0x0A, + 0x28, 0x44, 0x69, 0x6E, 0x61, 0x68, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x74, 0x2E, 0x29, + 0x20, 0x27, 0x49, 0x20, 0x68, 0x6F, 0x70, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x27, 0x6C, 0x6C, 0x20, 0x72, 0x65, 0x6D, + 0x65, 0x6D, 0x62, 0x65, 0x72, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x73, 0x61, 0x75, 0x63, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, + 0x6D, 0x69, 0x6C, 0x6B, 0x20, 0x61, 0x74, 0x0D, 0x0A, 0x74, + 0x65, 0x61, 0x2D, 0x74, 0x69, 0x6D, 0x65, 0x2E, 0x20, 0x44, + 0x69, 0x6E, 0x61, 0x68, 0x20, 0x6D, 0x79, 0x20, 0x64, 0x65, + 0x61, 0x72, 0x21, 0x20, 0x49, 0x20, 0x77, 0x69, 0x73, 0x68, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x6D, 0x65, 0x21, 0x20, 0x54, + 0x68, 0x65, 0x72, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6E, + 0x6F, 0x0D, 0x0A, 0x6D, 0x69, 0x63, 0x65, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x69, 0x72, 0x2C, 0x20, + 0x49, 0x27, 0x6D, 0x20, 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, + 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x63, 0x61, 0x74, 0x63, + 0x68, 0x20, 0x61, 0x20, 0x62, 0x61, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x0D, 0x0A, 0x6C, 0x69, 0x6B, 0x65, + 0x20, 0x61, 0x20, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x20, + 0x42, 0x75, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x63, 0x61, 0x74, + 0x73, 0x20, 0x65, 0x61, 0x74, 0x20, 0x62, 0x61, 0x74, 0x73, + 0x2C, 0x20, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, + 0x3F, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x0D, 0x0A, 0x62, + 0x65, 0x67, 0x61, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, + 0x74, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, + 0x6C, 0x65, 0x65, 0x70, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x73, + 0x61, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x68, + 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x64, 0x72, 0x65, 0x61, 0x6D, 0x79, 0x0D, + 0x0A, 0x73, 0x6F, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x77, + 0x61, 0x79, 0x2C, 0x20, 0x27, 0x44, 0x6F, 0x20, 0x63, 0x61, + 0x74, 0x73, 0x20, 0x65, 0x61, 0x74, 0x20, 0x62, 0x61, 0x74, + 0x73, 0x3F, 0x20, 0x44, 0x6F, 0x20, 0x63, 0x61, 0x74, 0x73, + 0x20, 0x65, 0x61, 0x74, 0x20, 0x62, 0x61, 0x74, 0x73, 0x3F, + 0x27, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x6F, 0x6D, 0x65, + 0x74, 0x69, 0x6D, 0x65, 0x73, 0x2C, 0x20, 0x27, 0x44, 0x6F, + 0x0D, 0x0A, 0x62, 0x61, 0x74, 0x73, 0x20, 0x65, 0x61, 0x74, + 0x20, 0x63, 0x61, 0x74, 0x73, 0x3F, 0x27, 0x20, 0x66, 0x6F, + 0x72, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x73, 0x65, 0x65, + 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, + 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x61, 0x6E, + 0x73, 0x77, 0x65, 0x72, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6F, 0x6E, + 0x2C, 0x0D, 0x0A, 0x69, 0x74, 0x20, 0x64, 0x69, 0x64, 0x6E, + 0x27, 0x74, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x6D, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x77, 0x61, 0x79, 0x20, 0x73, 0x68, 0x65, 0x20, 0x70, + 0x75, 0x74, 0x20, 0x69, 0x74, 0x2E, 0x20, 0x53, 0x68, 0x65, + 0x20, 0x66, 0x65, 0x6C, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x64, + 0x6F, 0x7A, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x6F, 0x66, 0x66, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x6A, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x67, 0x75, 0x6E, + 0x20, 0x74, 0x6F, 0x20, 0x64, 0x72, 0x65, 0x61, 0x6D, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x77, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x68, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x68, + 0x61, 0x6E, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, + 0x44, 0x69, 0x6E, 0x61, 0x68, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x61, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x65, 0x61, 0x72, 0x6E, 0x65, 0x73, 0x74, 0x6C, 0x79, 0x2C, + 0x20, 0x27, 0x4E, 0x6F, 0x77, 0x2C, 0x20, 0x44, 0x69, 0x6E, + 0x61, 0x68, 0x2C, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x6D, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x75, 0x74, + 0x68, 0x3A, 0x0D, 0x0A, 0x64, 0x69, 0x64, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x65, 0x76, 0x65, 0x72, 0x20, 0x65, 0x61, 0x74, + 0x20, 0x61, 0x20, 0x62, 0x61, 0x74, 0x3F, 0x27, 0x20, 0x77, + 0x68, 0x65, 0x6E, 0x20, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, + 0x6C, 0x79, 0x2C, 0x20, 0x74, 0x68, 0x75, 0x6D, 0x70, 0x21, + 0x20, 0x74, 0x68, 0x75, 0x6D, 0x70, 0x21, 0x20, 0x64, 0x6F, + 0x77, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6D, + 0x65, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x0D, 0x0A, 0x61, 0x20, + 0x68, 0x65, 0x61, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x74, + 0x69, 0x63, 0x6B, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, + 0x72, 0x79, 0x20, 0x6C, 0x65, 0x61, 0x76, 0x65, 0x73, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, + 0x61, 0x6C, 0x6C, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6F, 0x76, + 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x74, + 0x20, 0x61, 0x20, 0x62, 0x69, 0x74, 0x20, 0x68, 0x75, 0x72, + 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x6A, 0x75, 0x6D, 0x70, 0x65, 0x64, 0x20, 0x75, 0x70, + 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x66, 0x65, 0x65, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x3A, 0x0D, 0x0A, + 0x73, 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, + 0x20, 0x75, 0x70, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x64, 0x61, 0x72, 0x6B, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x68, + 0x65, 0x61, 0x64, 0x3B, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, + 0x65, 0x20, 0x68, 0x65, 0x72, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x6C, + 0x6F, 0x6E, 0x67, 0x20, 0x70, 0x61, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x57, 0x68, 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x74, + 0x69, 0x6C, 0x6C, 0x20, 0x69, 0x6E, 0x20, 0x73, 0x69, 0x67, + 0x68, 0x74, 0x2C, 0x20, 0x68, 0x75, 0x72, 0x72, 0x79, 0x69, + 0x6E, 0x67, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x69, 0x74, + 0x2E, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x6D, + 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x62, + 0x65, 0x20, 0x6C, 0x6F, 0x73, 0x74, 0x3A, 0x20, 0x61, 0x77, + 0x61, 0x79, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x69, 0x6E, 0x64, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x0D, 0x0A, 0x77, 0x61, 0x73, 0x20, 0x6A, 0x75, + 0x73, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x69, 0x6D, 0x65, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x61, 0x72, 0x20, 0x69, + 0x74, 0x20, 0x73, 0x61, 0x79, 0x2C, 0x20, 0x61, 0x73, 0x20, + 0x69, 0x74, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, + 0x61, 0x20, 0x63, 0x6F, 0x72, 0x6E, 0x65, 0x72, 0x2C, 0x20, + 0x27, 0x4F, 0x68, 0x20, 0x6D, 0x79, 0x20, 0x65, 0x61, 0x72, + 0x73, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x69, + 0x73, 0x6B, 0x65, 0x72, 0x73, 0x2C, 0x20, 0x68, 0x6F, 0x77, + 0x20, 0x6C, 0x61, 0x74, 0x65, 0x20, 0x69, 0x74, 0x27, 0x73, + 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x21, 0x27, + 0x20, 0x53, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, + 0x6C, 0x6F, 0x73, 0x65, 0x20, 0x62, 0x65, 0x68, 0x69, 0x6E, + 0x64, 0x20, 0x69, 0x74, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, + 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x74, 0x75, 0x72, 0x6E, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x72, 0x6E, + 0x65, 0x72, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x6C, 0x6F, 0x6E, 0x67, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x73, + 0x65, 0x65, 0x6E, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, + 0x6F, 0x75, 0x6E, 0x64, 0x0D, 0x0A, 0x68, 0x65, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6C, + 0x6F, 0x6E, 0x67, 0x2C, 0x20, 0x6C, 0x6F, 0x77, 0x20, 0x68, + 0x61, 0x6C, 0x6C, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x6C, 0x69, 0x74, 0x20, 0x75, + 0x70, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x72, 0x6F, 0x77, + 0x20, 0x6F, 0x66, 0x20, 0x6C, 0x61, 0x6D, 0x70, 0x73, 0x20, + 0x68, 0x61, 0x6E, 0x67, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x66, + 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, + 0x6F, 0x66, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x64, 0x6F, + 0x6F, 0x72, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x6F, + 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, + 0x6C, 0x6C, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64, 0x3B, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x0D, 0x0A, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x62, 0x65, 0x65, 0x6E, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x64, 0x6F, 0x77, + 0x6E, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x73, 0x69, 0x64, 0x65, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x75, 0x70, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x2C, 0x20, 0x74, + 0x72, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x76, 0x65, 0x72, + 0x79, 0x0D, 0x0A, 0x64, 0x6F, 0x6F, 0x72, 0x2C, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x6C, 0x6B, 0x65, 0x64, 0x20, + 0x73, 0x61, 0x64, 0x6C, 0x79, 0x20, 0x64, 0x6F, 0x77, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x69, 0x64, 0x64, 0x6C, + 0x65, 0x2C, 0x20, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x69, + 0x6E, 0x67, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x65, 0x76, 0x65, 0x72, 0x20, + 0x74, 0x6F, 0x0D, 0x0A, 0x67, 0x65, 0x74, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x53, 0x75, 0x64, 0x64, 0x65, 0x6E, 0x6C, 0x79, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, + 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x2D, + 0x6C, 0x65, 0x67, 0x67, 0x65, 0x64, 0x20, 0x74, 0x61, 0x62, + 0x6C, 0x65, 0x2C, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6D, 0x61, + 0x64, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x6F, 0x6C, 0x69, + 0x64, 0x0D, 0x0A, 0x67, 0x6C, 0x61, 0x73, 0x73, 0x3B, 0x20, + 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, + 0x20, 0x69, 0x74, 0x20, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, + 0x20, 0x61, 0x20, 0x74, 0x69, 0x6E, 0x79, 0x20, 0x67, 0x6F, + 0x6C, 0x64, 0x65, 0x6E, 0x20, 0x6B, 0x65, 0x79, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x27, + 0x73, 0x0D, 0x0A, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74, + 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6D, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x62, 0x65, 0x6C, 0x6F, 0x6E, + 0x67, 0x20, 0x74, 0x6F, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, + 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, + 0x61, 0x6C, 0x6C, 0x3B, 0x0D, 0x0A, 0x62, 0x75, 0x74, 0x2C, + 0x20, 0x61, 0x6C, 0x61, 0x73, 0x21, 0x20, 0x65, 0x69, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x6F, + 0x63, 0x6B, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x74, + 0x6F, 0x6F, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x2C, 0x20, + 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6B, 0x65, 0x79, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x6F, 0x6F, 0x20, 0x73, + 0x6D, 0x61, 0x6C, 0x6C, 0x2C, 0x0D, 0x0A, 0x62, 0x75, 0x74, + 0x20, 0x61, 0x74, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x72, 0x61, + 0x74, 0x65, 0x20, 0x69, 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6F, 0x70, 0x65, 0x6E, + 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x2E, 0x20, 0x48, 0x6F, 0x77, 0x65, 0x76, 0x65, + 0x72, 0x2C, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x0D, 0x0A, 0x74, 0x69, + 0x6D, 0x65, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2C, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x75, + 0x70, 0x6F, 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x77, 0x20, + 0x63, 0x75, 0x72, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x64, 0x20, 0x62, 0x65, + 0x66, 0x6F, 0x72, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, + 0x0A, 0x62, 0x65, 0x68, 0x69, 0x6E, 0x64, 0x20, 0x69, 0x74, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x66, 0x69, 0x66, 0x74, 0x65, + 0x65, 0x6E, 0x20, 0x69, 0x6E, 0x63, 0x68, 0x65, 0x73, 0x20, + 0x68, 0x69, 0x67, 0x68, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x67, 0x6F, + 0x6C, 0x64, 0x65, 0x6E, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x63, 0x6B, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x64, + 0x65, 0x6C, 0x69, 0x67, 0x68, 0x74, 0x20, 0x69, 0x74, 0x20, + 0x66, 0x69, 0x74, 0x74, 0x65, 0x64, 0x21, 0x0D, 0x0A, 0x0D, + 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x6F, 0x70, 0x65, + 0x6E, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, + 0x6F, 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, + 0x20, 0x6C, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, + 0x61, 0x20, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x20, 0x70, 0x61, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x2C, 0x20, 0x6E, 0x6F, 0x74, + 0x0D, 0x0A, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x6C, 0x61, 0x72, + 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x61, + 0x20, 0x72, 0x61, 0x74, 0x2D, 0x68, 0x6F, 0x6C, 0x65, 0x3A, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x6B, 0x6E, 0x65, 0x6C, 0x74, + 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x6C, 0x6F, + 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x0D, 0x0A, 0x69, 0x6E, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x76, 0x65, 0x6C, + 0x69, 0x65, 0x73, 0x74, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, + 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x65, 0x76, 0x65, 0x72, + 0x20, 0x73, 0x61, 0x77, 0x2E, 0x20, 0x48, 0x6F, 0x77, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x64, 0x61, 0x72, 0x6B, 0x20, 0x68, 0x61, 0x6C, 0x6C, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x61, + 0x6D, 0x6F, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x6F, 0x73, 0x65, + 0x20, 0x62, 0x65, 0x64, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x62, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x66, 0x6C, 0x6F, 0x77, + 0x65, 0x72, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x74, + 0x68, 0x6F, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6F, 0x6C, 0x20, + 0x66, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x2C, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x65, + 0x76, 0x65, 0x6E, 0x20, 0x67, 0x65, 0x74, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x74, 0x68, 0x72, + 0x6F, 0x75, 0x67, 0x68, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x64, 0x6F, 0x6F, 0x72, 0x77, 0x61, 0x79, 0x3B, 0x20, 0x27, + 0x61, 0x6E, 0x64, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x69, + 0x66, 0x20, 0x6D, 0x79, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x67, 0x6F, 0x20, 0x74, + 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x2C, 0x27, 0x20, 0x74, + 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x70, 0x6F, 0x6F, + 0x72, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x27, + 0x69, 0x74, 0x0D, 0x0A, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x62, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, + 0x6D, 0x79, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x65, + 0x72, 0x73, 0x2E, 0x20, 0x4F, 0x68, 0x2C, 0x20, 0x68, 0x6F, + 0x77, 0x20, 0x49, 0x20, 0x77, 0x69, 0x73, 0x68, 0x20, 0x49, + 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x0D, 0x0A, 0x73, 0x68, + 0x75, 0x74, 0x20, 0x75, 0x70, 0x20, 0x6C, 0x69, 0x6B, 0x65, + 0x20, 0x61, 0x20, 0x74, 0x65, 0x6C, 0x65, 0x73, 0x63, 0x6F, + 0x70, 0x65, 0x21, 0x20, 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x6B, 0x20, 0x49, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x2C, + 0x20, 0x69, 0x66, 0x20, 0x49, 0x20, 0x6F, 0x6E, 0x6C, 0x79, + 0x20, 0x6B, 0x6E, 0x65, 0x77, 0x20, 0x68, 0x6F, 0x77, 0x20, + 0x74, 0x6F, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x2E, 0x27, + 0x0D, 0x0A, 0x46, 0x6F, 0x72, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x73, 0x65, 0x65, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x6D, + 0x61, 0x6E, 0x79, 0x20, 0x6F, 0x75, 0x74, 0x2D, 0x6F, 0x66, + 0x2D, 0x74, 0x68, 0x65, 0x2D, 0x77, 0x61, 0x79, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x68, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x6C, + 0x61, 0x74, 0x65, 0x6C, 0x79, 0x2C, 0x0D, 0x0A, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x62, 0x65, 0x67, 0x75, 0x6E, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x66, 0x65, + 0x77, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x69, + 0x6E, 0x64, 0x65, 0x65, 0x64, 0x20, 0x77, 0x65, 0x72, 0x65, + 0x20, 0x72, 0x65, 0x61, 0x6C, 0x6C, 0x79, 0x0D, 0x0A, 0x69, + 0x6D, 0x70, 0x6F, 0x73, 0x73, 0x69, 0x62, 0x6C, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x62, 0x65, 0x20, 0x6E, 0x6F, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x69, 0x6E, 0x20, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, + 0x74, 0x74, 0x6C, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x2C, + 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x0D, 0x0A, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6C, + 0x65, 0x2C, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x68, 0x6F, + 0x70, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6D, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, + 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6B, 0x65, + 0x79, 0x20, 0x6F, 0x6E, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x6F, + 0x72, 0x20, 0x61, 0x74, 0x0D, 0x0A, 0x61, 0x6E, 0x79, 0x20, + 0x72, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, + 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x72, 0x75, 0x6C, 0x65, 0x73, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, 0x75, 0x74, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, + 0x20, 0x75, 0x70, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, + 0x65, 0x6C, 0x65, 0x73, 0x63, 0x6F, 0x70, 0x65, 0x73, 0x3A, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x74, 0x69, 0x6D, + 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, + 0x64, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x62, 0x6F, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x6F, 0x6E, + 0x20, 0x69, 0x74, 0x2C, 0x20, 0x28, 0x27, 0x77, 0x68, 0x69, + 0x63, 0x68, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6E, + 0x6C, 0x79, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x74, + 0x20, 0x68, 0x65, 0x72, 0x65, 0x0D, 0x0A, 0x62, 0x65, 0x66, + 0x6F, 0x72, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x29, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6E, 0x65, 0x63, 0x6B, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6F, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x70, 0x61, + 0x70, 0x65, 0x72, 0x0D, 0x0A, 0x6C, 0x61, 0x62, 0x65, 0x6C, + 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x20, 0x27, 0x44, 0x52, + 0x49, 0x4E, 0x4B, 0x20, 0x4D, 0x45, 0x27, 0x20, 0x62, 0x65, + 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x6C, 0x79, 0x20, + 0x70, 0x72, 0x69, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x6F, 0x6E, + 0x20, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x6C, 0x61, 0x72, + 0x67, 0x65, 0x0D, 0x0A, 0x6C, 0x65, 0x74, 0x74, 0x65, 0x72, + 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x49, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x61, 0x79, 0x20, 0x27, 0x44, 0x72, 0x69, 0x6E, 0x6B, + 0x20, 0x6D, 0x65, 0x2C, 0x27, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x69, 0x73, 0x65, 0x20, 0x6C, + 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, 0x6E, 0x6F, 0x74, + 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, + 0x64, 0x6F, 0x20, 0x54, 0x48, 0x41, 0x54, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x68, 0x75, 0x72, 0x72, 0x79, 0x2E, 0x20, + 0x27, 0x4E, 0x6F, 0x2C, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, + 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x73, + 0x65, 0x65, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x6D, 0x61, 0x72, 0x6B, + 0x65, 0x64, 0x20, 0x22, 0x70, 0x6F, 0x69, 0x73, 0x6F, 0x6E, + 0x22, 0x20, 0x6F, 0x72, 0x20, 0x6E, 0x6F, 0x74, 0x27, 0x3B, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x73, 0x65, + 0x76, 0x65, 0x72, 0x61, 0x6C, 0x20, 0x6E, 0x69, 0x63, 0x65, + 0x0D, 0x0A, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x68, + 0x69, 0x73, 0x74, 0x6F, 0x72, 0x69, 0x65, 0x73, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, + 0x72, 0x65, 0x6E, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x62, 0x75, 0x72, 0x6E, + 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x65, 0x61, 0x74, + 0x65, 0x6E, 0x20, 0x75, 0x70, 0x20, 0x62, 0x79, 0x20, 0x77, + 0x69, 0x6C, 0x64, 0x0D, 0x0A, 0x62, 0x65, 0x61, 0x73, 0x74, + 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x75, 0x6E, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x61, + 0x6E, 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x2C, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, + 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x57, 0x4F, + 0x55, 0x4C, 0x44, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x72, 0x65, + 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x72, + 0x75, 0x6C, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, + 0x20, 0x66, 0x72, 0x69, 0x65, 0x6E, 0x64, 0x73, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x74, 0x61, 0x75, 0x67, 0x68, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x6D, 0x3A, 0x20, 0x73, 0x75, 0x63, 0x68, + 0x20, 0x61, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x61, 0x20, 0x72, 0x65, 0x64, 0x2D, 0x68, 0x6F, 0x74, 0x0D, + 0x0A, 0x70, 0x6F, 0x6B, 0x65, 0x72, 0x20, 0x77, 0x69, 0x6C, + 0x6C, 0x20, 0x62, 0x75, 0x72, 0x6E, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x69, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x68, 0x6F, + 0x6C, 0x64, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6F, 0x6F, 0x20, + 0x6C, 0x6F, 0x6E, 0x67, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x66, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x63, 0x75, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x72, + 0x0D, 0x0A, 0x66, 0x69, 0x6E, 0x67, 0x65, 0x72, 0x20, 0x56, + 0x45, 0x52, 0x59, 0x20, 0x64, 0x65, 0x65, 0x70, 0x6C, 0x79, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x6B, 0x6E, + 0x69, 0x66, 0x65, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x75, 0x73, + 0x75, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x62, 0x6C, 0x65, 0x65, + 0x64, 0x73, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6E, 0x65, 0x76, 0x65, + 0x72, 0x0D, 0x0A, 0x66, 0x6F, 0x72, 0x67, 0x6F, 0x74, 0x74, + 0x65, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2C, 0x20, 0x69, + 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, 0x72, 0x69, 0x6E, + 0x6B, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x66, 0x72, 0x6F, + 0x6D, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x6D, 0x61, 0x72, 0x6B, 0x65, 0x64, 0x20, 0x27, 0x70, + 0x6F, 0x69, 0x73, 0x6F, 0x6E, 0x2C, 0x27, 0x20, 0x69, 0x74, + 0x20, 0x69, 0x73, 0x0D, 0x0A, 0x61, 0x6C, 0x6D, 0x6F, 0x73, + 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6E, 0x20, + 0x74, 0x6F, 0x20, 0x64, 0x69, 0x73, 0x61, 0x67, 0x72, 0x65, + 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x79, 0x6F, 0x75, + 0x2C, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x65, 0x72, 0x20, 0x6F, + 0x72, 0x20, 0x6C, 0x61, 0x74, 0x65, 0x72, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x48, 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x62, 0x6F, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x4E, 0x4F, 0x54, + 0x20, 0x6D, 0x61, 0x72, 0x6B, 0x65, 0x64, 0x20, 0x27, 0x70, + 0x6F, 0x69, 0x73, 0x6F, 0x6E, 0x2C, 0x27, 0x20, 0x73, 0x6F, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x76, 0x65, 0x6E, + 0x74, 0x75, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x61, 0x73, 0x74, 0x65, 0x0D, 0x0A, 0x69, 0x74, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x69, 0x6E, + 0x67, 0x20, 0x69, 0x74, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x6E, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x28, 0x69, 0x74, 0x20, + 0x68, 0x61, 0x64, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x66, 0x61, + 0x63, 0x74, 0x2C, 0x20, 0x61, 0x20, 0x73, 0x6F, 0x72, 0x74, + 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x69, 0x78, 0x65, 0x64, 0x20, + 0x66, 0x6C, 0x61, 0x76, 0x6F, 0x75, 0x72, 0x0D, 0x0A, 0x6F, + 0x66, 0x20, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79, 0x2D, 0x74, + 0x61, 0x72, 0x74, 0x2C, 0x20, 0x63, 0x75, 0x73, 0x74, 0x61, + 0x72, 0x64, 0x2C, 0x20, 0x70, 0x69, 0x6E, 0x65, 0x2D, 0x61, + 0x70, 0x70, 0x6C, 0x65, 0x2C, 0x20, 0x72, 0x6F, 0x61, 0x73, + 0x74, 0x20, 0x74, 0x75, 0x72, 0x6B, 0x65, 0x79, 0x2C, 0x20, + 0x74, 0x6F, 0x66, 0x66, 0x65, 0x65, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x68, 0x6F, 0x74, 0x0D, 0x0A, 0x62, 0x75, 0x74, + 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x61, 0x73, + 0x74, 0x2C, 0x29, 0x20, 0x73, 0x68, 0x65, 0x20, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x66, 0x69, + 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x69, 0x74, 0x20, + 0x6F, 0x66, 0x66, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, + 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, + 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, + 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, + 0x2A, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2A, + 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, + 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, + 0x20, 0x20, 0x20, 0x20, 0x2A, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, + 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, + 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, + 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, + 0x20, 0x2A, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, + 0x74, 0x20, 0x61, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, + 0x73, 0x20, 0x66, 0x65, 0x65, 0x6C, 0x69, 0x6E, 0x67, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x3B, 0x20, 0x27, 0x49, 0x20, 0x6D, 0x75, 0x73, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x73, 0x68, 0x75, 0x74, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x75, 0x70, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x61, 0x0D, 0x0A, 0x74, 0x65, 0x6C, 0x65, 0x73, + 0x63, 0x6F, 0x70, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x41, 0x6E, 0x64, 0x20, 0x73, 0x6F, 0x20, 0x69, 0x74, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x65, 0x64, + 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x6E, 0x6F, 0x77, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x74, + 0x65, 0x6E, 0x20, 0x69, 0x6E, 0x63, 0x68, 0x65, 0x73, 0x20, + 0x68, 0x69, 0x67, 0x68, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x66, 0x61, 0x63, 0x65, 0x0D, 0x0A, + 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x65, 0x6E, 0x65, 0x64, + 0x20, 0x75, 0x70, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x74, 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, 0x69, 0x6E, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6C, 0x6F, 0x76, 0x65, + 0x6C, 0x79, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x2E, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2C, 0x20, 0x68, 0x6F, + 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, 0x20, 0x73, 0x68, 0x65, + 0x0D, 0x0A, 0x77, 0x61, 0x69, 0x74, 0x65, 0x64, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x61, 0x20, 0x66, 0x65, 0x77, 0x20, 0x6D, + 0x69, 0x6E, 0x75, 0x74, 0x65, 0x73, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x65, 0x65, 0x20, 0x69, 0x66, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x73, 0x68, 0x72, 0x69, 0x6E, 0x6B, + 0x20, 0x61, 0x6E, 0x79, 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, + 0x65, 0x72, 0x3A, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, 0x66, + 0x65, 0x6C, 0x74, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x6E, 0x65, 0x72, 0x76, 0x6F, 0x75, 0x73, + 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x3B, 0x20, 0x27, 0x66, 0x6F, 0x72, 0x20, 0x69, 0x74, + 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x65, 0x6E, 0x64, + 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x0D, 0x0A, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, 0x69, 0x6E, + 0x20, 0x6D, 0x79, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x61, 0x6C, 0x74, 0x6F, 0x67, 0x65, + 0x74, 0x68, 0x65, 0x72, 0x2C, 0x20, 0x6C, 0x69, 0x6B, 0x65, + 0x20, 0x61, 0x20, 0x63, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x2E, + 0x20, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x0D, + 0x0A, 0x77, 0x68, 0x61, 0x74, 0x20, 0x49, 0x20, 0x73, 0x68, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x6C, 0x69, + 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x3F, 0x27, 0x20, + 0x41, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x72, + 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x61, 0x6E, + 0x63, 0x79, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x66, 0x6C, 0x61, 0x6D, 0x65, 0x20, 0x6F, 0x66, + 0x20, 0x61, 0x0D, 0x0A, 0x63, 0x61, 0x6E, 0x64, 0x6C, 0x65, + 0x20, 0x69, 0x73, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x61, + 0x66, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x20, 0x69, 0x73, 0x20, 0x62, + 0x6C, 0x6F, 0x77, 0x6E, 0x20, 0x6F, 0x75, 0x74, 0x2C, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x72, 0x65, + 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, 0x0D, 0x0A, 0x65, 0x76, + 0x65, 0x72, 0x20, 0x68, 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, + 0x73, 0x65, 0x65, 0x6E, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x41, 0x66, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20, + 0x77, 0x68, 0x69, 0x6C, 0x65, 0x2C, 0x20, 0x66, 0x69, 0x6E, + 0x64, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x68, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x65, + 0x64, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x64, 0x65, 0x63, + 0x69, 0x64, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x67, 0x6F, + 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x69, 0x6E, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, + 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x3B, 0x20, + 0x62, 0x75, 0x74, 0x2C, 0x20, 0x61, 0x6C, 0x61, 0x73, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x21, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x64, 0x6F, 0x6F, + 0x72, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x66, 0x6F, 0x72, 0x67, 0x6F, 0x74, 0x74, 0x65, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x67, 0x6F, 0x6C, 0x64, 0x65, 0x6E, 0x20, 0x6B, + 0x65, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x77, 0x65, + 0x6E, 0x74, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x69, 0x62, 0x6C, + 0x79, 0x20, 0x72, 0x65, 0x61, 0x63, 0x68, 0x0D, 0x0A, 0x69, + 0x74, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x73, 0x65, 0x65, 0x20, 0x69, 0x74, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x70, 0x6C, 0x61, 0x69, + 0x6E, 0x6C, 0x79, 0x20, 0x74, 0x68, 0x72, 0x6F, 0x75, 0x67, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x6C, 0x61, 0x73, + 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, + 0x0D, 0x0A, 0x62, 0x65, 0x73, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x63, 0x6C, 0x69, 0x6D, 0x62, 0x20, 0x75, 0x70, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6C, 0x65, 0x67, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x2C, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x74, 0x6F, 0x6F, 0x20, 0x73, 0x6C, 0x69, 0x70, 0x70, 0x65, + 0x72, 0x79, 0x3B, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x77, + 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x74, 0x69, 0x72, 0x65, 0x64, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x6F, 0x75, 0x74, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6E, + 0x67, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6F, 0x6F, + 0x72, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x73, 0x61, 0x74, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, + 0x72, 0x69, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x43, 0x6F, 0x6D, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x63, 0x72, 0x79, 0x69, 0x6E, 0x67, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x0D, 0x0A, 0x72, 0x61, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x73, 0x68, 0x61, 0x72, 0x70, 0x6C, + 0x79, 0x3B, 0x20, 0x27, 0x49, 0x20, 0x61, 0x64, 0x76, 0x69, + 0x73, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x74, 0x6F, 0x20, + 0x6C, 0x65, 0x61, 0x76, 0x65, 0x20, 0x6F, 0x66, 0x66, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, + 0x65, 0x21, 0x27, 0x20, 0x53, 0x68, 0x65, 0x20, 0x67, 0x65, + 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x6C, 0x79, 0x0D, 0x0A, 0x67, + 0x61, 0x76, 0x65, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, + 0x66, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x67, 0x6F, 0x6F, + 0x64, 0x20, 0x61, 0x64, 0x76, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x28, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, 0x65, 0x6C, + 0x64, 0x6F, 0x6D, 0x20, 0x66, 0x6F, 0x6C, 0x6C, 0x6F, 0x77, + 0x65, 0x64, 0x20, 0x69, 0x74, 0x29, 0x2C, 0x0D, 0x0A, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, 0x69, 0x6D, + 0x65, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x63, 0x6F, + 0x6C, 0x64, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x65, 0x76, 0x65, + 0x72, 0x65, 0x6C, 0x79, 0x20, 0x61, 0x73, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x65, 0x61, + 0x72, 0x73, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x0D, 0x0A, 0x68, + 0x65, 0x72, 0x20, 0x65, 0x79, 0x65, 0x73, 0x3B, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x6F, 0x20, 0x62, 0x6F, 0x78, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x6F, 0x77, 0x6E, 0x20, 0x65, 0x61, 0x72, 0x73, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x68, 0x61, 0x76, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x63, 0x68, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, + 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x20, 0x6F, 0x66, + 0x20, 0x63, 0x72, 0x6F, 0x71, 0x75, 0x65, 0x74, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x70, 0x6C, 0x61, + 0x79, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, + 0x73, 0x74, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, + 0x2C, 0x0D, 0x0A, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x20, + 0x63, 0x68, 0x69, 0x6C, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x66, 0x6F, 0x6E, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x70, 0x72, 0x65, 0x74, 0x65, 0x6E, 0x64, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, + 0x74, 0x77, 0x6F, 0x20, 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, + 0x2E, 0x0D, 0x0A, 0x27, 0x42, 0x75, 0x74, 0x20, 0x69, 0x74, + 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6E, 0x6F, 0x77, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, + 0x67, 0x68, 0x74, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x27, 0x74, 0x6F, 0x20, + 0x70, 0x72, 0x65, 0x74, 0x65, 0x6E, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x65, 0x20, 0x74, 0x77, 0x6F, 0x20, 0x70, 0x65, + 0x6F, 0x70, 0x6C, 0x65, 0x21, 0x0D, 0x0A, 0x57, 0x68, 0x79, + 0x2C, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, + 0x68, 0x61, 0x72, 0x64, 0x6C, 0x79, 0x20, 0x65, 0x6E, 0x6F, + 0x75, 0x67, 0x68, 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x65, 0x20, + 0x6C, 0x65, 0x66, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, + 0x6B, 0x65, 0x20, 0x4F, 0x4E, 0x45, 0x20, 0x72, 0x65, 0x73, + 0x70, 0x65, 0x63, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x70, + 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x21, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x53, 0x6F, 0x6F, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x65, 0x79, 0x65, 0x20, 0x66, 0x65, 0x6C, 0x6C, 0x20, 0x6F, + 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x67, 0x6C, 0x61, 0x73, 0x73, 0x20, 0x62, 0x6F, 0x78, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x6C, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x75, 0x6E, 0x64, 0x65, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6C, + 0x65, 0x3A, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, 0x6F, 0x70, + 0x65, 0x6E, 0x65, 0x64, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, + 0x6E, 0x20, 0x69, 0x74, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x61, + 0x6B, 0x65, 0x2C, 0x20, 0x6F, 0x6E, 0x20, 0x77, 0x68, 0x69, + 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x64, 0x73, 0x0D, 0x0A, 0x27, 0x45, 0x41, 0x54, 0x20, 0x4D, + 0x45, 0x27, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x62, 0x65, + 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x6C, 0x79, 0x20, + 0x6D, 0x61, 0x72, 0x6B, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, + 0x63, 0x75, 0x72, 0x72, 0x61, 0x6E, 0x74, 0x73, 0x2E, 0x20, + 0x27, 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x49, 0x27, 0x6C, + 0x6C, 0x20, 0x65, 0x61, 0x74, 0x20, 0x69, 0x74, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x0D, 0x0A, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x69, + 0x66, 0x20, 0x69, 0x74, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x73, + 0x20, 0x6D, 0x65, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x20, 0x6C, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x2C, 0x20, 0x49, 0x20, 0x63, + 0x61, 0x6E, 0x20, 0x72, 0x65, 0x61, 0x63, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6B, 0x65, 0x79, 0x3B, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, 0x0D, 0x0A, 0x6D, + 0x61, 0x6B, 0x65, 0x73, 0x20, 0x6D, 0x65, 0x20, 0x67, 0x72, + 0x6F, 0x77, 0x20, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x72, + 0x2C, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x63, 0x72, + 0x65, 0x65, 0x70, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x3B, 0x20, + 0x73, 0x6F, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x77, 0x61, 0x79, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x0D, 0x0A, + 0x67, 0x65, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x6E, + 0x27, 0x74, 0x20, 0x63, 0x61, 0x72, 0x65, 0x20, 0x77, 0x68, + 0x69, 0x63, 0x68, 0x20, 0x68, 0x61, 0x70, 0x70, 0x65, 0x6E, + 0x73, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x68, 0x65, + 0x20, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x62, 0x69, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x61, 0x6E, + 0x78, 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, + 0x27, 0x57, 0x68, 0x69, 0x63, 0x68, 0x20, 0x77, 0x61, 0x79, + 0x3F, 0x20, 0x57, 0x68, 0x69, 0x63, 0x68, 0x0D, 0x0A, 0x77, + 0x61, 0x79, 0x3F, 0x27, 0x2C, 0x20, 0x68, 0x6F, 0x6C, 0x64, + 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x61, + 0x6E, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x6F, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x66, + 0x65, 0x65, 0x6C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, + 0x77, 0x61, 0x79, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x0D, 0x0A, 0x67, 0x72, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x73, + 0x75, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x72, 0x65, 0x6D, 0x61, + 0x69, 0x6E, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x6D, 0x65, 0x0D, 0x0A, 0x73, 0x69, 0x7A, 0x65, 0x3A, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x73, 0x75, 0x72, + 0x65, 0x2C, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x67, 0x65, + 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x68, 0x61, + 0x70, 0x70, 0x65, 0x6E, 0x73, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x65, 0x61, 0x74, 0x73, 0x20, + 0x63, 0x61, 0x6B, 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x0D, 0x0A, 0x68, 0x61, 0x64, + 0x20, 0x67, 0x6F, 0x74, 0x20, 0x73, 0x6F, 0x20, 0x6D, 0x75, + 0x63, 0x68, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x65, + 0x78, 0x70, 0x65, 0x63, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6E, + 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x6F, 0x75, 0x74, 0x2D, 0x6F, 0x66, 0x2D, 0x74, 0x68, + 0x65, 0x2D, 0x77, 0x61, 0x79, 0x0D, 0x0A, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x61, 0x70, + 0x70, 0x65, 0x6E, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x69, 0x74, 0x20, 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x64, 0x75, 0x6C, 0x6C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x74, 0x75, 0x70, 0x69, + 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6C, 0x69, 0x66, 0x65, + 0x20, 0x74, 0x6F, 0x20, 0x67, 0x6F, 0x20, 0x6F, 0x6E, 0x0D, + 0x0A, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x6D, 0x6D, 0x6F, 0x6E, 0x20, 0x77, 0x61, 0x79, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x53, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x73, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x66, 0x69, 0x6E, + 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6B, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, + 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, + 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, + 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x0D, 0x0A, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, + 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, + 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, + 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, + 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, + 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, + 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, 0x48, 0x41, + 0x50, 0x54, 0x45, 0x52, 0x20, 0x49, 0x49, 0x2E, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x50, 0x6F, 0x6F, 0x6C, 0x20, 0x6F, 0x66, + 0x20, 0x54, 0x65, 0x61, 0x72, 0x73, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x43, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x65, 0x72, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, + 0x75, 0x73, 0x65, 0x72, 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, + 0x65, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x28, + 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x6F, + 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x73, 0x75, 0x72, 0x70, + 0x72, 0x69, 0x73, 0x65, 0x64, 0x2C, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x0D, 0x0A, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6F, + 0x72, 0x67, 0x6F, 0x74, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x74, + 0x6F, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x20, 0x67, 0x6F, + 0x6F, 0x64, 0x20, 0x45, 0x6E, 0x67, 0x6C, 0x69, 0x73, 0x68, + 0x29, 0x3B, 0x20, 0x27, 0x6E, 0x6F, 0x77, 0x20, 0x49, 0x27, + 0x6D, 0x0D, 0x0A, 0x6F, 0x70, 0x65, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, + 0x74, 0x20, 0x74, 0x65, 0x6C, 0x65, 0x73, 0x63, 0x6F, 0x70, + 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x65, 0x76, 0x65, + 0x72, 0x20, 0x77, 0x61, 0x73, 0x21, 0x20, 0x47, 0x6F, 0x6F, + 0x64, 0x2D, 0x62, 0x79, 0x65, 0x2C, 0x20, 0x66, 0x65, 0x65, + 0x74, 0x21, 0x27, 0x0D, 0x0A, 0x28, 0x66, 0x6F, 0x72, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x64, 0x6F, 0x77, 0x6E, + 0x20, 0x61, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x65, + 0x65, 0x74, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x73, + 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x62, + 0x65, 0x20, 0x61, 0x6C, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x6F, + 0x75, 0x74, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x73, 0x69, 0x67, + 0x68, 0x74, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x73, 0x6F, 0x20, 0x66, 0x61, 0x72, 0x20, 0x6F, + 0x66, 0x66, 0x29, 0x2E, 0x20, 0x27, 0x4F, 0x68, 0x2C, 0x20, + 0x6D, 0x79, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x6C, 0x69, + 0x74, 0x74, 0x6C, 0x65, 0x20, 0x66, 0x65, 0x65, 0x74, 0x2C, + 0x20, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x0D, + 0x0A, 0x77, 0x68, 0x6F, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, + 0x70, 0x75, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x79, 0x6F, 0x75, + 0x72, 0x20, 0x73, 0x68, 0x6F, 0x65, 0x73, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x73, 0x74, 0x6F, 0x63, 0x6B, 0x69, 0x6E, 0x67, + 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6E, 0x6F, 0x77, 0x2C, 0x20, 0x64, 0x65, 0x61, 0x72, 0x73, + 0x3F, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x73, 0x75, 0x72, 0x65, + 0x0D, 0x0A, 0x5F, 0x49, 0x5F, 0x20, 0x73, 0x68, 0x61, 0x6E, + 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x62, 0x6C, 0x65, + 0x21, 0x20, 0x49, 0x20, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, + 0x62, 0x65, 0x20, 0x61, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, + 0x20, 0x64, 0x65, 0x61, 0x6C, 0x20, 0x74, 0x6F, 0x6F, 0x20, + 0x66, 0x61, 0x72, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x72, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x0D, 0x0A, + 0x6D, 0x79, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x3A, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x6D, 0x61, 0x6E, + 0x61, 0x67, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x65, + 0x73, 0x74, 0x20, 0x77, 0x61, 0x79, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x63, 0x61, 0x6E, 0x3B, 0x2D, 0x2D, 0x62, 0x75, 0x74, + 0x20, 0x49, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, + 0x0D, 0x0A, 0x6B, 0x69, 0x6E, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x27, 0x6F, 0x72, 0x20, 0x70, 0x65, 0x72, 0x68, + 0x61, 0x70, 0x73, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, + 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x77, 0x61, 0x6C, 0x6B, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x49, 0x20, + 0x77, 0x61, 0x6E, 0x74, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x67, + 0x6F, 0x21, 0x20, 0x4C, 0x65, 0x74, 0x20, 0x6D, 0x65, 0x20, + 0x73, 0x65, 0x65, 0x3A, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, + 0x67, 0x69, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, + 0x61, 0x20, 0x6E, 0x65, 0x77, 0x20, 0x70, 0x61, 0x69, 0x72, + 0x20, 0x6F, 0x66, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x73, 0x20, + 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x43, 0x68, 0x72, 0x69, + 0x73, 0x74, 0x6D, 0x61, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x41, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x70, 0x6C, 0x61, + 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x68, + 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x68, 0x6F, 0x77, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x6D, 0x61, 0x6E, 0x61, 0x67, 0x65, 0x20, 0x69, 0x74, + 0x2E, 0x20, 0x27, 0x54, 0x68, 0x65, 0x79, 0x20, 0x6D, 0x75, + 0x73, 0x74, 0x0D, 0x0A, 0x67, 0x6F, 0x20, 0x62, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, + 0x72, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x3B, 0x20, 0x27, 0x61, 0x6E, + 0x64, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x66, 0x75, 0x6E, 0x6E, + 0x79, 0x20, 0x69, 0x74, 0x27, 0x6C, 0x6C, 0x20, 0x73, 0x65, + 0x65, 0x6D, 0x2C, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x69, 0x6E, + 0x67, 0x0D, 0x0A, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, + 0x73, 0x20, 0x74, 0x6F, 0x20, 0x6F, 0x6E, 0x65, 0x27, 0x73, + 0x20, 0x6F, 0x77, 0x6E, 0x20, 0x66, 0x65, 0x65, 0x74, 0x21, + 0x20, 0x41, 0x6E, 0x64, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x6F, + 0x64, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x77, 0x69, + 0x6C, 0x6C, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x21, 0x0D, 0x0A, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x4C, 0x49, + 0x43, 0x45, 0x27, 0x53, 0x20, 0x52, 0x49, 0x47, 0x48, 0x54, + 0x20, 0x46, 0x4F, 0x4F, 0x54, 0x2C, 0x20, 0x45, 0x53, 0x51, + 0x2E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x48, 0x45, 0x41, 0x52, 0x54, 0x48, 0x52, 0x55, 0x47, 0x2C, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x4E, 0x45, 0x41, 0x52, 0x20, 0x54, 0x48, 0x45, 0x20, + 0x46, 0x45, 0x4E, 0x44, 0x45, 0x52, 0x2C, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x28, 0x57, 0x49, 0x54, 0x48, 0x20, 0x41, 0x4C, 0x49, 0x43, + 0x45, 0x27, 0x53, 0x20, 0x4C, 0x4F, 0x56, 0x45, 0x29, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x4F, 0x68, 0x20, 0x64, 0x65, 0x61, + 0x72, 0x2C, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x6E, 0x6F, + 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x65, 0x20, 0x49, 0x27, 0x6D, + 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x4A, 0x75, 0x73, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x65, + 0x61, 0x64, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x6B, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x73, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x6F, 0x6F, 0x66, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x6C, 0x6C, 0x3A, 0x20, + 0x69, 0x6E, 0x20, 0x66, 0x61, 0x63, 0x74, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, 0x6E, 0x6F, 0x77, + 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, + 0x20, 0x6E, 0x69, 0x6E, 0x65, 0x20, 0x66, 0x65, 0x65, 0x74, + 0x20, 0x68, 0x69, 0x67, 0x68, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, + 0x63, 0x65, 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x75, 0x70, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x67, 0x6F, 0x6C, 0x64, 0x65, 0x6E, 0x0D, 0x0A, + 0x6B, 0x65, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x75, + 0x72, 0x72, 0x69, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x72, + 0x64, 0x65, 0x6E, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x50, 0x6F, 0x6F, 0x72, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x21, 0x20, 0x49, 0x74, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x61, 0x73, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x64, 0x6F, 0x2C, 0x20, 0x6C, 0x79, 0x69, + 0x6E, 0x67, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x6F, 0x6E, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2C, + 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, + 0x74, 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x69, 0x6E, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x72, + 0x64, 0x65, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x65, 0x79, 0x65, 0x3B, 0x20, 0x62, 0x75, + 0x74, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, 0x74, + 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x0D, 0x0A, 0x68, 0x6F, 0x70, + 0x65, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x61, 0x6E, + 0x20, 0x65, 0x76, 0x65, 0x72, 0x3A, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x73, 0x61, 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, + 0x74, 0x6F, 0x20, 0x63, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, + 0x75, 0x20, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x65, 0x20, 0x61, 0x73, 0x68, 0x61, 0x6D, 0x65, + 0x64, 0x20, 0x6F, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x27, 0x61, + 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x67, 0x69, 0x72, + 0x6C, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x0D, 0x0A, 0x79, 0x6F, + 0x75, 0x2C, 0x27, 0x20, 0x28, 0x73, 0x68, 0x65, 0x20, 0x6D, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, + 0x73, 0x61, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x29, 0x2C, + 0x20, 0x27, 0x74, 0x6F, 0x20, 0x67, 0x6F, 0x20, 0x6F, 0x6E, + 0x20, 0x63, 0x72, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, 0x79, 0x21, + 0x20, 0x53, 0x74, 0x6F, 0x70, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x0D, 0x0A, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x2C, 0x20, + 0x49, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, + 0x21, 0x27, 0x20, 0x42, 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, + 0x65, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x64, 0x64, 0x69, 0x6E, + 0x67, 0x20, 0x67, 0x61, 0x6C, 0x6C, 0x6F, 0x6E, 0x73, 0x20, + 0x6F, 0x66, 0x0D, 0x0A, 0x74, 0x65, 0x61, 0x72, 0x73, 0x2C, + 0x20, 0x75, 0x6E, 0x74, 0x69, 0x6C, 0x20, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, + 0x61, 0x72, 0x67, 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x6C, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, + 0x68, 0x65, 0x72, 0x2C, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x20, 0x66, 0x6F, 0x75, 0x72, 0x20, 0x69, 0x6E, 0x63, 0x68, + 0x65, 0x73, 0x0D, 0x0A, 0x64, 0x65, 0x65, 0x70, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x72, 0x65, 0x61, 0x63, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x64, 0x6F, 0x77, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x6C, 0x6C, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x66, 0x74, 0x65, 0x72, + 0x20, 0x61, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, 0x20, 0x61, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x70, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, + 0x66, 0x65, 0x65, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x73, 0x68, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, 0x79, 0x20, 0x64, + 0x72, 0x69, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, 0x65, + 0x79, 0x65, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, + 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x63, 0x6F, 0x6D, 0x69, 0x6E, 0x67, 0x2E, 0x20, 0x49, 0x74, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, + 0x68, 0x69, 0x74, 0x65, 0x0D, 0x0A, 0x52, 0x61, 0x62, 0x62, + 0x69, 0x74, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x69, + 0x6E, 0x67, 0x2C, 0x20, 0x73, 0x70, 0x6C, 0x65, 0x6E, 0x64, + 0x69, 0x64, 0x6C, 0x79, 0x20, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x64, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, + 0x20, 0x70, 0x61, 0x69, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x77, + 0x68, 0x69, 0x74, 0x65, 0x20, 0x6B, 0x69, 0x64, 0x20, 0x67, + 0x6C, 0x6F, 0x76, 0x65, 0x73, 0x20, 0x69, 0x6E, 0x0D, 0x0A, + 0x6F, 0x6E, 0x65, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x20, 0x66, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x3A, 0x20, 0x68, + 0x65, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x74, 0x72, 0x6F, + 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6C, 0x6F, 0x6E, + 0x67, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x67, 0x72, 0x65, + 0x61, 0x74, 0x0D, 0x0A, 0x68, 0x75, 0x72, 0x72, 0x79, 0x2C, + 0x20, 0x6D, 0x75, 0x74, 0x74, 0x65, 0x72, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x69, 0x6D, 0x73, 0x65, 0x6C, + 0x66, 0x20, 0x61, 0x73, 0x20, 0x68, 0x65, 0x20, 0x63, 0x61, + 0x6D, 0x65, 0x2C, 0x20, 0x27, 0x4F, 0x68, 0x21, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, + 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, + 0x65, 0x73, 0x73, 0x21, 0x0D, 0x0A, 0x4F, 0x68, 0x21, 0x20, + 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x62, 0x65, 0x20, 0x73, 0x61, 0x76, 0x61, 0x67, 0x65, 0x20, + 0x69, 0x66, 0x20, 0x49, 0x27, 0x76, 0x65, 0x20, 0x6B, 0x65, + 0x70, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x77, 0x61, 0x69, + 0x74, 0x69, 0x6E, 0x67, 0x21, 0x27, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x66, 0x65, 0x6C, 0x74, 0x20, 0x73, 0x6F, + 0x0D, 0x0A, 0x64, 0x65, 0x73, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79, + 0x20, 0x74, 0x6F, 0x20, 0x61, 0x73, 0x6B, 0x20, 0x68, 0x65, + 0x6C, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x20, + 0x6F, 0x6E, 0x65, 0x3B, 0x20, 0x73, 0x6F, 0x2C, 0x20, 0x77, + 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, + 0x62, 0x62, 0x69, 0x74, 0x0D, 0x0A, 0x63, 0x61, 0x6D, 0x65, + 0x20, 0x6E, 0x65, 0x61, 0x72, 0x20, 0x68, 0x65, 0x72, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, + 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x77, + 0x2C, 0x20, 0x74, 0x69, 0x6D, 0x69, 0x64, 0x20, 0x76, 0x6F, + 0x69, 0x63, 0x65, 0x2C, 0x20, 0x27, 0x49, 0x66, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x2C, + 0x20, 0x73, 0x69, 0x72, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x54, + 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x20, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x20, 0x76, 0x69, + 0x6F, 0x6C, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x2C, 0x20, 0x64, + 0x72, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x20, 0x6B, 0x69, 0x64, + 0x20, 0x67, 0x6C, 0x6F, 0x76, 0x65, 0x73, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x6E, 0x2C, + 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x6B, 0x75, 0x72, + 0x72, 0x69, 0x65, 0x64, 0x20, 0x61, 0x77, 0x61, 0x79, 0x20, + 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, + 0x61, 0x72, 0x6B, 0x6E, 0x65, 0x73, 0x73, 0x20, 0x61, 0x73, + 0x20, 0x68, 0x61, 0x72, 0x64, 0x20, 0x61, 0x73, 0x20, 0x68, + 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x67, 0x6F, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x75, 0x70, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x61, 0x6E, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x67, 0x6C, 0x6F, 0x76, 0x65, 0x73, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x68, 0x6F, 0x74, 0x2C, 0x20, + 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x6B, 0x65, 0x70, 0x74, 0x20, + 0x66, 0x61, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, + 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x3A, 0x20, + 0x27, 0x44, 0x65, 0x61, 0x72, 0x2C, 0x20, 0x64, 0x65, 0x61, + 0x72, 0x21, 0x20, 0x48, 0x6F, 0x77, 0x0D, 0x0A, 0x71, 0x75, + 0x65, 0x65, 0x72, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6F, + 0x2D, 0x64, 0x61, 0x79, 0x21, 0x20, 0x41, 0x6E, 0x64, 0x20, + 0x79, 0x65, 0x73, 0x74, 0x65, 0x72, 0x64, 0x61, 0x79, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, + 0x61, 0x73, 0x20, 0x75, 0x73, 0x75, 0x61, 0x6C, 0x2E, 0x0D, + 0x0A, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x20, + 0x69, 0x66, 0x20, 0x49, 0x27, 0x76, 0x65, 0x20, 0x62, 0x65, + 0x65, 0x6E, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x64, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x69, + 0x67, 0x68, 0x74, 0x3F, 0x20, 0x4C, 0x65, 0x74, 0x20, 0x6D, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x3A, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x49, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x73, 0x61, 0x6D, 0x65, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, + 0x49, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x75, 0x70, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x6D, 0x6F, 0x72, 0x6E, 0x69, 0x6E, + 0x67, 0x3F, 0x20, 0x49, 0x20, 0x61, 0x6C, 0x6D, 0x6F, 0x73, + 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x49, 0x20, + 0x63, 0x61, 0x6E, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, + 0x65, 0x72, 0x20, 0x66, 0x65, 0x65, 0x6C, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x0D, 0x0A, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x74, + 0x2E, 0x20, 0x42, 0x75, 0x74, 0x20, 0x69, 0x66, 0x20, 0x49, + 0x27, 0x6D, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x61, 0x6D, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x2C, 0x20, 0x57, + 0x68, 0x6F, 0x0D, 0x0A, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x20, 0x61, 0x6D, 0x20, + 0x49, 0x3F, 0x20, 0x41, 0x68, 0x2C, 0x20, 0x54, 0x48, 0x41, + 0x54, 0x27, 0x53, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, + 0x65, 0x61, 0x74, 0x20, 0x70, 0x75, 0x7A, 0x7A, 0x6C, 0x65, + 0x21, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x6B, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x6F, 0x76, 0x65, + 0x72, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, 0x65, 0x6E, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x6B, 0x6E, 0x65, 0x77, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, + 0x61, 0x67, 0x65, 0x20, 0x61, 0x73, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x74, 0x6F, 0x0D, 0x0A, + 0x73, 0x65, 0x65, 0x20, 0x69, 0x66, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x63, 0x68, 0x61, + 0x6E, 0x67, 0x65, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, + 0x6E, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x6D, 0x20, + 0x73, 0x75, 0x72, 0x65, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x41, 0x64, 0x61, 0x2C, 0x27, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x27, + 0x66, 0x6F, 0x72, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x61, + 0x69, 0x72, 0x20, 0x67, 0x6F, 0x65, 0x73, 0x20, 0x69, 0x6E, + 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x6C, 0x6F, 0x6E, 0x67, + 0x0D, 0x0A, 0x72, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x74, 0x73, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x69, 0x6E, 0x65, + 0x20, 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x67, + 0x6F, 0x20, 0x69, 0x6E, 0x20, 0x72, 0x69, 0x6E, 0x67, 0x6C, + 0x65, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, + 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x27, 0x6D, 0x20, + 0x73, 0x75, 0x72, 0x65, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, + 0x27, 0x74, 0x0D, 0x0A, 0x62, 0x65, 0x20, 0x4D, 0x61, 0x62, + 0x65, 0x6C, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x49, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x73, + 0x6F, 0x72, 0x74, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x68, 0x65, 0x2C, 0x20, 0x6F, 0x68, 0x21, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x73, 0x20, 0x73, + 0x75, 0x63, 0x68, 0x20, 0x61, 0x0D, 0x0A, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x21, 0x20, + 0x42, 0x65, 0x73, 0x69, 0x64, 0x65, 0x73, 0x2C, 0x20, 0x53, + 0x48, 0x45, 0x27, 0x53, 0x20, 0x73, 0x68, 0x65, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x49, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x2D, 0x2D, 0x6F, 0x68, 0x20, 0x64, + 0x65, 0x61, 0x72, 0x2C, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x70, + 0x75, 0x7A, 0x7A, 0x6C, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x69, + 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x69, 0x73, 0x21, 0x20, + 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x74, 0x72, 0x79, 0x20, 0x69, + 0x66, 0x20, 0x49, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x73, 0x20, 0x49, 0x20, 0x75, 0x73, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x20, + 0x4C, 0x65, 0x74, 0x20, 0x6D, 0x65, 0x0D, 0x0A, 0x73, 0x65, + 0x65, 0x3A, 0x20, 0x66, 0x6F, 0x75, 0x72, 0x20, 0x74, 0x69, + 0x6D, 0x65, 0x73, 0x20, 0x66, 0x69, 0x76, 0x65, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x77, 0x65, 0x6C, 0x76, 0x65, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x75, 0x72, 0x20, 0x74, + 0x69, 0x6D, 0x65, 0x73, 0x20, 0x73, 0x69, 0x78, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x69, 0x72, 0x74, 0x65, 0x65, 0x6E, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x66, 0x6F, 0x75, + 0x72, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x73, 0x20, 0x73, 0x65, + 0x76, 0x65, 0x6E, 0x20, 0x69, 0x73, 0x2D, 0x2D, 0x6F, 0x68, + 0x20, 0x64, 0x65, 0x61, 0x72, 0x21, 0x20, 0x49, 0x20, 0x73, + 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, + 0x20, 0x67, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x77, + 0x65, 0x6E, 0x74, 0x79, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x72, 0x61, 0x74, 0x65, 0x21, 0x0D, 0x0A, + 0x48, 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x6C, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x54, 0x61, + 0x62, 0x6C, 0x65, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, + 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x66, 0x79, 0x3A, + 0x20, 0x6C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x74, 0x72, 0x79, + 0x20, 0x47, 0x65, 0x6F, 0x67, 0x72, 0x61, 0x70, 0x68, 0x79, + 0x2E, 0x0D, 0x0A, 0x4C, 0x6F, 0x6E, 0x64, 0x6F, 0x6E, 0x20, + 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x70, + 0x69, 0x74, 0x61, 0x6C, 0x20, 0x6F, 0x66, 0x20, 0x50, 0x61, + 0x72, 0x69, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x50, + 0x61, 0x72, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x61, 0x70, 0x69, 0x74, 0x61, 0x6C, 0x20, + 0x6F, 0x66, 0x20, 0x52, 0x6F, 0x6D, 0x65, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x0D, 0x0A, 0x52, 0x6F, 0x6D, 0x65, 0x2D, 0x2D, + 0x6E, 0x6F, 0x2C, 0x20, 0x54, 0x48, 0x41, 0x54, 0x27, 0x53, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x77, 0x72, 0x6F, 0x6E, 0x67, + 0x2C, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x63, 0x65, 0x72, 0x74, + 0x61, 0x69, 0x6E, 0x21, 0x20, 0x49, 0x20, 0x6D, 0x75, 0x73, + 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, + 0x6E, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x64, 0x20, + 0x66, 0x6F, 0x72, 0x0D, 0x0A, 0x4D, 0x61, 0x62, 0x65, 0x6C, + 0x21, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x74, 0x72, 0x79, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x61, 0x79, 0x20, 0x22, + 0x48, 0x6F, 0x77, 0x20, 0x64, 0x6F, 0x74, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x2D, + 0x2D, 0x22, 0x27, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x65, 0x64, 0x20, + 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x68, 0x61, 0x6E, 0x64, 0x73, + 0x20, 0x6F, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, 0x6C, 0x61, + 0x70, 0x20, 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x73, 0x61, 0x79, + 0x69, 0x6E, 0x67, 0x20, 0x6C, 0x65, 0x73, 0x73, 0x6F, 0x6E, + 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, + 0x61, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x70, 0x65, + 0x61, 0x74, 0x20, 0x69, 0x74, 0x2C, 0x0D, 0x0A, 0x62, 0x75, + 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x76, 0x6F, 0x69, 0x63, + 0x65, 0x20, 0x73, 0x6F, 0x75, 0x6E, 0x64, 0x65, 0x64, 0x20, + 0x68, 0x6F, 0x61, 0x72, 0x73, 0x65, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x74, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, + 0x72, 0x64, 0x73, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x61, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x64, 0x6F, 0x3A, 0x2D, 0x2D, 0x0D, 0x0A, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x48, 0x6F, + 0x77, 0x20, 0x64, 0x6F, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x63, 0x72, + 0x6F, 0x63, 0x6F, 0x64, 0x69, 0x6C, 0x65, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x6D, 0x70, 0x72, 0x6F, + 0x76, 0x65, 0x20, 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, 0x69, + 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x61, 0x69, 0x6C, 0x2C, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x6E, 0x64, + 0x20, 0x70, 0x6F, 0x75, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x61, 0x74, 0x65, 0x72, 0x73, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4E, 0x69, 0x6C, 0x65, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4F, 0x6E, 0x20, 0x65, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x67, 0x6F, 0x6C, 0x64, 0x65, + 0x6E, 0x20, 0x73, 0x63, 0x61, 0x6C, 0x65, 0x21, 0x0D, 0x0A, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x48, 0x6F, + 0x77, 0x20, 0x63, 0x68, 0x65, 0x65, 0x72, 0x66, 0x75, 0x6C, + 0x6C, 0x79, 0x20, 0x68, 0x65, 0x20, 0x73, 0x65, 0x65, 0x6D, + 0x73, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x72, 0x69, 0x6E, 0x2C, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x48, 0x6F, + 0x77, 0x20, 0x6E, 0x65, 0x61, 0x74, 0x6C, 0x79, 0x20, 0x73, + 0x70, 0x72, 0x65, 0x61, 0x64, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x63, 0x6C, 0x61, 0x77, 0x73, 0x2C, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x77, 0x65, 0x6C, + 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x66, 0x69, 0x73, 0x68, 0x65, 0x73, 0x20, 0x69, + 0x6E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x57, + 0x69, 0x74, 0x68, 0x20, 0x67, 0x65, 0x6E, 0x74, 0x6C, 0x79, + 0x20, 0x73, 0x6D, 0x69, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x6A, + 0x61, 0x77, 0x73, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x27, 0x6D, 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, + 0x68, 0x6F, 0x73, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x70, 0x6F, 0x6F, 0x72, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, 0x65, 0x79, 0x65, 0x73, + 0x0D, 0x0A, 0x66, 0x69, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x74, 0x65, 0x61, 0x72, 0x73, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x61, 0x73, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, + 0x2C, 0x20, 0x27, 0x49, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, + 0x62, 0x65, 0x20, 0x4D, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x61, + 0x66, 0x74, 0x65, 0x72, 0x20, 0x61, 0x6C, 0x6C, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x49, 0x20, 0x73, 0x68, 0x61, + 0x6C, 0x6C, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x67, 0x6F, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x69, + 0x76, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x70, 0x6F, 0x6B, 0x79, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x68, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6E, + 0x65, 0x78, 0x74, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x6E, 0x6F, + 0x20, 0x74, 0x6F, 0x79, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x70, + 0x6C, 0x61, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x68, 0x21, 0x20, 0x65, 0x76, + 0x65, 0x72, 0x20, 0x73, 0x6F, 0x20, 0x6D, 0x61, 0x6E, 0x79, + 0x20, 0x6C, 0x65, 0x73, 0x73, 0x6F, 0x6E, 0x73, 0x20, 0x74, + 0x6F, 0x20, 0x6C, 0x65, 0x61, 0x72, 0x6E, 0x21, 0x20, 0x4E, + 0x6F, 0x2C, 0x20, 0x49, 0x27, 0x76, 0x65, 0x0D, 0x0A, 0x6D, + 0x61, 0x64, 0x65, 0x20, 0x75, 0x70, 0x20, 0x6D, 0x79, 0x20, + 0x6D, 0x69, 0x6E, 0x64, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x20, 0x69, 0x74, 0x3B, 0x20, 0x69, 0x66, 0x20, 0x49, 0x27, + 0x6D, 0x20, 0x4D, 0x61, 0x62, 0x65, 0x6C, 0x2C, 0x20, 0x49, + 0x27, 0x6C, 0x6C, 0x20, 0x73, 0x74, 0x61, 0x79, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x65, 0x21, 0x20, + 0x49, 0x74, 0x27, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x20, 0x6E, + 0x6F, 0x0D, 0x0A, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x70, 0x75, 0x74, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x73, 0x61, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x22, + 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x75, 0x70, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x64, 0x65, 0x61, 0x72, 0x21, + 0x22, 0x20, 0x49, 0x0D, 0x0A, 0x73, 0x68, 0x61, 0x6C, 0x6C, + 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, + 0x20, 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x61, + 0x79, 0x20, 0x22, 0x57, 0x68, 0x6F, 0x20, 0x61, 0x6D, 0x20, + 0x49, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x3F, 0x20, 0x54, 0x65, + 0x6C, 0x6C, 0x20, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x2C, 0x0D, 0x0A, 0x69, + 0x66, 0x20, 0x49, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x2C, 0x20, 0x49, 0x27, + 0x6C, 0x6C, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x75, 0x70, + 0x3A, 0x20, 0x69, 0x66, 0x20, 0x6E, 0x6F, 0x74, 0x2C, 0x20, + 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x73, 0x74, 0x61, 0x79, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x65, 0x0D, + 0x0A, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x49, 0x27, 0x6D, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x65, + 0x6C, 0x73, 0x65, 0x22, 0x2D, 0x2D, 0x62, 0x75, 0x74, 0x2C, + 0x20, 0x6F, 0x68, 0x20, 0x64, 0x65, 0x61, 0x72, 0x21, 0x27, + 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, + 0x20, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, 0x20, 0x62, 0x75, + 0x72, 0x73, 0x74, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x74, 0x65, + 0x61, 0x72, 0x73, 0x2C, 0x20, 0x27, 0x49, 0x20, 0x64, 0x6F, + 0x20, 0x77, 0x69, 0x73, 0x68, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x57, 0x4F, 0x55, 0x4C, 0x44, 0x20, 0x70, 0x75, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x21, 0x20, 0x49, + 0x20, 0x61, 0x6D, 0x20, 0x73, 0x6F, 0x20, 0x56, 0x45, 0x52, + 0x59, 0x20, 0x74, 0x69, 0x72, 0x65, 0x64, 0x0D, 0x0A, 0x6F, + 0x66, 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x61, 0x6C, 0x6F, 0x6E, 0x65, 0x20, 0x68, 0x65, + 0x72, 0x65, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x64, 0x6F, 0x77, 0x6E, + 0x20, 0x61, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x61, + 0x6E, 0x64, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x73, 0x75, 0x72, 0x70, 0x72, 0x69, 0x73, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, 0x0D, + 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x70, 0x75, 0x74, 0x20, 0x6F, 0x6E, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x27, 0x73, + 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x77, 0x68, + 0x69, 0x74, 0x65, 0x20, 0x6B, 0x69, 0x64, 0x20, 0x67, 0x6C, + 0x6F, 0x76, 0x65, 0x73, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, + 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x74, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x2E, 0x20, 0x27, + 0x48, 0x6F, 0x77, 0x20, 0x43, 0x41, 0x4E, 0x20, 0x49, 0x20, + 0x68, 0x61, 0x76, 0x65, 0x20, 0x64, 0x6F, 0x6E, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x3F, 0x27, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x2E, 0x20, + 0x27, 0x49, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x0D, 0x0A, 0x62, + 0x65, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x20, + 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6E, 0x2E, 0x27, 0x20, 0x53, 0x68, 0x65, 0x20, 0x67, 0x6F, + 0x74, 0x20, 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x6D, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x0D, 0x0A, 0x68, + 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x62, 0x79, 0x20, + 0x69, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x6F, + 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2C, 0x20, + 0x61, 0x73, 0x20, 0x6E, 0x65, 0x61, 0x72, 0x6C, 0x79, 0x20, + 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x67, 0x75, 0x65, 0x73, 0x73, 0x2C, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, + 0x77, 0x0D, 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, + 0x77, 0x6F, 0x20, 0x66, 0x65, 0x65, 0x74, 0x20, 0x68, 0x69, + 0x67, 0x68, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, + 0x20, 0x73, 0x68, 0x72, 0x69, 0x6E, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x72, 0x61, 0x70, 0x69, 0x64, 0x6C, 0x79, 0x3A, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x66, + 0x6F, 0x75, 0x6E, 0x64, 0x0D, 0x0A, 0x6F, 0x75, 0x74, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x61, 0x75, 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x66, 0x61, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x68, 0x6F, 0x6C, 0x64, 0x69, 0x6E, 0x67, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x64, 0x72, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x0D, 0x0A, 0x69, + 0x74, 0x20, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, 0x79, 0x2C, + 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, + 0x69, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x76, 0x6F, + 0x69, 0x64, 0x20, 0x73, 0x68, 0x72, 0x69, 0x6E, 0x6B, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x77, 0x61, 0x79, 0x20, 0x61, 0x6C, + 0x74, 0x6F, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, 0x74, 0x20, 0x57, + 0x41, 0x53, 0x20, 0x61, 0x20, 0x6E, 0x61, 0x72, 0x72, 0x6F, + 0x77, 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x21, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2C, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, + 0x64, 0x65, 0x61, 0x6C, 0x20, 0x66, 0x72, 0x69, 0x67, 0x68, + 0x74, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x0D, 0x0A, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, + 0x20, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x2C, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x67, 0x6C, + 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x6E, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x73, + 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x69, 0x6E, 0x20, 0x65, 0x78, + 0x69, 0x73, 0x74, 0x65, 0x6E, 0x63, 0x65, 0x3B, 0x20, 0x27, + 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x6E, 0x6F, 0x77, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x72, + 0x64, 0x65, 0x6E, 0x21, 0x27, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x72, 0x61, 0x6E, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x70, 0x65, + 0x65, 0x64, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x3A, 0x0D, 0x0A, 0x62, + 0x75, 0x74, 0x2C, 0x20, 0x61, 0x6C, 0x61, 0x73, 0x21, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x73, 0x68, 0x75, 0x74, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x67, 0x6F, 0x6C, + 0x64, 0x65, 0x6E, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x77, 0x61, + 0x73, 0x0D, 0x0A, 0x6C, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x6C, 0x61, 0x73, + 0x73, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x73, + 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x2C, 0x20, 0x27, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, + 0x20, 0x61, 0x72, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x73, 0x65, + 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x65, 0x76, 0x65, 0x72, + 0x2C, 0x27, 0x0D, 0x0A, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x72, + 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x2C, 0x20, 0x27, 0x66, + 0x6F, 0x72, 0x20, 0x49, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x6D, + 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x2C, 0x20, + 0x6E, 0x65, 0x76, 0x65, 0x72, 0x21, 0x0D, 0x0A, 0x41, 0x6E, + 0x64, 0x20, 0x49, 0x20, 0x64, 0x65, 0x63, 0x6C, 0x61, 0x72, + 0x65, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x74, 0x6F, 0x6F, + 0x20, 0x62, 0x61, 0x64, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x21, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x41, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, + 0x77, 0x6F, 0x72, 0x64, 0x73, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x66, 0x6F, 0x6F, 0x74, 0x20, 0x73, 0x6C, 0x69, 0x70, 0x70, + 0x65, 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6D, + 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x73, 0x70, 0x6C, + 0x61, 0x73, 0x68, 0x21, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x75, 0x70, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x63, 0x68, 0x69, 0x6E, 0x20, 0x69, + 0x6E, 0x20, 0x73, 0x61, 0x6C, 0x74, 0x20, 0x77, 0x61, 0x74, + 0x65, 0x72, 0x2E, 0x20, 0x48, 0x65, 0x72, 0x20, 0x66, 0x69, + 0x72, 0x73, 0x74, 0x20, 0x69, 0x64, 0x65, 0x61, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, + 0x65, 0x0D, 0x0A, 0x68, 0x61, 0x64, 0x20, 0x73, 0x6F, 0x6D, + 0x65, 0x68, 0x6F, 0x77, 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x65, + 0x6E, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x65, 0x61, 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, + 0x61, 0x73, 0x65, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x20, + 0x67, 0x6F, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x62, 0x79, + 0x0D, 0x0A, 0x72, 0x61, 0x69, 0x6C, 0x77, 0x61, 0x79, 0x2C, + 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, + 0x66, 0x2E, 0x20, 0x28, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x61, 0x73, + 0x69, 0x64, 0x65, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x69, + 0x6E, 0x0D, 0x0A, 0x68, 0x65, 0x72, 0x20, 0x6C, 0x69, 0x66, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, + 0x20, 0x63, 0x6F, 0x6E, 0x63, 0x6C, 0x75, 0x73, 0x69, 0x6F, + 0x6E, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x68, + 0x65, 0x72, 0x65, 0x76, 0x65, 0x72, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x67, 0x6F, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x6F, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x6E, 0x67, 0x6C, 0x69, + 0x73, 0x68, 0x20, 0x63, 0x6F, 0x61, 0x73, 0x74, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, 0x61, 0x20, + 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, + 0x62, 0x61, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x61, + 0x63, 0x68, 0x69, 0x6E, 0x65, 0x73, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x73, 0x65, 0x61, 0x2C, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, + 0x72, 0x65, 0x6E, 0x20, 0x64, 0x69, 0x67, 0x67, 0x69, 0x6E, + 0x67, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x6E, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x77, + 0x6F, 0x6F, 0x64, 0x65, 0x6E, 0x20, 0x73, 0x70, 0x61, 0x64, + 0x65, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x61, + 0x20, 0x72, 0x6F, 0x77, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x6C, + 0x6F, 0x64, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x6F, 0x75, + 0x73, 0x65, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, + 0x65, 0x68, 0x69, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6D, + 0x20, 0x61, 0x20, 0x72, 0x61, 0x69, 0x6C, 0x77, 0x61, 0x79, + 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x29, + 0x20, 0x48, 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x0D, 0x0A, + 0x6D, 0x61, 0x64, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x6F, 0x6F, 0x6C, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x65, 0x61, + 0x72, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x77, 0x65, 0x70, + 0x74, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, + 0x0D, 0x0A, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x69, 0x6E, 0x65, + 0x20, 0x66, 0x65, 0x65, 0x74, 0x20, 0x68, 0x69, 0x67, 0x68, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x77, 0x69, + 0x73, 0x68, 0x20, 0x49, 0x20, 0x68, 0x61, 0x64, 0x6E, 0x27, + 0x74, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, 0x20, 0x73, 0x6F, + 0x20, 0x6D, 0x75, 0x63, 0x68, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, + 0x6D, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x74, + 0x72, 0x79, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x74, 0x6F, 0x20, + 0x66, 0x69, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, 0x77, + 0x61, 0x79, 0x20, 0x6F, 0x75, 0x74, 0x2E, 0x20, 0x27, 0x49, + 0x20, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x20, + 0x70, 0x75, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x69, 0x74, 0x20, 0x6E, 0x6F, 0x77, 0x2C, + 0x20, 0x49, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x73, 0x65, + 0x2C, 0x20, 0x62, 0x79, 0x0D, 0x0A, 0x62, 0x65, 0x69, 0x6E, + 0x67, 0x20, 0x64, 0x72, 0x6F, 0x77, 0x6E, 0x65, 0x64, 0x20, + 0x69, 0x6E, 0x20, 0x6D, 0x79, 0x20, 0x6F, 0x77, 0x6E, 0x20, + 0x74, 0x65, 0x61, 0x72, 0x73, 0x21, 0x20, 0x54, 0x68, 0x61, + 0x74, 0x20, 0x57, 0x49, 0x4C, 0x4C, 0x20, 0x62, 0x65, 0x20, + 0x61, 0x20, 0x71, 0x75, 0x65, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, + 0x20, 0x73, 0x75, 0x72, 0x65, 0x21, 0x0D, 0x0A, 0x48, 0x6F, + 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, 0x20, 0x65, 0x76, 0x65, + 0x72, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x73, + 0x20, 0x71, 0x75, 0x65, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x2D, + 0x64, 0x61, 0x79, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x4A, + 0x75, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x73, + 0x70, 0x6C, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x6C, 0x20, 0x61, 0x20, 0x6C, + 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x77, 0x61, 0x79, 0x0D, + 0x0A, 0x6F, 0x66, 0x66, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x73, 0x77, 0x61, 0x6D, 0x20, 0x6E, + 0x65, 0x61, 0x72, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x6D, + 0x61, 0x6B, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x3A, + 0x20, 0x61, 0x74, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x0D, 0x0A, 0x69, 0x74, 0x20, 0x6D, 0x75, 0x73, 0x74, + 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x77, 0x61, 0x6C, 0x72, + 0x75, 0x73, 0x20, 0x6F, 0x72, 0x20, 0x68, 0x69, 0x70, 0x70, + 0x6F, 0x70, 0x6F, 0x74, 0x61, 0x6D, 0x75, 0x73, 0x2C, 0x20, + 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x73, 0x6D, + 0x61, 0x6C, 0x6C, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x77, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x6F, 0x6F, 0x6E, + 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x61, 0x20, 0x6D, + 0x6F, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x68, 0x61, 0x64, 0x0D, 0x0A, 0x73, 0x6C, 0x69, 0x70, 0x70, + 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x6C, 0x69, 0x6B, 0x65, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x69, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x61, + 0x6E, 0x79, 0x20, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x6E, 0x6F, + 0x77, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x27, + 0x74, 0x6F, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x3F, 0x0D, 0x0A, 0x45, 0x76, 0x65, 0x72, 0x79, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x73, 0x20, 0x73, + 0x6F, 0x20, 0x6F, 0x75, 0x74, 0x2D, 0x6F, 0x66, 0x2D, 0x74, + 0x68, 0x65, 0x2D, 0x77, 0x61, 0x79, 0x20, 0x64, 0x6F, 0x77, + 0x6E, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2C, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x49, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x76, 0x65, + 0x72, 0x79, 0x0D, 0x0A, 0x6C, 0x69, 0x6B, 0x65, 0x6C, 0x79, + 0x20, 0x69, 0x74, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x74, 0x61, + 0x6C, 0x6B, 0x3A, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6E, 0x79, + 0x20, 0x72, 0x61, 0x74, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x68, 0x61, + 0x72, 0x6D, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x72, 0x79, 0x69, + 0x6E, 0x67, 0x2E, 0x27, 0x20, 0x53, 0x6F, 0x20, 0x73, 0x68, + 0x65, 0x0D, 0x0A, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x3A, 0x20, + 0x27, 0x4F, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, + 0x64, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, + 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x70, 0x6F, 0x6F, 0x6C, 0x3F, 0x20, 0x49, 0x20, + 0x61, 0x6D, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x74, 0x69, + 0x72, 0x65, 0x64, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x73, 0x77, + 0x69, 0x6D, 0x6D, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2C, 0x20, 0x4F, + 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x21, 0x27, 0x20, 0x28, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, + 0x67, 0x68, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6D, + 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x0D, 0x0A, 0x77, 0x61, + 0x79, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x20, 0x6D, + 0x6F, 0x75, 0x73, 0x65, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, + 0x64, 0x6F, 0x6E, 0x65, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x65, + 0x66, 0x6F, 0x72, 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x0D, + 0x0A, 0x73, 0x68, 0x65, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, + 0x62, 0x65, 0x72, 0x65, 0x64, 0x20, 0x68, 0x61, 0x76, 0x69, + 0x6E, 0x67, 0x20, 0x73, 0x65, 0x65, 0x6E, 0x20, 0x69, 0x6E, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x62, 0x72, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x27, 0x73, 0x20, 0x4C, 0x61, 0x74, 0x69, 0x6E, + 0x20, 0x47, 0x72, 0x61, 0x6D, 0x6D, 0x61, 0x72, 0x2C, 0x20, + 0x27, 0x41, 0x20, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x2D, 0x2D, + 0x6F, 0x66, 0x0D, 0x0A, 0x61, 0x20, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x2D, 0x2D, 0x74, 0x6F, 0x20, 0x61, 0x20, 0x6D, 0x6F, + 0x75, 0x73, 0x65, 0x2D, 0x2D, 0x61, 0x20, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x2D, 0x2D, 0x4F, 0x20, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x21, 0x27, 0x29, 0x20, 0x54, 0x68, 0x65, 0x20, 0x4D, + 0x6F, 0x75, 0x73, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, + 0x64, 0x20, 0x61, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x72, + 0x61, 0x74, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x69, 0x6E, 0x71, + 0x75, 0x69, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x6C, 0x79, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x65, 0x65, 0x6D, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x74, 0x6F, 0x20, 0x77, 0x69, 0x6E, 0x6B, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x69, 0x74, 0x73, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x65, 0x79, 0x65, 0x73, 0x2C, 0x0D, 0x0A, 0x62, 0x75, + 0x74, 0x20, 0x69, 0x74, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x50, 0x65, 0x72, 0x68, 0x61, 0x70, 0x73, + 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, + 0x74, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x73, 0x74, 0x61, + 0x6E, 0x64, 0x20, 0x45, 0x6E, 0x67, 0x6C, 0x69, 0x73, 0x68, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x3B, 0x20, 0x27, 0x49, + 0x20, 0x64, 0x61, 0x72, 0x65, 0x73, 0x61, 0x79, 0x20, 0x69, + 0x74, 0x27, 0x73, 0x0D, 0x0A, 0x61, 0x20, 0x46, 0x72, 0x65, + 0x6E, 0x63, 0x68, 0x20, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x2C, + 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x76, 0x65, 0x72, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x57, 0x69, 0x6C, 0x6C, + 0x69, 0x61, 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6F, + 0x6E, 0x71, 0x75, 0x65, 0x72, 0x6F, 0x72, 0x2E, 0x27, 0x20, + 0x28, 0x46, 0x6F, 0x72, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x61, 0x6C, 0x6C, 0x0D, 0x0A, 0x68, 0x65, 0x72, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x68, 0x69, 0x73, 0x74, 0x6F, 0x72, 0x79, + 0x2C, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x6E, 0x6F, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x63, 0x6C, 0x65, 0x61, 0x72, 0x20, 0x6E, 0x6F, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x6C, 0x6F, 0x6E, + 0x67, 0x20, 0x61, 0x67, 0x6F, 0x0D, 0x0A, 0x61, 0x6E, 0x79, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x68, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x65, 0x64, 0x2E, 0x29, + 0x20, 0x53, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x62, 0x65, + 0x67, 0x61, 0x6E, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x3A, + 0x20, 0x27, 0x4F, 0x75, 0x20, 0x65, 0x73, 0x74, 0x20, 0x6D, + 0x61, 0x20, 0x63, 0x68, 0x61, 0x74, 0x74, 0x65, 0x3F, 0x27, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x0D, 0x0A, 0x77, 0x61, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, + 0x74, 0x20, 0x73, 0x65, 0x6E, 0x74, 0x65, 0x6E, 0x63, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, 0x46, 0x72, + 0x65, 0x6E, 0x63, 0x68, 0x20, 0x6C, 0x65, 0x73, 0x73, 0x6F, + 0x6E, 0x2D, 0x62, 0x6F, 0x6F, 0x6B, 0x2E, 0x20, 0x54, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x67, 0x61, + 0x76, 0x65, 0x20, 0x61, 0x0D, 0x0A, 0x73, 0x75, 0x64, 0x64, + 0x65, 0x6E, 0x20, 0x6C, 0x65, 0x61, 0x70, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x74, 0x65, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x71, 0x75, 0x69, 0x76, 0x65, 0x72, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x66, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2E, 0x0D, 0x0A, + 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x49, 0x20, 0x62, 0x65, 0x67, + 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x70, 0x61, 0x72, 0x64, + 0x6F, 0x6E, 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x68, 0x61, 0x73, + 0x74, 0x69, 0x6C, 0x79, 0x2C, 0x20, 0x61, 0x66, 0x72, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x68, 0x75, 0x72, 0x74, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x72, + 0x20, 0x61, 0x6E, 0x69, 0x6D, 0x61, 0x6C, 0x27, 0x73, 0x20, + 0x66, 0x65, 0x65, 0x6C, 0x69, 0x6E, 0x67, 0x73, 0x2E, 0x20, + 0x27, 0x49, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x66, + 0x6F, 0x72, 0x67, 0x6F, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x64, 0x69, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x63, 0x61, 0x74, 0x73, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x74, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x63, 0x61, 0x74, 0x73, 0x21, 0x27, 0x20, 0x63, + 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, + 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x73, 0x68, 0x72, 0x69, 0x6C, 0x6C, 0x2C, 0x20, 0x70, + 0x61, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x74, 0x65, 0x20, + 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2E, 0x20, 0x27, 0x57, 0x6F, + 0x75, 0x6C, 0x64, 0x0D, 0x0A, 0x59, 0x4F, 0x55, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x63, 0x61, 0x74, 0x73, 0x20, 0x69, + 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x77, 0x65, 0x72, 0x65, + 0x20, 0x6D, 0x65, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x68, + 0x61, 0x70, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x73, 0x6F, 0x6F, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x3A, + 0x20, 0x27, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x61, 0x6E, 0x67, 0x72, 0x79, 0x0D, 0x0A, 0x61, 0x62, + 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, 0x2E, 0x20, 0x41, 0x6E, + 0x64, 0x20, 0x79, 0x65, 0x74, 0x20, 0x49, 0x20, 0x77, 0x69, + 0x73, 0x68, 0x20, 0x49, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x73, 0x68, 0x6F, 0x77, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6F, 0x75, 0x72, 0x20, 0x63, 0x61, 0x74, 0x20, 0x44, 0x69, + 0x6E, 0x61, 0x68, 0x3A, 0x20, 0x49, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x6B, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x64, 0x0D, 0x0A, + 0x74, 0x61, 0x6B, 0x65, 0x20, 0x61, 0x20, 0x66, 0x61, 0x6E, + 0x63, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x61, 0x74, 0x73, + 0x20, 0x69, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x73, + 0x65, 0x65, 0x20, 0x68, 0x65, 0x72, 0x2E, 0x20, 0x53, 0x68, + 0x65, 0x20, 0x69, 0x73, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x64, 0x65, 0x61, 0x72, 0x20, 0x71, 0x75, 0x69, + 0x65, 0x74, 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2C, + 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x68, 0x61, 0x6C, + 0x66, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x73, 0x77, 0x61, 0x6D, 0x20, 0x6C, 0x61, 0x7A, 0x69, + 0x6C, 0x79, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x70, 0x6F, 0x6F, + 0x6C, 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x73, 0x69, 0x74, 0x73, 0x20, 0x70, 0x75, 0x72, + 0x72, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x6F, 0x20, 0x6E, 0x69, + 0x63, 0x65, 0x6C, 0x79, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x66, 0x69, 0x72, 0x65, 0x2C, 0x20, 0x6C, 0x69, + 0x63, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x70, 0x61, 0x77, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, + 0x77, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x66, 0x61, 0x63, 0x65, 0x2D, 0x2D, 0x61, 0x6E, + 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x69, 0x73, 0x20, 0x73, + 0x75, 0x63, 0x68, 0x20, 0x61, 0x20, 0x6E, 0x69, 0x63, 0x65, + 0x20, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x6F, 0x20, 0x6E, 0x75, 0x72, 0x73, 0x65, + 0x2D, 0x2D, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x27, + 0x73, 0x0D, 0x0A, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x20, + 0x63, 0x61, 0x70, 0x69, 0x74, 0x61, 0x6C, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x63, 0x61, 0x74, 0x63, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x69, 0x63, 0x65, 0x2D, + 0x2D, 0x6F, 0x68, 0x2C, 0x20, 0x49, 0x20, 0x62, 0x65, 0x67, + 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x70, 0x61, 0x72, 0x64, + 0x6F, 0x6E, 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, + 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x62, 0x72, 0x69, 0x73, 0x74, 0x6C, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6F, 0x76, 0x65, + 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, + 0x0D, 0x0A, 0x66, 0x65, 0x6C, 0x74, 0x20, 0x63, 0x65, 0x72, + 0x74, 0x61, 0x69, 0x6E, 0x20, 0x69, 0x74, 0x20, 0x6D, 0x75, + 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x61, 0x6C, + 0x6C, 0x79, 0x20, 0x6F, 0x66, 0x66, 0x65, 0x6E, 0x64, 0x65, + 0x64, 0x2E, 0x20, 0x27, 0x57, 0x65, 0x20, 0x77, 0x6F, 0x6E, + 0x27, 0x74, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x20, 0x61, 0x62, + 0x6F, 0x75, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, 0x6E, + 0x79, 0x0D, 0x0A, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x69, 0x66, + 0x20, 0x79, 0x6F, 0x75, 0x27, 0x64, 0x20, 0x72, 0x61, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x6E, 0x6F, 0x74, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x20, 0x69, 0x6E, 0x64, + 0x65, 0x65, 0x64, 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, + 0x65, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x74, 0x72, 0x65, 0x6D, 0x62, 0x6C, 0x69, 0x6E, 0x67, + 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x65, 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x20, + 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x74, 0x61, 0x69, 0x6C, 0x2E, + 0x20, 0x27, 0x41, 0x73, 0x20, 0x69, 0x66, 0x20, 0x49, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x74, 0x61, 0x6C, 0x6B, + 0x20, 0x6F, 0x6E, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, + 0x20, 0x73, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x21, 0x20, + 0x4F, 0x75, 0x72, 0x20, 0x66, 0x61, 0x6D, 0x69, 0x6C, 0x79, + 0x20, 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x48, 0x41, + 0x54, 0x45, 0x44, 0x0D, 0x0A, 0x63, 0x61, 0x74, 0x73, 0x3A, + 0x20, 0x6E, 0x61, 0x73, 0x74, 0x79, 0x2C, 0x20, 0x6C, 0x6F, + 0x77, 0x2C, 0x20, 0x76, 0x75, 0x6C, 0x67, 0x61, 0x72, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x21, 0x20, 0x44, 0x6F, + 0x6E, 0x27, 0x74, 0x20, 0x6C, 0x65, 0x74, 0x20, 0x6D, 0x65, + 0x20, 0x68, 0x65, 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6E, 0x61, 0x6D, 0x65, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x77, + 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x65, + 0x64, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x68, 0x75, 0x72, + 0x72, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x68, 0x61, 0x6E, + 0x67, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x63, + 0x6F, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x2E, 0x20, 0x27, 0x41, 0x72, 0x65, 0x20, 0x79, 0x6F, + 0x75, 0x2D, 0x2D, 0x61, 0x72, 0x65, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x66, 0x6F, 0x6E, 0x64, 0x2D, 0x2D, 0x6F, 0x66, 0x2D, + 0x2D, 0x6F, 0x66, 0x20, 0x64, 0x6F, 0x67, 0x73, 0x3F, 0x27, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, + 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x0D, 0x0A, + 0x61, 0x6E, 0x73, 0x77, 0x65, 0x72, 0x2C, 0x20, 0x73, 0x6F, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x65, 0x61, 0x67, 0x65, 0x72, + 0x6C, 0x79, 0x3A, 0x20, 0x27, 0x54, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x69, 0x73, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, + 0x20, 0x6E, 0x69, 0x63, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x64, 0x6F, 0x67, 0x20, 0x6E, 0x65, 0x61, + 0x72, 0x0D, 0x0A, 0x6F, 0x75, 0x72, 0x20, 0x68, 0x6F, 0x75, + 0x73, 0x65, 0x20, 0x49, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x68, 0x6F, 0x77, 0x20, 0x79, 0x6F, 0x75, 0x21, 0x20, + 0x41, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x62, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x2D, 0x65, 0x79, 0x65, 0x64, + 0x20, 0x74, 0x65, 0x72, 0x72, 0x69, 0x65, 0x72, 0x2C, 0x20, + 0x79, 0x6F, 0x75, 0x0D, 0x0A, 0x6B, 0x6E, 0x6F, 0x77, 0x2C, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6F, 0x68, 0x2C, 0x20, + 0x73, 0x75, 0x63, 0x68, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, + 0x63, 0x75, 0x72, 0x6C, 0x79, 0x20, 0x62, 0x72, 0x6F, 0x77, + 0x6E, 0x20, 0x68, 0x61, 0x69, 0x72, 0x21, 0x20, 0x41, 0x6E, + 0x64, 0x20, 0x69, 0x74, 0x27, 0x6C, 0x6C, 0x20, 0x66, 0x65, + 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, + 0x20, 0x77, 0x68, 0x65, 0x6E, 0x0D, 0x0A, 0x79, 0x6F, 0x75, + 0x20, 0x74, 0x68, 0x72, 0x6F, 0x77, 0x20, 0x74, 0x68, 0x65, + 0x6D, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x27, + 0x6C, 0x6C, 0x20, 0x73, 0x69, 0x74, 0x20, 0x75, 0x70, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x69, 0x74, 0x73, 0x20, 0x64, 0x69, 0x6E, 0x6E, + 0x65, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x73, 0x0D, 0x0A, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x2D, 0x2D, + 0x49, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x72, 0x65, + 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, 0x20, 0x68, 0x61, 0x6C, + 0x66, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2D, + 0x2D, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x20, 0x62, 0x65, + 0x6C, 0x6F, 0x6E, 0x67, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x61, + 0x20, 0x66, 0x61, 0x72, 0x6D, 0x65, 0x72, 0x2C, 0x0D, 0x0A, + 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x20, 0x73, 0x61, 0x79, + 0x73, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x73, 0x6F, 0x20, + 0x75, 0x73, 0x65, 0x66, 0x75, 0x6C, 0x2C, 0x20, 0x69, 0x74, + 0x27, 0x73, 0x20, 0x77, 0x6F, 0x72, 0x74, 0x68, 0x20, 0x61, + 0x20, 0x68, 0x75, 0x6E, 0x64, 0x72, 0x65, 0x64, 0x20, 0x70, + 0x6F, 0x75, 0x6E, 0x64, 0x73, 0x21, 0x20, 0x48, 0x65, 0x0D, + 0x0A, 0x73, 0x61, 0x79, 0x73, 0x20, 0x69, 0x74, 0x20, 0x6B, + 0x69, 0x6C, 0x6C, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x72, 0x61, 0x74, 0x73, 0x20, 0x61, 0x6E, + 0x64, 0x2D, 0x2D, 0x6F, 0x68, 0x20, 0x64, 0x65, 0x61, 0x72, + 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, + 0x73, 0x6F, 0x72, 0x72, 0x6F, 0x77, 0x66, 0x75, 0x6C, 0x0D, + 0x0A, 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x27, 0x49, 0x27, + 0x6D, 0x20, 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, 0x20, 0x49, + 0x27, 0x76, 0x65, 0x20, 0x6F, 0x66, 0x66, 0x65, 0x6E, 0x64, + 0x65, 0x64, 0x20, 0x69, 0x74, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6E, 0x21, 0x27, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x73, 0x77, 0x69, 0x6D, 0x6D, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x61, 0x77, 0x61, 0x79, 0x20, 0x66, 0x72, 0x6F, + 0x6D, 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, 0x73, 0x20, 0x68, + 0x61, 0x72, 0x64, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, + 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x67, 0x6F, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x61, 0x20, 0x63, + 0x6F, 0x6D, 0x6D, 0x6F, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, + 0x6E, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6F, 0x6F, + 0x6C, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x6F, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, + 0x20, 0x73, 0x6F, 0x66, 0x74, 0x6C, 0x79, 0x20, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x27, 0x4D, + 0x6F, 0x75, 0x73, 0x65, 0x20, 0x64, 0x65, 0x61, 0x72, 0x21, + 0x20, 0x44, 0x6F, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x62, + 0x61, 0x63, 0x6B, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x65, 0x0D, 0x0A, 0x77, + 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x20, + 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x63, 0x61, 0x74, 0x73, + 0x20, 0x6F, 0x72, 0x20, 0x64, 0x6F, 0x67, 0x73, 0x20, 0x65, + 0x69, 0x74, 0x68, 0x65, 0x72, 0x2C, 0x20, 0x69, 0x66, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, + 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x21, + 0x27, 0x20, 0x57, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x68, 0x65, + 0x61, 0x72, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, 0x20, + 0x69, 0x74, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, + 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x77, 0x61, 0x6D, 0x20, 0x73, 0x6C, 0x6F, 0x77, 0x6C, + 0x79, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x3A, 0x20, 0x69, 0x74, 0x73, 0x0D, 0x0A, + 0x66, 0x61, 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x71, + 0x75, 0x69, 0x74, 0x65, 0x20, 0x70, 0x61, 0x6C, 0x65, 0x20, + 0x28, 0x77, 0x69, 0x74, 0x68, 0x20, 0x70, 0x61, 0x73, 0x73, + 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x29, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x6F, + 0x77, 0x0D, 0x0A, 0x74, 0x72, 0x65, 0x6D, 0x62, 0x6C, 0x69, + 0x6E, 0x67, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x27, 0x4C, 0x65, 0x74, 0x20, 0x75, 0x73, 0x20, 0x67, 0x65, + 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x68, 0x6F, 0x72, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, + 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, + 0x79, 0x0D, 0x0A, 0x68, 0x69, 0x73, 0x74, 0x6F, 0x72, 0x79, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x27, + 0x6C, 0x6C, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x73, 0x74, + 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x79, 0x20, 0x69, 0x74, + 0x20, 0x69, 0x73, 0x20, 0x49, 0x20, 0x68, 0x61, 0x74, 0x65, + 0x20, 0x63, 0x61, 0x74, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x64, 0x6F, 0x67, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x68, 0x69, 0x67, + 0x68, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x67, 0x6F, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x6C, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x71, + 0x75, 0x69, 0x74, 0x65, 0x20, 0x63, 0x72, 0x6F, 0x77, 0x64, + 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x62, 0x69, 0x72, 0x64, 0x73, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x6E, 0x69, 0x6D, 0x61, 0x6C, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x66, 0x61, 0x6C, 0x6C, 0x65, 0x6E, 0x20, 0x69, 0x6E, 0x74, + 0x6F, 0x20, 0x69, 0x74, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x20, 0x44, + 0x75, 0x63, 0x6B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x20, + 0x44, 0x6F, 0x64, 0x6F, 0x2C, 0x0D, 0x0A, 0x61, 0x20, 0x4C, + 0x6F, 0x72, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6E, + 0x20, 0x45, 0x61, 0x67, 0x6C, 0x65, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x65, 0x76, 0x65, 0x72, 0x61, 0x6C, + 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x63, 0x75, 0x72, + 0x69, 0x6F, 0x75, 0x73, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x2E, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x6C, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x77, 0x61, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, 0x6F, 0x6C, 0x65, 0x20, + 0x70, 0x61, 0x72, 0x74, 0x79, 0x20, 0x73, 0x77, 0x61, 0x6D, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x68, + 0x6F, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, + 0x0D, 0x0A, 0x0D, 0x0A, 0x43, 0x48, 0x41, 0x50, 0x54, 0x45, + 0x52, 0x20, 0x49, 0x49, 0x49, 0x2E, 0x20, 0x41, 0x20, 0x43, + 0x61, 0x75, 0x63, 0x75, 0x73, 0x2D, 0x52, 0x61, 0x63, 0x65, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x20, 0x4C, 0x6F, 0x6E, + 0x67, 0x20, 0x54, 0x61, 0x6C, 0x65, 0x0D, 0x0A, 0x0D, 0x0A, + 0x54, 0x68, 0x65, 0x79, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, + 0x69, 0x6E, 0x64, 0x65, 0x65, 0x64, 0x20, 0x61, 0x20, 0x71, + 0x75, 0x65, 0x65, 0x72, 0x2D, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, + 0x6E, 0x67, 0x20, 0x70, 0x61, 0x72, 0x74, 0x79, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x61, 0x73, 0x73, 0x65, 0x6D, 0x62, + 0x6C, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x61, 0x6E, 0x6B, 0x2D, 0x2D, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x62, 0x69, 0x72, 0x64, 0x73, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x64, 0x72, 0x61, 0x67, 0x67, 0x6C, 0x65, + 0x64, 0x20, 0x66, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x73, + 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6E, 0x69, 0x6D, + 0x61, 0x6C, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x69, 0x72, 0x20, 0x66, 0x75, 0x72, 0x20, 0x63, + 0x6C, 0x69, 0x6E, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6C, + 0x6F, 0x73, 0x65, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x64, 0x72, 0x69, 0x70, 0x70, 0x69, 0x6E, 0x67, + 0x20, 0x77, 0x65, 0x74, 0x2C, 0x20, 0x63, 0x72, 0x6F, 0x73, + 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x75, 0x6E, 0x63, + 0x6F, 0x6D, 0x66, 0x6F, 0x72, 0x74, 0x61, 0x62, 0x6C, 0x65, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x66, + 0x69, 0x72, 0x73, 0x74, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x75, + 0x72, 0x73, 0x65, 0x20, 0x77, 0x61, 0x73, 0x2C, 0x20, 0x68, + 0x6F, 0x77, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, + 0x64, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x3A, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x61, 0x0D, 0x0A, 0x63, 0x6F, 0x6E, 0x73, 0x75, 0x6C, 0x74, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x62, 0x6F, 0x75, + 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20, + 0x66, 0x65, 0x77, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, + 0x73, 0x20, 0x69, 0x74, 0x20, 0x73, 0x65, 0x65, 0x6D, 0x65, + 0x64, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x6E, 0x61, + 0x74, 0x75, 0x72, 0x61, 0x6C, 0x0D, 0x0A, 0x74, 0x6F, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x66, + 0x69, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, + 0x66, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x66, 0x61, 0x6D, 0x69, 0x6C, 0x69, 0x61, 0x72, 0x6C, 0x79, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x6D, + 0x2C, 0x20, 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x0D, 0x0A, 0x6B, 0x6E, 0x6F, + 0x77, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x68, 0x65, 0x72, 0x20, 0x6C, 0x69, 0x66, 0x65, + 0x2E, 0x20, 0x49, 0x6E, 0x64, 0x65, 0x65, 0x64, 0x2C, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x71, 0x75, + 0x69, 0x74, 0x65, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x6E, 0x67, + 0x20, 0x61, 0x72, 0x67, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x4C, 0x6F, 0x72, 0x79, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, + 0x61, 0x74, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x74, 0x75, + 0x72, 0x6E, 0x65, 0x64, 0x20, 0x73, 0x75, 0x6C, 0x6B, 0x79, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x73, 0x61, 0x79, + 0x2C, 0x20, 0x27, 0x49, 0x20, 0x61, 0x6D, 0x20, 0x6F, 0x6C, + 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x0D, 0x0A, + 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, + 0x75, 0x73, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x62, + 0x65, 0x74, 0x74, 0x65, 0x72, 0x27, 0x3B, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x6F, 0x77, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x0D, 0x0A, 0x6B, 0x6E, + 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x6F, 0x77, 0x20, + 0x6F, 0x6C, 0x64, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x61, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4C, 0x6F, 0x72, 0x79, 0x20, 0x70, + 0x6F, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x6C, 0x79, 0x20, + 0x72, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x69, 0x74, 0x73, 0x0D, + 0x0A, 0x61, 0x67, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x6D, + 0x6F, 0x72, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, + 0x74, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x77, 0x68, + 0x6F, 0x20, 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x70, 0x65, 0x72, + 0x73, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x75, 0x74, + 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x20, 0x61, 0x6D, 0x6F, + 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x0D, 0x0A, + 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, + 0x2C, 0x20, 0x27, 0x53, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x77, + 0x6E, 0x2C, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6F, 0x66, 0x20, + 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, + 0x69, 0x73, 0x74, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x6D, + 0x65, 0x21, 0x20, 0x49, 0x27, 0x4C, 0x4C, 0x20, 0x73, 0x6F, + 0x6F, 0x6E, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x79, 0x6F, + 0x75, 0x0D, 0x0A, 0x64, 0x72, 0x79, 0x20, 0x65, 0x6E, 0x6F, + 0x75, 0x67, 0x68, 0x21, 0x27, 0x20, 0x54, 0x68, 0x65, 0x79, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x61, 0x74, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, + 0x65, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x61, + 0x72, 0x67, 0x65, 0x20, 0x72, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, + 0x6F, 0x75, 0x73, 0x65, 0x0D, 0x0A, 0x69, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6D, 0x69, 0x64, 0x64, 0x6C, 0x65, 0x2E, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x6B, 0x65, 0x70, + 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x65, 0x79, 0x65, 0x73, + 0x20, 0x61, 0x6E, 0x78, 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, + 0x20, 0x66, 0x69, 0x78, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, + 0x69, 0x74, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x66, 0x65, 0x6C, 0x74, 0x0D, 0x0A, 0x73, 0x75, + 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x63, 0x61, 0x74, 0x63, 0x68, 0x20, 0x61, + 0x20, 0x62, 0x61, 0x64, 0x20, 0x63, 0x6F, 0x6C, 0x64, 0x20, + 0x69, 0x66, 0x20, 0x73, 0x68, 0x65, 0x20, 0x64, 0x69, 0x64, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x67, 0x65, 0x74, 0x20, 0x64, + 0x72, 0x79, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, 0x6F, + 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x68, + 0x65, 0x6D, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6E, 0x20, 0x69, 0x6D, + 0x70, 0x6F, 0x72, 0x74, 0x61, 0x6E, 0x74, 0x20, 0x61, 0x69, + 0x72, 0x2C, 0x20, 0x27, 0x61, 0x72, 0x65, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x65, 0x61, 0x64, + 0x79, 0x3F, 0x20, 0x54, 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x72, 0x69, 0x65, + 0x73, 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x49, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x20, 0x53, 0x69, 0x6C, + 0x65, 0x6E, 0x63, 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x72, + 0x6F, 0x75, 0x6E, 0x64, 0x2C, 0x20, 0x69, 0x66, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x21, + 0x20, 0x22, 0x57, 0x69, 0x6C, 0x6C, 0x69, 0x61, 0x6D, 0x0D, + 0x0A, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x71, 0x75, + 0x65, 0x72, 0x6F, 0x72, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x73, + 0x65, 0x20, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x66, 0x61, 0x76, 0x6F, 0x75, 0x72, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6F, + 0x70, 0x65, 0x2C, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x6F, + 0x6F, 0x6E, 0x20, 0x73, 0x75, 0x62, 0x6D, 0x69, 0x74, 0x74, + 0x65, 0x64, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x62, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x45, 0x6E, 0x67, 0x6C, 0x69, 0x73, + 0x68, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x77, 0x61, 0x6E, + 0x74, 0x65, 0x64, 0x20, 0x6C, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x6C, + 0x61, 0x74, 0x65, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x0D, 0x0A, + 0x61, 0x63, 0x63, 0x75, 0x73, 0x74, 0x6F, 0x6D, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x75, 0x73, 0x75, 0x72, 0x70, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, + 0x6F, 0x6E, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2E, 0x20, 0x45, + 0x64, 0x77, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x4D, + 0x6F, 0x72, 0x63, 0x61, 0x72, 0x2C, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x65, 0x61, 0x72, 0x6C, 0x73, 0x20, 0x6F, 0x66, 0x0D, + 0x0A, 0x4D, 0x65, 0x72, 0x63, 0x69, 0x61, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x4E, 0x6F, 0x72, 0x74, 0x68, 0x75, 0x6D, 0x62, + 0x72, 0x69, 0x61, 0x2D, 0x2D, 0x22, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x55, 0x67, 0x68, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4C, 0x6F, 0x72, + 0x79, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x73, 0x68, 0x69, 0x76, 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x20, 0x62, 0x65, 0x67, 0x20, 0x79, 0x6F, + 0x75, 0x72, 0x20, 0x70, 0x61, 0x72, 0x64, 0x6F, 0x6E, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x66, 0x72, + 0x6F, 0x77, 0x6E, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x62, 0x75, + 0x74, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x70, 0x6F, 0x6C, + 0x69, 0x74, 0x65, 0x6C, 0x79, 0x3A, 0x20, 0x27, 0x44, 0x69, + 0x64, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x73, 0x70, 0x65, + 0x61, 0x6B, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, + 0x6F, 0x74, 0x20, 0x49, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4C, 0x6F, 0x72, 0x79, + 0x20, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, 0x79, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x74, 0x68, 0x6F, 0x75, + 0x67, 0x68, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, 0x69, + 0x64, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x2E, 0x20, + 0x27, 0x2D, 0x2D, 0x49, 0x20, 0x70, 0x72, 0x6F, 0x63, 0x65, + 0x65, 0x64, 0x2E, 0x20, 0x22, 0x45, 0x64, 0x77, 0x69, 0x6E, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x4D, 0x6F, 0x72, 0x63, 0x61, + 0x72, 0x2C, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x65, 0x61, + 0x72, 0x6C, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x65, 0x72, + 0x63, 0x69, 0x61, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x4E, 0x6F, + 0x72, 0x74, 0x68, 0x75, 0x6D, 0x62, 0x72, 0x69, 0x61, 0x2C, + 0x20, 0x64, 0x65, 0x63, 0x6C, 0x61, 0x72, 0x65, 0x64, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x68, 0x69, 0x6D, 0x3A, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x53, 0x74, + 0x69, 0x67, 0x61, 0x6E, 0x64, 0x2C, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x61, 0x74, 0x72, 0x69, 0x6F, 0x74, 0x69, + 0x63, 0x20, 0x61, 0x72, 0x63, 0x68, 0x62, 0x69, 0x73, 0x68, + 0x6F, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x43, 0x61, 0x6E, 0x74, + 0x65, 0x72, 0x62, 0x75, 0x72, 0x79, 0x2C, 0x20, 0x66, 0x6F, + 0x75, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x20, 0x61, 0x64, 0x76, + 0x69, 0x73, 0x61, 0x62, 0x6C, 0x65, 0x2D, 0x2D, 0x22, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x46, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x57, 0x48, 0x41, 0x54, 0x3F, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, + 0x6B, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x46, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x49, 0x54, 0x2C, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x72, 0x65, + 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x72, 0x61, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x6C, 0x79, + 0x3A, 0x20, 0x27, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, + 0x73, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, + 0x77, 0x20, 0x77, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x22, 0x69, + 0x74, 0x22, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x73, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x6B, 0x6E, 0x6F, + 0x77, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x22, 0x69, 0x74, + 0x22, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x73, 0x20, 0x77, 0x65, + 0x6C, 0x6C, 0x20, 0x65, 0x6E, 0x6F, 0x75, 0x67, 0x68, 0x2C, + 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x49, 0x20, 0x66, 0x69, + 0x6E, 0x64, 0x20, 0x61, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x44, 0x75, 0x63, 0x6B, 0x3A, 0x20, 0x27, + 0x69, 0x74, 0x27, 0x73, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, + 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x61, 0x20, 0x66, 0x72, 0x6F, + 0x67, 0x20, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x77, 0x6F, 0x72, + 0x6D, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x2C, 0x20, + 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x0D, 0x0A, 0x61, 0x72, 0x63, 0x68, 0x62, 0x69, + 0x73, 0x68, 0x6F, 0x70, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x3F, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x4D, + 0x6F, 0x75, 0x73, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x68, + 0x75, 0x72, 0x72, 0x69, 0x65, 0x64, 0x6C, 0x79, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x27, 0x22, + 0x2D, 0x2D, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x0D, 0x0A, 0x69, + 0x74, 0x20, 0x61, 0x64, 0x76, 0x69, 0x73, 0x61, 0x62, 0x6C, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x6F, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x45, 0x64, 0x67, 0x61, 0x72, 0x20, 0x41, + 0x74, 0x68, 0x65, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, + 0x20, 0x6D, 0x65, 0x65, 0x74, 0x20, 0x57, 0x69, 0x6C, 0x6C, + 0x69, 0x61, 0x6D, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x66, + 0x66, 0x65, 0x72, 0x20, 0x68, 0x69, 0x6D, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x63, 0x72, 0x6F, 0x77, 0x6E, 0x2E, 0x20, + 0x57, 0x69, 0x6C, 0x6C, 0x69, 0x61, 0x6D, 0x27, 0x73, 0x20, + 0x63, 0x6F, 0x6E, 0x64, 0x75, 0x63, 0x74, 0x20, 0x61, 0x74, + 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x2E, + 0x20, 0x42, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, + 0x6E, 0x73, 0x6F, 0x6C, 0x65, 0x6E, 0x63, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x4E, 0x6F, 0x72, + 0x6D, 0x61, 0x6E, 0x73, 0x2D, 0x2D, 0x22, 0x20, 0x48, 0x6F, + 0x77, 0x20, 0x61, 0x72, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, + 0x20, 0x6E, 0x6F, 0x77, 0x2C, 0x20, 0x6D, 0x79, 0x20, 0x64, + 0x65, 0x61, 0x72, 0x3F, 0x27, 0x20, 0x69, 0x74, 0x20, 0x63, + 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x64, 0x2C, 0x20, + 0x74, 0x75, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x74, + 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x73, + 0x20, 0x69, 0x74, 0x20, 0x73, 0x70, 0x6F, 0x6B, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x73, 0x20, 0x77, 0x65, + 0x74, 0x20, 0x61, 0x73, 0x20, 0x65, 0x76, 0x65, 0x72, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6D, 0x65, + 0x6C, 0x61, 0x6E, 0x63, 0x68, 0x6F, 0x6C, 0x79, 0x20, 0x74, + 0x6F, 0x6E, 0x65, 0x3A, 0x20, 0x27, 0x69, 0x74, 0x20, 0x64, + 0x6F, 0x65, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x73, 0x65, 0x65, + 0x6D, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x64, 0x72, 0x79, 0x20, + 0x6D, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x6E, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x73, 0x65, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x44, 0x6F, 0x64, 0x6F, 0x20, 0x73, 0x6F, 0x6C, 0x65, 0x6D, + 0x6E, 0x6C, 0x79, 0x2C, 0x20, 0x72, 0x69, 0x73, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x73, 0x20, 0x66, + 0x65, 0x65, 0x74, 0x2C, 0x20, 0x27, 0x49, 0x20, 0x6D, 0x6F, + 0x76, 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6D, 0x65, 0x65, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x64, 0x6A, 0x6F, 0x75, 0x72, 0x6E, 0x2C, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6D, + 0x6D, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x61, 0x64, + 0x6F, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, + 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x65, 0x6E, 0x65, 0x72, 0x67, + 0x65, 0x74, 0x69, 0x63, 0x0D, 0x0A, 0x72, 0x65, 0x6D, 0x65, + 0x64, 0x69, 0x65, 0x73, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x53, 0x70, 0x65, 0x61, 0x6B, 0x20, 0x45, 0x6E, + 0x67, 0x6C, 0x69, 0x73, 0x68, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x45, 0x61, 0x67, + 0x6C, 0x65, 0x74, 0x2E, 0x20, 0x27, 0x49, 0x20, 0x64, 0x6F, + 0x6E, 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x66, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x0D, 0x0A, + 0x74, 0x68, 0x6F, 0x73, 0x65, 0x20, 0x6C, 0x6F, 0x6E, 0x67, + 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x2C, 0x20, 0x77, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, + 0x6D, 0x6F, 0x72, 0x65, 0x2C, 0x20, 0x49, 0x20, 0x64, 0x6F, + 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, 0x6C, 0x69, 0x65, 0x76, + 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, 0x6F, 0x20, 0x65, + 0x69, 0x74, 0x68, 0x65, 0x72, 0x21, 0x27, 0x20, 0x41, 0x6E, + 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x45, 0x61, 0x67, + 0x6C, 0x65, 0x74, 0x20, 0x62, 0x65, 0x6E, 0x74, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x69, 0x74, 0x73, 0x20, 0x68, 0x65, + 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x69, 0x64, 0x65, + 0x20, 0x61, 0x20, 0x73, 0x6D, 0x69, 0x6C, 0x65, 0x3A, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x62, 0x69, + 0x72, 0x64, 0x73, 0x0D, 0x0A, 0x74, 0x69, 0x74, 0x74, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x61, 0x75, 0x64, 0x69, 0x62, 0x6C, + 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, + 0x74, 0x20, 0x49, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, 0x6F, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x44, 0x6F, 0x64, 0x6F, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x6E, 0x20, 0x6F, 0x66, 0x66, 0x65, 0x6E, 0x64, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x27, 0x77, + 0x61, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x65, 0x73, 0x74, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, + 0x74, 0x20, 0x75, 0x73, 0x20, 0x64, 0x72, 0x79, 0x20, 0x77, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, + 0x43, 0x61, 0x75, 0x63, 0x75, 0x73, 0x2D, 0x72, 0x61, 0x63, + 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, + 0x61, 0x74, 0x20, 0x49, 0x53, 0x20, 0x61, 0x20, 0x43, 0x61, + 0x75, 0x63, 0x75, 0x73, 0x2D, 0x72, 0x61, 0x63, 0x65, 0x3F, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x3B, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x6E, + 0x74, 0x65, 0x64, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x74, + 0x6F, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2C, 0x0D, 0x0A, 0x62, + 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x64, + 0x6F, 0x20, 0x68, 0x61, 0x64, 0x20, 0x70, 0x61, 0x75, 0x73, + 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x69, + 0x74, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x53, 0x4F, 0x4D, 0x45, 0x42, + 0x4F, 0x44, 0x59, 0x20, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x2C, 0x0D, + 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x6E, 0x6F, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x73, 0x65, 0x65, + 0x6D, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x63, 0x6C, 0x69, 0x6E, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, 0x20, + 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x79, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, + 0x6F, 0x64, 0x6F, 0x2C, 0x20, 0x27, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x65, 0x73, 0x74, 0x20, 0x77, 0x61, 0x79, 0x20, 0x74, + 0x6F, 0x20, 0x65, 0x78, 0x70, 0x6C, 0x61, 0x69, 0x6E, 0x20, + 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x64, + 0x6F, 0x20, 0x69, 0x74, 0x2E, 0x27, 0x20, 0x28, 0x41, 0x6E, + 0x64, 0x2C, 0x20, 0x61, 0x73, 0x0D, 0x0A, 0x79, 0x6F, 0x75, + 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x72, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x79, + 0x6F, 0x75, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x77, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x20, 0x64, 0x61, 0x79, 0x2C, 0x20, 0x49, 0x20, 0x77, 0x69, + 0x6C, 0x6C, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x0D, 0x0A, 0x79, + 0x6F, 0x75, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x6F, 0x64, 0x6F, 0x20, 0x6D, 0x61, 0x6E, 0x61, + 0x67, 0x65, 0x64, 0x20, 0x69, 0x74, 0x2E, 0x29, 0x0D, 0x0A, + 0x0D, 0x0A, 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x74, + 0x20, 0x6D, 0x61, 0x72, 0x6B, 0x65, 0x64, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x61, 0x20, 0x72, 0x61, 0x63, 0x65, 0x2D, 0x63, + 0x6F, 0x75, 0x72, 0x73, 0x65, 0x2C, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x63, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x2C, 0x20, 0x28, 0x27, + 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x61, 0x63, 0x74, 0x0D, + 0x0A, 0x73, 0x68, 0x61, 0x70, 0x65, 0x20, 0x64, 0x6F, 0x65, + 0x73, 0x6E, 0x27, 0x74, 0x20, 0x6D, 0x61, 0x74, 0x74, 0x65, + 0x72, 0x2C, 0x27, 0x20, 0x69, 0x74, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x2C, 0x29, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x6E, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x79, 0x20, 0x77, 0x65, 0x72, + 0x65, 0x20, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x64, 0x0D, 0x0A, + 0x61, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x2C, 0x20, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x27, 0x4F, 0x6E, + 0x65, 0x2C, 0x20, 0x74, 0x77, 0x6F, 0x2C, 0x20, 0x74, 0x68, + 0x72, 0x65, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, + 0x61, 0x77, 0x61, 0x79, 0x2C, 0x27, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x62, 0x65, 0x67, 0x61, + 0x6E, 0x20, 0x72, 0x75, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x6C, 0x69, 0x6B, 0x65, 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x6F, 0x66, 0x66, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x79, 0x0D, + 0x0A, 0x6C, 0x69, 0x6B, 0x65, 0x64, 0x2C, 0x20, 0x73, 0x6F, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x65, 0x61, 0x73, + 0x79, 0x20, 0x74, 0x6F, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x61, 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6F, 0x76, + 0x65, 0x72, 0x2E, 0x20, 0x48, 0x6F, 0x77, 0x65, 0x76, 0x65, + 0x72, 0x2C, 0x0D, 0x0A, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x68, 0x61, 0x64, 0x20, 0x62, 0x65, + 0x65, 0x6E, 0x20, 0x72, 0x75, 0x6E, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x61, 0x6E, 0x20, 0x68, + 0x6F, 0x75, 0x72, 0x20, 0x6F, 0x72, 0x20, 0x73, 0x6F, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x64, 0x72, 0x79, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x20, 0x44, 0x6F, 0x64, 0x6F, 0x20, 0x73, 0x75, 0x64, + 0x64, 0x65, 0x6E, 0x6C, 0x79, 0x20, 0x63, 0x61, 0x6C, 0x6C, + 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x27, 0x54, 0x68, + 0x65, 0x20, 0x72, 0x61, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, + 0x6F, 0x76, 0x65, 0x72, 0x21, 0x27, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x63, 0x72, 0x6F, 0x77, 0x64, 0x65, 0x64, 0x0D, 0x0A, 0x72, + 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x70, + 0x61, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x61, 0x73, 0x6B, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x27, 0x42, 0x75, 0x74, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x68, + 0x61, 0x73, 0x20, 0x77, 0x6F, 0x6E, 0x3F, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x54, 0x68, 0x69, 0x73, 0x20, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x44, 0x6F, 0x64, 0x6F, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x6E, 0x73, 0x77, 0x65, + 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, + 0x61, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x64, 0x65, + 0x61, 0x6C, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x6F, 0x75, + 0x67, 0x68, 0x74, 0x2C, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, + 0x69, 0x74, 0x20, 0x73, 0x61, 0x74, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x74, 0x69, + 0x6D, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x66, 0x69, 0x6E, 0x67, 0x65, 0x72, 0x20, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x75, 0x70, 0x6F, + 0x6E, 0x20, 0x69, 0x74, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x65, + 0x68, 0x65, 0x61, 0x64, 0x0D, 0x0A, 0x28, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x20, + 0x69, 0x6E, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x75, 0x73, 0x75, 0x61, 0x6C, 0x6C, 0x79, + 0x20, 0x73, 0x65, 0x65, 0x20, 0x53, 0x68, 0x61, 0x6B, 0x65, + 0x73, 0x70, 0x65, 0x61, 0x72, 0x65, 0x2C, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x69, 0x63, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x68, 0x69, + 0x6D, 0x29, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x74, 0x20, 0x77, + 0x61, 0x69, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x73, + 0x69, 0x6C, 0x65, 0x6E, 0x63, 0x65, 0x2E, 0x20, 0x41, 0x74, + 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x44, 0x6F, 0x64, 0x6F, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, + 0x0D, 0x0A, 0x27, 0x45, 0x56, 0x45, 0x52, 0x59, 0x42, 0x4F, + 0x44, 0x59, 0x20, 0x68, 0x61, 0x73, 0x20, 0x77, 0x6F, 0x6E, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x6D, 0x75, 0x73, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x70, 0x72, 0x69, 0x7A, 0x65, 0x73, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x42, 0x75, 0x74, 0x20, 0x77, 0x68, 0x6F, + 0x20, 0x69, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x69, 0x76, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, 0x7A, + 0x65, 0x73, 0x3F, 0x27, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, + 0x20, 0x61, 0x20, 0x63, 0x68, 0x6F, 0x72, 0x75, 0x73, 0x20, + 0x6F, 0x66, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x73, 0x20, + 0x61, 0x73, 0x6B, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x57, 0x68, 0x79, 0x2C, 0x20, 0x53, 0x48, 0x45, 0x2C, + 0x20, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x44, 0x6F, 0x64, 0x6F, 0x2C, 0x20, 0x70, 0x6F, + 0x69, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x66, 0x69, 0x6E, 0x67, 0x65, + 0x72, 0x3B, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x68, 0x6F, 0x6C, 0x65, 0x20, 0x70, 0x61, + 0x72, 0x74, 0x79, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, + 0x65, 0x20, 0x63, 0x72, 0x6F, 0x77, 0x64, 0x65, 0x64, 0x20, + 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, 0x2C, + 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x75, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x63, 0x6F, + 0x6E, 0x66, 0x75, 0x73, 0x65, 0x64, 0x0D, 0x0A, 0x77, 0x61, + 0x79, 0x2C, 0x20, 0x27, 0x50, 0x72, 0x69, 0x7A, 0x65, 0x73, + 0x21, 0x20, 0x50, 0x72, 0x69, 0x7A, 0x65, 0x73, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x20, 0x69, 0x64, 0x65, + 0x61, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x64, 0x6F, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x64, 0x65, 0x73, 0x70, 0x61, 0x69, 0x72, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x70, 0x75, 0x74, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x68, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x68, + 0x65, 0x72, 0x0D, 0x0A, 0x70, 0x6F, 0x63, 0x6B, 0x65, 0x74, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x70, 0x75, 0x6C, 0x6C, + 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x20, 0x62, + 0x6F, 0x78, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x6D, 0x66, + 0x69, 0x74, 0x73, 0x2C, 0x20, 0x28, 0x6C, 0x75, 0x63, 0x6B, + 0x69, 0x6C, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, + 0x6C, 0x74, 0x20, 0x77, 0x61, 0x74, 0x65, 0x72, 0x20, 0x68, + 0x61, 0x64, 0x0D, 0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x67, 0x6F, + 0x74, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x29, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x6E, 0x64, + 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x72, 0x6F, + 0x75, 0x6E, 0x64, 0x20, 0x61, 0x73, 0x20, 0x70, 0x72, 0x69, + 0x7A, 0x65, 0x73, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x65, 0x78, 0x61, 0x63, 0x74, + 0x6C, 0x79, 0x20, 0x6F, 0x6E, 0x65, 0x0D, 0x0A, 0x61, 0x2D, + 0x70, 0x69, 0x65, 0x63, 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x42, 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6D, + 0x75, 0x73, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, + 0x20, 0x70, 0x72, 0x69, 0x7A, 0x65, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x66, 0x20, + 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x2C, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x6F, 0x64, 0x6F, 0x20, 0x72, 0x65, + 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x67, 0x72, 0x61, 0x76, 0x65, 0x6C, 0x79, 0x2E, 0x20, + 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, 0x65, 0x6C, 0x73, 0x65, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x67, 0x6F, 0x74, 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x79, 0x6F, + 0x75, 0x72, 0x20, 0x70, 0x6F, 0x63, 0x6B, 0x65, 0x74, 0x3F, + 0x27, 0x20, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, + 0x6F, 0x6E, 0x2C, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x6E, 0x6C, 0x79, + 0x20, 0x61, 0x20, 0x74, 0x68, 0x69, 0x6D, 0x62, 0x6C, 0x65, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x73, 0x61, 0x64, 0x6C, 0x79, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x61, 0x6E, 0x64, 0x20, + 0x69, 0x74, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x68, 0x65, + 0x72, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x64, 0x6F, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x72, 0x6F, + 0x77, 0x64, 0x65, 0x64, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, + 0x6D, 0x6F, 0x72, 0x65, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x6C, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x64, 0x6F, + 0x20, 0x73, 0x6F, 0x6C, 0x65, 0x6D, 0x6E, 0x6C, 0x79, 0x0D, + 0x0A, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6D, 0x62, + 0x6C, 0x65, 0x2C, 0x20, 0x73, 0x61, 0x79, 0x69, 0x6E, 0x67, + 0x20, 0x27, 0x57, 0x65, 0x20, 0x62, 0x65, 0x67, 0x20, 0x79, + 0x6F, 0x75, 0x72, 0x20, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, + 0x61, 0x6E, 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x65, 0x6C, 0x65, 0x67, 0x61, 0x6E, 0x74, + 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x6D, 0x62, 0x6C, 0x65, 0x27, + 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x77, 0x68, 0x65, + 0x6E, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, 0x66, + 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x20, 0x73, + 0x70, 0x65, 0x65, 0x63, 0x68, 0x2C, 0x20, 0x74, 0x68, 0x65, + 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x68, 0x65, 0x65, + 0x72, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, 0x6F, 0x6C, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x61, 0x62, 0x73, 0x75, 0x72, 0x64, 0x2C, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, + 0x20, 0x73, 0x6F, 0x20, 0x67, 0x72, 0x61, 0x76, 0x65, 0x0D, + 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x64, 0x61, + 0x72, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x61, 0x75, 0x67, + 0x68, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, + 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, + 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x69, 0x6D, 0x70, + 0x6C, 0x79, 0x20, 0x62, 0x6F, 0x77, 0x65, 0x64, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6D, 0x62, 0x6C, 0x65, + 0x2C, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x73, 0x20, 0x73, 0x6F, 0x6C, 0x65, 0x6D, 0x6E, 0x20, + 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x6F, 0x20, + 0x65, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x6D, 0x66, 0x69, 0x74, 0x73, 0x3A, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x63, 0x61, 0x75, 0x73, 0x65, 0x64, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x6E, 0x6F, 0x69, 0x73, 0x65, 0x20, + 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x63, 0x6F, 0x6E, 0x66, 0x75, + 0x73, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x62, + 0x69, 0x72, 0x64, 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x6C, + 0x61, 0x69, 0x6E, 0x65, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x74, 0x61, 0x73, 0x74, + 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x69, 0x72, 0x73, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x6D, 0x61, 0x6C, 0x6C, 0x20, 0x6F, 0x6E, 0x65, 0x73, 0x20, + 0x63, 0x68, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, + 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x64, 0x20, 0x6F, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x2E, + 0x0D, 0x0A, 0x48, 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6F, 0x76, + 0x65, 0x72, 0x20, 0x61, 0x74, 0x20, 0x6C, 0x61, 0x73, 0x74, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x73, 0x61, 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x72, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x0D, 0x0A, 0x62, 0x65, 0x67, 0x67, 0x65, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, + 0x6D, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x70, 0x72, 0x6F, 0x6D, + 0x69, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x65, + 0x6C, 0x6C, 0x20, 0x6D, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x72, + 0x20, 0x68, 0x69, 0x73, 0x74, 0x6F, 0x72, 0x79, 0x2C, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, + 0x79, 0x0D, 0x0A, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x68, 0x61, 0x74, 0x65, 0x2D, 0x2D, 0x43, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x44, 0x2C, 0x27, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, + 0x72, 0x2C, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x61, 0x66, + 0x72, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x69, 0x74, 0x0D, 0x0A, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x62, 0x65, 0x20, 0x6F, 0x66, 0x66, 0x65, 0x6E, 0x64, 0x65, + 0x64, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x4D, 0x69, 0x6E, 0x65, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x61, 0x20, 0x73, 0x61, 0x64, 0x20, 0x74, 0x61, + 0x6C, 0x65, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x2C, + 0x20, 0x74, 0x75, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x0D, 0x0A, 0x73, 0x69, 0x67, 0x68, 0x69, 0x6E, + 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x20, + 0x49, 0x53, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, + 0x74, 0x61, 0x69, 0x6C, 0x2C, 0x20, 0x63, 0x65, 0x72, 0x74, + 0x61, 0x69, 0x6E, 0x6C, 0x79, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x64, 0x6F, + 0x77, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x77, 0x6F, + 0x6E, 0x64, 0x65, 0x72, 0x20, 0x61, 0x74, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x27, 0x73, + 0x20, 0x74, 0x61, 0x69, 0x6C, 0x3B, 0x20, 0x27, 0x62, 0x75, + 0x74, 0x20, 0x77, 0x68, 0x79, 0x20, 0x64, 0x6F, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x20, 0x69, 0x74, + 0x20, 0x73, 0x61, 0x64, 0x3F, 0x27, 0x20, 0x41, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x6B, 0x65, 0x70, 0x74, 0x20, + 0x6F, 0x6E, 0x20, 0x70, 0x75, 0x7A, 0x7A, 0x6C, 0x69, 0x6E, + 0x67, 0x0D, 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, + 0x74, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x69, 0x6E, 0x67, + 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x69, 0x64, 0x65, 0x61, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x6C, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, 0x73, 0x6F, 0x6D, 0x65, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6C, 0x69, 0x6B, 0x65, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x3A, 0x2D, 0x2D, 0x0D, 0x0A, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x27, 0x46, 0x75, 0x72, 0x79, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x2C, 0x20, 0x54, 0x68, 0x61, 0x74, 0x20, 0x68, + 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x6D, 0x65, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x68, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x4C, 0x65, 0x74, 0x20, 0x75, 0x73, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6F, + 0x74, 0x68, 0x20, 0x67, 0x6F, 0x20, 0x74, 0x6F, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x61, 0x77, + 0x3A, 0x20, 0x49, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, + 0x6F, 0x73, 0x65, 0x63, 0x75, 0x74, 0x65, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x59, 0x4F, + 0x55, 0x2E, 0x2D, 0x2D, 0x43, 0x6F, 0x6D, 0x65, 0x2C, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x74, 0x61, 0x6B, + 0x65, 0x20, 0x6E, 0x6F, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x6E, + 0x69, 0x61, 0x6C, 0x3B, 0x20, 0x57, 0x65, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, + 0x75, 0x73, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x72, 0x69, 0x61, 0x6C, 0x3A, 0x20, 0x46, 0x6F, 0x72, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, + 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x6F, 0x72, 0x6E, + 0x69, 0x6E, 0x67, 0x20, 0x49, 0x27, 0x76, 0x65, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6F, 0x20, + 0x64, 0x6F, 0x2E, 0x22, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x53, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x75, + 0x72, 0x2C, 0x20, 0x22, 0x53, 0x75, 0x63, 0x68, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, + 0x74, 0x72, 0x69, 0x61, 0x6C, 0x2C, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x61, + 0x72, 0x20, 0x53, 0x69, 0x72, 0x2C, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x57, 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6E, 0x6F, 0x20, 0x6A, + 0x75, 0x72, 0x79, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x6F, 0x72, 0x20, 0x6A, 0x75, 0x64, 0x67, + 0x65, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x61, 0x73, + 0x74, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x6F, 0x75, 0x72, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x74, 0x68, 0x2E, + 0x22, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6A, 0x75, + 0x64, 0x67, 0x65, 0x2C, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x62, 0x65, 0x20, 0x6A, 0x75, 0x72, 0x79, 0x2C, 0x22, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x53, 0x61, 0x69, 0x64, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x75, + 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F, 0x6C, 0x64, + 0x20, 0x46, 0x75, 0x72, 0x79, 0x3A, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x49, + 0x27, 0x6C, 0x6C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x72, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68, 0x6F, 0x6C, + 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x75, 0x73, 0x65, + 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x6E, 0x64, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x63, 0x6F, 0x6E, 0x64, 0x65, 0x6D, 0x6E, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6F, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x64, 0x65, 0x61, 0x74, 0x68, 0x2E, 0x22, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, + 0x75, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x61, 0x74, 0x74, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x73, 0x65, 0x76, 0x65, + 0x72, 0x65, 0x6C, 0x79, 0x2E, 0x20, 0x27, 0x57, 0x68, 0x61, + 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x0D, + 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x6F, 0x66, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, + 0x20, 0x62, 0x65, 0x67, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, + 0x70, 0x61, 0x72, 0x64, 0x6F, 0x6E, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x68, 0x75, 0x6D, 0x62, 0x6C, + 0x79, 0x3A, 0x20, 0x27, 0x79, 0x6F, 0x75, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x69, 0x66, 0x74, 0x68, 0x0D, 0x0A, + 0x62, 0x65, 0x6E, 0x64, 0x2C, 0x20, 0x49, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x6B, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x20, 0x68, 0x61, 0x64, 0x20, 0x4E, 0x4F, 0x54, 0x21, + 0x27, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x73, + 0x68, 0x61, 0x72, 0x70, 0x6C, 0x79, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x61, 0x6E, 0x67, 0x72, + 0x69, 0x6C, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, + 0x20, 0x6B, 0x6E, 0x6F, 0x74, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x72, 0x65, 0x61, + 0x64, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x75, + 0x73, 0x65, 0x66, 0x75, 0x6C, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x0D, 0x0A, + 0x61, 0x6E, 0x78, 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, + 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x68, 0x65, 0x72, 0x2E, + 0x20, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x64, 0x6F, 0x20, 0x6C, + 0x65, 0x74, 0x20, 0x6D, 0x65, 0x20, 0x68, 0x65, 0x6C, 0x70, + 0x20, 0x74, 0x6F, 0x20, 0x75, 0x6E, 0x64, 0x6F, 0x20, 0x69, + 0x74, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, + 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x64, 0x6F, 0x20, 0x6E, + 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x67, 0x65, 0x74, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x75, 0x70, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x77, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x0D, + 0x0A, 0x61, 0x77, 0x61, 0x79, 0x2E, 0x20, 0x27, 0x59, 0x6F, + 0x75, 0x20, 0x69, 0x6E, 0x73, 0x75, 0x6C, 0x74, 0x20, 0x6D, + 0x65, 0x20, 0x62, 0x79, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x69, + 0x6E, 0x67, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x6E, 0x6F, + 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x65, 0x21, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, 0x69, 0x64, 0x6E, 0x27, + 0x74, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x20, 0x69, 0x74, 0x21, + 0x27, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x64, 0x65, 0x64, 0x20, + 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2E, 0x20, 0x27, 0x42, 0x75, 0x74, 0x20, 0x79, 0x6F, 0x75, + 0x27, 0x72, 0x65, 0x20, 0x73, 0x6F, 0x20, 0x65, 0x61, 0x73, + 0x69, 0x6C, 0x79, 0x20, 0x6F, 0x66, 0x66, 0x65, 0x6E, 0x64, + 0x65, 0x64, 0x2C, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x6B, + 0x6E, 0x6F, 0x77, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x6F, + 0x6E, 0x6C, 0x79, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x6C, 0x65, + 0x64, 0x20, 0x69, 0x6E, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x79, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x50, 0x6C, 0x65, 0x61, + 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x62, 0x61, + 0x63, 0x6B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x69, 0x6E, + 0x69, 0x73, 0x68, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x73, + 0x74, 0x6F, 0x72, 0x79, 0x21, 0x27, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x20, + 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x69, 0x74, 0x3B, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x6F, + 0x74, 0x68, 0x65, 0x72, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x6A, 0x6F, 0x69, 0x6E, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, + 0x63, 0x68, 0x6F, 0x72, 0x75, 0x73, 0x2C, 0x20, 0x27, 0x59, + 0x65, 0x73, 0x2C, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x64, 0x6F, 0x21, 0x27, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x75, 0x73, 0x65, 0x20, + 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x73, 0x68, 0x6F, 0x6F, 0x6B, + 0x0D, 0x0A, 0x69, 0x74, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, + 0x20, 0x69, 0x6D, 0x70, 0x61, 0x74, 0x69, 0x65, 0x6E, 0x74, + 0x6C, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, + 0x6C, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6B, 0x65, + 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, + 0x74, 0x20, 0x61, 0x20, 0x70, 0x69, 0x74, 0x79, 0x20, 0x69, + 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, + 0x20, 0x73, 0x74, 0x61, 0x79, 0x21, 0x27, 0x20, 0x73, 0x69, + 0x67, 0x68, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4C, + 0x6F, 0x72, 0x79, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x6F, + 0x6F, 0x6E, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x0D, 0x0A, + 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x69, 0x67, + 0x68, 0x74, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6E, + 0x20, 0x6F, 0x6C, 0x64, 0x20, 0x43, 0x72, 0x61, 0x62, 0x20, + 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, + 0x70, 0x70, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x69, 0x74, 0x79, + 0x20, 0x6F, 0x66, 0x20, 0x73, 0x61, 0x79, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x64, + 0x61, 0x75, 0x67, 0x68, 0x74, 0x65, 0x72, 0x20, 0x27, 0x41, + 0x68, 0x2C, 0x20, 0x6D, 0x79, 0x20, 0x64, 0x65, 0x61, 0x72, + 0x21, 0x20, 0x4C, 0x65, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x6C, 0x65, 0x73, 0x73, + 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x6C, + 0x6F, 0x73, 0x65, 0x0D, 0x0A, 0x59, 0x4F, 0x55, 0x52, 0x20, + 0x74, 0x65, 0x6D, 0x70, 0x65, 0x72, 0x21, 0x27, 0x20, 0x27, + 0x48, 0x6F, 0x6C, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, + 0x74, 0x6F, 0x6E, 0x67, 0x75, 0x65, 0x2C, 0x20, 0x4D, 0x61, + 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x79, 0x6F, 0x75, 0x6E, 0x67, 0x20, 0x43, 0x72, + 0x61, 0x62, 0x2C, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x0D, 0x0A, 0x73, 0x6E, 0x61, 0x70, 0x70, 0x69, + 0x73, 0x68, 0x6C, 0x79, 0x2E, 0x20, 0x27, 0x59, 0x6F, 0x75, + 0x27, 0x72, 0x65, 0x20, 0x65, 0x6E, 0x6F, 0x75, 0x67, 0x68, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x72, 0x79, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x61, 0x74, 0x69, 0x65, 0x6E, 0x63, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x20, 0x6F, 0x79, 0x73, + 0x74, 0x65, 0x72, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x20, 0x77, 0x69, 0x73, 0x68, 0x20, 0x49, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x6F, 0x75, 0x72, 0x20, 0x44, 0x69, 0x6E, + 0x61, 0x68, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2C, 0x20, 0x49, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x49, 0x20, 0x64, 0x6F, + 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x61, 0x6C, 0x6F, 0x75, 0x64, 0x2C, + 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6E, + 0x67, 0x0D, 0x0A, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x20, + 0x69, 0x6E, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x75, + 0x6C, 0x61, 0x72, 0x2E, 0x20, 0x27, 0x53, 0x68, 0x65, 0x27, + 0x64, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x66, 0x65, 0x74, + 0x63, 0x68, 0x20, 0x69, 0x74, 0x20, 0x62, 0x61, 0x63, 0x6B, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x6E, 0x64, + 0x20, 0x77, 0x68, 0x6F, 0x20, 0x69, 0x73, 0x20, 0x44, 0x69, + 0x6E, 0x61, 0x68, 0x2C, 0x20, 0x69, 0x66, 0x20, 0x49, 0x20, + 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x76, 0x65, 0x6E, 0x74, + 0x75, 0x72, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x73, 0x6B, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6F, 0x6E, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x4C, 0x6F, 0x72, 0x79, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x65, + 0x61, 0x67, 0x65, 0x72, 0x6C, 0x79, 0x2C, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x72, 0x65, 0x61, + 0x64, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x61, 0x6C, 0x6B, + 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x70, 0x65, 0x74, 0x3A, 0x0D, 0x0A, 0x27, 0x44, 0x69, + 0x6E, 0x61, 0x68, 0x27, 0x73, 0x20, 0x6F, 0x75, 0x72, 0x20, + 0x63, 0x61, 0x74, 0x2E, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x73, + 0x68, 0x65, 0x27, 0x73, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x63, 0x61, 0x70, 0x69, 0x74, 0x61, 0x6C, 0x20, + 0x6F, 0x6E, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x63, 0x61, + 0x74, 0x63, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x69, 0x63, + 0x65, 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, 0x63, 0x61, 0x6E, + 0x27, 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x21, 0x20, + 0x41, 0x6E, 0x64, 0x20, 0x6F, 0x68, 0x2C, 0x20, 0x49, 0x20, + 0x77, 0x69, 0x73, 0x68, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x73, 0x65, 0x65, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x69, 0x72, 0x64, 0x73, 0x21, 0x20, + 0x57, 0x68, 0x79, 0x2C, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x27, + 0x6C, 0x6C, 0x20, 0x65, 0x61, 0x74, 0x20, 0x61, 0x20, 0x6C, + 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x62, 0x69, 0x72, 0x64, + 0x20, 0x61, 0x73, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x61, + 0x73, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x61, 0x74, 0x20, + 0x69, 0x74, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x73, 0x70, 0x65, 0x65, 0x63, 0x68, 0x20, + 0x63, 0x61, 0x75, 0x73, 0x65, 0x64, 0x20, 0x61, 0x20, 0x72, + 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x61, 0x62, 0x6C, 0x65, 0x20, + 0x73, 0x65, 0x6E, 0x73, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, + 0x61, 0x6D, 0x6F, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x70, 0x61, 0x72, 0x74, 0x79, 0x2E, 0x20, 0x53, 0x6F, 0x6D, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x62, 0x69, 0x72, 0x64, 0x73, 0x20, 0x68, 0x75, 0x72, 0x72, + 0x69, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x61, 0x74, + 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x3A, 0x20, 0x6F, 0x6E, 0x65, + 0x20, 0x6F, 0x6C, 0x64, 0x20, 0x4D, 0x61, 0x67, 0x70, 0x69, + 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x77, 0x72, + 0x61, 0x70, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x73, + 0x65, 0x6C, 0x66, 0x20, 0x75, 0x70, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x0D, 0x0A, 0x63, 0x61, 0x72, 0x65, 0x66, 0x75, 0x6C, + 0x6C, 0x79, 0x2C, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x72, 0x6B, + 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x27, 0x49, 0x20, 0x72, 0x65, + 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, + 0x62, 0x65, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x68, 0x6F, 0x6D, 0x65, 0x3B, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6E, 0x69, 0x67, 0x68, 0x74, 0x2D, 0x61, 0x69, 0x72, + 0x0D, 0x0A, 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, 0x74, 0x20, + 0x73, 0x75, 0x69, 0x74, 0x20, 0x6D, 0x79, 0x20, 0x74, 0x68, + 0x72, 0x6F, 0x61, 0x74, 0x21, 0x27, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x61, 0x20, 0x43, 0x61, 0x6E, 0x61, 0x72, 0x79, 0x20, + 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x74, 0x72, 0x65, 0x6D, + 0x62, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x76, 0x6F, 0x69, 0x63, + 0x65, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x69, 0x74, 0x73, 0x20, + 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, 0x65, 0x6E, 0x2C, 0x20, + 0x27, 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x61, 0x77, 0x61, 0x79, + 0x2C, 0x20, 0x6D, 0x79, 0x20, 0x64, 0x65, 0x61, 0x72, 0x73, + 0x21, 0x20, 0x49, 0x74, 0x27, 0x73, 0x20, 0x68, 0x69, 0x67, + 0x68, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x69, 0x6E, 0x20, 0x62, 0x65, 0x64, 0x21, 0x27, 0x0D, 0x0A, + 0x4F, 0x6E, 0x20, 0x76, 0x61, 0x72, 0x69, 0x6F, 0x75, 0x73, + 0x20, 0x70, 0x72, 0x65, 0x74, 0x65, 0x78, 0x74, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6D, + 0x6F, 0x76, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x6C, + 0x65, 0x66, 0x74, 0x20, 0x61, 0x6C, 0x6F, 0x6E, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x77, 0x69, 0x73, + 0x68, 0x20, 0x49, 0x20, 0x68, 0x61, 0x64, 0x6E, 0x27, 0x74, + 0x20, 0x6D, 0x65, 0x6E, 0x74, 0x69, 0x6F, 0x6E, 0x65, 0x64, + 0x20, 0x44, 0x69, 0x6E, 0x61, 0x68, 0x21, 0x27, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x6D, 0x65, 0x6C, 0x61, 0x6E, 0x63, + 0x68, 0x6F, 0x6C, 0x79, 0x0D, 0x0A, 0x74, 0x6F, 0x6E, 0x65, + 0x2E, 0x20, 0x27, 0x4E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x20, + 0x73, 0x65, 0x65, 0x6D, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x68, 0x65, 0x72, 0x2C, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x73, 0x75, + 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, 0x27, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x65, 0x73, 0x74, 0x0D, 0x0A, 0x63, + 0x61, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x20, 0x4F, 0x68, 0x2C, + 0x20, 0x6D, 0x79, 0x20, 0x64, 0x65, 0x61, 0x72, 0x20, 0x44, + 0x69, 0x6E, 0x61, 0x68, 0x21, 0x20, 0x49, 0x20, 0x77, 0x6F, + 0x6E, 0x64, 0x65, 0x72, 0x20, 0x69, 0x66, 0x20, 0x49, 0x20, + 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x65, 0x76, 0x65, 0x72, + 0x20, 0x73, 0x65, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, + 0x61, 0x6E, 0x79, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x21, 0x27, + 0x20, 0x41, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x74, 0x6F, 0x20, + 0x63, 0x72, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, + 0x65, 0x6C, 0x74, 0x20, 0x76, 0x65, 0x72, 0x79, 0x0D, 0x0A, + 0x6C, 0x6F, 0x6E, 0x65, 0x6C, 0x79, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6C, 0x6F, 0x77, 0x2D, 0x73, 0x70, 0x69, 0x72, 0x69, + 0x74, 0x65, 0x64, 0x2E, 0x20, 0x49, 0x6E, 0x20, 0x61, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x77, 0x68, 0x69, + 0x6C, 0x65, 0x2C, 0x20, 0x68, 0x6F, 0x77, 0x65, 0x76, 0x65, + 0x72, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, 0x0D, 0x0A, + 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x70, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x66, 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x73, 0x74, 0x65, 0x70, + 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, + 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x6F, + 0x6B, 0x65, 0x64, 0x20, 0x75, 0x70, 0x0D, 0x0A, 0x65, 0x61, + 0x67, 0x65, 0x72, 0x6C, 0x79, 0x2C, 0x20, 0x68, 0x61, 0x6C, + 0x66, 0x20, 0x68, 0x6F, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, + 0x75, 0x73, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x63, 0x68, + 0x61, 0x6E, 0x67, 0x65, 0x64, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x6D, 0x69, 0x6E, 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, 0x20, + 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x73, 0x74, 0x6F, 0x72, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, 0x48, 0x41, + 0x50, 0x54, 0x45, 0x52, 0x20, 0x49, 0x56, 0x2E, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x20, + 0x53, 0x65, 0x6E, 0x64, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x4C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x42, 0x69, + 0x6C, 0x6C, 0x0D, 0x0A, 0x0D, 0x0A, 0x49, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, 0x69, + 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x2C, + 0x20, 0x74, 0x72, 0x6F, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, + 0x73, 0x6C, 0x6F, 0x77, 0x6C, 0x79, 0x20, 0x62, 0x61, 0x63, + 0x6B, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x61, 0x6E, 0x78, 0x69, 0x6F, 0x75, 0x73, 0x6C, + 0x79, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x73, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x2C, 0x20, + 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x6C, 0x6F, 0x73, 0x74, 0x20, 0x73, 0x6F, + 0x6D, 0x65, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x3B, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, + 0x72, 0x64, 0x0D, 0x0A, 0x69, 0x74, 0x20, 0x6D, 0x75, 0x74, + 0x74, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, + 0x69, 0x74, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x27, 0x54, 0x68, + 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x21, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, + 0x73, 0x73, 0x21, 0x20, 0x4F, 0x68, 0x20, 0x6D, 0x79, 0x20, + 0x64, 0x65, 0x61, 0x72, 0x20, 0x70, 0x61, 0x77, 0x73, 0x21, + 0x20, 0x4F, 0x68, 0x0D, 0x0A, 0x6D, 0x79, 0x20, 0x66, 0x75, + 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x69, 0x73, + 0x6B, 0x65, 0x72, 0x73, 0x21, 0x20, 0x53, 0x68, 0x65, 0x27, + 0x6C, 0x6C, 0x20, 0x67, 0x65, 0x74, 0x20, 0x6D, 0x65, 0x20, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x2C, 0x20, + 0x61, 0x73, 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x61, 0x73, + 0x20, 0x66, 0x65, 0x72, 0x72, 0x65, 0x74, 0x73, 0x20, 0x61, + 0x72, 0x65, 0x0D, 0x0A, 0x66, 0x65, 0x72, 0x72, 0x65, 0x74, + 0x73, 0x21, 0x20, 0x57, 0x68, 0x65, 0x72, 0x65, 0x20, 0x43, + 0x41, 0x4E, 0x20, 0x49, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x64, 0x72, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x2C, 0x20, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x64, + 0x65, 0x72, 0x3F, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x67, 0x75, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x0D, 0x0A, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, + 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x66, 0x61, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x61, 0x69, 0x72, 0x20, 0x6F, 0x66, 0x20, + 0x77, 0x68, 0x69, 0x74, 0x65, 0x20, 0x6B, 0x69, 0x64, 0x20, + 0x67, 0x6C, 0x6F, 0x76, 0x65, 0x73, 0x2C, 0x0D, 0x0A, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x2D, 0x6E, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x64, 0x6C, 0x79, 0x20, 0x62, 0x65, 0x67, + 0x61, 0x6E, 0x20, 0x68, 0x75, 0x6E, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, 0x65, 0x72, 0x65, + 0x0D, 0x0A, 0x6E, 0x6F, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x65, 0x6E, + 0x2D, 0x2D, 0x65, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x20, 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x63, 0x68, + 0x61, 0x6E, 0x67, 0x65, 0x64, 0x20, 0x73, 0x69, 0x6E, 0x63, + 0x65, 0x20, 0x68, 0x65, 0x72, 0x20, 0x73, 0x77, 0x69, 0x6D, + 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x6F, 0x6F, 0x6C, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x68, + 0x61, 0x6C, 0x6C, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x67, 0x6C, 0x61, 0x73, 0x73, 0x20, + 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x2C, 0x0D, 0x0A, 0x68, 0x61, + 0x64, 0x20, 0x76, 0x61, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x6C, 0x65, 0x74, 0x65, 0x6C, + 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x56, 0x65, 0x72, 0x79, + 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x20, 0x6E, 0x6F, 0x74, + 0x69, 0x63, 0x65, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x68, 0x75, 0x6E, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x0D, 0x0A, 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, + 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x6E, + 0x67, 0x72, 0x79, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x20, + 0x27, 0x57, 0x68, 0x79, 0x2C, 0x20, 0x4D, 0x61, 0x72, 0x79, + 0x20, 0x41, 0x6E, 0x6E, 0x2C, 0x20, 0x77, 0x68, 0x61, 0x74, + 0x20, 0x41, 0x52, 0x45, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, + 0x6F, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x6F, 0x75, 0x74, 0x20, + 0x68, 0x65, 0x72, 0x65, 0x3F, 0x20, 0x52, 0x75, 0x6E, 0x20, + 0x68, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, 0x20, 0x6D, 0x65, + 0x20, 0x61, 0x20, 0x70, 0x61, 0x69, 0x72, 0x20, 0x6F, 0x66, + 0x20, 0x67, 0x6C, 0x6F, 0x76, 0x65, 0x73, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x61, 0x20, 0x66, 0x61, 0x6E, 0x21, 0x0D, 0x0A, + 0x51, 0x75, 0x69, 0x63, 0x6B, 0x2C, 0x20, 0x6E, 0x6F, 0x77, + 0x21, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x6F, 0x20, + 0x6D, 0x75, 0x63, 0x68, 0x20, 0x66, 0x72, 0x69, 0x67, 0x68, + 0x74, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x72, 0x61, 0x6E, 0x20, 0x6F, + 0x66, 0x66, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, + 0x0D, 0x0A, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, + 0x74, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x64, 0x20, + 0x74, 0x6F, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, + 0x74, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x20, 0x65, 0x78, 0x70, 0x6C, 0x61, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6D, 0x69, 0x73, 0x74, 0x61, 0x6B, + 0x65, 0x20, 0x69, 0x74, 0x0D, 0x0A, 0x68, 0x61, 0x64, 0x20, + 0x6D, 0x61, 0x64, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x48, 0x65, 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x6D, 0x65, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x68, 0x69, 0x73, 0x20, 0x68, + 0x6F, 0x75, 0x73, 0x65, 0x6D, 0x61, 0x69, 0x64, 0x2C, 0x27, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, + 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x72, 0x61, + 0x6E, 0x2E, 0x20, 0x27, 0x48, 0x6F, 0x77, 0x0D, 0x0A, 0x73, + 0x75, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x64, 0x20, 0x68, + 0x65, 0x27, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x20, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6E, 0x64, + 0x73, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x77, 0x68, 0x6F, 0x20, + 0x49, 0x20, 0x61, 0x6D, 0x21, 0x20, 0x42, 0x75, 0x74, 0x20, + 0x49, 0x27, 0x64, 0x20, 0x62, 0x65, 0x74, 0x74, 0x65, 0x72, + 0x20, 0x74, 0x61, 0x6B, 0x65, 0x20, 0x68, 0x69, 0x6D, 0x0D, + 0x0A, 0x68, 0x69, 0x73, 0x20, 0x66, 0x61, 0x6E, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x67, 0x6C, 0x6F, 0x76, 0x65, 0x73, 0x2D, + 0x2D, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x2C, 0x20, + 0x69, 0x66, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x66, + 0x69, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2E, 0x27, + 0x20, 0x41, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, 0x20, 0x73, + 0x68, 0x65, 0x0D, 0x0A, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x75, + 0x70, 0x6F, 0x6E, 0x20, 0x61, 0x20, 0x6E, 0x65, 0x61, 0x74, + 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x68, 0x6F, + 0x75, 0x73, 0x65, 0x2C, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, 0x6F, 0x66, 0x20, + 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x61, 0x20, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x62, + 0x72, 0x61, 0x73, 0x73, 0x0D, 0x0A, 0x70, 0x6C, 0x61, 0x74, + 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x20, 0x27, 0x57, 0x2E, 0x20, + 0x52, 0x41, 0x42, 0x42, 0x49, 0x54, 0x27, 0x20, 0x65, 0x6E, + 0x67, 0x72, 0x61, 0x76, 0x65, 0x64, 0x20, 0x75, 0x70, 0x6F, + 0x6E, 0x20, 0x69, 0x74, 0x2E, 0x20, 0x53, 0x68, 0x65, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x6F, 0x75, 0x74, 0x0D, 0x0A, 0x6B, 0x6E, 0x6F, + 0x63, 0x6B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x68, 0x75, 0x72, 0x72, 0x69, 0x65, 0x64, 0x20, 0x75, + 0x70, 0x73, 0x74, 0x61, 0x69, 0x72, 0x73, 0x2C, 0x20, 0x69, + 0x6E, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x66, 0x65, + 0x61, 0x72, 0x20, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6D, + 0x65, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x72, + 0x65, 0x61, 0x6C, 0x20, 0x4D, 0x61, 0x72, 0x79, 0x20, 0x41, + 0x6E, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, + 0x20, 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, + 0x6F, 0x75, 0x73, 0x65, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, + 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x66, 0x61, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x67, + 0x6C, 0x6F, 0x76, 0x65, 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x48, 0x6F, 0x77, 0x20, 0x71, 0x75, 0x65, 0x65, 0x72, + 0x20, 0x69, 0x74, 0x20, 0x73, 0x65, 0x65, 0x6D, 0x73, 0x2C, + 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, 0x74, 0x6F, 0x20, 0x62, + 0x65, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x20, 0x66, 0x6F, 0x72, + 0x0D, 0x0A, 0x61, 0x20, 0x72, 0x61, 0x62, 0x62, 0x69, 0x74, + 0x21, 0x20, 0x49, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x73, + 0x65, 0x20, 0x44, 0x69, 0x6E, 0x61, 0x68, 0x27, 0x6C, 0x6C, + 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x69, 0x6E, + 0x67, 0x20, 0x6D, 0x65, 0x20, 0x6F, 0x6E, 0x20, 0x6D, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x20, 0x6E, 0x65, 0x78, + 0x74, 0x21, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x73, 0x68, + 0x65, 0x0D, 0x0A, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x66, + 0x61, 0x6E, 0x63, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, 0x61, 0x70, + 0x70, 0x65, 0x6E, 0x3A, 0x20, 0x27, 0x22, 0x4D, 0x69, 0x73, + 0x73, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x21, 0x20, 0x43, + 0x6F, 0x6D, 0x65, 0x0D, 0x0A, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6C, 0x79, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x67, 0x65, 0x74, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x79, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x79, 0x6F, + 0x75, 0x72, 0x20, 0x77, 0x61, 0x6C, 0x6B, 0x21, 0x22, 0x20, + 0x22, 0x43, 0x6F, 0x6D, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x2C, + 0x0D, 0x0A, 0x6E, 0x75, 0x72, 0x73, 0x65, 0x21, 0x20, 0x42, + 0x75, 0x74, 0x20, 0x49, 0x27, 0x76, 0x65, 0x20, 0x67, 0x6F, + 0x74, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, + 0x75, 0x73, 0x65, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, + 0x74, 0x20, 0x67, 0x65, 0x74, 0x20, 0x6F, 0x75, 0x74, 0x2E, + 0x22, 0x20, 0x4F, 0x6E, 0x6C, 0x79, 0x20, 0x49, 0x20, 0x64, + 0x6F, 0x6E, 0x27, 0x74, 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x6E, + 0x6B, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x27, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, 0x27, + 0x64, 0x20, 0x6C, 0x65, 0x74, 0x20, 0x44, 0x69, 0x6E, 0x61, + 0x68, 0x20, 0x73, 0x74, 0x6F, 0x70, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x68, 0x6F, 0x75, 0x73, 0x65, 0x20, + 0x69, 0x66, 0x20, 0x69, 0x74, 0x0D, 0x0A, 0x62, 0x65, 0x67, + 0x61, 0x6E, 0x20, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6E, + 0x67, 0x20, 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x42, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x69, + 0x6D, 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x77, 0x61, 0x79, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, + 0x61, 0x20, 0x74, 0x69, 0x64, 0x79, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x72, 0x6F, 0x6F, 0x6D, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x74, 0x61, 0x62, 0x6C, + 0x65, 0x0D, 0x0A, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x69, 0x74, 0x20, 0x28, 0x61, + 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x68, 0x6F, 0x70, 0x65, 0x64, 0x29, 0x20, 0x61, 0x20, 0x66, + 0x61, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x77, 0x6F, + 0x20, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, + 0x70, 0x61, 0x69, 0x72, 0x73, 0x0D, 0x0A, 0x6F, 0x66, 0x20, + 0x74, 0x69, 0x6E, 0x79, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, + 0x20, 0x6B, 0x69, 0x64, 0x20, 0x67, 0x6C, 0x6F, 0x76, 0x65, + 0x73, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x6F, + 0x6B, 0x20, 0x75, 0x70, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, + 0x61, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x20, 0x70, + 0x61, 0x69, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x67, 0x6C, 0x6F, 0x76, 0x65, 0x73, 0x2C, 0x0D, 0x0A, + 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6A, 0x75, + 0x73, 0x74, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x20, 0x6C, 0x65, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x6F, 0x6F, 0x6D, 0x2C, 0x20, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, 0x65, 0x79, 0x65, + 0x20, 0x66, 0x65, 0x6C, 0x6C, 0x20, 0x75, 0x70, 0x6F, 0x6E, + 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x0D, + 0x0A, 0x62, 0x6F, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x73, 0x74, 0x6F, 0x6F, 0x64, 0x20, 0x6E, + 0x65, 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x2D, 0x67, 0x6C, 0x61, 0x73, + 0x73, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x6C, 0x61, 0x62, 0x65, + 0x6C, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x69, 0x6D, + 0x65, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x20, 0x27, 0x44, + 0x52, 0x49, 0x4E, 0x4B, 0x20, 0x4D, 0x45, 0x2C, 0x27, 0x20, + 0x62, 0x75, 0x74, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x74, + 0x68, 0x65, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x75, 0x6E, 0x63, 0x6F, 0x72, 0x6B, 0x65, 0x64, 0x20, + 0x69, 0x74, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x70, 0x75, 0x74, + 0x20, 0x69, 0x74, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x6C, 0x69, 0x70, 0x73, 0x2E, 0x20, 0x27, 0x49, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x53, 0x4F, 0x4D, 0x45, + 0x54, 0x48, 0x49, 0x4E, 0x47, 0x20, 0x69, 0x6E, 0x74, 0x65, + 0x72, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x73, + 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x68, + 0x61, 0x70, 0x70, 0x65, 0x6E, 0x2C, 0x27, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x0D, 0x0A, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, + 0x27, 0x77, 0x68, 0x65, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, + 0x49, 0x20, 0x65, 0x61, 0x74, 0x20, 0x6F, 0x72, 0x20, 0x64, + 0x72, 0x69, 0x6E, 0x6B, 0x20, 0x61, 0x6E, 0x79, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x3B, 0x20, 0x73, 0x6F, 0x20, 0x49, 0x27, + 0x6C, 0x6C, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x73, 0x65, + 0x65, 0x20, 0x77, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x62, 0x6F, 0x74, 0x74, 0x6C, 0x65, 0x20, + 0x64, 0x6F, 0x65, 0x73, 0x2E, 0x20, 0x49, 0x20, 0x64, 0x6F, + 0x20, 0x68, 0x6F, 0x70, 0x65, 0x20, 0x69, 0x74, 0x27, 0x6C, + 0x6C, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x6D, 0x65, 0x20, + 0x67, 0x72, 0x6F, 0x77, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x72, 0x65, 0x61, 0x6C, 0x6C, 0x79, 0x0D, 0x0A, + 0x49, 0x27, 0x6D, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, + 0x74, 0x69, 0x72, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x62, + 0x65, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x74, 0x69, 0x6E, 0x79, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x21, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x49, 0x74, 0x20, 0x64, 0x69, + 0x64, 0x20, 0x73, 0x6F, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x65, + 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x61, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x3A, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x0D, 0x0A, 0x64, 0x72, + 0x75, 0x6E, 0x6B, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x6F, 0x74, 0x74, 0x6C, 0x65, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x65, 0x69, 0x6C, 0x69, 0x6E, 0x67, 0x2C, 0x0D, + 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x73, 0x74, 0x6F, 0x6F, 0x70, 0x20, 0x74, 0x6F, + 0x20, 0x73, 0x61, 0x76, 0x65, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x6E, 0x65, 0x63, 0x6B, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, + 0x62, 0x65, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x72, 0x6F, 0x6B, + 0x65, 0x6E, 0x2E, 0x20, 0x53, 0x68, 0x65, 0x20, 0x68, 0x61, + 0x73, 0x74, 0x69, 0x6C, 0x79, 0x20, 0x70, 0x75, 0x74, 0x0D, + 0x0A, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x6F, 0x74, 0x74, 0x6C, 0x65, 0x2C, 0x20, 0x73, 0x61, + 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x27, 0x54, 0x68, 0x61, + 0x74, 0x27, 0x73, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, + 0x65, 0x6E, 0x6F, 0x75, 0x67, 0x68, 0x2D, 0x2D, 0x49, 0x20, + 0x68, 0x6F, 0x70, 0x65, 0x20, 0x49, 0x20, 0x73, 0x68, 0x61, + 0x6E, 0x27, 0x74, 0x0D, 0x0A, 0x67, 0x72, 0x6F, 0x77, 0x20, + 0x61, 0x6E, 0x79, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x2D, 0x2D, + 0x41, 0x73, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x2C, 0x20, + 0x49, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x67, 0x65, + 0x74, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x2D, 0x2D, 0x49, + 0x20, 0x64, 0x6F, 0x20, 0x77, 0x69, 0x73, 0x68, 0x20, 0x49, + 0x20, 0x68, 0x61, 0x64, 0x6E, 0x27, 0x74, 0x0D, 0x0A, 0x64, + 0x72, 0x75, 0x6E, 0x6B, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, + 0x20, 0x73, 0x6F, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x61, 0x73, 0x21, 0x20, + 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x6F, 0x6F, + 0x20, 0x6C, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x77, + 0x69, 0x73, 0x68, 0x20, 0x74, 0x68, 0x61, 0x74, 0x21, 0x20, + 0x53, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, + 0x6E, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x69, + 0x6E, 0x67, 0x2C, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6B, 0x6E, 0x65, 0x65, + 0x6C, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x6F, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0x3A, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x0D, 0x0A, 0x77, 0x61, 0x73, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x72, + 0x6F, 0x6F, 0x6D, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x20, 0x6F, + 0x66, 0x20, 0x6C, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x64, 0x6F, + 0x77, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x6F, + 0x6E, 0x65, 0x20, 0x65, 0x6C, 0x62, 0x6F, 0x77, 0x20, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x61, 0x72, 0x6D, 0x20, 0x63, 0x75, 0x72, 0x6C, 0x65, + 0x64, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, 0x2E, 0x0D, 0x0A, 0x53, + 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x67, 0x72, 0x6F, + 0x77, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x2C, + 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x61, 0x73, 0x74, + 0x20, 0x72, 0x65, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x70, 0x75, 0x74, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x61, 0x72, 0x6D, 0x20, 0x6F, 0x75, 0x74, + 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x20, + 0x75, 0x70, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x69, + 0x6D, 0x6E, 0x65, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x27, 0x4E, 0x6F, 0x77, + 0x20, 0x49, 0x0D, 0x0A, 0x63, 0x61, 0x6E, 0x20, 0x64, 0x6F, + 0x20, 0x6E, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x2C, 0x20, + 0x77, 0x68, 0x61, 0x74, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, + 0x61, 0x70, 0x70, 0x65, 0x6E, 0x73, 0x2E, 0x20, 0x57, 0x68, + 0x61, 0x74, 0x20, 0x57, 0x49, 0x4C, 0x4C, 0x20, 0x62, 0x65, + 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x65, + 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x4C, 0x75, 0x63, 0x6B, + 0x69, 0x6C, 0x79, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, + 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x6D, 0x61, 0x67, 0x69, + 0x63, 0x20, 0x62, 0x6F, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x69, 0x74, 0x73, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x20, + 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x2C, 0x0D, 0x0A, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x67, 0x72, 0x65, + 0x77, 0x20, 0x6E, 0x6F, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x72, 0x3A, 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x69, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x75, 0x6E, 0x63, 0x6F, 0x6D, 0x66, 0x6F, 0x72, 0x74, + 0x61, 0x62, 0x6C, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x2C, + 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x0D, + 0x0A, 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x65, 0x20, 0x6E, 0x6F, 0x20, 0x73, 0x6F, 0x72, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x63, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, 0x20, 0x65, + 0x76, 0x65, 0x72, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x72, 0x6F, 0x6F, 0x6D, 0x0D, 0x0A, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x6E, 0x6F, 0x20, 0x77, + 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x66, 0x65, 0x6C, 0x74, 0x20, 0x75, 0x6E, 0x68, 0x61, 0x70, + 0x70, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, + 0x70, 0x6C, 0x65, 0x61, 0x73, 0x61, 0x6E, 0x74, 0x65, 0x72, + 0x20, 0x61, 0x74, 0x20, 0x68, 0x6F, 0x6D, 0x65, 0x2C, 0x27, + 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x70, + 0x6F, 0x6F, 0x72, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, + 0x20, 0x27, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x6F, 0x6E, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x6E, 0x27, 0x74, 0x0D, 0x0A, 0x61, + 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x67, 0x72, 0x6F, 0x77, + 0x69, 0x6E, 0x67, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x72, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x6D, 0x61, 0x6C, 0x6C, + 0x65, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, + 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x65, + 0x64, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x62, 0x79, + 0x20, 0x6D, 0x69, 0x63, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x0D, + 0x0A, 0x72, 0x61, 0x62, 0x62, 0x69, 0x74, 0x73, 0x2E, 0x20, + 0x49, 0x20, 0x61, 0x6C, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x77, + 0x69, 0x73, 0x68, 0x20, 0x49, 0x20, 0x68, 0x61, 0x64, 0x6E, + 0x27, 0x74, 0x20, 0x67, 0x6F, 0x6E, 0x65, 0x20, 0x64, 0x6F, + 0x77, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x72, 0x61, + 0x62, 0x62, 0x69, 0x74, 0x2D, 0x68, 0x6F, 0x6C, 0x65, 0x2D, + 0x2D, 0x61, 0x6E, 0x64, 0x20, 0x79, 0x65, 0x74, 0x2D, 0x2D, + 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x79, 0x65, 0x74, 0x2D, 0x2D, + 0x69, 0x74, 0x27, 0x73, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x2C, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2C, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6F, 0x72, 0x74, + 0x20, 0x6F, 0x66, 0x20, 0x6C, 0x69, 0x66, 0x65, 0x21, 0x20, + 0x49, 0x20, 0x64, 0x6F, 0x20, 0x77, 0x6F, 0x6E, 0x64, 0x65, + 0x72, 0x20, 0x77, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x43, 0x41, + 0x4E, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x68, 0x61, 0x70, + 0x70, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, + 0x65, 0x21, 0x20, 0x57, 0x68, 0x65, 0x6E, 0x20, 0x49, 0x20, + 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x20, 0x66, 0x61, 0x69, 0x72, 0x79, 0x2D, 0x74, + 0x61, 0x6C, 0x65, 0x73, 0x2C, 0x20, 0x49, 0x20, 0x66, 0x61, + 0x6E, 0x63, 0x69, 0x65, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x0D, 0x0A, 0x6B, 0x69, 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6E, 0x65, 0x76, 0x65, + 0x72, 0x20, 0x68, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x65, 0x64, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6E, 0x6F, 0x77, 0x20, + 0x68, 0x65, 0x72, 0x65, 0x20, 0x49, 0x20, 0x61, 0x6D, 0x20, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x69, 0x64, + 0x64, 0x6C, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x6F, 0x6E, 0x65, + 0x21, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, + 0x20, 0x61, 0x20, 0x62, 0x6F, 0x6F, 0x6B, 0x20, 0x77, 0x72, + 0x69, 0x74, 0x74, 0x65, 0x6E, 0x20, 0x61, 0x62, 0x6F, 0x75, + 0x74, 0x20, 0x6D, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x21, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x49, 0x0D, 0x0A, 0x67, 0x72, 0x6F, 0x77, + 0x20, 0x75, 0x70, 0x2C, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x6F, 0x6E, 0x65, 0x2D, + 0x2D, 0x62, 0x75, 0x74, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x67, + 0x72, 0x6F, 0x77, 0x6E, 0x20, 0x75, 0x70, 0x20, 0x6E, 0x6F, + 0x77, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x61, 0x64, + 0x64, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x73, + 0x6F, 0x72, 0x72, 0x6F, 0x77, 0x66, 0x75, 0x6C, 0x0D, 0x0A, + 0x74, 0x6F, 0x6E, 0x65, 0x3B, 0x20, 0x27, 0x61, 0x74, 0x20, + 0x6C, 0x65, 0x61, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x72, 0x6F, 0x6F, + 0x6D, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x20, + 0x75, 0x70, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6D, 0x6F, 0x72, + 0x65, 0x20, 0x48, 0x45, 0x52, 0x45, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x42, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x6E, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x27, + 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x49, 0x20, 0x4E, 0x45, + 0x56, 0x45, 0x52, 0x20, 0x67, 0x65, 0x74, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x6E, 0x20, 0x49, 0x20, 0x61, 0x6D, 0x0D, 0x0A, 0x6E, + 0x6F, 0x77, 0x3F, 0x20, 0x54, 0x68, 0x61, 0x74, 0x27, 0x6C, + 0x6C, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x63, 0x6F, 0x6D, + 0x66, 0x6F, 0x72, 0x74, 0x2C, 0x20, 0x6F, 0x6E, 0x65, 0x20, + 0x77, 0x61, 0x79, 0x2D, 0x2D, 0x6E, 0x65, 0x76, 0x65, 0x72, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x61, 0x6E, 0x20, + 0x6F, 0x6C, 0x64, 0x20, 0x77, 0x6F, 0x6D, 0x61, 0x6E, 0x2D, + 0x2D, 0x62, 0x75, 0x74, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x6E, + 0x2D, 0x2D, 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x74, + 0x6F, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6C, 0x65, 0x73, + 0x73, 0x6F, 0x6E, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x65, + 0x61, 0x72, 0x6E, 0x21, 0x20, 0x4F, 0x68, 0x2C, 0x20, 0x49, + 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x54, 0x48, 0x41, 0x54, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x66, 0x6F, 0x6F, 0x6C, 0x69, + 0x73, 0x68, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x21, 0x27, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x61, 0x6E, 0x73, 0x77, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, + 0x66, 0x2E, 0x20, 0x27, 0x48, 0x6F, 0x77, 0x20, 0x63, 0x61, + 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6C, 0x65, 0x61, 0x72, + 0x6E, 0x0D, 0x0A, 0x6C, 0x65, 0x73, 0x73, 0x6F, 0x6E, 0x73, + 0x20, 0x69, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x65, 0x3F, 0x20, + 0x57, 0x68, 0x79, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x27, 0x73, 0x20, 0x68, 0x61, 0x72, 0x64, 0x6C, 0x79, 0x20, + 0x72, 0x6F, 0x6F, 0x6D, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x59, + 0x4F, 0x55, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6E, 0x6F, + 0x20, 0x72, 0x6F, 0x6F, 0x6D, 0x20, 0x61, 0x74, 0x20, 0x61, + 0x6C, 0x6C, 0x0D, 0x0A, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x6C, 0x65, 0x73, 0x73, 0x6F, 0x6E, 0x2D, 0x62, + 0x6F, 0x6F, 0x6B, 0x73, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x41, 0x6E, 0x64, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2C, 0x20, + 0x74, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x69, 0x72, + 0x73, 0x74, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x73, 0x69, 0x64, + 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x6B, 0x69, + 0x6E, 0x67, 0x0D, 0x0A, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, + 0x61, 0x20, 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, + 0x20, 0x61, 0x6C, 0x74, 0x6F, 0x67, 0x65, 0x74, 0x68, 0x65, + 0x72, 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x61, 0x66, 0x74, + 0x65, 0x72, 0x20, 0x61, 0x20, 0x66, 0x65, 0x77, 0x20, 0x6D, + 0x69, 0x6E, 0x75, 0x74, 0x65, 0x73, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, 0x0D, 0x0A, 0x61, 0x20, + 0x76, 0x6F, 0x69, 0x63, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x73, + 0x69, 0x64, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, + 0x74, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x6C, 0x69, 0x73, 0x74, 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x4D, 0x61, 0x72, 0x79, 0x20, 0x41, 0x6E, 0x6E, + 0x21, 0x20, 0x4D, 0x61, 0x72, 0x79, 0x20, 0x41, 0x6E, 0x6E, + 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2E, 0x20, 0x27, + 0x46, 0x65, 0x74, 0x63, 0x68, 0x20, 0x6D, 0x65, 0x20, 0x6D, + 0x79, 0x20, 0x67, 0x6C, 0x6F, 0x76, 0x65, 0x73, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, + 0x21, 0x27, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x63, + 0x61, 0x6D, 0x65, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x69, + 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, 0x66, 0x65, 0x65, 0x74, + 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, + 0x61, 0x69, 0x72, 0x73, 0x2E, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x6B, 0x6E, 0x65, 0x77, 0x20, 0x69, 0x74, 0x20, + 0x77, 0x61, 0x73, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x52, + 0x61, 0x62, 0x62, 0x69, 0x74, 0x20, 0x63, 0x6F, 0x6D, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x68, 0x65, 0x72, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x72, + 0x65, 0x6D, 0x62, 0x6C, 0x65, 0x64, 0x20, 0x74, 0x69, 0x6C, + 0x6C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x68, 0x6F, 0x6F, + 0x6B, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x68, 0x6F, 0x75, + 0x73, 0x65, 0x2C, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, + 0x66, 0x6F, 0x72, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x61, 0x62, + 0x6F, 0x75, 0x74, 0x20, 0x61, 0x20, 0x74, 0x68, 0x6F, 0x75, + 0x73, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x73, + 0x20, 0x61, 0x73, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x0D, + 0x0A, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, + 0x62, 0x62, 0x69, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x20, 0x72, 0x65, 0x61, + 0x73, 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, + 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, 0x20, 0x6F, 0x66, 0x20, + 0x69, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x50, 0x72, 0x65, + 0x73, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x20, 0x63, 0x61, + 0x6D, 0x65, 0x20, 0x75, 0x70, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x20, 0x69, 0x74, 0x3B, + 0x20, 0x62, 0x75, 0x74, 0x2C, 0x20, 0x61, 0x73, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, 0x6F, + 0x70, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x77, 0x61, + 0x72, 0x64, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x27, 0x73, 0x20, 0x65, 0x6C, 0x62, + 0x6F, 0x77, 0x20, 0x77, 0x61, 0x73, 0x20, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x68, 0x61, 0x72, 0x64, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x73, 0x74, 0x20, 0x69, 0x74, + 0x2C, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x74, + 0x74, 0x65, 0x6D, 0x70, 0x74, 0x20, 0x70, 0x72, 0x6F, 0x76, + 0x65, 0x64, 0x20, 0x61, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x75, + 0x72, 0x65, 0x2E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x68, 0x65, 0x61, 0x72, 0x64, 0x20, 0x69, 0x74, 0x20, 0x73, + 0x61, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x73, 0x65, + 0x6C, 0x66, 0x20, 0x27, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x49, + 0x27, 0x6C, 0x6C, 0x0D, 0x0A, 0x67, 0x6F, 0x20, 0x72, 0x6F, + 0x75, 0x6E, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x67, 0x65, + 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x48, 0x41, 0x54, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x27, + 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x2C, + 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x77, 0x61, 0x69, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x66, 0x61, 0x6E, 0x63, 0x69, 0x65, + 0x64, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, + 0x72, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x75, + 0x6E, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x2C, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, 0x6C, 0x79, 0x20, + 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x20, 0x6F, 0x75, 0x74, + 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x68, 0x61, 0x6E, 0x64, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x64, 0x65, + 0x20, 0x61, 0x20, 0x73, 0x6E, 0x61, 0x74, 0x63, 0x68, 0x20, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x69, 0x72, + 0x2E, 0x20, 0x53, 0x68, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x67, 0x65, 0x74, 0x20, 0x68, 0x6F, + 0x6C, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x2C, 0x0D, 0x0A, 0x62, 0x75, 0x74, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, + 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, + 0x73, 0x68, 0x72, 0x69, 0x65, 0x6B, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x61, 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x20, 0x63, 0x72, 0x61, 0x73, 0x68, + 0x20, 0x6F, 0x66, 0x20, 0x62, 0x72, 0x6F, 0x6B, 0x65, 0x6E, + 0x20, 0x67, 0x6C, 0x61, 0x73, 0x73, 0x2C, 0x0D, 0x0A, 0x66, + 0x72, 0x6F, 0x6D, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x63, 0x6C, 0x75, + 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6A, 0x75, 0x73, 0x74, + 0x20, 0x70, 0x6F, 0x73, 0x73, 0x69, 0x62, 0x6C, 0x65, 0x20, + 0x69, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, 0x66, 0x61, 0x6C, + 0x6C, 0x65, 0x6E, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x61, + 0x0D, 0x0A, 0x63, 0x75, 0x63, 0x75, 0x6D, 0x62, 0x65, 0x72, + 0x2D, 0x66, 0x72, 0x61, 0x6D, 0x65, 0x2C, 0x20, 0x6F, 0x72, + 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6F, + 0x72, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x4E, 0x65, 0x78, + 0x74, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x61, 0x6E, 0x20, + 0x61, 0x6E, 0x67, 0x72, 0x79, 0x20, 0x76, 0x6F, 0x69, 0x63, + 0x65, 0x2D, 0x2D, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x27, 0x73, 0x2D, 0x2D, 0x27, 0x50, 0x61, + 0x74, 0x21, 0x20, 0x50, 0x61, 0x74, 0x21, 0x20, 0x57, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x61, 0x72, 0x65, 0x20, 0x79, 0x6F, + 0x75, 0x3F, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x6E, 0x20, 0x61, 0x20, 0x76, 0x6F, 0x69, 0x63, + 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, 0x65, 0x61, 0x72, + 0x64, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x2C, 0x20, + 0x27, 0x53, 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6E, + 0x20, 0x49, 0x27, 0x6D, 0x20, 0x68, 0x65, 0x72, 0x65, 0x21, + 0x20, 0x44, 0x69, 0x67, 0x67, 0x69, 0x6E, 0x67, 0x0D, 0x0A, + 0x66, 0x6F, 0x72, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x65, 0x73, + 0x2C, 0x20, 0x79, 0x65, 0x72, 0x20, 0x68, 0x6F, 0x6E, 0x6F, + 0x75, 0x72, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x44, + 0x69, 0x67, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x61, 0x70, 0x70, 0x6C, 0x65, 0x73, 0x2C, 0x20, 0x69, + 0x6E, 0x64, 0x65, 0x65, 0x64, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x20, 0x61, 0x6E, 0x67, 0x72, 0x69, 0x6C, + 0x79, 0x2E, 0x20, 0x27, 0x48, 0x65, 0x72, 0x65, 0x21, 0x20, + 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, + 0x68, 0x65, 0x6C, 0x70, 0x20, 0x6D, 0x65, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x54, 0x48, 0x49, 0x53, 0x21, + 0x27, 0x20, 0x28, 0x53, 0x6F, 0x75, 0x6E, 0x64, 0x73, 0x20, + 0x6F, 0x66, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x62, 0x72, + 0x6F, 0x6B, 0x65, 0x6E, 0x20, 0x67, 0x6C, 0x61, 0x73, 0x73, + 0x2E, 0x29, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x77, + 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x6D, 0x65, 0x2C, 0x20, + 0x50, 0x61, 0x74, 0x2C, 0x20, 0x77, 0x68, 0x61, 0x74, 0x27, + 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, + 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x75, 0x72, + 0x65, 0x2C, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x61, 0x6E, + 0x20, 0x61, 0x72, 0x6D, 0x2C, 0x20, 0x79, 0x65, 0x72, 0x20, + 0x68, 0x6F, 0x6E, 0x6F, 0x75, 0x72, 0x21, 0x27, 0x20, 0x28, + 0x48, 0x65, 0x20, 0x70, 0x72, 0x6F, 0x6E, 0x6F, 0x75, 0x6E, + 0x63, 0x65, 0x64, 0x20, 0x69, 0x74, 0x20, 0x27, 0x61, 0x72, + 0x72, 0x75, 0x6D, 0x2E, 0x27, 0x29, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x41, 0x6E, 0x20, 0x61, 0x72, 0x6D, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x67, 0x6F, 0x6F, 0x73, 0x65, 0x21, 0x20, + 0x57, 0x68, 0x6F, 0x20, 0x65, 0x76, 0x65, 0x72, 0x20, 0x73, + 0x61, 0x77, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3F, 0x20, 0x57, 0x68, + 0x79, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x66, 0x69, 0x6C, 0x6C, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, 0x6F, 0x6C, + 0x65, 0x0D, 0x0A, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x21, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x75, 0x72, 0x65, + 0x2C, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x2C, + 0x20, 0x79, 0x65, 0x72, 0x20, 0x68, 0x6F, 0x6E, 0x6F, 0x75, + 0x72, 0x3A, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x74, 0x27, + 0x73, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x72, 0x6D, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, + 0x6C, 0x6C, 0x2C, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x67, + 0x6F, 0x74, 0x20, 0x6E, 0x6F, 0x20, 0x62, 0x75, 0x73, 0x69, + 0x6E, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x2C, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x72, + 0x61, 0x74, 0x65, 0x3A, 0x20, 0x67, 0x6F, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x61, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, + 0x61, 0x77, 0x61, 0x79, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x61, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x73, 0x69, 0x6C, + 0x65, 0x6E, 0x63, 0x65, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x63, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x68, 0x65, + 0x61, 0x72, 0x20, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, + 0x73, 0x0D, 0x0A, 0x6E, 0x6F, 0x77, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x6E, 0x3B, 0x20, 0x73, 0x75, 0x63, + 0x68, 0x20, 0x61, 0x73, 0x2C, 0x20, 0x27, 0x53, 0x75, 0x72, + 0x65, 0x2C, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x2C, 0x20, + 0x79, 0x65, 0x72, 0x20, 0x68, 0x6F, 0x6E, 0x6F, 0x75, 0x72, + 0x2C, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x2C, 0x20, + 0x61, 0x74, 0x0D, 0x0A, 0x61, 0x6C, 0x6C, 0x21, 0x27, 0x20, + 0x27, 0x44, 0x6F, 0x20, 0x61, 0x73, 0x20, 0x49, 0x20, 0x74, + 0x65, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x63, 0x6F, 0x77, 0x61, 0x72, 0x64, 0x21, + 0x27, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x74, 0x20, 0x6C, + 0x61, 0x73, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x70, + 0x72, 0x65, 0x61, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x68, + 0x65, 0x72, 0x0D, 0x0A, 0x68, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x6D, 0x61, 0x64, 0x65, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x73, 0x6E, 0x61, 0x74, 0x63, 0x68, 0x20, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x69, 0x72, + 0x2E, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x69, 0x6D, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x0D, 0x0A, 0x54, 0x57, 0x4F, 0x20, 0x6C, 0x69, + 0x74, 0x74, 0x6C, 0x65, 0x20, 0x73, 0x68, 0x72, 0x69, 0x65, + 0x6B, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x73, 0x6F, 0x75, 0x6E, 0x64, 0x73, 0x20, + 0x6F, 0x66, 0x20, 0x62, 0x72, 0x6F, 0x6B, 0x65, 0x6E, 0x20, + 0x67, 0x6C, 0x61, 0x73, 0x73, 0x2E, 0x20, 0x27, 0x57, 0x68, + 0x61, 0x74, 0x20, 0x61, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, + 0x72, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x63, 0x75, 0x63, 0x75, + 0x6D, 0x62, 0x65, 0x72, 0x2D, 0x66, 0x72, 0x61, 0x6D, 0x65, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x6D, 0x75, + 0x73, 0x74, 0x20, 0x62, 0x65, 0x21, 0x27, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x20, 0x27, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x27, 0x6C, 0x6C, 0x20, 0x64, 0x6F, 0x0D, 0x0A, + 0x6E, 0x65, 0x78, 0x74, 0x21, 0x20, 0x41, 0x73, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x70, 0x75, 0x6C, 0x6C, 0x69, 0x6E, 0x67, + 0x20, 0x6D, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x69, 0x6E, 0x64, 0x6F, + 0x77, 0x2C, 0x20, 0x49, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, + 0x77, 0x69, 0x73, 0x68, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x43, 0x4F, 0x55, 0x4C, 0x44, 0x21, 0x20, 0x49, 0x27, 0x6D, + 0x0D, 0x0A, 0x73, 0x75, 0x72, 0x65, 0x20, 0x49, 0x20, 0x64, + 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x73, 0x74, 0x61, 0x79, 0x20, 0x69, 0x6E, + 0x20, 0x68, 0x65, 0x72, 0x65, 0x20, 0x61, 0x6E, 0x79, 0x20, + 0x6C, 0x6F, 0x6E, 0x67, 0x65, 0x72, 0x21, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x53, 0x68, 0x65, 0x20, 0x77, 0x61, 0x69, 0x74, + 0x65, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x6F, 0x6D, + 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x6F, 0x75, 0x74, 0x20, 0x68, 0x65, 0x61, 0x72, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x3A, 0x20, 0x61, 0x74, + 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6D, 0x65, + 0x20, 0x61, 0x0D, 0x0A, 0x72, 0x75, 0x6D, 0x62, 0x6C, 0x69, + 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x63, 0x61, 0x72, 0x74, 0x77, 0x68, 0x65, + 0x65, 0x6C, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x6F, + 0x66, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x6D, + 0x61, 0x6E, 0x79, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x73, + 0x0D, 0x0A, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x61, 0x6C, 0x6B, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x67, 0x65, 0x74, 0x68, + 0x65, 0x72, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6D, 0x61, + 0x64, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x3A, 0x20, 0x27, 0x57, + 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x6C, 0x61, + 0x64, 0x64, 0x65, 0x72, 0x3F, 0x2D, 0x2D, 0x57, 0x68, 0x79, + 0x2C, 0x20, 0x49, 0x20, 0x68, 0x61, 0x64, 0x6E, 0x27, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x72, 0x69, 0x6E, 0x67, 0x20, + 0x62, 0x75, 0x74, 0x20, 0x6F, 0x6E, 0x65, 0x3B, 0x20, 0x42, + 0x69, 0x6C, 0x6C, 0x27, 0x73, 0x20, 0x67, 0x6F, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x2D, + 0x2D, 0x42, 0x69, 0x6C, 0x6C, 0x21, 0x0D, 0x0A, 0x66, 0x65, + 0x74, 0x63, 0x68, 0x20, 0x69, 0x74, 0x20, 0x68, 0x65, 0x72, + 0x65, 0x2C, 0x20, 0x6C, 0x61, 0x64, 0x21, 0x2D, 0x2D, 0x48, + 0x65, 0x72, 0x65, 0x2C, 0x20, 0x70, 0x75, 0x74, 0x20, 0x27, + 0x65, 0x6D, 0x20, 0x75, 0x70, 0x20, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x63, 0x6F, 0x72, 0x6E, 0x65, 0x72, + 0x2D, 0x2D, 0x4E, 0x6F, 0x2C, 0x20, 0x74, 0x69, 0x65, 0x20, + 0x27, 0x65, 0x6D, 0x0D, 0x0A, 0x74, 0x6F, 0x67, 0x65, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2D, + 0x2D, 0x74, 0x68, 0x65, 0x79, 0x20, 0x64, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x72, 0x65, 0x61, 0x63, 0x68, 0x20, 0x68, 0x61, + 0x6C, 0x66, 0x20, 0x68, 0x69, 0x67, 0x68, 0x20, 0x65, 0x6E, + 0x6F, 0x75, 0x67, 0x68, 0x20, 0x79, 0x65, 0x74, 0x2D, 0x2D, + 0x4F, 0x68, 0x21, 0x20, 0x74, 0x68, 0x65, 0x79, 0x27, 0x6C, + 0x6C, 0x0D, 0x0A, 0x64, 0x6F, 0x20, 0x77, 0x65, 0x6C, 0x6C, + 0x20, 0x65, 0x6E, 0x6F, 0x75, 0x67, 0x68, 0x3B, 0x20, 0x64, + 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, 0x70, 0x61, + 0x72, 0x74, 0x69, 0x63, 0x75, 0x6C, 0x61, 0x72, 0x2D, 0x2D, + 0x48, 0x65, 0x72, 0x65, 0x2C, 0x20, 0x42, 0x69, 0x6C, 0x6C, + 0x21, 0x20, 0x63, 0x61, 0x74, 0x63, 0x68, 0x20, 0x68, 0x6F, + 0x6C, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x0D, 0x0A, 0x72, 0x6F, 0x70, 0x65, 0x2D, 0x2D, 0x57, 0x69, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, 0x6F, + 0x66, 0x20, 0x62, 0x65, 0x61, 0x72, 0x3F, 0x2D, 0x2D, 0x4D, + 0x69, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6C, + 0x6F, 0x6F, 0x73, 0x65, 0x20, 0x73, 0x6C, 0x61, 0x74, 0x65, + 0x2D, 0x2D, 0x4F, 0x68, 0x2C, 0x20, 0x69, 0x74, 0x27, 0x73, + 0x20, 0x63, 0x6F, 0x6D, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x64, + 0x6F, 0x77, 0x6E, 0x21, 0x20, 0x48, 0x65, 0x61, 0x64, 0x73, + 0x20, 0x62, 0x65, 0x6C, 0x6F, 0x77, 0x21, 0x27, 0x20, 0x28, + 0x61, 0x20, 0x6C, 0x6F, 0x75, 0x64, 0x20, 0x63, 0x72, 0x61, + 0x73, 0x68, 0x29, 0x2D, 0x2D, 0x27, 0x4E, 0x6F, 0x77, 0x2C, + 0x20, 0x77, 0x68, 0x6F, 0x20, 0x64, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x3F, 0x2D, 0x2D, 0x49, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x42, 0x69, 0x6C, 0x6C, 0x2C, 0x20, 0x49, + 0x0D, 0x0A, 0x66, 0x61, 0x6E, 0x63, 0x79, 0x2D, 0x2D, 0x57, + 0x68, 0x6F, 0x27, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x6F, + 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x68, 0x69, 0x6D, 0x6E, 0x65, 0x79, 0x3F, 0x2D, 0x2D, + 0x4E, 0x61, 0x79, 0x2C, 0x20, 0x49, 0x20, 0x73, 0x68, 0x61, + 0x6E, 0x27, 0x74, 0x21, 0x20, 0x59, 0x4F, 0x55, 0x20, 0x64, + 0x6F, 0x20, 0x69, 0x74, 0x21, 0x2D, 0x2D, 0x54, 0x68, 0x61, + 0x74, 0x20, 0x49, 0x0D, 0x0A, 0x77, 0x6F, 0x6E, 0x27, 0x74, + 0x2C, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x21, 0x2D, 0x2D, 0x42, + 0x69, 0x6C, 0x6C, 0x27, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x67, + 0x6F, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x2D, 0x2D, 0x48, 0x65, + 0x72, 0x65, 0x2C, 0x20, 0x42, 0x69, 0x6C, 0x6C, 0x21, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, + 0x20, 0x73, 0x61, 0x79, 0x73, 0x20, 0x79, 0x6F, 0x75, 0x27, + 0x72, 0x65, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x67, 0x6F, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x68, 0x69, 0x6D, 0x6E, 0x65, 0x79, 0x21, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x21, 0x20, 0x53, 0x6F, 0x20, + 0x42, 0x69, 0x6C, 0x6C, 0x27, 0x73, 0x20, 0x67, 0x6F, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, + 0x69, 0x6D, 0x6E, 0x65, 0x79, 0x2C, 0x20, 0x68, 0x61, 0x73, + 0x20, 0x68, 0x65, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x0D, + 0x0A, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2E, 0x20, + 0x27, 0x53, 0x68, 0x79, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x73, 0x65, 0x65, 0x6D, 0x20, 0x74, 0x6F, 0x20, 0x70, + 0x75, 0x74, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x42, + 0x69, 0x6C, 0x6C, 0x21, 0x20, 0x49, 0x20, 0x77, 0x6F, 0x75, + 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x6E, 0x0D, 0x0A, 0x42, 0x69, 0x6C, 0x6C, 0x27, 0x73, 0x20, + 0x70, 0x6C, 0x61, 0x63, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x64, 0x65, 0x61, + 0x6C, 0x3A, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, + 0x72, 0x65, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x20, 0x69, 0x73, + 0x20, 0x6E, 0x61, 0x72, 0x72, 0x6F, 0x77, 0x2C, 0x20, 0x74, + 0x6F, 0x20, 0x62, 0x65, 0x20, 0x73, 0x75, 0x72, 0x65, 0x3B, + 0x20, 0x62, 0x75, 0x74, 0x0D, 0x0A, 0x49, 0x20, 0x54, 0x48, + 0x49, 0x4E, 0x4B, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x20, + 0x6B, 0x69, 0x63, 0x6B, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, + 0x68, 0x65, 0x20, 0x64, 0x72, 0x65, 0x77, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x20, 0x61, 0x73, 0x20, + 0x66, 0x61, 0x72, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x68, 0x69, 0x6D, 0x6E, 0x65, 0x79, + 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, + 0x61, 0x69, 0x74, 0x65, 0x64, 0x0D, 0x0A, 0x74, 0x69, 0x6C, + 0x6C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x72, + 0x64, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x61, 0x6E, 0x69, 0x6D, 0x61, 0x6C, 0x20, 0x28, 0x73, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, + 0x74, 0x20, 0x67, 0x75, 0x65, 0x73, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x73, 0x6F, 0x72, 0x74, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x29, 0x0D, 0x0A, + 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x63, 0x72, 0x61, 0x6D, + 0x62, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x62, 0x6F, 0x75, + 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x68, 0x69, 0x6D, 0x6E, 0x65, 0x79, 0x20, 0x63, 0x6C, 0x6F, + 0x73, 0x65, 0x20, 0x61, 0x62, 0x6F, 0x76, 0x65, 0x20, 0x68, + 0x65, 0x72, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x2C, 0x0D, + 0x0A, 0x73, 0x61, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x27, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x42, 0x69, + 0x6C, 0x6C, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x67, + 0x61, 0x76, 0x65, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x73, 0x68, + 0x61, 0x72, 0x70, 0x20, 0x6B, 0x69, 0x63, 0x6B, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, 0x69, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x73, 0x65, 0x65, 0x20, 0x77, + 0x68, 0x61, 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x68, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x20, 0x6E, 0x65, 0x78, + 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x72, + 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x67, 0x65, + 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x20, 0x63, 0x68, 0x6F, 0x72, + 0x75, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x27, 0x54, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x67, 0x6F, 0x65, 0x73, 0x20, 0x42, 0x69, + 0x6C, 0x6C, 0x21, 0x27, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, + 0x74, 0x27, 0x73, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x20, + 0x61, 0x6C, 0x6F, 0x6E, 0x67, 0x2D, 0x2D, 0x27, 0x43, 0x61, + 0x74, 0x63, 0x68, 0x20, 0x68, 0x69, 0x6D, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x68, 0x65, 0x64, 0x67, 0x65, 0x21, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x6E, 0x0D, 0x0A, 0x73, 0x69, 0x6C, 0x65, 0x6E, 0x63, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x6E, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x63, 0x6F, 0x6E, 0x66, 0x75, 0x73, 0x69, 0x6F, 0x6E, 0x20, + 0x6F, 0x66, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x73, 0x2D, + 0x2D, 0x27, 0x48, 0x6F, 0x6C, 0x64, 0x20, 0x75, 0x70, 0x20, + 0x68, 0x69, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, 0x2D, 0x2D, + 0x42, 0x72, 0x61, 0x6E, 0x64, 0x79, 0x0D, 0x0A, 0x6E, 0x6F, + 0x77, 0x2D, 0x2D, 0x44, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x63, + 0x68, 0x6F, 0x6B, 0x65, 0x20, 0x68, 0x69, 0x6D, 0x2D, 0x2D, + 0x48, 0x6F, 0x77, 0x20, 0x77, 0x61, 0x73, 0x20, 0x69, 0x74, + 0x2C, 0x20, 0x6F, 0x6C, 0x64, 0x20, 0x66, 0x65, 0x6C, 0x6C, + 0x6F, 0x77, 0x3F, 0x20, 0x57, 0x68, 0x61, 0x74, 0x20, 0x68, + 0x61, 0x70, 0x70, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x79, 0x6F, 0x75, 0x3F, 0x20, 0x54, 0x65, 0x6C, 0x6C, + 0x0D, 0x0A, 0x75, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, 0x21, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x4C, 0x61, 0x73, 0x74, 0x20, 0x63, 0x61, + 0x6D, 0x65, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x66, 0x65, 0x65, 0x62, 0x6C, 0x65, 0x2C, 0x20, + 0x73, 0x71, 0x75, 0x65, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x28, 0x27, 0x54, + 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x42, 0x69, 0x6C, 0x6C, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, + 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x29, 0x20, + 0x27, 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x49, 0x20, 0x68, + 0x61, 0x72, 0x64, 0x6C, 0x79, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x2D, 0x2D, 0x4E, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x2C, + 0x20, 0x74, 0x68, 0x61, 0x6E, 0x6B, 0x20, 0x79, 0x65, 0x3B, + 0x20, 0x49, 0x27, 0x6D, 0x20, 0x62, 0x65, 0x74, 0x74, 0x65, + 0x72, 0x20, 0x6E, 0x6F, 0x77, 0x2D, 0x2D, 0x62, 0x75, 0x74, + 0x20, 0x49, 0x27, 0x6D, 0x0D, 0x0A, 0x61, 0x20, 0x64, 0x65, + 0x61, 0x6C, 0x20, 0x74, 0x6F, 0x6F, 0x20, 0x66, 0x6C, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x2D, 0x2D, + 0x61, 0x6C, 0x6C, 0x20, 0x49, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x20, 0x69, 0x73, 0x2C, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x73, + 0x20, 0x61, 0x74, 0x20, 0x6D, 0x65, 0x0D, 0x0A, 0x6C, 0x69, + 0x6B, 0x65, 0x20, 0x61, 0x20, 0x4A, 0x61, 0x63, 0x6B, 0x2D, + 0x69, 0x6E, 0x2D, 0x74, 0x68, 0x65, 0x2D, 0x62, 0x6F, 0x78, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x75, 0x70, 0x20, 0x49, + 0x20, 0x67, 0x6F, 0x65, 0x73, 0x20, 0x6C, 0x69, 0x6B, 0x65, + 0x20, 0x61, 0x20, 0x73, 0x6B, 0x79, 0x2D, 0x72, 0x6F, 0x63, + 0x6B, 0x65, 0x74, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x53, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, 0x69, 0x64, + 0x2C, 0x20, 0x6F, 0x6C, 0x64, 0x20, 0x66, 0x65, 0x6C, 0x6C, + 0x6F, 0x77, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x73, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x20, 0x6D, + 0x75, 0x73, 0x74, 0x20, 0x62, 0x75, 0x72, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x68, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, + 0x74, 0x27, 0x73, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x3B, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x0D, 0x0A, 0x6F, + 0x75, 0x74, 0x20, 0x61, 0x73, 0x20, 0x6C, 0x6F, 0x75, 0x64, + 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x2C, 0x20, 0x27, 0x49, 0x66, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x64, 0x6F, 0x2E, 0x20, 0x49, 0x27, 0x6C, + 0x6C, 0x20, 0x73, 0x65, 0x74, 0x20, 0x44, 0x69, 0x6E, 0x61, + 0x68, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x64, 0x65, 0x61, 0x64, + 0x20, 0x73, 0x69, 0x6C, 0x65, 0x6E, 0x63, 0x65, 0x20, 0x69, + 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x6C, 0x79, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, + 0x27, 0x49, 0x0D, 0x0A, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, + 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x57, 0x49, 0x4C, 0x4C, 0x20, 0x64, 0x6F, 0x20, 0x6E, + 0x65, 0x78, 0x74, 0x21, 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x68, 0x61, 0x64, 0x20, 0x61, 0x6E, 0x79, + 0x20, 0x73, 0x65, 0x6E, 0x73, 0x65, 0x2C, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x27, 0x64, 0x20, 0x74, 0x61, 0x6B, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x72, 0x6F, 0x6F, 0x66, 0x20, + 0x6F, 0x66, 0x66, 0x2E, 0x27, 0x20, 0x41, 0x66, 0x74, 0x65, + 0x72, 0x20, 0x61, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, + 0x20, 0x6F, 0x72, 0x20, 0x74, 0x77, 0x6F, 0x2C, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, + 0x6D, 0x6F, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x20, 0x73, 0x61, + 0x79, 0x2C, 0x20, 0x27, 0x41, 0x20, 0x62, 0x61, 0x72, 0x72, + 0x6F, 0x77, 0x66, 0x75, 0x6C, 0x20, 0x77, 0x69, 0x6C, 0x6C, + 0x20, 0x64, 0x6F, 0x2C, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, + 0x67, 0x69, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x20, 0x62, 0x61, 0x72, + 0x72, 0x6F, 0x77, 0x66, 0x75, 0x6C, 0x20, 0x6F, 0x66, 0x20, + 0x57, 0x48, 0x41, 0x54, 0x3F, 0x27, 0x20, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6C, 0x6F, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x6F, 0x75, 0x62, + 0x74, 0x2C, 0x0D, 0x0A, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x6D, 0x6F, 0x6D, + 0x65, 0x6E, 0x74, 0x20, 0x61, 0x20, 0x73, 0x68, 0x6F, 0x77, + 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x70, 0x65, 0x62, 0x62, 0x6C, 0x65, 0x73, + 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x72, 0x61, 0x74, 0x74, + 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x77, 0x69, 0x6E, 0x64, + 0x6F, 0x77, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x6F, + 0x6D, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, + 0x20, 0x68, 0x69, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x63, 0x65, + 0x2E, 0x20, 0x27, 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x70, 0x75, + 0x74, 0x20, 0x61, 0x20, 0x73, 0x74, 0x6F, 0x70, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, 0x27, 0x0D, 0x0A, + 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x74, + 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x27, 0x59, + 0x6F, 0x75, 0x27, 0x64, 0x20, 0x62, 0x65, 0x74, 0x74, 0x65, + 0x72, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x21, + 0x27, 0x0D, 0x0A, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x70, + 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x61, 0x6E, + 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x64, 0x65, 0x61, 0x64, + 0x20, 0x73, 0x69, 0x6C, 0x65, 0x6E, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x6E, + 0x6F, 0x74, 0x69, 0x63, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x73, 0x75, 0x72, + 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x62, 0x62, 0x6C, + 0x65, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x69, 0x6E, 0x74, 0x6F, 0x0D, 0x0A, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x63, 0x61, 0x6B, 0x65, 0x73, 0x20, 0x61, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x6C, 0x61, 0x79, + 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6C, + 0x6F, 0x6F, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x20, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x69, 0x64, + 0x65, 0x61, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x69, 0x6E, + 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x68, 0x65, + 0x61, 0x64, 0x2E, 0x20, 0x27, 0x49, 0x66, 0x20, 0x49, 0x20, + 0x65, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x63, 0x61, 0x6B, + 0x65, 0x73, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, + 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x2C, 0x20, 0x27, 0x69, + 0x74, 0x27, 0x73, 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x0D, 0x0A, 0x53, 0x4F, + 0x4D, 0x45, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x20, + 0x69, 0x6E, 0x20, 0x6D, 0x79, 0x20, 0x73, 0x69, 0x7A, 0x65, + 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x73, 0x20, 0x69, + 0x74, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x70, 0x6F, + 0x73, 0x73, 0x69, 0x62, 0x6C, 0x79, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x6D, 0x65, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x72, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x6D, 0x75, 0x73, 0x74, + 0x0D, 0x0A, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x6D, 0x65, 0x20, + 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x72, 0x2C, 0x20, 0x49, + 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x73, 0x65, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x6F, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x73, 0x77, 0x61, 0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x61, 0x6B, 0x65, 0x73, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x64, 0x65, 0x6C, + 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x66, 0x69, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x62, 0x65, 0x67, 0x61, 0x6E, + 0x20, 0x73, 0x68, 0x72, 0x69, 0x6E, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6C, 0x79, 0x2E, + 0x20, 0x41, 0x73, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x61, + 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x20, 0x65, 0x6E, 0x6F, 0x75, + 0x67, 0x68, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, + 0x74, 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x2C, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x72, 0x61, 0x6E, 0x20, 0x6F, 0x75, 0x74, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6F, + 0x75, 0x73, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, + 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, + 0x20, 0x61, 0x20, 0x63, 0x72, 0x6F, 0x77, 0x64, 0x20, 0x6F, + 0x66, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x0D, 0x0A, + 0x61, 0x6E, 0x69, 0x6D, 0x61, 0x6C, 0x73, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x62, 0x69, 0x72, 0x64, 0x73, 0x20, 0x77, 0x61, + 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x75, 0x74, 0x73, + 0x69, 0x64, 0x65, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, + 0x6F, 0x6F, 0x72, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x4C, 0x69, 0x7A, 0x61, 0x72, 0x64, 0x2C, 0x20, 0x42, + 0x69, 0x6C, 0x6C, 0x2C, 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x69, 0x64, + 0x64, 0x6C, 0x65, 0x2C, 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, + 0x20, 0x68, 0x65, 0x6C, 0x64, 0x20, 0x75, 0x70, 0x20, 0x62, + 0x79, 0x20, 0x74, 0x77, 0x6F, 0x20, 0x67, 0x75, 0x69, 0x6E, + 0x65, 0x61, 0x2D, 0x70, 0x69, 0x67, 0x73, 0x2C, 0x20, 0x77, + 0x68, 0x6F, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x67, 0x69, + 0x76, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x0D, 0x0A, 0x73, + 0x6F, 0x6D, 0x65, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x62, 0x6F, + 0x74, 0x74, 0x6C, 0x65, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x79, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, + 0x61, 0x20, 0x72, 0x75, 0x73, 0x68, 0x20, 0x61, 0x74, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x68, 0x65, + 0x0D, 0x0A, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x65, 0x64, + 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x72, 0x61, 0x6E, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x61, 0x73, + 0x20, 0x68, 0x61, 0x72, 0x64, 0x20, 0x61, 0x73, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x66, + 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x0D, 0x0A, 0x73, 0x61, 0x66, 0x65, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x74, 0x68, 0x69, 0x63, 0x6B, 0x20, + 0x77, 0x6F, 0x6F, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x54, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x49, 0x27, 0x76, 0x65, + 0x20, 0x67, 0x6F, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x6F, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x6E, 0x64, 0x65, 0x72, 0x65, + 0x64, 0x0D, 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x6F, 0x64, + 0x2C, 0x20, 0x27, 0x69, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x67, + 0x72, 0x6F, 0x77, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x79, 0x20, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, + 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x3B, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6F, + 0x6E, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x69, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x6E, 0x64, + 0x20, 0x6D, 0x79, 0x20, 0x77, 0x61, 0x79, 0x20, 0x69, 0x6E, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6C, 0x6F, + 0x76, 0x65, 0x6C, 0x79, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, + 0x6E, 0x2E, 0x20, 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x69, 0x6C, 0x6C, + 0x20, 0x62, 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x65, 0x73, 0x74, 0x20, 0x70, 0x6C, 0x61, 0x6E, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x49, 0x74, 0x20, 0x73, 0x6F, 0x75, + 0x6E, 0x64, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x20, 0x65, 0x78, + 0x63, 0x65, 0x6C, 0x6C, 0x65, 0x6E, 0x74, 0x20, 0x70, 0x6C, + 0x61, 0x6E, 0x2C, 0x20, 0x6E, 0x6F, 0x20, 0x64, 0x6F, 0x75, + 0x62, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x6E, 0x65, 0x61, 0x74, 0x6C, 0x79, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x73, 0x69, 0x6D, 0x70, 0x6C, 0x79, + 0x0D, 0x0A, 0x61, 0x72, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x64, + 0x3B, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x6E, 0x6C, 0x79, + 0x20, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6C, 0x74, + 0x79, 0x20, 0x77, 0x61, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6D, + 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x69, 0x64, 0x65, + 0x61, 0x0D, 0x0A, 0x68, 0x6F, 0x77, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x65, 0x74, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, + 0x69, 0x74, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, + 0x69, 0x6C, 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x6E, 0x78, 0x69, + 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, 0x61, 0x6D, 0x6F, 0x6E, + 0x67, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x65, + 0x65, 0x73, 0x2C, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x73, 0x68, 0x61, 0x72, 0x70, 0x20, 0x62, + 0x61, 0x72, 0x6B, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x6F, + 0x76, 0x65, 0x72, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x65, + 0x61, 0x64, 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x75, 0x70, 0x20, + 0x69, 0x6E, 0x20, 0x61, 0x0D, 0x0A, 0x67, 0x72, 0x65, 0x61, + 0x74, 0x20, 0x68, 0x75, 0x72, 0x72, 0x79, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x41, 0x6E, 0x20, 0x65, 0x6E, 0x6F, 0x72, 0x6D, + 0x6F, 0x75, 0x73, 0x20, 0x70, 0x75, 0x70, 0x70, 0x79, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x74, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6C, + 0x61, 0x72, 0x67, 0x65, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x65, 0x79, 0x65, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x0D, 0x0A, 0x66, 0x65, 0x65, 0x62, 0x6C, 0x79, 0x20, 0x73, + 0x74, 0x72, 0x65, 0x74, 0x63, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x70, 0x61, + 0x77, 0x2C, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x6F, 0x75, 0x63, 0x68, 0x20, 0x68, + 0x65, 0x72, 0x2E, 0x20, 0x27, 0x50, 0x6F, 0x6F, 0x72, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x21, 0x27, 0x0D, 0x0A, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x63, 0x6F, 0x61, 0x78, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, + 0x20, 0x68, 0x61, 0x72, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x77, + 0x68, 0x69, 0x73, 0x74, 0x6C, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x69, 0x74, 0x3B, 0x20, 0x62, 0x75, 0x74, 0x0D, 0x0A, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x65, 0x72, + 0x72, 0x69, 0x62, 0x6C, 0x79, 0x20, 0x66, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x69, 0x74, 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x62, + 0x65, 0x0D, 0x0A, 0x68, 0x75, 0x6E, 0x67, 0x72, 0x79, 0x2C, + 0x20, 0x69, 0x6E, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, + 0x63, 0x61, 0x73, 0x65, 0x20, 0x69, 0x74, 0x20, 0x77, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x6C, 0x79, 0x20, 0x74, + 0x6F, 0x20, 0x65, 0x61, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x75, 0x70, 0x20, 0x69, 0x6E, 0x20, 0x73, 0x70, 0x69, 0x74, + 0x65, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x61, 0x6C, 0x6C, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x63, 0x6F, 0x61, 0x78, 0x69, 0x6E, + 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x48, 0x61, 0x72, 0x64, + 0x6C, 0x79, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x69, 0x6E, 0x67, + 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x64, 0x69, 0x64, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x70, + 0x69, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x75, 0x70, 0x20, 0x61, + 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x62, 0x69, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x74, 0x69, 0x63, 0x6B, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x68, 0x65, 0x6C, + 0x64, 0x20, 0x69, 0x74, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x70, 0x70, + 0x79, 0x3B, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x75, 0x70, + 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x70, + 0x70, 0x79, 0x20, 0x6A, 0x75, 0x6D, 0x70, 0x65, 0x64, 0x20, + 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x69, 0x72, 0x20, 0x6F, 0x66, 0x66, 0x0D, 0x0A, 0x61, 0x6C, + 0x6C, 0x20, 0x69, 0x74, 0x73, 0x20, 0x66, 0x65, 0x65, 0x74, + 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x2C, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x79, 0x65, 0x6C, + 0x70, 0x20, 0x6F, 0x66, 0x20, 0x64, 0x65, 0x6C, 0x69, 0x67, + 0x68, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x75, + 0x73, 0x68, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x74, 0x69, 0x63, 0x6B, 0x2C, 0x0D, 0x0A, + 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, 0x62, + 0x65, 0x6C, 0x69, 0x65, 0x76, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x77, 0x6F, 0x72, 0x72, 0x79, 0x20, 0x69, 0x74, 0x3B, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x64, 0x6F, 0x64, 0x67, 0x65, 0x64, 0x20, 0x62, 0x65, + 0x68, 0x69, 0x6E, 0x64, 0x20, 0x61, 0x20, 0x67, 0x72, 0x65, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x74, 0x6C, 0x65, + 0x2C, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x6B, 0x65, 0x65, 0x70, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x66, + 0x72, 0x6F, 0x6D, 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, 0x20, + 0x72, 0x75, 0x6E, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x3B, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, + 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x61, + 0x70, 0x70, 0x65, 0x61, 0x72, 0x65, 0x64, 0x20, 0x6F, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x6F, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2C, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x75, 0x70, 0x70, 0x79, 0x20, 0x6D, 0x61, + 0x64, 0x65, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x72, 0x75, 0x73, 0x68, 0x20, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x74, 0x69, 0x63, 0x6B, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x75, 0x6D, 0x62, 0x6C, 0x65, + 0x64, 0x20, 0x68, 0x65, 0x61, 0x64, 0x0D, 0x0A, 0x6F, 0x76, + 0x65, 0x72, 0x20, 0x68, 0x65, 0x65, 0x6C, 0x73, 0x20, 0x69, + 0x6E, 0x20, 0x69, 0x74, 0x73, 0x20, 0x68, 0x75, 0x72, 0x72, + 0x79, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, 0x68, + 0x6F, 0x6C, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x3B, + 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2C, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, + 0x68, 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x20, 0x67, + 0x61, 0x6D, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x70, 0x6C, 0x61, + 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x63, + 0x61, 0x72, 0x74, 0x2D, 0x68, 0x6F, 0x72, 0x73, 0x65, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, + 0x0D, 0x0A, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x74, + 0x6F, 0x20, 0x62, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6D, 0x70, + 0x6C, 0x65, 0x64, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, + 0x69, 0x74, 0x73, 0x20, 0x66, 0x65, 0x65, 0x74, 0x2C, 0x20, + 0x72, 0x61, 0x6E, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x74, 0x6C, + 0x65, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x3B, 0x20, 0x74, + 0x68, 0x65, 0x6E, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x75, 0x70, 0x70, 0x79, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, + 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x20, + 0x6F, 0x66, 0x20, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x20, 0x63, + 0x68, 0x61, 0x72, 0x67, 0x65, 0x73, 0x20, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x69, 0x63, 0x6B, 0x2C, + 0x20, 0x72, 0x75, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x0D, 0x0A, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x66, 0x6F, + 0x72, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x65, 0x61, 0x63, + 0x68, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x77, 0x61, + 0x79, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x62, 0x61, 0x72, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x68, 0x6F, 0x61, 0x72, 0x73, 0x65, 0x6C, 0x79, 0x0D, 0x0A, + 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, + 0x69, 0x6C, 0x65, 0x2C, 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x20, + 0x61, 0x74, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x69, 0x74, + 0x20, 0x73, 0x61, 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, + 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x77, 0x61, 0x79, + 0x20, 0x6F, 0x66, 0x66, 0x2C, 0x20, 0x70, 0x61, 0x6E, 0x74, + 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, + 0x0A, 0x69, 0x74, 0x73, 0x20, 0x74, 0x6F, 0x6E, 0x67, 0x75, + 0x65, 0x20, 0x68, 0x61, 0x6E, 0x67, 0x69, 0x6E, 0x67, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x73, + 0x20, 0x6D, 0x6F, 0x75, 0x74, 0x68, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x69, 0x74, 0x73, 0x20, 0x67, 0x72, 0x65, 0x61, + 0x74, 0x20, 0x65, 0x79, 0x65, 0x73, 0x20, 0x68, 0x61, 0x6C, + 0x66, 0x20, 0x73, 0x68, 0x75, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x65, 0x65, 0x6D, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x6F, + 0x70, 0x70, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x69, 0x74, 0x79, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6D, 0x61, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, 0x65, 0x73, 0x63, 0x61, + 0x70, 0x65, 0x3B, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, + 0x0D, 0x0A, 0x73, 0x65, 0x74, 0x20, 0x6F, 0x66, 0x66, 0x20, + 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x72, 0x61, 0x6E, 0x20, 0x74, 0x69, 0x6C, + 0x6C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x74, 0x69, 0x72, 0x65, + 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x62, 0x72, 0x65, 0x61, 0x74, 0x68, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x74, 0x69, 0x6C, 0x6C, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x70, 0x70, 0x79, + 0x27, 0x73, 0x20, 0x62, 0x61, 0x72, 0x6B, 0x20, 0x73, 0x6F, + 0x75, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 0x74, + 0x65, 0x20, 0x66, 0x61, 0x69, 0x6E, 0x74, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, + 0x6E, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, + 0x6E, 0x64, 0x20, 0x79, 0x65, 0x74, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x61, 0x20, 0x64, 0x65, 0x61, 0x72, 0x20, 0x6C, + 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x70, 0x75, 0x70, 0x70, + 0x79, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x21, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x6C, 0x65, 0x61, 0x6E, 0x74, 0x0D, 0x0A, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x73, 0x74, 0x20, 0x61, 0x20, 0x62, 0x75, 0x74, + 0x74, 0x65, 0x72, 0x63, 0x75, 0x70, 0x20, 0x74, 0x6F, 0x20, + 0x72, 0x65, 0x73, 0x74, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x61, + 0x6E, 0x6E, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x6C, 0x65, 0x61, 0x76, 0x65, 0x73, 0x3A, 0x20, 0x27, 0x49, + 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x64, 0x20, 0x74, + 0x65, 0x61, 0x63, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, + 0x20, 0x74, 0x72, 0x69, 0x63, 0x6B, 0x73, 0x20, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x2C, 0x20, 0x69, + 0x66, 0x2D, 0x2D, 0x69, 0x66, 0x20, 0x49, 0x27, 0x64, 0x0D, + 0x0A, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x62, 0x65, 0x65, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x73, 0x69, 0x7A, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x64, + 0x6F, 0x20, 0x69, 0x74, 0x21, 0x20, 0x4F, 0x68, 0x20, 0x64, + 0x65, 0x61, 0x72, 0x21, 0x20, 0x49, 0x27, 0x64, 0x20, 0x6E, + 0x65, 0x61, 0x72, 0x6C, 0x79, 0x20, 0x66, 0x6F, 0x72, 0x67, + 0x6F, 0x74, 0x74, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x0D, 0x0A, 0x49, 0x27, 0x76, 0x65, 0x20, 0x67, 0x6F, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x20, 0x75, + 0x70, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x21, 0x20, 0x4C, + 0x65, 0x74, 0x20, 0x6D, 0x65, 0x20, 0x73, 0x65, 0x65, 0x2D, + 0x2D, 0x68, 0x6F, 0x77, 0x20, 0x49, 0x53, 0x20, 0x69, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x6D, 0x61, 0x6E, + 0x61, 0x67, 0x65, 0x64, 0x3F, 0x20, 0x49, 0x0D, 0x0A, 0x73, + 0x75, 0x70, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x49, 0x20, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x61, + 0x74, 0x20, 0x6F, 0x72, 0x20, 0x64, 0x72, 0x69, 0x6E, 0x6B, + 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x3B, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, + 0x72, 0x65, 0x61, 0x74, 0x0D, 0x0A, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x2C, 0x20, 0x77, + 0x68, 0x61, 0x74, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x68, 0x65, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x63, 0x65, + 0x72, 0x74, 0x61, 0x69, 0x6E, 0x6C, 0x79, 0x20, 0x77, 0x61, + 0x73, 0x2C, 0x20, 0x77, 0x68, 0x61, 0x74, 0x3F, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, + 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x6F, 0x75, 0x6E, + 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, 0x74, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x77, 0x65, 0x72, + 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x6C, 0x61, 0x64, 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, + 0x67, 0x72, 0x61, 0x73, 0x73, 0x2C, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x73, 0x65, 0x65, 0x20, 0x61, 0x6E, 0x79, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x0D, 0x0A, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x6F, 0x20, 0x65, 0x61, 0x74, 0x20, 0x6F, 0x72, 0x20, + 0x64, 0x72, 0x69, 0x6E, 0x6B, 0x20, 0x75, 0x6E, 0x64, 0x65, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x69, 0x72, 0x63, + 0x75, 0x6D, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x73, 0x2E, + 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x61, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, + 0x6D, 0x75, 0x73, 0x68, 0x72, 0x6F, 0x6F, 0x6D, 0x20, 0x67, + 0x72, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x20, 0x6E, 0x65, 0x61, + 0x72, 0x20, 0x68, 0x65, 0x72, 0x2C, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, + 0x65, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x61, + 0x73, 0x0D, 0x0A, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, + 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x75, 0x6E, 0x64, 0x65, + 0x72, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x6F, 0x6E, 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, 0x73, 0x69, + 0x64, 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x62, 0x65, 0x68, 0x69, + 0x6E, 0x64, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x69, 0x74, 0x20, + 0x6F, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x65, + 0x65, 0x20, 0x77, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x77, 0x61, + 0x73, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x6F, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x53, 0x68, 0x65, 0x20, 0x73, 0x74, 0x72, + 0x65, 0x74, 0x63, 0x68, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x20, 0x75, 0x70, 0x20, 0x6F, 0x6E, + 0x20, 0x74, 0x69, 0x70, 0x74, 0x6F, 0x65, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x70, 0x65, 0x65, 0x70, 0x65, 0x64, 0x20, + 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, + 0x64, 0x67, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x6D, 0x75, 0x73, 0x68, 0x72, 0x6F, 0x6F, 0x6D, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x65, 0x79, 0x65, 0x73, 0x20, 0x69, 0x6D, 0x6D, 0x65, 0x64, + 0x69, 0x61, 0x74, 0x65, 0x6C, 0x79, 0x20, 0x6D, 0x65, 0x74, + 0x20, 0x74, 0x68, 0x6F, 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x61, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x63, 0x61, + 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x2C, + 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x73, 0x69, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x70, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, 0x61, + 0x72, 0x6D, 0x73, 0x20, 0x66, 0x6F, 0x6C, 0x64, 0x65, 0x64, + 0x2C, 0x20, 0x71, 0x75, 0x69, 0x65, 0x74, 0x6C, 0x79, 0x20, + 0x73, 0x6D, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x20, + 0x6C, 0x6F, 0x6E, 0x67, 0x0D, 0x0A, 0x68, 0x6F, 0x6F, 0x6B, + 0x61, 0x68, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x61, + 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, + 0x74, 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x68, 0x65, 0x72, 0x20, 0x6F, 0x72, 0x20, 0x6F, + 0x66, 0x20, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x65, 0x6C, 0x73, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, 0x48, 0x41, 0x50, + 0x54, 0x45, 0x52, 0x20, 0x56, 0x2E, 0x20, 0x41, 0x64, 0x76, + 0x69, 0x63, 0x65, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x61, + 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, + 0x61, 0x72, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, + 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, + 0x74, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x6F, 0x6D, + 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x69, 0x6E, 0x20, + 0x73, 0x69, 0x6C, 0x65, 0x6E, 0x63, 0x65, 0x3A, 0x0D, 0x0A, + 0x61, 0x74, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, + 0x6C, 0x61, 0x72, 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x68, 0x6F, 0x6F, 0x6B, 0x61, 0x68, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x73, + 0x20, 0x6D, 0x6F, 0x75, 0x74, 0x68, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x0D, 0x0A, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x20, 0x6C, 0x61, 0x6E, 0x67, 0x75, 0x69, 0x64, 0x2C, + 0x20, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x79, 0x20, 0x76, 0x6F, + 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, + 0x68, 0x6F, 0x20, 0x61, 0x72, 0x65, 0x20, 0x59, 0x4F, 0x55, + 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, + 0x6C, 0x61, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x74, + 0x20, 0x61, 0x6E, 0x20, 0x65, 0x6E, 0x63, 0x6F, 0x75, 0x72, + 0x61, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x70, 0x65, 0x6E, + 0x69, 0x6E, 0x67, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, + 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x2E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x2C, 0x0D, 0x0A, + 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x68, 0x79, + 0x6C, 0x79, 0x2C, 0x20, 0x27, 0x49, 0x2D, 0x2D, 0x49, 0x20, + 0x68, 0x61, 0x72, 0x64, 0x6C, 0x79, 0x20, 0x6B, 0x6E, 0x6F, + 0x77, 0x2C, 0x20, 0x73, 0x69, 0x72, 0x2C, 0x20, 0x6A, 0x75, + 0x73, 0x74, 0x20, 0x61, 0x74, 0x20, 0x70, 0x72, 0x65, 0x73, + 0x65, 0x6E, 0x74, 0x2D, 0x2D, 0x61, 0x74, 0x20, 0x6C, 0x65, + 0x61, 0x73, 0x74, 0x20, 0x49, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x0D, 0x0A, 0x77, 0x68, 0x6F, 0x20, 0x49, 0x20, 0x57, 0x41, + 0x53, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x49, 0x20, 0x67, + 0x6F, 0x74, 0x20, 0x75, 0x70, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x6D, 0x6F, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x62, 0x75, 0x74, 0x20, 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x6B, 0x20, 0x49, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x0D, 0x0A, + 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x64, 0x20, 0x73, 0x65, + 0x76, 0x65, 0x72, 0x61, 0x6C, 0x20, 0x74, 0x69, 0x6D, 0x65, + 0x73, 0x20, 0x73, 0x69, 0x6E, 0x63, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x6E, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, + 0x68, 0x61, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, + 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x20, 0x73, 0x74, 0x65, + 0x72, 0x6E, 0x6C, 0x79, 0x2E, 0x20, 0x27, 0x45, 0x78, 0x70, + 0x6C, 0x61, 0x69, 0x6E, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x65, + 0x78, 0x70, 0x6C, 0x61, 0x69, 0x6E, 0x20, 0x4D, 0x59, 0x53, + 0x45, 0x4C, 0x46, 0x2C, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x61, + 0x66, 0x72, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x73, 0x69, 0x72, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2C, 0x20, 0x27, 0x62, 0x65, 0x63, 0x61, 0x75, + 0x73, 0x65, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x6E, 0x6F, 0x74, + 0x0D, 0x0A, 0x6D, 0x79, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x73, 0x65, 0x65, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x73, 0x65, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, + 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x61, 0x66, + 0x72, 0x61, 0x69, 0x64, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, + 0x27, 0x74, 0x20, 0x70, 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, + 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x63, 0x6C, 0x65, 0x61, 0x72, + 0x6C, 0x79, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x70, 0x6F, 0x6C, 0x69, 0x74, 0x65, + 0x6C, 0x79, 0x2C, 0x0D, 0x0A, 0x27, 0x66, 0x6F, 0x72, 0x20, + 0x49, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x75, 0x6E, + 0x64, 0x65, 0x72, 0x73, 0x74, 0x61, 0x6E, 0x64, 0x20, 0x69, + 0x74, 0x20, 0x6D, 0x79, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x74, + 0x6F, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, + 0x69, 0x6E, 0x67, 0x20, 0x73, 0x6F, 0x20, 0x6D, 0x61, 0x6E, + 0x79, 0x0D, 0x0A, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x73, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x64, 0x61, 0x79, 0x20, 0x69, 0x73, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x63, 0x6F, 0x6E, 0x66, + 0x75, 0x73, 0x69, 0x6E, 0x67, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x74, 0x20, 0x69, 0x73, 0x6E, 0x27, 0x74, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, + 0x6C, 0x61, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, + 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x68, 0x61, + 0x70, 0x73, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x6E, 0x27, 0x74, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x69, 0x74, 0x20, 0x73, 0x6F, 0x20, 0x79, 0x65, 0x74, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x3B, 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, + 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x75, + 0x72, 0x6E, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x61, 0x20, + 0x63, 0x68, 0x72, 0x79, 0x73, 0x61, 0x6C, 0x69, 0x73, 0x2D, + 0x2D, 0x79, 0x6F, 0x75, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2C, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2D, 0x2D, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x0D, 0x0A, + 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x61, 0x20, 0x62, 0x75, + 0x74, 0x74, 0x65, 0x72, 0x66, 0x6C, 0x79, 0x2C, 0x20, 0x49, + 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x6B, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x6C, 0x6C, + 0x20, 0x66, 0x65, 0x65, 0x6C, 0x20, 0x69, 0x74, 0x20, 0x61, + 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x0D, 0x0A, 0x71, + 0x75, 0x65, 0x65, 0x72, 0x2C, 0x20, 0x77, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x4E, 0x6F, 0x74, 0x20, 0x61, 0x20, 0x62, 0x69, + 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, + 0x6C, 0x6C, 0x61, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x68, + 0x61, 0x70, 0x73, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x66, + 0x65, 0x65, 0x6C, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x6D, 0x61, + 0x79, 0x20, 0x62, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, + 0x72, 0x65, 0x6E, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x3B, 0x20, 0x27, + 0x61, 0x6C, 0x6C, 0x20, 0x49, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x0D, 0x0A, 0x69, 0x73, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x66, 0x65, 0x65, 0x6C, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x71, 0x75, 0x65, 0x65, 0x72, + 0x20, 0x74, 0x6F, 0x20, 0x4D, 0x45, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x21, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, + 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x20, + 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6D, 0x70, 0x74, 0x75, 0x6F, + 0x75, 0x73, 0x6C, 0x79, 0x2E, 0x20, 0x27, 0x57, 0x68, 0x6F, + 0x20, 0x61, 0x72, 0x65, 0x20, 0x59, 0x4F, 0x55, 0x3F, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x57, 0x68, 0x69, 0x63, 0x68, 0x20, + 0x62, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x6E, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x2E, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x66, + 0x65, 0x6C, 0x74, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x69, 0x72, 0x72, 0x69, 0x74, 0x61, 0x74, + 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, + 0x72, 0x27, 0x73, 0x20, 0x6D, 0x61, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x56, 0x45, 0x52, 0x59, + 0x0D, 0x0A, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x20, 0x72, 0x65, + 0x6D, 0x61, 0x72, 0x6B, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x64, 0x72, 0x65, 0x77, 0x20, + 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x75, 0x70, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x67, 0x72, 0x61, 0x76, + 0x65, 0x6C, 0x79, 0x2C, 0x20, 0x27, 0x49, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x6B, 0x2C, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x20, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x65, 0x6C, 0x6C, 0x20, 0x6D, 0x65, 0x20, 0x77, 0x68, 0x6F, + 0x20, 0x59, 0x4F, 0x55, 0x20, 0x61, 0x72, 0x65, 0x2C, 0x20, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x57, 0x68, 0x79, 0x3F, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, + 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x48, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x70, 0x75, 0x7A, 0x7A, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x69, 0x6F, 0x6E, 0x3B, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x73, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x6F, 0x66, + 0x20, 0x61, 0x6E, 0x79, 0x0D, 0x0A, 0x67, 0x6F, 0x6F, 0x64, + 0x20, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, + 0x72, 0x20, 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, + 0x56, 0x45, 0x52, 0x59, 0x20, 0x75, 0x6E, 0x70, 0x6C, 0x65, + 0x61, 0x73, 0x61, 0x6E, 0x74, 0x0D, 0x0A, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x69, 0x6E, 0x64, + 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x75, 0x72, 0x6E, + 0x65, 0x64, 0x20, 0x61, 0x77, 0x61, 0x79, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x62, 0x61, + 0x63, 0x6B, 0x21, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, + 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, + 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x20, 0x68, 0x65, 0x72, 0x2E, 0x20, 0x27, + 0x49, 0x27, 0x76, 0x65, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6D, 0x70, 0x6F, 0x72, + 0x74, 0x61, 0x6E, 0x74, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x73, + 0x61, 0x79, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x73, 0x6F, 0x75, 0x6E, 0x64, 0x65, 0x64, + 0x20, 0x70, 0x72, 0x6F, 0x6D, 0x69, 0x73, 0x69, 0x6E, 0x67, + 0x2C, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6E, 0x6C, + 0x79, 0x3A, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, + 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x63, 0x61, 0x6D, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x4B, 0x65, 0x65, 0x70, 0x20, 0x79, 0x6F, 0x75, 0x72, + 0x20, 0x74, 0x65, 0x6D, 0x70, 0x65, 0x72, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, + 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x73, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x3F, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x73, 0x77, 0x61, 0x6C, 0x6C, 0x6F, 0x77, 0x69, + 0x6E, 0x67, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x61, 0x6E, 0x67, 0x65, 0x72, 0x20, 0x61, 0x73, + 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x73, 0x20, 0x73, + 0x68, 0x65, 0x0D, 0x0A, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, + 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x61, + 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x77, 0x61, 0x69, + 0x74, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x64, 0x6F, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x70, + 0x65, 0x72, 0x68, 0x61, 0x70, 0x73, 0x20, 0x61, 0x66, 0x74, + 0x65, 0x72, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x69, 0x74, 0x20, + 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x74, 0x65, 0x6C, 0x6C, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x6F, 0x72, 0x74, 0x68, + 0x20, 0x68, 0x65, 0x61, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x20, + 0x46, 0x6F, 0x72, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x0D, 0x0A, + 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x73, 0x20, 0x69, 0x74, + 0x20, 0x70, 0x75, 0x66, 0x66, 0x65, 0x64, 0x20, 0x61, 0x77, + 0x61, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, + 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x2C, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x61, 0x74, 0x20, 0x6C, 0x61, + 0x73, 0x74, 0x20, 0x69, 0x74, 0x20, 0x75, 0x6E, 0x66, 0x6F, + 0x6C, 0x64, 0x65, 0x64, 0x20, 0x69, 0x74, 0x73, 0x0D, 0x0A, + 0x61, 0x72, 0x6D, 0x73, 0x2C, 0x20, 0x74, 0x6F, 0x6F, 0x6B, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6F, 0x6F, 0x6B, 0x61, + 0x68, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x69, + 0x74, 0x73, 0x20, 0x6D, 0x6F, 0x75, 0x74, 0x68, 0x20, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x27, 0x53, 0x6F, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x0D, + 0x0A, 0x79, 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x63, 0x68, + 0x61, 0x6E, 0x67, 0x65, 0x64, 0x2C, 0x20, 0x64, 0x6F, 0x20, + 0x79, 0x6F, 0x75, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x27, 0x6D, 0x20, 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, + 0x20, 0x49, 0x20, 0x61, 0x6D, 0x2C, 0x20, 0x73, 0x69, 0x72, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x3B, 0x20, 0x27, 0x49, 0x20, 0x63, 0x61, + 0x6E, 0x27, 0x74, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, + 0x61, 0x73, 0x20, 0x49, 0x0D, 0x0A, 0x75, 0x73, 0x65, 0x64, + 0x2D, 0x2D, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x20, 0x64, 0x6F, + 0x6E, 0x27, 0x74, 0x20, 0x6B, 0x65, 0x65, 0x70, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x73, 0x69, + 0x7A, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x65, 0x6E, + 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x73, 0x20, 0x74, + 0x6F, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, 0x21, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x43, 0x61, 0x6E, 0x27, 0x74, 0x20, + 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, 0x20, 0x57, + 0x48, 0x41, 0x54, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, + 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, + 0x6C, 0x61, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, + 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x49, 0x27, 0x76, 0x65, 0x20, + 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, + 0x61, 0x79, 0x20, 0x22, 0x48, 0x4F, 0x57, 0x20, 0x44, 0x4F, + 0x54, 0x48, 0x20, 0x54, 0x48, 0x45, 0x20, 0x4C, 0x49, 0x54, + 0x54, 0x4C, 0x45, 0x20, 0x42, 0x55, 0x53, 0x59, 0x20, 0x42, + 0x45, 0x45, 0x2C, 0x22, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, + 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x61, 0x6D, 0x65, + 0x0D, 0x0A, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6E, + 0x74, 0x21, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6D, 0x65, + 0x6C, 0x61, 0x6E, 0x63, 0x68, 0x6F, 0x6C, 0x79, 0x20, 0x76, + 0x6F, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x52, 0x65, 0x70, 0x65, 0x61, 0x74, 0x2C, 0x20, 0x22, 0x59, + 0x4F, 0x55, 0x20, 0x41, 0x52, 0x45, 0x20, 0x4F, 0x4C, 0x44, + 0x2C, 0x20, 0x46, 0x41, 0x54, 0x48, 0x45, 0x52, 0x20, 0x57, + 0x49, 0x4C, 0x4C, 0x49, 0x41, 0x4D, 0x2C, 0x22, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, + 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x66, 0x6F, 0x6C, 0x64, 0x65, 0x64, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x73, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x3A, 0x2D, + 0x2D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x27, 0x59, + 0x6F, 0x75, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6F, 0x6C, 0x64, + 0x2C, 0x20, 0x46, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x57, + 0x69, 0x6C, 0x6C, 0x69, 0x61, 0x6D, 0x2C, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x6E, 0x67, 0x20, 0x6D, + 0x61, 0x6E, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x27, 0x41, 0x6E, 0x64, 0x20, 0x79, + 0x6F, 0x75, 0x72, 0x20, 0x68, 0x61, 0x69, 0x72, 0x20, 0x68, + 0x61, 0x73, 0x20, 0x62, 0x65, 0x63, 0x6F, 0x6D, 0x65, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, + 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x41, 0x6E, 0x64, 0x20, + 0x79, 0x65, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x69, 0x6E, + 0x63, 0x65, 0x73, 0x73, 0x61, 0x6E, 0x74, 0x6C, 0x79, 0x20, + 0x73, 0x74, 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x79, + 0x6F, 0x75, 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, 0x2D, 0x2D, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x44, 0x6F, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x2C, 0x20, + 0x61, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x61, 0x67, + 0x65, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x27, 0x49, 0x6E, 0x20, 0x6D, 0x79, 0x20, + 0x79, 0x6F, 0x75, 0x74, 0x68, 0x2C, 0x27, 0x20, 0x46, 0x61, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x57, 0x69, 0x6C, 0x6C, 0x69, + 0x61, 0x6D, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6F, + 0x6E, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x27, 0x49, + 0x20, 0x66, 0x65, 0x61, 0x72, 0x65, 0x64, 0x20, 0x69, 0x74, + 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x69, 0x6E, 0x6A, + 0x75, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x72, + 0x61, 0x69, 0x6E, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x42, + 0x75, 0x74, 0x2C, 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x70, 0x65, 0x72, + 0x66, 0x65, 0x63, 0x74, 0x6C, 0x79, 0x20, 0x73, 0x75, 0x72, + 0x65, 0x20, 0x49, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6E, + 0x6F, 0x6E, 0x65, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x57, 0x68, 0x79, 0x2C, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x20, + 0x69, 0x74, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x27, 0x59, 0x6F, + 0x75, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6F, 0x6C, 0x64, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x79, 0x6F, 0x75, 0x74, 0x68, 0x2C, 0x20, 0x27, 0x61, + 0x73, 0x20, 0x49, 0x20, 0x6D, 0x65, 0x6E, 0x74, 0x69, 0x6F, + 0x6E, 0x65, 0x64, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, + 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x41, 0x6E, 0x64, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x67, 0x72, 0x6F, 0x77, + 0x6E, 0x20, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x75, 0x6E, 0x63, + 0x6F, 0x6D, 0x6D, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x66, 0x61, + 0x74, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x59, 0x65, 0x74, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x65, + 0x64, 0x20, 0x61, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x2D, 0x73, + 0x6F, 0x6D, 0x65, 0x72, 0x73, 0x61, 0x75, 0x6C, 0x74, 0x20, + 0x69, 0x6E, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x64, 0x6F, 0x6F, 0x72, 0x2D, 0x2D, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x50, 0x72, 0x61, 0x79, 0x2C, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x27, 0x49, 0x6E, 0x20, 0x6D, 0x79, 0x20, + 0x79, 0x6F, 0x75, 0x74, 0x68, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x67, + 0x65, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x68, 0x65, 0x20, 0x73, + 0x68, 0x6F, 0x6F, 0x6B, 0x20, 0x68, 0x69, 0x73, 0x20, 0x67, + 0x72, 0x65, 0x79, 0x20, 0x6C, 0x6F, 0x63, 0x6B, 0x73, 0x2C, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x27, 0x49, 0x20, 0x6B, + 0x65, 0x70, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6D, 0x79, + 0x20, 0x6C, 0x69, 0x6D, 0x62, 0x73, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6C, 0x65, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x42, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x75, 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x6F, 0x69, 0x6E, 0x74, 0x6D, 0x65, 0x6E, 0x74, + 0x2D, 0x2D, 0x6F, 0x6E, 0x65, 0x20, 0x73, 0x68, 0x69, 0x6C, + 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x6F, 0x78, 0x2D, 0x2D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x20, 0x6D, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x73, 0x65, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x61, 0x20, 0x63, 0x6F, 0x75, 0x70, 0x6C, 0x65, 0x3F, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x27, 0x59, + 0x6F, 0x75, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6F, 0x6C, 0x64, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x79, 0x6F, 0x75, 0x74, 0x68, 0x2C, 0x20, 0x27, + 0x61, 0x6E, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x6A, + 0x61, 0x77, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x74, 0x6F, + 0x6F, 0x20, 0x77, 0x65, 0x61, 0x6B, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x61, 0x6E, 0x79, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x75, 0x67, 0x68, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x73, 0x75, + 0x65, 0x74, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x59, 0x65, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x66, 0x69, 0x6E, 0x69, + 0x73, 0x68, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, + 0x6F, 0x6F, 0x73, 0x65, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6F, 0x6E, 0x65, 0x73, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x65, 0x61, 0x6B, 0x2D, 0x2D, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x50, 0x72, 0x61, 0x79, 0x20, 0x68, 0x6F, 0x77, 0x20, + 0x64, 0x69, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x61, + 0x6E, 0x61, 0x67, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x6F, + 0x20, 0x69, 0x74, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x27, 0x49, 0x6E, 0x20, 0x6D, 0x79, 0x20, 0x79, + 0x6F, 0x75, 0x74, 0x68, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x68, 0x69, 0x73, 0x20, 0x66, 0x61, 0x74, 0x68, + 0x65, 0x72, 0x2C, 0x20, 0x27, 0x49, 0x20, 0x74, 0x6F, 0x6F, + 0x6B, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, + 0x61, 0x77, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x41, + 0x6E, 0x64, 0x20, 0x61, 0x72, 0x67, 0x75, 0x65, 0x64, 0x20, + 0x65, 0x61, 0x63, 0x68, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x6D, 0x79, 0x20, 0x77, 0x69, + 0x66, 0x65, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x41, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x75, 0x73, 0x63, + 0x75, 0x6C, 0x61, 0x72, 0x20, 0x73, 0x74, 0x72, 0x65, 0x6E, + 0x67, 0x74, 0x68, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x69, 0x74, 0x20, 0x67, 0x61, 0x76, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x6D, 0x79, 0x20, 0x6A, 0x61, 0x77, 0x2C, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x48, 0x61, 0x73, 0x20, 0x6C, + 0x61, 0x73, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x72, 0x65, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x79, + 0x20, 0x6C, 0x69, 0x66, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x6F, 0x6C, 0x64, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x79, 0x6F, + 0x75, 0x74, 0x68, 0x2C, 0x20, 0x27, 0x6F, 0x6E, 0x65, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, 0x61, 0x72, 0x64, + 0x6C, 0x79, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x73, 0x65, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x61, 0x74, + 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x65, 0x79, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x61, 0x73, 0x20, 0x73, 0x74, 0x65, + 0x61, 0x64, 0x79, 0x20, 0x61, 0x73, 0x20, 0x65, 0x76, 0x65, + 0x72, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x59, 0x65, 0x74, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x62, 0x61, 0x6C, 0x61, 0x6E, + 0x63, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x20, 0x65, 0x65, 0x6C, + 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6E, + 0x64, 0x20, 0x6F, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, + 0x6E, 0x6F, 0x73, 0x65, 0x2D, 0x2D, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x57, 0x68, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x64, + 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x73, 0x6F, 0x20, 0x61, + 0x77, 0x66, 0x75, 0x6C, 0x6C, 0x79, 0x20, 0x63, 0x6C, 0x65, + 0x76, 0x65, 0x72, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x27, 0x49, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x61, 0x6E, 0x73, 0x77, 0x65, 0x72, 0x65, 0x64, 0x20, 0x74, + 0x68, 0x72, 0x65, 0x65, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x65, 0x6E, + 0x6F, 0x75, 0x67, 0x68, 0x2C, 0x27, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x53, 0x61, 0x69, 0x64, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x66, 0x61, 0x74, 0x68, 0x65, 0x72, 0x3B, 0x20, 0x27, + 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x67, 0x69, 0x76, 0x65, + 0x20, 0x79, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, + 0x61, 0x69, 0x72, 0x73, 0x21, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x44, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x6B, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x6C, + 0x69, 0x73, 0x74, 0x65, 0x6E, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x64, 0x61, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x75, 0x63, + 0x68, 0x20, 0x73, 0x74, 0x75, 0x66, 0x66, 0x3F, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x42, 0x65, 0x20, 0x6F, 0x66, 0x66, + 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, + 0x6B, 0x69, 0x63, 0x6B, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x73, 0x74, 0x61, 0x69, 0x72, 0x73, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, + 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x74, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x72, 0x69, 0x67, 0x68, + 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, + 0x6C, 0x6C, 0x61, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x4E, 0x6F, 0x74, 0x20, 0x51, 0x55, 0x49, 0x54, 0x45, 0x20, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x2C, 0x20, 0x49, 0x27, 0x6D, + 0x20, 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x74, 0x69, 0x6D, 0x69, 0x64, 0x6C, 0x79, 0x3B, + 0x20, 0x27, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x0D, + 0x0A, 0x68, 0x61, 0x76, 0x65, 0x20, 0x67, 0x6F, 0x74, 0x20, + 0x61, 0x6C, 0x74, 0x65, 0x72, 0x65, 0x64, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, + 0x77, 0x72, 0x6F, 0x6E, 0x67, 0x20, 0x66, 0x72, 0x6F, 0x6D, + 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x65, 0x6E, 0x64, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, + 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, + 0x20, 0x64, 0x65, 0x63, 0x69, 0x64, 0x65, 0x64, 0x6C, 0x79, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x69, 0x6C, + 0x65, 0x6E, 0x63, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, + 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, + 0x72, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x73, + 0x70, 0x65, 0x61, 0x6B, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x57, 0x68, 0x61, 0x74, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x20, + 0x64, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x77, 0x61, 0x6E, + 0x74, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x3F, 0x27, 0x20, + 0x69, 0x74, 0x20, 0x61, 0x73, 0x6B, 0x65, 0x64, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x49, 0x27, + 0x6D, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x70, 0x61, 0x72, 0x74, + 0x69, 0x63, 0x75, 0x6C, 0x61, 0x72, 0x20, 0x61, 0x73, 0x20, + 0x74, 0x6F, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x2C, 0x27, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x68, 0x61, 0x73, 0x74, + 0x69, 0x6C, 0x79, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, + 0x64, 0x3B, 0x20, 0x27, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x6F, + 0x6E, 0x65, 0x0D, 0x0A, 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, + 0x74, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x63, 0x68, 0x61, + 0x6E, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x6F, 0x20, 0x6F, + 0x66, 0x74, 0x65, 0x6E, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x49, 0x20, 0x44, 0x4F, 0x4E, 0x27, 0x54, 0x20, 0x6B, + 0x6E, 0x6F, 0x77, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, + 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x3A, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6E, + 0x65, 0x76, 0x65, 0x72, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, + 0x73, 0x6F, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x63, 0x6F, + 0x6E, 0x74, 0x72, 0x61, 0x64, 0x69, 0x63, 0x74, 0x65, 0x64, + 0x20, 0x69, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, 0x6C, 0x69, + 0x66, 0x65, 0x0D, 0x0A, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x66, 0x65, 0x6C, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6C, 0x6F, + 0x73, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, 0x74, + 0x65, 0x6D, 0x70, 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x41, 0x72, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, + 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x20, 0x6E, 0x6F, 0x77, + 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, + 0x6C, 0x61, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, + 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x49, 0x20, 0x73, 0x68, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, 0x4C, 0x49, 0x54, + 0x54, 0x4C, 0x45, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x72, + 0x2C, 0x20, 0x73, 0x69, 0x72, 0x2C, 0x20, 0x69, 0x66, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x6E, + 0x27, 0x74, 0x20, 0x6D, 0x69, 0x6E, 0x64, 0x2C, 0x27, 0x0D, + 0x0A, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x3A, 0x20, 0x27, 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, + 0x69, 0x6E, 0x63, 0x68, 0x65, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x20, 0x77, 0x72, 0x65, + 0x74, 0x63, 0x68, 0x65, 0x64, 0x20, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x67, 0x6F, + 0x6F, 0x64, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, + 0x69, 0x6E, 0x64, 0x65, 0x65, 0x64, 0x21, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, + 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x20, + 0x61, 0x6E, 0x67, 0x72, 0x69, 0x6C, 0x79, 0x2C, 0x20, 0x72, + 0x65, 0x61, 0x72, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x69, 0x74, + 0x73, 0x65, 0x6C, 0x66, 0x20, 0x75, 0x70, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, 0x73, + 0x70, 0x6F, 0x6B, 0x65, 0x20, 0x28, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6C, 0x79, + 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, 0x69, 0x6E, 0x63, + 0x68, 0x65, 0x73, 0x20, 0x68, 0x69, 0x67, 0x68, 0x29, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x42, 0x75, 0x74, 0x20, 0x49, + 0x27, 0x6D, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x21, 0x27, 0x20, + 0x70, 0x6C, 0x65, 0x61, 0x64, 0x65, 0x64, 0x20, 0x70, 0x6F, + 0x6F, 0x72, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x70, 0x69, 0x74, 0x65, 0x6F, 0x75, + 0x73, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2E, 0x20, 0x41, 0x6E, + 0x64, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, 0x49, 0x20, + 0x77, 0x69, 0x73, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x77, + 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x73, 0x6F, 0x20, 0x65, 0x61, 0x73, 0x69, 0x6C, 0x79, + 0x0D, 0x0A, 0x6F, 0x66, 0x66, 0x65, 0x6E, 0x64, 0x65, 0x64, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, + 0x27, 0x6C, 0x6C, 0x20, 0x67, 0x65, 0x74, 0x20, 0x75, 0x73, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, + 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x3B, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x20, 0x70, 0x75, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x68, 0x6F, 0x6F, + 0x6B, 0x61, 0x68, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x69, + 0x74, 0x73, 0x20, 0x6D, 0x6F, 0x75, 0x74, 0x68, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x73, + 0x6D, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x69, + 0x73, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x77, 0x61, 0x69, 0x74, 0x65, 0x64, 0x20, + 0x70, 0x61, 0x74, 0x69, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, + 0x75, 0x6E, 0x74, 0x69, 0x6C, 0x20, 0x69, 0x74, 0x20, 0x63, + 0x68, 0x6F, 0x73, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x70, + 0x65, 0x61, 0x6B, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2E, + 0x20, 0x49, 0x6E, 0x0D, 0x0A, 0x61, 0x20, 0x6D, 0x69, 0x6E, + 0x75, 0x74, 0x65, 0x20, 0x6F, 0x72, 0x20, 0x74, 0x77, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, + 0x70, 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x20, 0x74, 0x6F, 0x6F, + 0x6B, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6F, 0x6F, 0x6B, + 0x61, 0x68, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x69, 0x74, 0x73, 0x20, 0x6D, 0x6F, 0x75, 0x74, 0x68, 0x0D, + 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x79, 0x61, 0x77, 0x6E, 0x65, + 0x64, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x6F, 0x72, 0x20, + 0x74, 0x77, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x6F, 0x6F, 0x6B, 0x20, 0x69, 0x74, 0x73, + 0x65, 0x6C, 0x66, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x6E, 0x20, + 0x69, 0x74, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x64, 0x6F, 0x77, + 0x6E, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x6D, 0x75, 0x73, 0x68, 0x72, 0x6F, 0x6F, 0x6D, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x72, 0x61, 0x77, 0x6C, + 0x65, 0x64, 0x20, 0x61, 0x77, 0x61, 0x79, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x61, 0x73, 0x73, + 0x2C, 0x20, 0x6D, 0x65, 0x72, 0x65, 0x6C, 0x79, 0x20, 0x72, + 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x73, 0x20, 0x69, 0x74, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x2C, + 0x0D, 0x0A, 0x27, 0x4F, 0x6E, 0x65, 0x20, 0x73, 0x69, 0x64, + 0x65, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x67, 0x72, 0x6F, 0x77, + 0x20, 0x74, 0x61, 0x6C, 0x6C, 0x65, 0x72, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x20, 0x77, 0x69, + 0x6C, 0x6C, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x79, 0x6F, + 0x75, 0x0D, 0x0A, 0x67, 0x72, 0x6F, 0x77, 0x20, 0x73, 0x68, + 0x6F, 0x72, 0x74, 0x65, 0x72, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x4F, 0x6E, 0x65, 0x20, 0x73, 0x69, 0x64, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x57, 0x48, 0x41, 0x54, 0x3F, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x73, 0x69, 0x64, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x57, 0x48, + 0x41, 0x54, 0x3F, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6D, 0x75, 0x73, 0x68, 0x72, 0x6F, 0x6F, 0x6D, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, 0x69, 0x6C, + 0x6C, 0x61, 0x72, 0x2C, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, + 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x61, 0x73, 0x6B, 0x65, 0x64, 0x20, + 0x69, 0x74, 0x0D, 0x0A, 0x61, 0x6C, 0x6F, 0x75, 0x64, 0x3B, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, + 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6D, 0x6F, 0x6D, 0x65, + 0x6E, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x69, 0x67, + 0x68, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x69, 0x6E, 0x65, + 0x64, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x66, 0x75, 0x6C, + 0x6C, 0x79, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6D, 0x75, 0x73, 0x68, 0x72, 0x6F, 0x6F, 0x6D, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x61, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, + 0x65, 0x2C, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6E, 0x67, 0x0D, + 0x0A, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x6F, + 0x75, 0x74, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x77, + 0x6F, 0x20, 0x73, 0x69, 0x64, 0x65, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x69, 0x74, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x73, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x70, + 0x65, 0x72, 0x66, 0x65, 0x63, 0x74, 0x6C, 0x79, 0x0D, 0x0A, + 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2C, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x64, + 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6C, 0x74, 0x20, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x20, 0x48, + 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, 0x20, 0x61, 0x74, + 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x73, 0x68, 0x65, 0x0D, + 0x0A, 0x73, 0x74, 0x72, 0x65, 0x74, 0x63, 0x68, 0x65, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x6D, 0x73, 0x20, + 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x20, 0x61, + 0x73, 0x20, 0x66, 0x61, 0x72, 0x20, 0x61, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x67, 0x6F, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x72, + 0x6F, 0x6B, 0x65, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x61, 0x20, + 0x62, 0x69, 0x74, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x65, 0x64, 0x67, 0x65, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x68, 0x61, 0x6E, + 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x6E, 0x64, + 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x69, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x3F, + 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, + 0x66, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6E, 0x69, 0x62, + 0x62, 0x6C, 0x65, 0x64, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2D, 0x68, 0x61, + 0x6E, 0x64, 0x20, 0x62, 0x69, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x72, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x66, + 0x66, 0x65, 0x63, 0x74, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6E, 0x65, 0x78, 0x74, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, + 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, 0x65, 0x6C, 0x74, + 0x20, 0x61, 0x20, 0x76, 0x69, 0x6F, 0x6C, 0x65, 0x6E, 0x74, + 0x0D, 0x0A, 0x62, 0x6C, 0x6F, 0x77, 0x20, 0x75, 0x6E, 0x64, + 0x65, 0x72, 0x6E, 0x65, 0x61, 0x74, 0x68, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x63, 0x68, 0x69, 0x6E, 0x3A, 0x20, 0x69, 0x74, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x6B, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x6F, 0x6F, 0x74, + 0x21, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, + 0x64, 0x65, 0x61, 0x6C, 0x20, 0x66, 0x72, 0x69, 0x67, 0x68, + 0x74, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, + 0x75, 0x64, 0x64, 0x65, 0x6E, 0x20, 0x63, 0x68, 0x61, 0x6E, + 0x67, 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x66, 0x65, 0x6C, 0x74, 0x0D, 0x0A, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x74, 0x69, 0x6D, 0x65, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x6C, 0x6F, 0x73, + 0x74, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x73, 0x68, 0x72, 0x69, 0x6E, 0x6B, + 0x69, 0x6E, 0x67, 0x20, 0x72, 0x61, 0x70, 0x69, 0x64, 0x6C, + 0x79, 0x3B, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x0D, + 0x0A, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x77, 0x6F, + 0x72, 0x6B, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, + 0x20, 0x74, 0x6F, 0x20, 0x65, 0x61, 0x74, 0x20, 0x73, 0x6F, + 0x6D, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x62, 0x69, 0x74, 0x2E, + 0x20, 0x48, 0x65, 0x72, 0x20, 0x63, 0x68, 0x69, 0x6E, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x0D, 0x0A, 0x73, 0x6F, 0x20, 0x63, 0x6C, 0x6F, 0x73, + 0x65, 0x6C, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x73, + 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x6F, 0x6F, 0x74, + 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x68, 0x61, 0x72, + 0x64, 0x6C, 0x79, 0x20, 0x72, 0x6F, 0x6F, 0x6D, 0x20, 0x74, + 0x6F, 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x20, 0x68, 0x65, 0x72, + 0x0D, 0x0A, 0x6D, 0x6F, 0x75, 0x74, 0x68, 0x3B, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x64, 0x69, 0x64, + 0x20, 0x69, 0x74, 0x20, 0x61, 0x74, 0x20, 0x6C, 0x61, 0x73, + 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x6E, + 0x61, 0x67, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x77, + 0x61, 0x6C, 0x6C, 0x6F, 0x77, 0x20, 0x61, 0x20, 0x6D, 0x6F, + 0x72, 0x73, 0x65, 0x6C, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x6C, 0x65, 0x66, 0x74, 0x68, 0x61, 0x6E, + 0x64, 0x20, 0x62, 0x69, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x0D, 0x0A, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, + 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, + 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, + 0x20, 0x20, 0x20, 0x20, 0x2A, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, + 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, + 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x0D, + 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, + 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, + 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x20, 0x20, 0x20, 0x20, + 0x2A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x43, 0x6F, 0x6D, 0x65, 0x2C, 0x20, 0x6D, 0x79, 0x20, + 0x68, 0x65, 0x61, 0x64, 0x27, 0x73, 0x20, 0x66, 0x72, 0x65, + 0x65, 0x20, 0x61, 0x74, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x74, 0x6F, + 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x64, 0x65, 0x6C, 0x69, + 0x67, 0x68, 0x74, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x0D, 0x0A, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x64, 0x20, + 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x61, 0x6C, 0x61, 0x72, 0x6D, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x2C, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, + 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, + 0x65, 0x72, 0x73, 0x0D, 0x0A, 0x77, 0x65, 0x72, 0x65, 0x20, + 0x6E, 0x6F, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x3A, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x73, 0x65, 0x65, 0x2C, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x64, 0x6F, 0x77, 0x6E, + 0x2C, 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, 0x61, 0x6E, 0x20, + 0x69, 0x6D, 0x6D, 0x65, 0x6E, 0x73, 0x65, 0x20, 0x6C, 0x65, + 0x6E, 0x67, 0x74, 0x68, 0x20, 0x6F, 0x66, 0x20, 0x6E, 0x65, + 0x63, 0x6B, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, + 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x72, 0x69, 0x73, 0x65, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, + 0x61, 0x20, 0x73, 0x74, 0x61, 0x6C, 0x6B, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x0D, 0x0A, 0x73, 0x65, + 0x61, 0x20, 0x6F, 0x66, 0x20, 0x67, 0x72, 0x65, 0x65, 0x6E, + 0x20, 0x6C, 0x65, 0x61, 0x76, 0x65, 0x73, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x6C, 0x61, 0x79, 0x20, 0x66, 0x61, 0x72, + 0x20, 0x62, 0x65, 0x6C, 0x6F, 0x77, 0x20, 0x68, 0x65, 0x72, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, 0x74, + 0x20, 0x43, 0x41, 0x4E, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x67, 0x72, 0x65, 0x65, 0x6E, 0x20, + 0x73, 0x74, 0x75, 0x66, 0x66, 0x20, 0x62, 0x65, 0x3F, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x20, 0x27, 0x41, 0x6E, 0x64, 0x20, 0x77, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x48, 0x41, 0x56, 0x45, 0x20, 0x6D, + 0x79, 0x0D, 0x0A, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x65, + 0x72, 0x73, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x74, 0x6F, 0x3F, + 0x20, 0x41, 0x6E, 0x64, 0x20, 0x6F, 0x68, 0x2C, 0x20, 0x6D, + 0x79, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x68, 0x61, 0x6E, + 0x64, 0x73, 0x2C, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x69, 0x73, + 0x20, 0x69, 0x74, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x27, + 0x74, 0x20, 0x73, 0x65, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x3F, + 0x27, 0x0D, 0x0A, 0x53, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x6D, 0x6F, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x61, + 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6B, + 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6E, 0x6F, 0x20, + 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x20, 0x73, 0x65, 0x65, + 0x6D, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x6F, 0x6C, + 0x6C, 0x6F, 0x77, 0x2C, 0x0D, 0x0A, 0x65, 0x78, 0x63, 0x65, + 0x70, 0x74, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x73, 0x68, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x6D, 0x6F, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x20, 0x67, 0x72, + 0x65, 0x65, 0x6E, 0x20, 0x6C, 0x65, 0x61, 0x76, 0x65, 0x73, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x6E, 0x6F, 0x20, + 0x63, 0x68, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x73, 0x20, 0x75, 0x70, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x65, + 0x61, 0x64, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x74, + 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, + 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, + 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x6D, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x64, 0x65, 0x6C, 0x69, 0x67, 0x68, 0x74, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x65, 0x72, 0x0D, + 0x0A, 0x6E, 0x65, 0x63, 0x6B, 0x20, 0x77, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x62, 0x65, 0x6E, 0x64, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x65, 0x61, 0x73, 0x69, 0x6C, 0x79, 0x20, + 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x6C, 0x69, + 0x6B, 0x65, 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x70, 0x65, + 0x6E, 0x74, 0x2E, 0x20, 0x53, 0x68, 0x65, 0x20, 0x68, 0x61, + 0x64, 0x0D, 0x0A, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x73, 0x75, + 0x63, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x63, 0x75, 0x72, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x69, + 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x69, 0x6E, 0x74, + 0x6F, 0x20, 0x61, 0x20, 0x67, 0x72, 0x61, 0x63, 0x65, 0x66, + 0x75, 0x6C, 0x20, 0x7A, 0x69, 0x67, 0x7A, 0x61, 0x67, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, + 0x6F, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x64, + 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6D, 0x6F, + 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x65, 0x61, + 0x76, 0x65, 0x73, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x6E, 0x6F, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x6F, 0x70, 0x73, 0x0D, 0x0A, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x65, 0x65, + 0x73, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x77, 0x68, + 0x69, 0x63, 0x68, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x77, 0x61, 0x6E, + 0x64, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x61, 0x20, 0x73, 0x68, 0x61, 0x72, 0x70, + 0x20, 0x68, 0x69, 0x73, 0x73, 0x20, 0x6D, 0x61, 0x64, 0x65, + 0x0D, 0x0A, 0x68, 0x65, 0x72, 0x20, 0x64, 0x72, 0x61, 0x77, + 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x68, 0x75, 0x72, 0x72, 0x79, 0x3A, 0x20, 0x61, 0x20, + 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x70, 0x69, 0x67, 0x65, + 0x6F, 0x6E, 0x20, 0x68, 0x61, 0x64, 0x20, 0x66, 0x6C, 0x6F, + 0x77, 0x6E, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x66, 0x61, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x0D, 0x0A, 0x77, 0x61, 0x73, 0x20, 0x62, 0x65, 0x61, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, 0x76, + 0x69, 0x6F, 0x6C, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, 0x77, 0x69, + 0x6E, 0x67, 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, + 0x65, 0x72, 0x70, 0x65, 0x6E, 0x74, 0x21, 0x27, 0x20, 0x73, + 0x63, 0x72, 0x65, 0x61, 0x6D, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x50, 0x69, 0x67, 0x65, 0x6F, 0x6E, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x4E, 0x4F, + 0x54, 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x70, 0x65, 0x6E, + 0x74, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x67, + 0x6E, 0x61, 0x6E, 0x74, 0x6C, 0x79, 0x2E, 0x20, 0x27, 0x4C, + 0x65, 0x74, 0x20, 0x6D, 0x65, 0x20, 0x61, 0x6C, 0x6F, 0x6E, + 0x65, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x65, + 0x72, 0x70, 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x49, 0x20, 0x73, + 0x61, 0x79, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x21, 0x27, + 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x50, 0x69, 0x67, 0x65, 0x6F, 0x6E, + 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x73, 0x75, 0x62, 0x64, + 0x75, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x0D, + 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x6B, 0x69, + 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x6F, 0x62, 0x2C, + 0x20, 0x27, 0x49, 0x27, 0x76, 0x65, 0x20, 0x74, 0x72, 0x69, + 0x65, 0x64, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x77, + 0x61, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x65, 0x65, 0x6D, + 0x73, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x73, 0x75, 0x69, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x6D, 0x21, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x20, 0x68, 0x61, 0x76, 0x65, 0x6E, 0x27, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x65, 0x61, 0x73, + 0x74, 0x20, 0x69, 0x64, 0x65, 0x61, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x74, + 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x49, 0x27, 0x76, 0x65, 0x20, 0x74, 0x72, 0x69, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, 0x6F, 0x74, + 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x72, 0x65, 0x65, 0x73, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x27, 0x76, 0x65, + 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x62, 0x61, 0x6E, + 0x6B, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x27, + 0x76, 0x65, 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x0D, 0x0A, + 0x68, 0x65, 0x64, 0x67, 0x65, 0x73, 0x2C, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x50, 0x69, 0x67, 0x65, 0x6F, 0x6E, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x74, 0x74, + 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x3B, 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, + 0x74, 0x68, 0x6F, 0x73, 0x65, 0x0D, 0x0A, 0x73, 0x65, 0x72, + 0x70, 0x65, 0x6E, 0x74, 0x73, 0x21, 0x20, 0x54, 0x68, 0x65, + 0x72, 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x70, 0x6C, + 0x65, 0x61, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, + 0x6D, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6D, 0x6F, 0x72, + 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x6F, 0x72, 0x65, + 0x20, 0x70, 0x75, 0x7A, 0x7A, 0x6C, 0x65, 0x64, 0x2C, 0x20, + 0x62, 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x73, 0x61, 0x79, + 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x69, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x69, 0x67, + 0x65, 0x6F, 0x6E, 0x20, 0x68, 0x61, 0x64, 0x20, 0x66, 0x69, + 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x41, 0x73, 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, + 0x20, 0x77, 0x61, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x74, 0x72, + 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x65, 0x6E, 0x6F, 0x75, + 0x67, 0x68, 0x20, 0x68, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x67, 0x67, 0x73, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x50, 0x69, 0x67, 0x65, 0x6F, 0x6E, 0x3B, 0x0D, + 0x0A, 0x27, 0x62, 0x75, 0x74, 0x20, 0x49, 0x20, 0x6D, 0x75, + 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6F, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x2D, 0x6F, 0x75, + 0x74, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x65, 0x72, 0x70, + 0x65, 0x6E, 0x74, 0x73, 0x20, 0x6E, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x61, 0x79, 0x21, 0x20, + 0x57, 0x68, 0x79, 0x2C, 0x20, 0x49, 0x0D, 0x0A, 0x68, 0x61, + 0x76, 0x65, 0x6E, 0x27, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x61, 0x20, 0x77, 0x69, 0x6E, 0x6B, 0x20, 0x6F, 0x66, 0x20, + 0x73, 0x6C, 0x65, 0x65, 0x70, 0x20, 0x74, 0x68, 0x65, 0x73, + 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, 0x77, 0x65, + 0x65, 0x6B, 0x73, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x27, 0x6D, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, + 0x6F, 0x72, 0x72, 0x79, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x76, + 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x61, 0x6E, 0x6E, + 0x6F, 0x79, 0x65, 0x64, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x77, + 0x68, 0x6F, 0x20, 0x77, 0x61, 0x73, 0x20, 0x62, 0x65, 0x67, + 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x0D, + 0x0A, 0x73, 0x65, 0x65, 0x20, 0x69, 0x74, 0x73, 0x20, 0x6D, + 0x65, 0x61, 0x6E, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x41, 0x6E, 0x64, 0x20, 0x6A, 0x75, 0x73, 0x74, + 0x20, 0x61, 0x73, 0x20, 0x49, 0x27, 0x64, 0x20, 0x74, 0x61, + 0x6B, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x69, + 0x67, 0x68, 0x65, 0x73, 0x74, 0x20, 0x74, 0x72, 0x65, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, + 0x6F, 0x64, 0x2C, 0x27, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, + 0x6E, 0x75, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x50, 0x69, 0x67, 0x65, 0x6F, 0x6E, 0x2C, 0x20, 0x72, 0x61, + 0x69, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x73, 0x20, + 0x76, 0x6F, 0x69, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x61, + 0x20, 0x73, 0x68, 0x72, 0x69, 0x65, 0x6B, 0x2C, 0x20, 0x27, + 0x61, 0x6E, 0x64, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x61, + 0x73, 0x20, 0x49, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x49, 0x0D, 0x0A, + 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, + 0x66, 0x72, 0x65, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x20, 0x61, 0x74, 0x20, 0x6C, 0x61, 0x73, 0x74, + 0x2C, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x6D, 0x75, 0x73, + 0x74, 0x20, 0x6E, 0x65, 0x65, 0x64, 0x73, 0x20, 0x63, 0x6F, + 0x6D, 0x65, 0x20, 0x77, 0x72, 0x69, 0x67, 0x67, 0x6C, 0x69, + 0x6E, 0x67, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x66, 0x72, + 0x6F, 0x6D, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6B, + 0x79, 0x21, 0x20, 0x55, 0x67, 0x68, 0x2C, 0x20, 0x53, 0x65, + 0x72, 0x70, 0x65, 0x6E, 0x74, 0x21, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x42, 0x75, 0x74, 0x20, 0x49, 0x27, 0x6D, 0x20, + 0x4E, 0x4F, 0x54, 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x70, + 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x49, 0x20, 0x74, 0x65, 0x6C, + 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x20, + 0x27, 0x49, 0x27, 0x6D, 0x20, 0x61, 0x2D, 0x2D, 0x49, 0x27, + 0x6D, 0x20, 0x61, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x57, 0x65, 0x6C, 0x6C, 0x21, 0x20, 0x57, 0x48, 0x41, + 0x54, 0x20, 0x61, 0x72, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x3F, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x50, 0x69, 0x67, 0x65, 0x6F, 0x6E, 0x2E, 0x20, 0x27, + 0x49, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x73, 0x65, 0x65, 0x20, + 0x79, 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x74, 0x72, 0x79, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x69, 0x6E, + 0x76, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x49, 0x2D, 0x2D, 0x49, 0x27, 0x6D, 0x20, 0x61, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x67, 0x69, 0x72, + 0x6C, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x72, 0x61, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x74, 0x66, 0x75, + 0x6C, 0x6C, 0x79, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, + 0x65, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x75, + 0x6D, 0x62, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x68, + 0x61, 0x6E, 0x67, 0x65, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x67, 0x6F, 0x6E, 0x65, 0x20, 0x74, + 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x64, 0x61, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x41, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x6C, 0x79, 0x20, + 0x73, 0x74, 0x6F, 0x72, 0x79, 0x20, 0x69, 0x6E, 0x64, 0x65, + 0x65, 0x64, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x50, 0x69, 0x67, 0x65, 0x6F, 0x6E, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x74, 0x6F, 0x6E, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, + 0x65, 0x70, 0x65, 0x73, 0x74, 0x0D, 0x0A, 0x63, 0x6F, 0x6E, + 0x74, 0x65, 0x6D, 0x70, 0x74, 0x2E, 0x20, 0x27, 0x49, 0x27, + 0x76, 0x65, 0x20, 0x73, 0x65, 0x65, 0x6E, 0x20, 0x61, 0x20, + 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x6D, 0x61, 0x6E, 0x79, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x67, 0x69, 0x72, + 0x6C, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x6D, 0x79, 0x20, 0x74, + 0x69, 0x6D, 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6E, + 0x65, 0x76, 0x65, 0x72, 0x20, 0x4F, 0x4E, 0x45, 0x0D, 0x0A, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x6E, 0x65, 0x63, 0x6B, 0x20, 0x61, 0x73, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x21, 0x20, 0x4E, 0x6F, 0x2C, 0x20, + 0x6E, 0x6F, 0x21, 0x20, 0x59, 0x6F, 0x75, 0x27, 0x72, 0x65, + 0x20, 0x61, 0x20, 0x73, 0x65, 0x72, 0x70, 0x65, 0x6E, 0x74, + 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x75, 0x73, 0x65, + 0x0D, 0x0A, 0x64, 0x65, 0x6E, 0x79, 0x69, 0x6E, 0x67, 0x20, + 0x69, 0x74, 0x2E, 0x20, 0x49, 0x20, 0x73, 0x75, 0x70, 0x70, + 0x6F, 0x73, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x6C, 0x6C, + 0x20, 0x62, 0x65, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x69, 0x6E, + 0x67, 0x20, 0x6D, 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6E, + 0x65, 0x76, 0x65, 0x72, 0x20, 0x74, 0x61, 0x73, 0x74, 0x65, + 0x64, 0x20, 0x61, 0x6E, 0x0D, 0x0A, 0x65, 0x67, 0x67, 0x21, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x48, 0x41, + 0x56, 0x45, 0x20, 0x74, 0x61, 0x73, 0x74, 0x65, 0x64, 0x20, + 0x65, 0x67, 0x67, 0x73, 0x2C, 0x20, 0x63, 0x65, 0x72, 0x74, + 0x61, 0x69, 0x6E, 0x6C, 0x79, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x77, 0x68, 0x6F, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x74, 0x72, 0x75, 0x74, 0x68, + 0x66, 0x75, 0x6C, 0x0D, 0x0A, 0x63, 0x68, 0x69, 0x6C, 0x64, + 0x3B, 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x67, 0x69, 0x72, 0x6C, 0x73, 0x20, + 0x65, 0x61, 0x74, 0x20, 0x65, 0x67, 0x67, 0x73, 0x20, 0x71, + 0x75, 0x69, 0x74, 0x65, 0x20, 0x61, 0x73, 0x20, 0x6D, 0x75, + 0x63, 0x68, 0x20, 0x61, 0x73, 0x20, 0x73, 0x65, 0x72, 0x70, + 0x65, 0x6E, 0x74, 0x73, 0x20, 0x64, 0x6F, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x0D, 0x0A, 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, 0x6F, 0x6E, + 0x27, 0x74, 0x20, 0x62, 0x65, 0x6C, 0x69, 0x65, 0x76, 0x65, + 0x20, 0x69, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x69, 0x67, 0x65, 0x6F, + 0x6E, 0x3B, 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, 0x69, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x64, 0x6F, 0x2C, 0x20, + 0x77, 0x68, 0x79, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x27, 0x72, 0x65, 0x0D, 0x0A, 0x61, 0x20, + 0x6B, 0x69, 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x65, + 0x72, 0x70, 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x27, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x49, 0x20, + 0x63, 0x61, 0x6E, 0x20, 0x73, 0x61, 0x79, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x20, 0x6E, + 0x65, 0x77, 0x20, 0x69, 0x64, 0x65, 0x61, 0x20, 0x74, 0x6F, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x73, 0x69, 0x6C, + 0x65, 0x6E, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x0D, + 0x0A, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x20, 0x6F, 0x72, + 0x20, 0x74, 0x77, 0x6F, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x67, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x50, 0x69, 0x67, 0x65, 0x6F, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6F, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x75, 0x6E, + 0x69, 0x74, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x64, 0x64, + 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x27, 0x59, 0x6F, 0x75, 0x27, + 0x72, 0x65, 0x0D, 0x0A, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x65, 0x67, 0x67, 0x73, + 0x2C, 0x20, 0x49, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x54, + 0x48, 0x41, 0x54, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x65, + 0x6E, 0x6F, 0x75, 0x67, 0x68, 0x3B, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6F, 0x65, 0x73, + 0x20, 0x69, 0x74, 0x20, 0x6D, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x65, 0x0D, 0x0A, 0x77, 0x68, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x27, + 0x72, 0x65, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x67, 0x69, 0x72, 0x6C, 0x20, 0x6F, 0x72, 0x20, + 0x61, 0x20, 0x73, 0x65, 0x72, 0x70, 0x65, 0x6E, 0x74, 0x3F, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x20, 0x6D, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x20, 0x67, + 0x6F, 0x6F, 0x64, 0x20, 0x64, 0x65, 0x61, 0x6C, 0x20, 0x74, + 0x6F, 0x20, 0x4D, 0x45, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x68, 0x61, + 0x73, 0x74, 0x69, 0x6C, 0x79, 0x3B, 0x20, 0x27, 0x62, 0x75, + 0x74, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x66, + 0x6F, 0x72, 0x20, 0x65, 0x67, 0x67, 0x73, 0x2C, 0x20, 0x61, + 0x73, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, 0x70, 0x70, 0x65, + 0x6E, 0x73, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x66, + 0x20, 0x49, 0x20, 0x77, 0x61, 0x73, 0x2C, 0x20, 0x49, 0x20, + 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, + 0x77, 0x61, 0x6E, 0x74, 0x20, 0x59, 0x4F, 0x55, 0x52, 0x53, + 0x3A, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x0D, + 0x0A, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6D, + 0x20, 0x72, 0x61, 0x77, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x62, 0x65, 0x20, + 0x6F, 0x66, 0x66, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x50, 0x69, 0x67, 0x65, 0x6F, 0x6E, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x73, 0x75, 0x6C, 0x6B, 0x79, 0x20, 0x74, + 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, + 0x20, 0x73, 0x65, 0x74, 0x74, 0x6C, 0x65, 0x64, 0x0D, 0x0A, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, + 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x73, 0x20, + 0x6E, 0x65, 0x73, 0x74, 0x2E, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x63, 0x72, 0x6F, 0x75, 0x63, 0x68, 0x65, 0x64, + 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x6D, 0x6F, 0x6E, + 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x65, 0x65, + 0x73, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, + 0x61, 0x73, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x6E, 0x65, 0x63, 0x6B, 0x20, 0x6B, 0x65, + 0x70, 0x74, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x65, 0x6E, 0x74, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x64, + 0x20, 0x61, 0x6D, 0x6F, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x72, 0x61, 0x6E, 0x63, 0x68, 0x65, 0x73, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x65, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x74, 0x6F, 0x70, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x75, 0x6E, 0x74, 0x77, 0x69, + 0x73, 0x74, 0x20, 0x69, 0x74, 0x2E, 0x20, 0x41, 0x66, 0x74, + 0x65, 0x72, 0x20, 0x61, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, + 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x72, 0x65, 0x6D, 0x65, + 0x6D, 0x62, 0x65, 0x72, 0x65, 0x64, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x74, 0x69, 0x6C, + 0x6C, 0x20, 0x68, 0x65, 0x6C, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x6D, 0x75, 0x73, 0x68, 0x72, 0x6F, 0x6F, 0x6D, 0x20, + 0x69, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x61, 0x6E, + 0x64, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x73, + 0x68, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x63, 0x61, 0x72, 0x65, 0x66, 0x75, 0x6C, 0x6C, 0x79, 0x2C, + 0x20, 0x6E, 0x69, 0x62, 0x62, 0x6C, 0x69, 0x6E, 0x67, 0x20, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x74, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x6E, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x6F, 0x74, 0x68, 0x65, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x67, 0x72, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x74, 0x69, 0x6D, 0x65, 0x73, 0x20, 0x74, + 0x61, 0x6C, 0x6C, 0x65, 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x74, 0x69, 0x6D, 0x65, 0x73, 0x20, + 0x73, 0x68, 0x6F, 0x72, 0x74, 0x65, 0x72, 0x2C, 0x20, 0x75, + 0x6E, 0x74, 0x69, 0x6C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, + 0x61, 0x64, 0x0D, 0x0A, 0x73, 0x75, 0x63, 0x63, 0x65, 0x65, + 0x64, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x62, 0x72, 0x69, + 0x6E, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, + 0x6F, 0x20, 0x68, 0x65, 0x72, 0x20, 0x75, 0x73, 0x75, 0x61, + 0x6C, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x73, 0x6F, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x73, 0x69, + 0x6E, 0x63, 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x61, 0x6E, 0x79, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6E, 0x65, 0x61, 0x72, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x73, 0x69, 0x7A, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x69, 0x74, 0x0D, 0x0A, 0x66, 0x65, 0x6C, 0x74, + 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x73, 0x74, 0x72, + 0x61, 0x6E, 0x67, 0x65, 0x20, 0x61, 0x74, 0x20, 0x66, 0x69, + 0x72, 0x73, 0x74, 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x66, 0x65, 0x77, 0x20, 0x6D, 0x69, 0x6E, + 0x75, 0x74, 0x65, 0x73, 0x2C, 0x0D, 0x0A, 0x61, 0x6E, 0x64, + 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x74, 0x61, 0x6C, + 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x61, 0x73, 0x20, + 0x75, 0x73, 0x75, 0x61, 0x6C, 0x2E, 0x20, 0x27, 0x43, 0x6F, + 0x6D, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x27, + 0x73, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x6D, 0x79, 0x20, + 0x70, 0x6C, 0x61, 0x6E, 0x20, 0x64, 0x6F, 0x6E, 0x65, 0x0D, + 0x0A, 0x6E, 0x6F, 0x77, 0x21, 0x20, 0x48, 0x6F, 0x77, 0x20, + 0x70, 0x75, 0x7A, 0x7A, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x63, + 0x68, 0x61, 0x6E, 0x67, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, + 0x21, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x6E, 0x65, 0x76, 0x65, + 0x72, 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x67, 0x6F, 0x69, 0x6E, + 0x67, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x2C, 0x20, + 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6D, + 0x69, 0x6E, 0x75, 0x74, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x61, + 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x21, 0x20, 0x48, 0x6F, + 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, 0x20, 0x49, 0x27, 0x76, + 0x65, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x62, 0x61, 0x63, 0x6B, + 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x79, 0x20, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x0D, 0x0A, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x73, 0x2C, 0x20, 0x74, + 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x62, 0x65, 0x61, 0x75, + 0x74, 0x69, 0x66, 0x75, 0x6C, 0x20, 0x67, 0x61, 0x72, 0x64, + 0x65, 0x6E, 0x2D, 0x2D, 0x68, 0x6F, 0x77, 0x20, 0x49, 0x53, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x74, 0x6F, 0x20, + 0x62, 0x65, 0x20, 0x64, 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x49, + 0x20, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x3F, 0x27, 0x20, + 0x41, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x73, 0x75, 0x64, + 0x64, 0x65, 0x6E, 0x6C, 0x79, 0x20, 0x75, 0x70, 0x6F, 0x6E, + 0x20, 0x61, 0x6E, 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x0D, 0x0A, + 0x70, 0x6C, 0x61, 0x63, 0x65, 0x2C, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x68, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x20, + 0x69, 0x74, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x66, + 0x6F, 0x75, 0x72, 0x20, 0x66, 0x65, 0x65, 0x74, 0x20, 0x68, + 0x69, 0x67, 0x68, 0x2E, 0x20, 0x27, 0x57, 0x68, 0x6F, 0x65, + 0x76, 0x65, 0x72, 0x20, 0x6C, 0x69, 0x76, 0x65, 0x73, 0x0D, + 0x0A, 0x74, 0x68, 0x65, 0x72, 0x65, 0x2C, 0x27, 0x20, 0x74, + 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2C, 0x20, 0x27, 0x69, 0x74, 0x27, 0x6C, 0x6C, + 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x64, 0x6F, 0x20, + 0x74, 0x6F, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x75, 0x70, + 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x54, 0x48, + 0x49, 0x53, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x20, 0x77, + 0x68, 0x79, 0x2C, 0x0D, 0x0A, 0x49, 0x20, 0x73, 0x68, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x66, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, + 0x20, 0x77, 0x69, 0x74, 0x73, 0x21, 0x27, 0x20, 0x53, 0x6F, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, + 0x20, 0x6E, 0x69, 0x62, 0x62, 0x6C, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x68, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x69, + 0x74, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, + 0x20, 0x76, 0x65, 0x6E, 0x74, 0x75, 0x72, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x67, 0x6F, 0x20, 0x6E, 0x65, 0x61, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x68, 0x6F, 0x75, 0x73, 0x65, 0x20, + 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, + 0x68, 0x61, 0x64, 0x20, 0x62, 0x72, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x6E, 0x69, + 0x6E, 0x65, 0x20, 0x69, 0x6E, 0x63, 0x68, 0x65, 0x73, 0x20, + 0x68, 0x69, 0x67, 0x68, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, 0x48, 0x41, 0x50, 0x54, + 0x45, 0x52, 0x20, 0x56, 0x49, 0x2E, 0x20, 0x50, 0x69, 0x67, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x50, 0x65, 0x70, 0x70, 0x65, + 0x72, 0x0D, 0x0A, 0x0D, 0x0A, 0x46, 0x6F, 0x72, 0x20, 0x61, + 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x20, 0x6F, 0x72, + 0x20, 0x74, 0x77, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, + 0x74, 0x6F, 0x6F, 0x64, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x68, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x69, 0x6E, 0x67, + 0x20, 0x77, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x74, 0x6F, 0x20, + 0x64, 0x6F, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x2C, 0x20, 0x77, + 0x68, 0x65, 0x6E, 0x20, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, + 0x6C, 0x79, 0x20, 0x61, 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x6D, + 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x6C, 0x69, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x72, 0x75, + 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x75, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x77, 0x6F, + 0x6F, 0x64, 0x2D, 0x2D, 0x28, 0x73, 0x68, 0x65, 0x20, 0x63, + 0x6F, 0x6E, 0x73, 0x69, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, + 0x68, 0x69, 0x6D, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, + 0x61, 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x6D, 0x61, 0x6E, 0x20, + 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x68, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x6C, 0x69, + 0x76, 0x65, 0x72, 0x79, 0x3A, 0x0D, 0x0A, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x77, 0x69, 0x73, 0x65, 0x2C, 0x20, 0x6A, 0x75, + 0x64, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x79, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x66, 0x61, 0x63, 0x65, 0x20, 0x6F, 0x6E, + 0x6C, 0x79, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x63, + 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x68, 0x69, 0x6D, 0x20, + 0x61, 0x0D, 0x0A, 0x66, 0x69, 0x73, 0x68, 0x29, 0x2D, 0x2D, + 0x61, 0x6E, 0x64, 0x20, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, + 0x20, 0x6C, 0x6F, 0x75, 0x64, 0x6C, 0x79, 0x20, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, 0x69, 0x73, 0x20, 0x6B, + 0x6E, 0x75, 0x63, 0x6B, 0x6C, 0x65, 0x73, 0x2E, 0x20, 0x49, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6F, 0x70, 0x65, 0x6E, + 0x65, 0x64, 0x0D, 0x0A, 0x62, 0x79, 0x20, 0x61, 0x6E, 0x6F, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x6D, + 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x6C, 0x69, 0x76, 0x65, + 0x72, 0x79, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, + 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x66, 0x61, 0x63, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x61, 0x72, + 0x67, 0x65, 0x20, 0x65, 0x79, 0x65, 0x73, 0x20, 0x6C, 0x69, + 0x6B, 0x65, 0x20, 0x61, 0x0D, 0x0A, 0x66, 0x72, 0x6F, 0x67, + 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x6F, 0x74, 0x68, + 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x6D, 0x65, 0x6E, 0x2C, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x69, + 0x63, 0x65, 0x64, 0x2C, 0x20, 0x68, 0x61, 0x64, 0x20, 0x70, + 0x6F, 0x77, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x68, 0x61, + 0x69, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x75, + 0x72, 0x6C, 0x65, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x0D, 0x0A, + 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, + 0x20, 0x68, 0x65, 0x61, 0x64, 0x73, 0x2E, 0x20, 0x53, 0x68, + 0x65, 0x20, 0x66, 0x65, 0x6C, 0x74, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x20, + 0x74, 0x6F, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x2C, + 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x72, 0x65, 0x70, + 0x74, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x77, 0x61, 0x79, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x6F, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x65, 0x6E, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x46, + 0x69, 0x73, 0x68, 0x2D, 0x46, 0x6F, 0x6F, 0x74, 0x6D, 0x61, + 0x6E, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x62, 0x79, + 0x20, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x69, 0x6E, 0x67, + 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x75, 0x6E, 0x64, 0x65, + 0x72, 0x20, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x6D, 0x20, + 0x61, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x6C, 0x65, + 0x74, 0x74, 0x65, 0x72, 0x2C, 0x0D, 0x0A, 0x6E, 0x65, 0x61, + 0x72, 0x6C, 0x79, 0x20, 0x61, 0x73, 0x20, 0x6C, 0x61, 0x72, + 0x67, 0x65, 0x20, 0x61, 0x73, 0x20, 0x68, 0x69, 0x6D, 0x73, + 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x68, 0x65, 0x20, 0x68, 0x61, 0x6E, + 0x64, 0x65, 0x64, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, + 0x72, 0x2C, 0x0D, 0x0A, 0x73, 0x61, 0x79, 0x69, 0x6E, 0x67, + 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x73, 0x6F, 0x6C, + 0x65, 0x6D, 0x6E, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x20, + 0x27, 0x46, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, + 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x2E, 0x20, 0x41, 0x6E, + 0x20, 0x69, 0x6E, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x0D, 0x0A, 0x74, 0x6F, + 0x20, 0x70, 0x6C, 0x61, 0x79, 0x20, 0x63, 0x72, 0x6F, 0x71, + 0x75, 0x65, 0x74, 0x2E, 0x27, 0x20, 0x54, 0x68, 0x65, 0x20, + 0x46, 0x72, 0x6F, 0x67, 0x2D, 0x46, 0x6F, 0x6F, 0x74, 0x6D, + 0x61, 0x6E, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x61, 0x6D, 0x65, 0x20, 0x73, 0x6F, 0x6C, 0x65, 0x6D, + 0x6E, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x0D, 0x0A, 0x6F, + 0x6E, 0x6C, 0x79, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x72, 0x64, + 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x6F, 0x72, 0x64, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, + 0x74, 0x74, 0x6C, 0x65, 0x2C, 0x20, 0x27, 0x46, 0x72, 0x6F, + 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, + 0x6E, 0x2E, 0x20, 0x41, 0x6E, 0x0D, 0x0A, 0x69, 0x6E, 0x76, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, + 0x65, 0x73, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x70, 0x6C, 0x61, + 0x79, 0x20, 0x63, 0x72, 0x6F, 0x71, 0x75, 0x65, 0x74, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, + 0x62, 0x6F, 0x77, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x77, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, + 0x20, 0x63, 0x75, 0x72, 0x6C, 0x73, 0x20, 0x67, 0x6F, 0x74, + 0x20, 0x65, 0x6E, 0x74, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x6C, 0x61, 0x75, 0x67, 0x68, 0x65, 0x64, 0x20, 0x73, 0x6F, + 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x72, 0x75, 0x6E, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, + 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x77, 0x6F, 0x6F, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x66, + 0x65, 0x61, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x68, 0x65, 0x61, 0x72, 0x69, 0x6E, 0x67, + 0x20, 0x68, 0x65, 0x72, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6E, + 0x65, 0x78, 0x74, 0x20, 0x70, 0x65, 0x65, 0x70, 0x65, 0x64, + 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x46, 0x69, 0x73, 0x68, 0x2D, 0x46, 0x6F, 0x6F, 0x74, 0x6D, + 0x61, 0x6E, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, 0x6F, 0x6E, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x73, 0x69, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x6E, 0x65, 0x61, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x64, 0x6F, 0x6F, 0x72, 0x2C, 0x20, 0x73, + 0x74, 0x61, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x74, 0x75, + 0x70, 0x69, 0x64, 0x6C, 0x79, 0x20, 0x75, 0x70, 0x20, 0x69, + 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6B, + 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x69, 0x6D, + 0x69, 0x64, 0x6C, 0x79, 0x20, 0x75, 0x70, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6B, 0x6E, 0x6F, 0x63, 0x6B, + 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, + 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x73, + 0x6F, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x6B, 0x6E, 0x6F, 0x63, 0x6B, 0x69, + 0x6E, 0x67, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x6F, 0x74, 0x6D, 0x61, + 0x6E, 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x0D, 0x0A, 0x74, 0x77, + 0x6F, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x73, 0x2E, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2C, 0x20, 0x62, 0x65, + 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x49, 0x27, 0x6D, 0x20, + 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, + 0x65, 0x20, 0x73, 0x69, 0x64, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, 0x61, + 0x73, 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, 0x61, 0x72, 0x65, + 0x3B, 0x20, 0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x6C, 0x79, + 0x2C, 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x27, 0x72, 0x65, 0x20, 0x6D, 0x61, + 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x6E, 0x6F, 0x69, 0x73, 0x65, 0x20, 0x69, 0x6E, + 0x73, 0x69, 0x64, 0x65, 0x2C, 0x20, 0x6E, 0x6F, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x0D, 0x0A, + 0x70, 0x6F, 0x73, 0x73, 0x69, 0x62, 0x6C, 0x79, 0x20, 0x68, + 0x65, 0x61, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x2E, 0x27, 0x20, + 0x41, 0x6E, 0x64, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, + 0x6E, 0x6C, 0x79, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6D, 0x6F, 0x73, 0x74, + 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x6F, 0x72, 0x64, 0x69, + 0x6E, 0x61, 0x72, 0x79, 0x20, 0x6E, 0x6F, 0x69, 0x73, 0x65, + 0x0D, 0x0A, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6E, 0x2D, 0x2D, 0x61, + 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x20, + 0x68, 0x6F, 0x77, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x73, 0x6E, 0x65, 0x65, 0x7A, 0x69, 0x6E, 0x67, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x65, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x0D, 0x0A, 0x61, 0x20, 0x67, 0x72, + 0x65, 0x61, 0x74, 0x20, 0x63, 0x72, 0x61, 0x73, 0x68, 0x2C, + 0x20, 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x61, 0x20, 0x64, + 0x69, 0x73, 0x68, 0x20, 0x6F, 0x72, 0x20, 0x6B, 0x65, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x62, 0x65, + 0x65, 0x6E, 0x20, 0x62, 0x72, 0x6F, 0x6B, 0x65, 0x6E, 0x20, + 0x74, 0x6F, 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x73, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x50, 0x6C, 0x65, 0x61, 0x73, + 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x27, 0x68, 0x6F, 0x77, 0x20, 0x61, 0x6D, 0x20, + 0x49, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, 0x69, + 0x6E, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, + 0x62, 0x65, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x73, 0x65, + 0x6E, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x79, 0x6F, 0x75, + 0x72, 0x20, 0x6B, 0x6E, 0x6F, 0x63, 0x6B, 0x69, 0x6E, 0x67, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x6F, + 0x74, 0x6D, 0x61, 0x6E, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, + 0x6F, 0x6E, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, + 0x74, 0x20, 0x61, 0x74, 0x74, 0x65, 0x6E, 0x64, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x2C, 0x20, + 0x27, 0x69, 0x66, 0x20, 0x77, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, + 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6E, 0x20, 0x75, 0x73, + 0x2E, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x69, 0x6E, 0x73, 0x74, + 0x61, 0x6E, 0x63, 0x65, 0x2C, 0x0D, 0x0A, 0x69, 0x66, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x49, + 0x4E, 0x53, 0x49, 0x44, 0x45, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6B, 0x6E, 0x6F, + 0x63, 0x6B, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x20, + 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6C, 0x65, 0x74, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x27, 0x0D, + 0x0A, 0x48, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x75, 0x70, 0x20, 0x69, + 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6B, + 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x69, 0x6D, 0x65, 0x20, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x69, 0x6E, 0x67, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x64, 0x65, 0x63, 0x69, + 0x64, 0x65, 0x64, 0x6C, 0x79, 0x20, 0x75, 0x6E, 0x63, 0x69, + 0x76, 0x69, 0x6C, 0x2E, 0x20, 0x27, 0x42, 0x75, 0x74, 0x20, + 0x70, 0x65, 0x72, 0x68, 0x61, 0x70, 0x73, 0x20, 0x68, 0x65, + 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x68, 0x65, 0x6C, + 0x70, 0x20, 0x69, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, + 0x0D, 0x0A, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x3B, 0x20, 0x27, + 0x68, 0x69, 0x73, 0x20, 0x65, 0x79, 0x65, 0x73, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x73, 0x6F, 0x20, 0x56, 0x45, 0x52, 0x59, + 0x20, 0x6E, 0x65, 0x61, 0x72, 0x6C, 0x79, 0x20, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x70, 0x20, 0x6F, + 0x66, 0x20, 0x68, 0x69, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, + 0x2E, 0x0D, 0x0A, 0x42, 0x75, 0x74, 0x20, 0x61, 0x74, 0x20, + 0x61, 0x6E, 0x79, 0x20, 0x72, 0x61, 0x74, 0x65, 0x20, 0x68, + 0x65, 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x61, 0x6E, + 0x73, 0x77, 0x65, 0x72, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x2D, 0x2D, 0x48, 0x6F, 0x77, + 0x20, 0x61, 0x6D, 0x20, 0x49, 0x20, 0x74, 0x6F, 0x20, 0x67, + 0x65, 0x74, 0x20, 0x69, 0x6E, 0x3F, 0x27, 0x20, 0x73, 0x68, + 0x65, 0x0D, 0x0A, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x2C, 0x20, 0x61, 0x6C, 0x6F, 0x75, 0x64, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x73, 0x68, 0x61, 0x6C, + 0x6C, 0x20, 0x73, 0x69, 0x74, 0x20, 0x68, 0x65, 0x72, 0x65, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x6F, + 0x74, 0x6D, 0x61, 0x6E, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x72, + 0x6B, 0x65, 0x64, 0x2C, 0x20, 0x27, 0x74, 0x69, 0x6C, 0x6C, + 0x20, 0x74, 0x6F, 0x6D, 0x6F, 0x72, 0x72, 0x6F, 0x77, 0x2D, + 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x74, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6F, 0x75, + 0x73, 0x65, 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x65, 0x64, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x20, 0x6C, 0x61, 0x72, + 0x67, 0x65, 0x20, 0x70, 0x6C, 0x61, 0x74, 0x65, 0x20, 0x63, + 0x61, 0x6D, 0x65, 0x0D, 0x0A, 0x73, 0x6B, 0x69, 0x6D, 0x6D, + 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x73, + 0x74, 0x72, 0x61, 0x69, 0x67, 0x68, 0x74, 0x20, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x6F, 0x74, 0x6D, + 0x61, 0x6E, 0x27, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, 0x3A, + 0x20, 0x69, 0x74, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x67, + 0x72, 0x61, 0x7A, 0x65, 0x64, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x6E, 0x6F, 0x73, 0x65, 0x2C, 0x0D, 0x0A, 0x61, 0x6E, 0x64, + 0x20, 0x62, 0x72, 0x6F, 0x6B, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x70, 0x69, 0x65, 0x63, 0x65, 0x73, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x73, 0x74, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x65, 0x65, + 0x73, 0x20, 0x62, 0x65, 0x68, 0x69, 0x6E, 0x64, 0x20, 0x68, + 0x69, 0x6D, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x2D, 0x2D, + 0x6F, 0x72, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x64, 0x61, + 0x79, 0x2C, 0x20, 0x6D, 0x61, 0x79, 0x62, 0x65, 0x2C, 0x27, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x6F, 0x74, 0x6D, + 0x61, 0x6E, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, + 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x61, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2C, + 0x20, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6C, 0x79, 0x0D, 0x0A, + 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x6E, 0x6F, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x68, 0x61, 0x64, 0x20, 0x68, 0x61, + 0x70, 0x70, 0x65, 0x6E, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x48, 0x6F, 0x77, 0x20, 0x61, 0x6D, 0x20, 0x49, + 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, 0x69, 0x6E, + 0x3F, 0x27, 0x20, 0x61, 0x73, 0x6B, 0x65, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, + 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x75, + 0x64, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x52, 0x45, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x3F, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x46, 0x6F, 0x6F, 0x74, 0x6D, 0x61, 0x6E, 0x2E, 0x20, 0x27, + 0x54, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x0D, 0x0A, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x2C, 0x20, + 0x6E, 0x6F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x74, 0x3A, 0x20, + 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, + 0x74, 0x6F, 0x6C, 0x64, 0x20, 0x73, 0x6F, 0x2E, 0x20, 0x27, + 0x49, 0x74, 0x27, 0x73, 0x20, 0x72, 0x65, 0x61, 0x6C, 0x6C, + 0x79, 0x0D, 0x0A, 0x64, 0x72, 0x65, 0x61, 0x64, 0x66, 0x75, + 0x6C, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6D, 0x75, + 0x74, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x61, 0x72, 0x67, 0x75, + 0x65, 0x2E, 0x0D, 0x0A, 0x49, 0x74, 0x27, 0x73, 0x20, 0x65, + 0x6E, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x74, 0x6F, 0x20, 0x64, + 0x72, 0x69, 0x76, 0x65, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x63, + 0x72, 0x61, 0x7A, 0x79, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x54, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x6F, 0x74, 0x6D, 0x61, + 0x6E, 0x20, 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, + 0x6F, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x69, 0x74, + 0x79, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x72, 0x65, 0x70, 0x65, + 0x61, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x69, 0x73, 0x0D, + 0x0A, 0x72, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x2C, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x20, 0x27, 0x49, 0x20, 0x73, + 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x69, 0x74, 0x20, 0x68, + 0x65, 0x72, 0x65, 0x2C, 0x27, 0x20, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x2C, 0x20, 0x27, 0x6F, 0x6E, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x2C, 0x20, 0x66, 0x6F, + 0x72, 0x0D, 0x0A, 0x64, 0x61, 0x79, 0x73, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x64, 0x61, 0x79, 0x73, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x42, 0x75, 0x74, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x61, 0x6D, 0x20, 0x49, 0x20, 0x74, 0x6F, 0x20, + 0x64, 0x6F, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x41, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x46, 0x6F, 0x6F, 0x74, 0x6D, 0x61, 0x6E, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x77, + 0x68, 0x69, 0x73, 0x74, 0x6C, 0x69, 0x6E, 0x67, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x74, 0x68, + 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x61, 0x6C, 0x6B, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x69, 0x6D, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x64, 0x65, 0x73, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x65, 0x6C, 0x79, 0x3A, 0x20, 0x27, 0x68, 0x65, + 0x27, 0x73, 0x0D, 0x0A, 0x70, 0x65, 0x72, 0x66, 0x65, 0x63, + 0x74, 0x6C, 0x79, 0x20, 0x69, 0x64, 0x69, 0x6F, 0x74, 0x69, + 0x63, 0x21, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x69, 0x6E, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x64, 0x6F, + 0x6F, 0x72, 0x20, 0x6C, 0x65, 0x64, 0x20, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x61, 0x20, + 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x6B, 0x69, 0x74, 0x63, + 0x68, 0x65, 0x6E, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x20, + 0x6F, 0x66, 0x20, 0x73, 0x6D, 0x6F, 0x6B, 0x65, 0x20, 0x66, + 0x72, 0x6F, 0x6D, 0x0D, 0x0A, 0x6F, 0x6E, 0x65, 0x20, 0x65, + 0x6E, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6F, 0x74, 0x68, 0x65, 0x72, 0x3A, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x6E, 0x20, 0x61, 0x20, 0x74, 0x68, 0x72, 0x65, + 0x65, 0x2D, 0x6C, 0x65, 0x67, 0x67, 0x65, 0x64, 0x20, 0x73, + 0x74, 0x6F, 0x6F, 0x6C, 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x6D, 0x69, 0x64, 0x64, 0x6C, 0x65, 0x2C, + 0x20, 0x6E, 0x75, 0x72, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x20, 0x62, 0x61, 0x62, 0x79, 0x3B, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6F, 0x6F, 0x6B, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x6C, 0x65, 0x61, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x76, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, + 0x65, 0x2C, 0x20, 0x73, 0x74, 0x69, 0x72, 0x72, 0x69, 0x6E, + 0x67, 0x0D, 0x0A, 0x61, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x20, 0x63, 0x61, 0x75, 0x6C, 0x64, 0x72, 0x6F, 0x6E, 0x20, + 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x73, 0x65, 0x65, 0x6D, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x66, + 0x75, 0x6C, 0x6C, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x6F, 0x75, + 0x70, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, + 0x72, 0x65, 0x27, 0x73, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, + 0x69, 0x6E, 0x6C, 0x79, 0x20, 0x74, 0x6F, 0x6F, 0x20, 0x6D, + 0x75, 0x63, 0x68, 0x20, 0x70, 0x65, 0x70, 0x70, 0x65, 0x72, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, + 0x6F, 0x75, 0x70, 0x21, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x0D, 0x0A, + 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x6E, 0x65, 0x65, 0x7A, + 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x65, + 0x72, 0x74, 0x61, 0x69, 0x6E, 0x6C, 0x79, 0x20, 0x74, 0x6F, + 0x6F, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x6F, 0x66, 0x20, + 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x61, 0x69, 0x72, 0x2E, 0x20, 0x45, 0x76, 0x65, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, + 0x73, 0x0D, 0x0A, 0x73, 0x6E, 0x65, 0x65, 0x7A, 0x65, 0x64, + 0x20, 0x6F, 0x63, 0x63, 0x61, 0x73, 0x69, 0x6F, 0x6E, 0x61, + 0x6C, 0x6C, 0x79, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x61, 0x62, 0x79, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x73, 0x6E, 0x65, 0x65, 0x7A, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x6F, 0x77, 0x6C, + 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x61, 0x6C, 0x74, 0x65, 0x72, + 0x6E, 0x61, 0x74, 0x65, 0x6C, 0x79, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x20, 0x6D, 0x6F, 0x6D, + 0x65, 0x6E, 0x74, 0x27, 0x73, 0x20, 0x70, 0x61, 0x75, 0x73, + 0x65, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6F, 0x6E, 0x6C, + 0x79, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6B, 0x69, 0x74, 0x63, + 0x68, 0x65, 0x6E, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x73, 0x6E, + 0x65, 0x65, 0x7A, 0x65, 0x2C, 0x20, 0x77, 0x65, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6F, 0x6B, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x20, 0x6C, 0x61, 0x72, + 0x67, 0x65, 0x20, 0x63, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, + 0x63, 0x68, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x72, 0x74, 0x68, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x67, 0x72, 0x69, 0x6E, 0x6E, 0x69, + 0x6E, 0x67, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x65, 0x61, + 0x72, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x61, 0x72, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x50, 0x6C, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x6D, 0x65, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2C, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x74, 0x69, 0x6D, 0x69, 0x64, 0x6C, 0x79, 0x2C, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x0D, 0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x71, 0x75, + 0x69, 0x74, 0x65, 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x77, + 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x74, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x6D, + 0x61, 0x6E, 0x6E, 0x65, 0x72, 0x73, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x70, + 0x65, 0x61, 0x6B, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2C, + 0x20, 0x27, 0x77, 0x68, 0x79, 0x0D, 0x0A, 0x79, 0x6F, 0x75, + 0x72, 0x20, 0x63, 0x61, 0x74, 0x20, 0x67, 0x72, 0x69, 0x6E, + 0x73, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, + 0x27, 0x73, 0x20, 0x61, 0x20, 0x43, 0x68, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x20, 0x63, 0x61, 0x74, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, + 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x2C, 0x20, 0x27, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, + 0x77, 0x68, 0x79, 0x2E, 0x20, 0x50, 0x69, 0x67, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x68, 0x65, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, + 0x74, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x73, 0x75, 0x64, + 0x64, 0x65, 0x6E, 0x20, 0x76, 0x69, 0x6F, 0x6C, 0x65, 0x6E, + 0x63, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x0D, + 0x0A, 0x6A, 0x75, 0x6D, 0x70, 0x65, 0x64, 0x3B, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x77, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, + 0x62, 0x79, 0x2C, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x2C, + 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x6F, + 0x6F, 0x6B, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x61, 0x67, 0x65, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x65, 0x6E, 0x74, + 0x20, 0x6F, 0x6E, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x3A, + 0x2D, 0x2D, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, + 0x69, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x43, 0x68, 0x65, 0x73, + 0x68, 0x69, 0x72, 0x65, 0x20, 0x63, 0x61, 0x74, 0x73, 0x20, + 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x67, 0x72, 0x69, + 0x6E, 0x6E, 0x65, 0x64, 0x3B, 0x20, 0x69, 0x6E, 0x20, 0x66, + 0x61, 0x63, 0x74, 0x2C, 0x20, 0x49, 0x20, 0x64, 0x69, 0x64, + 0x6E, 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x0D, 0x0A, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x74, 0x73, 0x20, + 0x43, 0x4F, 0x55, 0x4C, 0x44, 0x20, 0x67, 0x72, 0x69, 0x6E, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, + 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x61, 0x6E, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x3B, 0x20, + 0x27, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x6F, 0x73, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x27, 0x65, 0x6D, 0x20, 0x64, 0x6F, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, 0x6F, + 0x6E, 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x6F, + 0x66, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x64, 0x6F, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x70, 0x6F, 0x6C, 0x69, 0x74, 0x65, 0x6C, 0x79, + 0x2C, 0x20, 0x66, 0x65, 0x65, 0x6C, 0x69, 0x6E, 0x67, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x0D, 0x0A, 0x70, 0x6C, 0x65, + 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x69, 0x6E, 0x74, + 0x6F, 0x20, 0x61, 0x20, 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x72, + 0x73, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x64, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, + 0x3B, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x27, 0x73, 0x20, 0x61, 0x20, 0x66, 0x61, 0x63, 0x74, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x6E, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, + 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x69, + 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x0D, 0x0A, 0x62, + 0x65, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, + 0x74, 0x6F, 0x20, 0x69, 0x6E, 0x74, 0x72, 0x6F, 0x64, 0x75, + 0x63, 0x65, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x73, 0x75, 0x62, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x6E, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x20, 0x57, + 0x68, 0x69, 0x6C, 0x65, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, + 0x77, 0x61, 0x73, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x78, 0x20, 0x6F, 0x6E, + 0x20, 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6F, 0x6F, 0x6B, 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x75, 0x6C, 0x64, 0x72, + 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x6F, 0x75, 0x70, + 0x20, 0x6F, 0x66, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x66, 0x69, 0x72, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x73, 0x65, + 0x74, 0x20, 0x74, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, + 0x74, 0x68, 0x72, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x20, 0x65, + 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x69, 0x6E, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x72, 0x65, 0x61, 0x63, 0x68, 0x20, 0x61, 0x74, 0x0D, + 0x0A, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, + 0x73, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x61, 0x62, 0x79, 0x2D, 0x2D, 0x74, 0x68, 0x65, + 0x20, 0x66, 0x69, 0x72, 0x65, 0x2D, 0x69, 0x72, 0x6F, 0x6E, + 0x73, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x66, 0x69, 0x72, + 0x73, 0x74, 0x3B, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x66, + 0x6F, 0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, 0x20, 0x61, 0x0D, + 0x0A, 0x73, 0x68, 0x6F, 0x77, 0x65, 0x72, 0x20, 0x6F, 0x66, + 0x20, 0x73, 0x61, 0x75, 0x63, 0x65, 0x70, 0x61, 0x6E, 0x73, + 0x2C, 0x20, 0x70, 0x6C, 0x61, 0x74, 0x65, 0x73, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x64, 0x69, 0x73, 0x68, 0x65, 0x73, + 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, + 0x65, 0x73, 0x73, 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x6E, + 0x6F, 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x20, 0x6F, + 0x66, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x65, 0x76, + 0x65, 0x6E, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x68, 0x69, 0x74, 0x20, 0x68, 0x65, 0x72, + 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x61, 0x62, 0x79, 0x20, 0x77, 0x61, 0x73, 0x20, 0x68, + 0x6F, 0x77, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x6F, 0x20, + 0x6D, 0x75, 0x63, 0x68, 0x20, 0x61, 0x6C, 0x72, 0x65, 0x61, + 0x64, 0x79, 0x2C, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x71, 0x75, 0x69, + 0x74, 0x65, 0x20, 0x69, 0x6D, 0x70, 0x6F, 0x73, 0x73, 0x69, + 0x62, 0x6C, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, + 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x6C, 0x6F, 0x77, 0x73, 0x20, 0x68, + 0x75, 0x72, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6F, 0x72, 0x20, + 0x6E, 0x6F, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, + 0x68, 0x2C, 0x20, 0x50, 0x4C, 0x45, 0x41, 0x53, 0x45, 0x20, + 0x6D, 0x69, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, + 0x79, 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x64, 0x6F, 0x69, + 0x6E, 0x67, 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x6A, 0x75, + 0x6D, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x75, 0x70, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x69, 0x6E, + 0x0D, 0x0A, 0x61, 0x6E, 0x20, 0x61, 0x67, 0x6F, 0x6E, 0x79, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x65, 0x72, 0x72, 0x6F, 0x72, + 0x2E, 0x20, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x67, 0x6F, 0x65, 0x73, 0x20, 0x68, 0x69, + 0x73, 0x20, 0x50, 0x52, 0x45, 0x43, 0x49, 0x4F, 0x55, 0x53, + 0x20, 0x6E, 0x6F, 0x73, 0x65, 0x27, 0x3B, 0x20, 0x61, 0x73, + 0x20, 0x61, 0x6E, 0x20, 0x75, 0x6E, 0x75, 0x73, 0x75, 0x61, + 0x6C, 0x6C, 0x79, 0x0D, 0x0A, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x20, 0x73, 0x61, 0x75, 0x63, 0x65, 0x70, 0x61, 0x6E, 0x20, + 0x66, 0x6C, 0x65, 0x77, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, + 0x20, 0x62, 0x79, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6E, 0x65, 0x61, + 0x72, 0x6C, 0x79, 0x20, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, + 0x64, 0x20, 0x69, 0x74, 0x20, 0x6F, 0x66, 0x66, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x66, 0x20, 0x65, 0x76, 0x65, + 0x72, 0x79, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x6D, 0x69, 0x6E, + 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, + 0x6F, 0x77, 0x6E, 0x20, 0x62, 0x75, 0x73, 0x69, 0x6E, 0x65, + 0x73, 0x73, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, + 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x68, 0x6F, 0x61, + 0x72, 0x73, 0x65, 0x0D, 0x0A, 0x67, 0x72, 0x6F, 0x77, 0x6C, + 0x2C, 0x20, 0x27, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x6C, 0x64, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x67, + 0x6F, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x61, 0x20, + 0x64, 0x65, 0x61, 0x6C, 0x20, 0x66, 0x61, 0x73, 0x74, 0x65, + 0x72, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x69, 0x74, 0x20, + 0x64, 0x6F, 0x65, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x57, 0x68, 0x69, 0x63, 0x68, 0x20, 0x77, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x4E, 0x4F, 0x54, 0x20, 0x62, 0x65, 0x20, + 0x61, 0x6E, 0x20, 0x61, 0x64, 0x76, 0x61, 0x6E, 0x74, 0x61, + 0x67, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x77, 0x68, 0x6F, + 0x20, 0x66, 0x65, 0x6C, 0x74, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x67, 0x6C, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x67, + 0x65, 0x74, 0x0D, 0x0A, 0x61, 0x6E, 0x20, 0x6F, 0x70, 0x70, + 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x69, 0x74, 0x79, 0x20, 0x6F, + 0x66, 0x20, 0x73, 0x68, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x20, + 0x6F, 0x66, 0x66, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x2E, + 0x20, 0x27, 0x4A, 0x75, 0x73, 0x74, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x6B, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x69, 0x74, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6D, 0x61, 0x6B, 0x65, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x64, 0x61, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6E, 0x69, + 0x67, 0x68, 0x74, 0x21, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x73, + 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x61, 0x72, + 0x74, 0x68, 0x20, 0x74, 0x61, 0x6B, 0x65, 0x73, 0x0D, 0x0A, + 0x74, 0x77, 0x65, 0x6E, 0x74, 0x79, 0x2D, 0x66, 0x6F, 0x75, + 0x72, 0x20, 0x68, 0x6F, 0x75, 0x72, 0x73, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x72, 0x6F, 0x75, 0x6E, + 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x69, 0x74, 0x73, 0x20, 0x61, + 0x78, 0x69, 0x73, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x54, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x66, 0x20, 0x61, 0x78, 0x65, 0x73, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, + 0x63, 0x68, 0x65, 0x73, 0x73, 0x2C, 0x20, 0x27, 0x63, 0x68, + 0x6F, 0x70, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x68, 0x65, 0x61, 0x64, 0x21, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x67, 0x6C, 0x61, + 0x6E, 0x63, 0x65, 0x64, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x61, 0x6E, 0x78, 0x69, 0x6F, 0x75, 0x73, 0x6C, + 0x79, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6F, 0x6F, 0x6B, 0x2C, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, + 0x65, 0x20, 0x69, 0x66, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6D, + 0x65, 0x61, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x61, + 0x6B, 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x68, 0x69, + 0x6E, 0x74, 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x6F, 0x6F, 0x6B, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x62, 0x75, 0x73, 0x69, 0x6C, 0x79, 0x20, 0x73, 0x74, + 0x69, 0x72, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x6F, 0x75, 0x70, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x62, 0x65, 0x20, 0x6C, + 0x69, 0x73, 0x74, 0x65, 0x6E, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, + 0x3A, 0x20, 0x27, 0x54, 0x77, 0x65, 0x6E, 0x74, 0x79, 0x2D, + 0x66, 0x6F, 0x75, 0x72, 0x20, 0x68, 0x6F, 0x75, 0x72, 0x73, + 0x2C, 0x20, 0x49, 0x20, 0x54, 0x48, 0x49, 0x4E, 0x4B, 0x3B, + 0x20, 0x6F, 0x72, 0x20, 0x69, 0x73, 0x0D, 0x0A, 0x69, 0x74, + 0x20, 0x74, 0x77, 0x65, 0x6C, 0x76, 0x65, 0x3F, 0x20, 0x49, + 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, + 0x2C, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x6F, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x4D, 0x45, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, + 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x3B, 0x20, 0x27, 0x49, + 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x63, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x61, 0x62, 0x69, 0x64, 0x65, 0x20, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x65, 0x73, 0x21, 0x27, 0x0D, 0x0A, + 0x41, 0x6E, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x62, 0x65, + 0x67, 0x61, 0x6E, 0x20, 0x6E, 0x75, 0x72, 0x73, 0x69, 0x6E, + 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, 0x63, 0x68, 0x69, 0x6C, + 0x64, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x73, + 0x69, 0x6E, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x20, 0x73, + 0x6F, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x6C, 0x75, + 0x6C, 0x6C, 0x61, 0x62, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x69, + 0x74, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x64, + 0x69, 0x64, 0x20, 0x73, 0x6F, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x67, 0x69, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, + 0x20, 0x61, 0x20, 0x76, 0x69, 0x6F, 0x6C, 0x65, 0x6E, 0x74, + 0x20, 0x73, 0x68, 0x61, 0x6B, 0x65, 0x20, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x65, 0x6E, 0x64, 0x20, 0x6F, 0x66, + 0x0D, 0x0A, 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6C, 0x69, + 0x6E, 0x65, 0x3A, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x27, 0x53, 0x70, 0x65, 0x61, 0x6B, 0x20, 0x72, 0x6F, 0x75, + 0x67, 0x68, 0x6C, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x79, 0x6F, + 0x75, 0x72, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, + 0x62, 0x6F, 0x79, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x41, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x61, 0x74, 0x20, 0x68, + 0x69, 0x6D, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x68, 0x65, + 0x20, 0x73, 0x6E, 0x65, 0x65, 0x7A, 0x65, 0x73, 0x3A, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x48, 0x65, 0x20, 0x6F, 0x6E, 0x6C, + 0x79, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x69, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x61, 0x6E, 0x6E, 0x6F, 0x79, 0x2C, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x42, 0x65, 0x63, 0x61, 0x75, + 0x73, 0x65, 0x20, 0x68, 0x65, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x73, 0x20, 0x69, 0x74, 0x20, 0x74, 0x65, 0x61, 0x73, 0x65, + 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x48, 0x4F, 0x52, + 0x55, 0x53, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x28, 0x49, + 0x6E, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x6F, 0x6F, 0x6B, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x62, 0x79, 0x20, + 0x6A, 0x6F, 0x69, 0x6E, 0x65, 0x64, 0x29, 0x3A, 0x2D, 0x2D, + 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x27, 0x57, 0x6F, 0x77, 0x21, 0x20, 0x77, 0x6F, 0x77, + 0x21, 0x20, 0x77, 0x6F, 0x77, 0x21, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x57, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x20, 0x73, + 0x61, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, + 0x63, 0x6F, 0x6E, 0x64, 0x20, 0x76, 0x65, 0x72, 0x73, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6F, + 0x6E, 0x67, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6B, 0x65, + 0x70, 0x74, 0x20, 0x74, 0x6F, 0x73, 0x73, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x62, 0x79, + 0x20, 0x76, 0x69, 0x6F, 0x6C, 0x65, 0x6E, 0x74, 0x6C, 0x79, + 0x20, 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x6F, + 0x77, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x68, 0x6F, 0x77, 0x6C, 0x65, 0x64, 0x20, 0x73, 0x6F, 0x2C, + 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, + 0x61, 0x72, 0x64, 0x6C, 0x79, 0x20, 0x68, 0x65, 0x61, 0x72, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, + 0x3A, 0x2D, 0x2D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x27, 0x49, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x20, 0x73, + 0x65, 0x76, 0x65, 0x72, 0x65, 0x6C, 0x79, 0x20, 0x74, 0x6F, + 0x20, 0x6D, 0x79, 0x20, 0x62, 0x6F, 0x79, 0x2C, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x49, 0x20, 0x62, 0x65, 0x61, 0x74, + 0x20, 0x68, 0x69, 0x6D, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, + 0x68, 0x65, 0x20, 0x73, 0x6E, 0x65, 0x65, 0x7A, 0x65, 0x73, + 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x46, 0x6F, 0x72, 0x20, + 0x68, 0x65, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x74, 0x68, 0x6F, + 0x72, 0x6F, 0x75, 0x67, 0x68, 0x6C, 0x79, 0x20, 0x65, 0x6E, + 0x6A, 0x6F, 0x79, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x54, + 0x68, 0x65, 0x20, 0x70, 0x65, 0x70, 0x70, 0x65, 0x72, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x68, 0x65, 0x20, 0x70, 0x6C, + 0x65, 0x61, 0x73, 0x65, 0x73, 0x21, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x43, 0x48, 0x4F, 0x52, 0x55, 0x53, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x57, + 0x6F, 0x77, 0x21, 0x20, 0x77, 0x6F, 0x77, 0x21, 0x20, 0x77, + 0x6F, 0x77, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, + 0x65, 0x72, 0x65, 0x21, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, + 0x61, 0x79, 0x20, 0x6E, 0x75, 0x72, 0x73, 0x65, 0x20, 0x69, + 0x74, 0x20, 0x61, 0x20, 0x62, 0x69, 0x74, 0x2C, 0x20, 0x69, + 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6C, 0x69, 0x6B, 0x65, + 0x21, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, + 0x68, 0x65, 0x73, 0x73, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x0D, + 0x0A, 0x66, 0x6C, 0x69, 0x6E, 0x67, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x62, 0x79, 0x20, 0x61, + 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, 0x73, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6B, 0x65, 0x2E, 0x20, + 0x27, 0x49, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x67, 0x6F, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x67, 0x65, 0x74, 0x20, 0x72, + 0x65, 0x61, 0x64, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x70, 0x6C, + 0x61, 0x79, 0x0D, 0x0A, 0x63, 0x72, 0x6F, 0x71, 0x75, 0x65, + 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x27, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x75, 0x72, + 0x72, 0x69, 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, 0x6F, 0x6D, + 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6F, 0x6B, + 0x20, 0x74, 0x68, 0x72, 0x65, 0x77, 0x0D, 0x0A, 0x61, 0x20, + 0x66, 0x72, 0x79, 0x69, 0x6E, 0x67, 0x2D, 0x70, 0x61, 0x6E, + 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x20, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x62, 0x75, + 0x74, 0x20, 0x69, 0x74, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, + 0x6D, 0x69, 0x73, 0x73, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x63, 0x61, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x61, 0x62, 0x79, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x64, 0x69, 0x66, + 0x66, 0x69, 0x63, 0x75, 0x6C, 0x74, 0x79, 0x2C, 0x20, 0x61, + 0x73, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, + 0x20, 0x71, 0x75, 0x65, 0x65, 0x72, 0x2D, 0x73, 0x68, 0x61, + 0x70, 0x65, 0x64, 0x0D, 0x0A, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x6C, 0x64, + 0x20, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, 0x73, 0x20, 0x61, + 0x72, 0x6D, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x65, + 0x67, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, + 0x2C, 0x20, 0x27, 0x6A, 0x75, 0x73, 0x74, 0x0D, 0x0A, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x61, 0x20, 0x73, 0x74, 0x61, 0x72, + 0x2D, 0x66, 0x69, 0x73, 0x68, 0x2C, 0x27, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x70, 0x6F, 0x6F, + 0x72, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, + 0x6E, 0x6F, 0x72, 0x74, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x61, 0x20, 0x73, 0x74, 0x65, 0x61, + 0x6D, 0x2D, 0x65, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x77, + 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x61, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6B, 0x65, 0x70, 0x74, 0x20, 0x64, 0x6F, + 0x75, 0x62, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x73, + 0x65, 0x6C, 0x66, 0x20, 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, + 0x0D, 0x0A, 0x73, 0x74, 0x72, 0x61, 0x69, 0x67, 0x68, 0x74, + 0x65, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x73, 0x65, + 0x6C, 0x66, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x61, 0x6C, 0x74, 0x6F, 0x67, 0x65, 0x74, 0x68, + 0x65, 0x72, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x6D, 0x69, + 0x6E, 0x75, 0x74, 0x65, 0x0D, 0x0A, 0x6F, 0x72, 0x20, 0x74, + 0x77, 0x6F, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x61, 0x73, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x61, + 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x64, 0x6F, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x6F, + 0x6C, 0x64, 0x20, 0x69, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x41, 0x73, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6D, + 0x61, 0x64, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x20, 0x77, + 0x61, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x6E, 0x75, 0x72, 0x73, + 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x28, 0x77, + 0x68, 0x69, 0x63, 0x68, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, + 0x6F, 0x0D, 0x0A, 0x74, 0x77, 0x69, 0x73, 0x74, 0x20, 0x69, + 0x74, 0x20, 0x75, 0x70, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, + 0x61, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x6B, 0x6E, 0x6F, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x20, 0x6B, 0x65, 0x65, 0x70, 0x20, + 0x74, 0x69, 0x67, 0x68, 0x74, 0x20, 0x68, 0x6F, 0x6C, 0x64, + 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x73, 0x20, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x0D, 0x0A, 0x65, 0x61, 0x72, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x66, 0x6F, + 0x6F, 0x74, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x61, 0x73, 0x20, + 0x74, 0x6F, 0x20, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6E, 0x74, + 0x20, 0x69, 0x74, 0x73, 0x20, 0x75, 0x6E, 0x64, 0x6F, 0x69, + 0x6E, 0x67, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6C, 0x66, 0x2C, + 0x29, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x61, 0x72, 0x72, + 0x69, 0x65, 0x64, 0x0D, 0x0A, 0x69, 0x74, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x20, 0x61, 0x69, 0x72, 0x2E, + 0x20, 0x27, 0x49, 0x46, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x6E, + 0x27, 0x74, 0x20, 0x74, 0x61, 0x6B, 0x65, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x20, 0x61, + 0x77, 0x61, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6D, + 0x65, 0x2C, 0x27, 0x0D, 0x0A, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x27, 0x74, 0x68, 0x65, 0x79, 0x27, 0x72, 0x65, 0x20, 0x73, + 0x75, 0x72, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x6B, 0x69, 0x6C, + 0x6C, 0x20, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, + 0x64, 0x61, 0x79, 0x20, 0x6F, 0x72, 0x20, 0x74, 0x77, 0x6F, + 0x3A, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, + 0x20, 0x69, 0x74, 0x20, 0x62, 0x65, 0x0D, 0x0A, 0x6D, 0x75, + 0x72, 0x64, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x65, + 0x61, 0x76, 0x65, 0x20, 0x69, 0x74, 0x20, 0x62, 0x65, 0x68, + 0x69, 0x6E, 0x64, 0x3F, 0x27, 0x20, 0x53, 0x68, 0x65, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, + 0x61, 0x73, 0x74, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x6C, 0x6F, 0x75, 0x64, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x6C, + 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x67, 0x72, 0x75, 0x6E, 0x74, 0x65, 0x64, 0x20, + 0x69, 0x6E, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x79, 0x20, 0x28, + 0x69, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6C, 0x65, 0x66, + 0x74, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x73, 0x6E, 0x65, 0x65, + 0x7A, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x29, 0x2E, 0x0D, + 0x0A, 0x27, 0x44, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x67, 0x72, + 0x75, 0x6E, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x3B, 0x20, 0x27, 0x74, + 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x20, 0x70, + 0x72, 0x6F, 0x70, 0x65, 0x72, 0x20, 0x77, 0x61, 0x79, 0x20, + 0x6F, 0x66, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x68, 0x65, 0x20, 0x62, 0x61, 0x62, 0x79, 0x20, 0x67, 0x72, + 0x75, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x61, 0x6E, 0x78, 0x69, 0x6F, + 0x75, 0x73, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, + 0x69, 0x74, 0x73, 0x20, 0x66, 0x61, 0x63, 0x65, 0x20, 0x74, + 0x6F, 0x0D, 0x0A, 0x73, 0x65, 0x65, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6D, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x69, 0x74, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, + 0x20, 0x6E, 0x6F, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x74, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, + 0x64, 0x0D, 0x0A, 0x61, 0x20, 0x56, 0x45, 0x52, 0x59, 0x20, + 0x74, 0x75, 0x72, 0x6E, 0x2D, 0x75, 0x70, 0x20, 0x6E, 0x6F, + 0x73, 0x65, 0x2C, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x6D, + 0x6F, 0x72, 0x65, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x61, + 0x20, 0x73, 0x6E, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x61, + 0x6E, 0x20, 0x61, 0x20, 0x72, 0x65, 0x61, 0x6C, 0x20, 0x6E, + 0x6F, 0x73, 0x65, 0x3B, 0x20, 0x61, 0x6C, 0x73, 0x6F, 0x20, + 0x69, 0x74, 0x73, 0x0D, 0x0A, 0x65, 0x79, 0x65, 0x73, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x65, 0x78, 0x74, 0x72, 0x65, 0x6D, 0x65, + 0x6C, 0x79, 0x20, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x61, 0x20, 0x62, 0x61, 0x62, 0x79, 0x3A, + 0x20, 0x61, 0x6C, 0x74, 0x6F, 0x67, 0x65, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x64, 0x69, + 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x0D, 0x0A, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, + 0x2E, 0x20, 0x27, 0x42, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, + 0x68, 0x61, 0x70, 0x73, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x73, 0x6F, 0x62, + 0x62, 0x69, 0x6E, 0x67, 0x2C, 0x27, 0x0D, 0x0A, 0x73, 0x68, + 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, + 0x64, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x73, + 0x20, 0x65, 0x79, 0x65, 0x73, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6E, 0x2C, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, 0x20, + 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x61, 0x6E, 0x79, 0x0D, 0x0A, 0x74, + 0x65, 0x61, 0x72, 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x4E, + 0x6F, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x6E, 0x6F, 0x20, 0x74, 0x65, 0x61, + 0x72, 0x73, 0x2E, 0x20, 0x27, 0x49, 0x66, 0x20, 0x79, 0x6F, + 0x75, 0x27, 0x72, 0x65, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x69, + 0x6E, 0x74, 0x6F, 0x20, 0x61, 0x20, 0x70, 0x69, 0x67, 0x2C, + 0x20, 0x6D, 0x79, 0x20, 0x64, 0x65, 0x61, 0x72, 0x2C, 0x27, + 0x0D, 0x0A, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2C, 0x20, 0x73, 0x65, 0x72, 0x69, 0x6F, 0x75, + 0x73, 0x6C, 0x79, 0x2C, 0x20, 0x27, 0x49, 0x27, 0x6C, 0x6C, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x64, 0x6F, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x79, 0x6F, 0x75, 0x2E, 0x20, 0x4D, 0x69, 0x6E, 0x64, 0x0D, + 0x0A, 0x6E, 0x6F, 0x77, 0x21, 0x27, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x73, + 0x6F, 0x62, 0x62, 0x65, 0x64, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6E, 0x20, 0x28, 0x6F, 0x72, 0x20, 0x67, 0x72, 0x75, 0x6E, + 0x74, 0x65, 0x64, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x69, 0x6D, 0x70, 0x6F, 0x73, 0x73, 0x69, 0x62, + 0x6C, 0x65, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x29, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x73, 0x69, 0x6C, 0x65, 0x6E, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6A, 0x75, 0x73, 0x74, + 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, + 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, + 0x2C, 0x20, 0x27, 0x4E, 0x6F, 0x77, 0x2C, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x61, 0x6D, 0x20, 0x49, 0x20, 0x74, 0x6F, + 0x20, 0x64, 0x6F, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x49, + 0x20, 0x67, 0x65, 0x74, 0x20, 0x69, 0x74, 0x20, 0x68, 0x6F, + 0x6D, 0x65, 0x3F, 0x27, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, + 0x69, 0x74, 0x20, 0x67, 0x72, 0x75, 0x6E, 0x74, 0x65, 0x64, + 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x73, 0x6F, + 0x20, 0x76, 0x69, 0x6F, 0x6C, 0x65, 0x6E, 0x74, 0x6C, 0x79, + 0x2C, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x69, + 0x74, 0x73, 0x20, 0x66, 0x61, 0x63, 0x65, 0x20, 0x69, 0x6E, + 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x61, 0x6C, 0x61, 0x72, + 0x6D, 0x2E, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x69, + 0x6D, 0x65, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x63, + 0x6F, 0x75, 0x6C, 0x64, 0x0D, 0x0A, 0x62, 0x65, 0x20, 0x4E, + 0x4F, 0x20, 0x6D, 0x69, 0x73, 0x74, 0x61, 0x6B, 0x65, 0x20, + 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, 0x3A, 0x20, + 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x65, 0x69, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, + 0x6E, 0x6F, 0x72, 0x20, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x74, + 0x68, 0x61, 0x6E, 0x20, 0x61, 0x20, 0x70, 0x69, 0x67, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, + 0x66, 0x65, 0x6C, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x69, 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, + 0x65, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x61, 0x62, + 0x73, 0x75, 0x72, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x61, 0x72, 0x72, + 0x79, 0x20, 0x69, 0x74, 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, + 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x6F, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x64, 0x6F, + 0x77, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x65, + 0x6C, 0x74, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x72, + 0x65, 0x6C, 0x69, 0x65, 0x76, 0x65, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x73, 0x65, 0x65, 0x0D, 0x0A, 0x69, 0x74, 0x20, 0x74, + 0x72, 0x6F, 0x74, 0x20, 0x61, 0x77, 0x61, 0x79, 0x20, 0x71, + 0x75, 0x69, 0x65, 0x74, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x6F, 0x64, + 0x2E, 0x20, 0x27, 0x49, 0x66, 0x20, 0x69, 0x74, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x6E, 0x20, 0x75, + 0x70, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, 0x69, 0x74, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, 0x61, 0x20, 0x64, 0x72, + 0x65, 0x61, 0x64, 0x66, 0x75, 0x6C, 0x6C, 0x79, 0x20, 0x75, + 0x67, 0x6C, 0x79, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x3A, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6D, 0x61, + 0x6B, 0x65, 0x73, 0x0D, 0x0A, 0x72, 0x61, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x61, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x73, 0x6F, + 0x6D, 0x65, 0x20, 0x70, 0x69, 0x67, 0x2C, 0x20, 0x49, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x2E, 0x27, 0x20, 0x41, 0x6E, + 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, + 0x6E, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x6F, 0x74, 0x68, 0x65, + 0x72, 0x0D, 0x0A, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, 0x65, + 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6B, 0x6E, 0x65, 0x77, + 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x6D, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x64, 0x6F, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x73, 0x20, 0x70, 0x69, + 0x67, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x73, 0x61, 0x79, + 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, 0x69, 0x66, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, + 0x6B, 0x6E, 0x65, 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x77, 0x61, 0x79, 0x20, 0x74, + 0x6F, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x6D, 0x2D, 0x2D, 0x27, 0x20, 0x77, 0x68, 0x65, + 0x6E, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x77, 0x61, 0x73, + 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x6C, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x20, 0x73, 0x65, 0x65, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x68, 0x65, 0x73, 0x68, 0x69, 0x72, + 0x65, 0x20, 0x43, 0x61, 0x74, 0x20, 0x73, 0x69, 0x74, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x61, 0x20, 0x62, + 0x6F, 0x75, 0x67, 0x68, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x0D, + 0x0A, 0x74, 0x72, 0x65, 0x65, 0x20, 0x61, 0x20, 0x66, 0x65, + 0x77, 0x20, 0x79, 0x61, 0x72, 0x64, 0x73, 0x20, 0x6F, 0x66, + 0x66, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x43, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x67, + 0x72, 0x69, 0x6E, 0x6E, 0x65, 0x64, 0x20, 0x77, 0x68, 0x65, + 0x6E, 0x20, 0x69, 0x74, 0x20, 0x73, 0x61, 0x77, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x20, 0x49, 0x74, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x67, 0x6F, 0x6F, 0x64, + 0x2D, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x64, 0x2C, 0x20, + 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x3A, 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, 0x20, + 0x69, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, 0x56, 0x45, 0x52, + 0x59, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x63, 0x6C, 0x61, + 0x77, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x20, 0x67, + 0x72, 0x65, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x6E, 0x79, 0x20, + 0x74, 0x65, 0x65, 0x74, 0x68, 0x2C, 0x20, 0x73, 0x6F, 0x20, + 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x66, 0x65, 0x6C, 0x74, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6F, 0x75, + 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, + 0x74, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x43, 0x68, 0x65, 0x73, + 0x68, 0x69, 0x72, 0x65, 0x20, 0x50, 0x75, 0x73, 0x73, 0x2C, + 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, + 0x6E, 0x2C, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x74, 0x69, 0x6D, 0x69, 0x64, 0x6C, 0x79, 0x2C, 0x20, 0x61, + 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x0D, 0x0A, 0x77, 0x68, 0x65, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x74, 0x20, 0x77, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x3A, 0x20, 0x68, + 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, 0x20, 0x69, 0x74, + 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x67, 0x72, 0x69, 0x6E, + 0x6E, 0x65, 0x64, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x77, 0x69, 0x64, 0x65, 0x72, 0x2E, 0x0D, + 0x0A, 0x27, 0x43, 0x6F, 0x6D, 0x65, 0x2C, 0x20, 0x69, 0x74, + 0x27, 0x73, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x64, + 0x20, 0x73, 0x6F, 0x20, 0x66, 0x61, 0x72, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, + 0x2E, 0x20, 0x27, 0x57, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x79, + 0x6F, 0x75, 0x0D, 0x0A, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x6D, + 0x65, 0x2C, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x2C, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x77, 0x61, 0x79, + 0x20, 0x49, 0x20, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, + 0x6F, 0x20, 0x67, 0x6F, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, + 0x68, 0x65, 0x72, 0x65, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x54, 0x68, 0x61, 0x74, 0x20, 0x64, 0x65, 0x70, 0x65, + 0x6E, 0x64, 0x73, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, + 0x20, 0x64, 0x65, 0x61, 0x6C, 0x20, 0x6F, 0x6E, 0x20, 0x77, + 0x68, 0x65, 0x72, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x77, + 0x61, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x65, 0x74, + 0x20, 0x74, 0x6F, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x63, 0x61, 0x72, + 0x65, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x2D, 0x2D, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, + 0x6E, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x6E, + 0x27, 0x74, 0x20, 0x6D, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, + 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x77, 0x61, 0x79, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x67, 0x6F, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, + 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x2D, 0x2D, 0x73, + 0x6F, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x61, 0x73, 0x20, + 0x49, 0x20, 0x67, 0x65, 0x74, 0x20, 0x53, 0x4F, 0x4D, 0x45, + 0x57, 0x48, 0x45, 0x52, 0x45, 0x2C, 0x27, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, + 0x61, 0x73, 0x20, 0x61, 0x6E, 0x20, 0x65, 0x78, 0x70, 0x6C, + 0x61, 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x27, 0x72, 0x65, 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x64, 0x6F, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x43, 0x61, 0x74, 0x2C, 0x20, 0x27, 0x69, 0x66, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x77, + 0x61, 0x6C, 0x6B, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x0D, 0x0A, + 0x65, 0x6E, 0x6F, 0x75, 0x67, 0x68, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x66, 0x65, + 0x6C, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x64, 0x65, 0x6E, 0x69, + 0x65, 0x64, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x6F, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, + 0x74, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, 0x20, 0x6C, 0x69, 0x76, + 0x65, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x68, 0x65, + 0x72, 0x65, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, + 0x6E, 0x20, 0x54, 0x48, 0x41, 0x54, 0x20, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x2C, 0x20, 0x77, 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, + 0x69, 0x74, 0x73, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, + 0x70, 0x61, 0x77, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2C, + 0x20, 0x27, 0x6C, 0x69, 0x76, 0x65, 0x73, 0x0D, 0x0A, 0x61, + 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x3A, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x54, 0x48, 0x41, 0x54, + 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x2C, 0x27, 0x20, 0x77, 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x70, 0x61, 0x77, 0x2C, 0x20, 0x27, 0x6C, 0x69, 0x76, 0x65, + 0x73, 0x20, 0x61, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x0D, + 0x0A, 0x48, 0x61, 0x72, 0x65, 0x2E, 0x20, 0x56, 0x69, 0x73, + 0x69, 0x74, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x3A, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x27, 0x72, 0x65, 0x20, 0x62, 0x6F, + 0x74, 0x68, 0x20, 0x6D, 0x61, 0x64, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x42, 0x75, 0x74, 0x20, 0x49, 0x20, 0x64, + 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x67, 0x6F, 0x20, 0x61, 0x6D, 0x6F, 0x6E, + 0x67, 0x20, 0x6D, 0x61, 0x64, 0x20, 0x70, 0x65, 0x6F, 0x70, + 0x6C, 0x65, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x72, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x65, 0x64, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x68, + 0x65, 0x6C, 0x70, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x43, 0x61, 0x74, 0x3A, 0x20, 0x27, 0x77, 0x65, 0x27, 0x72, + 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6D, 0x61, 0x64, 0x20, + 0x68, 0x65, 0x72, 0x65, 0x2E, 0x20, 0x49, 0x27, 0x6D, 0x20, + 0x6D, 0x61, 0x64, 0x2E, 0x0D, 0x0A, 0x59, 0x6F, 0x75, 0x27, + 0x72, 0x65, 0x20, 0x6D, 0x61, 0x64, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x48, 0x6F, 0x77, 0x20, 0x64, 0x6F, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x49, + 0x27, 0x6D, 0x20, 0x6D, 0x61, 0x64, 0x3F, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x6D, + 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, + 0x74, 0x2C, 0x20, 0x27, 0x6F, 0x72, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, + 0x68, 0x61, 0x76, 0x65, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, + 0x68, 0x65, 0x72, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x64, 0x69, 0x64, 0x6E, + 0x27, 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x65, 0x64, + 0x20, 0x69, 0x74, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, + 0x3B, 0x20, 0x68, 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, + 0x6F, 0x6E, 0x20, 0x27, 0x41, 0x6E, 0x64, 0x20, 0x68, 0x6F, + 0x77, 0x0D, 0x0A, 0x64, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x79, 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x6D, 0x61, 0x64, + 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x6F, 0x20, + 0x62, 0x65, 0x67, 0x69, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x61, 0x74, 0x2C, 0x20, 0x27, 0x61, 0x20, + 0x64, 0x6F, 0x67, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x6D, 0x61, 0x64, 0x2E, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x67, + 0x72, 0x61, 0x6E, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x3F, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x73, 0x75, + 0x70, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x73, 0x6F, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x6C, + 0x6C, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x27, 0x79, 0x6F, + 0x75, 0x20, 0x73, 0x65, 0x65, 0x2C, 0x20, 0x61, 0x20, 0x64, + 0x6F, 0x67, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x6C, 0x73, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, + 0x61, 0x6E, 0x67, 0x72, 0x79, 0x2C, 0x0D, 0x0A, 0x61, 0x6E, + 0x64, 0x20, 0x77, 0x61, 0x67, 0x73, 0x20, 0x69, 0x74, 0x73, + 0x20, 0x74, 0x61, 0x69, 0x6C, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x70, 0x6C, 0x65, 0x61, + 0x73, 0x65, 0x64, 0x2E, 0x20, 0x4E, 0x6F, 0x77, 0x20, 0x49, + 0x20, 0x67, 0x72, 0x6F, 0x77, 0x6C, 0x20, 0x77, 0x68, 0x65, + 0x6E, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x70, 0x6C, 0x65, 0x61, + 0x73, 0x65, 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, + 0x77, 0x61, 0x67, 0x20, 0x6D, 0x79, 0x20, 0x74, 0x61, 0x69, + 0x6C, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x49, 0x27, 0x6D, + 0x20, 0x61, 0x6E, 0x67, 0x72, 0x79, 0x2E, 0x20, 0x54, 0x68, + 0x65, 0x72, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, 0x49, 0x27, + 0x6D, 0x20, 0x6D, 0x61, 0x64, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x20, 0x69, + 0x74, 0x20, 0x70, 0x75, 0x72, 0x72, 0x69, 0x6E, 0x67, 0x2C, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x6C, + 0x69, 0x6E, 0x67, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x43, 0x61, 0x6C, 0x6C, 0x20, 0x69, 0x74, 0x20, + 0x77, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x2E, 0x20, + 0x27, 0x44, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x70, 0x6C, + 0x61, 0x79, 0x20, 0x63, 0x72, 0x6F, 0x71, 0x75, 0x65, 0x74, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x2D, + 0x64, 0x61, 0x79, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, + 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, 0x49, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, 0x65, 0x6E, + 0x20, 0x69, 0x6E, 0x76, 0x69, 0x74, 0x65, 0x64, 0x0D, 0x0A, + 0x79, 0x65, 0x74, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x59, 0x6F, 0x75, 0x27, 0x6C, 0x6C, 0x20, 0x73, 0x65, 0x65, + 0x20, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x43, 0x61, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x76, 0x61, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x20, 0x73, 0x75, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, + 0x64, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, + 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x6F, 0x20, + 0x75, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x71, 0x75, + 0x65, 0x65, 0x72, 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x73, 0x20, 0x68, 0x61, 0x70, 0x70, 0x65, 0x6E, 0x69, 0x6E, + 0x67, 0x2E, 0x20, 0x57, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6C, 0x6F, 0x6F, + 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x20, 0x77, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x62, 0x65, 0x65, 0x6E, 0x2C, 0x0D, 0x0A, 0x69, 0x74, + 0x20, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, 0x6C, 0x79, 0x20, + 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x65, 0x64, 0x20, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x42, 0x79, 0x2D, 0x74, 0x68, 0x65, 0x2D, 0x62, 0x79, 0x65, + 0x2C, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x62, 0x65, 0x63, + 0x61, 0x6D, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x61, 0x62, 0x79, 0x3F, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, + 0x2E, 0x20, 0x27, 0x49, 0x27, 0x64, 0x20, 0x6E, 0x65, 0x61, + 0x72, 0x6C, 0x79, 0x0D, 0x0A, 0x66, 0x6F, 0x72, 0x67, 0x6F, + 0x74, 0x74, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x73, + 0x6B, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, + 0x20, 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, 0x69, 0x6E, + 0x74, 0x6F, 0x20, 0x61, 0x20, 0x70, 0x69, 0x67, 0x2C, 0x27, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x71, 0x75, 0x69, + 0x65, 0x74, 0x6C, 0x79, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, + 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x61, 0x73, 0x20, 0x69, + 0x66, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, 0x63, + 0x6F, 0x6D, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x0D, 0x0A, + 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6E, 0x61, 0x74, 0x75, 0x72, + 0x61, 0x6C, 0x20, 0x77, 0x61, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x43, 0x61, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x76, 0x61, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x61, 0x69, 0x74, + 0x65, 0x64, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, + 0x65, 0x2C, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x65, 0x78, + 0x70, 0x65, 0x63, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, + 0x20, 0x73, 0x65, 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, + 0x74, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x0D, + 0x0A, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x61, + 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x20, 0x6F, 0x72, + 0x20, 0x74, 0x77, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x6C, 0x6B, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, 0x72, 0x65, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x0D, 0x0A, + 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x6C, 0x69, 0x76, 0x65, 0x2E, 0x20, 0x27, + 0x49, 0x27, 0x76, 0x65, 0x20, 0x73, 0x65, 0x65, 0x6E, 0x20, + 0x68, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x20, 0x62, 0x65, + 0x66, 0x6F, 0x72, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, + 0x0D, 0x0A, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x3B, 0x20, 0x27, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, + 0x48, 0x61, 0x72, 0x65, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, + 0x62, 0x65, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x74, + 0x65, 0x72, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x70, 0x65, 0x72, 0x68, 0x61, + 0x70, 0x73, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x69, 0x73, 0x20, 0x4D, 0x61, 0x79, 0x20, 0x69, 0x74, + 0x20, 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, + 0x72, 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x61, 0x64, + 0x2D, 0x2D, 0x61, 0x74, 0x20, 0x6C, 0x65, 0x61, 0x73, 0x74, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x73, 0x6F, 0x20, 0x6D, 0x61, + 0x64, 0x20, 0x61, 0x73, 0x0D, 0x0A, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x4D, 0x61, 0x72, 0x63, + 0x68, 0x2E, 0x27, 0x20, 0x41, 0x73, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, + 0x65, 0x64, 0x20, 0x75, 0x70, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x0D, 0x0A, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x73, 0x69, 0x74, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x61, 0x20, + 0x62, 0x72, 0x61, 0x6E, 0x63, 0x68, 0x20, 0x6F, 0x66, 0x20, + 0x61, 0x20, 0x74, 0x72, 0x65, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x44, 0x69, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x73, 0x61, 0x79, 0x20, 0x70, 0x69, 0x67, 0x2C, 0x20, 0x6F, + 0x72, 0x20, 0x66, 0x69, 0x67, 0x3F, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x70, 0x69, 0x67, 0x2C, 0x27, 0x20, 0x72, + 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x3B, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x49, + 0x20, 0x77, 0x69, 0x73, 0x68, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x6B, + 0x65, 0x65, 0x70, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, + 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x76, + 0x61, 0x6E, 0x69, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x73, + 0x6F, 0x20, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, 0x6C, 0x79, + 0x3A, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x6B, 0x65, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, + 0x20, 0x67, 0x69, 0x64, 0x64, 0x79, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x41, 0x6C, 0x6C, 0x20, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x3B, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x69, + 0x6D, 0x65, 0x20, 0x69, 0x74, 0x20, 0x76, 0x61, 0x6E, 0x69, + 0x73, 0x68, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, + 0x20, 0x73, 0x6C, 0x6F, 0x77, 0x6C, 0x79, 0x2C, 0x0D, 0x0A, + 0x62, 0x65, 0x67, 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, + 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x61, 0x69, 0x6C, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x69, 0x6E, + 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x0D, 0x0A, 0x72, + 0x65, 0x6D, 0x61, 0x69, 0x6E, 0x65, 0x64, 0x20, 0x73, 0x6F, + 0x6D, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, + 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x67, 0x6F, 0x6E, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x6C, 0x6C, 0x21, 0x20, 0x49, + 0x27, 0x76, 0x65, 0x20, 0x6F, 0x66, 0x74, 0x65, 0x6E, 0x20, + 0x73, 0x65, 0x65, 0x6E, 0x20, 0x61, 0x20, 0x63, 0x61, 0x74, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x61, + 0x20, 0x67, 0x72, 0x69, 0x6E, 0x2C, 0x27, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x3B, 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, 0x61, 0x20, + 0x67, 0x72, 0x69, 0x6E, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, + 0x6F, 0x75, 0x74, 0x20, 0x61, 0x20, 0x63, 0x61, 0x74, 0x21, + 0x20, 0x49, 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, + 0x75, 0x73, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x49, + 0x20, 0x65, 0x76, 0x65, 0x72, 0x20, 0x73, 0x61, 0x77, 0x20, + 0x69, 0x6E, 0x20, 0x6D, 0x79, 0x20, 0x6C, 0x69, 0x66, 0x65, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x67, 0x6F, + 0x6E, 0x65, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x66, 0x61, + 0x72, 0x74, 0x68, 0x65, 0x72, 0x20, 0x62, 0x65, 0x66, 0x6F, + 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6D, + 0x65, 0x20, 0x69, 0x6E, 0x20, 0x73, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6F, + 0x75, 0x73, 0x65, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, + 0x72, 0x65, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6D, + 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x68, 0x6F, 0x75, + 0x73, 0x65, 0x2C, 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x63, 0x68, 0x69, + 0x6D, 0x6E, 0x65, 0x79, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, + 0x20, 0x73, 0x68, 0x61, 0x70, 0x65, 0x64, 0x20, 0x6C, 0x69, + 0x6B, 0x65, 0x20, 0x65, 0x61, 0x72, 0x73, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, 0x6F, 0x66, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x63, + 0x68, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x66, + 0x75, 0x72, 0x2E, 0x20, 0x49, 0x74, 0x0D, 0x0A, 0x77, 0x61, + 0x73, 0x20, 0x73, 0x6F, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x20, 0x61, 0x20, 0x68, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x64, + 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x6F, 0x20, 0x6E, 0x65, + 0x61, 0x72, 0x65, 0x72, 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x0D, 0x0A, 0x6E, + 0x69, 0x62, 0x62, 0x6C, 0x65, 0x64, 0x20, 0x73, 0x6F, 0x6D, + 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x68, 0x61, + 0x6E, 0x64, 0x20, 0x62, 0x69, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x6D, 0x75, 0x73, 0x68, 0x72, 0x6F, 0x6F, 0x6D, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x72, 0x61, 0x69, 0x73, 0x65, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x74, + 0x6F, 0x0D, 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, + 0x77, 0x6F, 0x20, 0x66, 0x65, 0x65, 0x74, 0x20, 0x68, 0x69, + 0x67, 0x68, 0x3A, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x6C, 0x6B, 0x65, 0x64, 0x20, 0x75, 0x70, 0x20, 0x74, 0x6F, + 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x69, 0x74, 0x20, 0x72, + 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x69, 0x6D, 0x69, + 0x64, 0x6C, 0x79, 0x2C, 0x0D, 0x0A, 0x73, 0x61, 0x79, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x20, 0x27, 0x53, 0x75, 0x70, 0x70, 0x6F, + 0x73, 0x65, 0x20, 0x69, 0x74, 0x20, 0x73, 0x68, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x72, 0x61, 0x76, 0x69, + 0x6E, 0x67, 0x20, 0x6D, 0x61, 0x64, 0x20, 0x61, 0x66, 0x74, + 0x65, 0x72, 0x20, 0x61, 0x6C, 0x6C, 0x21, 0x20, 0x49, 0x20, + 0x61, 0x6C, 0x6D, 0x6F, 0x73, 0x74, 0x0D, 0x0A, 0x77, 0x69, + 0x73, 0x68, 0x20, 0x49, 0x27, 0x64, 0x20, 0x67, 0x6F, 0x6E, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, + 0x69, 0x6E, 0x73, 0x74, 0x65, 0x61, 0x64, 0x21, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, + 0x48, 0x41, 0x50, 0x54, 0x45, 0x52, 0x20, 0x56, 0x49, 0x49, + 0x2E, 0x20, 0x41, 0x20, 0x4D, 0x61, 0x64, 0x20, 0x54, 0x65, + 0x61, 0x2D, 0x50, 0x61, 0x72, 0x74, 0x79, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x61, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x73, + 0x65, 0x74, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x75, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x61, 0x20, 0x74, 0x72, 0x65, 0x65, 0x20, + 0x69, 0x6E, 0x20, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x6F, 0x75, 0x73, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, + 0x72, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x20, 0x68, 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x65, 0x61, 0x20, 0x61, 0x74, 0x20, 0x69, 0x74, 0x3A, + 0x20, 0x61, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x74, + 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x62, 0x65, 0x74, 0x77, 0x65, + 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x20, 0x66, + 0x61, 0x73, 0x74, 0x20, 0x61, 0x73, 0x6C, 0x65, 0x65, 0x70, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x77, 0x6F, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6E, 0x67, + 0x20, 0x69, 0x74, 0x20, 0x61, 0x73, 0x20, 0x61, 0x0D, 0x0A, + 0x63, 0x75, 0x73, 0x68, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x72, + 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x65, 0x6C, 0x62, 0x6F, 0x77, 0x73, 0x20, + 0x6F, 0x6E, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x76, 0x65, 0x72, 0x20, 0x69, 0x74, 0x73, 0x20, 0x68, 0x65, + 0x61, 0x64, 0x2E, 0x20, 0x27, 0x56, 0x65, 0x72, 0x79, 0x0D, + 0x0A, 0x75, 0x6E, 0x63, 0x6F, 0x6D, 0x66, 0x6F, 0x72, 0x74, + 0x61, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x3B, 0x20, 0x27, + 0x6F, 0x6E, 0x6C, 0x79, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x69, + 0x74, 0x27, 0x73, 0x20, 0x61, 0x73, 0x6C, 0x65, 0x65, 0x70, + 0x2C, 0x20, 0x49, 0x0D, 0x0A, 0x73, 0x75, 0x70, 0x70, 0x6F, + 0x73, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x65, 0x73, + 0x6E, 0x27, 0x74, 0x20, 0x6D, 0x69, 0x6E, 0x64, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x74, 0x61, + 0x62, 0x6C, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, + 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x6F, 0x6E, 0x65, 0x2C, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x68, 0x72, 0x65, 0x65, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x72, 0x6F, 0x77, 0x64, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x61, 0x74, 0x0D, 0x0A, 0x6F, 0x6E, 0x65, 0x20, 0x63, + 0x6F, 0x72, 0x6E, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x69, + 0x74, 0x3A, 0x20, 0x27, 0x4E, 0x6F, 0x20, 0x72, 0x6F, 0x6F, + 0x6D, 0x21, 0x20, 0x4E, 0x6F, 0x20, 0x72, 0x6F, 0x6F, 0x6D, + 0x21, 0x27, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x72, + 0x69, 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x73, 0x61, + 0x77, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x0D, 0x0A, 0x63, + 0x6F, 0x6D, 0x69, 0x6E, 0x67, 0x2E, 0x20, 0x27, 0x54, 0x68, + 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x50, 0x4C, 0x45, 0x4E, + 0x54, 0x59, 0x20, 0x6F, 0x66, 0x20, 0x72, 0x6F, 0x6F, 0x6D, + 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x67, 0x6E, + 0x61, 0x6E, 0x74, 0x6C, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x74, 0x0D, 0x0A, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, + 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x61, 0x72, 0x6D, 0x2D, + 0x63, 0x68, 0x61, 0x69, 0x72, 0x20, 0x61, 0x74, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x65, 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x61, 0x76, 0x65, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x77, 0x69, 0x6E, 0x65, 0x2C, + 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, + 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x20, 0x65, 0x6E, + 0x63, 0x6F, 0x75, 0x72, 0x61, 0x67, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x6F, 0x6E, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, + 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x6F, 0x75, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6C, + 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x69, 0x74, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x65, 0x61, 0x2E, 0x0D, + 0x0A, 0x27, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, + 0x73, 0x65, 0x65, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x77, 0x69, + 0x6E, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x72, + 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x65, 0x64, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, + 0x73, 0x6E, 0x27, 0x74, 0x20, 0x61, 0x6E, 0x79, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x6E, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x6E, 0x27, 0x74, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x63, 0x69, 0x76, 0x69, + 0x6C, 0x20, 0x6F, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x74, + 0x6F, 0x20, 0x6F, 0x66, 0x66, 0x65, 0x72, 0x20, 0x69, 0x74, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x61, 0x6E, 0x67, 0x72, 0x69, 0x6C, + 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x20, + 0x77, 0x61, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x63, 0x69, 0x76, 0x69, 0x6C, 0x20, 0x6F, 0x66, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x69, + 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x6F, 0x75, 0x74, 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, + 0x20, 0x69, 0x6E, 0x76, 0x69, 0x74, 0x65, 0x64, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, + 0x69, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x59, 0x4F, + 0x55, 0x52, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x3B, 0x20, 0x27, 0x69, 0x74, 0x27, 0x73, 0x20, 0x6C, + 0x61, 0x69, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, + 0x67, 0x72, 0x65, 0x61, 0x74, 0x0D, 0x0A, 0x6D, 0x61, 0x6E, + 0x79, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, + 0x6E, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x72, 0x20, 0x68, + 0x61, 0x69, 0x72, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x73, 0x20, + 0x63, 0x75, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x2E, 0x20, 0x48, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x0D, 0x0A, 0x66, 0x6F, 0x72, + 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x67, 0x72, 0x65, 0x61, + 0x74, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x73, 0x69, 0x74, + 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x77, 0x61, 0x73, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x73, 0x70, 0x65, 0x65, + 0x63, 0x68, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, + 0x75, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6C, + 0x65, 0x61, 0x72, 0x6E, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x74, + 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x70, 0x65, 0x72, + 0x73, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x72, 0x65, 0x6D, 0x61, + 0x72, 0x6B, 0x73, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x0D, 0x0A, 0x73, 0x65, + 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x3B, 0x20, 0x27, 0x69, + 0x74, 0x27, 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x72, + 0x75, 0x64, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, + 0x6F, 0x70, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x65, 0x79, 0x65, 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x77, 0x69, 0x64, 0x65, 0x20, 0x6F, 0x6E, 0x20, 0x68, + 0x65, 0x61, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x68, 0x65, 0x20, 0x53, 0x41, 0x49, 0x44, 0x0D, 0x0A, + 0x77, 0x61, 0x73, 0x2C, 0x20, 0x27, 0x57, 0x68, 0x79, 0x20, + 0x69, 0x73, 0x20, 0x61, 0x20, 0x72, 0x61, 0x76, 0x65, 0x6E, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x61, 0x20, 0x77, 0x72, + 0x69, 0x74, 0x69, 0x6E, 0x67, 0x2D, 0x64, 0x65, 0x73, 0x6B, + 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x43, 0x6F, 0x6D, + 0x65, 0x2C, 0x20, 0x77, 0x65, 0x20, 0x73, 0x68, 0x61, 0x6C, + 0x6C, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x73, 0x6F, 0x6D, + 0x65, 0x20, 0x66, 0x75, 0x6E, 0x20, 0x6E, 0x6F, 0x77, 0x21, + 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x20, 0x27, 0x49, 0x27, + 0x6D, 0x20, 0x67, 0x6C, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x79, 0x27, 0x76, 0x65, 0x0D, 0x0A, 0x62, 0x65, 0x67, 0x75, + 0x6E, 0x20, 0x61, 0x73, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x72, + 0x69, 0x64, 0x64, 0x6C, 0x65, 0x73, 0x2E, 0x2D, 0x2D, 0x49, + 0x20, 0x62, 0x65, 0x6C, 0x69, 0x65, 0x76, 0x65, 0x20, 0x49, + 0x20, 0x63, 0x61, 0x6E, 0x20, 0x67, 0x75, 0x65, 0x73, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x61, 0x6C, + 0x6F, 0x75, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x44, + 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x65, 0x61, 0x6E, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x63, 0x61, 0x6E, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, 0x6F, + 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6E, 0x73, + 0x77, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x3F, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, + 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x45, 0x78, + 0x61, 0x63, 0x74, 0x6C, 0x79, 0x20, 0x73, 0x6F, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, + 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x73, 0x68, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x73, 0x61, 0x79, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x65, 0x61, 0x6E, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, + 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x49, 0x20, 0x64, 0x6F, 0x2C, 0x27, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, + 0x79, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x3B, + 0x20, 0x27, 0x61, 0x74, 0x20, 0x6C, 0x65, 0x61, 0x73, 0x74, + 0x2D, 0x2D, 0x61, 0x74, 0x20, 0x6C, 0x65, 0x61, 0x73, 0x74, + 0x20, 0x49, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x49, 0x0D, 0x0A, 0x73, 0x61, 0x79, 0x2D, + 0x2D, 0x74, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, + 0x6F, 0x77, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, + 0x6F, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x20, + 0x62, 0x69, 0x74, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, + 0x72, 0x2E, 0x20, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x61, + 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x73, 0x61, 0x79, + 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x22, 0x49, 0x20, + 0x73, 0x65, 0x65, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x49, + 0x20, 0x65, 0x61, 0x74, 0x22, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x61, 0x73, 0x20, 0x22, 0x49, 0x20, + 0x65, 0x61, 0x74, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x49, + 0x20, 0x73, 0x65, 0x65, 0x22, 0x21, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x73, 0x61, 0x79, 0x2C, 0x27, + 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, + 0x65, 0x2C, 0x20, 0x27, 0x74, 0x68, 0x61, 0x74, 0x20, 0x22, + 0x49, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x49, 0x0D, 0x0A, 0x67, 0x65, 0x74, 0x22, 0x20, + 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x73, + 0x20, 0x22, 0x49, 0x20, 0x67, 0x65, 0x74, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x49, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x22, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, + 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6A, 0x75, 0x73, + 0x74, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, + 0x73, 0x61, 0x79, 0x2C, 0x27, 0x20, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, + 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, + 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x62, 0x65, 0x0D, 0x0A, 0x74, 0x61, 0x6C, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x69, 0x6E, 0x20, 0x68, 0x69, 0x73, 0x20, 0x73, + 0x6C, 0x65, 0x65, 0x70, 0x2C, 0x20, 0x27, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x22, 0x49, 0x20, 0x62, 0x72, 0x65, 0x61, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x49, 0x20, + 0x73, 0x6C, 0x65, 0x65, 0x70, 0x22, 0x20, 0x69, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x61, 0x73, 0x20, 0x22, + 0x49, 0x20, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x20, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x49, 0x20, 0x62, 0x72, 0x65, 0x61, 0x74, + 0x68, 0x65, 0x22, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x74, 0x20, 0x49, 0x53, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x61, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x79, 0x6F, 0x75, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x64, 0x72, 0x6F, 0x70, + 0x70, 0x65, 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x79, 0x20, 0x73, + 0x61, 0x74, 0x20, 0x73, 0x69, 0x6C, 0x65, 0x6E, 0x74, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x6D, 0x69, 0x6E, 0x75, + 0x74, 0x65, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, + 0x65, 0x72, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x72, + 0x61, 0x76, 0x65, 0x6E, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x2D, 0x64, 0x65, + 0x73, 0x6B, 0x73, 0x2C, 0x0D, 0x0A, 0x77, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x77, 0x61, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x6D, + 0x75, 0x63, 0x68, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, + 0x73, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x72, 0x65, 0x61, + 0x6B, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 0x6C, 0x65, + 0x6E, 0x63, 0x65, 0x2E, 0x20, 0x27, 0x57, 0x68, 0x61, 0x74, + 0x20, 0x64, 0x61, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6D, 0x6F, 0x6E, 0x74, 0x68, 0x0D, 0x0A, 0x69, + 0x73, 0x20, 0x69, 0x74, 0x3F, 0x27, 0x20, 0x68, 0x65, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x74, 0x75, 0x72, 0x6E, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x3A, 0x20, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x74, 0x61, 0x6B, 0x65, 0x6E, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x77, 0x61, 0x74, 0x63, 0x68, 0x20, 0x6F, 0x75, 0x74, + 0x20, 0x6F, 0x66, 0x20, 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x70, + 0x6F, 0x63, 0x6B, 0x65, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x75, + 0x6E, 0x65, 0x61, 0x73, 0x69, 0x6C, 0x79, 0x2C, 0x20, 0x73, + 0x68, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x20, + 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6E, 0x6F, 0x77, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x2C, 0x0D, + 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x6F, 0x6C, 0x64, 0x69, + 0x6E, 0x67, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x65, 0x61, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x63, 0x6F, 0x6E, + 0x73, 0x69, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x27, 0x54, 0x68, 0x65, 0x20, 0x66, 0x6F, 0x75, + 0x72, 0x74, 0x68, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x54, 0x77, 0x6F, 0x20, 0x64, 0x61, 0x79, 0x73, 0x20, 0x77, + 0x72, 0x6F, 0x6E, 0x67, 0x21, 0x27, 0x20, 0x73, 0x69, 0x67, + 0x68, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x2E, 0x20, 0x27, 0x49, 0x20, 0x74, + 0x6F, 0x6C, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x62, 0x75, + 0x74, 0x74, 0x65, 0x72, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, + 0x6E, 0x27, 0x74, 0x20, 0x73, 0x75, 0x69, 0x74, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x21, + 0x27, 0x20, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x6E, 0x67, 0x72, 0x69, 0x6C, 0x79, 0x20, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, + 0x48, 0x61, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x42, 0x45, 0x53, 0x54, 0x20, 0x62, 0x75, 0x74, 0x74, + 0x65, 0x72, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, + 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x20, + 0x6D, 0x65, 0x65, 0x6B, 0x6C, 0x79, 0x20, 0x72, 0x65, 0x70, + 0x6C, 0x69, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x59, 0x65, 0x73, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x63, 0x72, 0x75, 0x6D, 0x62, 0x73, + 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x67, 0x6F, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x73, + 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x2C, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x67, + 0x72, 0x75, 0x6D, 0x62, 0x6C, 0x65, 0x64, 0x3A, 0x0D, 0x0A, + 0x27, 0x79, 0x6F, 0x75, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, + 0x64, 0x6E, 0x27, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x70, 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x72, 0x65, 0x61, 0x64, 0x2D, 0x6B, 0x6E, 0x69, 0x66, 0x65, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, + 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x61, 0x74, 0x63, 0x68, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, + 0x69, 0x74, 0x20, 0x67, 0x6C, 0x6F, 0x6F, 0x6D, 0x69, 0x6C, + 0x79, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x68, 0x65, + 0x20, 0x64, 0x69, 0x70, 0x70, 0x65, 0x64, 0x0D, 0x0A, 0x69, + 0x74, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x63, 0x75, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x65, + 0x61, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6F, + 0x6B, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x3A, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x6F, 0x66, 0x0D, 0x0A, + 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x65, + 0x74, 0x74, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, + 0x79, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x72, 0x65, 0x6D, + 0x61, 0x72, 0x6B, 0x2C, 0x20, 0x27, 0x49, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x42, 0x45, 0x53, + 0x54, 0x20, 0x62, 0x75, 0x74, 0x74, 0x65, 0x72, 0x2C, 0x0D, + 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x76, + 0x65, 0x72, 0x20, 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, 0x6F, + 0x75, 0x6C, 0x64, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x63, 0x75, 0x72, 0x69, + 0x6F, 0x73, 0x69, 0x74, 0x79, 0x2E, 0x20, 0x27, 0x57, 0x68, + 0x61, 0x74, 0x20, 0x61, 0x0D, 0x0A, 0x66, 0x75, 0x6E, 0x6E, + 0x79, 0x20, 0x77, 0x61, 0x74, 0x63, 0x68, 0x21, 0x27, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x72, 0x6B, + 0x65, 0x64, 0x2E, 0x20, 0x27, 0x49, 0x74, 0x20, 0x74, 0x65, + 0x6C, 0x6C, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, + 0x79, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, + 0x6F, 0x6E, 0x74, 0x68, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, 0x74, 0x0D, 0x0A, 0x74, + 0x65, 0x6C, 0x6C, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x6F, + 0x27, 0x63, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x69, 0x74, 0x20, + 0x69, 0x73, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, + 0x68, 0x79, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x69, 0x74, 0x3F, 0x27, 0x20, 0x6D, 0x75, 0x74, 0x74, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x2E, 0x20, 0x27, 0x44, 0x6F, 0x65, + 0x73, 0x20, 0x59, 0x4F, 0x55, 0x52, 0x20, 0x77, 0x61, 0x74, + 0x63, 0x68, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x77, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x79, 0x65, + 0x61, 0x72, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x3F, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x66, 0x20, 0x63, 0x6F, + 0x75, 0x72, 0x73, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x2C, 0x27, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x72, 0x65, 0x70, + 0x6C, 0x69, 0x65, 0x64, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x72, 0x65, 0x61, 0x64, 0x69, 0x6C, 0x79, 0x3A, 0x20, 0x27, + 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, 0x73, + 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x69, + 0x74, 0x0D, 0x0A, 0x73, 0x74, 0x61, 0x79, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x79, 0x65, + 0x61, 0x72, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x75, 0x63, + 0x68, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x74, + 0x69, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x67, 0x65, 0x74, 0x68, + 0x65, 0x72, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, + 0x68, 0x69, 0x63, 0x68, 0x20, 0x69, 0x73, 0x20, 0x6A, 0x75, + 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x73, + 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x4D, 0x49, 0x4E, + 0x45, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x66, 0x65, 0x6C, 0x74, 0x20, 0x64, 0x72, 0x65, 0x61, 0x64, + 0x66, 0x75, 0x6C, 0x6C, 0x79, 0x20, 0x70, 0x75, 0x7A, 0x7A, + 0x6C, 0x65, 0x64, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x48, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x27, 0x73, 0x20, 0x72, 0x65, + 0x6D, 0x61, 0x72, 0x6B, 0x20, 0x73, 0x65, 0x65, 0x6D, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x6E, 0x6F, 0x0D, 0x0A, 0x73, 0x6F, 0x72, 0x74, 0x20, 0x6F, + 0x66, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x69, 0x6E, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x79, 0x65, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6E, 0x6C, + 0x79, 0x20, 0x45, 0x6E, 0x67, 0x6C, 0x69, 0x73, 0x68, 0x2E, + 0x20, 0x27, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x0D, 0x0A, 0x75, 0x6E, 0x64, + 0x65, 0x72, 0x73, 0x74, 0x61, 0x6E, 0x64, 0x20, 0x79, 0x6F, + 0x75, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x70, 0x6F, 0x6C, + 0x69, 0x74, 0x65, 0x6C, 0x79, 0x20, 0x61, 0x73, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x20, 0x44, 0x6F, + 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x20, 0x70, + 0x6F, 0x75, 0x72, 0x65, 0x64, 0x20, 0x61, 0x20, 0x6C, 0x69, + 0x74, 0x74, 0x6C, 0x65, 0x0D, 0x0A, 0x68, 0x6F, 0x74, 0x20, + 0x74, 0x65, 0x61, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x69, + 0x74, 0x73, 0x20, 0x6E, 0x6F, 0x73, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, + 0x6F, 0x75, 0x73, 0x65, 0x20, 0x73, 0x68, 0x6F, 0x6F, 0x6B, + 0x20, 0x69, 0x74, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, + 0x69, 0x6D, 0x70, 0x61, 0x74, 0x69, 0x65, 0x6E, 0x74, 0x6C, + 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, + 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x69, + 0x74, 0x73, 0x0D, 0x0A, 0x65, 0x79, 0x65, 0x73, 0x2C, 0x20, + 0x27, 0x4F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, + 0x2C, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, + 0x65, 0x3B, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x49, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, + 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, + 0x6D, 0x61, 0x72, 0x6B, 0x20, 0x6D, 0x79, 0x73, 0x65, 0x6C, + 0x66, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x61, + 0x76, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x67, 0x75, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x69, 0x64, 0x64, 0x6C, 0x65, 0x20, 0x79, 0x65, 0x74, 0x3F, + 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x74, + 0x75, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x0D, 0x0A, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, + 0x2C, 0x20, 0x49, 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, 0x69, + 0x74, 0x20, 0x75, 0x70, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, + 0x3A, 0x20, 0x27, 0x77, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x61, 0x6E, 0x73, 0x77, 0x65, 0x72, + 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x6E, 0x27, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x6C, 0x69, 0x67, 0x68, 0x74, 0x65, 0x73, 0x74, + 0x20, 0x69, 0x64, 0x65, 0x61, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, + 0x6F, 0x72, 0x20, 0x49, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, + 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x73, 0x69, 0x67, + 0x68, 0x65, 0x64, 0x20, 0x77, 0x65, 0x61, 0x72, 0x69, 0x6C, + 0x79, 0x2E, 0x20, 0x27, 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x6B, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x69, 0x67, 0x68, + 0x74, 0x20, 0x64, 0x6F, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x65, 0x74, 0x74, 0x65, + 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x74, 0x69, 0x6D, 0x65, 0x2C, 0x27, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x27, + 0x74, 0x68, 0x61, 0x6E, 0x20, 0x77, 0x61, 0x73, 0x74, 0x65, + 0x20, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x73, 0x6B, + 0x69, 0x6E, 0x67, 0x20, 0x72, 0x69, 0x64, 0x64, 0x6C, 0x65, + 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x6E, 0x6F, 0x20, 0x61, 0x6E, 0x73, 0x77, 0x65, + 0x72, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, + 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x65, 0x77, + 0x20, 0x54, 0x69, 0x6D, 0x65, 0x20, 0x61, 0x73, 0x20, 0x77, + 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x73, 0x20, 0x49, 0x20, 0x64, + 0x6F, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x2C, + 0x20, 0x27, 0x79, 0x6F, 0x75, 0x20, 0x77, 0x6F, 0x75, 0x6C, + 0x64, 0x6E, 0x27, 0x74, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x0D, + 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x49, 0x54, 0x2E, 0x20, 0x49, + 0x74, 0x27, 0x73, 0x20, 0x48, 0x49, 0x4D, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x65, 0x61, 0x6E, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, + 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x21, 0x27, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, + 0x72, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x74, 0x6F, + 0x73, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x68, 0x65, 0x61, 0x64, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, + 0x6D, 0x70, 0x74, 0x75, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x2E, + 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, 0x61, 0x72, 0x65, 0x20, + 0x73, 0x61, 0x79, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6E, 0x65, + 0x76, 0x65, 0x72, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x73, + 0x70, 0x6F, 0x6B, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x54, 0x69, + 0x6D, 0x65, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x50, + 0x65, 0x72, 0x68, 0x61, 0x70, 0x73, 0x20, 0x6E, 0x6F, 0x74, + 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x63, + 0x61, 0x75, 0x74, 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, + 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x3A, 0x20, 0x27, + 0x62, 0x75, 0x74, 0x20, 0x49, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x20, 0x49, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x65, 0x61, 0x74, 0x20, 0x74, 0x69, 0x6D, 0x65, + 0x0D, 0x0A, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x49, 0x20, 0x6C, + 0x65, 0x61, 0x72, 0x6E, 0x20, 0x6D, 0x75, 0x73, 0x69, 0x63, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x68, 0x21, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x63, 0x63, 0x6F, + 0x75, 0x6E, 0x74, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x69, + 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x2E, + 0x20, 0x27, 0x48, 0x65, 0x20, 0x77, 0x6F, 0x6E, 0x27, 0x74, + 0x20, 0x73, 0x74, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x61, + 0x74, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x4E, 0x6F, 0x77, + 0x2C, 0x20, 0x69, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6F, + 0x6E, 0x6C, 0x79, 0x20, 0x6B, 0x65, 0x70, 0x74, 0x20, 0x6F, + 0x6E, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x74, 0x65, 0x72, + 0x6D, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, 0x69, + 0x6D, 0x2C, 0x20, 0x68, 0x65, 0x27, 0x64, 0x20, 0x64, 0x6F, + 0x20, 0x61, 0x6C, 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x6E, + 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x79, 0x6F, + 0x75, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6C, 0x6F, + 0x63, 0x6B, 0x2E, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x69, 0x6E, + 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x2C, 0x20, 0x73, 0x75, + 0x70, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x6E, 0x69, 0x6E, 0x65, 0x20, 0x6F, + 0x27, 0x63, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x69, 0x6E, 0x0D, + 0x0A, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x6E, 0x69, + 0x6E, 0x67, 0x2C, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x74, + 0x69, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x67, + 0x69, 0x6E, 0x20, 0x6C, 0x65, 0x73, 0x73, 0x6F, 0x6E, 0x73, + 0x3A, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x64, 0x20, 0x6F, 0x6E, + 0x6C, 0x79, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x20, 0x61, + 0x0D, 0x0A, 0x68, 0x69, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x54, 0x69, 0x6D, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x67, 0x6F, 0x65, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6C, 0x6F, 0x63, 0x6B, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x74, 0x77, 0x69, 0x6E, + 0x6B, 0x6C, 0x69, 0x6E, 0x67, 0x21, 0x20, 0x48, 0x61, 0x6C, + 0x66, 0x2D, 0x70, 0x61, 0x73, 0x74, 0x20, 0x6F, 0x6E, 0x65, + 0x2C, 0x0D, 0x0A, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x64, 0x69, 0x6E, 0x6E, 0x65, 0x72, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x28, 0x27, 0x49, 0x20, 0x6F, 0x6E, + 0x6C, 0x79, 0x20, 0x77, 0x69, 0x73, 0x68, 0x20, 0x69, 0x74, + 0x20, 0x77, 0x61, 0x73, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x69, 0x74, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x20, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x2E, + 0x29, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, 0x74, + 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, + 0x67, 0x72, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x63, 0x65, 0x72, + 0x74, 0x61, 0x69, 0x6E, 0x6C, 0x79, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x66, 0x75, 0x6C, + 0x6C, 0x79, 0x3A, 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x6E, 0x2D, 0x2D, 0x49, 0x0D, 0x0A, 0x73, 0x68, + 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x68, 0x75, 0x6E, 0x67, 0x72, 0x79, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x4E, 0x6F, 0x74, 0x20, 0x61, 0x74, 0x20, 0x66, 0x69, + 0x72, 0x73, 0x74, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x68, 0x61, + 0x70, 0x73, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x3A, 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6B, 0x65, 0x65, + 0x70, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x68, + 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x61, 0x73, 0x74, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x61, 0x73, 0x20, 0x6C, 0x6F, 0x6E, 0x67, + 0x20, 0x61, 0x73, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6C, 0x69, + 0x6B, 0x65, 0x64, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x59, 0x4F, 0x55, 0x20, + 0x6D, 0x61, 0x6E, 0x61, 0x67, 0x65, 0x3F, 0x27, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x73, 0x6B, 0x65, 0x64, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x48, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x73, 0x68, 0x6F, 0x6F, + 0x6B, 0x20, 0x68, 0x69, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, + 0x20, 0x6D, 0x6F, 0x75, 0x72, 0x6E, 0x66, 0x75, 0x6C, 0x6C, + 0x79, 0x2E, 0x20, 0x27, 0x4E, 0x6F, 0x74, 0x20, 0x49, 0x21, + 0x27, 0x20, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, + 0x65, 0x64, 0x2E, 0x20, 0x27, 0x57, 0x65, 0x0D, 0x0A, 0x71, + 0x75, 0x61, 0x72, 0x72, 0x65, 0x6C, 0x6C, 0x65, 0x64, 0x20, + 0x6C, 0x61, 0x73, 0x74, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, + 0x2D, 0x2D, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x66, + 0x6F, 0x72, 0x65, 0x20, 0x48, 0x45, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x6D, 0x61, 0x64, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2D, 0x2D, 0x27, 0x20, 0x28, + 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x0D, 0x0A, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, 0x69, 0x73, 0x20, 0x74, + 0x65, 0x61, 0x20, 0x73, 0x70, 0x6F, 0x6F, 0x6E, 0x20, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, + 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x2C, 0x29, 0x20, 0x27, + 0x2D, 0x2D, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x65, 0x61, + 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x63, 0x65, 0x72, 0x74, 0x0D, + 0x0A, 0x67, 0x69, 0x76, 0x65, 0x6E, 0x20, 0x62, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, + 0x6F, 0x66, 0x20, 0x48, 0x65, 0x61, 0x72, 0x74, 0x73, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x0D, 0x0A, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x77, + 0x69, 0x6E, 0x6B, 0x6C, 0x65, 0x2C, 0x20, 0x74, 0x77, 0x69, + 0x6E, 0x6B, 0x6C, 0x65, 0x2C, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x62, 0x61, 0x74, 0x21, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x48, 0x6F, 0x77, 0x20, 0x49, 0x20, + 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x61, + 0x74, 0x21, 0x22, 0x0D, 0x0A, 0x0D, 0x0A, 0x59, 0x6F, 0x75, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x6F, 0x6E, 0x67, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x68, + 0x61, 0x70, 0x73, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x27, 0x76, 0x65, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, + 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x20, + 0x67, 0x6F, 0x65, 0x73, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x64, + 0x2C, 0x20, 0x27, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x77, 0x61, 0x79, 0x3A, 0x2D, 0x2D, 0x0D, 0x0A, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x55, 0x70, 0x20, + 0x61, 0x62, 0x6F, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x66, 0x6C, 0x79, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x4C, 0x69, 0x6B, 0x65, 0x20, 0x61, 0x20, 0x74, 0x65, + 0x61, 0x2D, 0x74, 0x72, 0x61, 0x79, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x6B, 0x79, 0x2E, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, + 0x77, 0x69, 0x6E, 0x6B, 0x6C, 0x65, 0x2C, 0x20, 0x74, 0x77, + 0x69, 0x6E, 0x6B, 0x6C, 0x65, 0x2D, 0x2D, 0x22, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x48, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, + 0x20, 0x73, 0x68, 0x6F, 0x6F, 0x6B, 0x20, 0x69, 0x74, 0x73, + 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, + 0x65, 0x67, 0x61, 0x6E, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x69, + 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x69, 0x74, 0x73, 0x20, + 0x73, 0x6C, 0x65, 0x65, 0x70, 0x20, 0x27, 0x54, 0x77, 0x69, + 0x6E, 0x6B, 0x6C, 0x65, 0x2C, 0x0D, 0x0A, 0x74, 0x77, 0x69, + 0x6E, 0x6B, 0x6C, 0x65, 0x2C, 0x20, 0x74, 0x77, 0x69, 0x6E, + 0x6B, 0x6C, 0x65, 0x2C, 0x20, 0x74, 0x77, 0x69, 0x6E, 0x6B, + 0x6C, 0x65, 0x2D, 0x2D, 0x27, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x73, 0x6F, + 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x70, 0x69, 0x6E, 0x63, 0x68, 0x0D, 0x0A, + 0x69, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, + 0x20, 0x69, 0x74, 0x20, 0x73, 0x74, 0x6F, 0x70, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x20, + 0x49, 0x27, 0x64, 0x20, 0x68, 0x61, 0x72, 0x64, 0x6C, 0x79, + 0x20, 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, + 0x76, 0x65, 0x72, 0x73, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x2C, 0x20, 0x27, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x51, 0x75, 0x65, 0x65, + 0x6E, 0x20, 0x6A, 0x75, 0x6D, 0x70, 0x65, 0x64, 0x20, 0x75, + 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x61, 0x77, 0x6C, + 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x22, 0x48, + 0x65, 0x27, 0x73, 0x20, 0x6D, 0x75, 0x72, 0x64, 0x65, 0x72, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, + 0x6D, 0x65, 0x21, 0x20, 0x4F, 0x66, 0x66, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x68, 0x65, + 0x61, 0x64, 0x21, 0x22, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x48, 0x6F, 0x77, 0x20, 0x64, 0x72, 0x65, 0x61, 0x64, 0x66, + 0x75, 0x6C, 0x6C, 0x79, 0x20, 0x73, 0x61, 0x76, 0x61, 0x67, + 0x65, 0x21, 0x27, 0x20, 0x65, 0x78, 0x63, 0x6C, 0x61, 0x69, + 0x6D, 0x65, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x6E, 0x64, 0x20, 0x65, + 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x6E, 0x63, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x6D, 0x6F, 0x75, 0x72, 0x6E, 0x66, 0x75, 0x6C, 0x20, + 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x27, 0x68, 0x65, 0x20, + 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x0D, 0x0A, 0x64, 0x6F, 0x20, + 0x61, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x49, 0x20, + 0x61, 0x73, 0x6B, 0x21, 0x20, 0x49, 0x74, 0x27, 0x73, 0x20, + 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x73, 0x69, 0x78, + 0x20, 0x6F, 0x27, 0x63, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6E, + 0x6F, 0x77, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x20, + 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x69, 0x64, 0x65, + 0x61, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x69, 0x6E, 0x74, + 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x27, 0x73, 0x20, + 0x68, 0x65, 0x61, 0x64, 0x2E, 0x20, 0x27, 0x49, 0x73, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x20, 0x73, 0x6F, 0x20, 0x6D, + 0x61, 0x6E, 0x79, 0x0D, 0x0A, 0x74, 0x65, 0x61, 0x2D, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, + 0x70, 0x75, 0x74, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x68, 0x65, + 0x72, 0x65, 0x3F, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x61, + 0x73, 0x6B, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x59, 0x65, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, + 0x73, 0x20, 0x69, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x73, 0x69, 0x67, 0x68, 0x3A, 0x20, 0x27, 0x69, 0x74, 0x27, + 0x73, 0x20, 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x74, + 0x65, 0x61, 0x2D, 0x74, 0x69, 0x6D, 0x65, 0x2C, 0x0D, 0x0A, + 0x61, 0x6E, 0x64, 0x20, 0x77, 0x65, 0x27, 0x76, 0x65, 0x20, + 0x6E, 0x6F, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x77, 0x61, 0x73, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x62, 0x65, 0x74, + 0x77, 0x65, 0x65, 0x6E, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, + 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, + 0x65, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x65, 0x65, + 0x70, 0x20, 0x6D, 0x6F, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x72, + 0x6F, 0x75, 0x6E, 0x64, 0x2C, 0x20, 0x49, 0x20, 0x73, 0x75, + 0x70, 0x70, 0x6F, 0x73, 0x65, 0x3F, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x45, 0x78, 0x61, 0x63, 0x74, 0x6C, + 0x79, 0x20, 0x73, 0x6F, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x3A, 0x20, 0x27, 0x61, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x67, + 0x65, 0x74, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x75, 0x70, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x42, 0x75, 0x74, + 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x70, 0x70, + 0x65, 0x6E, 0x73, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, + 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, + 0x3F, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x76, + 0x65, 0x6E, 0x74, 0x75, 0x72, 0x65, 0x64, 0x0D, 0x0A, 0x74, + 0x6F, 0x20, 0x61, 0x73, 0x6B, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x53, 0x75, 0x70, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, + 0x65, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, + 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x20, 0x69, 0x6E, + 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x65, 0x64, 0x2C, + 0x20, 0x79, 0x61, 0x77, 0x6E, 0x69, 0x6E, 0x67, 0x2E, 0x0D, + 0x0A, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x67, 0x65, 0x74, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x69, 0x72, 0x65, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x20, 0x49, + 0x20, 0x76, 0x6F, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x79, 0x6F, 0x75, 0x6E, 0x67, 0x20, 0x6C, 0x61, 0x64, 0x79, + 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x73, 0x20, 0x75, 0x73, 0x20, + 0x61, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x79, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x61, 0x66, + 0x72, 0x61, 0x69, 0x64, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x6E, + 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x6F, 0x6E, + 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x72, 0x61, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x61, 0x6C, 0x61, 0x72, 0x6D, 0x65, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x70, + 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x61, 0x6C, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, + 0x20, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x21, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, 0x63, + 0x72, 0x69, 0x65, 0x64, 0x2E, 0x20, 0x27, 0x57, 0x61, 0x6B, + 0x65, 0x20, 0x75, 0x70, 0x2C, 0x20, 0x44, 0x6F, 0x72, 0x6D, + 0x6F, 0x75, 0x73, 0x65, 0x21, 0x27, 0x20, 0x41, 0x6E, 0x64, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x79, 0x20, 0x70, 0x69, 0x6E, + 0x63, 0x68, 0x65, 0x64, 0x20, 0x69, 0x74, 0x20, 0x6F, 0x6E, + 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, 0x73, 0x69, 0x64, 0x65, + 0x73, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x44, 0x6F, + 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x73, 0x6C, 0x6F, + 0x77, 0x6C, 0x79, 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x65, 0x64, + 0x20, 0x68, 0x69, 0x73, 0x20, 0x65, 0x79, 0x65, 0x73, 0x2E, + 0x20, 0x27, 0x49, 0x20, 0x77, 0x61, 0x73, 0x6E, 0x27, 0x74, + 0x20, 0x61, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x2C, 0x27, 0x20, + 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x0D, 0x0A, 0x68, 0x6F, 0x61, 0x72, 0x73, 0x65, + 0x2C, 0x20, 0x66, 0x65, 0x65, 0x62, 0x6C, 0x65, 0x20, 0x76, + 0x6F, 0x69, 0x63, 0x65, 0x3A, 0x20, 0x27, 0x49, 0x20, 0x68, + 0x65, 0x61, 0x72, 0x64, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x77, 0x6F, 0x72, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x66, 0x65, 0x6C, 0x6C, 0x6F, 0x77, 0x73, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x20, 0x73, 0x61, 0x79, 0x69, 0x6E, 0x67, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x65, 0x6C, 0x6C, + 0x20, 0x75, 0x73, 0x20, 0x61, 0x20, 0x73, 0x74, 0x6F, 0x72, + 0x79, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, + 0x61, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, + 0x65, 0x73, 0x2C, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x64, 0x6F, 0x21, 0x27, 0x20, 0x70, 0x6C, 0x65, 0x61, + 0x64, 0x65, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x6E, 0x64, 0x20, 0x62, + 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6B, 0x20, 0x61, 0x62, + 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, 0x2C, 0x27, 0x20, 0x61, + 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x2C, 0x20, 0x27, 0x6F, 0x72, + 0x20, 0x79, 0x6F, 0x75, 0x27, 0x6C, 0x6C, 0x20, 0x62, 0x65, + 0x20, 0x61, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x0D, 0x0A, 0x62, 0x65, 0x66, 0x6F, 0x72, + 0x65, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x64, 0x6F, 0x6E, + 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x6E, + 0x63, 0x65, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x61, 0x20, + 0x74, 0x69, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, + 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x73, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x73, 0x2C, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x0D, 0x0A, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, + 0x68, 0x75, 0x72, 0x72, 0x79, 0x3B, 0x20, 0x27, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x6E, 0x61, + 0x6D, 0x65, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x45, + 0x6C, 0x73, 0x69, 0x65, 0x2C, 0x20, 0x4C, 0x61, 0x63, 0x69, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x54, 0x69, 0x6C, + 0x6C, 0x69, 0x65, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x6C, 0x69, 0x76, 0x65, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6F, + 0x74, 0x74, 0x6F, 0x6D, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, + 0x77, 0x65, 0x6C, 0x6C, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, 0x64, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x6C, 0x69, 0x76, 0x65, + 0x20, 0x6F, 0x6E, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x77, 0x68, + 0x6F, 0x20, 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x74, + 0x6F, 0x6F, 0x6B, 0x20, 0x61, 0x20, 0x67, 0x72, 0x65, 0x61, + 0x74, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x65, 0x73, 0x74, + 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x65, 0x61, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, + 0x72, 0x69, 0x6E, 0x6B, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x79, 0x20, 0x6C, 0x69, + 0x76, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x72, 0x65, + 0x61, 0x63, 0x6C, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, + 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x61, 0x66, 0x74, 0x65, + 0x72, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x20, + 0x6F, 0x72, 0x0D, 0x0A, 0x74, 0x77, 0x6F, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x79, 0x20, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x64, 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, + 0x77, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x67, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x72, 0x65, 0x6D, + 0x61, 0x72, 0x6B, 0x65, 0x64, 0x3B, 0x20, 0x27, 0x74, 0x68, + 0x65, 0x79, 0x27, 0x64, 0x0D, 0x0A, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x69, 0x6C, 0x6C, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x77, 0x65, 0x72, 0x65, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x3B, 0x20, + 0x27, 0x56, 0x45, 0x52, 0x59, 0x20, 0x69, 0x6C, 0x6C, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x66, 0x61, 0x6E, 0x63, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x68, + 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x6E, 0x20, + 0x65, 0x78, 0x74, 0x72, 0x61, 0x6F, 0x72, 0x64, 0x69, 0x6E, + 0x61, 0x72, 0x79, 0x20, 0x77, 0x61, 0x79, 0x73, 0x20, 0x6F, + 0x66, 0x0D, 0x0A, 0x6C, 0x69, 0x76, 0x69, 0x6E, 0x67, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, + 0x74, 0x20, 0x70, 0x75, 0x7A, 0x7A, 0x6C, 0x65, 0x64, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x6F, 0x20, 0x6D, 0x75, + 0x63, 0x68, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x3A, 0x20, + 0x27, 0x42, 0x75, 0x74, 0x0D, 0x0A, 0x77, 0x68, 0x79, 0x20, + 0x64, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x6C, + 0x69, 0x76, 0x65, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x6F, 0x74, 0x74, 0x6F, 0x6D, 0x20, 0x6F, 0x66, + 0x20, 0x61, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x3F, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x61, 0x6B, 0x65, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, + 0x65, 0x61, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, + 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2C, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x65, 0x61, 0x72, 0x6E, 0x65, 0x73, 0x74, 0x6C, 0x79, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x76, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x79, 0x65, 0x74, 0x2C, 0x27, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, + 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x20, 0x6F, 0x66, + 0x66, 0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x6E, + 0x65, 0x2C, 0x20, 0x27, 0x73, 0x6F, 0x20, 0x49, 0x20, 0x63, + 0x61, 0x6E, 0x27, 0x74, 0x0D, 0x0A, 0x74, 0x61, 0x6B, 0x65, + 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x65, 0x61, 0x6E, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, + 0x20, 0x74, 0x61, 0x6B, 0x65, 0x20, 0x4C, 0x45, 0x53, 0x53, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x3A, 0x20, + 0x27, 0x69, 0x74, 0x27, 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x65, 0x61, 0x73, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x61, 0x6B, 0x65, 0x0D, 0x0A, 0x4D, 0x4F, 0x52, 0x45, 0x20, + 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, + 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x61, 0x73, 0x6B, 0x65, + 0x64, 0x20, 0x59, 0x4F, 0x55, 0x52, 0x20, 0x6F, 0x70, 0x69, + 0x6E, 0x69, 0x6F, 0x6E, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x6F, 0x27, 0x73, 0x20, 0x6D, + 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x70, 0x65, 0x72, 0x73, + 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x72, + 0x6B, 0x73, 0x20, 0x6E, 0x6F, 0x77, 0x3F, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, + 0x61, 0x73, 0x6B, 0x65, 0x64, 0x20, 0x74, 0x72, 0x69, 0x75, + 0x6D, 0x70, 0x68, 0x61, 0x6E, 0x74, 0x6C, 0x79, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x64, + 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x71, 0x75, 0x69, + 0x74, 0x65, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x69, 0x73, 0x3A, 0x20, 0x73, + 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x65, 0x6C, 0x70, + 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, + 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, + 0x74, 0x65, 0x61, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x72, + 0x65, 0x61, 0x64, 0x2D, 0x61, 0x6E, 0x64, 0x2D, 0x62, 0x75, + 0x74, 0x74, 0x65, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, + 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x0D, 0x0A, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x20, 0x27, 0x57, 0x68, + 0x79, 0x20, 0x64, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x6C, 0x69, 0x76, 0x65, 0x20, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x6F, 0x74, 0x74, 0x6F, 0x6D, 0x20, + 0x6F, 0x66, 0x20, 0x61, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x3F, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x44, + 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x61, + 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x20, 0x6F, 0x72, + 0x20, 0x74, 0x77, 0x6F, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x6B, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, + 0x69, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x6E, 0x0D, 0x0A, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, + 0x27, 0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, + 0x74, 0x72, 0x65, 0x61, 0x63, 0x6C, 0x65, 0x2D, 0x77, 0x65, + 0x6C, 0x6C, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, + 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, + 0x73, 0x75, 0x63, 0x68, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x21, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x6E, 0x69, + 0x6E, 0x67, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x61, 0x6E, + 0x67, 0x72, 0x69, 0x6C, 0x79, 0x2C, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x48, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, + 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x27, 0x53, 0x68, + 0x21, 0x20, 0x73, 0x68, 0x21, 0x27, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, + 0x75, 0x73, 0x65, 0x20, 0x73, 0x75, 0x6C, 0x6B, 0x69, 0x6C, + 0x79, 0x0D, 0x0A, 0x72, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x65, + 0x64, 0x2C, 0x20, 0x27, 0x49, 0x66, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, + 0x63, 0x69, 0x76, 0x69, 0x6C, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x27, 0x64, 0x20, 0x62, 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, + 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x74, 0x6F, 0x72, 0x79, 0x20, 0x66, 0x6F, 0x72, + 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x6C, 0x66, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x2C, + 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x67, 0x6F, + 0x20, 0x6F, 0x6E, 0x21, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x68, 0x75, 0x6D, 0x62, 0x6C, 0x79, 0x3B, 0x20, + 0x27, 0x49, 0x20, 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x69, + 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x20, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x2E, 0x20, 0x49, 0x0D, 0x0A, 0x64, + 0x61, 0x72, 0x65, 0x20, 0x73, 0x61, 0x79, 0x20, 0x74, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x62, 0x65, + 0x20, 0x4F, 0x4E, 0x45, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x4F, 0x6E, 0x65, 0x2C, 0x20, 0x69, 0x6E, 0x64, 0x65, + 0x65, 0x64, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x67, 0x6E, 0x61, + 0x6E, 0x74, 0x6C, 0x79, 0x2E, 0x20, 0x48, 0x6F, 0x77, 0x65, + 0x76, 0x65, 0x72, 0x2C, 0x20, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x6E, 0x73, 0x65, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x74, 0x6F, + 0x0D, 0x0A, 0x67, 0x6F, 0x20, 0x6F, 0x6E, 0x2E, 0x20, 0x27, + 0x41, 0x6E, 0x64, 0x20, 0x73, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x73, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, 0x6C, + 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x73, 0x2D, 0x2D, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x6C, 0x65, 0x61, 0x72, 0x6E, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x72, 0x61, + 0x77, 0x2C, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, + 0x6F, 0x77, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x57, 0x68, 0x61, 0x74, 0x20, 0x64, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x64, 0x72, 0x61, 0x77, 0x3F, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2C, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x66, + 0x6F, 0x72, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6F, 0x6D, 0x69, 0x73, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x72, 0x65, + 0x61, 0x63, 0x6C, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, + 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x6F, 0x75, 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x69, 0x64, + 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x69, + 0x6D, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, + 0x77, 0x61, 0x6E, 0x74, 0x20, 0x61, 0x20, 0x63, 0x6C, 0x65, + 0x61, 0x6E, 0x20, 0x63, 0x75, 0x70, 0x2C, 0x27, 0x20, 0x69, + 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, + 0x72, 0x3A, 0x20, 0x27, 0x6C, 0x65, 0x74, 0x27, 0x73, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x6D, 0x6F, 0x76, 0x65, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x0D, 0x0A, + 0x6F, 0x6E, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x48, 0x65, + 0x20, 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, + 0x61, 0x73, 0x20, 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6B, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x20, + 0x66, 0x6F, 0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, 0x20, 0x68, + 0x69, 0x6D, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, + 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x0D, 0x0A, + 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, + 0x75, 0x73, 0x65, 0x27, 0x73, 0x20, 0x70, 0x6C, 0x61, 0x63, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x75, 0x6E, 0x77, 0x69, 0x6C, 0x6C, 0x69, 0x6E, 0x67, 0x6C, + 0x79, 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, + 0x20, 0x48, 0x61, 0x72, 0x65, 0x2E, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x6E, 0x6C, 0x79, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x67, + 0x6F, 0x74, 0x20, 0x61, 0x6E, 0x79, 0x0D, 0x0A, 0x61, 0x64, + 0x76, 0x61, 0x6E, 0x74, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, + 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x68, 0x61, + 0x6E, 0x67, 0x65, 0x3A, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, + 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x64, 0x65, 0x61, 0x6C, + 0x20, 0x77, 0x6F, 0x72, 0x73, 0x65, 0x20, 0x6F, 0x66, 0x66, + 0x20, 0x74, 0x68, 0x61, 0x6E, 0x0D, 0x0A, 0x62, 0x65, 0x66, + 0x6F, 0x72, 0x65, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, + 0x72, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6A, 0x75, 0x73, + 0x74, 0x20, 0x75, 0x70, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6D, 0x69, 0x6C, 0x6B, 0x2D, 0x6A, 0x75, 0x67, + 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x70, 0x6C, 0x61, 0x74, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x77, 0x69, 0x73, 0x68, 0x20, 0x74, + 0x6F, 0x20, 0x6F, 0x66, 0x66, 0x65, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x73, + 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, + 0x6E, 0x20, 0x76, 0x65, 0x72, 0x79, 0x0D, 0x0A, 0x63, 0x61, + 0x75, 0x74, 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x3A, 0x20, + 0x27, 0x42, 0x75, 0x74, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x6E, + 0x27, 0x74, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x73, 0x74, + 0x61, 0x6E, 0x64, 0x2E, 0x20, 0x57, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x64, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x64, 0x72, 0x61, 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x72, 0x65, 0x61, 0x63, 0x6C, 0x65, 0x0D, 0x0A, 0x66, 0x72, + 0x6F, 0x6D, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, + 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x64, 0x72, 0x61, + 0x77, 0x20, 0x77, 0x61, 0x74, 0x65, 0x72, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x77, 0x61, 0x74, + 0x65, 0x72, 0x2D, 0x77, 0x65, 0x6C, 0x6C, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x3B, 0x20, 0x27, 0x73, 0x6F, + 0x20, 0x49, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x0D, + 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x64, 0x72, 0x61, + 0x77, 0x20, 0x74, 0x72, 0x65, 0x61, 0x63, 0x6C, 0x65, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x74, + 0x72, 0x65, 0x61, 0x63, 0x6C, 0x65, 0x2D, 0x77, 0x65, 0x6C, + 0x6C, 0x2D, 0x2D, 0x65, 0x68, 0x2C, 0x20, 0x73, 0x74, 0x75, + 0x70, 0x69, 0x64, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x42, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x49, 0x4E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x2C, 0x27, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, + 0x6F, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x63, 0x68, 0x6F, 0x6F, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x0D, 0x0A, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, + 0x72, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x4F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, 0x65, 0x72, + 0x65, 0x27, 0x2C, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x3B, 0x20, 0x27, 0x2D, 0x2D, 0x77, 0x65, 0x6C, 0x6C, + 0x20, 0x69, 0x6E, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x68, 0x69, 0x73, 0x20, 0x61, 0x6E, 0x73, 0x77, 0x65, 0x72, + 0x20, 0x73, 0x6F, 0x20, 0x63, 0x6F, 0x6E, 0x66, 0x75, 0x73, + 0x65, 0x64, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x6C, 0x65, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, + 0x20, 0x67, 0x6F, 0x20, 0x6F, 0x6E, 0x20, 0x66, 0x6F, 0x72, + 0x0D, 0x0A, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x69, 0x6D, + 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, + 0x69, 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x69, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x54, 0x68, 0x65, 0x79, 0x20, 0x77, 0x65, 0x72, 0x65, + 0x20, 0x6C, 0x65, 0x61, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x6F, 0x20, 0x64, 0x72, 0x61, 0x77, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, + 0x2C, 0x20, 0x79, 0x61, 0x77, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x72, 0x75, 0x62, 0x62, 0x69, 0x6E, + 0x67, 0x0D, 0x0A, 0x69, 0x74, 0x73, 0x20, 0x65, 0x79, 0x65, + 0x73, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x69, 0x74, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, 0x6C, 0x65, + 0x65, 0x70, 0x79, 0x3B, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x64, 0x72, 0x65, 0x77, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x6D, 0x61, 0x6E, 0x6E, 0x65, 0x72, + 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x73, 0x2D, 0x2D, 0x65, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x62, + 0x65, 0x67, 0x69, 0x6E, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x61, 0x6E, 0x20, 0x4D, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x79, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x61, 0x6E, 0x20, 0x4D, 0x3F, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x79, 0x20, 0x6E, + 0x6F, 0x74, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, + 0x48, 0x61, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, + 0x69, 0x6C, 0x65, 0x6E, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x54, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x63, 0x6C, 0x6F, + 0x73, 0x65, 0x64, 0x20, 0x69, 0x74, 0x73, 0x20, 0x65, 0x79, + 0x65, 0x73, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x74, 0x69, 0x6D, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x66, 0x66, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x0D, + 0x0A, 0x61, 0x20, 0x64, 0x6F, 0x7A, 0x65, 0x3B, 0x20, 0x62, + 0x75, 0x74, 0x2C, 0x20, 0x6F, 0x6E, 0x20, 0x62, 0x65, 0x69, + 0x6E, 0x67, 0x20, 0x70, 0x69, 0x6E, 0x63, 0x68, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x6F, 0x6B, 0x65, 0x20, 0x75, 0x70, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x61, + 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x73, 0x68, + 0x72, 0x69, 0x65, 0x6B, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x3A, 0x20, 0x27, + 0x2D, 0x2D, 0x74, 0x68, 0x61, 0x74, 0x20, 0x62, 0x65, 0x67, + 0x69, 0x6E, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, + 0x6E, 0x20, 0x4D, 0x2C, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x73, 0x0D, 0x0A, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x2D, + 0x74, 0x72, 0x61, 0x70, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, 0x6F, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, + 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x6E, 0x65, 0x73, 0x73, 0x2D, 0x2D, 0x79, 0x6F, 0x75, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x73, 0x61, 0x79, 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x22, 0x6D, 0x75, 0x63, + 0x68, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x6E, 0x65, 0x73, 0x73, 0x22, 0x2D, 0x2D, 0x64, 0x69, + 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x65, 0x76, 0x65, 0x72, + 0x20, 0x73, 0x65, 0x65, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x73, + 0x20, 0x61, 0x0D, 0x0A, 0x64, 0x72, 0x61, 0x77, 0x69, 0x6E, + 0x67, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x6E, 0x65, 0x73, 0x73, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x52, 0x65, 0x61, 0x6C, 0x6C, 0x79, 0x2C, 0x20, + 0x6E, 0x6F, 0x77, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x61, 0x73, + 0x6B, 0x20, 0x6D, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x63, + 0x6F, 0x6E, 0x66, 0x75, 0x73, 0x65, 0x64, 0x2C, 0x20, 0x27, + 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x0D, 0x0A, 0x74, + 0x68, 0x69, 0x6E, 0x6B, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, + 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x72, 0x75, 0x64, 0x65, 0x6E, 0x65, 0x73, 0x73, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x6E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x61, + 0x72, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, 0x67, 0x6F, 0x74, + 0x20, 0x75, 0x70, 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x67, 0x72, + 0x65, 0x61, 0x74, 0x20, 0x64, 0x69, 0x73, 0x67, 0x75, 0x73, + 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, 0x6C, + 0x6B, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x3B, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x20, 0x66, 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x73, 0x6C, + 0x65, 0x65, 0x70, 0x20, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, + 0x74, 0x6C, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, + 0x6E, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x73, 0x20, 0x74, 0x6F, 0x6F, 0x6B, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6C, 0x65, 0x61, 0x73, 0x74, 0x20, 0x6E, 0x6F, 0x74, + 0x69, 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, + 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x62, 0x61, 0x63, + 0x6B, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x6F, 0x72, 0x20, + 0x74, 0x77, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x68, 0x61, 0x6C, + 0x66, 0x20, 0x68, 0x6F, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x20, + 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x68, 0x65, 0x72, 0x3A, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, + 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x73, 0x61, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, + 0x74, 0x72, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, + 0x70, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, + 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x74, + 0x6F, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x61, + 0x70, 0x6F, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, + 0x74, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x72, 0x61, 0x74, 0x65, + 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x6E, 0x65, 0x76, 0x65, + 0x72, 0x20, 0x67, 0x6F, 0x20, 0x54, 0x48, 0x45, 0x52, 0x45, + 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x21, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x70, 0x69, 0x63, + 0x6B, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x77, + 0x61, 0x79, 0x20, 0x74, 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x6F, 0x64, 0x2E, + 0x20, 0x27, 0x49, 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x74, 0x75, 0x70, 0x69, 0x64, 0x65, 0x73, 0x74, + 0x20, 0x74, 0x65, 0x61, 0x2D, 0x70, 0x61, 0x72, 0x74, 0x79, + 0x20, 0x49, 0x20, 0x65, 0x76, 0x65, 0x72, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x61, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6C, + 0x6C, 0x0D, 0x0A, 0x6D, 0x79, 0x20, 0x6C, 0x69, 0x66, 0x65, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x4A, 0x75, 0x73, 0x74, + 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x65, + 0x65, 0x73, 0x20, 0x68, 0x61, 0x64, 0x20, 0x61, 0x20, 0x64, + 0x6F, 0x6F, 0x72, 0x0D, 0x0A, 0x6C, 0x65, 0x61, 0x64, 0x69, + 0x6E, 0x67, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x69, + 0x6E, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x2E, 0x20, 0x27, 0x54, + 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x21, 0x27, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x2E, 0x20, 0x27, 0x42, 0x75, 0x74, 0x0D, 0x0A, + 0x65, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x27, 0x73, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, + 0x20, 0x74, 0x6F, 0x64, 0x61, 0x79, 0x2E, 0x20, 0x49, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x49, 0x20, 0x6D, 0x61, + 0x79, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, + 0x67, 0x6F, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x74, 0x20, 0x6F, + 0x6E, 0x63, 0x65, 0x2E, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, + 0x69, 0x6E, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x4F, 0x6E, 0x63, + 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x68, 0x61, 0x6C, + 0x6C, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x6C, 0x6F, + 0x73, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x0D, 0x0A, 0x67, 0x6C, + 0x61, 0x73, 0x73, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x2E, + 0x20, 0x27, 0x4E, 0x6F, 0x77, 0x2C, 0x20, 0x49, 0x27, 0x6C, + 0x6C, 0x20, 0x6D, 0x61, 0x6E, 0x61, 0x67, 0x65, 0x20, 0x62, + 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x74, 0x69, 0x6D, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x0D, 0x0A, + 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, + 0x62, 0x79, 0x20, 0x74, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x67, 0x6F, 0x6C, 0x64, 0x65, 0x6E, 0x20, 0x6B, 0x65, + 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x75, 0x6E, 0x6C, + 0x6F, 0x63, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x64, 0x6F, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x0D, 0x0A, 0x6C, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, + 0x6E, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x6E, 0x69, 0x62, 0x62, 0x6C, + 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6D, 0x75, 0x73, 0x68, 0x72, 0x6F, 0x6F, 0x6D, 0x20, + 0x28, 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x68, 0x61, 0x64, 0x20, + 0x6B, 0x65, 0x70, 0x74, 0x20, 0x61, 0x20, 0x70, 0x69, 0x65, + 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x20, 0x69, + 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, 0x70, 0x6F, 0x63, 0x6B, + 0x65, 0x74, 0x29, 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x61, 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x20, + 0x68, 0x69, 0x67, 0x68, 0x3A, 0x0D, 0x0A, 0x74, 0x68, 0x65, + 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x6C, 0x6B, + 0x65, 0x64, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x70, + 0x61, 0x73, 0x73, 0x61, 0x67, 0x65, 0x3A, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x54, 0x48, 0x45, 0x4E, 0x2D, 0x2D, 0x73, 0x68, + 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x61, 0x74, 0x0D, 0x0A, + 0x6C, 0x61, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, + 0x6C, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x2C, 0x20, + 0x61, 0x6D, 0x6F, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x66, 0x6C, 0x6F, + 0x77, 0x65, 0x72, 0x2D, 0x62, 0x65, 0x64, 0x73, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6F, + 0x6C, 0x0D, 0x0A, 0x66, 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, + 0x6E, 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x0D, 0x0A, 0x43, 0x48, 0x41, 0x50, 0x54, 0x45, 0x52, + 0x20, 0x56, 0x49, 0x49, 0x49, 0x2E, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x27, 0x73, 0x20, 0x43, + 0x72, 0x6F, 0x71, 0x75, 0x65, 0x74, 0x2D, 0x47, 0x72, 0x6F, + 0x75, 0x6E, 0x64, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x20, 0x6C, + 0x61, 0x72, 0x67, 0x65, 0x20, 0x72, 0x6F, 0x73, 0x65, 0x2D, + 0x74, 0x72, 0x65, 0x65, 0x20, 0x73, 0x74, 0x6F, 0x6F, 0x64, + 0x20, 0x6E, 0x65, 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x65, 0x6E, 0x74, 0x72, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, + 0x65, 0x6E, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, + 0x73, 0x65, 0x73, 0x0D, 0x0A, 0x67, 0x72, 0x6F, 0x77, 0x69, + 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x2C, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, + 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x65, 0x72, + 0x73, 0x20, 0x61, 0x74, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x62, + 0x75, 0x73, 0x69, 0x6C, 0x79, 0x0D, 0x0A, 0x70, 0x61, 0x69, + 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x6D, + 0x20, 0x72, 0x65, 0x64, 0x2E, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x0D, + 0x0A, 0x6E, 0x65, 0x61, 0x72, 0x65, 0x72, 0x20, 0x74, 0x6F, + 0x20, 0x77, 0x61, 0x74, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x6D, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6A, 0x75, 0x73, + 0x74, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, + 0x61, 0x6D, 0x65, 0x20, 0x75, 0x70, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x6D, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, + 0x65, 0x61, 0x72, 0x64, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, + 0x66, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x73, 0x61, + 0x79, 0x2C, 0x20, 0x27, 0x4C, 0x6F, 0x6F, 0x6B, 0x20, 0x6F, + 0x75, 0x74, 0x20, 0x6E, 0x6F, 0x77, 0x2C, 0x20, 0x46, 0x69, + 0x76, 0x65, 0x21, 0x20, 0x44, 0x6F, 0x6E, 0x27, 0x74, 0x20, + 0x67, 0x6F, 0x20, 0x73, 0x70, 0x6C, 0x61, 0x73, 0x68, 0x69, + 0x6E, 0x67, 0x20, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x20, 0x6F, + 0x76, 0x65, 0x72, 0x20, 0x6D, 0x65, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x21, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x63, 0x6F, 0x75, 0x6C, + 0x64, 0x6E, 0x27, 0x74, 0x20, 0x68, 0x65, 0x6C, 0x70, 0x20, + 0x69, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x46, 0x69, 0x76, 0x65, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x73, 0x75, 0x6C, 0x6B, 0x79, 0x20, 0x74, 0x6F, 0x6E, + 0x65, 0x3B, 0x20, 0x27, 0x53, 0x65, 0x76, 0x65, 0x6E, 0x20, + 0x6A, 0x6F, 0x67, 0x67, 0x65, 0x64, 0x20, 0x6D, 0x79, 0x0D, + 0x0A, 0x65, 0x6C, 0x62, 0x6F, 0x77, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x4F, 0x6E, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, + 0x20, 0x53, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x6C, 0x6F, 0x6F, + 0x6B, 0x65, 0x64, 0x20, 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x27, 0x54, 0x68, + 0x61, 0x74, 0x27, 0x73, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x2C, 0x20, 0x46, 0x69, 0x76, 0x65, 0x21, 0x20, 0x41, 0x6C, + 0x77, 0x61, 0x79, 0x73, 0x20, 0x6C, 0x61, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x0D, 0x0A, 0x62, 0x6C, 0x61, 0x6D, 0x65, 0x20, + 0x6F, 0x6E, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x73, 0x21, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x4F, 0x55, 0x27, + 0x44, 0x20, 0x62, 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x21, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x46, 0x69, 0x76, 0x65, 0x2E, + 0x20, 0x27, 0x49, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, + 0x73, 0x61, 0x79, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x0D, 0x0A, + 0x79, 0x65, 0x73, 0x74, 0x65, 0x72, 0x64, 0x61, 0x79, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x64, 0x65, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x62, + 0x65, 0x68, 0x65, 0x61, 0x64, 0x65, 0x64, 0x21, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, 0x66, + 0x6F, 0x72, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x77, 0x68, + 0x6F, 0x20, 0x68, 0x61, 0x64, 0x20, 0x73, 0x70, 0x6F, 0x6B, + 0x65, 0x6E, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, 0x74, 0x27, 0x73, + 0x20, 0x6E, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x59, + 0x4F, 0x55, 0x52, 0x20, 0x62, 0x75, 0x73, 0x69, 0x6E, 0x65, + 0x73, 0x73, 0x2C, 0x20, 0x54, 0x77, 0x6F, 0x21, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x53, 0x65, 0x76, 0x65, 0x6E, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x65, 0x73, 0x2C, + 0x20, 0x69, 0x74, 0x20, 0x49, 0x53, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x62, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x46, 0x69, 0x76, + 0x65, 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x27, + 0x6C, 0x6C, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x68, 0x69, + 0x6D, 0x2D, 0x2D, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x66, 0x6F, 0x72, 0x0D, 0x0A, 0x62, 0x72, 0x69, 0x6E, 0x67, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x6F, 0x6B, 0x20, 0x74, 0x75, 0x6C, 0x69, 0x70, 0x2D, 0x72, + 0x6F, 0x6F, 0x74, 0x73, 0x20, 0x69, 0x6E, 0x73, 0x74, 0x65, + 0x61, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x6F, 0x6E, 0x69, 0x6F, + 0x6E, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x65, + 0x76, 0x65, 0x6E, 0x20, 0x66, 0x6C, 0x75, 0x6E, 0x67, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x68, 0x69, 0x73, 0x20, 0x62, + 0x72, 0x75, 0x73, 0x68, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x62, + 0x65, 0x67, 0x75, 0x6E, 0x20, 0x27, 0x57, 0x65, 0x6C, 0x6C, + 0x2C, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x75, 0x6E, 0x6A, 0x75, 0x73, 0x74, 0x0D, + 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x2D, 0x2D, 0x27, + 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x65, 0x79, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x63, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x20, + 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, + 0x74, 0x6F, 0x6F, 0x64, 0x20, 0x77, 0x61, 0x74, 0x63, 0x68, + 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x6D, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x20, 0x63, 0x68, + 0x65, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x68, 0x69, 0x6D, 0x73, + 0x65, 0x6C, 0x66, 0x20, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, + 0x6C, 0x79, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, + 0x68, 0x65, 0x72, 0x73, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, + 0x64, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x61, 0x6C, + 0x73, 0x6F, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x61, + 0x6C, 0x6C, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, + 0x20, 0x62, 0x6F, 0x77, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x77, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x74, 0x65, 0x6C, 0x6C, + 0x20, 0x6D, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x74, 0x69, 0x6D, + 0x69, 0x64, 0x6C, 0x79, 0x2C, 0x20, 0x27, 0x77, 0x68, 0x79, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x61, 0x72, 0x65, 0x20, 0x70, + 0x61, 0x69, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x74, + 0x68, 0x6F, 0x73, 0x65, 0x20, 0x72, 0x6F, 0x73, 0x65, 0x73, + 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x46, 0x69, 0x76, 0x65, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x53, 0x65, 0x76, 0x65, 0x6E, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x54, + 0x77, 0x6F, 0x2E, 0x20, 0x54, 0x77, 0x6F, 0x20, 0x62, 0x65, + 0x67, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6C, + 0x6F, 0x77, 0x0D, 0x0A, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2C, + 0x20, 0x27, 0x57, 0x68, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x66, 0x61, 0x63, 0x74, 0x20, 0x69, 0x73, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x73, 0x65, 0x65, 0x2C, 0x20, 0x4D, 0x69, + 0x73, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, + 0x65, 0x6E, 0x20, 0x61, 0x0D, 0x0A, 0x52, 0x45, 0x44, 0x20, + 0x72, 0x6F, 0x73, 0x65, 0x2D, 0x74, 0x72, 0x65, 0x65, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x65, 0x20, 0x70, 0x75, + 0x74, 0x20, 0x61, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, 0x20, + 0x6F, 0x6E, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x62, 0x79, 0x20, + 0x6D, 0x69, 0x73, 0x74, 0x61, 0x6B, 0x65, 0x3B, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x0D, 0x0A, 0x77, 0x61, 0x73, + 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, 0x69, + 0x74, 0x20, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x77, 0x65, 0x20, + 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6F, 0x75, 0x72, 0x20, + 0x68, 0x65, 0x61, 0x64, 0x73, 0x20, 0x63, 0x75, 0x74, 0x20, + 0x6F, 0x66, 0x66, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, + 0x6E, 0x6F, 0x77, 0x2E, 0x0D, 0x0A, 0x53, 0x6F, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x73, 0x65, 0x65, 0x2C, 0x20, 0x4D, 0x69, + 0x73, 0x73, 0x2C, 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, 0x20, + 0x64, 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x75, 0x72, 0x20, + 0x62, 0x65, 0x73, 0x74, 0x2C, 0x20, 0x61, 0x66, 0x6F, 0x72, + 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6D, 0x65, + 0x73, 0x2C, 0x20, 0x74, 0x6F, 0x2D, 0x2D, 0x27, 0x20, 0x41, + 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x6D, 0x6F, + 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x46, 0x69, 0x76, 0x65, 0x2C, + 0x20, 0x77, 0x68, 0x6F, 0x20, 0x68, 0x61, 0x64, 0x20, 0x62, + 0x65, 0x65, 0x6E, 0x20, 0x61, 0x6E, 0x78, 0x69, 0x6F, 0x75, + 0x73, 0x6C, 0x79, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x2C, + 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x0D, 0x0A, 0x6F, + 0x75, 0x74, 0x20, 0x27, 0x54, 0x68, 0x65, 0x20, 0x51, 0x75, + 0x65, 0x65, 0x6E, 0x21, 0x20, 0x54, 0x68, 0x65, 0x20, 0x51, + 0x75, 0x65, 0x65, 0x6E, 0x21, 0x27, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, + 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x65, 0x72, 0x73, + 0x20, 0x69, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x6C, 0x79, + 0x20, 0x74, 0x68, 0x72, 0x65, 0x77, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x6D, 0x73, 0x65, 0x6C, 0x76, 0x65, 0x73, 0x20, 0x66, + 0x6C, 0x61, 0x74, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x69, 0x72, 0x20, 0x66, 0x61, 0x63, 0x65, 0x73, + 0x2E, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x61, 0x20, 0x73, 0x6F, 0x75, 0x6E, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x6D, 0x61, 0x6E, 0x79, 0x20, 0x66, 0x6F, + 0x6F, 0x74, 0x73, 0x74, 0x65, 0x70, 0x73, 0x2C, 0x0D, 0x0A, + 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x72, 0x6F, 0x75, + 0x6E, 0x64, 0x2C, 0x20, 0x65, 0x61, 0x67, 0x65, 0x72, 0x20, + 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x63, 0x61, 0x6D, + 0x65, 0x20, 0x74, 0x65, 0x6E, 0x20, 0x73, 0x6F, 0x6C, 0x64, + 0x69, 0x65, 0x72, 0x73, 0x20, 0x63, 0x61, 0x72, 0x72, 0x79, + 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6C, 0x75, 0x62, 0x73, 0x3B, + 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x77, 0x65, 0x72, + 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x68, 0x61, 0x70, + 0x65, 0x64, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, 0x67, + 0x61, 0x72, 0x64, 0x65, 0x6E, 0x65, 0x72, 0x73, 0x2C, 0x20, + 0x6F, 0x62, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x66, 0x6C, 0x61, 0x74, 0x2C, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x68, 0x61, + 0x6E, 0x64, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x65, + 0x65, 0x74, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x63, 0x6F, 0x72, 0x6E, 0x65, 0x72, 0x73, 0x3A, 0x20, + 0x6E, 0x65, 0x78, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x65, 0x6E, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x74, 0x69, 0x65, + 0x72, 0x73, 0x3B, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x6F, 0x72, 0x6E, 0x61, 0x6D, + 0x65, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x6F, 0x76, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, + 0x0A, 0x64, 0x69, 0x61, 0x6D, 0x6F, 0x6E, 0x64, 0x73, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, 0x6C, 0x6B, 0x65, + 0x64, 0x20, 0x74, 0x77, 0x6F, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x77, 0x6F, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x6F, 0x6C, 0x64, 0x69, 0x65, 0x72, 0x73, + 0x20, 0x64, 0x69, 0x64, 0x2E, 0x20, 0x41, 0x66, 0x74, 0x65, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x63, 0x61, + 0x6D, 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, + 0x79, 0x61, 0x6C, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, + 0x65, 0x6E, 0x3B, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x74, 0x65, 0x6E, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x64, 0x65, 0x61, 0x72, 0x73, 0x20, 0x63, + 0x61, 0x6D, 0x65, 0x0D, 0x0A, 0x6A, 0x75, 0x6D, 0x70, 0x69, + 0x6E, 0x67, 0x20, 0x6D, 0x65, 0x72, 0x72, 0x69, 0x6C, 0x79, + 0x20, 0x61, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x68, 0x61, 0x6E, + 0x64, 0x20, 0x69, 0x6E, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x2C, + 0x20, 0x69, 0x6E, 0x20, 0x63, 0x6F, 0x75, 0x70, 0x6C, 0x65, + 0x73, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6F, 0x72, 0x6E, + 0x61, 0x6D, 0x65, 0x6E, 0x74, 0x65, 0x64, 0x0D, 0x0A, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x68, 0x65, 0x61, 0x72, 0x74, 0x73, + 0x2E, 0x20, 0x4E, 0x65, 0x78, 0x74, 0x20, 0x63, 0x61, 0x6D, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x75, 0x65, 0x73, + 0x74, 0x73, 0x2C, 0x20, 0x6D, 0x6F, 0x73, 0x74, 0x6C, 0x79, + 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x73, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x6D, 0x6F, 0x6E, 0x67, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x6D, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x72, 0x65, 0x63, 0x6F, 0x67, 0x6E, 0x69, 0x73, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, 0x69, 0x74, + 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x3A, 0x20, + 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x61, 0x6C, + 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, + 0x68, 0x75, 0x72, 0x72, 0x69, 0x65, 0x64, 0x0D, 0x0A, 0x6E, + 0x65, 0x72, 0x76, 0x6F, 0x75, 0x73, 0x20, 0x6D, 0x61, 0x6E, + 0x6E, 0x65, 0x72, 0x2C, 0x20, 0x73, 0x6D, 0x69, 0x6C, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x65, 0x76, 0x65, 0x72, + 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x65, 0x6E, 0x74, + 0x20, 0x62, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, + 0x74, 0x0D, 0x0A, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x69, 0x6E, + 0x67, 0x20, 0x68, 0x65, 0x72, 0x2E, 0x20, 0x54, 0x68, 0x65, + 0x6E, 0x20, 0x66, 0x6F, 0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x6E, 0x61, 0x76, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x48, 0x65, 0x61, 0x72, 0x74, 0x73, + 0x2C, 0x20, 0x63, 0x61, 0x72, 0x72, 0x79, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x27, + 0x73, 0x0D, 0x0A, 0x63, 0x72, 0x6F, 0x77, 0x6E, 0x20, 0x6F, + 0x6E, 0x20, 0x61, 0x20, 0x63, 0x72, 0x69, 0x6D, 0x73, 0x6F, + 0x6E, 0x20, 0x76, 0x65, 0x6C, 0x76, 0x65, 0x74, 0x20, 0x63, + 0x75, 0x73, 0x68, 0x69, 0x6F, 0x6E, 0x3B, 0x20, 0x61, 0x6E, + 0x64, 0x2C, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x6F, 0x66, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x67, 0x72, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x70, 0x72, 0x6F, + 0x63, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x63, + 0x61, 0x6D, 0x65, 0x20, 0x54, 0x48, 0x45, 0x20, 0x4B, 0x49, + 0x4E, 0x47, 0x20, 0x41, 0x4E, 0x44, 0x20, 0x51, 0x55, 0x45, + 0x45, 0x4E, 0x20, 0x4F, 0x46, 0x20, 0x48, 0x45, 0x41, 0x52, + 0x54, 0x53, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x72, 0x61, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x64, 0x6F, 0x75, 0x62, 0x74, 0x66, + 0x75, 0x6C, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x6F, 0x75, 0x67, 0x68, 0x74, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x69, + 0x65, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x6F, 0x6E, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x66, 0x61, 0x63, 0x65, 0x0D, 0x0A, + 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x68, 0x72, 0x65, 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, + 0x6E, 0x65, 0x72, 0x73, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, + 0x65, 0x72, 0x20, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, 0x61, + 0x76, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, + 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x72, 0x75, 0x6C, 0x65, 0x20, 0x61, 0x74, 0x20, + 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, + 0x73, 0x3B, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, + 0x73, 0x69, 0x64, 0x65, 0x73, 0x2C, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6F, + 0x66, 0x0D, 0x0A, 0x61, 0x20, 0x70, 0x72, 0x6F, 0x63, 0x65, + 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x2C, 0x27, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x73, 0x68, 0x65, 0x2C, + 0x20, 0x27, 0x69, 0x66, 0x20, 0x70, 0x65, 0x6F, 0x70, 0x6C, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x74, 0x6F, 0x20, 0x6C, 0x69, 0x65, 0x20, 0x64, 0x6F, 0x77, + 0x6E, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x0D, 0x0A, 0x66, 0x61, 0x63, 0x65, 0x73, 0x2C, + 0x20, 0x73, 0x6F, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x6E, + 0x27, 0x74, 0x20, 0x73, 0x65, 0x65, 0x20, 0x69, 0x74, 0x3F, + 0x27, 0x20, 0x53, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, + 0x74, 0x6F, 0x6F, 0x64, 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, + 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x2C, 0x0D, 0x0A, 0x61, 0x6E, 0x64, + 0x20, 0x77, 0x61, 0x69, 0x74, 0x65, 0x64, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x57, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6F, + 0x6E, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x6F, 0x70, 0x70, + 0x6F, 0x73, 0x69, 0x74, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x74, 0x6F, 0x70, 0x70, + 0x65, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6F, + 0x6B, 0x65, 0x64, 0x0D, 0x0A, 0x61, 0x74, 0x20, 0x68, 0x65, + 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x73, 0x65, 0x76, 0x65, 0x72, 0x65, 0x6C, 0x79, + 0x20, 0x27, 0x57, 0x68, 0x6F, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x3F, 0x27, 0x20, 0x53, 0x68, 0x65, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x4B, 0x6E, 0x61, 0x76, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x48, 0x65, 0x61, 0x72, 0x74, + 0x73, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x6F, 0x6E, 0x6C, + 0x79, 0x20, 0x62, 0x6F, 0x77, 0x65, 0x64, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x73, 0x6D, 0x69, 0x6C, 0x65, 0x64, 0x20, 0x69, + 0x6E, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x79, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x49, 0x64, 0x69, 0x6F, 0x74, 0x21, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, 0x74, 0x6F, 0x73, + 0x73, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, + 0x65, 0x61, 0x64, 0x20, 0x69, 0x6D, 0x70, 0x61, 0x74, 0x69, + 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x3B, 0x20, 0x61, 0x6E, 0x64, + 0x2C, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x6F, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, + 0x6F, 0x6E, 0x2C, 0x20, 0x27, 0x57, 0x68, 0x61, 0x74, 0x27, + 0x73, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x6E, 0x61, 0x6D, + 0x65, 0x2C, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x3F, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4D, 0x79, 0x20, 0x6E, 0x61, + 0x6D, 0x65, 0x20, 0x69, 0x73, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x70, 0x6C, 0x65, 0x61, + 0x73, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x4D, 0x61, + 0x6A, 0x65, 0x73, 0x74, 0x79, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x70, 0x6F, 0x6C, 0x69, 0x74, 0x65, + 0x6C, 0x79, 0x3B, 0x0D, 0x0A, 0x62, 0x75, 0x74, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x2C, 0x20, + 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, + 0x2C, 0x20, 0x27, 0x57, 0x68, 0x79, 0x2C, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x27, 0x72, 0x65, 0x20, 0x6F, 0x6E, 0x6C, 0x79, + 0x20, 0x61, 0x20, 0x70, 0x61, 0x63, 0x6B, 0x20, 0x6F, 0x66, + 0x20, 0x63, 0x61, 0x72, 0x64, 0x73, 0x2C, 0x20, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x0D, 0x0A, 0x61, 0x6C, 0x6C, 0x2E, 0x20, + 0x49, 0x20, 0x6E, 0x65, 0x65, 0x64, 0x6E, 0x27, 0x74, 0x20, + 0x62, 0x65, 0x20, 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x21, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x6E, 0x64, 0x20, 0x77, 0x68, + 0x6F, 0x20, 0x61, 0x72, 0x65, 0x20, 0x54, 0x48, 0x45, 0x53, + 0x45, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, + 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, + 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x65, 0x72, + 0x73, 0x20, 0x77, 0x68, 0x6F, 0x0D, 0x0A, 0x77, 0x65, 0x72, + 0x65, 0x20, 0x6C, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x72, 0x6F, + 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, + 0x73, 0x65, 0x74, 0x72, 0x65, 0x65, 0x3B, 0x20, 0x66, 0x6F, + 0x72, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x73, 0x65, 0x65, + 0x2C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x6C, 0x79, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x0D, + 0x0A, 0x66, 0x61, 0x63, 0x65, 0x73, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x6E, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x73, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, + 0x65, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x65, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x70, 0x61, 0x63, 0x6B, 0x2C, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x77, 0x68, 0x65, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, + 0x6E, 0x65, 0x72, 0x73, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x73, + 0x6F, 0x6C, 0x64, 0x69, 0x65, 0x72, 0x73, 0x2C, 0x20, 0x6F, + 0x72, 0x0D, 0x0A, 0x63, 0x6F, 0x75, 0x72, 0x74, 0x69, 0x65, + 0x72, 0x73, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x72, + 0x65, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x6F, 0x77, 0x6E, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, + 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x6F, + 0x77, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x49, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x3F, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x73, 0x75, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x64, 0x20, + 0x61, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x6F, 0x77, 0x6E, + 0x20, 0x63, 0x6F, 0x75, 0x72, 0x61, 0x67, 0x65, 0x2E, 0x20, + 0x27, 0x49, 0x74, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x0D, 0x0A, + 0x62, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x20, 0x6F, + 0x66, 0x20, 0x4D, 0x49, 0x4E, 0x45, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, + 0x6E, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, 0x63, + 0x72, 0x69, 0x6D, 0x73, 0x6F, 0x6E, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x66, 0x75, 0x72, 0x79, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x2C, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x67, + 0x6C, 0x61, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x0D, + 0x0A, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x6C, 0x69, + 0x6B, 0x65, 0x20, 0x61, 0x20, 0x77, 0x69, 0x6C, 0x64, 0x20, + 0x62, 0x65, 0x61, 0x73, 0x74, 0x2C, 0x20, 0x73, 0x63, 0x72, + 0x65, 0x61, 0x6D, 0x65, 0x64, 0x20, 0x27, 0x4F, 0x66, 0x66, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x68, 0x65, 0x61, 0x64, 0x21, 0x20, 0x4F, 0x66, 0x66, 0x2D, + 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x6E, + 0x73, 0x65, 0x6E, 0x73, 0x65, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x6C, 0x6F, 0x75, 0x64, 0x6C, + 0x79, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x65, 0x63, 0x69, + 0x64, 0x65, 0x64, 0x6C, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, + 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, 0x73, 0x69, 0x6C, 0x65, + 0x6E, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, + 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x6C, 0x61, 0x69, 0x64, + 0x20, 0x68, 0x69, 0x73, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x20, + 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, + 0x72, 0x6D, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x69, + 0x6D, 0x69, 0x64, 0x6C, 0x79, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x27, 0x43, 0x6F, 0x6E, 0x73, 0x69, 0x64, 0x65, 0x72, + 0x2C, 0x20, 0x6D, 0x79, 0x0D, 0x0A, 0x64, 0x65, 0x61, 0x72, + 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6F, + 0x6E, 0x6C, 0x79, 0x20, 0x61, 0x20, 0x63, 0x68, 0x69, 0x6C, + 0x64, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x74, 0x75, 0x72, + 0x6E, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x67, 0x72, 0x69, 0x6C, + 0x79, 0x20, 0x61, 0x77, 0x61, 0x79, 0x20, 0x66, 0x72, 0x6F, + 0x6D, 0x20, 0x68, 0x69, 0x6D, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4B, 0x6E, 0x61, 0x76, 0x65, 0x20, 0x27, + 0x54, 0x75, 0x72, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x0D, + 0x0A, 0x6F, 0x76, 0x65, 0x72, 0x21, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x65, 0x20, 0x4B, 0x6E, 0x61, 0x76, 0x65, + 0x20, 0x64, 0x69, 0x64, 0x20, 0x73, 0x6F, 0x2C, 0x20, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x63, 0x61, 0x72, 0x65, 0x66, 0x75, + 0x6C, 0x6C, 0x79, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x6F, 0x6E, 0x65, 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x47, 0x65, 0x74, 0x20, 0x75, 0x70, + 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x73, 0x68, 0x72, 0x69, 0x6C, 0x6C, + 0x2C, 0x20, 0x6C, 0x6F, 0x75, 0x64, 0x20, 0x76, 0x6F, 0x69, + 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x0D, 0x0A, 0x67, + 0x61, 0x72, 0x64, 0x65, 0x6E, 0x65, 0x72, 0x73, 0x20, 0x69, + 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x6A, + 0x75, 0x6D, 0x70, 0x65, 0x64, 0x20, 0x75, 0x70, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, + 0x62, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, 0x79, 0x61, + 0x6C, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, 0x65, 0x6E, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x65, 0x76, 0x65, 0x72, + 0x79, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x65, 0x6C, 0x73, 0x65, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4C, 0x65, 0x61, 0x76, + 0x65, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x21, 0x27, 0x20, 0x73, 0x63, 0x72, 0x65, 0x61, 0x6D, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, + 0x6E, 0x2E, 0x20, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x61, + 0x6B, 0x65, 0x20, 0x6D, 0x65, 0x20, 0x67, 0x69, 0x64, 0x64, + 0x79, 0x2E, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x6E, 0x2C, 0x0D, 0x0A, 0x74, 0x75, 0x72, 0x6E, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x72, 0x6F, 0x73, 0x65, 0x2D, 0x74, 0x72, 0x65, 0x65, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, + 0x6F, 0x6E, 0x2C, 0x20, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, + 0x48, 0x41, 0x56, 0x45, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x62, + 0x65, 0x65, 0x6E, 0x20, 0x64, 0x6F, 0x69, 0x6E, 0x67, 0x20, + 0x68, 0x65, 0x72, 0x65, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x4D, 0x61, 0x79, 0x20, 0x69, 0x74, 0x20, 0x70, 0x6C, + 0x65, 0x61, 0x73, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, + 0x4D, 0x61, 0x6A, 0x65, 0x73, 0x74, 0x79, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x54, 0x77, 0x6F, 0x2C, 0x20, + 0x69, 0x6E, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x68, 0x75, 0x6D, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x6F, 0x6E, + 0x65, 0x2C, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x0D, 0x0A, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x6F, 0x6E, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x6B, 0x6E, 0x65, 0x65, 0x20, 0x61, 0x73, 0x20, + 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6B, 0x65, 0x2C, 0x20, + 0x27, 0x77, 0x65, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x74, + 0x72, 0x79, 0x69, 0x6E, 0x67, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x73, 0x65, 0x65, 0x21, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, 0x77, 0x68, 0x6F, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x77, + 0x68, 0x69, 0x6C, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, + 0x65, 0x78, 0x61, 0x6D, 0x69, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, 0x73, 0x65, 0x73, 0x2E, + 0x0D, 0x0A, 0x27, 0x4F, 0x66, 0x66, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x68, 0x65, + 0x61, 0x64, 0x73, 0x21, 0x27, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, + 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6D, 0x6F, 0x76, 0x65, 0x64, + 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x73, + 0x6F, 0x6C, 0x64, 0x69, 0x65, 0x72, 0x73, 0x20, 0x72, 0x65, + 0x6D, 0x61, 0x69, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x65, + 0x68, 0x69, 0x6E, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x75, 0x6E, 0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x61, 0x74, + 0x65, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x65, 0x72, + 0x73, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x72, 0x61, 0x6E, + 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x65, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x59, 0x6F, 0x75, 0x20, 0x73, 0x68, 0x61, 0x6E, 0x27, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x62, 0x65, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x64, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x70, 0x75, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x6D, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, + 0x61, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x0D, 0x0A, 0x66, + 0x6C, 0x6F, 0x77, 0x65, 0x72, 0x2D, 0x70, 0x6F, 0x74, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x74, 0x6F, 0x6F, 0x64, + 0x20, 0x6E, 0x65, 0x61, 0x72, 0x2E, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, 0x73, 0x6F, 0x6C, + 0x64, 0x69, 0x65, 0x72, 0x73, 0x20, 0x77, 0x61, 0x6E, 0x64, + 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x0D, 0x0A, 0x6D, 0x69, + 0x6E, 0x75, 0x74, 0x65, 0x20, 0x6F, 0x72, 0x20, 0x74, 0x77, + 0x6F, 0x2C, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, + 0x71, 0x75, 0x69, 0x65, 0x74, 0x6C, 0x79, 0x20, 0x6D, 0x61, + 0x72, 0x63, 0x68, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x20, + 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x73, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x41, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, 0x73, 0x20, 0x6F, + 0x66, 0x66, 0x3F, 0x27, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x74, + 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, + 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, + 0x65, 0x69, 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, 0x73, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x67, 0x6F, 0x6E, 0x65, 0x2C, 0x20, + 0x69, 0x66, 0x20, 0x69, 0x74, 0x20, 0x70, 0x6C, 0x65, 0x61, + 0x73, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x4D, 0x61, + 0x6A, 0x65, 0x73, 0x74, 0x79, 0x21, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x6F, 0x6C, 0x64, 0x69, 0x65, 0x72, 0x73, + 0x20, 0x73, 0x68, 0x6F, 0x75, 0x74, 0x65, 0x64, 0x0D, 0x0A, + 0x69, 0x6E, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x79, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, 0x74, 0x27, 0x73, + 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x21, 0x27, 0x20, 0x73, + 0x68, 0x6F, 0x75, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2E, 0x20, 0x27, 0x43, + 0x61, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x70, 0x6C, 0x61, + 0x79, 0x20, 0x63, 0x72, 0x6F, 0x71, 0x75, 0x65, 0x74, 0x3F, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x73, + 0x6F, 0x6C, 0x64, 0x69, 0x65, 0x72, 0x73, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x20, 0x73, 0x69, 0x6C, 0x65, 0x6E, 0x74, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, + 0x64, 0x20, 0x61, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x77, 0x61, + 0x73, 0x0D, 0x0A, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6E, 0x74, + 0x6C, 0x79, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x74, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x68, 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x59, 0x65, 0x73, 0x21, 0x27, 0x20, 0x73, 0x68, + 0x6F, 0x75, 0x74, 0x65, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x43, 0x6F, 0x6D, + 0x65, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x6E, + 0x21, 0x27, 0x20, 0x72, 0x6F, 0x61, 0x72, 0x65, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x6A, 0x6F, 0x69, 0x6E, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, 0x73, 0x69, + 0x6F, 0x6E, 0x2C, 0x0D, 0x0A, 0x77, 0x6F, 0x6E, 0x64, 0x65, + 0x72, 0x69, 0x6E, 0x67, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x6D, 0x75, 0x63, 0x68, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, 0x61, 0x70, 0x70, + 0x65, 0x6E, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x27, 0x73, 0x2D, 0x2D, 0x69, + 0x74, 0x27, 0x73, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x66, 0x69, 0x6E, 0x65, 0x20, 0x64, 0x61, 0x79, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x61, 0x20, 0x74, + 0x69, 0x6D, 0x69, 0x64, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, + 0x20, 0x61, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x73, 0x69, + 0x64, 0x65, 0x2E, 0x20, 0x53, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x0D, 0x0A, 0x77, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, + 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, + 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x70, 0x65, 0x65, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6E, + 0x78, 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, 0x69, 0x6E, + 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x61, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x56, 0x65, 0x72, + 0x79, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x3A, 0x20, 0x27, 0x2D, 0x2D, 0x77, + 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x3F, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x75, 0x73, 0x68, 0x21, + 0x20, 0x48, 0x75, 0x73, 0x68, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6C, + 0x6F, 0x77, 0x2C, 0x20, 0x68, 0x75, 0x72, 0x72, 0x69, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2E, 0x20, 0x48, 0x65, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x0D, 0x0A, 0x61, + 0x6E, 0x78, 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, 0x6F, + 0x76, 0x65, 0x72, 0x20, 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, + 0x6F, 0x75, 0x6C, 0x64, 0x65, 0x72, 0x20, 0x61, 0x73, 0x20, + 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6B, 0x65, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x72, + 0x61, 0x69, 0x73, 0x65, 0x64, 0x20, 0x68, 0x69, 0x6D, 0x73, + 0x65, 0x6C, 0x66, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x0D, 0x0A, + 0x74, 0x69, 0x70, 0x74, 0x6F, 0x65, 0x2C, 0x20, 0x70, 0x75, + 0x74, 0x20, 0x68, 0x69, 0x73, 0x20, 0x6D, 0x6F, 0x75, 0x74, + 0x68, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x65, 0x61, 0x72, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x27, 0x53, 0x68, 0x65, 0x27, 0x73, + 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x0D, 0x0A, 0x73, 0x65, + 0x6E, 0x74, 0x65, 0x6E, 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, 0x74, + 0x20, 0x66, 0x6F, 0x72, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x44, 0x69, 0x64, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x73, 0x61, 0x79, 0x20, 0x22, 0x57, 0x68, 0x61, 0x74, + 0x20, 0x61, 0x20, 0x70, 0x69, 0x74, 0x79, 0x21, 0x22, 0x3F, + 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, + 0x69, 0x74, 0x20, 0x61, 0x73, 0x6B, 0x65, 0x64, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x2C, 0x20, 0x49, 0x20, + 0x64, 0x69, 0x64, 0x6E, 0x27, 0x74, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x3A, + 0x20, 0x27, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x69, 0x74, 0x27, 0x73, + 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x20, + 0x70, 0x69, 0x74, 0x79, 0x2E, 0x20, 0x49, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x0D, 0x0A, 0x22, 0x57, 0x68, 0x61, 0x74, 0x20, + 0x66, 0x6F, 0x72, 0x3F, 0x22, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x53, 0x68, 0x65, 0x20, 0x62, 0x6F, 0x78, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, + 0x27, 0x73, 0x20, 0x65, 0x61, 0x72, 0x73, 0x2D, 0x2D, 0x27, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, + 0x74, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x2E, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x67, 0x61, 0x76, 0x65, 0x20, + 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x0D, 0x0A, + 0x73, 0x63, 0x72, 0x65, 0x61, 0x6D, 0x20, 0x6F, 0x66, 0x20, + 0x6C, 0x61, 0x75, 0x67, 0x68, 0x74, 0x65, 0x72, 0x2E, 0x20, + 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x68, 0x75, 0x73, 0x68, 0x21, + 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, + 0x69, 0x74, 0x20, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x66, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x65, 0x6E, 0x65, 0x64, 0x0D, 0x0A, + 0x74, 0x6F, 0x6E, 0x65, 0x2E, 0x20, 0x27, 0x54, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x77, 0x69, 0x6C, + 0x6C, 0x20, 0x68, 0x65, 0x61, 0x72, 0x20, 0x79, 0x6F, 0x75, + 0x21, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x73, 0x65, 0x65, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, + 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6C, 0x61, 0x74, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x47, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x79, 0x6F, 0x75, + 0x72, 0x20, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x73, 0x21, 0x27, + 0x20, 0x73, 0x68, 0x6F, 0x75, 0x74, 0x65, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x75, 0x6E, 0x64, 0x65, 0x72, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x70, 0x65, 0x6F, + 0x70, 0x6C, 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, + 0x72, 0x75, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x62, + 0x6F, 0x75, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x73, 0x2C, 0x20, 0x74, 0x75, 0x6D, 0x62, 0x6C, 0x69, 0x6E, + 0x67, 0x20, 0x75, 0x70, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, + 0x73, 0x74, 0x20, 0x65, 0x61, 0x63, 0x68, 0x0D, 0x0A, 0x6F, + 0x74, 0x68, 0x65, 0x72, 0x3B, 0x20, 0x68, 0x6F, 0x77, 0x65, + 0x76, 0x65, 0x72, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x67, 0x6F, 0x74, 0x20, 0x73, 0x65, 0x74, 0x74, 0x6C, 0x65, + 0x64, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x20, 0x6F, + 0x72, 0x20, 0x74, 0x77, 0x6F, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x0D, + 0x0A, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x2E, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x73, 0x65, 0x65, 0x6E, + 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, 0x20, 0x63, 0x75, + 0x72, 0x69, 0x6F, 0x75, 0x73, 0x20, 0x63, 0x72, 0x6F, 0x71, + 0x75, 0x65, 0x74, 0x2D, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x68, 0x65, 0x72, 0x20, 0x6C, + 0x69, 0x66, 0x65, 0x3B, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x75, 0x72, + 0x72, 0x6F, 0x77, 0x73, 0x3B, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x61, 0x6C, 0x6C, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, + 0x20, 0x6C, 0x69, 0x76, 0x65, 0x20, 0x68, 0x65, 0x64, 0x67, + 0x65, 0x68, 0x6F, 0x67, 0x73, 0x2C, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x20, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x74, 0x73, 0x20, + 0x6C, 0x69, 0x76, 0x65, 0x20, 0x66, 0x6C, 0x61, 0x6D, 0x69, + 0x6E, 0x67, 0x6F, 0x65, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6F, 0x6C, 0x64, 0x69, + 0x65, 0x72, 0x73, 0x20, 0x68, 0x61, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x73, 0x65, 0x6C, 0x76, 0x65, 0x73, 0x0D, 0x0A, + 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x74, 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x69, 0x72, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x73, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x65, 0x65, 0x74, 0x2C, + 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x63, 0x68, + 0x69, 0x65, 0x66, 0x20, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, + 0x75, 0x6C, 0x74, 0x79, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x61, 0x74, 0x20, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x69, 0x6E, 0x20, 0x6D, 0x61, 0x6E, 0x61, 0x67, 0x69, 0x6E, + 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x6C, 0x61, 0x6D, + 0x69, 0x6E, 0x67, 0x6F, 0x3A, 0x0D, 0x0A, 0x73, 0x68, 0x65, + 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x65, 0x64, 0x65, 0x64, + 0x20, 0x69, 0x6E, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x69, 0x74, 0x73, 0x20, 0x62, 0x6F, 0x64, 0x79, + 0x20, 0x74, 0x75, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x77, + 0x61, 0x79, 0x2C, 0x20, 0x63, 0x6F, 0x6D, 0x66, 0x6F, 0x72, + 0x74, 0x61, 0x62, 0x6C, 0x79, 0x20, 0x65, 0x6E, 0x6F, 0x75, + 0x67, 0x68, 0x2C, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x0D, + 0x0A, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x6D, 0x2C, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, 0x6C, + 0x65, 0x67, 0x73, 0x20, 0x68, 0x61, 0x6E, 0x67, 0x69, 0x6E, + 0x67, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x2C, 0x20, 0x62, 0x75, + 0x74, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x6C, + 0x79, 0x2C, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x67, + 0x6F, 0x74, 0x0D, 0x0A, 0x69, 0x74, 0x73, 0x20, 0x6E, 0x65, + 0x63, 0x6B, 0x20, 0x6E, 0x69, 0x63, 0x65, 0x6C, 0x79, 0x20, + 0x73, 0x74, 0x72, 0x61, 0x69, 0x67, 0x68, 0x74, 0x65, 0x6E, + 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, 0x6F, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x64, 0x67, 0x65, 0x68, + 0x6F, 0x67, 0x20, 0x61, 0x0D, 0x0A, 0x62, 0x6C, 0x6F, 0x77, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, + 0x68, 0x65, 0x61, 0x64, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x57, + 0x4F, 0x55, 0x4C, 0x44, 0x20, 0x74, 0x77, 0x69, 0x73, 0x74, + 0x20, 0x69, 0x74, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x72, 0x6F, + 0x75, 0x6E, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x20, 0x75, 0x70, 0x20, 0x69, 0x6E, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x66, 0x61, 0x63, 0x65, 0x2C, 0x0D, 0x0A, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x20, 0x70, 0x75, 0x7A, 0x7A, 0x6C, 0x65, 0x64, 0x20, + 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x68, 0x65, 0x6C, 0x70, 0x20, 0x62, 0x75, 0x72, 0x73, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x75, 0x74, 0x0D, 0x0A, 0x6C, + 0x61, 0x75, 0x67, 0x68, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x67, 0x6F, 0x74, 0x20, + 0x69, 0x74, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x0D, 0x0A, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x70, 0x72, + 0x6F, 0x76, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, + 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x64, 0x67, 0x65, + 0x68, 0x6F, 0x67, 0x20, 0x68, 0x61, 0x64, 0x20, 0x75, 0x6E, + 0x72, 0x6F, 0x6C, 0x6C, 0x65, 0x64, 0x0D, 0x0A, 0x69, 0x74, + 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x61, 0x63, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x72, + 0x61, 0x77, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x77, 0x61, + 0x79, 0x3A, 0x20, 0x62, 0x65, 0x73, 0x69, 0x64, 0x65, 0x73, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, + 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x0D, 0x0A, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x6C, + 0x79, 0x20, 0x61, 0x20, 0x72, 0x69, 0x64, 0x67, 0x65, 0x20, + 0x6F, 0x72, 0x20, 0x66, 0x75, 0x72, 0x72, 0x6F, 0x77, 0x20, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, + 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x76, 0x65, 0x72, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x0D, 0x0A, 0x68, 0x65, 0x64, 0x67, 0x65, 0x68, + 0x6F, 0x67, 0x20, 0x74, 0x6F, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x2C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, + 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x64, 0x2D, 0x75, 0x70, 0x20, + 0x73, 0x6F, 0x6C, 0x64, 0x69, 0x65, 0x72, 0x73, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, + 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x75, + 0x70, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, 0x6C, + 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x74, + 0x6F, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x70, 0x61, + 0x72, 0x74, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2C, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, + 0x63, 0x61, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x63, 0x6F, 0x6E, 0x63, 0x6C, 0x75, 0x73, + 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, + 0x6C, 0x74, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x20, 0x69, 0x6E, + 0x64, 0x65, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x68, 0x65, 0x20, 0x70, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x73, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x70, 0x6C, 0x61, 0x79, 0x65, + 0x64, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x77, 0x61, + 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x74, 0x75, 0x72, 0x6E, 0x73, 0x2C, 0x20, 0x71, 0x75, 0x61, + 0x72, 0x72, 0x65, 0x6C, 0x6C, 0x69, 0x6E, 0x67, 0x0D, 0x0A, + 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, + 0x69, 0x6C, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, + 0x69, 0x67, 0x68, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x64, 0x67, + 0x65, 0x68, 0x6F, 0x67, 0x73, 0x3B, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x0D, 0x0A, 0x74, 0x69, + 0x6D, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, + 0x65, 0x6E, 0x20, 0x77, 0x61, 0x73, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x20, 0x66, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x20, + 0x70, 0x61, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x74, + 0x61, 0x6D, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x73, + 0x68, 0x6F, 0x75, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x27, 0x4F, + 0x66, 0x66, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, 0x69, + 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, 0x21, 0x27, 0x20, 0x6F, + 0x72, 0x20, 0x27, 0x4F, 0x66, 0x66, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, + 0x21, 0x27, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x6F, + 0x6E, 0x63, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x0D, 0x0A, + 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x62, 0x65, 0x67, + 0x61, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x65, 0x65, 0x6C, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x75, 0x6E, 0x65, 0x61, + 0x73, 0x79, 0x3A, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, + 0x73, 0x75, 0x72, 0x65, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x73, + 0x20, 0x79, 0x65, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, 0x61, + 0x6E, 0x79, 0x0D, 0x0A, 0x64, 0x69, 0x73, 0x70, 0x75, 0x74, + 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, 0x62, 0x75, + 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6B, 0x6E, 0x65, 0x77, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6D, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x68, 0x61, 0x70, 0x70, 0x65, + 0x6E, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6D, 0x69, 0x6E, 0x75, + 0x74, 0x65, 0x2C, 0x0D, 0x0A, 0x27, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x73, 0x68, 0x65, 0x2C, 0x20, + 0x27, 0x77, 0x68, 0x61, 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x62, 0x65, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x6D, 0x65, 0x3F, 0x20, 0x54, 0x68, 0x65, 0x79, + 0x27, 0x72, 0x65, 0x20, 0x64, 0x72, 0x65, 0x61, 0x64, 0x66, + 0x75, 0x6C, 0x6C, 0x79, 0x0D, 0x0A, 0x66, 0x6F, 0x6E, 0x64, + 0x20, 0x6F, 0x66, 0x20, 0x62, 0x65, 0x68, 0x65, 0x61, 0x64, + 0x69, 0x6E, 0x67, 0x20, 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, + 0x20, 0x68, 0x65, 0x72, 0x65, 0x3B, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x77, 0x6F, 0x6E, + 0x64, 0x65, 0x72, 0x20, 0x69, 0x73, 0x2C, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, + 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6F, 0x6E, 0x65, 0x0D, 0x0A, + 0x6C, 0x65, 0x66, 0x74, 0x20, 0x61, 0x6C, 0x69, 0x76, 0x65, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x68, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x77, 0x61, 0x79, + 0x20, 0x6F, 0x66, 0x20, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x6F, 0x6E, 0x64, + 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x68, 0x65, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x63, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x67, 0x65, 0x74, 0x20, 0x61, + 0x77, 0x61, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, + 0x74, 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x65, + 0x65, 0x6E, 0x2C, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x64, + 0x20, 0x61, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, + 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x61, 0x6E, 0x63, + 0x65, 0x0D, 0x0A, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x61, 0x69, 0x72, 0x3A, 0x20, 0x69, 0x74, 0x20, 0x70, 0x75, + 0x7A, 0x7A, 0x6C, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, + 0x61, 0x74, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2C, 0x20, + 0x62, 0x75, 0x74, 0x2C, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, + 0x20, 0x77, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x69, 0x74, 0x0D, 0x0A, 0x61, 0x20, 0x6D, 0x69, 0x6E, 0x75, + 0x74, 0x65, 0x20, 0x6F, 0x72, 0x20, 0x74, 0x77, 0x6F, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, + 0x69, 0x74, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x62, 0x65, 0x20, 0x61, 0x20, 0x67, 0x72, 0x69, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x27, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x68, 0x65, 0x73, + 0x68, 0x69, 0x72, 0x65, 0x20, 0x43, 0x61, 0x74, 0x3A, 0x20, + 0x6E, 0x6F, 0x77, 0x20, 0x49, 0x20, 0x73, 0x68, 0x61, 0x6C, + 0x6C, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x73, 0x6F, 0x6D, + 0x65, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x61, 0x6C, 0x6B, 0x20, 0x74, 0x6F, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x48, 0x6F, 0x77, 0x20, 0x61, 0x72, 0x65, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x3F, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, + 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, + 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x6D, 0x6F, 0x75, 0x74, 0x68, 0x0D, 0x0A, + 0x65, 0x6E, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x69, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x70, 0x65, + 0x61, 0x6B, 0x20, 0x77, 0x69, 0x74, 0x68, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x61, + 0x69, 0x74, 0x65, 0x64, 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x65, 0x79, 0x65, 0x73, 0x20, 0x61, + 0x70, 0x70, 0x65, 0x61, 0x72, 0x65, 0x64, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x6E, 0x6F, + 0x64, 0x64, 0x65, 0x64, 0x2E, 0x20, 0x27, 0x49, 0x74, 0x27, + 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x75, 0x73, 0x65, 0x0D, 0x0A, + 0x73, 0x70, 0x65, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x20, 0x69, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x2C, 0x20, + 0x27, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x69, 0x74, 0x73, 0x20, + 0x65, 0x61, 0x72, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x63, 0x6F, 0x6D, 0x65, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x61, + 0x74, 0x20, 0x6C, 0x65, 0x61, 0x73, 0x74, 0x20, 0x6F, 0x6E, + 0x65, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, + 0x2E, 0x27, 0x20, 0x49, 0x6E, 0x20, 0x61, 0x6E, 0x6F, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, 0x6F, 0x6C, 0x65, + 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x61, 0x70, 0x70, 0x65, + 0x61, 0x72, 0x65, 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x70, 0x75, 0x74, 0x0D, 0x0A, 0x64, 0x6F, 0x77, 0x6E, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x6C, 0x61, 0x6D, 0x69, + 0x6E, 0x67, 0x6F, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, + 0x65, 0x67, 0x61, 0x6E, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x63, + 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x2C, 0x20, 0x66, + 0x65, 0x65, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x67, 0x6C, 0x61, 0x64, 0x0D, 0x0A, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x73, 0x6F, 0x6D, 0x65, + 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x69, 0x73, + 0x74, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x20, + 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x0D, 0x0A, 0x65, 0x6E, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x6F, + 0x66, 0x20, 0x69, 0x74, 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x69, + 0x6E, 0x20, 0x73, 0x69, 0x67, 0x68, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6E, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x20, 0x61, 0x70, 0x70, + 0x65, 0x61, 0x72, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x70, 0x6C, 0x61, 0x79, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x66, 0x61, 0x69, 0x72, 0x6C, 0x79, 0x2C, 0x27, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x62, 0x65, 0x67, + 0x61, 0x6E, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x72, 0x61, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x61, 0x0D, 0x0A, 0x63, 0x6F, 0x6D, + 0x70, 0x6C, 0x61, 0x69, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x71, + 0x75, 0x61, 0x72, 0x72, 0x65, 0x6C, 0x20, 0x73, 0x6F, 0x20, + 0x64, 0x72, 0x65, 0x61, 0x64, 0x66, 0x75, 0x6C, 0x6C, 0x79, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, + 0x20, 0x68, 0x65, 0x61, 0x72, 0x0D, 0x0A, 0x6F, 0x6E, 0x65, + 0x73, 0x65, 0x6C, 0x66, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, + 0x2D, 0x2D, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x73, 0x65, 0x65, + 0x6D, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x61, 0x6E, 0x79, 0x20, 0x72, 0x75, 0x6C, 0x65, 0x73, 0x20, + 0x69, 0x6E, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x75, + 0x6C, 0x61, 0x72, 0x3B, 0x0D, 0x0A, 0x61, 0x74, 0x20, 0x6C, + 0x65, 0x61, 0x73, 0x74, 0x2C, 0x20, 0x69, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x20, 0x61, 0x72, 0x65, 0x2C, 0x20, + 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x61, 0x74, 0x74, + 0x65, 0x6E, 0x64, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x2D, 0x2D, 0x61, 0x6E, 0x64, 0x20, 0x79, 0x6F, + 0x75, 0x27, 0x76, 0x65, 0x20, 0x6E, 0x6F, 0x20, 0x69, 0x64, + 0x65, 0x61, 0x20, 0x68, 0x6F, 0x77, 0x0D, 0x0A, 0x63, 0x6F, + 0x6E, 0x66, 0x75, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, + 0x20, 0x69, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x62, + 0x65, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6C, 0x69, 0x76, 0x65, + 0x3B, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x69, 0x6E, 0x73, 0x74, + 0x61, 0x6E, 0x63, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x61, + 0x72, 0x63, 0x68, 0x20, 0x49, 0x27, 0x76, 0x65, 0x20, 0x67, + 0x6F, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x67, 0x6F, 0x20, 0x74, + 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x6E, 0x65, 0x78, + 0x74, 0x20, 0x77, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x65, + 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2D, 0x2D, 0x61, + 0x6E, 0x64, 0x20, 0x49, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x63, 0x72, 0x6F, + 0x71, 0x75, 0x65, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x27, 0x73, 0x20, 0x68, + 0x65, 0x64, 0x67, 0x65, 0x68, 0x6F, 0x67, 0x20, 0x6A, 0x75, + 0x73, 0x74, 0x20, 0x6E, 0x6F, 0x77, 0x2C, 0x20, 0x6F, 0x6E, + 0x6C, 0x79, 0x0D, 0x0A, 0x69, 0x74, 0x20, 0x72, 0x61, 0x6E, + 0x20, 0x61, 0x77, 0x61, 0x79, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x69, 0x74, 0x20, 0x73, 0x61, 0x77, 0x20, 0x6D, 0x69, + 0x6E, 0x65, 0x20, 0x63, 0x6F, 0x6D, 0x69, 0x6E, 0x67, 0x21, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x6F, 0x77, 0x20, + 0x64, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, + 0x6E, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x20, 0x6C, 0x6F, 0x77, 0x20, 0x76, 0x6F, 0x69, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x74, + 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x3A, 0x20, 0x27, 0x73, 0x68, 0x65, 0x27, 0x73, 0x20, 0x73, + 0x6F, 0x20, 0x65, 0x78, 0x74, 0x72, 0x65, 0x6D, 0x65, 0x6C, + 0x79, 0x2D, 0x2D, 0x27, 0x20, 0x4A, 0x75, 0x73, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6E, + 0x6F, 0x74, 0x69, 0x63, 0x65, 0x64, 0x0D, 0x0A, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, + 0x65, 0x6E, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x6C, 0x6F, + 0x73, 0x65, 0x20, 0x62, 0x65, 0x68, 0x69, 0x6E, 0x64, 0x20, + 0x68, 0x65, 0x72, 0x2C, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x65, + 0x6E, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x73, 0x6F, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, + 0x2C, 0x0D, 0x0A, 0x27, 0x2D, 0x2D, 0x6C, 0x69, 0x6B, 0x65, + 0x6C, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x77, 0x69, 0x6E, 0x2C, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x27, 0x73, + 0x20, 0x68, 0x61, 0x72, 0x64, 0x6C, 0x79, 0x20, 0x77, 0x6F, + 0x72, 0x74, 0x68, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, + 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x51, 0x75, + 0x65, 0x65, 0x6E, 0x20, 0x73, 0x6D, 0x69, 0x6C, 0x65, 0x64, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, + 0x64, 0x20, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x57, 0x68, 0x6F, 0x20, 0x41, 0x52, 0x45, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x6F, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x75, 0x70, 0x20, 0x74, + 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, + 0x61, 0x74, 0x27, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, + 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x73, 0x69, 0x74, 0x79, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x27, 0x73, + 0x20, 0x61, 0x20, 0x66, 0x72, 0x69, 0x65, 0x6E, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x6D, 0x69, 0x6E, 0x65, 0x2D, 0x2D, 0x61, + 0x20, 0x43, 0x68, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x20, + 0x43, 0x61, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x3A, 0x20, 0x27, 0x61, + 0x6C, 0x6C, 0x6F, 0x77, 0x20, 0x6D, 0x65, 0x20, 0x74, 0x6F, + 0x0D, 0x0A, 0x69, 0x6E, 0x74, 0x72, 0x6F, 0x64, 0x75, 0x63, + 0x65, 0x20, 0x69, 0x74, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x20, 0x61, + 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, + 0x67, 0x3A, 0x20, 0x27, 0x68, 0x6F, 0x77, 0x65, 0x76, 0x65, + 0x72, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x6D, 0x61, 0x79, 0x0D, + 0x0A, 0x6B, 0x69, 0x73, 0x73, 0x20, 0x6D, 0x79, 0x20, 0x68, + 0x61, 0x6E, 0x64, 0x20, 0x69, 0x66, 0x20, 0x69, 0x74, 0x20, + 0x6C, 0x69, 0x6B, 0x65, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x27, 0x64, 0x20, 0x72, 0x61, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x6E, 0x6F, 0x74, 0x2C, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x20, 0x72, 0x65, 0x6D, + 0x61, 0x72, 0x6B, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x44, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, + 0x69, 0x6D, 0x70, 0x65, 0x72, 0x74, 0x69, 0x6E, 0x65, 0x6E, + 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x27, + 0x61, 0x6E, 0x64, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x61, 0x74, 0x20, 0x6D, 0x65, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x21, 0x27, 0x0D, 0x0A, 0x48, 0x65, 0x20, 0x67, 0x6F, 0x74, + 0x20, 0x62, 0x65, 0x68, 0x69, 0x6E, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x61, 0x73, 0x20, 0x68, 0x65, 0x20, + 0x73, 0x70, 0x6F, 0x6B, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x41, 0x20, 0x63, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x79, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x61, 0x74, 0x20, 0x61, + 0x20, 0x6B, 0x69, 0x6E, 0x67, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x20, + 0x27, 0x49, 0x27, 0x76, 0x65, 0x20, 0x72, 0x65, 0x61, 0x64, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x62, 0x6F, 0x6F, 0x6B, 0x2C, 0x0D, + 0x0A, 0x62, 0x75, 0x74, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x6E, + 0x27, 0x74, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, + 0x72, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x20, + 0x69, 0x74, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x64, 0x65, 0x63, 0x69, 0x64, 0x65, 0x64, 0x6C, 0x79, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x20, 0x63, 0x61, + 0x6C, 0x6C, 0x65, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, 0x77, 0x68, 0x6F, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x70, 0x61, 0x73, 0x73, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x27, 0x4D, + 0x79, 0x20, 0x64, 0x65, 0x61, 0x72, 0x21, 0x20, 0x49, 0x20, + 0x77, 0x69, 0x73, 0x68, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x77, + 0x6F, 0x75, 0x6C, 0x64, 0x0D, 0x0A, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x61, 0x74, 0x20, + 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x21, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, + 0x65, 0x6E, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6F, 0x6E, 0x6C, + 0x79, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, + 0x6F, 0x66, 0x20, 0x73, 0x65, 0x74, 0x74, 0x6C, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x64, 0x69, 0x66, 0x66, + 0x69, 0x63, 0x75, 0x6C, 0x74, 0x69, 0x65, 0x73, 0x2C, 0x20, + 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x6F, 0x72, 0x20, 0x73, + 0x6D, 0x61, 0x6C, 0x6C, 0x2E, 0x0D, 0x0A, 0x27, 0x4F, 0x66, + 0x66, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x68, 0x65, 0x61, 0x64, 0x21, 0x27, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x65, 0x76, 0x65, 0x6E, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x72, + 0x6F, 0x75, 0x6E, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x66, 0x65, 0x74, 0x63, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6F, 0x6E, 0x65, 0x72, 0x20, 0x6D, 0x79, 0x73, + 0x65, 0x6C, 0x66, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, + 0x65, 0x61, 0x67, 0x65, 0x72, 0x6C, 0x79, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x68, 0x65, 0x0D, 0x0A, 0x68, 0x75, 0x72, + 0x72, 0x69, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, + 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x67, 0x6F, 0x20, 0x62, 0x61, + 0x63, 0x6B, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x65, + 0x65, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x67, 0x61, 0x6D, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, + 0x6F, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x6F, 0x6E, 0x2C, 0x20, + 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, + 0x72, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, + 0x65, 0x6E, 0x27, 0x73, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, + 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x2C, 0x20, 0x73, 0x63, + 0x72, 0x65, 0x61, 0x6D, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x0D, 0x0A, 0x70, 0x61, 0x73, 0x73, 0x69, 0x6F, + 0x6E, 0x2E, 0x20, 0x53, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x61, 0x6C, 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, 0x68, + 0x65, 0x61, 0x72, 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, 0x73, + 0x65, 0x6E, 0x74, 0x65, 0x6E, 0x63, 0x65, 0x20, 0x74, 0x68, + 0x72, 0x65, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x73, 0x20, 0x74, + 0x6F, 0x20, 0x62, 0x65, 0x0D, 0x0A, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x65, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x68, + 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x69, 0x73, 0x73, + 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x74, + 0x75, 0x72, 0x6E, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x0D, 0x0A, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x61, 0x74, 0x20, + 0x61, 0x6C, 0x6C, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x69, 0x6E, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x63, + 0x6F, 0x6E, 0x66, 0x75, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6E, 0x65, + 0x76, 0x65, 0x72, 0x20, 0x6B, 0x6E, 0x65, 0x77, 0x0D, 0x0A, + 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x74, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x68, 0x65, 0x72, 0x20, 0x74, + 0x75, 0x72, 0x6E, 0x20, 0x6F, 0x72, 0x20, 0x6E, 0x6F, 0x74, + 0x2E, 0x20, 0x53, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x68, 0x65, 0x64, 0x67, 0x65, 0x68, 0x6F, 0x67, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x68, 0x65, + 0x64, 0x67, 0x65, 0x68, 0x6F, 0x67, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x65, 0x6E, 0x67, 0x61, 0x67, 0x65, 0x64, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x66, 0x69, 0x67, 0x68, 0x74, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x68, 0x65, 0x64, 0x67, 0x65, 0x68, 0x6F, + 0x67, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x73, + 0x65, 0x65, 0x6D, 0x65, 0x64, 0x0D, 0x0A, 0x74, 0x6F, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x6E, 0x20, 0x65, + 0x78, 0x63, 0x65, 0x6C, 0x6C, 0x65, 0x6E, 0x74, 0x20, 0x6F, + 0x70, 0x70, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x69, 0x74, 0x79, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x63, 0x72, 0x6F, 0x71, 0x75, + 0x65, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x6F, 0x74, + 0x68, 0x65, 0x72, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, + 0x6E, 0x6C, 0x79, 0x20, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, + 0x75, 0x6C, 0x74, 0x79, 0x20, 0x77, 0x61, 0x73, 0x2C, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, + 0x6C, 0x61, 0x6D, 0x69, 0x6E, 0x67, 0x6F, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x67, 0x6F, 0x6E, 0x65, 0x20, 0x61, 0x63, 0x72, + 0x6F, 0x73, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x69, + 0x64, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x2C, 0x20, 0x77, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x73, 0x65, 0x65, 0x20, + 0x69, 0x74, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6E, 0x67, 0x20, + 0x69, 0x6E, 0x20, 0x61, 0x20, 0x68, 0x65, 0x6C, 0x70, 0x6C, + 0x65, 0x73, 0x73, 0x0D, 0x0A, 0x73, 0x6F, 0x72, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x77, 0x61, 0x79, 0x20, 0x74, 0x6F, 0x20, + 0x66, 0x6C, 0x79, 0x20, 0x75, 0x70, 0x20, 0x69, 0x6E, 0x74, + 0x6F, 0x20, 0x61, 0x20, 0x74, 0x72, 0x65, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x42, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x69, 0x6D, 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x63, 0x61, 0x75, 0x67, 0x68, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x6C, 0x61, 0x6D, 0x69, 0x6E, + 0x67, 0x6F, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x72, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x69, 0x74, 0x20, 0x62, 0x61, + 0x63, 0x6B, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, + 0x67, 0x68, 0x74, 0x0D, 0x0A, 0x77, 0x61, 0x73, 0x20, 0x6F, + 0x76, 0x65, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, + 0x6F, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, + 0x64, 0x67, 0x65, 0x68, 0x6F, 0x67, 0x73, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x73, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x20, 0x27, 0x62, 0x75, + 0x74, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x6E, + 0x27, 0x74, 0x0D, 0x0A, 0x6D, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x20, 0x6D, 0x75, 0x63, 0x68, 0x2C, 0x27, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2C, 0x20, 0x27, 0x61, 0x73, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x63, 0x68, 0x65, + 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x67, 0x6F, 0x6E, 0x65, + 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x73, 0x69, 0x64, 0x65, 0x0D, 0x0A, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, + 0x2E, 0x27, 0x20, 0x53, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x74, 0x75, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x69, 0x74, 0x20, + 0x61, 0x77, 0x61, 0x79, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x6D, 0x2C, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6D, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x6E, 0x6F, 0x74, 0x0D, 0x0A, 0x65, + 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, + 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x76, 0x65, + 0x72, 0x73, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x66, 0x72, + 0x69, 0x65, 0x6E, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x57, + 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x67, 0x6F, + 0x74, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x43, 0x68, 0x65, 0x73, 0x68, 0x69, + 0x72, 0x65, 0x20, 0x43, 0x61, 0x74, 0x2C, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x75, 0x72, 0x70, + 0x72, 0x69, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x66, + 0x69, 0x6E, 0x64, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, + 0x61, 0x0D, 0x0A, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x63, + 0x72, 0x6F, 0x77, 0x64, 0x20, 0x63, 0x6F, 0x6C, 0x6C, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x69, 0x74, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x64, 0x69, 0x73, + 0x70, 0x75, 0x74, 0x65, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x6E, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, + 0x6E, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x65, 0x72, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, + 0x65, 0x65, 0x6E, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x61, + 0x6C, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x6F, + 0x6E, 0x63, 0x65, 0x2C, 0x0D, 0x0A, 0x77, 0x68, 0x69, 0x6C, + 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x72, 0x65, 0x73, 0x74, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x73, 0x69, 0x6C, 0x65, + 0x6E, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x75, 0x6E, 0x63, 0x6F, 0x6D, 0x66, 0x6F, 0x72, 0x74, 0x61, + 0x62, 0x6C, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x65, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, + 0x72, 0x65, 0x64, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x6C, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x79, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x73, 0x65, 0x74, 0x74, 0x6C, 0x65, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6F, + 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x79, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x61, 0x72, 0x67, + 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x2C, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x0D, 0x0A, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x70, 0x6F, 0x6B, + 0x65, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x69, 0x74, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x68, + 0x61, 0x72, 0x64, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x6F, + 0x75, 0x74, 0x20, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6C, 0x79, + 0x0D, 0x0A, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x79, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x69, 0x6F, 0x6E, 0x65, 0x72, 0x27, 0x73, 0x20, 0x61, + 0x72, 0x67, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x77, 0x61, + 0x73, 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, + 0x20, 0x63, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x61, + 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x75, 0x6E, 0x6C, 0x65, + 0x73, 0x73, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x64, 0x79, + 0x20, 0x74, 0x6F, 0x20, 0x63, 0x75, 0x74, 0x20, 0x69, 0x74, + 0x20, 0x6F, 0x66, 0x66, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x3A, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x65, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x6F, 0x20, 0x73, + 0x75, 0x63, 0x68, 0x20, 0x61, 0x0D, 0x0A, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x6E, 0x27, 0x74, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x20, + 0x61, 0x74, 0x20, 0x48, 0x49, 0x53, 0x20, 0x74, 0x69, 0x6D, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x6C, 0x69, 0x66, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x4B, 0x69, + 0x6E, 0x67, 0x27, 0x73, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6D, + 0x65, 0x6E, 0x74, 0x20, 0x77, 0x61, 0x73, 0x2C, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x61, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x63, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x0D, 0x0A, 0x62, + 0x65, 0x68, 0x65, 0x61, 0x64, 0x65, 0x64, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x77, 0x65, 0x72, 0x65, 0x6E, 0x27, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x20, 0x6E, 0x6F, + 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, + 0x27, 0x73, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6D, 0x65, 0x6E, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x69, 0x66, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x61, 0x73, 0x6E, 0x27, + 0x74, 0x20, 0x64, 0x6F, 0x6E, 0x65, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x6C, + 0x65, 0x73, 0x73, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x6E, 0x20, + 0x6E, 0x6F, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x73, 0x68, + 0x65, 0x27, 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x65, + 0x76, 0x65, 0x72, 0x79, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x2C, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2E, 0x20, + 0x28, 0x49, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x0D, 0x0A, 0x72, + 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, 0x6F, 0x6C, 0x65, 0x20, + 0x70, 0x61, 0x72, 0x74, 0x79, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, + 0x20, 0x73, 0x6F, 0x20, 0x67, 0x72, 0x61, 0x76, 0x65, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6E, 0x78, 0x69, 0x6F, 0x75, + 0x73, 0x2E, 0x29, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x6E, 0x6F, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x6C, 0x73, 0x65, + 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, 0x20, 0x62, 0x75, + 0x74, 0x20, 0x27, 0x49, 0x74, 0x20, 0x62, 0x65, 0x6C, 0x6F, + 0x6E, 0x67, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x3A, 0x0D, + 0x0A, 0x79, 0x6F, 0x75, 0x27, 0x64, 0x20, 0x62, 0x65, 0x74, + 0x74, 0x65, 0x72, 0x20, 0x61, 0x73, 0x6B, 0x20, 0x48, 0x45, + 0x52, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x68, 0x65, + 0x27, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x72, 0x69, 0x73, + 0x6F, 0x6E, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, + 0x75, 0x65, 0x65, 0x6E, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x65, 0x72, 0x3A, 0x20, + 0x27, 0x66, 0x65, 0x74, 0x63, 0x68, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x68, 0x65, 0x72, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x41, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x65, 0x72, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x6C, 0x69, + 0x6B, 0x65, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x72, 0x72, 0x6F, + 0x77, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x43, 0x61, 0x74, 0x27, 0x73, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x66, 0x61, + 0x64, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x77, 0x61, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, + 0x20, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, 0x6F, + 0x6E, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x2C, 0x0D, 0x0A, + 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, + 0x65, 0x20, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x63, + 0x6F, 0x6D, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, + 0x63, 0x68, 0x65, 0x73, 0x73, 0x2C, 0x20, 0x69, 0x74, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x65, 0x6E, 0x74, 0x69, 0x72, 0x65, + 0x6C, 0x79, 0x0D, 0x0A, 0x64, 0x69, 0x73, 0x61, 0x70, 0x70, + 0x65, 0x61, 0x72, 0x65, 0x64, 0x3B, 0x20, 0x73, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x65, 0x72, 0x20, 0x72, + 0x61, 0x6E, 0x20, 0x77, 0x69, 0x6C, 0x64, 0x6C, 0x79, 0x20, + 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x6F, 0x77, + 0x6E, 0x0D, 0x0A, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x77, + 0x68, 0x69, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x65, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x79, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, + 0x48, 0x41, 0x50, 0x54, 0x45, 0x52, 0x20, 0x49, 0x58, 0x2E, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, + 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x27, 0x73, 0x20, 0x53, + 0x74, 0x6F, 0x72, 0x79, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, + 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x6B, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x67, + 0x6C, 0x61, 0x64, 0x20, 0x49, 0x20, 0x61, 0x6D, 0x20, 0x74, + 0x6F, 0x20, 0x73, 0x65, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x64, 0x65, 0x61, 0x72, 0x20, 0x6F, 0x6C, 0x64, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x21, 0x27, 0x0D, 0x0A, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, + 0x63, 0x68, 0x65, 0x73, 0x73, 0x2C, 0x20, 0x61, 0x73, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x74, 0x75, 0x63, 0x6B, 0x65, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x6D, 0x20, 0x61, + 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x74, + 0x65, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x27, 0x73, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, 0x61, + 0x6C, 0x6B, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x74, + 0x6F, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x67, 0x6C, 0x61, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x69, 0x6E, 0x20, 0x73, 0x75, 0x63, + 0x68, 0x20, 0x61, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x61, + 0x6E, 0x74, 0x20, 0x74, 0x65, 0x6D, 0x70, 0x65, 0x72, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x70, 0x65, 0x72, 0x68, 0x61, 0x70, 0x73, 0x20, 0x69, 0x74, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x70, 0x70, 0x65, 0x72, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x6D, 0x61, 0x64, 0x65, 0x20, 0x68, 0x65, 0x72, 0x20, 0x73, + 0x6F, 0x0D, 0x0A, 0x73, 0x61, 0x76, 0x61, 0x67, 0x65, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x6D, 0x65, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6B, 0x69, 0x74, 0x63, 0x68, 0x65, 0x6E, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x65, 0x6E, 0x20, 0x49, + 0x27, 0x4D, 0x20, 0x61, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, + 0x73, 0x73, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x28, 0x6E, 0x6F, 0x74, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x68, 0x6F, 0x70, 0x65, 0x66, 0x75, 0x6C, 0x20, 0x74, + 0x6F, 0x6E, 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x29, 0x2C, 0x20, 0x27, 0x49, 0x20, 0x77, 0x6F, 0x6E, + 0x27, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x70, 0x65, 0x70, 0x70, 0x65, 0x72, 0x20, 0x69, + 0x6E, 0x20, 0x6D, 0x79, 0x20, 0x6B, 0x69, 0x74, 0x63, 0x68, + 0x65, 0x6E, 0x20, 0x41, 0x54, 0x20, 0x41, 0x4C, 0x4C, 0x2E, + 0x20, 0x53, 0x6F, 0x75, 0x70, 0x20, 0x64, 0x6F, 0x65, 0x73, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x0D, 0x0A, 0x77, 0x65, 0x6C, + 0x6C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x2D, + 0x2D, 0x4D, 0x61, 0x79, 0x62, 0x65, 0x20, 0x69, 0x74, 0x27, + 0x73, 0x20, 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x70, + 0x65, 0x70, 0x70, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x73, 0x20, 0x70, 0x65, 0x6F, + 0x70, 0x6C, 0x65, 0x20, 0x68, 0x6F, 0x74, 0x2D, 0x74, 0x65, + 0x6D, 0x70, 0x65, 0x72, 0x65, 0x64, 0x2C, 0x27, 0x0D, 0x0A, + 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, + 0x6E, 0x2C, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6D, 0x75, + 0x63, 0x68, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x68, 0x61, 0x76, 0x69, 0x6E, 0x67, + 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x6F, 0x75, 0x74, + 0x20, 0x61, 0x20, 0x6E, 0x65, 0x77, 0x20, 0x6B, 0x69, 0x6E, + 0x64, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x72, 0x75, 0x6C, 0x65, + 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x76, 0x69, 0x6E, + 0x65, 0x67, 0x61, 0x72, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x6D, 0x61, 0x6B, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6D, + 0x20, 0x73, 0x6F, 0x75, 0x72, 0x2D, 0x2D, 0x61, 0x6E, 0x64, + 0x20, 0x63, 0x61, 0x6D, 0x6F, 0x6D, 0x69, 0x6C, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x73, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x62, 0x69, 0x74, + 0x74, 0x65, 0x72, 0x2D, 0x2D, 0x61, 0x6E, 0x64, 0x2D, 0x2D, + 0x61, 0x6E, 0x64, 0x20, 0x62, 0x61, 0x72, 0x6C, 0x65, 0x79, + 0x2D, 0x73, 0x75, 0x67, 0x61, 0x72, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6D, 0x61, + 0x6B, 0x65, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, 0x65, + 0x6E, 0x0D, 0x0A, 0x73, 0x77, 0x65, 0x65, 0x74, 0x2D, 0x74, + 0x65, 0x6D, 0x70, 0x65, 0x72, 0x65, 0x64, 0x2E, 0x20, 0x49, + 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x77, 0x69, 0x73, 0x68, + 0x20, 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, 0x20, 0x6B, 0x6E, + 0x65, 0x77, 0x20, 0x74, 0x68, 0x61, 0x74, 0x3A, 0x20, 0x74, + 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, + 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x73, 0x6F, 0x0D, 0x0A, 0x73, 0x74, 0x69, 0x6E, 0x67, + 0x79, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, + 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x68, 0x65, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, + 0x20, 0x66, 0x6F, 0x72, 0x67, 0x6F, 0x74, 0x74, 0x65, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, + 0x73, 0x73, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x74, 0x69, 0x6D, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x0D, 0x0A, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x6C, 0x65, 0x64, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x20, 0x63, + 0x6C, 0x6F, 0x73, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x65, 0x61, 0x72, 0x2E, 0x20, 0x27, 0x59, 0x6F, + 0x75, 0x27, 0x72, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, + 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x2C, 0x20, 0x6D, 0x79, 0x20, 0x64, 0x65, 0x61, 0x72, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x6D, 0x61, 0x6B, 0x65, 0x73, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x66, 0x6F, 0x72, 0x67, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x61, 0x6C, 0x6B, 0x2E, 0x20, 0x49, 0x20, 0x63, 0x61, + 0x6E, 0x27, 0x74, 0x0D, 0x0A, 0x74, 0x65, 0x6C, 0x6C, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x6E, + 0x6F, 0x77, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x61, 0x6C, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x2C, 0x20, + 0x62, 0x75, 0x74, 0x20, 0x49, 0x20, 0x73, 0x68, 0x61, 0x6C, + 0x6C, 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, + 0x20, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x61, 0x20, + 0x62, 0x69, 0x74, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x50, 0x65, 0x72, 0x68, 0x61, 0x70, 0x73, 0x20, 0x69, 0x74, + 0x20, 0x68, 0x61, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x6F, 0x6E, + 0x65, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x76, 0x65, 0x6E, 0x74, 0x75, 0x72, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x75, 0x74, 0x2C, 0x20, 0x74, + 0x75, 0x74, 0x2C, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x2E, 0x20, + 0x27, 0x45, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x27, 0x73, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x61, 0x20, + 0x6D, 0x6F, 0x72, 0x61, 0x6C, 0x2C, 0x20, 0x69, 0x66, 0x20, + 0x6F, 0x6E, 0x6C, 0x79, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x20, + 0x63, 0x61, 0x6E, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, 0x69, + 0x74, 0x2E, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x73, 0x71, 0x75, 0x65, 0x65, 0x7A, 0x65, 0x64, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x75, + 0x70, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x72, 0x20, 0x74, + 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x27, 0x73, 0x20, + 0x73, 0x69, 0x64, 0x65, 0x20, 0x61, 0x73, 0x0D, 0x0A, 0x73, + 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6B, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x64, + 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x6B, 0x65, 0x65, + 0x70, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x6F, 0x20, 0x63, 0x6C, + 0x6F, 0x73, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, + 0x3A, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2C, 0x20, 0x62, + 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x56, 0x45, 0x52, 0x59, 0x20, 0x75, + 0x67, 0x6C, 0x79, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, + 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x6C, 0x79, 0x2C, 0x20, 0x62, + 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x65, 0x78, 0x61, 0x63, 0x74, + 0x6C, 0x79, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x73, 0x74, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x63, 0x68, 0x69, 0x6E, 0x20, 0x75, 0x70, + 0x6F, 0x6E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x27, 0x73, + 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x65, 0x72, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x61, 0x6E, 0x0D, 0x0A, 0x75, 0x6E, 0x63, 0x6F, + 0x6D, 0x66, 0x6F, 0x72, 0x74, 0x61, 0x62, 0x6C, 0x79, 0x20, + 0x73, 0x68, 0x61, 0x72, 0x70, 0x20, 0x63, 0x68, 0x69, 0x6E, + 0x2E, 0x20, 0x48, 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x64, 0x65, 0x2C, 0x20, + 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x62, 0x6F, + 0x72, 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x73, 0x20, 0x77, + 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x54, 0x68, 0x65, 0x20, 0x67, 0x61, 0x6D, 0x65, + 0x27, 0x73, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x6E, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x62, + 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, 0x6E, 0x6F, 0x77, 0x2C, + 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x2C, 0x20, 0x62, 0x79, 0x20, 0x77, 0x61, 0x79, 0x20, 0x6F, + 0x66, 0x20, 0x6B, 0x65, 0x65, 0x70, 0x69, 0x6E, 0x67, 0x20, + 0x75, 0x70, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x6E, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x27, 0x54, 0x69, 0x73, 0x20, + 0x73, 0x6F, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, + 0x73, 0x3A, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x61, 0x6C, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x2D, 0x2D, + 0x22, 0x4F, 0x68, 0x2C, 0x20, 0x27, 0x74, 0x69, 0x73, 0x20, + 0x6C, 0x6F, 0x76, 0x65, 0x2C, 0x0D, 0x0A, 0x27, 0x74, 0x69, + 0x73, 0x20, 0x6C, 0x6F, 0x76, 0x65, 0x2C, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x20, 0x67, + 0x6F, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x21, 0x22, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x6F, 0x6D, 0x65, 0x62, + 0x6F, 0x64, 0x79, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x27, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x68, 0x69, + 0x73, 0x70, 0x65, 0x72, 0x65, 0x64, 0x2C, 0x20, 0x27, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x64, + 0x6F, 0x6E, 0x65, 0x20, 0x62, 0x79, 0x20, 0x65, 0x76, 0x65, + 0x72, 0x79, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x6D, 0x69, 0x6E, + 0x64, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x69, + 0x72, 0x20, 0x6F, 0x77, 0x6E, 0x20, 0x62, 0x75, 0x73, 0x69, + 0x6E, 0x65, 0x73, 0x73, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x41, 0x68, 0x2C, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x21, + 0x20, 0x49, 0x74, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x73, 0x20, + 0x6D, 0x75, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x2C, 0x20, + 0x64, 0x69, 0x67, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, + 0x72, 0x0D, 0x0A, 0x73, 0x68, 0x61, 0x72, 0x70, 0x20, 0x6C, + 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x63, 0x68, 0x69, 0x6E, + 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x27, 0x73, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, + 0x65, 0x72, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x2C, 0x20, 0x27, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x61, + 0x6C, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x54, 0x48, 0x41, 0x54, + 0x20, 0x69, 0x73, 0x2D, 0x2D, 0x22, 0x54, 0x61, 0x6B, 0x65, + 0x20, 0x63, 0x61, 0x72, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x65, 0x6E, 0x73, 0x65, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6F, + 0x75, 0x6E, 0x64, 0x73, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, + 0x74, 0x61, 0x6B, 0x65, 0x20, 0x63, 0x61, 0x72, 0x65, 0x20, + 0x6F, 0x66, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x6D, 0x73, 0x65, + 0x6C, 0x76, 0x65, 0x73, 0x2E, 0x22, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x48, 0x6F, 0x77, 0x20, 0x66, 0x6F, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x66, 0x69, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6D, + 0x6F, 0x72, 0x61, 0x6C, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x73, 0x21, 0x27, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, + 0x64, 0x61, 0x72, 0x65, 0x20, 0x73, 0x61, 0x79, 0x20, 0x79, + 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x77, 0x6F, 0x6E, 0x64, + 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x68, 0x79, 0x20, + 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x70, 0x75, + 0x74, 0x20, 0x6D, 0x79, 0x20, 0x61, 0x72, 0x6D, 0x20, 0x72, + 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, + 0x77, 0x61, 0x69, 0x73, 0x74, 0x2C, 0x27, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x61, 0x66, 0x74, 0x65, + 0x72, 0x20, 0x61, 0x20, 0x70, 0x61, 0x75, 0x73, 0x65, 0x3A, + 0x20, 0x27, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x61, 0x73, + 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x49, 0x27, 0x6D, 0x20, 0x64, 0x6F, 0x75, 0x62, + 0x74, 0x66, 0x75, 0x6C, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x6D, 0x70, + 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x72, + 0x20, 0x66, 0x6C, 0x61, 0x6D, 0x69, 0x6E, 0x67, 0x6F, 0x2E, + 0x20, 0x53, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x49, 0x20, 0x74, + 0x72, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x70, + 0x65, 0x72, 0x69, 0x6D, 0x65, 0x6E, 0x74, 0x3F, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x45, 0x20, 0x6D, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x62, 0x69, 0x74, 0x65, 0x2C, 0x27, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x63, 0x61, 0x75, 0x74, + 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, 0x72, 0x65, 0x70, + 0x6C, 0x69, 0x65, 0x64, 0x2C, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x66, 0x65, 0x65, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x6E, 0x78, 0x69, 0x6F, + 0x75, 0x73, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x70, 0x65, + 0x72, 0x69, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x72, 0x69, + 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x56, 0x65, + 0x72, 0x79, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, + 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x3A, 0x20, 0x27, 0x66, + 0x6C, 0x61, 0x6D, 0x69, 0x6E, 0x67, 0x6F, 0x65, 0x73, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x61, 0x72, + 0x64, 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, 0x62, 0x69, 0x74, + 0x65, 0x2E, 0x20, 0x41, 0x6E, 0x64, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x61, 0x6C, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x2D, 0x2D, + 0x22, 0x42, 0x69, 0x72, 0x64, 0x73, 0x20, 0x6F, 0x66, 0x20, + 0x61, 0x20, 0x66, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x66, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x74, 0x6F, 0x67, 0x65, + 0x74, 0x68, 0x65, 0x72, 0x2E, 0x22, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x4F, 0x6E, 0x6C, 0x79, 0x20, 0x6D, 0x75, 0x73, + 0x74, 0x61, 0x72, 0x64, 0x20, 0x69, 0x73, 0x6E, 0x27, 0x74, + 0x20, 0x61, 0x20, 0x62, 0x69, 0x72, 0x64, 0x2C, 0x27, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x72, 0x65, 0x6D, 0x61, + 0x72, 0x6B, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x52, 0x69, 0x67, 0x68, 0x74, 0x2C, 0x20, 0x61, 0x73, 0x20, + 0x75, 0x73, 0x75, 0x61, 0x6C, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, + 0x68, 0x65, 0x73, 0x73, 0x3A, 0x20, 0x27, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x61, 0x20, 0x63, 0x6C, 0x65, 0x61, 0x72, 0x20, + 0x77, 0x61, 0x79, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x70, 0x75, 0x74, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x73, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, + 0x27, 0x73, 0x20, 0x61, 0x20, 0x6D, 0x69, 0x6E, 0x65, 0x72, + 0x61, 0x6C, 0x2C, 0x20, 0x49, 0x20, 0x54, 0x48, 0x49, 0x4E, + 0x4B, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x4F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x20, + 0x69, 0x74, 0x20, 0x69, 0x73, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, + 0x68, 0x65, 0x73, 0x73, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, + 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x72, 0x65, 0x61, + 0x64, 0x79, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x67, 0x72, 0x65, + 0x65, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x65, 0x76, 0x65, 0x72, + 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x3B, 0x20, 0x27, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x27, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, + 0x20, 0x6D, 0x75, 0x73, 0x74, 0x61, 0x72, 0x64, 0x2D, 0x6D, + 0x69, 0x6E, 0x65, 0x20, 0x6E, 0x65, 0x61, 0x72, 0x20, 0x68, + 0x65, 0x72, 0x65, 0x2E, 0x20, 0x41, 0x6E, 0x64, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x61, 0x6C, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, + 0x2D, 0x2D, 0x22, 0x54, 0x68, 0x65, 0x20, 0x6D, 0x6F, 0x72, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, + 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x69, 0x6E, 0x65, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6F, 0x66, + 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x72, 0x73, 0x2E, 0x22, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x49, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x21, 0x27, 0x20, 0x65, 0x78, + 0x63, 0x6C, 0x61, 0x69, 0x6D, 0x65, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x74, 0x74, + 0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x72, + 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x2C, 0x0D, 0x0A, 0x27, 0x69, + 0x74, 0x27, 0x73, 0x20, 0x61, 0x20, 0x76, 0x65, 0x67, 0x65, + 0x74, 0x61, 0x62, 0x6C, 0x65, 0x2E, 0x20, 0x49, 0x74, 0x20, + 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x6F, 0x6E, + 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, + 0x69, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, + 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x61, 0x67, 0x72, + 0x65, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x79, 0x6F, + 0x75, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, + 0x3B, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6D, 0x6F, 0x72, 0x61, 0x6C, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x69, 0x73, 0x2D, 0x2D, + 0x22, 0x42, 0x65, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x73, + 0x65, 0x65, 0x6D, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x22, + 0x2D, 0x2D, 0x6F, 0x72, 0x20, 0x69, 0x66, 0x20, 0x79, 0x6F, + 0x75, 0x27, 0x64, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x69, + 0x74, 0x20, 0x70, 0x75, 0x74, 0x20, 0x6D, 0x6F, 0x72, 0x65, + 0x0D, 0x0A, 0x73, 0x69, 0x6D, 0x70, 0x6C, 0x79, 0x2D, 0x2D, + 0x22, 0x4E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x69, 0x6D, 0x61, + 0x67, 0x69, 0x6E, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x77, + 0x69, 0x73, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x77, + 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6D, 0x69, 0x67, + 0x68, 0x74, 0x0D, 0x0A, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, + 0x20, 0x74, 0x6F, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x68, 0x61, 0x74, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, + 0x6F, 0x72, 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x77, 0x69, 0x73, 0x65, 0x0D, 0x0A, 0x74, 0x68, + 0x61, 0x6E, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x68, 0x61, 0x64, 0x20, 0x62, 0x65, 0x65, 0x6E, + 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x74, + 0x6F, 0x20, 0x62, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x77, 0x69, 0x73, 0x65, 0x2E, 0x22, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x20, + 0x49, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x75, + 0x6E, 0x64, 0x65, 0x72, 0x73, 0x74, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x62, 0x65, 0x74, 0x74, 0x65, + 0x72, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x70, 0x6F, 0x6C, 0x69, 0x74, 0x65, 0x6C, 0x79, 0x2C, 0x20, + 0x27, 0x69, 0x66, 0x0D, 0x0A, 0x49, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, + 0x6E, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x3A, 0x20, 0x62, 0x75, + 0x74, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6F, 0x6C, 0x6C, + 0x6F, 0x77, 0x20, 0x69, 0x74, 0x20, 0x61, 0x73, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x73, 0x61, 0x79, 0x20, 0x69, 0x74, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, 0x74, + 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x49, + 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x73, 0x61, 0x79, + 0x20, 0x69, 0x66, 0x20, 0x49, 0x20, 0x63, 0x68, 0x6F, 0x73, + 0x65, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, + 0x63, 0x68, 0x65, 0x73, 0x73, 0x20, 0x72, 0x65, 0x70, 0x6C, + 0x69, 0x65, 0x64, 0x2C, 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x61, + 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x6E, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x50, + 0x72, 0x61, 0x79, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, + 0x74, 0x72, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x20, 0x79, 0x6F, + 0x75, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x61, 0x79, 0x20, 0x69, 0x74, 0x20, 0x61, 0x6E, 0x79, + 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, + 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x74, 0x61, 0x6C, + 0x6B, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x72, + 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, + 0x68, 0x65, 0x73, 0x73, 0x2E, 0x20, 0x27, 0x49, 0x20, 0x6D, + 0x61, 0x6B, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x61, 0x20, + 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, 0x0D, 0x0A, 0x6F, + 0x66, 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x20, 0x49, 0x27, 0x76, 0x65, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x61, 0x73, 0x20, 0x79, 0x65, 0x74, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x20, 0x63, 0x68, + 0x65, 0x61, 0x70, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x20, 0x6F, + 0x66, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, 0x21, + 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x20, 0x27, 0x49, 0x27, + 0x6D, 0x20, 0x67, 0x6C, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x79, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x67, 0x69, + 0x76, 0x65, 0x0D, 0x0A, 0x62, 0x69, 0x72, 0x74, 0x68, 0x64, + 0x61, 0x79, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, + 0x73, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x21, 0x27, 0x20, 0x42, 0x75, 0x74, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x76, 0x65, 0x6E, 0x74, 0x75, 0x72, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x73, 0x61, 0x79, 0x20, 0x69, 0x74, 0x20, 0x6F, 0x75, + 0x74, 0x0D, 0x0A, 0x6C, 0x6F, 0x75, 0x64, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x69, 0x6E, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x3F, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, + 0x73, 0x20, 0x61, 0x73, 0x6B, 0x65, 0x64, 0x2C, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x64, 0x69, 0x67, 0x20, 0x6F, 0x66, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x73, 0x68, 0x61, 0x72, 0x70, 0x0D, 0x0A, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x63, 0x68, 0x69, + 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x76, + 0x65, 0x20, 0x61, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x73, 0x68, 0x61, 0x72, 0x70, 0x6C, 0x79, 0x2C, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x6E, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x66, 0x65, 0x65, + 0x6C, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x77, 0x6F, 0x72, 0x72, 0x69, 0x65, 0x64, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x4A, 0x75, 0x73, 0x74, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x73, 0x20, 0x6D, 0x75, + 0x63, 0x68, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x2C, 0x20, 0x27, + 0x61, 0x73, 0x20, 0x70, 0x69, 0x67, 0x73, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x6C, 0x79, 0x3B, + 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, + 0x6D, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x42, 0x75, + 0x74, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2C, 0x20, 0x74, 0x6F, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x27, 0x73, 0x20, 0x67, + 0x72, 0x65, 0x61, 0x74, 0x20, 0x73, 0x75, 0x72, 0x70, 0x72, + 0x69, 0x73, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, + 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x27, 0x73, 0x20, 0x76, + 0x6F, 0x69, 0x63, 0x65, 0x20, 0x64, 0x69, 0x65, 0x64, 0x20, + 0x61, 0x77, 0x61, 0x79, 0x2C, 0x20, 0x65, 0x76, 0x65, 0x6E, + 0x0D, 0x0A, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, + 0x69, 0x64, 0x64, 0x6C, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x66, 0x61, 0x76, 0x6F, 0x75, 0x72, 0x69, + 0x74, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x20, 0x27, 0x6D, + 0x6F, 0x72, 0x61, 0x6C, 0x2C, 0x27, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x6D, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6C, 0x69, + 0x6E, 0x6B, 0x65, 0x64, 0x0D, 0x0A, 0x69, 0x6E, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x72, 0x73, 0x20, 0x62, 0x65, 0x67, 0x61, + 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x72, 0x65, 0x6D, 0x62, + 0x6C, 0x65, 0x2E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x75, 0x70, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x73, 0x74, 0x6F, 0x6F, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x0D, 0x0A, 0x69, 0x6E, + 0x20, 0x66, 0x72, 0x6F, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x6D, 0x73, 0x20, + 0x66, 0x6F, 0x6C, 0x64, 0x65, 0x64, 0x2C, 0x20, 0x66, 0x72, + 0x6F, 0x77, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x61, 0x20, 0x74, 0x68, 0x75, 0x6E, 0x64, 0x65, + 0x72, 0x73, 0x74, 0x6F, 0x72, 0x6D, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x41, 0x20, 0x66, 0x69, 0x6E, 0x65, 0x20, 0x64, + 0x61, 0x79, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x4D, + 0x61, 0x6A, 0x65, 0x73, 0x74, 0x79, 0x21, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, + 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x20, 0x6C, 0x6F, 0x77, 0x2C, 0x20, 0x77, 0x65, 0x61, + 0x6B, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x77, 0x2C, 0x20, 0x49, 0x20, + 0x67, 0x69, 0x76, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x66, + 0x61, 0x69, 0x72, 0x20, 0x77, 0x61, 0x72, 0x6E, 0x69, 0x6E, + 0x67, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x74, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, + 0x6E, 0x2C, 0x20, 0x73, 0x74, 0x61, 0x6D, 0x70, 0x69, 0x6E, + 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x61, 0x73, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6B, 0x65, 0x3B, + 0x20, 0x27, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x6F, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x72, + 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x6D, 0x75, 0x73, 0x74, + 0x20, 0x62, 0x65, 0x20, 0x6F, 0x66, 0x66, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x6E, + 0x0D, 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x68, 0x61, + 0x6C, 0x66, 0x20, 0x6E, 0x6F, 0x20, 0x74, 0x69, 0x6D, 0x65, + 0x21, 0x20, 0x54, 0x61, 0x6B, 0x65, 0x20, 0x79, 0x6F, 0x75, + 0x72, 0x20, 0x63, 0x68, 0x6F, 0x69, 0x63, 0x65, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x44, 0x75, + 0x63, 0x68, 0x65, 0x73, 0x73, 0x20, 0x74, 0x6F, 0x6F, 0x6B, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x63, 0x68, 0x6F, 0x69, 0x63, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x67, 0x6F, 0x6E, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x67, + 0x6F, 0x20, 0x6F, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x2C, 0x27, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x0D, + 0x0A, 0x74, 0x6F, 0x6F, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, + 0x66, 0x72, 0x69, 0x67, 0x68, 0x74, 0x65, 0x6E, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, 0x20, 0x61, 0x20, + 0x77, 0x6F, 0x72, 0x64, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x73, 0x6C, 0x6F, 0x77, 0x6C, 0x79, 0x20, 0x66, 0x6F, 0x6C, + 0x6C, 0x6F, 0x77, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x63, 0x72, 0x6F, 0x71, 0x75, 0x65, 0x74, + 0x2D, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x67, 0x75, 0x65, 0x73, 0x74, 0x73, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x74, 0x61, 0x6B, 0x65, 0x6E, 0x20, 0x61, + 0x64, 0x76, 0x61, 0x6E, 0x74, 0x61, 0x67, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, + 0x6E, 0x27, 0x73, 0x20, 0x61, 0x62, 0x73, 0x65, 0x6E, 0x63, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x65, 0x72, + 0x65, 0x0D, 0x0A, 0x72, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x68, + 0x61, 0x64, 0x65, 0x3A, 0x20, 0x68, 0x6F, 0x77, 0x65, 0x76, + 0x65, 0x72, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, + 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x73, 0x61, 0x77, 0x20, 0x68, 0x65, 0x72, 0x2C, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x68, 0x75, 0x72, 0x72, 0x69, 0x65, + 0x64, 0x0D, 0x0A, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x61, 0x6D, 0x65, 0x2C, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, + 0x20, 0x6D, 0x65, 0x72, 0x65, 0x6C, 0x79, 0x20, 0x72, 0x65, + 0x6D, 0x61, 0x72, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x61, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, + 0x74, 0x27, 0x73, 0x20, 0x64, 0x65, 0x6C, 0x61, 0x79, 0x20, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x0D, 0x0A, 0x63, 0x6F, 0x73, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x6C, 0x69, 0x76, 0x65, 0x73, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x70, 0x6C, 0x61, 0x79, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, + 0x65, 0x65, 0x6E, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, + 0x6C, 0x65, 0x66, 0x74, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x71, + 0x75, 0x61, 0x72, 0x72, 0x65, 0x6C, 0x6C, 0x69, 0x6E, 0x67, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x74, 0x68, 0x65, + 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x70, 0x6C, 0x61, + 0x79, 0x65, 0x72, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x68, 0x6F, 0x75, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x27, + 0x4F, 0x66, 0x66, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, 0x21, 0x27, 0x20, + 0x6F, 0x72, 0x20, 0x27, 0x4F, 0x66, 0x66, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x68, 0x65, + 0x61, 0x64, 0x21, 0x27, 0x20, 0x54, 0x68, 0x6F, 0x73, 0x65, + 0x20, 0x77, 0x68, 0x6F, 0x6D, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x73, 0x65, 0x6E, 0x74, 0x65, 0x6E, 0x63, 0x65, 0x64, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x74, 0x61, 0x6B, 0x65, 0x6E, + 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x63, 0x75, 0x73, 0x74, + 0x6F, 0x64, 0x79, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x6F, 0x6C, 0x64, 0x69, 0x65, 0x72, 0x73, 0x2C, + 0x0D, 0x0A, 0x77, 0x68, 0x6F, 0x20, 0x6F, 0x66, 0x20, 0x63, + 0x6F, 0x75, 0x72, 0x73, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x6C, 0x65, 0x61, 0x76, 0x65, 0x20, 0x6F, + 0x66, 0x66, 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x72, 0x63, 0x68, 0x65, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x64, + 0x6F, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, 0x20, 0x73, 0x6F, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x62, 0x79, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x65, 0x6E, 0x64, 0x20, 0x6F, 0x66, + 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x61, 0x6E, 0x20, 0x68, + 0x6F, 0x75, 0x72, 0x20, 0x6F, 0x72, 0x20, 0x73, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x65, 0x72, 0x65, + 0x20, 0x6E, 0x6F, 0x20, 0x61, 0x72, 0x63, 0x68, 0x65, 0x73, + 0x20, 0x6C, 0x65, 0x66, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x70, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x73, 0x2C, 0x20, 0x65, + 0x78, 0x63, 0x65, 0x70, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x63, 0x75, 0x73, 0x74, + 0x6F, 0x64, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x75, + 0x6E, 0x64, 0x65, 0x72, 0x20, 0x73, 0x65, 0x6E, 0x74, 0x65, + 0x6E, 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x6C, 0x65, 0x66, 0x74, + 0x20, 0x6F, 0x66, 0x66, 0x2C, 0x20, 0x71, 0x75, 0x69, 0x74, + 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x62, + 0x72, 0x65, 0x61, 0x74, 0x68, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x27, 0x48, 0x61, 0x76, + 0x65, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x73, 0x65, 0x65, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, + 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x79, 0x65, + 0x74, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2E, 0x20, 0x27, 0x49, 0x20, 0x64, 0x6F, + 0x6E, 0x27, 0x74, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x6B, + 0x6E, 0x6F, 0x77, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x61, + 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, + 0x6C, 0x65, 0x20, 0x69, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x53, + 0x6F, 0x75, 0x70, 0x20, 0x69, 0x73, 0x20, 0x6D, 0x61, 0x64, + 0x65, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, + 0x65, 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, + 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x73, 0x61, 0x77, + 0x20, 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x68, + 0x65, 0x61, 0x72, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x6F, 0x6E, + 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x74, + 0x68, 0x65, 0x6E, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, + 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x20, + 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x65, 0x6C, 0x6C, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x68, 0x69, 0x73, 0x20, 0x68, + 0x69, 0x73, 0x74, 0x6F, 0x72, 0x79, 0x2C, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x41, 0x73, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x77, 0x61, 0x6C, 0x6B, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, + 0x20, 0x74, 0x6F, 0x67, 0x65, 0x74, 0x68, 0x65, 0x72, 0x2C, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x68, 0x65, 0x61, + 0x72, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, + 0x67, 0x20, 0x73, 0x61, 0x79, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x6C, 0x6F, 0x77, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, + 0x2C, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x6E, 0x79, 0x20, 0x67, 0x65, + 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x6C, 0x79, 0x2C, 0x20, 0x27, + 0x59, 0x6F, 0x75, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x70, 0x61, 0x72, 0x64, 0x6F, 0x6E, 0x65, 0x64, + 0x2E, 0x27, 0x20, 0x27, 0x43, 0x6F, 0x6D, 0x65, 0x2C, 0x20, + 0x54, 0x48, 0x41, 0x54, 0x27, 0x53, 0x20, 0x61, 0x20, 0x67, + 0x6F, 0x6F, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x21, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x66, 0x65, 0x6C, 0x74, + 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x75, 0x6E, 0x68, + 0x61, 0x70, 0x70, 0x79, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, + 0x6F, 0x66, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, + 0x65, 0x65, 0x6E, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6F, 0x72, + 0x64, 0x65, 0x72, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x54, 0x68, 0x65, 0x79, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, + 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x61, 0x20, 0x47, 0x72, 0x79, + 0x70, 0x68, 0x6F, 0x6E, 0x2C, 0x20, 0x6C, 0x79, 0x69, 0x6E, + 0x67, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x61, 0x73, 0x6C, + 0x65, 0x65, 0x70, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x75, 0x6E, 0x2E, 0x0D, 0x0A, 0x28, 0x49, 0x46, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x77, 0x68, 0x61, 0x74, + 0x20, 0x61, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, + 0x20, 0x69, 0x73, 0x2C, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x69, 0x63, + 0x74, 0x75, 0x72, 0x65, 0x2E, 0x29, 0x20, 0x27, 0x55, 0x70, + 0x2C, 0x20, 0x6C, 0x61, 0x7A, 0x79, 0x0D, 0x0A, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, + 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x61, 0x6B, + 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x79, 0x6F, 0x75, + 0x6E, 0x67, 0x20, 0x6C, 0x61, 0x64, 0x79, 0x20, 0x74, 0x6F, + 0x20, 0x73, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, + 0x6F, 0x63, 0x6B, 0x0D, 0x0A, 0x54, 0x75, 0x72, 0x74, 0x6C, + 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x61, 0x72, 0x20, 0x68, 0x69, 0x73, 0x20, 0x68, + 0x69, 0x73, 0x74, 0x6F, 0x72, 0x79, 0x2E, 0x20, 0x49, 0x20, + 0x6D, 0x75, 0x73, 0x74, 0x20, 0x67, 0x6F, 0x20, 0x62, 0x61, + 0x63, 0x6B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x65, 0x65, + 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x73, 0x6F, 0x6D, + 0x65, 0x0D, 0x0A, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x20, 0x49, 0x20, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x27, 0x3B, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x6C, 0x6B, 0x65, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x2C, + 0x20, 0x6C, 0x65, 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x6C, 0x6F, 0x6E, 0x65, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x74, 0x68, 0x65, + 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2E, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, + 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2C, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x6F, 0x6E, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x68, 0x6F, 0x6C, 0x65, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x62, 0x65, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x61, + 0x73, 0x20, 0x73, 0x61, 0x66, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x74, 0x61, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x69, 0x74, 0x20, 0x61, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x67, + 0x6F, 0x0D, 0x0A, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x73, 0x61, 0x76, 0x61, 0x67, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x3A, 0x20, 0x73, 0x6F, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x69, 0x74, 0x65, + 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x73, 0x61, + 0x74, 0x20, 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, + 0x75, 0x62, 0x62, 0x65, 0x64, 0x20, 0x69, 0x74, 0x73, 0x20, + 0x65, 0x79, 0x65, 0x73, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x6E, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, + 0x6E, 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x0D, 0x0A, 0x73, 0x68, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6F, 0x75, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x73, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x20, + 0x74, 0x68, 0x65, 0x6E, 0x20, 0x69, 0x74, 0x20, 0x63, 0x68, + 0x75, 0x63, 0x6B, 0x6C, 0x65, 0x64, 0x2E, 0x20, 0x27, 0x57, + 0x68, 0x61, 0x74, 0x20, 0x66, 0x75, 0x6E, 0x21, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, + 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2C, 0x0D, 0x0A, 0x68, + 0x61, 0x6C, 0x66, 0x20, 0x74, 0x6F, 0x20, 0x69, 0x74, 0x73, + 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, + 0x74, 0x6F, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, 0x49, + 0x53, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6E, 0x3F, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, + 0x79, 0x2C, 0x20, 0x53, 0x48, 0x45, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, + 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2E, 0x20, 0x27, 0x49, 0x74, + 0x27, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x66, 0x61, 0x6E, 0x63, 0x79, 0x2C, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x6E, + 0x65, 0x76, 0x65, 0x72, 0x0D, 0x0A, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x62, 0x6F, 0x64, + 0x79, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, + 0x77, 0x2E, 0x20, 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x6E, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x45, 0x76, 0x65, + 0x72, 0x79, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x73, 0x61, 0x79, + 0x73, 0x20, 0x22, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x6E, + 0x21, 0x22, 0x20, 0x68, 0x65, 0x72, 0x65, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x6C, 0x6F, + 0x77, 0x6C, 0x79, 0x0D, 0x0A, 0x61, 0x66, 0x74, 0x65, 0x72, + 0x20, 0x69, 0x74, 0x3A, 0x20, 0x27, 0x49, 0x20, 0x6E, 0x65, + 0x76, 0x65, 0x72, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x6F, + 0x20, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x6D, 0x79, 0x20, 0x6C, 0x69, 0x66, 0x65, 0x2C, + 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x21, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x79, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x67, 0x6F, 0x6E, 0x65, 0x20, + 0x66, 0x61, 0x72, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x73, 0x61, 0x77, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, + 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, + 0x65, 0x2C, 0x0D, 0x0A, 0x73, 0x69, 0x74, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x73, 0x61, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x6C, 0x6F, 0x6E, 0x65, 0x6C, 0x79, 0x20, 0x6F, 0x6E, 0x20, + 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x6C, + 0x65, 0x64, 0x67, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x72, 0x6F, + 0x63, 0x6B, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x61, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x61, 0x6D, + 0x65, 0x0D, 0x0A, 0x6E, 0x65, 0x61, 0x72, 0x65, 0x72, 0x2C, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x63, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x68, 0x65, 0x61, 0x72, 0x20, 0x68, 0x69, + 0x6D, 0x20, 0x73, 0x69, 0x67, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x68, 0x65, 0x61, 0x72, 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B, 0x2E, 0x20, 0x53, + 0x68, 0x65, 0x0D, 0x0A, 0x70, 0x69, 0x74, 0x69, 0x65, 0x64, + 0x20, 0x68, 0x69, 0x6D, 0x20, 0x64, 0x65, 0x65, 0x70, 0x6C, + 0x79, 0x2E, 0x20, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, 0x69, + 0x73, 0x20, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6F, 0x72, 0x72, + 0x6F, 0x77, 0x3F, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x61, + 0x73, 0x6B, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, + 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x47, 0x72, 0x79, + 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x61, 0x6E, 0x73, 0x77, 0x65, + 0x72, 0x65, 0x64, 0x2C, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, + 0x6E, 0x65, 0x61, 0x72, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x77, + 0x6F, 0x72, 0x64, 0x73, 0x20, 0x61, 0x73, 0x20, 0x62, 0x65, + 0x66, 0x6F, 0x72, 0x65, 0x2C, 0x20, 0x27, 0x49, 0x74, 0x27, + 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x68, 0x69, 0x73, 0x0D, + 0x0A, 0x66, 0x61, 0x6E, 0x63, 0x79, 0x2C, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x3A, 0x20, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, + 0x6E, 0x27, 0x74, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x6E, 0x6F, + 0x20, 0x73, 0x6F, 0x72, 0x72, 0x6F, 0x77, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x20, 0x43, + 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x6E, 0x21, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x53, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x75, 0x70, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, + 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2C, 0x20, 0x77, 0x68, + 0x6F, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x65, 0x79, + 0x65, 0x73, 0x0D, 0x0A, 0x66, 0x75, 0x6C, 0x6C, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x65, 0x61, 0x72, 0x73, 0x2C, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x54, 0x68, 0x69, 0x73, 0x20, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x79, 0x6F, 0x75, 0x6E, 0x67, 0x20, 0x6C, 0x61, 0x64, + 0x79, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, + 0x2C, 0x20, 0x27, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x6E, + 0x74, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x6F, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x0D, + 0x0A, 0x68, 0x69, 0x73, 0x74, 0x6F, 0x72, 0x79, 0x2C, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x74, 0x65, + 0x6C, 0x6C, 0x20, 0x69, 0x74, 0x20, 0x68, 0x65, 0x72, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, + 0x6C, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x64, 0x65, + 0x65, 0x70, 0x2C, 0x20, 0x68, 0x6F, 0x6C, 0x6C, 0x6F, 0x77, + 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x3A, 0x20, 0x27, 0x73, 0x69, + 0x74, 0x0D, 0x0A, 0x64, 0x6F, 0x77, 0x6E, 0x2C, 0x20, 0x62, + 0x6F, 0x74, 0x68, 0x20, 0x6F, 0x66, 0x20, 0x79, 0x6F, 0x75, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x20, 0x61, 0x20, + 0x77, 0x6F, 0x72, 0x64, 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x20, + 0x49, 0x27, 0x76, 0x65, 0x20, 0x66, 0x69, 0x6E, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x73, 0x61, 0x74, + 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6E, 0x6F, 0x62, 0x6F, 0x64, 0x79, 0x20, 0x73, 0x70, + 0x6F, 0x6B, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x73, 0x6F, + 0x6D, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x73, + 0x2E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, 0x0D, 0x0A, + 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, + 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x73, 0x65, + 0x65, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x68, 0x65, 0x20, 0x63, + 0x61, 0x6E, 0x20, 0x45, 0x56, 0x45, 0x4E, 0x20, 0x66, 0x69, + 0x6E, 0x69, 0x73, 0x68, 0x2C, 0x20, 0x69, 0x66, 0x20, 0x68, + 0x65, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, 0x74, 0x20, + 0x62, 0x65, 0x67, 0x69, 0x6E, 0x2E, 0x27, 0x20, 0x42, 0x75, + 0x74, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x69, + 0x74, 0x65, 0x64, 0x20, 0x70, 0x61, 0x74, 0x69, 0x65, 0x6E, + 0x74, 0x6C, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, + 0x6E, 0x63, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, + 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x61, 0x74, 0x20, + 0x6C, 0x61, 0x73, 0x74, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x61, 0x20, 0x64, 0x65, 0x65, 0x70, 0x20, 0x73, 0x69, + 0x67, 0x68, 0x2C, 0x20, 0x27, 0x49, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x61, 0x20, 0x72, 0x65, 0x61, 0x6C, 0x0D, 0x0A, 0x54, + 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x65, 0x73, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x64, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x66, 0x6F, + 0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, + 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6C, 0x6F, 0x6E, + 0x67, 0x20, 0x73, 0x69, 0x6C, 0x65, 0x6E, 0x63, 0x65, 0x2C, + 0x20, 0x62, 0x72, 0x6F, 0x6B, 0x65, 0x6E, 0x20, 0x6F, 0x6E, + 0x6C, 0x79, 0x20, 0x62, 0x79, 0x20, 0x61, 0x6E, 0x0D, 0x0A, + 0x6F, 0x63, 0x63, 0x61, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, + 0x20, 0x65, 0x78, 0x63, 0x6C, 0x61, 0x6D, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x27, 0x48, 0x6A, 0x63, + 0x6B, 0x72, 0x72, 0x68, 0x21, 0x27, 0x20, 0x66, 0x72, 0x6F, + 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, + 0x68, 0x6F, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, + 0x74, 0x0D, 0x0A, 0x68, 0x65, 0x61, 0x76, 0x79, 0x20, 0x73, + 0x6F, 0x62, 0x62, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, + 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2E, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x6E, 0x65, 0x61, 0x72, 0x6C, 0x79, 0x20, 0x67, + 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x75, 0x70, 0x20, + 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x73, 0x61, 0x79, 0x69, 0x6E, + 0x67, 0x2C, 0x20, 0x27, 0x54, 0x68, 0x61, 0x6E, 0x6B, 0x20, + 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x73, 0x69, 0x72, 0x2C, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x69, + 0x6E, 0x74, 0x65, 0x72, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x73, 0x74, 0x6F, 0x72, 0x79, 0x2C, 0x27, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, + 0x6C, 0x64, 0x0D, 0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x68, 0x65, + 0x6C, 0x70, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x4D, 0x55, + 0x53, 0x54, 0x20, 0x62, 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x65, + 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x2C, 0x20, + 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x74, + 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x0D, 0x0A, 0x6E, 0x6F, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x57, 0x68, 0x65, 0x6E, 0x20, 0x77, 0x65, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x2C, + 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, + 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x77, 0x65, + 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x61, 0x74, 0x20, 0x6C, + 0x61, 0x73, 0x74, 0x2C, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, + 0x63, 0x61, 0x6C, 0x6D, 0x6C, 0x79, 0x2C, 0x0D, 0x0A, 0x74, + 0x68, 0x6F, 0x75, 0x67, 0x68, 0x20, 0x73, 0x74, 0x69, 0x6C, + 0x6C, 0x20, 0x73, 0x6F, 0x62, 0x62, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x6E, + 0x6F, 0x77, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x6E, 0x2C, 0x20, 0x27, 0x77, 0x65, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x63, 0x68, 0x6F, 0x6F, + 0x6C, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x73, 0x65, 0x61, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6D, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x61, 0x6E, 0x20, 0x6F, 0x6C, 0x64, 0x20, 0x54, 0x75, 0x72, + 0x74, 0x6C, 0x65, 0x2D, 0x2D, 0x77, 0x65, 0x20, 0x75, 0x73, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x61, 0x6C, 0x6C, + 0x20, 0x68, 0x69, 0x6D, 0x20, 0x54, 0x6F, 0x72, 0x74, 0x6F, + 0x69, 0x73, 0x65, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x57, 0x68, 0x79, 0x20, 0x64, 0x69, 0x64, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x20, 0x68, 0x69, + 0x6D, 0x20, 0x54, 0x6F, 0x72, 0x74, 0x6F, 0x69, 0x73, 0x65, + 0x2C, 0x20, 0x69, 0x66, 0x20, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x6E, 0x27, 0x74, 0x20, 0x6F, 0x6E, 0x65, 0x3F, 0x27, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x73, 0x6B, + 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, + 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x68, 0x69, + 0x6D, 0x20, 0x54, 0x6F, 0x72, 0x74, 0x6F, 0x69, 0x73, 0x65, + 0x20, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x68, + 0x65, 0x20, 0x74, 0x61, 0x75, 0x67, 0x68, 0x74, 0x20, 0x75, + 0x73, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, + 0x72, 0x74, 0x6C, 0x65, 0x0D, 0x0A, 0x61, 0x6E, 0x67, 0x72, + 0x69, 0x6C, 0x79, 0x3A, 0x20, 0x27, 0x72, 0x65, 0x61, 0x6C, + 0x6C, 0x79, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x61, 0x72, 0x65, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x64, 0x75, 0x6C, 0x6C, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, + 0x20, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x62, 0x65, 0x20, 0x61, 0x73, 0x68, 0x61, 0x6D, 0x65, 0x64, + 0x20, 0x6F, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x73, 0x6B, + 0x69, 0x6E, 0x67, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, + 0x20, 0x73, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x27, 0x0D, 0x0A, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x3B, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, 0x73, 0x61, + 0x74, 0x20, 0x73, 0x69, 0x6C, 0x65, 0x6E, 0x74, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, + 0x61, 0x74, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x0D, 0x0A, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, + 0x66, 0x65, 0x6C, 0x74, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79, + 0x20, 0x74, 0x6F, 0x20, 0x73, 0x69, 0x6E, 0x6B, 0x20, 0x69, + 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x61, + 0x72, 0x74, 0x68, 0x2E, 0x20, 0x41, 0x74, 0x20, 0x6C, 0x61, + 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, + 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x73, 0x61, 0x69, 0x64, 0x0D, + 0x0A, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, + 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2C, + 0x20, 0x27, 0x44, 0x72, 0x69, 0x76, 0x65, 0x20, 0x6F, 0x6E, + 0x2C, 0x20, 0x6F, 0x6C, 0x64, 0x20, 0x66, 0x65, 0x6C, 0x6C, + 0x6F, 0x77, 0x21, 0x20, 0x44, 0x6F, 0x6E, 0x27, 0x74, 0x20, + 0x62, 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x64, 0x61, 0x79, + 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, 0x21, + 0x27, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x64, 0x73, 0x3A, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x65, + 0x73, 0x2C, 0x20, 0x77, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x73, 0x63, 0x68, 0x6F, 0x6F, 0x6C, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, + 0x61, 0x2C, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, 0x6E, 0x27, 0x74, + 0x20, 0x62, 0x65, 0x6C, 0x69, 0x65, 0x76, 0x65, 0x20, 0x69, + 0x74, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, + 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x49, 0x20, 0x64, 0x69, 0x64, 0x6E, 0x27, 0x74, + 0x21, 0x27, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, + 0x70, 0x74, 0x65, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, + 0x64, 0x69, 0x64, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, + 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x48, 0x6F, 0x6C, 0x64, 0x20, 0x79, 0x6F, 0x75, + 0x72, 0x20, 0x74, 0x6F, 0x6E, 0x67, 0x75, 0x65, 0x21, 0x27, + 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2C, 0x20, + 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x73, + 0x70, 0x65, 0x61, 0x6B, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, + 0x2E, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x57, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x65, 0x73, 0x74, 0x20, 0x6F, 0x66, + 0x20, 0x65, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x73, 0x2D, 0x2D, 0x69, 0x6E, 0x20, 0x66, 0x61, 0x63, 0x74, + 0x2C, 0x20, 0x77, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x73, 0x63, 0x68, 0x6F, 0x6F, 0x6C, 0x20, + 0x65, 0x76, 0x65, 0x72, 0x79, 0x20, 0x64, 0x61, 0x79, 0x2D, + 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x56, + 0x45, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x20, + 0x61, 0x20, 0x64, 0x61, 0x79, 0x2D, 0x73, 0x63, 0x68, 0x6F, + 0x6F, 0x6C, 0x2C, 0x20, 0x74, 0x6F, 0x6F, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x3B, 0x20, 0x27, 0x79, 0x6F, 0x75, 0x20, 0x6E, 0x65, 0x65, + 0x64, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, 0x73, 0x6F, + 0x20, 0x70, 0x72, 0x6F, 0x75, 0x64, 0x0D, 0x0A, 0x61, 0x73, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x69, 0x74, 0x68, + 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x73, 0x3F, 0x27, 0x20, + 0x61, 0x73, 0x6B, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, + 0x65, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x61, 0x6E, 0x78, 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x65, 0x73, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2C, 0x20, 0x27, 0x77, 0x65, 0x20, 0x6C, 0x65, + 0x61, 0x72, 0x6E, 0x65, 0x64, 0x20, 0x46, 0x72, 0x65, 0x6E, + 0x63, 0x68, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x75, 0x73, + 0x69, 0x63, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, + 0x6E, 0x64, 0x20, 0x77, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, + 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, + 0x74, 0x6C, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x43, + 0x65, 0x72, 0x74, 0x61, 0x69, 0x6E, 0x6C, 0x79, 0x20, 0x6E, + 0x6F, 0x74, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x69, 0x6E, 0x64, 0x69, + 0x67, 0x6E, 0x61, 0x6E, 0x74, 0x6C, 0x79, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x41, 0x68, 0x21, 0x20, 0x74, 0x68, 0x65, + 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x73, 0x20, 0x77, 0x61, + 0x73, 0x6E, 0x27, 0x74, 0x20, 0x61, 0x20, 0x72, 0x65, 0x61, + 0x6C, 0x6C, 0x79, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x73, + 0x63, 0x68, 0x6F, 0x6F, 0x6C, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x69, + 0x6E, 0x0D, 0x0A, 0x61, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x72, + 0x65, 0x6C, 0x69, 0x65, 0x66, 0x2E, 0x20, 0x27, 0x4E, 0x6F, + 0x77, 0x20, 0x61, 0x74, 0x20, 0x4F, 0x55, 0x52, 0x53, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x68, 0x61, 0x64, 0x20, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6E, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x6C, + 0x6C, 0x2C, 0x0D, 0x0A, 0x22, 0x46, 0x72, 0x65, 0x6E, 0x63, + 0x68, 0x2C, 0x20, 0x6D, 0x75, 0x73, 0x69, 0x63, 0x2C, 0x20, + 0x41, 0x4E, 0x44, 0x20, 0x57, 0x41, 0x53, 0x48, 0x49, 0x4E, + 0x47, 0x2D, 0x2D, 0x65, 0x78, 0x74, 0x72, 0x61, 0x2E, 0x22, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, + 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x65, 0x64, + 0x20, 0x69, 0x74, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x3B, 0x20, 0x27, 0x6C, 0x69, 0x76, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6F, + 0x74, 0x74, 0x6F, 0x6D, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x65, 0x61, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, + 0x6E, 0x27, 0x74, 0x20, 0x61, 0x66, 0x66, 0x6F, 0x72, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x65, 0x61, 0x72, 0x6E, 0x20, + 0x69, 0x74, 0x2E, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, + 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x68, 0x2E, 0x20, 0x27, + 0x49, 0x0D, 0x0A, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x74, 0x6F, + 0x6F, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x67, + 0x75, 0x6C, 0x61, 0x72, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, + 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, + 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x3F, 0x27, 0x20, 0x69, 0x6E, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x52, 0x65, 0x65, 0x6C, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x57, 0x72, 0x69, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x6F, 0x66, 0x20, 0x63, + 0x6F, 0x75, 0x72, 0x73, 0x65, 0x2C, 0x20, 0x74, 0x6F, 0x20, + 0x62, 0x65, 0x67, 0x69, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x0D, 0x0A, + 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x3B, 0x20, 0x27, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x20, 0x62, 0x72, 0x61, 0x6E, 0x63, 0x68, 0x65, + 0x73, 0x20, 0x6F, 0x66, 0x20, 0x41, 0x72, 0x69, 0x74, 0x68, + 0x6D, 0x65, 0x74, 0x69, 0x63, 0x2D, 0x2D, 0x41, 0x6D, 0x62, + 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x0D, 0x0A, 0x44, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2C, + 0x20, 0x55, 0x67, 0x6C, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x44, + 0x65, 0x72, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x6E, 0x65, 0x76, 0x65, + 0x72, 0x20, 0x68, 0x65, 0x61, 0x72, 0x64, 0x20, 0x6F, 0x66, + 0x20, 0x22, 0x55, 0x67, 0x6C, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x22, 0x27, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x76, 0x65, 0x6E, 0x74, 0x75, 0x72, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, 0x2E, + 0x20, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, + 0x69, 0x74, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, + 0x6C, 0x69, 0x66, 0x74, 0x65, 0x64, 0x20, 0x75, 0x70, 0x20, + 0x62, 0x6F, 0x74, 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, 0x70, + 0x61, 0x77, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x73, 0x75, 0x72, + 0x70, 0x72, 0x69, 0x73, 0x65, 0x2E, 0x20, 0x27, 0x57, 0x68, + 0x61, 0x74, 0x21, 0x20, 0x4E, 0x65, 0x76, 0x65, 0x72, 0x20, + 0x68, 0x65, 0x61, 0x72, 0x64, 0x20, 0x6F, 0x66, 0x0D, 0x0A, + 0x75, 0x67, 0x6C, 0x69, 0x66, 0x79, 0x69, 0x6E, 0x67, 0x21, + 0x27, 0x20, 0x69, 0x74, 0x20, 0x65, 0x78, 0x63, 0x6C, 0x61, + 0x69, 0x6D, 0x65, 0x64, 0x2E, 0x20, 0x27, 0x59, 0x6F, 0x75, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x77, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, + 0x66, 0x79, 0x20, 0x69, 0x73, 0x2C, 0x20, 0x49, 0x20, 0x73, + 0x75, 0x70, 0x70, 0x6F, 0x73, 0x65, 0x3F, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x59, 0x65, 0x73, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x64, 0x6F, 0x75, 0x62, 0x74, 0x66, 0x75, 0x6C, 0x6C, 0x79, + 0x3A, 0x20, 0x27, 0x69, 0x74, 0x20, 0x6D, 0x65, 0x61, 0x6E, + 0x73, 0x2D, 0x2D, 0x74, 0x6F, 0x2D, 0x2D, 0x6D, 0x61, 0x6B, + 0x65, 0x2D, 0x2D, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x2D, 0x2D, 0x70, 0x72, 0x65, 0x74, 0x74, 0x69, 0x65, + 0x72, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, + 0x6C, 0x6C, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x2C, 0x27, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, + 0x6F, 0x6E, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, + 0x2C, 0x20, 0x27, 0x69, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x75, + 0x67, 0x6C, 0x69, 0x66, 0x79, 0x20, 0x69, 0x73, 0x2C, 0x0D, + 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x41, 0x52, 0x45, 0x20, 0x61, + 0x20, 0x73, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x74, 0x6F, 0x6E, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x66, 0x65, 0x65, 0x6C, 0x20, 0x65, 0x6E, 0x63, 0x6F, 0x75, + 0x72, 0x61, 0x67, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x61, + 0x73, 0x6B, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6D, 0x6F, 0x72, + 0x65, 0x20, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6F, 0x6E, + 0x73, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, + 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x0D, 0x0A, + 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, + 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x27, 0x57, 0x68, 0x61, + 0x74, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x65, + 0x61, 0x72, 0x6E, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x4D, 0x79, 0x73, 0x74, + 0x65, 0x72, 0x79, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, + 0x65, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x2C, + 0x20, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x20, + 0x6F, 0x66, 0x66, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x73, 0x20, 0x6F, 0x6E, + 0x20, 0x68, 0x69, 0x73, 0x20, 0x66, 0x6C, 0x61, 0x70, 0x70, + 0x65, 0x72, 0x73, 0x2C, 0x20, 0x27, 0x2D, 0x2D, 0x4D, 0x79, + 0x73, 0x74, 0x65, 0x72, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x63, + 0x69, 0x65, 0x6E, 0x74, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, + 0x6F, 0x64, 0x65, 0x72, 0x6E, 0x2C, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x0D, 0x0A, 0x53, 0x65, 0x61, 0x6F, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x79, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, + 0x44, 0x72, 0x61, 0x77, 0x6C, 0x69, 0x6E, 0x67, 0x2D, 0x2D, + 0x74, 0x68, 0x65, 0x20, 0x44, 0x72, 0x61, 0x77, 0x6C, 0x69, + 0x6E, 0x67, 0x2D, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x61, 0x6E, 0x20, 0x6F, 0x6C, 0x64, + 0x20, 0x63, 0x6F, 0x6E, 0x67, 0x65, 0x72, 0x2D, 0x65, 0x65, + 0x6C, 0x2C, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x75, + 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6F, 0x6D, + 0x65, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x61, 0x20, 0x77, + 0x65, 0x65, 0x6B, 0x3A, 0x20, 0x48, 0x45, 0x20, 0x74, 0x61, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x75, 0x73, 0x20, 0x44, 0x72, + 0x61, 0x77, 0x6C, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x53, 0x74, + 0x72, 0x65, 0x74, 0x63, 0x68, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x46, 0x61, 0x69, 0x6E, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x43, 0x6F, 0x69, + 0x6C, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, + 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x54, 0x48, + 0x41, 0x54, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x3F, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x6C, 0x6C, + 0x2C, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, + 0x73, 0x68, 0x6F, 0x77, 0x20, 0x69, 0x74, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x6D, 0x79, 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x27, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, + 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x3A, 0x20, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x74, 0x6F, + 0x6F, 0x0D, 0x0A, 0x73, 0x74, 0x69, 0x66, 0x66, 0x2E, 0x20, + 0x41, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, + 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x6E, 0x65, 0x76, 0x65, + 0x72, 0x20, 0x6C, 0x65, 0x61, 0x72, 0x6E, 0x74, 0x20, 0x69, + 0x74, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x61, + 0x64, 0x6E, 0x27, 0x74, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x3A, 0x20, + 0x27, 0x49, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6C, 0x61, 0x73, 0x73, + 0x69, 0x63, 0x73, 0x20, 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, + 0x2C, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x2E, 0x0D, + 0x0A, 0x48, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x6E, + 0x20, 0x6F, 0x6C, 0x64, 0x20, 0x63, 0x72, 0x61, 0x62, 0x2C, + 0x20, 0x48, 0x45, 0x20, 0x77, 0x61, 0x73, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x6E, 0x65, 0x76, 0x65, + 0x72, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x69, 0x6D, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x68, 0x3A, 0x20, + 0x27, 0x68, 0x65, 0x20, 0x74, 0x61, 0x75, 0x67, 0x68, 0x74, + 0x0D, 0x0A, 0x4C, 0x61, 0x75, 0x67, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x47, 0x72, 0x69, 0x65, 0x66, + 0x2C, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x6F, 0x20, 0x68, 0x65, + 0x20, 0x64, 0x69, 0x64, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x68, + 0x65, 0x20, 0x64, 0x69, 0x64, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, + 0x70, 0x68, 0x6F, 0x6E, 0x2C, 0x20, 0x73, 0x69, 0x67, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x74, 0x75, 0x72, 0x6E, 0x3B, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x62, 0x6F, 0x74, 0x68, 0x0D, 0x0A, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x68, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x66, 0x61, 0x63, + 0x65, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, + 0x72, 0x20, 0x70, 0x61, 0x77, 0x73, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x41, 0x6E, 0x64, 0x20, 0x68, 0x6F, 0x77, 0x20, + 0x6D, 0x61, 0x6E, 0x79, 0x20, 0x68, 0x6F, 0x75, 0x72, 0x73, + 0x20, 0x61, 0x20, 0x64, 0x61, 0x79, 0x20, 0x64, 0x69, 0x64, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, 0x6F, 0x20, 0x6C, 0x65, + 0x73, 0x73, 0x6F, 0x6E, 0x73, 0x3F, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, + 0x69, 0x6E, 0x20, 0x61, 0x20, 0x68, 0x75, 0x72, 0x72, 0x79, + 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x63, 0x68, 0x61, 0x6E, 0x67, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x6A, + 0x65, 0x63, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, + 0x65, 0x6E, 0x20, 0x68, 0x6F, 0x75, 0x72, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x64, + 0x61, 0x79, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, + 0x75, 0x72, 0x74, 0x6C, 0x65, 0x3A, 0x20, 0x27, 0x6E, 0x69, + 0x6E, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, + 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x6F, 0x0D, + 0x0A, 0x6F, 0x6E, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x57, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x63, 0x75, 0x72, + 0x69, 0x6F, 0x75, 0x73, 0x20, 0x70, 0x6C, 0x61, 0x6E, 0x21, + 0x27, 0x20, 0x65, 0x78, 0x63, 0x6C, 0x61, 0x69, 0x6D, 0x65, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x27, 0x72, 0x65, 0x20, 0x63, + 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x6C, 0x65, 0x73, 0x73, + 0x6F, 0x6E, 0x73, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x72, 0x65, + 0x6D, 0x61, 0x72, 0x6B, 0x65, 0x64, 0x3A, 0x0D, 0x0A, 0x27, + 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x6C, 0x65, 0x73, 0x73, 0x65, 0x6E, 0x20, + 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x64, 0x61, 0x79, 0x20, 0x74, + 0x6F, 0x20, 0x64, 0x61, 0x79, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x61, 0x20, 0x6E, 0x65, + 0x77, 0x20, 0x69, 0x64, 0x65, 0x61, 0x20, 0x74, 0x6F, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6F, 0x76, 0x65, 0x72, + 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x0D, + 0x0A, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x72, 0x65, 0x6D, 0x61, + 0x72, 0x6B, 0x2E, 0x20, 0x27, 0x54, 0x68, 0x65, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x65, 0x6C, 0x65, 0x76, 0x65, 0x6E, + 0x74, 0x68, 0x20, 0x64, 0x61, 0x79, 0x20, 0x6D, 0x75, 0x73, + 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, + 0x6E, 0x20, 0x61, 0x0D, 0x0A, 0x68, 0x6F, 0x6C, 0x69, 0x64, + 0x61, 0x79, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, + 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x20, 0x69, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x6E, 0x64, 0x20, 0x68, 0x6F, + 0x77, 0x20, 0x64, 0x69, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6D, 0x61, 0x6E, 0x61, 0x67, 0x65, 0x20, 0x6F, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x77, 0x65, 0x6C, 0x66, 0x74, + 0x68, 0x3F, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x65, 0x61, + 0x67, 0x65, 0x72, 0x6C, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x54, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x65, 0x6E, + 0x6F, 0x75, 0x67, 0x68, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x20, 0x6C, 0x65, 0x73, 0x73, 0x6F, 0x6E, 0x73, 0x2C, 0x27, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, + 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, + 0x70, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x64, 0x65, 0x63, 0x69, 0x64, + 0x65, 0x64, 0x0D, 0x0A, 0x74, 0x6F, 0x6E, 0x65, 0x3A, 0x20, + 0x27, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x67, 0x61, 0x6D, 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x77, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x43, 0x48, 0x41, 0x50, 0x54, 0x45, 0x52, 0x20, 0x58, + 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x4C, 0x6F, 0x62, 0x73, + 0x74, 0x65, 0x72, 0x20, 0x51, 0x75, 0x61, 0x64, 0x72, 0x69, + 0x6C, 0x6C, 0x65, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, + 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, + 0x6C, 0x65, 0x20, 0x73, 0x69, 0x67, 0x68, 0x65, 0x64, 0x20, + 0x64, 0x65, 0x65, 0x70, 0x6C, 0x79, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x64, 0x72, 0x65, 0x77, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x66, 0x6C, 0x61, 0x70, 0x70, 0x65, 0x72, + 0x20, 0x61, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x0D, 0x0A, 0x68, + 0x69, 0x73, 0x20, 0x65, 0x79, 0x65, 0x73, 0x2E, 0x20, 0x48, + 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, + 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x73, 0x70, 0x65, 0x61, 0x6B, 0x2C, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x6D, + 0x69, 0x6E, 0x75, 0x74, 0x65, 0x20, 0x6F, 0x72, 0x0D, 0x0A, + 0x74, 0x77, 0x6F, 0x20, 0x73, 0x6F, 0x62, 0x73, 0x20, 0x63, + 0x68, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2E, 0x20, 0x27, 0x53, 0x61, + 0x6D, 0x65, 0x20, 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x61, 0x20, 0x62, 0x6F, + 0x6E, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x74, 0x68, 0x72, 0x6F, 0x61, 0x74, 0x2C, 0x27, 0x0D, 0x0A, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, + 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x3A, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x69, 0x74, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, + 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x73, 0x68, 0x61, + 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x69, 0x6D, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x70, 0x75, 0x6E, 0x63, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x68, 0x69, 0x6D, 0x20, 0x69, 0x6E, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x2E, 0x20, + 0x41, 0x74, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, + 0x74, 0x6C, 0x65, 0x20, 0x72, 0x65, 0x63, 0x6F, 0x76, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x68, 0x69, 0x73, 0x20, 0x76, 0x6F, + 0x69, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x2C, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x65, 0x61, 0x72, 0x73, + 0x0D, 0x0A, 0x72, 0x75, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x68, 0x69, 0x73, 0x20, 0x63, + 0x68, 0x65, 0x65, 0x6B, 0x73, 0x2C, 0x20, 0x68, 0x65, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x3A, 0x2D, 0x2D, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6C, 0x69, + 0x76, 0x65, 0x64, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x75, + 0x6E, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x61, 0x2D, 0x2D, 0x27, 0x20, 0x28, 0x27, 0x49, 0x20, + 0x68, 0x61, 0x76, 0x65, 0x6E, 0x27, 0x74, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x29, 0x2D, 0x2D, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x70, + 0x65, 0x72, 0x68, 0x61, 0x70, 0x73, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x6E, 0x65, 0x76, 0x65, + 0x72, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x69, 0x6E, 0x74, + 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x62, 0x73, 0x74, 0x65, 0x72, + 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x28, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x74, 0x6F, + 0x20, 0x73, 0x61, 0x79, 0x20, 0x27, 0x49, 0x20, 0x6F, 0x6E, + 0x63, 0x65, 0x20, 0x74, 0x61, 0x73, 0x74, 0x65, 0x64, 0x2D, + 0x2D, 0x27, 0x20, 0x62, 0x75, 0x74, 0x20, 0x63, 0x68, 0x65, + 0x63, 0x6B, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x20, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, 0x79, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x27, 0x4E, 0x6F, 0x2C, 0x20, 0x6E, 0x65, 0x76, + 0x65, 0x72, 0x27, 0x29, 0x20, 0x27, 0x2D, 0x2D, 0x73, 0x6F, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x6E, 0x6F, 0x20, 0x69, 0x64, 0x65, + 0x61, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x64, + 0x65, 0x6C, 0x69, 0x67, 0x68, 0x74, 0x66, 0x75, 0x6C, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x0D, 0x0A, 0x4C, + 0x6F, 0x62, 0x73, 0x74, 0x65, 0x72, 0x20, 0x51, 0x75, 0x61, + 0x64, 0x72, 0x69, 0x6C, 0x6C, 0x65, 0x20, 0x69, 0x73, 0x21, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x2C, 0x20, + 0x69, 0x6E, 0x64, 0x65, 0x65, 0x64, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, + 0x20, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, 0x73, 0x6F, 0x72, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x64, 0x61, 0x6E, + 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x69, 0x74, 0x3F, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x79, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2C, 0x20, 0x27, + 0x79, 0x6F, 0x75, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, + 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, + 0x61, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x61, 0x6C, 0x6F, + 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x73, 0x65, + 0x61, 0x2D, 0x73, 0x68, 0x6F, 0x72, 0x65, 0x2D, 0x2D, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x77, 0x6F, 0x20, 0x6C, + 0x69, 0x6E, 0x65, 0x73, 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, + 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2E, 0x20, + 0x27, 0x53, 0x65, 0x61, 0x6C, 0x73, 0x2C, 0x20, 0x74, 0x75, + 0x72, 0x74, 0x6C, 0x65, 0x73, 0x2C, 0x20, 0x73, 0x61, 0x6C, + 0x6D, 0x6F, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, + 0x6F, 0x20, 0x6F, 0x6E, 0x3B, 0x0D, 0x0A, 0x74, 0x68, 0x65, + 0x6E, 0x2C, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x79, 0x6F, + 0x75, 0x27, 0x76, 0x65, 0x20, 0x63, 0x6C, 0x65, 0x61, 0x72, + 0x65, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6A, 0x65, 0x6C, 0x6C, 0x79, 0x2D, 0x66, 0x69, 0x73, + 0x68, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x2D, 0x2D, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x48, 0x41, 0x54, 0x20, 0x67, + 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x74, + 0x61, 0x6B, 0x65, 0x73, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, + 0x74, 0x69, 0x6D, 0x65, 0x2C, 0x27, 0x20, 0x69, 0x6E, 0x74, + 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x65, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x2D, 0x2D, 0x79, 0x6F, + 0x75, 0x20, 0x61, 0x64, 0x76, 0x61, 0x6E, 0x63, 0x65, 0x20, + 0x74, 0x77, 0x69, 0x63, 0x65, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x45, 0x61, 0x63, 0x68, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x62, 0x73, 0x74, + 0x65, 0x72, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x70, 0x61, + 0x72, 0x74, 0x6E, 0x65, 0x72, 0x21, 0x27, 0x20, 0x63, 0x72, + 0x69, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, + 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x4F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x3A, 0x20, 0x27, 0x61, 0x64, 0x76, 0x61, + 0x6E, 0x63, 0x65, 0x20, 0x74, 0x77, 0x69, 0x63, 0x65, 0x2C, + 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x70, 0x61, + 0x72, 0x74, 0x6E, 0x65, 0x72, 0x73, 0x2D, 0x2D, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x2D, 0x2D, 0x63, 0x68, 0x61, 0x6E, + 0x67, 0x65, 0x20, 0x6C, 0x6F, 0x62, 0x73, 0x74, 0x65, 0x72, + 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x65, 0x74, + 0x69, 0x72, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x73, 0x61, 0x6D, + 0x65, 0x20, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2C, 0x27, 0x20, + 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, + 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, + 0x6E, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, + 0x77, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, + 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, + 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x27, + 0x79, 0x6F, 0x75, 0x20, 0x74, 0x68, 0x72, 0x6F, 0x77, 0x20, + 0x74, 0x68, 0x65, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x54, 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x62, 0x73, 0x74, + 0x65, 0x72, 0x73, 0x21, 0x27, 0x20, 0x73, 0x68, 0x6F, 0x75, + 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, + 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2C, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x61, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x20, + 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x69, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x2D, 0x2D, + 0x61, 0x73, 0x20, 0x66, 0x61, 0x72, 0x20, 0x6F, 0x75, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x61, 0x20, 0x61, 0x73, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, 0x2D, 0x2D, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x77, 0x69, 0x6D, + 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x6D, 0x21, 0x27, 0x20, 0x73, 0x63, 0x72, 0x65, 0x61, 0x6D, + 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, + 0x70, 0x68, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x54, 0x75, 0x72, 0x6E, 0x20, 0x61, 0x20, 0x73, 0x6F, 0x6D, + 0x65, 0x72, 0x73, 0x61, 0x75, 0x6C, 0x74, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x61, 0x21, 0x27, + 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, + 0x6C, 0x65, 0x2C, 0x20, 0x63, 0x61, 0x70, 0x65, 0x72, 0x69, + 0x6E, 0x67, 0x20, 0x77, 0x69, 0x6C, 0x64, 0x6C, 0x79, 0x0D, + 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x43, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x6C, + 0x6F, 0x62, 0x73, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x21, 0x27, 0x20, 0x79, 0x65, 0x6C, 0x6C, + 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, + 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x6F, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x69, + 0x74, 0x73, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x42, 0x61, 0x63, 0x6B, 0x20, 0x74, + 0x6F, 0x20, 0x6C, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x27, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x0D, 0x0A, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2C, + 0x20, 0x73, 0x75, 0x64, 0x64, 0x65, 0x6E, 0x6C, 0x79, 0x20, + 0x64, 0x72, 0x6F, 0x70, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x3B, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x77, + 0x6F, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x62, 0x65, 0x65, 0x6E, 0x0D, 0x0A, 0x6A, 0x75, 0x6D, + 0x70, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x6D, 0x61, 0x64, 0x20, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x69, 0x6D, 0x65, + 0x2C, 0x20, 0x73, 0x61, 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, + 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x73, 0x61, 0x64, 0x6C, 0x79, 0x0D, 0x0A, 0x61, + 0x6E, 0x64, 0x20, 0x71, 0x75, 0x69, 0x65, 0x74, 0x6C, 0x79, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, + 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x20, + 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x70, 0x72, 0x65, 0x74, 0x74, + 0x79, 0x20, 0x64, 0x61, 0x6E, 0x63, 0x65, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x74, 0x69, 0x6D, 0x69, 0x64, 0x6C, 0x79, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x73, 0x65, 0x65, 0x20, 0x61, 0x20, 0x6C, 0x69, + 0x74, 0x74, 0x6C, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, + 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, + 0x74, 0x6C, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x56, + 0x65, 0x72, 0x79, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x69, + 0x6E, 0x64, 0x65, 0x65, 0x64, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x43, 0x6F, 0x6D, 0x65, 0x2C, 0x20, + 0x6C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x74, 0x72, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x21, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, + 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, + 0x70, 0x68, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x27, 0x57, 0x65, + 0x20, 0x63, 0x61, 0x6E, 0x20, 0x64, 0x6F, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x6C, 0x6F, 0x62, 0x73, + 0x74, 0x65, 0x72, 0x73, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6B, 0x6E, 0x6F, 0x77, 0x2E, 0x20, 0x57, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x69, + 0x6E, 0x67, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, + 0x68, 0x2C, 0x20, 0x59, 0x4F, 0x55, 0x20, 0x73, 0x69, 0x6E, + 0x67, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, + 0x2E, 0x20, 0x27, 0x49, 0x27, 0x76, 0x65, 0x20, 0x66, 0x6F, + 0x72, 0x67, 0x6F, 0x74, 0x74, 0x65, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x53, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x73, 0x6F, 0x6C, + 0x65, 0x6D, 0x6E, 0x6C, 0x79, 0x20, 0x64, 0x61, 0x6E, 0x63, + 0x69, 0x6E, 0x67, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x65, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x61, 0x6E, 0x64, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x72, 0x65, + 0x61, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x65, 0x73, 0x20, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x70, 0x61, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x6F, 0x20, 0x63, + 0x6C, 0x6F, 0x73, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x77, 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x0D, 0x0A, 0x66, 0x6F, 0x72, 0x65, 0x70, 0x61, + 0x77, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x72, 0x6B, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x2C, + 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, + 0x6C, 0x65, 0x20, 0x73, 0x61, 0x6E, 0x67, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x2C, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, + 0x6C, 0x6F, 0x77, 0x6C, 0x79, 0x0D, 0x0A, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x61, 0x64, 0x6C, 0x79, 0x3A, 0x2D, 0x2D, 0x0D, + 0x0A, 0x0D, 0x0A, 0x20, 0x27, 0x22, 0x57, 0x69, 0x6C, 0x6C, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x77, 0x61, 0x6C, 0x6B, 0x20, + 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x66, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x3F, 0x22, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x61, 0x20, 0x77, 0x68, 0x69, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x20, 0x73, 0x6E, + 0x61, 0x69, 0x6C, 0x2E, 0x0D, 0x0A, 0x20, 0x22, 0x54, 0x68, + 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x61, 0x20, 0x70, 0x6F, + 0x72, 0x70, 0x6F, 0x69, 0x73, 0x65, 0x20, 0x63, 0x6C, 0x6F, + 0x73, 0x65, 0x20, 0x62, 0x65, 0x68, 0x69, 0x6E, 0x64, 0x20, + 0x75, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x65, + 0x27, 0x73, 0x20, 0x74, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6E, + 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x6D, 0x79, 0x20, 0x74, 0x61, + 0x69, 0x6C, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x53, 0x65, + 0x65, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x65, 0x61, 0x67, 0x65, + 0x72, 0x6C, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x6F, + 0x62, 0x73, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x75, 0x72, 0x74, 0x6C, + 0x65, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x64, 0x76, + 0x61, 0x6E, 0x63, 0x65, 0x21, 0x0D, 0x0A, 0x20, 0x54, 0x68, + 0x65, 0x79, 0x20, 0x61, 0x72, 0x65, 0x20, 0x77, 0x61, 0x69, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x2D, + 0x2D, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6A, + 0x6F, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, + 0x6E, 0x63, 0x65, 0x3F, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x57, + 0x69, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x77, + 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, + 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, + 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x2C, + 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6A, 0x6F, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, + 0x61, 0x6E, 0x63, 0x65, 0x3F, 0x0D, 0x0A, 0x20, 0x57, 0x69, + 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x77, 0x6F, + 0x6E, 0x27, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x77, + 0x69, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x77, + 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, + 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x6A, 0x6F, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, + 0x61, 0x6E, 0x63, 0x65, 0x3F, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, + 0x22, 0x59, 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x72, + 0x65, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x6E, 0x6F, 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x68, 0x6F, 0x77, 0x20, 0x64, 0x65, 0x6C, 0x69, 0x67, + 0x68, 0x74, 0x66, 0x75, 0x6C, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x69, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x0D, 0x0A, 0x20, 0x57, + 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x74, + 0x61, 0x6B, 0x65, 0x20, 0x75, 0x73, 0x20, 0x75, 0x70, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x72, 0x6F, 0x77, 0x20, + 0x75, 0x73, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x62, 0x73, 0x74, 0x65, 0x72, + 0x73, 0x2C, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x65, 0x61, 0x21, 0x22, 0x0D, 0x0A, 0x20, 0x42, 0x75, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6E, 0x61, 0x69, + 0x6C, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, + 0x22, 0x54, 0x6F, 0x6F, 0x20, 0x66, 0x61, 0x72, 0x2C, 0x20, + 0x74, 0x6F, 0x6F, 0x20, 0x66, 0x61, 0x72, 0x21, 0x22, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x67, 0x61, 0x76, 0x65, 0x20, 0x61, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x61, 0x73, 0x6B, 0x61, + 0x6E, 0x63, 0x65, 0x2D, 0x2D, 0x0D, 0x0A, 0x20, 0x53, 0x61, + 0x69, 0x64, 0x20, 0x68, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, + 0x6B, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, + 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6B, 0x69, 0x6E, 0x64, + 0x6C, 0x79, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x68, 0x65, + 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, 0x74, + 0x20, 0x6A, 0x6F, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x64, 0x61, 0x6E, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x20, 0x57, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, 0x74, + 0x2C, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x2C, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, + 0x6F, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x2C, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6A, 0x6F, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x6E, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x20, 0x57, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, + 0x6F, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x2C, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x6E, 0x6F, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6A, 0x6F, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x6E, 0x63, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x27, 0x22, 0x57, + 0x68, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x73, 0x20, 0x69, 0x74, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x66, + 0x61, 0x72, 0x20, 0x77, 0x65, 0x20, 0x67, 0x6F, 0x3F, 0x22, + 0x20, 0x68, 0x69, 0x73, 0x20, 0x73, 0x63, 0x61, 0x6C, 0x79, + 0x20, 0x66, 0x72, 0x69, 0x65, 0x6E, 0x64, 0x20, 0x72, 0x65, + 0x70, 0x6C, 0x69, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x20, 0x22, + 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x61, + 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x68, 0x6F, + 0x72, 0x65, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, + 0x6F, 0x77, 0x2C, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, + 0x69, 0x64, 0x65, 0x2E, 0x0D, 0x0A, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6F, + 0x66, 0x66, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x45, 0x6E, + 0x67, 0x6C, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6E, 0x65, 0x61, 0x72, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, + 0x74, 0x6F, 0x20, 0x46, 0x72, 0x61, 0x6E, 0x63, 0x65, 0x2D, + 0x2D, 0x0D, 0x0A, 0x20, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x74, + 0x75, 0x72, 0x6E, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x70, 0x61, + 0x6C, 0x65, 0x2C, 0x20, 0x62, 0x65, 0x6C, 0x6F, 0x76, 0x65, + 0x64, 0x20, 0x73, 0x6E, 0x61, 0x69, 0x6C, 0x2C, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x6A, 0x6F, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x64, 0x61, 0x6E, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x20, 0x57, 0x69, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, + 0x2C, 0x20, 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x79, 0x6F, + 0x75, 0x2C, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x79, 0x6F, + 0x75, 0x2C, 0x20, 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x79, + 0x6F, 0x75, 0x2C, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x6A, 0x6F, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x64, 0x61, 0x6E, 0x63, 0x65, 0x3F, 0x0D, 0x0A, + 0x20, 0x57, 0x69, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, 0x2C, + 0x20, 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x79, 0x6F, 0x75, + 0x2C, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x79, 0x6F, 0x75, + 0x2C, 0x20, 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x79, 0x6F, + 0x75, 0x2C, 0x20, 0x77, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x6A, 0x6F, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x64, 0x61, 0x6E, 0x63, 0x65, 0x3F, 0x22, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, 0x6E, 0x6B, + 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x69, 0x74, 0x27, 0x73, + 0x20, 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x69, 0x6E, + 0x74, 0x65, 0x72, 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x20, + 0x64, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x77, + 0x61, 0x74, 0x63, 0x68, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x66, + 0x65, 0x65, 0x6C, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x67, 0x6C, 0x61, 0x64, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x6F, 0x76, 0x65, 0x72, 0x20, 0x61, 0x74, 0x20, 0x6C, 0x61, + 0x73, 0x74, 0x3A, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x49, + 0x20, 0x64, 0x6F, 0x20, 0x73, 0x6F, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x75, 0x72, + 0x69, 0x6F, 0x75, 0x73, 0x20, 0x73, 0x6F, 0x6E, 0x67, 0x0D, + 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x68, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x61, + 0x73, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x68, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, + 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2C, + 0x20, 0x27, 0x74, 0x68, 0x65, 0x79, 0x2D, 0x2D, 0x79, 0x6F, + 0x75, 0x27, 0x76, 0x65, 0x20, 0x73, 0x65, 0x65, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x0D, 0x0A, 0x6F, 0x66, 0x20, + 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x3F, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x59, 0x65, 0x73, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, + 0x20, 0x27, 0x49, 0x27, 0x76, 0x65, 0x20, 0x6F, 0x66, 0x74, + 0x65, 0x6E, 0x20, 0x73, 0x65, 0x65, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x20, 0x61, 0x74, 0x20, 0x64, 0x69, 0x6E, 0x6E, + 0x2D, 0x2D, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x68, + 0x65, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x0D, 0x0A, 0x68, 0x61, 0x73, 0x74, 0x69, + 0x6C, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, + 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x44, 0x69, 0x6E, + 0x6E, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x62, 0x65, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, + 0x65, 0x2C, 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, 0x69, 0x66, + 0x20, 0x79, 0x6F, 0x75, 0x27, 0x76, 0x65, 0x0D, 0x0A, 0x73, + 0x65, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x73, + 0x6F, 0x20, 0x6F, 0x66, 0x74, 0x65, 0x6E, 0x2C, 0x20, 0x6F, + 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, 0x27, 0x72, 0x65, + 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x20, 0x62, 0x65, 0x6C, 0x69, 0x65, 0x76, + 0x65, 0x20, 0x73, 0x6F, 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x66, 0x75, + 0x6C, 0x6C, 0x79, 0x2E, 0x20, 0x27, 0x54, 0x68, 0x65, 0x79, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x69, + 0x72, 0x20, 0x74, 0x61, 0x69, 0x6C, 0x73, 0x20, 0x69, 0x6E, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x6D, 0x6F, + 0x75, 0x74, 0x68, 0x73, 0x2D, 0x2D, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x27, 0x72, 0x65, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x63, 0x72, 0x75, + 0x6D, 0x62, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x59, 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x77, 0x72, 0x6F, + 0x6E, 0x67, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x72, 0x75, 0x6D, 0x62, 0x73, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, + 0x6C, 0x65, 0x3A, 0x20, 0x27, 0x63, 0x72, 0x75, 0x6D, 0x62, + 0x73, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x61, 0x6C, + 0x6C, 0x0D, 0x0A, 0x77, 0x61, 0x73, 0x68, 0x20, 0x6F, 0x66, + 0x66, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x61, 0x2E, 0x20, 0x42, 0x75, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x48, 0x41, 0x56, 0x45, 0x20, 0x74, 0x68, + 0x65, 0x69, 0x72, 0x20, 0x74, 0x61, 0x69, 0x6C, 0x73, 0x20, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x6D, + 0x6F, 0x75, 0x74, 0x68, 0x73, 0x3B, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x72, 0x65, 0x61, 0x73, + 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x2D, 0x2D, 0x27, 0x20, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, + 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, + 0x79, 0x61, 0x77, 0x6E, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x75, 0x74, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x65, 0x79, 0x65, 0x73, 0x2E, 0x2D, 0x2D, 0x27, 0x54, 0x65, + 0x6C, 0x6C, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x61, 0x62, + 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, + 0x61, 0x73, 0x6F, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2C, 0x27, 0x20, + 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, + 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x20, 0x69, + 0x73, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, + 0x2C, 0x20, 0x27, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x57, 0x4F, 0x55, 0x4C, 0x44, 0x20, 0x67, + 0x6F, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6C, 0x6F, 0x62, 0x73, 0x74, 0x65, 0x72, 0x73, 0x0D, + 0x0A, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, + 0x6E, 0x63, 0x65, 0x2E, 0x20, 0x53, 0x6F, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x74, 0x68, 0x72, + 0x6F, 0x77, 0x6E, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x6F, + 0x20, 0x73, 0x65, 0x61, 0x2E, 0x20, 0x53, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x68, 0x61, 0x64, 0x20, 0x74, 0x6F, + 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x20, 0x6C, 0x6F, + 0x6E, 0x67, 0x0D, 0x0A, 0x77, 0x61, 0x79, 0x2E, 0x20, 0x53, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x67, 0x6F, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x74, 0x61, 0x69, + 0x6C, 0x73, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x6D, 0x6F, 0x75, + 0x74, 0x68, 0x73, 0x2E, 0x20, 0x53, 0x6F, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x6E, 0x27, + 0x74, 0x20, 0x67, 0x65, 0x74, 0x0D, 0x0A, 0x74, 0x68, 0x65, + 0x6D, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6E, 0x2E, 0x20, 0x54, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, + 0x61, 0x6C, 0x6C, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x54, 0x68, 0x61, 0x6E, 0x6B, 0x20, 0x79, 0x6F, 0x75, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2C, 0x20, 0x27, 0x69, 0x74, 0x27, 0x73, 0x20, + 0x76, 0x65, 0x72, 0x79, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x72, + 0x65, 0x73, 0x74, 0x69, 0x6E, 0x67, 0x2E, 0x20, 0x49, 0x20, + 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x6B, 0x6E, 0x65, 0x77, + 0x20, 0x73, 0x6F, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x0D, 0x0A, + 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x20, 0x77, 0x68, + 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x65, 0x66, 0x6F, + 0x72, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, + 0x20, 0x63, 0x61, 0x6E, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, + 0x68, 0x61, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2C, 0x20, + 0x69, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6C, 0x69, 0x6B, + 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, + 0x2E, 0x20, 0x27, 0x44, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x0D, + 0x0A, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x77, 0x68, 0x79, 0x20, + 0x69, 0x74, 0x27, 0x73, 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x65, + 0x64, 0x20, 0x61, 0x20, 0x77, 0x68, 0x69, 0x74, 0x69, 0x6E, + 0x67, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, + 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x6F, 0x75, + 0x67, 0x68, 0x74, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, + 0x69, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x20, 0x27, 0x57, 0x68, + 0x79, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x54, + 0x20, 0x44, 0x4F, 0x45, 0x53, 0x20, 0x54, 0x48, 0x45, 0x20, + 0x42, 0x4F, 0x4F, 0x54, 0x53, 0x20, 0x41, 0x4E, 0x44, 0x20, + 0x53, 0x48, 0x4F, 0x45, 0x53, 0x2E, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, + 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x73, 0x6F, 0x6C, 0x65, 0x6D, 0x6E, 0x6C, + 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x6F, 0x72, + 0x6F, 0x75, 0x67, 0x68, 0x6C, 0x79, 0x20, 0x70, 0x75, 0x7A, + 0x7A, 0x6C, 0x65, 0x64, 0x2E, 0x20, 0x27, 0x44, 0x6F, 0x65, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6F, 0x6F, 0x74, + 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x6F, 0x65, + 0x73, 0x21, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x72, 0x65, + 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x0D, 0x0A, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x79, 0x2C, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x59, 0x4F, 0x55, + 0x52, 0x20, 0x73, 0x68, 0x6F, 0x65, 0x73, 0x20, 0x64, 0x6F, + 0x6E, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x3F, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, + 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2E, 0x20, 0x27, 0x49, + 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x2C, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x0D, 0x0A, 0x6D, 0x61, 0x6B, 0x65, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x6D, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, 0x69, + 0x6E, 0x79, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, + 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x6D, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, + 0x6F, 0x6E, 0x73, 0x69, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, + 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x62, + 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x67, 0x61, 0x76, 0x65, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, + 0x61, 0x6E, 0x73, 0x77, 0x65, 0x72, 0x2E, 0x20, 0x27, 0x54, + 0x68, 0x65, 0x79, 0x27, 0x72, 0x65, 0x20, 0x64, 0x6F, 0x6E, + 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x62, 0x6C, 0x61, + 0x63, 0x6B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x49, 0x20, 0x62, + 0x65, 0x6C, 0x69, 0x65, 0x76, 0x65, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x42, 0x6F, 0x6F, 0x74, 0x73, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x68, 0x6F, 0x65, 0x73, 0x20, 0x75, + 0x6E, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x61, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, + 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, + 0x64, 0x65, 0x65, 0x70, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, + 0x2C, 0x0D, 0x0A, 0x27, 0x61, 0x72, 0x65, 0x20, 0x64, 0x6F, + 0x6E, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x77, 0x68, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x2E, 0x20, 0x4E, + 0x6F, 0x77, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, + 0x77, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x6E, + 0x64, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x6D, 0x61, 0x64, 0x65, + 0x20, 0x6F, 0x66, 0x3F, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x61, 0x73, 0x6B, 0x65, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, + 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x63, 0x75, 0x72, + 0x69, 0x6F, 0x73, 0x69, 0x74, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x53, 0x6F, 0x6C, 0x65, 0x73, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x65, 0x65, 0x6C, 0x73, 0x2C, 0x20, 0x6F, 0x66, + 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, + 0x6E, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, + 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6D, 0x70, + 0x61, 0x74, 0x69, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x3A, 0x0D, + 0x0A, 0x27, 0x61, 0x6E, 0x79, 0x20, 0x73, 0x68, 0x72, 0x69, + 0x6D, 0x70, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x74, 0x6F, 0x6C, 0x64, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x66, 0x20, 0x49, 0x27, 0x64, + 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x68, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x73, 0x65, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x73, 0x20, 0x77, 0x65, 0x72, + 0x65, 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x72, 0x75, + 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x6F, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x6F, 0x6E, 0x67, 0x2C, 0x20, + 0x27, 0x49, 0x27, 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x6F, 0x72, 0x70, 0x6F, 0x69, 0x73, 0x65, + 0x2C, 0x20, 0x22, 0x4B, 0x65, 0x65, 0x70, 0x20, 0x62, 0x61, + 0x63, 0x6B, 0x2C, 0x20, 0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, + 0x3A, 0x20, 0x77, 0x65, 0x0D, 0x0A, 0x64, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 0x59, 0x4F, 0x55, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x75, 0x73, 0x21, 0x22, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x79, + 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x6F, 0x62, 0x6C, 0x69, + 0x67, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x68, 0x69, 0x6D, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, + 0x74, 0x6C, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x3A, 0x20, + 0x27, 0x6E, 0x6F, 0x0D, 0x0A, 0x77, 0x69, 0x73, 0x65, 0x20, + 0x66, 0x69, 0x73, 0x68, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x67, 0x6F, 0x20, 0x61, 0x6E, 0x79, 0x77, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, + 0x20, 0x61, 0x20, 0x70, 0x6F, 0x72, 0x70, 0x6F, 0x69, 0x73, + 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x6F, + 0x75, 0x6C, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x69, 0x74, 0x20, + 0x72, 0x65, 0x61, 0x6C, 0x6C, 0x79, 0x3F, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x69, 0x6E, 0x20, 0x61, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x73, + 0x75, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x4F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, + 0x73, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, + 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x3A, + 0x20, 0x27, 0x77, 0x68, 0x79, 0x2C, 0x20, 0x69, 0x66, 0x20, + 0x61, 0x20, 0x66, 0x69, 0x73, 0x68, 0x20, 0x63, 0x61, 0x6D, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x4D, 0x45, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x0D, 0x0A, 0x74, 0x6F, 0x6C, 0x64, 0x20, 0x6D, + 0x65, 0x20, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, + 0x6F, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x20, 0x6A, 0x6F, 0x75, + 0x72, 0x6E, 0x65, 0x79, 0x2C, 0x20, 0x49, 0x20, 0x73, 0x68, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x73, 0x61, 0x79, 0x20, 0x22, + 0x57, 0x69, 0x74, 0x68, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, + 0x70, 0x6F, 0x72, 0x70, 0x6F, 0x69, 0x73, 0x65, 0x3F, 0x22, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x44, 0x6F, 0x6E, 0x27, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x65, 0x61, 0x6E, + 0x20, 0x22, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x22, + 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, + 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x20, 0x77, 0x68, 0x61, 0x74, + 0x20, 0x49, 0x20, 0x73, 0x61, 0x79, 0x2C, 0x27, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, + 0x72, 0x74, 0x6C, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, + 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x20, 0x6F, + 0x66, 0x66, 0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x74, 0x6F, + 0x6E, 0x65, 0x2E, 0x20, 0x41, 0x6E, 0x64, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, + 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x27, 0x43, 0x6F, + 0x6D, 0x65, 0x2C, 0x20, 0x6C, 0x65, 0x74, 0x27, 0x73, 0x20, + 0x68, 0x65, 0x61, 0x72, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x59, 0x4F, 0x55, 0x52, 0x20, 0x61, 0x64, + 0x76, 0x65, 0x6E, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x63, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x6D, 0x79, 0x20, 0x61, 0x64, 0x76, 0x65, 0x6E, + 0x74, 0x75, 0x72, 0x65, 0x73, 0x2D, 0x2D, 0x62, 0x65, 0x67, + 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x72, 0x6F, + 0x6D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6D, 0x6F, 0x72, + 0x6E, 0x69, 0x6E, 0x67, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, + 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x74, 0x69, + 0x6D, 0x69, 0x64, 0x6C, 0x79, 0x3A, 0x20, 0x27, 0x62, 0x75, + 0x74, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, + 0x75, 0x73, 0x65, 0x20, 0x67, 0x6F, 0x69, 0x6E, 0x67, 0x20, + 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, 0x6F, 0x20, 0x79, 0x65, + 0x73, 0x74, 0x65, 0x72, 0x64, 0x61, 0x79, 0x2C, 0x0D, 0x0A, + 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x49, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, 0x64, 0x69, 0x66, 0x66, + 0x65, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x70, 0x65, 0x72, 0x73, + 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x45, 0x78, 0x70, 0x6C, 0x61, 0x69, + 0x6E, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, + 0x74, 0x6C, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, + 0x6F, 0x2C, 0x20, 0x6E, 0x6F, 0x21, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x61, 0x64, 0x76, 0x65, 0x6E, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, + 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x6E, 0x20, 0x69, 0x6D, 0x70, 0x61, 0x74, 0x69, 0x65, + 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x3A, 0x0D, 0x0A, + 0x27, 0x65, 0x78, 0x70, 0x6C, 0x61, 0x6E, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x20, 0x74, 0x61, 0x6B, 0x65, 0x20, 0x73, + 0x75, 0x63, 0x68, 0x20, 0x61, 0x20, 0x64, 0x72, 0x65, 0x61, + 0x64, 0x66, 0x75, 0x6C, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x6F, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, + 0x74, 0x65, 0x6C, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x20, 0x68, 0x65, 0x72, 0x20, 0x61, 0x64, 0x76, + 0x65, 0x6E, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x66, 0x72, + 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, + 0x65, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x0D, 0x0A, 0x73, 0x61, + 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, 0x69, 0x74, + 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x2E, 0x20, + 0x53, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x6E, 0x65, 0x72, + 0x76, 0x6F, 0x75, 0x73, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x20, 0x69, 0x74, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x61, + 0x74, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2C, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x77, 0x6F, 0x20, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x67, 0x6F, + 0x74, 0x20, 0x73, 0x6F, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x2C, 0x20, 0x6F, + 0x6E, 0x65, 0x20, 0x6F, 0x6E, 0x20, 0x65, 0x61, 0x63, 0x68, + 0x20, 0x73, 0x69, 0x64, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x65, 0x64, 0x0D, 0x0A, 0x74, + 0x68, 0x65, 0x69, 0x72, 0x20, 0x65, 0x79, 0x65, 0x73, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x6F, 0x75, 0x74, 0x68, 0x73, + 0x20, 0x73, 0x6F, 0x20, 0x56, 0x45, 0x52, 0x59, 0x20, 0x77, + 0x69, 0x64, 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x67, 0x61, 0x69, 0x6E, 0x65, 0x64, 0x20, + 0x63, 0x6F, 0x75, 0x72, 0x61, 0x67, 0x65, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x0D, + 0x0A, 0x6F, 0x6E, 0x2E, 0x20, 0x48, 0x65, 0x72, 0x20, 0x6C, + 0x69, 0x73, 0x74, 0x65, 0x6E, 0x65, 0x72, 0x73, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x70, 0x65, 0x72, 0x66, 0x65, 0x63, + 0x74, 0x6C, 0x79, 0x20, 0x71, 0x75, 0x69, 0x65, 0x74, 0x20, + 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x67, + 0x6F, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x70, 0x61, 0x72, 0x74, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x0D, 0x0A, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x70, 0x65, + 0x61, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x27, 0x59, 0x4F, 0x55, + 0x20, 0x41, 0x52, 0x45, 0x20, 0x4F, 0x4C, 0x44, 0x2C, 0x20, + 0x46, 0x41, 0x54, 0x48, 0x45, 0x52, 0x20, 0x57, 0x49, 0x4C, + 0x4C, 0x49, 0x41, 0x4D, 0x2C, 0x27, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x72, 0x70, + 0x69, 0x6C, 0x6C, 0x61, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x77, 0x6F, 0x72, 0x64, + 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x6F, 0x6D, 0x69, + 0x6E, 0x67, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x64, + 0x72, 0x65, 0x77, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x6E, 0x67, + 0x20, 0x62, 0x72, 0x65, 0x61, 0x74, 0x68, 0x2C, 0x0D, 0x0A, + 0x61, 0x6E, 0x64, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x27, + 0x54, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x27, 0x73, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x20, 0x61, 0x73, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, + 0x73, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, 0x63, 0x61, + 0x6E, 0x20, 0x62, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, + 0x68, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, + 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x61, 0x6D, 0x65, + 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x74, + 0x21, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x72, + 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x66, 0x75, 0x6C, 0x6C, 0x79, + 0x2E, 0x20, 0x27, 0x49, 0x0D, 0x0A, 0x73, 0x68, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x68, 0x65, 0x61, 0x72, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x74, 0x72, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x65, + 0x70, 0x65, 0x61, 0x74, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6E, 0x6F, 0x77, 0x2E, 0x20, + 0x54, 0x65, 0x6C, 0x6C, 0x20, 0x68, 0x65, 0x72, 0x20, 0x74, + 0x6F, 0x0D, 0x0A, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x2E, 0x27, + 0x20, 0x48, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, + 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x61, 0x73, 0x20, 0x69, + 0x66, 0x20, 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x6B, 0x69, 0x6E, 0x64, 0x20, + 0x6F, 0x66, 0x0D, 0x0A, 0x61, 0x75, 0x74, 0x68, 0x6F, 0x72, + 0x69, 0x74, 0x79, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x53, 0x74, 0x61, 0x6E, 0x64, 0x20, 0x75, 0x70, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x20, + 0x22, 0x27, 0x54, 0x49, 0x53, 0x20, 0x54, 0x48, 0x45, 0x20, + 0x56, 0x4F, 0x49, 0x43, 0x45, 0x20, 0x4F, 0x46, 0x20, 0x54, + 0x48, 0x45, 0x20, 0x53, 0x4C, 0x55, 0x47, 0x47, 0x41, 0x52, + 0x44, 0x2C, 0x22, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x47, 0x72, 0x79, 0x70, 0x68, + 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x6F, + 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x6F, 0x72, 0x64, 0x65, + 0x72, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x61, 0x62, 0x6F, 0x75, + 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x72, 0x65, 0x70, 0x65, + 0x61, 0x74, 0x20, 0x6C, 0x65, 0x73, 0x73, 0x6F, 0x6E, 0x73, + 0x21, 0x27, 0x0D, 0x0A, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x3B, 0x20, 0x27, + 0x49, 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x20, 0x61, 0x73, + 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x20, 0x61, + 0x74, 0x20, 0x73, 0x63, 0x68, 0x6F, 0x6F, 0x6C, 0x20, 0x61, + 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x2E, 0x27, 0x20, 0x48, + 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, 0x20, 0x73, 0x68, + 0x65, 0x0D, 0x0A, 0x67, 0x6F, 0x74, 0x20, 0x75, 0x70, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, + 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, + 0x20, 0x69, 0x74, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x73, 0x6F, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4C, 0x6F, 0x62, + 0x73, 0x74, 0x65, 0x72, 0x0D, 0x0A, 0x51, 0x75, 0x61, 0x64, + 0x72, 0x69, 0x6C, 0x6C, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x72, 0x64, + 0x6C, 0x79, 0x20, 0x6B, 0x6E, 0x65, 0x77, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x73, 0x61, 0x79, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x64, 0x73, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x0D, 0x0A, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x71, 0x75, 0x65, 0x65, 0x72, 0x20, + 0x69, 0x6E, 0x64, 0x65, 0x65, 0x64, 0x3A, 0x2D, 0x2D, 0x0D, + 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x27, 0x27, 0x54, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4C, 0x6F, + 0x62, 0x73, 0x74, 0x65, 0x72, 0x3B, 0x20, 0x49, 0x20, 0x68, + 0x65, 0x61, 0x72, 0x64, 0x20, 0x68, 0x69, 0x6D, 0x20, 0x64, + 0x65, 0x63, 0x6C, 0x61, 0x72, 0x65, 0x2C, 0x0D, 0x0A, 0x20, + 0x20, 0x22, 0x59, 0x6F, 0x75, 0x20, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x62, 0x61, 0x6B, 0x65, 0x64, 0x20, 0x6D, 0x65, 0x20, + 0x74, 0x6F, 0x6F, 0x20, 0x62, 0x72, 0x6F, 0x77, 0x6E, 0x2C, + 0x20, 0x49, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x73, 0x75, + 0x67, 0x61, 0x72, 0x20, 0x6D, 0x79, 0x20, 0x68, 0x61, 0x69, + 0x72, 0x2E, 0x22, 0x0D, 0x0A, 0x20, 0x20, 0x41, 0x73, 0x20, + 0x61, 0x20, 0x64, 0x75, 0x63, 0x6B, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, 0x65, 0x79, 0x65, 0x6C, + 0x69, 0x64, 0x73, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x68, 0x65, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x6E, 0x6F, 0x73, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x54, 0x72, + 0x69, 0x6D, 0x73, 0x20, 0x68, 0x69, 0x73, 0x20, 0x62, 0x65, + 0x6C, 0x74, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x62, 0x75, 0x74, 0x74, 0x6F, 0x6E, 0x73, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x73, 0x20, + 0x6F, 0x75, 0x74, 0x20, 0x68, 0x69, 0x73, 0x20, 0x74, 0x6F, + 0x65, 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x5B, 0x6C, 0x61, 0x74, 0x65, + 0x72, 0x20, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, + 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x64, + 0x20, 0x61, 0x73, 0x20, 0x66, 0x6F, 0x6C, 0x6C, 0x6F, 0x77, + 0x73, 0x0D, 0x0A, 0x20, 0x20, 0x57, 0x68, 0x65, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6E, 0x64, 0x73, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x64, 0x72, + 0x79, 0x2C, 0x20, 0x68, 0x65, 0x20, 0x69, 0x73, 0x20, 0x67, + 0x61, 0x79, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x61, + 0x72, 0x6B, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x41, 0x6E, 0x64, + 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x74, 0x61, 0x6C, 0x6B, + 0x20, 0x69, 0x6E, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6D, + 0x70, 0x74, 0x75, 0x6F, 0x75, 0x73, 0x20, 0x74, 0x6F, 0x6E, + 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x53, 0x68, 0x61, 0x72, 0x6B, 0x2C, 0x0D, 0x0A, 0x20, 0x20, + 0x42, 0x75, 0x74, 0x2C, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x64, 0x65, 0x20, 0x72, + 0x69, 0x73, 0x65, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, + 0x68, 0x61, 0x72, 0x6B, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, + 0x61, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x2C, 0x0D, 0x0A, 0x20, + 0x20, 0x48, 0x69, 0x73, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x20, 0x61, 0x20, 0x74, 0x69, 0x6D, + 0x69, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x72, 0x65, + 0x6D, 0x75, 0x6C, 0x6F, 0x75, 0x73, 0x20, 0x73, 0x6F, 0x75, + 0x6E, 0x64, 0x2E, 0x5D, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, + 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x64, 0x69, 0x66, 0x66, + 0x65, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x72, 0x6F, 0x6D, + 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x49, 0x20, 0x75, 0x73, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x20, 0x49, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x61, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x6C, 0x6C, 0x2C, 0x20, + 0x49, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, 0x65, + 0x61, 0x72, 0x64, 0x20, 0x69, 0x74, 0x20, 0x62, 0x65, 0x66, + 0x6F, 0x72, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, + 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x3B, 0x20, 0x27, 0x62, + 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, 0x73, 0x6F, 0x75, 0x6E, + 0x64, 0x73, 0x0D, 0x0A, 0x75, 0x6E, 0x63, 0x6F, 0x6D, 0x6D, + 0x6F, 0x6E, 0x20, 0x6E, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, + 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x3B, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x73, 0x61, 0x74, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x66, 0x61, 0x63, 0x65, 0x20, 0x69, 0x6E, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x73, + 0x2C, 0x0D, 0x0A, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, 0x69, + 0x6E, 0x67, 0x20, 0x69, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x74, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x45, 0x56, 0x45, 0x52, 0x20, 0x68, 0x61, 0x70, 0x70, + 0x65, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6E, 0x61, + 0x74, 0x75, 0x72, 0x61, 0x6C, 0x20, 0x77, 0x61, 0x79, 0x20, + 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x49, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x6C, 0x69, 0x6B, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x20, 0x69, 0x74, 0x20, 0x65, 0x78, 0x70, 0x6C, + 0x61, 0x69, 0x6E, 0x65, 0x64, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x68, 0x65, 0x20, 0x63, 0x61, + 0x6E, 0x27, 0x74, 0x20, 0x65, 0x78, 0x70, 0x6C, 0x61, 0x69, + 0x6E, 0x20, 0x69, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, + 0x68, 0x6F, 0x6E, 0x20, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, + 0x79, 0x2E, 0x20, 0x27, 0x47, 0x6F, 0x20, 0x6F, 0x6E, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, + 0x65, 0x78, 0x74, 0x0D, 0x0A, 0x76, 0x65, 0x72, 0x73, 0x65, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x42, 0x75, 0x74, + 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x74, 0x6F, 0x65, 0x73, 0x3F, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, + 0x74, 0x6C, 0x65, 0x20, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, + 0x74, 0x65, 0x64, 0x2E, 0x20, 0x27, 0x48, 0x6F, 0x77, 0x20, + 0x43, 0x4F, 0x55, 0x4C, 0x44, 0x20, 0x68, 0x65, 0x20, 0x74, + 0x75, 0x72, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x0D, 0x0A, + 0x6F, 0x75, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x73, 0x65, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x3F, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x27, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x70, + 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, + 0x20, 0x64, 0x61, 0x6E, 0x63, 0x69, 0x6E, 0x67, 0x2E, 0x27, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x64, 0x72, 0x65, 0x61, 0x64, 0x66, 0x75, 0x6C, 0x6C, + 0x79, 0x0D, 0x0A, 0x70, 0x75, 0x7A, 0x7A, 0x6C, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, + 0x6F, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x67, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x62, 0x6A, + 0x65, 0x63, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x47, + 0x6F, 0x20, 0x6F, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x76, + 0x65, 0x72, 0x73, 0x65, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x72, + 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6D, + 0x70, 0x61, 0x74, 0x69, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x3A, + 0x20, 0x27, 0x69, 0x74, 0x0D, 0x0A, 0x62, 0x65, 0x67, 0x69, + 0x6E, 0x73, 0x20, 0x22, 0x49, 0x20, 0x70, 0x61, 0x73, 0x73, + 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x68, 0x69, 0x73, 0x20, + 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x2E, 0x22, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x64, + 0x69, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x64, 0x61, 0x72, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x69, 0x73, 0x6F, 0x62, + 0x65, 0x79, 0x2C, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x66, 0x65, 0x6C, 0x74, 0x20, + 0x73, 0x75, 0x72, 0x65, 0x20, 0x69, 0x74, 0x20, 0x77, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x6F, + 0x6D, 0x65, 0x0D, 0x0A, 0x77, 0x72, 0x6F, 0x6E, 0x67, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x20, 0x74, 0x72, 0x65, 0x6D, 0x62, 0x6C, 0x69, 0x6E, + 0x67, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x3A, 0x2D, 0x2D, + 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x27, 0x49, 0x20, 0x70, + 0x61, 0x73, 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x67, 0x61, 0x72, 0x64, 0x65, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x72, 0x6B, 0x65, + 0x64, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x65, 0x79, 0x65, 0x2C, 0x0D, 0x0A, 0x20, 0x20, + 0x48, 0x6F, 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4F, 0x77, + 0x6C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x50, 0x61, 0x6E, 0x74, 0x68, 0x65, 0x72, 0x20, 0x77, 0x65, + 0x72, 0x65, 0x20, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x20, 0x70, 0x69, 0x65, 0x2D, 0x2D, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x5B, 0x6C, 0x61, + 0x74, 0x65, 0x72, 0x20, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6F, + 0x6E, 0x73, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, + 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x66, 0x6F, 0x6C, 0x6C, + 0x6F, 0x77, 0x73, 0x0D, 0x0A, 0x20, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x50, 0x61, 0x6E, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, + 0x6F, 0x6F, 0x6B, 0x20, 0x70, 0x69, 0x65, 0x2D, 0x63, 0x72, + 0x75, 0x73, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x67, + 0x72, 0x61, 0x76, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x6D, 0x65, 0x61, 0x74, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x57, + 0x68, 0x69, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4F, + 0x77, 0x6C, 0x20, 0x68, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x64, 0x69, 0x73, 0x68, 0x20, 0x61, 0x73, 0x20, 0x69, + 0x74, 0x73, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x65, 0x61, + 0x74, 0x2E, 0x0D, 0x0A, 0x20, 0x20, 0x57, 0x68, 0x65, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x69, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x66, 0x69, 0x6E, + 0x69, 0x73, 0x68, 0x65, 0x64, 0x2C, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4F, 0x77, 0x6C, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x61, + 0x20, 0x62, 0x6F, 0x6F, 0x6E, 0x2C, 0x0D, 0x0A, 0x20, 0x20, + 0x57, 0x61, 0x73, 0x20, 0x6B, 0x69, 0x6E, 0x64, 0x6C, 0x79, + 0x20, 0x70, 0x65, 0x72, 0x6D, 0x69, 0x74, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x70, 0x6F, 0x63, 0x6B, 0x65, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6F, 0x6E, + 0x3A, 0x0D, 0x0A, 0x20, 0x20, 0x57, 0x68, 0x69, 0x6C, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x61, 0x6E, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0x20, 0x6B, 0x6E, 0x69, 0x66, 0x65, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x66, 0x6F, 0x72, 0x6B, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x61, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x6C, 0x2C, + 0x0D, 0x0A, 0x20, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x63, 0x6F, + 0x6E, 0x63, 0x6C, 0x75, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x61, 0x6E, 0x71, 0x75, 0x65, 0x74, 0x2D, + 0x2D, 0x5D, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, + 0x74, 0x20, 0x49, 0x53, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, + 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x72, 0x65, 0x70, 0x65, + 0x61, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x74, 0x75, 0x66, 0x66, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x0D, 0x0A, + 0x69, 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x65, + 0x64, 0x2C, 0x20, 0x27, 0x69, 0x66, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x65, 0x78, 0x70, + 0x6C, 0x61, 0x69, 0x6E, 0x20, 0x69, 0x74, 0x20, 0x61, 0x73, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x67, 0x6F, 0x20, 0x6F, 0x6E, + 0x3F, 0x20, 0x49, 0x74, 0x27, 0x73, 0x20, 0x62, 0x79, 0x20, + 0x66, 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, + 0x73, 0x74, 0x0D, 0x0A, 0x63, 0x6F, 0x6E, 0x66, 0x75, 0x73, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x49, 0x20, 0x65, 0x76, 0x65, 0x72, 0x20, 0x68, 0x65, 0x61, + 0x72, 0x64, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, + 0x65, 0x73, 0x2C, 0x20, 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x6B, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x64, 0x20, 0x62, 0x65, + 0x74, 0x74, 0x65, 0x72, 0x20, 0x6C, 0x65, 0x61, 0x76, 0x65, + 0x20, 0x6F, 0x66, 0x66, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, + 0x68, 0x6F, 0x6E, 0x3A, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, + 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x74, 0x6F, 0x6F, 0x20, 0x67, + 0x6C, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x6F, 0x20, + 0x73, 0x6F, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x68, + 0x61, 0x6C, 0x6C, 0x20, 0x77, 0x65, 0x20, 0x74, 0x72, 0x79, + 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4C, 0x6F, 0x62, 0x73, 0x74, 0x65, 0x72, + 0x20, 0x51, 0x75, 0x61, 0x64, 0x72, 0x69, 0x6C, 0x6C, 0x65, + 0x3F, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, + 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x0D, + 0x0A, 0x6F, 0x6E, 0x2E, 0x20, 0x27, 0x4F, 0x72, 0x20, 0x77, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6C, + 0x69, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x6F, + 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, + 0x74, 0x6F, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x61, 0x20, 0x73, 0x6F, 0x6E, 0x67, 0x3F, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x61, + 0x20, 0x73, 0x6F, 0x6E, 0x67, 0x2C, 0x20, 0x70, 0x6C, 0x65, + 0x61, 0x73, 0x65, 0x2C, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, + 0x74, 0x6C, 0x65, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x62, 0x65, 0x20, 0x73, 0x6F, 0x20, 0x6B, 0x69, 0x6E, 0x64, + 0x2C, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x0D, 0x0A, + 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x2C, 0x20, 0x73, + 0x6F, 0x20, 0x65, 0x61, 0x67, 0x65, 0x72, 0x6C, 0x79, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, + 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x72, 0x61, + 0x74, 0x68, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x66, 0x65, 0x6E, + 0x64, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x0D, + 0x0A, 0x27, 0x48, 0x6D, 0x21, 0x20, 0x4E, 0x6F, 0x20, 0x61, + 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x74, 0x61, 0x73, 0x74, 0x65, 0x73, + 0x21, 0x20, 0x53, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x22, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x53, + 0x6F, 0x75, 0x70, 0x2C, 0x22, 0x20, 0x77, 0x69, 0x6C, 0x6C, + 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x20, 0x6F, 0x6C, 0x64, 0x0D, + 0x0A, 0x66, 0x65, 0x6C, 0x6C, 0x6F, 0x77, 0x3F, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x4D, 0x6F, 0x63, + 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x20, 0x73, + 0x69, 0x67, 0x68, 0x65, 0x64, 0x20, 0x64, 0x65, 0x65, 0x70, + 0x6C, 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, + 0x67, 0x61, 0x6E, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, + 0x76, 0x6F, 0x69, 0x63, 0x65, 0x20, 0x73, 0x6F, 0x6D, 0x65, + 0x74, 0x69, 0x6D, 0x65, 0x73, 0x20, 0x63, 0x68, 0x6F, 0x6B, + 0x65, 0x64, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, 0x20, 0x73, + 0x6F, 0x62, 0x73, 0x2C, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x3A, 0x2D, 0x2D, + 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x27, 0x42, 0x65, + 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x20, 0x53, 0x6F, + 0x75, 0x70, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x72, 0x69, 0x63, + 0x68, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x67, 0x72, 0x65, 0x65, + 0x6E, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x57, 0x61, 0x69, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, + 0x68, 0x6F, 0x74, 0x20, 0x74, 0x75, 0x72, 0x65, 0x65, 0x6E, + 0x21, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x57, 0x68, 0x6F, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x64, + 0x61, 0x69, 0x6E, 0x74, 0x69, 0x65, 0x73, 0x20, 0x77, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x73, 0x74, + 0x6F, 0x6F, 0x70, 0x3F, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x53, + 0x6F, 0x75, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x65, 0x76, 0x65, 0x6E, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x20, + 0x53, 0x6F, 0x75, 0x70, 0x21, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x53, 0x6F, 0x75, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x69, 0x6E, 0x67, 0x2C, + 0x20, 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, + 0x20, 0x53, 0x6F, 0x75, 0x70, 0x21, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x42, 0x65, 0x61, 0x75, 0x2D, 0x2D, 0x6F, + 0x6F, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x20, 0x53, 0x6F, 0x6F, + 0x2D, 0x2D, 0x6F, 0x6F, 0x70, 0x21, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x42, 0x65, 0x61, 0x75, 0x2D, 0x2D, 0x6F, + 0x6F, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x20, 0x53, 0x6F, 0x6F, + 0x2D, 0x2D, 0x6F, 0x6F, 0x70, 0x21, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x53, 0x6F, 0x6F, 0x2D, 0x2D, 0x6F, 0x6F, 0x70, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x2D, 0x2D, + 0x65, 0x2D, 0x2D, 0x65, 0x76, 0x65, 0x6E, 0x69, 0x6E, 0x67, + 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x65, + 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x2C, 0x20, 0x62, + 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x20, 0x53, + 0x6F, 0x75, 0x70, 0x21, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x27, 0x42, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, + 0x6C, 0x20, 0x53, 0x6F, 0x75, 0x70, 0x21, 0x20, 0x57, 0x68, + 0x6F, 0x20, 0x63, 0x61, 0x72, 0x65, 0x73, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x66, 0x69, 0x73, 0x68, 0x2C, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x47, 0x61, 0x6D, 0x65, 0x2C, 0x20, 0x6F, 0x72, + 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x64, 0x69, 0x73, 0x68, 0x3F, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x57, 0x68, 0x6F, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x74, 0x77, 0x6F, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x50, 0x65, 0x6E, 0x6E, 0x79, 0x77, 0x6F, 0x72, 0x74, + 0x68, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x6F, 0x66, 0x20, + 0x62, 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x20, + 0x53, 0x6F, 0x75, 0x70, 0x3F, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x50, 0x65, 0x6E, 0x6E, 0x79, 0x77, 0x6F, 0x72, 0x74, 0x68, + 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x62, + 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x20, 0x53, + 0x6F, 0x75, 0x70, 0x3F, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x42, 0x65, 0x61, 0x75, 0x2D, 0x2D, 0x6F, 0x6F, 0x74, + 0x69, 0x66, 0x75, 0x6C, 0x20, 0x53, 0x6F, 0x6F, 0x2D, 0x2D, + 0x6F, 0x6F, 0x70, 0x21, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x42, 0x65, 0x61, 0x75, 0x2D, 0x2D, 0x6F, 0x6F, 0x74, + 0x69, 0x66, 0x75, 0x6C, 0x20, 0x53, 0x6F, 0x6F, 0x2D, 0x2D, + 0x6F, 0x6F, 0x70, 0x21, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x53, + 0x6F, 0x6F, 0x2D, 0x2D, 0x6F, 0x6F, 0x70, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x2D, 0x2D, 0x65, 0x2D, + 0x2D, 0x65, 0x76, 0x65, 0x6E, 0x69, 0x6E, 0x67, 0x2C, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x65, 0x61, 0x75, + 0x74, 0x69, 0x66, 0x75, 0x6C, 0x2C, 0x20, 0x62, 0x65, 0x61, + 0x75, 0x74, 0x69, 0x2D, 0x2D, 0x46, 0x55, 0x4C, 0x20, 0x53, + 0x4F, 0x55, 0x50, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x43, 0x68, 0x6F, 0x72, 0x75, 0x73, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, + 0x6F, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, + 0x74, 0x6C, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6A, 0x75, + 0x73, 0x74, 0x20, 0x62, 0x65, 0x67, 0x75, 0x6E, 0x0D, 0x0A, + 0x74, 0x6F, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x20, + 0x69, 0x74, 0x2C, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x61, + 0x20, 0x63, 0x72, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x27, 0x54, + 0x68, 0x65, 0x20, 0x74, 0x72, 0x69, 0x61, 0x6C, 0x27, 0x73, + 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, + 0x21, 0x27, 0x20, 0x77, 0x61, 0x73, 0x20, 0x68, 0x65, 0x61, + 0x72, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x43, 0x6F, 0x6D, 0x65, 0x20, + 0x6F, 0x6E, 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, + 0x6F, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x74, + 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, + 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x68, 0x75, + 0x72, 0x72, 0x69, 0x65, 0x64, 0x0D, 0x0A, 0x6F, 0x66, 0x66, + 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, + 0x77, 0x61, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6E, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6F, 0x6E, + 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, + 0x74, 0x20, 0x74, 0x72, 0x69, 0x61, 0x6C, 0x20, 0x69, 0x73, + 0x20, 0x69, 0x74, 0x3F, 0x27, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x70, 0x61, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x61, + 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x72, 0x61, 0x6E, 0x3B, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, + 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x20, 0x6F, 0x6E, 0x6C, + 0x79, 0x0D, 0x0A, 0x61, 0x6E, 0x73, 0x77, 0x65, 0x72, 0x65, + 0x64, 0x20, 0x27, 0x43, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x6E, + 0x21, 0x27, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x61, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x73, 0x74, 0x65, + 0x72, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x6D, + 0x6F, 0x72, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x66, 0x61, 0x69, 0x6E, 0x74, 0x6C, 0x79, + 0x0D, 0x0A, 0x63, 0x61, 0x6D, 0x65, 0x2C, 0x20, 0x63, 0x61, + 0x72, 0x72, 0x69, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x72, 0x65, 0x65, 0x7A, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x66, 0x6F, 0x6C, 0x6C, 0x6F, + 0x77, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6D, 0x65, 0x6C, 0x61, 0x6E, 0x63, + 0x68, 0x6F, 0x6C, 0x79, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, + 0x3A, 0x2D, 0x2D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x27, 0x53, 0x6F, 0x6F, 0x2D, 0x2D, 0x6F, 0x6F, 0x70, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x2D, 0x2D, + 0x65, 0x2D, 0x2D, 0x65, 0x76, 0x65, 0x6E, 0x69, 0x6E, 0x67, + 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x65, + 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x2C, 0x20, 0x62, + 0x65, 0x61, 0x75, 0x74, 0x69, 0x66, 0x75, 0x6C, 0x20, 0x53, + 0x6F, 0x75, 0x70, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, 0x48, 0x41, 0x50, 0x54, + 0x45, 0x52, 0x20, 0x58, 0x49, 0x2E, 0x20, 0x57, 0x68, 0x6F, + 0x20, 0x53, 0x74, 0x6F, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x54, 0x61, 0x72, 0x74, 0x73, 0x3F, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, + 0x6F, 0x66, 0x20, 0x48, 0x65, 0x61, 0x72, 0x74, 0x73, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x73, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, + 0x20, 0x74, 0x68, 0x72, 0x6F, 0x6E, 0x65, 0x20, 0x77, 0x68, + 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x79, 0x0D, 0x0A, 0x61, + 0x72, 0x72, 0x69, 0x76, 0x65, 0x64, 0x2C, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x61, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, + 0x20, 0x63, 0x72, 0x6F, 0x77, 0x64, 0x20, 0x61, 0x73, 0x73, + 0x65, 0x6D, 0x62, 0x6C, 0x65, 0x64, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2D, 0x2D, 0x61, + 0x6C, 0x6C, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x73, 0x20, 0x6F, + 0x66, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x0D, 0x0A, + 0x62, 0x69, 0x72, 0x64, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x62, 0x65, 0x61, 0x73, 0x74, 0x73, 0x2C, 0x20, 0x61, 0x73, + 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x68, 0x6F, 0x6C, 0x65, 0x20, 0x70, + 0x61, 0x63, 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x61, 0x72, + 0x64, 0x73, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x6E, + 0x61, 0x76, 0x65, 0x20, 0x77, 0x61, 0x73, 0x0D, 0x0A, 0x73, + 0x74, 0x61, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x62, 0x65, + 0x66, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, + 0x20, 0x69, 0x6E, 0x20, 0x63, 0x68, 0x61, 0x69, 0x6E, 0x73, + 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x73, + 0x6F, 0x6C, 0x64, 0x69, 0x65, 0x72, 0x20, 0x6F, 0x6E, 0x20, + 0x65, 0x61, 0x63, 0x68, 0x20, 0x73, 0x69, 0x64, 0x65, 0x20, + 0x74, 0x6F, 0x20, 0x67, 0x75, 0x61, 0x72, 0x64, 0x0D, 0x0A, + 0x68, 0x69, 0x6D, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6E, + 0x65, 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, + 0x6E, 0x67, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x57, 0x68, 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x61, 0x20, 0x74, 0x72, 0x75, 0x6D, 0x70, 0x65, 0x74, 0x20, + 0x69, 0x6E, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x68, 0x61, 0x6E, + 0x64, 0x2C, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x20, + 0x73, 0x63, 0x72, 0x6F, 0x6C, 0x6C, 0x20, 0x6F, 0x66, 0x20, + 0x70, 0x61, 0x72, 0x63, 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x20, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x2E, 0x20, 0x49, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6D, 0x69, 0x64, 0x64, + 0x6C, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6F, 0x75, 0x72, 0x74, 0x0D, 0x0A, 0x77, 0x61, 0x73, + 0x20, 0x61, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x2C, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x6C, 0x61, 0x72, + 0x67, 0x65, 0x20, 0x64, 0x69, 0x73, 0x68, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x75, 0x70, 0x6F, + 0x6E, 0x20, 0x69, 0x74, 0x3A, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x73, 0x6F, + 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x2C, 0x0D, 0x0A, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x6D, 0x61, 0x64, 0x65, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x71, 0x75, 0x69, + 0x74, 0x65, 0x20, 0x68, 0x75, 0x6E, 0x67, 0x72, 0x79, 0x20, + 0x74, 0x6F, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2D, 0x2D, 0x27, 0x49, 0x20, + 0x77, 0x69, 0x73, 0x68, 0x20, 0x74, 0x68, 0x65, 0x79, 0x27, + 0x64, 0x20, 0x67, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x74, 0x72, 0x69, 0x61, 0x6C, 0x20, 0x64, 0x6F, 0x6E, + 0x65, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x2C, 0x20, 0x27, 0x61, 0x6E, + 0x64, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x66, + 0x72, 0x65, 0x73, 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x21, + 0x27, 0x20, 0x42, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x0D, 0x0A, 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x6E, 0x6F, 0x20, 0x63, + 0x68, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x65, + 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x62, 0x6F, 0x75, 0x74, 0x0D, 0x0A, 0x68, 0x65, 0x72, + 0x2C, 0x20, 0x74, 0x6F, 0x20, 0x70, 0x61, 0x73, 0x73, 0x20, + 0x61, 0x77, 0x61, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x69, 0x6D, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6E, 0x65, + 0x76, 0x65, 0x72, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x69, 0x63, 0x65, + 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x2C, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x72, 0x65, 0x61, 0x64, 0x0D, 0x0A, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x69, 0x6E, + 0x20, 0x62, 0x6F, 0x6F, 0x6B, 0x73, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x70, 0x6C, 0x65, 0x61, + 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x6E, + 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x6B, 0x6E, 0x65, 0x77, 0x0D, 0x0A, 0x74, 0x68, 0x65, + 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x6E, + 0x65, 0x61, 0x72, 0x6C, 0x79, 0x20, 0x65, 0x76, 0x65, 0x72, + 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x2E, 0x20, 0x27, 0x54, 0x68, 0x61, 0x74, 0x27, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, 0x64, 0x67, + 0x65, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x68, 0x65, 0x72, + 0x73, 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x27, 0x62, 0x65, 0x63, + 0x61, 0x75, 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x69, + 0x73, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x77, 0x69, + 0x67, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, + 0x20, 0x6A, 0x75, 0x64, 0x67, 0x65, 0x2C, 0x20, 0x62, 0x79, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x2C, 0x20, + 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, + 0x6E, 0x67, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x73, + 0x20, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x65, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x63, 0x72, 0x6F, 0x77, 0x6E, 0x20, 0x6F, + 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x77, + 0x69, 0x67, 0x2C, 0x20, 0x28, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x72, 0x6F, + 0x6E, 0x74, 0x69, 0x73, 0x70, 0x69, 0x65, 0x63, 0x65, 0x20, + 0x69, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x77, 0x61, 0x6E, + 0x74, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, 0x20, 0x68, + 0x6F, 0x77, 0x20, 0x68, 0x65, 0x20, 0x64, 0x69, 0x64, 0x20, + 0x69, 0x74, 0x2C, 0x29, 0x20, 0x68, 0x65, 0x20, 0x64, 0x69, + 0x64, 0x0D, 0x0A, 0x6E, 0x6F, 0x74, 0x20, 0x6C, 0x6F, 0x6F, + 0x6B, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x63, + 0x6F, 0x6D, 0x66, 0x6F, 0x72, 0x74, 0x61, 0x62, 0x6C, 0x65, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6E, + 0x6C, 0x79, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x63, + 0x6F, 0x6D, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x41, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, 0x72, 0x79, + 0x2D, 0x62, 0x6F, 0x78, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x6F, + 0x73, 0x65, 0x20, 0x74, 0x77, 0x65, 0x6C, 0x76, 0x65, 0x20, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2C, + 0x27, 0x0D, 0x0A, 0x28, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x6F, 0x62, 0x6C, 0x69, 0x67, 0x65, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x73, 0x61, 0x79, 0x20, 0x27, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2C, 0x27, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x73, 0x65, 0x65, 0x2C, 0x20, 0x62, + 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0x20, 0x73, 0x6F, 0x6D, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x0D, 0x0A, 0x61, 0x6E, 0x69, 0x6D, + 0x61, 0x6C, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x62, + 0x69, 0x72, 0x64, 0x73, 0x2C, 0x29, 0x20, 0x27, 0x49, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x79, 0x20, 0x61, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6A, 0x75, 0x72, 0x6F, 0x72, 0x73, 0x2E, 0x27, 0x20, + 0x53, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x0D, 0x0A, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, + 0x77, 0x6F, 0x72, 0x64, 0x20, 0x74, 0x77, 0x6F, 0x20, 0x6F, + 0x72, 0x20, 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, 0x74, 0x69, + 0x6D, 0x65, 0x73, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74, + 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2C, + 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, 0x20, 0x72, 0x61, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6F, 0x75, 0x64, 0x20, + 0x6F, 0x66, 0x0D, 0x0A, 0x69, 0x74, 0x3A, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x75, + 0x67, 0x68, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x6C, 0x79, 0x20, 0x74, 0x6F, 0x6F, + 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x66, 0x65, 0x77, 0x20, 0x6C, 0x69, 0x74, 0x74, + 0x6C, 0x65, 0x20, 0x67, 0x69, 0x72, 0x6C, 0x73, 0x20, 0x6F, + 0x66, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x61, 0x67, 0x65, + 0x20, 0x6B, 0x6E, 0x65, 0x77, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6D, 0x65, 0x61, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, + 0x20, 0x69, 0x74, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6C, 0x6C, + 0x2E, 0x20, 0x48, 0x6F, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2C, + 0x20, 0x27, 0x6A, 0x75, 0x72, 0x79, 0x2D, 0x6D, 0x65, 0x6E, + 0x27, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x20, 0x64, 0x6F, 0x6E, 0x65, 0x0D, 0x0A, 0x6A, + 0x75, 0x73, 0x74, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, + 0x6C, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x74, 0x77, 0x65, 0x6C, 0x76, 0x65, 0x20, 0x6A, 0x75, 0x72, + 0x6F, 0x72, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x77, 0x72, 0x69, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x62, 0x75, 0x73, 0x69, + 0x6C, 0x79, 0x20, 0x6F, 0x6E, 0x20, 0x73, 0x6C, 0x61, 0x74, + 0x65, 0x73, 0x2E, 0x20, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x79, 0x0D, 0x0A, + 0x64, 0x6F, 0x69, 0x6E, 0x67, 0x3F, 0x27, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x20, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2E, 0x20, + 0x27, 0x54, 0x68, 0x65, 0x79, 0x20, 0x63, 0x61, 0x6E, 0x27, + 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x6E, 0x79, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x70, + 0x75, 0x74, 0x0D, 0x0A, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x79, + 0x65, 0x74, 0x2C, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x69, 0x61, 0x6C, + 0x27, 0x73, 0x20, 0x62, 0x65, 0x67, 0x75, 0x6E, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x79, 0x27, + 0x72, 0x65, 0x20, 0x70, 0x75, 0x74, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, + 0x72, 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x73, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, + 0x6E, 0x20, 0x77, 0x68, 0x69, 0x73, 0x70, 0x65, 0x72, 0x65, + 0x64, 0x20, 0x69, 0x6E, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x79, + 0x2C, 0x20, 0x27, 0x66, 0x6F, 0x72, 0x0D, 0x0A, 0x66, 0x65, + 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x73, 0x68, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x67, 0x65, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x62, 0x65, 0x66, + 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6E, + 0x64, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x72, 0x69, 0x61, 0x6C, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x53, 0x74, 0x75, 0x70, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x73, 0x21, 0x27, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x75, 0x64, 0x2C, 0x20, + 0x69, 0x6E, 0x64, 0x69, 0x67, 0x6E, 0x61, 0x6E, 0x74, 0x20, + 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x74, 0x6F, 0x70, 0x70, + 0x65, 0x64, 0x0D, 0x0A, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, + 0x79, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x57, 0x68, 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, 0x20, + 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x27, 0x53, 0x69, 0x6C, 0x65, + 0x6E, 0x63, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6F, 0x75, 0x72, 0x74, 0x21, 0x27, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x4B, 0x69, + 0x6E, 0x67, 0x20, 0x70, 0x75, 0x74, 0x20, 0x6F, 0x6E, 0x20, + 0x68, 0x69, 0x73, 0x20, 0x73, 0x70, 0x65, 0x63, 0x74, 0x61, + 0x63, 0x6C, 0x65, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x78, 0x69, + 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, 0x72, 0x6F, 0x75, 0x6E, + 0x64, 0x2C, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, + 0x20, 0x6F, 0x75, 0x74, 0x20, 0x77, 0x68, 0x6F, 0x0D, 0x0A, + 0x77, 0x61, 0x73, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x69, 0x6E, + 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x73, 0x65, + 0x65, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, + 0x20, 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, + 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x65, 0x69, 0x72, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, + 0x64, 0x65, 0x72, 0x73, 0x2C, 0x0D, 0x0A, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6A, 0x75, 0x72, 0x6F, 0x72, 0x73, 0x20, 0x77, 0x65, 0x72, + 0x65, 0x20, 0x77, 0x72, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x27, 0x73, 0x74, 0x75, 0x70, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x21, + 0x27, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, + 0x20, 0x73, 0x6C, 0x61, 0x74, 0x65, 0x73, 0x2C, 0x0D, 0x0A, + 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x6D, + 0x61, 0x6B, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x6D, 0x20, 0x64, 0x69, 0x64, 0x6E, 0x27, + 0x74, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x68, 0x6F, 0x77, + 0x20, 0x74, 0x6F, 0x20, 0x73, 0x70, 0x65, 0x6C, 0x6C, 0x0D, + 0x0A, 0x27, 0x73, 0x74, 0x75, 0x70, 0x69, 0x64, 0x2C, 0x27, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x61, 0x73, 0x6B, 0x20, 0x68, 0x69, 0x73, 0x20, 0x6E, 0x65, + 0x69, 0x67, 0x68, 0x62, 0x6F, 0x75, 0x72, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x20, 0x68, 0x69, 0x6D, 0x2E, + 0x20, 0x27, 0x41, 0x20, 0x6E, 0x69, 0x63, 0x65, 0x0D, 0x0A, + 0x6D, 0x75, 0x64, 0x64, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x73, 0x6C, 0x61, 0x74, 0x65, 0x73, 0x27, + 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x62, + 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x72, 0x69, 0x61, 0x6C, 0x27, 0x73, 0x20, 0x6F, 0x76, + 0x65, 0x72, 0x21, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x4F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, 0x72, 0x6F, 0x72, 0x73, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x61, 0x20, 0x70, 0x65, 0x6E, + 0x63, 0x69, 0x6C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, + 0x71, 0x75, 0x65, 0x61, 0x6B, 0x65, 0x64, 0x2E, 0x20, 0x54, + 0x68, 0x69, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x75, + 0x72, 0x73, 0x65, 0x2C, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x0D, 0x0A, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x73, 0x74, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, + 0x74, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x74, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x68, 0x69, + 0x6E, 0x64, 0x20, 0x68, 0x69, 0x6D, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x0D, 0x0A, 0x76, 0x65, 0x72, 0x79, 0x20, 0x73, 0x6F, + 0x6F, 0x6E, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x61, + 0x6E, 0x20, 0x6F, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x75, 0x6E, + 0x69, 0x74, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x61, 0x6B, + 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x20, 0x61, 0x77, 0x61, + 0x79, 0x2E, 0x20, 0x53, 0x68, 0x65, 0x20, 0x64, 0x69, 0x64, + 0x20, 0x69, 0x74, 0x20, 0x73, 0x6F, 0x20, 0x71, 0x75, 0x69, + 0x63, 0x6B, 0x6C, 0x79, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x6A, 0x75, 0x72, + 0x6F, 0x72, 0x20, 0x28, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x42, 0x69, 0x6C, 0x6C, 0x2C, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4C, 0x69, 0x7A, 0x61, 0x72, 0x64, 0x29, 0x20, 0x63, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6D, + 0x61, 0x6B, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x0D, 0x0A, 0x61, + 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x77, 0x68, 0x61, 0x74, + 0x20, 0x68, 0x61, 0x64, 0x20, 0x62, 0x65, 0x63, 0x6F, 0x6D, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x74, 0x3B, 0x20, 0x73, + 0x6F, 0x2C, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x68, + 0x75, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x69, 0x74, 0x2C, 0x20, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x0D, 0x0A, 0x6F, 0x62, 0x6C, 0x69, 0x67, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x66, + 0x69, 0x6E, 0x67, 0x65, 0x72, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x74, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x79, 0x3B, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x77, 0x61, 0x73, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, + 0x75, 0x73, 0x65, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, + 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x6E, 0x6F, 0x20, 0x6D, + 0x61, 0x72, 0x6B, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x6C, 0x61, 0x74, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x48, 0x65, 0x72, 0x61, 0x6C, 0x64, 0x2C, 0x20, + 0x72, 0x65, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x63, 0x63, 0x75, 0x73, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x4F, 0x6E, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x57, 0x68, 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, + 0x62, 0x62, 0x69, 0x74, 0x20, 0x62, 0x6C, 0x65, 0x77, 0x20, + 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, 0x62, 0x6C, 0x61, 0x73, + 0x74, 0x73, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x72, 0x75, 0x6D, 0x70, 0x65, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x0D, 0x0A, 0x75, + 0x6E, 0x72, 0x6F, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x61, 0x72, 0x63, 0x68, 0x6D, 0x65, 0x6E, + 0x74, 0x20, 0x73, 0x63, 0x72, 0x6F, 0x6C, 0x6C, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x61, + 0x73, 0x20, 0x66, 0x6F, 0x6C, 0x6C, 0x6F, 0x77, 0x73, 0x3A, + 0x2D, 0x2D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x27, + 0x54, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, + 0x6F, 0x66, 0x20, 0x48, 0x65, 0x61, 0x72, 0x74, 0x73, 0x2C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, + 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x61, 0x72, 0x74, 0x73, + 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, + 0x6C, 0x6C, 0x20, 0x6F, 0x6E, 0x20, 0x61, 0x20, 0x73, 0x75, + 0x6D, 0x6D, 0x65, 0x72, 0x20, 0x64, 0x61, 0x79, 0x3A, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x4B, + 0x6E, 0x61, 0x76, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x48, 0x65, + 0x61, 0x72, 0x74, 0x73, 0x2C, 0x20, 0x68, 0x65, 0x20, 0x73, + 0x74, 0x6F, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x6F, 0x73, 0x65, + 0x20, 0x74, 0x61, 0x72, 0x74, 0x73, 0x2C, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x74, + 0x6F, 0x6F, 0x6B, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x71, + 0x75, 0x69, 0x74, 0x65, 0x20, 0x61, 0x77, 0x61, 0x79, 0x21, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x43, 0x6F, 0x6E, 0x73, + 0x69, 0x64, 0x65, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, + 0x76, 0x65, 0x72, 0x64, 0x69, 0x63, 0x74, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6A, 0x75, 0x72, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x4E, 0x6F, 0x74, 0x20, 0x79, 0x65, 0x74, 0x2C, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x79, 0x65, 0x74, 0x21, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, + 0x20, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, 0x79, 0x20, 0x69, + 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x65, 0x64, + 0x2E, 0x20, 0x27, 0x54, 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, + 0x20, 0x61, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x0D, 0x0A, + 0x64, 0x65, 0x61, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6F, + 0x6D, 0x65, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x43, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x77, 0x69, 0x74, 0x6E, + 0x65, 0x73, 0x73, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x3B, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, + 0x68, 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, + 0x74, 0x20, 0x62, 0x6C, 0x65, 0x77, 0x20, 0x74, 0x68, 0x72, + 0x65, 0x65, 0x0D, 0x0A, 0x62, 0x6C, 0x61, 0x73, 0x74, 0x73, + 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, + 0x75, 0x6D, 0x70, 0x65, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x63, 0x61, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x6F, 0x75, + 0x74, 0x2C, 0x20, 0x27, 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, + 0x77, 0x69, 0x74, 0x6E, 0x65, 0x73, 0x73, 0x21, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, + 0x73, 0x74, 0x20, 0x77, 0x69, 0x74, 0x6E, 0x65, 0x73, 0x73, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x2E, 0x20, 0x48, 0x65, 0x20, + 0x63, 0x61, 0x6D, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x61, 0x20, 0x74, 0x65, 0x61, 0x63, 0x75, + 0x70, 0x20, 0x69, 0x6E, 0x20, 0x6F, 0x6E, 0x65, 0x0D, 0x0A, + 0x68, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x62, 0x72, 0x65, 0x61, 0x64, 0x2D, 0x61, 0x6E, 0x64, 0x2D, + 0x62, 0x75, 0x74, 0x74, 0x65, 0x72, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x2E, + 0x20, 0x27, 0x49, 0x20, 0x62, 0x65, 0x67, 0x20, 0x70, 0x61, + 0x72, 0x64, 0x6F, 0x6E, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x72, + 0x0D, 0x0A, 0x4D, 0x61, 0x6A, 0x65, 0x73, 0x74, 0x79, 0x2C, + 0x27, 0x20, 0x68, 0x65, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, + 0x2C, 0x20, 0x27, 0x66, 0x6F, 0x72, 0x20, 0x62, 0x72, 0x69, + 0x6E, 0x67, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x73, + 0x65, 0x20, 0x69, 0x6E, 0x3A, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x49, 0x20, 0x68, 0x61, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x71, + 0x75, 0x69, 0x74, 0x65, 0x20, 0x66, 0x69, 0x6E, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x0D, 0x0A, 0x6D, 0x79, 0x20, 0x74, 0x65, + 0x61, 0x20, 0x77, 0x68, 0x65, 0x6E, 0x20, 0x49, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x73, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x6F, + 0x72, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, + 0x75, 0x20, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x66, 0x69, 0x6E, 0x69, + 0x73, 0x68, 0x65, 0x64, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, + 0x2E, 0x20, 0x27, 0x57, 0x68, 0x65, 0x6E, 0x20, 0x64, 0x69, + 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x62, 0x65, 0x67, 0x69, + 0x6E, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, + 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, + 0x72, 0x65, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x66, 0x6F, 0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, + 0x20, 0x68, 0x69, 0x6D, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x63, 0x6F, 0x75, 0x72, 0x74, + 0x2C, 0x20, 0x61, 0x72, 0x6D, 0x2D, 0x69, 0x6E, 0x2D, 0x61, + 0x72, 0x6D, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, + 0x2E, 0x20, 0x27, 0x46, 0x6F, 0x75, 0x72, 0x74, 0x65, 0x65, + 0x6E, 0x74, 0x68, 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x61, 0x72, + 0x63, 0x68, 0x2C, 0x20, 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x6B, 0x20, 0x69, 0x74, 0x0D, 0x0A, 0x77, 0x61, 0x73, 0x2C, + 0x27, 0x20, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x46, 0x69, 0x66, 0x74, 0x65, + 0x65, 0x6E, 0x74, 0x68, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, + 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x53, 0x69, 0x78, 0x74, 0x65, 0x65, 0x6E, 0x74, + 0x68, 0x2C, 0x27, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x72, + 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, 0x72, + 0x79, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6A, 0x75, 0x72, 0x79, 0x20, 0x65, 0x61, 0x67, 0x65, + 0x72, 0x6C, 0x79, 0x0D, 0x0A, 0x77, 0x72, 0x6F, 0x74, 0x65, + 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x74, 0x68, 0x72, 0x65, 0x65, 0x20, 0x64, 0x61, 0x74, 0x65, + 0x73, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, + 0x20, 0x73, 0x6C, 0x61, 0x74, 0x65, 0x73, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x61, 0x64, + 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x75, + 0x70, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x72, 0x65, + 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x61, 0x6E, 0x73, 0x77, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x68, 0x69, 0x6C, 0x6C, 0x69, 0x6E, 0x67, 0x73, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x70, 0x65, 0x6E, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x61, 0x6B, 0x65, 0x20, + 0x6F, 0x66, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x68, + 0x61, 0x74, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, + 0x69, 0x6E, 0x67, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, + 0x20, 0x69, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x6D, 0x69, 0x6E, + 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x74, 0x6F, 0x6C, 0x65, + 0x6E, 0x21, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, + 0x6E, 0x67, 0x20, 0x65, 0x78, 0x63, 0x6C, 0x61, 0x69, 0x6D, + 0x65, 0x64, 0x2C, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, + 0x75, 0x72, 0x79, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x69, + 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x6D, + 0x61, 0x64, 0x65, 0x20, 0x61, 0x0D, 0x0A, 0x6D, 0x65, 0x6D, + 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x75, 0x6D, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x63, 0x74, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x6B, 0x65, 0x65, + 0x70, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x74, 0x6F, 0x20, + 0x73, 0x65, 0x6C, 0x6C, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x61, 0x64, + 0x64, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x61, 0x6E, 0x20, + 0x65, 0x78, 0x70, 0x6C, 0x61, 0x6E, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x3B, 0x20, 0x27, 0x49, 0x27, 0x76, 0x65, 0x20, 0x6E, + 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x6D, 0x79, + 0x20, 0x6F, 0x77, 0x6E, 0x2E, 0x20, 0x49, 0x27, 0x6D, 0x20, + 0x61, 0x20, 0x68, 0x61, 0x74, 0x74, 0x65, 0x72, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x48, 0x65, 0x72, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x70, + 0x75, 0x74, 0x20, 0x6F, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x73, 0x70, 0x65, 0x63, 0x74, 0x61, 0x63, 0x6C, 0x65, 0x73, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x65, 0x67, 0x61, + 0x6E, 0x20, 0x73, 0x74, 0x61, 0x72, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x2C, 0x0D, 0x0A, 0x77, 0x68, 0x6F, 0x20, + 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, 0x70, 0x61, 0x6C, + 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x69, 0x64, 0x67, + 0x65, 0x74, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x47, 0x69, 0x76, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, + 0x65, 0x76, 0x69, 0x64, 0x65, 0x6E, 0x63, 0x65, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4B, 0x69, 0x6E, 0x67, 0x3B, 0x20, 0x27, 0x61, 0x6E, 0x64, + 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, 0x20, + 0x6E, 0x65, 0x72, 0x76, 0x6F, 0x75, 0x73, 0x2C, 0x20, 0x6F, + 0x72, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x20, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x74, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x69, 0x73, 0x20, 0x64, 0x69, + 0x64, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x73, 0x65, 0x65, 0x6D, + 0x20, 0x74, 0x6F, 0x20, 0x65, 0x6E, 0x63, 0x6F, 0x75, 0x72, + 0x61, 0x67, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x6E, 0x65, 0x73, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, + 0x6C, 0x6C, 0x3A, 0x20, 0x68, 0x65, 0x20, 0x6B, 0x65, 0x70, + 0x74, 0x20, 0x73, 0x68, 0x69, 0x66, 0x74, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x6F, 0x6E, 0x65, + 0x20, 0x66, 0x6F, 0x6F, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x2C, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x75, 0x6E, + 0x65, 0x61, 0x73, 0x69, 0x6C, 0x79, 0x20, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x68, + 0x69, 0x73, 0x20, 0x63, 0x6F, 0x6E, 0x66, 0x75, 0x73, 0x69, + 0x6F, 0x6E, 0x20, 0x68, 0x65, 0x20, 0x62, 0x69, 0x74, 0x20, + 0x61, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x70, 0x69, + 0x65, 0x63, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, + 0x20, 0x68, 0x69, 0x73, 0x20, 0x74, 0x65, 0x61, 0x63, 0x75, + 0x70, 0x20, 0x69, 0x6E, 0x73, 0x74, 0x65, 0x61, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x62, 0x72, + 0x65, 0x61, 0x64, 0x2D, 0x61, 0x6E, 0x64, 0x2D, 0x62, 0x75, + 0x74, 0x74, 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x4A, + 0x75, 0x73, 0x74, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x66, 0x65, 0x6C, 0x74, 0x20, + 0x61, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x63, 0x75, 0x72, + 0x69, 0x6F, 0x75, 0x73, 0x20, 0x73, 0x65, 0x6E, 0x73, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x70, 0x75, 0x7A, 0x7A, 0x6C, 0x65, 0x64, 0x0D, + 0x0A, 0x68, 0x65, 0x72, 0x20, 0x61, 0x20, 0x67, 0x6F, 0x6F, + 0x64, 0x20, 0x64, 0x65, 0x61, 0x6C, 0x20, 0x75, 0x6E, 0x74, + 0x69, 0x6C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6D, 0x61, 0x64, + 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x77, 0x68, 0x61, 0x74, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x3A, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x62, 0x65, 0x67, + 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x0D, + 0x0A, 0x67, 0x72, 0x6F, 0x77, 0x20, 0x6C, 0x61, 0x72, 0x67, + 0x65, 0x72, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x61, 0x74, 0x20, 0x66, + 0x69, 0x72, 0x73, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x67, 0x65, 0x74, 0x20, 0x75, + 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x65, 0x61, 0x76, + 0x65, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, + 0x72, 0x74, 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6F, 0x6E, + 0x20, 0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x6F, 0x75, 0x67, 0x68, 0x74, 0x73, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x64, 0x65, 0x63, 0x69, 0x64, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x77, + 0x68, 0x65, 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x61, 0x73, 0x0D, 0x0A, 0x6C, 0x6F, 0x6E, + 0x67, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x72, 0x6F, 0x6F, 0x6D, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x68, 0x65, 0x72, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x77, 0x69, 0x73, 0x68, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x6E, + 0x27, 0x74, 0x20, 0x73, 0x71, 0x75, 0x65, 0x65, 0x7A, 0x65, + 0x20, 0x73, 0x6F, 0x2E, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, + 0x75, 0x73, 0x65, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x74, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x68, 0x65, 0x72, 0x2E, 0x20, 0x27, 0x49, 0x20, 0x63, 0x61, + 0x6E, 0x20, 0x68, 0x61, 0x72, 0x64, 0x6C, 0x79, 0x20, 0x62, + 0x72, 0x65, 0x61, 0x74, 0x68, 0x65, 0x2E, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, + 0x20, 0x68, 0x65, 0x6C, 0x70, 0x20, 0x69, 0x74, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6D, 0x65, 0x65, + 0x6B, 0x6C, 0x79, 0x3A, 0x20, 0x27, 0x49, 0x27, 0x6D, 0x20, + 0x67, 0x72, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x27, 0x76, 0x65, + 0x20, 0x6E, 0x6F, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x67, 0x72, 0x6F, 0x77, 0x20, 0x68, 0x65, + 0x72, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x44, 0x6F, + 0x6E, 0x27, 0x74, 0x20, 0x74, 0x61, 0x6C, 0x6B, 0x20, 0x6E, + 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x65, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x62, 0x6F, 0x6C, 0x64, + 0x6C, 0x79, 0x3A, 0x20, 0x27, 0x79, 0x6F, 0x75, 0x20, 0x6B, + 0x6E, 0x6F, 0x77, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x72, 0x65, + 0x20, 0x67, 0x72, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x0D, 0x0A, + 0x74, 0x6F, 0x6F, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x59, 0x65, 0x73, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x49, + 0x20, 0x67, 0x72, 0x6F, 0x77, 0x20, 0x61, 0x74, 0x20, 0x61, + 0x20, 0x72, 0x65, 0x61, 0x73, 0x6F, 0x6E, 0x61, 0x62, 0x6C, + 0x65, 0x20, 0x70, 0x61, 0x63, 0x65, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, + 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x3A, 0x20, 0x27, 0x6E, + 0x6F, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x0D, 0x0A, 0x72, 0x69, 0x64, 0x69, 0x63, 0x75, 0x6C, 0x6F, + 0x75, 0x73, 0x20, 0x66, 0x61, 0x73, 0x68, 0x69, 0x6F, 0x6E, + 0x2E, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x20, + 0x67, 0x6F, 0x74, 0x20, 0x75, 0x70, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x73, 0x75, 0x6C, 0x6B, 0x69, 0x6C, 0x79, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x65, + 0x64, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x73, 0x69, 0x64, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x74, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x6C, 0x65, 0x66, + 0x74, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x73, 0x74, 0x61, 0x72, + 0x69, 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x2C, 0x0D, 0x0A, 0x6A, 0x75, 0x73, 0x74, 0x20, + 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, + 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x20, 0x63, 0x72, 0x6F, 0x73, + 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x75, 0x72, 0x74, 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6F, 0x6E, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x66, + 0x66, 0x69, 0x63, 0x65, 0x72, 0x73, 0x0D, 0x0A, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x74, + 0x2C, 0x20, 0x27, 0x42, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x6D, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x69, 0x73, 0x74, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, + 0x6E, 0x67, 0x65, 0x72, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x63, 0x6F, + 0x6E, 0x63, 0x65, 0x72, 0x74, 0x21, 0x27, 0x20, 0x6F, 0x6E, + 0x0D, 0x0A, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x72, 0x65, 0x74, 0x63, 0x68, 0x65, 0x64, + 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x74, 0x72, + 0x65, 0x6D, 0x62, 0x6C, 0x65, 0x64, 0x20, 0x73, 0x6F, 0x2C, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x65, 0x20, 0x73, + 0x68, 0x6F, 0x6F, 0x6B, 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, + 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, 0x6F, 0x65, 0x73, 0x20, + 0x6F, 0x66, 0x66, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x47, + 0x69, 0x76, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x65, + 0x76, 0x69, 0x64, 0x65, 0x6E, 0x63, 0x65, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x72, + 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x6E, + 0x67, 0x72, 0x69, 0x6C, 0x79, 0x2C, 0x20, 0x27, 0x6F, 0x72, + 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x65, 0x64, 0x2C, 0x20, 0x77, 0x68, 0x65, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x27, 0x72, 0x65, + 0x20, 0x6E, 0x65, 0x72, 0x76, 0x6F, 0x75, 0x73, 0x20, 0x6F, + 0x72, 0x20, 0x6E, 0x6F, 0x74, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x61, 0x20, 0x70, 0x6F, + 0x6F, 0x72, 0x20, 0x6D, 0x61, 0x6E, 0x2C, 0x20, 0x79, 0x6F, + 0x75, 0x72, 0x20, 0x4D, 0x61, 0x6A, 0x65, 0x73, 0x74, 0x79, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x2C, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x74, 0x72, 0x65, 0x6D, + 0x62, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x76, 0x6F, 0x69, 0x63, + 0x65, 0x2C, 0x0D, 0x0A, 0x27, 0x2D, 0x2D, 0x61, 0x6E, 0x64, + 0x20, 0x49, 0x20, 0x68, 0x61, 0x64, 0x6E, 0x27, 0x74, 0x20, + 0x62, 0x65, 0x67, 0x75, 0x6E, 0x20, 0x6D, 0x79, 0x20, 0x74, + 0x65, 0x61, 0x2D, 0x2D, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x62, + 0x6F, 0x76, 0x65, 0x20, 0x61, 0x20, 0x77, 0x65, 0x65, 0x6B, + 0x20, 0x6F, 0x72, 0x20, 0x73, 0x6F, 0x2D, 0x2D, 0x61, 0x6E, + 0x64, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x62, 0x72, 0x65, + 0x61, 0x64, 0x2D, 0x61, 0x6E, 0x64, 0x2D, 0x62, 0x75, 0x74, + 0x74, 0x65, 0x72, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x73, 0x6F, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x2D, + 0x2D, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x77, 0x69, 0x6E, 0x6B, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x61, 0x2D, + 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, + 0x20, 0x74, 0x77, 0x69, 0x6E, 0x6B, 0x6C, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, 0x20, 0x62, 0x65, 0x67, + 0x61, 0x6E, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x65, 0x61, 0x2C, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x72, + 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x4F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, + 0x65, 0x20, 0x74, 0x77, 0x69, 0x6E, 0x6B, 0x6C, 0x69, 0x6E, + 0x67, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x73, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, 0x54, 0x21, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, + 0x69, 0x6E, 0x67, 0x20, 0x73, 0x68, 0x61, 0x72, 0x70, 0x6C, + 0x79, 0x2E, 0x20, 0x27, 0x44, 0x6F, 0x20, 0x79, 0x6F, 0x75, + 0x0D, 0x0A, 0x74, 0x61, 0x6B, 0x65, 0x20, 0x6D, 0x65, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x64, 0x75, 0x6E, 0x63, + 0x65, 0x3F, 0x20, 0x47, 0x6F, 0x20, 0x6F, 0x6E, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x61, + 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x6D, 0x61, 0x6E, 0x2C, + 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, + 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x6F, 0x73, + 0x74, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x74, + 0x77, 0x69, 0x6E, 0x6B, 0x6C, 0x65, 0x64, 0x20, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x2D, + 0x2D, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, 0x69, 0x64, 0x6E, 0x27, + 0x74, 0x21, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, + 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, 0x72, 0x65, 0x20, 0x69, + 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x65, 0x64, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x67, 0x72, 0x65, 0x61, + 0x74, 0x20, 0x68, 0x75, 0x72, 0x72, 0x79, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x64, 0x69, 0x64, + 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x64, 0x65, 0x6E, 0x79, + 0x20, 0x69, 0x74, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, + 0x20, 0x48, 0x61, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x48, 0x65, 0x20, 0x64, 0x65, 0x6E, 0x69, 0x65, 0x73, + 0x20, 0x69, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x3A, + 0x20, 0x27, 0x6C, 0x65, 0x61, 0x76, 0x65, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x70, 0x61, 0x72, + 0x74, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, + 0x6C, 0x6C, 0x2C, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6E, 0x79, + 0x20, 0x72, 0x61, 0x74, 0x65, 0x2C, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x65, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x2D, 0x2D, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x6C, 0x6F, + 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x61, 0x6E, 0x78, + 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, 0x72, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, 0x20, + 0x69, 0x66, 0x20, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x64, 0x65, 0x6E, 0x79, 0x20, 0x69, 0x74, 0x20, + 0x74, 0x6F, 0x6F, 0x3A, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x20, 0x64, 0x65, 0x6E, 0x69, 0x65, 0x64, 0x0D, 0x0A, + 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x62, + 0x65, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, + 0x61, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x41, 0x66, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x2C, 0x27, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x69, + 0x6E, 0x75, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x2C, 0x20, 0x27, 0x49, 0x20, + 0x63, 0x75, 0x74, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x6D, + 0x6F, 0x72, 0x65, 0x20, 0x62, 0x72, 0x65, 0x61, 0x64, 0x2D, + 0x61, 0x6E, 0x64, 0x2D, 0x62, 0x75, 0x74, 0x74, 0x65, 0x72, + 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x42, 0x75, + 0x74, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, + 0x75, 0x73, 0x65, 0x20, 0x73, 0x61, 0x79, 0x3F, 0x27, 0x20, + 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6A, 0x75, 0x72, 0x79, 0x20, 0x61, 0x73, 0x6B, 0x65, + 0x64, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, + 0x74, 0x20, 0x49, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, 0x20, + 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x48, 0x61, 0x74, 0x74, 0x65, 0x72, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x4D, 0x55, 0x53, 0x54, + 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, 0x2C, + 0x27, 0x20, 0x72, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, + 0x20, 0x27, 0x6F, 0x72, 0x20, 0x49, 0x27, 0x6C, 0x6C, 0x20, + 0x68, 0x61, 0x76, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x65, + 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x6D, 0x69, 0x73, + 0x65, 0x72, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x48, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x20, 0x64, 0x72, 0x6F, 0x70, 0x70, 0x65, + 0x64, 0x20, 0x68, 0x69, 0x73, 0x20, 0x74, 0x65, 0x61, 0x63, + 0x75, 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x72, 0x65, + 0x61, 0x64, 0x2D, 0x61, 0x6E, 0x64, 0x2D, 0x62, 0x75, 0x74, + 0x74, 0x65, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x0D, 0x0A, 0x64, 0x6F, 0x77, 0x6E, 0x20, + 0x6F, 0x6E, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6B, 0x6E, 0x65, + 0x65, 0x2E, 0x20, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x61, 0x20, + 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x6D, 0x61, 0x6E, 0x2C, 0x20, + 0x79, 0x6F, 0x75, 0x72, 0x20, 0x4D, 0x61, 0x6A, 0x65, 0x73, + 0x74, 0x79, 0x2C, 0x27, 0x20, 0x68, 0x65, 0x20, 0x62, 0x65, + 0x67, 0x61, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x59, + 0x6F, 0x75, 0x27, 0x72, 0x65, 0x20, 0x61, 0x20, 0x76, 0x65, + 0x72, 0x79, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x73, 0x70, + 0x65, 0x61, 0x6B, 0x65, 0x72, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, + 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x48, 0x65, 0x72, 0x65, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x67, 0x75, 0x69, 0x6E, 0x65, 0x61, 0x2D, 0x70, + 0x69, 0x67, 0x73, 0x20, 0x63, 0x68, 0x65, 0x65, 0x72, 0x65, + 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x69, 0x6D, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, + 0x6C, 0x79, 0x20, 0x73, 0x75, 0x70, 0x70, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x64, 0x20, 0x62, 0x79, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x20, 0x6F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x72, 0x73, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x75, 0x72, 0x74, 0x2E, 0x20, 0x28, 0x41, 0x73, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x69, 0x73, 0x20, 0x72, 0x61, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x61, 0x20, 0x68, 0x61, 0x72, 0x64, + 0x20, 0x77, 0x6F, 0x72, 0x64, 0x2C, 0x20, 0x49, 0x20, 0x77, + 0x69, 0x6C, 0x6C, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x0D, 0x0A, + 0x65, 0x78, 0x70, 0x6C, 0x61, 0x69, 0x6E, 0x20, 0x74, 0x6F, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x69, + 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x64, 0x6F, 0x6E, 0x65, + 0x2E, 0x20, 0x54, 0x68, 0x65, 0x79, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x61, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x63, + 0x61, 0x6E, 0x76, 0x61, 0x73, 0x20, 0x62, 0x61, 0x67, 0x2C, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x69, 0x65, + 0x64, 0x0D, 0x0A, 0x75, 0x70, 0x20, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6D, 0x6F, 0x75, 0x74, 0x68, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, + 0x73, 0x3A, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x73, 0x6C, + 0x69, 0x70, 0x70, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x67, 0x75, 0x69, 0x6E, 0x65, 0x61, 0x2D, 0x70, 0x69, 0x67, + 0x2C, 0x0D, 0x0A, 0x68, 0x65, 0x61, 0x64, 0x20, 0x66, 0x69, + 0x72, 0x73, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x6E, 0x20, 0x73, 0x61, 0x74, 0x20, 0x75, 0x70, + 0x6F, 0x6E, 0x20, 0x69, 0x74, 0x2E, 0x29, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x67, 0x6C, 0x61, 0x64, + 0x20, 0x49, 0x27, 0x76, 0x65, 0x20, 0x73, 0x65, 0x65, 0x6E, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6F, 0x6E, 0x65, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x20, 0x27, 0x49, + 0x27, 0x76, 0x65, 0x20, 0x73, 0x6F, 0x20, 0x6F, 0x66, 0x74, + 0x65, 0x6E, 0x20, 0x72, 0x65, 0x61, 0x64, 0x0D, 0x0A, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x77, 0x73, + 0x70, 0x61, 0x70, 0x65, 0x72, 0x73, 0x2C, 0x20, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6E, 0x64, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x72, 0x69, 0x61, 0x6C, 0x73, 0x2C, 0x20, + 0x22, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x61, 0x74, 0x74, 0x65, + 0x6D, 0x70, 0x74, 0x73, 0x0D, 0x0A, 0x61, 0x74, 0x20, 0x61, + 0x70, 0x70, 0x6C, 0x61, 0x75, 0x73, 0x65, 0x2C, 0x20, 0x77, + 0x68, 0x69, 0x63, 0x68, 0x20, 0x77, 0x61, 0x73, 0x20, 0x69, + 0x6D, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x6C, 0x79, + 0x20, 0x73, 0x75, 0x70, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, + 0x66, 0x66, 0x69, 0x63, 0x65, 0x72, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x63, 0x6F, 0x75, 0x72, + 0x74, 0x2C, 0x22, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x49, 0x20, + 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x75, 0x6E, 0x64, 0x65, + 0x72, 0x73, 0x74, 0x6F, 0x6F, 0x64, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x20, 0x69, 0x74, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x74, + 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x6E, 0x6F, 0x77, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x66, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x73, 0x74, 0x61, + 0x6E, 0x64, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x2C, 0x27, 0x20, + 0x63, 0x6F, 0x6E, 0x74, 0x69, 0x6E, 0x75, 0x65, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x4B, 0x69, 0x6E, 0x67, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x63, 0x61, 0x6E, + 0x27, 0x74, 0x20, 0x67, 0x6F, 0x20, 0x6E, 0x6F, 0x20, 0x6C, + 0x6F, 0x77, 0x65, 0x72, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x3A, 0x20, 0x27, 0x49, 0x27, 0x6D, 0x20, 0x6F, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6C, 0x6F, 0x6F, + 0x72, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, 0x69, + 0x73, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, + 0x65, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, + 0x20, 0x53, 0x49, 0x54, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x2C, + 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, + 0x20, 0x72, 0x65, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x48, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x67, 0x75, + 0x69, 0x6E, 0x65, 0x61, 0x2D, 0x70, 0x69, 0x67, 0x20, 0x63, + 0x68, 0x65, 0x65, 0x72, 0x65, 0x64, 0x2C, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x73, 0x75, 0x70, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x43, 0x6F, 0x6D, 0x65, 0x2C, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x75, 0x69, 0x6E, + 0x65, 0x61, 0x2D, 0x70, 0x69, 0x67, 0x73, 0x21, 0x27, 0x20, + 0x74, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x41, 0x6C, + 0x69, 0x63, 0x65, 0x2E, 0x20, 0x27, 0x4E, 0x6F, 0x77, 0x20, + 0x77, 0x65, 0x20, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x67, + 0x65, 0x74, 0x0D, 0x0A, 0x6F, 0x6E, 0x20, 0x62, 0x65, 0x74, + 0x74, 0x65, 0x72, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x27, 0x64, 0x20, 0x72, 0x61, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x20, 0x6D, 0x79, + 0x20, 0x74, 0x65, 0x61, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, + 0x6E, 0x20, 0x61, 0x6E, 0x78, 0x69, 0x6F, 0x75, 0x73, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, + 0x77, 0x68, 0x6F, 0x20, 0x77, 0x61, 0x73, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x69, + 0x6E, 0x67, 0x65, 0x72, 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x67, + 0x6F, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, + 0x74, 0x65, 0x72, 0x20, 0x68, 0x75, 0x72, 0x72, 0x69, 0x65, + 0x64, 0x6C, 0x79, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x74, 0x2C, 0x0D, + 0x0A, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x65, + 0x76, 0x65, 0x6E, 0x20, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x6F, 0x20, 0x70, 0x75, 0x74, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x73, 0x68, 0x6F, 0x65, 0x73, 0x20, 0x6F, + 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x2D, 0x2D, 0x61, + 0x6E, 0x64, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x74, 0x61, + 0x6B, 0x65, 0x20, 0x68, 0x69, 0x73, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x20, 0x6F, 0x66, 0x66, 0x20, 0x6F, 0x75, 0x74, 0x73, + 0x69, 0x64, 0x65, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x6F, 0x66, 0x66, + 0x69, 0x63, 0x65, 0x72, 0x73, 0x3A, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x48, 0x61, 0x74, 0x74, 0x65, + 0x72, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6F, 0x75, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x73, 0x69, 0x67, 0x68, 0x74, 0x20, 0x62, + 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x72, 0x20, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x67, 0x65, 0x74, 0x0D, 0x0A, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, 0x6F, 0x72, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x43, 0x61, 0x6C, 0x6C, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, + 0x77, 0x69, 0x74, 0x6E, 0x65, 0x73, 0x73, 0x21, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, + 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, + 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x77, 0x69, 0x74, + 0x6E, 0x65, 0x73, 0x73, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, + 0x27, 0x73, 0x20, 0x63, 0x6F, 0x6F, 0x6B, 0x2E, 0x20, 0x53, + 0x68, 0x65, 0x20, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65, 0x70, 0x70, 0x65, + 0x72, 0x2D, 0x62, 0x6F, 0x78, 0x20, 0x69, 0x6E, 0x0D, 0x0A, + 0x68, 0x65, 0x72, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x67, 0x75, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x77, 0x68, + 0x6F, 0x20, 0x69, 0x74, 0x20, 0x77, 0x61, 0x73, 0x2C, 0x20, + 0x65, 0x76, 0x65, 0x6E, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, + 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x67, 0x6F, 0x74, 0x20, + 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x63, 0x6F, 0x75, 0x72, 0x74, 0x2C, 0x20, 0x62, 0x79, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x61, 0x79, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, 0x20, 0x6E, + 0x65, 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x6F, + 0x6F, 0x72, 0x20, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x73, + 0x6E, 0x65, 0x65, 0x7A, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6C, + 0x6C, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x47, 0x69, 0x76, 0x65, 0x20, + 0x79, 0x6F, 0x75, 0x72, 0x20, 0x65, 0x76, 0x69, 0x64, 0x65, + 0x6E, 0x63, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x68, 0x61, 0x6E, 0x27, + 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6F, 0x6B, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x6E, + 0x78, 0x69, 0x6F, 0x75, 0x73, 0x6C, 0x79, 0x20, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, 0x69, 0x74, 0x65, + 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x2C, 0x20, 0x77, + 0x68, 0x6F, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x77, 0x20, 0x76, 0x6F, 0x69, + 0x63, 0x65, 0x2C, 0x0D, 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x72, + 0x20, 0x4D, 0x61, 0x6A, 0x65, 0x73, 0x74, 0x79, 0x20, 0x6D, + 0x75, 0x73, 0x74, 0x20, 0x63, 0x72, 0x6F, 0x73, 0x73, 0x2D, + 0x65, 0x78, 0x61, 0x6D, 0x69, 0x6E, 0x65, 0x20, 0x54, 0x48, + 0x49, 0x53, 0x20, 0x77, 0x69, 0x74, 0x6E, 0x65, 0x73, 0x73, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x6C, + 0x6C, 0x2C, 0x20, 0x69, 0x66, 0x20, 0x49, 0x20, 0x6D, 0x75, + 0x73, 0x74, 0x2C, 0x20, 0x49, 0x20, 0x6D, 0x75, 0x73, 0x74, + 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, + 0x67, 0x20, 0x73, 0x61, 0x69, 0x64, 0x2C, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x61, 0x20, 0x6D, 0x65, 0x6C, 0x61, 0x6E, + 0x63, 0x68, 0x6F, 0x6C, 0x79, 0x20, 0x61, 0x69, 0x72, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x2C, 0x0D, 0x0A, 0x61, 0x66, 0x74, + 0x65, 0x72, 0x20, 0x66, 0x6F, 0x6C, 0x64, 0x69, 0x6E, 0x67, + 0x20, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x6D, 0x73, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x66, 0x72, 0x6F, 0x77, 0x6E, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6F, 0x6F, 0x6B, 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x20, + 0x68, 0x69, 0x73, 0x20, 0x65, 0x79, 0x65, 0x73, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x0D, 0x0A, 0x6E, 0x65, 0x61, 0x72, 0x6C, + 0x79, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x73, + 0x69, 0x67, 0x68, 0x74, 0x2C, 0x20, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x64, + 0x65, 0x65, 0x70, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2C, + 0x20, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, + 0x20, 0x74, 0x61, 0x72, 0x74, 0x73, 0x20, 0x6D, 0x61, 0x64, + 0x65, 0x20, 0x6F, 0x66, 0x3F, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x50, 0x65, 0x70, 0x70, 0x65, 0x72, 0x2C, 0x20, 0x6D, + 0x6F, 0x73, 0x74, 0x6C, 0x79, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6F, + 0x6B, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x72, 0x65, + 0x61, 0x63, 0x6C, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x61, 0x20, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x79, + 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x20, 0x62, 0x65, 0x68, + 0x69, 0x6E, 0x64, 0x20, 0x68, 0x65, 0x72, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x43, 0x6F, 0x6C, 0x6C, 0x61, 0x72, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, + 0x75, 0x73, 0x65, 0x2C, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x20, 0x73, 0x68, 0x72, 0x69, + 0x65, 0x6B, 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x2E, 0x20, + 0x27, 0x42, 0x65, 0x68, 0x65, 0x61, 0x64, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x21, 0x0D, 0x0A, 0x54, 0x75, 0x72, 0x6E, 0x20, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, + 0x73, 0x65, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x63, 0x6F, 0x75, 0x72, 0x74, 0x21, 0x20, 0x53, 0x75, 0x70, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x68, 0x69, 0x6D, 0x21, + 0x20, 0x50, 0x69, 0x6E, 0x63, 0x68, 0x20, 0x68, 0x69, 0x6D, + 0x21, 0x20, 0x4F, 0x66, 0x66, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x77, 0x68, 0x69, 0x73, + 0x6B, 0x65, 0x72, 0x73, 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, + 0x46, 0x6F, 0x72, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x6D, + 0x69, 0x6E, 0x75, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x68, 0x6F, 0x6C, 0x65, 0x20, 0x63, 0x6F, 0x75, + 0x72, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x69, 0x6E, 0x20, + 0x63, 0x6F, 0x6E, 0x66, 0x75, 0x73, 0x69, 0x6F, 0x6E, 0x2C, + 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x44, 0x6F, 0x72, 0x6D, 0x6F, 0x75, 0x73, + 0x65, 0x0D, 0x0A, 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, + 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x2C, 0x20, + 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x73, 0x65, 0x74, 0x74, 0x6C, 0x65, 0x64, 0x20, 0x64, + 0x6F, 0x77, 0x6E, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x2C, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6F, 0x6B, 0x20, + 0x68, 0x61, 0x64, 0x0D, 0x0A, 0x64, 0x69, 0x73, 0x61, 0x70, + 0x70, 0x65, 0x61, 0x72, 0x65, 0x64, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x4E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x6D, 0x69, + 0x6E, 0x64, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x69, + 0x72, 0x20, 0x6F, 0x66, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, + 0x20, 0x72, 0x65, 0x6C, 0x69, 0x65, 0x66, 0x2E, 0x20, 0x27, + 0x43, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, + 0x65, 0x78, 0x74, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x6E, 0x65, + 0x73, 0x73, 0x2E, 0x27, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x68, + 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x6E, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x74, + 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, 0x27, 0x52, + 0x65, 0x61, 0x6C, 0x6C, 0x79, 0x2C, 0x20, 0x6D, 0x79, 0x20, + 0x64, 0x65, 0x61, 0x72, 0x2C, 0x0D, 0x0A, 0x59, 0x4F, 0x55, + 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x63, 0x72, 0x6F, 0x73, + 0x73, 0x2D, 0x65, 0x78, 0x61, 0x6D, 0x69, 0x6E, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x77, + 0x69, 0x74, 0x6E, 0x65, 0x73, 0x73, 0x2E, 0x20, 0x49, 0x74, + 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x73, 0x20, 0x6D, 0x79, 0x20, 0x66, 0x6F, 0x72, 0x65, + 0x68, 0x65, 0x61, 0x64, 0x0D, 0x0A, 0x61, 0x63, 0x68, 0x65, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, + 0x65, 0x20, 0x77, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, 0x69, 0x74, 0x65, 0x20, + 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x20, 0x61, 0x73, 0x20, + 0x68, 0x65, 0x20, 0x66, 0x75, 0x6D, 0x62, 0x6C, 0x65, 0x64, + 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6C, 0x69, 0x73, 0x74, 0x2C, 0x20, 0x66, 0x65, 0x65, 0x6C, + 0x69, 0x6E, 0x67, 0x20, 0x76, 0x65, 0x72, 0x79, 0x0D, 0x0A, + 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x20, 0x74, 0x6F, + 0x20, 0x73, 0x65, 0x65, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x77, + 0x69, 0x74, 0x6E, 0x65, 0x73, 0x73, 0x20, 0x77, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x6C, 0x69, 0x6B, 0x65, + 0x2C, 0x20, 0x27, 0x2D, 0x2D, 0x66, 0x6F, 0x72, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x68, 0x61, 0x76, 0x65, 0x6E, 0x27, + 0x74, 0x0D, 0x0A, 0x67, 0x6F, 0x74, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x20, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6E, 0x63, 0x65, + 0x20, 0x59, 0x45, 0x54, 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, + 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2E, 0x20, 0x49, 0x6D, + 0x61, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x73, 0x75, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x2C, 0x20, + 0x77, 0x68, 0x65, 0x6E, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, + 0x57, 0x68, 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, + 0x69, 0x74, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x6F, 0x75, + 0x74, 0x2C, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x6F, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x73, 0x68, 0x72, 0x69, 0x6C, 0x6C, 0x20, 0x6C, 0x69, + 0x74, 0x74, 0x6C, 0x65, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x6E, 0x61, 0x6D, + 0x65, 0x20, 0x27, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x21, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, + 0x43, 0x48, 0x41, 0x50, 0x54, 0x45, 0x52, 0x20, 0x58, 0x49, + 0x49, 0x2E, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x27, 0x73, + 0x20, 0x45, 0x76, 0x69, 0x64, 0x65, 0x6E, 0x63, 0x65, 0x0D, + 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x48, 0x65, 0x72, 0x65, + 0x21, 0x27, 0x20, 0x63, 0x72, 0x69, 0x65, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x71, 0x75, 0x69, 0x74, + 0x65, 0x20, 0x66, 0x6F, 0x72, 0x67, 0x65, 0x74, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x66, 0x6C, 0x75, 0x72, 0x72, 0x79, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6D, 0x6F, 0x6D, 0x65, 0x6E, 0x74, + 0x20, 0x68, 0x6F, 0x77, 0x0D, 0x0A, 0x6C, 0x61, 0x72, 0x67, + 0x65, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x67, 0x72, 0x6F, 0x77, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x66, 0x65, + 0x77, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x73, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6A, + 0x75, 0x6D, 0x70, 0x65, 0x64, 0x20, 0x75, 0x70, 0x20, 0x69, + 0x6E, 0x20, 0x73, 0x75, 0x63, 0x68, 0x0D, 0x0A, 0x61, 0x20, + 0x68, 0x75, 0x72, 0x72, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x69, 0x70, 0x70, 0x65, + 0x64, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6A, 0x75, 0x72, 0x79, 0x2D, 0x62, 0x6F, 0x78, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, + 0x64, 0x67, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x73, 0x6B, 0x69, 0x72, 0x74, 0x2C, 0x0D, 0x0A, 0x75, + 0x70, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, 0x72, + 0x79, 0x6D, 0x65, 0x6E, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x65, 0x61, 0x64, 0x73, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x72, + 0x6F, 0x77, 0x64, 0x20, 0x62, 0x65, 0x6C, 0x6F, 0x77, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x79, 0x20, 0x6C, 0x61, 0x79, + 0x20, 0x73, 0x70, 0x72, 0x61, 0x77, 0x6C, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x2C, 0x20, 0x72, 0x65, + 0x6D, 0x69, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x6D, 0x75, 0x63, + 0x68, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x67, 0x6C, 0x6F, + 0x62, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x67, 0x6F, 0x6C, 0x64, + 0x66, 0x69, 0x73, 0x68, 0x0D, 0x0A, 0x73, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x64, 0x20, 0x61, 0x63, 0x63, 0x69, 0x64, 0x65, + 0x6E, 0x74, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x75, 0x70, 0x73, + 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x65, 0x65, + 0x6B, 0x20, 0x62, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, 0x20, 0x49, 0x20, + 0x42, 0x45, 0x47, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x70, + 0x61, 0x72, 0x64, 0x6F, 0x6E, 0x21, 0x27, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x65, 0x78, 0x63, 0x6C, 0x61, 0x69, 0x6D, 0x65, + 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x74, 0x6F, 0x6E, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, + 0x20, 0x64, 0x69, 0x73, 0x6D, 0x61, 0x79, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x0D, 0x0A, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, + 0x70, 0x69, 0x63, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x20, 0x75, 0x70, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6E, 0x20, 0x61, 0x73, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6B, + 0x6C, 0x79, 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x2C, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x63, 0x63, 0x69, 0x64, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x74, 0x68, + 0x65, 0x20, 0x67, 0x6F, 0x6C, 0x64, 0x66, 0x69, 0x73, 0x68, + 0x20, 0x6B, 0x65, 0x70, 0x74, 0x20, 0x72, 0x75, 0x6E, 0x6E, + 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x68, 0x65, 0x61, 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x61, + 0x20, 0x76, 0x61, 0x67, 0x75, 0x65, 0x20, 0x73, 0x6F, 0x72, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x69, 0x64, 0x65, 0x61, 0x0D, + 0x0A, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x63, + 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x61, + 0x74, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x70, 0x75, 0x74, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, + 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, + 0x75, 0x72, 0x79, 0x2D, 0x62, 0x6F, 0x78, 0x2C, 0x20, 0x6F, + 0x72, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x64, 0x69, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x20, 0x74, 0x72, 0x69, + 0x61, 0x6C, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, + 0x70, 0x72, 0x6F, 0x63, 0x65, 0x65, 0x64, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, + 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x76, + 0x65, 0x72, 0x79, 0x20, 0x67, 0x72, 0x61, 0x76, 0x65, 0x20, + 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x27, 0x75, 0x6E, + 0x74, 0x69, 0x6C, 0x0D, 0x0A, 0x61, 0x6C, 0x6C, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6A, 0x75, 0x72, 0x79, 0x6D, 0x65, 0x6E, + 0x20, 0x61, 0x72, 0x65, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x70, + 0x72, 0x6F, 0x70, 0x65, 0x72, 0x20, 0x70, 0x6C, 0x61, 0x63, + 0x65, 0x73, 0x2D, 0x2D, 0x41, 0x4C, 0x4C, 0x2C, 0x27, 0x20, + 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x67, 0x72, + 0x65, 0x61, 0x74, 0x20, 0x65, 0x6D, 0x70, 0x68, 0x61, 0x73, + 0x69, 0x73, 0x2C, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x68, 0x61, 0x72, 0x64, 0x20, 0x61, 0x74, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x61, 0x73, 0x20, 0x68, + 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x64, 0x6F, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, 0x72, 0x79, 0x2D, 0x62, + 0x6F, 0x78, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x61, + 0x77, 0x20, 0x74, 0x68, 0x61, 0x74, 0x2C, 0x20, 0x69, 0x6E, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x74, 0x65, + 0x2C, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x70, 0x75, 0x74, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x4C, + 0x69, 0x7A, 0x61, 0x72, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x68, + 0x65, 0x61, 0x64, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x77, 0x61, + 0x72, 0x64, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x72, 0x20, 0x6C, 0x69, + 0x74, 0x74, 0x6C, 0x65, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x77, 0x61, 0x76, 0x69, 0x6E, + 0x67, 0x20, 0x69, 0x74, 0x73, 0x0D, 0x0A, 0x74, 0x61, 0x69, + 0x6C, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x6D, 0x65, 0x6C, 0x61, 0x6E, 0x63, 0x68, + 0x6F, 0x6C, 0x79, 0x20, 0x77, 0x61, 0x79, 0x2C, 0x20, 0x62, + 0x65, 0x69, 0x6E, 0x67, 0x20, 0x71, 0x75, 0x69, 0x74, 0x65, + 0x20, 0x75, 0x6E, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x6D, 0x6F, 0x76, 0x65, 0x2E, 0x20, 0x53, 0x68, 0x65, + 0x20, 0x73, 0x6F, 0x6F, 0x6E, 0x20, 0x67, 0x6F, 0x74, 0x0D, + 0x0A, 0x69, 0x74, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x70, + 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, 0x72, 0x69, 0x67, 0x68, + 0x74, 0x3B, 0x20, 0x27, 0x6E, 0x6F, 0x74, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, + 0x69, 0x66, 0x69, 0x65, 0x73, 0x20, 0x6D, 0x75, 0x63, 0x68, + 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x0D, 0x0A, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x3B, 0x20, 0x27, 0x49, 0x20, 0x73, 0x68, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x62, 0x65, 0x20, 0x51, 0x55, 0x49, 0x54, 0x45, 0x20, 0x61, + 0x73, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, + 0x69, 0x61, 0x6C, 0x0D, 0x0A, 0x6F, 0x6E, 0x65, 0x20, 0x77, + 0x61, 0x79, 0x20, 0x75, 0x70, 0x20, 0x61, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x2E, 0x27, + 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x73, 0x20, 0x73, 0x6F, 0x6F, + 0x6E, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, + 0x75, 0x72, 0x79, 0x20, 0x68, 0x61, 0x64, 0x20, 0x61, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x72, 0x65, 0x63, + 0x6F, 0x76, 0x65, 0x72, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6F, + 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x68, 0x6F, 0x63, + 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x75, 0x70, 0x73, 0x65, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x73, + 0x6C, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x70, 0x65, 0x6E, 0x63, 0x69, 0x6C, 0x73, 0x20, 0x68, 0x61, + 0x64, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x66, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x6E, + 0x64, 0x65, 0x64, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, + 0x6F, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x20, 0x74, + 0x68, 0x65, 0x79, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x6F, + 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x76, 0x65, 0x72, 0x79, + 0x20, 0x64, 0x69, 0x6C, 0x69, 0x67, 0x65, 0x6E, 0x74, 0x6C, + 0x79, 0x20, 0x74, 0x6F, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x20, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x20, 0x68, 0x69, 0x73, + 0x74, 0x6F, 0x72, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x61, 0x63, 0x63, 0x69, 0x64, 0x65, 0x6E, + 0x74, 0x2C, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x65, 0x78, 0x63, + 0x65, 0x70, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4C, 0x69, + 0x7A, 0x61, 0x72, 0x64, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, + 0x73, 0x65, 0x65, 0x6D, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x6F, + 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x6F, 0x76, 0x65, 0x72, + 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x6F, + 0x0D, 0x0A, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x73, 0x69, 0x74, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, 0x73, 0x20, 0x6D, 0x6F, + 0x75, 0x74, 0x68, 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x2C, 0x20, + 0x67, 0x61, 0x7A, 0x69, 0x6E, 0x67, 0x20, 0x75, 0x70, 0x20, + 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x6F, 0x6F, 0x66, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x63, 0x6F, 0x75, 0x72, 0x74, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6F, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, + 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x62, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x3F, + 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x4E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, 0x6F, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x57, 0x48, 0x41, 0x54, 0x45, 0x56, + 0x45, 0x52, 0x3F, 0x27, 0x20, 0x70, 0x65, 0x72, 0x73, 0x69, + 0x73, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, + 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, + 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x68, 0x61, + 0x74, 0x65, 0x76, 0x65, 0x72, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, 0x74, 0x27, 0x73, + 0x20, 0x76, 0x65, 0x72, 0x79, 0x20, 0x69, 0x6D, 0x70, 0x6F, + 0x72, 0x74, 0x61, 0x6E, 0x74, 0x2C, 0x27, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x2C, 0x20, 0x74, 0x75, 0x72, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, + 0x72, 0x79, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x0D, 0x0A, 0x6A, 0x75, 0x73, 0x74, 0x20, + 0x62, 0x65, 0x67, 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x6F, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x6F, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x73, 0x6C, + 0x61, 0x74, 0x65, 0x73, 0x2C, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, 0x69, 0x74, 0x65, + 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x0D, 0x0A, 0x69, + 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x65, 0x64, + 0x3A, 0x20, 0x27, 0x55, 0x4E, 0x69, 0x6D, 0x70, 0x6F, 0x72, + 0x74, 0x61, 0x6E, 0x74, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x72, + 0x20, 0x4D, 0x61, 0x6A, 0x65, 0x73, 0x74, 0x79, 0x20, 0x6D, + 0x65, 0x61, 0x6E, 0x73, 0x2C, 0x20, 0x6F, 0x66, 0x20, 0x63, + 0x6F, 0x75, 0x72, 0x73, 0x65, 0x2C, 0x27, 0x20, 0x68, 0x65, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x0D, 0x0A, 0x76, 0x65, 0x72, 0x79, 0x20, 0x72, 0x65, 0x73, + 0x70, 0x65, 0x63, 0x74, 0x66, 0x75, 0x6C, 0x20, 0x74, 0x6F, + 0x6E, 0x65, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x66, 0x72, + 0x6F, 0x77, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6D, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x61, + 0x63, 0x65, 0x73, 0x20, 0x61, 0x74, 0x20, 0x68, 0x69, 0x6D, + 0x20, 0x61, 0x73, 0x20, 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, + 0x6B, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x55, 0x4E, + 0x69, 0x6D, 0x70, 0x6F, 0x72, 0x74, 0x61, 0x6E, 0x74, 0x2C, + 0x20, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, + 0x2C, 0x20, 0x49, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x74, 0x2C, + 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, + 0x20, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, 0x79, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x0D, 0x0A, 0x74, 0x6F, + 0x20, 0x68, 0x69, 0x6D, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x6E, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, + 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x69, 0x6D, 0x70, 0x6F, 0x72, 0x74, 0x61, 0x6E, 0x74, 0x2D, + 0x2D, 0x75, 0x6E, 0x69, 0x6D, 0x70, 0x6F, 0x72, 0x74, 0x61, + 0x6E, 0x74, 0x2D, 0x2D, 0x75, 0x6E, 0x69, 0x6D, 0x70, 0x6F, + 0x72, 0x74, 0x61, 0x6E, 0x74, 0x2D, 0x2D, 0x69, 0x6D, 0x70, + 0x6F, 0x72, 0x74, 0x61, 0x6E, 0x74, 0x2D, 0x2D, 0x27, 0x20, + 0x61, 0x73, 0x20, 0x69, 0x66, 0x20, 0x68, 0x65, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6E, 0x67, + 0x0D, 0x0A, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x77, 0x6F, + 0x72, 0x64, 0x20, 0x73, 0x6F, 0x75, 0x6E, 0x64, 0x65, 0x64, + 0x20, 0x62, 0x65, 0x73, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x53, 0x6F, 0x6D, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6A, 0x75, 0x72, 0x79, 0x20, 0x77, 0x72, 0x6F, + 0x74, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, + 0x20, 0x27, 0x69, 0x6D, 0x70, 0x6F, 0x72, 0x74, 0x61, 0x6E, + 0x74, 0x2C, 0x27, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x6F, + 0x6D, 0x65, 0x20, 0x27, 0x75, 0x6E, 0x69, 0x6D, 0x70, 0x6F, + 0x72, 0x74, 0x61, 0x6E, 0x74, 0x2E, 0x27, 0x0D, 0x0A, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x73, 0x65, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2C, + 0x20, 0x61, 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x6E, 0x65, 0x61, 0x72, 0x20, 0x65, 0x6E, 0x6F, + 0x75, 0x67, 0x68, 0x20, 0x74, 0x6F, 0x20, 0x6C, 0x6F, 0x6F, + 0x6B, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x73, 0x6C, 0x61, 0x74, 0x65, 0x73, 0x3B, + 0x0D, 0x0A, 0x27, 0x62, 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, + 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x6D, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20, 0x62, 0x69, 0x74, + 0x2C, 0x27, 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x41, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6D, 0x6F, + 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, + 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x68, + 0x61, 0x64, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x74, 0x69, 0x6D, + 0x65, 0x20, 0x62, 0x75, 0x73, 0x69, 0x6C, 0x79, 0x20, 0x77, + 0x72, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x0D, + 0x0A, 0x68, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x65, 0x2D, + 0x62, 0x6F, 0x6F, 0x6B, 0x2C, 0x20, 0x63, 0x61, 0x63, 0x6B, + 0x6C, 0x65, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x27, 0x53, + 0x69, 0x6C, 0x65, 0x6E, 0x63, 0x65, 0x21, 0x27, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x62, 0x6F, 0x6F, 0x6B, 0x2C, 0x20, 0x27, 0x52, 0x75, + 0x6C, 0x65, 0x0D, 0x0A, 0x46, 0x6F, 0x72, 0x74, 0x79, 0x2D, + 0x74, 0x77, 0x6F, 0x2E, 0x20, 0x41, 0x4C, 0x4C, 0x20, 0x50, + 0x45, 0x52, 0x53, 0x4F, 0x4E, 0x53, 0x20, 0x4D, 0x4F, 0x52, + 0x45, 0x20, 0x54, 0x48, 0x41, 0x4E, 0x20, 0x41, 0x20, 0x4D, + 0x49, 0x4C, 0x45, 0x20, 0x48, 0x49, 0x47, 0x48, 0x20, 0x54, + 0x4F, 0x20, 0x4C, 0x45, 0x41, 0x56, 0x45, 0x20, 0x54, 0x48, + 0x45, 0x20, 0x43, 0x4F, 0x55, 0x52, 0x54, 0x2E, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x45, 0x76, 0x65, 0x72, 0x79, 0x62, 0x6F, + 0x64, 0x79, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, + 0x61, 0x74, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x27, 0x4D, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x61, 0x20, 0x6D, 0x69, 0x6C, 0x65, 0x20, 0x68, + 0x69, 0x67, 0x68, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x59, 0x6F, 0x75, 0x20, 0x61, 0x72, 0x65, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x4E, 0x65, 0x61, 0x72, 0x6C, 0x79, 0x20, 0x74, 0x77, + 0x6F, 0x20, 0x6D, 0x69, 0x6C, 0x65, 0x73, 0x20, 0x68, 0x69, + 0x67, 0x68, 0x2C, 0x27, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x65, 0x6C, 0x6C, + 0x2C, 0x20, 0x49, 0x20, 0x73, 0x68, 0x61, 0x6E, 0x27, 0x74, + 0x20, 0x67, 0x6F, 0x2C, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x72, 0x61, 0x74, 0x65, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x3A, + 0x20, 0x27, 0x62, 0x65, 0x73, 0x69, 0x64, 0x65, 0x73, 0x2C, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x61, 0x0D, 0x0A, 0x72, 0x65, 0x67, 0x75, 0x6C, + 0x61, 0x72, 0x20, 0x72, 0x75, 0x6C, 0x65, 0x3A, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x69, 0x6E, 0x76, 0x65, 0x6E, 0x74, 0x65, + 0x64, 0x20, 0x69, 0x74, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, + 0x6E, 0x6F, 0x77, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, + 0x6C, 0x64, 0x65, 0x73, 0x74, 0x20, 0x72, 0x75, 0x6C, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6F, + 0x6F, 0x6B, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x69, + 0x74, 0x20, 0x6F, 0x75, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x65, 0x20, 0x4E, 0x75, 0x6D, 0x62, 0x65, 0x72, + 0x20, 0x4F, 0x6E, 0x65, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x75, 0x72, 0x6E, 0x65, 0x64, 0x20, 0x70, 0x61, + 0x6C, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, + 0x75, 0x74, 0x20, 0x68, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x74, + 0x65, 0x2D, 0x62, 0x6F, 0x6F, 0x6B, 0x20, 0x68, 0x61, 0x73, + 0x74, 0x69, 0x6C, 0x79, 0x2E, 0x20, 0x27, 0x43, 0x6F, 0x6E, + 0x73, 0x69, 0x64, 0x65, 0x72, 0x20, 0x79, 0x6F, 0x75, 0x72, + 0x0D, 0x0A, 0x76, 0x65, 0x72, 0x64, 0x69, 0x63, 0x74, 0x2C, + 0x27, 0x20, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, 0x72, + 0x79, 0x2C, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x6C, 0x6F, + 0x77, 0x2C, 0x20, 0x74, 0x72, 0x65, 0x6D, 0x62, 0x6C, 0x69, + 0x6E, 0x67, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x72, 0x65, 0x27, + 0x73, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x65, 0x76, 0x69, + 0x64, 0x65, 0x6E, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x63, + 0x6F, 0x6D, 0x65, 0x20, 0x79, 0x65, 0x74, 0x2C, 0x20, 0x70, + 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x72, + 0x20, 0x4D, 0x61, 0x6A, 0x65, 0x73, 0x74, 0x79, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x57, 0x68, 0x69, 0x74, 0x65, 0x0D, 0x0A, 0x52, 0x61, 0x62, + 0x62, 0x69, 0x74, 0x2C, 0x20, 0x6A, 0x75, 0x6D, 0x70, 0x69, + 0x6E, 0x67, 0x20, 0x75, 0x70, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x68, 0x75, 0x72, + 0x72, 0x79, 0x3B, 0x20, 0x27, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x70, 0x61, 0x70, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x20, + 0x6A, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, + 0x70, 0x69, 0x63, 0x6B, 0x65, 0x64, 0x0D, 0x0A, 0x75, 0x70, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x61, + 0x74, 0x27, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x69, 0x74, 0x3F, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x49, 0x20, 0x68, 0x61, 0x76, 0x65, 0x6E, 0x27, + 0x74, 0x20, 0x6F, 0x70, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x69, + 0x74, 0x20, 0x79, 0x65, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, 0x69, + 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x2C, + 0x20, 0x27, 0x62, 0x75, 0x74, 0x20, 0x69, 0x74, 0x20, 0x73, + 0x65, 0x65, 0x6D, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, + 0x20, 0x61, 0x0D, 0x0A, 0x6C, 0x65, 0x74, 0x74, 0x65, 0x72, + 0x2C, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6E, 0x20, + 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x69, + 0x73, 0x6F, 0x6E, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x2D, 0x2D, + 0x74, 0x6F, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x62, 0x6F, 0x64, + 0x79, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, + 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x27, 0x75, + 0x6E, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6E, + 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x6E, 0x6F, 0x62, 0x6F, 0x64, + 0x79, 0x2C, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x69, + 0x73, 0x6E, 0x27, 0x74, 0x20, 0x75, 0x73, 0x75, 0x61, 0x6C, + 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, 0x6F, 0x77, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x6F, + 0x20, 0x69, 0x73, 0x20, 0x69, 0x74, 0x20, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x3F, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x6F, 0x6E, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, 0x72, + 0x79, 0x6D, 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x74, 0x20, 0x69, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74, + 0x20, 0x61, 0x6C, 0x6C, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, 0x69, 0x74, + 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x3B, 0x20, + 0x27, 0x69, 0x6E, 0x20, 0x66, 0x61, 0x63, 0x74, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, 0x0D, 0x0A, 0x6E, + 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x72, 0x69, + 0x74, 0x74, 0x65, 0x6E, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4F, 0x55, 0x54, 0x53, 0x49, 0x44, 0x45, 0x2E, + 0x27, 0x20, 0x48, 0x65, 0x20, 0x75, 0x6E, 0x66, 0x6F, 0x6C, + 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, + 0x70, 0x65, 0x72, 0x20, 0x61, 0x73, 0x20, 0x68, 0x65, 0x20, + 0x73, 0x70, 0x6F, 0x6B, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x0D, 0x0A, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x27, 0x49, + 0x74, 0x20, 0x69, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x61, 0x20, + 0x6C, 0x65, 0x74, 0x74, 0x65, 0x72, 0x2C, 0x20, 0x61, 0x66, + 0x74, 0x65, 0x72, 0x20, 0x61, 0x6C, 0x6C, 0x3A, 0x20, 0x69, + 0x74, 0x27, 0x73, 0x20, 0x61, 0x20, 0x73, 0x65, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x76, 0x65, 0x72, 0x73, 0x65, 0x73, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x72, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x70, 0x72, 0x69, 0x73, 0x6F, 0x6E, 0x65, 0x72, + 0x27, 0x73, 0x20, 0x68, 0x61, 0x6E, 0x64, 0x77, 0x72, 0x69, + 0x74, 0x69, 0x6E, 0x67, 0x3F, 0x27, 0x20, 0x61, 0x73, 0x6B, + 0x65, 0x64, 0x20, 0x61, 0x6E, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6A, 0x75, + 0x72, 0x79, 0x6D, 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x4E, 0x6F, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x79, 0x27, + 0x72, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x2C, 0x27, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, + 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, + 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, + 0x65, 0x65, 0x72, 0x65, 0x73, 0x74, 0x20, 0x74, 0x68, 0x69, + 0x6E, 0x67, 0x0D, 0x0A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, + 0x69, 0x74, 0x2E, 0x27, 0x20, 0x28, 0x54, 0x68, 0x65, 0x20, + 0x6A, 0x75, 0x72, 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x65, 0x64, 0x20, 0x70, 0x75, 0x7A, 0x7A, + 0x6C, 0x65, 0x64, 0x2E, 0x29, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x48, 0x65, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x68, 0x61, + 0x76, 0x65, 0x20, 0x69, 0x6D, 0x69, 0x74, 0x61, 0x74, 0x65, + 0x64, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x62, 0x6F, 0x64, 0x79, + 0x20, 0x65, 0x6C, 0x73, 0x65, 0x27, 0x73, 0x20, 0x68, 0x61, + 0x6E, 0x64, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2E, 0x20, + 0x28, 0x54, 0x68, 0x65, 0x20, 0x6A, 0x75, 0x72, 0x79, 0x0D, + 0x0A, 0x61, 0x6C, 0x6C, 0x20, 0x62, 0x72, 0x69, 0x67, 0x68, + 0x74, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x75, 0x70, 0x20, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x2E, 0x29, 0x0D, 0x0A, 0x0D, 0x0A, + 0x27, 0x50, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x79, 0x6F, + 0x75, 0x72, 0x20, 0x4D, 0x61, 0x6A, 0x65, 0x73, 0x74, 0x79, + 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4B, 0x6E, 0x61, 0x76, 0x65, 0x2C, 0x20, 0x27, + 0x49, 0x20, 0x64, 0x69, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x79, 0x0D, 0x0A, 0x63, + 0x61, 0x6E, 0x27, 0x74, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x65, + 0x20, 0x49, 0x20, 0x64, 0x69, 0x64, 0x3A, 0x20, 0x74, 0x68, + 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x6E, + 0x61, 0x6D, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6E, + 0x64, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x66, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, 0x69, 0x64, 0x6E, 0x27, + 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x20, 0x69, 0x74, 0x2C, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x27, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x6D, 0x61, + 0x6B, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x0D, 0x0A, 0x77, 0x6F, 0x72, 0x73, + 0x65, 0x2E, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x4D, 0x55, 0x53, + 0x54, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6D, 0x65, 0x61, + 0x6E, 0x74, 0x20, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x6D, 0x69, + 0x73, 0x63, 0x68, 0x69, 0x65, 0x66, 0x2C, 0x20, 0x6F, 0x72, + 0x20, 0x65, 0x6C, 0x73, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x27, + 0x64, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x73, 0x69, 0x67, + 0x6E, 0x65, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x0D, 0x0A, + 0x6E, 0x61, 0x6D, 0x65, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x20, + 0x61, 0x6E, 0x20, 0x68, 0x6F, 0x6E, 0x65, 0x73, 0x74, 0x20, + 0x6D, 0x61, 0x6E, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, + 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, + 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, 0x20, 0x63, + 0x6C, 0x61, 0x70, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, + 0x20, 0x68, 0x61, 0x6E, 0x64, 0x73, 0x20, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x3A, 0x20, 0x69, 0x74, 0x20, 0x77, + 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, + 0x73, 0x74, 0x20, 0x72, 0x65, 0x61, 0x6C, 0x6C, 0x79, 0x0D, + 0x0A, 0x63, 0x6C, 0x65, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, + 0x6E, 0x67, 0x20, 0x68, 0x61, 0x64, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x64, 0x61, 0x79, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x61, 0x74, + 0x20, 0x50, 0x52, 0x4F, 0x56, 0x45, 0x53, 0x20, 0x68, 0x69, + 0x73, 0x20, 0x67, 0x75, 0x69, 0x6C, 0x74, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, + 0x75, 0x65, 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x49, 0x74, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x65, 0x73, 0x20, + 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6F, 0x72, 0x74, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2E, 0x20, 0x27, 0x57, 0x68, 0x79, 0x2C, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, + 0x65, 0x76, 0x65, 0x6E, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x0D, + 0x0A, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, + 0x27, 0x72, 0x65, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x21, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x52, 0x65, 0x61, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, + 0x67, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x57, 0x68, 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, + 0x69, 0x74, 0x20, 0x70, 0x75, 0x74, 0x20, 0x6F, 0x6E, 0x20, + 0x68, 0x69, 0x73, 0x20, 0x73, 0x70, 0x65, 0x63, 0x74, 0x61, + 0x63, 0x6C, 0x65, 0x73, 0x2E, 0x20, 0x27, 0x57, 0x68, 0x65, + 0x72, 0x65, 0x20, 0x73, 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x49, + 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x2C, 0x20, 0x70, 0x6C, + 0x65, 0x61, 0x73, 0x65, 0x0D, 0x0A, 0x79, 0x6F, 0x75, 0x72, + 0x20, 0x4D, 0x61, 0x6A, 0x65, 0x73, 0x74, 0x79, 0x3F, 0x27, + 0x20, 0x68, 0x65, 0x20, 0x61, 0x73, 0x6B, 0x65, 0x64, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x42, 0x65, 0x67, 0x69, 0x6E, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x65, + 0x67, 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x20, 0x67, 0x72, 0x61, 0x76, 0x65, 0x6C, + 0x79, 0x2C, 0x20, 0x27, 0x61, 0x6E, 0x64, 0x20, 0x67, 0x6F, + 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x79, + 0x6F, 0x75, 0x0D, 0x0A, 0x63, 0x6F, 0x6D, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6E, 0x64, 0x3A, + 0x20, 0x74, 0x68, 0x65, 0x6E, 0x20, 0x73, 0x74, 0x6F, 0x70, + 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x73, + 0x65, 0x20, 0x77, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x76, 0x65, 0x72, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x57, 0x68, 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, + 0x62, 0x62, 0x69, 0x74, 0x20, 0x72, 0x65, 0x61, 0x64, 0x3A, + 0x2D, 0x2D, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x27, + 0x54, 0x68, 0x65, 0x79, 0x20, 0x74, 0x6F, 0x6C, 0x64, 0x20, + 0x6D, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x68, + 0x65, 0x72, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x41, + 0x6E, 0x64, 0x20, 0x6D, 0x65, 0x6E, 0x74, 0x69, 0x6F, 0x6E, + 0x65, 0x64, 0x20, 0x6D, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x68, + 0x69, 0x6D, 0x3A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x53, 0x68, + 0x65, 0x20, 0x67, 0x61, 0x76, 0x65, 0x20, 0x6D, 0x65, 0x20, + 0x61, 0x20, 0x67, 0x6F, 0x6F, 0x64, 0x20, 0x63, 0x68, 0x61, + 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x2C, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x42, 0x75, 0x74, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x49, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x73, 0x77, 0x69, 0x6D, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x48, 0x65, 0x20, 0x73, + 0x65, 0x6E, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x77, + 0x6F, 0x72, 0x64, 0x20, 0x49, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x67, 0x6F, 0x6E, 0x65, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x28, 0x57, 0x65, 0x20, 0x6B, 0x6E, + 0x6F, 0x77, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x62, + 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x29, 0x3A, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x49, 0x66, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x70, 0x75, 0x73, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x20, 0x6F, 0x6E, 0x2C, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x57, 0x68, 0x61, 0x74, 0x20, 0x77, 0x6F, 0x75, + 0x6C, 0x64, 0x20, 0x62, 0x65, 0x63, 0x6F, 0x6D, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x3F, 0x0D, 0x0A, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x49, 0x20, 0x67, 0x61, 0x76, 0x65, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x6F, 0x6E, 0x65, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x67, 0x61, 0x76, 0x65, 0x20, + 0x68, 0x69, 0x6D, 0x20, 0x74, 0x77, 0x6F, 0x2C, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x67, 0x61, + 0x76, 0x65, 0x20, 0x75, 0x73, 0x20, 0x74, 0x68, 0x72, 0x65, + 0x65, 0x20, 0x6F, 0x72, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x3B, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x54, 0x68, 0x65, 0x79, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, + 0x65, 0x64, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x68, 0x69, + 0x6D, 0x20, 0x74, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x2C, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x54, 0x68, 0x6F, 0x75, 0x67, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x77, 0x65, 0x72, + 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x65, 0x20, 0x62, 0x65, 0x66, + 0x6F, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, + 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x6F, 0x72, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x63, 0x68, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x62, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x49, 0x6E, + 0x76, 0x6F, 0x6C, 0x76, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x66, 0x66, 0x61, 0x69, + 0x72, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x48, 0x65, 0x20, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x73, 0x20, 0x74, 0x6F, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x66, 0x72, 0x65, 0x65, + 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x45, 0x78, 0x61, + 0x63, 0x74, 0x6C, 0x79, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, + 0x20, 0x77, 0x65, 0x72, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x4D, 0x79, 0x20, 0x6E, 0x6F, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x77, 0x61, 0x73, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x68, 0x61, 0x64, 0x20, + 0x62, 0x65, 0x65, 0x6E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x28, 0x42, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x66, 0x69, 0x74, 0x29, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x41, 0x6E, 0x20, 0x6F, 0x62, 0x73, 0x74, 0x61, 0x63, 0x6C, + 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6D, + 0x65, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6E, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x48, 0x69, 0x6D, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x6C, + 0x76, 0x65, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, + 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x44, + 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x6C, 0x65, 0x74, 0x20, 0x68, + 0x69, 0x6D, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x6C, 0x69, 0x6B, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x20, 0x62, 0x65, 0x73, 0x74, 0x2C, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x46, 0x6F, 0x72, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x65, 0x76, + 0x65, 0x72, 0x20, 0x62, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x41, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x2C, 0x20, + 0x6B, 0x65, 0x70, 0x74, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, + 0x73, 0x74, 0x2C, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x42, + 0x65, 0x74, 0x77, 0x65, 0x65, 0x6E, 0x20, 0x79, 0x6F, 0x75, + 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x6D, 0x65, 0x2E, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x54, + 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6D, 0x6F, 0x73, 0x74, 0x20, 0x69, 0x6D, 0x70, 0x6F, 0x72, + 0x74, 0x61, 0x6E, 0x74, 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6E, + 0x63, 0x65, 0x20, 0x77, 0x65, 0x27, 0x76, 0x65, 0x20, 0x68, + 0x65, 0x61, 0x72, 0x64, 0x20, 0x79, 0x65, 0x74, 0x2C, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x72, 0x75, 0x62, + 0x62, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x69, 0x73, 0x20, 0x68, + 0x61, 0x6E, 0x64, 0x73, 0x3B, 0x20, 0x27, 0x73, 0x6F, 0x20, + 0x6E, 0x6F, 0x77, 0x20, 0x6C, 0x65, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6A, 0x75, 0x72, 0x79, 0x2D, 0x2D, 0x27, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x66, 0x20, 0x61, 0x6E, 0x79, + 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x65, 0x78, 0x70, + 0x6C, 0x61, 0x69, 0x6E, 0x20, 0x69, 0x74, 0x2C, 0x27, 0x20, + 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x28, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x67, 0x72, 0x6F, 0x77, 0x6E, 0x20, 0x73, 0x6F, 0x20, + 0x6C, 0x61, 0x72, 0x67, 0x65, 0x0D, 0x0A, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x66, + 0x65, 0x77, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x74, 0x65, 0x73, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x68, 0x65, 0x20, + 0x77, 0x61, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x61, 0x20, 0x62, + 0x69, 0x74, 0x20, 0x61, 0x66, 0x72, 0x61, 0x69, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x72, 0x75, + 0x70, 0x74, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x68, 0x69, 0x6D, + 0x2C, 0x29, 0x20, 0x27, 0x49, 0x27, 0x6C, 0x6C, 0x20, 0x67, + 0x69, 0x76, 0x65, 0x20, 0x68, 0x69, 0x6D, 0x20, 0x73, 0x69, + 0x78, 0x70, 0x65, 0x6E, 0x63, 0x65, 0x2E, 0x20, 0x5F, 0x49, + 0x5F, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, 0x20, 0x62, 0x65, + 0x6C, 0x69, 0x65, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x27, 0x73, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x74, 0x6F, + 0x6D, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x6D, 0x65, 0x61, 0x6E, + 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x69, 0x74, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x6A, + 0x75, 0x72, 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x77, 0x72, + 0x6F, 0x74, 0x65, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x6F, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x73, 0x6C, + 0x61, 0x74, 0x65, 0x73, 0x2C, 0x20, 0x27, 0x53, 0x48, 0x45, + 0x20, 0x64, 0x6F, 0x65, 0x73, 0x6E, 0x27, 0x74, 0x20, 0x62, + 0x65, 0x6C, 0x69, 0x65, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x27, 0x73, 0x20, 0x61, 0x6E, 0x0D, 0x0A, 0x61, + 0x74, 0x6F, 0x6D, 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x65, 0x61, + 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, 0x69, 0x74, + 0x2C, 0x27, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6E, 0x6F, 0x6E, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, + 0x61, 0x74, 0x74, 0x65, 0x6D, 0x70, 0x74, 0x65, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x65, 0x78, 0x70, 0x6C, 0x61, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x70, 0x65, 0x72, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x27, 0x73, 0x20, 0x6E, 0x6F, 0x20, + 0x6D, 0x65, 0x61, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, + 0x20, 0x69, 0x74, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, + 0x20, 0x27, 0x74, 0x68, 0x61, 0x74, 0x20, 0x73, 0x61, 0x76, + 0x65, 0x73, 0x20, 0x61, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, + 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x74, 0x72, 0x6F, 0x75, 0x62, + 0x6C, 0x65, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, + 0x6F, 0x77, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x20, + 0x6E, 0x65, 0x65, 0x64, 0x6E, 0x27, 0x74, 0x20, 0x74, 0x72, + 0x79, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x6E, 0x64, 0x20, + 0x61, 0x6E, 0x79, 0x2E, 0x20, 0x41, 0x6E, 0x64, 0x20, 0x79, + 0x65, 0x74, 0x20, 0x49, 0x20, 0x64, 0x6F, 0x6E, 0x27, 0x74, + 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x2C, 0x27, 0x0D, 0x0A, 0x68, + 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x2C, + 0x20, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, + 0x65, 0x72, 0x73, 0x65, 0x73, 0x20, 0x6F, 0x6E, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x6B, 0x6E, 0x65, 0x65, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x0D, 0x0A, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x65, + 0x79, 0x65, 0x3B, 0x20, 0x27, 0x49, 0x20, 0x73, 0x65, 0x65, + 0x6D, 0x20, 0x74, 0x6F, 0x20, 0x73, 0x65, 0x65, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x69, 0x6E, + 0x67, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x2C, + 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x61, 0x6C, 0x6C, + 0x2E, 0x20, 0x22, 0x2D, 0x2D, 0x53, 0x41, 0x49, 0x44, 0x0D, + 0x0A, 0x49, 0x20, 0x43, 0x4F, 0x55, 0x4C, 0x44, 0x20, 0x4E, + 0x4F, 0x54, 0x20, 0x53, 0x57, 0x49, 0x4D, 0x2D, 0x2D, 0x22, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, 0x27, 0x74, + 0x20, 0x73, 0x77, 0x69, 0x6D, 0x2C, 0x20, 0x63, 0x61, 0x6E, + 0x20, 0x79, 0x6F, 0x75, 0x3F, 0x27, 0x20, 0x68, 0x65, 0x20, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x2C, 0x20, 0x74, 0x75, 0x72, + 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x4B, 0x6E, 0x61, 0x76, 0x65, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x4B, 0x6E, 0x61, + 0x76, 0x65, 0x20, 0x73, 0x68, 0x6F, 0x6F, 0x6B, 0x20, 0x68, + 0x69, 0x73, 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x73, 0x61, + 0x64, 0x6C, 0x79, 0x2E, 0x20, 0x27, 0x44, 0x6F, 0x20, 0x49, + 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x6C, 0x69, 0x6B, 0x65, + 0x20, 0x69, 0x74, 0x3F, 0x27, 0x20, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x2E, 0x20, 0x28, 0x57, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x68, 0x65, 0x0D, 0x0A, 0x63, 0x65, 0x72, 0x74, + 0x61, 0x69, 0x6E, 0x6C, 0x79, 0x20, 0x64, 0x69, 0x64, 0x20, + 0x4E, 0x4F, 0x54, 0x2C, 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, + 0x20, 0x6D, 0x61, 0x64, 0x65, 0x20, 0x65, 0x6E, 0x74, 0x69, + 0x72, 0x65, 0x6C, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x61, + 0x72, 0x64, 0x62, 0x6F, 0x61, 0x72, 0x64, 0x2E, 0x29, 0x0D, + 0x0A, 0x0D, 0x0A, 0x27, 0x41, 0x6C, 0x6C, 0x20, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x66, 0x61, + 0x72, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x68, 0x65, 0x20, 0x77, 0x65, 0x6E, 0x74, + 0x20, 0x6F, 0x6E, 0x20, 0x6D, 0x75, 0x74, 0x74, 0x65, 0x72, + 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, 0x65, 0x73, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x69, 0x6D, 0x73, 0x65, 0x6C, + 0x66, 0x3A, 0x20, 0x27, 0x22, 0x57, 0x45, 0x20, 0x4B, 0x4E, + 0x4F, 0x57, 0x20, 0x49, 0x54, 0x20, 0x54, 0x4F, 0x20, 0x42, + 0x45, 0x20, 0x54, 0x52, 0x55, 0x45, 0x2D, 0x2D, 0x22, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x27, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6A, 0x75, 0x72, 0x79, 0x2C, 0x20, 0x6F, 0x66, 0x0D, + 0x0A, 0x63, 0x6F, 0x75, 0x72, 0x73, 0x65, 0x2D, 0x2D, 0x22, + 0x49, 0x20, 0x47, 0x41, 0x56, 0x45, 0x20, 0x48, 0x45, 0x52, + 0x20, 0x4F, 0x4E, 0x45, 0x2C, 0x20, 0x54, 0x48, 0x45, 0x59, + 0x20, 0x47, 0x41, 0x56, 0x45, 0x20, 0x48, 0x49, 0x4D, 0x20, + 0x54, 0x57, 0x4F, 0x2D, 0x2D, 0x22, 0x20, 0x77, 0x68, 0x79, + 0x2C, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6D, 0x75, 0x73, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, + 0x68, 0x65, 0x0D, 0x0A, 0x64, 0x69, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x72, + 0x74, 0x73, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6B, 0x6E, + 0x6F, 0x77, 0x2D, 0x2D, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x42, 0x75, 0x74, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x67, 0x6F, + 0x65, 0x73, 0x20, 0x6F, 0x6E, 0x20, 0x22, 0x54, 0x48, 0x45, + 0x59, 0x20, 0x41, 0x4C, 0x4C, 0x20, 0x52, 0x45, 0x54, 0x55, + 0x52, 0x4E, 0x45, 0x44, 0x20, 0x46, 0x52, 0x4F, 0x4D, 0x20, + 0x48, 0x49, 0x4D, 0x20, 0x54, 0x4F, 0x20, 0x59, 0x4F, 0x55, + 0x2C, 0x22, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, + 0x57, 0x68, 0x79, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x61, 0x72, 0x65, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x72, 0x69, 0x75, + 0x6D, 0x70, 0x68, 0x61, 0x6E, 0x74, 0x6C, 0x79, 0x2C, 0x20, + 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x61, 0x72, 0x74, + 0x73, 0x0D, 0x0A, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x61, 0x62, 0x6C, 0x65, 0x2E, 0x20, 0x27, 0x4E, 0x6F, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x61, 0x6E, 0x20, + 0x62, 0x65, 0x20, 0x63, 0x6C, 0x65, 0x61, 0x72, 0x65, 0x72, + 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x54, 0x48, 0x41, 0x54, + 0x2E, 0x20, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x2D, 0x2D, 0x22, 0x42, 0x45, 0x46, 0x4F, 0x52, + 0x45, 0x20, 0x53, 0x48, 0x45, 0x0D, 0x0A, 0x48, 0x41, 0x44, + 0x20, 0x54, 0x48, 0x49, 0x53, 0x20, 0x46, 0x49, 0x54, 0x2D, + 0x2D, 0x22, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6E, 0x65, 0x76, + 0x65, 0x72, 0x20, 0x68, 0x61, 0x64, 0x20, 0x66, 0x69, 0x74, + 0x73, 0x2C, 0x20, 0x6D, 0x79, 0x20, 0x64, 0x65, 0x61, 0x72, + 0x2C, 0x20, 0x49, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, 0x3F, + 0x27, 0x20, 0x68, 0x65, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x51, 0x75, + 0x65, 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, + 0x65, 0x76, 0x65, 0x72, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, 0x65, + 0x6E, 0x20, 0x66, 0x75, 0x72, 0x69, 0x6F, 0x75, 0x73, 0x6C, + 0x79, 0x2C, 0x20, 0x74, 0x68, 0x72, 0x6F, 0x77, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x6B, 0x73, 0x74, + 0x61, 0x6E, 0x64, 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4C, 0x69, 0x7A, 0x61, 0x72, 0x64, 0x0D, 0x0A, 0x61, + 0x73, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, 0x70, 0x6F, 0x6B, + 0x65, 0x2E, 0x20, 0x28, 0x54, 0x68, 0x65, 0x20, 0x75, 0x6E, + 0x66, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x61, 0x74, 0x65, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x42, 0x69, 0x6C, + 0x6C, 0x20, 0x68, 0x61, 0x64, 0x20, 0x6C, 0x65, 0x66, 0x74, + 0x20, 0x6F, 0x66, 0x66, 0x20, 0x77, 0x72, 0x69, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x68, 0x69, 0x73, 0x0D, + 0x0A, 0x73, 0x6C, 0x61, 0x74, 0x65, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x66, 0x69, 0x6E, 0x67, + 0x65, 0x72, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x68, 0x65, 0x20, + 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x20, 0x6D, + 0x61, 0x64, 0x65, 0x20, 0x6E, 0x6F, 0x20, 0x6D, 0x61, 0x72, + 0x6B, 0x3B, 0x20, 0x62, 0x75, 0x74, 0x20, 0x68, 0x65, 0x20, + 0x6E, 0x6F, 0x77, 0x20, 0x68, 0x61, 0x73, 0x74, 0x69, 0x6C, + 0x79, 0x0D, 0x0A, 0x62, 0x65, 0x67, 0x61, 0x6E, 0x20, 0x61, + 0x67, 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x75, 0x73, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6E, 0x6B, 0x2C, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, + 0x74, 0x72, 0x69, 0x63, 0x6B, 0x6C, 0x69, 0x6E, 0x67, 0x20, + 0x64, 0x6F, 0x77, 0x6E, 0x20, 0x68, 0x69, 0x73, 0x20, 0x66, + 0x61, 0x63, 0x65, 0x2C, 0x20, 0x61, 0x73, 0x20, 0x6C, 0x6F, + 0x6E, 0x67, 0x20, 0x61, 0x73, 0x0D, 0x0A, 0x69, 0x74, 0x20, + 0x6C, 0x61, 0x73, 0x74, 0x65, 0x64, 0x2E, 0x29, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x54, 0x68, 0x65, 0x6E, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x77, 0x6F, 0x72, 0x64, 0x73, 0x20, 0x64, 0x6F, + 0x6E, 0x27, 0x74, 0x20, 0x46, 0x49, 0x54, 0x20, 0x79, 0x6F, + 0x75, 0x2C, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x6C, + 0x6F, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x72, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, + 0x72, 0x74, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, + 0x20, 0x73, 0x6D, 0x69, 0x6C, 0x65, 0x2E, 0x20, 0x54, 0x68, + 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x61, 0x20, + 0x64, 0x65, 0x61, 0x64, 0x20, 0x73, 0x69, 0x6C, 0x65, 0x6E, + 0x63, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x74, + 0x27, 0x73, 0x20, 0x61, 0x20, 0x70, 0x75, 0x6E, 0x21, 0x27, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x6E, 0x20, 0x6F, 0x66, 0x66, 0x65, 0x6E, 0x64, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x65, 0x76, 0x65, 0x72, 0x79, 0x62, 0x6F, 0x64, 0x79, + 0x20, 0x6C, 0x61, 0x75, 0x67, 0x68, 0x65, 0x64, 0x2C, 0x0D, + 0x0A, 0x27, 0x4C, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6A, 0x75, 0x72, 0x79, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x69, + 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, + 0x76, 0x65, 0x72, 0x64, 0x69, 0x63, 0x74, 0x2C, 0x27, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x4B, 0x69, 0x6E, 0x67, 0x20, 0x73, + 0x61, 0x69, 0x64, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, + 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x74, 0x77, 0x65, 0x6E, 0x74, 0x69, 0x65, 0x74, 0x68, 0x20, + 0x74, 0x69, 0x6D, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x64, 0x61, 0x79, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4E, + 0x6F, 0x2C, 0x20, 0x6E, 0x6F, 0x21, 0x27, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, + 0x65, 0x6E, 0x2E, 0x20, 0x27, 0x53, 0x65, 0x6E, 0x74, 0x65, + 0x6E, 0x63, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2D, + 0x2D, 0x76, 0x65, 0x72, 0x64, 0x69, 0x63, 0x74, 0x20, 0x61, + 0x66, 0x74, 0x65, 0x72, 0x77, 0x61, 0x72, 0x64, 0x73, 0x2E, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x53, 0x74, 0x75, 0x66, + 0x66, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6E, 0x6F, 0x6E, 0x73, + 0x65, 0x6E, 0x73, 0x65, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x6C, 0x6F, + 0x75, 0x64, 0x6C, 0x79, 0x2E, 0x20, 0x27, 0x54, 0x68, 0x65, + 0x20, 0x69, 0x64, 0x65, 0x61, 0x20, 0x6F, 0x66, 0x20, 0x68, + 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x73, 0x65, 0x6E, 0x74, 0x65, 0x6E, 0x63, 0x65, 0x20, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x21, 0x27, 0x0D, 0x0A, 0x0D, + 0x0A, 0x27, 0x48, 0x6F, 0x6C, 0x64, 0x20, 0x79, 0x6F, 0x75, + 0x72, 0x20, 0x74, 0x6F, 0x6E, 0x67, 0x75, 0x65, 0x21, 0x27, + 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x2C, 0x20, 0x74, 0x75, 0x72, + 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x70, 0x75, 0x72, 0x70, 0x6C, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x49, 0x20, 0x77, + 0x6F, 0x6E, 0x27, 0x74, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x27, 0x4F, 0x66, 0x66, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x65, 0x61, 0x64, + 0x21, 0x27, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, 0x75, 0x65, + 0x65, 0x6E, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x74, 0x65, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6F, + 0x70, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, 0x20, 0x76, + 0x6F, 0x69, 0x63, 0x65, 0x2E, 0x20, 0x4E, 0x6F, 0x62, 0x6F, + 0x64, 0x79, 0x0D, 0x0A, 0x6D, 0x6F, 0x76, 0x65, 0x64, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x68, 0x6F, 0x20, 0x63, + 0x61, 0x72, 0x65, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x79, + 0x6F, 0x75, 0x3F, 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x2C, 0x20, 0x28, 0x73, 0x68, + 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x67, 0x72, 0x6F, 0x77, + 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, + 0x75, 0x6C, 0x6C, 0x20, 0x73, 0x69, 0x7A, 0x65, 0x20, 0x62, + 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x74, 0x69, + 0x6D, 0x65, 0x2E, 0x29, 0x20, 0x27, 0x59, 0x6F, 0x75, 0x27, + 0x72, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x61, 0x20, 0x70, 0x61, 0x63, + 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x61, 0x72, 0x64, 0x73, + 0x21, 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x41, 0x74, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x68, + 0x6F, 0x6C, 0x65, 0x20, 0x70, 0x61, 0x63, 0x6B, 0x20, 0x72, + 0x6F, 0x73, 0x65, 0x20, 0x75, 0x70, 0x20, 0x69, 0x6E, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x69, 0x72, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x61, 0x6D, 0x65, 0x20, + 0x66, 0x6C, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x64, 0x6F, 0x77, + 0x6E, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x0D, 0x0A, 0x68, 0x65, + 0x72, 0x3A, 0x20, 0x73, 0x68, 0x65, 0x20, 0x67, 0x61, 0x76, + 0x65, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x73, 0x63, 0x72, 0x65, 0x61, 0x6D, 0x2C, 0x20, 0x68, + 0x61, 0x6C, 0x66, 0x20, 0x6F, 0x66, 0x20, 0x66, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, + 0x6C, 0x66, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x67, 0x65, + 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x74, 0x72, + 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x6F, 0x66, 0x66, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x75, 0x6E, + 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, + 0x6C, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x62, 0x61, 0x6E, 0x6B, 0x2C, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, 0x68, + 0x65, 0x61, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6C, 0x61, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x73, 0x69, 0x73, 0x74, 0x65, 0x72, 0x2C, 0x20, + 0x77, 0x68, 0x6F, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, 0x65, + 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x62, 0x72, 0x75, 0x73, 0x68, + 0x69, 0x6E, 0x67, 0x20, 0x61, 0x77, 0x61, 0x79, 0x20, 0x73, + 0x6F, 0x6D, 0x65, 0x20, 0x64, 0x65, 0x61, 0x64, 0x0D, 0x0A, + 0x6C, 0x65, 0x61, 0x76, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, 0x66, 0x6C, 0x75, 0x74, + 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x64, 0x6F, 0x77, 0x6E, + 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x72, 0x65, 0x65, 0x73, 0x20, 0x75, 0x70, 0x6F, 0x6E, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x61, 0x63, 0x65, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x57, 0x61, 0x6B, 0x65, 0x20, + 0x75, 0x70, 0x2C, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, + 0x64, 0x65, 0x61, 0x72, 0x21, 0x27, 0x20, 0x73, 0x61, 0x69, + 0x64, 0x20, 0x68, 0x65, 0x72, 0x20, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x3B, 0x20, 0x27, 0x57, 0x68, 0x79, 0x2C, 0x20, + 0x77, 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x6E, + 0x67, 0x20, 0x73, 0x6C, 0x65, 0x65, 0x70, 0x20, 0x79, 0x6F, + 0x75, 0x27, 0x76, 0x65, 0x0D, 0x0A, 0x68, 0x61, 0x64, 0x21, + 0x27, 0x0D, 0x0A, 0x0D, 0x0A, 0x27, 0x4F, 0x68, 0x2C, 0x20, + 0x49, 0x27, 0x76, 0x65, 0x20, 0x68, 0x61, 0x64, 0x20, 0x73, + 0x75, 0x63, 0x68, 0x20, 0x61, 0x20, 0x63, 0x75, 0x72, 0x69, + 0x6F, 0x75, 0x73, 0x20, 0x64, 0x72, 0x65, 0x61, 0x6D, 0x21, + 0x27, 0x20, 0x73, 0x61, 0x69, 0x64, 0x20, 0x41, 0x6C, 0x69, + 0x63, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x74, 0x6F, 0x6C, 0x64, 0x20, 0x68, 0x65, 0x72, + 0x0D, 0x0A, 0x73, 0x69, 0x73, 0x74, 0x65, 0x72, 0x2C, 0x20, + 0x61, 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x6D, 0x2C, 0x20, 0x61, 0x6C, 0x6C, 0x20, + 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x73, 0x74, 0x72, 0x61, + 0x6E, 0x67, 0x65, 0x20, 0x41, 0x64, 0x76, 0x65, 0x6E, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x68, + 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6A, 0x75, + 0x73, 0x74, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x62, 0x6F, 0x75, + 0x74, 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x65, + 0x6E, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, 0x0D, + 0x0A, 0x66, 0x69, 0x6E, 0x69, 0x73, 0x68, 0x65, 0x64, 0x2C, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x73, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x20, 0x6B, 0x69, 0x73, 0x73, 0x65, 0x64, 0x20, 0x68, + 0x65, 0x72, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x61, + 0x69, 0x64, 0x2C, 0x20, 0x27, 0x49, 0x74, 0x20, 0x57, 0x41, + 0x53, 0x20, 0x61, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6F, 0x75, + 0x73, 0x20, 0x64, 0x72, 0x65, 0x61, 0x6D, 0x2C, 0x0D, 0x0A, + 0x64, 0x65, 0x61, 0x72, 0x2C, 0x20, 0x63, 0x65, 0x72, 0x74, + 0x61, 0x69, 0x6E, 0x6C, 0x79, 0x3A, 0x20, 0x62, 0x75, 0x74, + 0x20, 0x6E, 0x6F, 0x77, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, + 0x74, 0x65, 0x61, 0x3B, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, + 0x67, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6C, 0x61, + 0x74, 0x65, 0x2E, 0x27, 0x20, 0x53, 0x6F, 0x0D, 0x0A, 0x41, + 0x6C, 0x69, 0x63, 0x65, 0x20, 0x67, 0x6F, 0x74, 0x20, 0x75, + 0x70, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x61, 0x6E, 0x20, + 0x6F, 0x66, 0x66, 0x2C, 0x20, 0x74, 0x68, 0x69, 0x6E, 0x6B, + 0x69, 0x6E, 0x67, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x72, 0x61, 0x6E, 0x2C, 0x20, 0x61, + 0x73, 0x20, 0x77, 0x65, 0x6C, 0x6C, 0x20, 0x73, 0x68, 0x65, + 0x20, 0x6D, 0x69, 0x67, 0x68, 0x74, 0x2C, 0x0D, 0x0A, 0x77, + 0x68, 0x61, 0x74, 0x20, 0x61, 0x20, 0x77, 0x6F, 0x6E, 0x64, + 0x65, 0x72, 0x66, 0x75, 0x6C, 0x20, 0x64, 0x72, 0x65, 0x61, + 0x6D, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, 0x64, 0x20, 0x62, + 0x65, 0x65, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x42, 0x75, + 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x20, 0x73, 0x61, 0x74, 0x20, 0x73, 0x74, 0x69, + 0x6C, 0x6C, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x20, 0x61, 0x73, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, + 0x68, 0x65, 0x72, 0x2C, 0x20, 0x6C, 0x65, 0x61, 0x6E, 0x69, + 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x0D, 0x0A, + 0x68, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x77, 0x61, 0x74, 0x63, + 0x68, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x75, 0x6E, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, 0x6E, + 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, 0x6C, 0x69, + 0x74, 0x74, 0x6C, 0x65, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x68, + 0x65, 0x72, 0x0D, 0x0A, 0x77, 0x6F, 0x6E, 0x64, 0x65, 0x72, + 0x66, 0x75, 0x6C, 0x20, 0x41, 0x64, 0x76, 0x65, 0x6E, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x2C, 0x20, 0x74, 0x69, 0x6C, 0x6C, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x6F, 0x20, 0x62, + 0x65, 0x67, 0x61, 0x6E, 0x20, 0x64, 0x72, 0x65, 0x61, 0x6D, + 0x69, 0x6E, 0x67, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, + 0x61, 0x20, 0x66, 0x61, 0x73, 0x68, 0x69, 0x6F, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x68, 0x65, 0x72, 0x20, 0x64, + 0x72, 0x65, 0x61, 0x6D, 0x3A, 0x2D, 0x2D, 0x0D, 0x0A, 0x0D, + 0x0A, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2C, 0x20, 0x73, 0x68, + 0x65, 0x20, 0x64, 0x72, 0x65, 0x61, 0x6D, 0x65, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, + 0x41, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x68, 0x65, 0x72, 0x73, + 0x65, 0x6C, 0x66, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6F, + 0x6E, 0x63, 0x65, 0x20, 0x61, 0x67, 0x61, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6E, 0x79, 0x0D, 0x0A, + 0x68, 0x61, 0x6E, 0x64, 0x73, 0x20, 0x77, 0x65, 0x72, 0x65, + 0x20, 0x63, 0x6C, 0x61, 0x73, 0x70, 0x65, 0x64, 0x20, 0x75, + 0x70, 0x6F, 0x6E, 0x20, 0x68, 0x65, 0x72, 0x20, 0x6B, 0x6E, + 0x65, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x65, + 0x61, 0x67, 0x65, 0x72, 0x20, 0x65, 0x79, 0x65, 0x73, 0x20, + 0x77, 0x65, 0x72, 0x65, 0x20, 0x6C, 0x6F, 0x6F, 0x6B, 0x69, + 0x6E, 0x67, 0x0D, 0x0A, 0x75, 0x70, 0x20, 0x69, 0x6E, 0x74, + 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x2D, 0x2D, 0x73, 0x68, + 0x65, 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x68, 0x65, + 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x74, 0x6F, 0x6E, 0x65, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x68, 0x65, 0x72, 0x20, 0x76, 0x6F, 0x69, 0x63, 0x65, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x65, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x0D, 0x0A, 0x71, 0x75, 0x65, 0x65, + 0x72, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x74, + 0x6F, 0x73, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, + 0x20, 0x68, 0x65, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6B, + 0x65, 0x65, 0x70, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x61, 0x6E, 0x64, 0x65, 0x72, 0x69, + 0x6E, 0x67, 0x20, 0x68, 0x61, 0x69, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x0D, 0x0A, 0x57, 0x4F, 0x55, 0x4C, 0x44, 0x20, + 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x20, 0x67, 0x65, 0x74, + 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x65, 0x79, 0x65, 0x73, 0x2D, 0x2D, 0x61, 0x6E, 0x64, 0x20, + 0x73, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x61, 0x73, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x65, 0x6E, 0x65, + 0x64, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x73, 0x65, 0x65, 0x6D, + 0x65, 0x64, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x6C, 0x69, 0x73, + 0x74, 0x65, 0x6E, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x68, 0x6F, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x61, 0x63, 0x65, + 0x20, 0x61, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x68, 0x65, + 0x72, 0x20, 0x62, 0x65, 0x63, 0x61, 0x6D, 0x65, 0x20, 0x61, + 0x6C, 0x69, 0x76, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x72, 0x61, 0x6E, 0x67, + 0x65, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, 0x20, + 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x73, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x27, 0x73, 0x20, 0x64, 0x72, 0x65, 0x61, + 0x6D, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x67, 0x72, 0x61, 0x73, 0x73, + 0x20, 0x72, 0x75, 0x73, 0x74, 0x6C, 0x65, 0x64, 0x20, 0x61, + 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x66, 0x65, 0x65, 0x74, + 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x57, 0x68, + 0x69, 0x74, 0x65, 0x20, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, + 0x20, 0x68, 0x75, 0x72, 0x72, 0x69, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x2D, 0x2D, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x66, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x65, 0x6E, 0x65, 0x64, 0x20, 0x4D, + 0x6F, 0x75, 0x73, 0x65, 0x20, 0x73, 0x70, 0x6C, 0x61, 0x73, + 0x68, 0x65, 0x64, 0x20, 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, + 0x79, 0x20, 0x74, 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x69, 0x67, 0x68, 0x62, + 0x6F, 0x75, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x70, 0x6F, 0x6F, + 0x6C, 0x2D, 0x2D, 0x73, 0x68, 0x65, 0x0D, 0x0A, 0x63, 0x6F, + 0x75, 0x6C, 0x64, 0x20, 0x68, 0x65, 0x61, 0x72, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x72, 0x61, 0x74, 0x74, 0x6C, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x61, + 0x63, 0x75, 0x70, 0x73, 0x20, 0x61, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x4D, 0x61, 0x72, 0x63, 0x68, 0x20, 0x48, 0x61, + 0x72, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x69, 0x73, + 0x20, 0x66, 0x72, 0x69, 0x65, 0x6E, 0x64, 0x73, 0x0D, 0x0A, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x2D, 0x65, + 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6D, 0x65, 0x61, 0x6C, + 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x68, 0x72, 0x69, 0x6C, 0x6C, 0x20, 0x76, 0x6F, 0x69, + 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x51, 0x75, 0x65, 0x65, 0x6E, 0x0D, 0x0A, 0x6F, 0x72, 0x64, + 0x65, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x66, 0x20, + 0x68, 0x65, 0x72, 0x20, 0x75, 0x6E, 0x66, 0x6F, 0x72, 0x74, + 0x75, 0x6E, 0x61, 0x74, 0x65, 0x20, 0x67, 0x75, 0x65, 0x73, + 0x74, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x2D, 0x2D, 0x6F, 0x6E, 0x63, + 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x69, 0x67, 0x2D, 0x62, 0x61, 0x62, 0x79, 0x0D, + 0x0A, 0x77, 0x61, 0x73, 0x20, 0x73, 0x6E, 0x65, 0x65, 0x7A, + 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x44, 0x75, 0x63, 0x68, 0x65, 0x73, 0x73, 0x27, 0x73, + 0x20, 0x6B, 0x6E, 0x65, 0x65, 0x2C, 0x20, 0x77, 0x68, 0x69, + 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x61, 0x74, 0x65, 0x73, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x64, 0x69, 0x73, 0x68, 0x65, 0x73, + 0x20, 0x63, 0x72, 0x61, 0x73, 0x68, 0x65, 0x64, 0x0D, 0x0A, + 0x61, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x74, 0x2D, + 0x2D, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x6D, 0x6F, 0x72, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x68, 0x72, 0x69, 0x65, + 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, + 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2C, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x71, 0x75, 0x65, 0x61, 0x6B, 0x69, 0x6E, + 0x67, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, + 0x4C, 0x69, 0x7A, 0x61, 0x72, 0x64, 0x27, 0x73, 0x20, 0x73, + 0x6C, 0x61, 0x74, 0x65, 0x2D, 0x70, 0x65, 0x6E, 0x63, 0x69, + 0x6C, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x68, 0x6F, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x70, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x67, 0x75, 0x69, + 0x6E, 0x65, 0x61, 0x2D, 0x70, 0x69, 0x67, 0x73, 0x2C, 0x0D, + 0x0A, 0x66, 0x69, 0x6C, 0x6C, 0x65, 0x64, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x61, 0x69, 0x72, 0x2C, 0x20, 0x6D, 0x69, 0x78, + 0x65, 0x64, 0x20, 0x75, 0x70, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, + 0x6E, 0x74, 0x20, 0x73, 0x6F, 0x62, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x69, 0x73, 0x65, 0x72, + 0x61, 0x62, 0x6C, 0x65, 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x0D, + 0x0A, 0x54, 0x75, 0x72, 0x74, 0x6C, 0x65, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x53, 0x6F, 0x20, 0x73, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x74, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x64, 0x20, 0x65, + 0x79, 0x65, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, + 0x61, 0x6C, 0x66, 0x20, 0x62, 0x65, 0x6C, 0x69, 0x65, 0x76, + 0x65, 0x64, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, + 0x20, 0x69, 0x6E, 0x0D, 0x0A, 0x57, 0x6F, 0x6E, 0x64, 0x65, + 0x72, 0x6C, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x74, 0x68, 0x6F, + 0x75, 0x67, 0x68, 0x20, 0x73, 0x68, 0x65, 0x20, 0x6B, 0x6E, + 0x65, 0x77, 0x20, 0x73, 0x68, 0x65, 0x20, 0x68, 0x61, 0x64, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x6F, 0x70, + 0x65, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x20, 0x61, 0x67, + 0x61, 0x69, 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x6C, 0x6C, 0x0D, 0x0A, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x64, 0x75, 0x6C, 0x6C, 0x20, 0x72, 0x65, 0x61, 0x6C, 0x69, + 0x74, 0x79, 0x2D, 0x2D, 0x74, 0x68, 0x65, 0x20, 0x67, 0x72, + 0x61, 0x73, 0x73, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x62, 0x65, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x72, 0x75, + 0x73, 0x74, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x77, 0x69, 0x6E, 0x64, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x6F, 0x6F, 0x6C, 0x20, 0x72, 0x69, 0x70, 0x70, 0x6C, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x61, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x65, 0x64, 0x73, 0x2D, + 0x2D, 0x74, 0x68, 0x65, 0x20, 0x72, 0x61, 0x74, 0x74, 0x6C, + 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x74, 0x65, 0x61, 0x63, 0x75, + 0x70, 0x73, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x63, + 0x68, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x69, 0x6E, 0x6B, 0x6C, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x68, + 0x65, 0x65, 0x70, 0x2D, 0x62, 0x65, 0x6C, 0x6C, 0x73, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x51, + 0x75, 0x65, 0x65, 0x6E, 0x27, 0x73, 0x20, 0x73, 0x68, 0x72, + 0x69, 0x6C, 0x6C, 0x0D, 0x0A, 0x63, 0x72, 0x69, 0x65, 0x73, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x76, 0x6F, + 0x69, 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x68, 0x65, 0x70, 0x68, 0x65, 0x72, 0x64, 0x20, + 0x62, 0x6F, 0x79, 0x2D, 0x2D, 0x61, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x6E, 0x65, 0x65, 0x7A, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x61, 0x62, + 0x79, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x73, 0x68, + 0x72, 0x69, 0x65, 0x6B, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x47, 0x72, 0x79, 0x70, 0x68, 0x6F, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x71, + 0x75, 0x65, 0x65, 0x72, 0x20, 0x6E, 0x6F, 0x69, 0x73, 0x65, + 0x73, 0x2C, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x63, + 0x68, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x28, 0x73, 0x68, 0x65, + 0x0D, 0x0A, 0x6B, 0x6E, 0x65, 0x77, 0x29, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x66, 0x75, + 0x73, 0x65, 0x64, 0x20, 0x63, 0x6C, 0x61, 0x6D, 0x6F, 0x75, + 0x72, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, + 0x75, 0x73, 0x79, 0x20, 0x66, 0x61, 0x72, 0x6D, 0x2D, 0x79, + 0x61, 0x72, 0x64, 0x2D, 0x2D, 0x77, 0x68, 0x69, 0x6C, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x6F, 0x77, 0x69, 0x6E, + 0x67, 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x61, 0x74, 0x74, 0x6C, 0x65, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6E, + 0x63, 0x65, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x74, + 0x61, 0x6B, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6C, + 0x61, 0x63, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x4D, 0x6F, 0x63, 0x6B, 0x20, 0x54, 0x75, 0x72, 0x74, + 0x6C, 0x65, 0x27, 0x73, 0x0D, 0x0A, 0x68, 0x65, 0x61, 0x76, + 0x79, 0x20, 0x73, 0x6F, 0x62, 0x73, 0x2E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x4C, 0x61, 0x73, 0x74, 0x6C, 0x79, 0x2C, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x72, 0x73, 0x65, + 0x6C, 0x66, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x6C, 0x69, 0x74, + 0x74, 0x6C, 0x65, 0x20, 0x73, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, 0x73, 0x0D, 0x0A, + 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x2C, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, 0x2D, + 0x74, 0x69, 0x6D, 0x65, 0x2C, 0x20, 0x62, 0x65, 0x20, 0x68, + 0x65, 0x72, 0x73, 0x65, 0x6C, 0x66, 0x20, 0x61, 0x20, 0x67, + 0x72, 0x6F, 0x77, 0x6E, 0x20, 0x77, 0x6F, 0x6D, 0x61, 0x6E, + 0x3B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x6F, 0x77, 0x20, + 0x73, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x0D, + 0x0A, 0x6B, 0x65, 0x65, 0x70, 0x2C, 0x20, 0x74, 0x68, 0x72, + 0x6F, 0x75, 0x67, 0x68, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x68, + 0x65, 0x72, 0x20, 0x72, 0x69, 0x70, 0x65, 0x72, 0x20, 0x79, + 0x65, 0x61, 0x72, 0x73, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x73, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6C, 0x6F, 0x76, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, + 0x61, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x68, 0x65, 0x72, + 0x0D, 0x0A, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x68, 0x6F, 0x6F, + 0x64, 0x3A, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x6F, 0x77, + 0x20, 0x73, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, + 0x20, 0x67, 0x61, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x62, + 0x6F, 0x75, 0x74, 0x20, 0x68, 0x65, 0x72, 0x20, 0x6F, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x6C, 0x69, 0x74, 0x74, 0x6C, 0x65, + 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x72, 0x65, 0x6E, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x6D, 0x61, 0x6B, 0x65, + 0x20, 0x54, 0x48, 0x45, 0x49, 0x52, 0x20, 0x65, 0x79, 0x65, + 0x73, 0x20, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x65, 0x61, 0x67, 0x65, 0x72, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x6D, 0x61, 0x6E, 0x79, 0x20, 0x61, + 0x20, 0x73, 0x74, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x74, + 0x61, 0x6C, 0x65, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x68, 0x61, + 0x70, 0x73, 0x20, 0x65, 0x76, 0x65, 0x6E, 0x0D, 0x0A, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x72, + 0x65, 0x61, 0x6D, 0x20, 0x6F, 0x66, 0x20, 0x57, 0x6F, 0x6E, + 0x64, 0x65, 0x72, 0x6C, 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x66, + 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x61, 0x67, 0x6F, 0x3A, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x73, + 0x68, 0x65, 0x20, 0x77, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x66, + 0x65, 0x65, 0x6C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, + 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, + 0x73, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x73, 0x6F, 0x72, + 0x72, 0x6F, 0x77, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x66, 0x69, 0x6E, 0x64, 0x20, 0x61, 0x20, 0x70, 0x6C, 0x65, + 0x61, 0x73, 0x75, 0x72, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x73, + 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x6A, 0x6F, 0x79, 0x73, + 0x2C, 0x0D, 0x0A, 0x72, 0x65, 0x6D, 0x65, 0x6D, 0x62, 0x65, + 0x72, 0x69, 0x6E, 0x67, 0x20, 0x68, 0x65, 0x72, 0x20, 0x6F, + 0x77, 0x6E, 0x20, 0x63, 0x68, 0x69, 0x6C, 0x64, 0x2D, 0x6C, + 0x69, 0x66, 0x65, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x68, 0x61, 0x70, 0x70, 0x79, 0x20, 0x73, + 0x75, 0x6D, 0x6D, 0x65, 0x72, 0x20, 0x64, 0x61, 0x79, 0x73, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, + 0x48, 0x45, 0x20, 0x45, 0x4E, 0x44, 0x0D, 0x0A, 0x0D, 0x0A, + 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x45, 0x6E, + 0x64, 0x20, 0x6F, 0x66, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x27, 0x73, 0x20, 0x41, 0x6C, 0x69, 0x63, 0x65, + 0x27, 0x73, 0x20, 0x41, 0x64, 0x76, 0x65, 0x6E, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x57, 0x6F, 0x6E, + 0x64, 0x65, 0x72, 0x6C, 0x61, 0x6E, 0x64, 0x2C, 0x20, 0x62, + 0x79, 0x20, 0x4C, 0x65, 0x77, 0x69, 0x73, 0x20, 0x43, 0x61, + 0x72, 0x72, 0x6F, 0x6C, 0x6C, 0x0D, 0x0A, 0x0D, 0x0A, 0x2A, + 0x2A, 0x2A, 0x20, 0x45, 0x4E, 0x44, 0x20, 0x4F, 0x46, 0x20, + 0x54, 0x48, 0x49, 0x53, 0x20, 0x50, 0x52, 0x4F, 0x4A, 0x45, + 0x43, 0x54, 0x20, 0x47, 0x55, 0x54, 0x45, 0x4E, 0x42, 0x45, + 0x52, 0x47, 0x20, 0x45, 0x42, 0x4F, 0x4F, 0x4B, 0x20, 0x41, + 0x4C, 0x49, 0x43, 0x45, 0x27, 0x53, 0x20, 0x41, 0x44, 0x56, + 0x45, 0x4E, 0x54, 0x55, 0x52, 0x45, 0x53, 0x20, 0x49, 0x4E, + 0x20, 0x57, 0x4F, 0x4E, 0x44, 0x45, 0x52, 0x4C, 0x41, 0x4E, + 0x44, 0x20, 0x2A, 0x2A, 0x2A, 0x0D, 0x0A, 0x0D, 0x0A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, + 0x66, 0x69, 0x6C, 0x65, 0x20, 0x73, 0x68, 0x6F, 0x75, 0x6C, + 0x64, 0x20, 0x62, 0x65, 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x64, + 0x20, 0x31, 0x31, 0x2E, 0x74, 0x78, 0x74, 0x20, 0x6F, 0x72, + 0x20, 0x31, 0x31, 0x2E, 0x7A, 0x69, 0x70, 0x20, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x0D, 0x0A, 0x54, 0x68, 0x69, 0x73, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x61, 0x73, + 0x73, 0x6F, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x66, + 0x69, 0x6C, 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x76, 0x61, + 0x72, 0x69, 0x6F, 0x75, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x6D, + 0x61, 0x74, 0x73, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x62, + 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x6E, + 0x3A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, + 0x77, 0x2E, 0x67, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2E, 0x6F, 0x72, 0x67, 0x2F, 0x31, 0x2F, 0x31, 0x31, + 0x2F, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x65, 0x64, 0x69, + 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x77, 0x69, 0x6C, 0x6C, + 0x20, 0x72, 0x65, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6F, 0x75, + 0x73, 0x20, 0x6F, 0x6E, 0x65, 0x2D, 0x2D, 0x74, 0x68, 0x65, + 0x20, 0x6F, 0x6C, 0x64, 0x20, 0x65, 0x64, 0x69, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x0D, 0x0A, 0x77, 0x69, 0x6C, 0x6C, 0x20, + 0x62, 0x65, 0x20, 0x72, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x64, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, + 0x72, 0x6B, 0x73, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x70, + 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x64, 0x6F, 0x6D, 0x61, + 0x69, 0x6E, 0x20, 0x70, 0x72, 0x69, 0x6E, 0x74, 0x20, 0x65, + 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x6D, 0x65, + 0x61, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6E, + 0x6F, 0x0D, 0x0A, 0x6F, 0x6E, 0x65, 0x20, 0x6F, 0x77, 0x6E, + 0x73, 0x20, 0x61, 0x20, 0x55, 0x6E, 0x69, 0x74, 0x65, 0x64, + 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x20, 0x63, 0x6F, + 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x73, 0x2C, 0x20, 0x73, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x0D, 0x0A, 0x28, 0x61, 0x6E, 0x64, 0x20, 0x79, 0x6F, + 0x75, 0x21, 0x29, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x63, 0x6F, + 0x70, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69, 0x74, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6E, + 0x69, 0x74, 0x65, 0x64, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x0D, + 0x0A, 0x70, 0x65, 0x72, 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6F, + 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x6F, 0x75, 0x74, 0x20, 0x70, 0x61, 0x79, 0x69, 0x6E, 0x67, + 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x72, 0x6F, 0x79, 0x61, 0x6C, 0x74, 0x69, 0x65, 0x73, + 0x2E, 0x20, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6C, + 0x20, 0x72, 0x75, 0x6C, 0x65, 0x73, 0x2C, 0x0D, 0x0A, 0x73, + 0x65, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x68, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x65, 0x6E, 0x65, + 0x72, 0x61, 0x6C, 0x20, 0x54, 0x65, 0x72, 0x6D, 0x73, 0x20, + 0x6F, 0x66, 0x20, 0x55, 0x73, 0x65, 0x20, 0x70, 0x61, 0x72, + 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x2C, 0x20, 0x61, + 0x70, 0x70, 0x6C, 0x79, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x63, + 0x6F, 0x70, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, + 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x73, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x70, 0x72, 0x6F, 0x74, + 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x52, + 0x4F, 0x4A, 0x45, 0x43, 0x54, 0x20, 0x47, 0x55, 0x54, 0x45, + 0x4E, 0x42, 0x45, 0x52, 0x47, 0x2D, 0x74, 0x6D, 0x20, 0x63, + 0x6F, 0x6E, 0x63, 0x65, 0x70, 0x74, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x74, 0x72, 0x61, 0x64, 0x65, 0x6D, 0x61, 0x72, 0x6B, + 0x2E, 0x20, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x74, 0x72, + 0x61, 0x64, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x2C, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x6E, 0x6F, 0x74, + 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, + 0x66, 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, 0x63, 0x68, 0x61, + 0x72, 0x67, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x65, 0x42, 0x6F, 0x6F, 0x6B, 0x73, 0x2C, 0x20, + 0x75, 0x6E, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x73, + 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x70, 0x65, + 0x72, 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x20, + 0x20, 0x49, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, 0x64, + 0x6F, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x63, 0x68, 0x61, 0x72, + 0x67, 0x65, 0x20, 0x61, 0x6E, 0x79, 0x74, 0x68, 0x69, 0x6E, + 0x67, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x63, 0x6F, 0x70, 0x69, + 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x65, 0x42, 0x6F, 0x6F, 0x6B, 0x2C, 0x20, 0x63, 0x6F, + 0x6D, 0x70, 0x6C, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x72, 0x75, + 0x6C, 0x65, 0x73, 0x20, 0x69, 0x73, 0x20, 0x76, 0x65, 0x72, + 0x79, 0x20, 0x65, 0x61, 0x73, 0x79, 0x2E, 0x20, 0x20, 0x59, + 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x75, 0x73, 0x65, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x42, 0x6F, 0x6F, + 0x6B, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6E, 0x65, 0x61, 0x72, + 0x6C, 0x79, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x70, 0x75, 0x72, + 0x70, 0x6F, 0x73, 0x65, 0x0D, 0x0A, 0x73, 0x75, 0x63, 0x68, + 0x20, 0x61, 0x73, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x64, 0x65, 0x72, 0x69, + 0x76, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x73, 0x2C, 0x20, 0x72, 0x65, 0x70, 0x6F, 0x72, 0x74, + 0x73, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6F, 0x72, 0x6D, + 0x61, 0x6E, 0x63, 0x65, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x0D, + 0x0A, 0x72, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2E, + 0x20, 0x20, 0x54, 0x68, 0x65, 0x79, 0x20, 0x6D, 0x61, 0x79, + 0x20, 0x62, 0x65, 0x20, 0x6D, 0x6F, 0x64, 0x69, 0x66, 0x69, + 0x65, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x70, 0x72, 0x69, + 0x6E, 0x74, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x67, + 0x69, 0x76, 0x65, 0x6E, 0x20, 0x61, 0x77, 0x61, 0x79, 0x2D, + 0x2D, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x64, + 0x6F, 0x0D, 0x0A, 0x70, 0x72, 0x61, 0x63, 0x74, 0x69, 0x63, + 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x41, 0x4E, 0x59, 0x54, 0x48, + 0x49, 0x4E, 0x47, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x70, + 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x64, 0x6F, 0x6D, 0x61, + 0x69, 0x6E, 0x20, 0x65, 0x42, 0x6F, 0x6F, 0x6B, 0x73, 0x2E, + 0x20, 0x20, 0x52, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x0D, + 0x0A, 0x73, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x64, + 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x20, 0x6C, 0x69, 0x63, 0x65, + 0x6E, 0x73, 0x65, 0x2C, 0x20, 0x65, 0x73, 0x70, 0x65, 0x63, + 0x69, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x63, 0x6F, 0x6D, 0x6D, + 0x65, 0x72, 0x63, 0x69, 0x61, 0x6C, 0x0D, 0x0A, 0x72, 0x65, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x2A, 0x2A, 0x2A, 0x20, 0x53, 0x54, 0x41, 0x52, 0x54, + 0x3A, 0x20, 0x46, 0x55, 0x4C, 0x4C, 0x20, 0x4C, 0x49, 0x43, + 0x45, 0x4E, 0x53, 0x45, 0x20, 0x2A, 0x2A, 0x2A, 0x0D, 0x0A, + 0x0D, 0x0A, 0x54, 0x48, 0x45, 0x20, 0x46, 0x55, 0x4C, 0x4C, + 0x20, 0x50, 0x52, 0x4F, 0x4A, 0x45, 0x43, 0x54, 0x20, 0x47, + 0x55, 0x54, 0x45, 0x4E, 0x42, 0x45, 0x52, 0x47, 0x20, 0x4C, + 0x49, 0x43, 0x45, 0x4E, 0x53, 0x45, 0x0D, 0x0A, 0x50, 0x4C, + 0x45, 0x41, 0x53, 0x45, 0x20, 0x52, 0x45, 0x41, 0x44, 0x20, + 0x54, 0x48, 0x49, 0x53, 0x20, 0x42, 0x45, 0x46, 0x4F, 0x52, + 0x45, 0x20, 0x59, 0x4F, 0x55, 0x20, 0x44, 0x49, 0x53, 0x54, + 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x20, 0x4F, 0x52, 0x20, + 0x55, 0x53, 0x45, 0x20, 0x54, 0x48, 0x49, 0x53, 0x20, 0x57, + 0x4F, 0x52, 0x4B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x6F, 0x20, + 0x70, 0x72, 0x6F, 0x74, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, + 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, + 0x74, 0x6D, 0x20, 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6F, 0x6E, + 0x20, 0x6F, 0x66, 0x20, 0x70, 0x72, 0x6F, 0x6D, 0x6F, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x72, + 0x65, 0x65, 0x0D, 0x0A, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, + 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, + 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x2C, 0x20, 0x62, 0x79, + 0x20, 0x75, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x72, 0x20, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x6F, + 0x72, 0x6B, 0x0D, 0x0A, 0x28, 0x6F, 0x72, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x77, 0x6F, + 0x72, 0x6B, 0x20, 0x61, 0x73, 0x73, 0x6F, 0x63, 0x69, 0x61, + 0x74, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x79, + 0x20, 0x77, 0x61, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, + 0x20, 0x22, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x0D, + 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x22, 0x29, 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x61, 0x67, + 0x72, 0x65, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6F, 0x6D, + 0x70, 0x6C, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, + 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x46, 0x75, 0x6C, 0x6C, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x4C, 0x69, 0x63, + 0x65, 0x6E, 0x73, 0x65, 0x20, 0x28, 0x61, 0x76, 0x61, 0x69, + 0x6C, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6C, 0x65, + 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x6E, 0x6C, 0x69, 0x6E, 0x65, + 0x20, 0x61, 0x74, 0x0D, 0x0A, 0x68, 0x74, 0x74, 0x70, 0x3A, + 0x2F, 0x2F, 0x67, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2E, 0x6F, 0x72, 0x67, 0x2F, 0x6C, 0x69, 0x63, 0x65, + 0x6E, 0x73, 0x65, 0x29, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x31, + 0x2E, 0x20, 0x20, 0x47, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, + 0x20, 0x54, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, + 0x55, 0x73, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x52, 0x65, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x2D, 0x74, 0x6D, 0x0D, 0x0A, 0x65, 0x6C, 0x65, 0x63, 0x74, + 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x73, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x41, 0x2E, 0x20, + 0x20, 0x42, 0x79, 0x20, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6E, + 0x67, 0x20, 0x6F, 0x72, 0x20, 0x75, 0x73, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x6E, 0x79, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x50, 0x72, + 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, + 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x0D, 0x0A, + 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, + 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x72, 0x65, 0x61, 0x64, 0x2C, 0x20, + 0x75, 0x6E, 0x64, 0x65, 0x72, 0x73, 0x74, 0x61, 0x6E, 0x64, + 0x2C, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x20, 0x74, 0x6F, + 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x61, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x69, 0x63, 0x65, 0x6E, + 0x73, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x74, + 0x65, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x75, 0x61, 0x6C, 0x20, + 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x79, 0x0D, 0x0A, + 0x28, 0x74, 0x72, 0x61, 0x64, 0x65, 0x6D, 0x61, 0x72, 0x6B, + 0x2F, 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x29, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, 0x65, 0x6E, + 0x74, 0x2E, 0x20, 0x20, 0x49, 0x66, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x64, 0x6F, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x67, + 0x72, 0x65, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x62, 0x69, + 0x64, 0x65, 0x20, 0x62, 0x79, 0x20, 0x61, 0x6C, 0x6C, 0x0D, + 0x0A, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6D, 0x73, + 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, + 0x67, 0x72, 0x65, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x2C, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x63, + 0x65, 0x61, 0x73, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6E, 0x67, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6E, 0x20, 0x6F, 0x72, 0x20, 0x64, 0x65, 0x73, 0x74, 0x72, + 0x6F, 0x79, 0x0D, 0x0A, 0x61, 0x6C, 0x6C, 0x20, 0x63, 0x6F, + 0x70, 0x69, 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x50, 0x72, + 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, + 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, + 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, + 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x79, + 0x6F, 0x75, 0x72, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x0D, 0x0A, 0x49, 0x66, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x70, 0x61, 0x69, 0x64, 0x20, 0x61, + 0x20, 0x66, 0x65, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x6F, + 0x62, 0x74, 0x61, 0x69, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x20, 0x63, 0x6F, 0x70, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x6F, + 0x72, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, + 0x6F, 0x20, 0x61, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, 0x65, 0x63, + 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x64, 0x6F, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x67, 0x72, + 0x65, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x62, + 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x74, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, + 0x65, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x6F, 0x62, 0x74, 0x61, + 0x69, 0x6E, 0x20, 0x61, 0x20, 0x72, 0x65, 0x66, 0x75, 0x6E, + 0x64, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x20, 0x6F, 0x72, + 0x0D, 0x0A, 0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x20, 0x74, + 0x6F, 0x20, 0x77, 0x68, 0x6F, 0x6D, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x70, 0x61, 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x66, 0x65, 0x65, 0x20, 0x61, 0x73, 0x20, 0x73, 0x65, 0x74, + 0x20, 0x66, 0x6F, 0x72, 0x74, 0x68, 0x20, 0x69, 0x6E, 0x20, + 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x20, + 0x31, 0x2E, 0x45, 0x2E, 0x38, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x31, 0x2E, 0x42, 0x2E, 0x20, 0x20, 0x22, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x22, 0x20, 0x69, 0x73, 0x20, 0x61, + 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, + 0x64, 0x20, 0x74, 0x72, 0x61, 0x64, 0x65, 0x6D, 0x61, 0x72, + 0x6B, 0x2E, 0x20, 0x20, 0x49, 0x74, 0x20, 0x6D, 0x61, 0x79, + 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x62, 0x65, 0x0D, 0x0A, + 0x75, 0x73, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, 0x6F, 0x72, + 0x20, 0x61, 0x73, 0x73, 0x6F, 0x63, 0x69, 0x61, 0x74, 0x65, + 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x77, + 0x61, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6E, + 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, + 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x62, 0x79, 0x20, + 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, 0x20, 0x77, 0x68, 0x6F, + 0x0D, 0x0A, 0x61, 0x67, 0x72, 0x65, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x62, 0x65, 0x20, 0x62, 0x6F, 0x75, 0x6E, 0x64, 0x20, + 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, + 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, 0x65, 0x6E, 0x74, + 0x2E, 0x20, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x61, 0x20, 0x66, 0x65, 0x77, 0x0D, 0x0A, + 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, 0x20, + 0x64, 0x6F, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6D, 0x6F, + 0x73, 0x74, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, + 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, + 0x0D, 0x0A, 0x65, 0x76, 0x65, 0x6E, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x6F, 0x75, 0x74, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x6C, + 0x79, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x20, 0x74, + 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, 0x65, + 0x6E, 0x74, 0x2E, 0x20, 0x20, 0x53, 0x65, 0x65, 0x0D, 0x0A, + 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x20, + 0x31, 0x2E, 0x43, 0x20, 0x62, 0x65, 0x6C, 0x6F, 0x77, 0x2E, + 0x20, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x74, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x64, 0x6F, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, 0x65, 0x63, + 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x73, 0x20, 0x69, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x66, 0x6F, 0x6C, 0x6C, 0x6F, 0x77, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, + 0x6D, 0x65, 0x6E, 0x74, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, + 0x68, 0x65, 0x6C, 0x70, 0x20, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x66, + 0x75, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, 0x65, + 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x0D, 0x0A, 0x77, + 0x6F, 0x72, 0x6B, 0x73, 0x2E, 0x20, 0x20, 0x53, 0x65, 0x65, + 0x20, 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x20, 0x31, 0x2E, 0x45, 0x20, 0x62, 0x65, 0x6C, 0x6F, 0x77, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x43, 0x2E, 0x20, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x20, 0x4C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, + 0x79, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, + 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x28, 0x22, 0x74, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x75, + 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x0D, 0x0A, + 0x6F, 0x72, 0x20, 0x50, 0x47, 0x4C, 0x41, 0x46, 0x29, 0x2C, + 0x20, 0x6F, 0x77, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6F, + 0x6D, 0x70, 0x69, 0x6C, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, + 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6C, + 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, + 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x0D, 0x0A, + 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, + 0x74, 0x6D, 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, + 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x2E, + 0x20, 0x20, 0x4E, 0x65, 0x61, 0x72, 0x6C, 0x79, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6E, 0x64, + 0x69, 0x76, 0x69, 0x64, 0x75, 0x61, 0x6C, 0x20, 0x77, 0x6F, + 0x72, 0x6B, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x0D, 0x0A, 0x63, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x61, 0x72, 0x65, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, + 0x20, 0x64, 0x6F, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6E, 0x69, 0x74, 0x65, + 0x64, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x2E, 0x20, + 0x20, 0x49, 0x66, 0x20, 0x61, 0x6E, 0x0D, 0x0A, 0x69, 0x6E, + 0x64, 0x69, 0x76, 0x69, 0x64, 0x75, 0x61, 0x6C, 0x20, 0x77, + 0x6F, 0x72, 0x6B, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6E, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, + 0x20, 0x64, 0x6F, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x69, 0x6E, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6E, 0x69, 0x74, 0x65, + 0x64, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x61, 0x72, 0x65, + 0x0D, 0x0A, 0x6C, 0x6F, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, + 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6E, 0x69, + 0x74, 0x65, 0x64, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, + 0x2C, 0x20, 0x77, 0x65, 0x20, 0x64, 0x6F, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x63, 0x6C, 0x61, 0x69, 0x6D, 0x20, 0x61, 0x20, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x70, + 0x72, 0x65, 0x76, 0x65, 0x6E, 0x74, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x0D, 0x0A, 0x63, 0x6F, 0x70, + 0x79, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x64, 0x69, 0x73, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x70, 0x65, 0x72, 0x66, 0x6F, 0x72, 0x6D, 0x69, 0x6E, 0x67, + 0x2C, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x69, + 0x6E, 0x67, 0x20, 0x6F, 0x72, 0x20, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x64, 0x65, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x69, 0x76, 0x65, 0x0D, 0x0A, 0x77, 0x6F, 0x72, + 0x6B, 0x73, 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6F, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x20, 0x61, 0x73, 0x20, 0x6C, 0x6F, 0x6E, 0x67, 0x20, 0x61, + 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6E, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6F, 0x20, + 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, + 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x0D, 0x0A, 0x61, + 0x72, 0x65, 0x20, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x64, + 0x2E, 0x20, 0x20, 0x4F, 0x66, 0x20, 0x63, 0x6F, 0x75, 0x72, + 0x73, 0x65, 0x2C, 0x20, 0x77, 0x65, 0x20, 0x68, 0x6F, 0x70, + 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x73, 0x75, 0x70, 0x70, + 0x6F, 0x72, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, + 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x0D, 0x0A, 0x47, 0x75, 0x74, + 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, + 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, + 0x20, 0x70, 0x72, 0x6F, 0x6D, 0x6F, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x65, 0x6C, 0x65, 0x63, + 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x73, 0x20, 0x62, 0x79, 0x0D, 0x0A, 0x66, 0x72, 0x65, + 0x65, 0x6C, 0x79, 0x20, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6E, + 0x67, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, + 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, + 0x74, 0x6D, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x20, 0x69, + 0x6E, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x6C, 0x69, 0x61, 0x6E, + 0x63, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, + 0x0D, 0x0A, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, + 0x65, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x6B, 0x65, 0x65, 0x70, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x2D, 0x74, 0x6D, 0x20, 0x6E, 0x61, 0x6D, 0x65, 0x20, 0x61, + 0x73, 0x73, 0x6F, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x6F, 0x72, 0x6B, 0x2E, 0x20, 0x20, 0x59, 0x6F, 0x75, + 0x20, 0x63, 0x61, 0x6E, 0x20, 0x65, 0x61, 0x73, 0x69, 0x6C, + 0x79, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x6C, 0x79, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, + 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, 0x65, 0x6E, + 0x74, 0x20, 0x62, 0x79, 0x0D, 0x0A, 0x6B, 0x65, 0x65, 0x70, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, + 0x6F, 0x72, 0x6B, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x6D, + 0x61, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x69, 0x74, + 0x73, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, + 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x20, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x4C, 0x69, + 0x63, 0x65, 0x6E, 0x73, 0x65, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x79, 0x6F, 0x75, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, + 0x20, 0x69, 0x74, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, + 0x74, 0x20, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x73, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x44, 0x2E, 0x20, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x6C, 0x61, 0x77, 0x73, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6C, 0x61, + 0x63, 0x65, 0x20, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6C, 0x6F, 0x63, + 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x6C, 0x73, 0x6F, 0x20, + 0x67, 0x6F, 0x76, 0x65, 0x72, 0x6E, 0x0D, 0x0A, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x61, 0x6E, + 0x20, 0x64, 0x6F, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x2E, 0x20, + 0x20, 0x43, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x6C, 0x61, 0x77, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x6D, + 0x6F, 0x73, 0x74, 0x20, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x69, 0x6E, + 0x0D, 0x0A, 0x61, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, + 0x6E, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x6F, + 0x66, 0x20, 0x63, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x2E, 0x20, + 0x20, 0x49, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x6F, 0x75, 0x74, 0x73, 0x69, 0x64, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x55, 0x6E, 0x69, 0x74, 0x65, 0x64, + 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x2C, 0x20, 0x63, + 0x68, 0x65, 0x63, 0x6B, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, + 0x6C, 0x61, 0x77, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x79, 0x6F, + 0x75, 0x72, 0x20, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x72, 0x79, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, + 0x65, 0x6E, 0x74, 0x0D, 0x0A, 0x62, 0x65, 0x66, 0x6F, 0x72, + 0x65, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x6C, 0x6F, 0x61, 0x64, + 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x69, + 0x6E, 0x67, 0x2C, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, + 0x79, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x66, + 0x6F, 0x72, 0x6D, 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x64, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x6F, 0x72, 0x0D, 0x0A, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x64, 0x65, 0x72, 0x69, 0x76, 0x61, + 0x74, 0x69, 0x76, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, + 0x20, 0x62, 0x61, 0x73, 0x65, 0x64, 0x20, 0x6F, 0x6E, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, + 0x6F, 0x72, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x2E, + 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x75, 0x6E, + 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x20, 0x72, 0x65, 0x70, 0x72, + 0x65, 0x73, 0x65, 0x6E, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x73, 0x20, 0x63, 0x6F, 0x6E, 0x63, 0x65, 0x72, 0x6E, 0x69, + 0x6E, 0x67, 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x69, 0x6E, 0x20, + 0x61, 0x6E, 0x79, 0x20, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x72, + 0x79, 0x20, 0x6F, 0x75, 0x74, 0x73, 0x69, 0x64, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x55, 0x6E, 0x69, 0x74, 0x65, 0x64, + 0x0D, 0x0A, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x45, 0x2E, 0x20, 0x20, 0x55, + 0x6E, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x68, 0x61, 0x76, 0x65, 0x20, 0x72, 0x65, 0x6D, 0x6F, 0x76, + 0x65, 0x64, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, 0x73, 0x20, 0x74, 0x6F, + 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, + 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x3A, 0x0D, + 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x45, 0x2E, 0x31, 0x2E, 0x20, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x6F, 0x6C, 0x6C, 0x6F, + 0x77, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x65, 0x6E, 0x74, 0x65, + 0x6E, 0x63, 0x65, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x6C, 0x69, 0x6E, + 0x6B, 0x73, 0x20, 0x74, 0x6F, 0x2C, 0x20, 0x6F, 0x72, 0x20, + 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6D, 0x6D, 0x65, + 0x64, 0x69, 0x61, 0x74, 0x65, 0x0D, 0x0A, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x20, 0x74, 0x6F, 0x2C, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x20, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x4C, 0x69, + 0x63, 0x65, 0x6E, 0x73, 0x65, 0x20, 0x6D, 0x75, 0x73, 0x74, + 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x20, 0x70, 0x72, + 0x6F, 0x6D, 0x69, 0x6E, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x0D, + 0x0A, 0x77, 0x68, 0x65, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, + 0x61, 0x6E, 0x79, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x20, 0x6F, + 0x66, 0x20, 0x61, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, + 0x28, 0x61, 0x6E, 0x79, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, + 0x6F, 0x6E, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x0D, 0x0A, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, + 0x20, 0x22, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, + 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x22, + 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x73, 0x2C, 0x20, + 0x6F, 0x72, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x77, 0x68, + 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x68, + 0x72, 0x61, 0x73, 0x65, 0x20, 0x22, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x22, 0x20, 0x69, 0x73, 0x20, 0x61, + 0x73, 0x73, 0x6F, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x29, + 0x20, 0x69, 0x73, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x65, 0x64, 0x2C, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, + 0x79, 0x65, 0x64, 0x2C, 0x20, 0x70, 0x65, 0x72, 0x66, 0x6F, + 0x72, 0x6D, 0x65, 0x64, 0x2C, 0x20, 0x76, 0x69, 0x65, 0x77, + 0x65, 0x64, 0x2C, 0x0D, 0x0A, 0x63, 0x6F, 0x70, 0x69, 0x65, + 0x64, 0x20, 0x6F, 0x72, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x3A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x69, 0x73, 0x20, 0x65, 0x42, 0x6F, 0x6F, + 0x6B, 0x20, 0x69, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x61, 0x6E, 0x79, 0x6F, 0x6E, 0x65, 0x20, 0x61, 0x6E, 0x79, + 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x61, 0x74, 0x20, 0x6E, + 0x6F, 0x20, 0x63, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x61, 0x6C, 0x6D, + 0x6F, 0x73, 0x74, 0x20, 0x6E, 0x6F, 0x20, 0x72, 0x65, 0x73, + 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, + 0x77, 0x68, 0x61, 0x74, 0x73, 0x6F, 0x65, 0x76, 0x65, 0x72, + 0x2E, 0x20, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, + 0x20, 0x63, 0x6F, 0x70, 0x79, 0x20, 0x69, 0x74, 0x2C, 0x20, + 0x67, 0x69, 0x76, 0x65, 0x20, 0x69, 0x74, 0x20, 0x61, 0x77, + 0x61, 0x79, 0x20, 0x6F, 0x72, 0x0D, 0x0A, 0x72, 0x65, 0x2D, + 0x75, 0x73, 0x65, 0x20, 0x69, 0x74, 0x20, 0x75, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, + 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, + 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x20, 0x4C, 0x69, + 0x63, 0x65, 0x6E, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x63, 0x6C, + 0x75, 0x64, 0x65, 0x64, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x42, 0x6F, 0x6F, + 0x6B, 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x6E, 0x6C, 0x69, 0x6E, + 0x65, 0x20, 0x61, 0x74, 0x20, 0x77, 0x77, 0x77, 0x2E, 0x67, + 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2E, 0x6F, + 0x72, 0x67, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x45, 0x2E, + 0x32, 0x2E, 0x20, 0x20, 0x49, 0x66, 0x20, 0x61, 0x6E, 0x20, + 0x69, 0x6E, 0x64, 0x69, 0x76, 0x69, 0x64, 0x75, 0x61, 0x6C, + 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, + 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, + 0x6D, 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, + 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x69, 0x73, + 0x20, 0x64, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x0D, 0x0A, + 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x64, 0x6F, 0x6D, 0x61, + 0x69, 0x6E, 0x20, 0x28, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x20, + 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6E, 0x67, + 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x74, 0x20, 0x69, + 0x73, 0x0D, 0x0A, 0x70, 0x6F, 0x73, 0x74, 0x65, 0x64, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x70, 0x65, 0x72, 0x6D, 0x69, + 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x29, + 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x20, 0x63, 0x61, 0x6E, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6F, + 0x70, 0x69, 0x65, 0x64, 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x6E, 0x79, 0x6F, 0x6E, + 0x65, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, + 0x6E, 0x69, 0x74, 0x65, 0x64, 0x20, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, + 0x20, 0x70, 0x61, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x66, 0x65, 0x65, 0x73, 0x0D, 0x0A, 0x6F, 0x72, + 0x20, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x73, 0x2E, 0x20, + 0x20, 0x49, 0x66, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x72, 0x20, + 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x6F, 0x20, + 0x61, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x0D, 0x0A, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x68, 0x72, + 0x61, 0x73, 0x65, 0x20, 0x22, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x22, 0x20, 0x61, 0x73, 0x73, 0x6F, 0x63, 0x69, + 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x6F, 0x72, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, 0x72, 0x69, + 0x6E, 0x67, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x77, 0x6F, 0x72, 0x6B, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x63, 0x6F, 0x6D, 0x70, + 0x6C, 0x79, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, + 0x73, 0x20, 0x6F, 0x66, 0x20, 0x70, 0x61, 0x72, 0x61, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x73, 0x20, 0x31, 0x2E, 0x45, 0x2E, + 0x31, 0x0D, 0x0A, 0x74, 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, + 0x20, 0x31, 0x2E, 0x45, 0x2E, 0x37, 0x20, 0x6F, 0x72, 0x20, + 0x6F, 0x62, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x70, 0x65, 0x72, + 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x66, 0x6F, + 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, + 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, + 0x6D, 0x20, 0x74, 0x72, 0x61, 0x64, 0x65, 0x6D, 0x61, 0x72, + 0x6B, 0x20, 0x61, 0x73, 0x20, 0x73, 0x65, 0x74, 0x20, 0x66, + 0x6F, 0x72, 0x74, 0x68, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x61, + 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x73, 0x20, 0x31, + 0x2E, 0x45, 0x2E, 0x38, 0x20, 0x6F, 0x72, 0x0D, 0x0A, 0x31, + 0x2E, 0x45, 0x2E, 0x39, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, + 0x2E, 0x45, 0x2E, 0x33, 0x2E, 0x20, 0x20, 0x49, 0x66, 0x20, + 0x61, 0x6E, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x76, 0x69, 0x64, + 0x75, 0x61, 0x6C, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, + 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x20, 0x69, 0x73, 0x20, 0x70, 0x6F, 0x73, 0x74, 0x65, 0x64, + 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x65, 0x72, 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6F, + 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x68, + 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x72, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6F, 0x6E, 0x0D, 0x0A, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x63, + 0x6F, 0x6D, 0x70, 0x6C, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x20, 0x62, 0x6F, 0x74, 0x68, 0x20, 0x70, 0x61, 0x72, 0x61, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x73, 0x20, 0x31, 0x2E, 0x45, + 0x2E, 0x31, 0x20, 0x74, 0x68, 0x72, 0x6F, 0x75, 0x67, 0x68, + 0x20, 0x31, 0x2E, 0x45, 0x2E, 0x37, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x61, 0x6E, 0x79, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, + 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x0D, 0x0A, 0x74, 0x65, 0x72, + 0x6D, 0x73, 0x20, 0x69, 0x6D, 0x70, 0x6F, 0x73, 0x65, 0x64, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, + 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x68, 0x6F, + 0x6C, 0x64, 0x65, 0x72, 0x2E, 0x20, 0x20, 0x41, 0x64, 0x64, + 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x74, 0x65, + 0x72, 0x6D, 0x73, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x62, + 0x65, 0x20, 0x6C, 0x69, 0x6E, 0x6B, 0x65, 0x64, 0x0D, 0x0A, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x4C, 0x69, + 0x63, 0x65, 0x6E, 0x73, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x20, + 0x70, 0x6F, 0x73, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x70, 0x65, 0x72, + 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x68, 0x6F, 0x6C, 0x64, 0x65, + 0x72, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, + 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x31, 0x2E, 0x45, 0x2E, 0x34, 0x2E, 0x20, 0x20, + 0x44, 0x6F, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x75, 0x6E, 0x6C, + 0x69, 0x6E, 0x6B, 0x20, 0x6F, 0x72, 0x20, 0x64, 0x65, 0x74, + 0x61, 0x63, 0x68, 0x20, 0x6F, 0x72, 0x20, 0x72, 0x65, 0x6D, + 0x6F, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, + 0x6C, 0x6C, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x2D, 0x74, 0x6D, 0x0D, 0x0A, 0x4C, 0x69, 0x63, 0x65, 0x6E, + 0x73, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x66, + 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, + 0x6F, 0x72, 0x6B, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x66, 0x69, 0x6C, 0x65, 0x73, 0x20, 0x63, 0x6F, + 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x0D, 0x0A, 0x77, 0x6F, 0x72, 0x6B, 0x20, + 0x6F, 0x72, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6F, 0x74, 0x68, + 0x65, 0x72, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x61, 0x73, + 0x73, 0x6F, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, + 0x2E, 0x45, 0x2E, 0x35, 0x2E, 0x20, 0x20, 0x44, 0x6F, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x2C, 0x20, + 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x2C, 0x20, 0x70, + 0x65, 0x72, 0x66, 0x6F, 0x72, 0x6D, 0x2C, 0x20, 0x64, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x6F, + 0x72, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x0D, + 0x0A, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, + 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x2C, 0x20, 0x6F, 0x72, + 0x20, 0x61, 0x6E, 0x79, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x6C, + 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, + 0x6F, 0x72, 0x6B, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, + 0x75, 0x74, 0x0D, 0x0A, 0x70, 0x72, 0x6F, 0x6D, 0x69, 0x6E, + 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x64, 0x69, 0x73, 0x70, + 0x6C, 0x61, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x73, 0x65, 0x6E, 0x74, 0x65, 0x6E, 0x63, 0x65, 0x20, + 0x73, 0x65, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x68, 0x20, + 0x69, 0x6E, 0x20, 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x20, 0x31, 0x2E, 0x45, 0x2E, 0x31, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x0D, 0x0A, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x65, 0x20, 0x6C, 0x69, 0x6E, 0x6B, 0x73, 0x20, 0x6F, 0x72, + 0x20, 0x69, 0x6D, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, + 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x6F, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x20, + 0x74, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x4C, 0x69, 0x63, 0x65, 0x6E, + 0x73, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x45, + 0x2E, 0x36, 0x2E, 0x20, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x6D, + 0x61, 0x79, 0x20, 0x63, 0x6F, 0x6E, 0x76, 0x65, 0x72, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x62, 0x69, 0x6E, 0x61, + 0x72, 0x79, 0x2C, 0x0D, 0x0A, 0x63, 0x6F, 0x6D, 0x70, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x64, 0x2C, 0x20, 0x6D, 0x61, 0x72, + 0x6B, 0x65, 0x64, 0x20, 0x75, 0x70, 0x2C, 0x20, 0x6E, 0x6F, + 0x6E, 0x70, 0x72, 0x6F, 0x70, 0x72, 0x69, 0x65, 0x74, 0x61, + 0x72, 0x79, 0x20, 0x6F, 0x72, 0x20, 0x70, 0x72, 0x6F, 0x70, + 0x72, 0x69, 0x65, 0x74, 0x61, 0x72, 0x79, 0x20, 0x66, 0x6F, + 0x72, 0x6D, 0x2C, 0x20, 0x69, 0x6E, 0x63, 0x6C, 0x75, 0x64, + 0x69, 0x6E, 0x67, 0x20, 0x61, 0x6E, 0x79, 0x0D, 0x0A, 0x77, + 0x6F, 0x72, 0x64, 0x20, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x73, + 0x73, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x72, 0x20, 0x68, 0x79, + 0x70, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x20, 0x66, 0x6F, + 0x72, 0x6D, 0x2E, 0x20, 0x20, 0x48, 0x6F, 0x77, 0x65, 0x76, + 0x65, 0x72, 0x2C, 0x20, 0x69, 0x66, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, 0x20, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x6F, + 0x72, 0x0D, 0x0A, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x20, 0x63, 0x6F, 0x70, 0x69, 0x65, 0x73, + 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x66, 0x6F, 0x72, + 0x6D, 0x61, 0x74, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x74, 0x68, 0x61, 0x6E, 0x0D, 0x0A, 0x22, 0x50, 0x6C, 0x61, + 0x69, 0x6E, 0x20, 0x56, 0x61, 0x6E, 0x69, 0x6C, 0x6C, 0x61, + 0x20, 0x41, 0x53, 0x43, 0x49, 0x49, 0x22, 0x20, 0x6F, 0x72, + 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x66, 0x6F, 0x72, + 0x6D, 0x61, 0x74, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x66, 0x66, 0x69, + 0x63, 0x69, 0x61, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6F, 0x6E, 0x0D, 0x0A, 0x70, 0x6F, 0x73, 0x74, 0x65, 0x64, + 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x66, + 0x66, 0x69, 0x63, 0x69, 0x61, 0x6C, 0x20, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x77, 0x65, + 0x62, 0x20, 0x73, 0x69, 0x74, 0x65, 0x20, 0x28, 0x77, 0x77, + 0x77, 0x2E, 0x67, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2E, 0x6F, 0x72, 0x67, 0x29, 0x2C, 0x0D, 0x0A, 0x79, + 0x6F, 0x75, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x2C, 0x20, 0x61, + 0x74, 0x20, 0x6E, 0x6F, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, + 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x63, 0x6F, 0x73, 0x74, + 0x2C, 0x20, 0x66, 0x65, 0x65, 0x20, 0x6F, 0x72, 0x20, 0x65, + 0x78, 0x70, 0x65, 0x6E, 0x73, 0x65, 0x20, 0x74, 0x6F, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2C, 0x20, + 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, 0x20, 0x61, 0x0D, + 0x0A, 0x63, 0x6F, 0x70, 0x79, 0x2C, 0x20, 0x61, 0x20, 0x6D, + 0x65, 0x61, 0x6E, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x65, 0x78, + 0x70, 0x6F, 0x72, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x61, 0x20, + 0x63, 0x6F, 0x70, 0x79, 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x61, + 0x20, 0x6D, 0x65, 0x61, 0x6E, 0x73, 0x20, 0x6F, 0x66, 0x20, + 0x6F, 0x62, 0x74, 0x61, 0x69, 0x6E, 0x69, 0x6E, 0x67, 0x20, + 0x61, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x20, 0x75, 0x70, 0x6F, + 0x6E, 0x0D, 0x0A, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x2C, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x6F, 0x72, 0x6B, 0x20, 0x69, 0x6E, 0x20, 0x69, 0x74, 0x73, + 0x20, 0x6F, 0x72, 0x69, 0x67, 0x69, 0x6E, 0x61, 0x6C, 0x20, + 0x22, 0x50, 0x6C, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x61, 0x6E, + 0x69, 0x6C, 0x6C, 0x61, 0x20, 0x41, 0x53, 0x43, 0x49, 0x49, + 0x22, 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x0D, 0x0A, 0x66, 0x6F, 0x72, 0x6D, 0x2E, 0x20, 0x20, 0x41, + 0x6E, 0x79, 0x20, 0x61, 0x6C, 0x74, 0x65, 0x72, 0x6E, 0x61, + 0x74, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x20, + 0x6D, 0x75, 0x73, 0x74, 0x20, 0x69, 0x6E, 0x63, 0x6C, 0x75, + 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6C, + 0x6C, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, + 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, + 0x74, 0x6D, 0x0D, 0x0A, 0x4C, 0x69, 0x63, 0x65, 0x6E, 0x73, + 0x65, 0x20, 0x61, 0x73, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x70, 0x61, + 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x20, 0x31, 0x2E, + 0x45, 0x2E, 0x31, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, + 0x45, 0x2E, 0x37, 0x2E, 0x20, 0x20, 0x44, 0x6F, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x20, + 0x61, 0x20, 0x66, 0x65, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x6F, 0x2C, + 0x20, 0x76, 0x69, 0x65, 0x77, 0x69, 0x6E, 0x67, 0x2C, 0x20, + 0x64, 0x69, 0x73, 0x70, 0x6C, 0x61, 0x79, 0x69, 0x6E, 0x67, + 0x2C, 0x0D, 0x0A, 0x70, 0x65, 0x72, 0x66, 0x6F, 0x72, 0x6D, + 0x69, 0x6E, 0x67, 0x2C, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x69, + 0x6E, 0x67, 0x20, 0x6F, 0x72, 0x20, 0x64, 0x69, 0x73, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x61, + 0x6E, 0x79, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x2D, 0x74, 0x6D, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x0D, + 0x0A, 0x75, 0x6E, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x6C, 0x79, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x20, 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x20, 0x31, 0x2E, 0x45, 0x2E, 0x38, 0x20, + 0x6F, 0x72, 0x20, 0x31, 0x2E, 0x45, 0x2E, 0x39, 0x2E, 0x0D, + 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x45, 0x2E, 0x38, 0x2E, 0x20, + 0x20, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x63, + 0x68, 0x61, 0x72, 0x67, 0x65, 0x20, 0x61, 0x20, 0x72, 0x65, + 0x61, 0x73, 0x6F, 0x6E, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x66, + 0x65, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x63, 0x6F, 0x70, + 0x69, 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x6F, 0x72, 0x20, + 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x69, 0x6E, 0x67, 0x0D, + 0x0A, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x6F, + 0x20, 0x6F, 0x72, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, + 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, + 0x6F, 0x72, 0x6B, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, + 0x64, 0x65, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x61, 0x74, 0x0D, + 0x0A, 0x0D, 0x0A, 0x2D, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x70, + 0x61, 0x79, 0x20, 0x61, 0x20, 0x72, 0x6F, 0x79, 0x61, 0x6C, + 0x74, 0x79, 0x20, 0x66, 0x65, 0x65, 0x20, 0x6F, 0x66, 0x20, + 0x32, 0x30, 0x25, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x67, 0x72, 0x6F, 0x73, 0x73, 0x20, 0x70, 0x72, 0x6F, + 0x66, 0x69, 0x74, 0x73, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, + 0x65, 0x72, 0x69, 0x76, 0x65, 0x20, 0x66, 0x72, 0x6F, 0x6D, + 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x50, 0x72, + 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, + 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x77, + 0x6F, 0x72, 0x6B, 0x73, 0x20, 0x63, 0x61, 0x6C, 0x63, 0x75, + 0x6C, 0x61, 0x74, 0x65, 0x64, 0x20, 0x75, 0x73, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x65, 0x74, 0x68, + 0x6F, 0x64, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x61, 0x6C, 0x72, 0x65, 0x61, 0x64, 0x79, + 0x20, 0x75, 0x73, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x61, + 0x6C, 0x63, 0x75, 0x6C, 0x61, 0x74, 0x65, 0x20, 0x79, 0x6F, + 0x75, 0x72, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, + 0x62, 0x6C, 0x65, 0x20, 0x74, 0x61, 0x78, 0x65, 0x73, 0x2E, + 0x20, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x65, 0x65, 0x20, + 0x69, 0x73, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F, + 0x77, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6F, 0x77, 0x6E, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x74, 0x72, 0x61, 0x64, 0x65, + 0x6D, 0x61, 0x72, 0x6B, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x68, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, + 0x61, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x64, 0x20, + 0x74, 0x6F, 0x20, 0x64, 0x6F, 0x6E, 0x61, 0x74, 0x65, 0x20, + 0x72, 0x6F, 0x79, 0x61, 0x6C, 0x74, 0x69, 0x65, 0x73, 0x20, + 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x20, 0x4C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, 0x79, + 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, 0x46, + 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, + 0x20, 0x20, 0x52, 0x6F, 0x79, 0x61, 0x6C, 0x74, 0x79, 0x20, + 0x70, 0x61, 0x79, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, + 0x62, 0x65, 0x20, 0x70, 0x61, 0x69, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6E, 0x20, 0x36, 0x30, 0x20, 0x64, 0x61, + 0x79, 0x73, 0x20, 0x66, 0x6F, 0x6C, 0x6C, 0x6F, 0x77, 0x69, + 0x6E, 0x67, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x64, 0x61, + 0x74, 0x65, 0x20, 0x6F, 0x6E, 0x20, 0x77, 0x68, 0x69, 0x63, + 0x68, 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x20, + 0x28, 0x6F, 0x72, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6C, 0x65, + 0x67, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x70, 0x72, + 0x65, 0x70, 0x61, 0x72, 0x65, 0x29, 0x20, 0x79, 0x6F, 0x75, + 0x72, 0x20, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x69, 0x63, + 0x20, 0x74, 0x61, 0x78, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x73, 0x2E, 0x20, + 0x20, 0x52, 0x6F, 0x79, 0x61, 0x6C, 0x74, 0x79, 0x20, 0x70, + 0x61, 0x79, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x20, 0x73, 0x68, + 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6C, + 0x65, 0x61, 0x72, 0x6C, 0x79, 0x20, 0x6D, 0x61, 0x72, 0x6B, + 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x73, 0x75, 0x63, 0x68, + 0x20, 0x61, 0x6E, 0x64, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x73, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x20, 0x4C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, 0x79, 0x20, + 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, 0x46, 0x6F, + 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, + 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, + 0x69, 0x6E, 0x20, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x34, 0x2C, 0x20, 0x22, 0x49, 0x6E, 0x66, 0x6F, 0x72, + 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x64, 0x6F, 0x6E, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x73, 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x20, 0x4C, 0x69, 0x74, 0x65, 0x72, 0x61, + 0x72, 0x79, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, + 0x20, 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x2E, 0x22, 0x0D, 0x0A, 0x0D, 0x0A, 0x2D, 0x20, 0x59, + 0x6F, 0x75, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, + 0x20, 0x61, 0x20, 0x66, 0x75, 0x6C, 0x6C, 0x20, 0x72, 0x65, + 0x66, 0x75, 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x6D, 0x6F, 0x6E, 0x65, 0x79, 0x20, 0x70, 0x61, + 0x69, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x75, 0x73, + 0x65, 0x72, 0x20, 0x77, 0x68, 0x6F, 0x20, 0x6E, 0x6F, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x73, 0x0D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x69, 0x6E, 0x20, 0x77, + 0x72, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x28, 0x6F, 0x72, + 0x20, 0x62, 0x79, 0x20, 0x65, 0x2D, 0x6D, 0x61, 0x69, 0x6C, + 0x29, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6E, 0x20, 0x33, + 0x30, 0x20, 0x64, 0x61, 0x79, 0x73, 0x20, 0x6F, 0x66, 0x20, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x73, 0x2F, 0x68, 0x65, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, + 0x6F, 0x74, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x65, 0x72, 0x6D, + 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, + 0x75, 0x6C, 0x6C, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x4C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x2E, 0x20, + 0x20, 0x59, 0x6F, 0x75, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x20, 0x73, 0x75, + 0x63, 0x68, 0x20, 0x61, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, + 0x74, 0x6F, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, + 0x6F, 0x72, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, + 0x65, 0x73, 0x74, 0x72, 0x6F, 0x79, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x63, 0x6F, 0x70, 0x69, 0x65, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, + 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73, 0x65, 0x64, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x70, 0x68, 0x79, 0x73, + 0x69, 0x63, 0x61, 0x6C, 0x20, 0x6D, 0x65, 0x64, 0x69, 0x75, + 0x6D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x6E, + 0x64, 0x20, 0x64, 0x69, 0x73, 0x63, 0x6F, 0x6E, 0x74, 0x69, + 0x6E, 0x75, 0x65, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, + 0x74, 0x6F, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x63, + 0x6F, 0x70, 0x69, 0x65, 0x73, 0x20, 0x6F, 0x66, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x2D, 0x20, 0x59, 0x6F, + 0x75, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, 0x2C, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x63, 0x63, 0x6F, 0x72, 0x64, + 0x61, 0x6E, 0x63, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, 0x20, + 0x31, 0x2E, 0x46, 0x2E, 0x33, 0x2C, 0x20, 0x61, 0x20, 0x66, + 0x75, 0x6C, 0x6C, 0x20, 0x72, 0x65, 0x66, 0x75, 0x6E, 0x64, + 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x6D, 0x6F, 0x6E, 0x65, 0x79, 0x20, + 0x70, 0x61, 0x69, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, + 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x6F, 0x72, 0x20, 0x61, + 0x20, 0x72, 0x65, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x6D, 0x65, + 0x6E, 0x74, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x2C, 0x20, 0x69, + 0x66, 0x20, 0x61, 0x20, 0x64, 0x65, 0x66, 0x65, 0x63, 0x74, + 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, + 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, + 0x69, 0x73, 0x20, 0x64, 0x69, 0x73, 0x63, 0x6F, 0x76, 0x65, + 0x72, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x72, 0x65, + 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6E, + 0x20, 0x39, 0x30, 0x20, 0x64, 0x61, 0x79, 0x73, 0x0D, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6F, 0x66, 0x20, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x70, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x2D, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x63, 0x6F, + 0x6D, 0x70, 0x6C, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x61, 0x6C, 0x6C, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x74, 0x65, 0x72, 0x6D, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, + 0x65, 0x6E, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x66, 0x72, + 0x65, 0x65, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, + 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6F, + 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x45, 0x2E, + 0x39, 0x2E, 0x20, 0x20, 0x49, 0x66, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x77, 0x69, 0x73, 0x68, 0x20, 0x74, 0x6F, 0x20, 0x63, + 0x68, 0x61, 0x72, 0x67, 0x65, 0x20, 0x61, 0x20, 0x66, 0x65, + 0x65, 0x20, 0x6F, 0x72, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x61, 0x20, 0x50, 0x72, + 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, + 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x0D, 0x0A, + 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, + 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x6F, 0x72, 0x20, 0x67, + 0x72, 0x6F, 0x75, 0x70, 0x20, 0x6F, 0x66, 0x20, 0x77, 0x6F, + 0x72, 0x6B, 0x73, 0x20, 0x6F, 0x6E, 0x20, 0x64, 0x69, 0x66, + 0x66, 0x65, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x65, 0x72, + 0x6D, 0x73, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x73, 0x65, 0x74, 0x0D, 0x0A, 0x66, 0x6F, 0x72, + 0x74, 0x68, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, 0x65, 0x6E, 0x74, + 0x2C, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x75, 0x73, 0x74, + 0x20, 0x6F, 0x62, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x70, 0x65, + 0x72, 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x69, + 0x6E, 0x20, 0x77, 0x72, 0x69, 0x74, 0x69, 0x6E, 0x67, 0x20, + 0x66, 0x72, 0x6F, 0x6D, 0x0D, 0x0A, 0x62, 0x6F, 0x74, 0x68, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x20, 0x4C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, + 0x79, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, + 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x4D, 0x69, 0x63, 0x68, 0x61, + 0x65, 0x6C, 0x0D, 0x0A, 0x48, 0x61, 0x72, 0x74, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6F, 0x77, 0x6E, 0x65, 0x72, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x74, 0x72, + 0x61, 0x64, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x2E, 0x20, 0x20, + 0x43, 0x6F, 0x6E, 0x74, 0x61, 0x63, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x0D, 0x0A, 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x73, 0x20, 0x73, 0x65, 0x74, + 0x20, 0x66, 0x6F, 0x72, 0x74, 0x68, 0x20, 0x69, 0x6E, 0x20, + 0x53, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x33, 0x20, + 0x62, 0x65, 0x6C, 0x6F, 0x77, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, + 0x31, 0x2E, 0x46, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, + 0x46, 0x2E, 0x31, 0x2E, 0x20, 0x20, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x20, 0x76, 0x6F, 0x6C, 0x75, 0x6E, 0x74, + 0x65, 0x65, 0x72, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x65, + 0x6D, 0x70, 0x6C, 0x6F, 0x79, 0x65, 0x65, 0x73, 0x20, 0x65, + 0x78, 0x70, 0x65, 0x6E, 0x64, 0x20, 0x63, 0x6F, 0x6E, 0x73, + 0x69, 0x64, 0x65, 0x72, 0x61, 0x62, 0x6C, 0x65, 0x0D, 0x0A, + 0x65, 0x66, 0x66, 0x6F, 0x72, 0x74, 0x20, 0x74, 0x6F, 0x20, + 0x69, 0x64, 0x65, 0x6E, 0x74, 0x69, 0x66, 0x79, 0x2C, 0x20, + 0x64, 0x6F, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, + 0x68, 0x74, 0x20, 0x72, 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x20, 0x6F, 0x6E, 0x2C, 0x20, 0x74, 0x72, 0x61, 0x6E, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x70, 0x72, 0x6F, 0x6F, 0x66, 0x72, 0x65, 0x61, 0x64, + 0x0D, 0x0A, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x64, + 0x6F, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x73, 0x20, 0x69, 0x6E, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, + 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, + 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x0D, 0x0A, + 0x63, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x2E, 0x20, 0x20, 0x44, 0x65, 0x73, 0x70, 0x69, 0x74, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x65, 0x66, 0x66, + 0x6F, 0x72, 0x74, 0x73, 0x2C, 0x20, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, 0x65, + 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x0D, 0x0A, 0x77, + 0x6F, 0x72, 0x6B, 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, + 0x20, 0x6F, 0x6E, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x79, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x62, + 0x65, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x64, 0x2C, 0x20, + 0x6D, 0x61, 0x79, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, + 0x6E, 0x0D, 0x0A, 0x22, 0x44, 0x65, 0x66, 0x65, 0x63, 0x74, + 0x73, 0x2C, 0x22, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x61, + 0x73, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, 0x6E, 0x6F, 0x74, + 0x20, 0x6C, 0x69, 0x6D, 0x69, 0x74, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x2C, 0x20, 0x69, 0x6E, 0x63, 0x6F, 0x6D, 0x70, 0x6C, + 0x65, 0x74, 0x65, 0x2C, 0x20, 0x69, 0x6E, 0x61, 0x63, 0x63, + 0x75, 0x72, 0x61, 0x74, 0x65, 0x20, 0x6F, 0x72, 0x0D, 0x0A, + 0x63, 0x6F, 0x72, 0x72, 0x75, 0x70, 0x74, 0x20, 0x64, 0x61, + 0x74, 0x61, 0x2C, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x65, 0x72, + 0x72, 0x6F, 0x72, 0x73, 0x2C, 0x20, 0x61, 0x20, 0x63, 0x6F, + 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6F, 0x72, + 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6E, 0x74, + 0x65, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x75, 0x61, 0x6C, 0x0D, + 0x0A, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x79, 0x20, + 0x69, 0x6E, 0x66, 0x72, 0x69, 0x6E, 0x67, 0x65, 0x6D, 0x65, + 0x6E, 0x74, 0x2C, 0x20, 0x61, 0x20, 0x64, 0x65, 0x66, 0x65, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x6F, 0x72, 0x20, 0x64, + 0x61, 0x6D, 0x61, 0x67, 0x65, 0x64, 0x20, 0x64, 0x69, 0x73, + 0x6B, 0x20, 0x6F, 0x72, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, + 0x20, 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0x2C, 0x20, 0x61, + 0x0D, 0x0A, 0x63, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x72, + 0x20, 0x76, 0x69, 0x72, 0x75, 0x73, 0x2C, 0x20, 0x6F, 0x72, + 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20, + 0x63, 0x6F, 0x64, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x64, 0x61, 0x6D, 0x61, 0x67, 0x65, 0x20, 0x6F, 0x72, + 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x62, 0x79, 0x0D, 0x0A, + 0x79, 0x6F, 0x75, 0x72, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70, + 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, + 0x2E, 0x46, 0x2E, 0x32, 0x2E, 0x20, 0x20, 0x4C, 0x49, 0x4D, + 0x49, 0x54, 0x45, 0x44, 0x20, 0x57, 0x41, 0x52, 0x52, 0x41, + 0x4E, 0x54, 0x59, 0x2C, 0x20, 0x44, 0x49, 0x53, 0x43, 0x4C, + 0x41, 0x49, 0x4D, 0x45, 0x52, 0x20, 0x4F, 0x46, 0x20, 0x44, + 0x41, 0x4D, 0x41, 0x47, 0x45, 0x53, 0x20, 0x2D, 0x20, 0x45, + 0x78, 0x63, 0x65, 0x70, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x22, 0x52, 0x69, 0x67, 0x68, 0x74, + 0x0D, 0x0A, 0x6F, 0x66, 0x20, 0x52, 0x65, 0x70, 0x6C, 0x61, + 0x63, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x72, 0x20, + 0x52, 0x65, 0x66, 0x75, 0x6E, 0x64, 0x22, 0x20, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x20, 0x31, 0x2E, 0x46, 0x2E, 0x33, 0x2C, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x0D, + 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x20, 0x4C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, 0x79, 0x20, + 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, 0x46, 0x6F, + 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6F, 0x77, 0x6E, 0x65, 0x72, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, + 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x74, + 0x72, 0x61, 0x64, 0x65, 0x6D, 0x61, 0x72, 0x6B, 0x2C, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6F, 0x74, + 0x68, 0x65, 0x72, 0x20, 0x70, 0x61, 0x72, 0x74, 0x79, 0x20, + 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, 0x65, + 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, + 0x72, 0x6B, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, + 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x64, 0x69, 0x73, 0x63, 0x6C, + 0x61, 0x69, 0x6D, 0x20, 0x61, 0x6C, 0x6C, 0x0D, 0x0A, 0x6C, + 0x69, 0x61, 0x62, 0x69, 0x6C, 0x69, 0x74, 0x79, 0x20, 0x74, + 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x64, 0x61, 0x6D, 0x61, 0x67, 0x65, 0x73, 0x2C, 0x20, 0x63, + 0x6F, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x65, + 0x78, 0x70, 0x65, 0x6E, 0x73, 0x65, 0x73, 0x2C, 0x20, 0x69, + 0x6E, 0x63, 0x6C, 0x75, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6C, + 0x65, 0x67, 0x61, 0x6C, 0x0D, 0x0A, 0x66, 0x65, 0x65, 0x73, + 0x2E, 0x20, 0x20, 0x59, 0x4F, 0x55, 0x20, 0x41, 0x47, 0x52, + 0x45, 0x45, 0x20, 0x54, 0x48, 0x41, 0x54, 0x20, 0x59, 0x4F, + 0x55, 0x20, 0x48, 0x41, 0x56, 0x45, 0x20, 0x4E, 0x4F, 0x20, + 0x52, 0x45, 0x4D, 0x45, 0x44, 0x49, 0x45, 0x53, 0x20, 0x46, + 0x4F, 0x52, 0x20, 0x4E, 0x45, 0x47, 0x4C, 0x49, 0x47, 0x45, + 0x4E, 0x43, 0x45, 0x2C, 0x20, 0x53, 0x54, 0x52, 0x49, 0x43, + 0x54, 0x0D, 0x0A, 0x4C, 0x49, 0x41, 0x42, 0x49, 0x4C, 0x49, + 0x54, 0x59, 0x2C, 0x20, 0x42, 0x52, 0x45, 0x41, 0x43, 0x48, + 0x20, 0x4F, 0x46, 0x20, 0x57, 0x41, 0x52, 0x52, 0x41, 0x4E, + 0x54, 0x59, 0x20, 0x4F, 0x52, 0x20, 0x42, 0x52, 0x45, 0x41, + 0x43, 0x48, 0x20, 0x4F, 0x46, 0x20, 0x43, 0x4F, 0x4E, 0x54, + 0x52, 0x41, 0x43, 0x54, 0x20, 0x45, 0x58, 0x43, 0x45, 0x50, + 0x54, 0x20, 0x54, 0x48, 0x4F, 0x53, 0x45, 0x0D, 0x0A, 0x50, + 0x52, 0x4F, 0x56, 0x49, 0x44, 0x45, 0x44, 0x20, 0x49, 0x4E, + 0x20, 0x50, 0x41, 0x52, 0x41, 0x47, 0x52, 0x41, 0x50, 0x48, + 0x20, 0x46, 0x33, 0x2E, 0x20, 0x20, 0x59, 0x4F, 0x55, 0x20, + 0x41, 0x47, 0x52, 0x45, 0x45, 0x20, 0x54, 0x48, 0x41, 0x54, + 0x20, 0x54, 0x48, 0x45, 0x20, 0x46, 0x4F, 0x55, 0x4E, 0x44, + 0x41, 0x54, 0x49, 0x4F, 0x4E, 0x2C, 0x20, 0x54, 0x48, 0x45, + 0x0D, 0x0A, 0x54, 0x52, 0x41, 0x44, 0x45, 0x4D, 0x41, 0x52, + 0x4B, 0x20, 0x4F, 0x57, 0x4E, 0x45, 0x52, 0x2C, 0x20, 0x41, + 0x4E, 0x44, 0x20, 0x41, 0x4E, 0x59, 0x20, 0x44, 0x49, 0x53, + 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x4F, 0x52, 0x20, 0x55, + 0x4E, 0x44, 0x45, 0x52, 0x20, 0x54, 0x48, 0x49, 0x53, 0x20, + 0x41, 0x47, 0x52, 0x45, 0x45, 0x4D, 0x45, 0x4E, 0x54, 0x20, + 0x57, 0x49, 0x4C, 0x4C, 0x20, 0x4E, 0x4F, 0x54, 0x20, 0x42, + 0x45, 0x0D, 0x0A, 0x4C, 0x49, 0x41, 0x42, 0x4C, 0x45, 0x20, + 0x54, 0x4F, 0x20, 0x59, 0x4F, 0x55, 0x20, 0x46, 0x4F, 0x52, + 0x20, 0x41, 0x43, 0x54, 0x55, 0x41, 0x4C, 0x2C, 0x20, 0x44, + 0x49, 0x52, 0x45, 0x43, 0x54, 0x2C, 0x20, 0x49, 0x4E, 0x44, + 0x49, 0x52, 0x45, 0x43, 0x54, 0x2C, 0x20, 0x43, 0x4F, 0x4E, + 0x53, 0x45, 0x51, 0x55, 0x45, 0x4E, 0x54, 0x49, 0x41, 0x4C, + 0x2C, 0x20, 0x50, 0x55, 0x4E, 0x49, 0x54, 0x49, 0x56, 0x45, + 0x20, 0x4F, 0x52, 0x0D, 0x0A, 0x49, 0x4E, 0x43, 0x49, 0x44, + 0x45, 0x4E, 0x54, 0x41, 0x4C, 0x20, 0x44, 0x41, 0x4D, 0x41, + 0x47, 0x45, 0x53, 0x20, 0x45, 0x56, 0x45, 0x4E, 0x20, 0x49, + 0x46, 0x20, 0x59, 0x4F, 0x55, 0x20, 0x47, 0x49, 0x56, 0x45, + 0x20, 0x4E, 0x4F, 0x54, 0x49, 0x43, 0x45, 0x20, 0x4F, 0x46, + 0x20, 0x54, 0x48, 0x45, 0x20, 0x50, 0x4F, 0x53, 0x53, 0x49, + 0x42, 0x49, 0x4C, 0x49, 0x54, 0x59, 0x20, 0x4F, 0x46, 0x20, + 0x53, 0x55, 0x43, 0x48, 0x0D, 0x0A, 0x44, 0x41, 0x4D, 0x41, + 0x47, 0x45, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x46, + 0x2E, 0x33, 0x2E, 0x20, 0x20, 0x4C, 0x49, 0x4D, 0x49, 0x54, + 0x45, 0x44, 0x20, 0x52, 0x49, 0x47, 0x48, 0x54, 0x20, 0x4F, + 0x46, 0x20, 0x52, 0x45, 0x50, 0x4C, 0x41, 0x43, 0x45, 0x4D, + 0x45, 0x4E, 0x54, 0x20, 0x4F, 0x52, 0x20, 0x52, 0x45, 0x46, + 0x55, 0x4E, 0x44, 0x20, 0x2D, 0x20, 0x49, 0x66, 0x20, 0x79, + 0x6F, 0x75, 0x20, 0x64, 0x69, 0x73, 0x63, 0x6F, 0x76, 0x65, + 0x72, 0x20, 0x61, 0x0D, 0x0A, 0x64, 0x65, 0x66, 0x65, 0x63, + 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, + 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x69, 0x6E, 0x20, 0x39, 0x30, 0x20, 0x64, 0x61, 0x79, 0x73, + 0x20, 0x6F, 0x66, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x2C, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x63, 0x61, 0x6E, 0x0D, 0x0A, 0x72, 0x65, 0x63, + 0x65, 0x69, 0x76, 0x65, 0x20, 0x61, 0x20, 0x72, 0x65, 0x66, + 0x75, 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6D, 0x6F, 0x6E, 0x65, 0x79, 0x20, 0x28, 0x69, 0x66, + 0x20, 0x61, 0x6E, 0x79, 0x29, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x70, 0x61, 0x69, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x69, + 0x74, 0x20, 0x62, 0x79, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x69, + 0x6E, 0x67, 0x20, 0x61, 0x0D, 0x0A, 0x77, 0x72, 0x69, 0x74, + 0x74, 0x65, 0x6E, 0x20, 0x65, 0x78, 0x70, 0x6C, 0x61, 0x6E, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x20, + 0x79, 0x6F, 0x75, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x2E, 0x20, 0x20, 0x49, + 0x66, 0x20, 0x79, 0x6F, 0x75, 0x0D, 0x0A, 0x72, 0x65, 0x63, + 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x6F, 0x6E, 0x20, 0x61, 0x20, + 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6C, 0x20, 0x6D, + 0x65, 0x64, 0x69, 0x75, 0x6D, 0x2C, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x65, 0x64, + 0x69, 0x75, 0x6D, 0x20, 0x77, 0x69, 0x74, 0x68, 0x0D, 0x0A, + 0x79, 0x6F, 0x75, 0x72, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, + 0x65, 0x6E, 0x20, 0x65, 0x78, 0x70, 0x6C, 0x61, 0x6E, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x20, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x70, 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x20, 0x6F, 0x72, + 0x20, 0x65, 0x6E, 0x74, 0x69, 0x74, 0x79, 0x20, 0x74, 0x68, + 0x61, 0x74, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, + 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x77, 0x69, 0x74, 0x68, + 0x0D, 0x0A, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x65, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6B, + 0x20, 0x6D, 0x61, 0x79, 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, + 0x20, 0x74, 0x6F, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, + 0x65, 0x20, 0x61, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x61, 0x63, + 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x63, 0x6F, 0x70, 0x79, + 0x20, 0x69, 0x6E, 0x20, 0x6C, 0x69, 0x65, 0x75, 0x20, 0x6F, + 0x66, 0x20, 0x61, 0x0D, 0x0A, 0x72, 0x65, 0x66, 0x75, 0x6E, + 0x64, 0x2E, 0x20, 0x20, 0x49, 0x66, 0x20, 0x79, 0x6F, 0x75, + 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x65, + 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x61, + 0x6C, 0x6C, 0x79, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x65, 0x72, 0x73, 0x6F, 0x6E, 0x20, 0x6F, 0x72, 0x20, 0x65, + 0x6E, 0x74, 0x69, 0x74, 0x79, 0x0D, 0x0A, 0x70, 0x72, 0x6F, + 0x76, 0x69, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x69, 0x74, 0x20, + 0x74, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x6D, 0x61, 0x79, + 0x20, 0x63, 0x68, 0x6F, 0x6F, 0x73, 0x65, 0x20, 0x74, 0x6F, + 0x20, 0x67, 0x69, 0x76, 0x65, 0x20, 0x79, 0x6F, 0x75, 0x20, + 0x61, 0x20, 0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x20, 0x6F, + 0x70, 0x70, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x69, 0x74, 0x79, + 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x72, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, + 0x69, 0x63, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x20, + 0x6C, 0x69, 0x65, 0x75, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, + 0x72, 0x65, 0x66, 0x75, 0x6E, 0x64, 0x2E, 0x20, 0x20, 0x49, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6F, + 0x6E, 0x64, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x0D, 0x0A, 0x69, + 0x73, 0x20, 0x61, 0x6C, 0x73, 0x6F, 0x20, 0x64, 0x65, 0x66, + 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x2C, 0x20, 0x79, 0x6F, + 0x75, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x64, 0x65, 0x6D, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x20, 0x72, 0x65, 0x66, 0x75, 0x6E, + 0x64, 0x20, 0x69, 0x6E, 0x20, 0x77, 0x72, 0x69, 0x74, 0x69, + 0x6E, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, + 0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72, 0x0D, 0x0A, + 0x6F, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x75, 0x6E, 0x69, 0x74, + 0x69, 0x65, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x66, 0x69, 0x78, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6F, 0x62, 0x6C, + 0x65, 0x6D, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x46, + 0x2E, 0x34, 0x2E, 0x20, 0x20, 0x45, 0x78, 0x63, 0x65, 0x70, + 0x74, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x6C, 0x69, 0x6D, 0x69, 0x74, 0x65, 0x64, 0x20, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x72, 0x65, 0x70, + 0x6C, 0x61, 0x63, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x6F, + 0x72, 0x20, 0x72, 0x65, 0x66, 0x75, 0x6E, 0x64, 0x20, 0x73, + 0x65, 0x74, 0x20, 0x66, 0x6F, 0x72, 0x74, 0x68, 0x0D, 0x0A, + 0x69, 0x6E, 0x20, 0x70, 0x61, 0x72, 0x61, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x20, 0x31, 0x2E, 0x46, 0x2E, 0x33, 0x2C, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x20, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x27, + 0x41, 0x53, 0x2D, 0x49, 0x53, 0x27, 0x20, 0x57, 0x49, 0x54, + 0x48, 0x20, 0x4E, 0x4F, 0x20, 0x4F, 0x54, 0x48, 0x45, 0x52, + 0x0D, 0x0A, 0x57, 0x41, 0x52, 0x52, 0x41, 0x4E, 0x54, 0x49, + 0x45, 0x53, 0x20, 0x4F, 0x46, 0x20, 0x41, 0x4E, 0x59, 0x20, + 0x4B, 0x49, 0x4E, 0x44, 0x2C, 0x20, 0x45, 0x58, 0x50, 0x52, + 0x45, 0x53, 0x53, 0x20, 0x4F, 0x52, 0x20, 0x49, 0x4D, 0x50, + 0x4C, 0x49, 0x45, 0x44, 0x2C, 0x20, 0x49, 0x4E, 0x43, 0x4C, + 0x55, 0x44, 0x49, 0x4E, 0x47, 0x20, 0x42, 0x55, 0x54, 0x20, + 0x4E, 0x4F, 0x54, 0x20, 0x4C, 0x49, 0x4D, 0x49, 0x54, 0x45, + 0x44, 0x20, 0x54, 0x4F, 0x0D, 0x0A, 0x57, 0x41, 0x52, 0x52, + 0x41, 0x4E, 0x54, 0x49, 0x45, 0x53, 0x20, 0x4F, 0x46, 0x20, + 0x4D, 0x45, 0x52, 0x43, 0x48, 0x41, 0x4E, 0x54, 0x49, 0x42, + 0x49, 0x4C, 0x49, 0x54, 0x59, 0x20, 0x4F, 0x52, 0x20, 0x46, + 0x49, 0x54, 0x4E, 0x45, 0x53, 0x53, 0x20, 0x46, 0x4F, 0x52, + 0x20, 0x41, 0x4E, 0x59, 0x20, 0x50, 0x55, 0x52, 0x50, 0x4F, + 0x53, 0x45, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x31, 0x2E, 0x46, + 0x2E, 0x35, 0x2E, 0x20, 0x20, 0x53, 0x6F, 0x6D, 0x65, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x20, 0x64, 0x6F, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x6C, 0x6C, 0x6F, 0x77, 0x20, + 0x64, 0x69, 0x73, 0x63, 0x6C, 0x61, 0x69, 0x6D, 0x65, 0x72, + 0x73, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, + 0x69, 0x6E, 0x20, 0x69, 0x6D, 0x70, 0x6C, 0x69, 0x65, 0x64, + 0x0D, 0x0A, 0x77, 0x61, 0x72, 0x72, 0x61, 0x6E, 0x74, 0x69, + 0x65, 0x73, 0x20, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x65, 0x78, 0x63, 0x6C, 0x75, 0x73, 0x69, 0x6F, 0x6E, 0x20, + 0x6F, 0x72, 0x20, 0x6C, 0x69, 0x6D, 0x69, 0x74, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x65, 0x72, + 0x74, 0x61, 0x69, 0x6E, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x20, 0x6F, 0x66, 0x20, 0x64, 0x61, 0x6D, 0x61, 0x67, 0x65, + 0x73, 0x2E, 0x0D, 0x0A, 0x49, 0x66, 0x20, 0x61, 0x6E, 0x79, + 0x20, 0x64, 0x69, 0x73, 0x63, 0x6C, 0x61, 0x69, 0x6D, 0x65, + 0x72, 0x20, 0x6F, 0x72, 0x20, 0x6C, 0x69, 0x6D, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x73, 0x65, 0x74, 0x20, + 0x66, 0x6F, 0x72, 0x74, 0x68, 0x20, 0x69, 0x6E, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, + 0x65, 0x6E, 0x74, 0x20, 0x76, 0x69, 0x6F, 0x6C, 0x61, 0x74, + 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x6C, 0x61, + 0x77, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, + 0x63, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, + 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x67, 0x72, 0x65, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x73, + 0x68, 0x61, 0x6C, 0x6C, 0x20, 0x62, 0x65, 0x0D, 0x0A, 0x69, + 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6D, 0x61, 0x78, 0x69, 0x6D, 0x75, 0x6D, + 0x20, 0x64, 0x69, 0x73, 0x63, 0x6C, 0x61, 0x69, 0x6D, 0x65, + 0x72, 0x20, 0x6F, 0x72, 0x20, 0x6C, 0x69, 0x6D, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x65, 0x72, 0x6D, + 0x69, 0x74, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x0D, 0x0A, + 0x74, 0x68, 0x65, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, + 0x61, 0x62, 0x6C, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x20, 0x6C, 0x61, 0x77, 0x2E, 0x20, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x69, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x69, 0x74, + 0x79, 0x20, 0x6F, 0x72, 0x20, 0x75, 0x6E, 0x65, 0x6E, 0x66, + 0x6F, 0x72, 0x63, 0x65, 0x61, 0x62, 0x69, 0x6C, 0x69, 0x74, + 0x79, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x0D, 0x0A, + 0x70, 0x72, 0x6F, 0x76, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, + 0x72, 0x65, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x68, + 0x61, 0x6C, 0x6C, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x76, 0x6F, + 0x69, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x6D, + 0x61, 0x69, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x70, 0x72, 0x6F, + 0x76, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x31, 0x2E, 0x46, 0x2E, 0x36, 0x2E, 0x20, 0x20, + 0x49, 0x4E, 0x44, 0x45, 0x4D, 0x4E, 0x49, 0x54, 0x59, 0x20, + 0x2D, 0x20, 0x59, 0x6F, 0x75, 0x20, 0x61, 0x67, 0x72, 0x65, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x69, 0x6E, 0x64, 0x65, 0x6D, + 0x6E, 0x69, 0x66, 0x79, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, + 0x6F, 0x6C, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x6F, + 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x74, 0x72, 0x61, 0x64, 0x65, + 0x6D, 0x61, 0x72, 0x6B, 0x20, 0x6F, 0x77, 0x6E, 0x65, 0x72, + 0x2C, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x61, 0x67, 0x65, 0x6E, + 0x74, 0x20, 0x6F, 0x72, 0x20, 0x65, 0x6D, 0x70, 0x6C, 0x6F, + 0x79, 0x65, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x2C, 0x20, 0x61, 0x6E, 0x79, 0x6F, 0x6E, 0x65, 0x0D, + 0x0A, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x69, 0x6E, 0x67, + 0x20, 0x63, 0x6F, 0x70, 0x69, 0x65, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, + 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, + 0x6D, 0x20, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, + 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x20, 0x69, + 0x6E, 0x20, 0x61, 0x63, 0x63, 0x6F, 0x72, 0x64, 0x61, 0x6E, + 0x63, 0x65, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6D, + 0x65, 0x6E, 0x74, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x61, + 0x6E, 0x79, 0x20, 0x76, 0x6F, 0x6C, 0x75, 0x6E, 0x74, 0x65, + 0x65, 0x72, 0x73, 0x20, 0x61, 0x73, 0x73, 0x6F, 0x63, 0x69, + 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, + 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x0D, 0x0A, 0x70, 0x72, 0x6F, + 0x6D, 0x6F, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x6C, + 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, + 0x6F, 0x72, 0x6B, 0x73, 0x2C, 0x0D, 0x0A, 0x68, 0x61, 0x72, + 0x6D, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x66, 0x72, 0x6F, 0x6D, + 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6C, 0x69, 0x61, 0x62, 0x69, + 0x6C, 0x69, 0x74, 0x79, 0x2C, 0x20, 0x63, 0x6F, 0x73, 0x74, + 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x65, 0x78, 0x70, 0x65, + 0x6E, 0x73, 0x65, 0x73, 0x2C, 0x20, 0x69, 0x6E, 0x63, 0x6C, + 0x75, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6C, 0x65, 0x67, 0x61, + 0x6C, 0x20, 0x66, 0x65, 0x65, 0x73, 0x2C, 0x0D, 0x0A, 0x74, + 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x69, 0x73, 0x65, 0x20, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6C, 0x79, 0x20, 0x6F, + 0x72, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x6C, 0x79, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x61, 0x6E, + 0x79, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, + 0x6F, 0x6C, 0x6C, 0x6F, 0x77, 0x69, 0x6E, 0x67, 0x20, 0x77, + 0x68, 0x69, 0x63, 0x68, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x64, + 0x6F, 0x0D, 0x0A, 0x6F, 0x72, 0x20, 0x63, 0x61, 0x75, 0x73, + 0x65, 0x20, 0x74, 0x6F, 0x20, 0x6F, 0x63, 0x63, 0x75, 0x72, + 0x3A, 0x20, 0x28, 0x61, 0x29, 0x20, 0x64, 0x69, 0x73, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6F, 0x72, 0x20, + 0x61, 0x6E, 0x79, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x0D, 0x0A, 0x77, 0x6F, 0x72, 0x6B, + 0x2C, 0x20, 0x28, 0x62, 0x29, 0x20, 0x61, 0x6C, 0x74, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x6D, 0x6F, + 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x2C, 0x20, 0x6F, 0x72, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x6F, 0x72, 0x20, 0x64, 0x65, + 0x6C, 0x65, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x74, 0x6F, + 0x20, 0x61, 0x6E, 0x79, 0x0D, 0x0A, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x77, 0x6F, 0x72, + 0x6B, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x28, 0x63, 0x29, + 0x20, 0x61, 0x6E, 0x79, 0x20, 0x44, 0x65, 0x66, 0x65, 0x63, + 0x74, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x63, 0x61, 0x75, 0x73, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x65, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x20, 0x32, 0x2E, 0x20, + 0x20, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4D, 0x69, 0x73, 0x73, 0x69, 0x6F, 0x6E, + 0x20, 0x6F, 0x66, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, + 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, + 0x67, 0x2D, 0x74, 0x6D, 0x0D, 0x0A, 0x0D, 0x0A, 0x50, 0x72, + 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, + 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x69, + 0x73, 0x20, 0x73, 0x79, 0x6E, 0x6F, 0x6E, 0x79, 0x6D, 0x6F, + 0x75, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x20, + 0x6F, 0x66, 0x0D, 0x0A, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, + 0x6F, 0x6E, 0x69, 0x63, 0x20, 0x77, 0x6F, 0x72, 0x6B, 0x73, + 0x20, 0x69, 0x6E, 0x20, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, + 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6C, 0x65, + 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, 0x69, + 0x64, 0x65, 0x73, 0x74, 0x20, 0x76, 0x61, 0x72, 0x69, 0x65, + 0x74, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x6D, 0x70, + 0x75, 0x74, 0x65, 0x72, 0x73, 0x0D, 0x0A, 0x69, 0x6E, 0x63, + 0x6C, 0x75, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x62, 0x73, + 0x6F, 0x6C, 0x65, 0x74, 0x65, 0x2C, 0x20, 0x6F, 0x6C, 0x64, + 0x2C, 0x20, 0x6D, 0x69, 0x64, 0x64, 0x6C, 0x65, 0x2D, 0x61, + 0x67, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6E, 0x65, + 0x77, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x72, + 0x73, 0x2E, 0x20, 0x20, 0x49, 0x74, 0x20, 0x65, 0x78, 0x69, + 0x73, 0x74, 0x73, 0x0D, 0x0A, 0x62, 0x65, 0x63, 0x61, 0x75, + 0x73, 0x65, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x65, 0x66, 0x66, 0x6F, 0x72, 0x74, 0x73, 0x20, 0x6F, 0x66, + 0x20, 0x68, 0x75, 0x6E, 0x64, 0x72, 0x65, 0x64, 0x73, 0x20, + 0x6F, 0x66, 0x20, 0x76, 0x6F, 0x6C, 0x75, 0x6E, 0x74, 0x65, + 0x65, 0x72, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x6F, + 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x66, 0x72, + 0x6F, 0x6D, 0x0D, 0x0A, 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, + 0x20, 0x69, 0x6E, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x77, 0x61, + 0x6C, 0x6B, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x6C, 0x69, 0x66, + 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x56, 0x6F, 0x6C, 0x75, + 0x6E, 0x74, 0x65, 0x65, 0x72, 0x73, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x66, 0x69, 0x6E, 0x61, 0x6E, 0x63, 0x69, 0x61, 0x6C, + 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x20, 0x74, + 0x6F, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, 0x20, + 0x76, 0x6F, 0x6C, 0x75, 0x6E, 0x74, 0x65, 0x65, 0x72, 0x73, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x0D, + 0x0A, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x6E, 0x65, 0x65, + 0x64, 0x2C, 0x20, 0x69, 0x73, 0x20, 0x63, 0x72, 0x69, 0x74, + 0x69, 0x63, 0x61, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, + 0x61, 0x63, 0x68, 0x69, 0x6E, 0x67, 0x20, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x27, 0x73, 0x0D, + 0x0A, 0x67, 0x6F, 0x61, 0x6C, 0x73, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x65, 0x6E, 0x73, 0x75, 0x72, 0x69, 0x6E, 0x67, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, + 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, + 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, + 0x63, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x0D, 0x0A, 0x72, 0x65, 0x6D, + 0x61, 0x69, 0x6E, 0x20, 0x66, 0x72, 0x65, 0x65, 0x6C, 0x79, + 0x20, 0x61, 0x76, 0x61, 0x69, 0x6C, 0x61, 0x62, 0x6C, 0x65, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x74, 0x6F, 0x20, + 0x63, 0x6F, 0x6D, 0x65, 0x2E, 0x20, 0x20, 0x49, 0x6E, 0x20, + 0x32, 0x30, 0x30, 0x31, 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x0D, 0x0A, 0x47, + 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x20, 0x4C, + 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, 0x79, 0x20, 0x41, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, 0x46, 0x6F, 0x75, 0x6E, + 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x77, 0x61, 0x73, + 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x74, + 0x6F, 0x20, 0x70, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, 0x20, + 0x61, 0x20, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x0D, 0x0A, + 0x61, 0x6E, 0x64, 0x20, 0x70, 0x65, 0x72, 0x6D, 0x61, 0x6E, + 0x65, 0x6E, 0x74, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x20, 0x67, 0x65, 0x6E, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x0D, + 0x0A, 0x54, 0x6F, 0x20, 0x6C, 0x65, 0x61, 0x72, 0x6E, 0x20, + 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x20, 0x4C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, + 0x79, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, + 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x0D, 0x0A, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x6F, 0x77, 0x20, + 0x79, 0x6F, 0x75, 0x72, 0x20, 0x65, 0x66, 0x66, 0x6F, 0x72, + 0x74, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x6F, 0x6E, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x63, 0x61, 0x6E, + 0x20, 0x68, 0x65, 0x6C, 0x70, 0x2C, 0x20, 0x73, 0x65, 0x65, + 0x20, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, + 0x33, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x34, 0x0D, 0x0A, 0x61, + 0x6E, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x75, + 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x77, 0x65, + 0x62, 0x20, 0x70, 0x61, 0x67, 0x65, 0x20, 0x61, 0x74, 0x20, + 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, + 0x2E, 0x70, 0x67, 0x6C, 0x61, 0x66, 0x2E, 0x6F, 0x72, 0x67, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, 0x65, 0x63, + 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x33, 0x2E, 0x20, 0x20, 0x49, + 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, + 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x20, 0x4C, + 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, 0x79, 0x20, 0x41, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x0D, 0x0A, 0x46, 0x6F, 0x75, + 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x0D, 0x0A, 0x0D, + 0x0A, 0x54, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, + 0x72, 0x67, 0x20, 0x4C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, + 0x79, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, + 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6E, 0x6F, 0x6E, 0x20, + 0x70, 0x72, 0x6F, 0x66, 0x69, 0x74, 0x0D, 0x0A, 0x35, 0x30, + 0x31, 0x28, 0x63, 0x29, 0x28, 0x33, 0x29, 0x20, 0x65, 0x64, + 0x75, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, + 0x63, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x20, 0x6F, 0x72, 0x67, 0x61, 0x6E, 0x69, 0x7A, 0x65, + 0x64, 0x20, 0x75, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6C, 0x61, 0x77, 0x73, 0x20, 0x6F, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x69, 0x73, 0x73, 0x69, 0x73, + 0x73, 0x69, 0x70, 0x70, 0x69, 0x20, 0x61, 0x6E, 0x64, 0x20, + 0x67, 0x72, 0x61, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x74, 0x61, + 0x78, 0x20, 0x65, 0x78, 0x65, 0x6D, 0x70, 0x74, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x61, + 0x6C, 0x0D, 0x0A, 0x52, 0x65, 0x76, 0x65, 0x6E, 0x75, 0x65, + 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2E, 0x20, + 0x20, 0x54, 0x68, 0x65, 0x20, 0x46, 0x6F, 0x75, 0x6E, 0x64, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x27, 0x73, 0x20, 0x45, 0x49, + 0x4E, 0x20, 0x6F, 0x72, 0x20, 0x66, 0x65, 0x64, 0x65, 0x72, + 0x61, 0x6C, 0x20, 0x74, 0x61, 0x78, 0x20, 0x69, 0x64, 0x65, + 0x6E, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x0D, 0x0A, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, + 0x69, 0x73, 0x20, 0x36, 0x34, 0x2D, 0x36, 0x32, 0x32, 0x31, + 0x35, 0x34, 0x31, 0x2E, 0x20, 0x20, 0x49, 0x74, 0x73, 0x20, + 0x35, 0x30, 0x31, 0x28, 0x63, 0x29, 0x28, 0x33, 0x29, 0x20, + 0x6C, 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, + 0x70, 0x6F, 0x73, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74, 0x0D, + 0x0A, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x70, 0x67, + 0x6C, 0x61, 0x66, 0x2E, 0x6F, 0x72, 0x67, 0x2F, 0x66, 0x75, + 0x6E, 0x64, 0x72, 0x61, 0x69, 0x73, 0x69, 0x6E, 0x67, 0x2E, + 0x20, 0x20, 0x43, 0x6F, 0x6E, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x0D, 0x0A, 0x4C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x72, 0x79, + 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x20, 0x46, + 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x74, 0x61, 0x78, 0x20, 0x64, 0x65, + 0x64, 0x75, 0x63, 0x74, 0x69, 0x62, 0x6C, 0x65, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6C, 0x6C, + 0x20, 0x65, 0x78, 0x74, 0x65, 0x6E, 0x74, 0x0D, 0x0A, 0x70, + 0x65, 0x72, 0x6D, 0x69, 0x74, 0x74, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x20, 0x55, 0x2E, 0x53, 0x2E, 0x20, 0x66, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x6C, 0x20, 0x6C, 0x61, 0x77, 0x73, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x27, 0x73, 0x20, 0x6C, 0x61, 0x77, + 0x73, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, + 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x27, 0x73, 0x20, 0x70, 0x72, 0x69, 0x6E, 0x63, 0x69, 0x70, + 0x61, 0x6C, 0x20, 0x6F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, + 0x69, 0x73, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x34, 0x35, 0x35, 0x37, 0x20, 0x4D, + 0x65, 0x6C, 0x61, 0x6E, 0x20, 0x44, 0x72, 0x2E, 0x20, 0x53, + 0x2E, 0x0D, 0x0A, 0x46, 0x61, 0x69, 0x72, 0x62, 0x61, 0x6E, + 0x6B, 0x73, 0x2C, 0x20, 0x41, 0x4B, 0x2C, 0x20, 0x39, 0x39, + 0x37, 0x31, 0x32, 0x2E, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x69, 0x74, 0x73, 0x20, 0x76, 0x6F, 0x6C, 0x75, 0x6E, 0x74, + 0x65, 0x65, 0x72, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x65, + 0x6D, 0x70, 0x6C, 0x6F, 0x79, 0x65, 0x65, 0x73, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x73, 0x63, 0x61, 0x74, 0x74, 0x65, 0x72, + 0x65, 0x64, 0x0D, 0x0A, 0x74, 0x68, 0x72, 0x6F, 0x75, 0x67, + 0x68, 0x6F, 0x75, 0x74, 0x20, 0x6E, 0x75, 0x6D, 0x65, 0x72, + 0x6F, 0x75, 0x73, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x2E, 0x20, 0x20, 0x49, 0x74, 0x73, 0x20, + 0x62, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x20, 0x6F, + 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6C, + 0x6F, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74, 0x0D, + 0x0A, 0x38, 0x30, 0x39, 0x20, 0x4E, 0x6F, 0x72, 0x74, 0x68, + 0x20, 0x31, 0x35, 0x30, 0x30, 0x20, 0x57, 0x65, 0x73, 0x74, + 0x2C, 0x20, 0x53, 0x61, 0x6C, 0x74, 0x20, 0x4C, 0x61, 0x6B, + 0x65, 0x20, 0x43, 0x69, 0x74, 0x79, 0x2C, 0x20, 0x55, 0x54, + 0x20, 0x38, 0x34, 0x31, 0x31, 0x36, 0x2C, 0x20, 0x28, 0x38, + 0x30, 0x31, 0x29, 0x20, 0x35, 0x39, 0x36, 0x2D, 0x31, 0x38, + 0x38, 0x37, 0x2C, 0x20, 0x65, 0x6D, 0x61, 0x69, 0x6C, 0x0D, + 0x0A, 0x62, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x40, + 0x70, 0x67, 0x6C, 0x61, 0x66, 0x2E, 0x6F, 0x72, 0x67, 0x2E, + 0x20, 0x20, 0x45, 0x6D, 0x61, 0x69, 0x6C, 0x20, 0x63, 0x6F, + 0x6E, 0x74, 0x61, 0x63, 0x74, 0x20, 0x6C, 0x69, 0x6E, 0x6B, + 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x75, 0x70, 0x20, 0x74, + 0x6F, 0x20, 0x64, 0x61, 0x74, 0x65, 0x20, 0x63, 0x6F, 0x6E, + 0x74, 0x61, 0x63, 0x74, 0x0D, 0x0A, 0x69, 0x6E, 0x66, 0x6F, + 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x63, 0x61, + 0x6E, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x6F, + 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x27, 0x73, + 0x20, 0x77, 0x65, 0x62, 0x20, 0x73, 0x69, 0x74, 0x65, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x6F, 0x66, 0x66, 0x69, 0x63, 0x69, + 0x61, 0x6C, 0x0D, 0x0A, 0x70, 0x61, 0x67, 0x65, 0x20, 0x61, + 0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x70, + 0x67, 0x6C, 0x61, 0x66, 0x2E, 0x6F, 0x72, 0x67, 0x0D, 0x0A, + 0x0D, 0x0A, 0x46, 0x6F, 0x72, 0x20, 0x61, 0x64, 0x64, 0x69, + 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x63, 0x6F, 0x6E, + 0x74, 0x61, 0x63, 0x74, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, + 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x0D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x44, 0x72, 0x2E, 0x20, 0x47, 0x72, + 0x65, 0x67, 0x6F, 0x72, 0x79, 0x20, 0x42, 0x2E, 0x20, 0x4E, + 0x65, 0x77, 0x62, 0x79, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x43, 0x68, 0x69, 0x65, 0x66, 0x20, 0x45, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x69, 0x76, 0x65, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x0D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x67, 0x62, 0x6E, 0x65, + 0x77, 0x62, 0x79, 0x40, 0x70, 0x67, 0x6C, 0x61, 0x66, 0x2E, + 0x6F, 0x72, 0x67, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x53, + 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x34, 0x2E, 0x20, + 0x20, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x44, + 0x6F, 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x74, + 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x0D, 0x0A, 0x4C, 0x69, 0x74, 0x65, 0x72, + 0x61, 0x72, 0x79, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, + 0x65, 0x20, 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x0D, 0x0A, 0x0D, 0x0A, 0x50, 0x72, 0x6F, 0x6A, + 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x64, 0x65, 0x70, + 0x65, 0x6E, 0x64, 0x73, 0x20, 0x75, 0x70, 0x6F, 0x6E, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, + 0x20, 0x73, 0x75, 0x72, 0x76, 0x69, 0x76, 0x65, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x77, 0x69, 0x64, + 0x65, 0x0D, 0x0A, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x20, + 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x73, 0x75, 0x70, + 0x70, 0x6F, 0x72, 0x74, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, + 0x6F, 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x74, + 0x6F, 0x20, 0x63, 0x61, 0x72, 0x72, 0x79, 0x20, 0x6F, 0x75, + 0x74, 0x20, 0x69, 0x74, 0x73, 0x20, 0x6D, 0x69, 0x73, 0x73, + 0x69, 0x6F, 0x6E, 0x20, 0x6F, 0x66, 0x0D, 0x0A, 0x69, 0x6E, + 0x63, 0x72, 0x65, 0x61, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, + 0x6F, 0x66, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, + 0x64, 0x6F, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x6C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, 0x64, 0x20, + 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x63, 0x61, 0x6E, 0x20, 0x62, 0x65, 0x0D, 0x0A, 0x66, + 0x72, 0x65, 0x65, 0x6C, 0x79, 0x20, 0x64, 0x69, 0x73, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x6D, 0x61, 0x63, 0x68, 0x69, 0x6E, 0x65, 0x20, 0x72, + 0x65, 0x61, 0x64, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x66, 0x6F, + 0x72, 0x6D, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x69, + 0x62, 0x6C, 0x65, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x77, 0x69, 0x64, 0x65, 0x73, 0x74, 0x0D, 0x0A, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x65, 0x71, + 0x75, 0x69, 0x70, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x69, 0x6E, + 0x63, 0x6C, 0x75, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x75, + 0x74, 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x65, 0x71, 0x75, + 0x69, 0x70, 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x20, 0x20, 0x4D, + 0x61, 0x6E, 0x79, 0x20, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x20, + 0x64, 0x6F, 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x0D, + 0x0A, 0x28, 0x24, 0x31, 0x20, 0x74, 0x6F, 0x20, 0x24, 0x35, + 0x2C, 0x30, 0x30, 0x30, 0x29, 0x20, 0x61, 0x72, 0x65, 0x20, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x75, 0x6C, 0x61, 0x72, + 0x6C, 0x79, 0x20, 0x69, 0x6D, 0x70, 0x6F, 0x72, 0x74, 0x61, + 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x69, 0x6E, + 0x74, 0x61, 0x69, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x61, + 0x78, 0x20, 0x65, 0x78, 0x65, 0x6D, 0x70, 0x74, 0x0D, 0x0A, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x52, 0x53, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x65, 0x20, 0x46, 0x6F, + 0x75, 0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, + 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x74, 0x65, + 0x64, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x6C, + 0x79, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x77, 0x73, 0x20, 0x72, + 0x65, 0x67, 0x75, 0x6C, 0x61, 0x74, 0x69, 0x6E, 0x67, 0x0D, + 0x0A, 0x63, 0x68, 0x61, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x68, 0x61, 0x72, 0x69, + 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x64, 0x6F, 0x6E, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x35, 0x30, 0x20, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x55, 0x6E, 0x69, 0x74, 0x65, 0x64, 0x0D, 0x0A, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x73, 0x2E, 0x20, 0x20, 0x43, 0x6F, 0x6D, + 0x70, 0x6C, 0x69, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x72, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x73, + 0x20, 0x61, 0x72, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x75, + 0x6E, 0x69, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x61, 0x6E, 0x64, + 0x20, 0x69, 0x74, 0x20, 0x74, 0x61, 0x6B, 0x65, 0x73, 0x20, + 0x61, 0x0D, 0x0A, 0x63, 0x6F, 0x6E, 0x73, 0x69, 0x64, 0x65, + 0x72, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x65, 0x66, 0x66, 0x6F, + 0x72, 0x74, 0x2C, 0x20, 0x6D, 0x75, 0x63, 0x68, 0x20, 0x70, + 0x61, 0x70, 0x65, 0x72, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x6E, 0x79, 0x20, 0x66, 0x65, + 0x65, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x65, 0x65, 0x74, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6B, 0x65, 0x65, 0x70, 0x20, + 0x75, 0x70, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, + 0x68, 0x65, 0x73, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x2E, 0x20, 0x20, + 0x57, 0x65, 0x20, 0x64, 0x6F, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x73, 0x6F, 0x6C, 0x69, 0x63, 0x69, 0x74, 0x20, 0x64, 0x6F, + 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x69, 0x6E, + 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, + 0x0D, 0x0A, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x77, 0x65, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x77, + 0x72, 0x69, 0x74, 0x74, 0x65, 0x6E, 0x20, 0x63, 0x6F, 0x6E, + 0x66, 0x69, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, + 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x6C, 0x69, 0x61, + 0x6E, 0x63, 0x65, 0x2E, 0x20, 0x20, 0x54, 0x6F, 0x0D, 0x0A, + 0x53, 0x45, 0x4E, 0x44, 0x20, 0x44, 0x4F, 0x4E, 0x41, 0x54, + 0x49, 0x4F, 0x4E, 0x53, 0x20, 0x6F, 0x72, 0x20, 0x64, 0x65, + 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x65, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x6F, + 0x66, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x6C, 0x69, 0x61, 0x6E, + 0x63, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x6E, 0x79, + 0x0D, 0x0A, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x75, 0x6C, + 0x61, 0x72, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x76, + 0x69, 0x73, 0x69, 0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3A, + 0x2F, 0x2F, 0x70, 0x67, 0x6C, 0x61, 0x66, 0x2E, 0x6F, 0x72, + 0x67, 0x0D, 0x0A, 0x0D, 0x0A, 0x57, 0x68, 0x69, 0x6C, 0x65, + 0x20, 0x77, 0x65, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x64, 0x6F, 0x20, 0x6E, 0x6F, + 0x74, 0x20, 0x73, 0x6F, 0x6C, 0x69, 0x63, 0x69, 0x74, 0x20, + 0x63, 0x6F, 0x6E, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x73, 0x20, 0x77, 0x68, 0x65, 0x72, + 0x65, 0x20, 0x77, 0x65, 0x0D, 0x0A, 0x68, 0x61, 0x76, 0x65, + 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6D, 0x65, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x73, 0x6F, 0x6C, 0x69, 0x63, 0x69, 0x74, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x2C, 0x20, + 0x77, 0x65, 0x20, 0x6B, 0x6E, 0x6F, 0x77, 0x20, 0x6F, 0x66, + 0x20, 0x6E, 0x6F, 0x20, 0x70, 0x72, 0x6F, 0x68, 0x69, 0x62, + 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x0D, 0x0A, 0x61, 0x67, 0x61, + 0x69, 0x6E, 0x73, 0x74, 0x20, 0x61, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x69, 0x6E, 0x67, 0x20, 0x75, 0x6E, 0x73, 0x6F, 0x6C, + 0x69, 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x64, 0x6F, 0x6E, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x66, 0x72, 0x6F, + 0x6D, 0x20, 0x64, 0x6F, 0x6E, 0x6F, 0x72, 0x73, 0x20, 0x69, + 0x6E, 0x20, 0x73, 0x75, 0x63, 0x68, 0x20, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x73, 0x20, 0x77, 0x68, 0x6F, 0x0D, 0x0A, 0x61, + 0x70, 0x70, 0x72, 0x6F, 0x61, 0x63, 0x68, 0x20, 0x75, 0x73, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6F, 0x66, 0x66, 0x65, + 0x72, 0x73, 0x20, 0x74, 0x6F, 0x20, 0x64, 0x6F, 0x6E, 0x61, + 0x74, 0x65, 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x49, 0x6E, 0x74, + 0x65, 0x72, 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, + 0x20, 0x64, 0x6F, 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, + 0x20, 0x61, 0x72, 0x65, 0x20, 0x67, 0x72, 0x61, 0x74, 0x65, + 0x66, 0x75, 0x6C, 0x6C, 0x79, 0x20, 0x61, 0x63, 0x63, 0x65, + 0x70, 0x74, 0x65, 0x64, 0x2C, 0x20, 0x62, 0x75, 0x74, 0x20, + 0x77, 0x65, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, + 0x6D, 0x61, 0x6B, 0x65, 0x0D, 0x0A, 0x61, 0x6E, 0x79, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x73, + 0x20, 0x63, 0x6F, 0x6E, 0x63, 0x65, 0x72, 0x6E, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x61, 0x78, 0x20, 0x74, 0x72, 0x65, 0x61, + 0x74, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x64, + 0x6F, 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x72, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x66, 0x72, + 0x6F, 0x6D, 0x0D, 0x0A, 0x6F, 0x75, 0x74, 0x73, 0x69, 0x64, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x6E, 0x69, 0x74, + 0x65, 0x64, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x2E, + 0x20, 0x20, 0x55, 0x2E, 0x53, 0x2E, 0x20, 0x6C, 0x61, 0x77, + 0x73, 0x20, 0x61, 0x6C, 0x6F, 0x6E, 0x65, 0x20, 0x73, 0x77, + 0x61, 0x6D, 0x70, 0x20, 0x6F, 0x75, 0x72, 0x20, 0x73, 0x6D, + 0x61, 0x6C, 0x6C, 0x20, 0x73, 0x74, 0x61, 0x66, 0x66, 0x2E, + 0x0D, 0x0A, 0x0D, 0x0A, 0x50, 0x6C, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, + 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x20, 0x57, + 0x65, 0x62, 0x20, 0x70, 0x61, 0x67, 0x65, 0x73, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, + 0x20, 0x64, 0x6F, 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x0D, + 0x0A, 0x6D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x73, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x2E, 0x20, 0x20, 0x44, 0x6F, 0x6E, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, + 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6E, + 0x20, 0x61, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, + 0x6F, 0x66, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x0D, 0x0A, + 0x77, 0x61, 0x79, 0x73, 0x20, 0x69, 0x6E, 0x63, 0x6C, 0x75, + 0x64, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6B, + 0x73, 0x2C, 0x20, 0x6F, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x20, + 0x70, 0x61, 0x79, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x20, + 0x63, 0x61, 0x72, 0x64, 0x20, 0x64, 0x6F, 0x6E, 0x61, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x0D, 0x0A, 0x54, 0x6F, 0x20, + 0x64, 0x6F, 0x6E, 0x61, 0x74, 0x65, 0x2C, 0x20, 0x70, 0x6C, + 0x65, 0x61, 0x73, 0x65, 0x20, 0x76, 0x69, 0x73, 0x69, 0x74, + 0x3A, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x70, + 0x67, 0x6C, 0x61, 0x66, 0x2E, 0x6F, 0x72, 0x67, 0x2F, 0x64, + 0x6F, 0x6E, 0x61, 0x74, 0x65, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, + 0x0A, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x35, + 0x2E, 0x20, 0x20, 0x47, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C, + 0x20, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x41, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x50, + 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, + 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, + 0x65, 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, + 0x0D, 0x0A, 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x2E, 0x0D, 0x0A, + 0x0D, 0x0A, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x6F, + 0x72, 0x20, 0x4D, 0x69, 0x63, 0x68, 0x61, 0x65, 0x6C, 0x20, + 0x53, 0x2E, 0x20, 0x48, 0x61, 0x72, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6F, 0x72, 0x69, 0x67, 0x69, + 0x6E, 0x61, 0x74, 0x6F, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, + 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, + 0x2D, 0x74, 0x6D, 0x0D, 0x0A, 0x63, 0x6F, 0x6E, 0x63, 0x65, + 0x70, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x6C, 0x69, + 0x62, 0x72, 0x61, 0x72, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x65, + 0x6C, 0x65, 0x63, 0x74, 0x72, 0x6F, 0x6E, 0x69, 0x63, 0x20, + 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x63, 0x6F, 0x75, 0x6C, 0x64, 0x20, 0x62, 0x65, 0x20, + 0x66, 0x72, 0x65, 0x65, 0x6C, 0x79, 0x20, 0x73, 0x68, 0x61, + 0x72, 0x65, 0x64, 0x0D, 0x0A, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x61, 0x6E, 0x79, 0x6F, 0x6E, 0x65, 0x2E, 0x20, 0x20, 0x46, + 0x6F, 0x72, 0x20, 0x74, 0x68, 0x69, 0x72, 0x74, 0x79, 0x20, + 0x79, 0x65, 0x61, 0x72, 0x73, 0x2C, 0x20, 0x68, 0x65, 0x20, + 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x61, + 0x6E, 0x64, 0x20, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x64, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, + 0x63, 0x74, 0x0D, 0x0A, 0x47, 0x75, 0x74, 0x65, 0x6E, 0x62, + 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x42, 0x6F, + 0x6F, 0x6B, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6F, + 0x6E, 0x6C, 0x79, 0x20, 0x61, 0x20, 0x6C, 0x6F, 0x6F, 0x73, + 0x65, 0x20, 0x6E, 0x65, 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x20, + 0x6F, 0x66, 0x20, 0x76, 0x6F, 0x6C, 0x75, 0x6E, 0x74, 0x65, + 0x65, 0x72, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x20, 0x65, 0x42, + 0x6F, 0x6F, 0x6B, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x6F, + 0x66, 0x74, 0x65, 0x6E, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x73, 0x65, + 0x76, 0x65, 0x72, 0x61, 0x6C, 0x20, 0x70, 0x72, 0x69, 0x6E, + 0x74, 0x65, 0x64, 0x0D, 0x0A, 0x65, 0x64, 0x69, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x2C, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x6F, + 0x66, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x65, + 0x64, 0x20, 0x61, 0x73, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, + 0x63, 0x20, 0x44, 0x6F, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x2E, 0x53, 0x2E, + 0x0D, 0x0A, 0x75, 0x6E, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x61, + 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x20, 0x6E, 0x6F, 0x74, 0x69, 0x63, 0x65, 0x20, 0x69, 0x73, + 0x20, 0x69, 0x6E, 0x63, 0x6C, 0x75, 0x64, 0x65, 0x64, 0x2E, + 0x20, 0x20, 0x54, 0x68, 0x75, 0x73, 0x2C, 0x20, 0x77, 0x65, + 0x20, 0x64, 0x6F, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x6E, 0x65, + 0x63, 0x65, 0x73, 0x73, 0x61, 0x72, 0x69, 0x6C, 0x79, 0x0D, + 0x0A, 0x6B, 0x65, 0x65, 0x70, 0x20, 0x65, 0x42, 0x6F, 0x6F, + 0x6B, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x63, 0x6F, 0x6D, 0x70, + 0x6C, 0x69, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x70, 0x61, 0x72, 0x74, + 0x69, 0x63, 0x75, 0x6C, 0x61, 0x72, 0x20, 0x70, 0x61, 0x70, + 0x65, 0x72, 0x20, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, + 0x2E, 0x0D, 0x0A, 0x0D, 0x0A, 0x0D, 0x0A, 0x4D, 0x6F, 0x73, + 0x74, 0x20, 0x70, 0x65, 0x6F, 0x70, 0x6C, 0x65, 0x20, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x20, 0x61, 0x74, 0x20, 0x6F, 0x75, + 0x72, 0x20, 0x57, 0x65, 0x62, 0x20, 0x73, 0x69, 0x74, 0x65, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x68, 0x61, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x61, 0x69, 0x6E, 0x20, + 0x50, 0x47, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x20, + 0x66, 0x61, 0x63, 0x69, 0x6C, 0x69, 0x74, 0x79, 0x3A, 0x0D, + 0x0A, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x74, + 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x67, + 0x75, 0x74, 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x2E, 0x6F, + 0x72, 0x67, 0x0D, 0x0A, 0x0D, 0x0A, 0x54, 0x68, 0x69, 0x73, + 0x20, 0x57, 0x65, 0x62, 0x20, 0x73, 0x69, 0x74, 0x65, 0x20, + 0x69, 0x6E, 0x63, 0x6C, 0x75, 0x64, 0x65, 0x73, 0x20, 0x69, + 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x50, 0x72, 0x6F, + 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, 0x65, 0x6E, + 0x62, 0x65, 0x72, 0x67, 0x2D, 0x74, 0x6D, 0x2C, 0x0D, 0x0A, + 0x69, 0x6E, 0x63, 0x6C, 0x75, 0x64, 0x69, 0x6E, 0x67, 0x20, + 0x68, 0x6F, 0x77, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x64, 0x6F, 0x6E, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x73, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x50, + 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x47, 0x75, 0x74, + 0x65, 0x6E, 0x62, 0x65, 0x72, 0x67, 0x20, 0x4C, 0x69, 0x74, + 0x65, 0x72, 0x61, 0x72, 0x79, 0x0D, 0x0A, 0x41, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x20, 0x46, 0x6F, 0x75, 0x6E, 0x64, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2C, 0x20, 0x68, 0x6F, 0x77, + 0x20, 0x74, 0x6F, 0x20, 0x68, 0x65, 0x6C, 0x70, 0x20, 0x70, + 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x20, 0x6F, 0x75, 0x72, + 0x20, 0x6E, 0x65, 0x77, 0x20, 0x65, 0x42, 0x6F, 0x6F, 0x6B, + 0x73, 0x2C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x6F, 0x77, + 0x20, 0x74, 0x6F, 0x0D, 0x0A, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x6F, 0x75, + 0x72, 0x20, 0x65, 0x6D, 0x61, 0x69, 0x6C, 0x20, 0x6E, 0x65, + 0x77, 0x73, 0x6C, 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, 0x74, + 0x6F, 0x20, 0x68, 0x65, 0x61, 0x72, 0x20, 0x61, 0x62, 0x6F, + 0x75, 0x74, 0x20, 0x6E, 0x65, 0x77, 0x20, 0x65, 0x42, 0x6F, + 0x6F, 0x6B, 0x73, 0x2E, 0x0D, 0x0A +}; +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_getactivehash.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_getactivehash.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,112 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "test-utils/arm_uc_test_getactivehash.h" + +#include "update-client-firmware-manager/arm_uc_firmware_manager.h" +#include "update-client-paal/arm_uc_paal_update.h" +#include "update-client-common/arm_uc_metadata_header_v2.h" + +#include <mbedtls/sha256.h> + +#if defined(TARGET_LIKE_POSIX) +#include <pal_plat_update.h> +#include <unistd.h> +#define __WFI() usleep(100) +#endif + +using namespace utest::v1; + +static bool FLAG_GET_ACTIVE_FIRMWARE_DETAILS_DONE = false; + +static void event_handler(uint32_t event) +{ + switch (event) + { + case UCFM_EVENT_INITIALIZE_DONE: + printf("UCFM_EVENT_INITIALIZE_DONE\r\n"); + break; + + case UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE: + printf("UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE\r\n"); + FLAG_GET_ACTIVE_FIRMWARE_DETAILS_DONE = true; + break; + + default: + TEST_ASSERT_MESSAGE(false, "callback failed"); + break; + } +} + +control_t test_get_active_hash() +{ + arm_uc_error_t result; + +#if defined(TARGET_K64F) + int32_t rc; + + FlashIAP flash; + rc = flash.init(); + TEST_ASSERT_TRUE_MESSAGE(rc == 0, "main: FlashIAP::init failed"); + + uint32_t sector_size = flash.get_sector_size(MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS); + TEST_ASSERT_TRUE_MESSAGE(sector_size == 0x1000, "main: FlashIAP::get_sector_size failed"); + + rc = flash.erase(MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS, sector_size); + TEST_ASSERT_TRUE_MESSAGE(rc == 0, "main: FlashIAP::erase failed"); + + uint8_t buffer[1024] = { 0 }; + arm_uc_firmware_details_t details = { 0 }; + arm_uc_buffer_t output = { + .size_max = 1024, + .size = 0, + .ptr = buffer + }; + + result = arm_uc_create_internal_header_v2(&details, &output); + TEST_ASSERT_TRUE_MESSAGE(result.error == ERR_NONE, "main: arm_uc_create_internal_header_v2 failed"); + + rc = flash.program(output.ptr, MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS, output.size); + TEST_ASSERT_TRUE_MESSAGE(rc == 0, "main: FlashIAP::program failed"); + +#elif defined(TARGET_LIKE_POSIX) +#warning Active firmware details not implemented on Linux +#endif + + result = ARM_UC_FirmwareManager.Initialize(event_handler); + TEST_ASSERT_TRUE_MESSAGE(result.error == ERR_NONE, "initialize"); + + FLAG_GET_ACTIVE_FIRMWARE_DETAILS_DONE = false; + + printf("GetActiveHash\r\n"); + arm_uc_firmware_details_t readback = { 0 }; + result = ARM_UC_FirmwareManager.GetActiveFirmwareDetails(&readback); + if (result.error != ERR_NONE) + { + printf("error: %s\r\n", ARM_UC_err2Str(result)); + } + TEST_ASSERT_TRUE_MESSAGE(result.error == ERR_NONE, "GetActiveHash"); + while(!FLAG_GET_ACTIVE_FIRMWARE_DETAILS_DONE) + { + ARM_UC_ProcessQueue(); + __WFI(); + } + + return CaseNext; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_getactivehash.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_getactivehash.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,31 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef TEST_GETACTIVEHASH_H +#define TEST_GETACTIVEHASH_H + +#include <greentea-client/test_env.h> +#include <utest/utest.h> +#include <unity/unity.h> + +using namespace utest::v1; + +control_t test_get_active_hash(void); + +#endif +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_gethash.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_gethash.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,224 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// fixup the compilation on ARMCC for PRIu32 +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include "test-utils/arm_uc_test_gethash.h" + +#include "update-client-firmware-manager/arm_uc_firmware_manager.h" +#include "update-client-paal/arm_uc_paal_update.h" + +#include "pal.h" +#include "test-utils/arm_uc_test_alice.h" + +#include <mbedtls/sha256.h> + +#if defined(TARGET_LIKE_POSIX) +#include <unistd.h> +#define __WFI() usleep(100) +#endif + +using namespace utest::v1; + +static uint8_t temp_nc[16]; +static arm_uc_buffer_t keyBuffer = { .size_max = 32, .size = 32, .ptr = (uint8_t*) key }; +static arm_uc_buffer_t ivBuffer = { .size_max = 16, .size = 16, .ptr = (uint8_t*) temp_nc }; +static arm_uc_buffer_t hashBuffer = { .size_max = 32, .size = 32, .ptr = (uint8_t*) hash }; + +#define BUF_SIZE 1024 +static uint8_t buf[BUF_SIZE] = {0}; +static arm_uc_buffer_t fragment = { + .size_max = BUF_SIZE, + .size = 0, + .ptr = buf +}; +static uint8_t buf_back[BUF_SIZE] = {0}; +static arm_uc_buffer_t back_buffer = { + .size_max = BUF_SIZE, + .size = 0, + .ptr = buf_back +}; +static arm_uc_firmware_details_t firmware_details = { 0 }; + +static bool FLAG_PREPARE_DONE = false; +static bool FLAG_WRITE_DONE = false; +static bool FLAG_FINALIZE_DONE = false; +static bool FLAG_GET_FIRMWARE_DETAILS_DONE = false; +static bool FLAG_GET_ACTIVE_FIRMWARE_DETAILS_DONE = false; + +static void event_handler(uint32_t event) +{ + switch (event) + { + case UCFM_EVENT_INITIALIZE_DONE: + printf("UCFM_EVENT_INITIALIZE_DONE\r\n"); + break; + + case UCFM_EVENT_PREPARE_DONE: + printf("UCFM_EVENT_PREPARE_DONE\r\n"); + FLAG_PREPARE_DONE = true; + break; + + case UCFM_EVENT_WRITE_DONE: + FLAG_WRITE_DONE = true; + break; + + case UCFM_EVENT_FINALIZE_DONE: + printf("UCFM_EVENT_FINALIZE_DONE\r\n"); + FLAG_FINALIZE_DONE = true; + break; + + case UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE: + printf("UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE\r\n"); + FLAG_GET_FIRMWARE_DETAILS_DONE = true; + break; + + case UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE: + printf("UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE\r\n"); + FLAG_GET_ACTIVE_FIRMWARE_DETAILS_DONE = true; + break; + + default: + printf("unexpected event: %" PRIu32 "\r\n", event); + TEST_ASSERT_MESSAGE(false, "call failed"); + break; + } +} + +control_t test_get_stored_hash_generic(arm_uc_buffer_t *front, arm_uc_buffer_t *back) +{ + arm_uc_error_t result; + + /* Setup new firmware */ + memcpy(temp_nc, nc, sizeof(nc)); + ARM_UCFM_Setup_t setup; + setup.mode = UCFM_MODE_AES_CTR_256_SHA_256; + setup.key = &keyBuffer; + setup.iv = &ivBuffer; + setup.hash = &hashBuffer; + setup.package_id = 0; + setup.package_size = sizeof(ecila); + + FLAG_PREPARE_DONE = false; + printf("Prepare\r\n"); + + /* temporary buffer */ + arm_uc_buffer_t buffer = { + .size_max = BUF_SIZE, + .size = 0, + .ptr = buf + }; + + /* firmware details struct */ + arm_uc_firmware_details_t details = { 0 }; + + memcpy(details.hash, hashBuffer.ptr, 32); + details.version = 0; + details.size = sizeof(ecila); + + result = ARM_UC_FirmwareManager.Initialize(event_handler); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, "Initialize"); + + result = ARM_UC_FirmwareManager.Prepare(&setup, &details, &buffer); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, "setup"); + while(!FLAG_PREPARE_DONE) + { + ARM_UC_ProcessQueue(); + __WFI(); + } + + uint32_t package_offset = 0; + printf("Write\r\n"); + while(package_offset < setup.package_size) + { + uint32_t remaining = setup.package_size - package_offset; + + fragment.size = (remaining > fragment.size_max)? fragment.size_max:remaining; + memcpy(fragment.ptr, ecila+package_offset, fragment.size); + + FLAG_WRITE_DONE = false; + result = ARM_UC_FirmwareManager.Write(&fragment); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, "Write"); + while(!FLAG_WRITE_DONE) + { + ARM_UC_ProcessQueue(); + __WFI(); + } + package_offset += fragment.size; + } + printf("\r\n"); + + TEST_ASSERT_EQUAL(package_offset, setup.package_size); + + FLAG_FINALIZE_DONE = false; + printf("Finish\r\n"); + result = ARM_UC_FirmwareManager.Finalize(front, back); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, "Finish"); + while(!FLAG_FINALIZE_DONE) + { + ARM_UC_ProcessQueue(); + __WFI(); + } + + FLAG_GET_FIRMWARE_DETAILS_DONE = false; + + printf("GetFirmwareDetails\r\n"); + result = ARM_UC_FirmwareManager.GetFirmwareDetails(setup.package_id, + &firmware_details); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, "GetFirmwareDetails"); + while(!FLAG_GET_FIRMWARE_DETAILS_DONE) + { + ARM_UC_ProcessQueue(); + __WFI(); + } + + printf("\r\n"); + + printf("expected hash : "); + for (size_t index = 0; index < 256/8; index++) + { + printf("%02X", hashBuffer.ptr[index]); + } + printf("\r\n"); + + printf("read hash: "); + for (size_t index = 0; index < 256/8; index++) + { + printf("%02X", firmware_details.hash[index]); + } + printf("\r\n"); + + TEST_ASSERT_EQUAL_HEX8_ARRAY(firmware_details.hash, + hashBuffer.ptr, + hashBuffer.size); + + return CaseNext; +} + +control_t test_get_stored_hash_single_buffer() +{ + return test_get_stored_hash_generic(&fragment, NULL); +} + +control_t test_get_stored_hash_double_buffering() +{ + return test_get_stored_hash_generic(&fragment, &back_buffer); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_gethash.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_gethash.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,32 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef TEST_GETHASH_H +#define TEST_GETHASH_H + +#include <greentea-client/test_env.h> +#include <utest/utest.h> +#include <unity/unity.h> + +using namespace utest::v1; + +control_t test_get_stored_hash_single_buffer(void); +control_t test_get_stored_hash_double_buffering(void); + +#endif +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_retval.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_retval.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,246 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "test-utils/arm_uc_test_retval.h" + +#include "update-client-firmware-manager/arm_uc_firmware_manager.h" +#include "update-client-paal/arm_uc_paal_update.h" + +#include "pal.h" +#include "test-utils/arm_uc_test_alice.h" + +#include <mbedtls/sha256.h> + +#if defined(TARGET_LIKE_POSIX) +#include <unistd.h> +#define __WFI() usleep(100) +#endif + +using namespace utest::v1; + +static uint8_t temp_nc[16]; +static arm_uc_buffer_t keyBuffer = { .size_max = 32, .size = 32, .ptr = (uint8_t*) key }; +static arm_uc_buffer_t ivBuffer = { .size_max = 16, .size = 16, .ptr = (uint8_t*) temp_nc }; +static arm_uc_buffer_t hashBuffer = { .size_max = 32, .size = 32, .ptr = (uint8_t*) hash }; + +#define BUF_SIZE 1024 +static uint8_t buf[BUF_SIZE] = {0}; +static arm_uc_buffer_t fragment = { + .size_max = BUF_SIZE, + .size = 0, + .ptr = buf +}; + +static uint8_t back_buf[BUF_SIZE] = {0}; +static arm_uc_buffer_t back_buffer = { + .size_max = BUF_SIZE, + .size = 0, + .ptr = back_buf +}; + +static arm_uc_firmware_details_t firmware_details = { 0 }; + +static bool FLAG_PREPARE_DONE = false; +static bool FLAG_WRITE_DONE = false; +static bool FLAG_WRITE_ERROR = false; +static bool FLAG_FINALIZE_DONE = false; +static bool FLAG_GET_FIRMWARE_DETAILS_DONE = false; +static bool FLAG_GET_ACTIVE_FIRMWARE_DETAILS_DONE = false; +static bool FLAG_FINALIZE_ERROR = false; + +static void event_handler(uint32_t event) +{ + switch (event) + { + case UCFM_EVENT_INITIALIZE_DONE: + printf("UCFM_EVENT_INITIALIZE_DONE\r\n"); + break; + + case UCFM_EVENT_PREPARE_DONE: + printf("UCFM_EVENT_PREPARE_DONE\r\n"); + FLAG_PREPARE_DONE = true; + break; + + case UCFM_EVENT_WRITE_DONE: + FLAG_WRITE_DONE = true; + break; + + case UCFM_EVENT_WRITE_ERROR: + printf("UCFM_EVENT_WRITE_ERROR\r\n"); + FLAG_WRITE_ERROR = true; + break; + + case UCFM_EVENT_FINALIZE_DONE: + printf("UCFM_EVENT_FINALIZE_DONE\r\n"); + FLAG_FINALIZE_DONE = true; + break; + + case UCFM_EVENT_FINALIZE_ERROR: + printf("UCFM_EVENT_FINALIZE_ERROR\r\n"); + FLAG_FINALIZE_ERROR = true; + break; + + case UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE: + printf("UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE\r\n"); + FLAG_GET_FIRMWARE_DETAILS_DONE = true; + break; + + case UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE: + printf("UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE\r\n"); + FLAG_GET_ACTIVE_FIRMWARE_DETAILS_DONE = true; + break; + + default: + TEST_ASSERT_MESSAGE(false, "callback failed"); + break; + } +} + +control_t test_retval_sanity_check() +{ + arm_uc_error_t result; + + /* Setup new firmware */ + memcpy(temp_nc, nc, sizeof(nc)); + ARM_UCFM_Setup_t setup; + setup.mode = UCFM_MODE_AES_CTR_256_SHA_256; + setup.key = &keyBuffer; + setup.iv = &ivBuffer; + setup.hash = &hashBuffer; + setup.package_id = 0; + setup.package_size = sizeof(ecila); + + /* temporary buffer */ + arm_uc_buffer_t buffer = { + .size_max = BUF_SIZE, + .size = 0, + .ptr = buf + }; + + /* firmware details struct */ + arm_uc_firmware_details_t details = { 0 }; + + memcpy(details.hash, hashBuffer.ptr, 32); + details.version = 0; + details.size = sizeof(ecila); + + printf("Initialize\r\n"); + result = ARM_UC_FirmwareManager.Initialize(NULL); + TEST_ASSERT_EQUAL_HEX_MESSAGE(FIRM_ERR_INVALID_PARAMETER, result.code, + "Initialize with null should return FIRM_ERR_INVALID_PARAMETER"); + + result = ARM_UC_FirmwareManager.Prepare(&setup, &details, &buffer); + TEST_ASSERT_EQUAL_HEX_MESSAGE(FIRM_ERR_UNINITIALIZED, result.code, + "Calling setup before Initialize should return FIRM_ERR_UNINITIALIZED"); + + fragment.size = 1; + result = ARM_UC_FirmwareManager.Write(&fragment); + TEST_ASSERT_EQUAL_HEX_MESSAGE(FIRM_ERR_UNINITIALIZED, result.code, + "Calling Update before Initialize should return FIRM_ERR_UNINITIALIZED"); + + fragment.size = 0; + result = ARM_UC_FirmwareManager.GetActiveFirmwareDetails(&firmware_details); + TEST_ASSERT_EQUAL_HEX_MESSAGE(FIRM_ERR_INVALID_PARAMETER, result.code, + "Calling GetActiveHash before Initialize should return FIRM_ERR_INVALID_PARAMETER"); + + result = ARM_UC_FirmwareManager.Finalize(NULL, NULL); + TEST_ASSERT_EQUAL_HEX_MESSAGE(FIRM_ERR_UNINITIALIZED, result.code, + "Calling Finish before Initialize should return FIRM_ERR_UNINITIALIZED"); + + result = ARM_UC_FirmwareManager.Initialize(event_handler); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, + "Initialize should succeed"); + + result = ARM_UC_FirmwareManager.Prepare(NULL, NULL, NULL); + TEST_ASSERT_EQUAL_HEX_MESSAGE(FIRM_ERR_INVALID_PARAMETER, result.code, + "Calling setup with NULL should return FIRM_ERR_INVALID_PARAMETER"); + + fragment.size = 1; + result = ARM_UC_FirmwareManager.Write(&fragment); + TEST_ASSERT_EQUAL_HEX_MESSAGE(FIRM_ERR_UNINITIALIZED, result.code, + "Calling Update before Setup should return FIRM_ERR_UNINITIALIZED"); + + result = ARM_UC_FirmwareManager.Finalize(NULL, NULL); + TEST_ASSERT_EQUAL_HEX_MESSAGE(FIRM_ERR_UNINITIALIZED, result.code, + "Calling Finalize before setup should return FIRM_ERR_UNINITIALIZED"); + + printf("setup\r\n"); + FLAG_PREPARE_DONE = false; + result = ARM_UC_FirmwareManager.Prepare(&setup, &details, &buffer); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, + "setup should succeed"); + while(!FLAG_PREPARE_DONE) + { + ARM_UC_ProcessQueue(); + __WFI(); + } + + result = ARM_UC_FirmwareManager.Finalize(NULL, NULL); + TEST_ASSERT_EQUAL_HEX_MESSAGE(FIRM_ERR_INVALID_PARAMETER, result.code, + "Calling Finalize without parameters should fail"); + + printf("setup\r\n"); + FLAG_PREPARE_DONE = false; + result = ARM_UC_FirmwareManager.Prepare(&setup, &details, &buffer); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, + "setup should succeed"); + + while(!FLAG_PREPARE_DONE) + { + ARM_UC_ProcessQueue(); + __WFI(); + } + + printf("write\r\n"); + uint32_t package_offset = 0; + while(package_offset < setup.package_size) + { + uint32_t remaining = setup.package_size - package_offset; + + fragment.size = (remaining > fragment.size_max)? fragment.size_max:remaining; + memcpy(fragment.ptr, ecila+package_offset, fragment.size); + + FLAG_WRITE_DONE = false; + FLAG_WRITE_ERROR = false; + result = ARM_UC_FirmwareManager.Write(&fragment); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, "Update"); + while(!FLAG_WRITE_DONE) + { + ARM_UC_ProcessQueue(); + TEST_ASSERT_EQUAL_HEX_MESSAGE(false, FLAG_WRITE_ERROR, "Write"); + __WFI(); + } + package_offset += fragment.size; + } + + TEST_ASSERT_EQUAL(package_offset, setup.package_size); + + FLAG_FINALIZE_DONE = false; + FLAG_FINALIZE_ERROR = false; + result = ARM_UC_FirmwareManager.Finalize(&fragment, &back_buffer); + TEST_ASSERT_EQUAL_HEX_MESSAGE(ERR_NONE, result.error, "Finish"); + while(!FLAG_FINALIZE_DONE) + { + ARM_UC_ProcessQueue(); + TEST_ASSERT_EQUAL_HEX_MESSAGE(false, FLAG_FINALIZE_ERROR, "Finish"); + __WFI(); + } + + return CaseNext; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_retval.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_retval.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,31 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef TEST_RETVAL_H +#define TEST_RETVAL_H + +#include <greentea-client/test_env.h> +#include <utest/utest.h> +#include <unity/unity.h> + +using namespace utest::v1; + +control_t test_retval_sanity_check(void); + +#endif +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_sanity.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_sanity.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,154 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "test-utils/arm_uc_test_sanity.h" + +#include "update-client-firmware-manager/arm_uc_firmware_manager.h" +#include "update-client-paal/arm_uc_paal_update.h" + +#include "pal.h" + +#include "test-utils/arm_uc_test_alice.h" + +#ifdef TARGET_LIKE_POSIX +#include <unistd.h> +#define __WFI() sleep(1) +#endif + +using namespace utest::v1; + +static uint8_t temp_nc[16]; +static arm_uc_buffer_t keyBuffer = { .size_max = 32, .size = 32, .ptr = (uint8_t*) key }; +static arm_uc_buffer_t ivBuffer = { .size_max = 16, .size = 16, .ptr = (uint8_t*) temp_nc }; +static arm_uc_buffer_t hashBuffer = { .size_max = 32, .size = 32, .ptr = (uint8_t*) hash }; + +#define BUF_SIZE 1024 +static uint8_t buf[BUF_SIZE] = {0}; +static arm_uc_buffer_t fragment = { + .size_max = BUF_SIZE, + .size = 0, + .ptr = buf +}; + +static bool FLAG_PREPARE_DONE = false; +static bool FLAG_WRITE_DONE = false; +static bool FLAG_FINALIZE_DONE = false; +static bool FLAG_GET_FIRMWARE_DETAILS_DONE = false; + +static void event_handler(uint32_t event) +{ + switch (event) + { + case UCFM_EVENT_INITIALIZE_DONE: + printf("UCFM_EVENT_INITIALIZE_DONE\r\n"); + break; + + case UCFM_EVENT_PREPARE_DONE: + printf("UCFM_EVENT_PREPARE_DONE\r\n"); + FLAG_PREPARE_DONE = true; + break; + + case UCFM_EVENT_WRITE_DONE: + FLAG_WRITE_DONE = true; + break; + + case UCFM_EVENT_FINALIZE_DONE: + printf("UCFM_EVENT_FINALIZE_DONE\r\n"); + FLAG_FINALIZE_DONE = true; + break; + + case UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE: + printf("UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE\r\n"); + FLAG_GET_FIRMWARE_DETAILS_DONE = true; + break; + + default: + TEST_ASSERT_MESSAGE(false, "callback failed"); + break; + } +} + +control_t test_update_check_input_buffer() +{ + arm_uc_error_t result = (arm_uc_error_t){ ERR_NONE }; + + result = ARM_UC_FirmwareManager.Initialize(event_handler); + TEST_ASSERT_TRUE_MESSAGE(result.error == ERR_NONE, "initialize"); + + /* Setup new firmware */ + memcpy(temp_nc, nc, sizeof(nc)); + ARM_UCFM_Setup_t setup; + setup.mode = UCFM_MODE_AES_CTR_256_SHA_256; + setup.key = &keyBuffer; + setup.iv = &ivBuffer; + setup.hash = &hashBuffer; + setup.package_id = 0; + setup.package_size = sizeof(ecila); + + FLAG_PREPARE_DONE = false; + printf("Setup\r\n"); + + /* temporary buffer */ + arm_uc_buffer_t buffer = { + .size_max = BUF_SIZE, + .size = 0, + .ptr = buf + }; + + /* firmware details struct */ + arm_uc_firmware_details_t details = { 0 }; + + memcpy(details.hash, hashBuffer.ptr, 32); + details.version = 0; + details.size = sizeof(ecila); + + result = ARM_UC_FirmwareManager.Prepare(&setup, &details, &buffer); + TEST_ASSERT_TRUE_MESSAGE(result.error == ERR_NONE, "setup"); + while(!FLAG_PREPARE_DONE) + { + ARM_UC_ProcessQueue(); + __WFI(); + } + + fragment.size = fragment.size_max; + result = ARM_UC_FirmwareManager.Write(&fragment); + TEST_ASSERT_EQUAL_HEX(ERR_NONE, result.error); + while(!UCFM_EVENT_WRITE_DONE) + { + ARM_UC_ProcessQueue(); + __WFI(); + } + + fragment.size = fragment.size_max + 1; + result = ARM_UC_FirmwareManager.Write(&fragment); + TEST_ASSERT_EQUAL_HEX(FIRM_ERR_INVALID_PARAMETER, result.code); + + fragment.size_max = 0; + result = ARM_UC_FirmwareManager.Write(&fragment); + TEST_ASSERT_EQUAL_HEX(FIRM_ERR_INVALID_PARAMETER, result.code); + + fragment.ptr = NULL; + result = ARM_UC_FirmwareManager.Write(&fragment); + TEST_ASSERT_EQUAL_HEX(FIRM_ERR_INVALID_PARAMETER, result.code); + + result = ARM_UC_FirmwareManager.Write(NULL); + TEST_ASSERT_EQUAL_HEX(FIRM_ERR_INVALID_PARAMETER, result.code); + + return CaseNext; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_sanity.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/test-utils/arm_uc_test_sanity.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,31 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef TEST_SANITY_H +#define TEST_SANITY_H + +#include <greentea-client/test_env.h> +#include <utest/utest.h> +#include <unity/unity.h> + +using namespace utest::v1; + +control_t test_update_check_input_buffer(void); + +#endif +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/update-client-firmware-manager/arm_uc_firmware_manager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/firmware-manager/update-client-firmware-manager/arm_uc_firmware_manager.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,158 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_FIRMWARE_MANAGER_H +#define ARM_UC_FIRMWARE_MANAGER_H + +#include "update-client-paal/arm_uc_paal_update_api.h" +#include "update-client-common/arm_uc_common.h" + +typedef void (*ARM_UCFM_SignalEvent_t)(uint32_t event); + +#define UCFM_MAX_BLOCK_SIZE 16 + +typedef enum { + UCFM_EVENT_INITIALIZE_DONE = ARM_UC_PAAL_EVENT_INITIALIZE_DONE, + UCFM_EVENT_PREPARE_DONE = ARM_UC_PAAL_EVENT_PREPARE_DONE, + UCFM_EVENT_WRITE_DONE = ARM_UC_PAAL_EVENT_WRITE_DONE, + UCFM_EVENT_FINALIZE_DONE = ARM_UC_PAAL_EVENT_FINALIZE_DONE, + UCFM_EVENT_ACTIVATE_DONE = ARM_UC_PAAL_EVENT_ACTIVATE_DONE, + UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE = ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE, + UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE = ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE, + UCFM_EVENT_GET_INSTALLER_DETAILS_DONE = ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE, + UCFM_EVENT_INITIALIZE_ERROR = ARM_UC_PAAL_EVENT_INITIALIZE_ERROR, + UCFM_EVENT_PREPARE_ERROR = ARM_UC_PAAL_EVENT_PREPARE_ERROR, + UCFM_EVENT_WRITE_ERROR = ARM_UC_PAAL_EVENT_WRITE_ERROR, + UCFM_EVENT_FINALIZE_ERROR = ARM_UC_PAAL_EVENT_FINALIZE_ERROR, + UCFM_EVENT_ACTIVATE_ERROR = ARM_UC_PAAL_EVENT_ACTIVATE_ERROR, + UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR = ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR, + UCFM_EVENT_GET_FIRMWARE_DETAILS_ERROR = ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_ERROR, + UCFM_EVENT_GET_INSTALLER_DETAILS_ERROR = ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_ERROR, + UCFM_EVENT_FINALIZE_INVALID_HASH_ERROR +} ARM_UCFM_Event_t; + +typedef enum { + UCFM_MODE_UNINIT, + UCFM_MODE_NONE_SHA_256, + UCFM_MODE_AES_CTR_128_SHA_256, + UCFM_MODE_AES_CTR_256_SHA_256 +} ARM_UCFM_mode_t; + +typedef struct _ARM_UCFM_Setup { + ARM_UCFM_mode_t mode; + arm_uc_buffer_t* key; + arm_uc_buffer_t* iv; + arm_uc_buffer_t* hash; + uint32_t package_id; + uint32_t package_size; +} ARM_UCFM_Setup_t; + +typedef struct _ARM_UC_FIRMWARE_MANAGER { + /** + * @brief Initialization function. + * @param handler Function pointer to the event handler. + * @return Error code. + */ + arm_uc_error_t (*Initialize)(ARM_UCFM_SignalEvent_t handler); + + /** + * @brief Setup new package to be processed. + * @details Generates UCFM_EVENT_PREPARE_DONE event if call is accepted. + * @param configuration Struct containing configuration data. + * @param buffer Scratch pad for temporary storage. + * @return Error code. + */ + arm_uc_error_t (*Prepare)(ARM_UCFM_Setup_t* configuration, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer); + + /** + * @brief Function for adding a package fragment. + * @details Generates either UCFM_EVENT_WRITE_DONE or UCFM_EVENT_WRITE_ERROR. + * @details Fragments are processed based on the mode set in the configure + * struct. This can include decryption, validation, and storage. + * @param input Buffer struct. + * @return Error code. + */ + arm_uc_error_t (*Write)(const arm_uc_buffer_t* input); + + /** + * @brief Function for finalizing the current package. + * @details Flushes all write buffers and initiates the hash validation. + * Generates UCFM_EVENT_FINALIZE_DONE, UCFM_EVENT_FINALIZE_ERROR + * or UCFM_EVENT_FINALIZE_INVALID_HASH_ERROR. + * To speed up hash computation, this function accepts two buffer + * arguments ('front' and 'back): + * - if both 'front' and 'back' are NULL, a small internal buffer is + * used. Note that this can have an adverse impact on performance. + * - if only 'front' isn't NULL, 'front' will be used instead of the + * internal buffer. If 'front' is a large buffer, a performance + * improvement is likely to be observed. + * - if both 'front' and 'back' are not NULL, the code will initiate + * a read in the back buffer, hash the data in the front buffer, + * then swap the buffers. This configuration should provide the + * best performance (but also uses the most memory). + * It is an error to call this function with 'front' equal to NULL + * and a non-null value for 'back'. + * NOTE: the buffer size must be a multiple of ARM_UC_SHA256_SIZE. + * @return Error code. + */ + arm_uc_error_t (*Finalize)(arm_uc_buffer_t* front, arm_uc_buffer_t* back); + + /** + * @brief Function for activating or installing the current package. + * @details Activates or installs the current package. + * In the future this function might take the image ID as + * paramter. + * @param location ID of slot to be activated. + * @return Error code. + */ + arm_uc_error_t (*Activate)(uint32_t location); + + /** + * @brief Get the firmware details for the currently active image. + * + * @param details Pointer to firmware details struct. + * @return Error code. + */ + arm_uc_error_t (*GetActiveFirmwareDetails)(arm_uc_firmware_details_t* details); + + /** + * @brief Get the firmware details for the specified location. + * + * @param location Location ID to get details for. + * @param details Pointer to firmware details struct. + * @return Error code. + */ + arm_uc_error_t (*GetFirmwareDetails)(uint32_t location, + arm_uc_firmware_details_t* details); + + /** + * @brief Get the installer details. + * @details Installer is responsible for applying the firmware image. + * + * @param details Pointer to installer details struct. + * @return Error code. + */ + arm_uc_error_t (*GetInstallerDetails)(arm_uc_installer_details_t* details); + +} ARM_UC_FIRMWARE_MANAGER_t; + +extern ARM_UC_FIRMWARE_MANAGER_t ARM_UC_FirmwareManager; + +#endif // ARM_UC_FIRMWARE_MANAGER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. \ No newline at end of file
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/DeviceMetadataResource.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/DeviceMetadataResource.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,241 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-lwm2m/DeviceMetadataResource.h" + +#include "update-client-common/arm_uc_common.h" +#include "pal4life-device-identity/pal_device_identity.h" + +#include <stdio.h> + +#define ARM_UCS_LWM2M_INTERNAL_ERROR (-1) +#define ARM_UCS_LWM2M_INTERNAL_SUCCESS (0) + +namespace DeviceMetadataResource { + + /* LWM2M Firmware Update Object */ + static M2MObject* deviceMetadataObject = NULL; + + /* LWM2M Firmware Update Object resources */ + static M2MResource* protocolSupportedResource = NULL; // /10255/0/0 + static M2MResource* bootloaderHashResource = NULL; // /10255/0/1 + static M2MResource* OEMBootloaderHashResource = NULL; // /10255/0/2 + static M2MResource* vendorIdResource = NULL; // /10255/0/3 + static M2MResource* classIdResource = NULL; // /10255/0/4 + static M2MResource* deviceIdResource = NULL; // /10255/0/5 +} + + +/** + * @brief Initialize LWM2M Device Metadata Object + * @details Sets up LWM2M object with accompanying resources. + */ +void DeviceMetadataResource::Initialize(void) +{ + static bool initialized = false; + + if (!initialized) + { + initialized = true; + + /* The LWM2M Firmware Update Object is at /10255 */ + deviceMetadataObject = M2MInterfaceFactory::create_object("10255"); + + if (deviceMetadataObject) + { + /* Set object operating mode to GET_ALLOWED */ + deviceMetadataObject->set_operation(M2MBase::GET_ALLOWED); + /* Create first (and only) instance /10255/0 */ + M2MObjectInstance* deviceMetadataInstance = deviceMetadataObject->create_object_instance(); + + if (deviceMetadataInstance) + { + /* Default values are non-standard, but the standard has no + values for indicating that the device is initializing. + */ + int64_t defaultVersion = 1; + const uint8_t invalid_value[] = "INVALID"; + const uint8_t invalid_value_size = sizeof(invalid_value) - 1; + + arm_uc_error_t err = { .code = ERR_INVALID_PARAMETER }; + arm_uc_guid_t guid = { 0 }; + uint8_t* value = NULL; + uint32_t value_length = 0; + + /* Set instance operating mode to GET_ALLOWED */ + deviceMetadataInstance->set_operation(M2MBase::GET_ALLOWED); + + /* Create Update resource /10255/0/0 */ + protocolSupportedResource = deviceMetadataInstance->create_dynamic_resource( + "0", + "ProtocolSupported", + M2MResourceInstance::INTEGER, + true); + if (protocolSupportedResource) + { + protocolSupportedResource->set_operation(M2MBase::GET_ALLOWED); + protocolSupportedResource->set_value(defaultVersion); + } + + /* Create Update resource /10255/0/1 */ + bootloaderHashResource = deviceMetadataInstance->create_static_resource( + "1", + "BootloaderHash", + M2MResourceInstance::OPAQUE, + (uint8_t *) invalid_value, + invalid_value_size); + if (bootloaderHashResource) + { + bootloaderHashResource->set_operation(M2MBase::GET_ALLOWED); + } + + /* Create Update resource /10255/0/2 */ + OEMBootloaderHashResource = deviceMetadataInstance->create_static_resource( + "2", + "OEMBootloaderHash", + M2MResourceInstance::OPAQUE, + (uint8_t *) invalid_value, + invalid_value_size); + if (OEMBootloaderHashResource) + { + OEMBootloaderHashResource->set_operation(M2MBase::GET_ALLOWED); + } + + /* get vendor ID */ + err = pal_getVendorGuid(&guid); + if (err.error == ERR_NONE) + { + value = (uint8_t *) &guid; + value_length = sizeof(arm_uc_guid_t); + } + else + { + value = (uint8_t *) invalid_value; + value_length = invalid_value_size; + } + + /* Create Update resource /10255/0/3 */ + vendorIdResource = deviceMetadataInstance->create_dynamic_resource( + "3", + "Vendor", + M2MResourceInstance::OPAQUE, + true); + + if (vendorIdResource) + { + vendorIdResource->set_operation(M2MBase::GET_ALLOWED); + vendorIdResource->set_value(value, value_length); + } + + /* get class ID */ + err = pal_getClassGuid(&guid); + if (err.error == ERR_NONE) + { + value = (uint8_t *) &guid; + value_length = sizeof(arm_uc_guid_t); + } + else + { + value = (uint8_t *) invalid_value; + value_length = invalid_value_size; + } + + /* Create Update resource /10255/0/4 */ + classIdResource = deviceMetadataInstance->create_dynamic_resource( + "4", + "Class", + M2MResourceInstance::OPAQUE, + true); + + if (classIdResource) + { + classIdResource->set_operation(M2MBase::GET_ALLOWED); + classIdResource->set_value(value, value_length); + } + + /* get device ID */ + err = pal_getDeviceGuid(&guid); + if (err.error == ERR_NONE) + { + value = (uint8_t *) &guid; + value_length = sizeof(arm_uc_guid_t); + } + else + { + value = (uint8_t *) invalid_value; + value_length = invalid_value_size; + } + + /* Create Update resource /10255/0/5 */ + deviceIdResource = deviceMetadataInstance->create_static_resource( + "5", + "DeviceId", + M2MResourceInstance::OPAQUE, + value, + value_length); + if (deviceIdResource) + { + deviceIdResource->set_operation(M2MBase::GET_ALLOWED); + } + } + } + } +} + +int32_t DeviceMetadataResource::setBootloaderHash(arm_uc_buffer_t* hash) +{ + UC_SRCE_TRACE("DeviceMetadataResource::setBootloaderHash ptr %p size %u", hash, hash->size); + + int32_t result = ARM_UCS_LWM2M_INTERNAL_ERROR; + + if (bootloaderHashResource && hash && hash->size > 0) + { + bool rt = bootloaderHashResource->set_value(hash->ptr, hash->size); + if (rt == true) + { + result = ARM_UCS_LWM2M_INTERNAL_SUCCESS; + } + } + + return result; +} + +int32_t DeviceMetadataResource::setOEMBootloaderHash(arm_uc_buffer_t* hash) +{ + UC_SRCE_TRACE("DeviceMetadataResource::setOEMBootloaderHash ptr %p size %u", hash, hash->size); + + int32_t result = ARM_UCS_LWM2M_INTERNAL_ERROR; + + if (OEMBootloaderHashResource && hash && hash->size > 0) + { + bool rt = OEMBootloaderHashResource->set_value(hash->ptr, hash->size); + if (rt == true) + { + result = ARM_UCS_LWM2M_INTERNAL_SUCCESS; + } + } + + return result; +} + +M2MObject* DeviceMetadataResource::getObject() +{ + Initialize(); + + return deviceMetadataObject; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/FirmwareUpdateResource.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/FirmwareUpdateResource.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,412 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-lwm2m/FirmwareUpdateResource.h" + +#include "update-client-common/arm_uc_common.h" + +#include <stdio.h> + +#define ARM_UCS_LWM2M_INTERNAL_ERROR (-1) +#define ARM_UCS_LWM2M_INTERNAL_SUCCESS (0) + +namespace FirmwareUpdateResource { + + /* send delayed response */ + enum { + ResourcePackage, + ResourcePackageURI, + ResourceUpdate + }; + + static void packageCallback(void* _parameters); + static void packageURICallback(void* _parameters); + static void updateCallback(void*); + static void notificationCallback(void); + static void sendDelayedResponseTask(uint32_t parameter); + + /* LWM2M Firmware Update Object */ + static M2MObject* updateObject = NULL; + + /* LWM2M Firmware Update Object resources */ + static M2MResource* resourcePackage = NULL; + static M2MResource* resourcePackageURI = NULL; + static M2MResource* resourceUpdate = NULL; + static M2MResource* resourceState = NULL; + static M2MResource* resourceResult = NULL; + static M2MResource* resourceName = NULL; + static M2MResource* resourceVersion = NULL; + + /* function pointers to callback functions */ + static void (*externalPackageCallback)(const uint8_t* buffer, uint16_t length) = NULL; + static void (*externalPackageURICallback)(const uint8_t* buffer, uint16_t length) = NULL; + static void (*externalUpdateCallback)(void) = NULL; + static void (*externalNotificationCallback)(void) = NULL; + + /* Callback structs for delayed response. + * + * There needs to be one per callback type to avoid collisions between different operations. + */ + static arm_uc_callback_t callbackNodePackage = { NULL, 0, NULL, 0 }; + static arm_uc_callback_t callbackNodePackageURI = { NULL, 0, NULL, 0 }; + static arm_uc_callback_t callbackNodeResourceUpdate = { NULL, 0, NULL, 0 }; +} + +/** + * @brief Initialize LWM2M Firmware Update Object + * @details Sets up LWM2M object with accompanying resources. + */ +void FirmwareUpdateResource::Initialize(void) +{ + static bool initialized = false; + + if (!initialized) + { + initialized = true; + + /* The LWM2M Firmware Update Object is at /5 */ + updateObject = M2MInterfaceFactory::create_object("5"); + + if (updateObject) + { + /* Create first (and only) instance /5/0 */ + M2MObjectInstance* updateInstance = updateObject->create_object_instance(); + + if (updateInstance) + { + /* Set observable so the Portal can read it */ + updateInstance->set_observable(true); + + /* Default values are non-standard, but the standard has no + values for indicating that the device is initializing. + */ + uint8_t defaultValue[] = {"-1"}; + uint8_t defaultVersion[] = {"-1"}; + + /* Create Package resource /5/0/0 */ + resourcePackage = updateInstance->create_dynamic_resource( + "0", "Package", M2MResourceInstance::OPAQUE, false); + if (resourcePackage) + { + /* This should be PUT according to the standard but + Connector client doesn't support callbacks for PUT. + */ + resourcePackage->set_operation(M2MBase::POST_ALLOWED); + resourcePackage->set_execute_function(packageCallback); + + /* The delayed response if for processing heavier loads */ + resourcePackage->set_delayed_response(true); + } + + /* Create Package URI resource /5/0/1 */ + resourcePackageURI = updateInstance->create_dynamic_resource( + "1", "PackageURI", M2MResourceInstance::STRING, false); + if (resourcePackageURI) + { + resourcePackageURI->set_operation(M2MBase::POST_ALLOWED); + resourcePackageURI->set_execute_function(packageURICallback); + resourcePackageURI->set_delayed_response(true); + } + + /* Create Update resource /5/0/2 */ + resourceUpdate = updateInstance->create_dynamic_resource( + "2", "Update", M2MResourceInstance::BOOLEAN, false); + if (resourceUpdate) + { + resourceUpdate->set_operation(M2MBase::POST_ALLOWED); + resourceUpdate->set_execute_function(updateCallback); + resourceUpdate->set_delayed_response(true); + } + + /* Create State resource /5/0/3 */ + resourceState = updateInstance->create_dynamic_resource( + "3", "State", M2MResourceInstance::INTEGER, true); + if (resourceState) + { + resourceState->set_operation(M2MBase::GET_ALLOWED); + resourceState->set_notification_sent_callback(notificationCallback); + resourceState->set_value(defaultValue, sizeof(defaultValue) - 1); + } + + /* Create Update Result resource /5/0/5 */ + resourceResult = updateInstance->create_dynamic_resource( + "5", "UpdateResult", M2MResourceInstance::INTEGER, true); + if (resourceResult) + { + resourceResult->set_operation(M2MBase::GET_ALLOWED); + resourceResult->set_notification_sent_callback(notificationCallback); + resourceResult->set_value(defaultValue, sizeof(defaultValue) - 1); + } + + /* Create PkgName resource /5/0/6 */ + resourceName = updateInstance->create_dynamic_resource( + "6", "PkgName", M2MResourceInstance::STRING, true); + if (resourceName) + { + resourceName->set_operation(M2MBase::GET_ALLOWED); + resourceName->set_value(defaultVersion, sizeof(defaultVersion) - 1); + } + + /* Create PkgVersion resource /5/0/7 */ + resourceVersion = updateInstance->create_dynamic_resource( + "7", "PkgVersion", M2MResourceInstance::STRING, true); + if (resourceVersion) + { + resourceVersion->set_operation(M2MBase::GET_ALLOWED); + resourceVersion->set_value(defaultVersion, sizeof(defaultVersion) - 1); + } + } + } + } +} + +M2MObject* FirmwareUpdateResource::getObject() +{ + Initialize(); + + return updateObject; +} + +void FirmwareUpdateResource::packageCallback(void* _parameters) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::packageCallback"); + + if (_parameters && externalPackageCallback) + { + /* recast parameter */ + M2MResource::M2MExecuteParameter* parameters = + static_cast<M2MResource::M2MExecuteParameter*>(_parameters); + + /* read payload */ + const uint8_t* buffer = parameters->get_argument_value(); + uint16_t length = parameters->get_argument_value_length(); + + /* invoke external callback function */ + externalPackageCallback(buffer, length); + + /* schedule delayed response */ + ARM_UC_PostCallback(&callbackNodePackage, + FirmwareUpdateResource::sendDelayedResponseTask, + FirmwareUpdateResource::ResourcePackage); + } +} + +void FirmwareUpdateResource::packageURICallback(void* _parameters) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::packageURICallback"); + + if (_parameters && externalPackageURICallback) + { + /* recast parameter */ + M2MResource::M2MExecuteParameter* parameters = + static_cast<M2MResource::M2MExecuteParameter*>(_parameters); + + /* read payload */ + const uint8_t* buffer = parameters->get_argument_value(); + uint16_t length = parameters->get_argument_value_length(); + + /* invoke external callback function */ + externalPackageURICallback(buffer, length); + + /* schedule delayed response */ + ARM_UC_PostCallback(&callbackNodePackageURI, + FirmwareUpdateResource::sendDelayedResponseTask, + FirmwareUpdateResource::ResourcePackageURI); + } +} + +void FirmwareUpdateResource::updateCallback(void* _parameters) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::updateCallback"); + + (void) _parameters; + + if (externalUpdateCallback) + { + /* invoke external callback function */ + externalUpdateCallback(); + + /* schedule delayed response */ + ARM_UC_PostCallback(&callbackNodeResourceUpdate, + FirmwareUpdateResource::sendDelayedResponseTask, + FirmwareUpdateResource::ResourceUpdate); + } +} + +void FirmwareUpdateResource::notificationCallback(void) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::notificationCallback"); + + if (externalNotificationCallback) + { + externalNotificationCallback(); + } +} + +void FirmwareUpdateResource::sendDelayedResponseTask(uint32_t parameter) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::sendDelayedResponseTask"); + + switch (parameter) + { + case FirmwareUpdateResource::ResourcePackage: + UC_SRCE_TRACE("resourcePackage->send_delayed_post_response"); + resourcePackage->send_delayed_post_response(); + break; + case FirmwareUpdateResource::ResourcePackageURI: + UC_SRCE_TRACE("resourcePackageURI->send_delayed_post_response"); + resourcePackageURI->send_delayed_post_response(); + break; + case FirmwareUpdateResource::ResourceUpdate: + UC_SRCE_TRACE("resourceUpdate->send_delayed_post_response"); + resourceUpdate->send_delayed_post_response(); + break; + default: + UC_SRCE_ERR_MSG("unsupported resource"); + break; + } +} + +/*****************************************************************************/ +/* Update Client Source */ +/*****************************************************************************/ + +/* Add callback for resource /5/0/0, Package */ +int32_t FirmwareUpdateResource::addPackageCallback(void (*cb)(const uint8_t* buffer, uint16_t length)) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::addPackageCallback: %p", cb); + + externalPackageCallback = cb; + + return ARM_UCS_LWM2M_INTERNAL_SUCCESS; +} + +/* Add callback for resource /5/0/1, Package URI */ +int32_t FirmwareUpdateResource::addPackageURICallback(void (*cb)(const uint8_t* buffer, uint16_t length)) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::addPackageURICallback: %p", cb); + + externalPackageURICallback = cb; + + return ARM_UCS_LWM2M_INTERNAL_SUCCESS; +} + +/* Add callback for resource /5/0/2, Update */ +int32_t FirmwareUpdateResource::addUpdateCallback(void (*cb)(void)) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::addUpdateCallback: %p", cb); + + externalUpdateCallback = cb; + + return ARM_UCS_LWM2M_INTERNAL_SUCCESS; +} + +/* Add callback for when send{State, UpdateResult} is done */ +int32_t FirmwareUpdateResource::addNotificationCallback(void (*cb)(void)) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::addNotificationCallback: %p", cb); + + externalNotificationCallback = cb; + + return ARM_UCS_LWM2M_INTERNAL_SUCCESS; +} + +/*****************************************************************************/ +/* Update Client Status */ +/*****************************************************************************/ + +/* Send state for resource /5/0/3, State */ +int32_t FirmwareUpdateResource::sendState(arm_ucs_lwm2m_state_t state) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::sendState"); + + int32_t result = ARM_UCS_LWM2M_INTERNAL_ERROR; + + if (state <= ARM_UCS_LWM2M_STATE_LAST) + { + /* valid states: 0-3 */ + uint8_t value[2]; + snprintf((char*)value, 2, "%d", state); + resourceState->set_value(value, 1); + + result = ARM_UCS_LWM2M_INTERNAL_SUCCESS; + } + + return result; +} + +/* Send result for resource /5/0/5, Update Result */ +int32_t FirmwareUpdateResource::sendUpdateResult(arm_ucs_lwm2m_result_t updateResult) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::sendUpdateResult"); + + int32_t result = ARM_UCS_LWM2M_INTERNAL_ERROR; + + if (updateResult <= ARM_UCS_LWM2M_RESULT_LAST) + { + /* valid results: 0-8 */ + uint8_t value[2]; + snprintf((char*)value, 2, "%d", updateResult); + resourceResult->set_value(value, 1); + + result = ARM_UCS_LWM2M_INTERNAL_SUCCESS; + } + + return result; +} + +/* Send name for resource /5/0/6 PkgName */ +int32_t FirmwareUpdateResource::sendPkgName(const uint8_t* name, uint16_t length) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::sendPkgName"); + + int32_t result = ARM_UCS_LWM2M_INTERNAL_ERROR; + + /* the maximum length is defined in the OMA LWM2M standard. */ + if ((name != NULL) && (length <= 255)) + { + uint8_t value[64] = { 0 }; + uint8_t index = 0; + + /* convert to printable characters using lookup table */ + for ( ; (index < 32) && (index < length); index++) + { + value[2 * index ] = arm_uc_hex_table[name[index] >> 4]; + value[2 * index + 1] = arm_uc_hex_table[name[index] & 0x0F]; + } + + resourceName->set_value(value, 2 * index); + + result = ARM_UCS_LWM2M_INTERNAL_SUCCESS; + } + + return result; +} + +/* Send version for resource /5/0/7, PkgVersion */ +int32_t FirmwareUpdateResource::sendPkgVersion(uint64_t version) +{ + UC_SRCE_TRACE("FirmwareUpdateResource::sendPkgVersion"); + + uint8_t value[21] = { 0 }; + uint8_t length = snprintf((char*) value, 21, "%llu" , version); + resourceVersion->set_value(value, length); + + return ARM_UCS_LWM2M_INTERNAL_SUCCESS; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/lwm2m-control.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/lwm2m-control.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,41 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-lwm2m/lwm2m-control.h" +#include "update-client-lwm2m/FirmwareUpdateResource.h" + +/** + * @brief Set callback function for externally triggering an update. + * @details The callback function is called when an external trigger + * is fired. The callback function should force an update. + * + * @param callback Function pointer. + */ +arm_uc_error_t ARM_UC_CONTROL_SetOverrideCallback(void (*callback)(void)) +{ + arm_uc_error_t retval = { .code = ERR_INVALID_PARAMETER }; + + int32_t result = FirmwareUpdateResource::addUpdateCallback(callback); + + if (result == 0) + { + retval.code = ERR_NONE; + } + + return retval; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/lwm2m-monitor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/lwm2m-monitor.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,337 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-lwm2m/lwm2m-monitor.h" +#include "update-client-lwm2m/FirmwareUpdateResource.h" +#include "update-client-lwm2m/DeviceMetadataResource.h" + +/** + * @brief Get driver version. + * @return Driver version. + */ +uint32_t ARM_UCS_LWM2M_MONITOR_GetVersion(void) +{ + return 0; +} + +/** + * @brief Get Source capabilities. + * @return Struct containing capabilites. See definition above. + */ +ARM_MONITOR_CAPABILITIES ARM_UCS_LWM2M_MONITOR_GetCapabilities(void) +{ + ARM_MONITOR_CAPABILITIES result = { .state = 1, + .result = 1, + .version = 1 }; + + return result; +} + +/** + * @brief Initialize Monitor. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_MONITOR_Initialize(void (*notification_handler)(void)) +{ + arm_uc_error_t retval = { .code = SRCE_ERR_NONE }; + + FirmwareUpdateResource::Initialize(); + FirmwareUpdateResource::addNotificationCallback(notification_handler); + + DeviceMetadataResource::Initialize(); + + return retval; +} + +/** + * @brief Uninitialized Monitor. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_MONITOR_Uninitialize(void) +{ + arm_uc_error_t retval = { .code = SRCE_ERR_NONE }; + + return retval; +} + +/** + * @brief Send Update Client state. + * @details From the OMA LWM2M Technical Specification: + * + * Indicates current state with respect to this firmware update. + * This value is set by the LWM2M Client. + * 0: Idle (before downloading or after successful updating) + * 1: Downloading (The data sequence is on the way) + * 2: Downloaded + * 3: Updating + * + * If writing the firmware package to Package Resource is done, + * or, if the device has downloaded the firmware package from the + * Package URI the state changes to Downloaded. + * + * If writing an empty string to Package Resource is done or + * writing an empty string to Package URI is done, the state + * changes to Idle. + * + * When in Downloaded state, and the executable Resource Update is + * triggered, the state changes to Updating. + * If the Update Resource failed, the state returns at Downloaded. + * If performing the Update Resource was successful, the state + * changes from Updating to Idle. + * + * @param state Valid states: ARM_UC_MONITOR_STATE_IDLE + * ARM_UC_MONITOR_STATE_DOWNLOADING + * ARM_UC_MONITOR_STATE_DOWNLOADED + * ARM_UC_MONITOR_STATE_UPDATING + * + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_MONITOR_SendState(arm_uc_monitor_state_t state) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + int32_t retval = -1; + + switch (state) + { + case ARM_UC_MONITOR_STATE_IDLE: + retval = FirmwareUpdateResource::sendState( + FirmwareUpdateResource::ARM_UCS_LWM2M_STATE_IDLE); + break; + case ARM_UC_MONITOR_STATE_DOWNLOADING: + retval = FirmwareUpdateResource::sendState( + FirmwareUpdateResource::ARM_UCS_LWM2M_STATE_DOWNLOADING); + break; + case ARM_UC_MONITOR_STATE_DOWNLOADED: + retval = FirmwareUpdateResource::sendState( + FirmwareUpdateResource::ARM_UCS_LWM2M_STATE_DOWNLOADED); + break; + case ARM_UC_MONITOR_STATE_UPDATING: + retval = FirmwareUpdateResource::sendState( + FirmwareUpdateResource::ARM_UCS_LWM2M_STATE_UPDATING); + break; + default: + break; + } + + if (retval == 0) + { + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Send update result. + * @details From the OMA LWM2M Technical Specification: + * + * Contains the result of downloading or updating the firmware + * 0: Initial value. Once the updating process is initiated + * (Download /Update), this Resource MUST be reset to Initial + * value. + * 1: Firmware updated successfully, + * 2: Not enough storage for the new firmware package. + * 3. Out of memory during downloading process. + * 4: Connection lost during downloading process. + * 5: CRC check failure for new downloaded package. + * 6: Unsupported package type. + * 7: Invalid URI + * 8: Firmware update failed + * + * This Resource MAY be reported by sending Observe operation. + * + * @param result Valid results: ARM_UC_MONITOR_RESULT_INITIAL + * ARM_UC_MONITOR_RESULT_SUCCESS + * ARM_UC_MONITOR_RESULT_ERROR_STORAGE + * ARM_UC_MONITOR_RESULT_ERROR_MEMORY + * ARM_UC_MONITOR_RESULT_ERROR_CONNECTION + * ARM_UC_MONITOR_RESULT_ERROR_CRC + * ARM_UC_MONITOR_RESULT_ERROR_TYPE + * ARM_UC_MONITOR_RESULT_ERROR_URI + * ARM_UC_MONITOR_RESULT_ERROR_UPDATE + * + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_MONITOR_SendUpdateResult(arm_uc_monitor_result_t updateResult) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + int32_t retval = -1; + + switch (updateResult) + { + case ARM_UC_MONITOR_RESULT_INITIAL: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_INITIAL); + break; + case ARM_UC_MONITOR_RESULT_SUCCESS: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_SUCCESS); + break; + case ARM_UC_MONITOR_RESULT_ERROR_STORAGE: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_ERROR_STORAGE); + break; + case ARM_UC_MONITOR_RESULT_ERROR_MEMORY: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_ERROR_MEMORY); + break; + case ARM_UC_MONITOR_RESULT_ERROR_CONNECTION: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_ERROR_CONNECTION); + break; + case ARM_UC_MONITOR_RESULT_ERROR_CRC: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_ERROR_CRC); + break; + case ARM_UC_MONITOR_RESULT_ERROR_TYPE: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_ERROR_TYPE); + break; + case ARM_UC_MONITOR_RESULT_ERROR_URI: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_ERROR_URI); + break; + case ARM_UC_MONITOR_RESULT_ERROR_UPDATE: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_ERROR_UPDATE); + break; + case ARM_UC_MONITOR_RESULT_ERROR_HASH: + retval = FirmwareUpdateResource::sendUpdateResult( + FirmwareUpdateResource::ARM_UCS_LWM2M_RESULT_ERROR_HASH); + break; + default: + break; + } + + if (retval == 0) + { + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Send current firmware name. + * @details The firmware name is the SHA256 hash. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_MONITOR_SendName(arm_uc_buffer_t* name) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + int32_t retval = -1; + + if (name && name->ptr) + { + retval = FirmwareUpdateResource::sendPkgName(name->ptr, name->size); + } + + if (retval == 0) + { + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Send current firmware version. + * @details The firmware version is the timestamp from the manifest that + * authorized the firmware. + * + * @param version Timestamp, 64 bit unsigned integer. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_MONITOR_SendVersion(uint64_t version) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + int32_t retval = FirmwareUpdateResource::sendPkgVersion(version); + + if (retval == 0) + { + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Set the bootloader hash. + * @details The bootloader hash is a hash of the bootloader. This is + * used for tracking the version of the bootloader used. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_MONITOR_SetBootloaderHash(arm_uc_buffer_t* hash) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + int32_t retval = DeviceMetadataResource::setBootloaderHash(hash); + + if (retval == 0) + { + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Set the OEM bootloader hash. + * @details If the end-user has modified the bootloader the hash of the + * modified bootloader can be set here. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_MONITOR_SetOEMBootloaderHash(arm_uc_buffer_t* hash) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + int32_t retval = DeviceMetadataResource::setOEMBootloaderHash(hash); + + if (retval == 0) + { + result.code = ERR_NONE; + } + + return result; +} + +ARM_UPDATE_MONITOR ARM_UCS_LWM2M_MONITOR = +{ + .GetVersion = ARM_UCS_LWM2M_MONITOR_GetVersion, + .GetCapabilities = ARM_UCS_LWM2M_MONITOR_GetCapabilities, + .Initialize = ARM_UCS_LWM2M_MONITOR_Initialize, + .Uninitialize = ARM_UCS_LWM2M_MONITOR_Uninitialize, + + .SendState = ARM_UCS_LWM2M_MONITOR_SendState, + .SendUpdateResult = ARM_UCS_LWM2M_MONITOR_SendUpdateResult, + .SendName = ARM_UCS_LWM2M_MONITOR_SendName, + .SendVersion = ARM_UCS_LWM2M_MONITOR_SendVersion, + + .SetBootloaderHash = ARM_UCS_LWM2M_MONITOR_SetBootloaderHash, + .SetOEMBootloaderHash = ARM_UCS_LWM2M_MONITOR_SetOEMBootloaderHash +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/lwm2m-source.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/source/lwm2m-source.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,404 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-common/arm_uc_common.h" +#include "update-client-lwm2m/lwm2m-source.h" +#include "update-client-lwm2m/FirmwareUpdateResource.h" +#include "update-client-lwm2m/DeviceMetadataResource.h" + + +/* forward declaration */ +static void ARM_UCS_PackageCallback(const uint8_t* buffer, uint16_t length); + +/* local copy of the received manifest */ +static uint8_t* arm_ucs_manifest_buffer = NULL; +static uint16_t arm_ucs_manifest_length = 0; + +/* callback function pointer and struct */ +static void (*ARM_UCS_EventHandler)(uint32_t event) = 0; +static arm_uc_callback_t callbackNodeManifest = { NULL, 0, NULL, 0 }; +static arm_uc_callback_t callbackNodeNotification = { NULL, 0, NULL, 0 }; + +/** + * @brief Get driver version. + * @return Driver version. + */ +uint32_t ARM_UCS_LWM2M_SOURCE_GetVersion(void) +{ + return 0; +} + +/** + * @brief Get Source capabilities. + * @return Struct containing capabilites. See definition above. + */ +ARM_SOURCE_CAPABILITIES ARM_UCS_LWM2M_SOURCE_GetCapabilities(void) +{ + ARM_SOURCE_CAPABILITIES result = { .notify = 0, + .manifest_default = 0, + .manifest_url = 0, + .firmware = 0, + .keytable = 0 }; + + /* the event handler must be set before module can be used */ + if (ARM_UCS_EventHandler != 0) + { + result.notify = 1; + result.manifest_default = 1; + } + + return result; +} + +/** + * @brief Initialize Source. + * @details Function pointer to event handler is passed as argument. + * + * @param cb_event Function pointer to event handler. See events above. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_Initialize(ARM_SOURCE_SignalEvent_t cb_event) +{ + UC_SRCE_TRACE("ARM_UCS_LWM2M_SOURCE_Initialize: %p", cb_event); + + arm_uc_error_t result = { .code = SRCE_ERR_INVALID_PARAMETER }; + + if (cb_event != 0) + { + /* store callback handler */ + ARM_UCS_EventHandler = cb_event; + + /* Initialize LWM2M Firmware Update Object */ + FirmwareUpdateResource::Initialize(); + + /* Register callback handler */ + FirmwareUpdateResource::addPackageCallback(ARM_UCS_PackageCallback); + + DeviceMetadataResource::Initialize(); + + result.code = SRCE_ERR_NONE; + } + + return result; +} + +/** + * @brief Uninitialized Source. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_Uninitialize(void) +{ + arm_uc_error_t retval = { .code = SRCE_ERR_NONE }; + + return retval; +} + +/** + * @brief Cost estimation for retrieving manifest from the default location. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestDefaultCost(uint32_t* cost) +{ + arm_uc_error_t result = { .code = SRCE_ERR_INVALID_PARAMETER }; + + if (cost != 0) + { + /* set cost to 0 when manifest is cached */ + if (arm_ucs_manifest_buffer && arm_ucs_manifest_length) + { + *cost = 0; + } + /* set cost to 0xFFFFFFFF when manifest has been read */ + else + { + *cost = 0xFFFFFFFF; + } + + result.code = SRCE_ERR_NONE; + } + + return result; +} + +/** + * @brief Retrieve manifest from the default location. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param buffer Struct containing byte array, maximum size, and actual size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestDefault(arm_uc_buffer_t* buffer, + uint32_t offset) +{ + arm_uc_error_t result = { .code = SRCE_ERR_INVALID_PARAMETER }; + + /* copy manifest from cache into buffer */ + if ((buffer != NULL) && + (buffer->ptr != NULL) && + (arm_ucs_manifest_buffer != NULL) && + (arm_ucs_manifest_length != 0) && + (offset < arm_ucs_manifest_length)) + { + /* remaining length based on offset request */ + uint16_t length = arm_ucs_manifest_length - offset; + + /* set actual length based on buffer size */ + if (length > buffer->size_max) + { + length = buffer->size_max; + } + + /* size check */ + if (length > 0) + { + /* copy manifest from local buffer to external buffer */ + memcpy(buffer->ptr, &arm_ucs_manifest_buffer[offset], length); + buffer->size = length; + + /* delete local buffer once the entire manifest has been read */ + if (offset + length >= arm_ucs_manifest_length) + { + delete[] arm_ucs_manifest_buffer; + arm_ucs_manifest_buffer = NULL; + arm_ucs_manifest_length = 0; + } + + result.code = SRCE_ERR_NONE; + + /* signal event handler that manifest has been copied to buffer */ + if (ARM_UCS_EventHandler) + { + ARM_UC_PostCallback(&callbackNodeManifest, + ARM_UCS_EventHandler, + EVENT_MANIFEST); + } + } + } + + return result; +} + +static void ARM_UCS_PackageCallback(const uint8_t* buffer, uint16_t length) +{ + uint32_t event_code = EVENT_ERROR; + + if (arm_ucs_manifest_buffer) + { + UC_SRCE_ERR_MSG("received new manifest before reading the old one"); + + /* delete old buffer to make space for the new one */ + delete[] arm_ucs_manifest_buffer; + arm_ucs_manifest_length = 0; + } + + /* allocate a local buffer of the same size as the manifest */ + arm_ucs_manifest_buffer = new uint8_t[length]; + + if (arm_ucs_manifest_buffer) + { + /* copy manifest from payload to local buffer */ + memcpy(arm_ucs_manifest_buffer, buffer, length); + arm_ucs_manifest_length = length; + + event_code = EVENT_NOTIFICATION; + } + + /* signal event handler with result */ + if (ARM_UCS_EventHandler) + { + ARM_UC_PostCallback(&callbackNodeNotification, + ARM_UCS_EventHandler, + event_code); + } +} + +/*****************************************************************************/ +/* Capabilities not supported by this source */ +/*****************************************************************************/ + +/** + * @brief Cost estimation for retrieving manifest from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param uri URI struct with manifest location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestURLCost(arm_uc_uri_t* uri, + uint32_t* cost) +{ + (void) uri; + (void) cost; + + arm_uc_error_t result = { .code = SRCE_ERR_INVALID_PARAMETER }; + + /* not supported - return default cost regardless of actual uri location */ + if (cost) + { + *cost = 0xFFFFFFFF; + result.code = SRCE_ERR_NONE; + } + + return result; +} + +/** + * @brief Cost estimation for retrieving firmware from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with firmware location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost(arm_uc_uri_t* uri, + uint32_t* cost) +{ + (void) uri; + (void) cost; + + arm_uc_error_t result = { .code = SRCE_ERR_INVALID_PARAMETER }; + + /* not supported - return default cost regardless of actual uri location */ + if (cost != 0) + { + *cost = 0xFFFFFFFF; + result.code = SRCE_ERR_NONE; + } + + return result; +} + +/** + * @brief Cost estimation for retrieving key table from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with keytable location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetKeytableURLCost(arm_uc_uri_t* uri, + uint32_t* cost) +{ + (void) uri; + (void) cost; + + arm_uc_error_t result = { .code = SRCE_ERR_INVALID_PARAMETER }; + + /* not supported - return default cost regardless of actual uri location */ + if ((uri != 0) && (cost != 0)) + { + *cost = 0xFFFFFFFF; + result.code = SRCE_ERR_NONE; + } + + return result; +} + +/** + * @brief Retrieve manifest from URL. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param uri URI struct with manifest location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetManifestURL(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer, + uint32_t offset) +{ + (void) uri; + (void) buffer; + (void) offset; + + arm_uc_error_t retval = { .code = SRCE_ERR_INVALID_PARAMETER }; + + return retval; +} + +/** + * @brief Retrieve firmware fragment. + * @details Firmware fragment is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with firmware location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Firmware offset to retrieve fragment from. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer, + uint32_t offset) +{ + (void) uri; + (void) buffer; + (void) offset; + + arm_uc_error_t retval = { .code = SRCE_ERR_INVALID_PARAMETER }; + + return retval; +} + +/** + * @brief Retrieve a key table from a URL. + * @details Key table is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with keytable location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_LWM2M_SOURCE_GetKeytableURL(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer) +{ + (void) uri; + (void) buffer; + + arm_uc_error_t retval = { .code = SRCE_ERR_INVALID_PARAMETER }; + + return retval; +} + +ARM_UPDATE_SOURCE ARM_UCS_LWM2M_SOURCE = +{ + .GetVersion = ARM_UCS_LWM2M_SOURCE_GetVersion, + .GetCapabilities = ARM_UCS_LWM2M_SOURCE_GetCapabilities, + .Initialize = ARM_UCS_LWM2M_SOURCE_Initialize, + .Uninitialize = ARM_UCS_LWM2M_SOURCE_Uninitialize, + .GetManifestDefaultCost = ARM_UCS_LWM2M_SOURCE_GetManifestDefaultCost, + .GetManifestURLCost = ARM_UCS_LWM2M_SOURCE_GetManifestURLCost, + .GetFirmwareURLCost = ARM_UCS_LWM2M_SOURCE_GetFirmwareURLCost, + .GetKeytableURLCost = ARM_UCS_LWM2M_SOURCE_GetKeytableURLCost, + .GetManifestDefault = ARM_UCS_LWM2M_SOURCE_GetManifestDefault, + .GetManifestURL = ARM_UCS_LWM2M_SOURCE_GetManifestURL, + .GetFirmwareFragment = ARM_UCS_LWM2M_SOURCE_GetFirmwareFragment, + .GetKeytableURL = ARM_UCS_LWM2M_SOURCE_GetKeytableURL +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/DeviceMetadataResource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/DeviceMetadataResource.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,41 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ARM_UCS_DEVICE_METADATA_RESOURCE_H__ +#define __ARM_UCS_DEVICE_METADATA_RESOURCE_H__ + +#include "update-client-common/arm_uc_common.h" + +#include "mbed-client/m2minterfacefactory.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mobject.h" + +namespace DeviceMetadataResource { + + void Initialize(void); + + M2MObject* getObject(void); + + /* set bootloader hash resource /10255/0/1 */ + int32_t setBootloaderHash(arm_uc_buffer_t* hash); + + /* set OEM bootloader hash resource /10255/0/2 */ + int32_t setOEMBootloaderHash(arm_uc_buffer_t* hash); +} + +#endif // __ARM_UCS_DEVICE_METADATA_RESOURCE_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/FirmwareUpdateResource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/FirmwareUpdateResource.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,81 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ARM_UCS_FIRMWARE_UPDATE_RESOURCE_H__ +#define __ARM_UCS_FIRMWARE_UPDATE_RESOURCE_H__ + +#include "mbed-client/m2minterfacefactory.h" +#include "mbed-client/m2mresource.h" +#include "mbed-client/m2mobject.h" + +namespace FirmwareUpdateResource { + + typedef enum { + ARM_UCS_LWM2M_STATE_FIRST = 0, + ARM_UCS_LWM2M_STATE_IDLE = ARM_UCS_LWM2M_STATE_FIRST, + ARM_UCS_LWM2M_STATE_DOWNLOADING = 1, + ARM_UCS_LWM2M_STATE_DOWNLOADED = 2, + ARM_UCS_LWM2M_STATE_UPDATING = 3, + ARM_UCS_LWM2M_STATE_LAST = ARM_UCS_LWM2M_STATE_UPDATING + } arm_ucs_lwm2m_state_t; + + typedef enum { + ARM_UCS_LWM2M_RESULT_FIRST = 0, + ARM_UCS_LWM2M_RESULT_INITIAL = ARM_UCS_LWM2M_RESULT_FIRST, + ARM_UCS_LWM2M_RESULT_SUCCESS = 1, + ARM_UCS_LWM2M_RESULT_ERROR_STORAGE = 2, + ARM_UCS_LWM2M_RESULT_ERROR_MEMORY = 3, + ARM_UCS_LWM2M_RESULT_ERROR_CONNECTION = 4, + ARM_UCS_LWM2M_RESULT_ERROR_CRC = 5, + ARM_UCS_LWM2M_RESULT_ERROR_TYPE = 6, + ARM_UCS_LWM2M_RESULT_ERROR_URI = 7, + ARM_UCS_LWM2M_RESULT_ERROR_UPDATE = 8, + ARM_UCS_LWM2M_RESULT_ERROR_HASH = 9, + ARM_UCS_LWM2M_RESULT_LAST = ARM_UCS_LWM2M_RESULT_ERROR_HASH + } arm_ucs_lwm2m_result_t; + + void Initialize(void); + + M2MObject* getObject(void); + + /* Add callback for resource /5/0/0, Package */ + int32_t addPackageCallback(void (*cb)(const uint8_t* buffer, uint16_t length)); + + /* Add callback for resource /5/0/1, Package URI */ + int32_t addPackageURICallback(void (*cb)(const uint8_t* buffer, uint16_t length)); + + /* Add callback for resource /5/0/2, Update */ + int32_t addUpdateCallback(void (*cb)(void)); + + /* Add callback for when send{State, UpdateResult} is done */ + int32_t addNotificationCallback(void (*notification_handler)(void)); + + /* Send state for resource /5/0/3, State */ + int32_t sendState(arm_ucs_lwm2m_state_t state); + + /* Send result for resource /5/0/5, Update Result */ + int32_t sendUpdateResult(arm_ucs_lwm2m_result_t result); + + /* Send name for resource /5/0/6, PkgName */ + int32_t sendPkgName(const uint8_t* name, uint16_t length); + + /* Send version for resource /5/0/7, PkgVersion */ + int32_t sendPkgVersion(uint64_t version); +} + +#endif // __ARM_UCS_FIRMWARE_UPDATE_RESOURCE_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/lwm2m-control.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/lwm2m-control.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,41 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_LWM2M_CONTROL_H +#define ARM_UC_LWM2M_CONTROL_H + +#include "update-client-common/arm_uc_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set callback function for externally triggering an update. + * @details The callback function is called when an external trigger + * is fired. The callback function should force an update. + * + * @param callback Function pointer. + */ +arm_uc_error_t ARM_UC_CONTROL_SetOverrideCallback(void (*callback)(void)); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UCS_LWM2M_CONTROL_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/lwm2m-monitor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/lwm2m-monitor.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ARM_UCS_LWM2M_MONITOR_H__ +#define __ARM_UCS_LWM2M_MONITOR_H__ + +#include "update-client-monitor/arm_uc_monitor.h" + +extern ARM_UPDATE_MONITOR ARM_UCS_LWM2M_MONITOR; + +#endif // __ARM_UCS_LWM2M_MONITOR_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/lwm2m-source.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/update-client-lwm2m/lwm2m-source.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ARM_UCS_LWM2M_SOURCE_H__ +#define __ARM_UCS_LWM2M_SOURCE_H__ + +#include "update-client-source/arm_uc_source.h" + +extern ARM_UPDATE_SOURCE ARM_UCS_LWM2M_SOURCE; + +#endif // __ARM_UCS_LWM2M_SOURCE_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,2 @@ +test/* +*/test/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmCommon.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmCommon.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,34 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-manifest-manager/update-client-manifest-manager-context.h" + +#include "arm_uc_mmCommon.h" +#include "arm_uc_mmConfig.h" +#include "update-client-manifest-manager/update-client-manifest-types.h" + +#include <string.h> + +arm_uc_mmPersistentContext_t arm_uc_mmPersistentContext = { 0 }; +const size_t arm_uc_mmDynamicContextSize = sizeof(arm_uc_mmContext_t); + +#if ARM_UC_MANIFEST_MANAGER_TRACE_ENABLE +volatile uint8_t arm_uc_mm_gDebugLevel = 10; +#else +volatile uint8_t arm_uc_mm_gDebugLevel = 0; +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmCommon.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmCommon.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,64 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MANIFEST_MANAGER_COMMON_H +#define MANIFEST_MANAGER_COMMON_H + +#include "update-client-manifest-manager/update-client-manifest-types.h" +#include "update-client-common/arm_uc_trace.h" +#include <string.h> +#include <stdio.h> + +enum arm_uc_mmEvent { + ARM_UC_MM_EVENT_INVALID = 0, + ARM_UC_MM_EVENT_BEGIN, +}; + +#define ARM_UC_MM_DEBUG_LOG_LEVEL_NONE 0 +#define ARM_UC_MM_DEBUG_LOG_LEVEL_VALS 9 +#define ARM_UC_MM_DEBUG_LOG_LEVEL_STATES 10 + +#define ARRAY_SIZE(X)\ + (sizeof(X)/sizeof((X)[0])) + +#define ARM_UC_MM_SET_BUFFER(BUF,ARRAY)\ + do {\ + (BUF).ptr = (ARRAY);\ + (BUF).size = 0;\ + (BUF).size_max = sizeof(ARRAY);\ + } while(0) + +#define ARM_UC_MFST_SET_ERROR(VAR, ERROR)\ + do {\ + VAR.code = ERROR;\ + if (VAR.error != ERR_NONE) {\ + arm_uc_mmPersistentContext.errorFile = __FILE__;\ + arm_uc_mmPersistentContext.errorLine = __LINE__;\ + }\ + }while (0) + + +#if ARM_UC_MANIFEST_MANAGER_TRACE_ENABLE +extern volatile uint8_t arm_uc_mm_gDebugLevel; +#define ARM_UC_MM_DEBUG_LOG(LEVEL,...) \ + if(arm_uc_mm_gDebugLevel >= LEVEL) {printf(__VA_ARGS__);} +#else +#define ARM_UC_MM_DEBUG_LOG(LEVEL,...) +#endif + +#endif //MANIFEST_MANAGER_COMMON_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmConfig.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmConfig.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,62 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MANIFEST_MANAGER_CONFIG_H +#define MANIFEST_MANAGER_CONFIG_H + +#include <limits.h> + +#define MAX_HASH_BYTES 32 +#define MAX_SYMM_KEY_BYTES 16 +// #define ECC_SIG_BYTES 71 +#define MAX_URI_BYTES 128 + +#define MANIFEST_SUPPORTED_VERSION 1 +#define MANIFEST_MANAGER_NO_STORAGE 1 + +#ifndef ARM_UC_MM_ENABLE_TEST_VECTORS +#define ARM_UC_MM_ENABLE_TEST_VECTORS 0 +#endif + +#ifndef ARM_UC_MM_ENABLE_INSERT_TEST_VECTORS +#define ARM_UC_MM_ENABLE_INSERT_TEST_VECTORS 0 +#endif + +#define RFC_4122_BYTES (128/CHAR_BIT) +#define RFC_4122_WORDS (RFC_4122_BYTES/sizeof(uint32_t)) + +#define CERT_MAX_STORAGE 1024 +#define CA_PREFIX "com.arm.mbed.update.mm.ca" +#define MANIFEST_PREFIX "com.arm.mbed.update.mm.m" + +#define MANIFEST_ROLLBACK_PROTECTION 0 + +#define CFSTORE_HASH_ID_SIZE ((((256 + CHAR_BIT - 1) / CHAR_BIT + 2) / 3) * 4 + 1) + +#define MANIFEST_STORAGE_RETENTION_LEVEL ARM_RETENTION_NVM +// TODO: Enable ACLs for manifest storage +#define MANIFEST_STORAGE_ACLS_ENABLED 0 +// TODO: Enable lazy flush +#define MANIFEST_STORAGE_LAZY_FLUSH_ENABLED 0 +// TODO: Enable flush-on-close +#define MANIFEST_STORAGE_FLUSH_ON_CLOSE_ENABLED 0 +// TODO: Enable storage-detect +#define MANIFEST_STORAGE_STORAGE_DETECT_ENABLED 0 +// TODO: Enable async callbacks for config store +#define MFST_ASYNC_KV_ASYNC 1 +#endif // MANIFEST_MANAGER_CONFIG_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmCryptoUtils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmCryptoUtils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,509 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_mmCryptoUtils.h" +#include "arm_uc_mmCommon.h" +#include "arm_uc_mmConfig.h" +#include "arm_uc_mmDerManifestParser.h" +#include "update-client-common/arm_uc_crypto.h" + +#include "update-client-control-center/arm_uc_certificate.h" + +#include "arm_uc_mmDerManifestAccessors.h" +#include "update-client-manifest-manager/update-client-manifest-manager.h" + +#include <string.h> + +void ARM_UC_mmVerifySignatureEntry(uint32_t event); +/** + * @file Cryptographic utilities + * This file provides two primary APIs: + * * Verifying manifest hashes + * * Verifying manifest signatures + * + * Some utility functions used by other files in this module are also provided. + * + * Algorithm support: + * ECC is currently supported, but RSA is not. + * Currently, only ECC secp256r1 (prime256v1) is supported. + * Currently, only SHA256 is supported. + * HMAC is not yet supported. + */ + +/** + * @brief Returns the sizes of the cryptographic primitives used by the supplied manifest. + * @details Extracts the cryptomode field from a manifest and returns a struct that describes the size of cryptographic + * primitives used in the manifest. The supplied manifest must have been validated. No validation is performed + * by this function. + * + * @param[in] buffer A buffer that contains a validated manifest. + * @return A struct cryptsize, which contains the AES primitive sizes and SHA primitive size, both in bytes. + * An invalid cryptographic mode specifier will cause primitive sizes of `0` to be returned. + */ +struct cryptsize getCryptInfo(arm_uc_buffer_t* buffer) +{ + struct cryptsize cs = {0}; + uint32_t cryptoMode = 1U; // default SHA256 and ECC + ARM_UC_mmGetCryptoMode(buffer, &cryptoMode); + + switch(cryptoMode) + { + case MFST_CRYPT_SHA256_ECC_AES128_PSK: + // case MFST_CRYPT_SHA256_HMAC_AES128_PSK: + cs.aeslen = 128/CHAR_BIT; + // case MFST_CRYPT_SHA256_HMAC: + case MFST_CRYPT_SHA256: + cs.hashlen = 256/CHAR_BIT; + break; + case MFST_CRYPT_SHA256_ECC: + cs.hashlen = 256/CHAR_BIT; + default: + break; + } + return cs; +} + +/** + * @brief Converts a cryptographic mode enum to a structure with mode identifiers + * @details In order to simplify many tests, the cryptographic mode identifier is converted into a structure of mode + * identifiers, one for each cryptographic primitive. This allows other parts of the code to examine the mode + * of one particular primitive without testing against many enums. This function performs no validation. The + * calling function should have performed validation in advance. If the cryptoMode is unrecognized, then a + * return will be populated with 0 for every flag. + * + * HMAC modes are not currently supported. + * TODO: Convert flags to enums + * @param[in] cryptoMode The cryptographic mode enum that specifies the settings for each primitive + * @return A structure of flags that indicate the mode of: + * * Hash algorithm + * * MAC + * * Symmetric Encryption + * * Pre-shared keys + * * Public Key modes + */ +arm_uc_mm_crypto_flags_t ARM_UC_mmGetCryptoFlags(uint32_t cryptoMode) +{ + + switch(cryptoMode) { + case MFST_CRYPT_SHA256: + return (arm_uc_mm_crypto_flags_t) {.hash = 1U}; + // case MFST_CRYPT_SHA256_HMAC: + // return (arm_uc_mm_crypto_flags_t) {.hash = 1, .hmac = 1}; + // case MFST_CRYPT_SHA256_HMAC_AES128_PSK: + // return (arm_uc_mm_crypto_flags_t) {.hash = 1, .hmac = 1, .aes = 1, .psk = 1}; + case MFST_CRYPT_SHA256_ECC: + return (arm_uc_mm_crypto_flags_t) {.hash = 1U, .ecc = 1U}; + case MFST_CRYPT_SHA256_ECC_AES128_PSK: + return (arm_uc_mm_crypto_flags_t) {.hash = 1U, .ecc = 1U, .aes = 1U, .psk = 1U}; + } + return (arm_uc_mm_crypto_flags_t) {.hash = 0}; + +} + +/** + * @brief Extracts the hash of a manifest from the manifest wrapper. + * @details This is a utility function that is used to extract the hash of the manifest for signature validation. + * This function does not perform validation of the hash buffer, so the hash buffer is expected to be populated + * with a known-good hash buffer. Typically, this buffer will be stack-allocated. + * @param[in] buffer The manifest to parse + * @param[out] hash Output buffer object to fill with the hash + * @return MFST_ERR_NONE on success, or a parser error code otherwise + */ +arm_uc_error_t ARM_UC_mmGetManifestHashFromBin(arm_uc_buffer_t* buffer, arm_uc_buffer_t* hash) +{ + const uint32_t fieldID = ARM_UC_MM_DER_SIG_HASH; + int rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, hash); + if (rc) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} + +/** + * Utility function for printing the hex value of a buffer. Used only for debugging. + * @param buf [description] + */ +#if 0 +static void hexprint_buffer(arm_uc_buffer_t* buf) +{ + for (size_t i = 0; i < buf->size; i++) + { + printf("%02x", buf->ptr[i]); + } +} +#endif + +/** + * @brief ARM_UC_mmValidateManifestHash processes a manifest in order to validate its hash + * @details The manifest parser extracts the manifest hash, calculates the hash of the manifest, then compares it to the + * hash included in the manifest. + * + * The outer wrapper of the manifest is called a SignedResource. It contains a Resource object and a + * ResourceSignature object. The Resource object contains a Resource Type identifier, an optional URL, and + * either a manifest or binary data. + * + * This function extracts the Resource object and the ResourceSignature object so that the Resource can be + * hashed and verified against the hash in the ResourceSignature. + * + * TODO: The dependency on the cryptoMode contained within the manifest will be removed with the change to CMS + * First, the Resource object is extracted. Next, the cryptoMode is extracted from the Resource object. This + * requires that the Resource object be a Manifest. + * + * @param[in] buffer The buffer that contains the manifest to validate + * @retval MFST_ERR_NONE on success + * @retval MFST_ERR_CRYPTO_MODE if there is a cryptographic mode error + * @retval Otherwise, a DER Parser error can be expected + */ +arm_uc_error_t ARM_UC_mmValidateManifestHash(arm_uc_buffer_t* buffer) +{ + uint8_t localhash[MAX_HASH_BYTES]; ///< An array to store the locally calculated hash + arm_uc_buffer_t local = { ///< A buffer structure to use for the locally calculated hash + .size_max = MAX_HASH_BYTES, + .size = 0, + .ptr = localhash + }; + arm_uc_buffer_t remote = { ///< A buffer for the hash provided in the manifest + .size_max = MAX_HASH_BYTES, + .size = 0, + .ptr = NULL + }; + arm_uc_buffer_t resource = { ///< A buffer for the resource (the manifest) that is wrapped by a signature + .size_max = MAX_HASH_BYTES, + .size = 0, + .ptr = NULL + }; + arm_uc_mdHandle_t hDigest = 0; ///< This handle is for the digest algorithm + arm_uc_error_t err = {MFST_ERR_NONE}; ///< The return code variable + uint32_t cryptoMode = 0; ///< A temporary local copy of the crytpoMode + arm_uc_mdType_t mdType = 0; ///< A type designator for the type of hash in use + + // Extract the "resource" contained in the Signed Resource object + err = ARM_UC_mmDERSignedResourceGetSingleValue(buffer, ARM_UC_MM_DER_RESOURCE, &resource); + if (!err.error) + { + // Extract the hash from the manifest + err = ARM_UC_mmGetManifestHash(buffer, &remote); + } + if (!err.error) + { + // Extract the cryptographic mode from the manifest + err = ARM_UC_mmGetCryptoMode(buffer, &cryptoMode); + } + if (!err.error) + { + // Set the hash type identifier + switch(cryptoMode) + { + case MFST_CRYPT_SHA256_ECC_AES128_PSK: + case MFST_CRYPT_SHA256: + case MFST_CRYPT_SHA256_ECC: + mdType = ARM_UC_CU_SHA256; + break; + default: + err.code = MFST_ERR_CRYPTO_MODE; + break; + } + } + if (!err.error) + { + // Initialize the message digest API + err = ARM_UC_cryptoHashSetup(&hDigest, mdType); + } + if (!err.error) + { + // NOTE: If a hash accelerator is present on-chip, this could be converted from a blocking call to an + // asynchronous one. + // Hash the resource + // Keep Coverity quiet - it can't resolve some semantic conditions here. + if ( resource.ptr == NULL ) { + ARM_UC_SET_ERROR(err, MFST_ERR_NULL_PTR); + } else { + err = ARM_UC_cryptoHashUpdate(&hDigest, &resource); + } + } + if (!err.error) + { + // Extract the locally calculated hash from the hash API + err = ARM_UC_cryptoHashFinish(&hDigest, &local); + } + if (!err.error) + { + // Check that the hashes match + // Keep Coverity quiet - it can't resolve some semantic conditions here. + if ( remote.ptr == NULL ) { + ARM_UC_SET_ERROR(err, MFST_ERR_NULL_PTR); + } else if(ARM_UC_BinCompareCT(&local, &remote)) { + ARM_UC_SET_ERROR(err, MFST_ERR_HASH); + } + } + // Explicitly set the manifest manager's no-error code, rather than another module's, which may be present here. + if (!err.error) + { + ARM_UC_SET_ERROR(err, MFST_ERR_NONE); + } + return err; +} + +enum arm_uc_mmCertificateFetchEvents { + ARM_UC_MM_CERTIFICATE_FETCH_UNINIT, + ARM_UC_MM_CERTIFICATE_FETCH_SUCCESS, + ARM_UC_MM_CERTIFICATE_FETCH_MISMATCH, + ARM_UC_MM_CERTIFICATE_FETCH_ERROR, +}; + +/** + * @brief Validates one signature of a manifest, once the signing certificate has been found. + * @param buffer Holding buffer for the manifest to validate. + * @param ca Buffer holding the certificate to use in verification + * @param sigIndex Index of the manifest signature to verify with this certificate + * @retval MFST_ERR_DER_FORMAT on parse error + * @retval MFST_ERR_CERT_INVALID if the certificate is not valid + * @retval MFST_ERR_INVALID_SIGNATURE if the signature is invalid + * @retval MFST_ERR_NONE for a valid signature + */ +static arm_uc_error_t ARM_UC_mmValidateSignatureCert(arm_uc_buffer_t* buffer, arm_uc_buffer_t* ca, uint32_t sigIndex) +{ + const uint32_t fieldIDs[] = {ARM_UC_MM_DER_SIG_HASH, ARM_UC_MM_DER_SIG_SIGNATURES}; + arm_uc_buffer_t fields[ARRAY_SIZE(fieldIDs)]; + + // Get the signature list + int rc = ARM_UC_mmDERGetSignedResourceValues(buffer, ARRAY_SIZE(fieldIDs), fieldIDs, fields); + if (rc) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + + // Get the specified signature block + arm_uc_buffer_t sigblock; + rc = ARM_UC_mmDERGetSequenceElement(&fields[1], sigIndex, &sigblock); + if (rc) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + + // Load the specified signature out of the signature block + arm_uc_buffer_t sig; + const uint32_t sigID = ARM_UC_MM_DER_SIG_SIGNATURE; + rc = ARM_UC_mmDERParseTree(&arm_uc_mmSignatures[0], &sigblock, 1U, &sigID, &sig); + if (rc) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + + // Validate the signature + return ARM_UC_verifyPkSignature(ca, &fields[0], &sig); +} + +struct { + arm_uc_mm_validate_signature_context_t* ctx; + arm_uc_callback_t callbackStorage; +} arm_uc_mmSignatureVerificationContext; + + +/** + * @brief Callback function to continue signature verification once the certificate has been found + * @details This function should be called by the certificate lookup function, which is provided by the application. + * The certificate lookup function should call this callback regardless of success or failure so that errors + * can be reported correctly. + * + * Caveats: + * The certificate supplied here MUST be the same buffer as was provided to the certificate fetch function. + * The fingerprint supplied here MUST be the same buffer as was provided to the certificate fetch function. + * + * These requirements are in place to ensure that only one signature verification may be carried out at a time. + * + * Once the basic checks are performed in the callback, it schedules the manifest manager to execute later. + * + * @param status Error code provided by the certificat lookup function + * @param certificate Buffer containing the certificate + * @param fingerprint Buffer containing the certificate fingerprint + */ +void ARM_UC_mmCertificateCallback(arm_uc_error_t status, const arm_uc_buffer_t* certificate, const arm_uc_buffer_t* fingerprint) +{ + uint32_t event = ARM_UC_MM_CERTIFICATE_FETCH_UNINIT; + UC_MMGR_TRACE("%s (%u)\n", __PRETTY_FUNCTION__, (unsigned)event); + if (status.error == ERR_NONE) + { + // Verify that this is the same buffer as was provided to the certificate fetch function. + if (fingerprint != &arm_uc_mmSignatureVerificationContext.ctx->fingerprint || + certificate != &arm_uc_mmSignatureVerificationContext.ctx->cert) + { + event = ARM_UC_MM_CERTIFICATE_FETCH_MISMATCH; + } + else + { + event = ARM_UC_MM_CERTIFICATE_FETCH_SUCCESS; + } + } + else + { + // Store the error for later reporting + arm_uc_mmSignatureVerificationContext.ctx->storedError = status; + event = ARM_UC_MM_CERTIFICATE_FETCH_ERROR; + } + // Post the Manifest Manager state machine entry point to the Update Client event queue + UC_MMGR_TRACE("%s Posting ARM_UC_mmVerifySignatureEntry(%lu)\n", __PRETTY_FUNCTION__, event); + ARM_UC_PostCallback(&arm_uc_mmSignatureVerificationContext.callbackStorage, ARM_UC_mmVerifySignatureEntry, event); +} + +/** + * @brief State machine that controls the verification of signatures. + * @details First, the state machine attempts to fetch the certificate. When the certificate has been fetched, + * the state machine validates the signature, then alerts the calling application with the result. + * + * + * @param[in] ctx Context pointer for the state machine + * @param[in] event Event to move the state machine forward + * @retval MFST_ERR_NONE on success + * @retval MFST_ERR_PENDING when the validation has not completed and is waiting for external input + * (e.g. certificate fetching) + * @retval Another error code otherwise. + */ +static arm_uc_error_t ARM_UC_mmValidateSignatureFSM(arm_uc_mm_validate_signature_context_t* ctx, uint32_t event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + enum arm_uc_mm_pk_sig_state oldState; + UC_MMGR_TRACE("%s (%lu)\n", __PRETTY_FUNCTION__, event); + do + { + oldState = ctx->state; + UC_MMGR_TRACE("%s state:%u\n", __PRETTY_FUNCTION__, oldState); + switch(ctx->state) + { + case UCMM_PKSIG_STATE_FIND_CA: + // Start the search for a certificate + // This state transitions automatically to UCMM_PKSIG_STATE_FINDING_CA unless there is an error + err = ARM_UC_certificateFetch(&ctx->cert, + &ctx->fingerprint, + &ctx->certList, + ARM_UC_mmCertificateCallback); + if (err.error == ERR_NONE || err.code == MFST_ERR_PENDING) + { + ctx->state = UCMM_PKSIG_STATE_FINDING_CA; + err.code = MFST_ERR_PENDING; + } + break; + case UCMM_PKSIG_STATE_FINDING_CA: + // Wait the Certificate fetch to complete. On completion, this state decides what to do with the result. + switch(event) + { + // If the certificate was fetched successfully, proceed to signature verification + case ARM_UC_MM_CERTIFICATE_FETCH_SUCCESS: + err.code = MFST_ERR_NONE; + ctx->state = UCMM_PKSIG_STATE_CHECK; + break; + // If an error occured, extract the error. + case ARM_UC_MM_CERTIFICATE_FETCH_ERROR: + err = ctx->storedError; + break; + // Otherwise, report a bad event. + case ARM_UC_MM_CERTIFICATE_FETCH_UNINIT: + case ARM_UC_MM_CERTIFICATE_FETCH_MISMATCH: + default: + err.code = MFST_ERR_BAD_EVENT; + break; + } + break; + // Validate the signature + case UCMM_PKSIG_STATE_CHECK: + err = ARM_UC_mmValidateSignatureCert(ctx->manifest, + &ctx->cert, ctx->sigIndex); + if (err.code == MFST_ERR_NONE) + { + ctx->state = UCMM_PKSIG_STATE_IDLE; + } + break; + case UCMM_PKSIG_STATE_IDLE: + err.code = MFST_ERR_NONE; + // The Entry function will report success after this state exits. + break; + default: + err = (arm_uc_error_t){MFST_ERR_INVALID_STATE}; + break; + } + + } while (err.code == MFST_ERR_NONE && ctx->state != oldState); + UC_MMGR_TRACE("%s() return code: %c%c:%hu (%s)\n", + __PRETTY_FUNCTION__, err.modulecc[0], err.modulecc[1], err.error, ARM_UC_err2Str(err)); + return err; +} +/** + * @brief Start signature verification. + * @details This API initiates a signature verification. The actual signature verification is carried out by + * + * + * @param[in] ctx Signature validation context. This contains all the state used by the signature validator. + * @param[in] buffer A buffer containing the manifest to verify + * @param[in] certBuffer A temporary storage buffer for certificate fetching + * @param[in] sigIndex Index of the signature to verify. + * @retval MFST_ERR_NONE on success + * @retval MFST_ERR_PENDING when the validation has not completed and is waiting for external input + * (e.g. certificate fetching) + * @retval Another error code otherwise. + */ +arm_uc_error_t ARM_UC_mmValidateSignature(arm_uc_mm_validate_signature_context_t* ctx, + void (*applicationEventHandler)(uint32_t), + arm_uc_buffer_t* buffer, + arm_uc_buffer_t* certBuffer, + uint32_t sigIndex) +{ + UC_MMGR_TRACE("%s (%u)\n", __PRETTY_FUNCTION__, (unsigned)sigIndex); + arm_uc_error_t err = {MFST_ERR_NONE}; + if (ctx == NULL) + { + ARM_UC_SET_ERROR(err, MFST_ERR_NULL_PTR); + } + if (err.error == ERR_NONE) + { +#ifdef ATOMIC_QUEUE_CONFIG_ELEMENT_LOCK + arm_uc_mmSignatureVerificationContext.callbackStorage.lock = 0; +#endif + arm_uc_mmSignatureVerificationContext.ctx = ctx; + // Extract the certificate identifier from the manifest + err = ARM_UC_mmGetCertificateId(buffer, sigIndex, &arm_uc_mmSignatureVerificationContext.ctx->fingerprint); + UC_MMGR_TRACE("%s %c%c:%hu (%s)\n", "Error code:", err.modulecc[0], err.modulecc[1], err.error, ARM_UC_err2Str(err)); + } + if(err.error == 0 && ctx) + { + // Copy all the relevant inputs into the state variable + err.code = MFST_ERR_NONE; + arm_uc_mmSignatureVerificationContext.ctx->manifest = buffer; + arm_uc_mmSignatureVerificationContext.ctx->applicationEventHandler = applicationEventHandler; + arm_uc_mmSignatureVerificationContext.ctx->state = UCMM_PKSIG_STATE_FIND_CA; + arm_uc_mmSignatureVerificationContext.ctx->sigIndex = sigIndex; + ARM_UC_buffer_shallow_copy(&arm_uc_mmSignatureVerificationContext.ctx->cert, certBuffer); + UC_MMGR_TRACE("%s Posting ARM_UC_mmVerifySignatureEntry(%lu)\n", __PRETTY_FUNCTION__, ARM_UC_MM_EVENT_BEGIN); + ARM_UC_PostCallback(&arm_uc_mmSignatureVerificationContext.callbackStorage, ARM_UC_mmVerifySignatureEntry, ARM_UC_MM_EVENT_BEGIN); + } + UC_MMGR_TRACE("%s %c%c:%hu (%s)\n", __PRETTY_FUNCTION__, err.modulecc[0], err.modulecc[1], err.error, ARM_UC_err2Str(err)); + return err; +} + +/** + * @brief Main entry point for callbacks to enter the state machine. + * @details Calls the signature verification state machine. If the result is not Pending, calls the application event + * handler with a result code. + * Application event handler is invoked directly, not queued because this function should have minimal stack + * and it should be called directly from the event queue. + * @param[in] event Event to forward to the state machine + */ +void ARM_UC_mmVerifySignatureEntry(uint32_t event) +{ + UC_MMGR_TRACE("%s (%u)\n", __PRETTY_FUNCTION__, (unsigned)event); + arm_uc_error_t err = ARM_UC_mmValidateSignatureFSM(arm_uc_mmSignatureVerificationContext.ctx , event); + if (err.code != MFST_ERR_NONE && err.code != MFST_ERR_PENDING) + { + arm_uc_mmSignatureVerificationContext.ctx->storedError = err; + arm_uc_mmSignatureVerificationContext.ctx->applicationEventHandler(ARM_UC_MM_RC_ERROR); + } + if (err.code == MFST_ERR_NONE && arm_uc_mmSignatureVerificationContext.ctx->state == UCMM_PKSIG_STATE_IDLE) + { + // A callback is not posted since this runs inside + arm_uc_mmSignatureVerificationContext.ctx->applicationEventHandler(ARM_UC_MM_RC_DONE); + } + UC_MMGR_TRACE("%s %c%c:%hu (%s)\n", __PRETTY_FUNCTION__, err.modulecc[0], err.modulecc[1], err.error, ARM_UC_err2Str(err)); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmCryptoUtils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmCryptoUtils.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,49 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MANIFEST_MANAGER_CRYPTO_FSM_H +#define MANIFEST_MANAGER_CRYPTO_FSM_H + +#include "update-client-manifest-manager/update-client-manifest-manager-context.h" +#include "update-client-manifest-manager/update-client-manifest-types.h" + + +arm_uc_error_t ARM_UC_mmValidateManifestHash(arm_uc_buffer_t* buffer); +arm_uc_error_t ARM_UC_mmValidateSignature(arm_uc_mm_validate_signature_context_t* ctx, + void (*applicationEventHandler)(uint32_t), + arm_uc_buffer_t* buffer, + arm_uc_buffer_t* certBuffer, + uint32_t sigIndex); +arm_uc_error_t ARM_UC_mmGetManifestHashFromBin(arm_uc_buffer_t* buffer, arm_uc_buffer_t* hash); +void ARM_UC_mmGetFirmwareHashFromBin(arm_uc_buffer_t* manifest, arm_uc_buffer_t* hash); + + +struct cryptsize { + uint32_t hashlen; + uint32_t aeslen; +}; + +struct cryptsize getCryptInfo(arm_uc_buffer_t* buffer); +/** + * NOTE: This function does no validation. cryptomode must already have been validated by validateCryptoMode + * + * */ +arm_uc_mm_crypto_flags_t ARM_UC_mmGetCryptoFlags(uint32_t cryptoMode); + + +#endif // MANIFEST_MANAGER_CRYPTO_FSM_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmDerManifestAccessors.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmDerManifestAccessors.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,260 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_mmDerManifestAccessors.h" +#include "arm_uc_mmDerManifestParser.h" +#include <string.h> + + +arm_uc_error_t ARM_UC_wrapMbedTLSError(int32_t mt_err) { + return (arm_uc_error_t){.error = -mt_err, .module = MBED_TLS_ERROR_PREFIX}; +} + +arm_uc_error_t ARM_UC_mmDERSignedResourceGetSingleValue(arm_uc_buffer_t* buffer, const int32_t fieldID, arm_uc_buffer_t* val) +{ + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, val); + arm_uc_error_t err = {ARM_UC_DP_ERR_UNKNOWN}; + if (rc < 0) { + err = ARM_UC_wrapMbedTLSError(rc); + } else if (rc == 0) { + err.code = ARM_UC_DP_ERR_NONE; + } else { //if (rc > 0) + err.code = ARM_UC_DP_ERR_NOT_FOUND; + } + return err; +} + +arm_uc_error_t ARM_UC_mmDERGetSingleValue( + const struct arm_uc_mmDerElement* desc, + arm_uc_buffer_t* buffer, + const int32_t valueID, + arm_uc_buffer_t* val) +{ + int32_t rc = ARM_UC_mmDERParseTree(desc, buffer, 1U, &valueID, val); + arm_uc_error_t err = {ARM_UC_DP_ERR_UNKNOWN}; + if (rc < 0) { + err = ARM_UC_wrapMbedTLSError(rc); + } else if (rc == 0) { + err.code = ARM_UC_DP_ERR_NONE; + } else { //if (rc > 0) + err.code = ARM_UC_DP_ERR_NOT_FOUND; + } + return err; +} + +uint32_t ARM_UC_mmGetCryptoModeInline(arm_uc_buffer_t* buffer) +{ + uint32_t val = 1U; // default to SHA256 and ECC + ARM_UC_mmGetCryptoMode(buffer, &val); + return val; +} +arm_uc_error_t ARM_UC_mmGetVersion(arm_uc_buffer_t* buffer, uint32_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_VERSION; + arm_uc_buffer_t field = { 0UL }; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, &field); + if (rc || field.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + *val = ARM_UC_mmDerBuf2Uint(&field); + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetCryptoMode(arm_uc_buffer_t* buffer, uint32_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_ENC_ENUM; + arm_uc_buffer_t field = { 0UL }; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, &field); + if (rc || field.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + *val = ARM_UC_mmDerBuf2Uint(&field); + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetTimestamp(arm_uc_buffer_t* buffer, uint64_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_TIMESTAMP; + arm_uc_buffer_t field = { 0UL }; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, &field); + if (rc || field.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + *val = ARM_UC_mmDerBuf2Uint64(&field); + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetValidFrom(arm_uc_buffer_t* buffer, uint64_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_VALID_FROM; + arm_uc_buffer_t field = { 0UL }; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, &field); + if (rc < 0 || field.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + if (rc > 0) return (arm_uc_error_t){MFST_ERR_EMPTY_FIELD}; + *val = ARM_UC_mmDerBuf2Uint64(&field); + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetValidTo(arm_uc_buffer_t* buffer, uint64_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_VALID_TO; + arm_uc_buffer_t field = { 0UL }; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, &field); + if (rc < 0 || field.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + if (rc > 0) return (arm_uc_error_t){MFST_ERR_EMPTY_FIELD}; + *val = ARM_UC_mmDerBuf2Uint64(&field); + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetVendorGuid(arm_uc_buffer_t* buffer, arm_uc_buffer_t* guid) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_VENDOR_UUID; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, guid); + if (rc || guid->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetClassGuid(arm_uc_buffer_t* buffer, arm_uc_buffer_t* guid) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_CLASS_UUID; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, guid); + if (rc || guid->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetDeviceGuid(arm_uc_buffer_t* buffer, arm_uc_buffer_t* guid) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_DEVICE_UUID; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, guid); + if (rc || guid->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} + +arm_uc_error_t ARM_UC_mmGetFwInitVector(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_FW_CRYPT_IV; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, val); + if (rc || val->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetFwUri(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, val); + if (rc || val->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetFwSize(arm_uc_buffer_t* buffer, uint32_t* val) +{ + arm_uc_buffer_t field = { 0UL }; + const int32_t fieldID = ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, &field); + if (rc || field.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + *val = ARM_UC_mmDerBuf2Uint(&field); + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetFwHash(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, val); + if (rc || val->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetFwSymmKey(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val) +{ + return (arm_uc_error_t){MFST_ERR_VERSION}; +} +arm_uc_error_t ARM_UC_mmGetFwCertId(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_FW_CRYPT_ID_LOCAL; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, val); + if (rc || val->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetDescription(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_DESC; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, val); + if (rc || val->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetManifestLinksUri(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_DEP_REF_URL; + int32_t rc = ARM_UC_mmDERParseTree(arm_uc_mmManifestDependencies, buffer, 1U, &fieldID, val); + if (rc || val->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetManifestLinksHash(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val) +{ + const int32_t fieldID = ARM_UC_MM_DER_MFST_DEP_REF_HASH; + int32_t rc = ARM_UC_mmDERParseTree(arm_uc_mmManifestDependencies, buffer, 1U, &fieldID, val); + if (rc || val->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetManifestLinksElement(arm_uc_buffer_t* buffer, uint32_t index, arm_uc_buffer_t* element) +{ + arm_uc_buffer_t elements = { 0UL }; + const int32_t fieldID = ARM_UC_MM_DER_MFST_DEPS; + int32_t rc = ARM_UC_mmDERGetSignedResourceValues(buffer, 1U, &fieldID, &elements); + if (rc || elements.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + element->ptr = NULL; + rc = ARM_UC_mmDERGetSequenceElement(&elements, index, element); + if (rc) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetManifestHash(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val) +{ + return ARM_UC_mmDERSignedResourceGetSingleValue(buffer, ARM_UC_MM_DER_SIG_HASH, val); +} +arm_uc_error_t ARM_UC_mmGetSignatureBlock(arm_uc_buffer_t* buffer, uint32_t idx, arm_uc_buffer_t* block) +{ + arm_uc_buffer_t signatures = { 0UL }; + arm_uc_error_t err = ARM_UC_mmDERSignedResourceGetSingleValue(buffer, ARM_UC_MM_DER_SIG_SIGNATURES, &signatures); + if (err.error) return err; + if (signatures.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + + int32_t rc = ARM_UC_mmDERGetSequenceElement(&signatures, idx, block); + if (rc) return ARM_UC_wrapMbedTLSError(rc); + if (block->ptr == NULL) return (arm_uc_error_t){ARM_UC_DP_ERR_NO_MORE_ELEMENTS}; + + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetSignature(arm_uc_buffer_t* buffer, uint32_t idx, arm_uc_buffer_t* val) +{ + arm_uc_buffer_t signatureBlock = { 0UL }; + arm_uc_error_t err = ARM_UC_mmGetSignatureBlock(buffer, idx, &signatureBlock); + if (err.error) return err; + if (signatureBlock.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + + err = ARM_UC_mmDERGetSingleValue(arm_uc_mmSignatures, &signatureBlock, ARM_UC_MM_DER_SIG_SIGNATURE, val); + if (err.error) return err; + if (val->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +} + +arm_uc_error_t ARM_UC_mmGetCertificateId(arm_uc_buffer_t* buffer, uint32_t sigIdx, arm_uc_buffer_t* val) +{ + arm_uc_buffer_t signatureBlock = { 0UL }; + arm_uc_error_t err = ARM_UC_mmGetSignatureBlock(buffer, sigIdx, &signatureBlock); + if (err.error) return err; + if (signatureBlock.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + + arm_uc_buffer_t seq = { 0UL }; + err = ARM_UC_mmDERGetSingleValue(arm_uc_mmSignatures, &signatureBlock, ARM_UC_MM_DER_SIG_CERTS, &seq); + if (err.error) return err; + if (seq.ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + + arm_uc_buffer_t element = { 0UL }; + element.ptr = NULL; + int32_t rc = ARM_UC_mmDERGetSequenceElement(&seq, 0, &element); + if (rc) return ARM_UC_wrapMbedTLSError(rc); + if (element.ptr == NULL) return (arm_uc_error_t){ARM_UC_DP_ERR_NO_MORE_ELEMENTS}; + + err = ARM_UC_mmDERGetSingleValue(arm_uc_mmSignatureCertificateReferences, &element, ARM_UC_MM_DER_SIG_CERT_FINGERPRINT, val ); + if (err.error) return err; + if (val->ptr == NULL) return (arm_uc_error_t){MFST_ERR_DER_FORMAT}; + return (arm_uc_error_t){MFST_ERR_NONE}; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmDerManifestAccessors.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmDerManifestAccessors.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,63 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_CLIENT_MANIFEST_MANAGER_ACCESSORS_H +#define ARM_UPDATE_CLIENT_MANIFEST_MANAGER_ACCESSORS_H +// WARNING: THIS IS A MACHINE-GENERATED FILE. DO NOT MODIFY. +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_common.h" +#define MFST_MAGIC 1414743629 +enum { + ARM_UC_MFST_CRYPTOMODE_UNINIT = 0, + ARM_UC_MFST_CRYPTOMODE_SHA256, + ARM_UC_MFST_CRYPTOMODE_SHA256_HMAC, + ARM_UC_MFST_CRYPTOMODE_SHA256_HMAC_AES128, + ARM_UC_MFST_CRYPTOMODE_SHA256_ECC, + ARM_UC_MFST_CRYPTOMODE_SHA256_ECC_AES128, + ARM_UC_MFST_CRYPTOMODE_MAX, +}; + +uint32_t ARM_UC_mmGetUint32_t(arm_uc_buffer_t* buffer, uint32_t offset); +arm_uc_error_t ARM_UC_mmGetMagic(arm_uc_buffer_t* buffer, uint32_t* val); +arm_uc_error_t ARM_UC_mmGetVersion(arm_uc_buffer_t* buffer, uint32_t* val); +arm_uc_error_t ARM_UC_mmGetCryptoMode(arm_uc_buffer_t* buffer, uint32_t* val); +arm_uc_error_t ARM_UC_mmGetNonce(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetVendorGuid(arm_uc_buffer_t* buffer, arm_uc_buffer_t* guid); +arm_uc_error_t ARM_UC_mmGetClassGuid(arm_uc_buffer_t* buffer, arm_uc_buffer_t* guid); +arm_uc_error_t ARM_UC_mmGetDeviceGuid(arm_uc_buffer_t* buffer, arm_uc_buffer_t* guid); +arm_uc_error_t ARM_UC_mmGetTimestamp(arm_uc_buffer_t* buffer, uint64_t* val); +arm_uc_error_t ARM_UC_mmGetValidFrom(arm_uc_buffer_t* buffer, uint64_t* val); +arm_uc_error_t ARM_UC_mmGetValidTo(arm_uc_buffer_t* buffer, uint64_t* val); +arm_uc_error_t ARM_UC_mmGetCertificateId(arm_uc_buffer_t* buffer, uint32_t sigIdx, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetFwInitVector(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetFwUri(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetFwSize(arm_uc_buffer_t* buffer, uint32_t* val); +arm_uc_error_t ARM_UC_mmGetFwHash(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetFwSymmKey(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetFwCertId(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetDescription(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetManifestLinksUri(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetManifestLinksHash(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); +arm_uc_error_t ARM_UC_mmGetManifestLinksElementCount(arm_uc_buffer_t* buffer, uint32_t* val); +uint32_t ARM_UC_mmGetManifestLinksElementSize(arm_uc_buffer_t* buffer, uint32_t baseOffset); +arm_uc_error_t ARM_UC_mmGetManifestLinksElement(arm_uc_buffer_t* buffer, uint32_t index, arm_uc_buffer_t* element); +arm_uc_error_t ARM_UC_mmGetManifestHash(arm_uc_buffer_t* buffer, arm_uc_buffer_t* val); + +arm_uc_error_t ARM_UC_mmDERSignedResourceGetSingleValue(arm_uc_buffer_t* buffer, const int32_t fieldID, arm_uc_buffer_t* val); + +#endif // ARM_UPDATE_CLIENT_MANIFEST_MANAGER_ACCESSORS_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmDerManifestParser.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmDerManifestParser.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,885 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_mmDerManifestParser.h" + +#include <stdio.h> + +#define DER_MANDATORY 0 +#define DER_OPTIONAL 1 + +#define ARM_UC_MM_DER_ELEMENT_INIT(ID, TAG, OPT, CHILDREN)\ + {.id = (ID), .subElements = (CHILDREN), .tag = (TAG), .optional = (OPT), .nSubElements = sizeof(CHILDREN)/sizeof(struct arm_uc_mmDerElement)} +#define ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ID, TAG, OPT)\ + {.id = (ID), .subElements = NULL, .tag = (TAG), .optional = (OPT), .nSubElements = 0} + + +/** + * @brief Descriptor for the apply period of a manifest. + * + * applyPeriod SEQUENCE { + * validFrom INTEGER, + * validTo INTEGER + * } + */ +static const struct arm_uc_mmDerElement ManifestApplyPeriod[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VALID_FROM, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VALID_TO, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY), +}; +/** + * @brief Descriptor of the encryptionMode + * + * encryptionMode CHOICE { + * enum ENUMERATED { + * invalid(0), + * aes-128-ctr-ecc-secp256r1-sha256(1), + * none-ecc-secp256r1-sha256(2), + * none-none-sha256(3) + * }, + * objectId OBJECT IDENTIFIER + * } + */ +static const struct arm_uc_mmDerElement encryptionModeChoice[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_ENC_ENUM, ARM_UC_MM_ASN1_ENUMERATED, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_ENC_OID, ARM_UC_MM_ASN1_OID, DER_MANDATORY), +}; +/** + * @brief Descriptor for resource aliases + * + * ResourceAlias ::= SEQUENCE { + * hash OCTET STRING, + * url Url + * } + */ +static const struct arm_uc_mmDerElement manifestResourceAlias[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_RESOURCE_ALIAS_HASH, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_RESOURCE_ALIAS_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_MANDATORY), +}; +/** + * @brief Descriptor of an Alias container + * + */ +static const struct arm_uc_mmDerElement manifestResourceAliases[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_RESOURCE_ALIAS, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, manifestResourceAlias) +}; + +/** + * @brief Descriptor of the firmware format + * + * format CHOICE {F + * enum ENUMERATED { + * undefined(0), raw-binary(1), cbor(2), hex-location-length-data(3), elf(4) + * }, + * objectId OBJECT IDENTIFIER + * }, + */ +static const struct arm_uc_mmDerElement manifestFwFmtChoice[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_FMT_ENUM, ARM_UC_MM_ASN1_ENUMERATED, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_FMT_OID, ARM_UC_MM_ASN1_OID, DER_MANDATORY), +}; + +/** + * @brief Descriptor of the certificate reference used for ECDH + * @details References an ECC certificate, which is used to perform ECDH with the target device's private key. This will + * allow derivation of a shared secret, which has been used to encrypt the symmetric encryption key. + * NOTE: this is the same ASN.1 sequence as arm_uc_mmSignatureCertificateReference, but it is duplicated in the parser to reduce parsing time. + * + * CertificateReference ::= SEQUENCE { + * fingerprint Bytes, + * url Url + * } + * + */ +static const struct arm_uc_mmDerElement manifestFwCryptIdCertRef[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_FINGERPRINT, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL), +}; +/** + * @brief Descriptor of the Local Info ID choice + * @details Describes either a locally held pre-shared key or a certificate. + * + * id CHOICE { + * key OCTET STRING, + * certificate CertificateReference + * }, + */ +static const struct arm_uc_mmDerElement manifestFwCryptIdChoice[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_LOCAL, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_REF, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, manifestFwCryptIdCertRef), +}; +/** + * @brief Descriptor of the encryption key options + * @details Encryption is currently not supported. + * When supported, the encryption key will be delivered either as an encrypted blob in the manifest, or in a key table, + * which is referenced in the Resource Reference below. + * + * key CHOICE { + * keyTable Url, + * cipherKey OCTET STRING + * } OPTIONAL + * + */ +static const struct arm_uc_mmDerElement manifestFwCryptKeyChoice[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_KEYTABLE_REF, ARM_UC_MM_ASN1_UTF8_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CIPHERKEY, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), +}; +/** + * @brief Descriptor of cryptographic information block + * @details Contains the information necessary to manage the encryption of the payload. + * encryptionInfo SEQUENCE { + * initVector OCTET STRING, + * id, + * key + * } OPTIONAL, + */ +static const struct arm_uc_mmDerElement manifestFwCryptInfo[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_IV, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_MANDATORY, manifestFwCryptIdChoice), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_OPTIONAL, manifestFwCryptKeyChoice), +}; + +/** + * @brief Descriptor of a firmware resource reference. + * @details Provides a hash, URL, and size of a payload + * + * ResourceReference ::= SEQUENCE { + * hash OCTET STRING, + * url Url OPTIONAL, + * size INTEGER + * } + */ +static const struct arm_uc_mmDerElement manifestFwRsrcRef[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY), +}; + +/** + * @brief Descriptor of a payload description block + * @details Describes the payload, including: + * * The payload format + * * Any cryptographic information required to decrypt the payload + * * The storage identifier for payload (where to store it on the target) + * * The resource reference of the payload (where it is stored, etc) + * * A free-text version field + * + * FirmwareDescription ::= SEQUENCE { + * format, + * encryptionInfo OPTIONAL, + * storageIdentifier UTF8String, + * reference ResourceReference, + * version UTF8String OPTIONAL + * } + */ +static const struct arm_uc_mmDerElement arm_uc_mmManifestFirmwareDescriptionElements[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_FMT_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_MANDATORY, manifestFwFmtChoice), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_CRYPT_INFO, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_OPTIONAL, manifestFwCryptInfo), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_STRG_ID, ARM_UC_MM_ASN1_UTF8_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_RSRC_REF, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, manifestFwRsrcRef), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_VER, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL), +}; + +const struct arm_uc_mmDerElement arm_uc_mmManifestFirmwareDescription[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FIRMWARE, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_OPTIONAL, arm_uc_mmManifestFirmwareDescriptionElements), +}; + +/** + * @brief Descriptor of a manifest dependency reference + * @details Provides a hash, URL, and size of a manifest dependency + * ResourceReference ::= SEQUENCE { + * hash OCTET STRING, + * url Url OPTIONAL, + * size INTEGER + * } + */ +static const struct arm_uc_mmDerElement arm_uc_mmManifestDependency[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DEP_REF_HASH, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DEP_REF_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DEP_REF_SIZE, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY), +}; +/** + * @brief Descriptor of a manifest dependency container + * @details Contains manifest dependency references + */ +const struct arm_uc_mmDerElement arm_uc_mmManifestDependencies[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_DEP, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmManifestDependency) +}; + +/** + * @brief Descriptor of the manifest sequence + * @details Contains all the information necessary to describe a manifest. + * + * Manifest ::= SEQUENCE { + * manifestVersion ENUMERATED { + * v1(1) + * }, + * description UTF8String OPTIONAL, + * timestamp INTEGER, + * vendorId UUID, + * classId UUID, + * deviceId UUID, + * nonce OCTET STRING, + * vendorInfo OCTET STRING, + * applyPeriod OPTIONAL, + * applyImmediately BOOLEAN, + * encryptionMode CHOICE { + * enum ENUMERATED { + * invalid(0), + * aes-128-ctr-ecc-secp256r1-sha256(1), + * none-ecc-secp256r1-sha256(2), + * none-none-sha256(3) + * }, + * objectId OBJECT IDENTIFIER + * }, + * aliases SEQUENCE OF ResourceAlias, + * dependencies SEQUENCE OF ResourceReference, + * firmware FirmwareDescription OPTIONAL + */ +static const struct arm_uc_mmDerElement ManifestElements[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VERSION, ARM_UC_MM_ASN1_ENUMERATED, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DESC, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_TIMESTAMP, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VENDOR_UUID, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_CLASS_UUID, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DEVICE_UUID, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_NONCE, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VENDOR_INFO, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_APPLY_PERIOD, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_OPTIONAL, ManifestApplyPeriod), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_APPLY_IMMEDIATELY, ARM_UC_MM_ASN1_BOOLEAN, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_ENCRYPTION_MODE_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_OPTIONAL, encryptionModeChoice), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_RESOURCE_ALIASES, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, manifestResourceAliases), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_DEPS, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmManifestDependencies), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FIRMWARE, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_OPTIONAL, arm_uc_mmManifestFirmwareDescriptionElements), +}; + +/** + * @brief Descriptor of the Resource Choice + * @details The resource can be one of a limited number of options. Currently, the supported resource types are Manifest + * and Firmware Image. The firmware image is simply an OCTET STRING, whereas the Manifest is an ASN.1 SEQUENCE (DER + * encoded) + * + * resource CHOICE { + * manifest Manifest, + * firmware Firmware + * } + */ +static const struct arm_uc_mmDerElement ResourceChoiceElements[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, ManifestElements), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_FW_IMAGE, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), +}; + +/** + * @brief Descriptor of a Resource object. + * @details A resource is composed of an optional reference URL, a resource type identifier, and a resource. + * + * Resource ::= SEQUENCE { + * url Url OPTIONAL, + * resourceType ENUMERATED { + * manifest(0), firmware(1) + * }, + * resource + * } + */ +static const struct arm_uc_mmDerElement ResourceElements[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_RESOURCE_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_RESOURCE_TYPE, ARM_UC_MM_ASN1_ENUMERATED, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_RESOURCE_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_MANDATORY, ResourceChoiceElements), +}; +/** +* @brief Descriptor of the certificate reference used for ECDSA signature verification +* @details References an ECC certificate, which is used to perform ECDSA with the target device's public key. The +* certificate used to sign the manifest is used to determine the permissions to be applied to the manifest. +* NOTE: this is the same ASN.1 sequence as manifestFwCryptIdCertRef, but it is duplicated in the parser to reduce parsing time. +* +* CertificateReference ::= SEQUENCE { +* fingerprint Bytes, +* url Url +* } + + */ +static const struct arm_uc_mmDerElement arm_uc_mmSignatureCertificateReference[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_CERT_FINGERPRINT, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_CERT_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL), +}; +/** + * @brief Certificate Reference container + */ +const struct arm_uc_mmDerElement arm_uc_mmSignatureCertificateReferences[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_CERT, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmSignatureCertificateReference), +}; + +const struct arm_uc_mmDerElement arm_uc_mmSignatureBlock[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_SIGNATURE, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_CERTS, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmSignatureCertificateReferences), +}; +const struct arm_uc_mmDerElement arm_uc_mmSignatures[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_SIGNATURE_BLOCK, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmSignatureBlock), +}; +/** + * @brief Descriptor of a resource signature + * @details Contains the signature of the resource object. To facilitate fast integrity checking, a hash is also + * provided. The certificate references allow the target device to establish a chain of trust. + * + * ResourceSignature ::= SEQUENCE { + * certificates SEQUENCE OF CertificateReference, + * hash OCTET STRING, + * signature OCTET STRING + * } + */ +const struct arm_uc_mmDerElement arm_uc_mmResourceSignature[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_HASH, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_SIGNATURES, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmSignatures), +}; +/** + * @brief Descriptor of a signed resource. + * @details The signed resource is a container for a resource and a signature. + * SignedResource ::= SEQUENCE { + * resource Resource, + * signature ResourceSignature + * } + */ +static const struct arm_uc_mmDerElement SignedResourceElements[] = +{ + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_RESOURCE, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, ResourceElements), + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmResourceSignature), +}; +/** + * @brief Container of a Signed Resource. + */ +static const struct arm_uc_mmDerElement SignedResource = + ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_ROOT, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, SignedResourceElements); + +#include "update-client-common/arm_uc_trace.h" + +enum arm_uc_mmDerParserLogLevels { + DER_PARSER_LOG_LEVEL_NONE, + DER_PARSER_LOG_LEVEL_DESCRIPTORS, + DER_PARSER_LOG_LEVEL_TAGS, + DER_PARSER_LOG_LEVEL_SIZES, + DER_PARSER_LOG_LEVEL_VALUES, + DER_PARSER_LOG_LEVEL_MAX +}; +uint32_t arm_uc_mm_derRecurseDepth; + +#ifndef ARM_UC_DER_PARSER_TRACE_ENABLE +#define ARM_UC_DER_PARSER_TRACE_ENABLE 0 +#endif + +#if ARM_UC_DER_PARSER_TRACE_ENABLE +volatile uint32_t arm_uc_mm_der_gDebugLevel = DER_PARSER_LOG_LEVEL_MAX; + +#define DER_PARSER_LOG_INDENT(LOG_LEVEL)\ +do { \ + if((LOG_LEVEL) <= arm_uc_mm_der_gDebugLevel) \ + { \ + for (uint32_t i = 0; i < arm_uc_mm_derRecurseDepth; i++) \ + { \ + printf(" "); \ + } \ + } \ +} while(0) + +#define DER_PARSER_LOG(LOG_LEVEL,...)\ + do { \ + if((LOG_LEVEL) <= arm_uc_mm_der_gDebugLevel) \ + { \ + printf(__VA_ARGS__); \ + } \ + } while(0) +#else +#define DER_PARSER_LOG_INDENT(LOG_LEVEL) +#define DER_PARSER_LOG(LOG_LEVEL,...) +#endif + +/* + * ASN.1 DER decoding routines + */ +int ARM_UC_MM_ASN1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ) +{ + if( ( end - *p ) < 1 ) + return( ARM_UC_DP_ERR_ASN1_OUT_OF_DATA ); + + if( ( **p & 0x80 ) == 0 ) + *len = *(*p)++; + else + { + switch( **p & 0x7F ) + { + case 1: + if( ( end - *p ) < 2 ) + return( ARM_UC_DP_ERR_ASN1_OUT_OF_DATA ); + + *len = (*p)[1]; + (*p) += 2; + break; + + case 2: + if( ( end - *p ) < 3 ) + return( ARM_UC_DP_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 8 ) | (*p)[2]; + (*p) += 3; + break; + + case 3: + if( ( end - *p ) < 4 ) + return( ARM_UC_DP_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 16 ) | + ( (size_t)(*p)[2] << 8 ) | (*p)[3]; + (*p) += 4; + break; + + case 4: + if( ( end - *p ) < 5 ) + return( ARM_UC_DP_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) | + ( (size_t)(*p)[3] << 8 ) | (*p)[4]; + (*p) += 5; + break; + + default: + return( ARM_UC_DP_ERR_ASN1_INVALID_LENGTH ); + } + } + + if( *len > (size_t) ( end - *p ) ) + return( ARM_UC_DP_ERR_ASN1_OUT_OF_DATA ); + + return( 0 ); +} + +int ARM_UC_MM_ASN1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ) +{ + if( ( end - *p ) < 1 ) + return( ARM_UC_DP_ERR_ASN1_OUT_OF_DATA ); + + if( **p != tag ) + return( ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + + return( ARM_UC_MM_ASN1_get_len( p, end, len ) ); +} + + +const char* ARM_UC_mmDERDescID2Str(uint32_t id) +{ + switch (id) { + #define ENUM_AUTO(name) case name: return #name; + ARM_UC_MM_DER_ID_LIST + #undef ENUM_AUTO + default: + return "Unknown DER ID"; + } +} + +/** + * @brief Internal state of the parser + */ +struct ARM_UC_MM_DERParserState { + uint32_t nValues; //!< Number of values remaining to parse + const uint32_t* valueIDs; //!< Current element of the value identifier array + arm_uc_buffer_t* buffers; //!< Current buffer of the value output array +}; +/** + * @brief Converts a buffer to an unsigned 32-bit integer + * @details Assumes that the buffer is an unsigned, big-endian integer and returns it. + * Limitations: + * * Expects the buffer to be 4 bytes long or less + * * Does not trap NULL buffers + * * Does not trap NULL pointers + * * Does not permit sign extension of negative values + * @param[in] buf The buffer to convert to an integer + * @return The integer value of the buffer + */ +uint32_t ARM_UC_mmDerBuf2Uint(arm_uc_buffer_t* buf) +{ + uint32_t rc = 0; + unsigned i; + for (i = 0; i < buf->size && i < sizeof(uint32_t); i++) + { + rc = (rc << 8) | buf->ptr[i]; + } + return rc; +} +/** + * @brief Converts a buffer to an unsigned 64-bit integer + * @details Assumes that the buffer is an unsigned, big-endian integer and returns it. + * Limitations: + * * Expects the buffer to be 8 bytes long or less + * * Does not trap NULL buffers + * * Does not trap NULL pointers + * * Does not permit sign extension of negative values + * @param[in] buf The buffer to convert to an integer + * @return The integer value of the buffer + */ +uint64_t ARM_UC_mmDerBuf2Uint64(arm_uc_buffer_t* buf) +{ + uint64_t rc = 0; + unsigned i; + for (i = 0; i < buf->size && i < sizeof(uint64_t); i++) + { + rc = (rc << 8) | buf->ptr[i]; + } + return rc; +} + +/** + * @brief Extracts the next tag in the DER string + * @details Validates the length of the string, then extracts the next value, interpreting it as a tag. + * Limitations: + * * Does not verify that any of the pointers are non-NULL + * * Does not validate tag values + * @param[in] p The current position in DER string + * @param[in] end The last position in the DER string + * @param[out] tag The extracted DER tag + * @retval 1 if the end has been encountered + * @retval 0 if the tag was successfully retrieved + */ +int ARM_UC_mmDERPeekTag(uint8_t* p, uint8_t* end, int* tag) +{ + if( ( end - p ) < 1 ) + { + return( 1 ); + } + *tag = *p; + return 0; +} + +/** + * @brief Extracts one or more tagged values from DER encoded data + * @details Recursively traverses the DER tree, searching for the identified values. + * The parser parses the input data, identified by `*pos` according to the following rules: + * + * * If the current descriptor is a choice, `ARM_UC_mmDERGetValues` attempts to resolve the choice. + * * Obtain the actual tag + * * Loop through each child of the choice element and compare it to the tag + * * If no tag mathces, return `ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG` + * * Otherwise replace `desc` with the descriptor of the matching tag + * * Get the tag for the current descriptor + * * If the tag is not found + * * If it was optional, exit with success + * * Otherwise, exit with ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG + * * If the descriptor ID matches the current extraction ID + * * Extract the value into the current buffer. + * * Advance the ID pointer, the buffer pointer, and decrement the value pointer. + * * If the descriptor is a sequence with more than one child, recurse into it (single-child sequences are SEQUENCE OF) + * * For each child element, + * * If the end has been not reached or the child descriptor is mandatory + * * call `ARM_UC_mmDERGetValues` with the child descriptor. + * * If the end does not match pos + * * fail with `ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH` + * * Otherwise + * * Update the current position + * * return success + * + * WARNING: ARM_UC_mmDERGetValues cannot resolve choices between two different sequences. + * + * NOTE: Choices are not currently returnable + * NOTE: An optimization should be possible to reduce the parsing time by skipping elements whose descriptors do not + * contain the next requested element ID + * NOTE: Length mismatch checking is not currently supported. + * + * To parse a SEQUENCE OF element, search for the SEQUENCE OF. Then, iterate through its elements with + * `ARM_UC_mmDERGetSequenceElement`. With each element, call `ARM_UC_mmDERParseTree` with the descriptor for the + * contents of the SEQUENCE OF. + * + * @param[in] desc Contains the current parsing descriptor + * @param[in] pos Pointer to pointer that holds the current parsing location + * @param[in] end Pointer to the end of the current element's container + * @param[in,out] state Parser state. Contains the parser's + * @retval ARM_UC_DP_ERR_ASN1_OUT_OF_DATA The parser has run out of data before running out of descriptors + * @retval ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG The parser has encountered an encoding error, or unsupported DER document + * @retval ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH The elements of the DER tree do not have consistent lengths. + * @retval 0 Success! + */ +int32_t ARM_UC_mmDERGetValues(const struct arm_uc_mmDerElement* desc, uint8_t** pos, uint8_t* end, struct ARM_UC_MM_DERParserState* state) +{ + size_t len; + int rc; + uint8_t* ElementEnd; + DER_PARSER_LOG_INDENT(DER_PARSER_LOG_LEVEL_DESCRIPTORS); + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, "%s", ARM_UC_mmDERDescID2Str(desc->id)); + + // TODO: return a choice result when a choice ID is in the list. + // Resolve the a choice. Cannot distinguish choices between two sequences. + if (desc->tag == ARM_UC_MM_ASN1_CHOICE) + { + int tag; + unsigned i; + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, "\n"); + // Get the tag of the next element and identify the descriptor that matches that tag. + rc = ARM_UC_mmDERPeekTag(*pos, end, &tag); + if (rc) + return rc; + rc = ( ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG ); + arm_uc_mm_derRecurseDepth++; + for (i = 0; i < desc->nSubElements; i++) + { + if (tag == desc->subElements[i].tag) + { + // desc = &desc->subElements[i]; + // rc = 0; + rc = ARM_UC_mmDERGetValues(&desc->subElements[i], pos, end, state); + break; + } + else + { + DER_PARSER_LOG_INDENT(DER_PARSER_LOG_LEVEL_DESCRIPTORS); + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, "%s (skipped)\n", ARM_UC_mmDERDescID2Str(desc->subElements[i].id)); + } + } + arm_uc_mm_derRecurseDepth--; + // If the matching tag is not in one of the desctiptors, then a parse error has been encountered. + // if (rc) + return rc; + } + // Store the entry position for saving sequences + uint8_t* seqpos = *pos; + // Get the next tag & length, advancing the parse position to just after the tag/length pair. + rc = ARM_UC_MM_ASN1_get_tag(pos, end, &len, desc->tag); + // If an optional tag was expected, but not encountered, it is not an error unless it was requested by the user. + if (rc == ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG && desc->optional && desc->id != state->valueIDs[0]) + { + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, " (skipped)\n"); + return 0; + } // TODO evaluate length handling in ARM_UC_MM_ASN1_get_tag + // If an error was encountered, abort. + if (rc) + { + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, " (error %d)\n", rc); + return rc; + } + // If the encountered tag is one of the requested IDs, record its location and size, then move on to the next value + if (desc->id == state->valueIDs[0]) + { + // If the element is a sequence, store the whole element, not just the content. + if (desc->tag == (ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE) && desc->nSubElements != 1) + { + state->buffers[0].ptr = seqpos; + state->buffers[0].size = len + (*pos - seqpos); + state->buffers[0].size_max = len + (*pos - seqpos); + } + else + { + state->buffers[0].ptr = *pos; + state->buffers[0].size = len; + state->buffers[0].size_max = len; + } + state->nValues--; + state->valueIDs++; + state->buffers++; + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, " (stored)\n"); + } + else + { + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, "\n"); + } + DER_PARSER_LOG_INDENT(DER_PARSER_LOG_LEVEL_TAGS); + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_TAGS, "%02X", desc->tag); + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_SIZES, " %X", len); + if (desc->tag != (ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE)) + { + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_VALUES, " "); + for (uint32_t i = 0; i < len; i++) + { + if (desc->tag == ARM_UC_MM_ASN1_UTF8_STRING) + { + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_VALUES, "%c", (char)(*pos)[i]); + } + else + { + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_VALUES, "%X", (*pos)[i]); + } + } + } + DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_TAGS, "\n"); + + // TODO: At this point, it should be possible to exit parsing of this element early if no requested ID is owned by + // this element or one of its children. + + // Update the end of the current element to pos+len + ElementEnd = *pos + len; + // If the element is a sequence, parse the sequence. + if (desc->tag == (ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE)) + { + /* Sequences with only a single element are treated as a SEQUENCE OF, which has special semantics. In order to + * extract the contents of a SEQUENCE OF, the caller must request the SEQUENCE OF element ID, then use + * ARM_UC_mmDERGetSequenceElement to extract the contents of the sequence, passing each one to + * ARM_UC_mmDERParseTree in order to extract any */ + if (desc->nSubElements != 1) // SEQUENCE + { + int i; + end = *pos + len; + arm_uc_mm_derRecurseDepth++; + for ( i = 0; rc == 0 && state->nValues != 0 && i < desc->nSubElements; i++ ) + { + // Escape if the end has been reached and the parsing elements are optional + if (!(*pos >= end && desc->subElements[i].optional)) { + // Parse a sub-tree + rc = ARM_UC_mmDERGetValues(&desc->subElements[i], pos, end, state); + } + } + arm_uc_mm_derRecurseDepth--; + } + } + + if (*pos > ElementEnd) // TODO: Add length mismatch check + { + // Fail if there is a length mismatch + return ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH; + } + else + { + // Update the current parsing position + *pos = ElementEnd; + } + return rc; +} + +/** + * @brief Extracts elements from an ASN.1 SEQUENCE OF by index + * @details Parses a SEQUENCE OF element, skipping elements until it finds the requested element. + * When the last element has been parsed, a further call to `ARM_UC_mmDERGetSequenceElement` will cause element to be + * populated with a NULL buffer pointer and 0 length, but `ARM_UC_mmDERGetSequenceElement` will still return success. + * + * @param[in] buffer The data to parse + * @param[in] index The element index to extract + * @param[out] element The buffer to populate with the extracted element + * + * @retval ARM_UC_DP_ERR_ASN1_OUT_OF_DATA The parser has run out of data before running out of descriptors + * @retval ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG The parser has encountered an encoding error, or unsupported DER document + * @retval ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH The elements of the DER tree do not have consistent lengths. + * @retval 0 Success! + */ +int32_t ARM_UC_mmDERGetSequenceElement(arm_uc_buffer_t* buffer, uint32_t index, arm_uc_buffer_t* element) +{ + uint8_t* pos = buffer->ptr; + uint8_t* end = pos + buffer->size; + int rc = 0; + size_t len = 0; + element->ptr = NULL; + element->size = 0; + element->size_max = 0; + for(; !rc; index--) + { + int tag; + rc = ARM_UC_mmDERPeekTag(pos, end, &tag); + if (rc) + { + // Peek-tag can only fail if pos >= end, so there was no element + // This is not an error, since the parser may not know how many elements are in the sequence. + return 0; + } + if (!index) + { + element->ptr = pos; + } + rc = ARM_UC_MM_ASN1_get_tag(&pos, end, &len, tag); + if (!index && !rc) + { + element->size = len + pos - element->ptr; + element->size_max = element->size; + break; + } + if (rc) + { + element->ptr = NULL; + break; + } + pos += len; + } + return rc; +} + +/** + * @brief Parses a tree of DER data by calling `ARM_UC_mmDERGetValues` + * @details Populates a parser state with the IDs to be extracted, the number of values and the buffers to extract into + * @param[in] desc Contains the current parsing descriptor + * @param[in] buffer The data to parse + * @param[in] nValues The number of values to search for + * @param[in] valueIDs Array of value identifiers + * @param[out] buffers Array of buffers to populate with the elements matching valueIDs + * @retval ARM_UC_DP_ERR_ASN1_OUT_OF_DATA The parser has run out of data before running out of descriptors + * @retval ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG The parser has encountered an encoding error, or unsupported DER document + * @retval ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH The elements of the DER tree do not have consistent lengths. + * @retval 0 Success! + * @retval >0 Number of remaining elements + */ +int32_t ARM_UC_mmDERParseTree(const struct arm_uc_mmDerElement* desc, arm_uc_buffer_t* buffer, uint32_t nValues, const int32_t* valueIDs, arm_uc_buffer_t* buffers) +{ + uint8_t *pos = buffer->ptr; + uint8_t *end = pos + buffer->size; + struct ARM_UC_MM_DERParserState state = { + nValues, valueIDs, buffers + }; + arm_uc_mm_derRecurseDepth = 0; + int32_t rc = ARM_UC_mmDERGetValues(desc, &pos, end, &state); + // printf("Failed at: index %lu: %lu with return code: %ld\n", nValues-state.nValues, *state.valueIDs, rc); + if (rc == 0 && state.nValues != 0) + { + return state.nValues; + } + return rc; +} +/** + * @brief Parses a tree of DER data by calling `ARM_UC_mmDERGetValues` + * @details Populates a parser state with the IDs to be extracted, the number of values and the buffers to extract into + * Calls `ARM_UC_mmDERParseTree` with `SignedResource` + * @param[in] buffer The data to parse + * @param[in] nValues The number of values to search for + * @param[in] valueIDs Array of value identifiers + * @param[out] buffers Array of buffers to populate with the elements matching valueIDs + * @retval ARM_UC_DP_ERR_ASN1_OUT_OF_DATA The parser has run out of data before running out of descriptors + * @retval ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG The parser has encountered an encoding error, or unsupported DER document + * @retval ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH The elements of the DER tree do not have consistent lengths. + * @retval 0 Success! + * @retval >0 Number of remaining elements + */ +int32_t ARM_UC_mmDERGetSignedResourceValues(arm_uc_buffer_t* buffer, uint32_t nValues, const int32_t* valueIDs, arm_uc_buffer_t* buffers) +{ + return ARM_UC_mmDERParseTree(&SignedResource, buffer, nValues, valueIDs, buffers); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmDerManifestParser.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmDerManifestParser.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,181 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_MM_DERPARSE_H +#define ARM_UC_MM_DERPARSE_H + +#include "update-client-common/arm_uc_types.h" +#include <stdint.h> +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name DER constants + * These constants comply with DER encoded the ANS1 type tags. + * DER encoding uses hexadecimal representation. + * An example DER sequence is:\n + * - 0x02 -- tag indicating INTEGER + * - 0x01 -- length in octets + * - 0x05 -- value + * Such sequences are typically read into \c ::mbedtls_x509_buf. + * \{ + */ +#define ARM_UC_MM_ASN1_BOOLEAN 0x01 +#define ARM_UC_MM_ASN1_INTEGER 0x02 +#define ARM_UC_MM_ASN1_BIT_STRING 0x03 +#define ARM_UC_MM_ASN1_OCTET_STRING 0x04 +#define ARM_UC_MM_ASN1_NULL 0x05 +#define ARM_UC_MM_ASN1_OID 0x06 +#define ARM_UC_MM_ASN1_ENUMERATED 0x0A +#define ARM_UC_MM_ASN1_UTF8_STRING 0x0C +#define ARM_UC_MM_ASN1_SEQUENCE 0x10 +#define ARM_UC_MM_ASN1_SET 0x11 +#define ARM_UC_MM_ASN1_PRINTABLE_STRING 0x13 +#define ARM_UC_MM_ASN1_T61_STRING 0x14 +#define ARM_UC_MM_ASN1_IA5_STRING 0x16 +#define ARM_UC_MM_ASN1_UTC_TIME 0x17 +#define ARM_UC_MM_ASN1_GENERALIZED_TIME 0x18 +#define ARM_UC_MM_ASN1_UNIVERSAL_STRING 0x1C +#define ARM_UC_MM_ASN1_BMP_STRING 0x1E +#define ARM_UC_MM_ASN1_PRIMITIVE 0x00 +#define ARM_UC_MM_ASN1_CONSTRUCTED 0x20 +#define ARM_UC_MM_ASN1_CONTEXT_SPECIFIC 0x80 +#define ARM_UC_MM_ASN1_CHOICE 0xFF // NOTE: This is not a real ASN1 number; it is a marker for choices + +/* \} name */ + +/** + * \name ASN1 Error codes + * These error codes are OR'ed to X509 error codes for + * higher error granularity. + * ASN1 is a standard to specify data structures. + * \{ + */ +#define ARM_UC_DP_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */ +#define ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */ +#define ARM_UC_DP_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */ +#define ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */ +#define ARM_UC_DP_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */ +#define ARM_UC_DP_ERR_ASN1_ALLOC_FAILED -0x006A /**< Memory allocation failed */ +#define ARM_UC_DP_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */ + +/* \} name */ + + +#define ARM_UC_MM_DER_ID_LIST \ + ENUM_AUTO(ARM_UC_MM_DER_UNINIT)\ + ENUM_AUTO(ARM_UC_MM_DER_ROOT)\ + ENUM_AUTO(ARM_UC_MM_DER_RESOURCE)\ + ENUM_AUTO(ARM_UC_MM_DER_RESOURCE_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_RESOURCE_TYPE)\ + ENUM_AUTO(ARM_UC_MM_DER_RESOURCE_CHOICE)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_VERSION)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_DESC)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_TIMESTAMP)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_UUIDS)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_VENDOR_UUID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_CLASS_UUID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_DEVICE_UUID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_NONCE)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_VENDOR_INFO)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_APPLY_PERIOD)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_VALID_FROM)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_VALID_TO)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_APPLY_IMMEDIATELY)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_ENCRYPTION_MODE_CHOICE)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_ENC_ENUM)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_ENC_OID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_RESOURCE_ALIASES)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_RESOURCE_ALIAS)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_RESOURCE_ALIAS_HASH)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_RESOURCE_ALIAS_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FIRMWARE)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_FMT_CHOICE)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_FMT_ENUM)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_FMT_OID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_INFO)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_IV)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CHOICE)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_LOCAL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_REF)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_FINGERPRINT)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CHOICE)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CIPHERKEY)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_KEYTABLE_REF)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_STRG_ID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_VER)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_DEPS)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_DEP)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_DEP_REF_HASH)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_DEP_REF_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_DEP_REF_SIZE)\ + ENUM_AUTO(ARM_UC_MM_DER_FW_IMAGE)\ + ENUM_AUTO(ARM_UC_MM_DER_SIG)\ + ENUM_AUTO(ARM_UC_MM_DER_SIG_HASH)\ + ENUM_AUTO(ARM_UC_MM_DER_SIG_SIGNATURES)\ + ENUM_AUTO(ARM_UC_MM_DER_SIG_SIGNATURE_BLOCK)\ + ENUM_AUTO(ARM_UC_MM_DER_SIG_SIGNATURE)\ + ENUM_AUTO(ARM_UC_MM_DER_SIG_CERTS)\ + ENUM_AUTO(ARM_UC_MM_DER_SIG_CERT)\ + ENUM_AUTO(ARM_UC_MM_DER_SIG_CERT_FINGERPRINT)\ + ENUM_AUTO(ARM_UC_MM_DER_SIG_CERT_URL)\ + +enum derIDs { +#define ENUM_AUTO(X) X, + ARM_UC_MM_DER_ID_LIST +#undef ENUM_AUTO +}; + +#define ARM_UC_DER_PARSER_ERROR_PREFIX TWO_CC('D', 'P') + +struct arm_uc_mmDerElement +{ + uint32_t id; + const struct arm_uc_mmDerElement* subElements; + uint8_t tag; + uint8_t optional; + uint8_t nSubElements; +}; + +extern const struct arm_uc_mmDerElement arm_uc_mmManifestUUID[]; +extern const struct arm_uc_mmDerElement arm_uc_mmManifestDependencies[]; +extern const struct arm_uc_mmDerElement arm_uc_mmManifestFirmwareDescription[]; +extern const struct arm_uc_mmDerElement arm_uc_mmResourceSignature[]; +extern const struct arm_uc_mmDerElement arm_uc_mmSignatures[]; +extern const struct arm_uc_mmDerElement arm_uc_mmSignatureCertificateReferences[]; + +int32_t ARM_UC_mmDERGetSignedResourceValues(arm_uc_buffer_t* buffer, uint32_t nValues, const int32_t* valueIDs, arm_uc_buffer_t* buffers); +uint32_t ARM_UC_mmDerBuf2Uint(arm_uc_buffer_t* buf); +uint64_t ARM_UC_mmDerBuf2Uint64(arm_uc_buffer_t* buf); +int32_t ARM_UC_mmDERGetSequenceElement(arm_uc_buffer_t* buffer, uint32_t index, arm_uc_buffer_t* element); +int32_t ARM_UC_mmDERParseTree(const struct arm_uc_mmDerElement* desc, arm_uc_buffer_t* buffer, uint32_t nValues, const int32_t* valueIDs, arm_uc_buffer_t* buffers); + + +#ifdef __cplusplus +} +#endif + + +#endif // ARM_UC_MM_DERPARSE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmFSMHelper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmFSMHelper.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_MM_FSM_HELPER_H +#define ARM_UC_MM_FSM_HELPER_H + +#define ARM_UC_MM_FSM_HELPER_START(CONTEXT, STATE_STR_FN)\ + uint32_t oldState;\ + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "> %s (%u)\n", __PRETTY_FUNCTION__, (unsigned)event);\ + do {\ + oldState = (CONTEXT).state;\ + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "+ %s state: %s(%u)\n", __PRETTY_FUNCTION__,\ + STATE_STR_FN((CONTEXT).state), (unsigned)(CONTEXT).state);\ + switch ((CONTEXT).state) + +#define ARM_UC_MM_FSM_HELPER_FINISH(CONTEXT)\ + } while (err.code == MFST_ERR_NONE && oldState != (CONTEXT).state);\ + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "< %s %c%c:%hu (%s)\n", __PRETTY_FUNCTION__,\ + err.modulecc[0], err.modulecc[1], err.error, ARM_UC_err2Str(err)) + +#endif // ARM_UC_MM_FSM_HELPER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmFetchFirmwareInfo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmFetchFirmwareInfo.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,391 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_mmCryptoUtils.h" +#include "arm_uc_mmCommon.h" +#include "arm_uc_mmConfig.h" +#include "arm_uc_mmDerManifestAccessors.h" +#include "arm_uc_mmDerManifestParser.h" +#include "arm_uc_mmFSMHelper.h" +#include "update-client-common/arm_uc_scheduler.h" + +#include "update-client-manifest-manager/update-client-manifest-manager.h" +#include "update-client-manifest-manager/update-client-manifest-types.h" + +#include "pal.h" + +#include <stdint.h> +#include <stdio.h> +#include <stddef.h> +#include <string.h> + +#define htobe PAL_HTONL +#ifndef htobe +static inline uint32_t htobe(uint32_t x) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return __builtin_bswap32(x); +#else + return x; +#endif +} +#endif + +#undef ARRAY_SIZE +#define ARRAY_SIZE(ENUM_AUTO)\ + (sizeof(ENUM_AUTO)/sizeof((ENUM_AUTO)[0])) + + +#define ARM_UC_MM_MFST_IMAGE_REF_FIELDS \ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_FMT_ENUM)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_STRG_ID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE)\ + +static const uint32_t imageRefFields [] = { + #define ENUM_AUTO(ENUM_AUTO) ENUM_AUTO, + ARM_UC_MM_MFST_IMAGE_REF_FIELDS + #undef ENUM_AUTO +}; +enum imageRefFieldIdxs { + #define ENUM_AUTO(ENUM_AUTO) IRF_ ## ENUM_AUTO ## _IDX, + ARM_UC_MM_MFST_IMAGE_REF_FIELDS + #undef ENUM_AUTO +}; + +static const char* ARM_UC_mmFwState2Str(uint32_t state) +{ + switch (state) { + #define ENUM_AUTO(name) case name: return #name; + #define ENUM_FIXED(name, val) ENUM_AUTO(name) + ARM_UC_MM_FW_STATE_LIST + #undef ENUM_AUTO + #undef ENUM_FIXED + default: + return "Unknown State"; + } +} + +int ARM_UC_mmGetImageRef(manifest_firmware_info_t* info, arm_uc_buffer_t* mfst_fwref) +{ + arm_uc_buffer_t buffers[ARRAY_SIZE(imageRefFields)]; + int rc = ARM_UC_mmDERParseTree(arm_uc_mmManifestFirmwareDescription, + mfst_fwref, + ARRAY_SIZE(imageRefFields), + imageRefFields, + buffers); + if (rc == 0) + { + // Found local key ID and encrypted key + info->cipherMode = ARM_UC_MM_CIPHERMODE_NONE; + // TODO: Handle non-enum format + uint32_t format = ARM_UC_mmDerBuf2Uint(&buffers[IRF_ARM_UC_MM_DER_MFST_FW_FMT_ENUM_IDX]); + memset(&info->format, 0, sizeof(info->format)); + info->format.words[RFC_4122_WORDS-1] = htobe(format); + + ARM_UC_buffer_shallow_copy(&info->strgId, &buffers[IRF_ARM_UC_MM_DER_MFST_FW_STRG_ID_IDX]); + ARM_UC_buffer_shallow_copy(&info->hash, &buffers[IRF_ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH_IDX]); + ARM_UC_buffer_shallow_copy(&info->uri, &buffers[IRF_ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL_IDX]); + info->size = ARM_UC_mmDerBuf2Uint(&buffers[IRF_ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE_IDX]); + } + return rc; +} + +#define ARM_UC_MM_MFST_CRYPT_LOCAL_ID_FIELDS \ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_FMT_ENUM)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_IV)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_LOCAL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CIPHERKEY)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_STRG_ID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE)\ + +static const uint32_t localEncKeyFields [] = { + #define ENUM_AUTO(ENUM_AUTO) ENUM_AUTO, + ARM_UC_MM_MFST_CRYPT_LOCAL_ID_FIELDS + #undef ENUM_AUTO +}; +enum localEncKeyFieldIdxs { + #define ENUM_AUTO(ENUM_AUTO) LEK_ ## ENUM_AUTO ## _IDX, + ARM_UC_MM_MFST_CRYPT_LOCAL_ID_FIELDS + #undef ENUM_AUTO +}; + +int ARM_UC_mmGetLocalIDAndKey(manifest_firmware_info_t* info, arm_uc_buffer_t* mfst_fwref) +{ + arm_uc_buffer_t buffers[ARRAY_SIZE(localEncKeyFields)]; + int rc = ARM_UC_mmDERParseTree(arm_uc_mmManifestFirmwareDescription, + mfst_fwref, + ARRAY_SIZE(localEncKeyFields), + localEncKeyFields, + buffers); + if (rc == 0) + { + // Found local key ID and encrypted key + info->cipherMode = ARM_UC_MM_CIPHERMODE_PSK; + // TODO: Handle non-enum format + uint32_t format = ARM_UC_mmDerBuf2Uint(&buffers[LEK_ARM_UC_MM_DER_MFST_FW_FMT_ENUM_IDX]); + memset(&info->format, 0, sizeof(info->format)); + info->format.words[RFC_4122_WORDS-1] = htobe(format); + ARM_UC_buffer_shallow_copy(&info->initVector, &buffers[LEK_ARM_UC_MM_DER_MFST_FW_CRYPT_IV_IDX]); + ARM_UC_buffer_shallow_copy(&info->psk.keyID, &buffers[LEK_ARM_UC_MM_DER_MFST_FW_FMT_ENUM_IDX]); + ARM_UC_buffer_shallow_copy(&info->psk.cipherKey, &buffers[LEK_ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CIPHERKEY_IDX]); + + ARM_UC_buffer_shallow_copy(&info->strgId, &buffers[LEK_ARM_UC_MM_DER_MFST_FW_STRG_ID_IDX]); + ARM_UC_buffer_shallow_copy(&info->hash, &buffers[LEK_ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH_IDX]); + ARM_UC_buffer_shallow_copy(&info->uri, &buffers[LEK_ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL_IDX]); + info->size = ARM_UC_mmDerBuf2Uint(&buffers[LEK_ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE_IDX]); + } + return rc; +} + + +#define ARM_UC_MM_MFST_CRYPT_CERT_KEY_FIELDS \ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_FMT_ENUM)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_IV)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_FINGERPRINT)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CIPHERKEY)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_STRG_ID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE)\ + +static const uint32_t certEncKeyFields [] = { + #define ENUM_AUTO(ENUM_AUTO) ENUM_AUTO, + ARM_UC_MM_MFST_CRYPT_CERT_KEY_FIELDS + #undef ENUM_AUTO +}; + +enum certEncKeyFieldIdxs { + #define ENUM_AUTO(ENUM_AUTO) CEK_ ## ENUM_AUTO ## _IDX, + ARM_UC_MM_MFST_CRYPT_CERT_KEY_FIELDS + #undef ENUM_AUTO +}; + +int ARM_UC_mmGetCertAndKey(manifest_firmware_info_t* info, arm_uc_buffer_t* mfst_fwref) +{ + arm_uc_buffer_t buffers[ARRAY_SIZE(certEncKeyFields)]; + int rc = ARM_UC_mmDERParseTree(arm_uc_mmManifestFirmwareDescription, + mfst_fwref, + ARRAY_SIZE(certEncKeyFields), + certEncKeyFields, + buffers); + if (rc == 0) + { + info->cipherMode = ARM_UC_MM_CIPHERMODE_CERT_CIPHERKEY; + // TODO: Handle non-enum format + uint32_t format = ARM_UC_mmDerBuf2Uint(&buffers[CEK_ARM_UC_MM_DER_MFST_FW_FMT_ENUM_IDX]); + memset(&info->format, 0, sizeof(info->format)); + info->format.words[RFC_4122_WORDS-1] = htobe(format); + ARM_UC_buffer_shallow_copy(&info->initVector, &buffers[CEK_ARM_UC_MM_DER_MFST_FW_CRYPT_IV_IDX]); + + ARM_UC_buffer_shallow_copy(&info->certCK.certFingerPrint, &buffers[CEK_ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_FINGERPRINT_IDX]); + ARM_UC_buffer_shallow_copy(&info->certCK.certURL, &buffers[CEK_ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_URL_IDX]); + ARM_UC_buffer_shallow_copy(&info->certCK.cipherKey, &buffers[CEK_ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CIPHERKEY_IDX]); + + ARM_UC_buffer_shallow_copy(&info->strgId, &buffers[CEK_ARM_UC_MM_DER_MFST_FW_STRG_ID_IDX]); + ARM_UC_buffer_shallow_copy(&info->hash, &buffers[CEK_ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH_IDX]); + ARM_UC_buffer_shallow_copy(&info->uri, &buffers[CEK_ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL_IDX]); + info->size = ARM_UC_mmDerBuf2Uint(&buffers[CEK_ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE_IDX]); + } + return rc; +} + + +#define ARM_UC_MM_MFST_CRYPT_CERT_KEYTABLE_FIELDS \ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_FMT_ENUM)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_IV)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_FINGERPRINT)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_KEYTABLE_REF)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_STRG_ID)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL)\ + ENUM_AUTO(ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE)\ + +static const uint32_t certKeyTableFields [] = { + #define ENUM_AUTO(ENUM_AUTO) ENUM_AUTO, + ARM_UC_MM_MFST_CRYPT_CERT_KEYTABLE_FIELDS + #undef ENUM_AUTO +}; + +enum certKeyTableFieldIdxs { + #define ENUM_AUTO(ENUM_AUTO) CKT_ ## ENUM_AUTO ## _IDX, + ARM_UC_MM_MFST_CRYPT_CERT_KEYTABLE_FIELDS + #undef ENUM_AUTO +}; + +int ARM_UC_mmGetCertAndKeyTable(manifest_firmware_info_t* info, arm_uc_buffer_t* mfst_fwref) +{ + arm_uc_buffer_t buffers[ARRAY_SIZE(certKeyTableFields)]; + int rc = ARM_UC_mmDERParseTree(arm_uc_mmManifestFirmwareDescription, + mfst_fwref, + ARRAY_SIZE(certKeyTableFields), + certKeyTableFields, + buffers); + if (rc == 0) + { + info->cipherMode = ARM_UC_MM_CIPHERMODE_CERT_KEYTABLE; + // TODO: Handle non-enum format + uint32_t format = ARM_UC_mmDerBuf2Uint(&buffers[CKT_ARM_UC_MM_DER_MFST_FW_FMT_ENUM_IDX]); + memset(&info->format, 0, sizeof(info->format)); + info->format.words[RFC_4122_WORDS-1] = htobe(format); + ARM_UC_buffer_shallow_copy(&info->initVector, &buffers[CKT_ARM_UC_MM_DER_MFST_FW_CRYPT_IV_IDX]); + + ARM_UC_buffer_shallow_copy(&info->certKT.certFingerPrint, &buffers[CKT_ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_FINGERPRINT_IDX]); + ARM_UC_buffer_shallow_copy(&info->certKT.certURL, &buffers[CKT_ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_URL_IDX]); + ARM_UC_buffer_shallow_copy(&info->certKT.keyTableURL, &buffers[CKT_ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_KEYTABLE_REF_IDX]); + + ARM_UC_buffer_shallow_copy(&info->strgId, &buffers[CKT_ARM_UC_MM_DER_MFST_FW_STRG_ID_IDX]); + ARM_UC_buffer_shallow_copy(&info->hash, &buffers[CKT_ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH_IDX]); + ARM_UC_buffer_shallow_copy(&info->uri, &buffers[CKT_ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL_IDX]); + info->size = ARM_UC_mmDerBuf2Uint(&buffers[CKT_ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE_IDX]); + } + return rc; +} + +arm_uc_error_t ARM_UC_mmFetchFirmwareInfoFSM(uint32_t event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + if (arm_uc_mmPersistentContext.ctx == NULL || *arm_uc_mmPersistentContext.ctx == NULL) + { + return (arm_uc_error_t){MFST_ERR_NULL_PTR}; + } + struct arm_uc_mm_fw_context_t* ctx = &(*arm_uc_mmPersistentContext.ctx)->getFw; + if (ctx->info == NULL) + { + return (arm_uc_error_t){MFST_ERR_NULL_PTR}; + } + ARM_UC_MM_FSM_HELPER_START(*ctx, ARM_UC_mmFwState2Str) { + case ARM_UC_MM_FW_STATE_IDLE: + err = (arm_uc_error_t){MFST_ERR_NONE}; + break; + case ARM_UC_MM_FW_STATE_BEGIN: + { + // If there is no manifest storage, assume it is still present in the input buffer + ctx->state = ARM_UC_MM_FW_STATE_READ_URI; + ARM_UC_MM_SET_BUFFER(ctx->current_data, ctx->info->manifestBuffer); + ctx->current_data.size = ctx->info->manifestSize; + break; + } + case ARM_UC_MM_FW_STATE_READ_URI: + { + // Get the encryption mode and the firmware info block. + const uint32_t fieldIDs [] = {ARM_UC_MM_DER_MFST_ENC_ENUM, ARM_UC_MM_DER_MFST_FIRMWARE}; + arm_uc_buffer_t buffers [sizeof(fieldIDs)/sizeof(fieldIDs[0])]; + int rc = ARM_UC_mmDERGetSignedResourceValues( + &ctx->current_data, + sizeof(fieldIDs)/sizeof(fieldIDs[0]), + fieldIDs, + buffers); + if (rc < 0) + { + err.code = MFST_ERR_DER_FORMAT; + break; + } + else if (rc > 0) + { + // in storage mode, firmware must be supplied. + err.code = MFST_ERR_EMPTY_FIELD; + break; + } + arm_uc_buffer_t fwBuf; + ARM_UC_buffer_shallow_copy(&fwBuf, &buffers[1]); + + // Store timestamp + ARM_UC_MM_SET_BUFFER(ctx->current_data, ctx->info->manifestBuffer); + ctx->current_data.size = ctx->info->manifestSize; + err = ARM_UC_mmGetTimestamp(&ctx->current_data, &ctx->info->timestamp); + if (err.error != 0) + { + break; + } + + ctx->info->cipherMode = ARM_UC_MM_CIPHERMODE_NONE; + // Found an encryption mode and firmware! + uint32_t cryptoMode = ARM_UC_mmDerBuf2Uint(&buffers[0]); + if (!ARM_UC_mmGetCryptoFlags(cryptoMode).aes) + { + // Encryption not in use. Skip key, ID, and IV extraction. + rc = ARM_UC_mmGetImageRef(ctx->info, &fwBuf); + if (rc == 0) + { + ctx->state = ARM_UC_MM_FW_STATE_NOTIFY; + err.code = MFST_ERR_NONE; + } + else + { + err.code = MFST_ERR_DER_FORMAT; + } + break; + } + // There are three possible combinations of encryption info: + // local key ID & encrypted key + rc = ARM_UC_mmGetLocalIDAndKey(ctx->info, &fwBuf); + if (!rc) { + ctx->state = ARM_UC_MM_FW_STATE_NOTIFY; + err.code = MFST_ERR_NONE; + break; + } + // Certificate and encrypted key + rc = ARM_UC_mmGetCertAndKey(ctx->info, &fwBuf); + if (!rc) { + ctx->state = ARM_UC_MM_FW_STATE_NOTIFY; + err.code = MFST_ERR_NONE; + break; + } + // Certificate and key table reference + rc = ARM_UC_mmGetCertAndKeyTable(ctx->info, &fwBuf); + if (!rc) { + ctx->state = ARM_UC_MM_FW_STATE_NOTIFY; + err.code = MFST_ERR_NONE; + break; + } + + break; + } + case ARM_UC_MM_FW_STATE_GET_FW_REF: + + // TODO: Ref only + case ARM_UC_MM_FW_STATE_NOTIFY: + ctx->state = ARM_UC_MM_FW_STATE_ROOT_NOTIFY_WAIT; + err.code = MFST_ERR_PENDING; + ARM_UC_PostCallback(&ctx->callbackStorage, arm_uc_mmPersistentContext.applicationEventHandler, ARM_UC_MM_RC_NEED_FW); + break; + + case ARM_UC_MM_FW_STATE_ROOT_NOTIFY_WAIT: + if (event == ARM_UC_MM_EVENT_BEGIN) + { + err.code = MFST_ERR_NONE; + ctx->state = ARM_UC_MM_FW_STATE_DONE; + } + break; + case ARM_UC_MM_FW_STATE_DONE: + // NOTE: The outer FSM will send the "done" message. + ctx->state = ARM_UC_MM_FW_STATE_IDLE; + break; + case ARM_UC_MM_FW_STATE_INVALID: + default: + err = (arm_uc_error_t){MFST_ERR_INVALID_STATE}; + break; + } ARM_UC_MM_FSM_HELPER_FINISH(*ctx); + return err; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmFetchFirmwareInfo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmFetchFirmwareInfo.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,28 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MANIFEST_MANAGER_FETCH_FIRMWARE_INFO_H +#define MANIFEST_MANAGER_FETCH_FIRMWARE_INFO_H + + +#include "arm_uc_mmConfig.h" +#include "update-client-common/arm_uc_common.h" + +arm_uc_error_t ARM_UC_mmFetchFirmwareInfoFSM(uint32_t event); + +#endif // MANIFEST_MANAGER_FETCH_FIRMWARE_INFO_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmGetLatestTimestamp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmGetLatestTimestamp.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,87 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_mmConfig.h" + +#include "arm_uc_mmGetLatestTimestamp.h" +#include "update-client-manifest-manager/update-client-manifest-manager-context.h" +#if !MANIFEST_MANAGER_NO_STORAGE +#include "cfstore-fsm.h" +#endif + +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" + +#define ARM_UC_MM_GET_LATEST_TS_STATE_LIST\ + ENUM_FIXED(ARM_UC_MM_GET_LATEST_TS_STATE_INVALID,0)\ + ENUM_AUTO(ARM_UC_MM_GET_LATEST_TS_STATE_BEGIN)\ + ENUM_AUTO(ARM_UC_MM_GET_LATEST_TS_STATE_FIND)\ + ENUM_AUTO(ARM_UC_MM_GET_LATEST_TS_STATE_READ)\ + ENUM_AUTO(ARM_UC_MM_GET_LATEST_TS_STATE_FETCH_NAME)\ + +enum arm_uc_mm_get_latest_ts_state { + #define ENUM_AUTO(name) name, + #define ENUM_FIXED(name, val) name = val, + ARM_UC_MM_GET_LATEST_TS_STATE_LIST + #undef ENUM_AUTO + #undef ENUM_FIXED +}; + +const char* ARM_UC_mmGetLatestTsState2Str(uint32_t state) +{ + switch (state) { + #define ENUM_AUTO(name) case name: return #name; + #define ENUM_FIXED(name, val) ENUM_AUTO(name) + ARM_UC_MM_GET_LATEST_TS_STATE_LIST + #undef ENUM_FIXED + #undef ENUM_AUTO + default: + return "Unknown State"; + } +} + +/** + * @brief Search the key/value store to find the latest timestamp. + * @detail Searches for all *.ts entries in the manifest manager key/value store prefix. As each entry is found, + * `getLatestManifestTimestampFSM()` updates ts with the largest timestamp encountered. If key is non-NULL, it is + * populated with the path to the largest timestamp. + * + * @param[out] ts Pointer to a 64-bit unsigned integer. Contains the largest timestamp encountered when + * getLatestManifestTimestampFSM completes. + * @param[out] key Pointer to a buffer; the location to store the key that contained the largest timestamp. + * @retval MFST_ERR_NONE Always returns success. + */ +arm_uc_error_t getLatestManifestTimestamp(uint64_t *ts, arm_uc_buffer_t* key) +{ + *ts = 0; + return (arm_uc_error_t){MFST_ERR_NONE}; +} + +/** + * @brief Run the getLatestManifestTimestampstate machine. + * @details Processes through the getLatestManifestTimestamp state machine in response to received events + * + * @param[in] event The event which has caused this run through the state machine + * @retval MFST_ERR_NONE getLatestManifestTimestampFSM has completed + * @retval MFST_ERR_PENDING getLatestManifestTimestampFSM is still on-going and waiting for an event + * @return any other error code indicates an error has occurred + */ +arm_uc_error_t getLatestManifestTimestampFSM(uint32_t event) +{ + return (arm_uc_error_t){MFST_ERR_NONE}; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmGetLatestTimestamp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmGetLatestTimestamp.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,28 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_MM_GET_LATEST_TIMESTAMP_H +#define ARM_UC_MM_GET_LATEST_TIMESTAMP_H + +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" + +arm_uc_error_t getLatestManifestTimestamp(uint64_t *ts, arm_uc_buffer_t* key); +arm_uc_error_t getLatestManifestTimestampFSM(uint32_t event); + +#endif // ARM_UC_MM_GET_LATEST_TIMESTAMP_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmInit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmInit.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,424 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_mmInit.h" +#include "arm_uc_mmCommon.h" +#if !MANIFEST_MANAGER_NO_STORAGE +#include "update-client-manifest-manager/update-client-manifest-manager-context.h" +#include "arm_uc_mmGetLatestTimestamp.h" +#include "arm_uc_mm_derparse.h" +#include "cfstore-fsm.h" +#include "crypto-fsm.h" +#include "accessors.h" +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_common.h" +#include "update-client-common/arm_uc_error.h" +#include "mbedtls/sha256.h" + +#include "arm_uc_mmFSMHelper.h" + +#ifndef min +#define min(X,Y) ((X) < (Y) ? (X) : (Y)) +#endif + +const char* ARM_UC_mmInitState2Str(uint32_t state) +{ + switch (state) { + #define ENUM_AUTO(name) case name: return #name; + #define ENUM_FIXED(name, val) ENUM_AUTO(name) + ARM_UC_MM_INIT_STATE_LIST + #undef ENUM_FIXED + #undef ENUM_AUTO + default: + return "Unknown State"; + } +} + + + +arm_uc_error_t arm_uc_mmInitFSM(uint32_t event) +{ + if (arm_uc_mmPersistentContext.ctx == NULL || *arm_uc_mmPersistentContext.ctx == NULL) + { + return (arm_uc_error_t){MFST_ERR_NULL_PTR}; + } + struct arm_uc_mmInitContext_t* ctx = &(*arm_uc_mmPersistentContext.ctx)->init; + arm_uc_error_t err = {MFST_ERR_PENDING}; + + ARM_UC_MM_FSM_HELPER_START(*ctx, ARM_UC_mmInitState2Str){ + case ARM_UC_MM_INIT_BEGIN: + // Find the latest manifest. + ARM_UC_MM_SET_BUFFER(ctx->keyPath, ctx->pathBuffer); + err = getLatestManifestTimestamp(&ctx->timestamp, &ctx->keyPath); + ctx->state = ARM_UC_MM_INIT_LATEST_MFST; + // clear the missing dep flag + ctx->missingDep = 0; + // Set the root manifest flag + ctx->root = 1; + + event = ARM_UC_MM_EVENT_BEGIN; + break; + case ARM_UC_MM_INIT_LATEST_MFST: + { + err = getLatestManifestTimestampFSM(event); + if (err.code != MFST_ERR_NONE) + { + break; + } + if (ctx->timestamp == 0) + { + err.code = MFST_ERR_NO_MANIFEST; + break; + } + // Copy out the root manifest's base path + strncpy((char*)ctx->rootManifestBasePath, (char*)ctx->keyPath.ptr, sizeof(ctx->rootManifestBasePath)-1); + ctx->rootManifestBasePath[sizeof(ctx->rootManifestBasePath)-1] = 0; + // Modify the key path. + char* pos = (char*)ctx->keyPath.ptr + strlen((char*)ctx->keyPath.ptr) - strlen("ts"); + *pos = 'm'; + *(pos + 1) = 0; + // Setup the manifest buffer + ARM_UC_MM_SET_BUFFER(ctx->manifest, ctx->manifestBuffer); + // Find the manifest + err = ARM_UC_mmCfStoreFindKey(&ctx->keyPath); + if (err.code != MFST_ERR_NONE) + { + break; + } + event = ARM_UC_MM_EVENT_CF_BEGIN; + ctx->state = ARM_UC_MM_INIT_FINDING; + // no break; + } + case ARM_UC_MM_INIT_FINDING: + if (event == UCMM_EVENT_CF_FIND_FAILED) + { + if (ctx->root) + { + //TODO: assert! This should not be possible! + err.code = MFST_ERR_INVALID_STATE; + } else { + // No more deps to find. + err.code = MFST_ERR_NONE; + } + break; + } + err = ARM_UC_mmCfStoreFindKeyFSM(event); + if (err.code != MFST_ERR_NONE) + { + break; + } + // Read the manifest + err = ARM_UC_mmCfStoreReadLastKey(&ctx->manifest); + if (err.code != MFST_ERR_NONE) { + break; + } + event = ARM_UC_MM_EVENT_CF_BEGIN; + ctx->state = ARM_UC_MM_INIT_READING; + // no break; + case ARM_UC_MM_INIT_READING: + // Read the manifest into a buffer + err = ARM_UC_mmCfStoreReadLastKeyFSM(event); + if (err.code != MFST_ERR_NONE) + { + break; + } + ctx->state = ARM_UC_MM_INIT_STATE_HASH_VERIFY; + // Preserve the manifest key + ARM_UC_mmCfStorePreserveLastKey(); + + // no break; + case ARM_UC_MM_INIT_STATE_HASH_VERIFY: + // Verify the manifest hash + err = ucmmValidateManifestHash(&ctx->manifest); + if (err.code == MFST_ERR_NONE) { + uint32_t val; + err = ARM_UC_mmGetCryptoMode(&ctx->manifest, &val); + if (err.code != MFST_ERR_NONE) + { + break; + } + ucmm_crypto_flags_t cryptoMode = ARM_UC_mmGetCryptoFlags(val); + if(cryptoMode.ecc || cryptoMode.rsa) { + ctx->state = ARM_UC_MM_INIT_STATE_PK_VERIFY; + } else { + ctx->state = ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN; + } + } + break; + case ARM_UC_MM_INIT_STATE_PK_VERIFY: + // Verify the manifest signature + err = ucmmValidateSignature(&ctx->manifest); + if (err.code == MFST_ERR_NONE) + { + ctx->state = ARM_UC_MM_INIT_STATE_PK_VERIFYING; + } + break; + case ARM_UC_MM_INIT_STATE_PK_VERIFYING: + err = ucmmValidateSignatureFSM(event); + if (err.code == MFST_ERR_NONE) + { + ctx->state = ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN; + } + break; + case ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN: + // ATTACKVECTOR: If an attacker can add a manifest to the dependency prefix in the config store, the manifest + // manager has no way to know that it is not valid, due to the flat file heirarchy. + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_MANIFEST_BEGIN; + // NO BREAK; + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_MANIFEST_BEGIN: + // Loop: manifest + // Set the depidx to 0 + ctx->depidx = 0; + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH; + // NO BREAK; + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH: + { + arm_uc_buffer_t dependency; + arm_uc_buffer_t hash; + // Read the dependency at depidx + err = ARM_UC_mmGetManifestLinksElement(&ctx->manifest, ctx->depidx, &dependency); + // If there isn't one + if (err.code != MFST_ERR_NONE) + { + break; + } + if (dependency.ptr == NULL) + { + // Exit Loop: dependency + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_END; + err.code = MFST_ERR_NONE; + break; + } + // Get the dependency hash + err = ARM_UC_mmGetManifestLinksHash(&dependency, &hash); + if (err.code != MFST_ERR_NONE) + { + break; + } + // Store the dependency hash + memcpy(ctx->currentHash, hash.ptr, min(hash.size, sizeof(ctx->currentHash))); + // Format the dependency search key + // The result of this operation is: + // com.arm.mbed.update.mm.m.<root manifest hash>.deps.<dependency hash>.m + // ASSUMES sizeof keypath > sizeof rootManifestBasePath + strncpy((char*)ctx->keyPath.ptr, (char*)ctx->rootManifestBasePath, sizeof(ctx->keyPath.ptr)); + ctx->keyPath.size = strlen(ctx->keyPath.ptr); + // Back up one space to remove the 'm' + strncpy((char*)ctx->keyPath.ptr + ctx->keyPath.size-1, "deps.", ctx->keyPath.size_max - ctx->keyPath.size); + ctx->keyPath.size = strlen(ctx->keyPath.ptr); + ARM_UC_Base64Enc(ctx->keyPath.ptr + ctx->keyPath.size, ctx->keyPath.size_max - ctx->keyPath.size, &hash); + ctx->keyPath.size = strlen(ctx->keyPath.ptr); + strncpy((char*)ctx->keyPath.ptr + ctx->keyPath.size, ".m", ctx->keyPath.size_max - ctx->keyPath.size); + ctx->keyPath.size += 3; // add one for null terminator + + // Find the dependency in the config store + err = ucmmCfstoreFindAndRead((char*)ctx->keyPath.ptr, &ctx->manifest); + if (err.code == MFST_ERR_NONE) + { + event = ARM_UC_MM_EVENT_BEGIN; + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_READING_DEPENDENCY; + } + break; + } + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_READING_DEPENDENCY: + // If there is no matching dependency + if (event == UCMM_EVENT_CF_FIND_FAILED) + { + // Set the missing dep flag + ctx->missingDep = 1; + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK; + // Continue... + err.code = MFST_ERR_NONE; + break; + } + // Find/Read the dependency manifest + err = ucmmCfstoreFindAndReadFSM(event); + if (err.code != MFST_ERR_NONE) + { + break; + } + // There is a matching dependency + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_CHECK_HASH; + // No break; + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_CHECK_HASH: + { +#if MAX_HASH_BYTES != 256/8 +#error Hash size mismatch +#endif + uint8_t localhash[MAX_HASH_BYTES]; + arm_uc_buffer_t local = { + .size_max = MAX_HASH_BYTES, + .size = 256/8, + .ptr = localhash + }; + arm_uc_buffer_t resource; + const int32_t valueID = ARM_UC_MM_DER_RESOURCE; + int rc = ARM_UC_mmDERGetSignedResourceValues(&resource, 1, &valueID, &resource); + if (rc) + { + err.code = MFST_ERR_DER_FORMAT; + break; + } + { + // Calculate the dependency hash + mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + mbedtls_sha256_starts(&ctx, 0); + mbedtls_sha256_update(&ctx, resource.ptr, resource.size); + mbedtls_sha256_finish(&ctx, local.ptr); + } + { + arm_uc_buffer_t remote = { + .size_max = MAX_HASH_BYTES, + .size = 256/8, + .ptr = ctx->currentHash + }; + // Validate the dependency hash + if(ARM_UC_BinCompareCT(&local, &remote)) + { + // If invalid, Set the missing dep flag + ctx->missingDep = 1; + // Delete the manifest + ARM_UC_mmCfStoreDeleteLastKey(); + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_DELETE; + event = ARM_UC_MM_EVENT_CF_BEGIN; + } + else + { + // End Loop: dependency + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ; + // Increment the depidx + ctx->depidx++; + } + } + break; + } + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_DELETE: + err = ARM_UC_mmCfStoreDeleteLastKeyFSM(event); + if (err.code == MFST_ERR_NONE) + { + // Make sure a URI exists. + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK; + } + break; + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK: + { + // modify the search path + char* pos = (char*)ctx->keyPath.ptr + ctx->keyPath.size - 2; // null terminator + strncpy(pos, "uri", ctx->keyPath.size_max - (ctx->keyPath.size - 2)); // null terminator + // Check if there is a URI entry + // HACK: No API for find without ovewriting the existing stored key. Use find/read even though we don't need the + // data. + err = ucmmCfstoreFindAndRead((char*)ctx->keyPath.ptr, &ctx->manifest); + if (err.code != MFST_ERR_NONE) + { + break; + } + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECKING; + event = ARM_UC_MM_EVENT_CF_BEGIN; + // no break + } + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECKING: + if (event == UCMM_EVENT_CF_FIND_FAILED) + { + // TODO: Erase all deps and start over. + err.code = MFST_ERR_INVALID_STATE; + break; + } + err = ucmmCfstoreFindAndReadFSM(event); + if (err.code == MFST_ERR_NONE) + { + // Increment the depidx + ctx->depidx++; + // End Loop: dependency + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ; + } + break; + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ: + // Loop: dependency + // Restore the manifest key + ARM_UC_mmCfStoreRestoreLastKey(); + // Seek the current key + err = ARM_UC_mmCfStoreSeekLastKey(0); + if (err.code == MFST_ERR_NONE) + { + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_SEEKING; + } + break; + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_SEEKING: + err = ARM_UC_mmCfStoreSeekLastKeyFSM(event); + if (err.code != MFST_ERR_NONE) + { + break; + } + // Read the current key + err = ARM_UC_mmCfStoreReadLastKey(&ctx->manifest); + if (err.code != MFST_ERR_NONE) + { + break; + } + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READING; + event = ARM_UC_MM_EVENT_CF_BEGIN; + // no break + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READING: + err = ARM_UC_mmCfStoreReadLastKeyFSM(event); + if (err.code == MFST_ERR_NONE) + { + ctx->state = ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH; + // Preserve the manifest key + ARM_UC_mmCfStorePreserveLastKey(); + } + break; + case ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_END: + // Format the dependency search key + strncpy((char*)ctx->keyPath.ptr, (char*)ctx->rootManifestBasePath, sizeof(ctx->rootManifestBasePath)); + ctx->keyPath.size = sizeof(ctx->rootManifestBasePath)-1; + strncpy((char*)ctx->keyPath.ptr + ctx->keyPath.size, ".deps.*", ctx->keyPath.size_max - ctx->keyPath.size); + ctx->keyPath.size += sizeof(".deps.*") - 1; + // If the root flag is set + if (ctx->root) + { + // Clear the root flag + ctx->root = 0; + // Start the dependency search + err = ARM_UC_mmCfStoreFindKey(&ctx->keyPath); + } + else + { + // Continue the dependency search + err = ARM_UC_mmCfStoreFindNextKey(); + } + if (err.code == MFST_ERR_NONE) + { + event = ARM_UC_MM_EVENT_CF_BEGIN; + // End Loop: manifest + ctx->state = ARM_UC_MM_INIT_FINDING; + } + break; + default: + err.code = MFST_ERR_INVALID_STATE; + break; + } ARM_UC_MM_FSM_HELPER_FINISH(*ctx); + if (err.code == MFST_ERR_NONE && ctx->missingDep == 1) + { + // TODO: Configure & trigger insert FSM + } + return err; +} + +#endif // !MANIFEST_MANAGER_NO_STORAGE
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmInit.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmInit.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,59 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_MM_INIT_H +#define ARM_UC_MM_INIT_H + +#include "update-client-manifest-manager/update-client-manifest-manager-context.h" +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" + +#define ARM_UC_MM_INIT_STATE_LIST\ + ENUM_FIXED(ARM_UC_MM_INIT_UNINIT,0)\ + ENUM_AUTO(ARM_UC_MM_INIT_BEGIN)\ + ENUM_AUTO(ARM_UC_MM_INIT_LATEST_MFST)\ + ENUM_AUTO(ARM_UC_MM_INIT_FINDING)\ + ENUM_AUTO(ARM_UC_MM_INIT_READING)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_HASH_VERIFY)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_PK_VERIFY)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_PK_VERIFYING)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_ROOT_DEPS_VERIFY_BEGIN)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_MANIFEST_BEGIN)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_GET_HASH)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_READING_DEPENDENCY)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_CHECK_HASH)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_DELETE)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECK)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_URI_CHECKING)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READ)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_SEEKING)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_READING)\ + ENUM_AUTO(ARM_UC_MM_INIT_STATE_DEPS_LOOP_DEPENDENCY_END)\ + + +enum arm_uc_mm_init_state { + #define ENUM_AUTO(name) name, + #define ENUM_FIXED(name, val) name = val, + ARM_UC_MM_INIT_STATE_LIST + #undef ENUM_AUTO + #undef ENUM_FIXED +}; + +arm_uc_error_t arm_uc_mmInitFSM(uint32_t event); + +#endif // ARM_UC_MM_INIT_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmInsertManifest.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmInsertManifest.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,667 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_mmCryptoUtils.h" +#include "arm_uc_mmCommon.h" +#include "arm_uc_mmConfig.h" +#include "arm_uc_mmStateSelector.h" +#include "arm_uc_mmDerManifestAccessors.h" +#include "arm_uc_mmDerManifestParser.h" +#include "arm_uc_mmGetLatestTimestamp.h" +#include "arm_uc_mmFSMHelper.h" +#include "arm_uc_mmInsertManifest.h" +#include "update-client-common/arm_uc_scheduler.h" + +#include "update-client-manifest-manager/update-client-manifest-manager-context.h" +#include "update-client-manifest-manager/update-client-manifest-manager.h" +#include "update-client-manifest-manager/update-client-manifest-types.h" + +#include "pal4life-device-identity/pal_device_identity.h" +#include "pal.h" + +#include <stdint.h> +#include <stdio.h> +#include <stddef.h> +#include <string.h> + +/** + * @file arm_uc_mmInsertManifest.c + * @brief Inserts a manifest into a slot specified by the manifest. + * @details This API is used by the manifest manager to validate and store a manifest. + * + * The workflow for inserting a manifest is: + * 1. Check the version of the manifest + * 2. Validate the cryptographic mode + * 3. Verify the hash of the manifest. + * 4. Verify each signature of the manifest. + * 5. Validate the applicability of the manifest (GUID matching) + * 6. Validate the storage identifier + * TBD: Store the manifest in the KCM + * + * NOTE: There is a security vs. energy tradeoff in this code. + * To optimize for energy, the cheapest fields should be checked first, that means checking applicability before + * hash or signature. However, to optimize for security, we must prioritize safety over energy. Since parsers are + * notorious sources of bugs, we must make every effort to protect the parser from insecure content. This means + * accessing the absolute minimum of fields prior to verifyinng the signature. + * + * The current version of this code optimizes for security. Once the parser has been more thoroughly validated, we can + * consider exposing it to more unvalidated data as an energy saving measure. + * + * @dot + * digraph { + * Idle + * Idle -> Begin [label="[event == BEGIN]"] + * Begin + * Begin -> VerifyBasicParameters + * VerifyBasicParameters + * // Validate the manifest size (This is a precursor to security validation) + * // Validate the manifest version (This is required in order to know how to parse the manifest) + * // Validate the manifest encryption mode (This is required in order to know how to validate the signature) + * VerifyBasicParameters -> VerifyHash + * VerifyBasicParameters -> VerifyFail [label="[Basic Parameters invalid]"] + * VerifyHash + * VerifyHash -> VerifySignatureLoopStart + * VerifyHash -> VerifyFail [label="[Hash invalid]"] + * VerifySignatureLoopStart + * VerifySignatureLoopStart -> VerifySignatureStart + * VerifySignatureStart + * VerifySignatureStart -> VerifySignature + * VerifySignatureStart -> VerifyParameters [label="[No More Signatures]"] + * VerifySignature + * VerifySignature -> VerifyParameters [label="[Last Signature]"] + * VerifySignature -> VerifyFail [label="[Signature invalid]"] + * // Validate the applicability of the manifest (GUID matching) + * // Validate the storage identifier + * VerifyParameters + * VerifyParameters -> VerifyTimestamp + * VerifyParameters -> VerifyFail [label="[Parameters invalid]"] + * VerifyTimestampStart + * VerifyTimestampStart -> VerifyTimestamp + * VerifyTimestamp + * VerifyTimestamp -> VerifyApplication + * VerifyTimestamp -> VerifyFail [label="[Timestamp too old]"] + * VerifyApplication + * VerifyApplication -> VerifyDone + * VerifyApplication -> VerifyFail [label="[App denied]"] + * VerifyFail + * VerifyFail -> Idle + * VerifyDone + * VerifyDone -> AlertHub + * AlertHub + * AlertHub -> Idle + * } + * @enddot + */ + + +static const char* ARM_UC_mmInsertState2Str(uint32_t state) +{ + switch (state) { + #define ENUM_AUTO(name) case name: return #name; + #define ENUM_FIXED(name, val) ENUM_AUTO(name) + ARM_UC_MM_INS_STATE_LIST + #undef ENUM_AUTO + #undef ENUM_FIXED + default: + return "Unknown State"; + } +} + +#define max(A,B) ((A)>(B)?(A):(B)) + +/** @brief Validate that the resource contained in this signed container is a manifest. + */ +static arm_uc_error_t validateResourceType(arm_uc_buffer_t* buffer) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + arm_uc_buffer_t type = { 0 }; + // Read the resource type field. + err = ARM_UC_mmDERSignedResourceGetSingleValue(buffer, + ARM_UC_MM_DER_RESOURCE_TYPE, &type); + if (type.ptr == NULL) + { + err.code = MFST_ERR_DER_FORMAT; + } + else if (err.error == ERR_NONE) + { + // The resource type must be a manifest. + if (ARM_UC_mmDerBuf2Uint(&type) != 0) + { + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_DER_FORMAT); + } + } + return err; +} +/** @brief Validate that this manifest is a supported version + */ +static arm_uc_error_t validateManifestVersion(arm_uc_buffer_t* buffer) +{ + uint32_t val = 0; + // Read the manifest version + arm_uc_error_t err = ARM_UC_mmGetVersion(buffer, &val); + if (err.code == MFST_ERR_NONE) + { + // Verify the manifest version + if (val != MANIFEST_SUPPORTED_VERSION) { + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_VERSION); + } + } + return err; +} + +/** @brief Validate the manifest size + */ +static arm_uc_error_t validateManifestSize(arm_uc_buffer_t* buffer) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + arm_uc_buffer_t val = {0}; + + // Get the manifest inner part + err = ARM_UC_mmDERSignedResourceGetSingleValue(buffer, ARM_UC_MM_DER_MFST, &val); + if (err.error == ERR_NONE) + { + // Make sure that the manifest does not overrun. + uintptr_t bufend = (uintptr_t)buffer->ptr + buffer->size; + uintptr_t valend = (uintptr_t)val.ptr + val.size; + if (bufend < valend) + { + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_SIZE); + } + // TODO: There should be a minimum size for the manifest too. + } + return err; +} + +/** @brief Validate the crypto mode + * @details The manifest must contain a cryptographic mode identifier. Only a small number of modes are supported. If + * the manifest is to be processed, then one of these modes must be supported. + * + * While the manifest format supports OID cryptographic mode identifiers, these are not currently supported in + * the update client. + */ +static arm_uc_error_t validateCryptoMode(arm_uc_buffer_t* buffer, arm_uc_mm_crypto_flags_t* flags) +{ + uint32_t cryptoMode = 1U; // default SHA256 and ECC + arm_uc_error_t err = ARM_UC_mmGetCryptoMode(buffer, &cryptoMode); + if (err.error == ERR_NONE) + { + if (cryptoMode <= MFST_CRYPT_UNINIT || MFST_CRYPT_MAX <= cryptoMode) + { + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_CRYPTO_MODE); + } + else + { + *flags = ARM_UC_mmGetCryptoFlags(cryptoMode); + } + } + return err; +} + +// Validate that the manifest applies to this device +static arm_uc_error_t validateFirmwareApplicability(arm_uc_buffer_t* buffer) +{ + arm_uc_buffer_t vendor_guid = {0}; + arm_uc_buffer_t class_guid = {0}; + arm_uc_buffer_t device_guid = {0}; + + arm_uc_error_t err = {MFST_ERR_NONE}; + if (err.code == MFST_ERR_NONE) + err = ARM_UC_mmGetVendorGuid(buffer, &vendor_guid); + if (err.code == MFST_ERR_NONE) + err = ARM_UC_mmGetClassGuid(buffer, &class_guid); + if (err.code == MFST_ERR_NONE) + err = ARM_UC_mmGetDeviceGuid(buffer, &device_guid); + if (err.code == MFST_ERR_NONE) + err = pal_deviceIdentityCheck( + (vendor_guid.size != 0UL ? &vendor_guid : NULL), + (class_guid.size != 0UL ? &class_guid : NULL), + (device_guid.size != 0UL ? &device_guid : NULL) + ); + return err; +} +/* + * DOT Setup + * DOT: digraph { + */ + +/* @brief Idle state + * @details The idle state generates no events and causes no state transitions. It only moves to a new state when the + * `ARM_UC_MM_EVENT_BEGIN` event is received. + * DOT States: + * DOT: Idle + * DOT: Idle -> Begin [label="[event == BEGIN]"] + */ +static arm_uc_error_t state_idle(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + if (*event == ARM_UC_MM_EVENT_BEGIN) + { + ctx->state = ARM_UC_MM_INS_STATE_BEGIN; + } + return err; +} +/* @brief Begin state + * @details This is an empty placeholder state that is used as a state transition target for Idle. This allows + * modifications to the FSM flow without modifying Idle. + * DOT States: + * DOT: Begin + * DOT: Begin -> VerifyBasicParameters + */ +static arm_uc_error_t state_begin(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_BASIC_PARAMS; + return err; +} +/* @brief Verify critical pre-security parameters + * @details Some parameters must be verified before security validation. These parameters are critical to either finding + * or validating the security parameters themselves. The parameters validated are: + * + * * The resource size (This is a precursor to security validation) + * * The resource is a manifest (A non-manifest will not be accepted) + * * The manifest version (This is required in order to know how to parse the manifest) + * * The manifest encryption mode (This is required in order to know how to validate the signature) + * + * DOT States: + * DOT: VerifyBasicParameters + * DOT: VerifyBasicParameters -> VerifyHash + * DOT: VerifyBasicParameters -> VerifyFail [label="[Basic Parameters invalid]"] + */ +static arm_uc_error_t state_verifyBasicParameters(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + + if (err.error == ERR_NONE) + { + err = validateResourceType(&ctx->manifest); + } + if (err.error == ERR_NONE) + { + err = validateManifestSize(&ctx->manifest); + } + if (err.error == ERR_NONE) + { + err = validateManifestVersion(&ctx->manifest); + } + if (err.error == ERR_NONE) + { + err = validateCryptoMode(&ctx->manifest, &ctx->cryptoMode); + } + // Set the state based on error condition + if (err.error == ERR_NONE) + { + ctx->state = ARM_UC_MM_INS_STATE_HASH_VERIFY; + } + else + { + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_FAIL; + } + return err; +} +/** @brief Verify the manifest hash + * @details Manifest hash verification happens in a single state. This is because hash verification is currently + * considered to be a blocking operation. If an asynchronous hash accelerator is used, this will need to be + * modified to use two states to handle hash initiation and waiting for completion. + * + * DOT States: + * DOT: VerifyHash + * DOT: VerifyHash -> VerifySignatureLoopStart + * DOT: VerifyHash -> VerifyFail [label="[Hash invalid]"] + */ +static arm_uc_error_t state_verifyHash(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = ARM_UC_mmValidateManifestHash(&ctx->manifest); + if (err.error == ERR_NONE) + { + // If the cryptoMode specifies either ecc or rsa, then we can validate that. + if(ctx->cryptoMode.ecc || ctx->cryptoMode.rsa) + { + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_SIG_LOOP; + } + else + { + // Unsigned manifests are not supported at this time, so they count as a failure. + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_INVALID_SIGNATURE); + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_FAIL; + } + } + else + { + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_HASH); + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_FAIL; + } + return err; +} +/** @brief Start the signature verification loop. + * @details This state provides initialization for the signature verification loop. + * The outer loop is tracked by `loopCounters[0]` and represents the signature index. + * + * DOT States: + * DOT: VerifySignatureLoopStart + * DOT: VerifySignatureLoopStart -> VerifySignatureStart + */ +static arm_uc_error_t state_verifySignatureLoopStart(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + // Set the exterior loop counter + ctx->loopCounters[0] = 0; + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_SIG_START; + return err; +} +/** @brief Begin verifying the signature. + * @details This calls the ARM_UC_mmValidateSignature setup function, but does not start the signature verification + * state machine. `ARM_UC_mmValidateSignature` attempts to read a signature at the index specified by the + * outer loop counter (`loopCounters[0]`). If it fails, it assumes that all signatures have been processed. + * If at least one signature has been processed, then continue with validation, but a minimum of one signature + * is required for validation. + * + * DOT States: + * DOT: VerifySignatureStart + * DOT: VerifySignatureStart -> VerifySignature + * DOT: VerifySignatureStart -> VerifyParameters [label="[No More Signatures]"] + */ +static arm_uc_error_t state_verifySignatureStart(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + // start the signature verification + arm_uc_error_t err = ARM_UC_mmValidateSignature(&ctx->signatureContext, + ARM_UC_mmCallbackFSMEntry, + &ctx->manifest, + &ctx->certificateStorage, + ctx->loopCounters[0]); + if (err.error == ERR_NONE) + { + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_SIG_WAIT; + *event = ARM_UC_MM_RC_NONE; + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_PENDING); + } + // If there are no more signatures and at least one signature was validated + if (err.code == ARM_UC_DP_ERR_NO_MORE_ELEMENTS) + { + if (ctx->loopCounters[0] >= 1) + { + // Signature validation done. Move on to parameter validation. + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_PARAMS; + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_NONE); + } + else + { + // WARNING: If the fingerprint is empty, MFST_ERR_INVALID_SIGNATURE is returned. + // At least one signature is required. + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_INVALID_SIGNATURE); + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_FAIL; + } + } + return err; +} +/** @brief Wait for signature validation to complete. + * @details Calls the `ARM_UC_mmValidateSignature` state machine and collects exit status. When signature validation is + * complete, the return value will be `MFST_ERR_NONE`. + * + * DOT States: + * DOT: VerifySignature + * DOT: VerifySignature -> VerifyFail [label="[Signature invalid]"] + * DOT: VerifySignature -> VerifySignatureStart + */ +static arm_uc_error_t state_verifySignature(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + // Wait for the signature verification to end. + // If the signature validation ended + if (*event == ARM_UC_MM_RC_DONE) + { + // Increment the loop counter + ctx->loopCounters[0] += 1; + // Return to the beginning of the loop. + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_SIG_START; + } + else if (*event == ARM_UC_MM_RC_ERROR) + { + err = ctx->signatureContext.storedError; + } + else + { + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_BAD_EVENT); + } + return err; +} +/** @brief Validates remaining parsable parameters + * @details This currently means only the firmware applicability, as identified by UUID. Several additiional parameters + * could be validated: + * + * * Storage identifier + * * Payload type identifier + * * URI validation in payload reference + * * Valid size of payload hash + * * nonce size, non-zero + * * Valid From, Valid To + * * timestamp + * * Encryption info + * + * + * DOT States: + * DOT: VerifyParameters + * DOT: VerifyParameters -> VerifyApplication + * DOT: VerifyParameters -> VerifyFail [label="[Parameters invalid]"] + */ +static arm_uc_error_t state_verifyParameters(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = validateFirmwareApplicability(&ctx->manifest); + if (err.error == ERR_NONE) + { + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_TS_START; + } + return err; +} +/** @brief Initiate timestamp verification. + * @details This starts the process of loading the active timestamp. This may be a non-blocking operation. + * + * DOT States: + * DOT: VerifyTimestampStart + * DOT: VerifyTimestampStart -> VerifyTimestamp + */ +static arm_uc_error_t state_verifyTimestampStart(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + // Since this is a root manifest, extract maximum stored timestamp + arm_uc_error_t err = getLatestManifestTimestamp(&ctx->max_ts, NULL); + if (err.error == ERR_NONE) + { + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_TS; + *event = ARM_UC_MM_EVENT_BEGIN; + } + return err; +} +/** @brief Waits for the active timestamp to be loaded. + * @details Once the active timestamp has been loaded, this validates the inserted manifest timestamp. + * + * DOT States: + * DOT: VerifyTimestamp + * DOT: VerifyTimestamp -> VerifyApplication + * DOT: VerifyTimestamp -> VerifyFail [label="[Timestamp too old]"] + */ +static arm_uc_error_t state_verifyTimestamp(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = getLatestManifestTimestampFSM(*event); + if (err.error == ERR_NONE) + { + err = ARM_UC_mmGetTimestamp(&ctx->manifest, &ctx->current_ts); + } + if (err.error == ERR_NONE) + { +#if MANIFEST_ROLLBACK_PROTECTION + // Validate the timestamp for rollback protection. + if (arm_uc_mmContext.max_ts >= arm_uc_mmContext.current_ts) + { + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_ROLLBACK); + } + else +#endif + { + ARM_UC_MFST_SET_ERROR(err, MFST_ERR_NONE); + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_APP; + } + } + return err; +} + +/** @brief Calls out to a handler provided by the application. + * @details Currently unimplemented. + * + * DOT States: + * DOT: VerifyApplication + * DOT: VerifyApplication -> VerifyDone + * DOT: VerifyApplication -> VerifyFail [label="[App denied]"] + */ +static arm_uc_error_t state_verifyApplication(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + if (err.error == ERR_NONE) + { + ctx->state = ARM_UC_MM_INS_STATE_VERIFY_DONE; + } + return err; +} +/** @brief Verification has failed. + * @details This state will never be entered. This is for documentation purposes only. The state machine exits when an + * error is detected, so this state cannot be entered. The hub will be notified via the state machine's error + * handler. + * + * DOT States: + * DOT: VerifyFail + * DOT: VerifyFail -> Idle + */ + + +/** @brief Verification has completed successfully. + * @details This is a placeholder state that may be useful if more operations must be performed after verification, + * for example, storage of the manifest. + * + * DOT States: + * DOT: VerifyDone + * DOT: VerifyDone -> AlertHub + */ +static arm_uc_error_t state_verifyDone(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + if (err.error == ERR_NONE) + { + ctx->state = ARM_UC_MM_INS_STATE_ALERT; + } + return err; +} +/** @brief Alert the hub that insert has finished processing the manifest. + * @details Queues a callback to the hub, that reports completion. + * + * DOT States: + * DOT: AlertHub + * DOT: AlertHub -> Idle + */ +static arm_uc_error_t state_alertHub(struct arm_uc_mmInsertContext_t* ctx, uint32_t* event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + return err; +} +/** + * DOT Teardown + * DOT: } + */ + +arm_uc_error_t ARM_UC_mmInsertFSM(uint32_t event) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + struct arm_uc_mmInsertContext_t* ctx; + if (arm_uc_mmPersistentContext.ctx == NULL || *arm_uc_mmPersistentContext.ctx == NULL) + { + return (arm_uc_error_t){MFST_ERR_NULL_PTR}; + } + ctx = &(*arm_uc_mmPersistentContext.ctx)->insert; + + uint32_t oldState; +#if ARM_UC_MM_ENABLE_INSERT_TEST_VECTORS + uint32_t oldEvent; +#endif + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "> %s (%u)\n", __PRETTY_FUNCTION__, (unsigned)event); + do { + // Preserve the old state to check for state transitions + oldState = ctx->state; + +#if ARM_UC_MM_ENABLE_INSERT_TEST_VECTORS + // Preserve the old event for testing + oldEvent = event; +#endif + // Reset error logging + arm_uc_mmPersistentContext.errorFile = NULL; + arm_uc_mmPersistentContext.errorLine = 0; + + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "+ %s state: %s(%u)\n", __PRETTY_FUNCTION__, + ARM_UC_mmInsertState2Str(ctx->state), (unsigned)ctx->state);\ + switch (ctx->state) + { + case ARM_UC_MM_INS_STATE_IDLE: + err = state_idle(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_BEGIN: + err = state_begin(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_VERIFY_BASIC_PARAMS: + err = state_verifyBasicParameters(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_HASH_VERIFY: + err = state_verifyHash(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_VERIFY_SIG_LOOP: + err = state_verifySignatureLoopStart(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_VERIFY_SIG_START: + err = state_verifySignatureStart(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_VERIFY_SIG_WAIT: + err = state_verifySignature(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_VERIFY_PARAMS: + err = state_verifyParameters(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_VERIFY_TS_START: + err = state_verifyTimestampStart(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_VERIFY_TS: + err = state_verifyTimestamp(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_VERIFY_APP: + err = state_verifyApplication(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_VERIFY_DONE: + err = state_verifyDone(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_ALERT: + err = state_alertHub(ctx, &event); + break; + case ARM_UC_MM_INS_STATE_INVALID: + default: + err = (arm_uc_error_t){MFST_ERR_INVALID_STATE}; + break; + } +#if ARM_UC_MM_ENABLE_INSERT_TEST_VECTORS + if (arm_uc_mmPersistentContext.testHook) + { + arm_uc_mmPersistentContext.testHook("insert", *arm_uc_mmPersistentContext.ctx, oldState, oldEvent, err); + } +#endif + } while (err.code == MFST_ERR_NONE && oldState != ctx->state); + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "< %s %c%c:%hu (%s)\n", __PRETTY_FUNCTION__, err.modulecc[0], err.modulecc[1], err.error, ARM_UC_err2Str(err)); + return err; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmInsertManifest.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmInsertManifest.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,28 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MANIFEST_MANAGER_INSERT_MANIFEST_H +#define MANIFEST_MANAGER_INSERT_MANIFEST_H + + +#include "arm_uc_mmConfig.h" +#include "update-client-common/arm_uc_common.h" + +arm_uc_error_t ARM_UC_mmInsertFSM(uint32_t event); + +#endif // MANIFEST_MANAGER_INSERT_MANIFEST_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmStateSelector.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmStateSelector.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,128 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_mmCryptoUtils.h" +#include "arm_uc_mmCommon.h" +#include "arm_uc_mmConfig.h" +#include "arm_uc_mmStateSelector.h" +#include "arm_uc_mmInit.h" +#include "arm_uc_mmFSMHelper.h" +#include "arm_uc_mmFetchFirmwareInfo.h" +#include "arm_uc_mmInsertManifest.h" + +#include "update-client-manifest-manager/update-client-manifest-manager-context.h" +#include "update-client-manifest-manager/update-client-manifest-manager.h" +#include "update-client-manifest-manager/update-client-manifest-types.h" + +#include "update-client-common/arm_uc_scheduler.h" + +#include <stdint.h> +#include <stdio.h> +#include <stddef.h> +#include <string.h> + +arm_uc_error_t ARM_UC_mmSetState(enum arm_uc_mmState_t newState) +{ + arm_uc_mmPersistentContext.state = newState; + return (arm_uc_error_t){MFST_ERR_NONE}; +} + +#if 0 +static void printCryptoFlags(ucmm_crypto_flags_t *flags) +{ + printf("ucmm_crypto_flags_t @ %p = {\n", flags); + printf(" .hash = %u,\n",flags->hash); + printf(" .hmac = %u,\n",flags->hmac); + printf(" .rsa = %u,\n",flags->rsa); + printf(" .ecc = %u,\n",flags->ecc); + printf(" .aes = %u,\n",flags->aes); + printf("}\n"); +} +#endif + +arm_uc_error_t ARM_UC_mmFSM(uint32_t event) +{ + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "> %s (%u)\n", __PRETTY_FUNCTION__, (unsigned)event); + + arm_uc_error_t err = {MFST_ERR_NONE}; + enum arm_uc_mmState_t oldState; + do { + oldState = arm_uc_mmPersistentContext.state; + switch(arm_uc_mmPersistentContext.state) + { + case ARM_UC_MM_STATE_IDLE: + err = (arm_uc_error_t){MFST_ERR_NONE}; + break; +// Placeholder for init +#if 0 + case ARM_UC_MM_STATE_INIT: + err = arm_uc_mmInitFSM(event); + if (err.code == MFST_ERR_NONE) + { + err = ARM_UC_mmSetState(ARM_UC_MM_STATE_IDLE); + ARM_UC_PostCallback(&arm_uc_mmContext.cfstore_callback_storage, arm_uc_mmPersistentContext.applicationEventHandler, ARM_UC_MM_RC_DONE); + } + break; +#endif + case ARM_UC_MM_STATE_INSERTING: + err = ARM_UC_mmInsertFSM(event); + if (err.code == MFST_ERR_NONE) + { + err = ARM_UC_mmSetState(ARM_UC_MM_STATE_IDLE); + ARM_UC_PostCallback(&arm_uc_mmPersistentContext.applicationCallbackStorage, arm_uc_mmPersistentContext.applicationEventHandler, ARM_UC_MM_RC_DONE); + } + break; + case ARM_UC_MM_STATE_FWINFO: + err = ARM_UC_mmFetchFirmwareInfoFSM(event); + if (err.code == MFST_ERR_NONE) + { + err = ARM_UC_mmSetState(ARM_UC_MM_STATE_IDLE); + ARM_UC_PostCallback(&arm_uc_mmPersistentContext.applicationCallbackStorage, arm_uc_mmPersistentContext.applicationEventHandler, ARM_UC_MM_RC_DONE); + } + break; + case ARM_UC_MM_STATE_TEST: + if (arm_uc_mmPersistentContext.testFSM != NULL) { + err = arm_uc_mmPersistentContext.testFSM(event); + if (err.code == MFST_ERR_NONE) + { + err = ARM_UC_mmSetState(ARM_UC_MM_STATE_IDLE); + ARM_UC_PostCallback(&arm_uc_mmPersistentContext.applicationCallbackStorage, arm_uc_mmPersistentContext.applicationEventHandler, ARM_UC_MM_RC_DONE); + } + break; + } + case ARM_UC_MM_STATE_INVALID: + default: + err = (arm_uc_error_t){MFST_ERR_INVALID_STATE}; + break; + } + } while (err.code == MFST_ERR_NONE && oldState != arm_uc_mmPersistentContext.state); + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES, "< %s %c%c:%hu (%s)\n", __PRETTY_FUNCTION__, err.modulecc[0], err.modulecc[1], err.error, ARM_UC_err2Str(err)); + return err; +} + +void ARM_UC_mmCallbackFSMEntry(uint32_t event) +{ + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES,"> %s (%u)\n", __PRETTY_FUNCTION__, (unsigned)event); + arm_uc_error_t err = ARM_UC_mmFSM(event); + if (err.code != MFST_ERR_NONE && err.code != MFST_ERR_PENDING) + { + arm_uc_mmPersistentContext.reportedError = err; + arm_uc_mmPersistentContext.applicationEventHandler((uint32_t)ARM_UC_MM_RC_ERROR); + } + ARM_UC_MM_DEBUG_LOG(ARM_UC_MM_DEBUG_LOG_LEVEL_STATES,"< %s %c%c:%hu (%s)\n", __PRETTY_FUNCTION__, err.modulecc[0], err.modulecc[1], err.error, ARM_UC_err2Str(err)); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmStateSelector.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/arm_uc_mmStateSelector.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MANIFEST_MANAGER_CORE_FSM_H +#define MANIFEST_MANAGER_CORE_FSM_H + +#include "update-client-common/arm_uc_scheduler.h" +#include "arm_uc_mmConfig.h" + +#include "update-client-manifest-manager/update-client-manifest-manager-context.h" + +arm_uc_error_t ARM_UC_mmSetState(enum arm_uc_mmState_t newState); +arm_uc_error_t ARM_UC_mmFSM(uint32_t event); +void ARM_UC_mmCallbackFSMEntry(uint32_t event); + + + +#endif // MANIFEST_MANAGER_CORE_FSM_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/manifest-manager-api.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/source/manifest-manager-api.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,157 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_mmCommon.h" +#include "arm_uc_mmConfig.h" +#include "arm_uc_mmStateSelector.h" +#include "arm_uc_mmInit.h" + +#include "update-client-manifest-manager/update-client-manifest-manager.h" +#include "update-client-manifest-manager/update-client-manifest-manager-context.h" +#include "update-client-manifest-manager/update-client-manifest-types.h" +#include "update-client-manifest-manager/arm-pal-kv.h" + +#include "update-client-common/arm_uc_scheduler.h" +#include "update-client-common/arm_uc_utilities.h" +#include "update-client-common/arm_uc_error.h" + +#include <stdint.h> +#include <stdio.h> +#include <stddef.h> +#include <string.h> + +/** + * @file manifest_manager.c + * @brief Manifest Manager API + * @details This file specifies the API used to interact with the manifest manager + */ + +arm_uc_error_t ARM_UC_mmInit(arm_uc_mmContext_t** mmCtx, void (*event_handler)(uint32_t), const arm_pal_key_value_api* api) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + if (mmCtx == NULL || *mmCtx == NULL) + { + return (arm_uc_error_t){MFST_ERR_NULL_PTR}; + } + + arm_uc_mmPersistentContext.ctx = mmCtx; + arm_uc_mmPersistentContext.applicationEventHandler = event_handler; + arm_uc_mmPersistentContext.testFSM = NULL; + + // initialize callback node + arm_uc_mmPersistentContext.applicationCallbackStorage.lock = 0; + + ARM_UC_PostCallback(&arm_uc_mmPersistentContext.applicationCallbackStorage, event_handler, ARM_UC_MM_RC_DONE); +// This code will be re-enabled when storage is available +#if 0 + ARM_UC_mmCfStoreInit(api); + + // Initialize the Init FSM + arm_uc_mmContext_t* ctx = *mmCtx; + ctx->init.state = ARM_UC_MM_INIT_BEGIN; + + err = ARM_UC_mmSetState(ARM_UC_MM_STATE_INIT); + if (err.code != MFST_ERR_NONE) + { + return err; + } + // Start the Init FSM + ARM_UC_PostCallback(&ctx->init.callbackStorage, ARM_UC_mmCallbackFSMEntry, ARM_UC_MM_EVENT_BEGIN); +#endif + return err; +} + +arm_uc_error_t ARM_UC_mmInsert(arm_uc_mmContext_t** ctx, arm_uc_buffer_t* buffer, arm_uc_buffer_t* certificateStorage, arm_uc_manifest_handle_t* ID) +{ + if (ctx == NULL || *ctx == NULL || buffer == NULL ) + { + return (arm_uc_error_t){MFST_ERR_NULL_PTR}; + } + arm_uc_mmPersistentContext.ctx = ctx; + // Setup the state machine + arm_uc_error_t err = ARM_UC_mmSetState(ARM_UC_MM_STATE_INSERTING); + if (err.code != MFST_ERR_NONE) + { + return err; + } + struct arm_uc_mmInsertContext_t* insertCtx = &(*arm_uc_mmPersistentContext.ctx)->insert; + // Store the buffer pointer + ARM_UC_buffer_shallow_copy(&insertCtx->manifest, buffer); + insertCtx->state = ARM_UC_MM_INS_STATE_BEGIN; + // Store the ID pointer + insertCtx->ID = ID; + // Store the certificate buffer + ARM_UC_buffer_shallow_copy(&insertCtx->certificateStorage, certificateStorage); + + // initialize callback node + insertCtx->callbackStorage.lock = 0; + + // Start the FSM + ARM_UC_PostCallback(&insertCtx->callbackStorage, ARM_UC_mmCallbackFSMEntry, ARM_UC_MM_EVENT_BEGIN); + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmFetchFirmwareInfo(arm_uc_mmContext_t** ctx, struct manifest_firmware_info_t* info, const arm_uc_manifest_handle_t* ID) +{ + if (ctx == NULL || *ctx == NULL || info == NULL ) + { + return (arm_uc_error_t){MFST_ERR_NULL_PTR}; + } + arm_uc_mmPersistentContext.ctx = ctx; + // Initialize the state machine + arm_uc_error_t err = ARM_UC_mmSetState(ARM_UC_MM_STATE_FWINFO); + if (err.code != MFST_ERR_NONE) + { + return err; + } + struct arm_uc_mm_fw_context_t* fwCtx = &(*arm_uc_mmPersistentContext.ctx)->getFw; + fwCtx->state = ARM_UC_MM_FW_STATE_BEGIN; + fwCtx->info = info; + + // initialize callback node + fwCtx->callbackStorage.lock = 0; + + // Start the state machine + ARM_UC_PostCallback(&fwCtx->callbackStorage, ARM_UC_mmCallbackFSMEntry, ARM_UC_MM_EVENT_BEGIN); + + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmFetchNextFirmwareInfo(struct manifest_firmware_info_t* info) +{ + struct arm_uc_mm_fw_context_t* fwCtx = &(*arm_uc_mmPersistentContext.ctx)->getFw; + fwCtx->info = info; + + // initialize callback node + fwCtx->callbackStorage.lock = 0; + + // Continue the state machine + ARM_UC_PostCallback(&fwCtx->callbackStorage, ARM_UC_mmCallbackFSMEntry, ARM_UC_MM_EVENT_BEGIN); + return (arm_uc_error_t){MFST_ERR_NONE}; +} +arm_uc_error_t ARM_UC_mmGetError() +{ + return arm_uc_mmPersistentContext.reportedError; +} + +#if ARM_UC_MM_ENABLE_TEST_VECTORS +arm_uc_error_t ARM_UC_mmRegisterTestHook(ARM_UC_mmTestHook_t hook) +{ + arm_uc_error_t err = {MFST_ERR_NONE}; + arm_uc_mmPersistentContext.testHook = hook; + return err; +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/update-client-manifest-manager/arm-pal-kv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/update-client-manifest-manager/arm-pal-kv.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,82 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_PAL_KV_H +#define ARM_PAL_KV_H + +#include <stdint.h> +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ARM_PAL_KV_KEY_MAX_PATH 220 + +typedef struct arm_pal_key_value_api { + uint32_t (*keySize)(); + void (*keyInit)(void* key); + + int32_t (*Close)(void* hkey); + int32_t (*Create)(const char* key_name, size_t value_len, const void* kdesc, void* hkey); + int32_t (*Delete)(void* hkey); + int32_t (*Find)(const char* key_name_query, const void* previous, void* next); + int32_t (*Flush)(void); + int32_t (*GetKeyName)(void* hkey, char* key_name, uint8_t *key_len); + int32_t (*GetValueLen)(void* hkey, size_t *value_len); + int32_t (*Initialize)( + void(*callback)(int32_t status, int32_t cmd_code, void *client_context, void* handle), + void *client_context); + int32_t (*PowerControl)(uint32_t state); + int32_t (*Read)(void* hkey, void* data, size_t* len); + int32_t (*Open)(const char* key_name, uint32_t flags, void* hkey); + int32_t (*Rseek)(void* hkey, size_t offset); + int32_t (*Uninitialize)(void); + int32_t (*Write)(void* hkey, const char* data, size_t* len); +} arm_pal_key_value_api; + + +#define ARM_PAL_KV_OPENMODE_RD (1 << 3) + +uint32_t ARM_PAL_KV_keySize(const arm_pal_key_value_api* api); +void ARM_PAL_KV_keyInit(const arm_pal_key_value_api* api, void* key); +int32_t ARM_PAL_KV_Close(const arm_pal_key_value_api* api, void* hkey); +int32_t ARM_PAL_KV_Create(const arm_pal_key_value_api* api, const char* key_name, size_t value_len, const void* kdesc, void* hkey); +int32_t ARM_PAL_KV_Delete(const arm_pal_key_value_api* api, void* hkey); +int32_t ARM_PAL_KV_Find(const arm_pal_key_value_api* api, const char* key_name_query, const void* previous, void* next); +int32_t ARM_PAL_KV_Flush(const arm_pal_key_value_api* api); +int32_t ARM_PAL_KV_GetKeyName(const arm_pal_key_value_api* api, void* hkey, char* key_name, uint8_t *key_len); +int32_t ARM_PAL_KV_GetValueLen(const arm_pal_key_value_api* api, void* hkey, size_t *value_len); +int32_t ARM_PAL_KV_Initialize(const arm_pal_key_value_api* api, void(*callback)(int32_t status, int32_t cmd_code, void *client_context, void* handle),void *client_context); +int32_t ARM_PAL_KV_PowerControl(const arm_pal_key_value_api* api, uint32_t state); +int32_t ARM_PAL_KV_Read(const arm_pal_key_value_api* api, void* hkey, void* data, size_t* len); +int32_t ARM_PAL_KV_Open(const arm_pal_key_value_api* api, const char* key_name, uint32_t flags, void* hkey); +int32_t ARM_PAL_KV_Rseek(const arm_pal_key_value_api* api, void* hkey, size_t offset); +int32_t ARM_PAL_KV_Uninitialize(const arm_pal_key_value_api* api); +int32_t ARM_PAL_KV_Write(const arm_pal_key_value_api* api, void* hkey, const char* data, size_t* len); + + + + +#ifdef __cplusplus +} +#endif + + +#endif // ARM_PAL_KV_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/update-client-manifest-manager/update-client-manifest-manager-context.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/update-client-manifest-manager/update-client-manifest-manager-context.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,235 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_MM_CONTEXT_TYPES_H +#define ARM_UC_MM_CONTEXT_TYPES_H + +#include "update-client-manifest-manager/update-client-manifest-types.h" +#include "update-client-manifest-manager/../source/arm_uc_mmConfig.h" +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_scheduler.h" +#include "update-client-manifest-manager/arm-pal-kv.h" + + +struct arm_uc_mmInitContext_t { + uint64_t timestamp; + uint32_t state; + arm_uc_buffer_t manifest; + arm_uc_buffer_t keyPath; + uint32_t loopCounters[1]; + + arm_uc_callback_t callbackStorage; // initialized in hub + struct { + unsigned root:1; + unsigned depidx:3; + unsigned missingDep:1; + }; + uint8_t rootManifestBasePath[sizeof(MANIFEST_PREFIX ".." ) + CFSTORE_HASH_ID_SIZE]; + uint8_t pathBuffer[220]; + uint8_t manifestBuffer[640]; + uint8_t currentHash [MAX_HASH_BYTES]; + +}; + +struct arm_uc_mm_get_latest_ts_context { + uint64_t current_ts; + uint64_t* max_ts; + uint32_t state; + arm_uc_buffer_t current_data; + arm_uc_buffer_t max_ts_key; +}; + +enum arm_uc_mm_pk_sig_state { + UCMM_PKSIG_STATE_INVALID = 0, + UCMM_PKSIG_STATE_FIND_CA, + UCMM_PKSIG_STATE_FINDING_CA, + UCMM_PKSIG_STATE_CHECK, + UCMM_PKSIG_STATE_IDLE, +}; + +typedef struct arm_uc_mm_validate_signature_context{ + enum arm_uc_mm_pk_sig_state state; + void (* applicationEventHandler)(uint32_t); + arm_uc_buffer_t fingerprint; + arm_uc_buffer_t certList; + arm_uc_buffer_t cert; + arm_uc_buffer_t* manifest; + arm_uc_error_t storedError; + uint32_t sigIndex; +} arm_uc_mm_validate_signature_context_t; + +#define ARM_UC_MM_FW_STATE_LIST\ + ENUM_FIXED(ARM_UC_MM_FW_STATE_INVALID,0)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_IDLE)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_BEGIN)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FIND_ROOT)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FETCH_TS)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FETCH_NAME)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FIND_NEXT_ROOT)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FORMAT_ROOT_PREFIX)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FIND_MANIFEST)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_READ_MANIFEST)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FETCH_ROOT)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FIND_URI)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_READ_URI)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FETCH_URI_KEY)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FETCH_HASH)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FETCH_DEP_URI)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_FETCH_DEP_HASH)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_GET_FW_REF)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_NOTIFY)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_ROOT_NOTIFY_WAIT)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_NEXT_IMAGE)\ + ENUM_AUTO(ARM_UC_MM_FW_STATE_DONE)\ + + +enum arm_uc_mm_fw_state { + #define ENUM_AUTO(name) name, + #define ENUM_FIXED(name, val) name = val, + ARM_UC_MM_FW_STATE_LIST + #undef ENUM_AUTO + #undef ENUM_FIXED +}; + +struct arm_uc_mm_fw_context_t { + struct arm_uc_mm_get_latest_ts_context getLatestTs; + uint64_t ts; + arm_uc_manifest_handle_t* ID; + enum arm_uc_mm_fw_state state; + struct manifest_firmware_info_t* info; + arm_uc_callback_t callbackStorage; // initialized in hub + arm_uc_buffer_t current_data; + char hashIDbuffer[CFSTORE_HASH_ID_SIZE]; + uint8_t keyBuffer[ARM_PAL_KV_KEY_MAX_PATH]; +}; + +#define ARM_UC_MM_INS_STATE_LIST\ + ENUM_FIXED(ARM_UC_MM_INS_STATE_INVALID,0)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_IDLE)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_BEGIN)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_BASIC_PARAMS)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_HASH_VERIFY)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_SIG_LOOP)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_SIG_START)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_SIG_WAIT)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_PARAMS)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_APP)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_FAIL)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_DONE)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_STORE_BEGIN)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_MATCHING)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_MATCH_FETCHING)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_STORE_MANIFEST_BEGIN)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_STORE_MANIFEST)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_STORE_FW_URI)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_STORE_FW_HASH)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_STORE_AES)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_STORE_DEPS)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_DEPSTART)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_DEP_WAITING)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_COMPLETION)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_COMPLETION_FINDING)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_TS_START)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_VERIFY_TS)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_STORE_TS_START)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_STORE_TS)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_DEP_CHECK)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_DEP_CHECKING)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_DEP_DELETE)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_DONE)\ + ENUM_AUTO(ARM_UC_MM_INS_STATE_ALERT)\ + + +enum arm_uc_mm_insert_state { + #define ENUM_AUTO(name) name, + #define ENUM_FIXED(name, val) name = val, + ARM_UC_MM_INS_STATE_LIST + #undef ENUM_AUTO + #undef ENUM_FIXED +}; + +struct arm_uc_mmInsertContext_t { + struct arm_uc_mm_get_latest_ts_context getLatestTs; + arm_uc_mm_validate_signature_context_t signatureContext; + uint64_t max_ts; + uint64_t current_ts; + arm_uc_manifest_handle_t* ID; + enum arm_uc_mm_insert_state state; + arm_uc_callback_t callbackStorage; // initialized in hub + arm_uc_buffer_t manifest; + arm_uc_mm_crypto_flags_t cryptoMode; + arm_uc_buffer_t certificateStorage; + uint32_t loopCounters[1]; +}; + +struct arm_uc_mmContext_t { + // Operational Contexts + union { + struct arm_uc_mmInitContext_t init; + struct arm_uc_mm_fw_context_t getFw; + struct arm_uc_mmInsertContext_t insert; + }; +}; +typedef struct arm_uc_mmContext_t arm_uc_mmContext_t; + + +enum arm_uc_mmState_t { + ARM_UC_MM_STATE_INVALID=0, + ARM_UC_MM_STATE_IDLE, + ARM_UC_MM_STATE_INIT, + ARM_UC_MM_STATE_INSERTING, + ARM_UC_MM_STATE_STORING_CA, + ARM_UC_MM_STATE_FWINFO, + ARM_UC_MM_STATE_TEST, +}; + +typedef void (*ARM_UC_mmTestHook_t)(const char*, arm_uc_mmContext_t*, uint32_t, uint32_t, arm_uc_error_t); + +struct arm_uc_mmPersistentContext_t { + enum arm_uc_mmState_t state; + arm_uc_error_t reportedError; + const char* errorFile; + uint32_t errorLine; + struct arm_uc_mmContext_t** ctx; + arm_uc_callback_t applicationCallbackStorage; // initialized in mmCommon + void (*applicationEventHandler)(uint32_t); + arm_uc_error_t (*testFSM)(uint32_t event); +#if ARM_UC_MM_ENABLE_TEST_VECTORS + ARM_UC_mmTestHook_t testHook; +#endif +}; + +typedef struct arm_uc_mmPersistentContext_t arm_uc_mmPersistentContext_t; +extern arm_uc_mmPersistentContext_t arm_uc_mmPersistentContext; + +static inline arm_uc_mmContext_t* arm_uc_mmBuf2Context(arm_uc_buffer_t* b) { + return (arm_uc_mmContext_t*)b->ptr; +} + +static inline arm_uc_error_t arm_uc_mmContextBufSizeCheck(arm_uc_buffer_t* b) { + arm_uc_error_t err = { .code = MFST_ERR_NONE }; + if (b->size_max < sizeof(arm_uc_mmContext_t)) { + err.code = MFST_ERR_SIZE; + return err; + } + return err; +} + + +#endif // ARM_UC_MM_CONTEXT_TYPES_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/update-client-manifest-manager/update-client-manifest-manager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/update-client-manifest-manager/update-client-manifest-manager.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,199 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +/** + * @file draft-api.h + * @brief Manifest Manager API + * @details This file specifies the API used to interact with the manifest manager + * # Expected API call pattern + * The update hub should call the API in the following way: + * - The update hub initializes the manifest manager: `manifest_manager_init()` + * - TODO: The manifest manager checks internal consistency of the latest manifest. + * - The udpate hub passes a manifest to the manifest manager: `manifest_manager_insert()` + * - The manifest manager: + * - checks for validity of the manifest and exits with a failure if it is invalid. + * - validates the integrity of the manifest (hash) + * - validates the authenticity of the manifest (signature) + * - checks that the manifest applies to the local hardware + * - reports the Device, Vendor, and Device Class GUIDs to the update hub for validation. + * - searches for a matching dependency placeholder + * - if a match is found, + * - stores the manifest as a dependency + * - otherwise + * - TODO: Validates the timestamp. + * NOTE: Timestamp cannot be validated before this point since it is only validated on root manifests + * - stores the maninfest as a new root manifest + * - stores the firmware URI and hash (HACK: Also embeds the firmware size, inip vector and AES key in the hash) + * - stores a placeholder for each linked manifest + * - stores the manifest timestamp + * - The manifest manager searches for dependency placeholders + * - If there is a placeholder, report it to the hub and exit pending. + * - otherwise, report DONE to the hub. + * - If the update hub receives a manifest request, + * - It obtains that manifest and calls `manifest_manager_insert()` starting this process again. + * - If the update hub receives a DONE report, + * - It initiates a firmware request, using the `ARM_UC_mmFetchFirmwareInfo()` API + * - The manifest manager: + * - finds the most recent root manifest + * - searches for any firmware placeholders + * - reports the firmware to the hub + * - Until the hub receives a DONE report, it + * - extracts the firmware information using `ARM_UC_mmGetFirmwareInfo()` + * - fetches the firmware image + * - installs the firmware image + * - starts the search for the next firmware, using `ARM_UC_mmFetchNextFirmwareInfo()` + */ +#include "update-client-manifest-manager-context.h" +#include "update-client-manifest-manager/update-client-manifest-types.h" +#include "update-client-manifest-manager/arm-pal-kv.h" +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern const size_t arm_uc_mmDynamicContextSize; +/** + * @brief Result codes for the application event handler + * @details These result codes are passed to the event handler. They are used to indicate action required by the calling + * application and status of the manifest manager. + */ +enum arm_uc_mmResultCode { + ARM_UC_MM_RC_ERROR = 0, /**< status: The manifest manager failed during the previous operation. Extract further + * error information using `ARM_UC_mmGetError()` */ + ARM_UC_MM_RC_NONE, ///< action: No action necessary + ARM_UC_MM_RC_NEED_DEP, /**< action: The firmware manager needs the manifest specified by + * `ARM_UC_mmGetCurrentManifestDependency()` in order to keep processing the + * firmware update */ + ARM_UC_MM_RC_NEED_FW, /**< action: The firmware manager needs the firmware specified by + * `ARM_UC_mmGetFirmwareInfo()` in order to keep processing the firmware update */ + ARM_UC_MM_RC_DONE ///< status: The last operation completed successfully +}; + + +/** + * @brief Initialize module and register event handler. + * @details The event handler is shared among all asynchronous calls. + * + * Walks the most recent manifest tree for validity of the tree and presence of the associated images + * + * @param[in] ctxbuf Context object for the manifest manager + * @param callback Function pointer to event handler. + * @param api Pointer to API structure for the key/value storage + * @return Error code. + */ +arm_uc_error_t ARM_UC_mmInit(arm_uc_mmContext_t** ctxbuf, void (*event_handler)(uint32_t), const arm_pal_key_value_api* api); + +/** + * @brief Insert manifest. + * @details Validates and parses manifest. + * Event is generated when call is complete. + * + * @param[in] buffer Struct containing pointer to byte array, maximum length, + * and actual length. + * @param[out] ID Pointer to a manifest handle. This handle will be populated on success. + * @return Error code, indicating parsing errors, validity of the manifest, etc. Error codes are TBD. + */ +arm_uc_error_t ARM_UC_mmInsert(arm_uc_mmContext_t** ctx, arm_uc_buffer_t* buffer, arm_uc_buffer_t* certificateStorage, arm_uc_manifest_handle_t* ID); + +/** + * @brief Get manifest firmware information + * @details Fills the manifest_firmware_info_t struct with URL information. + * + * struct manifest_firmware { + * uint32_t size; ///< The size of the firmware in bytes + * arm_uc_buffer_t hash; ///< The hash of the firmware image + * arm_uc_buffer_t uri; ///< The location of the firmware + * arm_uc_buffer_t initVector; ///< AES initialization vector + * arm_uc_buffer_t keyID; ///< Identifier for a locally stored AES key + * arm_uc_buffer_t key; ///< An encrypted AES key + * manifest_guid_t format; ///< The format used for the firmware. This is either an enum when the first 96 bits + * /// are 0. Otherwise, this is a RFC4122 GUID. * / + * arm_uc_buffer_t version; ///< A text representation of the version number. + * }; + * + * + * @param[in] ID Value identifying the manifest. + * @param[out] info Struct containing the URL. + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_mmFetchFirmwareInfo(arm_uc_mmContext_t** ctx, struct manifest_firmware_info_t* info, const arm_uc_manifest_handle_t* ID); + +/** + * @brief Starts extracting firmware information from a tree of manifests + * @details `ARM_UC_mmFetchFirmwareInfo()` begins the process of extracting firmware information in the config store + * This API should only be called once for a root manifest. It always completes asynchronously on success: a return of + *`MFST_ERR_NONE` will be followed by a callback with `ARM_UC_MM_RC_DONE`. Errors may be returned synchronously or + * asynchronously. + * + * The caller should wait for a callback via the function pointer provided in `manifest_manager_init()`. If the event + * provided to the callback is `ARM_UC_MM_RC_NEED_FW`, then a new firmware info block is ready for access via + * `ARM_UC_mmGetFirmwareInfo()`. If the event is `ARM_UC_MM_RC_DONE` then no more firmware info blocks are provided via + * this root manifest. + * + * @param[in] ID a handle for the manifest to search. TODO: The manifest manager currently just selects the latest root + * manifest. + * @return An error code on failure, MFST_ERR_NONE on success, or MFST_ERR_PENDING if the find has not completed. + */ +// arm_uc_error_t ARM_UC_mmFetchFirmwareInfo(arm_uc_manifest_handle_t* ID); + +/** + * @brief Continues extracting firmware information from a tree of manifests + * @details `ARM_UC_mmFetchNextFirmwareInfo()` obtains the next firmware information block in a tree of manifests. It + * always completes asynchronously on success: a return of `MFST_ERR_NONE` will be followed by a callback with + * `ARM_UC_MM_RC_DONE`. + * + * The caller should wait for a callback via the function pointer provided in `manifest_manager_init()`. If the event + * provided to the callback is `ARM_UC_MM_RC_NEED_FW`, then a new firmware info block is ready for access via + * `ARM_UC_mmGetFirmwareInfo()`. If the event is `ARM_UC_MM_RC_DONE` then no more firmware info blocks are provided via + * this root manifest. + * + * @return An error code on failure, MFST_ERR_NONE on success, or MFST_ERR_PENDING if the find has not completed. + */ +arm_uc_error_t ARM_UC_mmFetchNextFirmwareInfo(struct manifest_firmware_info_t* info); + +/** + * @brief Extract the last error reported to a callback with `ARM_UC_MM_RC_ERROR` + * @details Retrieves the internal error code stored in the manifest manager. When an error occurs in the manifest + * manager, during an asynchronous operation, it is not possible to pass this information directly to the application, + * so it is stored internally for later retrieval and an error event is queued for handling by the application event + * handler. + * + * @return The stored error code. + */ +arm_uc_error_t ARM_UC_mmGetError(void); + +/** + * @brief Extracts the current dependency manifest information + * @details When the manifest manager reports `ARM_UC_MM_RC_NEED_DEP` to the application event handler, it stores the + * manifest dependency that induced that request. When the application event handler processes the request, it can + * extract the manifest URI from the manifest manager using this function. + * + * @param[out] uri The buffer where the manifest URI should be stored. + * @return An error code on failure or MFST_ERR_NONE on success. + */ +arm_uc_error_t ARM_UC_mmGetCurrentManifestDependency(arm_uc_buffer_t* uri); + +#if ARM_UC_MM_ENABLE_TEST_VECTORS +arm_uc_error_t ARM_UC_mmRegisterTestHook(ARM_UC_mmTestHook_t hook); +#endif + +#ifdef __cplusplus +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/update-client-manifest-manager/update-client-manifest-types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/manifest-manager/update-client-manifest-manager/update-client-manifest-types.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,133 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef UPDATE_CLIENT_MANIFEST_MANAGER_TYPES_H +#define UPDATE_CLIENT_MANIFEST_MANAGER_TYPES_H + +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_common.h" + +#include <limits.h> +#include <stdint.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define RFC_4122_BYTES (128/CHAR_BIT) +#define RFC_4122_WORDS (RFC_4122_BYTES/sizeof(uint32_t)) +#define ARM_UC_MANIFEST_HANDLE_BUFFER_BYTES (256/CHAR_BIT) + +// NOTE: Manifest Handles are not used yet +typedef uint8_t arm_uc_manifest_handle_t[ARM_UC_MANIFEST_HANDLE_BUFFER_BYTES]; + + +/** + * @brief RFC 4122 GUID container + * GUIDs are a fixed size, so this container provides a consistent storage for them. Accessors are provided for both + * byte-wise and word-wise access. + */ +typedef struct manifest_guid_t { + union { + uint8_t bytes[RFC_4122_BYTES]; + uint32_t words[RFC_4122_WORDS]; + }; +} manifest_guid_t; + +/** + * @brief Allowed cryptographic modes + * This list must be kept in sync with the manifest generator. + * Only a minimum set of cryptographic modes should be permitted + */ +enum manifest_crypto_mode { + MFST_CRYPT_UNINIT = 0, //!< Uninitialized mode. This mode will always fail + MFST_CRYPT_SHA256_ECC_AES128_PSK, /*!< Manifest is signed with ECDSA. Firmware is encrypted with AES128-CTR, using a + * pre-shared key. Firmware plaintext is hashed with SHA256. */ + MFST_CRYPT_SHA256_ECC, //!< Manifest is signed with ECDSA. Firmware is hashed with SHA256 + MFST_CRYPT_SHA256, //!< Manifest and firmware are hashed with SHA256. Not recommended for production + // MFST_CRYPT_SHA256_HMAC, //!< Manifest is signed with HMAC. Firmware is hashed with SHA256 + // MFST_CRYPT_SHA256_HMAC_AES128_PSK, /*!< Manifest is signed with HMAC. Firmware is encrypted with AES128-CTR, using a + // * pre-shared key. Firmware plaintext is hashed with SHA256. */ + MFST_CRYPT_MAX, +}; + +/** + * @brief Helper structure + * This structure converts the cryptomode to testable flags + */ +typedef struct arm_uc_mm_crypto_flags_t { + unsigned hash:2; + unsigned hmac:1; + unsigned rsa:2; + unsigned ecc:2; + unsigned aes:2; + unsigned psk:1; +} arm_uc_mm_crypto_flags_t; + +enum arm_uc_mmCipherMode_t { + ARM_UC_MM_CIPHERMODE_NONE, + ARM_UC_MM_CIPHERMODE_PSK, + ARM_UC_MM_CIPHERMODE_CERT_CIPHERKEY, + ARM_UC_MM_CIPHERMODE_CERT_KEYTABLE, +}; + +/** + * @brief Firmware Information + * @details Contains the details about the firmware image referenced by the manifest + */ +struct manifest_firmware_info_t { + uint64_t timestamp; ///< Root Manifest timestamp. + manifest_guid_t format; /**< The format used for the firmware. This is either an enum when the first 96 bits + * are 0. Otherwise, this is a RFC4122 GUID. */ + + uint32_t cryptoMode; + uint32_t size; ///< The size of the firmware in bytes + arm_uc_buffer_t hash; ///< The hash of the firmware image + arm_uc_buffer_t uri; ///< The location of the firmware + arm_uc_buffer_t strgId; ///< The location of the firmware + + uint32_t cipherMode; + arm_uc_buffer_t initVector; ///< AES initialization vector. 0 is not permitted. + union { + struct { + arm_uc_buffer_t keyID; ///< Identifier for a locally stored AES key + arm_uc_buffer_t cipherKey; ///< An encrypted AES key + } psk; + struct { + arm_uc_buffer_t certFingerPrint; + arm_uc_buffer_t certURL; + arm_uc_buffer_t cipherKey; + } certCK; + struct { + arm_uc_buffer_t certFingerPrint; + arm_uc_buffer_t certURL; + arm_uc_buffer_t keyTableURL; + } certKT; + }; + uint32_t manifestSize; + uint8_t manifestBuffer[640]; +}; +typedef struct manifest_firmware_info_t manifest_firmware_info_t; + + +#ifdef __cplusplus +} +#endif +#endif // UPDATE_CLIENT_MANIFEST_MANAGER_TYPES_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/monitor/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/monitor/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/monitor/update-client-monitor/arm_uc_monitor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/monitor/update-client-monitor/arm_uc_monitor.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,203 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ARM_UPDATE_MONITOR_H__ +#define __ARM_UPDATE_MONITOR_H__ + +#include "update-client-common/arm_uc_common.h" + +#include <stdint.h> + +/** + * @brief Struct containing the Monitor's capabilities. + * @details state: Monitor can report the device's state. + * result: Monitor can report the update result. + * version: Monitor can report the current version. + */ +typedef struct _ARM_MONITOR_CAPABILITIES { + uint32_t state: 1; + uint32_t result: 1; + uint32_t version: 1; + uint32_t reserved: 30; +} ARM_MONITOR_CAPABILITIES; + +/** + * + */ +typedef enum { + ARM_UC_MONITOR_STATE_FIRST = 0, + ARM_UC_MONITOR_STATE_IDLE = ARM_UC_MONITOR_STATE_FIRST, + ARM_UC_MONITOR_STATE_DOWNLOADING = 1, + ARM_UC_MONITOR_STATE_DOWNLOADED = 2, + ARM_UC_MONITOR_STATE_UPDATING = 3, + ARM_UC_MONITOR_STATE_LAST = ARM_UC_MONITOR_STATE_UPDATING +} arm_uc_monitor_state_t; + +typedef enum { + ARM_UC_MONITOR_RESULT_FIRST = 0, + ARM_UC_MONITOR_RESULT_INITIAL = ARM_UC_MONITOR_RESULT_FIRST, + ARM_UC_MONITOR_RESULT_SUCCESS = 1, + ARM_UC_MONITOR_RESULT_ERROR_STORAGE = 2, + ARM_UC_MONITOR_RESULT_ERROR_MEMORY = 3, + ARM_UC_MONITOR_RESULT_ERROR_CONNECTION = 4, + ARM_UC_MONITOR_RESULT_ERROR_CRC = 5, + ARM_UC_MONITOR_RESULT_ERROR_TYPE = 6, + ARM_UC_MONITOR_RESULT_ERROR_URI = 7, + ARM_UC_MONITOR_RESULT_ERROR_UPDATE = 8, + ARM_UC_MONITOR_RESULT_ERROR_HASH = 9, + ARM_UC_MONITOR_RESULT_LAST = ARM_UC_MONITOR_RESULT_ERROR_HASH +} arm_uc_monitor_result_t; + +/** + * @brief Structure definition holding API function pointers. + */ +typedef struct _ARM_UPDATE_MONITOR { + + /** + * @brief Get driver version. + * @return Driver version. + */ + uint32_t (*GetVersion)(void); + + /** + * @brief Get Source capabilities. + * @return Struct containing capabilites. See definition above. + */ + ARM_MONITOR_CAPABILITIES (*GetCapabilities)(void); + + /** + * @brief Initialize Monitor. + * @return Error code. + */ + arm_uc_error_t (*Initialize)(void (*notification_handler)(void)); + + /** + * @brief Uninitialized Monitor. + * @return Error code. + */ + arm_uc_error_t (*Uninitialize)(void); + + /** + * @brief Send Update Client state. + * @details From the OMA LWM2M Technical Specification: + * + * Indicates current state with respect to this firmware update. + * This value is set by the LWM2M Client. + * 0: Idle (before downloading or after successful updating) + * 1: Downloading (The data sequence is on the way) + * 2: Downloaded + * 3: Updating + * + * If writing the firmware package to Package Resource is done, + * or, if the device has downloaded the firmware package from the + * Package URI the state changes to Downloaded. + * + * If writing an empty string to Package Resource is done or + * writing an empty string to Package URI is done, the state + * changes to Idle. + * + * When in Downloaded state, and the executable Resource Update is + * triggered, the state changes to Updating. + * If the Update Resource failed, the state returns at Downloaded. + * If performing the Update Resource was successful, the state + * changes from Updating to Idle. + * + * @param state Valid states: ARM_UC_MONITOR_STATE_IDLE + * ARM_UC_MONITOR_STATE_DOWNLOADING + * ARM_UC_MONITOR_STATE_DOWNLOADED + * ARM_UC_MONITOR_STATE_UPDATING + * + * @return Error code. + */ + arm_uc_error_t (*SendState)(arm_uc_monitor_state_t state); + + /** + * @brief Send update result. + * @details From the OMA LWM2M Technical Specification: + * + * Contains the result of downloading or updating the firmware + * 0: Initial value. Once the updating process is initiated + * (Download /Update), this Resource MUST be reset to Initial + * value. + * 1: Firmware updated successfully, + * 2: Not enough storage for the new firmware package. + * 3. Out of memory during downloading process. + * 4: Connection lost during downloading process. + * 5: CRC check failure for new downloaded package. + * 6: Unsupported package type. + * 7: Invalid URI + * 8: Firmware update failed + * + * This Resource MAY be reported by sending Observe operation. + * + * @param result Valid results: ARM_UC_MONITOR_RESULT_INITIAL + * ARM_UC_MONITOR_RESULT_SUCCESS + * ARM_UC_MONITOR_RESULT_ERROR_STORAGE + * ARM_UC_MONITOR_RESULT_ERROR_MEMORY + * ARM_UC_MONITOR_RESULT_ERROR_CONNECTION + * ARM_UC_MONITOR_RESULT_ERROR_CRC + * ARM_UC_MONITOR_RESULT_ERROR_TYPE + * ARM_UC_MONITOR_RESULT_ERROR_URI + * ARM_UC_MONITOR_RESULT_ERROR_UPDATE + * ARM_UC_MONITOR_RESULT_ERROR_HASH + * + * @return Error code. + */ + arm_uc_error_t (*SendUpdateResult)(arm_uc_monitor_result_t updateResult); + + /** + * @brief Send current firmware name. + * @details The firmware name is the SHA256 hash. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ + arm_uc_error_t (*SendName)(arm_uc_buffer_t* name); + + /** + * @brief Send current firmware version. + * @details The firmware version is the timestamp from the manifest that + * authorized the firmware. + * + * @param version Timestamp, 64 bit unsigned integer. + * @return Error code. + */ + arm_uc_error_t (*SendVersion)(uint64_t version); + + /** + * @brief Set the bootloader hash. + * @details The bootloader hash is a hash of the bootloader. This is + * used for tracking the version of the bootloader used. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ + arm_uc_error_t (*SetBootloaderHash)(arm_uc_buffer_t* hash); + + /** + * @brief Set the OEM bootloader hash. + * @details If the end-user has modified the bootloader the hash of the + * modified bootloader can be set here. + * + * @param name Pointer to buffer struct. Hash is stored as byte array. + * @return Error code. + */ + arm_uc_error_t (*SetOEMBootloaderHash)(arm_uc_buffer_t* hash); +} ARM_UPDATE_MONITOR; + +#endif /* __ARM_UPDATE_MONITOR_H__ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/TESTS/syntax/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/TESTS/syntax/main.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,61 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <greentea-client/test_env.h> +#include <utest/utest.h> +#include <unity/unity.h> + +#include "update-client-paal/arm_uc_paal_update_api.h" + +using namespace utest::v1; + +#if defined(TARGET_LIKE_POSIX) +#include <unistd.h> +#define __WFI() usleep(100) +#endif + +control_t syntax_check() +{ + ARM_UC_PAAL_UPDATE test = { 0 }; + + return CaseNext; +} + +Case cases[] = { + Case("syntax_check", syntax_check), +}; + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ +#if defined(TARGET_LIKE_MBED) + GREENTEA_SETUP(60, "default_auto"); +#endif + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_setup, cases); + +#if defined(TARGET_LIKE_MBED) +int main() +#elif defined(TARGET_LIKE_POSIX) +void app_start(int argc __unused, char** argv __unused) +#endif +{ + // Run the test specification + Harness::run(specification); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/source/arm_uc_paal_update.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/source/arm_uc_paal_update.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,330 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// fixup the compilation on ARMCC for PRIu32 +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include "update-client-paal/arm_uc_paal_update.h" + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "UCPI" + +static const ARM_UC_PAAL_UPDATE* paal_update_implementation = NULL; + +/** + * @brief Set PAAL Update implementation. + * + * @param implementation Function pointer struct to implementation. + * @return Returns ERR_NONE on accept and ERR_INVALID_PARAMETER otherwise. + */ +arm_uc_error_t ARM_UCP_SetPAALUpdate(const ARM_UC_PAAL_UPDATE* implementation) +{ + tr_debug("ARM_UCP_SetPAALUpdate"); + + paal_update_implementation = implementation; + + return (arm_uc_error_t){ ERR_NONE }; +} + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ + tr_debug("ARM_UCP_Initialize"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation) + { + result = paal_update_implementation->Initialize(callback); + } + + return result; +} + +/** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UCP_GetCapabilities(void) +{ + tr_debug("ARM_UCP_GetCapabilities"); + + ARM_UC_PAAL_UPDATE_CAPABILITIES result = { 0 }; + + if (paal_update_implementation) + { + result = paal_update_implementation->GetCapabilities(); + } + + return result; +} + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UCP_GetMaxID(void) +{ + tr_debug("ARM_UCP_GetMaxID"); + + uint32_t result = 0; + + if (paal_update_implementation) + { + result = paal_update_implementation->GetMaxID(); + } + + return result; +} + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Prepare(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer) +{ + tr_debug("ARM_UCP_Prepare"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && details && buffer) + { + result = paal_update_implementation->Prepare(location, + details, + buffer); + } + + return result; +} + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer) +{ + tr_debug("ARM_UCP_Write: %p %p", paal_update_implementation, buffer); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && buffer) + { + result = paal_update_implementation->Write(location, offset, buffer); + } + + return result; +} + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Finalize(uint32_t location) +{ + tr_debug("ARM_UCP_Finalize"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation) + { + result = paal_update_implementation->Finalize(location); + } + + return result; +} + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer) +{ + tr_debug("ARM_UCP_Read: %" PRIX32 " %p", offset, buffer); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && buffer) + { + result = paal_update_implementation->Read(location, offset, buffer); + } + + return result; +} + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Activate(uint32_t location) +{ + tr_debug("ARM_UCP_Activate"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation) + { + result = paal_update_implementation->Activate(location); + } + + return result; +} + +/** + * @brief Get firmware details for the actively running firmware. + * @details This call populates the passed details struct with information + * about the currently active firmware image. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details) +{ + tr_debug("ARM_UCP_GetActiveFirmwareDetails"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && details) + { + result = paal_update_implementation->GetActiveFirmwareDetails(details); + } + + return result; +} + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetFirmwareDetails(uint32_t location, + arm_uc_firmware_details_t* details) +{ + tr_debug("ARM_UCP_GetFirmwareDetails"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && details) + { + result = paal_update_implementation->GetFirmwareDetails(location, + details); + } + + return result; +} + +/** + * @brief Get details for the component responsible for installation. + * @details This call populates the passed details struct with information + * about the local installer. Only the fields marked as supported + * in the capabilities bitmap will have valid values. The + * installer could be the bootloader, a recovery image, or some + * other component responsible for applying the new firmware + * image. + * + * @param details Pointer to installer details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetInstallerDetails(arm_uc_installer_details_t* details) +{ + tr_debug("ARM_UCP_GetInstallerDetails"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && details) + { + result = paal_update_implementation->GetInstallerDetails(details); + } + + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/update-client-paal/arm_uc_paal_update.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/update-client-paal/arm_uc_paal_update.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,191 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-paal/arm_uc_paal_update_api.h" + +/* Not including arm_uc_common.h to avoid the scheduler from being + included in the mbed-bootloader. +*/ +#include "update-client-common/arm_uc_error.h" +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set PAAL Update implementation. + * + * @param implementation Function pointer struct to implementation. + * @return Returns ERR_NONE on accept and ERR_INVALID_PARAMETER otherwise. + */ +arm_uc_error_t ARM_UCP_SetPAALUpdate(const ARM_UC_PAAL_UPDATE* implementation); + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + +/** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UCP_GetCapabilities(void); + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UCP_GetMaxID(void); + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Prepare(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer); + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer); + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Finalize(uint32_t location); + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer); + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Activate(uint32_t location); + +/** + * @brief Get firmware details for the actively running firmware. + * @details This call populates the passed details struct with information + * about the currently active firmware image. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details); + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetFirmwareDetails(uint32_t location, + arm_uc_firmware_details_t* details); + +/** + * @brief Get details for the component responsible for installation. + * @details This call populates the passed details struct with information + * about the local installer. Only the fields marked as supported + * in the capabilities bitmap will have valid values. The + * installer could be the bootloader, a recovery image, or some + * other component responsible for applying the new firmware + * image. + * + * @param details Pointer to installer details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetInstallerDetails(arm_uc_installer_details_t* details); + +#ifdef __cplusplus +} +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/update-client-paal/arm_uc_paal_update_api.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/paal/update-client-paal/arm_uc_paal_update_api.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,236 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAAL_UPDATE_API_H +#define ARM_UC_PAAL_UPDATE_API_H + +/* Not including arm_uc_common.h to avoid the scheduler from being + included in the mbed-bootloader. +*/ +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" + +#include <stdint.h> + +/** + * @brief Prototype for event handler. + */ +typedef void (*ARM_UC_PAAL_UPDATE_SignalEvent_t)(uint32_t event); + +/** + * @brief Asynchronous events. + */ +enum +{ + ARM_UC_PAAL_EVENT_INITIALIZE_DONE, + ARM_UC_PAAL_EVENT_PREPARE_DONE, + ARM_UC_PAAL_EVENT_WRITE_DONE, + ARM_UC_PAAL_EVENT_FINALIZE_DONE, + ARM_UC_PAAL_EVENT_READ_DONE, + ARM_UC_PAAL_EVENT_ACTIVATE_DONE, + ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE, + ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE, + ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE, + ARM_UC_PAAL_EVENT_INITIALIZE_ERROR, + ARM_UC_PAAL_EVENT_PREPARE_ERROR, + ARM_UC_PAAL_EVENT_WRITE_ERROR, + ARM_UC_PAAL_EVENT_FINALIZE_ERROR, + ARM_UC_PAAL_EVENT_READ_ERROR, + ARM_UC_PAAL_EVENT_ACTIVATE_ERROR, + ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR, + ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_ERROR, + ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_ERROR, +}; + +/** + * @brief Bitmap with supported header features. + * @details The PAAL Update implementation indicates what features are + * supported. This can be used after a call to one of the GetDetails + * to see which fields have valid values and what fields should be set + * in the call to Prepare. + */ +typedef struct _ARM_UC_PAAL_UPDATE_CAPABILITIES { + uint32_t installer_arm_hash: 1; + uint32_t installer_oem_hash: 1; + uint32_t installer_layout: 1; + uint32_t firmware_hash: 1; + uint32_t firmware_hmac: 1; + uint32_t firmware_campaign: 1; + uint32_t firmware_version: 1; + uint32_t firmware_size: 1; + uint32_t reserved: 24; +} ARM_UC_PAAL_UPDATE_CAPABILITIES; + +/** + * @brief Structure definition holding API function pointers. + */ +typedef struct _ARM_UC_PAAL_UPDATE { + + /** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Initialize)(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + + /** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ + ARM_UC_PAAL_UPDATE_CAPABILITIES (*GetCapabilities)(void); + + /** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ + uint32_t (*GetMaxID)(void); + + /** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Prepare)(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer); + + /** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Write)(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer); + + /** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Finalize)(uint32_t location); + + /** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Read)(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer); + + /** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Activate)(uint32_t location); + + /** + * @brief Get firmware details for the actively running firmware. + * @details This call populates the passed details struct with information + * about the currently active firmware image. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*GetActiveFirmwareDetails)(arm_uc_firmware_details_t* details); + + /** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*GetFirmwareDetails)(uint32_t location, + arm_uc_firmware_details_t* details); + + /** + * @brief Get details for the component responsible for installation. + * @details This call populates the passed details struct with information + * about the local installer. Only the fields marked as supported + * in the capabilities bitmap will have valid values. The + * installer could be the bootloader, a recovery image, or some + * other component responsible for applying the new firmware + * image. + * + * @param details Pointer to installer details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*GetInstallerDetails)(arm_uc_installer_details_t* details); + +} ARM_UC_PAAL_UPDATE; + +#endif /* ARM_UC_PAAL_UPDATE_API_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_paal_classic_pal.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_paal_classic_pal.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,581 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#include "update-client-pal-filesystem/arm_uc_pal_extensions.h" +#include "update-client-common/arm_uc_utilities.h" +#include "update-client-common/arm_uc_metadata_header_v2.h" +#include "arm_uc_pal_filesystem_utils.h" + +#include "pal.h" + +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "UCPI" + +#include <stdio.h> + +#define ARM_UC_FIRMWARE_FOLDER_NAME "firmware" + +/* pointer to external callback handler */ +static ARM_UC_PAAL_UPDATE_SignalEvent_t arm_uc_pal_external_callback = NULL; + +static void arm_uc_pal_classic_signal_callback(uint32_t event) +{ + if (arm_uc_pal_external_callback) + { + arm_uc_pal_external_callback(event); + } +} + +static void arm_uc_pal_classic_callback(palImageEvents_t event) +{ + /* + ARM_UC_PAAL_EVENT_INITIALIZE_DONE, + ARM_UC_PAAL_EVENT_PREPARE_DONE, + ARM_UC_PAAL_EVENT_WRITE_DONE, + ARM_UC_PAAL_EVENT_FINALIZE_DONE, + ARM_UC_PAAL_EVENT_READ_DONE, + ARM_UC_PAAL_EVENT_ACTIVATE_DONE, + ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE, + ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE, + ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE, + ARM_UC_PAAL_EVENT_INITIALIZE_ERROR, + ARM_UC_PAAL_EVENT_PREPARE_ERROR, + ARM_UC_PAAL_EVENT_WRITE_ERROR, + ARM_UC_PAAL_EVENT_FINALIZE_ERROR, + ARM_UC_PAAL_EVENT_READ_ERROR, + ARM_UC_PAAL_EVENT_ACTIVATE_ERROR, + ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR, + ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_ERROR, + ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_ERROR, + */ + tr_debug("arm_uc_pal_classic_callback"); + + switch (event) + { + case PAL_IMAGE_EVENT_INIT: + arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE); + break; + case PAL_IMAGE_EVENT_PREPARE: + arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE); + break; + case PAL_IMAGE_EVENT_WRITE: + arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_WRITE_DONE); + break; + case PAL_IMAGE_EVENT_FINALIZE: + arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_FINALIZE_DONE); + break; + case PAL_IMAGE_EVENT_READTOBUFFER: + arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_READ_DONE); + break; + case PAL_IMAGE_EVENT_ACTIVATE: + arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); + break; + default: + break; + } +} + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_Classic_PAL_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (callback) + { + palStatus_t status1 = pal_imageInitAPI(arm_uc_pal_classic_callback); + arm_uc_error_t status2 = pal_ext_imageInitAPI(arm_uc_pal_classic_signal_callback); + + if ((status1 == PAL_SUCCESS) && (status2.error == ERR_NONE)) + { + arm_uc_pal_external_callback = callback; + + result.code = ERR_NONE; + } + else + { + result.code = ERR_NOT_READY; + } + } + + return result; +} + +/** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_Classic_PAL_GetCapabilities(void) +{ + ARM_UC_PAAL_UPDATE_CAPABILITIES result = { + .installer_arm_hash = 0, + .installer_oem_hash = 0, + .installer_layout = 0, + .firmware_hash = 1, + .firmware_hmac = 0, + .firmware_campaign = 0, + .firmware_version = 1, + .firmware_size = 1 + }; + + return result; +} + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_Classic_PAL_GetMaxID(void) +{ + return 1; +} + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_Classic_PAL_Prepare(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details && buffer) + { + /* encode firmware details in buffer */ + arm_uc_error_t header_status = arm_uc_create_external_header_v2(details, + buffer); + + if (header_status.error == ERR_NONE) + { + /* format file name and path */ + char file_path[PAL_MAX_FILE_AND_FOLDER_LENGTH] = { 0 }; + + result = arm_uc_pal_filesystem_get_path(location, + FIRMWARE_IMAGE_ITEM_HEADER, + file_path, + PAL_MAX_FILE_AND_FOLDER_LENGTH); + + if (result.code == ERR_NONE) + { + tr_debug("file_path: %s", file_path); + + palFileDescriptor_t file = 0; + + /* open file and get file handler */ + palStatus_t status = pal_fsFopen(file_path, + PAL_FS_FLAG_READWRITETRUNC, + &file); + + if (status == PAL_SUCCESS) + { + size_t xfer_size = 0; + + /* write buffer to file */ + status = pal_fsFwrite(&file, + buffer->ptr, + buffer->size, + &xfer_size); + + tr_debug("written: %lu", (unsigned long)xfer_size); + + /* call event hadnler and set return code if write was successful */ + if ((status == PAL_SUCCESS) && + (xfer_size == buffer->size)) + { + result.code = ERR_NONE; + + arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE); + } + + /* close file after write */ + status = pal_fsFclose(&file); + + if (status != PAL_SUCCESS) + { + tr_error("pal_fsFclose failed: %" PRId32, status); + } + } + else + { + tr_error("pal_fsFopen failed: %" PRId32, status); + } + } + else + { + tr_error("file name and path too long"); + } + } + else + { + tr_error("header too large for buffer"); + } + } + + return result; +} + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_Classic_PAL_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer) + { + palStatus_t status = pal_imageWrite(location, + offset, + (palConstBuffer_t*) buffer); + + if (status == PAL_SUCCESS) + { + result.code = ERR_NONE; + } + else + { + result.code = ERR_NOT_READY; + } + } + + return result; +} + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_Classic_PAL_Finalize(uint32_t location) +{ + arm_uc_error_t result = { .code = ERR_NOT_READY }; + + palStatus_t status = pal_imageFinalize(location); + + if (status == PAL_SUCCESS) + { + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param locati + * on Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_Classic_PAL_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer) + { + palStatus_t status = pal_imageReadToBuffer(location, + offset, + (palBuffer_t*) buffer); + + if (status == PAL_SUCCESS) + { + tr_debug("pal_imageReadToBuffer succeeded: %" PRIX32, buffer->size); + result.code = ERR_NONE; + } + else + { + tr_error("pal_imageReadToBuffer failed"); + result.code = ERR_NOT_READY; + } + } + + return result; +} + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_Classic_PAL_Activate(uint32_t location) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + result = pal_ext_imageActivate(location); + + return result; +} + +/** + * @brief Get firmware details for the actively running firmware. + * @details This call populates the passed details struct with information + * about the currently active firmware image. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_Classic_PAL_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + result = pal_ext_imageGetActiveDetails(details); + } + + return result; +} + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_Classic_PAL_GetFirmwareDetails(uint32_t location, + arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + char file_path[PAL_MAX_FILE_AND_FOLDER_LENGTH+1] = { 0 }; + + palStatus_t status = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, + PAL_MAX_FILE_AND_FOLDER_LENGTH, + file_path); + + if (status == PAL_SUCCESS) + { + /* keep track of file and folder length */ + /* add mount point name length */ + int length = arm_uc_strnlen((const uint8_t *)file_path, PAL_MAX_FILE_AND_FOLDER_LENGTH); + + /* add slash if needed */ + if (( length == 0) || + ((length < PAL_MAX_FILE_AND_FOLDER_LENGTH) && + (file_path[length - 1] != '/'))) + { + file_path[length] = '/'; + file_path[++length] = 0; + } + + + /* check that path didn't overrun */ + if (length < PAL_MAX_FILE_AND_FOLDER_LENGTH) + { + /* start snprintf after the mount point name and add length */ + length += snprintf(&file_path[length], + PAL_MAX_FILE_AND_FOLDER_LENGTH - length, + ARM_UC_FIRMWARE_FOLDER_NAME "/header_%" PRIu32 ".bin", + location); + + /* check that file path didn't overrun */ + if (length < PAL_MAX_FILE_AND_FOLDER_LENGTH) + { + tr_debug("file_path: %d %s", length, file_path); + + palFileDescriptor_t file = 0; + + /* open metadata header file if it exists */ + palStatus_t pal_rc = pal_fsFopen(file_path, + PAL_FS_FLAG_READONLY, + &file); + + if (pal_rc == PAL_SUCCESS) + { + size_t xfer_size = 0; + + /* read metadata header */ + uint8_t read_buffer[ARM_UC_EXTERNAL_HEADER_SIZE_V2] = { 0 }; + + pal_rc = pal_fsFread(&file, + read_buffer, + ARM_UC_EXTERNAL_HEADER_SIZE_V2, + &xfer_size); + + /* check return code */ + if ((pal_rc == PAL_SUCCESS) && + (xfer_size == ARM_UC_EXTERNAL_HEADER_SIZE_V2)) + { + tr_debug("read bytes: %lu", (unsigned long)xfer_size); + + /* read out header magic */ + uint32_t headerMagic = arm_uc_parse_uint32(&read_buffer[0]); + + /* read out header magic */ + uint32_t headerVersion = arm_uc_parse_uint32(&read_buffer[4]); + + /* choose version to decode */ + if ((headerMagic == ARM_UC_EXTERNAL_HEADER_MAGIC_V2) && + (headerVersion == ARM_UC_EXTERNAL_HEADER_VERSION_V2)) + { + result = arm_uc_parse_external_header_v2(read_buffer, details); + + tr_debug("version: %" PRIu64, details->version); + tr_debug("size: %"PRIu64, details->size); + + if (result.error == ERR_NONE) + { + arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE); + } + } + else + { + /* invalid header format */ + tr_error("invalid header in slot %" PRIu32, location); + } + } + else if (xfer_size != ARM_UC_EXTERNAL_HEADER_SIZE_V2) + { + /* invalid header format */ + tr_error("invalid header in slot %" PRIu32, location); + } + else + { + /* unsuccessful read */ + tr_error("pal_fsFread returned 0x%" PRIX32, (uint32_t) pal_rc); + } + + /* close file after use */ + pal_rc = pal_fsFclose(&file); + + if (pal_rc != PAL_SUCCESS) + { + tr_error("pal_fsFclose failed: %" PRId32, pal_rc); + } + } + else + { + /* header file not present, slot is either invalid or unused. */ + result.code = ERR_NOT_READY; + } + } + } + } + } + + return result; +} + +/** + * @brief Get details for the component responsible for installation. + * @details This call populates the passed details struct with information + * about the local installer. Only the fields marked as supported + * in the capabilities bitmap will have valid values. The + * installer could be the bootloader, a recovery image, or some + * other component responsible for applying the new firmware + * image. + * + * @param details Pointer to installer details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_Classic_PAL_GetInstallerDetails(arm_uc_installer_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + result = pal_ext_installerGetDetails(details); + } + + return result; +} + +const ARM_UC_PAAL_UPDATE ARM_UCP_FILESYSTEM = +{ + .Initialize = ARM_UC_Classic_PAL_Initialize, + .GetCapabilities = ARM_UC_Classic_PAL_GetCapabilities, + .GetMaxID = ARM_UC_Classic_PAL_GetMaxID, + .Prepare = ARM_UC_Classic_PAL_Prepare, + .Write = ARM_UC_Classic_PAL_Write, + .Finalize = ARM_UC_Classic_PAL_Finalize, + .Read = ARM_UC_Classic_PAL_Read, + .Activate = ARM_UC_Classic_PAL_Activate, + .GetActiveFirmwareDetails = ARM_UC_Classic_PAL_GetActiveFirmwareDetails, + .GetFirmwareDetails = ARM_UC_Classic_PAL_GetFirmwareDetails, + .GetInstallerDetails = ARM_UC_Classic_PAL_GetInstallerDetails +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_filesystem_utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_filesystem_utils.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,79 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_pal_filesystem_utils.h" +#include "update-client-common/arm_uc_utilities.h" + +#include "pal.h" + +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "UCPI" + +#include <stdio.h> + +/** + * @brief Get the path of the specified item (header or file) for a firmware image + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param location Index of the firmware image in storage. + * @param what 'FIRMWARE_IMAGE_ITEM_HEADER' to return the path to the image + * header, or 'FIRMWARE_IMAGE_ITEM_DATA' to return the path to the + * actual image data. + * @param dest Where to write the path. + * @param dest_size Size of the 'dest' array above. It should be at least + * PAL_MAX_FILE_AND_FOLDER_LENGTH. + * @return ERR_INVALID_PARAMETER if an error occured, ERR_NONE otherwise. + */ +arm_uc_error_t arm_uc_pal_filesystem_get_path(uint32_t location, + firmwareImageItemType what, + char *dest, + uint32_t dest_size) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (dest && dest_size > 0) + { + /* copy the base directory of firmware into dest */ + int length = snprintf(dest, dest_size, "%s", pal_imageGetFolder()); + + /* add missing slash at end if needed */ + if ((length < dest_size) && (dest[length - 1] != '/')) + { + dest[length] = '/'; + length++; + } + + /* start snprintf after the mount point name and add length */ + length += snprintf(&dest[length], + dest_size - length, + "%s_%" PRIu32 ".bin", + what == FIRMWARE_IMAGE_ITEM_HEADER ? "header" : "image", + location); + + /* check that file path didn't overrun */ + if (length < dest_size) + { + result.code = ERR_NONE; + } + } + + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_filesystem_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_filesystem_utils.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,40 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_FILESYSTEM_UTILS +#define ARM_UC_PAL_FILESYSTEM_UTILS + +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + FIRMWARE_IMAGE_ITEM_HEADER = 0, + FIRMWARE_IMAGE_ITEM_DATA +} firmwareImageItemType; + +arm_uc_error_t arm_uc_pal_filesystem_get_path(uint32_t location, firmwareImageItemType what, char *dest, uint32_t dest_size); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UC_PAL_FILESYSTEM_UTILS
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_linux_extensions.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_linux_extensions.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,177 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_IS_PC_LINUX) + +#include "update-client-pal-filesystem/arm_uc_pal_extensions.h" + +#include "update-client-common/arm_uc_metadata_header_v2.h" +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_utilities.h" +#include "arm_uc_pal_filesystem_utils.h" + +#include "pal.h" + +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "update-client-extensions" + +#include <stdlib.h> +#include <inttypes.h> +#include <limits.h> +#include <stdio.h> + +#ifndef MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS +#define MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS +#define MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS 0 +#endif + +static void (*arm_ucex_linux_callback)(uint32_t) = NULL; +static palImageId_t arm_ucex_activate_image_id; + +#ifndef PAL_UPDATE_ACTIVATE_SCRIPT +#define PAL_UPDATE_ACTIVATE_SCRIPT "./activate_script" +#endif + +arm_uc_error_t pal_ext_imageInitAPI(void (*callback)(uint32_t)) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + arm_ucex_linux_callback = callback; + + return result; +} + +arm_uc_error_t pal_ext_imageGetActiveDetails(arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* dummy implementation, return 0 */ + memset(details, 0, sizeof(arm_uc_firmware_details_t)); + + result.code = ERR_NONE; + + if (arm_ucex_linux_callback) + { + arm_ucex_linux_callback(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE); + } + } + + return result; +} + +arm_uc_error_t pal_ext_installerGetDetails(arm_uc_installer_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* dummy implementation, return 0 */ + memset(details, 0, sizeof(arm_uc_installer_details_t)); + + result.code = ERR_NONE; + + if (arm_ucex_linux_callback) + { + arm_ucex_linux_callback(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE); + } + } + + return result; +} + +static void pal_ext_imageActivationWorker(void* location) +{ + char cmd_buf[sizeof(PAL_UPDATE_ACTIVATE_SCRIPT) + 1 + PAL_MAX_FILE_AND_FOLDER_LENGTH + 1]; + char path_buf[PAL_MAX_FILE_AND_FOLDER_LENGTH]; + + arm_uc_error_t result = arm_uc_pal_filesystem_get_path(*(palImageId_t*)location, FIRMWARE_IMAGE_ITEM_DATA, + path_buf, PAL_MAX_FILE_AND_FOLDER_LENGTH); + palStatus_t rc = PAL_ERR_GENERIC_FAILURE; + + if (result.code == ERR_NONE) + { + int err = snprintf(cmd_buf, sizeof(cmd_buf), "%s %s", + PAL_UPDATE_ACTIVATE_SCRIPT, path_buf); + if (err > 0) + { + rc = PAL_SUCCESS; + } + else + { + tr_err("snprintf failed with err %i", err); + rc = PAL_ERR_GENERIC_FAILURE; + } + } + + + if (rc == PAL_SUCCESS) + { + tr_debug("Activate by executing %s", cmd_buf); + int err = system(cmd_buf); + err = WEXITSTATUS(err); + + if (err != -1) + { + tr_debug("Activate completed with %" PRId32, err); + rc = PAL_SUCCESS; + } + else + { + tr_err("system call failed with err %" PRId32, err); + rc = PAL_ERR_GENERIC_FAILURE; + } + } + fflush(stdout); + sleep(1); + + if (arm_ucex_linux_callback) + { + uint32_t event = (rc == PAL_SUCCESS? ARM_UC_PAAL_EVENT_ACTIVATE_DONE : ARM_UC_PAAL_EVENT_ACTIVATE_ERROR); + arm_ucex_linux_callback(event); + } +} + +arm_uc_error_t pal_ext_imageActivate(uint32_t location) +{ + arm_uc_error_t err = { .code = ERR_INVALID_PARAMETER }; + + memcpy(&arm_ucex_activate_image_id, &location, sizeof(palImageId_t)); + + palThreadID_t thread_id = 0; + palStatus_t rc = pal_osThreadCreateWithAlloc(pal_ext_imageActivationWorker, &arm_ucex_activate_image_id, + PAL_osPriorityBelowNormal, PTHREAD_STACK_MIN, NULL, &thread_id); + if (rc != PAL_SUCCESS) + { + tr_err("Thread creation failed with %x", rc); + err.code = ERR_INVALID_PARAMETER; + } + else + { + tr_debug("Activation thread created, thread ID: %" PRIu32, thread_id); + err.code = ERR_NONE; + } + + return err; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_mbed_extensions.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/source/arm_uc_pal_mbed_extensions.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,54 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_LIKE_MBED) + +#include "update-client-pal-filesystem/arm_uc_pal_extensions.h" + +#include "update-client-pal-flashiap/arm_uc_pal_flashiap_implementation.h" + +static void (*arm_ucex_mbed_callback)(uint32_t) = 0; + +arm_uc_error_t pal_ext_imageInitAPI(void (*callback)(uint32_t)) +{ + arm_ucex_mbed_callback = callback; + + return ARM_UC_PAL_FlashIAP_Initialize(callback); +} + +arm_uc_error_t pal_ext_imageGetActiveDetails(arm_uc_firmware_details_t* details) +{ + return ARM_UC_PAL_FlashIAP_GetActiveDetails(details); +} + +arm_uc_error_t pal_ext_installerGetDetails(arm_uc_installer_details_t* details) +{ + return ARM_UC_PAL_FlashIAP_GetInstallerDetails(details); +} + +arm_uc_error_t pal_ext_imageActivate(uint32_t location) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + /* pal_imageActivate not implemented */ + arm_ucex_mbed_callback(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); + + return result; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/update-client-pal-filesystem/arm_uc_pal_extensions.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/update-client-pal-filesystem/arm_uc_pal_extensions.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,42 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_EXTENSIONS +#define ARM_UC_PAL_EXTENSIONS + +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" +#include "update-client-paal/arm_uc_paal_update_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +arm_uc_error_t pal_ext_imageInitAPI(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + +arm_uc_error_t pal_ext_imageGetActiveDetails(arm_uc_firmware_details_t* details); + +arm_uc_error_t pal_ext_installerGetDetails(arm_uc_installer_details_t* details); + +arm_uc_error_t pal_ext_imageActivate(uint32_t location); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UC_PAL_EXTENSIONS
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/update-client-pal-filesystem/arm_uc_pal_filesystem.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-filesystem/update-client-pal-filesystem/arm_uc_pal_filesystem.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_CLASSIC_H +#define ARM_UC_PAL_CLASSIC_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +extern ARM_UC_PAAL_UPDATE ARM_UCP_FILESYSTEM; + +#endif // ARM_UC_PAL_CLASSIC_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/source/arm_uc_pal_flashiap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/source/arm_uc_pal_flashiap.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,52 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#include "update-client-pal-flashiap/arm_uc_pal_flashiap_implementation.h" + +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_PAL_FlashIAP_GetCapabilities(void) +{ + ARM_UC_PAAL_UPDATE_CAPABILITIES result = { + .installer_arm_hash = 0, + .installer_oem_hash = 0, + .installer_layout = 0, + .firmware_hash = 1, + .firmware_hmac = 0, + .firmware_campaign = 0, + .firmware_version = 1, + .firmware_size = 1 + }; + + return result; +} + +const ARM_UC_PAAL_UPDATE ARM_UCP_FLASHIAP = +{ + .Initialize = ARM_UC_PAL_FlashIAP_Initialize, + .GetCapabilities = ARM_UC_PAL_FlashIAP_GetCapabilities, + .GetMaxID = ARM_UC_PAL_FlashIAP_GetMaxID, + .Prepare = ARM_UC_PAL_FlashIAP_Prepare, + .Write = ARM_UC_PAL_FlashIAP_Write, + .Finalize = ARM_UC_PAL_FlashIAP_Finalize, + .Read = ARM_UC_PAL_FlashIAP_Read, + .Activate = ARM_UC_PAL_FlashIAP_Activate, + .GetActiveFirmwareDetails = ARM_UC_PAL_FlashIAP_GetActiveDetails, + .GetFirmwareDetails = ARM_UC_PAL_FlashIAP_GetFirmwareDetails, + .GetInstallerDetails = ARM_UC_PAL_FlashIAP_GetInstallerDetails +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/source/arm_uc_pal_flashiap_implementation.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/source/arm_uc_pal_flashiap_implementation.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,593 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_LIKE_MBED) + +#include "update-client-pal-flashiap/arm_uc_pal_flashiap.h" + +#include "update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h" + +#include "update-client-common/arm_uc_metadata_header_v2.h" +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_utilities.h" + +#include "mbed-trace/mbed_trace.h" +#define TRACE_GROUP "UCPI" + +#ifndef MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS +#define MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS +#define MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS +#define MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE +#define MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE 1 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS +#define MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS 1 +#endif + +/* consistency check */ +#if (MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE == 0) +#error Update client storage page cannot be zero. +#endif + +#if (MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS == 0) +#error Update client storage locations must be at least 1. +#endif + +/* Check that the statically allocated buffers are aligned with the block size */ +#define ARM_UC_PAL_ONE_BUFFER (ARM_UC_BUFFER_SIZE / 2) +#define ARM_UC_PAL_PAGES (ARM_UC_PAL_ONE_BUFFER / MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) + +#if !((ARM_UC_PAL_PAGES * MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) == ARM_UC_PAL_ONE_BUFFER) +#error Update client buffer must be divisible by the block page size +#endif + +/* Calculate aligned external header size */ +#define ARM_UC_PAL_HEADER_SIZE (((ARM_UC_EXTERNAL_HEADER_SIZE_V2 + MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE - 1) \ + / MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) * MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) + +static void (*arm_uc_pal_flashiap_callback)(uint32_t) = NULL; + +static void arm_uc_pal_flashiap_signal_internal(uint32_t event) +{ + if (arm_uc_pal_flashiap_callback) + { + arm_uc_pal_flashiap_callback(event); + } +} + +arm_uc_error_t ARM_UC_PAL_FlashIAP_Initialize(void (*callback)(uint32_t)) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + int32_t status = arm_uc_flashiap_init(); + + if (status == ARM_UC_FLASHIAP_SUCCESS) + { + arm_uc_pal_flashiap_callback = callback; + + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_FlashIAP_GetMaxID(void) +{ + return MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS; +} + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Prepare(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details && buffer && buffer->ptr) + { + tr_debug("ARM_UC_PAL_FlashIAP_Prepare: %" PRIX32 " %" PRIX32, + location, details->size); + + /* encode firmware details in buffer */ + result = arm_uc_create_internal_header_v2(details, buffer); + + /* make space for new firmware */ + if (result.error == ERR_NONE) + { + /* find location start address */ + uint32_t start_address = + MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + + (location * MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE / + MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS); + + /* find end address */ + uint32_t end_address = start_address + + ARM_UC_PAL_HEADER_SIZE + + details->size; + + /* erase */ + uint32_t erase_address = start_address; + + while (erase_address < end_address) + { + uint32_t sector_size = arm_uc_flashiap_get_sector_size(start_address); + + int32_t status = arm_uc_flashiap_erase(erase_address, sector_size); + + tr_debug("erase: %" PRIX32 " %" PRIX32 " %" PRId32, + erase_address, + sector_size, + status); + + if (status == ARM_UC_FLASHIAP_SUCCESS) + { + erase_address += sector_size; + } + else + { + result.code = ERR_INVALID_PARAMETER; + break; + } + } + + if (result.error == ERR_NONE) + { + tr_debug("program: %" PRIX32 " %" PRIX32, + start_address, + ARM_UC_PAL_HEADER_SIZE); + + uint32_t page_size = arm_uc_flashiap_get_page_size(); + + /* set default return code */ + result.code = ERR_NONE; + + for (uint32_t index = 0; + index < ARM_UC_PAL_HEADER_SIZE; + index += page_size) + { + /* write header */ + int32_t status = arm_uc_flashiap_program(&buffer->ptr[index], + start_address + index, + page_size); + + if (status != ARM_UC_FLASHIAP_SUCCESS) + { + /* set return code */ + result.code = ERR_INVALID_PARAMETER; + break; + } + } + + if (result.error == ERR_NONE) + { + /* signal done */ + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_PREPARE_DONE); + } + else + { + tr_error("arm_uc_flashiap_program failed"); + } + } + else + { + tr_error("arm_uc_flashiap_erase failed"); + } + } + else + { + tr_error("arm_uc_create_internal_header_v2 failed"); + } + } + + return result; +} + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer && buffer->ptr) + { + /* find location address */ + uint32_t physical_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + + (location * MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE / + MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS) + + ARM_UC_PAL_HEADER_SIZE + + offset; + + tr_debug("ARM_UC_PAL_FlashIAP_Write: %p %" PRIX32 " %" PRIX32 " %" PRIX32, + buffer->ptr, + buffer->size, + physical_address, + offset); + + /* set default return code */ + result.code = ERR_NONE; + + uint32_t page_size = arm_uc_flashiap_get_page_size(); + + for (uint32_t index = 0; index < buffer->size; index += page_size) + { + int status = arm_uc_flashiap_program(&buffer->ptr[index], + physical_address + index, + page_size); + + if (status != ARM_UC_FLASHIAP_SUCCESS) + { + /* set return code */ + result.code = ERR_INVALID_PARAMETER; + break; + } + } + + if (result.error == ERR_NONE) + { + /* signal done */ + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_WRITE_DONE); + } + else + { + tr_error("arm_uc_flashiap_program failed"); + } + } + + return result; +} + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Finalize(uint32_t location) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + tr_debug("ARM_UC_PAL_FlashIAP_Finalize"); + + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_FINALIZE_DONE); + + return result; +} + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer && buffer->ptr) + { + tr_debug("ARM_UC_PAL_FlashIAP_Read: %" PRIX32 " %" PRIX32 " %" PRIX32, + location, offset, buffer->size_max); + + /* find location address */ + uint32_t physical_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + + (location * MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE / + MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS) + + ARM_UC_PAL_HEADER_SIZE + + offset; + + uint32_t read_size = buffer->size_max; + + int status = arm_uc_flashiap_read(buffer->ptr, + physical_address, + read_size); + + if (status == ARM_UC_FLASHIAP_SUCCESS) + { + /* set buffer size */ + buffer->size = read_size; + + /* set return code */ + result.code = ERR_NONE; + + /* signal done */ + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_READ_DONE); + } + else + { + tr_error("arm_uc_flashiap_read failed"); + } + } + + return result; +} + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Activate(uint32_t location) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + tr_debug("ARM_UC_PAL_FlashIAP_Activate"); + + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); + + return result; +} + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetFirmwareDetails( + uint32_t location, + arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + tr_debug("ARM_UC_PAL_FlashIAP_GetFirmwareDetails"); + + /* find location address */ + uint32_t physical_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + + (location * MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE / + MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS); + + uint8_t buffer[ARM_UC_PAL_HEADER_SIZE] = { 0 }; + + int status = arm_uc_flashiap_read(buffer, + physical_address, + ARM_UC_PAL_HEADER_SIZE); + + if (status == ARM_UC_FLASHIAP_SUCCESS) + { + result = arm_uc_parse_internal_header_v2(buffer, details); + + if (result.error == ERR_NONE) + { + /* signal done */ + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE); + } + else + { + tr_error("arm_uc_parse_internal_header_v2 failed"); + } + } + else + { + tr_error("arm_uc_flashiap_read failed"); + } + } + + return result; +} + +/*****************************************************************************/ + +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetActiveDetails(arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* read details from memory if offset is set */ + if (MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS) + { + /* set default error code */ + result.code = ERR_NOT_READY; + + /* Use flash driver eventhough we are reading from internal flash. + This will make it easier to use with uVisor. + */ + uint8_t version_buffer[8] = { 0 }; + + /* read metadata magic and version from flash */ + int rc = arm_uc_flashiap_read(version_buffer, + MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS, + 8); + + if (rc == ARM_UC_FLASHIAP_SUCCESS) + { + /* read out header magic */ + uint32_t headerMagic = arm_uc_parse_uint32(&version_buffer[0]); + + /* read out header magic */ + uint32_t headerVersion = arm_uc_parse_uint32(&version_buffer[4]); + + /* choose version to decode */ + switch(headerVersion) + { + case ARM_UC_INTERNAL_HEADER_VERSION_V2: + { + result.code = ERR_NONE; + /* Check the header magic */ + if (headerMagic != ARM_UC_INTERNAL_HEADER_MAGIC_V2) + { + tr_error("firmware header is v2, but does not contain v2 magic"); + result.code = ERR_NOT_READY; + } + + uint8_t read_buffer[ARM_UC_INTERNAL_HEADER_SIZE_V2] = { 0 }; + /* Read the rest of the header */ + if (result.error == ERR_NONE) + { + rc = arm_uc_flashiap_read(read_buffer, + MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS, + ARM_UC_INTERNAL_HEADER_SIZE_V2); + if (rc != 0) + { + result.code = ERR_NOT_READY; + tr_error("failed to read v2 header"); + } + } + /* Parse the header */ + if (result.error == ERR_NONE) + { + result = arm_uc_parse_internal_header_v2(read_buffer, details); + if (result.error != ERR_NONE) + { + tr_error("failed to parse v2 header"); + } + } + break; + } + /* + * Other firmware header versions can be supported here. + */ + default: + { + tr_error("unrecognized firmware header version"); + result.code = ERR_NOT_READY; + } + } + } + else + { + tr_error("flash read failed"); + } + } + else + { + /* offset not set - zero out struct */ + memset(details, 0, sizeof(arm_uc_firmware_details_t)); + + result.code = ERR_NONE; + } + + /* signal event if operation was successful */ + if (result.error == ERR_NONE) + { + tr_debug("callback"); + + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE); + } + } + + return result; +} + +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetInstallerDetails(arm_uc_installer_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* only read from memory if offset is set */ + if (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS) + { + uint8_t* arm = (uint8_t*) (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS + + offsetof(arm_uc_installer_details_t, arm_hash)); + + uint8_t* oem = (uint8_t*) (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS + + offsetof(arm_uc_installer_details_t, oem_hash)); + + uint8_t* layout = (uint8_t*) (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS + + offsetof(arm_uc_installer_details_t, layout)); + + /* populate installer details struct */ + memcpy(&details->arm_hash, arm, ARM_UC_SHA256_SIZE); + memcpy(&details->oem_hash, oem, ARM_UC_SHA256_SIZE); + details->layout = arm_uc_parse_uint32(layout); + } + else + { + /* offset not set, zero details struct */ + memset(details, 0, sizeof(arm_uc_installer_details_t)); + } + + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE); + + result.code = ERR_NONE; + } + + return result; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/source/arm_uc_pal_flashiap_mbed.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/source/arm_uc_pal_flashiap_mbed.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,61 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_LIKE_MBED) + +#include "update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h" +#include "mbed.h" + +static FlashIAP flash; + +int32_t arm_uc_flashiap_init() +{ + /* Workaround for https://github.com/ARMmbed/mbed-os/issues/4967 + * pal_init calls flash.init() before here. Second call to flash.init() will + * return -1 error state. Hence we ignore the result of flash.init here. + */ + flash.init(); + return 0; +} + +int32_t arm_uc_flashiap_erase(uint32_t address, uint32_t size) +{ + return flash.erase(address, size); +} + +int32_t arm_uc_flashiap_program(const uint8_t* buffer, uint32_t address, uint32_t size) +{ + return flash.program(buffer, address, size); +} + +int32_t arm_uc_flashiap_read(uint8_t* buffer, uint32_t address, uint32_t size) +{ + return flash.read(buffer, address, size); +} + +uint32_t arm_uc_flashiap_get_page_size(void) +{ + return flash.get_page_size(); +} + +uint32_t arm_uc_flashiap_get_sector_size(uint32_t address) +{ + return flash.get_sector_size(address); +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_FLASHIAP_H +#define ARM_UC_PAL_FLASHIAP_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +extern ARM_UC_PAAL_UPDATE ARM_UCP_FLASHIAP; + +#endif /* ARM_UC_PAL_FLASHIAP_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_implementation.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_implementation.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,143 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_FLASHIAP_IMPLEMENTATION_H +#define ARM_UC_PAL_FLASHIAP_IMPLEMENTATION_H + +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" +#include "update-client-paal/arm_uc_paal_update_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +arm_uc_error_t ARM_UC_PAL_FlashIAP_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_FlashIAP_GetMaxID(void); + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Prepare(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer); + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer); + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Finalize(uint32_t location); + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer); + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Activate(uint32_t location); + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetFirmwareDetails( + uint32_t location, + arm_uc_firmware_details_t* details); + +/*****************************************************************************/ + +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetActiveDetails(arm_uc_firmware_details_t* details); + +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetInstallerDetails(arm_uc_installer_details_t* details); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UC_PAL_FLASHIAP_IMPLEMENTATION_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,96 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_FLASHIAP_PLATFORM_H +#define ARM_UC_PAL_FLASHIAP_PLATFORM_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + ARM_UC_FLASHIAP_SUCCESS = 0, + ARM_UC_FLASHIAP_FAIL = -1 +}; + +/** Initialize a flash IAP device + * + * Should be called once per lifetime of the object. + * @return 0 on success or a negative error code on failure + */ +int32_t arm_uc_flashiap_init(); + +/** Erase sectors + * + * The state of an erased sector is undefined until it has been programmed + * + * @param address Address of a sector to begin erasing, must be a multiple of the sector size + * @param size Size to erase in bytes, must be a multiple of the sector size + * @return 0 on success, negative error code on failure + */ +int32_t arm_uc_flashiap_erase(uint32_t address, uint32_t size); + +/** Program data to pages + * + * The sectors must have been erased prior to being programmed + * + * @param buffer Buffer of data to be written + * @param address Address of a page to begin writing to, must be a multiple of program and sector sizes + * @param size Size to write in bytes, must be a multiple of program and sector sizes + * @return 0 on success, negative error code on failure + */ +int32_t arm_uc_flashiap_program(const uint8_t* buffer, + uint32_t address, + uint32_t size); + +/** Read data from a flash device. + * + * This method invokes memcpy - reads number of bytes from the address + * + * @param buffer Buffer to write to + * @param address Flash address to begin reading from + * @param size Size to read in bytes + * @return 0 on success, negative error code on failure + */ +int32_t arm_uc_flashiap_read(uint8_t* buffer, + uint32_t address, + uint32_t size); + +/** Get the program page size + * + * @return Size of a program page in bytes + */ +uint32_t arm_uc_flashiap_get_page_size(void); + +/** Get the sector size at the defined address + * + * Sector size might differ at address ranges. + * An example <0-0x1000, sector size=1024; 0x10000-0x20000, size=2048> + * + * @param address Address of or inside the sector to query + * @return Size of a sector in bytes + */ +uint32_t arm_uc_flashiap_get_sector_size(uint32_t address); + +#ifdef __cplusplus +} +#endif + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/arm_update_cmdline.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/arm_update_cmdline.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,61 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# default values +LOCATION=0 +OFFSET=0 +SIZE=0 + +# parse command line arguments +while [ $# -gt 1 ] +do +key="$1" +case $key in + -h|--header) + HEADER="$2" + shift # past argument=value + ;; + -f|--firmware) + FIRMWARE="$2" + shift # past argument=value + ;; + -l|--location) + LOCATION="$2" + shift # past argument=value + ;; + -o|--offset) + OFFSET="$2" + shift # past argument=value + ;; + -s|--size) + SIZE="$2" + shift # past argument=value + ;; + *) + # unknown option + ;; +esac +shift +done + +# echo "header: ${HEADER}" +# echo "firmware: ${FIRMWARE}" +# echo "location: ${LOCATION}" +# echo "offset: ${OFFSET}" +# echo "size: ${SIZE}"
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_activate.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_activate.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,35 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. ../../../arm_update_cmdline.sh + +mkdir -p /tmp/extended + +# copy header to store +VALUE=$(cp $HEADER /tmp/extended/header.bin) + +exit $VALUE
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_active_details.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_active_details.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,34 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. ../../../arm_update_cmdline.sh + +# copy stored header to expected location +VALUE=$(cp /tmp/extended/header.bin $HEADER) + +echo $HEADER + +exit $VALUE
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_details.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_details.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,34 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. ../../../arm_update_cmdline.sh + +VALUE=$(cp /tmp/extended/header_${LOCATION}.bin $HEADER) + +echo $HEADER + +exit $VALUE
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_finalize.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_finalize.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. ../../../arm_update_cmdline.sh + +# This script is called after the last firmware fragment is written +# and before the firmware is read back for verification. + +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_initialize.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_initialize.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,30 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. ../../../arm_update_cmdline.sh + +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_installer.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_installer.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,30 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. ../../../arm_update_cmdline.sh + +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_prepare.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_prepare.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,37 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. ../../../arm_update_cmdline.sh + +# create directory to store header and firmware +mkdir -p /tmp/extended + +# move header and firmeware to extended directory for local control +cp $HEADER /tmp/extended/header_${LOCATION}.bin +cp $FIRMWARE /tmp/extended/firmware_${LOCATION}.bin + +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_read.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_read.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,36 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. ../../../arm_update_cmdline.sh + +# copy fragment from stored firmware to temporary file +VALUE=$(dd if=/tmp/extended/firmware_${LOCATION}.bin of=/tmp/firmware_fragment.bin count=$SIZE ibs=1 skip=$OFFSET 2>/dev/null) + +# indicate to Update client where to read fragment from +echo "/tmp/firmware_fragment.bin" + +exit $VALUE
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_write.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/generic/arm_update_write.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,39 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. ../../../arm_update_cmdline.sh + +# get size of pre-allocated binary file +FILESIZE="$(wc -c <"/tmp/extended/firmware_${LOCATION}.bin")" + +# insert firmware fragment into binary file +VALUE=$(dd if=$FIRMWARE of=/tmp/extended/firmware_${LOCATION}.bin ibs=1 obs=1 count=${FILESIZE} seek=${OFFSET}) + +# clean up +rm $FIRMWARE + +exit $VALUE
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/openwrt/arm_update_activate.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/openwrt/arm_update_activate.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,115 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# This script takes two parameters: -f|--firmware and -h|--header +# Parameters are parsed by arm_update_cmdline.sh +# +# It uses arm_update_kernel.sh to parse the the kernel commandline passed to +# the kernel by U-Boot. This command line contains two parameters: +# mbed.root : identifier for the active partition +# mbed.boot : boot loader identifier +# +# If both the firmware and header exists, the script will overwrite the update +# partition with the firmware and write the header to the update flags partition. +# If both operations are successful, the active flags partition is erased. +# +# Boot order: +# <slot 0><slot 1> : boot +# empty - empty : slot 0 +# empty - valid : slot 1 +# valid - valid : slot 0 +# valid - empty : slot 0 + +# Find mtd partitions +# +# ACTIVE_SLOT +# ACTIVE_SLOT_MTD +# ACTIVE_FLAGS_MTD +# UPDATE_SLOT +# UPDATE_SLOT_MTD +# UPDATE_FLAGS_MTD +# +. arm_update_kernel.sh + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. arm_update_cmdline.sh + +# +# Check that header and firmware are set and exist +# +if [ ! -f $HEADER ] || [ -z $HEADER ]; then + echo "header doesn't exists"; + exit 1; +fi + +if [ ! -f $FIRMWARE ] || [ -z $FIRMWARE ]; then + echo "firmware doesn't exists" + exit 1; +fi + +# write firmware to ubi partition +ubiformat /dev/${UPDATE_SLOT_MTD} -f $FIRMWARE --yes +VALUE=$? + +# exit if return code is not zero +if [ $VALUE -ne 0 ]; then + echo "failed to format new image" + exit $VALUE +fi + +# erase sector +flash_erase /dev/${UPDATE_FLAGS_MTD} 0 1 +VALUE=$? + +# exit if return code is not zero +if [ $VALUE -ne 0 ]; then + echo "failed to erase update flags" + exit $VALUE +fi + +# write header to update partition +# if this is the default partition, this will activate it +nandwrite -p -s 0 /dev/${UPDATE_FLAGS_MTD} $HEADER +VALUE=$? + +# exit if return code is not zero +if [ $VALUE -ne 0 ]; then + echo "failed to write new header" + exit $VALUE +fi + +# erase active header +# if this is the default partition, this will activate the update partition +flash_erase /dev/${ACTIVE_FLAGS_MTD} 0 1 +VALUE=$? + +# exit if return code is not zero +if [ $VALUE -ne 0 ]; then + echo "failed to erase active header" + exit $VALUE +fi + +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/openwrt/arm_update_active_details.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/openwrt/arm_update_active_details.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,70 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# header name (not prefix) +HEADER_NAME="header" + +# header size +HEADER_SIZE=112 + +# Find mtd partitions +# +# ACTIVE_SLOT_MTD +# ACTIVE_FLAGS_MTD +# UPDATE_SLOT_MTD +# UPDATE_FLAGS_MTD +# +. arm_update_kernel.sh + +# +# get active flags +# + +# expected location for header +echo "/tmp/${HEADER_NAME}.bin" + +# dump to temporary file +nanddump -f /tmp/${HEADER_NAME}.tmp /dev/${ACTIVE_FLAGS_MTD} 2>/dev/null +VALUE=$? + +# exit if return code is not zero +if [ $VALUE -ne 0 ]; then + exit $VALUE +fi + +# truncate file to only contain header +dd if=/tmp/${HEADER_NAME}.tmp of=/tmp/${HEADER_NAME}.bin ibs=1 count=${HEADER_SIZE} 2>/dev/null +VALUE=$? + +# exit if return code is not zero +if [ $VALUE -ne 0 ]; then + exit $VALUE +fi + +# clean up +rm -f /tmp/${HEADER_NAME}.tmp 2>/dev/null +VALUE=$? + +# exit if return code is not zero +if [ $VALUE -ne 0 ]; then + exit $VALUE +fi + +# success +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/openwrt/arm_update_kernel.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/openwrt/arm_update_kernel.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,95 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse kernel command line to find: +# +# Active no.: ${ACTIVE_SLOT} +# Active slot: ${ACTIVE_SLOT_MTD} +# Active flags: ${ACTIVE_FLAGS_MTD} +# +# Update no.: ${UPDATE_SLOT} +# Update slot: ${UPDATE_SLOT_MTD} +# Update flags: ${UPDATE_FLAGS_MTD} +# + +# /proc/cmdline parameter that holds the active slot name +KERNEL_PREFIX="ubi.mtd" + +# firmware prefix +FIRMWARE_PREFIX="ROOT_" + +# flags prefix +FLAGS_PREFIX="FLAGS_" + +# +# parse /proc/cmdline and read the active slot +# + +# get parameter +for x in $(cat /proc/cmdline); do + case "$x" in + $KERNEL_PREFIX=*) + LINUX="${x#*=}" + ;; + esac +done + +# read active slot number +ACTIVE_SLOT=${LINUX//${FIRMWARE_PREFIX}/} + +# deduce alternate, update slot +if [ $ACTIVE_SLOT == 0 ]; then + UPDATE_SLOT=1 +else + UPDATE_SLOT=0 +fi + +# +# get active mtd for slot and flags +# +ACTIVE_NAME_MTD="${FIRMWARE_PREFIX}${ACTIVE_SLOT}" +ACTIVE_LINE_MTD=$(cat /proc/mtd | grep ${ACTIVE_NAME_MTD}) +ACTIVE_SLOT_MTD=${ACTIVE_LINE_MTD%:*} + +ACTIVE_NAME_MTD="${FLAGS_PREFIX}${ACTIVE_SLOT}" +ACTIVE_LINE_MTD=$(cat /proc/mtd | grep ${ACTIVE_NAME_MTD}) +ACTIVE_FLAGS_MTD=${ACTIVE_LINE_MTD%:*} + +# +# get update mtd for slot and flags +# +UPDATE_NAME_MTD="${FIRMWARE_PREFIX}${UPDATE_SLOT}" +UPDATE_LINE_MTD=$(cat /proc/mtd | grep ${UPDATE_NAME_MTD}) +UPDATE_SLOT_MTD=${UPDATE_LINE_MTD%:*} + +UPDATE_NAME_MTD="${FLAGS_PREFIX}${UPDATE_SLOT}" +UPDATE_LINE_MTD=$(cat /proc/mtd | grep ${UPDATE_NAME_MTD}) +UPDATE_FLAGS_MTD=${UPDATE_LINE_MTD%:*} + +# +# result +# +# echo "Active no.: ${ACTIVE_SLOT}" +# echo "Active slot: ${ACTIVE_SLOT_MTD}" +# echo "Active flags: ${ACTIVE_FLAGS_MTD}" +# +# echo "Update no.: ${UPDATE_SLOT}" +# echo "Update slot: ${UPDATE_SLOT_MTD}" +# echo "Update flags: ${UPDATE_FLAGS_MTD}" +#
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/yocto_rpi/arm_update_activate.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/yocto_rpi/arm_update_activate.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,143 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +set -x +# Write a partition image file to a partition and set the boot flags. + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. /opt/arm/arm_update_cmdline.sh + +# Return the number of the partition with the given label (in $1) +# Exit with error if the partition can't be found +getpart() { + res=`readlink -f /dev/disk/by-label/$1` + if [[ ${res:0:13}x == "/dev/mmcblk0px" ]]; then + echo `echo $res | cut -d'p' -f2` + fi +} + +# Detect root partitions +root1=`getpart "rootfs1"` +if [ "${root1}"x == "x" ]; then + echo "Unable to find partition with label 'rootfs1'" + exit 9 +fi +root2=`getpart "rootfs2"` +if [ "${root2}"x == "x" ]; then + echo "Unable to find partition with label 'rootfs2'" + exit 9 +fi +ROOTS="$root1 $root2" + +# Flag partition +FLAGS=`getpart "bootflags"` +if [ "${FLAGS}"x == "x" ]; then + echo "Unable to find partition with label 'bootflags'" + exit 9 +fi + +# Find the partition that is currently mounted to / +activePartition=`lsblk -nro NAME,MOUNTPOINT | grep -e ".* /$" | cut -d ' ' -f1` +# Find the disk that contains the current root +activeDisk=`lsblk -nro pkname /dev/${activePartition}` +# Get the format of the partition name +partitionPrefix=`echo ${activePartition} | sed -e "s|^\([a-z0-9]*[a-z]\)[0-9]$|\1|"` + +nextPartition="" +nextPartitionLabel="" +nextRoot="" +# Find the other root partition by listing both root partitions and filtering out the active partition +for pNum in ${ROOTS} ; do + if [[ "${partitionPrefix}${pNum}" != "$activePartition" ]]; then + nextPartition="${partitionPrefix}${pNum}" + nextRoot=${pNum} + break + fi +done + +if [[ -z "${nextPartition}" ]]; then + exit 1 +fi + +# Make sure that nextPartition exists in the disk +if ! lsblk -nr /dev/${nextPartition} > /dev/null ; then + exit 2 +fi + +# Make sure the next partition isn't mounted. +umount /dev/${nextPartition} > /dev/null +# Set next partition label based on whether it is first or second root +if [[ "${nextRoot}" == "5" ]]; then + nextPartitionLabel="rootfs1" +fi +if [[ "${nextRoot}" == "6" ]]; then + nextPartitionLabel="rootfs2" +fi +# Create the file system on the next partition +if ! mkfs -t ext4 -L ${nextPartitionLabel} -F /dev/${nextPartition}; then + echo "mkfs failed on the new root partition" + exit 3 +fi +# Mount the next partition +if ! mount /dev/${nextPartition} /mnt/root; then + echo "Unable to mount the new root partition" + exit 4 +fi +# Uncompress the image +if ! tar xvjf $FIRMWARE -C /mnt/root; then + echo "Image copy failed" + exit 5 +fi +umount /mnt/root + +if ! mkdir -p /mnt/flags ; then + exit 6 +fi + +# Make sure flags partition isn't mounted. +umount /dev/${partitionPrefix}${FLAGS} > /dev/null +if ! mount /dev/${partitionPrefix}${FLAGS} /mnt/flags ; then + exit 7 +fi + +# Boot Flags +if [[ "${nextRoot}" == "5" ]]; then + cp $HEADER /mnt/flags/five + sync + rm -f /mnt/flags/six + sync +elif [[ "${nextRoot}" == "6" ]]; then + cp $HEADER /mnt/flags/six + sync + rm -f /mnt/flags/five + sync +fi + +if ! umount /mnt/flags ; then + exit 8 +fi + +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/yocto_rpi/arm_update_active_details.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/yocto_rpi/arm_update_active_details.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,86 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Parse command line +# +# HEADER +# FIRMWARE +# LOCATION +# OFFSET +# SIZE +# +. /opt/arm/arm_update_cmdline.sh + +# header directory +HEADER_DIR=$(dirname ${HEADER}) + +# header name (not prefix) +HEADER_NAME="header" + +# location where the update client will find the header +HEADER_PATH=${HEADER_DIR}"/"${HEADER_NAME}".bin" + +# header size +HEADER_SIZE=112 + +set -x +# Return the number of the partition with the given label (in $1) +# Exit with error if the partition can't be found +getpart() { + res=`readlink -f /dev/disk/by-label/$1` + if [[ ${res:0:13}x == "/dev/mmcblk0px" ]]; then + echo `echo $res | cut -d'p' -f2` + fi +} + +# Flag partition +FLAGS=`getpart "bootflags"` +if [ "${FLAGS}"x == "x" ]; then + echo "Unable to find partition with label 'bootflags'" + exit 9 +fi + +# Find the partition that is currently mounted to / +activePartition=`lsblk -nro NAME,MOUNTPOINT | grep -e ".* /$" | cut -d ' ' -f1` +activePartitionNum=`echo ${activePartition} | grep -Eo '[0-9]+$'` + +# Get the format of the partition name +partitionPrefix=`echo ${activePartition} | sed -e "s|^\([a-z0-9]*[a-z]\)[0-9]$|\1|"` + +# Make sure flags partition isn't mounted. +umount /dev/${partitionPrefix}${FLAGS} > /dev/null + +# mount flags partition +if ! mount /dev/${partitionPrefix}${FLAGS} /mnt/flags ; then + exit 7 +fi + +# Boot Flags +if [ "${activePartitionNum}" == "5" ] && [ -e "/mnt/flags/five" ]; then + cp /mnt/flags/five $HEADER_PATH + sync +elif [ "${activePartitionNum}" == "6" ] && [ -e "/mnt/flags/six" ]; then + cp /mnt/flags/six $HEADER_PATH + sync +else + echo "Warning: No active firmware header found!" + exit 9 +fi + +exit 0
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/yotta_install.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/scripts/yotta_install.sh Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,22 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Copyright 2016-2017 ARM Ltd. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# Copy generic scripts to top level application so the test app can find them +cp scripts/generic/arm_* ../../ +cp scripts/arm_update_cmdline.sh ../../
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_generic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_generic.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,182 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_IS_PC_LINUX) + +#include "update-client-paal/arm_uc_paal_update_api.h" +#include "update-client-pal-linux/arm_uc_pal_linux_implementation.h" +#include "update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h" + +/** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_PAL_Linux_GetCapabilities_Generic(void) +{ + const ARM_UC_PAAL_UPDATE_CAPABILITIES result = { + .installer_arm_hash = 0, + .installer_oem_hash = 0, + .installer_layout = 0, + .firmware_hash = 1, + .firmware_hmac = 0, + .firmware_campaign = 0, + .firmware_version = 1, + .firmware_size = 1 + }; + + return result; +} + +arm_ucp_worker_t arm_uc_worker_parameters_initialize = { + .command = "../../../arm_update_initialize.sh", + .header = 0, + .firmware = 0, + .location = 0, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_INITIALIZE_DONE, + .failure_event = ARM_UC_PAAL_EVENT_INITIALIZE_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_prepare = { + .command = "../../../arm_update_prepare.sh", + .header = 1, + .firmware = 1, + .location = 1, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_PREPARE_DONE, + .failure_event = ARM_UC_PAAL_EVENT_PREPARE_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_read = { + .command = "../../../arm_update_read.sh", + .header = 0, + .firmware = 0, + .location = 1, + .offset = 1, + .size = 1, + .success_event = ARM_UC_PAAL_EVENT_READ_DONE, + .failure_event = ARM_UC_PAAL_EVENT_READ_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_write = { + .command = "../../../arm_update_write.sh", + .header = 0, + .firmware = 1, + .location = 1, + .offset = 1, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_WRITE_DONE, + .failure_event = ARM_UC_PAAL_EVENT_WRITE_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_finalize = { + .command = "../../../arm_update_finalize.sh", + .header = 1, + .firmware = 1, + .location = 1, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_FINALIZE_DONE, + .failure_event = ARM_UC_PAAL_EVENT_FINALIZE_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_details = { + .command = "../../../arm_update_details.sh", + .header = 1, + .firmware = 0, + .location = 1, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE, + .failure_event = ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_active_details = { + .command = "../../../arm_update_active_details.sh", + .header = 1, + .firmware = 0, + .location = 0, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE, + .failure_event = ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_activate = { + .command = "../../../arm_update_activate.sh", + .header = 1, + .firmware = 1, + .location = 0, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_ACTIVATE_DONE, + .failure_event = ARM_UC_PAAL_EVENT_ACTIVATE_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_installer = { + .command = "../../../arm_update_installer.sh", + .header = 1, + .firmware = 0, + .location = 0, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE, + .failure_event = ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_ERROR +}; + +arm_uc_error_t ARM_UC_PAL_Linux_Initialize_Generic(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ +#if 1 + extern arm_ucp_worker_config_t arm_uc_worker_parameters; + + arm_uc_worker_parameters.activate = &arm_uc_worker_parameters_activate; + arm_uc_worker_parameters.active_details = &arm_uc_worker_parameters_active_details; + arm_uc_worker_parameters.details = &arm_uc_worker_parameters_details; + arm_uc_worker_parameters.finalize = &arm_uc_worker_parameters_finalize; + arm_uc_worker_parameters.initialize = &arm_uc_worker_parameters_initialize; + arm_uc_worker_parameters.installer = &arm_uc_worker_parameters_installer; + arm_uc_worker_parameters.prepare = &arm_uc_worker_parameters_prepare; +// arm_uc_worker_parameters.read = &arm_uc_worker_parameters_read; +// arm_uc_worker_parameters.write = &arm_uc_worker_parameters_write; +#endif + + return ARM_UC_PAL_Linux_Initialize(callback); +} + +const ARM_UC_PAAL_UPDATE ARM_UCP_LINUX_GENERIC = +{ + .Initialize = ARM_UC_PAL_Linux_Initialize_Generic, + .GetCapabilities = ARM_UC_PAL_Linux_GetCapabilities_Generic, + .GetMaxID = ARM_UC_PAL_Linux_GetMaxID, + .Prepare = ARM_UC_PAL_Linux_Prepare, + .Write = ARM_UC_PAL_Linux_Write, + .Finalize = ARM_UC_PAL_Linux_Finalize, + .Read = ARM_UC_PAL_Linux_Read, + .Activate = ARM_UC_PAL_Linux_Activate, + .GetActiveFirmwareDetails = ARM_UC_PAL_Linux_GetActiveFirmwareDetails, + .GetFirmwareDetails = ARM_UC_PAL_Linux_GetFirmwareDetails, + .GetInstallerDetails = ARM_UC_PAL_Linux_GetInstallerDetails +}; + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_implementation.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_implementation.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,779 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_IS_PC_LINUX) + +#include "update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h" +#include "update-client-pal-linux/arm_uc_pal_linux_implementation.h" +#include "update-client-paal/arm_uc_paal_update_api.h" + +#include "update-client-common/arm_uc_trace.h" +#include "update-client-common/arm_uc_utilities.h" +#include "update-client-common/arm_uc_metadata_header_v2.h" + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> +#include <stdio.h> +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/wait.h> + +/* worker struct, must be accessible externally */ +arm_ucp_worker_config_t arm_uc_worker_parameters = { 0 }; + +static FILE* arm_uc_firmware_descriptor = NULL; + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (callback) + { + arm_uc_pal_linux_internal_set_callback(callback); + + /* create folder for headers if it does not already exist */ + errno = 0; + int status = mkdir(ARM_UC_HEADER_FOLDER_PATH, 0700); + + if ((status == 0) || (errno == EEXIST)) + { + /* create folder for firmwares if it does not already exist */ + errno = 0; + status = mkdir(ARM_UC_FIRMWARE_FOLDER_PATH, 0700); + + if ((status == 0) || (errno == EEXIST)) + { + /* set return code on success */ + result.code = ERR_NONE; + } + } + + /* signal completion or perform extended preparation */ + if (result.error == ERR_NONE) + { + /* set explicit ERR_NONE upon success */ + result.code = ERR_NONE; + + if (arm_uc_worker_parameters.initialize) + { + /* use extended prepare, invoke script from worker thread */ + pthread_t thread; + + /* create a second thread which executes worker_parameters_prepare */ + int status = pthread_create(&thread, + NULL, + arm_uc_pal_linux_extended_post_worker, + arm_uc_worker_parameters.initialize); + + /* check if thread was created successfully */ + if (status != 0) + { + result.code = ERR_INVALID_PARAMETER; + } + } + else + { + /* call event handler */ + arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE); + } + } + + } + + return result; +} + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_Linux_GetMaxID(void) +{ + return 1; +} + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Prepare(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details && buffer) + { + UC_PAAL_TRACE("details size: %" PRIu64, details->size); + + /* write header */ + result = arm_uc_pal_linux_internal_write_header(&location, details); + + /* allocate space for firmware */ + if (result.error == ERR_NONE) + { + char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 }; + + /* construct header file path */ + result = arm_uc_pal_linux_internal_file_path(file_path, + ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH, + ARM_UC_FIRMWARE_FOLDER_PATH, + "firmware", + &location); + + UC_PAAL_TRACE("file path: %s", file_path); + + if (result.error == ERR_NONE) + { + /* open file */ + errno = 0; + FILE* descriptor = fopen(file_path, "wb"); + + if (descriptor != NULL) + { + /* allocate space by writing empty file */ + memset(buffer->ptr, 0, buffer->size_max); + buffer->size = buffer->size_max; + + uint64_t index = 0; + while (index < details->size) + { + /* calculate write size to handle overspill */ + size_t actual_size = details->size - index; + + if (actual_size > buffer->size) + { + actual_size = buffer->size; + } + + /* write buffer */ + size_t xfer_size = fwrite(buffer->ptr, + sizeof(uint8_t), + actual_size, + descriptor); + + /* break out if write failed */ + if (xfer_size == actual_size) + { + index += actual_size; + } + else + { + result.code = ERR_INVALID_PARAMETER; + break; + } + } + + /* close file after write */ + int status = fclose(descriptor); + + if (status == EOF) + { + UC_PAAL_ERR_MSG("failed to allocate space for firmware"); + result.code = ERR_INVALID_PARAMETER; + } + } + else + { + UC_PAAL_ERR_MSG("failed to open file: %s", strerror(errno)); + } + } + else + { + UC_PAAL_ERR_MSG("file name and path too long"); + } + } + else + { + UC_PAAL_ERR_MSG("could not write header"); + } + + /* signal completion or perform extended preparation */ + if (result.error == ERR_NONE) + { + /* set explicit ERR_NONE upon success */ + result.code = ERR_NONE; + + if (arm_uc_worker_parameters.prepare) + { + /* use extended prepare, invoke script from worker thread */ + pthread_t thread; + + /* export location */ + arm_uc_pal_linux_internal_set_location(&location); + + /* create a second thread which executes worker_parameters_prepare */ + int status = pthread_create(&thread, + NULL, + arm_uc_pal_linux_extended_post_worker, + arm_uc_worker_parameters.prepare); + + /* check if thread was created successfully */ + if (status != 0) + { + result.code = ERR_INVALID_PARAMETER; + } + } + else + { + /* call event handler */ + arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE); + } + } + } + + return result; +} + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer) + { + /* reverse default error code */ + result.code = ERR_NONE; + + /* open file if descriptor is not set */ + if (arm_uc_firmware_descriptor == NULL) + { + char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 }; + + /* construct firmware file path */ + result = arm_uc_pal_linux_internal_file_path(file_path, + ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH, + ARM_UC_FIRMWARE_FOLDER_PATH, + "firmware", + &location); + + if (result.error == ERR_NONE) + { + /* open file */ + if (arm_uc_worker_parameters.write) + { + /* in extended write, each fragment is stored in its own file */ + arm_uc_firmware_descriptor = fopen(file_path, "w+b"); + + /* export offset before resetting it */ + arm_uc_pal_linux_internal_set_offset(offset); + offset = 0; + } + else + { + /* in normal write, each fragment is added to an existing file */ + arm_uc_firmware_descriptor = fopen(file_path, "r+b"); + } + } + else + { + UC_PAAL_ERR_MSG("firmware file name and path too long"); + } + } + + /* continue if file is open */ + if (arm_uc_firmware_descriptor != NULL) + { + /* set write position */ + int status = fseek(arm_uc_firmware_descriptor, + offset, + SEEK_SET); + + /* continue if position is set */ + if (status == 0) + { + /* write buffer */ + size_t xfer_size = fwrite(buffer->ptr, + sizeof(uint8_t), + buffer->size, + arm_uc_firmware_descriptor); + + /* set error code if write failed */ + if (xfer_size != buffer->size) + { + UC_PAAL_ERR_MSG("failed to write firmware"); + result.code = ERR_INVALID_PARAMETER; + } + + /* if using extended write */ + if (arm_uc_worker_parameters.write) + { + /* close file after write */ + int status = fclose(arm_uc_firmware_descriptor); + arm_uc_firmware_descriptor = NULL; + + if (status == EOF) + { + UC_PAAL_ERR_MSG("failed to close firmware file"); + result.code = ERR_INVALID_PARAMETER; + } + } + } + else + { + UC_PAAL_ERR_MSG("failed to seek in firmware"); + result.code = ERR_INVALID_PARAMETER; + } + } + + /* signal completion or perform extended write */ + if (result.error == ERR_NONE) + { + /* set explicit ERR_NONE */ + result.code = ERR_NONE; + + if (arm_uc_worker_parameters.write) + { + /* use extended write, invoke script from worker thread */ + pthread_t thread; + + /* export location */ + arm_uc_pal_linux_internal_set_location(&location); + + /* create a second thread which executes worker_parameters_write */ + int status = pthread_create(&thread, + NULL, + arm_uc_pal_linux_extended_post_worker, + arm_uc_worker_parameters.write); + + /* check if thread was successfully created */ + if (status != 0) + { + result.code = ERR_INVALID_PARAMETER; + } + } + else + { + /* call event handler */ + arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_WRITE_DONE); + } + } + } + + return result; +} + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Finalize(uint32_t location) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + /* only close firmware file if descriptor is not NULL */ + if (arm_uc_firmware_descriptor != NULL) + { + /* close file */ + int status = fclose(arm_uc_firmware_descriptor); + arm_uc_firmware_descriptor = NULL; + + if (status == EOF) + { + UC_PAAL_ERR_MSG("failed to close firmware file"); + result.code = ERR_INVALID_PARAMETER; + } + } + + /* signal completion or perform extended finalization */ + if (result.error == ERR_NONE) + { + /* explicitly set code to ERR_NONE */ + result.code = ERR_NONE; + + /* use extended finalize, invoke script from worker thread */ + if (arm_uc_worker_parameters.finalize) + { + pthread_t thread; + + /* export location */ + arm_uc_pal_linux_internal_set_location(&location); + + /* create a second thread which executes worker_parameters_finalize */ + int status = pthread_create(&thread, + NULL, + arm_uc_pal_linux_extended_post_worker, + arm_uc_worker_parameters.finalize); + + /* check if thread was successfully created */ + if (status != 0) + { + result.code = ERR_INVALID_PARAMETER; + } + } + else + { + /* call event handler */ + arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_FINALIZE_DONE); + } + } + + return result; +} + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param locati + * on Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer) + { + /* use extended finalize, invoke script from worker thread */ + if (arm_uc_worker_parameters.read) + { + pthread_t thread; + + /* export location, offset and buffer */ + arm_uc_pal_linux_internal_set_location(&location); + arm_uc_pal_linux_internal_set_offset(offset); + arm_uc_pal_linux_internal_set_buffer(buffer); + + /* create a second thread which executes worker_parameters_read */ + int status = pthread_create(&thread, + NULL, + arm_uc_pal_linux_extended_pre_worker, + arm_uc_worker_parameters.read); + + /* check if thread was successfully created */ + if (status == 0) + { + result.code = ERR_NONE; + } + } + else + { + /* normal read */ + char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 }; + + /* construct firmware file path */ + result = arm_uc_pal_linux_internal_file_path(file_path, + ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH, + ARM_UC_FIRMWARE_FOLDER_PATH, + "firmware", + &location); + + /* file path is valid */ + if (result.error == ERR_NONE) + { + result = arm_uc_pal_linux_internal_read(file_path, offset, buffer); + + /* signal completion */ + if (result.error == ERR_NONE) + { + /* call event handler */ + arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_READ_DONE); + } + } + } + } + + return result; +} + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Activate(uint32_t location) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + /* read firmware details from location */ + arm_uc_firmware_details_t details = { 0 }; + result = arm_uc_pal_linux_internal_read_header(&location, &details); + + if (result.error == ERR_NONE) + { + UC_PAAL_TRACE("version: %" PRIu64, details.version); + UC_PAAL_TRACE("size: %"PRIu64, details.size); + + /* write details to active location */ + result = arm_uc_pal_linux_internal_write_header(NULL, &details); + + if (result.error == ERR_NONE) + { + /* explicitly set code to ERR_NONE */ + result.code = ERR_NONE; + + /* use extended activate, invoke script from worker thread */ + if (arm_uc_worker_parameters.activate) + { + pthread_t thread; + + /* export location */ + arm_uc_pal_linux_internal_set_location(&location); + + /* create a second thread which executes worker_parameters_read */ + int status = pthread_create(&thread, + NULL, + arm_uc_pal_linux_extended_post_worker, + arm_uc_worker_parameters.activate); + + /* check if thread was successfully created */ + if (status != 0) + { + result.code = ERR_INVALID_PARAMETER; + } + } + else + { + arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); + } + } + } + + return result; +} + +/** + * @brief Get firmware details for the actively running firmware. + * @details This call populates the passed details struct with information + * about the currently active firmware image. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* use extended get firmware details, invoke script from worker thread */ + if (arm_uc_worker_parameters.active_details) + { + pthread_t thread; + + /* export details */ + arm_uc_pal_linux_internal_set_details(details); + + /* create a second thread which executes worker_parameters_read */ + int status = pthread_create(&thread, + NULL, + arm_uc_pal_linux_extended_pre_worker, + arm_uc_worker_parameters.active_details); + + /* check if thread was created successfully */ + if (status == 0) + { + result.code = ERR_NONE; + } + } + else + { + /* normal read */ + result = arm_uc_pal_linux_internal_read_header(NULL, details); + + if (result.error == ERR_NONE) + { + UC_PAAL_TRACE("version: %" PRIu64, details->version); + UC_PAAL_TRACE("size: %"PRIu64, details->size); + + if (result.error == ERR_NONE) + { + arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE); + } + } + } + } + + return result; +} + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_GetFirmwareDetails(uint32_t location, + arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* use extended get firmware details, invoke script from worker thread */ + if (arm_uc_worker_parameters.details) + { + pthread_t thread; + + /* export location and details */ + arm_uc_pal_linux_internal_set_location(&location); + arm_uc_pal_linux_internal_set_details(details); + + /* create a second thread which executes worker_parameters_read */ + int status = pthread_create(&thread, + NULL, + arm_uc_pal_linux_extended_pre_worker, + arm_uc_worker_parameters.details); + + /* check if thread was created successfully */ + if (status == 0) + { + result.code = ERR_NONE; + } + } + else + { + /* normal read */ + result = arm_uc_pal_linux_internal_read_header(&location, details); + + if (result.error == ERR_NONE) + { + UC_PAAL_TRACE("version: %" PRIu64, details->version); + UC_PAAL_TRACE("size: %"PRIu64, details->size); + + arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE); + } + } + } + + return result; +} + +/** + * @brief Get details for the component responsible for installation. + * @details This call populates the passed details struct with information + * about the local installer. Only the fields marked as supported + * in the capabilities bitmap will have valid values. The + * installer could be the bootloader, a recovery image, or some + * other component responsible for applying the new firmware + * image. + * + * @param details Pointer to installer details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_GetInstallerDetails(arm_uc_installer_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* use extended installer details, invoke script from worker thread */ + if (arm_uc_worker_parameters.installer) + { + pthread_t thread; + + /* export installer details */ + arm_uc_pal_linux_internal_set_installer(details); + + /* create a second thread which executes worker_parameters_read */ + int status = pthread_create(&thread, + NULL, + arm_uc_pal_linux_extended_pre_worker, + arm_uc_worker_parameters.installer); + + /* check if threas was created successfully */ + if (status == 0) + { + result.code = ERR_NONE; + } + } + else + { + /* normal read */ + result = arm_uc_pal_linux_internal_read_installer(details); + + if (result.error == ERR_NONE) + { + arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE); + } + } + } + + return result; +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_implementation_internal.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_implementation_internal.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,759 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_IS_PC_LINUX) + +#include "update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h" + +#include "update-client-common/arm_uc_trace.h" +#include "update-client-common/arm_uc_utilities.h" +#include "update-client-common/arm_uc_metadata_header_v2.h" + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> +#include <stdio.h> +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/wait.h> + +/* pointer to external callback handler */ +static ARM_UC_PAAL_UPDATE_SignalEvent_t arm_uc_pal_external_callback = NULL; + +void arm_uc_pal_linux_signal_callback(uint32_t event) +{ + if (arm_uc_pal_external_callback) + { + arm_uc_pal_external_callback(event); + } +} + +void arm_uc_pal_linux_internal_set_callback(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ + arm_uc_pal_external_callback = callback; +} + +static uint32_t arm_uc_offset = 0; +static arm_uc_buffer_t* arm_uc_buffer = NULL; +static arm_uc_firmware_details_t* arm_uc_details = NULL; +static arm_uc_installer_details_t* arm_uc_installer = NULL; +static uint32_t* arm_uc_location = NULL; +static uint32_t arm_uc_location_buffer = 0; + +void arm_uc_pal_linux_internal_set_offset(uint32_t offset) +{ + arm_uc_offset = offset; +} + +void arm_uc_pal_linux_internal_set_buffer(arm_uc_buffer_t* buffer) +{ + arm_uc_buffer = buffer; +} + +void arm_uc_pal_linux_internal_set_details(arm_uc_firmware_details_t* details) +{ + arm_uc_details = details; +} + +void arm_uc_pal_linux_internal_set_installer(arm_uc_installer_details_t* details) +{ + arm_uc_installer = details; +} + +void arm_uc_pal_linux_internal_set_location(uint32_t* location) +{ + if (location) + { + arm_uc_location_buffer = *location; + arm_uc_location = &arm_uc_location_buffer; + } + else + { + arm_uc_location = NULL; + } +} + +arm_uc_error_t arm_uc_pal_linux_internal_file_path(char* buffer, + size_t buffer_length, + const char* folder, + const char* type, + uint32_t* location) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer && folder && type) + { + int actual_length = 0; + + if (location) + { + /* construct file path using location */ + actual_length = snprintf(buffer, buffer_length, + "%s/%s_%" PRIu32 ".bin", folder, type, *location); + } + else + { + /* construct file path without location */ + actual_length = snprintf(buffer, buffer_length, + "%s/%s.bin", folder, type); + } + + /* check that the buffer is large enough */ + if (actual_length < buffer_length) + { + result.code = ERR_NONE; + } + } + + return result; +} + +static bool arm_uc_pal_linux_internal_command(arm_ucp_worker_t* parameters, + char* command, + size_t command_length) +{ + /* default to failed */ + bool valid = false; + + if (parameters && command) + { + /* invert status */ + valid = true; + + int length = snprintf(command, + command_length, + "%s ", + parameters->command); + + /* initialize remaining */ + int remaining = command_length - length; + + /* add header parameter if requested */ + if ((remaining > 0) && (parameters->header)) + { + char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 }; + + /* construct header file path */ + arm_uc_error_t result = + arm_uc_pal_linux_internal_file_path(file_path, + sizeof(file_path), + ARM_UC_HEADER_FOLDER_PATH, + "header", + arm_uc_location); + + /* generated valid file path */ + if (result.error == ERR_NONE) + { + /* add parameter to command line */ + length += snprintf(&command[length], + remaining, + "-h %s ", + file_path); + } + + /* update remaining */ + remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length; + + /* check validity */ + valid = ((result.error == ERR_NONE) && (remaining > 0)); + } + + /* add firmware parameter if requested */ + if ((valid) && (parameters->firmware)) + { + char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 }; + + /* construct firmware file path */ + arm_uc_error_t result = + arm_uc_pal_linux_internal_file_path(file_path, + sizeof(file_path), + ARM_UC_FIRMWARE_FOLDER_PATH, + "firmware", + arm_uc_location); + + /* generated valid file path */ + if (result.error == ERR_NONE) + { + /* add parameter to command line */ + length += snprintf(&command[length], + remaining, + "-f %s ", + file_path); + } + + /* update remaining */ + remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length; + + /* check validity */ + valid = ((result.error == ERR_NONE) && (remaining > 0)); + } + + /* add location parameter if requested */ + if ((valid) && (parameters->location)) + { + /* add parameter to command line */ + length += snprintf(&command[length], + remaining, + "-l %" PRIu32 " ", + *arm_uc_location); + + /* update remaining */ + remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length; + + /* check validity */ + valid = (remaining > 0); + } + + /* add offset parameter if requested */ + if ((valid) && (parameters->offset)) + { + /* add parameter to command line */ + length += snprintf(&command[length], + remaining, + "-o %" PRIu32 " ", + arm_uc_offset); + + /* update remaining */ + remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length; + + /* check validity */ + valid = (remaining > 0); + } + + /* add size parameter if requested */ + if ((valid) && (parameters->size)) + { + if (arm_uc_buffer) + { + /* add parameter to command line */ + length += snprintf(&command[length], + remaining, + "-s %" PRIu32 " ", + arm_uc_buffer->size_max); + + /* update remaining */ + remaining = ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH - length; + + /* check validity */ + valid = (remaining > 0); + } + else + { + valid = false; + } + } + } + + return valid; +} + +arm_uc_error_t arm_uc_pal_linux_internal_read(const char* file_path, + uint32_t offset, + arm_uc_buffer_t* buffer) +{ + /* default to failure result */ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (file_path && buffer) + { + /* open file */ + errno = 0; + FILE* descriptor = fopen(file_path, "rb"); + + /* continue if file is open */ + if (descriptor != NULL) + { + /* set read position */ + int status = fseek(descriptor, offset, SEEK_SET); + + /* continue if position is set */ + if (status == 0) + { + /* read buffer */ + errno = 0; + size_t xfer_size = fread(buffer->ptr, + sizeof(uint8_t), + buffer->size_max, + descriptor); + + /* set buffer size if read succeeded */ + status = ferror(descriptor); + + if (status == 0) + { + buffer->size = xfer_size; + + /* set successful result */ + result.code = ERR_NONE; + } + else + { + /* set error code if read failed */ + UC_PAAL_ERR_MSG("failed to read %s: %s", file_path, strerror(errno)); + buffer->size = 0; + } + + /* close file after read */ + fclose(descriptor); + } + else + { + UC_PAAL_ERR_MSG("failed to seek in: %s", file_path); + } + } + else + { + UC_PAAL_ERR_MSG("failed to open %s: %s", file_path, strerror(errno)); + } + } + + return result; +} + +arm_uc_error_t arm_uc_pal_linux_internal_read_header(uint32_t* location, + arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* construct header file path */ + char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 }; + + result = arm_uc_pal_linux_internal_file_path(file_path, + ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH, + ARM_UC_HEADER_FOLDER_PATH, + "header", + location); + + /* file path is valid */ + if (result.error == ERR_NONE) + { + /* allocate external header sized read buffer since it will be + large enough to hold either an internal or external header. + */ + uint8_t read_buffer[ARM_UC_EXTERNAL_HEADER_SIZE_V2] = { 0 }; + + arm_uc_buffer_t buffer = { + .size_max = sizeof(read_buffer), + .size = 0, + .ptr = read_buffer + }; + + /* read metadata header */ + result = arm_uc_pal_linux_internal_read(file_path, 0, &buffer); + + /* check return code */ + if (result.error == ERR_NONE) + { + UC_PAAL_TRACE("header bytes: %u", buffer.size); + + /* read out header magic */ + uint32_t headerMagic = arm_uc_parse_uint32(&read_buffer[0]); + + /* read out header magic */ + uint32_t headerVersion = arm_uc_parse_uint32(&read_buffer[4]); + + /* choose version to decode */ + if ((headerMagic == ARM_UC_INTERNAL_HEADER_MAGIC_V2) && + (headerVersion == ARM_UC_INTERNAL_HEADER_VERSION_V2) && + (buffer.size == ARM_UC_INTERNAL_HEADER_SIZE_V2)) + { + result = arm_uc_parse_internal_header_v2(read_buffer, details); + } + else if ((headerMagic == ARM_UC_EXTERNAL_HEADER_MAGIC_V2) && + (headerVersion == ARM_UC_EXTERNAL_HEADER_VERSION_V2) && + (buffer.size == ARM_UC_EXTERNAL_HEADER_SIZE_V2)) + { + result = arm_uc_parse_external_header_v2(read_buffer, details); + } + else + { + UC_PAAL_ERR_MSG("invalid header in slot %" PRIu32, location); + + /* invalid header format */ + result.code = ERR_INVALID_PARAMETER; + } + } + else + { + /* unsuccessful read */ + UC_PAAL_ERR_MSG("unable to read header in slot %" PRIX32, location); + } + } + else + { + UC_PAAL_ERR_MSG("header file name and path too long"); + } + } + + return result; +} + +arm_uc_error_t arm_uc_pal_linux_internal_read_installer(arm_uc_installer_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* construct file path */ + char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 }; + + result = arm_uc_pal_linux_internal_file_path(file_path, + ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH, + ARM_UC_INSTALLER_FOLDER_PATH, + "installer", + NULL); + + /* file path is valid */ + if (result.error == ERR_NONE) + { + uint8_t read_buffer[2 * sizeof(arm_uc_hash_t) + sizeof(uint32_t)] = { 0 }; + + arm_uc_buffer_t buffer = { + .size_max = sizeof(read_buffer), + .size = 0, + .ptr = read_buffer + }; + + /* read installer details */ + result = arm_uc_pal_linux_internal_read(file_path, 0, &buffer); + + UC_PAAL_TRACE("installer bytes: %u", buffer.size); + + /* check return code */ + if ((result.error == ERR_NONE) && + (buffer.size == sizeof(read_buffer))) + { + memcpy(details->arm_hash, + buffer.ptr, + sizeof(arm_uc_hash_t)); + + memcpy(details->oem_hash, + &buffer.ptr[sizeof(arm_uc_hash_t)], + sizeof(arm_uc_hash_t)); + + details->layout = arm_uc_parse_uint32(&buffer.ptr[2 * sizeof(arm_uc_hash_t)]); + } + else + { + /* unsuccessful read */ + UC_PAAL_ERR_MSG("unable to read installer details"); + } + } + else + { + UC_PAAL_ERR_MSG("installer file name and path too long"); + } + } + + return result; +} + +arm_uc_error_t arm_uc_pal_linux_internal_write_header(uint32_t* location, + const arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* allocate external header sized buffer since it will be + large enough to hold either an internal or external header. + */ + uint8_t temp_buffer[ARM_UC_EXTERNAL_HEADER_SIZE_V2] = { 0 }; + + arm_uc_buffer_t buffer = { + .size_max = sizeof(temp_buffer), + .size = 0, + .ptr = temp_buffer + }; + + /* encode firmware details in buffer */ +#if ARM_UC_USE_EXTERNAL_HEADER + result = arm_uc_create_external_header_v2(details, &buffer); +#else + result = arm_uc_create_internal_header_v2(details, &buffer); +#endif + + /* write header file */ + if (result.error == ERR_NONE) + { + char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 }; + + /* construct header file path */ + result = arm_uc_pal_linux_internal_file_path(file_path, + ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH, + ARM_UC_HEADER_FOLDER_PATH, + "header", + location); + + if (result.error == ERR_NONE) + { + /* inverse result */ + result.code = ERR_INVALID_PARAMETER; + + /* open file and get file handler */ + errno = 0; + FILE* file = fopen(file_path, "wb"); + + if (file != NULL) + { + /* write buffer to file */ + size_t xfer_size = fwrite(buffer.ptr, + sizeof(uint8_t), + buffer.size, + file); + + UC_PAAL_TRACE("written: %u", xfer_size); + + /* close file after write */ + int status = fclose(file); + + if ((xfer_size == buffer.size) && + (status != EOF)) + { + /* set return code if write was successful */ + result.code = ERR_NONE; + } + else + { + UC_PAAL_ERR_MSG("failed to write header"); + } + } + else + { + UC_PAAL_ERR_MSG("file open failed: %s", strerror(errno)); + } + } + else + { + UC_PAAL_ERR_MSG("header file name and path too long"); + } + } + else + { + UC_PAAL_ERR_MSG("header too large for buffer"); + } + + } + + return result; +} + +/** + * @brief Function to run script in a worker thread before file operations. + * + * @param params Pointer to arm_ucp_worker_t struct. + */ +void* arm_uc_pal_linux_extended_pre_worker(void* params) +{ + /* default to failure */ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + /* get parameters */ + arm_ucp_worker_t* parameters = (arm_ucp_worker_t*) params; + + /* file path to script result */ + char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 }; + + /* construct script command */ + char command[ARM_UC_MAXIMUM_COMMAND_LENGTH] = { 0 }; + + int error = 0; + int valid = arm_uc_pal_linux_internal_command(parameters, + command, + ARM_UC_MAXIMUM_COMMAND_LENGTH); + + /* command is valid */ + if (valid) + { + UC_PAAL_TRACE("Extended pre-script command: %s", command); + + /* execute script */ + errno = 0; + FILE* pipe = popen(command, "r"); + + if (pipe) + { + /* read pipe */ + size_t xfer_size = fread(file_path, + sizeof(uint8_t), + ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH, + pipe); + + /* trim non-printable characters */ + for (size_t index = 0; index < xfer_size; index++) + { + /* space is the first printable character */ + if (file_path[index] < ' ') + { + /* truncate string */ + file_path[index] = '\0'; + break; + } + } + + int status = 0; + + /* check fread error status */ + status = ferror(pipe); + if (status == 0) + { + /* Wait for child thread termination and check exit status */ + status = pclose(pipe); + + /* make sure child thread terminated correctly and scirpt exit status is 0 */ + if (status != -1 && WIFEXITED(status)) + { + if (WEXITSTATUS(status) == 0) + { + /* switch from boolean result to arm_uc_error_t */ + result.code = ERR_NONE; + } + else + { + UC_PAAL_ERR_MSG("Script exited with non-zero status %" PRId32, status); + } + } + else + { + UC_PAAL_ERR_MSG("pipe terminated incorrectly %" PRId32, status); + } + } + else + { + UC_PAAL_ERR_MSG("failed to read pipe: %" PRId32, status); + } + } + else + { + UC_PAAL_ERR_MSG("failed to execute script: %" PRId32, errno); + } + } + + /* file path is valid */ + if (result.error == ERR_NONE) + { + /* invert status */ + result.code = ERR_INVALID_PARAMETER; + + extern arm_ucp_worker_config_t arm_uc_worker_parameters; + + /* perform read operation */ + if ((parameters == arm_uc_worker_parameters.read) && + (arm_uc_buffer != NULL)) + { + result = arm_uc_pal_linux_internal_read(file_path, 0, arm_uc_buffer); + + /* reset global buffer */ + arm_uc_buffer = NULL; + } + + /* read details */ + if ((parameters == arm_uc_worker_parameters.details) && + (arm_uc_details != NULL)) + { + result = arm_uc_pal_linux_internal_read_header(arm_uc_location, + arm_uc_details); + + /* reset global details pointer */ + arm_uc_details = NULL; + } + + /* read active details */ + if ((parameters == arm_uc_worker_parameters.active_details) && + (arm_uc_details != NULL)) + { + result = arm_uc_pal_linux_internal_read_header(NULL, + arm_uc_details); + + /* reset global details pointer */ + arm_uc_details = NULL; + } + + /* read installer details */ + if ((parameters == arm_uc_worker_parameters.installer) && + (arm_uc_installer != NULL)) + { + result = arm_uc_pal_linux_internal_read_installer(arm_uc_installer); + + /* reset global installer pointer */ + arm_uc_installer = NULL; + } + } + + if (result.error == ERR_NONE) + { + UC_PAAL_TRACE("pre-script complete"); + + arm_uc_pal_linux_signal_callback(parameters->success_event); + } + else + { + UC_PAAL_ERR_MSG("pre-script failed"); + + arm_uc_pal_linux_signal_callback(parameters->failure_event); + } +} + +/** + * @brief Function to run script in a worker thread before file operations. + * + * @param params Pointer to arm_ucp_worker_t struct. + */ +void* arm_uc_pal_linux_extended_post_worker(void* params) +{ + /* get parameters */ + arm_ucp_worker_t* parameters = (arm_ucp_worker_t*) params; + + /* construct script command */ + char command[ARM_UC_MAXIMUM_COMMAND_LENGTH] = { 0 }; + + int error = 0; + int valid = arm_uc_pal_linux_internal_command(parameters, + command, + ARM_UC_MAXIMUM_COMMAND_LENGTH); + + if (valid) + { + UC_PAAL_TRACE("Extended post-script command: %s", command); + + /* execute script command */ + error = system(command); + error = WEXITSTATUS(error); + + /* update valid flag */ + valid = (error == 0); + } + + if (valid) + { + UC_PAAL_TRACE("post-script completed"); + + arm_uc_pal_linux_signal_callback(parameters->success_event); + } + else + { + UC_PAAL_ERR_MSG("post-script failed: %" PRId32, error); + + arm_uc_pal_linux_signal_callback(parameters->failure_event); + } +} + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_openwrt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_openwrt.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,103 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_IS_PC_LINUX) + +#include "update-client-paal/arm_uc_paal_update_api.h" +#include "update-client-pal-linux/arm_uc_pal_linux_implementation.h" +#include "update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h" + +/** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_PAL_Linux_GetCapabilities_OpenWRT(void) +{ + const ARM_UC_PAAL_UPDATE_CAPABILITIES result = { + .installer_arm_hash = 0, + .installer_oem_hash = 0, + .installer_layout = 0, + .firmware_hash = 1, + .firmware_hmac = 0, + .firmware_campaign = 0, + .firmware_version = 1, + .firmware_size = 1 + }; + + return result; +} + +arm_ucp_worker_t arm_uc_worker_parameters_active_details = { + .command = "/usr/sbin/arm_update_active_details.sh", + .header = 1, + .firmware = 0, + .location = 0, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE, + .failure_event = ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_activate = { + .command = "/usr/sbin/arm_update_activate.sh", + .header = 1, + .firmware = 1, + .location = 0, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_ACTIVATE_DONE, + .failure_event = ARM_UC_PAAL_EVENT_ACTIVATE_ERROR +}; + +arm_uc_error_t ARM_UC_PAL_Linux_Initialize_OpenWRT(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ + extern arm_ucp_worker_config_t arm_uc_worker_parameters; + + arm_uc_worker_parameters.activate = &arm_uc_worker_parameters_activate; + arm_uc_worker_parameters.active_details = &arm_uc_worker_parameters_active_details; + arm_uc_worker_parameters.details = NULL; + arm_uc_worker_parameters.finalize = NULL; + arm_uc_worker_parameters.initialize = NULL; + arm_uc_worker_parameters.installer = NULL; + arm_uc_worker_parameters.prepare = NULL; + arm_uc_worker_parameters.read = NULL; + arm_uc_worker_parameters.write = NULL; + + return ARM_UC_PAL_Linux_Initialize(callback); +} + +const ARM_UC_PAAL_UPDATE ARM_UCP_LINUX_OPENWRT = +{ + .Initialize = ARM_UC_PAL_Linux_Initialize_OpenWRT, + .GetCapabilities = ARM_UC_PAL_Linux_GetCapabilities_OpenWRT, + .GetMaxID = ARM_UC_PAL_Linux_GetMaxID, + .Prepare = ARM_UC_PAL_Linux_Prepare, + .Write = ARM_UC_PAL_Linux_Write, + .Finalize = ARM_UC_PAL_Linux_Finalize, + .Read = ARM_UC_PAL_Linux_Read, + .Activate = ARM_UC_PAL_Linux_Activate, + .GetActiveFirmwareDetails = ARM_UC_PAL_Linux_GetActiveFirmwareDetails, + .GetFirmwareDetails = ARM_UC_PAL_Linux_GetFirmwareDetails, + .GetInstallerDetails = ARM_UC_PAL_Linux_GetInstallerDetails +}; + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_yocto_rpi.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/source/arm_uc_pal_linux_yocto_rpi.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,103 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_IS_PC_LINUX) + +#include "update-client-paal/arm_uc_paal_update_api.h" +#include "update-client-pal-linux/arm_uc_pal_linux_implementation.h" +#include "update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h" + +/** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_PAL_Linux_GetCapabilities_Yocto_RPi(void) +{ + const ARM_UC_PAAL_UPDATE_CAPABILITIES result = { + .installer_arm_hash = 0, + .installer_oem_hash = 0, + .installer_layout = 0, + .firmware_hash = 1, + .firmware_hmac = 0, + .firmware_campaign = 0, + .firmware_version = 1, + .firmware_size = 1 + }; + + return result; +} + +arm_ucp_worker_t arm_uc_worker_parameters_active_details = { + .command = "/opt/arm/arm_update_active_details.sh", + .header = 1, + .firmware = 0, + .location = 0, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE, + .failure_event = ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR +}; + +arm_ucp_worker_t arm_uc_worker_parameters_activate = { + .command = "/opt/arm/arm_update_activate.sh", + .header = 1, + .firmware = 1, + .location = 0, + .offset = 0, + .size = 0, + .success_event = ARM_UC_PAAL_EVENT_ACTIVATE_DONE, + .failure_event = ARM_UC_PAAL_EVENT_ACTIVATE_ERROR +}; + +arm_uc_error_t ARM_UC_PAL_Linux_Initialize_Yocto_RPi(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ + extern arm_ucp_worker_config_t arm_uc_worker_parameters; + + arm_uc_worker_parameters.activate = &arm_uc_worker_parameters_activate; + arm_uc_worker_parameters.active_details = &arm_uc_worker_parameters_active_details; + arm_uc_worker_parameters.details = NULL; + arm_uc_worker_parameters.finalize = NULL; + arm_uc_worker_parameters.initialize = NULL; + arm_uc_worker_parameters.installer = NULL; + arm_uc_worker_parameters.prepare = NULL; + arm_uc_worker_parameters.read = NULL; + arm_uc_worker_parameters.write = NULL; + + return ARM_UC_PAL_Linux_Initialize(callback); +} + +const ARM_UC_PAAL_UPDATE ARM_UCP_LINUX_YOCTO_RPI = +{ + .Initialize = ARM_UC_PAL_Linux_Initialize_Yocto_RPi, + .GetCapabilities = ARM_UC_PAL_Linux_GetCapabilities_Yocto_RPi, + .GetMaxID = ARM_UC_PAL_Linux_GetMaxID, + .Prepare = ARM_UC_PAL_Linux_Prepare, + .Write = ARM_UC_PAL_Linux_Write, + .Finalize = ARM_UC_PAL_Linux_Finalize, + .Read = ARM_UC_PAL_Linux_Read, + .Activate = ARM_UC_PAL_Linux_Activate, + .GetActiveFirmwareDetails = ARM_UC_PAL_Linux_GetActiveFirmwareDetails, + .GetFirmwareDetails = ARM_UC_PAL_Linux_GetFirmwareDetails, + .GetInstallerDetails = ARM_UC_PAL_Linux_GetInstallerDetails +}; + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/update-client-pal-linux/arm_uc_pal_linux_generic.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/update-client-pal-linux/arm_uc_pal_linux_generic.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_LINUX_H +#define ARM_UC_PAL_LINUX_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +extern ARM_UC_PAAL_UPDATE ARM_UCP_LINUX_GENERIC; + +#endif // ARM_UC_PAL_LINUX_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/update-client-pal-linux/arm_uc_pal_linux_implementation.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/update-client-pal-linux/arm_uc_pal_linux_implementation.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,172 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_LINUX_IMPLEMENTATION_H +#define ARM_UC_PAL_LINUX_IMPLEMENTATION_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_Linux_GetMaxID(void); + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Prepare(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer); + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer); + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Finalize(uint32_t location); + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer); + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_Activate(uint32_t location); + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_GetFirmwareDetails(uint32_t location, + arm_uc_firmware_details_t* details); + +/** + * @brief Get firmware details for the actively running firmware. + * @details This call populates the passed details struct with information + * about the currently active firmware image. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details); + +/** + * @brief Get details for the component responsible for installation. + * @details This call populates the passed details struct with information + * about the local installer. Only the fields marked as supported + * in the capabilities bitmap will have valid values. The + * installer could be the bootloader, a recovery image, or some + * other component responsible for applying the new firmware + * image. + * + * @param details Pointer to installer details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_Linux_GetInstallerDetails(arm_uc_installer_details_t* details); + +#ifdef __cplusplus +} +#endif + +#endif /* ARM_UC_PAL_Linux_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,121 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_LINUX_IMPLEMENTATION_INTERNAL_H +#define ARM_UC_PAL_LINUX_IMPLEMENTATION_INTERNAL_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#include <stdbool.h> +#include <stdio.h> + +#ifdef PAL_UPDATE_FIRMWARE_DIR +#define ARM_UC_FIRMWARE_FOLDER_PATH PAL_UPDATE_FIRMWARE_DIR +#define ARM_UC_HEADER_FOLDER_PATH PAL_UPDATE_FIRMWARE_DIR +#endif + +#ifndef ARM_UC_FIRMWARE_FOLDER_PATH +#define ARM_UC_FIRMWARE_FOLDER_PATH "/tmp" +#endif + +#ifndef ARM_UC_HEADER_FOLDER_PATH +#define ARM_UC_HEADER_FOLDER_PATH "/tmp" +#endif + +#ifndef ARM_UC_INSTALLER_FOLDER_PATH +#define ARM_UC_INSTALLER_FOLDER_PATH "/tmp" +#endif + +#ifndef ARM_UC_USE_EXTERNAL_HEADER +#define ARM_UC_USE_EXTERNAL_HEADER 0 +#endif + +#define ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH 128 +#define ARM_UC_MAXIMUM_COMMAND_LENGTH 256 + +typedef struct { + const char* command; + bool header; + bool firmware; + bool location; + bool offset; + bool size; + int32_t success_event; + int32_t failure_event; +} arm_ucp_worker_t; + +typedef struct { + arm_ucp_worker_t* activate; + arm_ucp_worker_t* active_details; + arm_ucp_worker_t* details; + arm_ucp_worker_t* finalize; + arm_ucp_worker_t* initialize; + arm_ucp_worker_t* installer; + arm_ucp_worker_t* prepare; + arm_ucp_worker_t* read; + arm_ucp_worker_t* write; +} arm_ucp_worker_config_t; + +void arm_uc_pal_linux_signal_callback(uint32_t event); + +/* set module variables */ +void arm_uc_pal_linux_internal_set_callback(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); +void arm_uc_pal_linux_internal_set_offset(uint32_t offset); +void arm_uc_pal_linux_internal_set_buffer(arm_uc_buffer_t* buffer); +void arm_uc_pal_linux_internal_set_details(arm_uc_firmware_details_t* details); +void arm_uc_pal_linux_internal_set_installer(arm_uc_installer_details_t* details); +void arm_uc_pal_linux_internal_set_location(uint32_t* location); + +/* construct file path */ +arm_uc_error_t arm_uc_pal_linux_internal_file_path(char* buffer, + size_t buffer_length, + const char* folder, + const char* type, + uint32_t* location); + +/* read firmware header */ +arm_uc_error_t arm_uc_pal_linux_internal_read_header(uint32_t* location, + arm_uc_firmware_details_t* details); + +/* read installer header */ +arm_uc_error_t arm_uc_pal_linux_internal_read_installer(arm_uc_installer_details_t* details); + +/* write firmware header*/ +arm_uc_error_t arm_uc_pal_linux_internal_write_header(uint32_t* location, + const arm_uc_firmware_details_t* details); + +/* read file */ +arm_uc_error_t arm_uc_pal_linux_internal_read(const char* file_path, + uint32_t offset, + arm_uc_buffer_t* buffer); + +/** + * @brief Function to run script in a worker thread before file operations. + * + * @param params Pointer to arm_ucp_worker_t struct. + */ +void* arm_uc_pal_linux_extended_pre_worker(void* params); + +/** + * @brief Function to run script in a worker thread before file operations. + * + * @param params Pointer to arm_ucp_worker_t struct. + */ +void* arm_uc_pal_linux_extended_post_worker(void* params); + +#endif /* ARM_UC_PAL_LINUX_IMPLEMENTATION_INTERNAL_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/update-client-pal-linux/arm_uc_pal_linux_openwrt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-linux/update-client-pal-linux/arm_uc_pal_linux_openwrt.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_LINUX_H +#define ARM_UC_PAL_LINUX_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +extern ARM_UC_PAAL_UPDATE ARM_UCP_LINUX_OPENWRT; + +#endif // ARM_UC_PAL_LINUX_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-target-specific/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-target-specific/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-target-specific/source/arm_uc_pal_realtek_rtl8195am.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-target-specific/source/arm_uc_pal_realtek_rtl8195am.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,777 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(TARGET_REALTEK_RTL8195AM) + +#include "update-client-paal/arm_uc_paal_update_api.h" +#include "update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h" + +#include "update-client-common/arm_uc_metadata_header_v2.h" +#include "update-client-common/arm_uc_common.h" + +#include "ota_api.h" +#include "flash_ext.h" + +#define HEADER_SIZE (OTA_CRC32_OFS + 4) + +typedef enum { + BASE_ADDRESS_RUNNING, + BASE_ADDRESS_SPARE +} base_address_t; + +/** + * Base address, for caching between operations. + */ +static size_t arm_uc_base_address = 0; + +/** + * Callback handler. + */ +static void (*arm_uc_pal_rtl8195am_callback)(uint32_t) = NULL; + +/** + * @brief Signal external event handler with NULL pointer check. + * + * @param[in] event The event + */ +static void arm_uc_pal_rtl8195am_signal_internal(uint32_t event) +{ + if (arm_uc_pal_rtl8195am_callback) + { + arm_uc_pal_rtl8195am_callback(event); + } +} + +/** + * @brief Create header compatible with the RTL8195AM bootloader + * + * @param[in] details Update client firmware details struct. + * @param buffer Scratch buffer for creating the header. + * + * @return ERR_NONE on success. ERR_INVALID_PARAMETER on failure. + */ +static arm_uc_error_t arm_uc_pal_create_realtek_header(const arm_uc_firmware_details_t* details, arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details && buffer && buffer->ptr && (buffer->size_max >= HEADER_SIZE)) + { + /* set tag */ + buffer->ptr[OTA_TAG_OFS ] = OTA_TAG_ID & 0xFF; + buffer->ptr[OTA_TAG_OFS + 1] = (OTA_TAG_ID >> 8) & 0xFF; + buffer->ptr[OTA_TAG_OFS + 2] = (OTA_TAG_ID >> 16) & 0xFF; + buffer->ptr[OTA_TAG_OFS + 3] = (OTA_TAG_ID >> 24) & 0xFF; + + /* set version tag */ + buffer->ptr[OTA_VER_OFS ] = OTA_VER_ID & 0xFF; + buffer->ptr[OTA_VER_OFS + 1] = (OTA_VER_ID >> 8) & 0xFF; + buffer->ptr[OTA_VER_OFS + 2] = (OTA_VER_ID >> 16) & 0xFF; + buffer->ptr[OTA_VER_OFS + 3] = (OTA_VER_ID >> 24) & 0xFF; + + /* set timestamp */ + buffer->ptr[OTA_EPOCH_OFS ] = details->version & 0xFF; + buffer->ptr[OTA_EPOCH_OFS + 1] = (details->version >> 8) & 0xFF; + buffer->ptr[OTA_EPOCH_OFS + 2] = (details->version >> 16) & 0xFF; + buffer->ptr[OTA_EPOCH_OFS + 3] = (details->version >> 24) & 0xFF; + buffer->ptr[OTA_EPOCH_OFS + 4] = (details->version >> 32) & 0xFF; + buffer->ptr[OTA_EPOCH_OFS + 5] = (details->version >> 40) & 0xFF; + buffer->ptr[OTA_EPOCH_OFS + 6] = (details->version >> 48) & 0xFF; + buffer->ptr[OTA_EPOCH_OFS + 7] = (details->version >> 56) & 0xFF; + + /* set size */ + uint32_t size_with_header = details->size + HEADER_SIZE; + + buffer->ptr[OTA_SIZE_OFS ] = size_with_header & 0xFF; + buffer->ptr[OTA_SIZE_OFS + 1] = (size_with_header >> 8) & 0xFF; + buffer->ptr[OTA_SIZE_OFS + 2] = (size_with_header >> 16) & 0xFF; + buffer->ptr[OTA_SIZE_OFS + 3] = (size_with_header >> 24) & 0xFF; + + /* copy hash */ + for (size_t index = 0; index < ARM_UC_SHA256_SIZE; index++) + { + buffer->ptr[OTA_HASH_OFS + index] = details->hash[index]; + } + + /* copy campaign */ + for (size_t index = 0; index < ARM_UC_GUID_SIZE; index++) + { + buffer->ptr[OTA_CAMPAIGN_OFS + index] = details->campaign[index]; + } + + /* set buffer size minus CRC */ + buffer->size = HEADER_SIZE - 4; + + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Read header for the image located at the base address. + * + * @param[in] base_address Start address for firmware slot. + * @param details Update client details struct. + * + * @return ERR_NONE on success, ERR_INVALID_PARAMETER on failure. + */ +static arm_uc_error_t arm_uc_pal_get_realtek_header(uint32_t base_address, + arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + uint8_t buffer[HEADER_SIZE] = { 0 }; + + int rc = arm_uc_flashiap_read(buffer, base_address, sizeof(buffer)); + + if (rc == 0) + { +#if 0 + printf("debug: \r\n"); + for (size_t index = 0; index < sizeof(buffer); index++) + { + printf("%02X", buffer[index]); + } + printf("\r\n"); +#endif + + /* parse tag */ + uint32_t tag = buffer[OTA_TAG_OFS + 3]; + tag = (tag << 8) | buffer[OTA_TAG_OFS + 2]; + tag = (tag << 8) | buffer[OTA_TAG_OFS + 1]; + tag = (tag << 8) | buffer[OTA_TAG_OFS + 0]; + + /* parse version tag */ + uint32_t version_tag = buffer[OTA_VER_OFS + 3]; + version_tag = (version_tag << 8) | buffer[OTA_VER_OFS + 2]; + version_tag = (version_tag << 8) | buffer[OTA_VER_OFS + 1]; + version_tag = (version_tag << 8) | buffer[OTA_VER_OFS + 0]; + + UC_PAAL_TRACE("tag: %" PRIX32, tag); + UC_PAAL_TRACE("version_tag: %" PRIX32, version_tag); + + /* check tags */ + if ((tag == OTA_TAG_ID) && (version_tag == OTA_VER_ID)) + { + /* parse CRC */ + uint32_t crc_header = buffer[OTA_CRC32_OFS + 3]; + crc_header = (crc_header << 8) | buffer[OTA_CRC32_OFS + 2]; + crc_header = (crc_header << 8) | buffer[OTA_CRC32_OFS + 1]; + crc_header = (crc_header << 8) | buffer[OTA_CRC32_OFS + 0]; + + /* calculate crc */ + uint32_t crc_calculated = arm_uc_crc32(buffer, OTA_CRC32_OFS); + + UC_PAAL_TRACE("CRC header: %" PRIX32, crc_header); + UC_PAAL_TRACE("CRC calculated: %" PRIX32, crc_calculated); + + /* check crc before proceeding */ + if (crc_header == crc_calculated) + { + /* parse size */ + uint32_t size = buffer[OTA_SIZE_OFS + 3]; + size = (size << 8) | buffer[OTA_SIZE_OFS + 2]; + size = (size << 8) | buffer[OTA_SIZE_OFS + 1]; + size = (size << 8) | buffer[OTA_SIZE_OFS + 0]; + + /* parse version */ + uint64_t version = buffer[OTA_EPOCH_OFS + 7]; + version = (version << 8) | buffer[OTA_EPOCH_OFS + 6]; + version = (version << 8) | buffer[OTA_EPOCH_OFS + 5]; + version = (version << 8) | buffer[OTA_EPOCH_OFS + 4]; + version = (version << 8) | buffer[OTA_EPOCH_OFS + 3]; + version = (version << 8) | buffer[OTA_EPOCH_OFS + 2]; + version = (version << 8) | buffer[OTA_EPOCH_OFS + 1]; + version = (version << 8) | buffer[OTA_EPOCH_OFS + 0]; + + /* copy hash */ + for (size_t index = 0; index < ARM_UC_SHA256_SIZE; index++) + { + details->hash[index] = buffer[OTA_HASH_OFS + index]; + } + + details->size = size - HEADER_SIZE; + details->version = version; + + UC_PAAL_TRACE("size: %" PRIu64, details->size); + UC_PAAL_TRACE("version: %" PRIu64, details->version); + +#if 0 + printf("hash: "); + for (size_t index = 0; index < ARM_UC_SHA256_SIZE; index++) + { + printf("%02X", details->hash[index]); + } + printf("\r\n"); +#endif + + result.code = ERR_NONE; + } + else + { + UC_PAAL_ERR_MSG("header crc check failed"); + } + } + else + { + UC_PAAL_ERR_MSG("invalid header"); + } + } + else + { + UC_PAAL_ERR_MSG("error reading from flash"); + } + } + + return result; +} + +/** + * @brief Find base address of either running or spare firmare slot. + * + * @param[in] find Enum specifying what to find (running or spare slot). + * + * @return Base address. + */ +static uint32_t arm_uc_pal_find_base_address(base_address_t find) +{ + uint32_t base_address = 0; + + arm_uc_firmware_details_t slot_0 = { 0 }; + arm_uc_firmware_details_t slot_1 = { 0 }; + + /* read header from both slots */ + arm_uc_error_t result_0 = arm_uc_pal_get_realtek_header(OTA_REGION1_BASE, &slot_0); + arm_uc_error_t result_1 = arm_uc_pal_get_realtek_header(OTA_REGION2_BASE, &slot_1); + + /* both headers are valid */ + if ((result_0.error == ERR_NONE) && (result_1.error == ERR_NONE)) + { + /* running firmware has the highest version number */ + if (find == BASE_ADDRESS_RUNNING) + { + base_address = (slot_0.version >= slot_1.version) ? OTA_REGION1_BASE : OTA_REGION2_BASE; + } + /* spare firmware has the lowest version number */ + else + { + /* same test, swap result */ + base_address = (slot_0.version >= slot_1.version) ? OTA_REGION2_BASE : OTA_REGION1_BASE; + } + } + /* only slot0 has a valid header */ + else if (result_0.error == ERR_NONE) + { + if (find == BASE_ADDRESS_RUNNING) + { + /* only valid header must be the running one */ + base_address = OTA_REGION1_BASE; + } + else + { + /* slot with invalid header can be used as spare */ + base_address = OTA_REGION2_BASE; + } + } + /* only slot1 has a valid header */ + else if (result_1.error == ERR_NONE) + { + if (find == BASE_ADDRESS_RUNNING) + { + /* only valid header must be the running one */ + base_address = OTA_REGION2_BASE; + } + else + { + /* slot with invalid header can be used as spare */ + base_address = OTA_REGION1_BASE; + } + } + + /* if both headers are invalid return 0 */ + + return base_address; +} + +/*****************************************************************************/ + +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Initialize(void (*callback)(uint32_t)) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + arm_uc_pal_rtl8195am_callback = callback; + + return result; +} + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_RTL8195AM_GetMaxID(void) +{ + return 2; +} + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Prepare(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details && buffer && buffer->ptr) + { + UC_PAAL_TRACE("Prepare: %" PRIX32 " %" PRIX64 " %" PRIu64, + location, + details->size, + details->version); + + /* find location for the spare slot */ + arm_uc_base_address = arm_uc_pal_find_base_address(BASE_ADDRESS_SPARE); + + UC_PAAL_TRACE("spare base: %" PRIX32, arm_uc_base_address); + + /* check that the firmware can fit the spare slot */ + if (((arm_uc_base_address == OTA_REGION1_BASE) && (details->size < OTA_REGION1_SIZE)) || + ((arm_uc_base_address == OTA_REGION2_BASE) && (details->size < OTA_REGION2_SIZE))) + { + /* encode firmware details in buffer */ + result = arm_uc_pal_create_realtek_header(details, buffer); + + /* make space for new firmware */ + if (result.error == ERR_NONE) + { + /* find end address */ + uint32_t end_address = arm_uc_base_address + HEADER_SIZE + details->size; + + /* erase */ + uint32_t erase_address = arm_uc_base_address; + + while (erase_address < end_address) + { + uint32_t sector_size = arm_uc_flashiap_get_sector_size(erase_address); + + int status = arm_uc_flashiap_erase(erase_address, sector_size); + + UC_PAAL_TRACE("erase: %" PRIX32 " %" PRIX32 " %d", + erase_address, + sector_size, + status); + + if (status == 0) + { + erase_address += sector_size; + } + else + { + result.code = ERR_INVALID_PARAMETER; + break; + } + } + + /* write header */ + if (result.error == ERR_NONE) + { + UC_PAAL_TRACE("program: %u %" PRIu32, + arm_uc_base_address, + buffer->size); + + /* set default return code */ + result.code = ERR_NONE; + + /* write header without CRC */ + int status = arm_uc_flashiap_program(buffer->ptr, + arm_uc_base_address, + buffer->size); + + if (status != 0) + { + /* set return code */ + result.code = ERR_INVALID_PARAMETER; + } + + if (result.error == ERR_NONE) + { + /* signal done */ + arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_PREPARE_DONE); + } + else + { + UC_PAAL_ERR_MSG("flash program failed"); + } + } + else + { + UC_PAAL_ERR_MSG("flash erase failed"); + } + } + else + { + UC_PAAL_ERR_MSG("create header failed"); + } + } + else + { + UC_PAAL_ERR_MSG("firmware larger than slot"); + } + } + + return result; +} + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer && buffer->ptr) + { + /* find location address */ + uint32_t physical_address = arm_uc_base_address + HEADER_SIZE + offset; + + UC_PAAL_TRACE("Write: %p %" PRIX32 " %" PRIX32 " %" PRIX32, + buffer->ptr, + buffer->size, + offset, + physical_address); + + /* set default return code */ + result.code = ERR_NONE; + + for (size_t index = 0; index < buffer->size; ) + { + /* write aligned */ + size_t modulo = (physical_address + index) % FLASH_PAGE_SIZE; + size_t remaining = buffer->size - index; + size_t write_size = 0; + + /* fill remaining flash page */ + if (modulo > 0) + { + write_size = modulo; + } + /* write last page */ + else if (remaining < FLASH_PAGE_SIZE) + { + write_size = remaining; + } + /* write full page */ + else + { + write_size = FLASH_PAGE_SIZE; + } + + int status = arm_uc_flashiap_program(&buffer->ptr[index], + physical_address + index, + write_size); + + if (status != 0) + { + /* set return code */ + result.code = ERR_INVALID_PARAMETER; + break; + } + + index += write_size; + } + + if (result.error == ERR_NONE) + { + /* signal done */ + arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_WRITE_DONE); + } + else + { + UC_PAAL_ERR_MSG("flash program failed"); + } + } + + return result; +} + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Finalize(uint32_t location) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + UC_PAAL_TRACE("Finalize"); + + arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_FINALIZE_DONE); + + return result; +} + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer && buffer->ptr) + { + /* find the base address for the spare slot if not already set */ + if (arm_uc_base_address == 0) + { + arm_uc_base_address = arm_uc_pal_find_base_address(BASE_ADDRESS_SPARE); + } + + /* calculate actual physical address */ + uint32_t physical_address = arm_uc_base_address + HEADER_SIZE + offset; + + UC_PAAL_TRACE("Read: %" PRIX32 " %" PRIX32 " %" PRIX32, + physical_address, + offset, + buffer->size_max); + + uint32_t read_size = buffer->size_max; + + int status = arm_uc_flashiap_read(buffer->ptr, physical_address, read_size); + + if (status == 0) + { + /* set buffer size */ + buffer->size = read_size; + + /* set return code */ + result.code = ERR_NONE; + + /* signal done */ + arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_READ_DONE); + } + else + { + UC_PAAL_ERR_MSG("flash read failed"); + } + } + + return result; +} + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Activate(uint32_t location) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + UC_PAAL_TRACE("Activate"); + + uint8_t buffer[HEADER_SIZE] = { 0 }; + + int status = arm_uc_flashiap_read(buffer, arm_uc_base_address, sizeof(buffer)); + + if (status == 0) + { + /* calculate CRC */ + uint32_t crc = arm_uc_crc32(buffer, OTA_CRC32_OFS); + + buffer[0] = crc & 0xFF; + buffer[1] = (crc >> 8) & 0xFF; + buffer[2] = (crc >> 16) & 0xFF; + buffer[3] = (crc >> 24) & 0xFF; + + /* set crc in header to signal the bootloader that the image is ready */ + status = arm_uc_flashiap_program(buffer, arm_uc_base_address + OTA_CRC32_OFS, 4); + + if (status == 0) + { + /* set return code */ + result.code = ERR_NONE; + + /* signal done */ + arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); + } + } + + return result; +} + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_GetFirmwareDetails( + uint32_t location, + arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + /* this function is only used by the mbed Bootloader */ + + return result; +} + +/*****************************************************************************/ + +arm_uc_error_t ARM_UC_PAL_RTL8195AM_GetActiveDetails(arm_uc_firmware_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + UC_PAAL_TRACE("GetActiveDetails"); + + /* find running slot */ + uint32_t base_address = arm_uc_pal_find_base_address(BASE_ADDRESS_RUNNING); + + UC_PAAL_TRACE("active base: %" PRIX32, base_address); + + result = arm_uc_pal_get_realtek_header(base_address, details); + + /* signal event if operation was successful */ + if (result.error == ERR_NONE) + { + arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE); + } + } + + return result; +} + +arm_uc_error_t ARM_UC_PAL_RTL8195AM_GetInstallerDetails(arm_uc_installer_details_t* details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) + { + /* reset installer details struct */ + memset(&details->arm_hash, 0, ARM_UC_SHA256_SIZE); + memset(&details->oem_hash, 0, ARM_UC_SHA256_SIZE); + details->layout = 0; + + /* the magic tag identifies the bootloader it is compatible with */ + details->oem_hash[0] = (OTA_TAG_ID >> 24) & 0xFF; + details->oem_hash[1] = (OTA_TAG_ID >> 16) & 0xFF; + details->oem_hash[2] = (OTA_TAG_ID >> 8) & 0xFF; + details->oem_hash[3] = OTA_TAG_ID & 0xFF; + + details->oem_hash[4] = (OTA_VER_ID >> 24) & 0xFF; + details->oem_hash[5] = (OTA_VER_ID >> 16) & 0xFF; + details->oem_hash[6] = (OTA_VER_ID >> 8) & 0xFF; + details->oem_hash[7] = OTA_VER_ID & 0xFF; + + result.code = ERR_NONE; + + arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE); + } + + return result; +} + +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_PAL_RTL8195AM_GetCapabilities(void) +{ + ARM_UC_PAAL_UPDATE_CAPABILITIES result = { + .installer_arm_hash = 0, + .installer_oem_hash = 0, + .installer_layout = 0, + .firmware_hash = 1, + .firmware_hmac = 0, + .firmware_campaign = 0, + .firmware_version = 1, + .firmware_size = 1 + }; + + return result; +} + +const ARM_UC_PAAL_UPDATE ARM_UCP_REALTEK_RTL8195AM = +{ + .Initialize = ARM_UC_PAL_RTL8195AM_Initialize, + .GetCapabilities = ARM_UC_PAL_RTL8195AM_GetCapabilities, + .GetMaxID = ARM_UC_PAL_RTL8195AM_GetMaxID, + .Prepare = ARM_UC_PAL_RTL8195AM_Prepare, + .Write = ARM_UC_PAL_RTL8195AM_Write, + .Finalize = ARM_UC_PAL_RTL8195AM_Finalize, + .Read = ARM_UC_PAL_RTL8195AM_Read, + .Activate = ARM_UC_PAL_RTL8195AM_Activate, + .GetActiveFirmwareDetails = ARM_UC_PAL_RTL8195AM_GetActiveDetails, + .GetFirmwareDetails = ARM_UC_PAL_RTL8195AM_GetFirmwareDetails, + .GetInstallerDetails = ARM_UC_PAL_RTL8195AM_GetInstallerDetails +}; + +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-target-specific/update-client-pal-target-specific/arm_uc_pal_realtek_rtl8195am.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/pal-target-specific/update-client-pal-target-specific/arm_uc_pal_realtek_rtl8195am.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,145 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_RTL8195AM_IMPLEMENTATION_H +#define ARM_UC_PAL_RTL8195AM_IMPLEMENTATION_H + +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" +#include "update-client-paal/arm_uc_paal_update_api.h" + +extern ARM_UC_PAAL_UPDATE ARM_UCP_REALTEK_RTL8195AM; + +#ifdef __cplusplus +extern "C" { +#endif + +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_RTL8195AM_GetMaxID(void); + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Prepare(uint32_t location, + const arm_uc_firmware_details_t* details, + arm_uc_buffer_t* buffer); + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t* buffer); + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Finalize(uint32_t location); + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t* buffer); + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_Activate(uint32_t location); + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_RTL8195AM_GetFirmwareDetails( + uint32_t location, + arm_uc_firmware_details_t* details); + +/*****************************************************************************/ + +arm_uc_error_t ARM_UC_PAL_RTL8195AM_GetActiveDetails(arm_uc_firmware_details_t* details); + +arm_uc_error_t ARM_UC_PAL_RTL8195AM_GetInstallerDetails(arm_uc_installer_details_t* details); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UC_PAL_RTL8195AM_IMPLEMENTATION_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_http_socket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_http_socket.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,122 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-source-http-socket/arm_uc_http_socket.h" +#include "update-client-common/arm_uc_common.h" + +#include "arm_uc_http_socket_private.h" + +/*****************************************************************************/ +/* Public Function */ +/*****************************************************************************/ + +/** + * @brief Initialize Http module. + * @details Function pointer to event handler is passed as argument. + * + * @param context Struct holding all global variables. + * @param handler Event handler for signaling when each operation is complete. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_Initialize(arm_uc_http_socket_context_t* context, + ARM_UCS_HttpEvent_t handler) +{ + return arm_uc_socket_initialize(context, handler); +} + +/** + * @brief Resets HTTP socket to uninitialized state and clears memory struct. + * @details HTTP sockets must be initialized again before use. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_Terminate() +{ + return arm_uc_socket_terminate(); +} + +/** + * @brief Get hash for resource at URI. + * @details Store hash in provided buffer. Enclosing "" and '\0' are removed. + * + * Event generated: EVENT_HASH + * + * @param uri Pointer to struct with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_GetHash(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer) +{ + return arm_uc_socket_get(uri, buffer, UINT32_MAX, RQST_TYPE_HASH_ETAG); +} + +/** + * @brief Get date for resource at URI. + * @details Store Last-Modified data in provided buffer. Enclosing "" and '\0' are removed. + * + * Event generated: EVENT_DATE + * + * @param uri Pointer to struct with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_GetDate(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer) +{ + return arm_uc_socket_get(uri, buffer, UINT32_MAX, RQST_TYPE_HASH_DATE); +} + +/** + * @brief Get full resource at URI. + * @details Download resource at URI and store in provided buffer. + * If the provided buffer is not big enough to contain the whole resource + * what can fit in the buffer will be downloaded. + * The user can then use GetFragment to download the rest. + + * Events generated: EVENT_DOWNLOAD_PENDING if there is still data to + * download and EVENT_DOWNLOAD_DONE if the file is completely downloaded. + * + * @param uri Pointer to structure with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_GetFile(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer) +{ + return arm_uc_socket_get(uri, buffer, UINT32_MAX, RQST_TYPE_GET_FILE); +} + +/** + * @brief Get partial resource at URI. + * @details Download resource at URI from given offset and store in buffer. + * + * The buffer maxSize determines how big a fragment to download. If the + * buffer is larger than the requested fragment (offset to end-of-file) + * the buffer size is set to indicate the number of available bytes. + * + * Events generated: EVENT_DOWNLOAD_PENDING if there is still data to + * download and EVENT_DOWNLOAD_DONE if the file is completely downloaded. + * + * @param uri Pointer to structure with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @param offset Offset in resource to begin download from. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_GetFragment(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer, + uint32_t offset) +{ + return arm_uc_socket_get(uri, buffer, offset, RQST_TYPE_GET_FRAG); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_http_socket_private.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_http_socket_private.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,1021 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_http_socket_private.h" + +#include "arm_uc_socket_help.h" + +#include <pal.h> + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#if !defined(ARM_UC_SOCKET_TIMEOUT_MS) +#define ARM_UC_SOCKET_TIMEOUT_MS 10000 /* 10 seconds */ +#endif + +/* Pointer to struct containing all global variables. + Can be dynamically allocated and deallocated. +*/ +static arm_uc_http_socket_context_t* context = NULL; + +/** + * @brief Initialize Http module. + * @details A memory struct is passed as well as a function pointer for event + * handling. + * + * @param context Struct holding all global variables. + * @param handler Event handler for signaling when each operation is complete. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_initialize(arm_uc_http_socket_context_t* _context, + void (*handler)(uint32_t)) +{ + UC_SRCE_TRACE("arm_uc_socket_initialize"); + + /* default return value */ + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_FAILED }; + + /* save global context */ + context = _context; + + if (context) + { + /* initialize global variables */ + context->callback_handler = handler; + + context->request_uri = NULL; + context->request_buffer = NULL; + context->request_offset = 0; + context->request_type = RQST_TYPE_NONE; + + context->socket_state = STATE_DISCONNECTED; + context->expected_event = SOCKET_EVENT_UNDEFINED; + context->expected_remaining = 0; + + context->socket = NULL; + + context->isr_callback_counter = 0; + + context->timeout_timer_id = 0; + + context->cache_address.addressType = 0; + memset(context->cache_address.addressData, 0, PAL_NET_MAX_ADDR_SIZE); + context->cache_address_length = 0; + + /* set return value to success */ + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + } + + return result; +} + +/** + * @brief Resets HTTP socket to uninitialized state and clears memory struct. + * @details HTTP sockets must be initialized again before use. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_terminate() +{ + /* default return value */ + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_FAILED }; + + if (context) + { + /* close socket */ + arm_uc_socket_close(); + + /* reset all global variables */ + context->request_uri = NULL; + context->request_buffer = NULL; + context->request_offset = 0; + context->request_type = RQST_TYPE_NONE; + + context->socket_state = STATE_DISCONNECTED; + context->expected_event = SOCKET_EVENT_UNDEFINED; + context->expected_remaining = 0; + + context->socket = NULL; + + context = NULL; + + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + } + + return result; +} + +/** + * @brief Get resource at URI. + * @details Download resource at URI from given offset and store in buffer. + * Events are generated when download finish or on error + * + * @param uri Pointer to structure with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @param offset Offset in resource to begin download from. + * @param type Indicate what type of request that was initiated. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_get(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer, + uint32_t offset, + arm_uc_rqst_t type) +{ + UC_SRCE_TRACE("arm_uc_socket_get"); + + /* default return value */ + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + + /* check for NULL pointers */ + if (uri && + uri->scheme && + uri->host && + uri->path && + buffer && + buffer->ptr && + context) + { + /* parameters are valid */ + result.code = SRCE_ERR_NONE; + + /* store request */ + context->request_uri = uri; + context->request_buffer = buffer; + context->request_offset = offset; + context->request_type = type; + + /* clear buffer */ + context->request_buffer->size = 0; + + UC_SRCE_TRACE("Socket State: %d", context->socket_state); + + /* connect socket if not already connected */ + result = arm_uc_socket_connect(); + } + + return result; +} + +/** + * @brief Connect to server set in the global URI struct. + * @details Connecting generates a socket event, which automatically processes + * the request passed in arm_uc_socket_get. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_connect() +{ + /* default return value */ + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_FAILED }; + + /* NULL pointer check */ + if (context && context->request_uri) + { + if (context->socket_state == STATE_DISCONNECTED) + { + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + + /* create new async PAL socket */ + palStatus_t pal_inner = pal_asynchronousSocket(PAL_AF_INET, + PAL_SOCK_STREAM, + true, + 0, + arm_uc_socket_isr, + &context->socket); + + if (pal_inner != PAL_SUCCESS) + { + UC_SRCE_ERR_MSG("socket creation failed with pal status: 0x%" PRIX32, + (uint32_t) pal_inner); + arm_uc_socket_close(); + result = (arm_uc_error_t){ SRCE_ERR_FAILED }; + } + else + { + UC_SRCE_TRACE("socket: create success"); + } + + /* create socket timeout timer */ + if (result.code == SRCE_ERR_NONE) + { + pal_inner = pal_osTimerCreate(arm_uc_timeout_timer_callback, + NULL, + palOsTimerOnce, + &context->timeout_timer_id); + + if (pal_inner != PAL_SUCCESS) + { + UC_SRCE_ERR_MSG("socket timeout timer creation failed"); + arm_uc_socket_close(); + result = (arm_uc_error_t){ SRCE_ERR_FAILED }; + } + else + { + /* start socket timeout timer */ + pal_inner = pal_osTimerStart(context->timeout_timer_id, + ARM_UC_SOCKET_TIMEOUT_MS); + + if (pal_inner != PAL_SUCCESS) + { + UC_SRCE_ERR_MSG("Start socket timeout timer failed"); + arm_uc_socket_close(); + result = (arm_uc_error_t){ SRCE_ERR_FAILED }; + } + } + } + + /* convert URI to PAL address if cache is empty */ + if ((result.code == SRCE_ERR_NONE) && + (context->cache_address_length == 0)) + { + /* dns loopup */ + pal_inner = pal_getAddressInfo(context->request_uri->host, + &context->cache_address, + &context->cache_address_length); + + if (pal_inner != PAL_SUCCESS) + { + UC_SRCE_ERR_MSG("pal_getAddressInfo (DNS) failed"); + arm_uc_socket_close(); + result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + } + else + { + /* set PAL port */ + pal_inner = pal_setSockAddrPort(&context->cache_address, + context->request_uri->port); + + if (pal_inner != PAL_SUCCESS) + { + UC_SRCE_ERR_MSG("pal_setSockAddrPort returned: 0x%" PRIX32, + (uint32_t) pal_inner); + arm_uc_socket_close(); + result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + } + } + } + + /* connect to server */ + if (result.code == SRCE_ERR_NONE) + { + pal_inner = pal_connect(context->socket, + &context->cache_address, + context->cache_address_length); + UC_SRCE_TRACE("pal_connect returned: 0x%" PRIX32, + (uint32_t) pal_inner); + + if (pal_inner == PAL_SUCCESS) /* synchronous finish */ + { + context->socket_state = STATE_CONNECTED_IDLE; + context->expected_event = SOCKET_EVENT_CONNECT_DONE; + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + arm_uc_socket_isr(NULL); + } + else if (pal_inner == PAL_ERR_SOCKET_IN_PROGRES) /* asynchronous finish */ + { + context->expected_event = SOCKET_EVENT_CONNECT_DONE; + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + } + else + { + UC_SRCE_ERR_MSG("Error: socket connection failed"); + result = (arm_uc_error_t){ SRCE_ERR_FAILED }; + arm_uc_socket_close(); + } + } + } + else if (context->socket_state == STATE_CONNECTED_IDLE) /* already connected */ + { + /* Socket already connected, progress state machine */ + palStatus_t pal_inner = pal_osTimerStart(context->timeout_timer_id, + ARM_UC_SOCKET_TIMEOUT_MS); + + if (pal_inner != PAL_SUCCESS) + { + UC_SRCE_ERR_MSG("Start socket timeout timer failed"); + arm_uc_socket_close(); + return (arm_uc_error_t){ SRCE_ERR_FAILED }; + } + + UC_SRCE_TRACE("Socket already connected, progress state machine"); + context->expected_event = SOCKET_EVENT_CONNECT_DONE; + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + arm_uc_socket_isr(NULL); + } + else /* socket busy */ + { + UC_SRCE_TRACE("Socket Busy"); + result = (arm_uc_error_t){ SRCE_ERR_BUSY }; + } + } + + UC_SRCE_TRACE("arm_uc_socket_connect returning %s", ARM_UC_err2Str(result)); + + return result; +} + +/** + * @brief Send request passed in arm_uc_socket_get. + * @details This call assumes the HTTP socket is already connected to server. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_send_request() +{ + /* default return value */ + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_FAILED }; + + /* NULL pointer check */ + if (context) + { + /* get local references */ + arm_uc_buffer_t* request_buffer = context->request_buffer; + arm_uc_uri_t* request_uri = context->request_uri; + arm_uc_rqst_t request_type = context->request_type; + + /* template for generating HTTP requests */ + static const char HTTP_HEADER_TEMPLATE[] = + "%s %s HTTP/1.1\r\n" // status line + "Host: %s\r\n"; // mandated for http 1.1 + + if (request_type == RQST_TYPE_HASH_ETAG || + request_type == RQST_TYPE_HASH_DATE) + { + /* construct ETag and Date request header */ + request_buffer->size = snprintf((char *) request_buffer->ptr, + request_buffer->size_max, + HTTP_HEADER_TEMPLATE, + "HEAD", + request_uri->path, + request_uri->host); + } + else + { + /* construct download header */ + request_buffer->size = snprintf((char *) request_buffer->ptr, + request_buffer->size_max, + HTTP_HEADER_TEMPLATE, + "GET", + request_uri->path, + request_uri->host); + } + + if (request_type == RQST_TYPE_GET_FRAG) + { + /* construct the Range field that makes this a partial content request */ + request_buffer->size += snprintf((char *) request_buffer->ptr + request_buffer->size, + request_buffer->size_max - request_buffer->size, + "Range: bytes=%" PRIu32 "-%" PRIu32 "\r\n", + context->request_offset, + context->request_offset + request_buffer->size_max - 1); + } + + /* terminate request with a carriage return and newline */ + request_buffer->size += snprintf((char *) request_buffer->ptr + request_buffer->size, + request_buffer->size_max - request_buffer->size, + "\r\n"); + + /* terminate string */ + request_buffer->ptr[request_buffer->size] = '\0'; + UC_SRCE_TRACE("%s", request_buffer->ptr); + + /*************************************************************************/ + + size_t bytes_sent = 0; + + /* send HTTP request */ + palStatus_t pal_result = pal_send(context->socket, + request_buffer->ptr, + request_buffer->size, + &bytes_sent); + + if ((pal_result == PAL_SUCCESS) || (pal_result == PAL_ERR_SOCKET_WOULD_BLOCK)) /* asynchronous finish */ + { + UC_SRCE_TRACE("send success"); + + /* reset buffer and prepare to receive header */ + request_buffer->size = 0; + context->socket_state = STATE_PROCESS_HEADER; + context->expected_event = SOCKET_EVENT_SEND_DONE; + + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + } + else + { + UC_SRCE_TRACE("send error 0x%" PRIX32, (uint32_t) pal_result); + + /* clean up */ + arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); + } + } + + return result; +} + +/** + * @brief Receive data from HTTP socket. + * @details Data is stored in global buffer. The call will automatically retry + * if the socket is busy. + */ +void arm_uc_socket_receive() +{ + /* NULL pointer check */ + if (context) + { + /* get local references */ + arm_uc_buffer_t* request_buffer = context->request_buffer; + + size_t received_bytes = 0; + palStatus_t pal_result = PAL_SUCCESS; + + while ( (context->socket_state != STATE_DISCONNECTED) && + (pal_result == PAL_SUCCESS) && + context->request_buffer ) + { + if (request_buffer->size >= request_buffer->size_max) + { + UC_SRCE_ERR_MSG("There is no space in the buffer left"); + arm_uc_socket_error(UCS_HTTP_EVENT_ERROR_BUFFER_SIZE); + break; + } + + /* append data from socket receive buffer to request buffer. */ + pal_result = pal_recv(context->socket, + &(request_buffer->ptr[request_buffer->size]), + request_buffer->size_max - request_buffer->size, + &received_bytes); + + if (pal_result == PAL_SUCCESS && received_bytes > 0) + { + /* Note: the proper formatter %zu is not supported on mbed's libc, + * hence the casts to difference type. + */ + UC_SRCE_TRACE("recv success: %lu bytes received", + (unsigned long)received_bytes); + + if (request_buffer->size + received_bytes > request_buffer->size_max) + { + UC_SRCE_ERR_MSG("Got more data than available space in the buffer"); + arm_uc_socket_error(UCS_HTTP_EVENT_ERROR_BUFFER_SIZE); + break; + } + + /* update buffer size with received bytes */ + request_buffer->size += received_bytes; + + /* update expected event to signal receive done */ + context->expected_event = SOCKET_EVENT_RECEIVE_CONTINUE; + + /* received data */ + if (context->socket_state == STATE_PROCESS_HEADER) + { + /* expecting HTTP header */ + arm_uc_socket_process_header(); + } + else if (context->socket_state == STATE_PROCESS_BODY) + { + /* expecting body */ + arm_uc_socket_process_body(); + } + else + { + /* unexpected data, generate error and clean up */ + arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); + } + } + else if (pal_result == PAL_ERR_SOCKET_WOULD_BLOCK) + { + /* Note: at least on mbed os the pal_recv() returns garbage on recievedDataSize + * if the socket call returns anything but PAL_SUCCESS, so this needs to + * recalculate the remaining bytes count. + */ + UC_SRCE_TRACE("recv: pending: %" PRIu32, + (request_buffer->size_max - request_buffer->size)); + + /* update expected event to retry receiving */ + context->expected_event = SOCKET_EVENT_RECEIVE_CONTINUE; + } + else + { + UC_SRCE_ERR_MSG("Error: socket receive failed"); + + /* clean up */ + arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); + } + } + } +} + +/** + * @brief Function is called when some data has been received but an HTTP + * header has yet to be processed. + * @details Function is called repeatedly until a header is found or the buffer + * is full. Once a header is found, the ETag, date, or content length + * is parsed. For file and fragment downloads the receive process is + * restarted and the header is erased. + */ +void arm_uc_socket_process_header() +{ + /* NULL pointer check */ + if (context) + { + /* get local references */ + arm_uc_buffer_t* request_buffer = context->request_buffer; + arm_uc_uri_t* request_uri = context->request_uri; + arm_uc_rqst_t request_type = context->request_type; + + /* setup default return to be failure */ + bool request_successfully_processed = false; + + uint32_t index = arm_uc_strnstrn(request_buffer->ptr, + request_buffer->size, + (const uint8_t*) "\r\n\r\n", + 4); + + /* Continue receiving if full header is not found. */ + if (index > request_buffer->size) + { + request_successfully_processed = true; + arm_uc_socket_receive(); + } + else + { + /* process header */ + UC_SRCE_TRACE("HTTP header found"); + + const char header_tag[] = "HTTP/1.1 "; + + uint32_t header_start = arm_uc_strnstrn(request_buffer->ptr, + request_buffer->size, + (const uint8_t*) header_tag, + sizeof(header_tag) - 1); + + /* found beginning of header */ + if (header_start < request_buffer->size) + { + /* status code is after the header tag */ + header_start = header_start + sizeof(header_tag) - 1; + } + + /* buffer size check */ + if (header_start < request_buffer->size) + { + /* parse status code */ + bool header_parsed = false; + uint32_t status_code = arm_uc_str2uint32( + &(request_buffer->ptr[header_start]), + request_buffer->size - header_start, + &header_parsed); + + if (header_parsed == true) + { + UC_SRCE_TRACE("HTTP status code %" PRIu32, status_code); + + /* Redirect status codes: + 301: Moved Permanently + 302: Found [Elsewhere] + 303: See Other + 307: Temporary Redirect + */ + if ((status_code >= 301 && status_code <= 303) || + (status_code == 307)) + { + /* move location to front of buffer */ + const char tag[] = "Location"; + bool found = arm_uc_socket_trim_value(request_buffer, + tag, + sizeof(tag) - 1); + + if (found) + { + /* NULL terminate string */ + request_buffer->ptr[request_buffer->size] = '\0'; + + /* parse location and store in URI */ + arm_uc_error_t err = arm_uc_str2uri(request_buffer->ptr, + request_buffer->size, + request_uri); + + if ((err.error == ERR_NONE) && + (request_uri->scheme == URI_SCHEME_HTTP)) + { + UC_SRCE_TRACE("HTTP redirecting to http://%s:%" PRIu16 "/%s", + request_uri->host, + request_uri->port, + request_uri->path); + + /* close socket */ + pal_close(&context->socket); + + /* reset buffer */ + request_buffer->size = 0; + + /* reconnect to new uri location */ + err = arm_uc_socket_connect(); + if (err.error == ERR_NONE) + { + /* send the request to the new uri */ + err = arm_uc_socket_send_request(); + } + + if (err.error == ERR_NONE) + { + request_successfully_processed = true; + } + else + { + UC_SRCE_ERR_MSG("Error: HTTP redirect failed"); + } + } + else + { + UC_SRCE_ERR_MSG("Error: unable to parse URI string"); + } + } + else + { + UC_SRCE_ERR_MSG("Error: unable to find redirect location"); + } + } + /* All remaining codes outside 200-226 are treated as errors */ + else if (status_code < 200 || status_code > 226) + { + UC_SRCE_ERR_MSG("Error: server returned HTTP status code %" PRIu32, + status_code); + } + /* All codes between 200 to 226 */ + else + { + if (request_type == RQST_TYPE_HASH_ETAG) + { + /* look for ETag and move to front of buffer */ + const char tag[] = "ETag"; + bool found = arm_uc_socket_trim_value(request_buffer, + tag, + sizeof(tag) - 1); + + if (found) + { + /* ETag successfully read - post callback */ + if (context->callback_handler) + { + palStatus_t status = pal_osTimerStop(context->timeout_timer_id); + if (status != PAL_SUCCESS) + { + UC_SRCE_ERR_MSG("pal_osTimerStop returned 0x%" PRIX32, + (uint32_t) status); + arm_uc_socket_close(); + } + + ARM_UC_PostCallback(&context->event_callback_struct, + context->callback_handler, + UCS_HTTP_EVENT_HASH); + } + + /* request complete - close socket */ + arm_uc_socket_close(); + + /* success - no clean up needed */ + request_successfully_processed = true; + } + else + { + UC_SRCE_ERR_MSG("Error: unable to find ETag"); + } + } + else if (request_type == RQST_TYPE_HASH_DATE) + { + /* look for date and move to front of buffer */ + const char tag[] = "Last-Modified"; + bool found = arm_uc_socket_trim_value(request_buffer, + tag, + sizeof(tag) - 1); + + if (found) + { + /* date successfully read - post callback */ + if (context->callback_handler) + { + palStatus_t status = pal_osTimerStop(context->timeout_timer_id); + if (status != PAL_SUCCESS) + { + UC_SRCE_ERR_MSG("pal_osTimerStop returned 0x%" PRIX32, + (uint32_t) status); + arm_uc_socket_close(); + } + + ARM_UC_PostCallback(&context->event_callback_struct, + context->callback_handler, + UCS_HTTP_EVENT_DATE); + } + + /* request complete - close socket */ + arm_uc_socket_close(); + + /* signal clean up is not needed */ + request_successfully_processed = true; + } + else + { + UC_SRCE_ERR_MSG("Error: unable to find last modified date"); + } + } + /* request is GetFile or GetFragment */ + else + { + /* save current buffer size so we can recover body after + the content length has been read. */ + uint32_t current_size = request_buffer->size; + + /* find content length and move value to front of buffer */ + const char tag[] = "Content-Length"; + bool found = arm_uc_socket_trim_value(request_buffer, + tag, + sizeof(tag) - 1); + + if (found) + { + /* NULL terminate string */ + request_buffer->ptr[request_buffer->size] = '\0'; + + /* parse full length of content */ + int parsed = sscanf((char *) request_buffer->ptr, + "%10" SCNu32, + &context->expected_remaining); + + /* only continue if exactly one argument was parsed */ + if (parsed == 1) + { + UC_SRCE_TRACE("content: %" PRIu32, + context->expected_remaining); + + /* replace HTTP header with body */ + memmove(request_buffer->ptr, + &(request_buffer->ptr[index + 4]), + current_size - (index + 4)); + + /* set size of partial body */ + request_buffer->size = current_size - (index + 4); + + /* */ + if (request_buffer->size >= context->expected_remaining) + { + /* all data received - process data */ + arm_uc_socket_process_body(); + } + else + { + /* expecting more data - continue receiving */ + UC_SRCE_TRACE("expecting more data %" PRIu32 "/%" PRIu32 "\r\n", + request_buffer->size, + context->expected_remaining); + } + + /* signal clean up is not needed */ + request_successfully_processed = true; + + /* continue processing body */ + context->socket_state = STATE_PROCESS_BODY; + } + else + { + UC_SRCE_ERR_MSG("Error: unable to parse content length"); + } + } + else + { + UC_SRCE_ERR_MSG("Error: unable find content length"); + } + } + } + } + else + { + UC_SRCE_ERR_MSG("Error: unable to read status code"); + } + } + else + { + UC_SRCE_ERR_MSG("Error: HTTP header not found"); + } + } + + /* clean up */ + if (request_successfully_processed == false) + { + arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); + } + } +} + +/** + * @brief Function is called when file or fragment is being downloaded. + * @details Function drives the download and continues until the buffer is full + * or the expected amount of data has been downloaded. + */ +void arm_uc_socket_process_body() +{ + /* NULL pointer check */ + if (context) + { + /* check if all expected bytes have been received */ + if (context->request_buffer->size >= context->expected_remaining) + { + UC_SRCE_TRACE("process body done"); + + /* fragment or file successfully received - post callback */ + if (context->callback_handler) + { + palStatus_t status = pal_osTimerStop(context->timeout_timer_id); + if (status != PAL_SUCCESS) + { + UC_SRCE_ERR_MSG("pal_osTimerStop returned 0x%" PRIX32, + (uint32_t) status); + arm_uc_socket_close(); + } + + ARM_UC_PostCallback(&context->event_callback_struct, + context->callback_handler, + UCS_HTTP_EVENT_DOWNLOAD); + } + + /* reset buffers and state */ + context->socket_state = STATE_CONNECTED_IDLE; + context->request_buffer = NULL; + context->expected_event = SOCKET_EVENT_UNDEFINED; + } + } +} + +/** + * @brief Close socket and set internal state to disconnected. + */ +void arm_uc_socket_close() +{ + /* NULL pointer check */ + if (context) + { + /* close socket if not NULL */ + if (context->socket) + { + pal_close(&context->socket); + } + + /* delete socket timeout timer */ + if (context->timeout_timer_id != (palTimerID_t) NULL) + { + pal_osTimerDelete(&context->timeout_timer_id); + } + + /* reset buffers and state */ + context->request_buffer = NULL; + context->expected_event = SOCKET_EVENT_UNDEFINED; + context->socket_state = STATE_DISCONNECTED; + context->timeout_timer_id = 0; + } +} + +/** + * @brief Close socket, set internal state to disconnected and generate error + * event. + */ +void arm_uc_socket_error(arm_ucs_http_event_t error) +{ + /* NULL pointer check */ + if (context) + { + if (context->socket_state != STATE_DISCONNECTED) + { + /* close socket */ + arm_uc_socket_close(); + } + + /* clear DNS cache */ + context->cache_address.addressType = 0; + memset(context->cache_address.addressData, 0, PAL_NET_MAX_ADDR_SIZE); + context->cache_address_length = 0; + + /* if callback handler is set, generate error event */ + if (context->callback_handler) + { + UC_SRCE_ERR_MSG("posting to callback with event %d", error); + ARM_UC_PostCallback(&context->event_callback_struct, + context->callback_handler, + error); + } + } +} + +/** + * @brief PAL socket event handler. + * @param unused PAL API doesn't support parameters. + */ +void arm_uc_socket_callback(uint32_t unused) +{ + (void) unused; + + UC_SRCE_TRACE("arm_uc_socket_callback"); + + /* NULL pointer check */ + if (context) + { + /* unlock posting callbacks to the queue */ + pal_osAtomicIncrement(&context->isr_callback_counter, -1); + + switch (context->expected_event) + { + case SOCKET_EVENT_CONNECT_DONE: + UC_SRCE_TRACE("Connect done"); + + context->socket_state = STATE_CONNECTED_IDLE; + { + arm_uc_error_t result = arm_uc_socket_send_request(); + if (result.code != SRCE_ERR_NONE) + { + UC_SRCE_ERR_MSG("arm_uc_socket_send_request failed: %s", + ARM_UC_err2Str(result)); + arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); + } + } + break; + + case SOCKET_EVENT_SEND_DONE: + UC_SRCE_TRACE("send done"); + + /* request send, receive response */ + context->expected_event = SOCKET_EVENT_RECEIVE_CONTINUE; + arm_uc_socket_receive(); + break; + + case SOCKET_EVENT_RECEIVE_CONTINUE: + UC_SRCE_TRACE("recv continue"); + + /* outstanding data, continue receiving */ + arm_uc_socket_receive(); + break; + + case SOCKET_EVENT_TIMER_FIRED: + UC_SRCE_TRACE("socket timeout timer fired"); + + arm_uc_socket_error(UCS_HTTP_EVENT_ERROR); + break; + + case SOCKET_EVENT_UNDEFINED: + default: + UC_SRCE_TRACE("event: undefined"); + break; + } + } +} + +/** + * @brief Callback handler for PAL socket events. Callbacks go through the task + * queue because we don't know what context we are running from. + */ +void arm_uc_socket_isr(void* unused) +{ + /* NULL pointer check */ + if (context) + { + /* ensure we only have one callback in flight */ + int32_t count = pal_osAtomicIncrement(&context->isr_callback_counter, 0); + + if (count == 0) + { + pal_osAtomicIncrement(&context->isr_callback_counter, 1); + + /* post callback to de-escalate event */ + ARM_UC_PostCallback(&context->isr_callback_struct, + arm_uc_socket_callback, + 0); + } + } +} + +/** + * @brief Callback handler for the socket timeout timer callback. + * Callbacks go through the task queue because we don't know + * what context we are running from. + */ +void arm_uc_timeout_timer_callback(void const *unused) +{ + (void) unused; + + context->expected_event = SOCKET_EVENT_TIMER_FIRED; + /* push event to the socket event queue */ + arm_uc_socket_isr(NULL); +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_http_socket_private.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_http_socket_private.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,130 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ARM_UC_HTTP_SOCKET_PRIVATE_H__ +#define __ARM_UC_HTTP_SOCKET_PRIVATE_H__ + +#include "update-client-source-http-socket/arm_uc_http_socket.h" +#include "update-client-common/arm_uc_common.h" + +/** + * @brief Initialize Http module. + * @details A memory struct is passed as well as a function pointer for event + * handling. + * + * @param context Struct holding all global variables. + * @param handler Event handler for signaling when each operation is complete. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_initialize(arm_uc_http_socket_context_t* context, + ARM_UCS_HttpEvent_t handler); + +/** + * @brief Resets HTTP socket to uninitialized state and clears memory struct. + * @details HTTP sockets must be initialized again before use. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_terminate(void); + +/** + * @brief Get resource at URI. + * @details Download resource at URI from given offset and store in buffer. + * Events are generated when download finish or on error + * + * @param uri Pointer to structure with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @param offset Offset in resource to begin download from. + * @param type Indicate what type of request that was initiated. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_get(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer, + uint32_t offset, + arm_uc_rqst_t type); + +/** + * @brief Connect to server set in the global URI struct. + * @details Connecting generates a socket event, which automatically processes + * the request passed in arm_uc_socket_get. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_connect(void); + +/** + * @brief Send request passed in arm_uc_socket_get. + * @details This call assumes the HTTP socket is already connected to server. + * @return Error code. + */ +arm_uc_error_t arm_uc_socket_send_request(void); + +/** + * @brief Receive data from HTTP socket. + * @details Data is stored in global buffer. The call will automatically retry + * if the socket is busy. + */ +void arm_uc_socket_receive(void); + +/** + * @brief Function is called when some data has been received but an HTTP + * header has yet to be processed. + * @details Function is called repeatedly until a header is found or the buffer + * is full. Once a header is found, the ETag, date, or content length + * is parsed. For file and fragment downloads the receive process is + * restarted and the header is erased. + */ +void arm_uc_socket_process_header(void); + +/** + * @brief Function is called when file or fragment is being downloaded. + * @details Function drives the download and continues until the buffer is full + * or the expected amount of data has been downloaded. + */ +void arm_uc_socket_process_body(void); + +/** + * @brief Close socket and set internal state to disconnected. + */ +void arm_uc_socket_close(void); + +/** + * @brief Close socket, set internal state to disconnected and generate error + * event. + * @param error The code of the error event. + */ +void arm_uc_socket_error(arm_ucs_http_event_t error); + +/** + * @brief Callback function for handling events in application context. + * @param unused Unused. + */ +void arm_uc_socket_callback(uint32_t unused); + +/** + * @brief Callback function for handling events in interrupt context. + * @details All events are de-escalated through the callback queue. + */ +void arm_uc_socket_isr(void*); + +/** + * @brief Callback handler for the socket timeout timer callback. + * Callbacks go through the task queue because we don't know + * what context we are running from. + */ +void arm_uc_timeout_timer_callback(void const *); + +#endif // __ARM_UC_HTTP_SOCKET_PRIVATE_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_socket_help.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_socket_help.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,81 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_socket_help.h" + +#include <string.h> + +/** + * @brief Helper function for picking out values from an HTTP header. + * @details The buffer is searched for the tag provided tag and if found the + * remainder of that line is MOVED to the front of the buffer and the + * size is shrunk to only include the detected value. + * + * @param buffer Pointer to an arm_uc_buffer_t. + * @param tag_buffer Pointer to tag (a string). + * @param tag_size Length of the tag. + * @return True if tag was found. False otherwise. + */ +bool arm_uc_socket_trim_value(arm_uc_buffer_t* buffer, + const char* tag_buffer, + uint32_t tag_size) +{ + /* default return value */ + bool result = false; + + /* check for NULL pointers */ + if (buffer && buffer->ptr && tag_buffer) + { + /* search for the tag */ + uint32_t start = arm_uc_strnstrn(buffer->ptr, + buffer->size, + (const uint8_t*) tag_buffer, + tag_size); + + /* check if index is within bounds */ + if (start < buffer->size) + { + /* remove tag */ + start += tag_size; + + /* remove ": " between tag and value */ + start += 2; + + /* search for the end of the line */ + uint32_t length = arm_uc_strnstrn(&(buffer->ptr[start]), + buffer->size - start, + (const uint8_t*) "\r", + 1); + + /* move value to front of buffer if all indices are within bounds */ + if ((start + length) < buffer->size) + { + /* memmove handles overlapping regions */ + memmove(buffer->ptr, &(buffer->ptr[start]), length); + + /* resize buffer */ + buffer->size = length; + + /* set return value to success */ + result = true; + } + } + } + + return result; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_socket_help.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/source/arm_uc_socket_help.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,42 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ARM_UC_SOCKET_HELP_H__ +#define __ARM_UC_SOCKET_HELP_H__ + +#include "update-client-common/arm_uc_common.h" + +#include <stdbool.h> +#include <stdint.h> + +/** + * @brief Helper function for picking out values from an HTTP header. + * @details The buffer is searched for the tag provided tag and if found the + * remainder of that line is MOVED to the front of the buffer and the + * size is shrunk to only include the detected value. + * + * @param buffer Pointer to an arm_uc_buffer_t. + * @param tag_buffer Pointer to tag (a string). + * @param tag_size Length of the tag. + * @return True if tag was found. False otherwise. + */ +bool arm_uc_socket_trim_value(arm_uc_buffer_t* buffer, + const char* tag_buffer, + uint32_t tag_size); + +#endif // __ARM_UC_SOCKET_HELP_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/update-client-source-http-socket/arm_uc_http_socket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http-socket/update-client-source-http-socket/arm_uc_http_socket.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,188 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef UPDATE_CLIENT_SOURCE_HTTP_SOCKET_H +#define UPDATE_CLIENT_SOURCE_HTTP_SOCKET_H + +#include "update-client-common/arm_uc_common.h" + +#include <pal.h> + +/** + * @brief Events passed to event handler. + * @details EVENT_HASH Get hash complete. + * EVENT_DATE Get date complete. + * EVENT_DOWNLOAD_PENDING Download complete with data pending. + * EVENT_DOWNLOAD_DONE Download complete, all done. + */ +typedef enum { + UCS_HTTP_EVENT_HASH, + UCS_HTTP_EVENT_DATE, + UCS_HTTP_EVENT_DOWNLOAD, + UCS_HTTP_EVENT_ERROR, + UCS_HTTP_EVENT_ERROR_BUFFER_SIZE +} arm_ucs_http_event_t; + +typedef enum { + RQST_TYPE_NONE, // to indicate idle + RQST_TYPE_HASH_ETAG, + RQST_TYPE_HASH_DATE, + RQST_TYPE_GET_FILE, + RQST_TYPE_GET_FRAG +} arm_uc_rqst_t; + +typedef enum { + STATE_DISCONNECTED, + STATE_PROCESS_HEADER, + STATE_PROCESS_BODY, + STATE_CONNECTED_IDLE +} arm_uc_socket_state_t; + +typedef enum { + SOCKET_EVENT_CONNECT_DONE, + SOCKET_EVENT_SEND_DONE, + SOCKET_EVENT_RECEIVE_CONTINUE, + SOCKET_EVENT_UNDEFINED, + SOCKET_EVENT_TIMER_FIRED +} arm_uc_socket_event_t; + +/** + * @brief Prototype for event handler. + */ +typedef void (*ARM_UCS_HttpEvent_t)(uint32_t event); + +typedef struct { + /* external callback handler */ + ARM_UCS_HttpEvent_t callback_handler; + + /* location */ + arm_uc_uri_t* request_uri; + + /* buffer to store downloaded data */ + arm_uc_buffer_t* request_buffer; + + /* fragment offset in a multi-fragment download */ + uint32_t request_offset; + + /* request type */ + arm_uc_rqst_t request_type; + + /* internal state */ + arm_uc_socket_state_t socket_state; + + /* expected socket event */ + arm_uc_socket_event_t expected_event; + + /* remaining bytes in request */ + uint32_t expected_remaining; + + /* structs for callback queue */ + int32_t isr_callback_counter; + arm_uc_callback_t isr_callback_struct; // initialized in source-http + arm_uc_callback_t event_callback_struct; // initialized in source-http + arm_uc_callback_t timer_callback_struct; // initialized in source-http + + /* pointer to socket */ + palSocket_t socket; + + /* timer id for the socket timeout timer */ + palTimerID_t timeout_timer_id; + + /* cache for storing DNS lookup */ + palSocketAddress_t cache_address; + palSocketLength_t cache_address_length; +} arm_uc_http_socket_context_t; + +/** + * @brief Initialize Http module. + * @details A memory struct is passed as well as a function pointer for event + * handling. + * + * @param context Struct holding all global variables. + * @param handler Event handler for signaling when each operation is complete. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_Initialize(arm_uc_http_socket_context_t* context, + ARM_UCS_HttpEvent_t handler); + +/** + * @brief Resets HTTP socket to uninitialized state and clears memory struct. + * @details HTTP sockets must be initialized again before use. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_Terminate(void); + +/** + * @brief Get hash for resource at URI. + * @details Store hash in provided buffer. Enclosing "" and '\0' are removed. + * + * Event generated: EVENT_HASH + * + * @param uri Pointer to struct with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_GetHash(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer); + +/** + * @brief Get date for resource at URI. + * @details Store Last-Modified data in provided buffer. Enclosing "" and '\0' are removed. + * + * Event generated: EVENT_DATE + * + * @param uri Pointer to struct with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_GetDate(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer); + +/** + * @brief Get full resource at URI. + * @details Download resource at URI and store in provided buffer. + * If the provided buffer is not big enough to contain the whole resource + * what can fit in the buffer will be downloaded. + * The user can then use GetFragment to download the rest. + + * Events generated: EVENT_DOWNLOAD_PENDING if there is still data to + * download and EVENT_DOWNLOAD_DONE if the file is completely downloaded. + * + * @param uri Pointer to structure with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_GetFile(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer); + +/** + * @brief Get partial resource at URI. + * @details Download resource at URI from given offset and store in buffer. + * + * The buffer maxSize determines how big a fragment to download. If the + * buffer is larger than the requested fragment (offset to end-of-file) + * the buffer size is set to indicate the number of available bytes. + * + * Events generated: EVENT_DOWNLOAD_PENDING if there is still data to + * download and EVENT_DOWNLOAD_DONE if the file is completely downloaded. + * + * @param uri Pointer to structure with resource location. + * @param buffer Pointer to structure with buffer location, maxSize, and size. + * @param offset Offset in resource to begin download from. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_HttpSocket_GetFragment(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer, uint32_t offset); + +#endif /* UPDATE_CLIENT_SOURCE_HTTP_SOCKET_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http/source/arm_uc_source_http.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http/source/arm_uc_source_http.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,761 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-source-http/arm_uc_source_http.h" +#include "update-client-source-http/arm_uc_source_http_extra.h" + +#include "update-client-source-http-socket/arm_uc_http_socket.h" + +#include <time.h> +#include <stdio.h> +#include <stdbool.h> + +#define ARM_UCS_DEFAULT_COST (1000) +#define ARM_UCS_HASH_LENGTH (40) + +typedef struct _ARM_UCS_Configuration +{ + arm_uc_uri_t manifest; + uint32_t interval; + uint32_t currentCost; + time_t lastPoll; + int8_t hash[ARM_UCS_HASH_LENGTH]; + void (*eventHandler)(uint32_t event); +} ARM_UCS_Configuration_t; + +static ARM_UCS_Configuration_t default_config = { + .manifest = { + .size_max = 0, + .size = 0, + .ptr = NULL, + .scheme = URI_SCHEME_NONE, + .port = 0, + .host = NULL, + .path = NULL + }, + .interval = 0, + .currentCost = 0xFFFFFFFF, + .lastPoll = 0, + .hash = { 0 }, + .eventHandler = 0 +}; + +typedef enum { + STATE_UCS_HTTP_IDLE, + STATE_UCS_HTTP_MANIFEST, + STATE_UCS_HTTP_FIRMWARE, + STATE_UCS_HTTP_KEYTABLE, + STATE_UCS_HTTP_HASH +} arm_ucs_http_state_t; + +#define MAX_RETRY 3 +typedef struct { + arm_ucs_http_state_t stateHttp; + arm_uc_uri_t *uri; + arm_uc_buffer_t *buffer; + uint32_t offset; + uint8_t retryCount; +} arm_ucs_state_t; + +static arm_ucs_state_t arm_ucs_state; + +static arm_uc_http_socket_context_t arm_uc_http_socket_context = { 0 }; + +/* Helper function for resetting internal state */ +static inline void uc_state_reset() +{ + arm_ucs_state.stateHttp = STATE_UCS_HTTP_IDLE; + arm_ucs_state.uri = NULL; + arm_ucs_state.buffer = NULL; + arm_ucs_state.offset = 0; + arm_ucs_state.retryCount = 0; +} + +/* Helper function for checking if the stored hash is all zeros */ +static inline bool hash_is_zero() +{ + bool result = true; + + for (uint32_t index = 0; index < ARM_UCS_HASH_LENGTH; index++) + { + if (default_config.hash[index] != 0) + { + result = false; + break; + } + } + + return result; +} + +static arm_uc_error_t ARM_UCS_Get(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer, + uint32_t offset, + arm_ucs_http_state_t newHttpState); + +/******************************************************************************/ +/* ARM Update Client Source Extra */ +/******************************************************************************/ + +/** + * @brief Set URI location for the default manifest. + * @details The default manifest is polled regularly and generates a + * notification upon change. The URI struct and the content pointer to + * must be valid throughout the lifetime of the application. + * + * @param uri URI struct with manifest location. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_SetDefaultManifestURL(arm_uc_uri_t* uri) +{ + UC_SRCE_TRACE("ARM_UCS_SetDefaultManifestURL"); + + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + + if (uri != 0) + { + /* check scheme is http */ + if (uri->scheme == URI_SCHEME_HTTP) + { + /* copy pointers to local struct */ + default_config.manifest = *uri; + + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + } + } + + return result; +} + +/** + * @brief Set polling interval for notification generation. + * @details The default manifest location is polled with this interval. + * + * @param seconds Seconds between each poll. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_SetPollingInterval(uint32_t seconds) +{ + UC_SRCE_TRACE("ARM_UCS_SetPollingInterval"); + + default_config.interval = seconds; + + return (arm_uc_error_t){ SRCE_ERR_NONE }; +} + +/** + * @brief Main function for the Source. + * @details This function will query the default manifest location and generate + * a notification if it has changed since the last time it was checked. + * The number of queries generated is bound by the polling interval. + * + * This function should be used on systems with timed callbacks. + * + * @return Seconds until the next polling interval. + */ +uint32_t ARM_UCS_CallMultipleTimes(arm_uc_buffer_t* hash_buffer) +{ + uint32_t result = default_config.interval; + time_t unixtime = time(NULL); + uint32_t elapsed = unixtime - default_config.lastPoll; + + if ((default_config.eventHandler == NULL) || + (arm_ucs_state.stateHttp != STATE_UCS_HTTP_IDLE) || + (hash_buffer == NULL)) + { + return default_config.interval; + } + + if (elapsed >= default_config.interval) + { + UC_SRCE_TRACE("ARM_UCS_CallMultipleTimes"); + + // poll default URI + default_config.lastPoll = unixtime; + + // get resource hash + arm_ucs_state.stateHttp = STATE_UCS_HTTP_HASH; + arm_ucs_state.buffer = hash_buffer; + + arm_uc_error_t retval = ARM_UCS_HttpSocket_GetHash(&default_config.manifest, + arm_ucs_state.buffer); + if (retval.error != ERR_NONE) + { + uc_state_reset(); + return default_config.interval; + } + } + else + { + result = (elapsed > 0) ? default_config.interval - elapsed : default_config.interval; + } + + return result; +} + + +ARM_UCS_HTTPSourceExtra_t ARM_UCS_HTTPSourceExtra = +{ + .SetDefaultManifestURL = ARM_UCS_SetDefaultManifestURL, + .SetPollingInterval = ARM_UCS_SetPollingInterval, + .CallMultipleTimes = ARM_UCS_CallMultipleTimes +}; + +/******************************************************************************/ +/* ARM Update Client Source */ +/******************************************************************************/ + +static void ARM_UCS_ProcessHash() +{ + UC_SRCE_TRACE("ARM_UCS_ProcessHash"); + +#if ARM_UC_SOURCE_MANAGER_TRACE_ENABLE + printf("hash: "); + for (uint32_t index = 0; index < arm_ucs_state.buffer->size; index++) + { + printf("%c", arm_ucs_state.buffer->ptr[index]); + } + printf("\r\n"); +#endif + + bool hashIsNew = false; + bool firstBoot = hash_is_zero(); + + /* compare hash with previous check */ + for (uint32_t index = 0; index < arm_ucs_state.buffer->size; index++) + { + /* compare hash */ + if (default_config.hash[index] != arm_ucs_state.buffer->ptr[index]) + { + /* store new hash */ + default_config.hash[index] = arm_ucs_state.buffer->ptr[index]; + + hashIsNew = true; + } + } + + /* Request complete, reset state */ + uc_state_reset(); + + /* Signal that a new manifest is available if the hash is non-zero + and different from the last check. + */ + if (hashIsNew && !firstBoot) + { + if (default_config.eventHandler) + { + default_config.eventHandler(EVENT_NOTIFICATION); + } + } +} + +static void ARM_UCS_HTTPEvent(uint32_t event) +{ + UC_SRCE_TRACE("ARM_UCS_HTTPEvent"); + + switch (event) + { + /* Hash received, process it */ + case UCS_HTTP_EVENT_HASH: + UC_SRCE_TRACE("UCS_HTTP_EVENT_HASH"); + + ARM_UCS_ProcessHash(); + break; + + /* Download complete */ + case UCS_HTTP_EVENT_DOWNLOAD: + { + UC_SRCE_TRACE("UCS_HTTP_EVENT_DOWNLOAD"); + + /* cache state before resetting it */ + arm_ucs_http_state_t previous_state = arm_ucs_state.stateHttp; + + /* reset internal state */ + uc_state_reset(); + + /* signal successful download based on request */ + if (default_config.eventHandler) + { + if (previous_state == STATE_UCS_HTTP_MANIFEST) + { + default_config.eventHandler(EVENT_MANIFEST); + } + else if (previous_state == STATE_UCS_HTTP_FIRMWARE) + { + default_config.eventHandler(EVENT_FIRMWARE); + } + else if (previous_state == STATE_UCS_HTTP_KEYTABLE) + { + default_config.eventHandler(EVENT_KEYTABLE); + } + else + { + default_config.eventHandler(EVENT_ERROR); + } + } + } + break; + + /* Socket error */ + case UCS_HTTP_EVENT_ERROR: + { + UC_SRCE_TRACE("UCS_HTTP_EVENT_ERROR"); + + /* Treat polling as retry when reading hash */ + if (arm_ucs_state.stateHttp == STATE_UCS_HTTP_HASH) + { + /* If the stored hash is zero, this error is most likely + generated due to the default manifest not being uploaded + yet. Mark the stored hash as non-zero, so the first time + the device successfully retrieves a hash we download the + manifest. + */ + bool result = hash_is_zero(); + + if (result) + { + default_config.hash[0] = 0xFF; + } + + /* reset state but don't take any further action */ + uc_state_reset(); + } + /* Perform MAX_RETRY otherwise */ + else if (arm_ucs_state.retryCount < MAX_RETRY) + { + /* restore buffer size on retry */ + arm_ucs_state.buffer->size = arm_ucs_state.buffer->size_max; + + /* restore stateHttp */ + arm_ucs_http_state_t previous_state = arm_ucs_state.stateHttp; + arm_ucs_state.stateHttp = STATE_UCS_HTTP_IDLE; + + arm_uc_error_t retval = ARM_UCS_Get(arm_ucs_state.uri, + arm_ucs_state.buffer, + arm_ucs_state.offset, + previous_state); + + /* retry unsuccessful */ + if (retval.error != ERR_NONE) + { + /* reset internal state */ + uc_state_reset(); + + /* generate error event */ + if (default_config.eventHandler) + { + default_config.eventHandler(EVENT_ERROR); + } + } + } + else + { + /* reset internal state */ + uc_state_reset(); + + /* generate error event */ + if (default_config.eventHandler) + { + default_config.eventHandler(EVENT_ERROR); + } + } + } + break; + + /* supplied buffer not large enough */ + case UCS_HTTP_EVENT_ERROR_BUFFER_SIZE: + { + /* reset internal state */ + uc_state_reset(); + + /* generate error event */ + if (default_config.eventHandler) + { + default_config.eventHandler(EVENT_ERROR_BUFFER_SIZE); + } + } + break; + + default: + UC_SRCE_TRACE("Unknown event"); + break; + } +} + +/** + * @brief Get driver version. + * @return Driver version. + */ +uint32_t ARM_UCS_GetVersion(void) +{ + UC_SRCE_TRACE("ARM_UCS_GetVersion"); + + return 0; +} + +/** + * @brief Get Source capabilities. + * @return Struct containing capabilites. See definition above. + */ +ARM_SOURCE_CAPABILITIES ARM_UCS_GetCapabilities(void) +{ + UC_SRCE_TRACE("ARM_UCS_GetCapabilities"); + + ARM_SOURCE_CAPABILITIES result = { + .notify = 0, + .manifest_default = 0, + .manifest_url = 0, + .firmware = 0, + .keytable = 0 + }; + + /* the event handler must be set before module can be used */ + if (default_config.eventHandler != 0) + { + result.manifest_url = 1; + result.firmware = 1; + result.keytable = 1; + + /* notification requires that the default manifest is set */ + if ((default_config.manifest.port != 0) || (default_config.interval != 0)) + { + result.notify = 1; + result.manifest_default = 1; + } + } + + return result; +} + +/** + * @brief Initialize Source. + * @details Function pointer to event handler is passed as argument. + * + * @param cb_event Function pointer to event handler. See events above. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_Initialize(ARM_SOURCE_SignalEvent_t cb_event) +{ + UC_SRCE_TRACE("ARM_UCS_Initialize"); + + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + + if (cb_event != 0) + { + default_config.currentCost = ARM_UCS_DEFAULT_COST; + default_config.eventHandler = cb_event; + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + + /* register http callback handler */ + ARM_UCS_HttpSocket_Initialize(&arm_uc_http_socket_context, + ARM_UCS_HTTPEvent); + } + + uc_state_reset(); + return result; +} + +/** + * @brief Uninitialized Source. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_Uninitialize(void) +{ + UC_SRCE_TRACE("ARM_UCS_Uninitialize"); + + return (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; +} + +/** + * @brief Cost estimation for retrieving manifest from the default location. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetManifestDefaultCost(uint32_t* cost) +{ + UC_SRCE_TRACE("ARM_UCS_GetManifestDefaultCost"); + + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + + if (cost != 0) + { + *cost = default_config.currentCost; + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + } + + return result; +} + +/** + * @brief Cost estimation for retrieving manifest from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param uri URI struct with manifest location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetManifestURLCost(arm_uc_uri_t* uri, uint32_t* cost) +{ + UC_SRCE_TRACE("ARM_UCS_GetManifestURLCost"); + + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + + /* return default cost regardless of actual uri location */ + if ((uri != 0) && (cost != 0)) + { + *cost = default_config.currentCost; + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + } + /* return no-path cost if URL is invalid */ + else if (cost != 0) + { + *cost = 0xFFFFFFFF; + result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + } + + return result; +} + +/** + * @brief Cost estimation for retrieving firmware from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with firmware location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetFirmwareURLCost(arm_uc_uri_t* uri, uint32_t* cost) +{ + UC_SRCE_TRACE("ARM_UCS_GetFirmwareURLCost"); + + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + + /* return default cost regardless of actual uri location */ + if ((uri != 0) && (cost != 0)) + { + *cost = default_config.currentCost; + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + } + /* return no-path cost if URL is invalid */ + else if (cost != 0) + { + *cost = 0xFFFFFFFF; + result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + } + + return result; +} + +/** + * @brief Cost estimation for retrieving key table from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with keytable location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetKeytableURLCost(arm_uc_uri_t* uri, uint32_t* cost) +{ + UC_SRCE_TRACE("ARM_UCS_GetKeytableURLCost"); + + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + + /* return default cost regardless of actual uri location */ + if ((uri != 0) && (cost != 0)) + { + *cost = default_config.currentCost; + result = (arm_uc_error_t){ SRCE_ERR_NONE }; + } + /* return no-path cost if URL is invalid */ + else if (cost != 0) + { + *cost = 0xFFFFFFFF; + result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + } + + return result; +} + +/** + * @brief (Internal) Retrieve resource according to the given parameters + * in arm_ucs_state and store the returned data in the buffer in arm_ucs_state. + * @param uri URI struct with resource location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Offset to retrieve fragment from. + * @param newHttpState The intended new http state to be assigned to arm_ucs_state.stateHttp + */ +static arm_uc_error_t ARM_UCS_Get(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer, + uint32_t offset, + arm_ucs_http_state_t newHttpState) +{ + UC_SRCE_TRACE("ARM_UCS_Get"); + + // check current state + if (default_config.eventHandler == 0) + { + UC_SRCE_ERR_MSG("Uninitialized"); + + return (arm_uc_error_t){ SRCE_ERR_UNINITIALIZED }; + } + else if (arm_ucs_state.stateHttp != STATE_UCS_HTTP_IDLE) + { + UC_SRCE_ERR_MSG("Busy"); + + return (arm_uc_error_t){ SRCE_ERR_BUSY }; + } + + // assign new state + arm_ucs_state.stateHttp = newHttpState; + arm_ucs_state.uri = uri; + arm_ucs_state.buffer = buffer; + arm_ucs_state.offset = offset; + + // Call the socket layer to get the requested data + arm_uc_error_t result = (arm_uc_error_t){ SRCE_ERR_INVALID_PARAMETER }; + + while ((result.error != ERR_NONE) && (arm_ucs_state.retryCount++ < MAX_RETRY)) + { + // restore buffer size on retry + arm_ucs_state.buffer->size = arm_ucs_state.buffer->size_max; + + switch(arm_ucs_state.stateHttp) + { + case STATE_UCS_HTTP_MANIFEST: + case STATE_UCS_HTTP_FIRMWARE: + if (arm_ucs_state.buffer != 0 && arm_ucs_state.uri != 0) + { + result = ARM_UCS_HttpSocket_GetFragment(arm_ucs_state.uri, + arm_ucs_state.buffer, + arm_ucs_state.offset); + } + break; + + case STATE_UCS_HTTP_KEYTABLE: + if (arm_ucs_state.buffer != 0 && arm_ucs_state.uri != 0) + { + result = ARM_UCS_HttpSocket_GetFile(arm_ucs_state.uri, + arm_ucs_state.buffer); + } + break; + + default: + UC_SRCE_ERR_MSG("Invalid request parameter"); + result = (arm_uc_error_t) { SRCE_ERR_INVALID_PARAMETER }; + break; + } + } + + if (result.error != ERR_NONE) + { + uc_state_reset(); + } + + return result; +} + +/** + * @brief Retrieve manifest from the default location. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param buffer Struct containing byte array, maximum size, and actual size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetManifestDefault(arm_uc_buffer_t* buffer, uint32_t offset) +{ + UC_SRCE_TRACE("ARM_UCS_GetManifestDefault"); + + return ARM_UCS_Get(&default_config.manifest, buffer, offset, STATE_UCS_HTTP_MANIFEST); +} + +/** + * @brief Retrieve manifest from URL. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param uri URI struct with manifest location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetManifestURL(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer, uint32_t offset) +{ + UC_SRCE_TRACE("ARM_UCS_GetManifestURL"); + + return ARM_UCS_Get(uri, buffer, offset, STATE_UCS_HTTP_MANIFEST); +} + +/** + * @brief Retrieve firmware fragment. + * @details Firmware fragment is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with firmware location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Firmware offset to retrieve fragment from. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetFirmwareFragment(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer, uint32_t offset) +{ + UC_SRCE_TRACE("ARM_UCS_GetFirmwareFragment"); + + return ARM_UCS_Get(uri, buffer, offset, STATE_UCS_HTTP_FIRMWARE); +} + +/** + * @brief Retrieve a key table from a URL. + * @details Key table is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with keytable location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetKeytableURL(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer) +{ + UC_SRCE_TRACE("ARM_UCS_GetKeytableURL"); + + return ARM_UCS_Get(uri, buffer, UINT32_MAX, STATE_UCS_HTTP_KEYTABLE); +} + +ARM_UPDATE_SOURCE ARM_UCS_HTTPSource = +{ + .GetVersion = ARM_UCS_GetVersion, + .GetCapabilities = ARM_UCS_GetCapabilities, + .Initialize = ARM_UCS_Initialize, + .Uninitialize = ARM_UCS_Uninitialize, + .GetManifestDefaultCost = ARM_UCS_GetManifestDefaultCost, + .GetManifestURLCost = ARM_UCS_GetManifestURLCost, + .GetFirmwareURLCost = ARM_UCS_GetFirmwareURLCost, + .GetKeytableURLCost = ARM_UCS_GetKeytableURLCost, + .GetManifestDefault = ARM_UCS_GetManifestDefault, + .GetManifestURL = ARM_UCS_GetManifestURL, + .GetFirmwareFragment = ARM_UCS_GetFirmwareFragment, + .GetKeytableURL = ARM_UCS_GetKeytableURL +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http/update-client-source-http/arm_uc_source_http.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http/update-client-source-http/arm_uc_source_http.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,147 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __UPDATE_CLIENT_SOURCE_HTTP_H__ +#define __UPDATE_CLIENT_SOURCE_HTTP_H__ + +#include "update-client-source/arm_uc_source.h" + +/** + * @brief Get driver version. + * @return Driver version. + */ +uint32_t ARM_UCS_GetVersion(void); + +/** + * @brief Get Source capabilities. + * @return Struct containing capabilites. See definition above. + */ +ARM_SOURCE_CAPABILITIES ARM_UCS_GetCapabilities(void); + +/** + * @brief Initialize Source. + * @details Function pointer to event handler is passed as argument. + * + * @param cb_event Function pointer to event handler. See events above. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_Initialize(ARM_SOURCE_SignalEvent_t cb_event); + +/** + * @brief Uninitialized Source. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_Uninitialize(void); + +/** + * @brief Cost estimation for retrieving manifest from the default location. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetManifestDefaultCost(uint32_t* cost); + +/** + * @brief Cost estimation for retrieving manifest from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param uri URI struct with manifest location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetManifestURLCost(arm_uc_uri_t* uri, uint32_t* cost); + +/** + * @brief Cost estimation for retrieving firmware from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with firmware location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetFirmwareURLCost(arm_uc_uri_t* uri, uint32_t* cost); + +/** + * @brief Cost estimation for retrieving key table from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with keytable location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetKeytableURLCost(arm_uc_uri_t* uri, uint32_t* cost); + +/** + * @brief Retrieve manifest from the default location. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Manifest offset in bytes where the requested fragment begins. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetManifestDefault(arm_uc_buffer_t* buffer, uint32_t offset); + +/** + * @brief Retrieve manifest from URL. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param uri URI struct with manifest location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Manifest offset in bytes where the requested fragment begins. + * + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetManifestURL(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer, uint32_t offset); + +/** + * @brief Retrieve firmware fragment. + * @details Firmware fragment is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with firmware location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Firmware offset to retrieve fragment from. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetFirmwareFragment(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer, uint32_t offset); + +/** + * @brief Retrieve a key table from a URL. + * @details Key table is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with keytable location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_GetKeytableURL(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer); + +extern ARM_UPDATE_SOURCE ARM_UCS_HTTPSource; + +#endif // __UPDATE_CLIENT_SOURCE_HTTP_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http/update-client-source-http/arm_uc_source_http_extra.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-http/update-client-source-http/arm_uc_source_http_extra.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,69 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __UPDATE_CLIENT_SOURCE_HTTP_EXTRA_H__ +#define __UPDATE_CLIENT_SOURCE_HTTP_EXTRA_H__ + +#include "update-client-common/arm_uc_common.h" + +#include <stdint.h> + +/** + * @brief Set URI location for the default manifest. + * @details The default manifest is polled regularly and generates a + * notification upon change. The URI struct and the content pointer to + * must be valid throughout the lifetime of the application. + * + * @param uri URI struct with manifest location. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_SetDefaultManifestURL(arm_uc_uri_t* uri); + +/** + * @brief Set polling interval for notification generation. + * @details The default manifest location is polled with this interval. + * + * @param seconds Seconds between each poll. + * @return Error code. + */ +arm_uc_error_t ARM_UCS_SetPollingInterval(uint32_t seconds); + +/** + * @brief Main function for the Source. + * @details This function will query the default manifest location and generate + * a notification if it has changed since the last time it was checked. + * The number of queries generated is bound by the polling interval. + * + * This function should be used on systems with timed callbacks. + * + * @param buffer arm_uc_buffer_t for storing HTTP header during hash check. + * @return Seconds until the next polling interval. + */ +uint32_t ARM_UCS_CallMultipleTimes(arm_uc_buffer_t* buffer); + + +typedef struct _ARM_UCS_HTTPLinuxExtra_t +{ + arm_uc_error_t (*SetDefaultManifestURL)(arm_uc_uri_t* uri); + arm_uc_error_t (*SetPollingInterval)(uint32_t seconds); + uint32_t (*CallMultipleTimes)(arm_uc_buffer_t* buffer); +} ARM_UCS_HTTPSourceExtra_t; + +extern ARM_UCS_HTTPSourceExtra_t ARM_UCS_HTTPSourceExtra; + +#endif // __UPDATE_CLIENT_SOURCE_HTTP_EXTRA_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-manager/.mbedignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-manager/.mbedignore Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,3 @@ +TESTS/tests/sanity/* +test/* +*/test/*
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-manager/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-manager/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-manager/source/arm_uc_source_manager.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-manager/source/arm_uc_source_manager.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,518 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-source-manager/arm_uc_source_manager.h" + +#include "update-client-common/arm_uc_common.h" +#include "update-client-source/arm_uc_source.h" + +#include <stdint.h> +#include <stdlib.h> + +static const ARM_UPDATE_SOURCE* source_registry[MAX_SOURCES]; +static ARM_SOURCE_SignalEvent_t event_cb; + +// storage set aside for adding event_cb to the event queue +static arm_uc_callback_t event_cb_storage = { 0 }; + +typedef enum { + QUERY_TYPE_UNKNOWN, + QUERY_TYPE_MANIFEST_DEFAULT, + QUERY_TYPE_MANIFEST_URL, + QUERY_TYPE_FRIMWARE, + QUERY_TYPE_KEYTABLE +} query_type_t; + +typedef struct { + arm_uc_uri_t *uri; // the uri from which the resourced should be fetched + arm_uc_buffer_t *buffer; // buffer given by caller to contain the results of the fetch + uint32_t offset; // offset parameter passed to the source + query_type_t type; // type of request, whether is manifest, firmware or keytable + uint8_t excludes[MAX_SOURCES]; // records the tried and failed sources during a get request + uint8_t current_source; // records the index of source use in the get request in progress +} request_t; + +// Hold information about the request in flight, there will always only be one request in flight +static request_t request_in_flight; + +/* ==================================================================== * + * Private Functions * + * ==================================================================== */ + +/** + * @brief Initialise a request_t struct, called when a new request + * have been initiated from the hub + */ +static arm_uc_error_t ARM_UCSM_RequestStructInit(request_t* request); + +/** + * @brief The SourceRegistry is an array of ARM_UPDATE_SOURCE + */ +static arm_uc_error_t ARM_UCSM_SourceRegistryInit(); +static arm_uc_error_t ARM_UCSM_SourceRegistryAdd(const ARM_UPDATE_SOURCE* source); +static arm_uc_error_t ARM_UCSM_SourceRegistryRemove(const ARM_UPDATE_SOURCE* source); + +/** + * @brief return the index of the source with the smalllest cost + * @param url Struct containing URL. NULL for default Manifest. + * @param type The type of current request. + * @param excludes Pointer to an array of size MAX_SOURCES to indicate + * sources we want to exclude in the search. Set excludes[i]=1 to + * exclude source_registry[i] + * @param index Used to return the index of the source with the smalllest cost + */ +static arm_uc_error_t ARM_UCSM_SourceRegistryGetLowestCost(arm_uc_uri_t* uri, + query_type_t type, + uint8_t* excludes, + uint32_t* index); + +/** + * @brief Find the source of lowest cost and call the correspoding method + * depending on the type of the request. Retry with source of the next + * smallest cost if previous sources failed until the source registry + * is exhausted. + */ +static arm_uc_error_t ARM_UCSM_Get(request_t* req); + +/** + * @brief Catch callbacks from sources to enable error handling + */ +static void ARM_UCSM_CallbackWrapper(uint32_t event); + +/** + * @brief Retry get due to source being busy + */ +static void ARM_UCSM_AsyncRetryGet(uint32_t); + +/** + * @brief Initialise the `Request` struct + */ +static arm_uc_error_t ARM_UCSM_RequestStructInit(request_t* request) +{ + for (uint32_t i=0; i<MAX_SOURCES; i++) + { + request->excludes[i] = 0; + } + + request->current_source = MAX_SOURCES; + request->uri = NULL; + request->offset = 0; + request->type = QUERY_TYPE_UNKNOWN; + request->buffer = NULL; + + return (arm_uc_error_t){ SOMA_ERR_NONE }; +} + +/** + * @brief Initialise the source_registry array to NULL + */ +static arm_uc_error_t ARM_UCSM_SourceRegistryInit() +{ + for(uint32_t i=0; i<MAX_SOURCES; i++) + { + source_registry[i] = NULL; + } + + return (arm_uc_error_t){ SOMA_ERR_NONE }; +} +/** + * @brief Returns the index of the given source in the source array, + * or MAX_SOURCES if the source is not found + */ +static uint32_t ARM_UCSM_GetIndexOfSource(const ARM_UPDATE_SOURCE* source) +{ + uint32_t index = MAX_SOURCES; + + for(uint32_t i=0; i<MAX_SOURCES; i++) + { + if(source_registry[i] == source) + { + index = i; + break; + } + } + return index; +} + +/** + * @brief Add pointer to source to the source_registry array + */ +static arm_uc_error_t ARM_UCSM_SourceRegistryAdd(const ARM_UPDATE_SOURCE* source) +{ + uint8_t added = 0; + + for(uint32_t i=0; i<MAX_SOURCES; i++) + { + if(source_registry[i] == NULL) + { + source_registry[i] = source; + added = 1; + break; + } + } + + if (added == 0) // registry full + { + return (arm_uc_error_t){ SOMA_ERR_SOURCE_REGISTRY_FULL }; + } + + return (arm_uc_error_t){ SOMA_ERR_NONE }; +} + +/** + * @brief Remove pointer to source from the source_registry array + */ +static arm_uc_error_t ARM_UCSM_SourceRegistryRemove(const ARM_UPDATE_SOURCE* source) +{ + uint32_t index = ARM_UCSM_GetIndexOfSource(source); + + if (index == MAX_SOURCES) // source not found + { + return (arm_uc_error_t){ SOMA_ERR_SOURCE_NOT_FOUND }; + } + + source_registry[index] = NULL; + return (arm_uc_error_t){ SOMA_ERR_NONE }; +} + +/** + * @brief return the index of the source with the smalllest cost + * @param url Struct containing URL. NULL for default Manifest. + * @param type The type of current request. + * @param excludes Pointer to an array of size MAX_SOURCES to indicate + * sources we want to exclude in the search. Set excludes[i]=1 to + * exclude source_registry[i] + * @param index Used to return the index of the source with the smalllest cost + */ +static arm_uc_error_t ARM_UCSM_SourceRegistryGetLowestCost(arm_uc_uri_t* uri, + query_type_t type, + uint8_t* excludes, + uint32_t* index) +{ + uint32_t min_cost = UINT32_MAX; + uint32_t min_cost_index = 0; + arm_uc_error_t retval = (arm_uc_error_t){ SOMA_ERR_NONE }; + + // loop trough all sources + for (uint32_t i=0; i<MAX_SOURCES; i++) + { + // if source is NULL or it has been explicitly excluded because of failure before + if (source_registry[i] == NULL || (excludes != NULL && excludes[i] == 1)) + { + continue; + } + + ARM_SOURCE_CAPABILITIES cap = source_registry[i]->GetCapabilities(); + + uint32_t cost = UINT32_MAX; + if (uri == NULL && type == QUERY_TYPE_MANIFEST_DEFAULT && cap.manifest_default == 1) + { + retval = source_registry[i]->GetManifestDefaultCost(&cost); + } + else if (uri != NULL && type == QUERY_TYPE_MANIFEST_URL && cap.manifest_url == 1) + { + retval = source_registry[i]->GetManifestURLCost(uri, &cost); + } + else if (uri != NULL && type == QUERY_TYPE_FRIMWARE && cap.firmware == 1) + { + retval = source_registry[i]->GetFirmwareURLCost(uri, &cost); + } + else if (uri != NULL && type == QUERY_TYPE_KEYTABLE && cap.keytable == 1) + { + retval = source_registry[i]->GetKeytableURLCost(uri, &cost); + } + + if (retval.code != SRCE_ERR_NONE) // get cost from source i failed + { + // cost is invalid at this point, hence skip to next iteration + continue; + } + + // record the cost and i if cost is lower + if (min_cost > cost) + { + min_cost = cost; + min_cost_index = i; + } + } + + if (min_cost == UINT32_MAX) + { + return (arm_uc_error_t){ SOMA_ERR_NO_ROUTE_TO_SOURCE }; + } + + *index = min_cost_index; + return (arm_uc_error_t){ SOMA_ERR_NONE }; +} + +/** + * @brief Find the source of lowest cost and call the correspoding method + * depending on the type of the request. Retry with source of the next + * smallest cost if previous sources failed until the source registry + * is exhausted. + */ +static arm_uc_error_t ARM_UCSM_Get(request_t* req) +{ + UC_SRCE_TRACE("ARM_UCSM_Get"); + uint32_t index = 0; + + // get the source of lowest cost + arm_uc_error_t retval = ARM_UCSM_SourceRegistryGetLowestCost(req->uri, + req->type, + req->excludes, + &index); + if (retval.code != SOMA_ERR_NONE) + { + return retval; + } + + if ((req->uri == NULL) && (req->type == QUERY_TYPE_MANIFEST_DEFAULT)) + { + retval = source_registry[index]->GetManifestDefault(req->buffer, req->offset); + } + else if ((req->uri != NULL) && (req->type == QUERY_TYPE_MANIFEST_URL)) + { + retval = source_registry[index]->GetManifestURL(req->uri, req->buffer, req->offset); + } + else if ((req->uri != NULL) && (req->type == QUERY_TYPE_FRIMWARE)) + { + UC_SRCE_TRACE("calling source %" PRIu32 " GetFirmwareFragment", index); + retval = source_registry[index]->GetFirmwareFragment(req->uri, req->buffer, req->offset); + } + else if ((req->uri != NULL) && (req->type == QUERY_TYPE_KEYTABLE)) + { + retval = source_registry[index]->GetKeytableURL(req->uri, req->buffer); + } + else + { + return (arm_uc_error_t){ SOMA_ERR_INVALID_PARAMETER }; + } + + if (retval.code == SRCE_ERR_BUSY) + { + ARM_UC_PostCallback(&event_cb_storage, ARM_UCSM_AsyncRetryGet, 0); + return (arm_uc_error_t){ SOMA_ERR_NONE }; + } + else if (retval.error != ERR_NONE) + { + // failure, try source with the next smallest cost + UC_SRCE_TRACE("failure, try source with the next smallest cost"); + req->excludes[index] = 1; + return ARM_UCSM_Get(req); + } + + // record the index of source handling the get request currently + req->current_source = index; + UC_SRCE_TRACE("Current Source %" PRIu32, index); + + return (arm_uc_error_t){ SOMA_ERR_NONE }; +} + +/** + * @brief If source is busy ARM_UCSM_AsyncRetryGet is registered with + the event queue so it is called again to retry the same source + */ +static void ARM_UCSM_AsyncRetryGet(uint32_t unused) +{ + (void) unused; + + arm_uc_error_t retval = ARM_UCSM_Get(&request_in_flight); + if (retval.error != ERR_NONE) + { + ARM_UCSM_RequestStructInit(&request_in_flight); + ARM_UC_PostCallback(&event_cb_storage, event_cb, ARM_UC_SM_EVENT_ERROR); + } +} + +/** + * @brief Translate source event into source manager event + */ +static ARM_UC_SM_Event_t ARM_UCSM_TranslateEvent(uint32_t source_event) +{ + ARM_UC_SM_Event_t event = ARM_UC_SM_EVENT_ERROR; + + switch(source_event) + { + case EVENT_NOTIFICATION: + event = ARM_UC_SM_EVENT_NOTIFICATION; + break; + case EVENT_MANIFEST: + event = ARM_UC_SM_EVENT_MANIFEST; + break; + case EVENT_FIRMWARE: + event = ARM_UC_SM_EVENT_FIRMWARE; + break; + case EVENT_KEYTABLE: + event = ARM_UC_SM_EVENT_KEYTABLE; + break; + case EVENT_ERROR: + event = ARM_UC_SM_EVENT_ERROR; + break; + case EVENT_ERROR_BUFFER_SIZE: + event = ARM_UC_SM_EVENT_ERROR_BUFFER_SIZE; + break; + } + + return event; +} + +/** + * @brief Catch callbacks from sources to enable error handling + */ +static void ARM_UCSM_CallbackWrapper(uint32_t source_event) +{ + ARM_UC_SM_Event_t event = ARM_UCSM_TranslateEvent(source_event); + + if (event == ARM_UC_SM_EVENT_ERROR && request_in_flight.type != QUERY_TYPE_UNKNOWN) + { + request_in_flight.excludes[request_in_flight.current_source] = 1; + arm_uc_error_t retval = ARM_UCSM_Get(&request_in_flight); + if (retval.code != SOMA_ERR_NONE) + { + ARM_UCSM_RequestStructInit(&request_in_flight); + ARM_UC_PostCallback(&event_cb_storage, event_cb, event); + } + } + else + { + ARM_UCSM_RequestStructInit(&request_in_flight); + ARM_UC_PostCallback(&event_cb_storage, event_cb, event); + } +} + +/* ==================================================================== * + * Public API * + * ==================================================================== */ + +/* further documentation of the API can be found in source_manager.h */ + +arm_uc_error_t ARM_UCSM_Initialize(ARM_SOURCE_SignalEvent_t callback) +{ + // remember the callback + event_cb = callback; + + // init source_registry to NULL + return ARM_UCSM_SourceRegistryInit(); +} + +arm_uc_error_t ARM_UCSM_AddSource(const ARM_UPDATE_SOURCE* source) +{ + if (ARM_UCSM_GetIndexOfSource(source) != MAX_SOURCES) + { + // Source already added, don't add again + // TODO: should this return SOMA_ERR_NONE or a new error + // SOMA_ERR_ALREADY_PRESENT? + return (arm_uc_error_t){ SOMA_ERR_NONE }; + } + source->Initialize(ARM_UCSM_CallbackWrapper); + return ARM_UCSM_SourceRegistryAdd(source); +} + +arm_uc_error_t ARM_UCSM_RemoveSource(const ARM_UPDATE_SOURCE* source) +{ + arm_uc_error_t err = ARM_UCSM_SourceRegistryRemove(source); + if (err.code == SOMA_ERR_NONE) + { + // Call 'uninitialize' only if the source was found (and removed) + source->Uninitialize(); + } + return err; +} + +/* All the `Get` APIs map into `ARM_UCSM_Get` */ + +arm_uc_error_t ARM_UCSM_GetManifest(arm_uc_buffer_t* buffer, uint32_t offset) +{ + ARM_UCSM_RequestStructInit(&request_in_flight); + request_in_flight.buffer = buffer; + request_in_flight.offset = offset; + request_in_flight.type = QUERY_TYPE_MANIFEST_DEFAULT; + + arm_uc_error_t retval = ARM_UCSM_Get(&request_in_flight); + if (retval.code != SOMA_ERR_NONE) + { + ARM_UCSM_RequestStructInit(&request_in_flight); + } + + return retval; +} + +arm_uc_error_t ARM_UCSM_GetManifestFrom(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer, + uint32_t offset) +{ + ARM_UCSM_RequestStructInit(&request_in_flight); + request_in_flight.uri = uri; + request_in_flight.buffer = buffer; + request_in_flight.offset = offset; + request_in_flight.type = QUERY_TYPE_MANIFEST_URL; + + arm_uc_error_t retval = ARM_UCSM_Get(&request_in_flight); + if (retval.code != SOMA_ERR_NONE) + { + ARM_UCSM_RequestStructInit(&request_in_flight); + } + + return retval; +} + +arm_uc_error_t ARM_UCSM_GetFirmwareFragment(arm_uc_uri_t* uri, + arm_uc_buffer_t* buffer, + uint32_t offset) +{ + UC_SRCE_TRACE("ARM_UCSM_GetFirmwareFragment"); + ARM_UCSM_RequestStructInit(&request_in_flight); + request_in_flight.uri = uri; + request_in_flight.buffer = buffer; + request_in_flight.offset = offset; + request_in_flight.type = QUERY_TYPE_FRIMWARE; + + arm_uc_error_t retval = ARM_UCSM_Get(&request_in_flight); + if (retval.code != SOMA_ERR_NONE) + { + ARM_UCSM_RequestStructInit(&request_in_flight); + } + + return retval; +} + +arm_uc_error_t ARM_UCSM_GetKeytable(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer) +{ + ARM_UCSM_RequestStructInit(&request_in_flight); + request_in_flight.uri = uri; + request_in_flight.buffer = buffer; + request_in_flight.type = QUERY_TYPE_KEYTABLE; + + arm_uc_error_t retval = ARM_UCSM_Get(&request_in_flight); + if (retval.code != SOMA_ERR_NONE) + { + ARM_UCSM_RequestStructInit(&request_in_flight); + } + + return retval; +} + +ARM_UC_SOURCE_MANAGER_t ARM_UC_SourceManager = { + .Initialize = ARM_UCSM_Initialize, + .AddSource = ARM_UCSM_AddSource, + .RemoveSource = ARM_UCSM_RemoveSource, + .GetManifest = ARM_UCSM_GetManifest, + .GetManifestFrom = ARM_UCSM_GetManifestFrom, + .GetFirmwareFragment = ARM_UCSM_GetFirmwareFragment, + .GetKeytable = ARM_UCSM_GetKeytable +};
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-manager/update-client-source-manager/arm_uc_source_manager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source-manager/update-client-source-manager/arm_uc_source_manager.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,145 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_SOURCE_MANAGER_H +#define ARM_UC_SOURCE_MANAGER_H + +#include "update-client-common/arm_uc_common.h" +#include "update-client-source/arm_uc_source.h" + +typedef enum { + ARM_UC_SM_EVENT_NOTIFICATION, + ARM_UC_SM_EVENT_MANIFEST, + ARM_UC_SM_EVENT_FIRMWARE, + ARM_UC_SM_EVENT_KEYTABLE, + ARM_UC_SM_EVENT_ERROR, + ARM_UC_SM_EVENT_ERROR_BUFFER_SIZE +} ARM_UC_SM_Event_t; + +typedef struct _ARM_UC_SOURCE_MANAGER { + + /** + * @brief Initialize module and register event handler. + * @details The event handler is shared among all asynchronous calls. + * + * @param callback Function pointer to event handler. + * @return Error code. + */ + arm_uc_error_t (*Initialize)(ARM_SOURCE_SignalEvent_t event_cb); + + /** + * @brief Add firmware source to manager. + * @details Each source is represented as a pointer to a struct, containing + * function pointers. + * + * For example: + * typedef struct _ARM_UPDATE_SOURCE { + * ARM_DRIVER_VERSION (*GetVersion) (void); + * ARM_SOURC_CAPABILITIES (*GetCapabilities)(void); + * int32_t (*Initialize) (ARM_SOURCE_SignalEvent_t event); + * } ARM_UPDATE_SOURCE; + * + * @param source Collection of function pointers to source. + * @return Error code. + */ + arm_uc_error_t (*AddSource)(const ARM_UPDATE_SOURCE* source); + arm_uc_error_t (*RemoveSource)(const ARM_UPDATE_SOURCE* source); + + /** + * @brief Copy manifest into provided buffer. + * @details Default manifest location is used. An event is generated when the + * manifest has been received. + * + * @param buffer Struct holding a byte array, maximum size, and actual size. + * + * @return Error code. + */ + arm_uc_error_t (*GetManifest)(arm_uc_buffer_t* buffer, uint32_t offset); + + /** + * @brief Copy manifest into provided buffer. + * @details Manifest location is provided. An event is generated when the + * manifest has been received. + * + * @param uri Struct containing the URI to the manifest. + * @param buffer Struct holding a byte array, maximum size, and actual size. + * + * @return Error code. + */ + arm_uc_error_t (*GetManifestFrom)(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer, uint32_t offset); + + /** + * @brief Copy firmware fragment into provided buffer. + * @details Firmware is downloaded one fragment at a time. Each call generates + * an event when the fragment has been received. + * + * @param uri Struct containing the URI to the manifest. + * @param buffer Struct holding a byte array, maximum size, and actual size. + * @param offset Firmware offset in bytes where the next fragment begins. + * @return Error code. + */ + arm_uc_error_t (*GetFirmwareFragment)(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer, uint32_t offset); + + /** + * @brief Retrieve key table and write it into provided buffer. + * @details An event is generated when the manifest has been received. + * + * @param uri Struct containing the URI to the keytable. + * @param buffer Struct holding a byte array, maximum size, and actual size. + * @return Error code. + */ + arm_uc_error_t (*GetKeytable)(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer); + +} ARM_UC_SOURCE_MANAGER_t; + +extern ARM_UC_SOURCE_MANAGER_t ARM_UC_SourceManager; + +/** + * Usage examples + * + * void callback(uint32_t event) + * { + * switch (event) + * { + * // New manifest is available + * case ARM_UC_SM_EVENT_NOTIFICATION: + * break; + * + * // Manifest received from default location + * case ARM_UC_SM_EVENT_MANIFEST: + * break; + * + * // Manifest received from URL + * case ARM_UC_SM_EVENT_FIRMWARE: + * break; + * + * // Firmware fragment received + * case ARM_UC_SM_EVENT_KEYTABLE: + * break; + * } + * } + * + * void main(int) + * { + * // initialize Source Manager with callback handler + * ARM_UC_SourceManager.Initialise(callback); + * } + * + */ + +#endif /* SOURCE_MANAGER_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source/LICENSE --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source/LICENSE Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source/update-client-source/arm_uc_source.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/modules/source/update-client-source/arm_uc_source.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,190 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __ARM_UPDATE_SOURCE_H__ +#define __ARM_UPDATE_SOURCE_H__ + +#include "update-client-common/arm_uc_common.h" + +#include <stdint.h> + +/** + * @brief Struct containing the Source's capabilities. + * @details notify: Source can notify about new manifests. + * manifest_default: Source can download manifest from default location. + * manifest_url: Source can download manifest from URL. + * firmware: Source can download firmware from URL. + */ +typedef struct _ARM_SOURCE_CAPABILITIES { + uint32_t notify: 1; + uint32_t manifest_default: 1; + uint32_t manifest_url: 1; + uint32_t firmware: 1; + uint32_t keytable: 1; + uint32_t reserved: 27; +} ARM_SOURCE_CAPABILITIES; + +/** + * @brief Events passed to event handler. + * @details EVENT_NOTIFICATION: New manifest is available. + * EVENT_MANIFEST: Manifest retrieved. + * EVENT_FIRMWARE: Firmware fragment retrieved. + */ +typedef enum _ARM_SOURCE_EVENT { + EVENT_NOTIFICATION, + EVENT_MANIFEST, + EVENT_FIRMWARE, + EVENT_KEYTABLE, + EVENT_ERROR, + EVENT_ERROR_BUFFER_SIZE +} ARM_SOURCE_EVENT; + +/** + * @brief Prototype for event handler. + */ +typedef void (*ARM_SOURCE_SignalEvent_t)(uint32_t event); + +/** + * @brief Structure definition holding API function pointers. + */ +typedef struct _ARM_UPDATE_SOURCE { + + /** + * @brief Get driver version. + * @return Driver version. + */ + uint32_t (*GetVersion)(void); + + /** + * @brief Get Source capabilities. + * @return Struct containing capabilites. See definition above. + */ + ARM_SOURCE_CAPABILITIES (*GetCapabilities)(void); + + /** + * @brief Initialize Source. + * @details Function pointer to event handler is passed as argument. + * + * @param cb_event Function pointer to event handler. See events above. + * @return Error code. + */ + arm_uc_error_t (*Initialize)(ARM_SOURCE_SignalEvent_t cb_event); + + /** + * @brief Uninitialized Source. + * @return Error code. + */ + arm_uc_error_t (*Uninitialize)(void); + + /** + * @brief Cost estimation for retrieving manifest from the default location. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param cost Pointer to variable for the return value. + * @return Error code. + */ + arm_uc_error_t (*GetManifestDefaultCost)(uint32_t* cost); + + /** + * @brief Cost estimation for retrieving manifest from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The manifest is already downloaded. + * 0xFFFFFFFF - Cannot retrieve manifest from this Source. + * + * @param uri URI struct with manifest location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ + arm_uc_error_t (*GetManifestURLCost)(arm_uc_uri_t* uri, uint32_t* cost); + + /** + * @brief Cost estimation for retrieving firmware from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with firmware location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ + arm_uc_error_t (*GetFirmwareURLCost)(arm_uc_uri_t* uri, uint32_t* cost); + + /** + * @brief Cost estimation for retrieving key table from URL. + * @details The estimation can vary over time and should not be cached too long. + * 0x00000000 - The firmware is already downloaded. + * 0xFFFFFFFF - Cannot retrieve firmware from this Source. + * + * @param uri URI struct with keytable location. + * @param cost Pointer to variable for the return value. + * @return Error code. + */ + arm_uc_error_t (*GetKeytableURLCost)(arm_uc_uri_t* uri, uint32_t* cost); + + /** + * @brief Retrieve manifest from the default location. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Manifest offset in bytes where the requested fragment begins. + * @return Error code. + */ + arm_uc_error_t (*GetManifestDefault)(arm_uc_buffer_t* buffer, uint32_t offset); + + /** + * @brief Retrieve manifest from URL. + * @details Manifest is stored in supplied buffer. + * Event is generated once manifest is in buffer. + * + * @param uri URI struct with manifest location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Manifest offset in bytes where the requested fragment begins. + * + * @return Error code. + */ + arm_uc_error_t (*GetManifestURL)(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer, uint32_t offset); + + /** + * @brief Retrieve firmware fragment. + * @details Firmware fragment is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with firmware location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @param offset Firmware offset to retrieve fragment from. + * @return Error code. + */ + arm_uc_error_t (*GetFirmwareFragment)(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer, uint32_t offset); + + /** + * @brief Retrieve a key table from a URL. + * @details Key table is stored in supplied buffer. + * Event is generated once fragment is in buffer. + * + * @param uri URI struct with keytable location. + * @param buffer Struct containing byte array, maximum size, and actual size. + * @return Error code. + */ + arm_uc_error_t (*GetKeytableURL)(arm_uc_uri_t* uri, arm_uc_buffer_t* buffer); + +} ARM_UPDATE_SOURCE; + +#endif /* __ARM_UPDATE_SOURCE_H__ */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,416 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-hub/update_client_hub.h" + +#include "update-client-common/arm_uc_common.h" +#include "update-client-control-center/arm_uc_control_center.h" +#include "update-client-control-center/arm_uc_pre_shared_key.h" +#include "update-client-control-center/arm_uc_certificate.h" +#include "update-client-source-manager/arm_uc_source_manager.h" +#include "update-client-firmware-manager/arm_uc_firmware_manager.h" +#include "update-client-manifest-manager/update-client-manifest-manager.h" + +#include "update_client_hub_state_machine.h" +#include "update_client_hub_event_handlers.h" +#include "update_client_hub_error_handler.h" + +#include "pal4life-device-identity/pal_device_identity.h" + +#define HANDLE_INIT_ERROR(retval, msg, ...)\ + if (retval.error != ERR_NONE)\ + {\ + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_UNINITIALIZED);\ + UC_HUB_ERR_MSG(msg " error code %s", ##__VA_ARGS__, ARM_UC_err2Str(retval));\ + return retval;\ + } + +static const ARM_UPDATE_SOURCE** arm_uc_sources = NULL; +static uint8_t arm_uc_sources_size = 0; + +static arm_uc_mmContext_t manifestManagerInitContext = { 0 }; +static arm_uc_mmContext_t* pManifestManagerInitContext = &manifestManagerInitContext; + +/** + * @brief Call initialiser of all components of the client. + * finish asynchronously, will invoke callback when + * initialisation is done. + * @param init_cb the callback to be invoked at the end of initilastion. + */ +arm_uc_error_t ARM_UC_HUB_Initialize(void (*init_cb)(int32_t)) +{ + arm_uc_error_t retval; + + if (ARM_UC_HUB_getState() != ARM_UC_HUB_STATE_UNINITIALIZED) + { + UC_HUB_ERR_MSG("Already Initialized"); + return (arm_uc_error_t){ ERR_INVALID_PARAMETER }; + } + + ARM_UC_HUB_setInitializationCallback(init_cb); + + /* Register event handler with Control Center. */ + retval = ARM_UC_ControlCenter_Initialize(ARM_UC_HUB_ControlCenterEventHandler); + HANDLE_INIT_ERROR(retval, "Control Center init failed") + + /* Register event handler with Firmware Manager */ + retval = ARM_UC_FirmwareManager.Initialize(ARM_UC_HUB_FirmwareManagerEventHandler); + HANDLE_INIT_ERROR(retval, "Firmware Manager init failed") + + /* Register event handler with Source Manager */ + retval = ARM_UC_SourceManager.Initialize(ARM_UC_HUB_SourceManagerEventHandler); + HANDLE_INIT_ERROR(retval, "Source Manager init failed") + + for (uint8_t index = 0; index < arm_uc_sources_size; index++) + { + ARM_UC_SourceManager.AddSource(arm_uc_sources[index]); + } + + /* Register event handler and add config store implementation to manifest + manager. + */ + retval = ARM_UC_mmInit(&pManifestManagerInitContext, + ARM_UC_HUB_ManifestManagerEventHandler, + NULL); + HANDLE_INIT_ERROR(retval, "Manifest manager init failed") + + /* add hard coded certificates to the manifest manager */ + // retval = ARM_UC_mmStoreCertificate(CA_PATH, cert, CERT_SIZE); + // if ((retval.error != ERR_NONE) && (retval.code != MFST_ERR_PENDING)) + // { + // HANDLE_INIT_ERROR(retval, "Manifest manager StoreCertificate failed") + // } + + return (arm_uc_error_t){ ERR_NONE }; +} + +/** + * @brief Process events in the event queue. + */ +arm_uc_error_t ARM_UC_HUB_ProcessEvents() +{ + ARM_UC_ProcessQueue(); + + return (arm_uc_error_t){ ERR_NONE }; +} + +/** + * @brief Register callback function for when callbacks are added to an empty queue. + */ +arm_uc_error_t ARM_UC_HUB_AddNotificationHandler(void (*handler)(void)) +{ + ARM_UC_AddNotificationHandler(handler); + + return (arm_uc_error_t){ ERR_NONE }; +} + +/** + * @brief Add source to the Update Client. + */ +arm_uc_error_t ARM_UC_HUB_SetSources(const ARM_UPDATE_SOURCE* sources[], + uint8_t size) +{ + arm_uc_sources = sources; + arm_uc_sources_size = size; + + return (arm_uc_error_t){ ERR_NONE }; +} + +/** + * Set PAAL Update implementation + */ +arm_uc_error_t ARM_UC_HUB_SetStorage(const ARM_UC_PAAL_UPDATE* implementation) +{ + return ARM_UCP_SetPAALUpdate(implementation); +} + +/** + * @brief Add monitor to the control center. + */ +arm_uc_error_t ARM_UC_HUB_AddMonitor(const ARM_UPDATE_MONITOR* monitor) +{ + return ARM_UC_ControlCenter_AddMonitor(monitor); +} + +/** + * @brief Temporary error reporting function. + */ +void ARM_UC_HUB_AddErrorCallback(void (*callback)(int32_t error)) +{ + ARM_UC_HUB_AddErrorCallbackInternal(callback); +} + +/** + * @brief Authorize request. + */ +arm_uc_error_t ARM_UC_Authorize(arm_uc_request_t request) +{ + return ARM_UC_ControlCenter_Authorize(request); +} + +/** + * @brief Set callback for receiving download progress. + * @details User application call for setting callback handler. + * The callback function takes the progreess in percent as argument. + * + * @param callback Function pointer to the progress function. + * @return Error code. + */ +arm_uc_error_t ARM_UC_SetProgressHandler(void (*callback)(uint32_t progress, uint32_t total)) +{ + return ARM_UC_ControlCenter_SetProgressHandler(callback); +} + +/** + * @brief Set callback function for authorizing requests. + * @details User application call for setting callback handler. + * The callback function takes an enum request and an authorization + * function pointer. To authorize the given request, the caller + * invokes the authorization function. + * + * @param callback Function pointer to the authorization function. + * @return Error code. + */ +arm_uc_error_t ARM_UC_SetAuthorizeHandler(void (*callback)(int32_t)) +{ + return ARM_UC_ControlCenter_SetAuthorityHandler(callback); +} + +/** + * @brief Override update authorization handler. + * @details Force download and update to progress regardless of authorization + * handler. This function is used for unblocking an update in a buggy + * application. + */ +void ARM_UC_OverrideAuthorization(void) +{ + ARM_UC_ControlCenter_OverrideAuthorization(); +} + +/** + * @brief Add certificate. + * @details [long description] + * + * @param certificate Pointer to certiface being added. + * @param certificate_length Certificate length. + * @param fingerprint Pointer to the fingerprint of the certificate being added. + * @param fingerprint_length Fingerprint length. + * @return Error code. + */ +arm_uc_error_t ARM_UC_AddCertificate(const uint8_t* certificate, + uint16_t certificate_length, + const uint8_t* fingerprint, + uint16_t fingerprint_length, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*)) +{ + return ARM_UC_Certificate_Add(certificate, + certificate_length, + fingerprint, + fingerprint_length, + callback); +} + +/** + * @brief Set pointer to pre-shared-key with the given size. + * + * @param key Pointer to pre-shared-key. + * @param bits Key size in bits. + * + * @return Error code. + */ +arm_uc_error_t ARM_UC_AddPreSharedKey(const uint8_t* key, uint16_t bits) +{ + return ARM_UC_PreSharedKey_SetKey(key, bits); +} + +/** + * @brief Function for setting the vendor ID. + * @details The ID is copied to a 16 byte struct. Any data after the first + * 16 bytes will be ignored. + * @param id Pointer to ID. + * @param length Length of ID. + * @return Error code. + */ +arm_uc_error_t ARM_UC_SetVendorId(const uint8_t* id, uint8_t length) +{ + arm_uc_guid_t uuid = { 0 }; + + if (id) + { + for (uint8_t index = 0; + (index < sizeof(arm_uc_guid_t) && (index < length)); + index++) + { + ((uint8_t*) uuid)[index] = id[index]; + } + } + + return pal_setVendorGuid(&uuid); +} + +/** + * @brief Function for setting the class ID. + * @details The ID is copied to a 16 byte struct. Any data after the first + * 16 bytes will be ignored. + * @param id Pointer to ID. + * @param length Length of ID. + * @return Error code. + */ +arm_uc_error_t ARM_UC_SetClassId(const uint8_t* id, uint8_t length) +{ + arm_uc_guid_t uuid = { 0 }; + + if (id) + { + for (uint8_t index = 0; + (index < sizeof(arm_uc_guid_t) && (index < length)); + index++) + { + ((uint8_t*) uuid)[index] = id[index]; + } + } + + return pal_setClassGuid(&uuid); +} + +/** + * @brief Function for setting the device ID. + * @details The ID is copied to a 16 byte struct. Any data after the first + * 16 bytes will be ignored. + * @param id Pointer to ID. + * @param length Length of ID. + * @return Error code. + */ +arm_uc_error_t ARM_UC_SetDeviceId(const uint8_t* id, uint8_t length) +{ + arm_uc_guid_t uuid = { 0 }; + + if (id) + { + for (uint8_t index = 0; + (index < sizeof(arm_uc_guid_t) && (index < length)); + index++) + { + ((uint8_t*) uuid)[index] = id[index]; + } + } + + return pal_setDeviceGuid(&uuid); +} + +/** + * @brief Function for reporting the vendor ID. + * @details 16 bytes are copied into the supplied buffer. + * @param id Pointer to storage for ID. MUST be at least 16 bytes long. + * @param id_max the size of the ID buffer + * @param id_size pointer to a variable to receive the size of the ID + * written into the buffer (always 16). + * @return Error code. + */ +arm_uc_error_t ARM_UC_GetVendorId(uint8_t* id, + const size_t id_max, + size_t* id_size) +{ + arm_uc_guid_t guid = {0}; + arm_uc_error_t err = {ERR_NONE}; + if (id_max < sizeof(arm_uc_guid_t)) + { + err.code = ARM_UC_DI_ERR_SIZE; + } + if (err.error == ERR_NONE) + { + err = pal_getVendorGuid(&guid); + } + if (err.error == ERR_NONE) + { + memcpy(id, guid, sizeof(arm_uc_guid_t)); + if (id_size != NULL) + { + *id_size = sizeof(arm_uc_guid_t); + } + } + return err; +} + +/** + * @brief Function for reporting the class ID. + * @details 16 bytes are copied into the supplied buffer. + * @param id Pointer to storage for ID. MUST be at least 16 bytes long. + * @param id_max the size of the ID buffer + * @param id_size pointer to a variable to receive the size of the ID + * written into the buffer (always 16). + * @return Error code. + */ +arm_uc_error_t ARM_UC_GetClassId(uint8_t* id, + const size_t id_max, + size_t* id_size) +{ + arm_uc_guid_t guid = {0}; + arm_uc_error_t err = {ERR_NONE}; + if (id_max < sizeof(arm_uc_guid_t)) + { + err.code = ARM_UC_DI_ERR_SIZE; + } + if (err.error == ERR_NONE) + { + err = pal_getClassGuid(&guid); + } + if (err.error == ERR_NONE) + { + memcpy(id, guid, sizeof(arm_uc_guid_t)); + if (id_size != NULL) + { + *id_size = sizeof(arm_uc_guid_t); + } + } + return err; +} + +/** + * @brief Function for reporting the device ID. + * @details 16 bytes are copied into the supplied buffer. + * @param id Pointer to storage for ID. MUST be at least 16 bytes long. + * @param id_max the size of the ID buffer + * @param id_size pointer to a variable to receive the size of the ID + * written into the buffer (always 16). + * @return Error code. + */ +arm_uc_error_t ARM_UC_GetDeviceId(uint8_t* id, + const size_t id_max, + size_t* id_size) +{ + arm_uc_guid_t guid = {0}; + arm_uc_error_t err = {ERR_NONE}; + if (id_max < sizeof(arm_uc_guid_t)) + { + err.code = ARM_UC_DI_ERR_SIZE; + } + if (err.error == ERR_NONE) + { + err = pal_getDeviceGuid(&guid); + } + if (err.error == ERR_NONE) + { + memcpy(id, guid, sizeof(arm_uc_guid_t)); + if (id_size != NULL) + { + *id_size = sizeof(arm_uc_guid_t); + } + } + return err; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_error_handler.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_error_handler.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,170 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update_client_hub_error_handler.h" + +#include "update-client-control-center/arm_uc_control_center.h" +#include "update-client-common/arm_uc_common.h" + +static void (*arm_uc_error_callback_handler)(int32_t error) = NULL; + +void ARM_UC_HUB_AddErrorCallbackInternal(void (*callback)(int32_t error)) +{ + arm_uc_error_callback_handler = callback; +} + +/** + * @brief Error handler. + * @details Generates error code for the user application and any registered + * monitors. Also responsible for setting the Hub back to a consistent + * state. + * + * Supported error codes: + * + * ARM_UC_MONITOR_RESULT_INITIAL + * ARM_UC_MONITOR_RESULT_SUCCESS + * ARM_UC_MONITOR_RESULT_ERROR_STORAGE + * ARM_UC_MONITOR_RESULT_ERROR_MEMORY + * ARM_UC_MONITOR_RESULT_ERROR_CONNECTION + * ARM_UC_MONITOR_RESULT_ERROR_CRC + * ARM_UC_MONITOR_RESULT_ERROR_TYPE + * ARM_UC_MONITOR_RESULT_ERROR_URI + * ARM_UC_MONITOR_RESULT_ERROR_UPDATE + * ARM_UC_MONITOR_RESULT_ERROR_HASH + * + * @param error arm_uc_error_t code. + * @param state Internal Hub state. + */ +void ARM_UC_HUB_ErrorHandler(int32_t error, arm_uc_hub_state_t state) +{ + UC_HUB_TRACE("error: %" PRIX32 " %d", (uint32_t) error, state); + + int32_t error_external = ARM_UC_WARNING_UNKNOWN; + arm_uc_monitor_result_t error_monitor = ARM_UC_MONITOR_RESULT_INITIAL; + + switch (error) + { + /* Certificate Manager */ + case ARM_UC_CM_ERR_NOT_FOUND: + UC_HUB_ERR_MSG("ARM_UC_CM_ERR_NOT_FOUND: %" PRIX32, + (uint32_t) ARM_UC_CM_ERR_NOT_FOUND); + error_external = ARM_UC_WARNING_CERTIFICATE_NOT_FOUND; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_TYPE; + break; + + /* Firmware Manager */ + case FIRM_ERR_WRITE: + UC_HUB_ERR_MSG("FIRM_ERR_WRITE: %" PRIX32, + (uint32_t) FIRM_ERR_WRITE); + error_external = ARM_UC_ERROR_WRITE_TO_STORAGE; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_STORAGE; + break; + + case FIRM_ERR_INVALID_PARAMETER: + UC_HUB_ERR_MSG("FIRM_ERR_INVALID_PARAMETER: %" PRIX32, + (uint32_t) FIRM_ERR_INVALID_PARAMETER); + error_external = ARM_UC_ERROR_WRITE_TO_STORAGE; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_STORAGE; + break; + + case FIRM_ERR_INVALID_HASH: + UC_HUB_ERR_MSG("FIRM_ERR_INVALID_HASH: %" PRIX32, + (uint32_t) FIRM_ERR_INVALID_HASH); + error_external = ARM_UC_ERROR_INVALID_HASH; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_HASH; + break; + + /* Manifest Manager */ + case MFST_ERR_NULL_PTR: + UC_HUB_ERR_MSG("MFST_ERR_NULL_PTR: %" PRIX32, + (uint32_t) MFST_ERR_NULL_PTR); + error_external = ARM_UC_WARNING_IDENTITY_NOT_FOUND; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_TYPE; + break; + + case MFST_ERR_GUID_VENDOR: + UC_HUB_ERR_MSG("MFST_ERR_GUID_VENDOR: %" PRIX32, + (uint32_t) MFST_ERR_GUID_VENDOR); + error_external = ARM_UC_WARNING_VENDOR_MISMATCH; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_TYPE; + break; + + case MFST_ERR_GUID_DEVCLASS: + UC_HUB_ERR_MSG("MFST_ERR_GUID_DEVCLASS: %" PRIX32, + (uint32_t) MFST_ERR_GUID_DEVCLASS); + error_external = ARM_UC_WARNING_CLASS_MISMATCH; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_TYPE; + break; + + case MFST_ERR_GUID_DEVICE: + UC_HUB_ERR_MSG("MFST_ERR_GUID_DEVICE: %" PRIX32, + (uint32_t) MFST_ERR_GUID_DEVICE); + error_external = ARM_UC_WARNING_DEVICE_MISMATCH; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_TYPE; + break; + + case MFST_ERR_CERT_INVALID: + UC_HUB_ERR_MSG("MFST_ERR_CERT_INVALID: %" PRIX32, + (uint32_t) MFST_ERR_CERT_INVALID); + error_external = ARM_UC_WARNING_CERTIFICATE_INVALID; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_TYPE; + break; + + case MFST_ERR_INVALID_SIGNATURE: + UC_HUB_ERR_MSG("MFST_ERR_INVALID_SIGNATURE: %" PRIX32, + (uint32_t) MFST_ERR_INVALID_SIGNATURE); + error_external = ARM_UC_WARNING_SIGNATURE_INVALID; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_TYPE; + break; + + /* Source Manager */ + case SOMA_ERR_INVALID_PARAMETER: + UC_HUB_ERR_MSG("SOMA_ERR_INVALID_PARAMETER: %" PRIX32, + (uint32_t) SOMA_ERR_INVALID_PARAMETER); + error_external = ARM_UC_WARNING_URI_NOT_FOUND; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_URI; + break; + + /* Hub */ + case HUB_ERR_ROLLBACK_PROTECTION: + UC_HUB_ERR_MSG("HUB_ERR_ROLLBACK_PROTECTION: %" PRIX32, + (uint32_t) HUB_ERR_ROLLBACK_PROTECTION); + error_external = ARM_UC_WARNING_ROLLBACK_PROTECTION; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_TYPE; + break; + + default: + UC_HUB_ERR_MSG("Unknown error"); + error_external = ARM_UC_WARNING_UNKNOWN; + error_monitor = ARM_UC_MONITOR_RESULT_ERROR_TYPE; + break; + } + + /* send external code to user application */ + if (arm_uc_error_callback_handler) + { + arm_uc_error_callback_handler(error_external); + } + + /* send error code to monitor */ + ARM_UC_ControlCenter_ReportUpdateResult(error_monitor); + + /* progress state in hub */ + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_ERROR_UNKNOWN); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_error_handler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_error_handler.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,30 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_HUB_ERROR_HANDLER_H +#define ARM_UC_HUB_ERROR_HANDLER_H + +#include "update_client_hub_state_machine.h" + +#include "update-client-common/arm_uc_common.h" + +void ARM_UC_HUB_AddErrorCallbackInternal(void (*callback)(int32_t error)); + +void ARM_UC_HUB_ErrorHandler(int32_t error, arm_uc_hub_state_t state); + +#endif // ARM_UC_HUB_ERROR_HANDLER_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_event_handlers.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_event_handlers.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,464 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update_client_hub_event_handlers.h" +#include "update_client_hub_error_handler.h" + +#include "update_client_hub_state_machine.h" + +#include "update-client-common/arm_uc_common.h" +#include "update-client-firmware-manager/arm_uc_firmware_manager.h" +#include "update-client-manifest-manager/update-client-manifest-manager.h" +#include "update-client-source-manager/arm_uc_source_manager.h" +#include "update-client-control-center/arm_uc_control_center.h" + +/** + * @brief event handler registered with the firmware manager + * events drive state changes of the state machine + */ +void ARM_UC_HUB_FirmwareManagerEventHandler(uint32_t event) +{ + arm_uc_hub_state_t arm_uc_hub_state = ARM_UC_HUB_getState(); + + switch(event) + { + /* Firmware writing setup complete */ + case UCFM_EVENT_PREPARE_DONE: + UC_HUB_TRACE("UCFM_EVENT_PREPARE_DONE"); + + /* Storage prepared for firmware. Download first fragment. */ + if (arm_uc_hub_state == ARM_UC_HUB_STATE_SETUP_FIRMWARE) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT); + } + else + { + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_INVALID_PARAMETER, arm_uc_hub_state); + } + break; + + /* Firmware fragment written */ + case UCFM_EVENT_WRITE_DONE: + UC_HUB_TRACE("UCFM_EVENT_WRITE_DONE"); + + /* Firmware fragment stored */ + + /* Fragment stored before network could finish, + i.e., network is the bottleneck: + Action: + - wait for network to complete + */ + if (arm_uc_hub_state == ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_WAIT_FOR_NETWORK); + } + /* Fragment stored after network finished, + i.e, storage is the bottleneck: + Action: + - store fragment + - download next fragment + */ + else if (arm_uc_hub_state == ARM_UC_HUB_STATE_WAIT_FOR_STORAGE) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD); + } + /* Last fragment stored. + Action: + - finalize storage + */ + else if (arm_uc_hub_state == ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_FINALIZE_STORAGE); + } + else + { + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_INVALID_PARAMETER, arm_uc_hub_state); + } + break; + + /* Final firmware fragment written and commited */ + case UCFM_EVENT_FINALIZE_DONE: + UC_HUB_TRACE("UCFM_EVENT_FINALIZE_DONE"); + + /* Firmware stored and verified. */ + if (arm_uc_hub_state == ARM_UC_HUB_STATE_FINALIZE_STORAGE) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_STORAGE_FINALIZED); + } + else + { + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_INVALID_PARAMETER, arm_uc_hub_state); + } + break; + + /* Firmware image marked as active or installed */ + case UCFM_EVENT_ACTIVATE_DONE: + UC_HUB_TRACE("UCFM_EVENT_ACTIVATE_DONE"); + + /* Firmware activated. Reboot system. */ + if (arm_uc_hub_state == ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_REBOOT); + } + else + { + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_INVALID_PARAMETER, arm_uc_hub_state); + } + break; + + case UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE: + UC_HUB_TRACE("UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE"); + + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_REPORT_ACTIVE_HASH); + break; + + case UCFM_EVENT_GET_INSTALLER_DETAILS_DONE: + UC_HUB_TRACE("UCFM_EVENT_GET_INSTALLER_DETAILS_DONE"); + + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_REPORT_INSTALLER_DETAILS); + break; + + /* Encountered error while writing firmware */ + case UCFM_EVENT_WRITE_ERROR: + UC_HUB_TRACE("UCFM_EVENT_WRITE_ERROR"); + + if ((arm_uc_hub_state == ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD) || + (arm_uc_hub_state == ARM_UC_HUB_STATE_WAIT_FOR_STORAGE) || + (arm_uc_hub_state == ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT)) + { + /* write error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_WRITE, arm_uc_hub_state); + } + else + { + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_INVALID_PARAMETER, arm_uc_hub_state); + } + break; + + /* Encountered error while committing final firmware fragment */ + case UCFM_EVENT_FINALIZE_ERROR: + UC_HUB_TRACE("UCFM_EVENT_FINALIZE_ERROR"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_INVALID_PARAMETER, arm_uc_hub_state); + break; + + + /* Got an unexpected hash of the firmare image */ + case UCFM_EVENT_FINALIZE_INVALID_HASH_ERROR: + UC_HUB_TRACE("UCFM_EVENT_FINALIZE_INVALID_HASH_ERROR"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_INVALID_HASH, arm_uc_hub_state); + break; + + /* Encountered error while trying to activate or install firmware image */ + case UCFM_EVENT_ACTIVATE_ERROR: + UC_HUB_TRACE("UCFM_EVENT_ACTIVATE_ERROR"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_ACTIVATE, arm_uc_hub_state); + break; + + case UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR: + /* client should be able to proceed as normal */ + UC_HUB_TRACE("UCFM_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR"); + + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS); + break; + + case UCFM_EVENT_GET_INSTALLER_DETAILS_ERROR: + /* client should be able to proceed as normal */ + UC_HUB_TRACE("UCFM_EVENT_GET_INSTALLER_DETAILS_ERROR"); + + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_IDLE); + break; + + case UCFM_EVENT_INITIALIZE_DONE: + /* TODO Fix whole call chain to support async init */ + /* swallow async init done event here */ + UC_HUB_TRACE("UCFM_EVENT_INITIALIZE_DONE"); + break; + + case UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE: + UC_HUB_TRACE("UCFM_EVENT_GET_FIRMWARE_DETAILS_DONE"); + break; + + case UCFM_EVENT_INITIALIZE_ERROR: + UC_HUB_TRACE("UCFM_EVENT_INITIALIZE_ERROR"); + break; + + case UCFM_EVENT_PREPARE_ERROR: + UC_HUB_TRACE("UCFM_EVENT_PREPARE_ERROR"); + break; + + case UCFM_EVENT_GET_FIRMWARE_DETAILS_ERROR: + UC_HUB_TRACE("UCFM_EVENT_GET_FIRMWARE_DETAILS_ERROR"); + break; + + default: + UC_HUB_TRACE("Firmware Manager: Invalid Event: %" PRIu32, event); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(FIRM_ERR_INVALID_PARAMETER, arm_uc_hub_state); + break; + } +} + +/** + * @brief event handler registered with the manifest manager + * events drive state changes of the state machine + */ +void ARM_UC_HUB_ManifestManagerEventHandler(uint32_t event) +{ + arm_uc_hub_state_t arm_uc_hub_state = ARM_UC_HUB_getState(); + + if (event == ARM_UC_MM_RC_ERROR && arm_uc_hub_state == ARM_UC_HUB_STATE_UNINITIALIZED) + { + // TODO: An empty config store may be an error in the future. + if (ARM_UC_mmGetError().code == MFST_ERR_NO_MANIFEST) + { + event = ARM_UC_MM_RC_DONE; + } + } + switch(event) + { + /* Status: The manifest manager failed during the previous operation. + Extract further error information using ARM_UC_mmGetError. + */ + case ARM_UC_MM_RC_ERROR: + UC_HUB_TRACE("ARM_UC_MM_RC_ERROR"); + + /* Report error. */ + ARM_UC_HUB_ErrorHandler(ARM_UC_mmGetError().code, arm_uc_hub_state); + break; + + /* Unused */ + case ARM_UC_MM_RC_NONE: + UC_HUB_TRACE("ARM_UC_MM_RC_NONE"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(MFST_ERR_INVALID_STATE, arm_uc_hub_state); + break; + + /* Action: The firmware manager needs the manifest specified by + ARM_UC_mmGetCurrentManifestDependency in order to keep processing + the firmware update. + */ + case ARM_UC_MM_RC_NEED_DEP: + UC_HUB_TRACE("ARM_UC_MM_RC_NEED_DEP"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(MFST_ERR_NO_MANIFEST, arm_uc_hub_state); + break; + + /* Action: The firmware manager needs the firmware specified by + ARM_UC_mmGetFirmwareInfo in order to keep processing the firmware + update. + */ + case ARM_UC_MM_RC_NEED_FW: + UC_HUB_TRACE("ARM_UC_MM_RC_NEED_FW"); + + /* Download firmware by first reading information from manifest */ + if(arm_uc_hub_state == ARM_UC_HUB_STATE_MANIFEST_COMPLETE) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_CHECK_VERSION); + } + else + { + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(MFST_ERR_INVALID_STATE, arm_uc_hub_state); + } + break; + + /* Status: The last operation completed successfully */ + case ARM_UC_MM_RC_DONE: + UC_HUB_TRACE("ARM_UC_MM_RC_DONE"); + + /* Update Hub has been initialized. */ + if(arm_uc_hub_state == ARM_UC_HUB_STATE_UNINITIALIZED) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_INITIALIZED); + } + /* Manifest processed */ + else if(arm_uc_hub_state == ARM_UC_HUB_STATE_MANIFEST_FETCHED) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_MANIFEST_COMPLETE); + } + else + { + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(MFST_ERR_INVALID_STATE, arm_uc_hub_state); + } + break; + + default: + UC_HUB_TRACE("Manifest Manager: Invalid Event"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(MFST_ERR_BAD_EVENT, arm_uc_hub_state); + break; + } +} + +/** + * @brief event handler registered with the source manager + * events drive state changes of the state machine + */ +void ARM_UC_HUB_SourceManagerEventHandler(uint32_t event) +{ + arm_uc_hub_state_t arm_uc_hub_state = ARM_UC_HUB_getState(); + + switch(event) + { + /* Received notification */ + case ARM_UC_SM_EVENT_NOTIFICATION: + UC_HUB_TRACE("ARM_UC_SM_EVENT_NOTIFICATION"); + + /* Fetch manifest */ + if(arm_uc_hub_state == ARM_UC_HUB_STATE_IDLE) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_NOTIFIED); + } + /* No else. All notifications are ignored during an ongoing update. */ + break; + + /* Downloaded manifest */ + case ARM_UC_SM_EVENT_MANIFEST: + UC_HUB_TRACE("ARM_UC_SM_EVENT_MANIFEST"); + + /* Process the newly downloaded manifest */ + if (arm_uc_hub_state == ARM_UC_HUB_STATE_NOTIFIED) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_MANIFEST_FETCHED); + } + else + { + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(SOMA_ERR_INVALID_PARAMETER, arm_uc_hub_state); + } + break; + + /* Downloaded firmware fragment */ + case ARM_UC_SM_EVENT_FIRMWARE: + UC_HUB_TRACE("ARM_UC_SM_EVENT_FIRMWARE"); + + /* Received firmware fragment */ + + /* 1. First fragment received, source and storage idle, or, + 2. N fragment received after storage went idle. + Action: + - store fragment + - download next fragment + */ + if ((arm_uc_hub_state == ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT) || + (arm_uc_hub_state == ARM_UC_HUB_STATE_WAIT_FOR_NETWORK)) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD); + } + /* 1. N fragment received, storing still in progress, + i.e., the storage is the bottleneck: + - All buffers are in use, wait for storage + */ + else if (arm_uc_hub_state == ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_WAIT_FOR_STORAGE); + } + /* Invalid state, abort and report error. */ + else + { + ARM_UC_HUB_ErrorHandler(SOMA_ERR_INVALID_PARAMETER, arm_uc_hub_state); + } + break; + + /* Downloaded keytable */ + case ARM_UC_SM_EVENT_KEYTABLE: + UC_HUB_TRACE("ARM_UC_SM_EVENT_KEYTABLE"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(SOMA_ERR_INVALID_PARAMETER, arm_uc_hub_state); + break; + + /* Source Manager encountered an error */ + case ARM_UC_SM_EVENT_ERROR: + UC_HUB_TRACE("ARM_UC_SM_EVENT_ERROR"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(SOMA_ERR_INVALID_PARAMETER, arm_uc_hub_state); + break; + + default: + UC_HUB_TRACE("Source Manager: Invalid Event"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(SOMA_ERR_INVALID_PARAMETER, arm_uc_hub_state); + break; + } +} + +void ARM_UC_HUB_ControlCenterEventHandler(uint32_t event) +{ + arm_uc_hub_state_t arm_uc_hub_state = ARM_UC_HUB_getState(); + + switch(event) + { + case ARM_UCCC_EVENT_AUTHORIZE_DOWNLOAD: + UC_HUB_TRACE("ARM_UCCC_EVENT_AUTHORIZE_DOWNLOAD"); + + if (arm_uc_hub_state == ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION) + { + /* Download approved. Download firmware. */ + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_DOWNLOAD_AUTHORIZED); + } + break; + + case ARM_UCCC_EVENT_AUTHORIZE_INSTALL: + UC_HUB_TRACE("ARM_UCCC_EVENT_AUTHORIZE_INSTALL"); + + if (arm_uc_hub_state == ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION) + { + /* Installation approved. Set firmware as active image and reboot. */ + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_INSTALL_AUTHORIZED); + } + break; + + case ARM_UCCC_EVENT_MONITOR_SEND_DONE: + UC_HUB_TRACE("ARM_UCCC_EVENT_MONITOR_SEND_DONE"); + +/* TODO: use timeout to ensure callback doesn't stall reboot */ +#if 0 + if (arm_uc_hub_state == ARM_UC_HUB_STATE_INSTALL_AUTHORIZED) + { + ARM_UC_HUB_setState(ARM_UC_HUB_STATE_REBOOT); + } +#endif + break; + + default: + UC_HUB_TRACE("Control Center: Invalid Event"); + + /* Invalid state, abort and report error. */ + ARM_UC_HUB_ErrorHandler(ERR_INVALID_PARAMETER, arm_uc_hub_state); + break; + } +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_event_handlers.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_event_handlers.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,52 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_HUB_EVENT_HANDLERS_H +#define ARM_UC_HUB_EVENT_HANDLERS_H + +#include <stdint.h> + +/** + * @brief Event handler for the Firmware Manager. + * + * @param event Event ID. + */ +void ARM_UC_HUB_FirmwareManagerEventHandler(uint32_t event); + +/** + * @brief Event handler for the Manifest Manager. + * + * @param event Event ID. + */ +void ARM_UC_HUB_ManifestManagerEventHandler(uint32_t event); + +/** + * @brief Event handler for the Source Manager. + * + * @param event Event ID. + */ +void ARM_UC_HUB_SourceManagerEventHandler(uint32_t event); + +/** + * @brief Event handler for the Control Center. + * + * @param event Event ID. + */ +void ARM_UC_HUB_ControlCenterEventHandler(uint32_t event); + +#endif // ARM_UC_HUB_EVENT_HANDLERS_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_state_machine.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_state_machine.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,757 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update_client_hub_state_machine.h" +#include "update_client_hub_error_handler.h" +#include "update-client-hub/update_client_hub.h" + +#include "update-client-common/arm_uc_common.h" +#include "update-client-firmware-manager/arm_uc_firmware_manager.h" +#include "update-client-manifest-manager/update-client-manifest-manager.h" +#include "update-client-source-manager/arm_uc_source_manager.h" +#include "update-client-control-center/arm_uc_control_center.h" +#include "update-client-control-center/arm_uc_pre_shared_key.h" + +#include "mbedtls/aes.h" + +#include "pal.h" + +#include <inttypes.h> + +/*****************************************************************************/ +/* Global variables */ +/*****************************************************************************/ + +// state of the hub state machine +static arm_uc_hub_state_t arm_uc_hub_state = ARM_UC_HUB_STATE_UNINITIALIZED; + +// the call back function registered by the user to signal end of intilisation +static void (*arm_uc_hub_init_cb)(int32_t) = NULL; + +// The hub uses a double buffer system to speed up firmware download and storage +#define BUFFER_SIZE_MAX (ARM_UC_BUFFER_SIZE / 2) // define size of the double buffers +static uint8_t message[BUFFER_SIZE_MAX]; +static arm_uc_buffer_t front_buffer = { + .size_max = BUFFER_SIZE_MAX, + .size = 0, + .ptr = message +}; + +static uint8_t message2[BUFFER_SIZE_MAX]; +static arm_uc_buffer_t back_buffer = { + .size_max = BUFFER_SIZE_MAX, + .size = 0, + .ptr = message2 +}; + +// version (timestamp) of the current running application +static arm_uc_firmware_details_t arm_uc_active_details = { 0 }; + +// bootloader information +static arm_uc_installer_details_t arm_uc_installer_details = { 0 }; + +// variable to keep track of the offset into the firmware image during download +static uint32_t firmware_offset = 0; + +// variable to store the firmware config during firmware manager setup +static ARM_UCFM_Setup_t arm_uc_hub_firmware_config = { 0 }; + +// buffer to store the decoded firmware key +#define PLAIN_FIRMWARE_KEY_SIZE 16 +static uint8_t plainFirmwareKey[PLAIN_FIRMWARE_KEY_SIZE]; +static arm_uc_buffer_t arm_uc_hub_plain_key = { + .size_max = PLAIN_FIRMWARE_KEY_SIZE, + .size = PLAIN_FIRMWARE_KEY_SIZE, + .ptr = plainFirmwareKey +}; + +static arm_uc_mmContext_t manifestManagerContext = { 0 }; +static arm_uc_mmContext_t* pManifestManagerContext = &manifestManagerContext; +static manifest_firmware_info_t fwinfo = { 0 }; + +// buffer to store a uri struct +#define URI_STRING_LEN 256 +uint8_t uri_buffer[URI_STRING_LEN] = {0}; + +static arm_uc_uri_t uri = { + .size_max = sizeof(uri_buffer), + .size = 0, + .ptr = uri_buffer, + .port = 0, + .scheme = URI_SCHEME_NONE, + .host = NULL, + .path = NULL, +}; + +/*****************************************************************************/ +/* Debug */ +/*****************************************************************************/ + +#if ARM_UC_HUB_TRACE_ENABLE +static void arm_uc_hub_debug_output() +{ + printf("Manifest timestamp: %" PRIu64 "\r\n", fwinfo.timestamp); + + if (uri.scheme == URI_SCHEME_HTTP) + { + printf("Firmware URL http://%s:%" PRIu16 "%s\r\n", + uri.host, uri.port, uri.path); + } + + printf("Firmware size: %" PRIu32 "\r\n",fwinfo.size); + + printf("Firmware hash (%" PRIu32 "): ", fwinfo.hash.size); + for (unsigned i = 0; i < fwinfo.hash.size; i++) + { + printf("%02" PRIx8, fwinfo.hash.ptr[i]); + } + printf("\r\n"); + + if (fwinfo.cipherMode == ARM_UC_MM_CIPHERMODE_PSK) + { + printf("PSK ID: "); + for (unsigned i = 0; i < fwinfo.psk.keyID.size; i++) + { + printf("%02" PRIx8, *(fwinfo.psk.keyID.ptr+i)); + } + printf("\r\n"); + + printf("cipherKey(16): "); + for (unsigned i = 0; i < 16; i++) + { + printf("%02" PRIx8, *(fwinfo.psk.cipherKey.ptr+i)); + } + printf("\r\n"); + + printf("Decrypted Firmware Symmetric Key(16): "); + for (unsigned i = 0; i < 16; i++) + { + printf("%02" PRIx8, arm_uc_hub_plain_key.ptr[i]); + } + printf("\r\n"); + + printf("fwinfo.initVector\r\n"); + for (unsigned i = 0; i < 16; i++) + { + printf("%02" PRIx8, *(fwinfo.initVector.ptr+i)); + } + printf("\r\n"); + } + + printf("Storage location: %" PRIu32 "\r\n", + arm_uc_hub_firmware_config.package_id); +} +#endif + +/*****************************************************************************/ +/* State machine */ +/*****************************************************************************/ + +/* Short hand for simple error handling code */ +#define HANDLE_ERROR(retval, msg, ...) \ + if (retval.error != ERR_NONE) \ + { \ + UC_HUB_ERR_MSG(msg " error code %s", \ + ##__VA_ARGS__, \ + ARM_UC_err2Str(retval)); \ + new_state = ARM_UC_HUB_STATE_IDLE; \ + break; \ + } + +arm_uc_hub_state_t ARM_UC_HUB_getState() +{ + return arm_uc_hub_state; +} + +void ARM_UC_HUB_setInitializationCallback(void (*callback)(int32_t)) +{ + arm_uc_hub_init_cb = callback; +} + +void ARM_UC_HUB_setState(arm_uc_hub_state_t new_state) +{ + arm_uc_error_t retval; + + /* Loop until state is unchanged. + First loop is mandatory regardless of current state. + */ + do + { + /* store new stage */ + arm_uc_hub_state = new_state; + + switch (arm_uc_hub_state) + { + /*****************************************************************/ + /* Initialization */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_INITIALIZED: + UC_HUB_TRACE("ARM_UC_HUB_STATE_INITIALIZED"); + + /* signal that the Hub is initialized */ + if (arm_uc_hub_init_cb) + { + arm_uc_hub_init_cb(ARM_UC_INIT_DONE); + } + + /* report the active firmware hash to the Cloud in parallel + with the main user application. + */ + new_state = ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS; + break; + + /*****************************************************************/ + /* Report current firmware hash */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS: + UC_HUB_TRACE("ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS"); + + retval = ARM_UC_FirmwareManager.GetActiveFirmwareDetails(&arm_uc_active_details); + HANDLE_ERROR(retval, "Firmware manager GetActiveFirmwareDetails failed"); + break; + + case ARM_UC_HUB_STATE_REPORT_ACTIVE_HASH: + UC_HUB_TRACE("ARM_UC_HUB_STATE_REPORT_ACTIVE_HASH"); + + /* copy hash to buffer */ + memcpy(front_buffer.ptr, + arm_uc_active_details.hash, + ARM_UC_SHA256_SIZE); + + front_buffer.size = ARM_UC_SHA256_SIZE; + + /* send hash to update service */ + ARM_UC_ControlCenter_ReportName(&front_buffer); + + new_state = ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION; + break; + + /*****************************************************************/ + /* Report current firmware version */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION: + UC_HUB_TRACE("ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION"); + + UC_HUB_TRACE("Active version: %" PRIu64, + arm_uc_active_details.version); + + /* send timestamp to update service */ + ARM_UC_ControlCenter_ReportVersion(arm_uc_active_details.version); + + new_state = ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS; + break; + + /*****************************************************************/ + /* Report bootloader information */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS: + UC_HUB_TRACE("ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS"); + + retval = ARM_UC_FirmwareManager.GetInstallerDetails(&arm_uc_installer_details); + HANDLE_ERROR(retval, "Firmware manager GetInstallerDetails failed"); + break; + + case ARM_UC_HUB_STATE_REPORT_INSTALLER_DETAILS: + UC_HUB_TRACE("ARM_UC_HUB_STATE_REPORT_INSTALLER_DETAILS"); + +#if 0 + printf("bootloader: "); + for (uint32_t index = 0; index < 20; index++) + { + printf("%02X", arm_uc_installer_details.arm_hash[index]); + } + printf("\r\n"); + + printf("layout: %" PRIu32 "\r\n", arm_uc_installer_details.layout); +#endif + + /* report installer details to mbed cloud */ + arm_uc_buffer_t bootloader_hash = { + .size_max = ARM_UC_SHA256_SIZE, + .size = ARM_UC_SHA256_SIZE, + .ptr = (arm_uc_installer_details.arm_hash) + }; + ARM_UC_ControlCenter_ReportBootloaderHash(&bootloader_hash); + + bootloader_hash.ptr = (arm_uc_installer_details.oem_hash); + ARM_UC_ControlCenter_ReportOEMBootloaderHash(&bootloader_hash); + + /* set new state */ + new_state = ARM_UC_HUB_STATE_IDLE; + break; + + /*****************************************************************/ + /* Idle */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_IDLE: + UC_HUB_TRACE("ARM_UC_MONITOR_STATE_IDLE"); + + /* signal monitor that device has entered IDLE state */ + ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_IDLE); + break; + + /*****************************************************************/ + /* Download manifest */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_NOTIFIED: + UC_HUB_TRACE("ARM_UC_HUB_STATE_NOTIFIED"); + + /* notification received of a new manifest, hence go get said manifest */ + retval = ARM_UC_SourceManager.GetManifest(&front_buffer, 0); + HANDLE_ERROR(retval, "Source manager GetManifest failed"); + break; + + case ARM_UC_HUB_STATE_MANIFEST_FETCHED: + UC_HUB_TRACE("ARM_UC_HUB_STATE_MANIFEST_FETCHED"); + + /* Save the manifest for later */ + memcpy(&fwinfo.manifestBuffer, front_buffer.ptr, + ARM_UC_util_min(sizeof(fwinfo.manifestBuffer), front_buffer.size)); + /* Save the manifest size for later */ + fwinfo.manifestSize = front_buffer.size; + /* insert the manifest we just fetched into manifest manager */ + retval = ARM_UC_mmInsert(&pManifestManagerContext, &front_buffer, &back_buffer, NULL); + if (retval.code != MFST_ERR_PENDING) + { + HANDLE_ERROR(retval, "Manifest manager Insert failed") + } + break; + + /*****************************************************************/ + /* Rollback protection */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_MANIFEST_COMPLETE: + UC_HUB_TRACE("ARM_UC_HUB_STATE_MANIFEST_COMPLETE"); + + /* get the firmware info out of the manifest we just inserted + into the manifest manager + */ + retval = ARM_UC_mmFetchFirmwareInfo(&pManifestManagerContext, + &fwinfo, + NULL); + if (retval.code != MFST_ERR_PENDING) + { + HANDLE_ERROR(retval, "Manifest manager fetch info failed") + } + break; + + case ARM_UC_HUB_STATE_CHECK_VERSION: + UC_HUB_TRACE("ARM_UC_HUB_STATE_CHECK_VERSION"); + + /* only continue if timestamp is newer than active version */ + if (fwinfo.timestamp > arm_uc_active_details.version) + { + /* set new state */ + new_state = ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP; + } + else + { + UC_HUB_ERR_MSG("version: %" PRIu64 " <= %" PRIu64, + fwinfo.timestamp, + arm_uc_active_details.version); + + /* signal warning through external handler */ + ARM_UC_HUB_ErrorHandler(HUB_ERR_ROLLBACK_PROTECTION, + ARM_UC_HUB_STATE_CHECK_VERSION); + + /* set new state */ + new_state = ARM_UC_HUB_STATE_IDLE; + } + break; + + /*****************************************************************/ + /* Parse manifest */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP: + UC_HUB_TRACE("ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP"); + + /* store pointer to hash */ + arm_uc_hub_firmware_config.hash = &fwinfo.hash; + + /* parse the url string into a arm_uc_uri_t struct */ + retval = arm_uc_str2uri(fwinfo.uri.ptr, + fwinfo.uri.size, + &uri); + + /* URI-based errors are propagated to monitor */ + if (retval.error != ERR_NONE) + { + /* make sure that the URI string is always 0-terminated */ + fwinfo.uri.ptr[fwinfo.uri.size_max - 1] = '\0'; + UC_HUB_ERR_MSG("Unable to parse URI string %s", fwinfo.uri.ptr); + + /* signal warning through external handler */ + ARM_UC_HUB_ErrorHandler(SOMA_ERR_INVALID_PARAMETER, + ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP); + + /* set new state */ + new_state = ARM_UC_HUB_STATE_IDLE; + break; + } + + /* store firmware size */ + arm_uc_hub_firmware_config.package_size = fwinfo.size; + + /* read cryptography mode to determine if firmware is encrypted */ + switch(fwinfo.cipherMode) + { + case ARM_UC_MM_CIPHERMODE_NONE: + arm_uc_hub_firmware_config.mode = UCFM_MODE_NONE_SHA_256; + break; + + case ARM_UC_MM_CIPHERMODE_PSK: + { + /* Get pre-shared-key from the Control Center */ + /* TODO: this call should be asynchronous */ + const uint8_t* arm_uc_pre_shared_key = NULL; + retval = ARM_UC_PreSharedKey_GetKey(&arm_uc_pre_shared_key, 128); + HANDLE_ERROR(retval, "Unable to get PSK"); + + /* Decode the firmware key to be used to decode the firmware */ + UC_HUB_TRACE("Decoding firmware AES key..."); + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_dec(&ctx, arm_uc_pre_shared_key, 128); + mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, fwinfo.psk.cipherKey.ptr, arm_uc_hub_plain_key.ptr); + + arm_uc_hub_firmware_config.mode = UCFM_MODE_AES_CTR_128_SHA_256; + arm_uc_hub_firmware_config.key = &arm_uc_hub_plain_key; + arm_uc_hub_firmware_config.iv = &fwinfo.initVector; + } + break; + + case ARM_UC_MM_CIPHERMODE_CERT_CIPHERKEY: + case ARM_UC_MM_CIPHERMODE_CERT_KEYTABLE: + default: + retval.code = MFST_ERR_CRYPTO_MODE; + HANDLE_ERROR(retval, "Unsupported AES Key distribution mode..."); + break; + } + + /* check if storage ID has been set */ + if (fwinfo.strgId.size == 0 || fwinfo.strgId.ptr == NULL) + { + /* no storage ID set, use default value 0 */ + arm_uc_hub_firmware_config.package_id = 0; + } + else + { + /* check if storage ID is "default" */ + uint32_t location = arm_uc_strnstrn(fwinfo.strgId.ptr, + fwinfo.strgId.size, + (const uint8_t*) "default", + 7); + + if (location != UINT32_MAX) + { + arm_uc_hub_firmware_config.package_id = 0; + } + else + { + /* parse storage ID */ + bool success = false; + arm_uc_hub_firmware_config.package_id = + arm_uc_str2uint32(fwinfo.strgId.ptr, + fwinfo.strgId.size, + &success); + } + } + +#if ARM_UC_HUB_TRACE_ENABLE + arm_uc_hub_debug_output(); +#endif + + /* Set new state */ + new_state = ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION; + break; + + /*****************************************************************/ + /* Download authorization */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION: + UC_HUB_TRACE("ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION"); + + /* Signal control center */ + ARM_UC_ControlCenter_GetAuthorization(ARM_UCCC_REQUEST_DOWNLOAD); + + /* Set new state */ + new_state = ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION; + break; + + case ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION: + UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION"); + break; + + case ARM_UC_HUB_STATE_DOWNLOAD_AUTHORIZED: + UC_HUB_TRACE("ARM_UC_HUB_STATE_DOWNLOAD_AUTHORIZED"); + + /* Set new state */ + new_state = ARM_UC_HUB_STATE_SETUP_FIRMWARE; + break; + + /*****************************************************************/ + /* Download firmware */ + /*****************************************************************/ + + /* The firmware is downloaded in fragments. While one fragment is + written to storage, the next fragment is being downloaded. + + In the ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT state, the first + fragment is being downloaded. Once completed, the first fragment + will be in the front_buffer and both the network stack and + storage stack will be idle. + + In the ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD state, the front and + back buffers are swapped. The front buffer is being used for + downloading the next fragment while the back buffer is being + written to storage. + + ARM_UC_FirmwareManager.Write and + ARM_UC_SourceManager.GetFirmwareFragment will both finish + asynchronously generating two events: + ARM_UC_SM_EVENT_FIRMWARE and UCFM_EVENT_UPDATE_DONE. + + If the ARM_UC_SM_EVENT_FIRMWARE event is generated first, the + system enters the ARM_UC_HUB_STATE_WAIT_FOR_STORAGE state. + If the UCFM_EVENT_UPDATE_DONE event is generated first, the + system enters the ARM_UC_HUB_STATE_WAIT_FOR_NETWORK state. + The second generated event will move the system back to the + ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD state. + + The download will stop once the fragment offset is larger than + the firmware size written in the manifest. This moves the system + to the ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT state. + + Once the last fragment is written, the newly written firmware + committed in the ARM_UC_HUB_STATE_FINALIZE_STORAGE state. + */ + case ARM_UC_HUB_STATE_SETUP_FIRMWARE: + { + UC_HUB_TRACE("ARM_UC_HUB_STATE_SETUP_FIRMWARE"); + + /* store the firmware info in the manifest_firmware_info_t struct */ + arm_uc_firmware_details_t arm_uc_hub_firmware_details = { 0 }; + + /* use manifest timestamp as firmware header version */ + arm_uc_hub_firmware_details.version = fwinfo.timestamp; + arm_uc_hub_firmware_details.size = fwinfo.size; + + /* copy hash */ + memcpy(arm_uc_hub_firmware_details.hash, + fwinfo.hash.ptr, + ARM_UC_SHA256_SIZE); + + #if 0 + memcpy(arm_uc_hub_firmware_details.campaign, + configuration.campaign, + ARM_UC_GUID_SIZE); + #endif + + /* setup the firmware manager to get ready for firmware storage */ + retval = ARM_UC_FirmwareManager.Prepare(&arm_uc_hub_firmware_config, + &arm_uc_hub_firmware_details, + &front_buffer); + HANDLE_ERROR(retval, "ARM_UC_FirmwareManager Setup failed") + } + break; + + case ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT: + UC_HUB_TRACE("ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT"); + + /* set state to downloading when trying to fetch the first chunk of firmware */ + UC_HUB_TRACE("Setting Monitor State: ARM_UC_MONITOR_STATE_DOWNLOADING"); + ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_DOWNLOADING); + + /* reset download values */ + front_buffer.size = 0; + back_buffer.size = 0; + firmware_offset = 0; + + /* Check firmware size before entering the download state machine. + An empty firmware is used for erasing a slot. + */ + if (firmware_offset < fwinfo.size) + { + /* get first firmware fragment */ + UC_HUB_TRACE("Getting next chunk at offset %" PRIu32, + firmware_offset); + retval = ARM_UC_SourceManager.GetFirmwareFragment(&uri, + &front_buffer, + firmware_offset); + HANDLE_ERROR(retval, "GetFirmwareFragment failed") + } + else + { + /* No download is necessary, send next state to monitor service + and close storage slot. + */ + UC_HUB_TRACE("Firmware empty, skip download phase and finalize"); + UC_HUB_TRACE("Setting Monitor State: ARM_UC_MONITOR_STATE_DOWNLOADED"); + ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_DOWNLOADED); + new_state = ARM_UC_HUB_STATE_FINALIZE_STORAGE; + } + break; + + case ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD: + UC_HUB_TRACE("ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD"); + + /* swap the front and back buffers + the back buffer contained just downloaded firmware chunk + the front buffer can now be cleared and used to download new chunk + */ + { + arm_uc_buffer_t temp_buf_ptr = front_buffer; + front_buffer = back_buffer; + back_buffer = temp_buf_ptr; + } + + UC_HUB_TRACE("Fragment: %" PRIu32 " %" PRIu32, firmware_offset, back_buffer.size); + + /* increase offset by the amount that we just downloaded */ + firmware_offset += back_buffer.size; + + /* store the downloaded chunk in the back buffer */ + if (back_buffer.size > 0) + { + retval = ARM_UC_FirmwareManager.Write(&back_buffer); + HANDLE_ERROR(retval, "ARM_UC_FirmwareManager Update failed") + } + + /* go fetch a new chunk using the front buffer if more are expected */ + if (firmware_offset < fwinfo.size) + { + front_buffer.size = 0; + UC_HUB_TRACE("Getting next chunk at offset: %" PRIu32, firmware_offset); + retval = ARM_UC_SourceManager.GetFirmwareFragment(&uri, &front_buffer, firmware_offset); + HANDLE_ERROR(retval, "GetFirmwareFragment failed") + } + else + { + UC_HUB_TRACE("Store last fragment"); + new_state = ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT; + } + + /* report progress */ + ARM_UC_ControlCenter_ReportProgress(firmware_offset, fwinfo.size); + break; + + case ARM_UC_HUB_STATE_WAIT_FOR_STORAGE: + UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_STORAGE"); + break; + + case ARM_UC_HUB_STATE_WAIT_FOR_NETWORK: + UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_NETWORK"); + break; + + case ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT: + UC_HUB_TRACE("ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT"); + + /* set state to downloaded when the full size of the firmware + have been fetched. + */ + UC_HUB_TRACE("Setting Monitor State: ARM_UC_MONITOR_STATE_DOWNLOADED"); + ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_DOWNLOADED); + break; + + case ARM_UC_HUB_STATE_FINALIZE_STORAGE: + UC_HUB_TRACE("ARM_UC_HUB_STATE_FINALIZE_STORAGE"); + + retval = ARM_UC_FirmwareManager.Finalize(&front_buffer, &back_buffer); + HANDLE_ERROR(retval, "ARM_UC_FirmwareManager Finalize failed") + break; + + /*****************************************************************/ + /* Install authorization */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_STORAGE_FINALIZED: + UC_HUB_TRACE("ARM_UC_HUB_STATE_STORAGE_FINALIZED"); + + /* Signal control center */ + ARM_UC_ControlCenter_GetAuthorization(ARM_UCCC_REQUEST_INSTALL); + + /* Set new state */ + new_state = ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION; + break; + + case ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION: + UC_HUB_TRACE("ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION"); + break; + + case ARM_UC_HUB_STATE_INSTALL_AUTHORIZED: + UC_HUB_TRACE("ARM_UC_HUB_STATE_INSTALL_AUTHORIZED"); + + UC_HUB_TRACE("Setting Monitor State: ARM_UC_MONITOR_STATE_UPDATING"); + ARM_UC_ControlCenter_ReportState(ARM_UC_MONITOR_STATE_UPDATING); + +/* TODO: set timeout on ReportState before relying on callback to progress state machine */ + new_state = ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE; + break; + + case ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE: + UC_HUB_TRACE("ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE"); + + /* Firmware verification passes, activate firmware image. + */ + ARM_UC_FirmwareManager.Activate(arm_uc_hub_firmware_config.package_id); + break; + + case ARM_UC_HUB_STATE_REBOOT: + UC_HUB_TRACE("ARM_UC_HUB_STATE_REBOOT"); + + /* Firmware activated, now reboot the system to apply + the new image. + */ + pal_osReboot(); + + /* Reboot not implemented on this platform. + Report new firmware hash and continue operation. + */ + new_state = ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS; + break; + + /*****************************************************************/ + /* Error */ + /*****************************************************************/ + case ARM_UC_HUB_STATE_ERROR_FIRMWARE_MANAGER: + UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_FIRMWARE_MANAGER"); + new_state = ARM_UC_HUB_STATE_IDLE; + break; + + case ARM_UC_HUB_STATE_ERROR_MANIFEST_MANAGER: + UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_MANIFEST_MANAGER"); + new_state = ARM_UC_HUB_STATE_IDLE; + break; + + case ARM_UC_HUB_STATE_ERROR_SOURCE_MANAGER: + UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_SOURCE_MANAGER"); + new_state = ARM_UC_HUB_STATE_IDLE; + break; + + case ARM_UC_HUB_STATE_ERROR_CONTROL_CENTER: + UC_HUB_TRACE("ARM_UC_HUB_STATE_ERROR_CONTROL_CENTER"); + new_state = ARM_UC_HUB_STATE_IDLE; + break; + + default: + new_state = ARM_UC_HUB_STATE_IDLE; + break; + } + } + while (arm_uc_hub_state != new_state); +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_state_machine.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/source/update_client_hub_state_machine.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,86 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_HUB_STATE_MACHINE_H +#define ARM_UC_HUB_STATE_MACHINE_H + +#include <stdint.h> + + +/** + * States in the Update Hub. + */ +typedef enum { + ARM_UC_HUB_STATE_UNINITIALIZED, + ARM_UC_HUB_STATE_INITIALIZED, + ARM_UC_HUB_STATE_GET_ACTIVE_FIRMWARE_DETAILS, + ARM_UC_HUB_STATE_REPORT_ACTIVE_HASH, + ARM_UC_HUB_STATE_REPORT_ACTIVE_VERSION, + ARM_UC_HUB_STATE_GET_INSTALLER_DETAILS, + ARM_UC_HUB_STATE_REPORT_INSTALLER_DETAILS, + ARM_UC_HUB_STATE_IDLE, + ARM_UC_HUB_STATE_NOTIFIED, + ARM_UC_HUB_STATE_CERT_STORED, + ARM_UC_HUB_STATE_MANIFEST_FETCHED, + ARM_UC_HUB_STATE_MANIFEST_COMPLETE, + ARM_UC_HUB_STATE_CHECK_VERSION, + ARM_UC_HUB_STATE_PREPARE_FIRMWARE_SETUP, + ARM_UC_HUB_STATE_REQUEST_DOWNLOAD_AUTHORIZATION, + ARM_UC_HUB_STATE_WAIT_FOR_DOWNLOAD_AUTHORIZATION, + ARM_UC_HUB_STATE_DOWNLOAD_AUTHORIZED, + ARM_UC_HUB_STATE_SETUP_FIRMWARE, + ARM_UC_HUB_STATE_FETCH_FIRST_FRAGMENT, + ARM_UC_HUB_STATE_STORE_AND_DOWNLOAD, + ARM_UC_HUB_STATE_WAIT_FOR_STORAGE, + ARM_UC_HUB_STATE_WAIT_FOR_NETWORK, + ARM_UC_HUB_STATE_STORE_LAST_FRAGMENT, + ARM_UC_HUB_STATE_FINALIZE_STORAGE, + ARM_UC_HUB_STATE_STORAGE_FINALIZED, + ARM_UC_HUB_STATE_WAIT_FOR_INSTALL_AUTHORIZATION, + ARM_UC_HUB_STATE_INSTALL_AUTHORIZED, + ARM_UC_HUB_STATE_ACTIVATE_FIRMWARE, + ARM_UC_HUB_STATE_REBOOT, + ARM_UC_HUB_STATE_ERROR_FIRMWARE_MANAGER, + ARM_UC_HUB_STATE_ERROR_MANIFEST_MANAGER, + ARM_UC_HUB_STATE_ERROR_SOURCE_MANAGER, + ARM_UC_HUB_STATE_ERROR_CONTROL_CENTER, + ARM_UC_HUB_STATE_ERROR_UNKNOWN, +} arm_uc_hub_state_t; + +/** + * @brief Read internal state. + * @return State + */ +arm_uc_hub_state_t ARM_UC_HUB_getState(void); + +/** + * @brief Set internal state. + * @details Setting the state will perform actions related to that state. + * + * @param state New state. + */ +void ARM_UC_HUB_setState(arm_uc_hub_state_t state); + +/** + * @brief Set callback function for when the Update Client is initialized. + * + * @param callback Function pointer. + */ +void ARM_UC_HUB_setInitializationCallback(void (*callback)(int32_t)); + +#endif // ARM_UC_HUB_STATE_MACHINE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/update-client-hub/update_client_certificate.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/update-client-hub/update_client_certificate.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,27 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_HUB_CERTIFICATE_H +#define ARM_UC_HUB_CERTIFICATE_H + +#warning This file is deprecated. \ + Use update-client-control-center/arm_uc_certificate.h instead + +#include "update-client-control-center/arm_uc_certificate.h" + +#endif // ARM_UC_HUB_CERTIFICATE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/update-client-hub/update_client_hub.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/update-client-hub/update_client_hub.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,258 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_CLIENT_HUB_H +#define ARM_UPDATE_CLIENT_HUB_H + +#include "update-client-common/arm_uc_common.h" +#include "update-client-source/arm_uc_source.h" +#include "update-client-monitor/arm_uc_monitor.h" +#include "update-client-control-center/arm_uc_control_center.h" +#include "update-client-paal/arm_uc_paal_update.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Initialization return codes. + */ + enum { + ARM_UC_INIT_DONE + }; + + /** + * @brief Start the initialization of the hub. + * @details When initilisation finishes, the user callback function + * will be called. The "event" parameter to the callback + * function should be ignored. + * + * @param function to be called when initilisation is finished. + * @return Error code. + */ + arm_uc_error_t ARM_UC_HUB_Initialize(void (*callback)(int32_t)); + + /** + * @brief Process events in the event queue. + * @details The update client is driven by events in an atomic queue, + * the user need to call this function periodically to process + * events in the queue and hence move the client forward. + * + * @return Error code. + * @note Here's a code snippet to suggest how this API might be used by callers: + * \code + * int main() { + * retval = ARM_UC_Hub.Initialize(init_finish_cb); + * while(true) { + * ARM_UC_Hub.ProcessEvents(); + * __WFI(); + * } + * } + * \endcode + */ + arm_uc_error_t ARM_UC_HUB_ProcessEvents(void); + + /** + * @brief Register callback function for when callbacks are added to an + * empty queue. + * @details This function is called at least once (maybe more) when + * callbacks are added to an empty queue. Useful for scheduling + * when the queue needs to be processed. + * @param handler Function pointer to function to be called when elements are + * added to an empty queue. + */ + arm_uc_error_t ARM_UC_HUB_AddNotificationHandler(void (*handler)(void)); + + /** + * @brief Add sources to the update client. + * @details Sources are transport methods for manifest and firmwares. + * + * @param sources Pointer to an array of source pointers. + * @param size Number of elements in the pointer array. + * @return Error code. + */ + arm_uc_error_t ARM_UC_HUB_SetSources(const ARM_UPDATE_SOURCE* sources[], + uint8_t size); + + /** + * @brief Set implementation for storing firmware. + * @details Storage abstraction for handling different storage medium. + * + * @param implementation Function pointer struct to Update PAL implementation. + * @return Error code. + */ + arm_uc_error_t ARM_UC_HUB_SetStorage(const ARM_UC_PAAL_UPDATE* implementation); + + /** + * @brief Add monitor to the update client. + * @details Monitors send the update status and results. + * + * @param monitor The monitor to be added to the update client. + * @return Error code. + */ + arm_uc_error_t ARM_UC_HUB_AddMonitor(const ARM_UPDATE_MONITOR* monitor); + + /** + * @brief Temporary error reporting function. + * @details This function will be absorbed into the add monitor call. + * + * @param callback Error reporting function. + */ + void ARM_UC_HUB_AddErrorCallback(void (*callback)(int32_t error)); + + /** + * @brief Authorize request. + * @details Function is called when the user application authorizes + * requests from the Update Client. + * + * @param request Requests are passed through the callback function. + * @return Error code. + */ + arm_uc_error_t ARM_UC_Authorize(arm_uc_request_t request); + + /** + * @brief Set callback for receiving download progress. + * @details User application call for setting callback handler. + * The callback function takes the progreess in percent as argument. + * + * @param callback Function pointer to the progress function. + * @return Error code. + */ + arm_uc_error_t ARM_UC_SetProgressHandler(void (*callback)(uint32_t progress, uint32_t total)); + + /** + * @brief Set callback function for authorizing requests. + * @details User application call for setting callback handler. + * The callback function takes an enum request and an authorization + * function pointer. To authorize the given request, the caller + * invokes the authorization function. + * + * @param callback Function pointer to the authorization function. + * @return Error code. + */ + arm_uc_error_t ARM_UC_SetAuthorizeHandler(void (*callback)(int32_t)); + + /** + * @brief Override update authorization handler. + * @details Force download and update to progress regardless of authorization + * handler. This function is used for unblocking an update in a buggy + * application. + */ + void ARM_UC_OverrideAuthorization(void); + + /** + * @brief Add certificate. + * @details [long description] + * + * @param certificate Pointer to certiface being added. + * @param certificate_length Certificate length. + * @param fingerprint Pointer to the fingerprint of the certificate being added. + * @param fingerprint_length Fingerprint length. + * @param callback Callback handler for certificate insertion events. + * @return Error code. + */ + arm_uc_error_t ARM_UC_AddCertificate(const uint8_t* certificate, + uint16_t certificate_length, + const uint8_t* fingerprint, + uint16_t fingerprint_length, + void (*callback)(arm_uc_error_t, const arm_uc_buffer_t*)); + + /** + * @brief Set pointer to pre-shared-key with the given size. + * + * @param key Pointer to pre-shared-key. + * @param bits Key size in bits. + * + * @return Error code. + */ + arm_uc_error_t ARM_UC_AddPreSharedKey(const uint8_t* key, uint16_t bits); + + /** + * @brief Function for setting the vendor ID. + * @details The ID is copied to a 16 byte struct. Any data after the first + * 16 bytes will be ignored. + * @param id Pointer to ID. + * @param length Length of ID. + * @return Error code. + */ + arm_uc_error_t ARM_UC_SetVendorId(const uint8_t* id, uint8_t length); + + /** + * @brief Function for setting the class ID. + * @details The ID is copied to a 16 byte struct. Any data after the first + * 16 bytes will be ignored. + * @param id Pointer to ID. + * @param length Length of ID. + * @return Error code. + */ + arm_uc_error_t ARM_UC_SetClassId(const uint8_t* id, uint8_t length); + + /** + * @brief Function for setting the device ID. + * @details The ID is copied to a 16 byte struct. Any data after the first + * 16 bytes will be ignored. + * @param id Pointer to ID. + * @param length Length of ID. + * @return Error code. + */ + arm_uc_error_t ARM_UC_SetDeviceId(const uint8_t* id, uint8_t length); + + /** + * @brief Function for reporting the vendor ID. + * @details 16 bytes are copied into the supplied buffer. + * @param id Pointer to storage for ID. MUST be at least 16 bytes long. + * @param id_max the size of the ID buffer + * @param id_size pointer to a variable to receive the size of the ID + * written into the buffer (always 16). + * @return Error code. + */ + arm_uc_error_t ARM_UC_GetVendorId(uint8_t* id, + const size_t id_max, + size_t* id_size); + + /** + * @brief Function for reporting the class ID. + * @details 16 bytes are copied into the supplied buffer. + * @param id Pointer to storage for ID. MUST be at least 16 bytes long. + * @param id_max the size of the ID buffer + * @param id_size pointer to a variable to receive the size of the ID + * written into the buffer (always 16). + * @return Error code. + */ + arm_uc_error_t ARM_UC_GetClassId(uint8_t* id, + const size_t id_max, + size_t* id_size); + + /** + * @brief Function for reporting the device ID. + * @details 16 bytes are copied into the supplied buffer. + * @param id Pointer to storage for ID. MUST be at least 16 bytes long. + * @param id_max the size of the ID buffer + * @param id_size pointer to a variable to receive the size of the ID + * written into the buffer (always 16). + * @return Error code. + */ + arm_uc_error_t ARM_UC_GetDeviceId(uint8_t* id, + const size_t id_max, + size_t* id_size); + +#ifdef __cplusplus +} +#endif + +#endif /* ARM_UPDATE_CLIENT_HUB_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/update-client-hub/update_client_public.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed-cloud-client/update-client-hub/update-client-hub/update_client_public.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,24 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_CLIENT_PUBLIC_H +#define ARM_UPDATE_CLIENT_PUBLIC_H + +#include "update-client-common/arm_uc_public.h" + +#endif /* ARM_UPDATE_CLIENT_PUBLIC_H */
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed_cloud_client_resource.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed_cloud_client_resource.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,113 @@ +#include "mbed.h" +#include "mbed_cloud_client_resource.h" +#include "simple-mbed-cloud-client.h" + +void path_to_ids(const char* path, unsigned int *object_id, + unsigned int *instance_id, unsigned int *resource_id) { + int len = strlen(path); + char *buffer = new char[len + 1]; + buffer[len] = '\0'; + strncpy(buffer, path, len); + unsigned int index = 0; + char * pch = strtok (buffer, "/"); + + unsigned int *ptr; + while (pch != NULL && index < 3) { + switch (index) { + case 0: + ptr = object_id; + break; + + case 1: + ptr = instance_id; + break; + + case 2: + ptr = resource_id; + break; + } + + *ptr = atoi(pch); + pch = strtok (NULL, "/"); + index++; + } + + delete[] buffer; +} + +MbedCloudClientResource::MbedCloudClientResource(SimpleMbedCloudClient *client, const char *path, const char *name) +: client(client), resource(NULL), path(path), name(name), putCallback(NULL), + postCallback(NULL), notificationCallback(NULL) { +} + +void MbedCloudClientResource::observable(bool observable) { + this->isObservable = observable; +} + +void MbedCloudClientResource::methods(unsigned int methodMask) { + this->methodMask = methodMask; +} + +void MbedCloudClientResource::attach_put_callback(Callback<void(const char*)> callback) { + this->putCallback = callback; +} + +void MbedCloudClientResource::attach_post_callback(Callback<void(void*)> callback) { + this->postCallback = callback; +} + +void MbedCloudClientResource::attach_notification_callback(Callback<void(const M2MBase&, const NoticationDeliveryStatus)> callback) { + this->notificationCallback = callback; +} + +void MbedCloudClientResource::detach_put_callback() { + this->putCallback = NULL; +} + +void MbedCloudClientResource::detach_post_callback() { + this->postCallback = NULL; +} + +void MbedCloudClientResource::detach_notification_callback() { + this->notificationCallback = NULL; +} + +void MbedCloudClientResource::set_value(int value) { + this->value = ""; + this->value.append_int(value); + + if (this->resource) { + this->resource->set_value((uint8_t*)this->value.c_str(), this->value.size()); + } +} + +void MbedCloudClientResource::set_value(char *value) { + this->value = value; + + if (this->resource) { + this->resource->set_value((uint8_t*)this->value.c_str(), strlen(value)); + } +} + +String MbedCloudClientResource::get_value() { + if (this->resource) { + return this->resource->get_value_string(); + } else { + return this->value; + } +} + +void MbedCloudClientResource::get_data(mcc_resource_def *resourceDef) { + path_to_ids(this->path.c_str(), &(resourceDef->object_id), &(resourceDef->instance_id), &(resourceDef->resource_id)); + resourceDef->name = this->name; + resourceDef->method_mask = this->methodMask; + resourceDef->observable = this->isObservable; + resourceDef->value = this->get_value(); + resourceDef->put_callback = &(this->putCallback); + resourceDef->post_callback = &(this->postCallback); + resourceDef->notification_callback = &(this->notificationCallback); +} + +void MbedCloudClientResource::set_resource(M2MResource *res) { + this->resource = res; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed_cloud_client_resource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed_cloud_client_resource.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,67 @@ +#ifndef MBED_CLOUD_CLIENT_RESOURCE_H +#define MBED_CLOUD_CLIENT_RESOURCE_H + +#include "mbed.h" +#include "simple-mbed-cloud-client.h" +#include "mbed-client/m2mstring.h" + +namespace M2MMethod { + +enum M2MMethod { + GET = 0x01, + PUT = 0x02, + POST = 0x04, + DELETE = 0x08 +}; + +}; + +struct mcc_resource_def { + unsigned int object_id; + unsigned int instance_id; + unsigned int resource_id; + String name; + unsigned int method_mask; + String value; + bool observable; + Callback<void(const char*)> *put_callback; + Callback<void(void*)> *post_callback; + Callback<void(const M2MBase&, const NoticationDeliveryStatus)> *notification_callback; +}; + +class SimpleMbedCloudClient; + +class MbedCloudClientResource { + public: + MbedCloudClientResource(SimpleMbedCloudClient *client, const char *path, const char *name); + + void observable(bool observable); + void methods(unsigned int methodMask); + void attach_put_callback(Callback<void(const char*)> callback); + void attach_post_callback(Callback<void(void*)> callback); + void attach_notification_callback(Callback<void(const M2MBase&, const NoticationDeliveryStatus)> callback); + void detach_put_callback(); + void detach_post_callback(); + void detach_notification_callback(); + void set_value(int value); + void set_value(char *value); + String get_value(); + + void get_data(mcc_resource_def *resourceDef); + void set_resource(M2MResource *res); + + private: + SimpleMbedCloudClient *client; + M2MResource *resource; + String path; + String name; + String value; + bool isObservable; + unsigned int methodMask; + + Callback<void(const char*)> putCallback; + Callback<void(void*)> postCallback; + Callback<void(const M2MBase&, const NoticationDeliveryStatus)> notificationCallback; +}; + +#endif // MBED_CLOUD_CLIENT_RESOURCE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/mbed_cloud_client_user_config_template.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/mbed_cloud_client_user_config_template.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,57 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// This file is a template and it's intented to be copied to the application +/* // Enable this configuration + +#ifndef MBED_CLOUD_CLIENT_USER_CONFIG_H +#define MBED_CLOUD_CLIENT_USER_CONFIG_H + + +#define MBED_CLOUD_CLIENT_ENDPOINT_TYPE "default" + +// Enable either TCP or UDP, but no both +#define MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP +// MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP + +#define MBED_CLOUD_CLIENT_LIFETIME 3600 + +#define MBED_CLOUD_CLIENT_SUPPORT_UPDATE +#define SN_COAP_MAX_BLOCKWISE_PAYLOAD_SIZE 1024 + +// set flag to enable update support in mbed Cloud client +#define MBED_CLOUD_CLIENT_SUPPORT_UPDATE + +// set download buffer size in bytes (min. 1024 bytes) + +// Use larger buffers in Linux // +#ifdef __linux__ +#define MBED_CLOUD_CLIENT_UPDATE_BUFFER (2 * 1024 * 1024) +#else +#define MBED_CLOUD_CLIENT_UPDATE_BUFFER 2048 +#endif + +// Developer flags for Update feature +#if MBED_CONF_APP_DEVELOPER_MODE == 1 + #define MBED_CLOUD_DEV_UPDATE_CERT + #define MBED_CLOUD_DEV_UPDATE_ID +#endif // MBED_CONF_APP_DEVELOPER_MODE + +#endif // MBED_CLOUD_CLIENT_USER_CONFIG_H + +*/
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/memory_tests.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/memory_tests.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,33 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef __MEMORY_TESTS_H__ +#define __MEMORY_TESTS_H__ + +#include "mbed-client/m2minterface.h" +#include "mbed.h" + +// A function for creating a batch of resources for memory consumption purposes. +void m2mobject_test_set(M2MObjectList& object_list); + +// Print into serial the m2m object sizes and heap allocation sizes. +void m2mobject_stats(); + +void heap_stats(); + +#endif // !__MEMORY_TESTS_H__
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/pal_plat_rot_insecure.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/pal_plat_rot_insecure.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,53 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + + +#include "pal_plat_rtos.h" + +#define PAL_DEVICE_KEY_SIZE_IN_BYTES 16 + +//THIS CODE IS FOR TESTING PURPOSES ONLY. DO NOT USE IN PRODUCTION ENVIRONMENTS. REPLACE WITH A PROPER IMPLEMENTATION BEFORE USE +palStatus_t __attribute__((weak)) pal_plat_osGetRoT128Bit(uint8_t *keyBuf, size_t keyLenBytes) +{ +#if defined (__CC_ARM) /* ARM compiler. */ + #warning("PAL_INSECURE- You are using insecure Root Of Trust implementation, DO NOT USE IN PRODUCTION ENVIRONMENTS. REPLACE WITH A PROPER IMPLEMENTATION BEFORE USE") +#else + #pragma message ("You are using insecure Root Of Trust implementation, DO NOT USE IN PRODUCTION ENVIRONMENTS. REPLACE WITH A PROPER IMPLEMENTATION BEFORE USE") +#endif + static bool runOnce = true; + if (runOnce) { + + PAL_LOG(WARN, "You are using insecure Root Of Trust implementation"); + runOnce = false; + } + + if (keyLenBytes < PAL_DEVICE_KEY_SIZE_IN_BYTES) { + return PAL_ERR_BUFFER_TOO_SMALL; + } + + if (NULL == keyBuf) { + return PAL_ERR_NULL_POINTER; + } + + for (int i=0; i < PAL_DEVICE_KEY_SIZE_IN_BYTES; i++) { + keyBuf[i] = i; + } + + return PAL_SUCCESS; +} +
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/resource.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/resource.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,90 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "mbed-cloud-client/MbedCloudClient.h" +#include "m2mresource.h" +#include "mbed-client/m2minterface.h" +#include <stdio.h> +#include <string.h> +#include "mbed.h" + +static void notification_delivery_status_cb_thunk(const M2MBase& base, + const NoticationDeliveryStatus status, + void *client_args) { + ((Callback<void(const M2MBase& base, const NoticationDeliveryStatus status)>*)client_args)->call(base, status); +} + +M2MResource* add_resource(M2MObjectList *list, uint16_t object_id, uint16_t instance_id, + uint16_t resource_id, const char *resource_type, M2MResourceInstance::ResourceType data_type, + M2MBase::Operation allowed, const char *value, bool observable, Callback<void(const char*)> *put_cb, + Callback<void(void*)> *post_cb, + Callback<void(const M2MBase&, const NoticationDeliveryStatus)> *notification_status_cb) +{ + M2MObject *object = NULL; + M2MObjectInstance* object_instance = NULL; + M2MResource* resource = NULL; + char name[6]; + + //check if object already exists. + if (!list->empty()) { + M2MObjectList::const_iterator it; + it = list->begin(); + for ( ; it != list->end(); it++ ) { + if ((*it)->name_id() == object_id) { + object = (*it); + break; + } + } + } + //Create new object if needed. + if (!object) { + snprintf(name, 6, "%d", object_id); + object = M2MInterfaceFactory::create_object(name); + list->push_back(object); + } else { + //check if instance already exists. + object_instance = object->object_instance(instance_id); + } + //Create new instance if needed. + if (!object_instance) { + object_instance = object->create_object_instance(instance_id); + } + //create the recource. + snprintf(name, 6, "%d", resource_id); + resource = object_instance->create_dynamic_resource(name, resource_type, data_type, observable); + //Set value if available. + if (value != "") { + resource->set_value((const unsigned char*)value, strlen(value)); + } + //Set allowed operations for accessing the resource. + resource->set_operation(allowed); + if (observable) { + resource->set_notification_delivery_status_cb(notification_delivery_status_cb_thunk, notification_status_cb); + } + + + resource->set_value_updated_function( + FP1<void, const char*>(put_cb, + (void (Callback<void(const char*)>::*)(const char*)) + &Callback<void(const char*)>::call)); + resource->set_execute_function(FP1<void, void*>(post_cb, + (void (Callback<void(void*)>::*)(void*)) + &Callback<void(void*)>::call)); + + return resource; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/resource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/resource.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,66 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + + +#ifndef RESOURCE_H +#define RESOURCE_H + + +/** + * \brief Helper function for creating different kind of resources. + * The path of the resource will be "object_id/instance_id/resource_id" + * For example if object_id = 1, instance_id = 2, resource_id = 3 + * the path would be 1/2/3 + * + * \param list Pointer to the object list, + * contains objects to be registered to the server. + * \param object_id Name of the object in integer format. + * \param instance_id Name of the instance in integer format. + * \param resource_id Name of the resource in integer format. + * \param resource_type Resource type name. + * \param data_type Data type of the resource value. + * \param allowed Methods allowed for accessing this resource. + * \param value Resource value as a null terminated string. + * May be set as NULL. + * \param observable Resource set observable if true. + * \param cb Function pointer to either: + * value_updated_callback2 if allowed & GET_PUT_ALLOWED + * OR + * execute_callback_2 in if allowed & POST_ALLOWED. + * In other cases this parameter is ignored. + * + * NOTE: This function is not designed to support setting both + * GET_PUT_ALLOWED and POST_ALLOWED for parameter allowed + * at the same time. + * \param notification_status_cb Function pointer to notification_delivery_status_cb + * if resource is set to be observable. + */ +M2MResource* add_resource(M2MObjectList *list, + uint16_t object_id, + uint16_t instance_id, + uint16_t resource_id, + const char *resource_type, + M2MResourceInstance::ResourceType data_type, + M2MBase::Operation allowed, + const char *value, + bool observable, + Callback<void(const char*)> *put_cb, + Callback<void(void*)> *post_cb, + Callback<void(const M2MBase&, const NoticationDeliveryStatus)> *notification_status_cb); + +#endif //RESOURCE_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/simple-mbed-cloud-client.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/simple-mbed-cloud-client.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,303 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include <stdio.h> +#include "simple-mbed-cloud-client.h" +#include "mbed-cloud-client/MbedCloudClient.h" +#include "m2mdevice.h" +#include "m2mresource.h" +#include "mbed-client/m2minterface.h" +#include "key_config_manager.h" +#include "resource.h" +#include "mbed-client/m2mvector.h" +#include "mbed_cloud_client_resource.h" +#include "factory_configurator_client.h" + +#ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#include MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#endif + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE +#include "update_ui_example.h" +#endif + +#ifdef MBED_HEAP_STATS_ENABLED +#include "memory_tests.h" +#endif + +#define DEFAULT_FIRMWARE_PATH "/sd/firmware" + +SimpleMbedCloudClient::SimpleMbedCloudClient(NetworkInterface *net) : + _registered(false), + _register_called(false), + net(net) { +} + +SimpleMbedCloudClient::~SimpleMbedCloudClient() { + for (unsigned int i = 0; _resources.size(); i++) { + delete _resources[i]; + } +} + +int SimpleMbedCloudClient::init() { + // Initialize the FCC + fcc_status_e fcc_status = fcc_init(); + if(fcc_status != FCC_STATUS_SUCCESS) { + printf("fcc_init failed with status %d! - exit\n", fcc_status); + return 1; + } + + // Resets storage to an empty state. + // Use this function when you want to clear storage from all the factory-tool generated data and user data. + // After this operation device must be injected again by using factory tool or developer certificate. +#ifdef RESET_STORAGE + printf("Reset storage to an empty state.\n"); + fcc_status_e delete_status = fcc_storage_delete(); + if (delete_status != FCC_STATUS_SUCCESS) { + printf("Failed to delete storage - %d\n", delete_status); + } +#endif + + // Deletes existing firmware images from storage. + // This deletes any existing firmware images during application startup. + // This compilation flag is currently implemented only for mbed OS. +#ifdef RESET_FIRMWARE + palStatus_t status = PAL_SUCCESS; + status = pal_fsRmFiles(DEFAULT_FIRMWARE_PATH); + if(status == PAL_SUCCESS) { + printf("Firmware storage erased.\n"); + } else if (status == PAL_ERR_FS_NO_PATH) { + printf("Firmware path not found/does not exist.\n"); + } else { + printf("Firmware storage erasing failed with %" PRId32, status); + return 1; + } +#endif + +#if MBED_CONF_APP_DEVELOPER_MODE == 1 + printf("Start developer flow\n"); + fcc_status = fcc_developer_flow(); + if (fcc_status == FCC_STATUS_KCM_FILE_EXIST_ERROR) { + printf("Developer credentials already exist\n"); + } else if (fcc_status != FCC_STATUS_SUCCESS) { + printf("Failed to load developer credentials - exit\n"); + return 1; + } +#endif + fcc_status = fcc_verify_device_configured_4mbed_cloud(); + if (fcc_status != FCC_STATUS_SUCCESS) { + printf("Device not configured for mbed Cloud - exit\n"); + return 1; + } +} + +bool SimpleMbedCloudClient::call_register() { + + _cloud_client.on_registered(this, &SimpleMbedCloudClient::client_registered); + _cloud_client.on_unregistered(this, &SimpleMbedCloudClient::client_unregistered); + _cloud_client.on_error(this, &SimpleMbedCloudClient::error); + + printf("Connecting...\n"); + bool setup = _cloud_client.setup(net); + _register_called = true; + if (!setup) { + printf("Client setup failed\n"); + return false; + } + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + /* Set callback functions for authorizing updates and monitoring progress. + Code is implemented in update_ui_example.cpp + Both callbacks are completely optional. If no authorization callback + is set, the update process will procede immediately in each step. + */ + update_ui_set_cloud_client(&_cloud_client); + _cloud_client.set_update_authorize_handler(update_authorize); + _cloud_client.set_update_progress_handler(update_progress); +#endif + return true; +} + +void SimpleMbedCloudClient::close() { + _cloud_client.close(); +} + +void SimpleMbedCloudClient::register_update() { + _cloud_client.register_update(); +} + +void SimpleMbedCloudClient::client_registered() { + _registered = true; + printf("\nClient registered\n\n"); + static const ConnectorClientEndpointInfo* endpoint = NULL; + if (endpoint == NULL) { + endpoint = _cloud_client.endpoint_info(); + if (endpoint) { + +#if MBED_CONF_APP_DEVELOPER_MODE == 1 + printf("Endpoint Name: %s\r\n", endpoint->internal_endpoint_name.c_str()); +#else + printf("Endpoint Name: %s\r\n", endpoint->endpoint_name.c_str()); +#endif + printf("Device Id: %s\r\n", endpoint->internal_endpoint_name.c_str()); + } + } +#ifdef MBED_HEAP_STATS_ENABLED + heap_stats(); +#endif +} + +void SimpleMbedCloudClient::client_unregistered() { + _registered = false; + _register_called = false; + printf("\nClient unregistered - Exiting application\n\n"); +#ifdef MBED_HEAP_STATS_ENABLED + heap_stats(); +#endif +} + +void SimpleMbedCloudClient::error(int error_code) { + const char *error; + switch(error_code) { + case MbedCloudClient::ConnectErrorNone: + error = "MbedCloudClient::ConnectErrorNone"; + break; + case MbedCloudClient::ConnectAlreadyExists: + error = "MbedCloudClient::ConnectAlreadyExists"; + break; + case MbedCloudClient::ConnectBootstrapFailed: + error = "MbedCloudClient::ConnectBootstrapFailed"; + break; + case MbedCloudClient::ConnectInvalidParameters: + error = "MbedCloudClient::ConnectInvalidParameters"; + break; + case MbedCloudClient::ConnectNotRegistered: + error = "MbedCloudClient::ConnectNotRegistered"; + break; + case MbedCloudClient::ConnectTimeout: + error = "MbedCloudClient::ConnectTimeout"; + break; + case MbedCloudClient::ConnectNetworkError: + error = "MbedCloudClient::ConnectNetworkError"; + break; + case MbedCloudClient::ConnectResponseParseFailed: + error = "MbedCloudClient::ConnectResponseParseFailed"; + break; + case MbedCloudClient::ConnectUnknownError: + error = "MbedCloudClient::ConnectUnknownError"; + break; + case MbedCloudClient::ConnectMemoryConnectFail: + error = "MbedCloudClient::ConnectMemoryConnectFail"; + break; + case MbedCloudClient::ConnectNotAllowed: + error = "MbedCloudClient::ConnectNotAllowed"; + break; + case MbedCloudClient::ConnectSecureConnectionFailed: + error = "MbedCloudClient::ConnectSecureConnectionFailed"; + break; + case MbedCloudClient::ConnectDnsResolvingFailed: + error = "MbedCloudClient::ConnectDnsResolvingFailed"; + break; +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + case MbedCloudClient::UpdateWarningCertificateNotFound: + error = "MbedCloudClient::UpdateWarningCertificateNotFound"; + break; + case MbedCloudClient::UpdateWarningIdentityNotFound: + error = "MbedCloudClient::UpdateWarningIdentityNotFound"; + break; + case MbedCloudClient::UpdateWarningCertificateInvalid: + error = "MbedCloudClient::UpdateWarningCertificateInvalid"; + break; + case MbedCloudClient::UpdateWarningSignatureInvalid: + error = "MbedCloudClient::UpdateWarningSignatureInvalid"; + break; + case MbedCloudClient::UpdateWarningVendorMismatch: + error = "MbedCloudClient::UpdateWarningVendorMismatch"; + break; + case MbedCloudClient::UpdateWarningClassMismatch: + error = "MbedCloudClient::UpdateWarningClassMismatch"; + break; + case MbedCloudClient::UpdateWarningDeviceMismatch: + error = "MbedCloudClient::UpdateWarningDeviceMismatch"; + break; + case MbedCloudClient::UpdateWarningURINotFound: + error = "MbedCloudClient::UpdateWarningURINotFound"; + break; + case MbedCloudClient::UpdateWarningRollbackProtection: + error = "MbedCloudClient::UpdateWarningRollbackProtection"; + break; + case MbedCloudClient::UpdateWarningUnknown: + error = "MbedCloudClient::UpdateWarningUnknown"; + break; + case MbedCloudClient::UpdateErrorWriteToStorage: + error = "MbedCloudClient::UpdateErrorWriteToStorage"; + break; + case MbedCloudClient::UpdateErrorInvalidHash: + error = "MbedCloudClient::UpdateErrorInvalidHash"; + break; +#endif + default: + error = "UNKNOWN"; + } + printf("\nError occurred : %s\r\n", error); + printf("Error code : %d\r\n\n", error_code); + printf("Error details : %s\r\n\n",_cloud_client.error_description()); +} + +bool SimpleMbedCloudClient::is_client_registered() { + return _registered; +} + +bool SimpleMbedCloudClient::is_register_called() { + return _register_called; +} + +void SimpleMbedCloudClient::register_and_connect() { + // TODO this might not work if called more than once... + mcc_resource_def resourceDef; + + // TODO clean up + for (unsigned int i = 0; i < _resources.size(); i++) { + _resources[i]->get_data(&resourceDef); + M2MResource *res = add_resource(&_obj_list, resourceDef.object_id, resourceDef.instance_id, + resourceDef.resource_id, resourceDef.name.c_str(), M2MResourceInstance::STRING, + (M2MBase::Operation)resourceDef.method_mask, resourceDef.value.c_str(), resourceDef.observable, + resourceDef.put_callback, resourceDef.post_callback, resourceDef.notification_callback); + _resources[i]->set_resource(res); + } + _cloud_client.add_objects(_obj_list); + + // Start registering to the cloud. + call_register(); + + // Print memory statistics if the MBED_HEAP_STATS_ENABLED is defined. + #ifdef MBED_HEAP_STATS_ENABLED + printf("Register being called\r\n"); + heap_stats(); + #endif +} + +MbedCloudClient& SimpleMbedCloudClient::get_cloud_client() { + return _cloud_client; +} + +MbedCloudClientResource* SimpleMbedCloudClient::create_resource(const char *path, const char *name) { + MbedCloudClientResource *resource = new MbedCloudClientResource(this, path, name); + _resources.push_back(resource); + return resource; +}
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/simple-mbed-cloud-client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/simple-mbed-cloud-client.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,63 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + + +#ifndef SIMPLEMBEDCLOUDCLIENT_H +#define SIMPLEMBEDCLOUDCLIENT_H +#include <stdio.h> +#include "mbed-cloud-client/MbedCloudClient.h" +#include "m2mdevice.h" +#include "m2mresource.h" +#include "mbed-client/m2minterface.h" +#include "mbed-client/m2mvector.h" +#include "mbed_cloud_client_resource.h" +#include "mbed.h" +#include "NetworkInterface.h" + +class MbedCloudClientResource; + +class SimpleMbedCloudClient { + +public: + + SimpleMbedCloudClient(NetworkInterface *net); + ~SimpleMbedCloudClient(); + + int init(); + bool call_register(); + void close(); + void register_update(); + void client_registered(); + void client_unregistered(); + void error(int error_code); + bool is_client_registered(); + bool is_register_called(); + void register_and_connect(); + MbedCloudClient& get_cloud_client(); + MbedCloudClientResource* create_resource(const char *path, const char *name); + +private: + M2MObjectList _obj_list; + MbedCloudClient _cloud_client; + bool _registered; + bool _register_called; + Vector<MbedCloudClientResource*> _resources; + NetworkInterface *net; +}; + +#endif // SIMPLEMBEDCLOUDCLIENT_H
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/update_default_resources.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/update_default_resources.c Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,41 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#include MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#endif + +#include <stdint.h> + +#ifdef MBED_CLOUD_DEV_UPDATE_ID +const uint8_t arm_uc_vendor_id[16] = { "dev_manufacturer" }; +const uint16_t arm_uc_vendor_id_size = sizeof(arm_uc_vendor_id); + +const uint8_t arm_uc_class_id[16] = { "dev_model_number" }; +const uint16_t arm_uc_class_id_size = sizeof(arm_uc_class_id); +#endif + +#ifdef MBED_CLOUD_DEV_UPDATE_CERT +const uint8_t arm_uc_default_fingerprint[32] = { 0 }; +const uint16_t arm_uc_default_fingerprint_size = + sizeof(arm_uc_default_fingerprint); + +const uint8_t arm_uc_default_certificate[1] = { 0 }; +const uint16_t arm_uc_default_certificate_size = + sizeof(arm_uc_default_certificate); +#endif
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/update_ui_example.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/update_ui_example.cpp Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,141 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update_ui_example.h" + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + +#include <stdio.h> +#include <stdint.h> + +static MbedCloudClient* _client; + +#ifdef ARM_UPDATE_CLIENT_VERSION_VALUE +#if ARM_UPDATE_CLIENT_VERSION_VALUE > 101000 +void update_ui_set_cloud_client(MbedCloudClient* client) +{ + _client = client; +} + +void update_authorize(int32_t request) +{ + switch (request) + { + /* Cloud Client wishes to download new firmware. This can have a negative + impact on the performance of the rest of the system. + + The user application is supposed to pause performance sensitive tasks + before authorizing the download. + + Note: the authorization call can be postponed and called later. + This doesn't affect the performance of the Cloud Client. + */ + case MbedCloudClient::UpdateRequestDownload: + printf("Firmware download requested\r\n"); + printf("Authorization granted\r\n"); + _client->update_authorize(MbedCloudClient::UpdateRequestDownload); + + break; + + /* Cloud Client wishes to reboot and apply the new firmware. + + The user application is supposed to save all current work before rebooting. + + Note: the authorization call can be postponed and called later. + This doesn't affect the performance of the Cloud Client. + */ + case MbedCloudClient::UpdateRequestInstall: + printf("Firmware install requested\r\n"); + printf("Authorization granted\r\n"); + _client->update_authorize(MbedCloudClient::UpdateRequestInstall); + break; + + default: + printf("Error - unknown request\r\n"); + break; + } +} +#endif +#endif + +void update_progress(uint32_t progress, uint32_t total) +{ + uint8_t percent = (uint8_t)((uint64_t)progress * 100 / total); + +/* only show progress bar if debug trace is disabled */ +#if !defined(MBED_CONF_MBED_TRACE_ENABLE) \ + && !ARM_UC_ALL_TRACE_ENABLE \ + && !ARM_UC_HUB_TRACE_ENABLE + + printf("\rDownloading: ["); + for (uint8_t index = 0; index < 50; index++) + { + if (index < percent / 2) + { + printf("+"); + } + else if (index == percent / 2) + { + static uint8_t old_max = 0; + static uint8_t counter = 0; + + if (index == old_max) + { + counter++; + } + else + { + old_max = index; + counter = 0; + } + + switch (counter % 4) + { + case 0: + printf("/"); + break; + case 1: + printf("-"); + break; + case 2: + printf("\\"); + break; + case 3: + default: + printf("|"); + break; + } + } + else + { + printf(" "); + } + } + printf("] %d %%", percent); + fflush(stdout); +#else + printf("Downloading: %d %%\r\n", percent); +#endif + + if (progress == total) + { + printf("\r\nDownload completed\r\n"); + } +} + +#endif // MBED_CLOUD_CLIENT_SUPPORT_UPDATE
diff -r 000000000000 -r 119624335925 simple-mbed-cloud-client/update_ui_example.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client/update_ui_example.h Sat Jun 30 01:40:30 2018 +0000 @@ -0,0 +1,52 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef UPDATE_UI_EXAMPLE_H +#define UPDATE_UI_EXAMPLE_H + +#include "mbed-cloud-client/MbedCloudClient.h" + +#ifdef MBED_CLOUD_CLIENT_SUPPORT_UPDATE + +#ifdef ARM_UPDATE_CLIENT_VERSION_VALUE +#if ARM_UPDATE_CLIENT_VERSION_VALUE > 101000 +/** + * @brief Function for authorizing firmware downloads and reboots. + * @param request The request under consideration. + */ +void update_authorize(int32_t request); +#endif +#endif + +/** + * @brief Callback function for reporting the firmware download progress. + * @param progress Received bytes. + * @param total Total amount of bytes to be received. + */ +void update_progress(uint32_t progress, uint32_t total); + +/** + * @brief Set the cloud client instance for the update UI to use + * @param[in] client pointer to the cloud client instance + */ +void update_ui_set_cloud_client(MbedCloudClient* client); + + +#endif // MBED_CLOUD_CLIENT_SUPPORT_UPDATE + +#endif // UPDATE_UI_EXAMPLE_H